tizen 2.3.1 release accepted/tizen_2.4_mobile tizen_2.3.1 tizen_2.4 accepted/tizen/2.4/mobile/20151029.031010 submit/tizen_2.3.1/20150915.083017 submit/tizen_2.4/20151028.064956 tizen_2.3.1_release tizen_2.4_mobile_release
authorjk7744.park <jk7744.park@samsung.com>
Tue, 8 Sep 2015 13:49:29 +0000 (22:49 +0900)
committerjk7744.park <jk7744.park@samsung.com>
Tue, 8 Sep 2015 13:49:29 +0000 (22:49 +0900)
579 files changed:
.gitignore [deleted file]
AUTHORS
COPYING
Makefile.am
NEWS
README
THANKS [new file with mode: 0644]
TODO
autogen.sh
configure.ac
contrib/python/README [deleted file]
contrib/python/lib/fontconfig.pyx [deleted file]
contrib/python/lib/harfbuzz.pyx [deleted file]
contrib/python/runpy [deleted file]
contrib/python/scripts/hbtestfont [deleted file]
contrib/python/setup.py [deleted file]
debian/changelog [deleted file]
debian/compat [deleted file]
debian/control [deleted file]
debian/copyright [deleted file]
debian/dirs [deleted file]
debian/libharfbuzz-dev.install [deleted file]
debian/libharfbuzz.install [deleted file]
debian/rules [deleted file]
docs/Makefile.am [new file with mode: 0644]
docs/reference/Makefile.am [new file with mode: 0644]
docs/reference/harfbuzz-docs.xml [new file with mode: 0644]
docs/reference/harfbuzz-overrides.txt [moved from debian/docs with 100% similarity, mode: 0644]
docs/reference/harfbuzz-sections.txt [new file with mode: 0644]
docs/reference/version.xml.in [new file with mode: 0644]
git.mk
harfbuzz.manifest [new file with mode: 0644]
m4/ax_pthread.m4 [new file with mode: 0644]
m4/libtool.m4 [new file with mode: 0644]
m4/ltoptions.m4 [new file with mode: 0644]
m4/ltsugar.m4 [new file with mode: 0644]
m4/ltversion.m4 [new file with mode: 0644]
m4/lt~obsolete.m4 [new file with mode: 0644]
m4/pkg.m4 [new file with mode: 0644]
packaging/harfbuzz.spec
src/Makefile.am
src/check-c-linkage-decls.sh
src/check-defs.sh [new file with mode: 0755]
src/check-header-guards.sh
src/check-includes.sh
src/check-internal-symbols.sh [deleted file]
src/check-libstdc++.sh
src/check-static-inits.sh [new file with mode: 0755]
src/check-symbols.sh [new file with mode: 0755]
src/gen-arabic-table.py
src/gen-indic-table.py
src/harfbuzz-gobject.pc.in [new file with mode: 0644]
src/harfbuzz-icu.pc.in [new file with mode: 0644]
src/harfbuzz.pc.in [new file with mode: 0644]
src/hb-atomic-private.hh
src/hb-blob.cc
src/hb-blob.h
src/hb-buffer-deserialize-json.rl [new file with mode: 0644]
src/hb-buffer-deserialize-text.rl [new file with mode: 0644]
src/hb-buffer-private.hh
src/hb-buffer-serialize.cc [new file with mode: 0644]
src/hb-buffer.cc
src/hb-buffer.h
src/hb-cache-private.hh
src/hb-common.cc
src/hb-common.h
src/hb-coretext.cc [new file with mode: 0644]
src/hb-coretext.h [new file with mode: 0644]
src/hb-deprecated.h [moved from src/hb-version.h with 66% similarity]
src/hb-face-private.hh [new file with mode: 0644]
src/hb-face.cc [new file with mode: 0644]
src/hb-face.h [new file with mode: 0644]
src/hb-fallback-shape.cc
src/hb-font-private.hh
src/hb-font.cc
src/hb-font.h
src/hb-ft.cc
src/hb-ft.h
src/hb-glib.cc
src/hb-glib.h
src/hb-gobject-enums.cc.tmpl
src/hb-gobject-enums.h.tmpl [moved from src/indic.cc with 66% similarity]
src/hb-gobject-structs.cc
src/hb-gobject-structs.h [new file with mode: 0644]
src/hb-gobject.h
src/hb-graphite2.cc
src/hb-graphite2.h
src/hb-icu.cc
src/hb-icu.h
src/hb-mutex-private.hh
src/hb-object-private.hh
src/hb-open-file-private.hh
src/hb-open-type-private.hh
src/hb-ot-cmap-table.hh [new file with mode: 0644]
src/hb-ot-font.cc [new file with mode: 0644]
src/hb-ot-font.h [moved from src/hb-fallback-shape-private.hh with 72% similarity]
src/hb-ot-head-table.hh
src/hb-ot-hhea-table.hh
src/hb-ot-hmtx-table.hh
src/hb-ot-layout-common-private.hh
src/hb-ot-layout-gdef-table.hh
src/hb-ot-layout-gpos-table.hh
src/hb-ot-layout-gsub-table.hh
src/hb-ot-layout-gsubgpos-private.hh
src/hb-ot-layout-jstf-table.hh [new file with mode: 0644]
src/hb-ot-layout-private.hh
src/hb-ot-layout.cc
src/hb-ot-layout.h
src/hb-ot-map-private.hh
src/hb-ot-map.cc
src/hb-ot-maxp-table.hh
src/hb-ot-name-table.hh
src/hb-ot-shape-complex-arabic-fallback.hh [new file with mode: 0644]
src/hb-ot-shape-complex-arabic-table.hh
src/hb-ot-shape-complex-arabic-win1256.hh [new file with mode: 0644]
src/hb-ot-shape-complex-arabic.cc
src/hb-ot-shape-complex-default.cc [moved from src/hb-uniscribe-private.hh with 68% similarity]
src/hb-ot-shape-complex-hangul.cc [new file with mode: 0644]
src/hb-ot-shape-complex-hebrew.cc [new file with mode: 0644]
src/hb-ot-shape-complex-indic-machine.hh [deleted file]
src/hb-ot-shape-complex-indic-machine.rl
src/hb-ot-shape-complex-indic-private.hh
src/hb-ot-shape-complex-indic-table.cc [moved from src/hb-ot-shape-complex-indic-table.hh with 63% similarity]
src/hb-ot-shape-complex-indic.cc
src/hb-ot-shape-complex-misc.cc [deleted file]
src/hb-ot-shape-complex-myanmar-machine.rl [new file with mode: 0644]
src/hb-ot-shape-complex-myanmar.cc [new file with mode: 0644]
src/hb-ot-shape-complex-private.hh
src/hb-ot-shape-complex-sea-machine.rl [new file with mode: 0644]
src/hb-ot-shape-complex-sea.cc [new file with mode: 0644]
src/hb-ot-shape-complex-thai.cc [new file with mode: 0644]
src/hb-ot-shape-complex-tibetan.cc [new file with mode: 0644]
src/hb-ot-shape-fallback-private.hh [new file with mode: 0644]
src/hb-ot-shape-fallback.cc [new file with mode: 0644]
src/hb-ot-shape-normalize-private.hh
src/hb-ot-shape-normalize.cc
src/hb-ot-shape-private.hh
src/hb-ot-shape.cc
src/hb-ot-shape.h [new file with mode: 0644]
src/hb-ot-tag.cc
src/hb-ot.h
src/hb-private.hh
src/hb-set-private.hh
src/hb-set.cc
src/hb-set.h
src/hb-shape-plan-private.hh [new file with mode: 0644]
src/hb-shape-plan.cc [new file with mode: 0644]
src/hb-shape-plan.h [new file with mode: 0644]
src/hb-shape.cc
src/hb-shape.h
src/hb-shaper-impl-private.hh [moved from src/hb-graphite2-private.hh with 77% similarity]
src/hb-shaper-list.hh [new file with mode: 0644]
src/hb-shaper-private.hh [new file with mode: 0644]
src/hb-shaper.cc [new file with mode: 0644]
src/hb-tt-font.cc [deleted file]
src/hb-ucdn.cc [new file with mode: 0644]
src/hb-ucdn/COPYING [new file with mode: 0644]
src/hb-ucdn/Makefile.am [new file with mode: 0644]
src/hb-ucdn/Makefile.in [moved from test/shaping/Makefile.in with 53% similarity]
src/hb-ucdn/README [new file with mode: 0644]
src/hb-ucdn/ucdn.c [new file with mode: 0644]
src/hb-ucdn/ucdn.h [new file with mode: 0644]
src/hb-ucdn/unicodedata_db.h [new file with mode: 0644]
src/hb-unicode-private.hh
src/hb-unicode.cc
src/hb-unicode.h
src/hb-uniscribe.cc
src/hb-uniscribe.h
src/hb-utf-private.hh [new file with mode: 0644]
src/hb-version.h.in
src/hb-warning.cc
src/hb.h
src/main.cc
src/sample.py [new file with mode: 0755]
src/test-buffer-serialize.cc [new file with mode: 0644]
src/test-size-params.cc [new file with mode: 0644]
src/test-would-substitute.cc [new file with mode: 0644]
src/test.cc [new file with mode: 0644]
test/api/.valgrind-suppressions [new file with mode: 0644]
test/api/Makefile.am
test/api/hb-test.h
test/api/test-blob.c
test/api/test-buffer.c
test/api/test-c.c
test/api/test-font.c
test/api/test-object.c
test/api/test-ot-tag.c
test/api/test-set.c [new file with mode: 0644]
test/api/test-shape-complex.c [deleted file]
test/api/test-unicode.c
test/api/test-version.c
test/shaping/Makefile.am
test/shaping/fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/37033cc5cf37bb223d7355153016b6ccece93b28.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/7e14e7883ed152baa158b80e207b66114c823a8b.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/8454d22037f892e76614e1645d066689a0200e61.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/MANIFEST [new file with mode: 0644]
test/shaping/fonts/sha1sum/a919b33197965846f21074b24e30250d67277bce.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/bb9473d2403488714043bcfb946c9f78b86ad627.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/d629e7fedc0b350222d7987345fe61613fa3929a.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/df768b9c257e0c9c35786c47cae15c46571d56be.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/e207635780b42f898d58654b65098763e340f5c7.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf [new file with mode: 0644]
test/shaping/fonts/sha1sum/f499fbc23865022234775c43503bba2e63978fe1.ttf [new file with mode: 0644]
test/shaping/hb_test_tools.py
test/shaping/record-test.sh [new file with mode: 0755]
test/shaping/run-tests.sh [new file with mode: 0755]
test/shaping/tests/MANIFEST [new file with mode: 0644]
test/shaping/tests/arabic-fallback-shaping.tests [new file with mode: 0644]
test/shaping/tests/arabic-feature-order.tests [new file with mode: 0644]
test/shaping/tests/context-matching.tests [new file with mode: 0644]
test/shaping/tests/hangul-jamo.tests [new file with mode: 0644]
test/shaping/tests/indic-joiner-candrabindu.tests [new file with mode: 0644]
test/shaping/tests/indic-old-spec.tests [new file with mode: 0644]
test/shaping/tests/indic-pref-blocking.tests [new file with mode: 0644]
test/shaping/tests/mongolian-variation-selector.tests [new file with mode: 0644]
test/shaping/tests/zero-width-marks.tests [new file with mode: 0644]
test/shaping/texts/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/mehran.txt [new file with mode: 0755]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/2grams.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/3grams.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/4grams.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/5grams.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/6grams.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/7grams.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/8grams.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mandaic/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mandaic/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mongolian/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/non-joining.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/poem.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/variation-selectors.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-nko/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-syriac/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/alaph.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-ethiopic/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-han/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-han/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-han/misc/cjk-compat.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-hiragana/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/kazuraki-liga.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-linear-b/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-tifinagh/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-hangul/script-hangul/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/diacritics.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/reph.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/dottedcircle.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/eyelash.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/joiners.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/spec-deviations.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/tricky-reordering.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/right-matras.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/cibu.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/bindu.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/extensive.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/reph.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/split-matras.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/LICENSE [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/README [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/SOURCES [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/south-east-asian/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/other-marks-invalid.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/other-marks.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-myanmar/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/otspec.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/utn11.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-cham/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-cham/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-cham/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-tai-tham/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/torture.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-lao/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-lao/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-lao/misc/sara-am.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-thai/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-thai/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-thai/misc/misc.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-thai/misc/phinthu.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-thai/misc/pua-shaping.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-thai/script-thai/misc/sara-am.txt [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/MANIFEST [new file with mode: 0644]
test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/misc.txt [new file with mode: 0644]
util/Makefile.am
util/ansi-print.cc
util/hb-ot-shape-closure.cc
util/hb-shape.cc
util/hb-view.cc
util/helper-cairo-ansi.cc
util/helper-cairo.cc
util/helper-cairo.hh
util/main-font-text.hh
util/options.cc
util/options.hh
util/shape-consumer.hh
util/view-cairo.cc
util/view-cairo.hh

diff --git a/.gitignore b/.gitignore
deleted file mode 100644 (file)
index 0583e19..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*.bak
-/*.lo
-/*.o
-/*.orig
-/*.rej
-/*.tab.c
-/*~
-/.*.sw[nop]
-/.deps
-/.gitignore
-/.libs
-/ChangeLog
-/GPATH
-/GRTAGS
-/GSYMS
-/GTAGS
-/ID
-/INSTALL
-/Makefile
-/Makefile.in
-/TAGS
-/_libs
-/aclocal.m4
-/autom4te.cache
-/autoscan.log
-/compile
-/config.cache
-/config.guess
-/config.h
-/config.h.in
-/config.log
-/config.lt
-/config.status
-/config.status.lineno
-/config.sub
-/configure
-/configure.lineno
-/configure.scan
-/depcomp
-/harfbuzz.pc
-/install-sh
-/libtool
-/ltmain.sh
-/missing
-/mkinstalldirs
-/so_locations
-/src/Makefile.in
-/stamp-h1
-/tags
-/test/Makefile.in
-/config.guess.cdbs-orig
-/config.sub.cdbs-orig
-/debian/*.debhelper.log
-/debian/*.substvars
-/debian/*.debhelper
-/debian/stamp-autotools
-/debian/stamp-autotools-files
-/debian/stamp-makefile-build
-/debian/stamp-makefile-install
-/debian/tmp/
-/debian/files
-/debian/libharfbuzz/
-/debian/libharfbuzz-dbg/
-/debian/libharfbuzz-dev/
diff --git a/AUTHORS b/AUTHORS
index e69de29..81cdc4c 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -0,0 +1,9 @@
+Behdad Esfahbod
+Simon Hausmann
+Martin Hosken
+Jonathan Kew
+Lars Knoll
+Werner Lemberg
+Roozbeh Pournader
+Owen Taylor
+David Turner
diff --git a/COPYING b/COPYING
index 4bb77a0..9d1056f 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,11 +1,16 @@
 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 © 2011 Codethink Limited
-Copyright © 2010,2011  Google, Inc.
-Copyright © 2006  Behdad Esfahbod
+Copyright © 2010,2011,2012  Google, 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 © 2006  Behdad Esfahbod
+Copyright © 2005  David Turner
 Copyright © 2004,2007,2008,2009,2010  Red Hat, Inc.
 Copyright © 1998-2004  David Turner and Werner Lemberg
 
index a405dbf..7a874aa 100644 (file)
@@ -2,32 +2,26 @@
 
 NULL =
 
-SUBDIRS = src util test
+ACLOCAL_AMFLAGS = -I m4
 
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = harfbuzz.pc
+#SUBDIRS = src util test docs
+SUBDIRS = src
 
 EXTRA_DIST = \
        autogen.sh \
        harfbuzz.doap \
+       Android.mk \
+       README.python \
        $(NULL)
 
 MAINTAINERCLEANFILES = \
+       $(GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL) \
+       $(GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL) \
+       $(GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN) \
        $(srcdir)/INSTALL \
-       $(srcdir)/aclocal.m4 \
-       $(srcdir)/autoscan.log \
-       $(srcdir)/compile \
-       $(srcdir)/config.guess \
-       $(srcdir)/config.h.in \
-       $(srcdir)/config.sub \
-       $(srcdir)/configure.scan \
-       $(srcdir)/depcomp \
-       $(srcdir)/install-sh \
-       $(srcdir)/ltmain.sh \
-       $(srcdir)/missing \
-       $(srcdir)/mkinstalldirs \
        $(srcdir)/ChangeLog \
-       `find "$(srcdir)" -type f -name Makefile.in -print`
+       $(srcdir)/gtk-doc.make \
+       $(NULL)
 
 
 #
@@ -36,28 +30,37 @@ MAINTAINERCLEANFILES = \
 CHANGELOG_RANGE =
 ChangeLog: $(srcdir)/ChangeLog
 $(srcdir)/ChangeLog:
-       $(AM_V_GEN) if test -d "$(srcdir)/.git"; then \
-         (GIT_DIR=$(top_srcdir)/.git ./missing --run \
-          git log $(CHANGELOG_RANGE) --stat) | fmt --split-only > $@.tmp \
-         && mv -f $@.tmp $@ \
+       $(AM_V_GEN) if test -d "$(top_srcdir)/.git"; then \
+         (GIT_DIR=$(top_srcdir)/.git \
+          $(GIT) log $(CHANGELOG_RANGE) --stat) | fmt --split-only > $@.tmp \
+         && mv -f $@.tmp "$(srcdir)/ChangeLog" \
          || ($(RM) $@.tmp; \
              echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
-             (test -f $@ || echo git-log is required to generate this file >> $@)); \
+             (test -f $@ || echo git-log is required to generate this file >> "$(srcdir)/$@")); \
        else \
          test -f $@ || \
          (echo A git checkout and git-log is required to generate ChangeLog >&2 && \
-         echo A git checkout and git-log is required to generate this file >> $@); \
+         echo A git checkout and git-log is required to generate this file >> "$(srcdir)/$@"); \
        fi
-.PHONY: $(srcdir)/ChangeLog
+.PHONY: ChangeLog $(srcdir)/ChangeLog
 
 
 #
 # Release engineering
 #
 
+DISTCHECK_CONFIGURE_FLAGS = \
+       --enable-gtk-doc \
+       --disable-doc-cross-references \
+       --with-gobject \
+       --enable-introspection \
+       $(NULL)
+
 # TODO: Copy infrastructure from cairo
 
+# TAR_OPTIONS is not set as env var for 'make dist'.  How to fix that?
 TAR_OPTIONS = --owner=0 --group=0
+
 dist-hook: dist-clear-sticky-bits
 # Clean up any sticky bits we may inherit from parent dir
 dist-clear-sticky-bits:
@@ -76,5 +79,4 @@ $(gpg_file): $(sha256_file)
 release-files: $(tar_file) $(sha256_file) $(gpg_file)
 
 
-
 -include $(top_srcdir)/git.mk
diff --git a/NEWS b/NEWS
index d31c548..c4950e2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,865 @@
+Overview of changes leading to 0.9.40
+Friday, March 20, 2015
+=====================================
+
+- Another hb-coretext crasher fix.  Ouch!
+- Happy Norouz!
+
+
+Overview of changes leading to 0.9.39
+Wednesday, March 4, 2015
+=====================================
+
+- Critical hb-coretext fixes.
+- Optimizations and refactoring; no functional change
+  expected.
+- Misc build fixes.
+
+
+Overview of changes leading to 0.9.38
+Friday, January 23, 2015
+=====================================
+
+- Fix minor out-of-bounds access in Indic shaper.
+- Change New Tai Lue shaping engine from South-East Asian to default,
+  reflecting change in Unicode encoding model.
+- Add hb-shape --font-size.  Can take up to two numbers for separate
+  x / y size.
+- Fix CoreText and FreeType scale issues with negative scales.
+- Reject blobs larger than 2GB.  This might break some icu-le-hb clients
+  that need security fixes.  See:
+  http://www.icu-project.org/trac/ticket/11450
+- Avoid accessing font tables during face destruction, in casce rogue
+  clients released face data already.
+- Fix up gobject-introspection a bit.  Python bindings kinda working.
+  See README.python.
+- Misc fixes.
+- API additions:
+  hb_ft_face_create_referenced()
+  hb_ft_font_create_referenced()
+
+
+Overview of changes leading to 0.9.37
+Wednesday, December 17, 2014
+=====================================
+
+- Fix out-of-bounds access in Context lookup format 3.
+- Indic: Allow ZWJ/ZWNJ before syllable modifiers.
+
+
+Overview of changes leading to 0.9.36
+Thursday, November 20, 2014
+=====================================
+
+- First time that three months went by without a release since
+  0.9.2 was released on August 10, 2012!
+- Fix performance bug in hb_ot_collect_glyphs():
+  https://bugzilla.mozilla.org/show_bug.cgi?id=1090869
+- Add basic vertical-text support to hb-ot-font.
+- Misc build fixes.
+
+
+Overview of changes leading to 0.9.35
+Saturday, August 13, 2014
+=====================================
+
+- Fix major shape-plan caching bug when more than one shaper were
+  provided to hb_shape_full() (as exercised by XeTeX).
+  http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1246370.html
+- Fix Arabic fallback shaping regression.  This was broken in 0.9.32.
+- Major hb-coretext fixes.  That backend is complete now, including
+  respecing buffer direction and language, down to vertical writing.
+- Build fixes for Windows CE.  Should build fine now.
+- Misc fixes:
+  Use atexit() only if it's safe to call from shared library
+  https://bugs.freedesktop.org/show_bug.cgi?id=82246
+  Mandaic had errors in its Unicode Joining_Type
+  https://bugs.freedesktop.org/show_bug.cgi?id=82306
+- API changes:
+
+  * hb_buffer_clear_contents() does not reset buffer flags now.
+
+    After 763e5466c0a03a7c27020e1e2598e488612529a7, one doesn't
+    need to set flags for different pieces of text.  The flags now
+    are something the client sets up once, depending on how it
+    actually uses the buffer.  As such, don't clear it in
+    clear_contents().
+
+    I don't expect any changes to be needed to any existing client.
+
+
+Overview of changes leading to 0.9.34
+Saturday, August 2, 2014
+=====================================
+
+- hb_feature_from_string() now accepts CSS font-feature-settings format.
+- As a result, hb-shape / hb-view --features also accept CSS-style strings.
+  Eg, "'liga' off" is accepted now.
+- Add old-spec Myanmar shaper:
+  https://bugs.freedesktop.org/show_bug.cgi?id=81775
+- Don't apply 'calt' in Hangul shaper.
+- Fix mark advance zeroing for Hebrew shaper:
+  https://bugs.freedesktop.org/show_bug.cgi?id=76767
+- Implement Windows-1256 custom Arabic shaping.  Only built on Windows,
+  and requires help from get_glyph().  Used by Firefox.
+  https://bugzilla.mozilla.org/show_bug.cgi?id=1045139
+- Disable 'liga' in vertical text.
+- Build fixes.
+- API changes:
+
+  * Make HB_BUFFER_FLAG_BOT/EOT easier to use.
+
+    Previously, we expected users to provide BOT/EOT flags when the
+    text *segment* was at paragraph boundaries.  This meant that for
+    clients that provide full paragraph to HarfBuzz (eg. Pango), they
+    had code like this:
+
+      hb_buffer_set_flags (hb_buffer,
+                           (item_offset == 0 ? HB_BUFFER_FLAG_BOT : 0) |
+                           (item_offset + item_length == paragraph_length ?
+                            HB_BUFFER_FLAG_EOT : 0));
+
+      hb_buffer_add_utf8 (hb_buffer,
+                          paragraph_text, paragraph_length,
+                          item_offset, item_length);
+
+    After this change such clients can simply say:
+
+      hb_buffer_set_flags (hb_buffer,
+                           HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
+
+      hb_buffer_add_utf8 (hb_buffer,
+                          paragraph_text, paragraph_length,
+                          item_offset, item_length);
+
+    Ie, HarfBuzz itself checks whether the segment is at the beginning/end
+    of the paragraph.  Clients that only pass item-at-a-time to HarfBuzz
+    continue not setting any flags whatsoever.
+
+    Another way to put it is: if there's pre-context text in the buffer,
+    HarfBuzz ignores the BOT flag.  If there's post-context, it ignores
+    EOT flag.
+
+
+Overview of changes leading to 0.9.33
+Tuesday, July 22, 2014
+=====================================
+
+- Turn off ARabic 'cswh' feature that was accidentally turned on.
+- Add HB_TAG_MAX_SIGNED.
+- Make hb_face_make_immutable() really make face immutable!
+- Windows build fixes.
+
+
+Overview of changes leading to 0.9.32
+Thursday, July 17, 2014
+=====================================
+
+- Apply Arabic shaping features in spec order exactly.
+- Another fix for Mongolian free variation selectors.
+- For non-Arabic scripts in Arabic shaper apply 'rlig' and 'calt'
+  together.
+- Minor adjustment to U+FFFD logic.
+- Fix hb-coretext build.
+
+
+Overview of changes leading to 0.9.31
+Wednesday, July 16, 2014
+=====================================
+
+- Only accept valid UTF-8/16/32; we missed many cases before.
+- Better shaping of invalid UTF-8/16/32.  Falls back to
+  U+FFFD REPLACEMENT CHARACTER now.
+- With all changes in this release, the buffer will contain fully
+  valid Unicode after hb_buffer_add_utf8/16/32 no matter how
+  broken the input is.  This can be overriden though.  See below.
+- Fix Mongolian Variation Selectors for fonts without GDEF.
+- Fix minor invalid buffer access.
+- Accept zh-Hant and zh-Hans language tags.  hb_ot_tag_to_language()
+  now uses these instead of private tags.
+- Build fixes.
+- New API:
+  * hb_buffer_add_codepoints().  This does what hb_buffer_add_utf32()
+    used to do, ie. no validity check on the input at all.  add_utf32
+    now replaces invalid Unicode codepoints with the replacement
+    character (see below).
+  * hb_buffer_set_replacement_codepoint()
+  * hb_buffer_get_replacement_codepoint()
+    Previously, in hb_buffer_add_utf8 and hb_buffer_add_utf16, when
+    we detected broken input, we replaced that with (hb_codepoint_t)-1.
+    This has changed to use U+FFFD now, but can be changed using these
+    new API.
+
+
+Overview of changes leading to 0.9.30
+Wednesday, July 9, 2014
+=====================================
+
+- Update to Unicode 7.0.0:
+  * New scripts Manichaean and Psalter Pahlavi are shaped using
+    Arabic shaper.
+  * All the other new scripts to through the generic shaper for
+    now.
+- Minor Indic improvements.
+- Fix graphite2 backend cluster mapping [crasher!]
+- API changes:
+  * New HB_SCRIPT_* values for Unicode 7.0 scripts.
+  * New function hb_ot_layout_language_get_required_feature().
+- Build fixes.
+
+
+Overview of changes leading to 0.9.29
+Thursday, May 29, 2014
+=====================================
+
+- Implement cmap in hb-ot-font.h.  No variation-selectors yet.
+- Myanmar: Allow MedialYa+Asat.
+- Various Indic fixes:
+  * Support most characters in Extended Devanagary and Vedic
+    Unicode blocks.
+  * Allow digits and a some punctuation as consonant placeholders.
+- Build fixes.
+
+
+Overview of changes leading to 0.9.28
+Monday, April 28, 2014
+=====================================
+
+- Unbreak old-spec Indic shaping. (bug 76705)
+- Fix shaping of U+17DD and U+0FC6.
+- Add HB_NO_MERGE_CLUSTERS build option.  NOT to be enabled by default
+  for shipping libraries.  It's an option for further experimentation
+  right now.  When we are sure how to do it properly, we will add
+  public run-time API for the functionality.
+- Build fixes.
+
+
+Overview of changes leading to 0.9.27
+Tuesday, March 18, 2014
+=====================================
+
+- Don't use "register" storage class specifier
+- Wrap definition of free_langs() with HAVE_ATEXIT
+- Add coretext_aat shaper and hb_coretext_face_create() constructor
+- If HAVE_ICU_BUILTIN is defined, use hb-icu Unicode callbacks
+- Add Myanmar test case from OpenType Myanmar spec
+- Only do fallback Hebrew composition if no GPOS 'mark' available
+- Allow bootstrapping without gtk-doc
+- Use AM_MISSING_PROG for ragel and git
+- Typo in ucdn's Makefile.am
+- Improve MemoryBarrier() implementation
+
+
+Overview of changes leading to 0.9.26
+Thursday, January 30, 2014
+=====================================
+
+- Misc fixes.
+- Fix application of 'rtlm' feature.
+- Automatically apply frac/numr/dnom around U+2044 FRACTION SLASH.
+- New header: hb-ot-shape.h
+- Uniscribe: fix scratch-buffer accounting.
+- Reorder Tai Tham SAKOT to after tone-marks.
+- Add Hangul shaper.
+- New files:
+  hb-ot-shape-complex-hangul.cc
+  hb-ot-shape-complex-hebrew.cc
+  hb-ot-shape-complex-tibetan.cc
+- Disable 'cswh' feature in Arabic shaper.
+- Coretext: better handle surrogate pairs.
+- Add HB_TAG_MAX and _HB_SCRIPT_MAX_VALUE.
+
+
+Overview of changes leading to 0.9.25
+Wednesday, December 4, 2013
+=====================================
+
+- Myanmar shaper improvements.
+- Avoid font fallback in CoreText backend.
+- Additional OpenType language tag mappiongs.
+- More aggressive shape-plan caching.
+- Build with / require automake 1.13.
+- Build with libtool 2.4.2.418 alpha to support ppc64le.
+
+
+Overview of changes leading to 0.9.24
+Tuesday, November 13, 2013
+=====================================
+
+- Misc compiler warning fixes with clang.
+- No functional changes.
+
+
+Overview of changes leading to 0.9.23
+Monday, October 28, 2013
+=====================================
+
+- "Udupi HarfBuzz Hackfest", Paris, October 14..18 2013.
+- Fix (Chain)Context recursion with non-monotone lookup positions.
+- Misc Indic bug fixes.
+- New Javanese / Buginese shaping, similar to Windows 8.1.
+
+
+Overview of changes leading to 0.9.22
+Thursday, October 3, 2013
+=====================================
+
+- Fix use-after-end-of-scope in hb_language_from_string().
+- Fix hiding of default_ignorables if font doesn't have space glyph.
+- Protect against out-of-range lookup indices.
+
+- API Changes:
+
+  * Added hb_ot_layout_table_get_lookup_count()
+
+
+Overview of changes leading to 0.9.21
+Monday, September 16, 2013
+=====================================
+
+- Rename gobject-introspection library name from harfbuzz to HarfBuzz.
+- Remove (long disabled) hb-old and hb-icu-le test shapers.
+- Misc gtk-doc and gobject-introspection annotations.
+- Misc fixes.
+- API changes:
+
+  * Add HB_SET_VALUE_INVALID
+
+Overview of changes leading to 0.9.20
+Thursday, August 29, 2013
+=====================================
+
+General:
+- Misc substitute_closure() fixes.
+- Build fixes.
+
+Documentation:
+- gtk-doc boilerplate integrated.  Docs are built now, but
+  contain no contents.  By next release hopefully we have
+  some content in.  Enable using --enable-gtk-doc.
+
+GObject and Introspection:
+- Added harfbuzz-gobject library (hb-gobject.h) that has type
+  bindings for all HarfBuzz objects and enums.  Enable using
+  --with-gobject.
+- Added gobject-introspection boilerplate.  Nothing useful
+  right now.  Work in progress.  Gets enabled automatically if
+  --with-gobject is used.  Override with --disable-introspection.
+
+OpenType shaper:
+- Apply 'mark' in Myanmar shaper.
+- Don't apply 'dlig' by default.
+
+Uniscribe shaper:
+- Support user features.
+- Fix loading of fonts that are also installed on the system.
+- Fix shaping of Arabic Presentation Forms.
+- Fix build with wide chars.
+
+CoreText shaper:
+- Support user features.
+
+Source changes:
+- hb_face_t code moved to hb-face.h / hb-face.cc.
+- Added hb-deprecated.h.
+
+API changes:
+- Added HB_DISABLE_DEPRECATED.
+- Deprecated HB_SCRIPT_CANADIAN_ABORIGINAL; replaced by
+  HB_SCRIPT_CANADIAN_SYLLABICS.
+- Deprecated HB_BUFFER_FLAGS_DEFAULT; replaced by
+  HB_BUFFER_FLAG_DEFAULT.
+- Deprecated HB_BUFFER_SERIALIZE_FLAGS_DEFAULT; replaced by
+  HB_BUFFER_SERIALIZE_FLAG_DEFAULT.
+
+
+Overview of changes leading to 0.9.19
+Tuesday, July 16, 2013
+=====================================
+
+- Build fixes.
+- Better handling of multiple variation selectors in a row.
+- Pass on variation selector to GSUB if not consumed by cmap.
+- Fix undefined memory access.
+- Add Javanese config to Indic shaper.
+- Misc bug fixes.
+
+Overview of changes leading to 0.9.18
+Tuesday, May 28, 2013
+=====================================
+
+New build system:
+
+- All unneeded code is all disabled by default,
+
+- Uniscribe and CoreText shapers can be enabled with their --with options,
+
+- icu_le and old shapers cannot be enabled for now,
+
+- glib, freetype, and cairo will be detected automatically.
+  They can be force on/off'ed with their --with options,
+
+- icu and graphite2 are default off, can be enabled with their --with
+  options,
+
+Moreover, ICU support is now build into a separate library:
+libharfbuzz-icu.so, and a new harfbuzz-icu.pc is shipped for it.
+Distros can enable ICU now without every application on earth
+getting linked to via libharfbuzz.so.
+
+For distros I recommend that they make sure they are building --with-glib
+--with-freetype --with-cairo, --with-icu, and optionally --with-graphite2;
+And package harfbuzz and harfbuzz-icu separately.
+
+
+Overview of changes leading to 0.9.17
+Monday, May 20, 2013
+=====================================
+
+- Build fixes.
+- Fix bug in hb_set_get_min().
+- Fix regression with Arabic mark positioning / width-zeroing.
+
+Overview of changes leading to 0.9.16
+Friday, April 19, 2013
+=====================================
+
+- Major speedup in OpenType lookup processing.  With the Amiri
+  Arabic font, this release is over 3x faster than previous
+  release.  All scripts / languages should see this speedup.
+
+- New --num-iterations option for hb-shape / hb-view; useful for
+  profiling.
+
+Overview of changes leading to 0.9.15
+Friday, April 05, 2013
+=====================================
+
+- Build fixes.
+- Fix crasher in graphite2 shaper.
+- Fix Arabic mark width zeroing regression.
+- Don't compose Hangul jamo into Unicode syllables.
+
+
+Overview of changes leading to 0.9.14
+Thursday, March 21, 2013
+=====================================
+
+- Build fixes.
+- Fix time-consuming sanitize with malicious fonts.
+- Implement hb_buffer_deserialize_glyphs() for both json and text.
+- Do not ignore Hangul filler characters.
+- Indic fixes:
+  * Fix Malayalam pre-base reordering interaction with post-forms.
+  * Further adjust ZWJ handling.  Should fix known regressions from
+    0.9.13.
+
+
+Overview of changes leading to 0.9.13
+Thursday, February 25, 2013
+=====================================
+
+- Build fixes.
+- Ngapi HarfBuzz Hackfest in London (February 2013):
+  * Fixed all known Indic bugs,
+  * New Win8-style Myanmar shaper,
+  * New South-East Asian shaper for Tai Tham, Cham, and New Tai Lue,
+  * Smartly ignore Default_Ignorable characters (joiners, etc) wheb
+    matching GSUB/GPOS lookups,
+  * Fix 'Phags-Pa U+A872 shaping,
+  * Fix partial disabling of default-on features,
+  * Allow disabling of TrueType kerning.
+- Fix possible crasher with broken fonts with overlapping tables.
+- Removed generated files from git again.  So, one needs ragel to
+  bootstrap from the git tree.
+
+API changes:
+- hb_shape() and related APIs now abort if buffer direction is
+  HB_DIRECTION_INVALID.  Previously, hb_shape() was calling
+  hb_buffer_guess_segment_properties() on the buffer before
+  shaping.  The heuristics in that function are fragile.  If the
+  user really wants the old behvaior, they can call that function
+  right before calling hb_shape() to get the old behavior.
+- hb_blob_create_sub_blob() always creates sub-blob with
+  HB_MEMORY_MODE_READONLY.  See comments for the reason.
+
+
+Overview of changes leading to 0.9.12
+Thursday, January 18, 2013
+=====================================
+
+- Build fixes for Sun compiler.
+- Minor bug fix.
+
+Overview of changes leading to 0.9.11
+Thursday, January 10, 2013
+=====================================
+
+- Build fixes.
+- Fix GPOS mark attachment with null Anchor offsets.
+- [Indic] Fix old-spec reordering of viramas if sequence ends in one.
+- Fix multi-threaded shaper data creation crash.
+- Add atomic ops for Solaris.
+
+API changes:
+- Rename hb_buffer_clear() to hb_buffer_clear_contents().
+
+
+Overview of changes leading to 0.9.10
+Thursday, January 3, 2013
+=====================================
+
+- [Indic] Fixed rendering of Malayalam dot-reph
+- Updated OT language tags.
+- Updated graphite2 backend.
+- Improved hb_ot_layout_get_size_params() logic.
+- Improve hb-shape/hb-view help output.
+- Fixed hb-set.h implementation to not crash.
+- Fixed various issues with hb_ot_layout_collect_lookups().
+- Various build fixes.
+
+New API:
+
+hb_graphite2_face_get_gr_face()
+hb_graphite2_font_get_gr_font()
+hb_coretext_face_get_cg_font()
+
+Modified API:
+
+hb_ot_layout_get_size_params()
+
+
+Overview of changes leading to 0.9.9
+Wednesday, December 5, 2012
+====================================
+
+- Fix build on Windows.
+- Minor improvements.
+
+
+Overview of changes leading to 0.9.8
+Tuesday, December 4, 2012
+====================================
+
+
+- Actually implement hb_shape_plan_get_shaper ().
+- Make UCDB data tables const.
+- Lots of internal refactoring in OTLayout tables.
+- Flesh out hb_ot_layout_lookup_collect_glyphs().
+
+New API:
+
+hb_ot_layout_collect_lookups()
+hb_ot_layout_get_size_params()
+
+
+Overview of changes leading to 0.9.7
+Sunday, November 21, 2012
+====================================
+
+
+HarfBuzz "All-You-Can-Eat-Sushi" (aka Vancouver) Hackfest and follow-on fixes.
+
+- Fix Arabic contextual joining using pre-context text.
+- Fix Sinhala "split matra" mess.
+- Fix Khmer shaping with broken fonts.
+- Implement Thai "PUA" shaping for old fonts.
+- Do NOT route Kharoshthi script through the Indic shaper.
+- Disable fallback positioning for Indic and Thai shapers.
+- Misc fixes.
+
+
+hb-shape / hb-view changes:
+
+- Add --text-before and --text-after
+- Add --bot / --eot / --preserve-default-ignorables
+- hb-shape --output-format=json
+
+
+New API:
+
+hb_buffer_clear()
+
+hb_buffer_flags_t
+
+HB_BUFFER_FLAGS_DEFAULT
+HB_BUFFER_FLAG_BOT
+HB_BUFFER_FLAG_EOT
+HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES
+
+hb_buffer_set_flags()
+hb_buffer_get_flags()
+
+HB_BUFFER_SERIALIZE_FLAGS
+hb_buffer_serialize_glyphs()
+hb_buffer_deserialize_glyphs()
+hb_buffer_serialize_list_formats()
+
+hb_set_add_range()
+hb_set_del_range()
+hb_set_get_population()
+hb_set_next_range()
+
+hb_face_[sg]et_glyph_count()
+
+hb_segment_properties_t
+HB_SEGMENT_PROPERTIES_DEFAULT
+hb_segment_properties_equal()
+hb_segment_properties_hash()
+
+hb_buffer_set_segment_properties()
+hb_buffer_get_segment_properties()
+
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class()
+hb_ot_layout_get_glyphs_in_class()
+
+hb_shape_plan_t
+hb_shape_plan_create()
+hb_shape_plan_create_cached()
+hb_shape_plan_get_empty()
+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_ot_shape_plan_collect_lookups()
+
+
+API changes:
+
+- Remove "mask" parameter from hb_buffer_add().
+- Rename hb_ot_layout_would_substitute_lookup() and hb_ot_layout_substitute_closure_lookup().
+- hb-set.h API const correction.
+- Renamed hb_set_min/max() to hb_set_get_min/max().
+- Rename hb_ot_layout_feature_get_lookup_indexes() to hb_ot_layout_feature_get_lookups().
+- Rename hb_buffer_guess_properties() to hb_buffer_guess_segment_properties().
+
+
+
+Overview of changes leading to 0.9.6
+Sunday, November 13, 2012
+====================================
+
+- Don't clear pre-context text if no new context is provided.
+- Fix ReverseChainingSubstLookup, which was totally borked.
+- Adjust output format of hb-shape a bit.
+- Include config.h.in in-tree.  Makes it easier for alternate build systems.
+- Fix hb_buffer_set_length(buffer, 0) invalid memory allocation.
+- Use ICU LayoutEngine's C API instead of C++.  Avoids much headache.
+- Drop glyphs for all of Unicode Default_Ignorable characters.
+- Misc build fixes.
+
+Arabic shaper:
+- Enable 'dlig' and 'mset' features in Arabic shaper.
+- Implement 'Phags-pa shaping, improve Mongolian.
+
+Indic shaper:
+- Decompose Sinhala split matras the way old HarfBuzz / Pango did.
+- Initial support for Consonant Medials.
+- Start adding new-style Myanmar shaping.
+- Make reph and 'pref' logic introspect the font.
+- Route Meetei-Mayek through the Indic shaper.
+- Don't apply 'liga' in Indic shaper.
+- Improve Malayalam pre-base reordering Ra interaction with Chillus.
+
+
+
+Overview of changes leading to 0.9.5
+Sunday, October 14, 2012
+====================================
+
+- Synthetic-GSUB Arabic fallback shaping.
+
+- Misc Indic improvements.
+
+- Add build system support for pthread.
+
+- Imported UCDN for in-tree Unicode callbacks implementation.
+
+- Context-aware Arabic joining.
+
+- Misc other fixes.
+
+- New API:
+
+  hb_feature_to/from-string()
+  hb_buffer_[sg]et_content_type()
+
+
+
+Overview of changes leading to 0.9.4
+Tuesday, Sep 03, 2012
+====================================
+
+- Indic improvements with old-spec Malayalam.
+
+- Better fallback glyph positioning, specially with Thai / Lao marks.
+
+- Implement dotted-circle insertion.
+
+- Better Arabic fallback shaping / ligation.
+
+- Added ICU LayoutEngine backend for testing.  Call it by the 'icu_le' name.
+
+- Misc fixes.
+
+
+
+Overview of changes leading to 0.9.3
+Friday, Aug 18, 2012
+====================================
+
+- Fixed fallback mark positioning for left-to-right text.
+
+- Improve mark positioning for the remaining combining classes.
+
+- Unbreak Thai and fallback Arabic shaping.
+
+- Port Arabic shaper to shape-plan caching.
+
+- Use new ICU normalizer functions.
+
+
+
+Overview of changes leading to 0.9.2
+Friday, Aug 10, 2012
+====================================
+
+- Over a thousand commits!  This is the first major release of HarfBuzz.
+
+- HarfBuzz is feature-complete now!  It should be in par, or better, than
+  both Pango's shapers and old HarfBuzz / Qt shapers.
+
+- New Indic shaper, supporting main Indic scripts, Sinhala, and Khmer.
+
+- Improved Arabic shaper, with fallback Arabic shaping, supporting Arabic,
+  Sinhala, N'ko, Mongolian, and Mandaic.
+
+- New Thai / Lao shaper.
+
+- Tibetan / Hangul support in the generic shaper.
+
+- Synthetic GDEF support for fonts without a GDEF table.
+
+- Fallback mark positioning for fonts without a GPOS table.
+
+- Unicode normalization shaping heuristic during glyph mapping.
+
+- New experimental Graphite2 backend.
+
+- New Uniscribe backend (primarily for testing).
+
+- New CoreText backend (primarily for testing).
+
+- Major optimization and speedup.
+
+- Test suites and testing infrastructure (work in progress).
+
+- Greatly improved hb-view cmdline tool.
+
+- hb-shape cmdline tool.
+
+- Unicode 6.1 support.
+
+Summary of API changes:
+
+o Changed API:
+
+  - Users are expected to only include main header files now (ie. hb.h,
+    hb-glib.h, hb-ft.h, ...)
+
+  - All struct tag names had their initial underscore removed.
+    Ie. "struct _hb_buffer_t" is "struct hb_buffer_t" now.
+
+  - All set_user_data() functions now take a "replace" boolean parameter.
+
+  - 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,
+    meaning "nul-terminated".
+
+  - hb_direction_t enum values changed.
+
+  - All *_from_string() APIs now take a length parameter to allow for
+    non-nul-terminated strings. A -1 length means "nul-terminated".
+
+  - Typedef for hb_language_t changed.
+
+  - hb_get_table_func_t renamed to hb_reference_table_func_t.
+
+  - hb_ot_layout_table_choose_script()
+
+  - Various renames in hb-unicode.h.
+
+o New API:
+
+  - hb_buffer_guess_properties()
+    Automatically called by hb_shape().
+
+  - hb_buffer_normalize_glyphs()
+
+  - hb_tag_from_string()
+
+  - hb-coretext.h
+
+  - hb-uniscribe.h
+
+  - hb_face_reference_blob()
+  - hb_face_[sg]et_index()
+  - hb_face_set_upem()
+
+  - hb_font_get_glyph_name_func_t
+    hb_font_get_glyph_from_name_func_t
+    hb_font_funcs_set_glyph_name_func()
+    hb_font_funcs_set_glyph_from_name_func()
+    hb_font_get_glyph_name()
+    hb_font_get_glyph_from_name()
+    hb_font_glyph_to_string()
+    hb_font_glyph_from_string()
+
+  - hb_font_set_funcs_data()
+
+  - hb_ft_font_set_funcs()
+  - hb_ft_font_get_face()
+
+  - hb-gobject.h (work in progress)
+
+  - hb_ot_shape_glyphs_closure()
+    hb_ot_layout_substitute_closure_lookup()
+
+  - hb-set.h
+
+  - hb_shape_full()
+
+  - hb_unicode_combining_class_t
+
+  - hb_unicode_compose_func_t
+    hb_unicode_decompose_func_t
+    hb_unicode_decompose_compatibility_func_t
+    hb_unicode_funcs_set_compose_func()
+    hb_unicode_funcs_set_decompose_func()
+    hb_unicode_funcs_set_decompose_compatibility_func()
+    hb_unicode_compose()
+    hb_unicode_decompose()
+    hb_unicode_decompose_compatibility()
+
+o Removed API:
+
+  - hb_ft_get_font_funcs()
+
+  - hb_ot_layout_substitute_start()
+    hb_ot_layout_substitute_lookup()
+    hb_ot_layout_substitute_finish()
+    hb_ot_layout_position_start()
+    hb_ot_layout_position_lookup()
+    hb_ot_layout_position_finish()
+
+
+
 Overview of changes leading to 0.6.0
 Friday, May 27, 2011
 ====================================
diff --git a/README b/README
index 74e739d..d34bc74 100644 (file)
--- a/README
+++ b/README
@@ -1,3 +1,6 @@
+[![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
+[![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
+
 This is HarfBuzz, a text shaping library.
 
 For bug reports, mailing list, and other information please visit:
diff --git a/THANKS b/THANKS
new file mode 100644 (file)
index 0000000..940cfde
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,7 @@
+Bradley Grainger
+Khaled Hosny
+Kenichi Ishibashi
+Ryan Lortie
+Jeff Muizelaar
+suzuki toshiya
+Philip Withnall
diff --git a/TODO b/TODO
index 4a1ad19..e1aa39c 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,82 +1,55 @@
 General fixes:
 =============
 
-- Warn at compile time (and runtime with HB_DEBUG?) if no Unicode / font
-  funcs found / set.
+- AAT 'morx' implementation.
+
+- Return "safe-to-break" bit from shaping.
+
+- Implement 'rand' feature.
 
-- In hb_shape(), assert if direction is INVALID.
+- mask propagation? (when ligation, "or" the masks).
 
-- Fix TT 'kern' on/off and GPOS interaction (move kerning before GPOS).
+- Warn at compile time (and runtime with HB_DEBUG?) if no Unicode / font
+  funcs found / set.
 
 - Do proper rounding when scaling from font space?  May be a non-issue.
 
 - Misc features:
   * init/medi/fina/isol for non-cursive scripts
-  * vkna,hkna etc for kana, etc
-
-- Move non-native direction and normalization handling to the generic non-OT
-  layer, such that uniscribe and other backends can use.
-
-- Uniscribe backend needs to enforce one direction only, otherwise cluster
-  values can confuse the user.
-
-- GSUB ligation should call merge_clusters().  Also other places.
-
-- Convert NBSP into space glyph.
-
-- Synthetic GDEF.
-
-- Add Pango backend?
-
-- Add ICUlayout backend?
-
-- Add ICUlayout API?
-
-- Add Old HarfBuzz backend?
-
-- Add Old HarfBuzz API?
 
 
 API issues to fix before 1.0:
 ============================
 
-- Add default font_funcs / Unicode funcs API and to utils.
+- API to accept a list of languages?
 
 - Add init_func to font_funcs.  Adjust ft.
 
-- Add pkg-config files for glue codes (harfbuzz-glib, etc)
+- hb-ft load_flags issues.
 
-- Figure out how many .so objects, how to link, etc
+- Add pkg-config files for glue codes (harfbuzz-glib, etc)
 
 - 'const' for getter APIs? (use mutable internally)
 
-- blob_from_file?
+- Remove hb_ot_shape_glyphs_closure()?
 
 
 API additions
 =============
 
-- Buffer (de)serialize API ala hb-shape?
+- Language to/from script.
 
-- Move feature parsing from util into the library
+- blob_from_file?
 
 - Add hb-cairo glue
 
 - Add sanitize API (and a cached version, that saves result on blob user-data)
 
-- Add glib GBoxedType stuff and introspection
-
-- Add Uniscribe face / font get API
-
 - BCP 47 language handling / API (language_matches?)
 
-- Add hb_face_get_glyph_count()?
-
-- Add hb_font_create_linear()?
+- Add hb_font_create_unscaled()?
 
-- Add hb_shape_plan()/hb_shape_planned()
-
-- Add query API for aalt-like features?
+- Add query / enumeration API for aalt-like features?
 
 - SFNT api? get_num_faces? get_table_tags? (there's something in stash)
 
@@ -88,9 +61,7 @@ API additions
 hb-view / hb-shape enhancements:
 ===============================
 
-- Add --width, --height, --auto-size, --align, etc?
-- Add XML and JSON formats to hb-shape
-- --features="init=medi=isol=fina=0"
+- Add --width, --height, --auto-size, --ink-box, --align, etc?
 
 
 Tests to write:
@@ -104,16 +75,7 @@ Tests to write:
 
 - GObject, FreeType, etc
 
-- hb_set_t
-
 - hb_cache_t and relatives
 
-
-Optimizations:
-=============
-
-- Avoid allocating blob objects internally for for_data() faces?
-
-- Add caching layer to hb-ft?
-
-- Cache feature-less shape plans internally on the face.
+- hb_feature_to/from_string
+- hb_buffer_[sg]et_contents
index 833a621..ff1b0c0 100755 (executable)
@@ -19,9 +19,22 @@ which pkg-config || {
        exit 1
 }
 
+echo -n "checking for libtoolize... "
+which glibtoolize || which libtoolize || {
+       echo "*** No libtoolize (libtool) found, please install it ***"
+       exit 1
+}
+echo -n "checking for gtkdocize... "
+if which gtkdocize ; then
+       gtkdocize --copy || exit 1
+else
+       echo "*** No gtkdocize (gtk-doc) found, skipping documentation ***"
+       echo "EXTRA_DIST = " > gtk-doc.make
+fi
+
 echo -n "checking for autoreconf... "
 which autoreconf || {
-       echo "*** No autoreconf found, please install it ***"
+       echo "*** No autoreconf (autoconf) found, please install it ***"
        exit 1
 }
 
index 2fb058f..895eadf 100644 (file)
@@ -1,17 +1,20 @@
 AC_PREREQ([2.64])
-AC_INIT([harfbuzz],
-        [0.9.0],
+AC_INIT([HarfBuzz],
+        [0.9.40],
         [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz],
         [harfbuzz],
         [http://harfbuzz.org/])
 
-AC_CONFIG_SRCDIR([harfbuzz.pc.in])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
 AC_CONFIG_HEADERS([config.h])
 
-AM_INIT_AUTOMAKE([1.11.1 gnu dist-bzip2 no-dist-gzip -Wall no-define])
+AM_INIT_AUTOMAKE([1.11.1 gnits tar-pax dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
+AM_CONDITIONAL(AUTOMAKE_OLDER_THAN_1_13, test $am__api_version = 1.11 -o $am__api_version = 1.12)
 AM_SILENT_RULES([yes])
 
 # Initialize libtool
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 LT_PREREQ([2.2])
 LT_INIT([disable-static])
 
@@ -19,6 +22,9 @@ LT_INIT([disable-static])
 AC_PROG_CC
 AM_PROG_CC_C_O
 AC_PROG_CXX
+PKG_PROG_PKG_CONFIG([0.20])
+AM_MISSING_PROG([RAGEL], [ragel])
+AM_MISSING_PROG([GIT], [git])
 
 # Version
 m4_define(hb_version_triplet,m4_split(AC_PACKAGE_VERSION,[[.]]))
@@ -49,14 +55,24 @@ m4_define([hb_libtool_current],
 HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age
 AC_SUBST(HB_LIBTOOL_VERSION_INFO)
 
-dnl GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
+# Documentation
+have_gtk_doc=false
+m4_ifdef([GTK_DOC_CHECK], [
+GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
+       if test "x$enable_gtk_doc" = xyes; then
+               have_gtk_doc=true
+       fi
+], [
+       AM_CONDITIONAL([ENABLE_GTK_DOC], false)
+])
 
 # Functions and headers
-AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize sched_yield mmap _setmode isatty)
-AC_CHECK_HEADERS(unistd.h sys/mman.h sched.h io.h)
+AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty)
+AC_CHECK_HEADERS(unistd.h sys/mman.h)
 
 # Compiler flags
 AC_CANONICAL_HOST
+AC_CHECK_ALIGNOF([struct{char;}])
 if test "x$GCC" = "xyes"; then
 
        # Make symbols link locally
@@ -65,14 +81,49 @@ if test "x$GCC" = "xyes"; then
        # Make sure we don't link to libstdc++
        CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
 
+       # Assorted warnings
+       CXXFLAGS="$CXXFLAGS -Wcast-align"
+
+       case "$host" in
+               *-*-mingw*)
+               ;;
+               *)
+                       # Hide inline methods
+                       CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden"
+               ;;
+       esac
+
        case "$host" in
                arm-*-*)
-                       # Request byte alignment on arm
-                       CXXFLAGS="$CXXFLAGS -mstructure-size-boundary=8"
+                       if test "x$ac_cv_alignof_struct_char__" != x1; then
+                               # Request byte alignment
+                               CXXFLAGS="$CXXFLAGS -mstructure-size-boundary=8"
+                       fi
                ;;
        esac
 fi
 
+AM_CONDITIONAL(HAVE_GCC, test "x$GCC" = "xyes")
+
+hb_os_win32=no
+AC_MSG_CHECKING([for native Win32])
+case "$host" in
+  *-*-mingw*)
+    hb_os_win32=yes
+    ;;
+esac
+AC_MSG_RESULT([$hb_os_win32])
+AM_CONDITIONAL(OS_WIN32, test "$hb_os_win32" = "yes")
+
+have_pthread=false
+if test "$hb_os_win32" = no; then
+       AX_PTHREAD([have_pthread=true])
+fi
+if $have_pthread; then
+       AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads])
+fi
+AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread)
+
 dnl ==========================================================================
 
 have_ot=true
@@ -81,21 +132,43 @@ if $have_ot; then
 fi
 AM_CONDITIONAL(HAVE_OT, $have_ot)
 
+have_fallback=true
+if $have_fallback; then
+       AC_DEFINE(HAVE_FALLBACK, 1, [Have simple TrueType Layout backend])
+fi
+AM_CONDITIONAL(HAVE_FALLBACK, $have_fallback)
+
 dnl ===========================================================================
 
-PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, have_glib=true, have_glib=false)
+AC_ARG_WITH(glib,
+       [AS_HELP_STRING([--with-glib=@<:@yes/no/auto@:>@],
+                       [Use glib @<:@default=auto@:>@])],,
+       [with_glib=auto])
+have_glib=false
+if test "x$with_glib" = "xyes" -o "x$with_glib" = "xauto"; then
+       PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, have_glib=true, :)
+fi
+if test "x$with_glib" = "xyes" -a "x$have_glib" != "xtrue"; then
+       AC_MSG_ERROR([glib support requested but glib-2.0 not found])
+fi
 if $have_glib; then
        AC_DEFINE(HAVE_GLIB, 1, [Have glib2 library])
 fi
 AM_CONDITIONAL(HAVE_GLIB, $have_glib)
 
-PKG_CHECK_MODULES(GTHREAD, gthread-2.0, have_gthread=true, have_gthread=false)
-if $have_gthread; then
-       AC_DEFINE(HAVE_GTHREAD, 1, [Have gthread2 library])
-fi
-AM_CONDITIONAL(HAVE_GTHREAD, $have_gthread)
+dnl ===========================================================================
 
-PKG_CHECK_MODULES(GOBJECT, gobject-2.0 glib-2.0 >= 2.16, have_gobject=true, have_gobject=false)
+AC_ARG_WITH(gobject,
+       [AS_HELP_STRING([--with-gobject=@<:@yes/no/auto@:>@],
+                       [Use gobject @<:@default=auto@:>@])],,
+       [with_gobject=no])
+have_gobject=false
+if test "x$with_gobject" = "xyes" -o "x$with_gobject" = "xauto"; then
+       PKG_CHECK_MODULES(GOBJECT, gobject-2.0 glib-2.0, have_gobject=true, :)
+fi
+if test "x$with_gobject" = "xyes" -a "x$have_gobject" != "xtrue"; then
+       AC_MSG_ERROR([gobject support requested but gobject-2.0 / glib-2.0 not found])
+fi
 if $have_gobject; then
        AC_DEFINE(HAVE_GOBJECT, 1, [Have gobject2 library])
        GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
@@ -103,15 +176,58 @@ if $have_gobject; then
 fi
 AM_CONDITIONAL(HAVE_GOBJECT, $have_gobject)
 
+dnl ===========================================================================
+
+
+dnl ===========================================================================
+# Gobject-Introspection
+have_introspection=false
+m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [
+       if $have_gobject; then
+               GOBJECT_INTROSPECTION_CHECK([1.34.0])
+               if test "x$found_introspection" = xyes; then
+                       have_introspection=true
+               fi
+       else
+               AM_CONDITIONAL([HAVE_INTROSPECTION], false)
+       fi
+], [
+       AM_CONDITIONAL([HAVE_INTROSPECTION], false)
+])
+
+dnl ===========================================================================
+
+have_ucdn=true
+if $have_glib; then
+       have_ucdn=false
+fi
+if $have_ucdn; then
+       AC_DEFINE(HAVE_UCDN, 1, [Have UCDN Unicode functions])
+fi
+AM_CONDITIONAL(HAVE_UCDN, $have_ucdn)
+
 dnl ==========================================================================
 
-PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, have_cairo=false)
+AC_ARG_WITH(cairo,
+       [AS_HELP_STRING([--with-cairo=@<:@yes/no/auto@:>@],
+                       [Use cairo @<:@default=auto@:>@])],,
+       [with_cairo=auto])
+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, :)
+fi
+if test "x$with_cairo" = "xyes" -a "x$have_cairo" != "xtrue"; then
+       AC_MSG_ERROR([cairo support requested but not found])
+fi
 if $have_cairo; then
        AC_DEFINE(HAVE_CAIRO, 1, [Have cairo graphics library])
 fi
 AM_CONDITIONAL(HAVE_CAIRO, $have_cairo)
 
-PKG_CHECK_MODULES(CAIRO_FT, cairo-ft, have_cairo_ft=true, have_cairo_ft=false)
+have_cairo_ft=false
+if $have_cairo; then
+       PKG_CHECK_MODULES(CAIRO_FT, cairo-ft, have_cairo_ft=true, :)
+fi
 if $have_cairo_ft; then
        AC_DEFINE(HAVE_CAIRO_FT, 1, [Have cairo-ft support in cairo graphics library])
 fi
@@ -119,73 +235,147 @@ AM_CONDITIONAL(HAVE_CAIRO_FT, $have_cairo_ft)
 
 dnl ==========================================================================
 
-PKG_CHECK_MODULES(ICU, icu, have_icu=true, [
-       have_icu=true
-       AC_CHECK_HEADERS(unicode/uchar.h,, have_icu=false)
-       AC_MSG_CHECKING([for libicuuc])
-       LIBS_old=$LIBS
-       LIBS="$LIBS -licuuc"
-       AC_TRY_LINK([#include <unicode/uchar.h>],
-                   [u_getIntPropertyValue (0, (UProperty)0);],
-                   AC_MSG_RESULT(yes),
-                   AC_MSG_RESULT(no);have_icu=false)
-       LIBS=$LIBS_old
-       if $have_icu; then
-               ICU_CFLAGS=-D_REENTRANT
-               ICU_LIBS="-licuuc"
-               AC_SUBST(ICU_CFLAGS)
-               AC_SUBST(ICU_LIBS)
+AC_ARG_WITH(icu,
+       [AS_HELP_STRING([--with-icu=@<:@yes/no/auto@:>@],
+                       [Use ICU @<:@default=auto@:>@])],,
+       [with_icu=auto])
+have_icu=false
+if test "x$with_icu" = "xyes" -o "x$with_icu" = "xauto"; then
+       PKG_CHECK_MODULES(ICU, icu-uc, have_icu=true, :)
+
+       dnl Fallback to icu-config if ICU pkg-config files could not be found
+       if test "$have_icu" != "true"; then
+               AC_CHECK_TOOL(ICU_CONFIG, icu-config, no)
+               AC_MSG_CHECKING([for ICU by using icu-config fallback])
+               if test "$ICU_CONFIG" != "no" && "$ICU_CONFIG" --version >/dev/null; then
+                       have_icu=true
+                       # We don't use --cflags as this gives us a lot of things that we don't
+                       # necessarily want, like debugging and optimization flags
+                       # See man (1) icu-config for more info.
+                       ICU_CFLAGS=`$ICU_CONFIG --cppflags`
+                       ICU_LIBS=`$ICU_CONFIG --ldflags-searchpath --ldflags-libsonly`
+                       AC_SUBST(ICU_CFLAGS)
+                       AC_SUBST(ICU_LIBS)
+                       AC_MSG_RESULT([yes])
+               else
+                       AC_MSG_RESULT([no])
+               fi
        fi
-])
+fi
+if test "x$with_icu" = "xyes" -a "x$have_icu" != "xtrue"; then
+       AC_MSG_ERROR([icu support requested but icu-uc not found])
+fi
 if $have_icu; then
+       CXXFLAGS="$CXXFLAGS `$PKG_CONFIG --variable=CXXFLAGS icu-uc`"
        AC_DEFINE(HAVE_ICU, 1, [Have ICU library])
 fi
 AM_CONDITIONAL(HAVE_ICU, $have_icu)
 
 dnl ==========================================================================
 
-PKG_CHECK_MODULES(GRAPHITE2, graphite2, have_graphite=true, have_graphite=false)
-if $have_graphite; then
-    AC_DEFINE(HAVE_GRAPHITE2, 1, [Have Graphite library])
+AC_ARG_WITH(graphite2,
+       [AS_HELP_STRING([--with-graphite2=@<:@yes/no/auto@:>@],
+                       [Use the graphite2 library @<:@default=no@:>@])],,
+       [with_graphite2=no])
+have_graphite2=false
+if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then
+       PKG_CHECK_MODULES(GRAPHITE2, graphite2, have_graphite2=true, :)
+fi
+if test "x$with_graphite2" = "xyes" -a "x$have_graphite2" != "xtrue"; then
+       AC_MSG_ERROR([graphite2 support requested but libgraphite2 not found])
 fi
-AM_CONDITIONAL(HAVE_GRAPHITE2, $have_graphite)
+if $have_graphite2; then
+       AC_DEFINE(HAVE_GRAPHITE2, 1, [Have Graphite2 library])
+fi
+AM_CONDITIONAL(HAVE_GRAPHITE2, $have_graphite2)
 
 dnl ==========================================================================
 
-PKG_CHECK_MODULES(FREETYPE, freetype2 >= 2.3.8, have_freetype=true, have_freetype=false)
+AC_ARG_WITH(freetype,
+       [AS_HELP_STRING([--with-freetype=@<:@yes/no/auto@:>@],
+                       [Use the FreeType library @<:@default=auto@:>@])],,
+       [with_freetype=auto])
+have_freetype=false
+if test "x$with_freetype" = "xyes" -o "x$with_freetype" = "xauto"; then
+       PKG_CHECK_MODULES(FREETYPE, freetype2 >= 2.4.2, have_freetype=true, :)
+fi
+if test "x$with_freetype" = "xyes" -a "x$have_freetype" != "xtrue"; then
+       AC_MSG_ERROR([FreeType support requested but libfreetype2 not found])
+fi
 if $have_freetype; then
        AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
-       _save_libs="$LIBS"
-       _save_cflags="$CFLAGS"
-       LIBS="$LIBS $FREETYPE_LIBS"
-       CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
-       AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
-       LIBS="$_save_libs"
-       CFLAGS="$_save_cflags"
 fi
 AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
 
 dnl ===========================================================================
 
-AC_CHECK_HEADERS(usp10.h windows.h, have_uniscribe=true, have_uniscribe=false)
+AC_ARG_WITH(uniscribe,
+       [AS_HELP_STRING([--with-uniscribe=@<:@yes/no/auto@:>@],
+                       [Use the Uniscribe library @<:@default=no@:>@])],,
+       [with_uniscribe=no])
+have_uniscribe=false
+if test "x$with_uniscribe" = "xyes" -o "x$with_uniscribe" = "xauto"; then
+       AC_CHECK_HEADERS(usp10.h windows.h, have_uniscribe=true)
+fi
+if test "x$with_uniscribe" = "xyes" -a "x$have_uniscribe" != "xtrue"; then
+       AC_MSG_ERROR([uniscribe support requested but not found])
+fi
 if $have_uniscribe; then
        UNISCRIBE_CFLAGS=
-       UNISCRIBE_LIBS="-lusp10 -lgdi32"
+       UNISCRIBE_LIBS="-lusp10 -lgdi32 -lrpcrt4"
        AC_SUBST(UNISCRIBE_CFLAGS)
        AC_SUBST(UNISCRIBE_LIBS)
-       AC_DEFINE(HAVE_UNISCRIBE, 1, [Have Uniscribe backend])
+       AC_DEFINE(HAVE_UNISCRIBE, 1, [Have Uniscribe library])
 fi
 AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe)
 
 dnl ===========================================================================
 
+AC_ARG_WITH(coretext,
+       [AS_HELP_STRING([--with-coretext=@<:@yes/no/auto@:>@],
+                       [Use CoreText @<:@default=no@:>@])],,
+       [with_coretext=no])
+have_coretext=false
+if test "x$with_coretext" = "xyes" -o "x$with_coretext" = "xauto"; then
+       AC_CHECK_TYPE(CTFontRef, have_coretext=true,, [#include <ApplicationServices/ApplicationServices.h>])
+
+       if $have_coretext; then
+               CORETEXT_CFLAGS=
+               CORETEXT_LIBS="-framework ApplicationServices"
+               AC_SUBST(CORETEXT_CFLAGS)
+               AC_SUBST(CORETEXT_LIBS)
+       else
+               # On iOS CoreText and CoreGraphics are stand-alone frameworks
+               if test "x$have_coretext" != "xtrue"; then
+                       AC_CHECK_TYPE(CTFontRef, have_coretext=true,, [#include <CoreText/CoreText.h>])
+               fi
+
+               if $have_coretext; then
+                       CORETEXT_CFLAGS=
+                       CORETEXT_LIBS="-framework CoreText -framework CoreGraphics"
+                       AC_SUBST(CORETEXT_CFLAGS)
+                       AC_SUBST(CORETEXT_LIBS)
+               fi
+       fi
+fi
+if test "x$with_coretext" = "xyes" -a "x$have_coretext" != "xtrue"; then
+       AC_MSG_ERROR([CoreText support requested but libcoretext not found])
+fi
+if $have_coretext; then
+       AC_DEFINE(HAVE_CORETEXT, 1, [Have Core Text backend])
+fi
+AM_CONDITIONAL(HAVE_CORETEXT, $have_coretext)
+
+dnl ===========================================================================
+
 AC_CACHE_CHECK([for Intel atomic primitives], hb_cv_have_intel_atomic_primitives, [
        hb_cv_have_intel_atomic_primitives=false
-       AC_TRY_LINK([], [
+       AC_TRY_LINK([
                void memory_barrier (void) { __sync_synchronize (); }
-               int atomic_add (int i) { return __sync_fetch_and_add (&i, 1); }
-               int atomic_cmpxchg (int *i, int *j, int *k) { return __sync_bool_compare_and_swap (&i, j, k); }
-               ], hb_cv_have_intel_atomic_primitives=true
+               int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
+               int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
+               void mutex_unlock (int *m) { __sync_lock_release (m); }
+               ], [], hb_cv_have_intel_atomic_primitives=true
        )
 ])
 if $hb_cv_have_intel_atomic_primitives; then
@@ -194,15 +384,69 @@ fi
 
 dnl ===========================================================================
 
+AC_CACHE_CHECK([for Solaris atomic operations], hb_cv_have_solaris_atomic_ops, [
+       hb_cv_have_solaris_atomic_ops=false
+       AC_TRY_LINK([
+               #include <atomic.h>
+               /* This requires Solaris Studio 12.2 or newer: */
+               #include <mbarrier.h>
+               void memory_barrier (void) { __machine_rw_barrier (); }
+               int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
+               void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
+               ], [], hb_cv_have_solaris_atomic_ops=true
+       )
+])
+if $hb_cv_have_solaris_atomic_ops; then
+       AC_DEFINE(HAVE_SOLARIS_ATOMIC_OPS, 1, [Have Solaris __machine_*_barrier and atomic_* operations])
+fi
+
+if test "$os_win32" = no && ! $have_pthread; then
+       AC_CHECK_HEADERS(sched.h)
+       AC_SEARCH_LIBS(sched_yield,rt,AC_DEFINE(HAVE_SCHED_YIELD, 1, [Have sched_yield]))
+fi
+
+dnl ===========================================================================
+
 AC_CONFIG_FILES([
 Makefile
-harfbuzz.pc
 src/Makefile
 src/hb-version.h
+src/hb-ucdn/Makefile
 util/Makefile
 test/Makefile
 test/api/Makefile
 test/shaping/Makefile
+docs/Makefile
+docs/reference/Makefile
+docs/reference/version.xml
 ])
 
 AC_OUTPUT
+
+AC_MSG_NOTICE([
+
+Build configuration:
+
+Unicode callbacks (you want at least one):
+       Glib:                   ${have_glib}
+       ICU:                    ${have_icu}
+       UCDN:                   ${have_ucdn}
+
+Font callbacks (the more the better):
+       FreeType:               ${have_freetype}
+
+Tools used for command-line utilities:
+       Cairo:                  ${have_cairo}
+
+Additional shapers (the more the better):
+       Graphite2:              ${have_graphite2}
+
+Platform shapers (not normally needed):
+       CoreText:               ${have_coretext}
+       Uniscribe:              ${have_uniscribe}
+
+Other features:
+       Documentation:          ${have_gtk_doc}
+       GObject bindings:       ${have_gobject}
+       Introspection:          ${have_introspection}
+])
diff --git a/contrib/python/README b/contrib/python/README
deleted file mode 100644 (file)
index 72a3527..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-This contains a wrapping of harfbuzz into python. The module is dependent on pyrex. To build, type:
-
-python setup.py build
-
-In addition there is a test application, hbtestfont. It has GTK based gui output and for this, python modules for gtk, gobject and cairo are needed. The application may be run without gui output using the --nogui option.
-
-Applications may be executed in the build context, without needing to install any modules or libraries, using the runpy script from the contrib/python directory. Thus one might type:
-
-./runpy script/hbtestfont -f "Charis SIL" 0048 0069 0303
-
diff --git a/contrib/python/lib/fontconfig.pyx b/contrib/python/lib/fontconfig.pyx
deleted file mode 100644 (file)
index 16e0289..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-cdef extern from "fontconfig/fontconfig.h" :
-    ctypedef struct FcPattern :
-        pass
-    ctypedef struct FcConfig :
-        pass
-    cdef enum FcResult '_FcResult' :
-        FcResultMatch = 0, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId,
-        FcResultOutOfMemory
-
-    ctypedef char FcChar8
-    FcPattern *FcNameParse(FcChar8 *name)
-    FcPattern *FcFontMatch(FcConfig *config, FcPattern *match, FcResult *res)
-    FcResult FcPatternGetInteger(FcPattern *pattern, char *typeid, int index, int *res)
-    FcResult FcPatternGetString(FcPattern *pattern, char *typeid, int index, FcChar8 **res)
-    void FcPatternPrint(FcPattern *pattern)
-    void FcPatternDestroy(FcPattern *pattern)
-
-    FcConfig *FcConfigGetCurrent()
-
-cdef class fcPattern :
-    cdef FcPattern *_pattern
-
-    def __init__(self, char *name) :
-        cdef FcPattern *temp
-        cdef FcResult res
-
-        temp = FcNameParse(<FcChar8 *>name)
-        self._pattern = FcFontMatch(FcConfigGetCurrent(), temp, &res)
-        if res != FcResultMatch :
-            print "Failed to match" + str(res)
-            self._pattern = <FcPattern *>0
-
-    def __destroy__(self) :
-        FcPatternDestroy(self._pattern)
-
-    def getInteger(self, char *typeid, int index) :
-        cdef int res
-        if self._pattern == <FcPattern *>0 or FcPatternGetInteger(self._pattern, typeid, index, &res) != FcResultMatch : return None
-        return res
-
-    def getString(self, char *typeid, int index) :
-        cdef FcChar8 *res
-        if self._pattern == <FcPattern *>0 or FcPatternGetString(self._pattern, typeid, index, &res) != FcResultMatch : return None
-        return <char *>res
-
-    def debugPrint(self) :
-        FcPatternPrint(self._pattern)
diff --git a/contrib/python/lib/harfbuzz.pyx b/contrib/python/lib/harfbuzz.pyx
deleted file mode 100644 (file)
index f483fd6..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-cdef extern from "stdlib.h":
-    ctypedef int size_t
-    void *malloc(size_t size)
-    void free(void* ptr)
-
-cdef extern from "ft2build.h" :
-    pass
-
-cdef extern from "freetype/freetype.h" :
-    ctypedef void *FT_Library
-    ctypedef void *FT_Face
-    ctypedef int FT_Error
-
-    FT_Error FT_Init_FreeType (FT_Library *alib)
-    FT_Error FT_Done_FreeType (FT_Library alib)
-    FT_Error FT_Done_Face (FT_Face alib)
-    FT_Error FT_New_Face( FT_Library library, char *path, unsigned long index, FT_Face *aface)
-    FT_Error FT_Set_Char_Size (FT_Face aFace, unsigned int size_x, unsigned int size_y, unsigned int res_x, unsigned int res_y)
-
-cdef extern from "hb-common.h" :
-    cdef enum hb_direction_t :
-        HB_DIRECTION_LTR
-        HB_DIRECTION_RTL
-        HB_DIRECTION_TTB
-        HB_DIRECTION_BTT
-    ctypedef unsigned long hb_codepoint_t
-    ctypedef long hb_position_t
-    ctypedef unsigned long hb_mask_t
-    ctypedef unsigned long hb_tag_t
-    hb_tag_t hb_tag_from_string (char *s)
-    ctypedef void (*hb_destroy_func_t) (void *user_data)
-
-cdef extern from "hb-unicode.h" :
-# there must be a better way of syncing this list with the true source
-    ctypedef enum hb_script_t :
-        HB_SCRIPT_COMMON = 0
-
-cdef extern from "hb-language.h" :
-    ctypedef void *hb_language_t
-    hb_language_t hb_language_from_string(char *str)
-    char * hb_language_to_string(hb_language_t language)
-
-cdef extern from "hb-ot-tag.h" :
-    hb_script_t hb_ot_tag_to_script (hb_tag_t tag)
-
-cdef extern from "hb-buffer.h" :
-    ctypedef struct hb_buffer_t :
-        pass
-
-    ctypedef struct hb_glyph_info_t :
-        hb_codepoint_t codepoint
-        hb_mask_t mask
-        unsigned long cluster
-
-    ctypedef union hb_var_int_t:
-        unsigned long u32
-
-    ctypedef struct hb_glyph_position_t :
-        hb_position_t x_advance
-        hb_position_t y_advance
-        hb_position_t x_offset
-        hb_position_t y_offset
-        hb_var_int_t  var
-
-    hb_buffer_t *hb_buffer_create(unsigned int size)
-    hb_buffer_t *hb_buffer_reference(hb_buffer_t *buffer)
-    unsigned int hb_buffer_get_reference_count(hb_buffer_t *buffer)
-    void hb_buffer_destroy(hb_buffer_t *buffer)
-    void hb_buffer_set_direction(hb_buffer_t *buffer, hb_direction_t direction)
-    hb_direction_t hb_buffer_get_direction(hb_buffer_t *buffer)
-    void hb_buffer_set_script(hb_buffer_t *buffer, hb_script_t script)
-    hb_script_t hb_buffer_get_script(hb_buffer_t *buffer)
-    void hb_buffer_set_language(hb_buffer_t *buffer, hb_language_t language)
-    hb_language_t hb_buffer_get_language(hb_buffer_t *buffer)
-    void hb_buffer_clear(hb_buffer_t *)
-    void hb_buffer_clear_positions(hb_buffer_t *buffer)
-    void hb_buffer_ensure(hb_buffer_t *buffer, unsigned int size)
-    void hb_buffer_reverse(hb_buffer_t *buffer)
-    void hb_buffer_reverse_clusters(hb_buffer_t *buffer)
-    void hb_buffer_add_glyph(hb_buffer_t *buffer, hb_codepoint_t codepoint, hb_mask_t mask, unsigned int cluster)
-    void hb_buffer_add_utf8(hb_buffer_t *buffer, char *text, unsigned int text_length, unsigned int item_offset, unsigned int item_length)
-    unsigned int hb_buffer_get_length(hb_buffer_t *buffer)
-    hb_glyph_info_t *hb_buffer_get_glyph_infos(hb_buffer_t *buffer)
-    hb_glyph_position_t *hb_buffer_get_glyph_positions(hb_buffer_t *buffer)
-
-cdef extern from "hb-blob.h" :
-    cdef struct hb_blob_t :
-        pass
-# do I need blob functions here?
-
-cdef extern from "hb-font.h" :
-    ctypedef struct hb_face_t :
-        pass
-    ctypedef struct hb_font_t :
-        pass
-
-    ctypedef hb_blob_t * (*hb_get_table_func_t) (hb_tag_t tag, void *user_data)
-    hb_face_t * hb_face_create_for_data(hb_blob_t *blob, unsigned int index)
-    hb_face_t * hb_face_create_for_tables(hb_get_table_func_t get_table, hb_destroy_func_t destroy, void *user_data)
-    hb_face_t * hb_face_reference(hb_face_t *face)
-    unsigned int hb_face_get_reference_count(hb_face_t *face)
-    void hb_face_destroy(hb_face_t *face)
-    void hb_font_destroy(hb_font_t *font)
-    hb_blob_t * hb_face_get_table(hb_face_t *face, hb_tag_t tag)
-
-
-cdef extern from "hb-shape.h" :
-    ctypedef struct hb_feature_t :
-        int tag
-        unsigned int value
-        unsigned int start
-        unsigned int end
-
-    void hb_shape (hb_font_t *font, hb_face_t *face, hb_buffer_t *buffer, hb_feature_t *features, unsigned int num_features)
-
-cdef extern from "hb-ft.h" :
-    hb_face_t *hb_ft_face_create (FT_Face ft_face, hb_destroy_func_t destroy)
-    hb_font_t *hb_ft_font_create (FT_Face ft_face, hb_destroy_func_t destroy)
-
-class glyphinfo :
-    def __init__(self, gid, cluster, advance, offset, internal = 0) :
-        self.gid = gid
-        self.cluster = cluster
-        self.advance = advance
-        self.offset = offset
-        self.internal = internal
-
-    def __repr__(self) :
-        res = "{0:d}>{1:d}@({2:.2f},{3:.2f})+({4:.2f},{5:.2f})".format(self.gid, self.cluster, self.offset[0], self.offset[1], self.advance[0], self.advance[1])
-        if self.internal : res += "/i=" + str(self.internal)
-        return res
-
-cdef class buffer :
-    cdef hb_buffer_t *buffer
-
-    def __init__(self, char *text, unsigned int length) :
-        """Note text must be a utf-8 string and length is number of chars"""
-        self.buffer = hb_buffer_create(length)
-        hb_buffer_add_utf8(self.buffer, text, length, 0, len(text))
-
-    def set_scriptlang(self, char *script, char *lang) :
-        cdef hb_language_t language
-        cdef hb_script_t scriptnum
-
-        language = hb_language_from_string(lang)
-        scriptnum = hb_ot_tag_to_script(hb_tag_from_string(script))
-        hb_buffer_set_script(self.buffer, scriptnum)
-        hb_buffer_set_language(self.buffer, language)
-
-    def get_info(self, scale = 1) :
-        cdef hb_glyph_info_t *infos
-        cdef hb_glyph_position_t *positions
-        cdef unsigned int num
-        cdef unsigned int i
-        res = []
-
-        num = hb_buffer_get_length(self.buffer)
-        infos = hb_buffer_get_glyph_infos(self.buffer)
-        positions = hb_buffer_get_glyph_positions(self.buffer)
-        for 0 <= i < num :
-            temp = glyphinfo(infos[i].codepoint, infos[i].cluster, (positions[i].x_advance / scale, positions[i].y_advance / scale), (positions[i].x_offset / scale, positions[i].y_offset / scale), positions[i].var.u32)
-            res.append(temp)
-        return res
-
-    def get_settings(self) :
-        cdef hb_script_t script
-        cdef hb_language_t lang
-
-        script = hb_buffer_get_script(self.buffer)
-        lang = hb_buffer_get_language(self.buffer)
-        return {'script' : script, 'language' : hb_language_to_string(lang)}
-
-    def __del__(self) :
-        hb_buffer_destroy(self.buffer)
-
-cdef class ft :
-    cdef FT_Library engine
-    cdef FT_Face face
-    cdef hb_face_t *hbface
-    cdef hb_font_t *hbfont
-
-    def __init__(self, char *fname, size) :
-        cdef FT_Library engine
-        FT_Init_FreeType(&engine)
-        self.engine = engine
-        cdef FT_Face face
-        FT_New_Face(engine, fname, 0, &face)
-        FT_Set_Char_Size(face, size << 6, size << 6, 72, 72)
-        self.face = face
-        self.hbface = hb_ft_face_create(face, <void (*)(void *)>hb_face_destroy)
-        self.hbfont = hb_ft_font_create(face, <void (*)(void *)>hb_font_destroy)
-
-    def __del__(self) :
-        cdef FT_Library engine
-        engine = self.engine
-        cdef FT_Face face
-        face = self.face
-        FT_Done_Face(face)
-        FT_Done_FreeType(engine)
-
-    def shape(self, buffer aBuffer, features = {}) :
-        cdef hb_feature_t *feats
-        cdef hb_feature_t *aFeat
-        feats = <hb_feature_t *>malloc(sizeof(hb_feature_t) * len(features))
-        aFeat = feats
-        for k,v in features.items() :
-            aFeat.tag = hb_tag_from_string (k)
-            aFeat.value = int(v)
-            aFeat.start = 0
-            aFeat.end = -1
-            aFeat += 1
-        hb_shape(self.hbfont, self.hbface, aBuffer.buffer, feats, len(features))
-
-
diff --git a/contrib/python/runpy b/contrib/python/runpy
deleted file mode 100755 (executable)
index b39db1b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-LD_LIBRARY_PATH=../../src/.libs PYTHONPATH=build/lib.`python -c 'import distutils.util, sys; print distutils.util.get_platform()+"-"+str(sys.version_info[0])+"."+str(sys.version_info[1])'` "$@"
diff --git a/contrib/python/scripts/hbtestfont b/contrib/python/scripts/hbtestfont
deleted file mode 100755 (executable)
index 7736ae6..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/usr/bin/python
-
-import harfbuzz, optparse, sys
-from fontconfig import fcPattern
-
-usage = '''usage: %prog [options] codepoints
-    Generates output of glyphs and positions. Each entry is of the form:
-        glyphid>cluster@(offsetx,offsety)+(advancex,advancey)
-
-    codepoints is a space separated list of hex values of Unicode codepoints'''
-p = optparse.OptionParser(usage=usage)
-p.add_option('-s', '--size', default=32, type="int", help="point size")
-p.add_option('-l', '--lang', help="language code")
-p.add_option('-c', '--script', help="script code")
-p.add_option('-F', '--feature', action='append', help="define a feature key=val")
-p.add_option('-f', '--font', help='Font to use to render glyphs. My be a font file', default="verdana")
-p.add_option('-b', '--bold', help='Choose bold fonts', action='store_true')
-p.add_option('-i', '--italic', help='Choose italic fonts', action='store_true')
-p.add_option('-d', '--debug', action='store_true', help="Output trace info")
-p.add_option('--nogui', action='store_true', help="Don't display a gui")
-(opts, args) = p.parse_args()
-
-if opts.font.lower().endswith(".ttf") :
-    fpat = ":file="
-else :
-    fpat = ""
-fpat += opts.font + ":weight="
-fpat += "bold" if opts.bold else "medium"
-fpat += ":slant="
-fpat += "italic" if opts.italic else "roman"
-pat = fcPattern(fpat)
-fname = pat.getString("file", 0)
-family = pat.getString("family", 0)
-print "Processing: " + fname
-if opts.font.lower().endswith(".ttf") and opts.font != fname :
-    print "Failed to find font in fontconfig. Exiting"
-    sys.exit(1)
-
-ft = harfbuzz.ft(fname, opts.size)
-text = "".join(unichr(int(c, 16)) for c in args)
-bytes = text.encode('utf_8')
-buffer = harfbuzz.buffer(bytes, len(text))
-if (opts.lang or opts.script) : buffer.set_scriptlang(opts.script if opts.script else "", opts.lang if opts.lang else "")
-features = {}
-if opts.feature :
-    for f in opts.feature :
-        k, v = f.split("=")
-        features[k] = v
-ft.shape(buffer, features = features)
-res = buffer.get_info(64)       # scale for 26.6
-print res
-
-if not opts.nogui :
-    try:
-        import gtk
-        import gobject
-        import cairo
-        from gtk import gdk
-    except :
-        raise SystemExit
-    import pygtk
-
-    if gtk.pygtk_version < (2, 8) :
-        print "PyGtk 2.8 or later required"
-        raise SystemExit
-
-    class GlyphsWindow (gtk.Widget) :
-        def __init__(self, fontname, bold, italic, size, glyphs) :
-            gtk.Widget.__init__(self)
-            self.fontname = fontname
-            self.size = size
-            self.glyphs = glyphs
-            self.bold = bold
-            self.italic = italic
-
-        def do_realize(self) :
-            self.set_flags(gtk.REALIZED)
-            self.window = gdk.Window(
-                    self.get_parent_window(),
-                    width = self.allocation.width,
-                    height = self.allocation.height,
-                    window_type = gdk.WINDOW_CHILD,
-                    wclass = gdk.INPUT_OUTPUT,
-                    event_mask = self.get_events() | gdk.EXPOSURE_MASK)
-            self.window.set_user_data(self)
-            self.style.attach(self.window)
-            self.style.set_background(self.window, gtk.STATE_NORMAL)
-            self.window.move_resize(*self.allocation)
-            
-        def do_unrealize(self) :
-            self.window.destroy()
-
-        def do_expose_event(self, event) :
-            cr = self.window.cairo_create()
-            cr.set_matrix(cairo.Matrix(1, 0, 0, 1, 0, 1.5 * self.size))
-            cr.set_font_face(cairo.ToyFontFace(self.fontname, cairo.FONT_SLANT_ITALIC if self.italic else cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD if self.bold else cairo.FONT_WEIGHT_NORMAL))
-            cr.set_font_size(self.size)
-            cr.show_glyphs(self.glyphs)      # [(gid, originx, originy)]
-
-    glyphs = []
-    org = [0, 0]
-    for g in res :
-        glyphs.append((g.gid, org[0] + g.offset[0], org[1] + g.offset[1]))
-        org[0] += g.advance[0]
-        org[1] += g.advance[1]
-
-    gobject.type_register(GlyphsWindow)
-    win = gtk.Window()
-    win.resize(org[0] + 10, 2 * opts.size + 40)
-    win.connect('delete-event', gtk.main_quit)
-    frame = gtk.Frame("glyphs")
-    win.add(frame)
-    w = GlyphsWindow(family, opts.bold, opts.italic, opts.size, glyphs)
-    frame.add(w)
-    win.show_all()
-    gtk.main()
diff --git a/contrib/python/setup.py b/contrib/python/setup.py
deleted file mode 100755 (executable)
index f592728..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/python
-
-from distutils.core import setup
-from glob import glob
-from Pyrex.Distutils.extension import Extension
-from Pyrex.Distutils import build_ext
-
-setup(name='harfbuzz',
-    version='0.0.1',
-    description='Harfbuzz compatibility layer',
-    long_description='Harfbuzz python integration modules and supporting scripts',
-    maintainer='Martin Hosken',
-    maintainer_email='martin_hosken@sil.org',
-    packages=['harfbuzz'],
-    ext_modules = [
-        Extension("harfbuzz", ["lib/harfbuzz.pyx"], libraries=["harfbuzz"], library_dirs=["../../src/.libs"], include_dirs=["/usr/include/freetype2", "../../src"]),
-        Extension("fontconfig", ["lib/fontconfig.pyx"], libraries=["fontconfig"])
-        ],
-    cmdclass = {'build_ext' : build_ext},
-    scripts = glob('scripts/*'),
-    license = 'LGPL',
-    platforms = ['Linux', 'Win32', 'Mac OS X'],
-    package_dir = {'harfbuzz' : 'lib'}
-)
-
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100755 (executable)
index f60ddf7..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-harfbuzz (0.9.0-1slp2+1) unstable; urgency=low
-
-  * Upgrade to latest harfbuzz
-  * Git: 165.213.180.234:slp/pkgs/h/harfbuzz
-  * Tag: harfbuzz_0.9.1-1slp2+1
-
- -- Ankush Dua <ankush.d@samsung.com>  Wed, 27 June 2012 15:00:08 +0900
-
-harfbuzz (0.7.0-1slp2+1) unstable; urgency=low
-
-  * Upgrade to latest harfbuzz
-
- -- Mike McCormack <mj.mccormack@samsung.com>  Wed, 03 Aug 2011 17:42:58 +0900
-
-harfbuzz (0.4.1-1slp2+2) unstable; urgency=low
-
-  * Move headers to dev package
-  * use CMake to build
-
- -- Mike McCormack <mj.mccormack@samsung.com>  Thu, 21 Apr 2011 19:10:30 +0900
-
-harfbuzz (0.4.1-1slp2+1) unstable; urgency=low
-
-  * Fixed an issue with uninitialized values
-  * Fixed an issue with log clusters not updated correctly.
-  * Git: 165.213.180.234:slp/pkgs/h/harfbuzz
-  * Tag: harfbuzz_0.4.1-1slp2+1
-
- -- Tom Hacohen <tom.hacohen@partner.samsung.com>  Tue, 18 Jan 2011 16:00:38 +0900
-
-harfbuzz (0.4.0-1slp2+13) unstable; urgency=low
-
-  * Fixed version number in the .pc file
-  * Git: 165.213.180.234:slp/pkgs/h/harfbuzz
-  * Tag: harfbuzz_0.4.0-1slp2+13
-
- -- Tom Hacohen <tom.hacohen@partner.samsung.com>  Tue, 04 Jan 2011 16:45:04 +0200
-
-harfbuzz (0.4.0-1slp2+12) unstable; urgency=low
-
-  * Modify git repository path
-  * Git: 165.213.180.234:slp/pkgs/h/harfbuzz
-  * Tag: harfbuzz_0.4.0-1slp2+12
-
- -- Jihoon Kim <jihoon48.kim@samsung.com>  Mon, 20 Dec 2010 13:45:30 +0900
-
-harfbuzz (0.4.0-1slp2+11) unstable; urgency=low
-
-  * Change FPIC to fPIC
-  * Git: 165.213.180.234:/git/slp/pkgs/harfbuzz
-  * Tag: harfbuzz_0.4.0-1slp2+11
-
- -- Jihoon Kim <jihoon48.kim@samsung.com>  Mon, 20 Dec 2010 13:39:26 +0900
-
-harfbuzz (0.4.0-1slp2+10) unstable; urgency=low
-
-  * Add git tag
-  * Git: 165.213.180.234:/git/slp/pkgs/harfbuzz
-  * Tag: harfbuzz_0.4.0-1slp2+10
-
- -- Jihoon Kim <jihoon48.kim@samsung.com>  Wed, 10 Nov 2010 11:30:49 +0900
-
-harfbuzz (0.4.0-1slp2+8) unstable; urgency=low
-
-  * Added maintainer according to policy
-
- -- prameet.k <prameet.k@partner.samsung.com>  Fri, 21 May 2010 10:00:53 +0900
-
-harfbuzz (0.4.0-1slp2+7) unstable; urgency=low
-
-  * Change maintainer according to the policy
-
- -- Jihoon Kim <jihoon48.kim@samsung.com>  Wed, 21 Apr 2010 10:00:53 +0900
-
-harfbuzz (0.4.0-1slp2+6) unstable; urgency=high
-
-  * Modified the control file
-
- -- Janani <janani.k@samsung.com>  Thu, 08 Apr 2010 15:14:53 +0530
-
-harfbuzz (0.4.0-1slp2+5) unstable; urgency=low
-
-  * Removed DOS style line endings 
-
- -- Janani <janani.k@samsung.com>  Thu, 08 Apr 2010 10:53:45 +0530
-
-harfbuzz (0.4.0-1slp2+4) unstable; urgency=low
-
-  * Minor changes 
-
- -- Janani <janani.k@samsung.com>  Tue, 06 Apr 2010 13:14:09 +0530
-
-harfbuzz (0.4.0-1slp2+3) unstable; urgency=low
-
-  * Modified makefile and install file
-
- -- Janani <janani.k@samsung.com>  Tue, 06 Apr 2010 13:11:30 +0530
-
-harfbuzz (0.4.0-1slp2+2) unstable; urgency=low
-
-  * Package name changed 
-
- -- Janani <janani.k@samsung.com>  Fri, 26 Mar 2010 14:18:04 +0530
-
-harfbuzz (0.4.0-1slp2+1) unstable; urgency=low
-
-  * Repackaging
-
- -- Janani <janani.k@samsung.com>  Fri, 26 Mar 2010 10:14:37 +0530
-
-harfbuzz (0.3) unstable; urgency=low
-
-  * Email ID corrected
-
- -- Janani <janani.k@samsung.com>  Wed, 17 Mar 2010 16:00:07 +0530
-
-harfbuzz (0.2) unstable; urgency=low
-
-  * Owner Changed
-
- -- Janani <janani.k@samsung.com>  Mon, 15 Mar 2010 16:57:26 +0530
-
-harfbuzz (0.1) unstable; urgency=low
-
-  * Initial Release.
-
- -- Janani <janani.k@samsung.com>  Fri, 05 Mar 2010 10:49:10 +0530
diff --git a/debian/compat b/debian/compat
deleted file mode 100755 (executable)
index 7ed6ff8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-5
diff --git a/debian/control b/debian/control
deleted file mode 100755 (executable)
index 065539e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-Source: harfbuzz
-Section: libs
-Priority: optional
-Maintainer: janani <janani.k@samsung.com>, Ankush Dua <ankush.d@samsung.com>
-Build-Depends: debhelper (>= 5),libfreetype6-dev, pkg-config, ragel
-Standards-Version: 3.7.2
-
-Package: libharfbuzz
-Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}
-Description: Hindi Reshaping Library 
-
-
-Package: libharfbuzz-dev
-Architecture: any
-Section: libdevel
-Depends: ${misc:Depends}, libharfbuzz (= ${binary:Version})
-Description: Hindi reshaping library (unstripped)
-
-Package: libharfbuzz-dbg
-Section: debug
-Architecture: any
-Depends: ${misc:Depends}, libharfbuzz (= ${Source-Version})
-Description: Hindi reshaping library (unstripped)
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100755 (executable)
index 634932c..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-This is harfbuzz library ,maintained by prameet <prameet.k@partner.samsung.com>
-on Fri, 05 Mar 2010 10:49:10 +0530.
-
-The original source can always be found at:
-       ftp://ftp.debian.org/dists/unstable/main/source/
-
-Copyright Holder:  unknown
-
-License:
-
-  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 package; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
-
-On Debian systems, the complete text of the GNU General
-Public License can be found in `/usr/share/common-licenses/GPL'.
diff --git a/debian/dirs b/debian/dirs
deleted file mode 100755 (executable)
index ca882bb..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-usr/bin
-usr/sbin
diff --git a/debian/libharfbuzz-dev.install b/debian/libharfbuzz-dev.install
deleted file mode 100644 (file)
index 3e46237..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-debian/tmp/usr/include/*
-debian/tmp/usr/lib/lib*.so
-debian/tmp/usr/lib/pkgconfig/*.pc
diff --git a/debian/libharfbuzz.install b/debian/libharfbuzz.install
deleted file mode 100755 (executable)
index 0177db1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-debian/tmp/usr/lib/libharfbuzz.so.*
diff --git a/debian/rules b/debian/rules
deleted file mode 100755 (executable)
index 8882abb..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/make -f
-
-include /usr/share/cdbs/1/class/autotools.mk
-include /usr/share/cdbs/1/rules/debhelper.mk
-
-DEB_CONFIGURE_SCRIPT := ./autogen.sh
-
-DEB_MAKE_CLEAN_TARGET := distclean
-
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644 (file)
index 0000000..034926c
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIRS = reference
+
+-include $(top_srcdir)/git.mk
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
new file mode 100644 (file)
index 0000000..f7a4ad6
--- /dev/null
@@ -0,0 +1,111 @@
+# Process this file with automake to produce Makefile.in
+
+# We require automake 1.6 at least.
+AUTOMAKE_OPTIONS = 1.6
+
+# This is a blank Makefile.am for using gtk-doc.
+# Copy this to your project's API docs directory and modify the variables to
+# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
+# of using the various options.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=harfbuzz
+
+# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
+#DOC_MODULE_VERSION=$(HB_VERSION_MAJOR)
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
+
+# Directories containing the source code.
+# gtk-doc will search all .c and .h files beneath these paths
+# for inline comments documenting functions and macros.
+# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
+DOC_SOURCE_DIR=$(top_srcdir)/src $(top_builddir)/src
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED"
+
+# Header files or dirs to ignore when scanning. Use base file/dir names
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
+IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.h' | sed 's@^.*/@@'`
+if HAVE_GOBJECT
+else
+IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
+endif
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
+MKDB_OPTIONS=--source-suffixes=h,cc --xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)"
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkhtml
+MKHTML_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_srcdir)/src/hb.h $(top_srcdir)/src/hb-*.h
+CFILE_GLOB=$(top_srcdir)/src/hb-*.cc
+
+# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
+# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
+EXTRA_HFILES=$(top_builddir)/src/hb-version.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files= version.xml
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+GTKDOC_CFLAGS=
+GTKDOC_LIBS=$(top_builddir)/src/libharfbuzz.la
+if HAVE_GOBJECT
+GTKDOC_LIBS+=$(top_builddir)/src/libharfbuzz-gobject.la
+endif
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST += version.xml.in
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+#DISTCLEANFILES +=
+
+# Comment this out if you want 'make check' to test you doc status
+# and run some sanity checks
+if ENABLE_GTK_DOC
+TESTS_ENVIRONMENT = cd $(srcdir) && \
+  DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
+  SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
+#TESTS = $(GTKDOC_CHECK)
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/docs/reference/harfbuzz-docs.xml b/docs/reference/harfbuzz-docs.xml
new file mode 100644 (file)
index 0000000..2731fab
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
+  <!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
+  <!ENTITY version SYSTEM "version.xml">
+]>
+<book id="index">
+  <bookinfo>
+    <title>HarfBuzz Reference Manual</title>
+    <releaseinfo>
+      for HarfBuzz &version;.
+      <!--The latest version of this documentation can be found on-line at
+      <ulink role="online-location" url="http://[SERVER]/libharfbuzz/index.html">http://[SERVER]/libharfbuzz/</ulink>.-->
+    </releaseinfo>
+  </bookinfo>
+
+  <chapter>
+    <title>[Insert title here]</title>
+    <xi:include href="xml/hb.xml"/>
+    <xi:include href="xml/hb-common.xml"/>
+    <xi:include href="xml/hb-unicode.xml"/>
+    <xi:include href="xml/hb-buffer.xml"/>
+    <xi:include href="xml/hb-blob.xml"/>
+    <xi:include href="xml/hb-face.xml"/>
+    <xi:include href="xml/hb-font.xml"/>
+    <xi:include href="xml/hb-shape.xml"/>
+
+    <xi:include href="xml/hb-version.xml"/>
+    <xi:include href="xml/hb-deprecated.xml"/>
+
+    <xi:include href="xml/hb-set.xml"/>
+
+    <xi:include href="xml/hb-ot.xml"/>
+    <xi:include href="xml/hb-ot-layout.xml"/>
+    <xi:include href="xml/hb-ot-tag.xml"/>
+
+    <xi:include href="xml/hb-shape-plan.xml"/>
+
+    <xi:include href="xml/hb-glib.xml"/>
+    <xi:include href="xml/hb-icu.xml"/>
+
+    <xi:include href="xml/hb-ft.xml"/>
+
+    <xi:include href="xml/hb-graphite2.xml"/>
+    <xi:include href="xml/hb-uniscribe.xml"/>
+    <xi:include href="xml/hb-coretext.xml"/>
+
+    <xi:include href="xml/hb-gobject.xml"/>
+
+  </chapter>
+  <chapter id="object-tree">
+    <title>Object Hierarchy</title>
+     <xi:include href="xml/tree_index.sgml"/>
+  </chapter>
+  <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>
+
+  <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
+</book>
old mode 100755 (executable)
new mode 100644 (file)
similarity index 100%
rename from debian/docs
rename to docs/reference/harfbuzz-overrides.txt
diff --git a/docs/reference/harfbuzz-sections.txt b/docs/reference/harfbuzz-sections.txt
new file mode 100644 (file)
index 0000000..3612dad
--- /dev/null
@@ -0,0 +1,498 @@
+<SECTION>
+<FILE>hb</FILE>
+<SUBSECTION Private>
+HB_H_IN
+</SECTION>
+
+<SECTION>
+<FILE>hb-blob</FILE>
+hb_blob_create
+hb_blob_create_sub_blob
+hb_blob_destroy
+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_add
+hb_buffer_add_utf16
+hb_buffer_add_utf32
+hb_buffer_add_utf8
+hb_buffer_allocation_successful
+hb_buffer_clear_contents
+hb_buffer_content_type_t
+hb_buffer_create
+hb_buffer_deserialize_glyphs
+hb_buffer_destroy
+hb_buffer_flags_t
+hb_buffer_get_content_type
+hb_buffer_get_direction
+hb_buffer_get_empty
+hb_buffer_get_flags
+hb_buffer_get_glyph_infos
+hb_buffer_get_glyph_positions
+hb_buffer_get_language
+hb_buffer_get_length
+hb_buffer_get_script
+hb_buffer_get_segment_properties
+hb_buffer_get_unicode_funcs
+hb_buffer_get_user_data
+hb_buffer_guess_segment_properties
+hb_buffer_normalize_glyphs
+hb_buffer_pre_allocate
+hb_buffer_reference
+hb_buffer_reset
+hb_buffer_reverse
+hb_buffer_reverse_clusters
+hb_buffer_serialize_flags_t
+hb_buffer_serialize_format_from_string
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_to_string
+hb_buffer_serialize_glyphs
+hb_buffer_serialize_list_formats
+hb_buffer_set_content_type
+hb_buffer_set_direction
+hb_buffer_set_flags
+hb_buffer_set_language
+hb_buffer_set_length
+hb_buffer_set_script
+hb_buffer_set_segment_properties
+hb_buffer_set_unicode_funcs
+hb_buffer_set_user_data
+hb_buffer_t
+hb_glyph_info_t
+hb_glyph_position_t
+hb_segment_properties_equal
+hb_segment_properties_hash
+hb_segment_properties_t
+</SECTION>
+
+<SECTION>
+<FILE>hb-common</FILE>
+HB_DIRECTION_REVERSE
+HB_LANGUAGE_INVALID
+HB_TAG
+HB_TAG_NONE
+HB_TAG_MAX
+HB_UNTAG
+hb_bool_t
+hb_codepoint_t
+hb_destroy_func_t
+hb_direction_from_string
+hb_direction_t
+hb_direction_to_string
+hb_language_from_string
+hb_language_get_default
+hb_language_t
+hb_language_to_string
+hb_mask_t
+hb_position_t
+hb_script_from_iso15924_tag
+hb_script_from_string
+hb_script_get_horizontal_direction
+hb_script_t
+hb_script_to_iso15924_tag
+hb_tag_from_string
+hb_tag_t
+hb_tag_to_string
+hb_user_data_key_t
+hb_var_int_t
+HB_DIRECTION_IS_BACKWARD
+HB_DIRECTION_IS_FORWARD
+HB_DIRECTION_IS_HORIZONTAL
+HB_DIRECTION_IS_VALID
+HB_DIRECTION_IS_VERTICAL
+<SUBSECTION Private>
+HB_BEGIN_DECLS
+HB_END_DECLS
+int16_t
+int32_t
+int64_t
+int8_t
+uint16_t
+uint32_t
+uint64_t
+uint8_t
+</SECTION>
+
+<SECTION>
+<FILE>hb-deprecated</FILE>
+HB_BUFFER_FLAGS_DEFAULT
+HB_BUFFER_SERIALIZE_FLAGS_DEFAULT
+HB_SCRIPT_CANADIAN_ABORIGINAL
+</SECTION>
+
+<SECTION>
+<FILE>hb-coretext</FILE>
+HB_CORETEXT_TAG_MORT
+HB_CORETEXT_TAG_MORX
+hb_coretext_face_create
+hb_coretext_face_get_cg_font
+hb_coretext_font_get_ct_font
+</SECTION>
+
+<SECTION>
+<FILE>hb-face</FILE>
+hb_face_create
+hb_face_create_for_tables
+hb_face_destroy
+hb_face_get_empty
+hb_face_get_glyph_count
+hb_face_get_index
+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_t
+</SECTION>
+
+<SECTION>
+<FILE>hb-font</FILE>
+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_func
+hb_font_funcs_set_glyph_h_advance_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_kerning_func
+hb_font_funcs_set_glyph_v_origin_func
+hb_font_funcs_set_user_data
+hb_font_funcs_t
+hb_font_get_empty
+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_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_func_t
+hb_font_get_glyph_h_advance
+hb_font_get_glyph_h_advance_func_t
+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_kerning
+hb_font_get_glyph_v_kerning_func_t
+hb_font_get_glyph_v_origin
+hb_font_get_glyph_v_origin_func_t
+hb_font_get_parent
+hb_font_get_ppem
+hb_font_get_scale
+hb_font_get_user_data
+hb_font_glyph_from_string
+hb_font_glyph_to_string
+hb_font_is_immutable
+hb_font_make_immutable
+hb_font_reference
+hb_font_set_funcs
+hb_font_set_funcs_data
+hb_font_set_ppem
+hb_font_set_scale
+hb_font_set_user_data
+hb_font_subtract_glyph_origin_for_direction
+hb_font_t
+hb_reference_table_func_t
+</SECTION>
+
+<SECTION>
+<FILE>hb-ft</FILE>
+hb_ft_face_create
+hb_ft_face_create_cached
+hb_ft_font_create
+hb_ft_font_get_face
+hb_ft_font_set_funcs
+</SECTION>
+
+<SECTION>
+<FILE>hb-glib</FILE>
+hb_glib_get_unicode_funcs
+hb_glib_script_from_script
+hb_glib_script_to_script
+</SECTION>
+
+<SECTION>
+<FILE>hb-gobject</FILE>
+HB_GOBJECT_TYPE_BLOB
+HB_GOBJECT_TYPE_BUFFER
+HB_GOBJECT_TYPE_BUFFER_CONTENT_TYPE
+HB_GOBJECT_TYPE_BUFFER_FLAGS
+HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FLAGS
+HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FORMAT
+HB_GOBJECT_TYPE_DIRECTION
+HB_GOBJECT_TYPE_FACE
+HB_GOBJECT_TYPE_FONT
+HB_GOBJECT_TYPE_FONT_FUNCS
+HB_GOBJECT_TYPE_MEMORY_MODE
+HB_GOBJECT_TYPE_OT_LAYOUT_GLYPH_CLASS
+HB_GOBJECT_TYPE_SCRIPT
+HB_GOBJECT_TYPE_SHAPE_PLAN
+HB_GOBJECT_TYPE_UNICODE_COMBINING_CLASS
+HB_GOBJECT_TYPE_UNICODE_FUNCS
+HB_GOBJECT_TYPE_UNICODE_GENERAL_CATEGORY
+hb_gobject_blob_get_type
+hb_gobject_buffer_content_type_get_type
+hb_gobject_buffer_flags_get_type
+hb_gobject_buffer_get_type
+hb_gobject_buffer_serialize_flags_get_type
+hb_gobject_buffer_serialize_format_get_type
+hb_gobject_direction_get_type
+hb_gobject_face_get_type
+hb_gobject_font_funcs_get_type
+hb_gobject_font_get_type
+hb_gobject_memory_mode_get_type
+hb_gobject_ot_layout_glyph_class_get_type
+hb_gobject_script_get_type
+hb_gobject_shape_plan_get_type
+hb_gobject_unicode_combining_class_get_type
+hb_gobject_unicode_funcs_get_type
+hb_gobject_unicode_general_category_get_type
+<SUBSECTION Private>
+HB_GOBJECT_H_IN
+</SECTION>
+
+<SECTION>
+<FILE>hb-gobject</FILE>
+
+</SECTION>
+
+<SECTION>
+<FILE>hb-graphite2</FILE>
+HB_GRAPHITE2_TAG_SILF
+hb_graphite2_face_get_gr_face
+hb_graphite2_font_get_gr_font
+</SECTION>
+
+<SECTION>
+<FILE>hb-icu</FILE>
+hb_icu_get_unicode_funcs
+hb_icu_script_from_script
+hb_icu_script_to_script
+</SECTION>
+
+<SECTION>
+<FILE>hb-ot</FILE>
+<SUBSECTION Private>
+HB_OT_H_IN
+</SECTION>
+
+<SECTION>
+<FILE>hb-ot-font</FILE>
+hb_ot_font_set_funcs
+</SECTION>
+
+<SECTION>
+<FILE>hb-ot-shape</FILE>
+hb_ot_shape_glyphs_closure
+</SECTION>
+
+<SECTION>
+<FILE>hb-ot-layout</FILE>
+HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
+HB_OT_LAYOUT_NO_FEATURE_INDEX
+HB_OT_LAYOUT_NO_SCRIPT_INDEX
+HB_OT_TAG_GDEF
+HB_OT_TAG_GPOS
+HB_OT_TAG_GSUB
+hb_ot_layout_collect_lookups
+hb_ot_layout_feature_get_lookups
+hb_ot_layout_get_attach_points
+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_glyph_sequence_func_t
+hb_ot_layout_has_glyph_classes
+hb_ot_layout_has_positioning
+hb_ot_layout_has_substitution
+hb_ot_layout_language_find_feature
+hb_ot_layout_language_get_feature_indexes
+hb_ot_layout_language_get_feature_tags
+hb_ot_layout_language_get_required_feature
+hb_ot_layout_lookup_collect_glyphs
+hb_ot_layout_lookup_substitute_closure
+hb_ot_layout_lookup_would_substitute
+hb_ot_layout_script_find_language
+hb_ot_layout_script_get_language_tags
+hb_ot_layout_table_choose_script
+hb_ot_layout_table_find_script
+hb_ot_layout_table_get_feature_tags
+hb_ot_layout_table_get_script_tags
+hb_ot_layout_table_get_lookup_count
+hb_ot_shape_plan_collect_lookups
+<SUBSECTION Private>
+Xhb_ot_layout_lookup_enumerate_sequences
+Xhb_ot_layout_lookup_position
+Xhb_ot_layout_lookup_substitute
+</SECTION>
+
+<SECTION>
+<FILE>hb-ot-tag</FILE>
+HB_OT_TAG_DEFAULT_LANGUAGE
+HB_OT_TAG_DEFAULT_SCRIPT
+hb_ot_tag_from_language
+hb_ot_tag_to_language
+hb_ot_tag_to_script
+hb_ot_tags_from_script
+</SECTION>
+
+<SECTION>
+<FILE>hb-set</FILE>
+HB_SET_VALUE_INVALID
+hb_set_add
+hb_set_add_range
+hb_set_allocation_successful
+hb_set_clear
+hb_set_create
+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_intersect
+hb_set_invert
+hb_set_is_empty
+hb_set_is_equal
+hb_set_next
+hb_set_next_range
+hb_set_reference
+hb_set_set
+hb_set_set_user_data
+hb_set_subtract
+hb_set_symmetric_difference
+hb_set_t
+hb_set_union
+</SECTION>
+
+<SECTION>
+<FILE>hb-shape</FILE>
+hb_feature_from_string
+hb_feature_t
+hb_feature_to_string
+hb_shape
+hb_shape_full
+hb_shape_list_shapers
+</SECTION>
+
+<SECTION>
+<FILE>hb-shape-plan</FILE>
+hb_shape_plan_create
+hb_shape_plan_create_cached
+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_set_user_data
+hb_shape_plan_t
+</SECTION>
+
+<SECTION>
+<FILE>hb-unicode</FILE>
+HB_UNICODE_MAX_DECOMPOSITION_LEN
+hb_unicode_combining_class
+hb_unicode_combining_class_func_t
+hb_unicode_combining_class_t
+hb_unicode_compose
+hb_unicode_compose_func_t
+hb_unicode_decompose
+hb_unicode_decompose_compatibility
+hb_unicode_decompose_func_t
+hb_unicode_eastasian_width
+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_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_compatibility_func
+hb_unicode_funcs_set_decompose_func
+hb_unicode_funcs_set_eastasian_width_func
+hb_unicode_funcs_set_general_category_func
+hb_unicode_funcs_set_mirroring_func
+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_general_category_t
+hb_unicode_mirroring
+hb_unicode_mirroring_func_t
+hb_unicode_script
+hb_unicode_script_func_t
+</SECTION>
+
+<SECTION>
+<FILE>hb-uniscribe</FILE>
+hb_uniscribe_font_get_hfont
+hb_uniscribe_font_get_logfontw
+</SECTION>
+
+<SECTION>
+<FILE>hb-version</FILE>
+HB_VERSION_ATLEAST
+HB_VERSION_MAJOR
+HB_VERSION_MICRO
+HB_VERSION_MINOR
+HB_VERSION_STRING
+hb_version
+hb_version_atleast
+hb_version_string
+</SECTION>
diff --git a/docs/reference/version.xml.in b/docs/reference/version.xml.in
new file mode 100644 (file)
index 0000000..de213c2
--- /dev/null
@@ -0,0 +1 @@
+@HB_VERSION@
diff --git a/git.mk b/git.mk
index 088ef0b..091d7ec 100644 (file)
--- a/git.mk
+++ b/git.mk
@@ -1,18 +1,24 @@
 # git.mk
 #
 # 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,
-# are permitted in any medium without royalty provided the copyright
+# is permitted in any medium without royalty provided the copyright
 # notice and this notice are preserved.
 #
-# The canonical source for this file is pango/git.mk, or whereever the
-# header of pango/git.mk suggests in the future.
+# The latest version of this file can be downloaded from:
+GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk
+#
+# Bugs, etc, should be reported upstream at:
+#   https://github.com/behdad/git.mk
 #
 # To use in your project, import this file in your git repo's toplevel,
 # then do "make -f git.mk".  This modifies all Makefile.am files in
-# your project to include git.mk.
+# your project to -include git.mk.  Remember to add that line to new
+# Makefile.am files you create in your project, or just rerun the
+# "make -f git.mk".
 #
 # This enables automatic .gitignore generation.  If you need to ignore
 # more files, add them to the GITIGNOREFILES variable in your Makefile.am.
@@ -22,7 +28,7 @@
 #
 # The only case that you need to manually add a file to GITIGNOREFILES is
 # when remove files in one of mostlyclean-local, clean-local, distclean-local,
-# or maintainer-clean-local.
+# or maintainer-clean-local make targets.
 #
 # Note that for files like editor backup, etc, there are better places to
 # ignore them.  See "man gitignore".
 # If "make maintainer-clean" removes the files but they are not recognized
 # by this script (that is, if "git status" shows untracked files still), send
 # me the output of "git status" as well as your Makefile.am and Makefile for
-# the directories involved.
+# the directories involved and I'll diagnose.
 #
 # For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
-# pango/Makefile.am.
+# Makefile.am.sample in the git.mk git repo.
 #
 # Don't EXTRA_DIST this file.  It is supposed to only live in git clones,
 # not tarballs.  It serves no useful purpose in tarballs and clutters the
 # build dir.
 #
 # This file knows how to handle autoconf, automake, libtool, gtk-doc,
-# gnome-doc-utils, intltool.
+# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
+# appstream.
+#
+# This makefile provides the following targets:
 #
+# - all: "make all" will build all gitignore files.
+# - gitignore: makes all gitignore files in the current dir and subdirs.
+# - .gitignore: make gitignore file for the current dir.
+# - gitignore-recurse: makes all gitignore files in the subdirs.
 #
 # KNOWN ISSUES:
 #
 #   example.
 #
 
+
+
+###############################################################################
+# Variables user modules may want to add to toplevel MAINTAINERCLEANFILES:
+###############################################################################
+
+#
+# Most autotools-using modules should be fine including this variable in their
+# toplevel MAINTAINERCLEANFILES:
+GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL = \
+       $(srcdir)/aclocal.m4 \
+       $(srcdir)/autoscan.log \
+       $(srcdir)/configure.scan \
+       `AUX_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_AUX_DIR:$$1' ./configure.ac); \
+        test "x$$AUX_DIR" = "x$(srcdir)/" && AUX_DIR=$(srcdir); \
+        for x in \
+               ar-lib \
+               compile \
+               config.guess \
+               config.sub \
+               depcomp \
+               install-sh \
+               ltmain.sh \
+               missing \
+               mkinstalldirs \
+               test-driver \
+               ylwrap \
+        ; do echo "$$AUX_DIR/$$x"; done` \
+       `cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_HEADERS:$$1' ./configure.ac | \
+       head -n 1 | while read f; do echo "$(srcdir)/$$f.in"; done`
+#
+# All modules should also be fine including the following variable, which
+# removes automake-generated Makefile.in files:
+GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN = \
+       `cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_FILES:$$1' ./configure.ac | \
+       while read f; do \
+         case $$f in Makefile|*/Makefile) \
+           test -f "$(srcdir)/$$f.am" && echo "$(srcdir)/$$f.in";; esac; \
+       done`
+#
+# Modules that use libtool and use  AC_CONFIG_MACRO_DIR() may also include this,
+# though it's harmless to include regardless.
+GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL = \
+       `MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
+        if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
+               for x in \
+                       libtool.m4 \
+                       ltoptions.m4 \
+                       ltsugar.m4 \
+                       ltversion.m4 \
+                       lt~obsolete.m4 \
+               ; do echo "$$MACRO_DIR/$$x"; done; \
+        fi`
+
+
+
+###############################################################################
+# Default rule is to install ourselves in all Makefile.am files:
+###############################################################################
+
 git-all: git-mk-install
 
 git-mk-install:
-       @echo Installing git makefile
-       @any_failed=; find $(top_srcdir) -name Makefile.am | while read x; do \
+       @echo "Installing git makefile"
+       @any_failed=; \
+               find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \
                if grep 'include .*/git.mk' $$x >/dev/null; then \
-                       echo $$x already includes git.mk; \
+                       echo "$$x already includes git.mk"; \
                else \
                        failed=; \
                        echo "Updating $$x"; \
@@ -71,19 +145,25 @@ git-mk-install:
                                mv $$x.tmp $$x || failed=1; \
                        fi; \
                        if test x$$failed = x; then : else \
-                               echo Failed updating $$x; >&2 \
+                               echo "Failed updating $$x"; >&2 \
                                any_failed=1; \
                        fi; \
        fi; done; test -z "$$any_failed"
 
-.PHONY: git-all git-mk-install
+git-mk-update:
+       wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk
+
+.PHONY: git-all git-mk-install git-mk-update
+
 
 
-### .gitignore generation
+###############################################################################
+# Actual .gitignore generation:
+###############################################################################
 
 $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
-       $(AM_V_GEN) \
-       { \
+       @echo "git.mk: Generating $@"
+       @{ \
                if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
                        for x in \
                                $(DOC_MODULE)-decl-list.txt \
@@ -91,35 +171,74 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
                                tmpl/$(DOC_MODULE)-unused.sgml \
                                "tmpl/*.bak" \
                                xml html \
-                       ; do echo /$$x; done; \
+                       ; do echo "/$$x"; done; \
+                       FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \
+                       case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \
                fi; \
-               if test "x$(DOC_MODULE)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
+               if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
+                       for lc in $(DOC_LINGUAS); do \
+                               for x in \
+                                       $(if $(DOC_MODULE),$(DOC_MODULE).xml) \
+                                       $(DOC_PAGES) \
+                                       $(DOC_INCLUDES) \
+                               ; do echo "/$$lc/$$x"; done; \
+                       done; \
                        for x in \
-                               $(_DOC_C_DOCS) \
-                               $(_DOC_LC_DOCS) \
                                $(_DOC_OMF_ALL) \
                                $(_DOC_DSK_ALL) \
                                $(_DOC_HTML_ALL) \
-                               $(_DOC_POFILES) \
+                               $(_DOC_MOFILES) \
+                               $(DOC_H_FILE) \
                                "*/.xml2po.mo" \
                                "*/*.omf.out" \
                        ; do echo /$$x; done; \
                fi; \
+               if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
+                       for lc in $(HELP_LINGUAS); do \
+                               for x in \
+                                       $(HELP_FILES) \
+                                       "$$lc.stamp" \
+                                       "$$lc.mo" \
+                               ; do echo "/$$lc/$$x"; done; \
+                       done; \
+               fi; \
+               if test "x$(gsettings_SCHEMAS)" = x; then :; else \
+                       for x in \
+                               $(gsettings_SCHEMAS:.xml=.valid) \
+                               $(gsettings__enum_file) \
+                       ; do echo "/$$x"; done; \
+               fi; \
+               if test "x$(appdata_XML)" = x; then :; else \
+                       for x in \
+                               $(appdata_XML:.xml=.valid) \
+                       ; do echo "/$$x"; done; \
+               fi; \
+               if test "x$(appstream_XML)" = x; then :; else \
+                       for x in \
+                               $(appstream_XML:.xml=.valid) \
+                       ; do echo "/$$x"; done; \
+               fi; \
                if test -f $(srcdir)/po/Makefile.in.in; then \
                        for x in \
                                po/Makefile.in.in \
+                               po/Makefile.in.in~ \
                                po/Makefile.in \
                                po/Makefile \
+                               po/Makevars.template \
                                po/POTFILES \
+                               po/Rules-quot \
                                po/stamp-it \
                                po/.intltool-merge-cache \
                                "po/*.gmo" \
+                               "po/*.header" \
                                "po/*.mo" \
+                               "po/*.sed" \
+                               "po/*.sin" \
                                po/$(GETTEXT_PACKAGE).pot \
                                intltool-extract.in \
                                intltool-merge.in \
                                intltool-update.in \
-                       ; do echo /$$x; done; \
+                       ; do echo "/$$x"; done; \
                fi; \
                if test -f $(srcdir)/configure; then \
                        for x in \
@@ -129,21 +248,38 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
                                stamp-h1 \
                                libtool \
                                config.lt \
-                       ; do echo /$$x; done; \
+                       ; do echo "/$$x"; done; \
+               fi; \
+               if test "x$(DEJATOOL)" = x; then :; else \
+                       for x in \
+                               $(DEJATOOL) \
+                       ; do echo "/$$x.sum"; echo "/$$x.log"; done; \
+                       echo /site.exp; \
+               fi; \
+               if test "x$(am__dirstamp)" = x; then :; else \
+                       echo "$(am__dirstamp)"; \
+               fi; \
+               if test "x$(LTCOMPILE)" = x -a "x$(LTCXXCOMPILE)" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
+                       for x in \
+                               "*.lo" \
+                               ".libs" "_libs" \
+                       ; do echo "$$x"; done; \
                fi; \
                for x in \
                        .gitignore \
                        $(GITIGNOREFILES) \
                        $(CLEANFILES) \
-                       $(PROGRAMS) \
-                       $(check_PROGRAMS) \
-                       $(EXTRA_PROGRAMS) \
-                       $(LTLIBRARIES) \
+                       $(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \
+                       $(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \
+                       $(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \
                        so_locations \
-                       .libs _libs \
                        $(MOSTLYCLEANFILES) \
-                       "*.$(OBJEXT)" \
-                       "*.lo" \
+                       $(TEST_LOGS) \
+                       $(TEST_LOGS:.log=.trs) \
+                       $(TEST_SUITE_LOG) \
+                       $(TESTS:=.test) \
+                       "*.gcda" \
+                       "*.gcno" \
                        $(DISTCLEANFILES) \
                        $(am__CONFIG_DISTCLEAN_FILES) \
                        $(CONFIG_CLEAN_FILES) \
@@ -151,7 +287,10 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
                        "*.tab.c" \
                        $(MAINTAINERCLEANFILES) \
                        $(BUILT_SOURCES) \
-                       $(DEPDIR) \
+                       $(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \
+                       $(filter %_vala.stamp,$(DIST_COMMON)) \
+                       $(filter %.vapi,$(DIST_COMMON)) \
+                       $(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \
                        Makefile \
                        Makefile.in \
                        "*.orig" \
@@ -159,7 +298,12 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
                        "*.bak" \
                        "*~" \
                        ".*.sw[nop]" \
-               ; do echo /$$x; done; \
+                       ".dirstamp" \
+               ; do echo "/$$x"; done; \
+               for x in \
+                       "*.$(OBJEXT)" \
+                       $(DEPDIR) \
+               ; do echo "$$x"; done; \
        } | \
        sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
        sed 's@/[.]/@/@g' | \
@@ -167,15 +311,19 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
        mv $@.tmp $@;
 
 all: $(srcdir)/.gitignore gitignore-recurse-maybe
+gitignore: $(srcdir)/.gitignore gitignore-recurse
+
 gitignore-recurse-maybe:
-       @if test "x$(SUBDIRS)" = "x$(DIST_SUBDIRS)"; then :; else \
-               $(MAKE) $(AM_MAKEFLAGS) gitignore-recurse; \
-       fi;
+       @for subdir in $(DIST_SUBDIRS); do \
+         case " $(SUBDIRS) " in \
+           *" $$subdir "*) :;; \
+           *) test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir");; \
+         esac; \
+       done
 gitignore-recurse:
-       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
-         test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || echo "Skipping $$subdir"); \
+       @for subdir in $(DIST_SUBDIRS); do \
+           test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir"); \
        done
-gitignore: $(srcdir)/.gitignore gitignore-recurse
 
 maintainer-clean: gitignore-clean
 gitignore-clean:
diff --git a/harfbuzz.manifest b/harfbuzz.manifest
new file mode 100644 (file)
index 0000000..317cf89
--- /dev/null
@@ -0,0 +1,10 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+       <assign>
+               <filesystem path="/usr/bin/hb-ot-shape-closure" exec_label="none" />
+               <filesystem path="/usr/bin/hb-shape" exec_label="none" />
+               <filesystem path="/usr/bin/hb-view" exec_label="none" />
+       </assign>
+</manifest>
diff --git a/m4/ax_pthread.m4 b/m4/ax_pthread.m4
new file mode 100644 (file)
index 0000000..d90de34
--- /dev/null
@@ -0,0 +1,309 @@
+# ===========================================================================
+#        http://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC to any special C compiler that is needed for
+#   multi-threaded programs (defaults to the value of CC otherwise). (This
+#   is necessary on AIX to use the special cc_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also link it with them as well. e.g. you should link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threads programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
+#   (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   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 <http://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.
+
+#serial 18
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
+        AC_MSG_RESULT($ax_pthread_ok)
+        if test x"$ax_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case ${host_os} in
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
+        ;;
+
+        darwin*)
+        ax_pthread_flags="-pthread $ax_pthread_flags"
+        ;;
+esac
+
+if test x"$ax_pthread_ok" = xno; then
+for flag in $ax_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
+                if test x"$ax_pthread_config" = xno; then continue; fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }],
+                       [pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */])],
+                [ax_pthread_ok=yes],
+                [])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($ax_pthread_ok)
+        if test "x$ax_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_MSG_CHECKING([for joinable pthread attribute])
+        attr_name=unknown
+        for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+            AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                           [int attr = $attr; return attr /* ; */])],
+                [attr_name=$attr; break],
+                [])
+        done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case ${host_os} in
+            aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
+            osf* | hpux*) flag="-D_REENTRANT";;
+            solaris*)
+            if test "$GCC" = "yes"; then
+                flag="-D_REENTRANT"
+            else
+                flag="-mt -D_REENTRANT"
+            fi
+            ;;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            ax_cv_PTHREAD_PRIO_INHERIT, [
+                AC_LINK_IFELSE([
+                    AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                    [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
+            AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+        if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+        fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$ax_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
diff --git a/m4/libtool.m4 b/m4/libtool.m4
new file mode 100644 (file)
index 0000000..828104c
--- /dev/null
@@ -0,0 +1,8001 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool 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 GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+                  [m4_fatal([Libtool version $1 or higher is required],
+                            63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\    *)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+       [m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+       [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+       [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+          m4_quote(lt_decl_varnames),
+       m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+                       lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+                                          [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+       dnl If the libtool generation code has been placed in $CONFIG_LT,
+       dnl instead of duplicating it all over again into config.status,
+       dnl then we will have config.status run $CONFIG_LT later, so it
+       dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_REPLACE_SHELLFNS
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],                 [_LT_LANG(C)],
+  [C++],               [_LT_LANG(CXX)],
+  [Go],                        [_LT_LANG(GO)],
+  [Java],              [_LT_LANG(GCJ)],
+  [Fortran 77],                [_LT_LANG(F77)],
+  [Fortran],           [_LT_LANG(FC)],
+  [Windows Resource],  [_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+       [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+       [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+       [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+       # By default we will add the -single_module flag. You can override
+       # by either setting the environment variable LT_MULTI_MODULE
+       # non-empty at configure time, or by adding -multi_module to the
+       # link flags.
+       rm -rf libconftest.dylib*
+       echo "int foo(void){return 1;}" > conftest.c
+       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+       # If there is a non-empty error log, and "single_module"
+       # appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+         cat conftest.err >&AS_MESSAGE_LOG_FD
+       # Otherwise, if the output was created with a 0 exit code from
+       # the compiler, it worked.
+       elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+         lt_cv_apple_cc_single_mod=yes
+       else
+         cat conftest.err >&AS_MESSAGE_LOG_FD
+       fi
+       rm -rf libconftest.dylib*
+       rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+       [lt_cv_ld_exported_symbols_list=yes],
+       [lt_cv_ld_exported_symbols_list=no])
+       LDFLAGS="$save_LDFLAGS"
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+       cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+       10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+       10.[[012]]*)
+         _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+       10.*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+         /^0/ {
+             s/^0  *\([^ ]*\) *$/\1/
+             p
+         }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[  --with-sysroot[=DIR] Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([${with_sysroot}])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+       HPUX_IA64_MODE="32"
+       ;;
+      *ELF-64*)
+       HPUX_IA64_MODE="64"
+       ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+       *32-bit*)
+         LD="${LD-ld} -melf32bsmip"
+         ;;
+       *N32*)
+         LD="${LD-ld} -melf32bmipn32"
+         ;;
+       *64-bit*)
+         LD="${LD-ld} -melf64bmip"
+       ;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+       *32-bit*)
+         LD="${LD-ld} -32"
+         ;;
+       *N32*)
+         LD="${LD-ld} -n32"
+         ;;
+       *64-bit*)
+         LD="${LD-ld} -64"
+         ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+       case $host in
+         x86_64-*kfreebsd*-gnu)
+           LD="${LD-ld} -m elf_i386_fbsd"
+           ;;
+         x86_64-*linux*)
+           LD="${LD-ld} -m elf_i386"
+           ;;
+         ppc64-*linux*|powerpc64-*linux*)
+           LD="${LD-ld} -m elf32ppclinux"
+           ;;
+         s390x-*linux*)
+           LD="${LD-ld} -m elf_s390"
+           ;;
+         sparc64-*linux*)
+           LD="${LD-ld} -m elf32_sparc"
+           ;;
+       esac
+       ;;
+      *64-bit*)
+       case $host in
+         x86_64-*kfreebsd*-gnu)
+           LD="${LD-ld} -m elf_x86_64_fbsd"
+           ;;
+         x86_64-*linux*)
+           LD="${LD-ld} -m elf_x86_64"
+           ;;
+         ppc*-*linux*|powerpc*-*linux*)
+           LD="${LD-ld} -m elf64ppc"
+           ;;
+         s390*-*linux*|s390*-*tpf*)
+           LD="${LD-ld} -m elf64_s390"
+           ;;
+         sparc*-*linux*)
+           LD="${LD-ld} -m elf64_sparc"
+           ;;
+       esac
+       ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+       if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+         LD="${LD-ld} -64"
+       fi
+       ;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test "$ac_status" -eq 0; then
+       # Ensure the archiver fails upon bogus file names.
+       rm -f conftest.$ac_objext libconftest.a
+       AC_TRY_EVAL([lt_ar_try])
+       if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#              [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536      # usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[        ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+                = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+             test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL          RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL                DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL                0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW           RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW         DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW       RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW     DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW     0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+         if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+       }
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+         [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+           [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+       [AC_CHECK_FUNC([dlopen],
+             [lt_cv_dlopen="dlopen"],
+         [AC_CHECK_LIB([dl], [dlopen],
+               [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+           [AC_CHECK_LIB([svld], [dlopen],
+                 [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+             [AC_CHECK_LIB([dld], [dld_link],
+                   [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+             ])
+           ])
+         ])
+       ])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+         lt_cv_dlopen_self, [dnl
+         _LT_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+           lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+         lt_cv_dlopen_self_static, [dnl
+         _LT_TRY_DLOPEN_SELF(
+           lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+           lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+        [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+        [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+        [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+       [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+       [], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+       lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+          echo ' yes '
+          echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+       :
+      else
+       can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+       if test "$lt_cv_prog_gnu_ld" = yes; then
+               version_type=linux # correct to gnu/linux during the next big refactor
+       else
+               version_type=irix
+       fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+        LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+        [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[  ]*hwcap[        ]/d;s/[:,      ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+    *)                         need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+       shlibpath_overrides_runpath=no
+       ;;
+      *)
+       shlibpath_overrides_runpath=yes
+       ;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+       ;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+       case $deplibs_check_method in
+       "file_magic "*)
+         file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+         MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+         if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+           $EGREP "$file_magic_regex" > /dev/null; then
+           :
+         else
+           cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+         fi ;;
+       esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+        [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+       [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd* | netbsdelf*-gnu)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+       # Check to see if the nm accepts a BSD-compat flag.
+       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+       #   nm: unknown option "B" ignored
+       # Tru64's nm complains that /dev/null is an invalid object file
+       case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+       */dev/null* | *'Invalid file or object type'*)
+         lt_cv_path_NM="$tmp_nm -B"
+         break
+         ;;
+       *)
+         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+         */dev/null*)
+           lt_cv_path_NM="$tmp_nm -p"
+           break
+           ;;
+         *)
+           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+           continue # so that we can try to find one that supports BSD flags
+           ;;
+         esac
+         ;;
+       esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+       [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[    ]]\($symcode$symcode*\)[[       ]][[    ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+       mv -f "$nlist"T "$nlist"
+      else
+       rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+       if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+         cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t@_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+         # Now generate the symbol file.
+         eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+         cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t@_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+         $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+         cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+         # Now try linking the two files.
+         mv conftest.$ac_objext conftstm.$ac_objext
+         lt_globsym_save_LIBS=$LIBS
+         lt_globsym_save_CFLAGS=$CFLAGS
+         LIBS="conftstm.$ac_objext"
+         CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+         if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+           pipe_works=yes
+         fi
+         LIBS=$lt_globsym_save_LIBS
+         CFLAGS=$lt_globsym_save_CFLAGS
+       else
+         echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+       fi
+      else
+       echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+       # All AIX code is PIC.
+       if test "$host_cpu" = ia64; then
+         # AIX 5 now supports IA64 processor
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       else
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+       fi
+       ;;
+      chorus*)
+       case $cc_basename in
+       cxch68*)
+         # Green Hills C++ Compiler
+         # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+         ;;
+       esac
+       ;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+       # This hack is so that the source file can tell whether it is being
+       # built for inclusion in a dll (and should export symbols for example).
+       m4_if([$1], [GCJ], [],
+         [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+       ;;
+      dgux*)
+       case $cc_basename in
+         ec++*)
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         ghcx*)
+           # Green Hills C++ Compiler
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      freebsd* | dragonfly*)
+       # FreeBSD uses GNU C++
+       ;;
+      hpux9* | hpux10* | hpux11*)
+       case $cc_basename in
+         CC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+           if test "$host_cpu" != ia64; then
+             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+           fi
+           ;;
+         aCC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+           case $host_cpu in
+           hppa*64*|ia64*)
+             # +Z the default
+             ;;
+           *)
+             _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+             ;;
+           esac
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      interix*)
+       # This is c89, which is MS Visual C++ (no shared libs)
+       # Anyone wants to do a port?
+       ;;
+      irix5* | irix6* | nonstopux*)
+       case $cc_basename in
+         CC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           # CC pic flag -KPIC is the default.
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+       case $cc_basename in
+         KCC*)
+           # KAI C++ Compiler
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           ;;
+         ecpc* )
+           # old Intel C++ for x86_64 which still supported -KPIC.
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         icpc* )
+           # Intel C++, used to be incompatible with GCC.
+           # ICC 10 doesn't accept -KPIC any more.
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+           ;;
+         pgCC* | pgcpp*)
+           # Portland Group C++ compiler
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         cxx*)
+           # Compaq C++
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+           # IBM XL 8.0, 9.0 on PPC and BlueGene
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+           ;;
+         *)
+           case `$CC -V 2>&1 | sed 5q` in
+           *Sun\ C*)
+             # Sun C++ 5.9
+             _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+             _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+             _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+             ;;
+           esac
+           ;;
+       esac
+       ;;
+      lynxos*)
+       ;;
+      m88k*)
+       ;;
+      mvs*)
+       case $cc_basename in
+         cxx*)
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      netbsd* | netbsdelf*-gnu)
+       ;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+       case $cc_basename in
+         KCC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+           ;;
+         RCC*)
+           # Rational C++ 2.4.1
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         cxx*)
+           # Digital/Compaq C++
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           # Make sure the PIC flag is empty.  It appears that all Alpha
+           # Linux and Compaq Tru64 Unix objects are PIC.
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      psos*)
+       ;;
+      solaris*)
+       case $cc_basename in
+         CC* | sunCC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+           ;;
+         gcx*)
+           # Green Hills C++ Compiler
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      sunos4*)
+       case $cc_basename in
+         CC*)
+           # Sun C++ 4.x
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+         lcc*)
+           # Lucid
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+       case $cc_basename in
+         CC*)
+           _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+           ;;
+       esac
+       ;;
+      tandem*)
+       case $cc_basename in
+         NCC*)
+           # NonStop-UX NCC 3.20
+           _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+           ;;
+         *)
+           ;;
+       esac
+       ;;
+      vxworks*)
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+       ;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       ;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+       # AIX 5 now supports IA64 processor
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+       [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+       # +Z the default
+       ;;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+       ;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+       ;;
+      nagfor*)
+       # NAG Fortran compiler
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+       ;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+       # which looks to be a dead project)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+       # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+       ;;
+      *)
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+         # Sun Fortran 8.3 passes all unrecognized flags to the linker
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+         ;;
+       *Sun\ F* | *Sun*Fortran*)
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+         ;;
+       *Sun\ C*)
+         # Sun C 5.9
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         ;;
+        *Intel*\ [[CF]]*Compiler*)
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+         ;;
+       *Portland\ Group*)
+         _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+         _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+         _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+         ;;
+       esac
+       ;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+       _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+       _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+       _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+       [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+       [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+       [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+       # The AIX port of GNU ld has always aspired to compatibility
+       # with the native linker.  However, as the warning in the GNU ld
+       # block says, versions before 2.19.5* couldn't really create working
+       # shared libraries, regardless of the interface used.
+       case `$LD -v 2>&1` in
+         *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+         *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+         *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+         *)
+           lt_use_gnu_ld_interface=yes
+           ;;
+       esac
+       ;;
+      *)
+       lt_use_gnu_ld_interface=yes
+       ;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+       # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+       # support --undefined.  This deserves some investigation.  FIXME
+       _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+       # If the export-symbols file already is a .def file (1st line
+       # is EXPORTS), use it as is; otherwise, prepend...
+       _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+         cp $export_symbols $output_objdir/$soname.def;
+       else
+         echo EXPORTS > $output_objdir/$soname.def;
+         cat $export_symbols >> $output_objdir/$soname.def;
+       fi~
+       $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+       case $cc_basename in
+         diet\ *) tmp_diet=yes;;       # linux-dietlibc with static linking (!diet-dyn)
+       esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+        && test "$tmp_diet" = no
+      then
+       tmp_addflag=' $pic_flag'
+       tmp_sharedflag='-shared'
+       case $cc_basename,$host_cpu in
+        pgcc*)                         # Portland Group C compiler
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag'
+         ;;
+       pgf77* | pgf90* | pgf95* | pgfortran*)
+                                       # Portland Group f77 and f90 compilers
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         tmp_addflag=' $pic_flag -Mnomain' ;;
+       ecc*,ia64* | icc*,ia64*)        # Intel C compiler on ia64
+         tmp_addflag=' -i_dynamic' ;;
+       efc*,ia64* | ifort*,ia64*)      # Intel Fortran compiler on ia64
+         tmp_addflag=' -i_dynamic -nofor_main' ;;
+       ifc* | ifort*)                  # Intel Fortran compiler
+         tmp_addflag=' -nofor_main' ;;
+       lf95*)                          # Lahey Fortran 8.1
+         _LT_TAGVAR(whole_archive_flag_spec, $1)=
+         tmp_sharedflag='--shared' ;;
+       xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+         tmp_sharedflag='-qmkshrobj'
+         tmp_addflag= ;;
+       nvcc*)  # Cuda Compiler Driver 2.2
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(compiler_needs_object, $1)=yes
+         ;;
+       esac
+       case `$CC -V 2>&1 | sed 5q` in
+       *Sun\ C*)                       # Sun C 5.9
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+         _LT_TAGVAR(compiler_needs_object, $1)=yes
+         tmp_sharedflag='-G' ;;
+       *Sun\ F*)                       # Sun Fortran 8.3
+         tmp_sharedflag='-G' ;;
+       esac
+       _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+           cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+           echo "local: *; };" >> $output_objdir/$libname.ver~
+           $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+       case $cc_basename in
+       xlf* | bgf* | bgxlf* | mpixlf*)
+         # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+         _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+         if test "x$supports_anon_versioning" = xyes; then
+           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+             cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+             echo "local: *; };" >> $output_objdir/$libname.ver~
+             $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+         fi
+         ;;
+       esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+       wlarc=
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+       ;;
+       *)
+         # For security reasons, it is highly recommended that you always
+         # use absolute paths for naming shared libraries, and exclude the
+         # DT_RUNPATH tag from executables and libraries.  But doing so
+         # requires that you compile everything twice, which is a pain.
+         if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+         else
+           _LT_TAGVAR(ld_shlibs, $1)=no
+         fi
+       ;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+       # Neither direct hardcoding nor static linking is supported with a
+       # broken collect2.
+       _LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+       # On IA64, the linker does run time linking by default, so we don't
+       # have to do anything special.
+       aix_use_runtimelinking=no
+       exp_sym_flag='-Bexport'
+       no_entry_flag=""
+      else
+       # If we're using GNU nm, then we don't want the "-C" option.
+       # -C means demangle to AIX nm, but means don't demangle with GNU nm
+       # Also, AIX nm treats weak defined symbols like other global
+       # defined symbols, whereas GNU nm marks them as "W".
+       if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+       else
+         _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+       fi
+       aix_use_runtimelinking=no
+
+       # Test if we are trying to use run time linking or normal
+       # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+       # need to do runtime linking.
+       case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+         for ld_flag in $LDFLAGS; do
+         if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+           aix_use_runtimelinking=yes
+           break
+         fi
+         done
+         ;;
+       esac
+
+       exp_sym_flag='-bexport'
+       no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+       case $host_os in aix4.[[012]]|aix4.[[012]].*)
+       # We only want to do this on AIX 4.2 and lower, the check
+       # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" &&
+          strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+         then
+         # We have reworked collect2
+         :
+         else
+         # We have old collect2
+         _LT_TAGVAR(hardcode_direct, $1)=unsupported
+         # It fails to find uninstalled libraries when the uninstalled
+         # path is not listed in the libpath.  Setting hardcode_minus_L
+         # to unsupported forces relinking
+         _LT_TAGVAR(hardcode_minus_L, $1)=yes
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
+         ;;
+       esac
+       shared_flag='-shared'
+       if test "$aix_use_runtimelinking" = yes; then
+         shared_flag="$shared_flag "'${wl}-G'
+       fi
+       _LT_TAGVAR(link_all_deplibs, $1)=no
+      else
+       # not using gcc
+       if test "$host_cpu" = ia64; then
+       # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+       # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+       else
+         if test "$aix_use_runtimelinking" = yes; then
+           shared_flag='${wl}-G'
+         else
+           shared_flag='${wl}-bM:SRE'
+         fi
+       fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+       # Warning - without using the other runtime loading flags (-brtl),
+       # -berok will link without error, but may produce a broken library.
+       _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+       if test "$host_cpu" = ia64; then
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+         _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+         _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+       else
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+         # Warning - without using the other run time loading flags,
+         # -berok will link without error, but may produce a broken library.
+         _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+         _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+         if test "$with_gnu_ld" = yes; then
+           # We only use this code for GNU lds that support --whole-archive.
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+         else
+           # Exported symbols can be pulled into shared objects from archives
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+         fi
+         _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+         # This is similar to how AIX traditionally builds its shared libraries.
+         _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+       fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+       # Native MSVC
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+       _LT_TAGVAR(always_export_symbols, $1)=yes
+       _LT_TAGVAR(file_list_spec, $1)='@'
+       # Tell ltmain to make .lib files, not .a files.
+       libext=lib
+       # Tell ltmain to make .dll files, not .so files.
+       shrext_cmds=".dll"
+       # FIXME: Setting linknames here is a bad hack.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+       _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+           sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+         else
+           sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+         fi~
+         $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+         linknames='
+       # The linker will not automatically build a static lib if we build a DLL.
+       # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+       _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+       _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+       # Don't use ranlib
+       _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+       _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+         lt_tool_outputfile="@TOOL_OUTPUT@"~
+         case $lt_outputfile in
+           *.exe|*.EXE) ;;
+           *)
+             lt_outputfile="$lt_outputfile.exe"
+             lt_tool_outputfile="$lt_tool_outputfile.exe"
+             ;;
+         esac~
+         if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+           $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+           $RM "$lt_outputfile.manifest";
+         fi'
+       ;;
+      *)
+       # Assume MSVC wrapper
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+       _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+       # Tell ltmain to make .lib files, not .a files.
+       libext=lib
+       # Tell ltmain to make .dll files, not .so files.
+       shrext_cmds=".dll"
+       # FIXME: Setting linknames here is a bad hack.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+       # The linker will automatically build a .lib file if we build a DLL.
+       _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+       # FIXME: Should let the user specify the lib program.
+       _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+       ;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+       _LT_TAGVAR(hardcode_direct, $1)=yes
+       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+       # hardcode_minus_L: Not really in the search PATH,
+       # but as the default location of the library.
+       _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+       case $host_cpu in
+       hppa*64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       esac
+      else
+       case $host_cpu in
+       hppa*64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       ia64*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+       m4_if($1, [], [
+         # Older versions of the 11.00 compiler do not understand -b yet
+         # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+         _LT_LINKER_OPTION([if $CC understands -b],
+           _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+           [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+           [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+         [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+         ;;
+       esac
+      fi
+      if test "$with_gnu_ld" = no; then
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+       _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+       case $host_cpu in
+       hppa*64*|ia64*)
+         _LT_TAGVAR(hardcode_direct, $1)=no
+         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+         ;;
+       *)
+         _LT_TAGVAR(hardcode_direct, $1)=yes
+         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+         # hardcode_minus_L: Not really in the search PATH,
+         # but as the default location of the library.
+         _LT_TAGVAR(hardcode_minus_L, $1)=yes
+         ;;
+       esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       # Try to use the -exported_symbol ld option, if it does not
+       # work, assume that -exports_file does not work either and
+       # implicitly export all symbols.
+       # This should be the same for all languages, so no per-tag cache variable.
+       AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+         [lt_cv_irix_exported_symbol],
+         [save_LDFLAGS="$LDFLAGS"
+          LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+          AC_LINK_IFELSE(
+            [AC_LANG_SOURCE(
+               [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+                             [C++], [[int foo (void) { return 0; }]],
+                             [Fortran 77], [[
+      subroutine foo
+      end]],
+                             [Fortran], [[
+      subroutine foo
+      end]])])],
+             [lt_cv_irix_exported_symbol=yes],
+             [lt_cv_irix_exported_symbol=no])
+           LDFLAGS="$save_LDFLAGS"])
+       if test "$lt_cv_irix_exported_symbol" = yes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+       fi
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+       _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+       _LT_TAGVAR(hardcode_direct, $1)=yes
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+       if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+       else
+         case $host_os in
+          openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+            _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+            ;;
+          *)
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+            ;;
+         esac
+       fi
+      else
+       _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)     # as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+       _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+       $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+       # Both c and cxx compiler support -rpath directly
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+       wlarc='${wl}'
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+       case `$CC -V 2>&1` in
+       *"Compilers 5.0"*)
+         wlarc=''
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+         ;;
+       *)
+         wlarc='${wl}'
+         _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+         $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+         ;;
+       esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+       # The compiler driver will combine and reorder linker options,
+       # but understands `-z linker_flag'.  GCC discards it without `$wl',
+       # but is careful enough not to reorder.
+       # Supported since Solaris 2.6 (maybe 2.5.1?)
+       if test "$GCC" = yes; then
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+       else
+         _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+       fi
+       ;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+       # Use $CC to link under sequent, because it throws in some extra .o
+       # files that make .init and .fini sections work.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+       sni)
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+       ;;
+       siemens)
+         ## LD is ld it makes a PLAMLIB
+         ## CC just makes a GrossModule.
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+         _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+       motorola)
+         _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+         _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+       ;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+       _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       runpath_var=LD_RUN_PATH
+       hardcode_runpath_var=yes
+       _LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+       _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+       ;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+       [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+       [$RM conftest*
+       echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+       if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+         soname=conftest
+         lib=conftest
+         libobjs=conftest.$ac_objext
+         deplibs=
+         wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+         pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+         compiler_flags=-v
+         linker_flags=-v
+         verstring=
+         output_objdir=.
+         libname=conftest
+         lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+         _LT_TAGVAR(allow_undefined_flag, $1)=
+         if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+         then
+           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+         else
+           lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+         fi
+         _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+       else
+         cat conftest.err 1>&5
+       fi
+       $RM conftest*
+       ])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+         $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+           for ld_flag in $LDFLAGS; do
+             case $ld_flag in
+             *-brtl*)
+               aix_use_runtimelinking=yes
+               break
+               ;;
+             esac
+           done
+           ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+         collect2name=`${CC} -print-prog-name=collect2`
+         if test -f "$collect2name" &&
+            strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+         then
+           # We have reworked collect2
+           :
+         else
+           # We have old collect2
+           _LT_TAGVAR(hardcode_direct, $1)=unsupported
+           # It fails to find uninstalled libraries when the uninstalled
+           # path is not listed in the libpath.  Setting hardcode_minus_L
+           # to unsupported forces relinking
+           _LT_TAGVAR(hardcode_minus_L, $1)=yes
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=
+         fi
+          esac
+          shared_flag='-shared'
+         if test "$aix_use_runtimelinking" = yes; then
+           shared_flag="$shared_flag "'${wl}-G'
+         fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+         # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+         # chokes on -Wl,-G. The following line is correct:
+         shared_flag='-G'
+          else
+           if test "$aix_use_runtimelinking" = yes; then
+             shared_flag='${wl}-G'
+           else
+             shared_flag='${wl}-bM:SRE'
+           fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+       # export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+           _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+           _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+           # Determine the default libpath from the value encoded in an
+           # empty executable.
+           _LT_SYS_MODULE_PATH_AIX([$1])
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+           # Warning - without using the other run time loading flags,
+           # -berok will link without error, but may produce a broken library.
+           _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+           _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+           if test "$with_gnu_ld" = yes; then
+             # We only use this code for GNU lds that support --whole-archive.
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+           else
+             # Exported symbols can be pulled into shared objects from archives
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+           fi
+           _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+           # This is similar to how AIX traditionally builds its shared
+           # libraries.
+           _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+       if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+         # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+         # support --undefined.  This deserves some investigation.  FIXME
+         _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+       else
+         _LT_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+         # FIXME: insert proper C++ library support
+         _LT_TAGVAR(ld_shlibs, $1)=no
+         ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+       case $GXX,$cc_basename in
+       ,cl* | no,cl*)
+         # Native MSVC
+         # hardcode_libdir_flag_spec is actually meaningless, as there is
+         # no search path for DLLs.
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+         _LT_TAGVAR(always_export_symbols, $1)=yes
+         _LT_TAGVAR(file_list_spec, $1)='@'
+         # Tell ltmain to make .lib files, not .a files.
+         libext=lib
+         # Tell ltmain to make .dll files, not .so files.
+         shrext_cmds=".dll"
+         # FIXME: Setting linknames here is a bad hack.
+         _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+         _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+             $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+           else
+             $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+           fi~
+           $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+           linknames='
+         # The linker will not automatically build a static lib if we build a DLL.
+         # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+         # Don't use ranlib
+         _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+         _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+           lt_tool_outputfile="@TOOL_OUTPUT@"~
+           case $lt_outputfile in
+             *.exe|*.EXE) ;;
+             *)
+               lt_outputfile="$lt_outputfile.exe"
+               lt_tool_outputfile="$lt_tool_outputfile.exe"
+               ;;
+           esac~
+           func_to_tool_file "$lt_outputfile"~
+           if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+             $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+             $RM "$lt_outputfile.manifest";
+           fi'
+         ;;
+       *)
+         # g++
+         # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+         # as there is no search path for DLLs.
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+         _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+         _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+         _LT_TAGVAR(always_export_symbols, $1)=no
+         _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+         if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+           # If the export-symbols file already is a .def file (1st line
+           # is EXPORTS), use it as is; otherwise, prepend...
+           _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+             cp $export_symbols $output_objdir/$soname.def;
+           else
+             echo EXPORTS > $output_objdir/$soname.def;
+             cat $export_symbols >> $output_objdir/$soname.def;
+           fi~
+           $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+         else
+           _LT_TAGVAR(ld_shlibs, $1)=no
+         fi
+         ;;
+       esac
+       ;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+       ;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          ghcx*)
+           # Green Hills C++ Compiler
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+       # switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                            # but as the default
+                                            # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+         _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+             _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+                                                # but as the default
+                                                # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          aCC*)
+           case $host_cpu in
+             hppa*64*)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+               ;;
+             ia64*)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+               ;;
+             *)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+               ;;
+           esac
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+           ;;
+          *)
+           if test "$GXX" = yes; then
+             if test $with_gnu_ld = no; then
+               case $host_cpu in
+                 hppa*64*)
+                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+                   ;;
+                 ia64*)
+                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+                   ;;
+                 *)
+                   _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+                   ;;
+               esac
+             fi
+           else
+             # FIXME: insert proper C++ library support
+             _LT_TAGVAR(ld_shlibs, $1)=no
+           fi
+           ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+       _LT_TAGVAR(hardcode_direct, $1)=no
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+       # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+       # Instead, shared libraries are loaded at an image base (0x10000000 by
+       # default) and relocated if they conflict, which is a slow very memory
+       # consuming and fragmenting process.  To avoid this, we pick a random,
+       # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+       # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+       _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+       _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+       ;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+           # SGI C++
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+           # Archives containing C++ object files must be created using
+           # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+           # necessary to make sure instantiated templates are included
+           # in the archive.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+           ;;
+          *)
+           if test "$GXX" = yes; then
+             if test "$with_gnu_ld" = no; then
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+             else
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+             fi
+           fi
+           _LT_TAGVAR(link_all_deplibs, $1)=yes
+           ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+        case $cc_basename in
+          KCC*)
+           # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+           # KCC will only create a shared library if the output file
+           # ends with ".so" (or ".sl" for HP-UX), so rename the library
+           # to its proper name (with version) after linking.
+           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+           # Archives containing C++ object files must be created using
+           # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+           ;;
+         icpc* | ecpc* )
+           # Intel C++
+           with_gnu_ld=yes
+           # version 8.0 and above of icpc choke on multiply defined symbols
+           # if we add $predep_objects and $postdep_objects, however 7.1 and
+           # earlier do not add the objects themselves.
+           case `$CC -V 2>&1` in
+             *"Version 7."*)
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+               ;;
+             *)  # Version 8.0 or newer
+               tmp_idyn=
+               case $host_cpu in
+                 ia64*) tmp_idyn=' -i_dynamic';;
+               esac
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+               ;;
+           esac
+           _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+           ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+           case `$CC -V` in
+           *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+             _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+             _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+               $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+               $RANLIB $oldlib'
+             _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+             _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+               $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+             ;;
+           *) # Version 6 and above use weak symbols
+             _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+             ;;
+           esac
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+           _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+         cxx*)
+           # Compaq C++
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+           runpath_var=LD_RUN_PATH
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+           ;;
+         xl* | mpixl* | bgxl*)
+           # IBM XL 8.0 on PPC, with GNU ld
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+           _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+           if test "x$supports_anon_versioning" = xyes; then
+             _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+               cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+               echo "local: *; };" >> $output_objdir/$libname.ver~
+               $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+           fi
+           ;;
+         *)
+           case `$CC -V 2>&1 | sed 5q` in
+           *Sun\ C*)
+             # Sun C++ 5.9
+             _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+             _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+             _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+             _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+             _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+             # Not sure whether something based on
+             # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+             # would be better.
+             output_verbose_link_cmd='func_echo_all'
+
+             # Archives containing C++ object files must be created using
+             # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+             # necessary to make sure instantiated templates are included
+             # in the archive.
+             _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+             ;;
+           esac
+           ;;
+       esac
+       ;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       ;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+       ;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+         *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+       esac
+       ;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+         _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+         wlarc=
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+         _LT_TAGVAR(hardcode_direct, $1)=yes
+         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       fi
+       # Workaround some broken pre-1.5 toolchains
+       output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+       ;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+       ;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+       _LT_TAGVAR(ld_shlibs, $1)=no
+       ;;
+
+      openbsd*)
+       if test -f /usr/libexec/ld.so; then
+         _LT_TAGVAR(hardcode_direct, $1)=yes
+         _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+         _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+         _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+         if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+           _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+           _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+         fi
+         output_verbose_link_cmd=func_echo_all
+       else
+         _LT_TAGVAR(ld_shlibs, $1)=no
+       fi
+       ;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+           # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+           # KCC will only create a shared library if the output file
+           # ends with ".so" (or ".sl" for HP-UX), so rename the library
+           # to its proper name (with version) after linking.
+           _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+           # Archives containing C++ object files must be created using
+           # the KAI C++ compiler.
+           case $host in
+             osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+             *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+           esac
+           ;;
+          RCC*)
+           # Rational C++ 2.4.1
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          cxx*)
+           case $host in
+             osf3*)
+               _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+               ;;
+             *)
+               _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+                 echo "-hidden">> $lib.exp~
+                 $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+                 $RM $lib.exp'
+               _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+               ;;
+           esac
+
+           _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+           # Commands to make compiler produce verbose output that lists
+           # what "hidden" libraries, object files and flags are used when
+           # linking a shared library.
+           #
+           # There doesn't appear to be a way to prevent this compiler from
+           # explicitly linking system object files so we need to strip them
+           # from the output so that they don't get included in the library
+           # dependencies.
+           output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+           ;;
+         *)
+           if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+             _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+             case $host in
+               osf3*)
+                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+                 ;;
+               *)
+                 _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+                 ;;
+             esac
+
+             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+             _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+             # Commands to make compiler produce verbose output that lists
+             # what "hidden" libraries, object files and flags are used when
+             # linking a shared library.
+             output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+           else
+             # FIXME: insert proper C++ library support
+             _LT_TAGVAR(ld_shlibs, $1)=no
+           fi
+           ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+           # Sun C++ 4.x
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          lcc*)
+           # Lucid
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+           # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+           _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+           _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+             $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+           _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+           _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+           case $host_os in
+             solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+             *)
+               # The compiler driver will combine and reorder linker options,
+               # but understands `-z linker_flag'.
+               # Supported since Solaris 2.6 (maybe 2.5.1?)
+               _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+               ;;
+           esac
+           _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+           output_verbose_link_cmd='func_echo_all'
+
+           # Archives containing C++ object files must be created using
+           # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+           # necessary to make sure instantiated templates are included
+           # in the archive.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+           ;;
+          gcx*)
+           # Green Hills C++ Compiler
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+           # The C++ compiler must be used to create the archive.
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+           ;;
+          *)
+           # GNU C++ compiler with Solaris linker
+           if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+             _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+             if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+               _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                 $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+               # Commands to make compiler produce verbose output that lists
+               # what "hidden" libraries, object files and flags are used when
+               # linking a shared library.
+               output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+             else
+               # g++ 2.7 appears to require `-G' NOT `-shared' on this
+               # platform.
+               _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+               _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                 $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+               # Commands to make compiler produce verbose output that lists
+               # what "hidden" libraries, object files and flags are used when
+               # linking a shared library.
+               output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+             fi
+
+             _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+             case $host_os in
+               solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+               *)
+                 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+                 ;;
+             esac
+           fi
+           ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+       *)
+         _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+         ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+       # Note: We can NOT use -z defs as we might desire, because we do not
+       # link with -lc, and that would cause any symbols used from libc to
+       # always be unresolved, which means just about no library would
+       # ever link correctly.  If we're not using GNU ld we use -z text
+       # though, which does catch some bad symbols but isn't as heavy-handed
+       # as -z defs.
+       _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+       _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+       _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+       _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+       _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+       _LT_TAGVAR(link_all_deplibs, $1)=yes
+       _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+       runpath_var='LD_RUN_PATH'
+
+       case $cc_basename in
+          CC*)
+           _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+             '"$_LT_TAGVAR(old_archive_cmds, $1)"
+           _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+             '"$_LT_TAGVAR(reload_cmds, $1)"
+           ;;
+         *)
+           _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+           ;;
+       esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+           # NonStop-UX NCC 3.20
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+          *)
+           # FIXME: insert proper C++ library support
+           _LT_TAGVAR(ld_shlibs, $1)=no
+           ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case ${2} in
+  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case ${prev}${p} in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+        prev=$p
+        continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test "$pre_test_object_deps_done" = no; then
+        case ${prev} in
+        -L | -R)
+          # Internal compiler library paths should come after those
+          # provided the user.  The postdeps already come after the
+          # user supplied libs so there is no need to process them.
+          if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+            _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+          else
+            _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+          fi
+          ;;
+        # The "-l" case would never come before the object being
+        # linked, so don't bother handling this case.
+        esac
+       else
+        if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+          _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+        else
+          _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+        fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+        pre_test_object_deps_done=yes
+        continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+        if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+          _LT_TAGVAR(predep_objects, $1)="$p"
+        else
+          _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+        fi
+       else
+        if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+          _LT_TAGVAR(postdep_objects, $1)="$p"
+        else
+          _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+        fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC* | sunCC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+       if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+         test "$enable_shared" = yes && enable_static=no
+       fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+  CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+       if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+         test "$enable_shared" = yes && enable_static=no
+       fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([    ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary parameter first.
+    func_stripname_result=${3}
+    func_stripname_result=${func_stripname_result#"${1}"}
+    func_stripname_result=${func_stripname_result%"${2}"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+    func_split_long_opt_name=${1%%=*}
+    func_split_long_opt_arg=${1#*=}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+    func_split_short_opt_arg=${1#??}
+    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+    case ${1} in
+      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+      *)    func_lo2o_result=${1} ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
+
+  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
+
+  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+    func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
new file mode 100644 (file)
index 0000000..5d9acd8
--- /dev/null
@@ -0,0 +1,384 @@
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+           [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+                     [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+                  [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+       [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_shared=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+       [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+       [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_static=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+       [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_fast_install=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+        [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+       [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+       IFS="$lt_save_ifs"
+       if test "X$lt_pkg" = "X$lt_p"; then
+         pic_mode=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+                [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+                [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+                [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+                [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+                [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
new file mode 100644 (file)
index 0000000..9000a05
--- /dev/null
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+          m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+            [m4_foreach([_Lt_suffix],
+               ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+       [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+         [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+                [lt_append([$1], [$2], [$3])$4],
+                [$5])],
+         [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+       m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+       [$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+                     [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
new file mode 100644 (file)
index 0000000..07a8602
--- /dev/null
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers                      -*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
new file mode 100644 (file)
index 0000000..c573da9
--- /dev/null
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],  [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],             [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],        [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],         [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],    [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],           [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],             [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],    [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],           [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],       [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],               [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],        [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],    [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],    [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],         [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],            [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],  [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],             [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],            [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],    [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],   [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],          [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],            [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],           [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],  [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],    [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],          [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],          [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],                [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],     [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],          [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],   [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],           [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],           [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],           [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],  [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],      [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],    [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],    [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],        [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],    [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],     [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],         [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],       [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],        [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],                [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],        [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],   [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],              [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],               [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],              [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/m4/pkg.m4 b/m4/pkg.m4
new file mode 100644 (file)
index 0000000..0048a3f
--- /dev/null
+++ b/m4/pkg.m4
@@ -0,0 +1,157 @@
+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
+# 
+# Copyright © 2004 Scott James Remnant <scott@netsplit.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 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=m4_default([$1], [0.9.0])
+       AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               AC_MSG_RESULT([yes])
+       else
+               AC_MSG_RESULT([no])
+               PKG_CONFIG=""
+       fi
+               
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists.  Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$PKG_CONFIG"; then
+    if test -n "$$1"; then
+        pkg_cv_[]$1="$$1"
+    else
+        PKG_CHECK_EXISTS([$3],
+                         [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+                        [pkg_failed=yes])
+    fi
+else
+       pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+        else 
+               $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+       ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+               [AC_MSG_RESULT([no])
+                $4])
+elif test $pkg_failed = untried; then
+       ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
+               [$4])
+else
+       $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+       $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+       ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
index cda2d79..692ef33 100644 (file)
@@ -1,17 +1,20 @@
 Name:           harfbuzz
-Summary:        Hindi Reshaping Library
-Version:        0.9.0
+Summary:     Font Reshaping Library
+Version:        0.9.40
 Release:        1
 Group:          TO_BE/FILLED_IN
-License:        TO BE FILLED IN
+License:        MIT
 Source0:        %{name}-%{version}.tar.gz
+#BuildRequires:  pkgconfig(cairo)
 BuildRequires:  pkgconfig(freetype2)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(icu-i18n)
 BuildRequires:  which
 BuildRequires:  ragel
 
 
 %description
-Hindi Reshaping Library
+Font Reshaping Library
 
 
 %package devel
@@ -29,6 +32,8 @@ Development files for %{name}
 
 %build
 %autogen
+export CXXFLAGS+=" -fdata-sections -ffunction-sections -Wl,--gc-sections"
+export CFLAGS+=" -fdata-sections -ffunction-sections -Wl,--gc-sections"
 %configure
 
 make %{?jobs:-j%jobs}
@@ -37,11 +42,18 @@ make %{?jobs:-j%jobs}
 %install
 rm -rf %{buildroot}
 %make_install
+mkdir -p %{buildroot}/usr/share/license
+cp %{_builddir}/%{buildsubdir}/COPYING %{buildroot}/usr/share/license/%{name}
 
 
 %files
 %defattr(-,root,root,-)
 %{_libdir}/lib*.so.*
+#%{_bindir}/hb-ot-shape-closure
+#%{_bindir}/hb-shape
+#%{_bindir}/hb-view
+%manifest %{name}.manifest
+/usr/share/license/%{name}
 
 
 %files devel
index 344cc57..c99967f 100644 (file)
@@ -1,15 +1,21 @@
 # Process this file with automake to produce Makefile.in
 
 NULL =
+SUBDIRS =
+DIST_SUBDIRS =
 BUILT_SOURCES =
 EXTRA_DIST =
 CLEANFILES =
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
+DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 
-# The following warning options are useful for debugging: -Wpadded -Wcast-align
+# The following warning options are useful for debugging: -Wpadded
 #AM_CXXFLAGS =
 
+# Convenience targets:
+lib: libharfbuzz.la
+
 lib_LTLIBRARIES = libharfbuzz.la
 
 HBCFLAGS =
@@ -17,18 +23,22 @@ HBLIBS =
 HBSOURCES =  \
        hb-atomic-private.hh \
        hb-blob.cc \
+       hb-buffer-deserialize-json.hh \
+       hb-buffer-deserialize-text.hh \
        hb-buffer-private.hh \
+       hb-buffer-serialize.cc \
        hb-buffer.cc \
        hb-cache-private.hh \
        hb-common.cc \
-       hb-fallback-shape-private.hh \
-       hb-fallback-shape.cc \
+       hb-face-private.hh \
+       hb-face.cc \
        hb-font-private.hh \
        hb-font.cc \
        hb-mutex-private.hh \
        hb-object-private.hh \
        hb-open-file-private.hh \
        hb-open-type-private.hh \
+       hb-ot-cmap-table.hh \
        hb-ot-head-table.hh \
        hb-ot-hhea-table.hh \
        hb-ot-hmtx-table.hh \
@@ -39,9 +49,15 @@ HBSOURCES =  \
        hb-set-private.hh \
        hb-set.cc \
        hb-shape.cc \
-       hb-tt-font.cc \
+       hb-shape-plan-private.hh \
+       hb-shape-plan.cc \
+       hb-shaper-list.hh \
+       hb-shaper-impl-private.hh \
+       hb-shaper-private.hh \
+       hb-shaper.cc \
        hb-unicode-private.hh \
        hb-unicode.cc \
+       hb-utf-private.hh \
        hb-warning.cc \
        $(NULL)
 HBHEADERS = \
@@ -49,44 +65,74 @@ HBHEADERS = \
        hb-blob.h \
        hb-buffer.h \
        hb-common.h \
+       hb-deprecated.h \
+       hb-face.h \
        hb-font.h \
        hb-set.h \
        hb-shape.h \
+       hb-shape-plan.h \
        hb-unicode.h \
+       $(NULL)
+HBNODISTHEADERS = \
        hb-version.h \
        $(NULL)
 
 if HAVE_OT
 HBSOURCES += \
+       hb-ot-font.cc \
        hb-ot-layout.cc \
        hb-ot-layout-common-private.hh \
        hb-ot-layout-gdef-table.hh \
        hb-ot-layout-gpos-table.hh \
        hb-ot-layout-gsubgpos-private.hh \
        hb-ot-layout-gsub-table.hh \
+       hb-ot-layout-jstf-table.hh \
        hb-ot-layout-private.hh \
        hb-ot-map.cc \
        hb-ot-map-private.hh \
        hb-ot-shape.cc \
        hb-ot-shape-complex-arabic.cc \
+       hb-ot-shape-complex-arabic-fallback.hh \
        hb-ot-shape-complex-arabic-table.hh \
+       hb-ot-shape-complex-arabic-win1256.hh \
+       hb-ot-shape-complex-default.cc \
+       hb-ot-shape-complex-hangul.cc \
+       hb-ot-shape-complex-hebrew.cc \
        hb-ot-shape-complex-indic.cc \
        hb-ot-shape-complex-indic-machine.hh \
        hb-ot-shape-complex-indic-private.hh \
-       hb-ot-shape-complex-indic-table.hh \
-       hb-ot-shape-complex-misc.cc \
+       hb-ot-shape-complex-indic-table.cc \
+       hb-ot-shape-complex-myanmar.cc \
+       hb-ot-shape-complex-myanmar-machine.hh \
+       hb-ot-shape-complex-sea.cc \
+       hb-ot-shape-complex-sea-machine.hh \
+       hb-ot-shape-complex-thai.cc \
+       hb-ot-shape-complex-tibetan.cc \
        hb-ot-shape-complex-private.hh \
        hb-ot-shape-normalize-private.hh \
        hb-ot-shape-normalize.cc \
+       hb-ot-shape-fallback-private.hh \
+       hb-ot-shape-fallback.cc \
        hb-ot-shape-private.hh \
        $(NULL)
 HBHEADERS += \
        hb-ot.h \
+       hb-ot-font.h \
        hb-ot-layout.h \
+       hb-ot-shape.h \
        hb-ot-tag.h \
        $(NULL)
 endif
 
+if HAVE_FALLBACK
+HBSOURCES += hb-fallback-shape.cc
+endif
+
+if HAVE_PTHREAD
+HBCFLAGS += $(PTHREAD_CFLAGS)
+HBLIBS   += $(PTHREAD_LIBS)
+endif
+
 if HAVE_GLIB
 HBCFLAGS += $(GLIB_CFLAGS)
 HBLIBS   += $(GLIB_LIBS)
@@ -94,28 +140,6 @@ HBSOURCES += hb-glib.cc
 HBHEADERS += hb-glib.h
 endif
 
-if HAVE_GOBJECT
-HBCFLAGS += $(GOBJECT_CFLAGS)
-HBLIBS   += $(GOBJECT_LIBS)
-HBSOURCES += hb-gobject-structs.cc
-nodist_HBSOURCES = hb-gobject-enums.cc
-HBHEADERS += hb-gobject.h
-BUILT_SOURCES += hb-gobject-enums.cc
-EXTRA_DIST += hb-gobject-enums.cc.tmpl
-DISTCLEANFILES += hb-gobject-enums.cc
-
-hb-gobject-enums.cc: hb-gobject-enums.cc.tmpl $(HBHEADERS)
-       $(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > "$@.tmp" && \
-       mv "$@.tmp" "$@" || ( $(RM) "@.tmp" && false )
-endif
-
-if HAVE_ICU
-HBCFLAGS += $(ICU_CFLAGS)
-HBLIBS   += $(ICU_LIBS)
-HBSOURCES += hb-icu.cc
-HBHEADERS += hb-icu.h
-endif
-
 if HAVE_FREETYPE
 HBCFLAGS += $(FREETYPE_CFLAGS)
 HBLIBS   += $(FREETYPE_LIBS)
@@ -126,89 +150,258 @@ endif
 if HAVE_GRAPHITE2
 HBCFLAGS += $(GRAPHITE2_CFLAGS)
 HBLIBS   += $(GRAPHITE2_LIBS)
-HBSOURCES += hb-graphite2.cc hb-graphite2-private.hh
+HBSOURCES += hb-graphite2.cc
 HBHEADERS += hb-graphite2.h
 endif
 
 if HAVE_UNISCRIBE
 HBCFLAGS += $(UNISCRIBE_CFLAGS)
 HBLIBS   += $(UNISCRIBE_LIBS)
-HBSOURCES += hb-uniscribe.cc hb-uniscribe-private.hh
+HBSOURCES += hb-uniscribe.cc
 HBHEADERS += hb-uniscribe.h
 endif
 
-# Use a C linker, not C++; Don't link to libstdc++
+if HAVE_CORETEXT
+HBCFLAGS += $(CORETEXT_CFLAGS)
+HBLIBS   += $(CORETEXT_LIBS)
+HBSOURCES += hb-coretext.cc
+HBHEADERS += hb-coretext.h
+endif
+
+if HAVE_UCDN
+SUBDIRS += hb-ucdn
+HBCFLAGS += -I$(srcdir)/hb-ucdn
+HBLIBS   += hb-ucdn/libhb-ucdn.la
+HBSOURCES += hb-ucdn.cc
+endif
+DIST_SUBDIRS += hb-ucdn
+
+
+# Put the library together
+
+if OS_WIN32
+export_symbols = -export-symbols harfbuzz.def
+harfbuzz_def_dependency = harfbuzz.def
+libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
+else
+# Use a C linker for GCC, not C++; Don't link to libstdc++
+if HAVE_GCC
 libharfbuzz_la_LINK = $(LINK) $(libharfbuzz_la_LDFLAGS)
-libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
-nodist_libharfbuzz_la_SOURCES = $(nodist_HBSOURCES)
+else
+libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
+endif
+endif
+
+libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) $(HBNODISTHEADERS)
 libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
-libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
 libharfbuzz_la_LIBADD = $(HBLIBS)
+EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
 pkginclude_HEADERS = $(HBHEADERS)
-nodist_pkginclude_HEADERS = hb-version.h
+nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = harfbuzz.pc
+EXTRA_DIST += harfbuzz.pc.in
+
+if HAVE_ICU
+lib_LTLIBRARIES += libharfbuzz-icu.la
+libharfbuzz_icu_la_SOURCES = hb-icu.cc
+libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
+libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
+pkginclude_HEADERS += hb-icu.h
+pkgconfig_DATA += harfbuzz-icu.pc
+endif
+EXTRA_DIST += harfbuzz-icu.pc.in
+
+if HAVE_GOBJECT
+lib_LTLIBRARIES += libharfbuzz-gobject.la
+libharfbuzz_gobject_la_SOURCES = hb-gobject-structs.cc
+nodist_libharfbuzz_gobject_la_SOURCES = hb-gobject-enums.cc
+libharfbuzz_gobject_la_CPPFLAGS = $(GOBJECT_CFLAGS)
+libharfbuzz_gobject_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
+pkginclude_HEADERS += hb-gobject.h hb-gobject-structs.h
+nodist_pkginclude_HEADERS += hb-gobject-enums.h
+pkgconfig_DATA += harfbuzz-gobject.pc
+
+BUILT_SOURCES += \
+       hb-gobject-enums.cc \
+       hb-gobject-enums.h \
+       $(NULL)
+DISTCLEANFILES += \
+       hb-gobject-enums.cc \
+       hb-gobject-enums.h \
+       $(NULL)
+hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
+       $(AM_V_GEN) $(GLIB_MKENUMS) \
+               --identifier-prefix hb_ --symbol-prefix hb_gobject \
+               --template $^ | \
+       sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
+       || ($(RM) "$@"; false)
+endif
+EXTRA_DIST += \
+       harfbuzz-gobject.pc.in \
+       hb-gobject-enums.cc.tmpl \
+       hb-gobject-enums.h.tmpl \
+       $(NULL)
+
+
+%.pc: %.pc.in $(top_builddir)/config.status
+       $(AM_V_GEN) \
+       $(SED)  -e 's@%prefix%@$(prefix)@g' \
+               -e 's@%exec_prefix%@$(exec_prefix)@g' \
+               -e 's@%libdir%@$(libdir)@g' \
+               -e 's@%includedir%@$(includedir)@g' \
+               -e 's@%VERSION%@$(VERSION)@g' \
+       "$<" > "$@" \
+       || ($(RM) "$@"; false)
+
+CLEANFILES += $(pkgconfig_DATA)
+
+
+CLEANFILES += harfbuzz.def
+harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
+       $(AM_V_GEN) (echo EXPORTS; \
+       (cat $^ || echo 'hb_ERROR ()' ) | \
+       $(EGREP) '^hb_.* \(' | \
+       sed -e 's/ (.*//' | \
+       LANG=C sort; \
+       echo LIBRARY libharfbuzz-$(HB_VERSION_MAJOR).dll; \
+       ) >"$@"
+       @ ! grep -q hb_ERROR "$@" \
+       || ($(RM) "$@"; false)
 
 
 GENERATORS = \
        gen-arabic-table.py \
        gen-indic-table.py \
        $(NULL)
-
 EXTRA_DIST += $(GENERATORS)
 
 unicode-tables: arabic-table indic-table
 
 indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
-       $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.hh.tmp && \
-       mv hb-ot-shape-complex-indic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-indic-table.hh || \
-       ($(RM) hb-ot-shape-complex-indic-table.hh.tmp; false)
+       $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
+       || ($(RM) hb-ot-shape-complex-indic-table.cc; false)
 
-arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
-       $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh.tmp && \
-       mv hb-ot-shape-complex-arabic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-arabic-table.hh || \
-       ($(RM) hb-ot-shape-complex-arabic-table.hh.tmp; false)
+arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
+       $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh \
+       || ($(RM) hb-ot-shape-complex-arabic-table.hh; false)
 
+built-sources: $(BUILT_SOURCES)
 
-.PHONY: unicode-tables arabic-table indic-table
+.PHONY: unicode-tables arabic-table indic-table built-sources
 
-BUILT_SOURCES += hb-ot-shape-complex-indic-machine.hh
-EXTRA_DIST += hb-ot-shape-complex-indic-machine.rl
-hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
-       $(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \
-       mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
+RAGEL_GENERATED = \
+       $(srcdir)/hb-buffer-deserialize-json.hh \
+       $(srcdir)/hb-buffer-deserialize-text.hh \
+       $(srcdir)/hb-ot-shape-complex-indic-machine.hh \
+       $(srcdir)/hb-ot-shape-complex-myanmar-machine.hh \
+       $(srcdir)/hb-ot-shape-complex-sea-machine.hh \
+       $(NULL)
+BUILT_SOURCES += $(RAGEL_GENERATED)
+EXTRA_DIST += \
+       hb-buffer-deserialize-json.rl \
+       hb-buffer-deserialize-text.rl \
+       hb-ot-shape-complex-indic-machine.rl \
+       hb-ot-shape-complex-myanmar-machine.rl \
+       hb-ot-shape-complex-sea-machine.rl \
+       $(NULL)
+MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
+$(srcdir)/%.hh: $(srcdir)/%.rl
+       $(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
+       || ($(RM) "$@"; false)
 
-noinst_PROGRAMS = main indic
+noinst_PROGRAMS = \
+       main \
+       test \
+       test-buffer-serialize \
+       test-size-params \
+       test-would-substitute \
+       $(NULL)
 bin_PROGRAMS =
 
 main_SOURCES = main.cc
 main_CPPFLAGS = $(HBCFLAGS)
 main_LDADD = libharfbuzz.la $(HBLIBS)
 
-indic_SOURCES = indic.cc
-indic_CPPFLAGS = $(HBCFLAGS)
-indic_LDADD = libharfbuzz.la $(HBLIBS)
+test_SOURCES = test.cc
+test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
+test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
+
+test_would_substitute_SOURCES = test-would-substitute.cc
+test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
+test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
+
+test_size_params_SOURCES = test-size-params.cc
+test_size_params_CPPFLAGS = $(HBCFLAGS)
+test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
+
+test_buffer_serialize_SOURCES = test-buffer-serialize.cc
+test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
+test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
 
 dist_check_SCRIPTS = \
        check-c-linkage-decls.sh \
+       check-defs.sh \
        check-header-guards.sh \
-       check-internal-symbols.sh \
        check-includes.sh \
+       check-libstdc++.sh \
+       check-static-inits.sh \
+       check-symbols.sh \
        $(NULL)
 
-if HAVE_ICU
-else
-dist_check_SCRIPTS += check-libstdc++.sh
-endif
-
 TESTS = $(dist_check_SCRIPTS)
 TESTS_ENVIRONMENT = \
        srcdir="$(srcdir)" \
        MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
        HBSOURCES="$(HBSOURCES)" \
-       HBHEADERS="$(HBHEADERS)" \
+       HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \
+       $(NULL)
+
+if HAVE_INTROSPECTION
+
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?!
+INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
+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_CFLAGS = \
+       $(INCLUDES) \
+       $(HBCFLAGS) \
+       -DHB_H \
+       -DHB_H_IN \
+       -DHB_OT_H \
+       -DHB_OT_H_IN \
+       -DHB_GOBJECT_H \
+       -DHB_GOBJECT_H_IN \
+       $(NULL)
+HarfBuzz_0_0_gir_LIBS = \
+       libharfbuzz.la \
+       libharfbuzz-gobject.la \
+       $(NULL)
+HarfBuzz_0_0_gir_FILES = \
+       $(HBHEADERS) \
+       $(HBNODISTHEADERS) \
+       $(HBSOURCES) \
+       hb-gobject-enums.cc \
+       hb-gobject-enums.h \
+       hb-gobject-structs.cc \
+       hb-gobject-structs.h \
        $(NULL)
 
-scan:
-       g-ir-scanner $(HBCFLAGS) $(HBHEADERS) -n hb --strip-prefix=hb --library libharfbuzz.la
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(INTROSPECTION_GIRS)
 
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelib_DATA)
+
+endif
 
 -include $(top_srcdir)/git.mk
index e7c95ab..b10310f 100755 (executable)
@@ -6,13 +6,21 @@ export LC_ALL
 test -z "$srcdir" && srcdir=.
 stat=0
 
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
 
 
 for x in $HBHEADERS; do
        test -f $srcdir/$x && x=$srcdir/$x
        if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then
-               echo "Ouch, file $x does not HB_BEGIN_DECLS / HB_END_DECLS"
+               echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should"
+               stat=1
+       fi
+done
+for x in $HBSOURCES; do
+       test -f $srcdir/$x && x=$srcdir/$x
+       if grep -q HB_BEGIN_DECLS "$x" || grep -q HB_END_DECLS "$x"; then
+               echo "Ouch, file $x has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn't"
                stat=1
        fi
 done
diff --git a/src/check-defs.sh b/src/check-defs.sh
new file mode 100755 (executable)
index 0000000..65a2467
--- /dev/null
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+test -z "$MAKE" && MAKE=make
+stat=0
+
+if which nm 2>/dev/null >/dev/null; then
+       :
+else
+       echo "check-defs.sh: 'nm' not found; skipping test"
+       exit 77
+fi
+
+defs="harfbuzz.def"
+$MAKE $defs > /dev/null
+tested=false
+for def in $defs; do
+       lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
+       so=.libs/lib${lib}.so
+
+       EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
+
+       if test -f "$so"; then
+
+               echo "Checking that $so has the same symbol list as $def"
+               {
+                       echo EXPORTS
+                       echo "$EXPORTED_SYMBOLS"
+                       # cheat: copy the last line from the def file!
+                       tail -n1 "$def"
+               } | diff "$def" - >&2 || stat=1
+
+               tested=true
+       fi
+done
+if ! $tested; then
+       echo "check-defs.sh: libharfbuzz shared library not found; skipping test"
+       exit 77
+fi
+
+exit $stat
index af9fa7f..9a3302c 100755 (executable)
@@ -6,8 +6,8 @@ export LC_ALL
 test -z "$srcdir" && srcdir=.
 stat=0
 
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
 
 
 for x in $HBHEADERS $HBSOURCES; do
index 79323a7..902f235 100755 (executable)
@@ -6,16 +6,14 @@ export LC_ALL
 test -z "$srcdir" && srcdir=.
 stat=0
 
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
-
-
-cd "$srcdir"
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
 
 
 echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
 
 for x in $HBHEADERS; do
+       test -f "$srcdir/$x" && x="$srcdir/$x"
        grep '#.*\<include\>' "$x" /dev/null | head -n 1
 done |
 grep -v '"hb-common[.]h"' |
@@ -28,7 +26,8 @@ grep . >&2 && stat=1
 echo 'Checking that source files #include "hb-*private.hh" first (or none)'
 
 for x in $HBSOURCES; do
-       grep '#.*\<include\>' "$x" /dev/null | head -n 1
+       test -f "$srcdir/$x" && x="$srcdir/$x"
+       grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
 done |
 grep -v '"hb-.*private[.]hh"' |
 grep -v 'hb-private[.]hh:' |
@@ -36,7 +35,10 @@ grep . >&2 && stat=1
 
 
 echo 'Checking that there is no #include <hb.*.h>'
-grep '#.*\<include\>.*<.*hb' $HBHEADERS $HBSOURCES >&2 && stat=1
+for x in $HBHEADERS $HBSOURCES; do
+       test -f "$srcdir/$x" && x="$srcdir/$x"
+       grep '#.*\<include\>.*<.*hb' "$x" /dev/null >&2 && stat=1
+done
 
 
 exit $stat
diff --git a/src/check-internal-symbols.sh b/src/check-internal-symbols.sh
deleted file mode 100755 (executable)
index a24a693..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-stat=0
-
-
-if which nm 2>/dev/null >/dev/null; then
-       :
-else
-       echo "check-internal-symbols.sh: 'nm' not found; skipping test"
-       exit 77
-fi
-
-tested=false
-for suffix in so; do
-       so=.libs/libharfbuzz.$suffix
-       if test -f "$so"; then
-               echo "Checking that we are exposing internal symbols"
-               if nm $so | grep ' T ' | grep -v ' T _fini\>\| T _init\>\| T hb_'; then
-                       echo "Ouch, internal symbols exposed"
-                       stat=1
-               fi
-               tested=true
-       fi
-done
-if ! $tested; then
-       echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
-       exit 77
-fi
-
-exit $stat
index 0521532..27deb42 100755 (executable)
@@ -17,17 +17,17 @@ fi
 tested=false
 for suffix in so dylib; do
        so=.libs/libharfbuzz.$suffix
-       if test -f "$so"; then
-               echo "Checking that we are not linking to libstdc++"
-               if ldd $so | grep 'libstdc[+][+]'; then
-                       echo "Ouch, linked to libstdc++"
-                       stat=1
-               fi
-               tested=true
+       if ! test -f "$so"; then continue; fi
+
+       echo "Checking that we are not linking to libstdc++"
+       if ldd $so | grep 'libstdc[+][+]'; then
+               echo "Ouch, linked to libstdc++"
+               stat=1
        fi
+       tested=true
 done
 if ! $tested; then
-       echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
+       echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"
        exit 77
 fi
 
diff --git a/src/check-static-inits.sh b/src/check-static-inits.sh
new file mode 100755 (executable)
index 0000000..1446fa7
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+stat=0
+
+
+if which objdump 2>/dev/null >/dev/null; then
+       :
+else
+       echo "check-static-inits.sh: 'objdump' not found; skipping test"
+       exit 77
+fi
+
+OBJS=.libs/*.o
+if test "x`echo $OBJS`" = "x$OBJS" 2>/dev/null >/dev/null; then
+       echo "check-static-inits.sh: object files not found; skipping test"
+       exit 77
+fi
+
+echo "Checking that no object file has static initializers"
+for obj in $OBJS; do
+       if objdump -t "$obj" | grep '[.][cd]tors' | grep -v '\<00*\>'; then
+               echo "Ouch, $obj has static initializers/finalizers"
+               stat=1
+       fi
+done
+
+echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff"
+for obj in $OBJS; do
+       if objdump -t "$obj" | grep '__cxa_'; then
+               echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff"
+               stat=1
+       fi
+done
+
+exit $stat
diff --git a/src/check-symbols.sh b/src/check-symbols.sh
new file mode 100755 (executable)
index 0000000..b2bf43f
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+stat=0
+
+
+if which nm 2>/dev/null >/dev/null; then
+       :
+else
+       echo "check-symbols.sh: 'nm' not found; skipping test"
+       exit 77
+fi
+
+echo "Checking that we are not exposing internal symbols"
+tested=false
+for suffix in so dylib; do
+       so=.libs/libharfbuzz.$suffix
+       if ! test -f "$so"; then continue; fi
+       
+       EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
+
+       prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
+
+       # On mac, C symbols are prefixed with _
+       if test $suffix = dylib; then prefix="_$prefix"; fi
+
+       echo "Processing $so"
+       if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}_"; then
+               echo "Ouch, internal symbols exposed"
+               stat=1
+       fi
+
+       tested=true
+done
+if ! $tested; then
+       echo "check-symbols.sh: no shared library found; skipping test"
+       exit 77
+fi
+
+exit $stat
index 2d3c881..308435f 100755 (executable)
@@ -3,34 +3,48 @@
 import sys
 import os.path
 
-if len (sys.argv) != 3:
-       print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt"
+if len (sys.argv) != 4:
+       print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
        sys.exit (1)
 
 files = [file (x) for x in sys.argv[1:]]
 
-headers = [[files[0].readline (), files[0].readline ()]]
+headers = [[files[0].readline (), files[0].readline ()], [files[2].readline (), files[2].readline ()]]
 headers.append (["UnicodeData.txt does not have a header."])
 while files[0].readline ().find ('##################') < 0:
        pass
 
+blocks = {}
+def read_blocks(f):
+       global blocks
+       for line in f:
 
-def print_joining_table(f):
+               j = line.find ('#')
+               if j >= 0:
+                       line = line[:j]
 
-       print
-       print "static const uint8_t joining_table[] ="
-       print "{"
+               fields = [x.strip () for x in line.split (';')]
+               if len (fields) == 1:
+                       continue
+
+               uu = fields[0].split ('..')
+               start = int (uu[0], 16)
+               if len (uu) == 1:
+                       end = start
+               else:
+                       end = int (uu[1], 16)
+
+               t = fields[1]
+
+               for u in range (start, end + 1):
+                       blocks[u] = t
+
+def print_joining_table(f):
 
-       min_u = 0x110000
-       max_u = 0
-       num = 0
-       last = -1
-       block = ''
+       values = {}
        for line in f:
 
                if line[0] == '#':
-                       if line.find (" characters"):
-                               block = line[2:].strip ()
                        continue
 
                fields = [x.strip () for x in line.split (';')]
@@ -38,43 +52,100 @@ def print_joining_table(f):
                        continue
 
                u = int (fields[0], 16)
-               if u == 0x200C or u == 0x200D:
-                       continue
-               if u < last:
-                       raise Exception ("Input data character not sorted", u)
-               min_u = min (min_u, u)
-               max_u = max (max_u, u)
-               num += 1
-
-               if block:
-                       print "\n  /* %s */\n" % block
-                       block = ''
-
-               if last != -1:
-                       last += 1
-                       while last < u:
-                               print "  JOINING_TYPE_X, /* %04X */" % last
-                               last += 1
-               else:
-                       last = u
 
                if fields[3] in ["ALAPH", "DALATH RISH"]:
                        value = "JOINING_GROUP_" + fields[3].replace(' ', '_')
                else:
                        value = "JOINING_TYPE_" + fields[2]
-               print "  %s, /* %s */" % (value, '; '.join(fields))
+               values[u] = value
+
+       short_value = {}
+       for value in set([v for v in values.values()] + ['JOINING_TYPE_X']):
+               short = ''.join(x[0] for x in value.split('_')[2:])
+               assert short not in short_value.values()
+               short_value[value] = short
 
        print
-       print "};"
+       for value,short in short_value.items():
+               print "#define %s       %s" % (short, value)
+
+       uu = sorted(values.keys())
+       num = len(values)
+       all_blocks = set([blocks[u] for u in uu])
+
+       last = -100000
+       ranges = []
+       for u in uu:
+               if u - last <= 1+16*5:
+                       ranges[-1][-1] = u
+               else:
+                       ranges.append([u,u])
+               last = u
+
        print
-       print "#define JOINING_TABLE_FIRST      0x%04X" % min_u
-       print "#define JOINING_TABLE_LAST       0x%04X" % max_u
+       print "static const uint8_t joining_table[] ="
+       print "{"
+       last_block = None
+       offset = 0
+       for start,end in ranges:
+
+               print
+               print "#define joining_offset_0x%04xu %d" % (start, offset)
+
+               for u in range(start, end+1):
+
+                       block = blocks.get(u, last_block)
+                       value = values.get(u, "JOINING_TYPE_X")
+
+                       if block != last_block or u == start:
+                               if u != start:
+                                       print
+                               if block in all_blocks:
+                                       print "\n  /* %s */" % block
+                               else:
+                                       print "\n  /* FILLER */"
+                               last_block = block
+                               if u % 32 != 0:
+                                       print
+                                       print "  /* %04X */" % (u//32*32), "  " * (u % 32),
+
+                       if u % 32 == 0:
+                               print
+                               print "  /* %04X */ " % u,
+                       sys.stdout.write("%s," % short_value[value])
+               print
+
+               offset += end - start + 1
+       print
+       occupancy = num * 100. / offset
+       print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
        print
 
-       occupancy = num * 100 / (max_u - min_u + 1)
-       # Maintain at least 40% occupancy in the table */
-       if occupancy < 40:
-               raise Exception ("Table too sparse, please investigate: ", occupancy)
+       page_bits = 12;
+       print
+       print "static unsigned int"
+       print "joining_type (hb_codepoint_t u)"
+       print "{"
+       print "  switch (u >> %d)" % page_bits
+       print "  {"
+       pages = set([u>>page_bits for u in [s for s,e in ranges]+[e for s,e in ranges]])
+       for p in sorted(pages):
+               print "    case 0x%0Xu:" % p
+               for (start,end) in ranges:
+                       if p not in [start>>page_bits, end>>page_bits]: continue
+                       offset = "joining_offset_0x%04xu" % start
+                       print "      if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
+               print "      break;"
+               print ""
+       print "    default:"
+       print "      break;"
+       print "  }"
+       print "  return X;"
+       print "}"
+       print
+       for value,short in short_value.items():
+               print "#undef %s" % (short)
+       print
 
 def print_shaping_table(f):
 
@@ -122,15 +193,15 @@ def print_shaping_table(f):
        keys = shapes.keys ()
        min_u, max_u = min (keys), max (keys)
        for u in range (min_u, max_u + 1):
-               s = [shapes[u][shape] if u in shapes and shape in shapes[u] else u
+               s = [shapes[u][shape] if u in shapes and shape in shapes[u] else 0
                     for shape in  ['initial', 'medial', 'final', 'isolated']]
-               value = ', '.join ("0x%04X" % c for c in s)
+               value = ', '.join ("0x%04Xu" % c for c in s)
                print "  {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else "")
 
        print "};"
        print
-       print "#define SHAPING_TABLE_FIRST      0x%04X" % min_u
-       print "#define SHAPING_TABLE_LAST       0x%04X" % max_u
+       print "#define SHAPING_TABLE_FIRST      0x%04Xu" % min_u
+       print "#define SHAPING_TABLE_LAST       0x%04Xu" % max_u
        print
 
        ligas = {}
@@ -148,9 +219,9 @@ def print_shaping_table(f):
                        ligas[liga[0]].append ((liga[1], c))
        max_i = max (len (ligas[l]) for l in ligas)
        print
-       print "static const struct {"
+       print "static const struct ligature_set_t {"
        print " uint16_t first;"
-       print " struct {"
+       print " struct ligature_pairs_t {"
        print "   uint16_t second;"
        print "   uint16_t ligature;"
        print " } ligatures[%d];" % max_i
@@ -160,9 +231,9 @@ def print_shaping_table(f):
        keys.sort ()
        for first in keys:
 
-               print "  { 0x%04X, {" % (first)
+               print "  { 0x%04Xu, {" % (first)
                for liga in ligas[first]:
-                       print "    { 0x%04X, 0x%04X }, /* %s */" % (liga[0], liga[1], names[liga[1]])
+                       print "    { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]])
                print "  }},"
 
        print "};"
@@ -174,7 +245,7 @@ print "/* == Start of generated table == */"
 print "/*"
 print " * The following table is generated by running:"
 print " *"
-print " *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt"
+print " *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
 print " *"
 print " * on files with these headers:"
 print " *"
@@ -187,6 +258,7 @@ print "#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
 print "#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
 print
 
+read_blocks (files[2])
 print_joining_table (files[0])
 print_shaping_table (files[1])
 
index 94aa2ab..f5716bd 100755 (executable)
@@ -6,11 +6,12 @@ if len (sys.argv) != 4:
        print >>sys.stderr, "usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt"
        sys.exit (1)
 
+BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
+
 files = [file (x) for x in sys.argv[1:]]
 
 headers = [[f.readline () for i in range (2)] for f in files]
 
-blocks = {}
 data = [{} for f in files]
 values = [{} for f in files]
 for i, f in enumerate (files):
@@ -35,10 +36,7 @@ for i, f in enumerate (files):
 
                for u in range (start, end + 1):
                        data[i][u] = t
-               values[i][t] = values[i].get (t, 0) + 1
-
-               if i == 2:
-                       blocks[t] = (start, end)
+               values[i][t] = values[i].get (t, 0) + end - start + 1
 
 # Merge data into one dict:
 defaults = ('Other', 'Not_Applicable', 'No_Block')
@@ -52,10 +50,15 @@ for i,d in enumerate (data):
                if not u in combined:
                        combined[u] = list (defaults)
                combined[u][i] = v
+combined = {k:v for k,v in combined.items() if v[2] not in BLACKLISTED_BLOCKS}
 data = combined
 del combined
 num = len (data)
 
+for u in [0x17CD, 0x17CE, 0x17CF, 0x17D0, 0x17D3]:
+       if data[u][0] == 'Other':
+               data[u][0] = "Vowel_Dependent"
+
 # Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
 singles = {}
 for u in [0x00A0, 0x25CC]:
@@ -75,13 +78,16 @@ for h in headers:
                print " * %s" % (l.strip())
 print " */"
 print
-print "#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH"
-print "#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH"
+print '#include "hb-ot-shape-complex-indic-private.hh"'
 print
 
 # Shorten values
 short = [{
        "Bindu":                'Bi',
+       "Cantillation_Mark":    'Ca',
+       "Joiner":               'ZWJ',
+       "Non_Joiner":           'ZWNJ',
+       "Number":               'Nd',
        "Visarga":              'Vs',
        "Vowel":                'Vo',
        "Vowel_Dependent":      'M',
@@ -89,14 +95,14 @@ short = [{
 },{
        "Not_Applicable":       'x',
 }]
-all_shorts = [[],[]]
+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].append (s)
+               all_shorts[i][s] = v
 
 what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
 what_short = ["ISC", "IMC"]
@@ -111,8 +117,8 @@ for i in range (2):
                else:
                        s = ''.join ([c for c in v_no_and if ord ('A') <= ord (c) <= ord ('Z')])
                        if s in all_shorts[i]:
-                               raise Exception ("Duplicate short value alias", v, s)
-                       all_shorts[i].append (s)
+                               raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
+                       all_shorts[i][s] = v
                        short[i][v] = s
                print "#define %s_%s    %s_%s   %s/* %3d chars; %s */" % \
                        (what_short[i], s, what[i], v.upper (), \
@@ -125,11 +131,16 @@ print
 
 total = 0
 used = 0
+last_block = None
 def print_block (block, start, end, data):
-       print
-       print
-       print "  /* %s  (%04X..%04X) */" % (block, start, end)
+       global total, used, last_block
+       if block and block != last_block:
+               print
+               print
+               print "  /* %s */" % block
        num = 0
+       assert start % 8 == 0
+       assert (end+1) % 8 == 0
        for u in range (start, end+1):
                if u % 8 == 0:
                        print
@@ -139,14 +150,15 @@ def print_block (block, start, end, data):
                d = data.get (u, defaults)
                sys.stdout.write ("%9s" % ("_(%s,%s)," % (short[0][d[0]], short[1][d[1]])))
 
-       global total, used
        total += end - start + 1
        used += num
+       if block:
+               last_block = block
 
 uu = data.keys ()
 uu.sort ()
 
-last = -1
+last = -100000
 num = 0
 offset = 0
 starts = []
@@ -156,11 +168,16 @@ for u in uu:
        if u <= last:
                continue
        block = data[u][2]
-       (start, end) = blocks[block]
+
+       start = u//8*8
+       end = start+1
+       while end in uu and block == data[end][2]:
+               end += 1
+       end = (end-1)//8*8 + 7
 
        if start != last + 1:
-               if start - last <= 33:
-                       print_block ("FILLER", last+1, start-1, data)
+               if start - last <= 1+16*3:
+                       print_block (None, last+1, start-1, data)
                        last = start-1
                else:
                        if last >= 0:
@@ -168,7 +185,7 @@ for u in uu:
                                offset += ends[-1] - starts[-1]
                        print
                        print
-                       print "#define indic_offset_0x%04x %d" % (start, offset)
+                       print "#define indic_offset_0x%04xu %d" % (start, offset)
                        starts.append (start)
 
        print_block (block, start, end, data)
@@ -177,19 +194,30 @@ ends.append (last + 1)
 offset += ends[-1] - starts[-1]
 print
 print
-print "#define indic_offset_total %d" % offset
-print
 occupancy = used * 100. / total
-print "}; /* Table occupancy: %d%% */" % occupancy
+page_bits = 12
+print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
 print
-print "static INDIC_TABLE_ELEMENT_TYPE"
-print "get_indic_categories (hb_codepoint_t u)"
+print "INDIC_TABLE_ELEMENT_TYPE"
+print "hb_indic_get_categories (hb_codepoint_t u)"
 print "{"
-for (start,end) in zip (starts, ends):
-       offset = "indic_offset_0x%04x" % start
-       print "  if (0x%04X <= u && u <= 0x%04X) return indic_table[u - 0x%04X + %s];" % (start, end, start, offset)
-for u,d in singles.items ():
-       print "  if (unlikely (u == 0x%04X)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
+print "  switch (u >> %d)" % page_bits
+print "  {"
+pages = set([u>>page_bits for u in starts+ends+singles.keys()])
+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 = "indic_offset_0x%04xu" % start
+               print "      if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
+       for u,d in singles.items ():
+               if p != u>>page_bits: continue
+               print "      if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
+       print "      break;"
+       print ""
+print "    default:"
+print "      break;"
+print "  }"
 print "  return _(x,x);"
 print "}"
 print
@@ -202,8 +230,6 @@ for i in range (2):
                print "#undef %s_%s" % \
                        (what_short[i], short[i][v])
 print
-print "#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */"
-print
 print "/* == End of generated table == */"
 
 # Maintain at least 30% occupancy in the table */
diff --git a/src/harfbuzz-gobject.pc.in b/src/harfbuzz-gobject.pc.in
new file mode 100644 (file)
index 0000000..7008360
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library GObject integration
+Version: %VERSION%
+
+Requires: harfbuzz gobject-2.0 glib-2.0
+Libs: -L${libdir} -lharfbuzz-gobject
+Cflags: -I${includedir}/harfbuzz
diff --git a/src/harfbuzz-icu.pc.in b/src/harfbuzz-icu.pc.in
new file mode 100644 (file)
index 0000000..949869a
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library ICU integration
+Version: %VERSION%
+
+Requires: harfbuzz
+Requires.private: icu-uc
+Libs: -L${libdir} -lharfbuzz-icu
+Cflags: -I${includedir}/harfbuzz
diff --git a/src/harfbuzz.pc.in b/src/harfbuzz.pc.in
new file mode 100644 (file)
index 0000000..7f27bbb
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library
+Version: %VERSION%
+
+Libs: -L${libdir} -lharfbuzz
+Cflags: -I${includedir}/harfbuzz
index c543a8d..e6738b7 100644 (file)
 #if 0
 
 
-#elif !defined(HB_NO_MT) && defined(_MSC_VER) && _MSC_VER >= 1600
+#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
 
-#include <intrin.h>
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchangePointer)
+#include <windows.h>
 
-typedef long hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V)       _InterlockedExchangeAdd (&(AI), (V))
+/* MinGW has a convoluted history of supporting MemoryBarrier
+ * properly.  As such, define a function to wrap the whole
+ * thing. */
+static inline void _HBMemoryBarrier (void) {
+#if !defined(MemoryBarrier)
+  long dummy = 0;
+  InterlockedExchange (&dummy, 1);
+#else
+  MemoryBarrier ();
+#endif
+}
 
-#define hb_atomic_ptr_get(P)           (MemoryBarrier (), (void *) *(P))
-#define hb_atomic_ptr_cmpexch(P,O,N)   (_InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
+typedef LONG hb_atomic_int_t;
+#define hb_atomic_int_add(AI, V)       InterlockedExchangeAdd (&(AI), (V))
+
+#define hb_atomic_ptr_get(P)           (_HBMemoryBarrier (), (void *) *(P))
+#define hb_atomic_ptr_cmpexch(P,O,N)   (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
 
 
 #elif !defined(HB_NO_MT) && defined(__APPLE__)
 
 #include <libkern/OSAtomic.h>
+#ifdef __MAC_OS_X_MIN_REQUIRED
+#include <AvailabilityMacros.h>
+#elif defined(__IPHONE_OS_MIN_REQUIRED)
+#include <Availability.h>
+#endif
 
 typedef int32_t hb_atomic_int_t;
 #define hb_atomic_int_add(AI, V)       (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
 
 #define hb_atomic_ptr_get(P)           (OSMemoryBarrier (), (void *) *(P))
+#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
 #define hb_atomic_ptr_cmpexch(P,O,N)   OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+#else
+#if __ppc64__ || __x86_64__ || __aarch64__
+#define hb_atomic_ptr_cmpexch(P,O,N)    OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
+#else
+#define hb_atomic_ptr_cmpexch(P,O,N)    OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
+#endif
+#endif
 
 
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) && !defined(__MINGW32__)
+#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 typedef int hb_atomic_int_t;
 #define hb_atomic_int_add(AI, V)       __sync_fetch_and_add (&(AI), (V))
@@ -73,18 +97,17 @@ typedef int hb_atomic_int_t;
 #define hb_atomic_ptr_get(P)           (void *) (__sync_synchronize (), *(P))
 #define hb_atomic_ptr_cmpexch(P,O,N)   __sync_bool_compare_and_swap ((P), (O), (N))
 
-#elif !defined(HB_NO_MT) && defined(HAVE_GLIB)
 
-#include <glib.h>
-typedef int hb_atomic_int_t;
-#if GLIB_CHECK_VERSION(2,29,5)
-#define hb_atomic_int_add(AI, V)       g_atomic_int_add (&(AI), (V))
-#else
-#define hb_atomic_int_add(AI, V)       g_atomic_int_exchange_and_add (&(AI), (V))
-#endif
+#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
+
+#include <atomic.h>
+#include <mbarrier.h>
+
+typedef unsigned int hb_atomic_int_t;
+#define hb_atomic_int_add(AI, V)       ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
 
-#define hb_atomic_ptr_get(P)           g_atomic_pointer_get (P)
-#define hb_atomic_ptr_cmpexch(P,O,N)   g_atomic_pointer_compare_and_exchange ((void **) (P), (void *) (O), (void *) (N))
+#define hb_atomic_ptr_get(P)           ( ({__machine_rw_barrier ();}), (void *) *(P))
+#define hb_atomic_ptr_cmpexch(P,O,N)   ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
 
 
 #elif !defined(HB_NO_MT)
index 3cc2d9d..8759a25 100644 (file)
  * Red Hat Author(s): Behdad Esfahbod
  */
 
+/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199309L
+#endif
+
 #include "hb-private.hh"
 
-#include "hb-blob.h"
 #include "hb-object-private.hh"
 
 #ifdef HAVE_SYS_MMAN_H
@@ -46,7 +50,7 @@
 #endif
 
 
-struct _hb_blob_t {
+struct hb_blob_t {
   hb_object_header_t header;
   ASSERT_POD ();
 
@@ -73,6 +77,22 @@ _hb_blob_destroy_user_data (hb_blob_t *blob)
   }
 }
 
+/**
+ * hb_blob_create: (skip)
+ * @data: Pointer to blob data.
+ * @length: Length of @data in bytes.
+ * @mode: Memory mode for @data.
+ * @user_data: Data parameter to pass to @destroy.
+ * @destroy: Callback to call when @data is not needed anymore.
+ *
+ * Creates a new "blob" object wrapping @data.  The @mode parameter is used
+ * to negotiate ownership and lifecycle of @data.
+ *
+ * Return value: New blob, or the empty blob if something failed or if @length is
+ * zero.  Destroy with hb_blob_destroy().
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_create (const char        *data,
                unsigned int       length,
@@ -82,7 +102,10 @@ hb_blob_create (const char        *data,
 {
   hb_blob_t *blob;
 
-  if (!length || !(blob = hb_object_create<hb_blob_t> ())) {
+  if (!length ||
+      length >= 1u << 31 ||
+      data + length < data /* overflows */ ||
+      !(blob = hb_object_create<hb_blob_t> ())) {
     if (destroy)
       destroy (user_data);
     return hb_blob_get_empty ();
@@ -106,6 +129,26 @@ hb_blob_create (const char        *data,
   return blob;
 }
 
+/**
+ * hb_blob_create_sub_blob:
+ * @parent: Parent blob.
+ * @offset: Start offset of sub-blob within @parent, in bytes.
+ * @length: Length of sub-blob.
+ *
+ * Returns a blob that represents a range of bytes in @parent.  The new
+ * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
+ * will never modify data in the parent blob.  The parent data is not
+ * expected to be modified, and will result in undefined behavior if it
+ * is.
+ *
+ * Makes @parent immutable.
+ *
+ * Return value: New blob, or the empty blob if something failed or if
+ * @length is zero or @offset is beyond the end of @parent's data.  Destroy
+ * with hb_blob_destroy().
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_create_sub_blob (hb_blob_t    *parent,
                         unsigned int  offset,
@@ -120,13 +163,24 @@ hb_blob_create_sub_blob (hb_blob_t    *parent,
 
   blob = hb_blob_create (parent->data + offset,
                         MIN (length, parent->length - offset),
-                        parent->mode,
+                        HB_MEMORY_MODE_READONLY,
                         hb_blob_reference (parent),
                         (hb_destroy_func_t) hb_blob_destroy);
 
   return blob;
 }
 
+/**
+ * hb_blob_get_empty:
+ *
+ * Returns the singleton empty blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: (transfer full): the empty blob.
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_get_empty (void)
 {
@@ -146,12 +200,36 @@ hb_blob_get_empty (void)
   return const_cast<hb_blob_t *> (&_hb_blob_nil);
 }
 
+/**
+ * hb_blob_reference: (skip)
+ * @blob: a blob.
+ *
+ * Increases the reference count on @blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: @blob.
+ *
+ * Since: 1.0
+ **/
 hb_blob_t *
 hb_blob_reference (hb_blob_t *blob)
 {
   return hb_object_reference (blob);
 }
 
+/**
+ * hb_blob_destroy: (skip)
+ * @blob: a blob.
+ *
+ * Descreases the reference count on @blob, and if it reaches zero, destroys
+ * @blob, freeing all memory, possibly calling the destroy-callback the blob
+ * was created for if it has not been called already.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Since: 1.0
+ **/
 void
 hb_blob_destroy (hb_blob_t *blob)
 {
@@ -162,6 +240,18 @@ hb_blob_destroy (hb_blob_t *blob)
   free (blob);
 }
 
+/**
+ * hb_blob_set_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to set.
+ * @data: data to set.
+ * @destroy: callback to call when @data is not needed anymore.
+ * @replace: whether to replace an existing data with the same key.
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_blob_set_user_data (hb_blob_t          *blob,
                       hb_user_data_key_t *key,
@@ -172,6 +262,17 @@ hb_blob_set_user_data (hb_blob_t          *blob,
   return hb_object_set_user_data (blob, key, data, destroy, replace);
 }
 
+/**
+ * hb_blob_get_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to get.
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_blob_get_user_data (hb_blob_t          *blob,
                       hb_user_data_key_t *key)
@@ -180,6 +281,14 @@ hb_blob_get_user_data (hb_blob_t          *blob,
 }
 
 
+/**
+ * hb_blob_make_immutable:
+ * @blob: a blob.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_blob_make_immutable (hb_blob_t *blob)
 {
@@ -189,6 +298,16 @@ hb_blob_make_immutable (hb_blob_t *blob)
   blob->immutable = true;
 }
 
+/**
+ * hb_blob_is_immutable:
+ * @blob: a blob.
+ *
+ * 
+ *
+ * Return value: TODO
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_blob_is_immutable (hb_blob_t *blob)
 {
@@ -196,12 +315,33 @@ hb_blob_is_immutable (hb_blob_t *blob)
 }
 
 
+/**
+ * hb_blob_get_length:
+ * @blob: a blob.
+ *
+ * 
+ *
+ * Return value: the length of blob data in bytes.
+ *
+ * Since: 1.0
+ **/
 unsigned int
 hb_blob_get_length (hb_blob_t *blob)
 {
   return blob->length;
 }
 
+/**
+ * hb_blob_get_data:
+ * @blob: a blob.
+ * @length: (out):
+ *
+ * 
+ *
+ * Returns: (transfer none) (array length=length): 
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
 {
@@ -211,6 +351,22 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
   return blob->data;
 }
 
+/**
+ * hb_blob_get_data_writable:
+ * @blob: a blob.
+ * @length: (out): output length of the writable data.
+ *
+ * Tries to make blob data writable (possibly copying it) and
+ * return pointer to data.
+ *
+ * Fails if blob has been made immutable, or if memory allocation
+ * fails.
+ *
+ * Returns: (transfer none) (array length=length): Writable blob data,
+ * or %NULL if failed.
+ *
+ * Since: 1.0
+ **/
 char *
 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
 {
@@ -321,5 +477,3 @@ _try_writable (hb_blob_t *blob)
 
   return true;
 }
-
-
index 360310b..b2419ab 100644 (file)
 HB_BEGIN_DECLS
 
 
+/*
+ * Note re various memory-modes:
+ *
+ * - In no case shall the HarfBuzz client modify memory
+ *   that is passed to HarfBuzz in a blob.  If there is
+ *   any such possibility, MODE_DUPLICATE should be used
+ *   such that HarfBuzz makes a copy immediately,
+ *
+ * - Use MODE_READONLY otherse, unless you really really
+ *   really know what you are doing,
+ *
+ * - MODE_WRITABLE is appropriate if you really made a
+ *   copy of data solely for the purpose of passing to
+ *   HarfBuzz and doing that just once (no reuse!),
+ *
+ * - If the font is mmap()ed, it's ok to use
+ *   READONLY_MAY_MAKE_WRITABLE, however, using that mode
+ *   correctly is very tricky.  Use MODE_READONLY instead.
+ */
 typedef enum {
   HB_MEMORY_MODE_DUPLICATE,
   HB_MEMORY_MODE_READONLY,
@@ -43,7 +62,7 @@ typedef enum {
   HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
 } hb_memory_mode_t;
 
-typedef struct _hb_blob_t hb_blob_t;
+typedef struct hb_blob_t hb_blob_t;
 
 hb_blob_t *
 hb_blob_create (const char        *data,
@@ -52,6 +71,12 @@ hb_blob_create (const char        *data,
                void              *user_data,
                hb_destroy_func_t  destroy);
 
+/* Always creates with MEMORY_MODE_READONLY.
+ * Even if the parent blob is writable, we don't
+ * want the user of the sub-blob to be able to
+ * modify the parent data as that data may be
+ * shared among multiple sub-blobs.
+ */
 hb_blob_t *
 hb_blob_create_sub_blob (hb_blob_t    *parent,
                         unsigned int  offset,
diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl
new file mode 100644 (file)
index 0000000..91b350f
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * 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
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
+#define HB_BUFFER_DESERIALIZE_JSON_HH
+
+#include "hb-private.hh"
+
+%%{
+
+machine deserialize_json;
+alphtype unsigned char;
+write data;
+
+action clear_item {
+       memset (&info, 0, sizeof (info));
+       memset (&pos , 0, sizeof (pos ));
+}
+
+action add_item {
+       buffer->add_info (info);
+       if (buffer->in_error)
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+
+action tok {
+       tok = p;
+}
+
+action parse_glyph {
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &info.codepoint))
+         return false;
+}
+
+action parse_gid       { 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; }
+
+unum   = '0' | [1-9] digit*;
+num    = '-'? unum;
+
+comma = space* ',' space*;
+colon = space* ':' space*;
+
+glyph_id = unum;
+glyph_name = alpha (alnum|'_'|'.'|'-')*;
+
+glyph_string   = '"' (glyph_name >tok %parse_glyph) '"';
+glyph_number = (glyph_id >tok %parse_gid);
+
+glyph  = "\"g\""  colon (glyph_string | glyph_number);
+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);
+
+element = glyph | cluster | xoffset | yoffset | xadvance | yadvance;
+item   =
+       ( '{' space* element (comma element)* space* '}')
+       >clear_item
+       @add_item
+       ;
+
+main := space* item (comma item)* space* (','|']')?;
+
+}%%
+
+static hb_bool_t
+_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
+                                   const char *buf,
+                                   unsigned int buf_len,
+                                   const char **end_ptr,
+                                   hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len;
+
+  /* Ensure we have positions. */
+  (void) hb_buffer_get_glyph_positions (buffer, NULL);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? ',' : '['))
+  {
+    *end_ptr = ++p;
+  }
+
+  const char *tok = NULL;
+  int cs;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
+  %%{
+    write init;
+    write exec;
+  }%%
+
+  *end_ptr = p;
+
+  return p == pe && *(p-1) != ']';
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl
new file mode 100644 (file)
index 0000000..8a682f7
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_HH
+
+#include "hb-private.hh"
+
+%%{
+
+machine deserialize_text;
+alphtype unsigned char;
+write data;
+
+action clear_item {
+       memset (&info, 0, sizeof (info));
+       memset (&pos , 0, sizeof (pos ));
+}
+
+action add_item {
+       buffer->add_info (info);
+       if (buffer->in_error)
+         return false;
+       buffer->pos[buffer->len - 1] = pos;
+       *end_ptr = p;
+}
+
+action tok {
+       tok = p;
+}
+
+action parse_glyph {
+       if (!hb_font_glyph_from_string (font,
+                                       tok, p - tok,
+                                       &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; }
+
+unum   = '0' | [1-9] digit*;
+num    = '-'? unum;
+
+glyph_id = unum;
+glyph_name = alpha (alnum|'_'|'.'|'-')*;
+
+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))?;
+item   =
+       (
+               glyph
+               cluster?
+               offsets?
+               advances?
+       )
+       >clear_item
+       %add_item
+       ;
+
+main := space* item (space* '|' space* item)* space* ('|'|']')?;
+
+}%%
+
+static hb_bool_t
+_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
+                                   const char *buf,
+                                   unsigned int buf_len,
+                                   const char **end_ptr,
+                                   hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len;
+
+  /* Ensure we have positions. */
+  (void) hb_buffer_get_glyph_positions (buffer, NULL);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? '|' : '['))
+  {
+    *end_ptr = ++p;
+  }
+
+  const char *eof = pe, *tok = NULL;
+  int cs;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
+  %%{
+    write init;
+    write exec;
+  }%%
+
+  *end_ptr = p;
+
+  return p == pe && *(p-1) != ']';
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */
index b539f26..069f925 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright © 1998-2004  David Turner and Werner Lemberg
  * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 #define HB_BUFFER_PRIVATE_HH
 
 #include "hb-private.hh"
-#include "hb-buffer.h"
 #include "hb-object-private.hh"
 #include "hb-unicode-private.hh"
 
 
-
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
 ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
 
-typedef struct _hb_segment_properties_t {
-    hb_direction_t      direction;
-    hb_script_t         script;
-    hb_language_t       language;
-    ASSERT_POD ();
-} hb_segment_properties_t;
 
+/*
+ * hb_buffer_t
+ */
 
-struct _hb_buffer_t {
+struct hb_buffer_t {
   hb_object_header_t header;
   ASSERT_POD ();
 
   /* Information about how the text in the buffer should be treated */
-
   hb_unicode_funcs_t *unicode; /* Unicode functions */
-  hb_segment_properties_t props; /* Script, language, direction */
+  hb_buffer_flags_t flags; /* BOT / EOT / etc. */
+  hb_codepoint_t replacement; /* U+FFFD or something else. */
 
   /* Buffer contents */
+  hb_buffer_content_type_t content_type;
+  hb_segment_properties_t props; /* Script, language, direction */
 
   bool in_error; /* Allocation failed */
   bool have_output; /* Whether we have an output buffer going on */
@@ -81,49 +78,80 @@ struct _hb_buffer_t {
   inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
   inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
 
+  inline bool has_separate_output (void) const { return info != out_info; }
+
   unsigned int serial;
+
+  /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
   uint8_t allocated_var_bytes[8];
   const char *allocated_var_owner[8];
 
+  /* Text before / after the main buffer contents.
+   * Always in Unicode, and ordered outward.
+   * Index 0 is for "pre-context", 1 for "post-context". */
+  static const unsigned int CONTEXT_LENGTH = 5;
+  hb_codepoint_t context[2][CONTEXT_LENGTH];
+  unsigned int context_len[2];
+
 
   /* Methods */
 
   HB_INTERNAL void reset (void);
+  HB_INTERNAL void clear (void);
 
   inline unsigned int backtrack_len (void) const
   { return have_output? out_len : idx; }
+  inline unsigned int lookahead_len (void) const
+  { return len - idx; }
   inline unsigned int next_serial (void) { return serial++; }
 
   HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
   HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
+  HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner);
   HB_INTERNAL void deallocate_var_all (void);
 
   HB_INTERNAL void add (hb_codepoint_t  codepoint,
-                       hb_mask_t       mask,
                        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 (void);
   HB_INTERNAL void reverse_clusters (void);
-  HB_INTERNAL void guess_properties (void);
+  HB_INTERNAL void guess_segment_properties (void);
 
   HB_INTERNAL void swap_buffers (void);
+  HB_INTERNAL void remove_output (void);
   HB_INTERNAL void clear_output (void);
   HB_INTERNAL void clear_positions (void);
-  HB_INTERNAL void replace_glyphs_be16 (unsigned int num_in,
-                                       unsigned int num_out,
-                                       const uint16_t *glyph_data_be);
+
   HB_INTERNAL void replace_glyphs (unsigned int num_in,
                                   unsigned int num_out,
                                   const hb_codepoint_t *glyph_data);
+
   HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
   /* Makes a copy of the glyph at idx to output and replace glyph_index */
   HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
+  HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info);
   /* Copies glyph at idx to output but doesn't advance idx */
   HB_INTERNAL void copy_glyph (void);
+  HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
   /* Copies glyph at idx to output and advance idx.
    * If there's no output, just advance idx. */
-  HB_INTERNAL void next_glyph (void);
+  inline void
+  next_glyph (void)
+  {
+    if (have_output)
+    {
+      if (unlikely (out_info != info || out_len != idx)) {
+       if (unlikely (!make_room_for (1, 1))) return;
+       out_info[out_len] = info[idx];
+      }
+      out_len++;
+    }
+
+    idx++;
+  }
+
   /* Advance idx without copying to output. */
   inline void skip_glyph (void) { idx++; }
 
@@ -151,11 +179,18 @@ struct _hb_buffer_t {
   HB_INTERNAL bool enlarge (unsigned int size);
 
   inline bool ensure (unsigned int size)
-  { return likely (size <= allocated) ? true : enlarge (size); }
+  { return likely (!size || size < allocated) ? true : enlarge (size); }
+
+  inline bool ensure_inplace (unsigned int size)
+  { return likely (!size || size < allocated); }
 
   HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+  HB_INTERNAL bool shift_forward (unsigned int count);
 
-  HB_INTERNAL void *get_scratch_buffer (unsigned int *size);
+  typedef long scratch_buffer_t;
+  HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
+
+  inline void clear_context (unsigned int side) { context_len[side] = 0; }
 };
 
 
@@ -166,7 +201,8 @@ struct _hb_buffer_t {
        HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
 #define HB_BUFFER_DEALLOCATE_VAR(b, var) \
        HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var)
-
+#define HB_BUFFER_ASSERT_VAR(b, var) \
+       HB_BUFFER_XALLOCATE_VAR (b, assert_var, var (), #var)
 
 
 #endif /* HB_BUFFER_PRIVATE_HH */
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
new file mode 100644 (file)
index 0000000..406d69d
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * 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
+ */
+
+#include "hb-buffer-private.hh"
+
+
+static const char *serialize_formats[] = {
+  "text",
+  "json",
+  NULL
+};
+
+/**
+ * hb_buffer_serialize_list_formats:
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+const char **
+hb_buffer_serialize_list_formats (void)
+{
+  return serialize_formats;
+}
+
+/**
+ * hb_buffer_serialize_format_from_string:
+ * @str: 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len)
+{
+  /* Upper-case it. */
+  return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
+}
+
+/**
+ * hb_buffer_serialize_format_to_string:
+ * @format: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
+{
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:      return serialize_formats[0];
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:      return serialize_formats[1];
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:   return NULL;
+  }
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_json (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_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    /* In the following code, we know b is large enough that no overflow can happen. */
+
+#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
+
+    if (i)
+      *p++ = ',';
+
+    *p++ = '{';
+
+    APPEND ("\"g\":");
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+    {
+      char g[128];
+      hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
+      *p++ = '"';
+      for (char *q = g; *q; q++) {
+        if (*q == '"')
+         *p++ = '\\';
+       *p++ = *q;
+      }
+      *p++ = '"';
+    }
+    else
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
+    }
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+    {
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
+                    pos[i].x_offset, pos[i].y_offset);
+      p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+                    pos[i].x_advance, pos[i].y_advance);
+    }
+
+    *p++ = '}';
+
+    unsigned int l = p - b;
+    if (buf_size > l)
+    {
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+  }
+
+  return end - start;
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_text (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_flags_t flags)
+{
+  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+
+  *buf_consumed = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    char b[1024];
+    char *p = b;
+
+    /* In the following code, we know b is large enough that no overflow can happen. */
+
+    if (i)
+      *p++ = '|';
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+    {
+      hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
+      p += strlen (p);
+    }
+    else
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
+    }
+
+    if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+    {
+      if (pos[i].x_offset || pos[i].y_offset)
+       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
+
+      *p++ = '+';
+      p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
+      if (pos[i].y_advance)
+       p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+    }
+
+    unsigned int l = p - b;
+    if (buf_size > l)
+    {
+      memcpy (buf, b, l);
+      buf += l;
+      buf_size -= l;
+      *buf_consumed += l;
+      *buf = '\0';
+    } else
+      return i - start;
+  }
+
+  return end - start;
+}
+
+/* Returns number of items, starting at start, that were serialized. */
+/**
+ * hb_buffer_serialize_glyphs:
+ * @buffer: a buffer.
+ * @start: 
+ * @end: 
+ * @buf: (array length=buf_size):
+ * @buf_size: 
+ * @buf_consumed: (out):
+ * @font: 
+ * @format: 
+ * @flags: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+                           unsigned int start,
+                           unsigned int end,
+                           char *buf,
+                           unsigned int buf_size,
+                           unsigned int *buf_consumed, /* May be NULL */
+                           hb_font_t *font, /* May be NULL */
+                           hb_buffer_serialize_format_t format,
+                           hb_buffer_serialize_flags_t flags)
+{
+  assert (start <= end && end <= buffer->len);
+
+  unsigned int sconsumed;
+  if (!buf_consumed)
+    buf_consumed = &sconsumed;
+  *buf_consumed = 0;
+
+  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+         buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  if (unlikely (start == end))
+    return 0;
+
+  if (!font)
+    font = hb_font_get_empty ();
+
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+      return _hb_buffer_serialize_glyphs_text (buffer, start, end,
+                                              buf, buf_size, buf_consumed,
+                                              font, flags);
+
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+      return _hb_buffer_serialize_glyphs_json (buffer, start, end,
+                                              buf, buf_size, buf_consumed,
+                                              font, flags);
+
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+      return 0;
+
+  }
+}
+
+
+static hb_bool_t
+parse_uint (const char *pp, const char *end, uint32_t *pv)
+{
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+  strncpy (buf, pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  uint32_t v;
+
+  errno = 0;
+  v = strtol (p, &pend, 10);
+  if (errno || p == pend || pend - p != end - pp)
+    return false;
+
+  *pv = v;
+  return true;
+}
+
+static hb_bool_t
+parse_int (const char *pp, const char *end, int32_t *pv)
+{
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+  strncpy (buf, pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  int32_t v;
+
+  errno = 0;
+  v = strtol (p, &pend, 10);
+  if (errno || p == pend || pend - p != end - pp)
+    return false;
+
+  *pv = v;
+  return true;
+}
+
+#include "hb-buffer-deserialize-json.hh"
+#include "hb-buffer-deserialize-text.hh"
+
+/**
+ * hb_buffer_deserialize_glyphs:
+ * @buffer: a buffer.
+ * @buf: (array length=buf_len):
+ * @buf_len: 
+ * @end_ptr: (out):
+ * @font: 
+ * @format: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+                             const char *buf,
+                             int buf_len, /* -1 means nul-terminated */
+                             const char **end_ptr, /* May be NULL */
+                             hb_font_t *font, /* May be NULL */
+                             hb_buffer_serialize_format_t format)
+{
+  const char *end;
+  if (!end_ptr)
+    end_ptr = &end;
+  *end_ptr = buf;
+
+  assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+         buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  if (buf_len == -1)
+    buf_len = strlen (buf);
+
+  if (!buf_len)
+  {
+    *end_ptr = buf;
+    return false;
+  }
+
+  hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  if (!font)
+    font = hb_font_get_empty ();
+
+  switch (format)
+  {
+    case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+      return _hb_buffer_deserialize_glyphs_text (buffer,
+                                                buf, buf_len, end_ptr,
+                                                font);
+
+    case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+      return _hb_buffer_deserialize_glyphs_json (buffer,
+                                                buf, buf_len, end_ptr,
+                                                font);
+
+    default:
+    case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+      return false;
+
+  }
+}
index e2c34f1..b9fe263 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright © 1998-2004  David Turner and Werner Lemberg
  * Copyright © 2004,2007,2009,2010  Red Hat, Inc.
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  */
 
 #include "hb-buffer-private.hh"
-
-#include <string.h>
-
+#include "hb-utf-private.hh"
 
 
 #ifndef HB_DEBUG_BUFFER
 #define HB_DEBUG_BUFFER (HB_DEBUG+0)
 #endif
 
-#define _HB_BUFFER_UNICODE_FUNCS_DEFAULT (const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default))
-#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
+
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+                            const hb_segment_properties_t *b)
+{
+  return a->direction == b->direction &&
+        a->script    == b->script    &&
+        a->language  == b->language  &&
+        a->reserved1 == b->reserved1 &&
+        a->reserved2 == b->reserved2;
+
+}
+
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p)
+{
+  return (unsigned int) p->direction ^
+        (unsigned int) p->script ^
+        (intptr_t) (p->language);
+}
+
+
 
 /* Here is how the buffer works internally:
  *
@@ -76,7 +94,7 @@ hb_buffer_t::enlarge (unsigned int size)
   if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
     goto done;
 
-  while (size > new_allocated)
+  while (size >= new_allocated)
     new_allocated += (new_allocated >> 1) + 32;
 
   ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
@@ -121,17 +139,35 @@ hb_buffer_t::make_room_for (unsigned int num_in,
   return true;
 }
 
-void *
+bool
+hb_buffer_t::shift_forward (unsigned int count)
+{
+  assert (have_output);
+  if (unlikely (!ensure (len + count))) return false;
+
+  memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
+  len += count;
+  idx += count;
+
+  return true;
+}
+
+hb_buffer_t::scratch_buffer_t *
 hb_buffer_t::get_scratch_buffer (unsigned int *size)
 {
   have_output = false;
   have_positions = false;
+
   out_len = 0;
-  *size = allocated * sizeof (pos[0]);
-  return pos;
+  out_info = info;
+
+  assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
+  *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
+  return (scratch_buffer_t *) (void *) pos;
 }
 
 
+
 /* HarfBuzz-Internal API */
 
 void
@@ -141,11 +177,23 @@ hb_buffer_t::reset (void)
     return;
 
   hb_unicode_funcs_destroy (unicode);
-  unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT;
+  unicode = hb_unicode_funcs_get_default ();
+  flags = HB_BUFFER_FLAG_DEFAULT;
+  replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+
+  clear ();
+}
+
+void
+hb_buffer_t::clear (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
 
-  hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
+  hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
   props = default_props;
 
+  content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
   in_error = false;
   have_output = false;
   have_positions = false;
@@ -153,17 +201,18 @@ hb_buffer_t::reset (void)
   idx = 0;
   len = 0;
   out_len = 0;
+  out_info = info;
 
   serial = 0;
   memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
   memset (allocated_var_owner, 0, sizeof allocated_var_owner);
 
-  out_info = info;
+  memset (context, 0, sizeof context);
+  memset (context_len, 0, sizeof context_len);
 }
 
 void
 hb_buffer_t::add (hb_codepoint_t  codepoint,
-                 hb_mask_t       mask,
                  unsigned int    cluster)
 {
   hb_glyph_info_t *glyph;
@@ -174,13 +223,37 @@ hb_buffer_t::add (hb_codepoint_t  codepoint,
 
   memset (glyph, 0, sizeof (*glyph));
   glyph->codepoint = codepoint;
-  glyph->mask = mask;
+  glyph->mask = 1;
   glyph->cluster = cluster;
 
   len++;
 }
 
 void
+hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
+{
+  if (unlikely (!ensure (len + 1))) return;
+
+  info[len] = glyph_info;
+
+  len++;
+}
+
+
+void
+hb_buffer_t::remove_output (void)
+{
+  if (unlikely (hb_object_is_inert (this)))
+    return;
+
+  have_output = false;
+  have_positions = false;
+
+  out_len = 0;
+  out_info = info;
+}
+
+void
 hb_buffer_t::clear_output (void)
 {
   if (unlikely (hb_object_is_inert (this)))
@@ -202,6 +275,9 @@ hb_buffer_t::clear_positions (void)
   have_output = false;
   have_positions = true;
 
+  out_len = 0;
+  out_info = info;
+
   memset (pos, 0, sizeof (pos[0]) * len);
 }
 
@@ -230,46 +306,17 @@ hb_buffer_t::swap_buffers (void)
   idx = 0;
 }
 
-void
-hb_buffer_t::replace_glyphs_be16 (unsigned int num_in,
-                                 unsigned int num_out,
-                                 const uint16_t *glyph_data_be)
-{
-  if (!make_room_for (num_in, num_out)) return;
-
-  hb_glyph_info_t orig_info = info[idx];
-  for (unsigned int i = 1; i < num_in; i++)
-  {
-    hb_glyph_info_t *inf = &info[idx + i];
-    orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
-  }
-
-  hb_glyph_info_t *pinfo = &out_info[out_len];
-  for (unsigned int i = 0; i < num_out; i++)
-  {
-    *pinfo = orig_info;
-    pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]);
-    pinfo++;
-  }
-
-  idx  += num_in;
-  out_len += num_out;
-}
 
 void
 hb_buffer_t::replace_glyphs (unsigned int num_in,
                             unsigned int num_out,
                             const uint32_t *glyph_data)
 {
-  if (!make_room_for (num_in, num_out)) return;
+  if (unlikely (!make_room_for (num_in, num_out))) return;
 
-  hb_glyph_info_t orig_info = info[idx];
-  for (unsigned int i = 1; i < num_in; i++)
-  {
-    hb_glyph_info_t *inf = &info[idx + i];
-    orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
-  }
+  merge_clusters (idx, idx + num_in);
 
+  hb_glyph_info_t orig_info = info[idx];
   hb_glyph_info_t *pinfo = &out_info[out_len];
   for (unsigned int i = 0; i < num_out; i++)
   {
@@ -285,7 +332,7 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
 void
 hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
 {
-  if (!make_room_for (0, 1)) return;
+  if (unlikely (!make_room_for (0, 1))) return;
 
   out_info[out_len] = info[idx];
   out_info[out_len].codepoint = glyph_index;
@@ -294,46 +341,77 @@ hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
 }
 
 void
-hb_buffer_t::copy_glyph (void)
+hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
 {
-  if (!make_room_for (0, 1)) return;
+  if (unlikely (!make_room_for (0, 1))) return;
 
-  out_info[out_len] = info[idx];
+  out_info[out_len] = glyph_info;
 
   out_len++;
 }
 
 void
-hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+hb_buffer_t::copy_glyph (void)
 {
-  if (!make_room_for (1, 1)) return;
+  if (unlikely (!make_room_for (0, 1))) return;
 
   out_info[out_len] = info[idx];
-  out_info[out_len].codepoint = glyph_index;
 
-  idx++;
   out_len++;
 }
 
-void
-hb_buffer_t::next_glyph (void)
+bool
+hb_buffer_t::move_to (unsigned int i)
 {
-  if (have_output)
+  if (!have_output)
   {
-    if (out_info != info)
-    {
-      if (unlikely (!ensure (out_len + 1))) return;
-      out_info[out_len] = info[idx];
-    }
-    else if (out_len != idx)
-      out_info[out_len] = info[idx];
+    assert (i <= len);
+    idx = i;
+    return true;
+  }
 
-    out_len++;
+  assert (i <= out_len + (len - idx));
+
+  if (out_len < i)
+  {
+    unsigned int count = i - out_len;
+    if (unlikely (!make_room_for (count, count))) return false;
+
+    memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
+    idx += count;
+    out_len += count;
+  }
+  else if (out_len > i)
+  {
+    /* Tricky part: rewinding... */
+    unsigned int count = out_len - i;
+
+    if (unlikely (idx < count && !shift_forward (count + 32))) return false;
+
+    assert (idx >= count);
+
+    idx -= count;
+    out_len -= count;
+    memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
   }
 
+  return true;
+}
+
+void
+hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+{
+  if (unlikely (out_info != info || out_len != idx)) {
+    if (unlikely (!make_room_for (1, 1))) return;
+    out_info[out_len] = info[idx];
+  }
+  out_info[out_len].codepoint = glyph_index;
+
   idx++;
+  out_len++;
 }
 
+
 void
 hb_buffer_t::set_masks (hb_mask_t    value,
                        hb_mask_t    mask,
@@ -365,7 +443,7 @@ hb_buffer_t::reverse_range (unsigned int start,
 {
   unsigned int i, j;
 
-  if (start == end - 1)
+  if (end - start < 2)
     return;
 
   for (i = start, j = end - 1; i < j; i++, j--) {
@@ -376,7 +454,7 @@ hb_buffer_t::reverse_range (unsigned int start,
     info[j] = t;
   }
 
-  if (pos) {
+  if (have_positions) {
     for (i = start, j = end - 1; i < j; i++, j--) {
       hb_glyph_position_t t;
 
@@ -423,32 +501,77 @@ void
 hb_buffer_t::merge_clusters (unsigned int start,
                             unsigned int end)
 {
-  unsigned int cluster = this->info[start].cluster;
+#ifdef HB_NO_MERGE_CLUSTERS
+  return;
+#endif
+
+  if (unlikely (end - start < 2))
+    return;
+
+  unsigned int cluster = info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN (cluster, this->info[i].cluster);
+    cluster = MIN (cluster, info[i].cluster);
+
+  /* Extend end */
+  while (end < len && info[end - 1].cluster == info[end].cluster)
+    end++;
+
+  /* Extend start */
+  while (idx < start && info[start - 1].cluster == info[start].cluster)
+    start--;
+
+  /* If we hit the start of buffer, continue in out-buffer. */
+  if (idx == start)
+    for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
+      out_info[i - 1].cluster = cluster;
+
   for (unsigned int i = start; i < end; i++)
-    this->info[i].cluster = cluster;
+    info[i].cluster = cluster;
 }
 void
 hb_buffer_t::merge_out_clusters (unsigned int start,
                                 unsigned int end)
 {
-  unsigned int cluster = this->out_info[start].cluster;
+#ifdef HB_NO_MERGE_CLUSTERS
+  return;
+#endif
+
+  if (unlikely (end - start < 2))
+    return;
+
+  unsigned int cluster = out_info[start].cluster;
 
   for (unsigned int i = start + 1; i < end; i++)
-    cluster = MIN (cluster, this->out_info[i].cluster);
+    cluster = MIN (cluster, out_info[i].cluster);
+
+  /* Extend start */
+  while (start && out_info[start - 1].cluster == out_info[start].cluster)
+    start--;
+
+  /* Extend end */
+  while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
+    end++;
+
+  /* If we hit the end of out-buffer, continue in buffer. */
+  if (end == out_len)
+    for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
+      info[i].cluster = cluster;
+
   for (unsigned int i = start; i < end; i++)
-    this->out_info[i].cluster = cluster;
+    out_info[i].cluster = cluster;
 }
 
 void
-hb_buffer_t::guess_properties (void)
+hb_buffer_t::guess_segment_properties (void)
 {
+  assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+         (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+
   /* If script is set to INVALID, guess from buffer contents */
   if (props.script == HB_SCRIPT_INVALID) {
     for (unsigned int i = 0; i < len; i++) {
-      hb_script_t script = hb_unicode_script (unicode, info[i].codepoint);
+      hb_script_t script = unicode->script (info[i].codepoint);
       if (likely (script != HB_SCRIPT_COMMON &&
                  script != HB_SCRIPT_INHERITED &&
                  script != HB_SCRIPT_UNKNOWN)) {
@@ -487,7 +610,7 @@ void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const c
 {
   assert (byte_i < 8 && byte_i + count <= 8);
 
-  if (DEBUG (BUFFER))
+  if (DEBUG_ENABLED (BUFFER))
     dump_var_allocation (this);
   DEBUG_MSG (BUFFER, this,
             "Allocating var bytes %d..%d for %s",
@@ -502,7 +625,7 @@ void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const c
 
 void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
 {
-  if (DEBUG (BUFFER))
+  if (DEBUG_ENABLED (BUFFER))
     dump_var_allocation (this);
 
   DEBUG_MSG (BUFFER, this,
@@ -517,6 +640,22 @@ void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const
   }
 }
 
+void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
+{
+  if (DEBUG_ENABLED (BUFFER))
+    dump_var_allocation (this);
+
+  DEBUG_MSG (BUFFER, this,
+            "Asserting var bytes %d..%d for %s",
+            byte_i, byte_i + count - 1, owner);
+
+  assert (byte_i < 8 && byte_i + count <= 8);
+  for (unsigned int i = byte_i; i < byte_i + count; i++) {
+    assert (allocated_var_bytes[i]);
+    assert (0 == strcmp (allocated_var_owner[i], owner));
+  }
+}
+
 void hb_buffer_t::deallocate_var_all (void)
 {
   memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
@@ -525,8 +664,17 @@ void hb_buffer_t::deallocate_var_all (void)
 
 /* Public API */
 
+/**
+ * hb_buffer_create: (Xconstructor)
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
 hb_buffer_t *
-hb_buffer_create ()
+hb_buffer_create (void)
 {
   hb_buffer_t *buffer;
 
@@ -538,29 +686,61 @@ hb_buffer_create ()
   return buffer;
 }
 
+/**
+ * hb_buffer_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_buffer_t *
 hb_buffer_get_empty (void)
 {
   static const hb_buffer_t _hb_buffer_nil = {
     HB_OBJECT_HEADER_STATIC,
 
-    _HB_BUFFER_UNICODE_FUNCS_DEFAULT,
-    _HB_BUFFER_PROPS_DEFAULT,
+    const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
+    HB_BUFFER_FLAG_DEFAULT,
+    HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
 
+    HB_BUFFER_CONTENT_TYPE_INVALID,
+    HB_SEGMENT_PROPERTIES_DEFAULT,
     true, /* in_error */
     true, /* have_output */
     true  /* have_positions */
+
+    /* Zero is good enough for everything else. */
   };
 
   return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
 }
 
+/**
+ * hb_buffer_reference: (skip)
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_buffer_t *
 hb_buffer_reference (hb_buffer_t *buffer)
 {
   return hb_object_reference (buffer);
 }
 
+/**
+ * hb_buffer_destroy: (skip)
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_destroy (hb_buffer_t *buffer)
 {
@@ -574,6 +754,20 @@ hb_buffer_destroy (hb_buffer_t *buffer)
   free (buffer);
 }
 
+/**
+ * hb_buffer_set_user_data: (skip)
+ * @buffer: a buffer.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_set_user_data (hb_buffer_t        *buffer,
                         hb_user_data_key_t *key,
@@ -584,6 +778,17 @@ hb_buffer_set_user_data (hb_buffer_t        *buffer,
   return hb_object_set_user_data (buffer, key, data, destroy, replace);
 }
 
+/**
+ * hb_buffer_get_user_data: (skip)
+ * @buffer: a buffer.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_buffer_get_user_data (hb_buffer_t        *buffer,
                         hb_user_data_key_t *key)
@@ -592,27 +797,89 @@ hb_buffer_get_user_data (hb_buffer_t        *buffer,
 }
 
 
+/**
+ * hb_buffer_set_content_type:
+ * @buffer: a buffer.
+ * @content_type: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_content_type (hb_buffer_t              *buffer,
+                           hb_buffer_content_type_t  content_type)
+{
+  buffer->content_type = content_type;
+}
+
+/**
+ * hb_buffer_get_content_type:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_buffer_content_type_t
+hb_buffer_get_content_type (hb_buffer_t *buffer)
+{
+  return buffer->content_type;
+}
+
+
+/**
+ * hb_buffer_set_unicode_funcs:
+ * @buffer: a buffer.
+ * @unicode_funcs: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
-                            hb_unicode_funcs_t *unicode)
+                            hb_unicode_funcs_t *unicode_funcs)
 {
   if (unlikely (hb_object_is_inert (buffer)))
     return;
 
-  if (!unicode)
-    unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT;
+  if (!unicode_funcs)
+    unicode_funcs = hb_unicode_funcs_get_default ();
 
-  hb_unicode_funcs_reference (unicode);
+
+  hb_unicode_funcs_reference (unicode_funcs);
   hb_unicode_funcs_destroy (buffer->unicode);
-  buffer->unicode = unicode;
+  buffer->unicode = unicode_funcs;
 }
 
+/**
+ * hb_buffer_get_unicode_funcs:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_buffer_get_unicode_funcs (hb_buffer_t        *buffer)
 {
   return buffer->unicode;
 }
 
+/**
+ * hb_buffer_set_direction:
+ * @buffer: a buffer.
+ * @direction: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_direction (hb_buffer_t    *buffer,
                         hb_direction_t  direction)
@@ -624,12 +891,31 @@ hb_buffer_set_direction (hb_buffer_t    *buffer,
   buffer->props.direction = direction;
 }
 
+/**
+ * hb_buffer_get_direction:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_direction_t
 hb_buffer_get_direction (hb_buffer_t    *buffer)
 {
   return buffer->props.direction;
 }
 
+/**
+ * hb_buffer_set_script:
+ * @buffer: a buffer.
+ * @script: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_script (hb_buffer_t *buffer,
                      hb_script_t  script)
@@ -640,12 +926,31 @@ hb_buffer_set_script (hb_buffer_t *buffer,
   buffer->props.script = script;
 }
 
+/**
+ * hb_buffer_get_script:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_script_t
 hb_buffer_get_script (hb_buffer_t *buffer)
 {
   return buffer->props.script;
 }
 
+/**
+ * hb_buffer_set_language:
+ * @buffer: a buffer.
+ * @language: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_set_language (hb_buffer_t   *buffer,
                        hb_language_t  language)
@@ -656,40 +961,221 @@ hb_buffer_set_language (hb_buffer_t   *buffer,
   buffer->props.language = language;
 }
 
+/**
+ * hb_buffer_get_language:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer)
 {
   return buffer->props.language;
 }
 
+/**
+ * hb_buffer_set_segment_properties:
+ * @buffer: a buffer.
+ * @props: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+                                 const hb_segment_properties_t *props)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->props = *props;
+}
+
+/**
+ * hb_buffer_get_segment_properties:
+ * @buffer: a buffer.
+ * @props: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+                                 hb_segment_properties_t *props)
+{
+  *props = buffer->props;
+}
+
+
+/**
+ * hb_buffer_set_flags:
+ * @buffer: a buffer.
+ * @flags: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_flags (hb_buffer_t       *buffer,
+                    hb_buffer_flags_t  flags)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->flags = flags;
+}
+
+/**
+ * hb_buffer_get_flags:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer)
+{
+  return buffer->flags;
+}
+
+
+/**
+ * hb_buffer_set_replacement_codepoint:
+ * @buffer: a buffer.
+ * @replacement: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
+                                    hb_codepoint_t  replacement)
+{
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  buffer->replacement = replacement;
+}
+
+/**
+ * hb_buffer_get_replacement_codepoint:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer)
+{
+  return buffer->replacement;
+}
 
+
+/**
+ * hb_buffer_reset:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_reset (hb_buffer_t *buffer)
 {
   buffer->reset ();
 }
 
+/**
+ * hb_buffer_clear_contents:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_clear_contents (hb_buffer_t *buffer)
+{
+  buffer->clear ();
+}
+
+/**
+ * hb_buffer_pre_allocate:
+ * @buffer: a buffer.
+ * @size: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
 {
   return buffer->ensure (size);
 }
 
+/**
+ * hb_buffer_allocation_successful:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_allocation_successful (hb_buffer_t  *buffer)
 {
   return !buffer->in_error;
 }
 
+/**
+ * hb_buffer_add:
+ * @buffer: a buffer.
+ * @codepoint: 
+ * @cluster: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add (hb_buffer_t    *buffer,
               hb_codepoint_t  codepoint,
-              hb_mask_t       mask,
               unsigned int    cluster)
 {
-  buffer->add (codepoint, mask, cluster);
+  buffer->add (codepoint, cluster);
+  buffer->clear_context (1);
 }
 
+/**
+ * hb_buffer_set_length:
+ * @buffer: a buffer.
+ * @length: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_buffer_set_length (hb_buffer_t  *buffer,
                      unsigned int  length)
@@ -708,16 +1194,45 @@ hb_buffer_set_length (hb_buffer_t  *buffer,
   }
 
   buffer->len = length;
+
+  if (!length)
+  {
+    buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
+    buffer->clear_context (0);
+  }
+  buffer->clear_context (1);
+
   return true;
 }
 
+/**
+ * hb_buffer_get_length:
+ * @buffer: a buffer.
+ *
+ * Returns the number of items in the buffer.
+ *
+ * Return value: buffer length.
+ *
+ * Since: 1.0
+ **/
 unsigned int
 hb_buffer_get_length (hb_buffer_t *buffer)
 {
   return buffer->len;
 }
 
-/* Return value valid as long as buffer not modified */
+/**
+ * hb_buffer_get_glyph_infos:
+ * @buffer: a buffer.
+ * @length: (out): output array length.
+ *
+ * Returns buffer glyph information array.  Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph information array.
+ *
+ * Since: 1.0
+ **/
 hb_glyph_info_t *
 hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
                            unsigned int *length)
@@ -728,7 +1243,18 @@ hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
   return (hb_glyph_info_t *) buffer->info;
 }
 
-/* Return value valid as long as buffer not modified */
+/**
+ * hb_buffer_get_glyph_positions:
+ * @buffer: a buffer.
+ * @length: (out): output length.
+ *
+ * Returns buffer glyph position array.  Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph position array.
+ *
+ * Since: 1.0
+ **/
 hb_glyph_position_t *
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
                                unsigned int *length)
@@ -742,88 +1268,147 @@ hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
   return (hb_glyph_position_t *) buffer->pos;
 }
 
+/**
+ * hb_buffer_reverse:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer contents.
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_reverse (hb_buffer_t *buffer)
 {
   buffer->reverse ();
 }
 
+/**
+ * hb_buffer_reverse_clusters:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer clusters.  That is, the buffer contents are
+ * reversed, then each cluster (consecutive items having the
+ * same cluster number) are reversed again.
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer)
 {
   buffer->reverse_clusters ();
 }
 
+/**
+ * hb_buffer_guess_segment_properties:
+ * @buffer: a buffer.
+ *
+ * Sets unset buffer segment properties based on buffer Unicode
+ * contents.  If buffer is not empty, it must have content type
+ * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ *
+ * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * will be set to the Unicode script of the first character in
+ * the buffer that has a script other than %HB_SCRIPT_COMMON,
+ * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
+ *
+ * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
+ * it will be set to the natural horizontal direction of the
+ * buffer script as returned by hb_script_get_horizontal_direction().
+ *
+ * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
+ * it will be set to the process's default language as returned by
+ * hb_language_get_default().  This may change in the future by
+ * taking buffer script into consideration when choosing a language.
+ *
+ * Since: 1.0
+ **/
 void
-hb_buffer_guess_properties (hb_buffer_t *buffer)
-{
-  buffer->guess_properties ();
-}
-
-#define ADD_UTF(T) \
-       HB_STMT_START { \
-         if (text_length == -1) { \
-           text_length = 0; \
-           const T *p = (const T *) text; \
-           while (*p) { \
-             text_length++; \
-             p++; \
-           } \
-         } \
-         if (item_length == -1) \
-           item_length = text_length - item_offset; \
-         buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \
-         const T *next = (const T *) text + item_offset; \
-         const T *end = next + item_length; \
-         while (next < end) { \
-           hb_codepoint_t u; \
-           const T *old_next = next; \
-           next = UTF_NEXT (next, end, u); \
-           hb_buffer_add (buffer, u, 1,  old_next - (const T *) text); \
-         } \
-       } HB_STMT_END
-
-
-#define UTF8_COMPUTE(Char, Mask, Len) \
-  if (Char < 128) { Len = 1; Mask = 0x7f; } \
-  else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
-  else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
-  else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
-  else Len = 0;
-
-static inline const uint8_t *
-hb_utf8_next (const uint8_t *text,
-             const uint8_t *end,
-             hb_codepoint_t *unicode)
-{
-  uint8_t c = *text;
-  unsigned int mask, len;
-
-  /* TODO check for overlong sequences? */
-
-  UTF8_COMPUTE (c, mask, len);
-  if (unlikely (!len || (unsigned int) (end - text) < len)) {
-    *unicode = -1;
-    return text + 1;
-  } else {
-    hb_codepoint_t result;
-    unsigned int i;
-    result = c & mask;
-    for (i = 1; i < len; i++)
-      {
-       if (unlikely ((text[i] & 0xc0) != 0x80))
-         {
-           *unicode = -1;
-           return text + 1;
-         }
-       result <<= 6;
-       result |= (text[i] & 0x3f);
-      }
-    *unicode = result;
-    return text + len;
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
+{
+  buffer->guess_segment_properties ();
+}
+
+template <typename utf_t>
+static inline void
+hb_buffer_add_utf (hb_buffer_t  *buffer,
+                  const typename utf_t::codepoint_t *text,
+                  int           text_length,
+                  unsigned int  item_offset,
+                  int           item_length)
+{
+  typedef typename utf_t::codepoint_t T;
+  const hb_codepoint_t replacement = buffer->replacement;
+
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+         (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+
+  if (unlikely (hb_object_is_inert (buffer)))
+    return;
+
+  if (text_length == -1)
+    text_length = utf_t::strlen (text);
+
+  if (item_length == -1)
+    item_length = text_length - item_offset;
+
+  buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
+
+  /* If buffer is empty and pre-context provided, install it.
+   * This check is written this way, to make sure people can
+   * provide pre-context in one add_utf() call, then provide
+   * text in a follow-up call.  See:
+   *
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
+   */
+  if (!buffer->len && item_offset > 0)
+  {
+    /* Add pre-context */
+    buffer->clear_context (0);
+    const T *prev = text + item_offset;
+    const T *start = text;
+    while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
+    {
+      hb_codepoint_t u;
+      prev = utf_t::prev (prev, start, &u, replacement);
+      buffer->context[0][buffer->context_len[0]++] = u;
+    }
   }
+
+  const T *next = text + item_offset;
+  const T *end = next + item_length;
+  while (next < end)
+  {
+    hb_codepoint_t u;
+    const T *old_next = next;
+    next = utf_t::next (next, end, &u, replacement);
+    buffer->add (u, old_next - (const T *) text);
+  }
+
+  /* Add post-context */
+  buffer->clear_context (1);
+  end = text + text_length;
+  while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
+  {
+    hb_codepoint_t u;
+    next = utf_t::next (next, end, &u, replacement);
+    buffer->context[1][buffer->context_len[1]++] = u;
+  }
+
+  buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
 }
 
+/**
+ * hb_buffer_add_utf8:
+ * @buffer: a buffer.
+ * @text: (array length=text_length) (element-type uint8_t):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add_utf8 (hb_buffer_t  *buffer,
                    const char   *text,
@@ -831,45 +1416,43 @@ hb_buffer_add_utf8 (hb_buffer_t  *buffer,
                    unsigned int  item_offset,
                    int           item_length)
 {
-#define UTF_NEXT(S, E, U)      hb_utf8_next (S, E, &(U))
-  ADD_UTF (uint8_t);
-#undef UTF_NEXT
-}
-
-static inline const uint16_t *
-hb_utf16_next (const uint16_t *text,
-              const uint16_t *end,
-              hb_codepoint_t *unicode)
-{
-  uint16_t c = *text++;
-
-  if (unlikely (c >= 0xd800 && c < 0xdc00)) {
-    /* high surrogate */
-    uint16_t l;
-    if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) {
-      /* low surrogate */
-      *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
-       text++;
-    } else
-      *unicode = -1;
-  } else
-    *unicode = c;
-
-  return text;
+  hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
 }
 
+/**
+ * hb_buffer_add_utf16:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add_utf16 (hb_buffer_t    *buffer,
                     const uint16_t *text,
                     int             text_length,
                     unsigned int    item_offset,
-                    int            item_length)
+                    int             item_length)
 {
-#define UTF_NEXT(S, E, U)      hb_utf16_next (S, E, &(U))
-  ADD_UTF (uint16_t);
-#undef UTF_NEXT
+  hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
 }
 
+/**
+ * hb_buffer_add_utf32:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_buffer_add_utf32 (hb_buffer_t    *buffer,
                     const uint32_t *text,
@@ -877,9 +1460,135 @@ hb_buffer_add_utf32 (hb_buffer_t    *buffer,
                     unsigned int    item_offset,
                     int             item_length)
 {
-#define UTF_NEXT(S, E, U)      ((U) = *(S), (S)+1)
-  ADD_UTF (uint32_t);
-#undef UTF_NEXT
+  hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
+}
+
+/**
+ * hb_buffer_add_latin1:
+ * @buffer: a buffer.
+ * @text: (array length=text_length) (element-type uint8_t):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_add_latin1 (hb_buffer_t   *buffer,
+                     const uint8_t *text,
+                     int            text_length,
+                     unsigned int   item_offset,
+                     int            item_length)
+{
+  hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
 }
 
+/**
+ * hb_buffer_add_codepoints:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length: 
+ * @item_offset: 
+ * @item_length: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_add_codepoints (hb_buffer_t          *buffer,
+                         const hb_codepoint_t *text,
+                         int                   text_length,
+                         unsigned int          item_offset,
+                         int                   item_length)
+{
+  hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
+}
+
+
+static int
+compare_info_codepoint (const hb_glyph_info_t *pa,
+                       const hb_glyph_info_t *pb)
+{
+  return (int) pb->codepoint - (int) pa->codepoint;
+}
+
+static inline void
+normalize_glyphs_cluster (hb_buffer_t *buffer,
+                         unsigned int start,
+                         unsigned int end,
+                         bool backward)
+{
+  hb_glyph_position_t *pos = buffer->pos;
+
+  /* Total cluster advance */
+  hb_position_t total_x_advance = 0, total_y_advance = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    total_x_advance += pos[i].x_advance;
+    total_y_advance += pos[i].y_advance;
+  }
 
+  hb_position_t x_advance = 0, y_advance = 0;
+  for (unsigned int i = start; i < end; i++)
+  {
+    pos[i].x_offset += x_advance;
+    pos[i].y_offset += y_advance;
+
+    x_advance += pos[i].x_advance;
+    y_advance += pos[i].y_advance;
+
+    pos[i].x_advance = 0;
+    pos[i].y_advance = 0;
+  }
+
+  if (backward)
+  {
+    /* Transfer all cluster advance to the last glyph. */
+    pos[end - 1].x_advance = total_x_advance;
+    pos[end - 1].y_advance = total_y_advance;
+
+    hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
+  } else {
+    /* Transfer all cluster advance to the first glyph. */
+    pos[start].x_advance += total_x_advance;
+    pos[start].y_advance += total_y_advance;
+    for (unsigned int i = start + 1; i < end; i++) {
+      pos[i].x_offset -= total_x_advance;
+      pos[i].y_offset -= total_y_advance;
+    }
+    hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
+  }
+}
+
+/**
+ * hb_buffer_normalize_glyphs:
+ * @buffer: a buffer.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
+{
+  assert (buffer->have_positions);
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+
+  unsigned int count = buffer->len;
+  if (unlikely (!count)) return;
+  hb_glyph_info_t *info = buffer->info;
+
+  unsigned int start = 0;
+  unsigned int end;
+  for (end = start + 1; end < count; end++)
+    if (info[start].cluster != info[end].cluster) {
+      normalize_glyphs_cluster (buffer, start, end, backward);
+      start = end;
+    }
+  normalize_glyphs_cluster (buffer, start, end, backward);
+}
index fe53197..e5b46d8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright © 1998-2004  David Turner and Werner Lemberg
  * Copyright © 2004,2007,2009  Red Hat, Inc.
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 
 #include "hb-common.h"
 #include "hb-unicode.h"
+#include "hb-font.h"
 
 HB_BEGIN_DECLS
 
 
-typedef struct _hb_buffer_t hb_buffer_t;
-
-typedef struct _hb_glyph_info_t {
+typedef struct hb_glyph_info_t {
   hb_codepoint_t codepoint;
   hb_mask_t      mask;
   uint32_t       cluster;
@@ -52,7 +51,7 @@ typedef struct _hb_glyph_info_t {
   hb_var_int_t   var2;
 } hb_glyph_info_t;
 
-typedef struct _hb_glyph_position_t {
+typedef struct hb_glyph_position_t {
   hb_position_t  x_advance;
   hb_position_t  y_advance;
   hb_position_t  x_offset;
@@ -63,6 +62,36 @@ typedef struct _hb_glyph_position_t {
 } hb_glyph_position_t;
 
 
+typedef struct hb_segment_properties_t {
+  hb_direction_t  direction;
+  hb_script_t     script;
+  hb_language_t   language;
+  /*< private >*/
+  void           *reserved1;
+  void           *reserved2;
+} hb_segment_properties_t;
+
+#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
+                                      HB_SCRIPT_INVALID, \
+                                      HB_LANGUAGE_INVALID, \
+                                      NULL, \
+                                      NULL}
+
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+                            const hb_segment_properties_t *b);
+
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p);
+
+
+
+/*
+ * hb_buffer_t
+ */
+
+typedef struct hb_buffer_t hb_buffer_t;
+
 hb_buffer_t *
 hb_buffer_create (void);
 
@@ -87,6 +116,20 @@ hb_buffer_get_user_data (hb_buffer_t        *buffer,
                         hb_user_data_key_t *key);
 
 
+typedef enum {
+  HB_BUFFER_CONTENT_TYPE_INVALID = 0,
+  HB_BUFFER_CONTENT_TYPE_UNICODE,
+  HB_BUFFER_CONTENT_TYPE_GLYPHS
+} hb_buffer_content_type_t;
+
+void
+hb_buffer_set_content_type (hb_buffer_t              *buffer,
+                           hb_buffer_content_type_t  content_type);
+
+hb_buffer_content_type_t
+hb_buffer_get_content_type (hb_buffer_t *buffer);
+
+
 void
 hb_buffer_set_unicode_funcs (hb_buffer_t        *buffer,
                             hb_unicode_funcs_t *unicode_funcs);
@@ -112,15 +155,59 @@ void
 hb_buffer_set_language (hb_buffer_t   *buffer,
                        hb_language_t  language);
 
+
 hb_language_t
 hb_buffer_get_language (hb_buffer_t *buffer);
 
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+                                 const hb_segment_properties_t *props);
+
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+                                 hb_segment_properties_t *props);
+
+void
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
+
+
+typedef enum { /*< flags >*/
+  HB_BUFFER_FLAG_DEFAULT                       = 0x00000000u,
+  HB_BUFFER_FLAG_BOT                           = 0x00000001u, /* Beginning-of-text */
+  HB_BUFFER_FLAG_EOT                           = 0x00000002u, /* End-of-text */
+  HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES   = 0x00000004u
+} hb_buffer_flags_t;
+
+void
+hb_buffer_set_flags (hb_buffer_t       *buffer,
+                    hb_buffer_flags_t  flags);
+
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer);
+
+
+
+#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
+
+/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
+ * Default is 0xFFFDu. */
+void
+hb_buffer_set_replacement_codepoint (hb_buffer_t    *buffer,
+                                    hb_codepoint_t  replacement);
+
+hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t    *buffer);
+
 
 /* Resets the buffer.  Afterwards it's as if it was just created,
  * except that it has a larger buffer allocated perhaps... */
 void
 hb_buffer_reset (hb_buffer_t *buffer);
 
+/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
+void
+hb_buffer_clear_contents (hb_buffer_t *buffer);
+
 /* Returns false if allocation failed */
 hb_bool_t
 hb_buffer_pre_allocate (hb_buffer_t  *buffer,
@@ -137,16 +224,12 @@ hb_buffer_reverse (hb_buffer_t *buffer);
 void
 hb_buffer_reverse_clusters (hb_buffer_t *buffer);
 
-void
-hb_buffer_guess_properties (hb_buffer_t *buffer);
-
 
 /* Filling the buffer in */
 
 void
 hb_buffer_add (hb_buffer_t    *buffer,
               hb_codepoint_t  codepoint,
-              hb_mask_t       mask,
               unsigned int    cluster);
 
 void
@@ -170,6 +253,22 @@ hb_buffer_add_utf32 (hb_buffer_t    *buffer,
                     unsigned int    item_offset,
                     int             item_length);
 
+/* Allows only access to first 256 Unicode codepoints. */
+void
+hb_buffer_add_latin1 (hb_buffer_t   *buffer,
+                     const uint8_t *text,
+                     int            text_length,
+                     unsigned int   item_offset,
+                     int            item_length);
+
+/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
+void
+hb_buffer_add_codepoints (hb_buffer_t          *buffer,
+                         const hb_codepoint_t *text,
+                         int                   text_length,
+                         unsigned int          item_offset,
+                         int                   item_length);
+
 
 /* Clears any new items added at the end */
 hb_bool_t
@@ -193,6 +292,61 @@ hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
                                unsigned int *length);
 
 
+/* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
+ * The resulting clusters should behave identical to pre-reordering clusters.
+ * NOTE: This has nothing to do with Unicode normalization. */
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
+
+
+/*
+ * Serialize
+ */
+
+typedef enum { /*< flags >*/
+  HB_BUFFER_SERIALIZE_FLAG_DEFAULT             = 0x00000000u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS         = 0x00000001u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS                = 0x00000002u,
+  HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES      = 0x00000004u
+} hb_buffer_serialize_flags_t;
+
+typedef enum {
+  HB_BUFFER_SERIALIZE_FORMAT_TEXT      = HB_TAG('T','E','X','T'),
+  HB_BUFFER_SERIALIZE_FORMAT_JSON      = HB_TAG('J','S','O','N'),
+  HB_BUFFER_SERIALIZE_FORMAT_INVALID   = HB_TAG_NONE
+} hb_buffer_serialize_format_t;
+
+/* len=-1 means str is NUL-terminated. */
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len);
+
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
+
+const char **
+hb_buffer_serialize_list_formats (void);
+
+/* Returns number of items, starting at start, that were serialized. */
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+                           unsigned int start,
+                           unsigned int end,
+                           char *buf,
+                           unsigned int buf_size,
+                           unsigned int *buf_consumed, /* May be NULL */
+                           hb_font_t *font, /* May be NULL */
+                           hb_buffer_serialize_format_t format,
+                           hb_buffer_serialize_flags_t flags);
+
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+                             const char *buf,
+                             int buf_len, /* -1 means nul-terminated */
+                             const char **end_ptr, /* May be NULL */
+                             hb_font_t *font, /* May be NULL */
+                             hb_buffer_serialize_format_t format);
+
+
 HB_END_DECLS
 
 #endif /* HB_BUFFER_H */
index a0928a0..19b70b7 100644 (file)
@@ -49,6 +49,8 @@ struct hb_cache_t
     unsigned int v = values[k];
     if ((v >> value_bits) != (key >> cache_bits))
       return false;
+    *value = v & ((1<<value_bits)-1);
+    return true;
   }
 
   inline bool set (unsigned int key, unsigned int value)
index 331d255..1516211 100644 (file)
 
 #include "hb-private.hh"
 
-#include "hb-version.h"
-
 #include "hb-mutex-private.hh"
 #include "hb-object-private.hh"
 
 #include <locale.h>
 
 
+/* hb_options_t */
+
+hb_options_union_t _hb_options;
+
+void
+_hb_options_init (void)
+{
+  hb_options_union_t u;
+  u.i = 0;
+  u.opts.initialized = 1;
+
+  char *c = getenv ("HB_OPTIONS");
+  u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
+
+  /* This is idempotent and threadsafe. */
+  _hb_options = u;
+}
+
 
 /* hb_tag_t */
 
+/**
+ * hb_tag_from_string:
+ * @str: (array length=len) (element-type uint8_t): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_tag_t
-hb_tag_from_string (const char *s, int len)
+hb_tag_from_string (const char *str, int len)
 {
   char tag[4];
   unsigned int i;
 
-  if (!s || !len || !*s)
+  if (!str || !len || !*str)
     return HB_TAG_NONE;
 
   if (len < 0 || len > 4)
     len = 4;
-  for (i = 0; i < (unsigned) len && s[i]; i++)
-    tag[i] = s[i];
+  for (i = 0; i < (unsigned) len && str[i]; i++)
+    tag[i] = str[i];
   for (; i < 4; i++)
     tag[i] = ' ';
 
   return HB_TAG_CHAR4 (tag);
 }
 
+/**
+ * hb_tag_to_string:
+ * @tag: 
+ * @buf: (array fixed-size=4): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_tag_to_string (hb_tag_t tag, char *buf)
+{
+  buf[0] = (char) (uint8_t) (tag >> 24);
+  buf[1] = (char) (uint8_t) (tag >> 16);
+  buf[2] = (char) (uint8_t) (tag >>  8);
+  buf[3] = (char) (uint8_t) (tag >>  0);
+}
+
 
 /* hb_direction_t */
 
@@ -68,6 +113,17 @@ const char direction_strings[][4] = {
   "btt"
 };
 
+/**
+ * hb_direction_from_string:
+ * @str: (array length=len) (element-type uint8_t): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_direction_t
 hb_direction_from_string (const char *str, int len)
 {
@@ -85,6 +141,16 @@ hb_direction_from_string (const char *str, int len)
   return HB_DIRECTION_INVALID;
 }
 
+/**
+ * hb_direction_to_string:
+ * @direction: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_direction_to_string (hb_direction_t direction)
 {
@@ -98,7 +164,7 @@ hb_direction_to_string (hb_direction_t direction)
 
 /* hb_language_t */
 
-struct _hb_language_t {
+struct hb_language_impl_t {
   const char s[1];
 };
 
@@ -160,7 +226,7 @@ struct hb_language_item_t {
     return *this;
   }
 
-  void finish (void) { free (lang); }
+  void finish (void) { free ((void *) lang); }
 };
 
 
@@ -168,6 +234,7 @@ struct hb_language_item_t {
 
 static hb_language_item_t *langs;
 
+#ifdef HB_USE_ATEXIT
 static
 void free_langs (void)
 {
@@ -178,6 +245,7 @@ void free_langs (void)
     langs = next;
   }
 }
+#endif
 
 static hb_language_item_t *
 lang_find_or_insert (const char *key)
@@ -197,11 +265,12 @@ retry:
   *lang = key;
 
   if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
+    lang->finish ();
     free (lang);
     goto retry;
   }
 
-#ifdef HAVE_ATEXIT
+#ifdef HB_USE_ATEXIT
   if (!first_lang)
     atexit (free_langs); /* First person registers atexit() callback. */
 #endif
@@ -210,17 +279,32 @@ retry:
 }
 
 
+/**
+ * hb_language_from_string:
+ * @str: (array length=len) (element-type uint8_t): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_language_t
 hb_language_from_string (const char *str, int len)
 {
+  char strbuf[64];
+
   if (!str || !len || !*str)
     return HB_LANGUAGE_INVALID;
 
-  char strbuf[32];
-  if (len >= 0) {
+  if (len >= 0)
+  {
+    /* NUL-terminate it. */
     len = MIN (len, (int) sizeof (strbuf) - 1);
-    str = (char *) memcpy (strbuf, str, len);
+    memcpy (strbuf, str, len);
     strbuf[len] = '\0';
+    str = strbuf;
   }
 
   hb_language_item_t *item = lang_find_or_insert (str);
@@ -228,6 +312,16 @@ hb_language_from_string (const char *str, int len)
   return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
 }
 
+/**
+ * hb_language_to_string:
+ * @language: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_language_to_string (hb_language_t language)
 {
@@ -235,20 +329,24 @@ hb_language_to_string (hb_language_t language)
   return language->s;
 }
 
+/**
+ * hb_language_get_default:
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_language_t
 hb_language_get_default (void)
 {
-  static hb_language_t default_language;
-
-  if (!default_language) {
-    /* This block is not quite threadsafe, but is not as bad as
-     * it looks since it's idempotent.  As long as pointer ops
-     * are atomic, we are safe. */
+  static hb_language_t default_language = HB_LANGUAGE_INVALID;
 
-    /* I hear that setlocale() doesn't honor env vars on Windows,
-     * but for now we ignore that. */
-
-    default_language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+  hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
+  if (unlikely (language == HB_LANGUAGE_INVALID)) {
+    language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+    (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
   }
 
   return default_language;
@@ -257,6 +355,16 @@ hb_language_get_default (void)
 
 /* hb_script_t */
 
+/**
+ * hb_script_from_iso15924_tag:
+ * @tag: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag)
 {
@@ -264,7 +372,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
     return HB_SCRIPT_INVALID;
 
   /* Be lenient, adjust case (one capital letter followed by three small letters) */
-  tag = (tag & 0xDFDFDFDF) | 0x00202020;
+  tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
 
   switch (tag) {
 
@@ -284,25 +392,56 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
   }
 
   /* If it looks right, just use the tag as a script */
-  if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060)
+  if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
     return (hb_script_t) tag;
 
   /* Otherwise, return unknown */
   return HB_SCRIPT_UNKNOWN;
 }
 
+/**
+ * hb_script_from_string:
+ * @s: (array length=len) (element-type uint8_t): 
+ * @len: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_script_t
 hb_script_from_string (const char *s, int len)
 {
   return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
 }
 
+/**
+ * hb_script_to_iso15924_tag:
+ * @script: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_tag_t
 hb_script_to_iso15924_tag (hb_script_t script)
 {
   return (hb_tag_t) script;
 }
 
+/**
+ * hb_script_get_horizontal_direction:
+ * @script: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_direction_t
 hb_script_get_horizontal_direction (hb_script_t script)
 {
@@ -346,6 +485,14 @@ hb_script_get_horizontal_direction (hb_script_t script)
     case HB_SCRIPT_MEROITIC_CURSIVE:
     case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
 
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_MENDE_KIKAKUI:
+    case HB_SCRIPT_NABATAEAN:
+    case HB_SCRIPT_OLD_NORTH_ARABIAN:
+    case HB_SCRIPT_PALMYRENE:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+
       return HB_DIRECTION_RTL;
   }
 
@@ -359,8 +506,7 @@ bool
 hb_user_data_array_t::set (hb_user_data_key_t *key,
                           void *              data,
                           hb_destroy_func_t   destroy,
-                          hb_bool_t           replace,
-                          hb_mutex_t         &lock)
+                          hb_bool_t           replace)
 {
   if (!key)
     return false;
@@ -378,23 +524,26 @@ hb_user_data_array_t::set (hb_user_data_key_t *key,
 }
 
 void *
-hb_user_data_array_t::get (hb_user_data_key_t *key,
-                          hb_mutex_t         &lock)
+hb_user_data_array_t::get (hb_user_data_key_t *key)
 {
   hb_user_data_item_t item = {NULL };
 
   return items.find (key, &item, lock) ? item.data : NULL;
 }
 
-void
-hb_user_data_array_t::finish (hb_mutex_t &lock)
-{
-  items.finish (lock);
-}
-
 
 /* hb_version */
 
+/**
+ * hb_version:
+ * @major: (out): Library major version component.
+ * @minor: (out): Library minor version component.
+ * @micro: (out): Library micro version component.
+ *
+ * Returns library version as three integer components.
+ *
+ * Since: 1.0
+ **/
 void
 hb_version (unsigned int *major,
            unsigned int *minor,
@@ -405,18 +554,37 @@ hb_version (unsigned int *major,
   *micro = HB_VERSION_MICRO;
 }
 
+/**
+ * hb_version_string:
+ *
+ * Returns library version as a string with three components.
+ *
+ * Return value: library version string.
+ *
+ * Since: 1.0
+ **/
 const char *
 hb_version_string (void)
 {
   return HB_VERSION_STRING;
 }
 
+/**
+ * hb_version_atleast:
+ * @major: 
+ * @minor: 
+ * @micro: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_version_check (unsigned int major,
-                 unsigned int minor,
-                 unsigned int micro)
+hb_version_atleast (unsigned int major,
+                   unsigned int minor,
+                   unsigned int micro)
 {
-  return HB_VERSION_CHECK (major, minor, micro);
+  return HB_VERSION_ATLEAST (major, minor, micro);
 }
-
-
index 562b04c..b6ce3f7 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef HB_COMMON_H
 #define HB_COMMON_H
 
+#ifndef HB_BEGIN_DECLS
 # ifdef __cplusplus
 #  define HB_BEGIN_DECLS       extern "C" {
 #  define HB_END_DECLS         }
@@ -40,8 +41,7 @@
 #  define HB_BEGIN_DECLS
 #  define HB_END_DECLS
 # endif /* !__cplusplus */
-
-HB_BEGIN_DECLS
+#endif
 
 #if !defined (HB_DONT_DEFINE_STDINT)
 
@@ -67,6 +67,8 @@ typedef unsigned __int64 uint64_t;
 
 #endif
 
+HB_BEGIN_DECLS
+
 
 typedef int hb_bool_t;
 
@@ -88,13 +90,20 @@ typedef union _hb_var_int_t {
 
 typedef uint32_t hb_tag_t;
 
-#define HB_TAG(a,b,c,d) ((hb_tag_t)((((uint8_t)(a))<<24)|(((uint8_t)(b))<<16)|(((uint8_t)(c))<<8)|((uint8_t)(d))))
+#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
 #define HB_UNTAG(tag)   ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
 
 #define HB_TAG_NONE HB_TAG(0,0,0,0)
+#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
+#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
 
-/* len=-1 means str is NUL-terminated */
-hb_tag_t hb_tag_from_string (const char *str, int len);
+/* len=-1 means str is NUL-terminated. */
+hb_tag_t
+hb_tag_from_string (const char *str, int len);
+
+/* buf should have 4 bytes. */
+void
+hb_tag_to_string (hb_tag_t tag, char *buf);
 
 
 /* hb_direction_t */
@@ -114,17 +123,18 @@ hb_direction_from_string (const char *str, int len);
 const char *
 hb_direction_to_string (hb_direction_t direction);
 
+#define HB_DIRECTION_IS_VALID(dir)     ((((unsigned int) (dir)) & ~3U) == 4)
+/* Direction must be valid for the following */
 #define HB_DIRECTION_IS_HORIZONTAL(dir)        ((((unsigned int) (dir)) & ~1U) == 4)
 #define HB_DIRECTION_IS_VERTICAL(dir)  ((((unsigned int) (dir)) & ~1U) == 6)
 #define HB_DIRECTION_IS_FORWARD(dir)   ((((unsigned int) (dir)) & ~2U) == 4)
 #define HB_DIRECTION_IS_BACKWARD(dir)  ((((unsigned int) (dir)) & ~2U) == 5)
-#define HB_DIRECTION_IS_VALID(dir)     ((((unsigned int) (dir)) & ~3U) == 4)
-#define HB_DIRECTION_REVERSE(dir)      ((hb_direction_t) (((unsigned int) (dir)) ^ 1)) /* Direction must be valid */
+#define HB_DIRECTION_REVERSE(dir)      ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
 
 
 /* hb_language_t */
 
-typedef struct _hb_language_t *hb_language_t;
+typedef const struct hb_language_impl_t *hb_language_t;
 
 /* len=-1 means str is NUL-terminated */
 hb_language_t
@@ -139,178 +149,166 @@ hb_language_t
 hb_language_get_default (void);
 
 
-/* hb_unicode_general_category_t */
-
-typedef enum
-{
-  HB_UNICODE_GENERAL_CATEGORY_CONTROL,                 /* Cc */
-  HB_UNICODE_GENERAL_CATEGORY_FORMAT,                  /* Cf */
-  HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,              /* Cn */
-  HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE,             /* Co */
-  HB_UNICODE_GENERAL_CATEGORY_SURROGATE,               /* Cs */
-  HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER,                /* Ll */
-  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER,         /* Lm */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER,            /* Lo */
-  HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER,                /* Lt */
-  HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER,                /* Lu */
-  HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK,            /* Mc */
-  HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK,          /* Me */
-  HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK,                /* Mn */
-  HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER,          /* Nd */
-  HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER,           /* Nl */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER,            /* No */
-  HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION,     /* Pc */
-  HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION,                /* Pd */
-  HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION,       /* Pe */
-  HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION,       /* Pf */
-  HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION,     /* Pi */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION,       /* Po */
-  HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION,                /* Ps */
-  HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL,         /* Sc */
-  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL,         /* Sk */
-  HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL,             /* Sm */
-  HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL,            /* So */
-  HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR,          /* Zl */
-  HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR,     /* Zp */
-  HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR          /* Zs */
-} hb_unicode_general_category_t;
-
-
 /* hb_script_t */
 
 /* http://unicode.org/iso15924/ */
 /* http://goo.gl/x9ilM */
+/* Unicode Character Database property: Script (sc) */
 typedef enum
 {
-  /* Unicode-1.1 additions */
-  HB_SCRIPT_COMMON                     = HB_TAG ('Z','y','y','y'),
-  HB_SCRIPT_ARABIC                     = HB_TAG ('A','r','a','b'),
-  HB_SCRIPT_ARMENIAN                   = HB_TAG ('A','r','m','n'),
-  HB_SCRIPT_BENGALI                    = HB_TAG ('B','e','n','g'),
-  HB_SCRIPT_BOPOMOFO                   = HB_TAG ('B','o','p','o'),
-  HB_SCRIPT_CANADIAN_ABORIGINAL                = HB_TAG ('C','a','n','s'),
-  HB_SCRIPT_CHEROKEE                   = HB_TAG ('C','h','e','r'),
-  HB_SCRIPT_COPTIC                     = HB_TAG ('C','o','p','t'),
-  HB_SCRIPT_CYRILLIC                   = HB_TAG ('C','y','r','l'),
-  HB_SCRIPT_DEVANAGARI                 = HB_TAG ('D','e','v','a'),
-  HB_SCRIPT_GEORGIAN                   = HB_TAG ('G','e','o','r'),
-  HB_SCRIPT_GREEK                      = HB_TAG ('G','r','e','k'),
-  HB_SCRIPT_GUJARATI                   = HB_TAG ('G','u','j','r'),
-  HB_SCRIPT_GURMUKHI                   = HB_TAG ('G','u','r','u'),
-  HB_SCRIPT_HANGUL                     = HB_TAG ('H','a','n','g'),
-  HB_SCRIPT_HAN                                = HB_TAG ('H','a','n','i'),
-  HB_SCRIPT_HEBREW                     = HB_TAG ('H','e','b','r'),
-  HB_SCRIPT_HIRAGANA                   = HB_TAG ('H','i','r','a'),
-  HB_SCRIPT_INHERITED                  = HB_TAG ('Z','i','n','h'),
-  HB_SCRIPT_KANNADA                    = HB_TAG ('K','n','d','a'),
-  HB_SCRIPT_KATAKANA                   = HB_TAG ('K','a','n','a'),
-  HB_SCRIPT_LAO                                = HB_TAG ('L','a','o','o'),
-  HB_SCRIPT_LATIN                      = HB_TAG ('L','a','t','n'),
-  HB_SCRIPT_MALAYALAM                  = HB_TAG ('M','l','y','m'),
-  HB_SCRIPT_MONGOLIAN                  = HB_TAG ('M','o','n','g'),
-  HB_SCRIPT_OGHAM                      = HB_TAG ('O','g','a','m'),
-  HB_SCRIPT_ORIYA                      = HB_TAG ('O','r','y','a'),
-  HB_SCRIPT_RUNIC                      = HB_TAG ('R','u','n','r'),
-  HB_SCRIPT_SYRIAC                     = HB_TAG ('S','y','r','c'),
-  HB_SCRIPT_TAMIL                      = HB_TAG ('T','a','m','l'),
-  HB_SCRIPT_TELUGU                     = HB_TAG ('T','e','l','u'),
-  HB_SCRIPT_THAI                       = HB_TAG ('T','h','a','i'),
-  HB_SCRIPT_YI                         = HB_TAG ('Y','i','i','i'),
-
-  /* Unicode-2.0 additions */
-  HB_SCRIPT_TIBETAN                    = HB_TAG ('T','i','b','t'),
-
-  /* Unicode-3.0 additions */
-  HB_SCRIPT_ETHIOPIC                   = HB_TAG ('E','t','h','i'),
-  HB_SCRIPT_KHMER                      = HB_TAG ('K','h','m','r'),
-  HB_SCRIPT_MYANMAR                    = HB_TAG ('M','y','m','r'),
-  HB_SCRIPT_SINHALA                    = HB_TAG ('S','i','n','h'),
-  HB_SCRIPT_THAANA                     = HB_TAG ('T','h','a','a'),
-
-  /* Unicode-3.1 additions */
-  HB_SCRIPT_DESERET                    = HB_TAG ('D','s','r','t'),
-  HB_SCRIPT_GOTHIC                     = HB_TAG ('G','o','t','h'),
-  HB_SCRIPT_OLD_ITALIC                 = HB_TAG ('I','t','a','l'),
-
-  /* Unicode-3.2 additions */
-  HB_SCRIPT_BUHID                      = HB_TAG ('B','u','h','d'),
-  HB_SCRIPT_HANUNOO                    = HB_TAG ('H','a','n','o'),
-  HB_SCRIPT_TAGALOG                    = HB_TAG ('T','g','l','g'),
-  HB_SCRIPT_TAGBANWA                   = HB_TAG ('T','a','g','b'),
-
-  /* Unicode-4.0 additions */
-  HB_SCRIPT_BRAILLE                    = HB_TAG ('B','r','a','i'),
-  HB_SCRIPT_CYPRIOT                    = HB_TAG ('C','p','r','t'),
-  HB_SCRIPT_LIMBU                      = HB_TAG ('L','i','m','b'),
-  HB_SCRIPT_LINEAR_B                   = HB_TAG ('L','i','n','b'),
-  HB_SCRIPT_OSMANYA                    = HB_TAG ('O','s','m','a'),
-  HB_SCRIPT_SHAVIAN                    = HB_TAG ('S','h','a','w'),
-  HB_SCRIPT_TAI_LE                     = HB_TAG ('T','a','l','e'),
-  HB_SCRIPT_UGARITIC                   = HB_TAG ('U','g','a','r'),
-
-  /* Unicode-4.1 additions */
-  HB_SCRIPT_BUGINESE                   = HB_TAG ('B','u','g','i'),
-  HB_SCRIPT_GLAGOLITIC                 = HB_TAG ('G','l','a','g'),
-  HB_SCRIPT_KHAROSHTHI                 = HB_TAG ('K','h','a','r'),
-  HB_SCRIPT_NEW_TAI_LUE                        = HB_TAG ('T','a','l','u'),
-  HB_SCRIPT_OLD_PERSIAN                        = HB_TAG ('X','p','e','o'),
-  HB_SCRIPT_SYLOTI_NAGRI               = HB_TAG ('S','y','l','o'),
-  HB_SCRIPT_TIFINAGH                   = HB_TAG ('T','f','n','g'),
-
-  /* Unicode-5.0 additions */
-  HB_SCRIPT_BALINESE                   = HB_TAG ('B','a','l','i'),
-  HB_SCRIPT_CUNEIFORM                  = HB_TAG ('X','s','u','x'),
-  HB_SCRIPT_NKO                                = HB_TAG ('N','k','o','o'),
-  HB_SCRIPT_PHAGS_PA                   = HB_TAG ('P','h','a','g'),
-  HB_SCRIPT_PHOENICIAN                 = HB_TAG ('P','h','n','x'),
-  HB_SCRIPT_UNKNOWN                    = HB_TAG ('Z','z','z','z'),
-
-  /* Unicode-5.1 additions */
-  HB_SCRIPT_CARIAN                     = HB_TAG ('C','a','r','i'),
-  HB_SCRIPT_CHAM                       = HB_TAG ('C','h','a','m'),
-  HB_SCRIPT_KAYAH_LI                   = HB_TAG ('K','a','l','i'),
-  HB_SCRIPT_LEPCHA                     = HB_TAG ('L','e','p','c'),
-  HB_SCRIPT_LYCIAN                     = HB_TAG ('L','y','c','i'),
-  HB_SCRIPT_LYDIAN                     = HB_TAG ('L','y','d','i'),
-  HB_SCRIPT_OL_CHIKI                   = HB_TAG ('O','l','c','k'),
-  HB_SCRIPT_REJANG                     = HB_TAG ('R','j','n','g'),
-  HB_SCRIPT_SAURASHTRA                 = HB_TAG ('S','a','u','r'),
-  HB_SCRIPT_SUNDANESE                  = HB_TAG ('S','u','n','d'),
-  HB_SCRIPT_VAI                                = HB_TAG ('V','a','i','i'),
-
-  /* Unicode-5.2 additions */
-  HB_SCRIPT_AVESTAN                    = HB_TAG ('A','v','s','t'),
-  HB_SCRIPT_BAMUM                      = HB_TAG ('B','a','m','u'),
-  HB_SCRIPT_EGYPTIAN_HIEROGLYPHS       = HB_TAG ('E','g','y','p'),
-  HB_SCRIPT_IMPERIAL_ARAMAIC           = HB_TAG ('A','r','m','i'),
-  HB_SCRIPT_INSCRIPTIONAL_PAHLAVI      = HB_TAG ('P','h','l','i'),
-  HB_SCRIPT_INSCRIPTIONAL_PARTHIAN     = HB_TAG ('P','r','t','i'),
-  HB_SCRIPT_JAVANESE                   = HB_TAG ('J','a','v','a'),
-  HB_SCRIPT_KAITHI                     = HB_TAG ('K','t','h','i'),
-  HB_SCRIPT_LISU                       = HB_TAG ('L','i','s','u'),
-  HB_SCRIPT_MEETEI_MAYEK               = HB_TAG ('M','t','e','i'),
-  HB_SCRIPT_OLD_SOUTH_ARABIAN          = HB_TAG ('S','a','r','b'),
-  HB_SCRIPT_OLD_TURKIC                 = HB_TAG ('O','r','k','h'),
-  HB_SCRIPT_SAMARITAN                  = HB_TAG ('S','a','m','r'),
-  HB_SCRIPT_TAI_THAM                   = HB_TAG ('L','a','n','a'),
-  HB_SCRIPT_TAI_VIET                   = HB_TAG ('T','a','v','t'),
-
-  /* Unicode-6.0 additions */
-  HB_SCRIPT_BATAK                      = HB_TAG ('B','a','t','k'),
-  HB_SCRIPT_BRAHMI                     = HB_TAG ('B','r','a','h'),
-  HB_SCRIPT_MANDAIC                    = HB_TAG ('M','a','n','d'),
-
-  /* Unicode-6.1 additions */
-  HB_SCRIPT_CHAKMA                     = HB_TAG ('C','a','k','m'),
-  HB_SCRIPT_MEROITIC_CURSIVE           = HB_TAG ('M','e','r','c'),
-  HB_SCRIPT_MEROITIC_HIEROGLYPHS       = HB_TAG ('M','e','r','o'),
-  HB_SCRIPT_MIAO                       = HB_TAG ('P','l','r','d'),
-  HB_SCRIPT_SHARADA                    = HB_TAG ('S','h','r','d'),
-  HB_SCRIPT_SORA_SOMPENG               = HB_TAG ('S','o','r','a'),
-  HB_SCRIPT_TAKRI                      = HB_TAG ('T','a','k','r'),
-
-  /* No script set */
-  HB_SCRIPT_INVALID                    = HB_TAG_NONE
+  /*1.1*/ HB_SCRIPT_COMMON                     = HB_TAG ('Z','y','y','y'),
+  /*1.1*/ HB_SCRIPT_INHERITED                  = HB_TAG ('Z','i','n','h'),
+  /*5.0*/ HB_SCRIPT_UNKNOWN                    = HB_TAG ('Z','z','z','z'),
+
+  /*1.1*/ HB_SCRIPT_ARABIC                     = HB_TAG ('A','r','a','b'),
+  /*1.1*/ HB_SCRIPT_ARMENIAN                   = HB_TAG ('A','r','m','n'),
+  /*1.1*/ HB_SCRIPT_BENGALI                    = HB_TAG ('B','e','n','g'),
+  /*1.1*/ HB_SCRIPT_CYRILLIC                   = HB_TAG ('C','y','r','l'),
+  /*1.1*/ HB_SCRIPT_DEVANAGARI                 = HB_TAG ('D','e','v','a'),
+  /*1.1*/ HB_SCRIPT_GEORGIAN                   = HB_TAG ('G','e','o','r'),
+  /*1.1*/ HB_SCRIPT_GREEK                      = HB_TAG ('G','r','e','k'),
+  /*1.1*/ HB_SCRIPT_GUJARATI                   = HB_TAG ('G','u','j','r'),
+  /*1.1*/ HB_SCRIPT_GURMUKHI                   = HB_TAG ('G','u','r','u'),
+  /*1.1*/ HB_SCRIPT_HANGUL                     = HB_TAG ('H','a','n','g'),
+  /*1.1*/ HB_SCRIPT_HAN                                = HB_TAG ('H','a','n','i'),
+  /*1.1*/ HB_SCRIPT_HEBREW                     = HB_TAG ('H','e','b','r'),
+  /*1.1*/ HB_SCRIPT_HIRAGANA                   = HB_TAG ('H','i','r','a'),
+  /*1.1*/ HB_SCRIPT_KANNADA                    = HB_TAG ('K','n','d','a'),
+  /*1.1*/ HB_SCRIPT_KATAKANA                   = HB_TAG ('K','a','n','a'),
+  /*1.1*/ HB_SCRIPT_LAO                                = HB_TAG ('L','a','o','o'),
+  /*1.1*/ HB_SCRIPT_LATIN                      = HB_TAG ('L','a','t','n'),
+  /*1.1*/ HB_SCRIPT_MALAYALAM                  = HB_TAG ('M','l','y','m'),
+  /*1.1*/ HB_SCRIPT_ORIYA                      = HB_TAG ('O','r','y','a'),
+  /*1.1*/ HB_SCRIPT_TAMIL                      = HB_TAG ('T','a','m','l'),
+  /*1.1*/ HB_SCRIPT_TELUGU                     = HB_TAG ('T','e','l','u'),
+  /*1.1*/ HB_SCRIPT_THAI                       = HB_TAG ('T','h','a','i'),
+
+  /*2.0*/ HB_SCRIPT_TIBETAN                    = HB_TAG ('T','i','b','t'),
+
+  /*3.0*/ HB_SCRIPT_BOPOMOFO                   = HB_TAG ('B','o','p','o'),
+  /*3.0*/ HB_SCRIPT_BRAILLE                    = HB_TAG ('B','r','a','i'),
+  /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS         = HB_TAG ('C','a','n','s'),
+  /*3.0*/ HB_SCRIPT_CHEROKEE                   = HB_TAG ('C','h','e','r'),
+  /*3.0*/ HB_SCRIPT_ETHIOPIC                   = HB_TAG ('E','t','h','i'),
+  /*3.0*/ HB_SCRIPT_KHMER                      = HB_TAG ('K','h','m','r'),
+  /*3.0*/ HB_SCRIPT_MONGOLIAN                  = HB_TAG ('M','o','n','g'),
+  /*3.0*/ HB_SCRIPT_MYANMAR                    = HB_TAG ('M','y','m','r'),
+  /*3.0*/ HB_SCRIPT_OGHAM                      = HB_TAG ('O','g','a','m'),
+  /*3.0*/ HB_SCRIPT_RUNIC                      = HB_TAG ('R','u','n','r'),
+  /*3.0*/ HB_SCRIPT_SINHALA                    = HB_TAG ('S','i','n','h'),
+  /*3.0*/ HB_SCRIPT_SYRIAC                     = HB_TAG ('S','y','r','c'),
+  /*3.0*/ HB_SCRIPT_THAANA                     = HB_TAG ('T','h','a','a'),
+  /*3.0*/ HB_SCRIPT_YI                         = HB_TAG ('Y','i','i','i'),
+
+  /*3.1*/ HB_SCRIPT_DESERET                    = HB_TAG ('D','s','r','t'),
+  /*3.1*/ HB_SCRIPT_GOTHIC                     = HB_TAG ('G','o','t','h'),
+  /*3.1*/ HB_SCRIPT_OLD_ITALIC                 = HB_TAG ('I','t','a','l'),
+
+  /*3.2*/ HB_SCRIPT_BUHID                      = HB_TAG ('B','u','h','d'),
+  /*3.2*/ HB_SCRIPT_HANUNOO                    = HB_TAG ('H','a','n','o'),
+  /*3.2*/ HB_SCRIPT_TAGALOG                    = HB_TAG ('T','g','l','g'),
+  /*3.2*/ HB_SCRIPT_TAGBANWA                   = HB_TAG ('T','a','g','b'),
+
+  /*4.0*/ HB_SCRIPT_CYPRIOT                    = HB_TAG ('C','p','r','t'),
+  /*4.0*/ HB_SCRIPT_LIMBU                      = HB_TAG ('L','i','m','b'),
+  /*4.0*/ HB_SCRIPT_LINEAR_B                   = HB_TAG ('L','i','n','b'),
+  /*4.0*/ HB_SCRIPT_OSMANYA                    = HB_TAG ('O','s','m','a'),
+  /*4.0*/ HB_SCRIPT_SHAVIAN                    = HB_TAG ('S','h','a','w'),
+  /*4.0*/ HB_SCRIPT_TAI_LE                     = HB_TAG ('T','a','l','e'),
+  /*4.0*/ HB_SCRIPT_UGARITIC                   = HB_TAG ('U','g','a','r'),
+
+  /*4.1*/ HB_SCRIPT_BUGINESE                   = HB_TAG ('B','u','g','i'),
+  /*4.1*/ HB_SCRIPT_COPTIC                     = HB_TAG ('C','o','p','t'),
+  /*4.1*/ HB_SCRIPT_GLAGOLITIC                 = HB_TAG ('G','l','a','g'),
+  /*4.1*/ HB_SCRIPT_KHAROSHTHI                 = HB_TAG ('K','h','a','r'),
+  /*4.1*/ HB_SCRIPT_NEW_TAI_LUE                        = HB_TAG ('T','a','l','u'),
+  /*4.1*/ HB_SCRIPT_OLD_PERSIAN                        = HB_TAG ('X','p','e','o'),
+  /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI               = HB_TAG ('S','y','l','o'),
+  /*4.1*/ HB_SCRIPT_TIFINAGH                   = HB_TAG ('T','f','n','g'),
+
+  /*5.0*/ HB_SCRIPT_BALINESE                   = HB_TAG ('B','a','l','i'),
+  /*5.0*/ HB_SCRIPT_CUNEIFORM                  = HB_TAG ('X','s','u','x'),
+  /*5.0*/ HB_SCRIPT_NKO                                = HB_TAG ('N','k','o','o'),
+  /*5.0*/ HB_SCRIPT_PHAGS_PA                   = HB_TAG ('P','h','a','g'),
+  /*5.0*/ HB_SCRIPT_PHOENICIAN                 = HB_TAG ('P','h','n','x'),
+
+  /*5.1*/ HB_SCRIPT_CARIAN                     = HB_TAG ('C','a','r','i'),
+  /*5.1*/ HB_SCRIPT_CHAM                       = HB_TAG ('C','h','a','m'),
+  /*5.1*/ HB_SCRIPT_KAYAH_LI                   = HB_TAG ('K','a','l','i'),
+  /*5.1*/ HB_SCRIPT_LEPCHA                     = HB_TAG ('L','e','p','c'),
+  /*5.1*/ HB_SCRIPT_LYCIAN                     = HB_TAG ('L','y','c','i'),
+  /*5.1*/ HB_SCRIPT_LYDIAN                     = HB_TAG ('L','y','d','i'),
+  /*5.1*/ HB_SCRIPT_OL_CHIKI                   = HB_TAG ('O','l','c','k'),
+  /*5.1*/ HB_SCRIPT_REJANG                     = HB_TAG ('R','j','n','g'),
+  /*5.1*/ HB_SCRIPT_SAURASHTRA                 = HB_TAG ('S','a','u','r'),
+  /*5.1*/ HB_SCRIPT_SUNDANESE                  = HB_TAG ('S','u','n','d'),
+  /*5.1*/ HB_SCRIPT_VAI                                = HB_TAG ('V','a','i','i'),
+
+  /*5.2*/ HB_SCRIPT_AVESTAN                    = HB_TAG ('A','v','s','t'),
+  /*5.2*/ HB_SCRIPT_BAMUM                      = HB_TAG ('B','a','m','u'),
+  /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS       = HB_TAG ('E','g','y','p'),
+  /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC           = HB_TAG ('A','r','m','i'),
+  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI      = HB_TAG ('P','h','l','i'),
+  /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN     = HB_TAG ('P','r','t','i'),
+  /*5.2*/ HB_SCRIPT_JAVANESE                   = HB_TAG ('J','a','v','a'),
+  /*5.2*/ HB_SCRIPT_KAITHI                     = HB_TAG ('K','t','h','i'),
+  /*5.2*/ HB_SCRIPT_LISU                       = HB_TAG ('L','i','s','u'),
+  /*5.2*/ HB_SCRIPT_MEETEI_MAYEK               = HB_TAG ('M','t','e','i'),
+  /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN          = HB_TAG ('S','a','r','b'),
+  /*5.2*/ HB_SCRIPT_OLD_TURKIC                 = HB_TAG ('O','r','k','h'),
+  /*5.2*/ HB_SCRIPT_SAMARITAN                  = HB_TAG ('S','a','m','r'),
+  /*5.2*/ HB_SCRIPT_TAI_THAM                   = HB_TAG ('L','a','n','a'),
+  /*5.2*/ HB_SCRIPT_TAI_VIET                   = HB_TAG ('T','a','v','t'),
+
+  /*6.0*/ HB_SCRIPT_BATAK                      = HB_TAG ('B','a','t','k'),
+  /*6.0*/ HB_SCRIPT_BRAHMI                     = HB_TAG ('B','r','a','h'),
+  /*6.0*/ HB_SCRIPT_MANDAIC                    = HB_TAG ('M','a','n','d'),
+
+  /*6.1*/ HB_SCRIPT_CHAKMA                     = HB_TAG ('C','a','k','m'),
+  /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE           = HB_TAG ('M','e','r','c'),
+  /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS       = HB_TAG ('M','e','r','o'),
+  /*6.1*/ HB_SCRIPT_MIAO                       = HB_TAG ('P','l','r','d'),
+  /*6.1*/ HB_SCRIPT_SHARADA                    = HB_TAG ('S','h','r','d'),
+  /*6.1*/ HB_SCRIPT_SORA_SOMPENG               = HB_TAG ('S','o','r','a'),
+  /*6.1*/ HB_SCRIPT_TAKRI                      = HB_TAG ('T','a','k','r'),
+
+  /*7.0*/ HB_SCRIPT_BASSA_VAH                  = HB_TAG ('B','a','s','s'),
+  /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN         = HB_TAG ('A','g','h','b'),
+  /*7.0*/ HB_SCRIPT_DUPLOYAN                   = HB_TAG ('D','u','p','l'),
+  /*7.0*/ HB_SCRIPT_ELBASAN                    = HB_TAG ('E','l','b','a'),
+  /*7.0*/ HB_SCRIPT_GRANTHA                    = HB_TAG ('G','r','a','n'),
+  /*7.0*/ HB_SCRIPT_KHOJKI                     = HB_TAG ('K','h','o','j'),
+  /*7.0*/ HB_SCRIPT_KHUDAWADI                  = HB_TAG ('S','i','n','d'),
+  /*7.0*/ HB_SCRIPT_LINEAR_A                   = HB_TAG ('L','i','n','a'),
+  /*7.0*/ HB_SCRIPT_MAHAJANI                   = HB_TAG ('M','a','h','j'),
+  /*7.0*/ HB_SCRIPT_MANICHAEAN                 = HB_TAG ('M','a','n','i'),
+  /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI              = HB_TAG ('M','e','n','d'),
+  /*7.0*/ HB_SCRIPT_MODI                       = HB_TAG ('M','o','d','i'),
+  /*7.0*/ HB_SCRIPT_MRO                                = HB_TAG ('M','r','o','o'),
+  /*7.0*/ HB_SCRIPT_NABATAEAN                  = HB_TAG ('N','b','a','t'),
+  /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN          = HB_TAG ('N','a','r','b'),
+  /*7.0*/ HB_SCRIPT_OLD_PERMIC                 = HB_TAG ('P','e','r','m'),
+  /*7.0*/ HB_SCRIPT_PAHAWH_HMONG               = HB_TAG ('H','m','n','g'),
+  /*7.0*/ HB_SCRIPT_PALMYRENE                  = HB_TAG ('P','a','l','m'),
+  /*7.0*/ HB_SCRIPT_PAU_CIN_HAU                        = HB_TAG ('P','a','u','c'),
+  /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI            = HB_TAG ('P','h','l','p'),
+  /*7.0*/ HB_SCRIPT_SIDDHAM                    = HB_TAG ('S','i','d','d'),
+  /*7.0*/ HB_SCRIPT_TIRHUTA                    = HB_TAG ('T','i','r','h'),
+  /*7.0*/ HB_SCRIPT_WARANG_CITI                        = HB_TAG ('W','a','r','a'),
+
+  /* No script set. */
+  HB_SCRIPT_INVALID                            = HB_TAG_NONE,
+
+  /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
+   * without risking undefined behavior.  Include both a signed and unsigned max,
+   * since technically enums are int, and indeed, hb_script_t ends up being signed.
+   * See this thread for technicalities:
+   *
+   *   http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
+   */
+  _HB_SCRIPT_MAX_VALUE                         = HB_TAG_MAX, /*< skip >*/
+  _HB_SCRIPT_MAX_VALUE_SIGNED                  = HB_TAG_MAX_SIGNED /*< skip >*/
+
 } hb_script_t;
 
 
@@ -319,7 +317,7 @@ typedef enum
 hb_script_t
 hb_script_from_iso15924_tag (hb_tag_t tag);
 
-/* suger for tag_from_string() then script_from_iso15924_tag */
+/* sugar for tag_from_string() then script_from_iso15924_tag */
 /* len=-1 means s is NUL-terminated */
 hb_script_t
 hb_script_from_string (const char *s, int len);
@@ -333,7 +331,7 @@ hb_script_get_horizontal_direction (hb_script_t script);
 
 /* User data */
 
-typedef struct _hb_user_data_key_t {
+typedef struct hb_user_data_key_t {
   /*< private >*/
   char unused;
 } hb_user_data_key_t;
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
new file mode 100644 (file)
index 0000000..4a45175
--- /dev/null
@@ -0,0 +1,1194 @@
+/*
+ * 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
+ */
+
+#define HB_SHAPER coretext
+#define hb_coretext_shaper_face_data_t CGFont
+#include "hb-shaper-impl-private.hh"
+
+#include "hb-coretext.h"
+
+
+#ifndef HB_DEBUG_CORETEXT
+#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
+#endif
+
+
+static void
+release_table_data (void *user_data)
+{
+  CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
+  CFRelease(cf_data);
+}
+
+static hb_blob_t *
+reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
+  CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
+  if (unlikely (!cf_data))
+    return NULL;
+
+  const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
+  const size_t length = CFDataGetLength (cf_data);
+  if (!data || !length)
+    return NULL;
+
+  return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
+                        reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
+                        release_table_data);
+}
+
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font)
+{
+  return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
+}
+
+
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
+
+
+/*
+ * shaper face data
+ */
+
+static void
+release_data (void *info, const void *data, size_t size)
+{
+  assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
+          hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
+
+  hb_blob_destroy ((hb_blob_t *) info);
+}
+
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
+{
+  hb_coretext_shaper_face_data_t *data = NULL;
+
+  if (face->destroy == (hb_destroy_func_t) CGFontRelease)
+  {
+    data = CGFontRetain ((CGFontRef) face->user_data);
+  }
+  else
+  {
+    hb_blob_t *blob = hb_face_reference_blob (face);
+    unsigned int blob_length;
+    const char *blob_data = hb_blob_get_data (blob, &blob_length);
+    if (unlikely (!blob_length))
+      DEBUG_MSG (CORETEXT, face, "Face has empty blob");
+
+    CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
+    if (likely (provider))
+    {
+      data = CGFontCreateWithDataProvider (provider);
+      CGDataProviderRelease (provider);
+    }
+  }
+
+  if (unlikely (!data)) {
+    DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+  }
+
+  return data;
+}
+
+void
+_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
+{
+  CFRelease (data);
+}
+
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face)
+{
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  return face_data;
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_coretext_shaper_font_data_t {
+  CTFontRef ct_font;
+  CGFloat x_mult, y_mult; /* From CT space to HB space. */
+};
+
+hb_coretext_shaper_font_data_t *
+_hb_coretext_shaper_font_data_create (hb_font_t *font)
+{
+  if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
+
+  hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  hb_face_t *face = font->face;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+  /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
+  CGFloat font_size = 36.; /* Default... */
+  /* No idea if the following is even a good idea. */
+  if (font->y_ppem)
+    font_size = font->y_ppem;
+
+  if (font_size < 0)
+    font_size = -font_size;
+  data->x_mult = (CGFloat) font->x_scale / font_size;
+  data->y_mult = (CGFloat) font->y_scale / font_size;
+  data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
+  if (unlikely (!data->ct_font)) {
+    DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
+    free (data);
+    return NULL;
+  }
+
+  return data;
+}
+
+void
+_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
+{
+  CFRelease (data->ct_font);
+  free (data);
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_coretext_shaper_shape_plan_data_t {};
+
+hb_coretext_shaper_shape_plan_data_t *
+_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                            const hb_feature_t *user_features HB_UNUSED,
+                                            unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+  if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
+  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+  return font_data->ct_font;
+}
+
+
+/*
+ * shaper
+ */
+
+struct feature_record_t {
+  unsigned int feature;
+  unsigned int setting;
+};
+
+struct active_feature_t {
+  feature_record_t rec;
+  unsigned int order;
+
+  static int cmp (const active_feature_t *a, const active_feature_t *b) {
+    return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
+          a->order < b->order ? -1 : a->order > b->order ? 1 :
+          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;
+  }
+};
+
+struct feature_event_t {
+  unsigned int index;
+  bool start;
+  active_feature_t feature;
+
+  static int cmp (const feature_event_t *a, const feature_event_t *b) {
+    return a->index < b->index ? -1 : a->index > b->index ? 1 :
+          a->start < b->start ? -1 : a->start > b->start ? 1 :
+          active_feature_t::cmp (&a->feature, &b->feature);
+  }
+};
+
+struct range_record_t {
+  CTFontRef font;
+  unsigned int index_first; /* == start */
+  unsigned int index_last;  /* == end - 1 */
+};
+
+
+/* The following enum members are added in OS X 10.8. */
+#define kAltHalfWidthTextSelector              6
+#define kAltProportionalTextSelector           5
+#define kAlternateHorizKanaOffSelector         1
+#define kAlternateHorizKanaOnSelector          0
+#define kAlternateKanaType                     34
+#define kAlternateVertKanaOffSelector          3
+#define kAlternateVertKanaOnSelector           2
+#define kCaseSensitiveLayoutOffSelector                1
+#define kCaseSensitiveLayoutOnSelector         0
+#define kCaseSensitiveLayoutType               33
+#define kCaseSensitiveSpacingOffSelector       3
+#define kCaseSensitiveSpacingOnSelector                2
+#define kContextualAlternatesOffSelector       1
+#define kContextualAlternatesOnSelector                0
+#define kContextualAlternatesType              36
+#define kContextualLigaturesOffSelector                19
+#define kContextualLigaturesOnSelector         18
+#define kContextualSwashAlternatesOffSelector  5
+#define kContextualSwashAlternatesOnSelector   4
+#define kDefaultLowerCaseSelector              0
+#define kDefaultUpperCaseSelector              0
+#define kHistoricalLigaturesOffSelector                21
+#define kHistoricalLigaturesOnSelector         20
+#define kHojoCharactersSelector                        12
+#define kJIS2004CharactersSelector             11
+#define kLowerCasePetiteCapsSelector           2
+#define kLowerCaseSmallCapsSelector            1
+#define kLowerCaseType                         37
+#define kMathematicalGreekOffSelector          11
+#define kMathematicalGreekOnSelector           10
+#define kNLCCharactersSelector                 13
+#define kQuarterWidthTextSelector              4
+#define kScientificInferiorsSelector           4
+#define kStylisticAltEightOffSelector          17
+#define kStylisticAltEightOnSelector           16
+#define kStylisticAltEighteenOffSelector       37
+#define kStylisticAltEighteenOnSelector                36
+#define kStylisticAltElevenOffSelector         23
+#define kStylisticAltElevenOnSelector          22
+#define kStylisticAltFifteenOffSelector                31
+#define kStylisticAltFifteenOnSelector         30
+#define kStylisticAltFiveOffSelector           11
+#define kStylisticAltFiveOnSelector            10
+#define kStylisticAltFourOffSelector           9
+#define kStylisticAltFourOnSelector            8
+#define kStylisticAltFourteenOffSelector       29
+#define kStylisticAltFourteenOnSelector                28
+#define kStylisticAltNineOffSelector           19
+#define kStylisticAltNineOnSelector            18
+#define kStylisticAltNineteenOffSelector       39
+#define kStylisticAltNineteenOnSelector                38
+#define kStylisticAltOneOffSelector            3
+#define kStylisticAltOneOnSelector             2
+#define kStylisticAltSevenOffSelector          15
+#define kStylisticAltSevenOnSelector           14
+#define kStylisticAltSeventeenOffSelector      35
+#define kStylisticAltSeventeenOnSelector       34
+#define kStylisticAltSixOffSelector            13
+#define kStylisticAltSixOnSelector             12
+#define kStylisticAltSixteenOffSelector                33
+#define kStylisticAltSixteenOnSelector         32
+#define kStylisticAltTenOffSelector            21
+#define kStylisticAltTenOnSelector             20
+#define kStylisticAltThirteenOffSelector       27
+#define kStylisticAltThirteenOnSelector                26
+#define kStylisticAltThreeOffSelector          7
+#define kStylisticAltThreeOnSelector           6
+#define kStylisticAltTwelveOffSelector         25
+#define kStylisticAltTwelveOnSelector          24
+#define kStylisticAltTwentyOffSelector         41
+#define kStylisticAltTwentyOnSelector          40
+#define kStylisticAltTwoOffSelector            5
+#define kStylisticAltTwoOnSelector             4
+#define kStylisticAlternativesType             35
+#define kSwashAlternatesOffSelector            3
+#define kSwashAlternatesOnSelector             2
+#define kThirdWidthTextSelector                        3
+#define kTraditionalNamesCharactersSelector    14
+#define kUpperCasePetiteCapsSelector           2
+#define kUpperCaseSmallCapsSelector            1
+#define kUpperCaseType                         38
+
+/* Table data courtesy of Apple. */
+static const struct feature_mapping_t {
+    FourCharCode otFeatureTag;
+    uint16_t aatFeatureType;
+    uint16_t selectorToEnable;
+    uint16_t selectorToDisable;
+} feature_mappings[] = {
+    { 'c2pc',   kUpperCaseType,             kUpperCasePetiteCapsSelector,           kDefaultUpperCaseSelector },
+    { 'c2sc',   kUpperCaseType,             kUpperCaseSmallCapsSelector,            kDefaultUpperCaseSelector },
+    { 'calt',   kContextualAlternatesType,  kContextualAlternatesOnSelector,        kContextualAlternatesOffSelector },
+    { 'case',   kCaseSensitiveLayoutType,   kCaseSensitiveLayoutOnSelector,         kCaseSensitiveLayoutOffSelector },
+    { 'clig',   kLigaturesType,             kContextualLigaturesOnSelector,         kContextualLigaturesOffSelector },
+    { 'cpsp',   kCaseSensitiveLayoutType,   kCaseSensitiveSpacingOnSelector,        kCaseSensitiveSpacingOffSelector },
+    { 'cswh',   kContextualAlternatesType,  kContextualSwashAlternatesOnSelector,   kContextualSwashAlternatesOffSelector },
+    { 'dlig',   kLigaturesType,             kRareLigaturesOnSelector,               kRareLigaturesOffSelector },
+    { 'expt',   kCharacterShapeType,        kExpertCharactersSelector,              16 },
+    { 'frac',   kFractionsType,             kDiagonalFractionsSelector,             kNoFractionsSelector },
+    { 'fwid',   kTextSpacingType,           kMonospacedTextSelector,                7 },
+    { 'halt',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
+    { 'hist',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
+    { 'hkna',   kAlternateKanaType,         kAlternateHorizKanaOnSelector,          kAlternateHorizKanaOffSelector, },
+    { 'hlig',   kLigaturesType,             kHistoricalLigaturesOnSelector,         kHistoricalLigaturesOffSelector },
+    { 'hngl',   kTransliterationType,       kHanjaToHangulSelector,                 kNoTransliterationSelector },
+    { 'hojo',   kCharacterShapeType,        kHojoCharactersSelector,                16 },
+    { 'hwid',   kTextSpacingType,           kHalfWidthTextSelector,                 7 },
+    { 'ital',   kItalicCJKRomanType,        kCJKItalicRomanOnSelector,              kCJKItalicRomanOffSelector },
+    { 'jp04',   kCharacterShapeType,        kJIS2004CharactersSelector,             16 },
+    { 'jp78',   kCharacterShapeType,        kJIS1978CharactersSelector,             16 },
+    { 'jp83',   kCharacterShapeType,        kJIS1983CharactersSelector,             16 },
+    { 'jp90',   kCharacterShapeType,        kJIS1990CharactersSelector,             16 },
+    { 'liga',   kLigaturesType,             kCommonLigaturesOnSelector,             kCommonLigaturesOffSelector },
+    { 'lnum',   kNumberCaseType,            kUpperCaseNumbersSelector,              2 },
+    { 'mgrk',   kMathematicalExtrasType,    kMathematicalGreekOnSelector,           kMathematicalGreekOffSelector },
+    { 'nlck',   kCharacterShapeType,        kNLCCharactersSelector,                 16 },
+    { 'onum',   kNumberCaseType,            kLowerCaseNumbersSelector,              2 },
+    { 'ordn',   kVerticalPositionType,      kOrdinalsSelector,                      kNormalPositionSelector },
+    { 'palt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'pcap',   kLowerCaseType,             kLowerCasePetiteCapsSelector,           kDefaultLowerCaseSelector },
+    { 'pkna',   kTextSpacingType,           kProportionalTextSelector,              7 },
+    { 'pnum',   kNumberSpacingType,         kProportionalNumbersSelector,           4 },
+    { 'pwid',   kTextSpacingType,           kProportionalTextSelector,              7 },
+    { 'qwid',   kTextSpacingType,           kQuarterWidthTextSelector,              7 },
+    { 'ruby',   kRubyKanaType,              kRubyKanaOnSelector,                    kRubyKanaOffSelector },
+    { 'sinf',   kVerticalPositionType,      kScientificInferiorsSelector,           kNormalPositionSelector },
+    { 'smcp',   kLowerCaseType,             kLowerCaseSmallCapsSelector,            kDefaultLowerCaseSelector },
+    { 'smpl',   kCharacterShapeType,        kSimplifiedCharactersSelector,          16 },
+    { 'ss01',   kStylisticAlternativesType, kStylisticAltOneOnSelector,             kStylisticAltOneOffSelector },
+    { 'ss02',   kStylisticAlternativesType, kStylisticAltTwoOnSelector,             kStylisticAltTwoOffSelector },
+    { 'ss03',   kStylisticAlternativesType, kStylisticAltThreeOnSelector,           kStylisticAltThreeOffSelector },
+    { 'ss04',   kStylisticAlternativesType, kStylisticAltFourOnSelector,            kStylisticAltFourOffSelector },
+    { 'ss05',   kStylisticAlternativesType, kStylisticAltFiveOnSelector,            kStylisticAltFiveOffSelector },
+    { 'ss06',   kStylisticAlternativesType, kStylisticAltSixOnSelector,             kStylisticAltSixOffSelector },
+    { 'ss07',   kStylisticAlternativesType, kStylisticAltSevenOnSelector,           kStylisticAltSevenOffSelector },
+    { 'ss08',   kStylisticAlternativesType, kStylisticAltEightOnSelector,           kStylisticAltEightOffSelector },
+    { 'ss09',   kStylisticAlternativesType, kStylisticAltNineOnSelector,            kStylisticAltNineOffSelector },
+    { 'ss10',   kStylisticAlternativesType, kStylisticAltTenOnSelector,             kStylisticAltTenOffSelector },
+    { 'ss11',   kStylisticAlternativesType, kStylisticAltElevenOnSelector,          kStylisticAltElevenOffSelector },
+    { 'ss12',   kStylisticAlternativesType, kStylisticAltTwelveOnSelector,          kStylisticAltTwelveOffSelector },
+    { 'ss13',   kStylisticAlternativesType, kStylisticAltThirteenOnSelector,        kStylisticAltThirteenOffSelector },
+    { 'ss14',   kStylisticAlternativesType, kStylisticAltFourteenOnSelector,        kStylisticAltFourteenOffSelector },
+    { 'ss15',   kStylisticAlternativesType, kStylisticAltFifteenOnSelector,         kStylisticAltFifteenOffSelector },
+    { 'ss16',   kStylisticAlternativesType, kStylisticAltSixteenOnSelector,         kStylisticAltSixteenOffSelector },
+    { 'ss17',   kStylisticAlternativesType, kStylisticAltSeventeenOnSelector,       kStylisticAltSeventeenOffSelector },
+    { 'ss18',   kStylisticAlternativesType, kStylisticAltEighteenOnSelector,        kStylisticAltEighteenOffSelector },
+    { 'ss19',   kStylisticAlternativesType, kStylisticAltNineteenOnSelector,        kStylisticAltNineteenOffSelector },
+    { 'ss20',   kStylisticAlternativesType, kStylisticAltTwentyOnSelector,          kStylisticAltTwentyOffSelector },
+    { 'subs',   kVerticalPositionType,      kInferiorsSelector,                     kNormalPositionSelector },
+    { 'sups',   kVerticalPositionType,      kSuperiorsSelector,                     kNormalPositionSelector },
+    { 'swsh',   kContextualAlternatesType,  kSwashAlternatesOnSelector,             kSwashAlternatesOffSelector },
+    { 'titl',   kStyleOptionsType,          kTitlingCapsSelector,                   kNoStyleOptionsSelector },
+    { 'tnam',   kCharacterShapeType,        kTraditionalNamesCharactersSelector,    16 },
+    { 'tnum',   kNumberSpacingType,         kMonospacedNumbersSelector,             4 },
+    { 'trad',   kCharacterShapeType,        kTraditionalCharactersSelector,         16 },
+    { 'twid',   kTextSpacingType,           kThirdWidthTextSelector,                7 },
+    { 'unic',   kLetterCaseType,            14,                                     15 },
+    { 'valt',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'vert',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
+    { 'vhal',   kTextSpacingType,           kAltHalfWidthTextSelector,              7 },
+    { 'vkna',   kAlternateKanaType,         kAlternateVertKanaOnSelector,           kAlternateVertKanaOffSelector },
+    { 'vpal',   kTextSpacingType,           kAltProportionalTextSelector,           7 },
+    { 'vrt2',   kVerticalSubstitutionType,  kSubstituteVerticalFormsOnSelector,     kSubstituteVerticalFormsOffSelector },
+    { 'zero',   kTypographicExtrasType,     kSlashedZeroOnSelector,                 kSlashedZeroOffSelector },
+};
+
+static int
+_hb_feature_mapping_cmp (const void *key_, const void *entry_)
+{
+  unsigned int key = * (unsigned int *) key_;
+  const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
+  return key < entry->otFeatureTag ? -1 :
+        key > entry->otFeatureTag ? 1 :
+        0;
+}
+
+hb_bool_t
+_hb_coretext_shape (hb_shape_plan_t    *shape_plan,
+                   hb_font_t          *font,
+                    hb_buffer_t        *buffer,
+                    const hb_feature_t *features,
+                    unsigned int        num_features)
+{
+  hb_face_t *face = font->face;
+  hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+  /* Attach marks to their bases, to match the 'ot' shaper.
+   * Adapted from hb-ot-shape:hb_form_clusters().
+   * Note that this only makes us be closer to the 'ot' shaper,
+   * but by no means the same.  For example, if there's
+   * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
+   * continue pointing to B2 even though B2 was merged into B1's
+   * cluster... */
+  {
+    hb_unicode_funcs_t *unicode = buffer->unicode;
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 1; i < count; i++)
+      if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint)))
+       buffer->merge_clusters (i - 1, i + 1);
+  }
+
+  hb_auto_array_t<feature_record_t> feature_records;
+  hb_auto_array_t<range_record_t> range_records;
+
+  /*
+   * Set up features.
+   * (copied + modified from code from hb-uniscribe.cc)
+   */
+  if (num_features)
+  {
+    /* Sort features by start/end events. */
+    hb_auto_array_t<feature_event_t> feature_events;
+    for (unsigned int i = 0; i < num_features; i++)
+    {
+      const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
+                                                                              feature_mappings,
+                                                                              ARRAY_LENGTH (feature_mappings),
+                                                                              sizeof (feature_mappings[0]),
+                                                                              _hb_feature_mapping_cmp);
+      if (!mapping)
+        continue;
+
+      active_feature_t feature;
+      feature.rec.feature = mapping->aatFeatureType;
+      feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
+      feature.order = i;
+
+      feature_event_t *event;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+       goto fail_features;
+      event->index = features[i].start;
+      event->start = true;
+      event->feature = feature;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+       goto fail_features;
+      event->index = features[i].end;
+      event->start = false;
+      event->feature = feature;
+    }
+    feature_events.qsort ();
+    /* Add a strategic final event. */
+    {
+      active_feature_t feature;
+      feature.rec.feature = HB_TAG_NONE;
+      feature.rec.setting = 0;
+      feature.order = num_features + 1;
+
+      feature_event_t *event = feature_events.push ();
+      if (unlikely (!event))
+       goto fail_features;
+      event->index = 0; /* This value does magic. */
+      event->start = false;
+      event->feature = feature;
+    }
+
+    /* Scan events and save features for each range. */
+    hb_auto_array_t<active_feature_t> active_features;
+    unsigned int last_index = 0;
+    for (unsigned int i = 0; i < feature_events.len; i++)
+    {
+      feature_event_t *event = &feature_events[i];
+
+      if (event->index != last_index)
+      {
+        /* Save a snapshot of active features and the range. */
+       range_record_t *range = range_records.push ();
+       if (unlikely (!range))
+         goto fail_features;
+
+       if (active_features.len)
+       {
+         CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+         /* TODO sort and resolve conflicting features? */
+         /* active_features.qsort (); */
+         for (unsigned int j = 0; j < active_features.len; j++)
+         {
+           CFStringRef keys[2] = {
+             kCTFontFeatureTypeIdentifierKey,
+             kCTFontFeatureSelectorIdentifierKey
+           };
+           CFNumberRef values[2] = {
+             CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
+             CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
+           };
+           CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
+                                                      (const void **) keys,
+                                                      (const void **) values,
+                                                      2,
+                                                      &kCFTypeDictionaryKeyCallBacks,
+                                                      &kCFTypeDictionaryValueCallBacks);
+           CFRelease (values[0]);
+           CFRelease (values[1]);
+
+           CFArrayAppendValue (features_array, dict);
+           CFRelease (dict);
+
+         }
+
+         CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+                                                          (const void **) &kCTFontFeatureSettingsAttribute,
+                                                          (const void **) &features_array,
+                                                          1,
+                                                          &kCFTypeDictionaryKeyCallBacks,
+                                                          &kCFTypeDictionaryValueCallBacks);
+         CFRelease (features_array);
+
+         CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+         CFRelease (attributes);
+
+         range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+         CFRelease (font_desc);
+       }
+       else
+       {
+         range->font = NULL;
+       }
+
+       range->index_first = last_index;
+       range->index_last  = event->index - 1;
+
+       last_index = event->index;
+      }
+
+      if (event->start) {
+        active_feature_t *feature = active_features.push ();
+       if (unlikely (!feature))
+         goto fail_features;
+       *feature = event->feature;
+      } else {
+        active_feature_t *feature = active_features.find (&event->feature);
+       if (feature)
+         active_features.remove (feature - active_features.array);
+      }
+    }
+
+    if (!range_records.len) /* No active feature found. */
+      goto fail_features;
+  }
+  else
+  {
+  fail_features:
+    num_features = 0;
+  }
+
+  unsigned int scratch_size;
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+
+#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
+  Type *name = (Type *) scratch; \
+  { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    if (unlikely (_consumed > scratch_size)) \
+    { \
+      on_no_room; \
+      assert (0); \
+    } \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  }
+
+  ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
+  unsigned int chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++) {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    if (likely (c <= 0xFFFFu))
+      pchars[chars_len++] = c;
+    else if (unlikely (c > 0x10FFFFu))
+      pchars[chars_len++] = 0xFFFDu;
+    else {
+      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+    }
+  }
+
+  ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
+  chars_len = 0;
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
+    hb_codepoint_t c = buffer->info[i].codepoint;
+    unsigned int cluster = buffer->info[i].cluster;
+    log_clusters[chars_len++] = cluster;
+    if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+      log_clusters[chars_len++] = cluster; /* Surrogates. */
+  }
+
+#define FAIL(...) \
+  HB_STMT_START { \
+    DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
+    ret = false; \
+    goto fail; \
+  } HB_STMT_END;
+
+  bool ret = true;
+  CFStringRef string_ref = NULL;
+  CTLineRef line = NULL;
+
+  if (0)
+  {
+resize_and_retry:
+    DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
+    /* string_ref uses the scratch-buffer for backing store, and line references
+     * string_ref (via attr_string).  We must release those before resizing buffer. */
+    assert (string_ref);
+    assert (line);
+    CFRelease (string_ref);
+    CFRelease (line);
+    string_ref = NULL;
+    line = NULL;
+
+    /* Get previous start-of-scratch-area, that we use later for readjusting
+     * our existing scratch arrays. */
+    unsigned int old_scratch_used;
+    hb_buffer_t::scratch_buffer_t *old_scratch;
+    old_scratch = buffer->get_scratch_buffer (&old_scratch_used);
+    old_scratch_used = scratch - old_scratch;
+
+    if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+      FAIL ("Buffer resize failed");
+
+    /* Adjust scratch, pchars, and log_cluster arrays.  This is ugly, but really the
+     * cleanest way to do without completely restructuring the rest of this shaper. */
+    scratch = buffer->get_scratch_buffer (&scratch_size);
+    pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
+    log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
+    scratch += old_scratch_used;
+    scratch_size -= old_scratch_used;
+  }
+retry:
+  {
+    string_ref = CFStringCreateWithCharactersNoCopy (NULL,
+                                                    pchars, chars_len,
+                                                    kCFAllocatorNull);
+    if (unlikely (!string_ref))
+      FAIL ("CFStringCreateWithCharactersNoCopy failed");
+
+    /* Create an attributed string, populate it, and create a line from it, then release attributed string. */
+    {
+      CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault,
+                                                                                 chars_len);
+      if (unlikely (!attr_string))
+       FAIL ("CFAttributedStringCreateMutable failed");
+      CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
+      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+      {
+       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+                                       kCTVerticalFormsAttributeName, kCFBooleanTrue);
+      }
+
+      if (buffer->props.language)
+      {
+/* What's the iOS equivalent of this check?
+ * The symbols was introduced in iOS 7.0.
+ * At any rate, our fallback is safe and works fine. */
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
+#  define kCTLanguageAttributeName CFSTR ("NSLanguage")
+#endif
+        CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
+                                                           hb_language_to_string (buffer->props.language),
+                                                           kCFStringEncodingUTF8,
+                                                           kCFAllocatorNull);
+       if (unlikely (!lang))
+         FAIL ("CFStringCreateWithCStringNoCopy failed");
+       CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+                                       kCTLanguageAttributeName, lang);
+       CFRelease (lang);
+      }
+      CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+                                     kCTFontAttributeName, font_data->ct_font);
+
+      if (num_features)
+      {
+       unsigned int start = 0;
+       range_record_t *last_range = &range_records[0];
+       for (unsigned int k = 0; k < chars_len; k++)
+       {
+         range_record_t *range = last_range;
+         while (log_clusters[k] < range->index_first)
+           range--;
+         while (log_clusters[k] > range->index_last)
+           range++;
+         if (range != last_range)
+         {
+           if (last_range->font)
+             CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
+                                             kCTFontAttributeName, last_range->font);
+
+           start = k;
+         }
+
+         last_range = range;
+       }
+       if (start != chars_len && last_range->font)
+         CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
+                                         kCTFontAttributeName, last_range->font);
+      }
+
+      int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
+      CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
+      CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
+                                                   (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
+                                                   (const void **) &level_number,
+                                                   1,
+                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                   &kCFTypeDictionaryValueCallBacks);
+      if (unlikely (!options))
+        FAIL ("CFDictionaryCreate failed");
+
+      CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
+      CFRelease (options);
+      CFRelease (attr_string);
+      if (unlikely (!typesetter))
+       FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed");
+
+      line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
+      CFRelease (typesetter);
+      if (unlikely (!line))
+       FAIL ("CTTypesetterCreateLine failed");
+    }
+
+    CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
+    unsigned int num_runs = CFArrayGetCount (glyph_runs);
+    DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
+
+    buffer->len = 0;
+    uint32_t status_and = ~0, status_or = 0;
+    double advances_so_far = 0;
+
+    const CFRange range_all = CFRangeMake (0, 0);
+
+    for (unsigned int i = 0; i < num_runs; i++)
+    {
+      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);
+      double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
+      if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+         run_advance = -run_advance;
+      DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+
+      /* CoreText does automatic font fallback (AKA "cascading") for  characters
+       * not supported by the requested font, and provides no way to turn it off,
+       * so we must detect if the returned run uses a font other than the requested
+       * one and fill in the buffer with .notdef glyphs instead of random glyph
+       * indices from a different font.
+       */
+      CFDictionaryRef attributes = CTRunGetAttributes (run);
+      CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
+      if (!CFEqual (run_ct_font, font_data->ct_font))
+      {
+       /* The run doesn't use our main font instance.  We have to figure out
+        * whether font fallback happened, or this is just CoreText giving us
+        * another CTFont using the same underlying CGFont.  CoreText seems
+        * to do that in a variety of situations, one of which being vertical
+        * text, but also perhaps for caching reasons.
+        *
+        * First, see if it uses any of our subfonts created to set font features...
+        *
+        * Next, compare the CGFont to the one we used to create our fonts.
+        * Even this doesn't work all the time.
+        *
+        * Finally, we compare PS names, which I don't think are unique...
+        *
+        * Looks like if we really want to be sure here we have to modify the
+        * font to change the name table, similar to what we do in the uniscribe
+        * backend.
+        *
+        * However, even that wouldn't work if we were passed in the CGFont to
+        * begin with.
+        *
+        * Webkit uses a slightly different approach: it installs LastResort
+        * as fallback chain, and then checks PS name of used font against
+        * LastResort.  That one is safe for any font except for LastResort,
+        * as opposed to ours, which can fail if we are using any uninstalled
+        * font that has the same name as an installed font.
+        *
+        * See: http://github.com/behdad/harfbuzz/pull/36
+        */
+       bool matched = false;
+       for (unsigned int i = 0; i < range_records.len; i++)
+         if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
+         {
+           matched = true;
+           break;
+         }
+       if (!matched)
+       {
+         CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
+         if (run_cg_font)
+         {
+           matched = CFEqual (run_cg_font, face_data);
+           CFRelease (run_cg_font);
+         }
+       }
+       if (!matched)
+       {
+         CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
+         CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
+         CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
+         CFRelease (run_ps_name);
+         CFRelease (font_ps_name);
+         if (result == kCFCompareEqualTo)
+           matched = true;
+       }
+       if (!matched)
+       {
+         CFRange range = CTRunGetStringRange (run);
+          DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
+                    range.location, range.location + range.length);
+         if (!buffer->ensure_inplace (buffer->len + range.length))
+           goto resize_and_retry;
+         hb_glyph_info_t *info = buffer->info + buffer->len;
+
+         hb_codepoint_t notdef = 0;
+         hb_direction_t dir = buffer->props.direction;
+         hb_position_t x_advance, y_advance, x_offset, y_offset;
+         hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance);
+         hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset);
+         hb_position_t advance = x_advance + y_advance;
+         x_offset = -x_offset;
+         y_offset = -y_offset;
+
+         unsigned int old_len = buffer->len;
+         for (CFIndex j = range.location; j < range.location + range.length; j++)
+         {
+             UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
+             if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
+             {
+               ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
+               if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
+                 /* This is the second of a surrogate pair.  Don't need .notdef
+                  * for this one. */
+                 continue;
+             }
+             if (buffer->unicode->is_default_ignorable (ch))
+               continue;
+
+             info->codepoint = notdef;
+             info->cluster = log_clusters[j];
+
+             info->mask = advance;
+             info->var1.u32 = x_offset;
+             info->var2.u32 = y_offset;
+
+             info++;
+             buffer->len++;
+         }
+         if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+           buffer->reverse_range (old_len, buffer->len);
+         advances_so_far += run_advance;
+         continue;
+       }
+      }
+
+      unsigned int num_glyphs = CTRunGetGlyphCount (run);
+      if (num_glyphs == 0)
+       continue;
+
+      if (!buffer->ensure_inplace (buffer->len + num_glyphs))
+       goto resize_and_retry;
+
+      hb_glyph_info_t *run_info = buffer->info + buffer->len;
+
+      /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
+       * succeed, and so copying data to our own buffer will be rare.  Reports
+       * have it that this changed in OS X 10.10 Yosemite, and NULL is returned
+       * frequently.  At any rate, we can test that codepath by setting USE_PTR
+       * to false. */
+
+#define USE_PTR true
+
+#define SCRATCH_SAVE() \
+  unsigned int scratch_size_saved = scratch_size; \
+  hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
+
+#define SCRATCH_RESTORE() \
+  scratch_size = scratch_size_saved; \
+  scratch = scratch_saved;
+
+      { /* Setup glyphs */
+        SCRATCH_SAVE();
+       const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
+       if (!glyphs) {
+         ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
+         CTRunGetGlyphs (run, range_all, glyph_buf);
+         glyphs = glyph_buf;
+       }
+       const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
+       if (!string_indices) {
+         ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
+         CTRunGetStringIndices (run, range_all, index_buf);
+         string_indices = index_buf;
+       }
+       hb_glyph_info_t *info = run_info;
+       for (unsigned int j = 0; j < num_glyphs; j++)
+       {
+         info->codepoint = glyphs[j];
+         info->cluster = log_clusters[string_indices[j]];
+         info++;
+       }
+       SCRATCH_RESTORE();
+      }
+      {
+        /* Setup positions.
+        * Note that CoreText does not return advances for glyphs.  As such,
+        * for all but last glyph, we use the delta position to next glyph as
+        * advance (in the advance direction only), and for last glyph we set
+        * whatever is needed to make the whole run's advance add up. */
+        SCRATCH_SAVE();
+       const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
+       if (!positions) {
+         ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
+         CTRunGetPositions (run, range_all, position_buf);
+         positions = position_buf;
+       }
+       hb_glyph_info_t *info = run_info;
+       CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
+       if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+       {
+         hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
+         for (unsigned int j = 0; j < num_glyphs; j++)
+         {
+           double advance;
+           if (likely (j + 1 < num_glyphs))
+             advance = positions[j + 1].x - positions[j].x;
+           else /* last glyph */
+             advance = run_advance - (positions[j].x - positions[0].x);
+           info->mask = advance * x_mult;
+           info->var1.u32 = x_offset;
+           info->var2.u32 = positions[j].y * y_mult;
+           info++;
+         }
+       }
+       else
+       {
+         hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
+         for (unsigned int j = 0; j < num_glyphs; j++)
+         {
+           double advance;
+           if (likely (j + 1 < num_glyphs))
+             advance = positions[j + 1].y - positions[j].y;
+           else /* last glyph */
+             advance = run_advance - (positions[j].y - positions[0].y);
+           info->mask = advance * y_mult;
+           info->var1.u32 = positions[j].x * x_mult;
+           info->var2.u32 = y_offset;
+           info++;
+         }
+       }
+       SCRATCH_RESTORE();
+       advances_so_far += run_advance;
+      }
+#undef SCRATCH_RESTORE
+#undef SCRATCH_SAVE
+#undef USE_PTR
+#undef ALLOCATE_ARRAY
+
+      buffer->len += num_glyphs;
+    }
+
+    /* Make sure all runs had the expected direction. */
+    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;
+    hb_glyph_info_t *info = buffer->info;
+    hb_glyph_position_t *pos = buffer->pos;
+    if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+      for (unsigned int i = 0; i < count; i++)
+      {
+       pos->x_advance = info->mask;
+       pos->x_offset = info->var1.u32;
+       pos->y_offset = info->var2.u32;
+       info++, pos++;
+      }
+    else
+      for (unsigned int i = 0; i < count; i++)
+      {
+       pos->y_advance = info->mask;
+       pos->x_offset = info->var1.u32;
+       pos->y_offset = info->var2.u32;
+       info++, pos++;
+      }
+
+    /* Fix up clusters so that we never return out-of-order indices;
+     * if core text has reordered glyphs, we'll merge them to the
+     * beginning of the reordered cluster.  CoreText is nice enough
+     * to tell us whenever it has produced nonmonotonic results...
+     * Note that we assume the input clusters were nonmonotonic to
+     * begin with.
+     *
+     * 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))
+    {
+      hb_glyph_info_t *info = buffer->info;
+      if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
+      {
+       unsigned int cluster = info[count - 1].cluster;
+       for (unsigned int i = count - 1; i > 0; i--)
+       {
+         cluster = MIN (cluster, info[i - 1].cluster);
+         info[i - 1].cluster = cluster;
+       }
+      }
+      else
+      {
+       unsigned int cluster = info[0].cluster;
+       for (unsigned int i = 1; i < count; i++)
+       {
+         cluster = MIN (cluster, info[i].cluster);
+         info[i].cluster = cluster;
+       }
+      }
+    }
+  }
+
+#undef FAIL
+
+fail:
+  if (string_ref)
+    CFRelease (string_ref);
+  if (line)
+    CFRelease (line);
+
+  for (unsigned int i = 0; i < range_records.len; i++)
+    if (range_records[i].font)
+      CFRelease (range_records[i].font);
+
+  return ret;
+}
+
+
+/*
+ * AAT shaper
+ */
+
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
+
+
+/*
+ * shaper face data
+ */
+
+struct hb_coretext_aat_shaper_face_data_t {};
+
+hb_coretext_aat_shaper_face_data_t *
+_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
+{
+  hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
+  /* Umm, we just reference the table to check whether it exists.
+   * Maybe add better API for this? */
+  if (!hb_blob_get_length (mort_blob))
+  {
+    hb_blob_destroy (mort_blob);
+    mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
+    if (!hb_blob_get_length (mort_blob))
+    {
+      hb_blob_destroy (mort_blob);
+      return NULL;
+    }
+  }
+  hb_blob_destroy (mort_blob);
+
+  return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+}
+
+void
+_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_coretext_aat_shaper_font_data_t {};
+
+hb_coretext_aat_shaper_font_data_t *
+_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
+{
+  return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+}
+
+void
+_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_coretext_aat_shaper_shape_plan_data_t {};
+
+hb_coretext_aat_shaper_shape_plan_data_t *
+_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                            const hb_feature_t *user_features HB_UNUSED,
+                                            unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_coretext_aat_shape (hb_shape_plan_t    *shape_plan,
+                       hb_font_t          *font,
+                       hb_buffer_t        *buffer,
+                       const hb_feature_t *features,
+                       unsigned int        num_features)
+{
+  return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
+}
diff --git a/src/hb-coretext.h b/src/hb-coretext.h
new file mode 100644 (file)
index 0000000..25267bc
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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
+ */
+
+#ifndef HB_CORETEXT_H
+#define HB_CORETEXT_H
+
+#include "hb.h"
+
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+#  include <CoreText/CoreText.h>
+#  include <CoreGraphics/CoreGraphics.h>
+#else
+#  include <ApplicationServices/ApplicationServices.h>
+#endif
+
+HB_BEGIN_DECLS
+
+
+#define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
+#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
+
+
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font);
+
+
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face);
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font);
+
+
+HB_END_DECLS
+
+#endif /* HB_CORETEXT_H */
similarity index 66%
rename from src/hb-version.h
rename to src/hb-deprecated.h
index 43ec9cf..30ae4b1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 #error "Include <hb.h> instead."
 #endif
 
-#ifndef HB_VERSION_H
-#define HB_VERSION_H
+#ifndef HB_DEPRECATED_H
+#define HB_DEPRECATED_H
 
 #include "hb-common.h"
+#include "hb-unicode.h"
+#include "hb-font.h"
 
 HB_BEGIN_DECLS
 
+#ifndef HB_DISABLE_DEPRECATED
 
-#define HB_VERSION_MAJOR 0
-#define HB_VERSION_MINOR 9
-#define HB_VERSION_MICRO 0
+#define HB_SCRIPT_CANADIAN_ABORIGINAL          HB_SCRIPT_CANADIAN_SYLLABICS
 
-#define HB_VERSION_STRING "0.9.0"
-
-#define HB_VERSION_CHECK(major,minor,micro) \
-       ((major)*10000+(minor)*100+(micro) >= \
-        HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
-
-
-void
-hb_version (unsigned int *major,
-           unsigned int *minor,
-           unsigned int *micro);
-
-const char *
-hb_version_string (void);
-
-hb_bool_t
-hb_version_check (unsigned int major,
-                 unsigned int minor,
-                 unsigned int micro);
+#define HB_BUFFER_FLAGS_DEFAULT                        HB_BUFFER_FLAG_DEFAULT
+#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT      HB_BUFFER_SERIALIZE_FLAG_DEFAULT
 
+#endif
 
 HB_END_DECLS
 
-#endif /* HB_VERSION_H */
+#endif /* HB_DEPRECATED_H */
diff --git a/src/hb-face-private.hh b/src/hb-face-private.hh
new file mode 100644 (file)
index 0000000..c4266ff
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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
+ */
+
+#ifndef HB_FACE_PRIVATE_HH
+#define HB_FACE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+
+
+/*
+ * hb_face_t
+ */
+
+struct hb_face_t {
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_bool_t immutable;
+
+  hb_reference_table_func_t  reference_table_func;
+  void                      *user_data;
+  hb_destroy_func_t          destroy;
+
+  unsigned int index;
+  mutable unsigned int upem;
+  mutable unsigned int num_glyphs;
+
+  struct hb_shaper_data_t shaper_data;
+
+  struct plan_node_t {
+    hb_shape_plan_t *shape_plan;
+    plan_node_t *next;
+  } *shape_plans;
+
+
+  inline hb_blob_t *reference_table (hb_tag_t tag) const
+  {
+    hb_blob_t *blob;
+
+    if (unlikely (!reference_table_func))
+      return hb_blob_get_empty ();
+
+    blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
+    if (unlikely (!blob))
+      return hb_blob_get_empty ();
+
+    return blob;
+  }
+
+  inline HB_PURE_FUNC unsigned int get_upem (void) const
+  {
+    if (unlikely (!upem))
+      load_upem ();
+    return upem;
+  }
+
+  inline unsigned int get_num_glyphs (void) const
+  {
+    if (unlikely (num_glyphs == (unsigned int) -1))
+      load_num_glyphs ();
+    return num_glyphs;
+  }
+
+  private:
+  HB_INTERNAL void load_upem (void) const;
+  HB_INTERNAL void load_num_glyphs (void) const;
+};
+
+extern HB_INTERNAL const hb_face_t _hb_face_nil;
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_FACE_PRIVATE_HH */
diff --git a/src/hb-face.cc b/src/hb-face.cc
new file mode 100644 (file)
index 0000000..9348af7
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot-layout-private.hh"
+
+#include "hb-font-private.hh"
+#include "hb-open-file-private.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
+
+#include "hb-cache-private.hh"
+
+#include <string.h>
+
+
+/*
+ * hb_face_t
+ */
+
+const hb_face_t _hb_face_nil = {
+  HB_OBJECT_HEADER_STATIC,
+
+  true, /* immutable */
+
+  NULL, /* reference_table_func */
+  NULL, /* user_data */
+  NULL, /* destroy */
+
+  0,    /* index */
+  1000, /* upem */
+  0,    /* num_glyphs */
+
+  {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  },
+
+  NULL, /* shape_plans */
+};
+
+
+/**
+ * hb_face_create_for_tables:
+ * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data: 
+ * @destroy: 
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
+                          void                      *user_data,
+                          hb_destroy_func_t          destroy)
+{
+  hb_face_t *face;
+
+  if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
+    if (destroy)
+      destroy (user_data);
+    return hb_face_get_empty ();
+  }
+
+  face->reference_table_func = reference_table_func;
+  face->user_data = user_data;
+  face->destroy = destroy;
+
+  face->upem = 0;
+  face->num_glyphs = (unsigned int) -1;
+
+  return face;
+}
+
+
+typedef struct hb_face_for_data_closure_t {
+  hb_blob_t *blob;
+  unsigned int  index;
+} hb_face_for_data_closure_t;
+
+static hb_face_for_data_closure_t *
+_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
+{
+  hb_face_for_data_closure_t *closure;
+
+  closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
+  if (unlikely (!closure))
+    return NULL;
+
+  closure->blob = blob;
+  closure->index = index;
+
+  return closure;
+}
+
+static void
+_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
+{
+  hb_blob_destroy (closure->blob);
+  free (closure);
+}
+
+static hb_blob_t *
+_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
+
+  if (tag == HB_TAG_NONE)
+    return hb_blob_reference (data->blob);
+
+  const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
+  const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+
+  const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
+
+  hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
+
+  return blob;
+}
+
+/**
+ * hb_face_create: (Xconstructor)
+ * @blob: 
+ * @index: 
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_create (hb_blob_t    *blob,
+               unsigned int  index)
+{
+  hb_face_t *face;
+
+  if (unlikely (!blob || !hb_blob_get_length (blob)))
+    return hb_face_get_empty ();
+
+  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
+
+  if (unlikely (!closure))
+    return hb_face_get_empty ();
+
+  face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
+                                   closure,
+                                   (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
+
+  hb_face_set_index (face, index);
+
+  return face;
+}
+
+/**
+ * hb_face_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_get_empty (void)
+{
+  return const_cast<hb_face_t *> (&_hb_face_nil);
+}
+
+
+/**
+ * hb_face_reference: (skip)
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_reference (hb_face_t *face)
+{
+  return hb_object_reference (face);
+}
+
+/**
+ * hb_face_destroy: (skip)
+ * @face: a face.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_destroy (hb_face_t *face)
+{
+  if (!hb_object_destroy (face)) return;
+
+  for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
+  {
+    hb_face_t::plan_node_t *next = node->next;
+    hb_shape_plan_destroy (node->shape_plan);
+    free (node);
+    node = next;
+  }
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  if (face->destroy)
+    face->destroy (face->user_data);
+
+  free (face);
+}
+
+/**
+ * hb_face_set_user_data: (skip)
+ * @face: a face.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_face_set_user_data (hb_face_t          *face,
+                      hb_user_data_key_t *key,
+                      void *              data,
+                      hb_destroy_func_t   destroy,
+                      hb_bool_t           replace)
+{
+  return hb_object_set_user_data (face, key, data, destroy, replace);
+}
+
+/**
+ * hb_face_get_user_data: (skip)
+ * @face: a face.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+void *
+hb_face_get_user_data (hb_face_t          *face,
+                      hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (face, key);
+}
+
+/**
+ * hb_face_make_immutable:
+ * @face: a face.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_make_immutable (hb_face_t *face)
+{
+  if (unlikely (hb_object_is_inert (face)))
+    return;
+
+  face->immutable = true;
+}
+
+/**
+ * hb_face_is_immutable:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face)
+{
+  return face->immutable;
+}
+
+
+/**
+ * hb_face_reference_table:
+ * @face: a face.
+ * @tag: 
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+                        hb_tag_t   tag)
+{
+  return face->reference_table (tag);
+}
+
+/**
+ * hb_face_reference_blob:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face)
+{
+  return face->reference_table (HB_TAG_NONE);
+}
+
+/**
+ * hb_face_set_index:
+ * @face: a face.
+ * @index: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_index (hb_face_t    *face,
+                  unsigned int  index)
+{
+  if (face->immutable)
+    return;
+
+  face->index = index;
+}
+
+/**
+ * hb_face_get_index:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_index (hb_face_t    *face)
+{
+  return face->index;
+}
+
+/**
+ * hb_face_set_upem:
+ * @face: a face.
+ * @upem: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_upem (hb_face_t    *face,
+                 unsigned int  upem)
+{
+  if (face->immutable)
+    return;
+
+  face->upem = upem;
+}
+
+/**
+ * hb_face_get_upem:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_upem (hb_face_t *face)
+{
+  return face->get_upem ();
+}
+
+void
+hb_face_t::load_upem (void) const
+{
+  hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
+  const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
+  upem = head_table->get_upem ();
+  hb_blob_destroy (head_blob);
+}
+
+/**
+ * hb_face_set_glyph_count:
+ * @face: a face.
+ * @glyph_count: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+                        unsigned int  glyph_count)
+{
+  if (face->immutable)
+    return;
+
+  face->num_glyphs = glyph_count;
+}
+
+/**
+ * hb_face_get_glyph_count:
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face)
+{
+  return face->get_num_glyphs ();
+}
+
+void
+hb_face_t::load_num_glyphs (void) const
+{
+  hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
+  const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
+  num_glyphs = maxp_table->get_num_glyphs ();
+  hb_blob_destroy (maxp_blob);
+}
+
+
diff --git a/src/hb-face.h b/src/hb-face.h
new file mode 100644 (file)
index 0000000..f682c46
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_FACE_H
+#define HB_FACE_H
+
+#include "hb-common.h"
+#include "hb-blob.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * hb_face_t
+ */
+
+typedef struct hb_face_t hb_face_t;
+
+hb_face_t *
+hb_face_create (hb_blob_t    *blob,
+               unsigned int  index);
+
+typedef hb_blob_t * (*hb_reference_table_func_t)  (hb_face_t *face, hb_tag_t tag, void *user_data);
+
+/* calls destroy() when not needing user_data anymore */
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t  reference_table_func,
+                          void                      *user_data,
+                          hb_destroy_func_t          destroy);
+
+hb_face_t *
+hb_face_get_empty (void);
+
+hb_face_t *
+hb_face_reference (hb_face_t *face);
+
+void
+hb_face_destroy (hb_face_t *face);
+
+hb_bool_t
+hb_face_set_user_data (hb_face_t          *face,
+                      hb_user_data_key_t *key,
+                      void *              data,
+                      hb_destroy_func_t   destroy,
+                      hb_bool_t           replace);
+
+
+void *
+hb_face_get_user_data (hb_face_t          *face,
+                      hb_user_data_key_t *key);
+
+void
+hb_face_make_immutable (hb_face_t *face);
+
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face);
+
+
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+                        hb_tag_t   tag);
+
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face);
+
+void
+hb_face_set_index (hb_face_t    *face,
+                  unsigned int  index);
+
+unsigned int
+hb_face_get_index (hb_face_t    *face);
+
+void
+hb_face_set_upem (hb_face_t    *face,
+                 unsigned int  upem);
+
+unsigned int
+hb_face_get_upem (hb_face_t *face);
+
+void
+hb_face_set_glyph_count (hb_face_t    *face,
+                        unsigned int  glyph_count);
+
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face);
+
+
+HB_END_DECLS
+
+#endif /* HB_FACE_H */
index 5939887..9d061a9 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-fallback-shape-private.hh"
+#define HB_SHAPER fallback
+#include "hb-shaper-impl-private.hh"
 
-#include "hb-buffer-private.hh"
+
+/*
+ * shaper face data
+ */
+
+struct hb_fallback_shaper_face_data_t {};
+
+hb_fallback_shaper_face_data_t *
+_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED)
+{
+  return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_fallback_shaper_font_data_t {};
+
+hb_fallback_shaper_font_data_t *
+_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+  return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_fallback_shaper_shape_plan_data_t {};
+
+hb_fallback_shaper_shape_plan_data_t *
+_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                           const hb_feature_t *user_features HB_UNUSED,
+                                           unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
 
 hb_bool_t
-_hb_fallback_shape (hb_font_t          *font,
+_hb_fallback_shape (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                   hb_font_t          *font,
                    hb_buffer_t        *buffer,
                    const hb_feature_t *features HB_UNUSED,
                    unsigned int        num_features HB_UNUSED)
 {
-  buffer->guess_properties ();
+  /* 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.
+   */
 
-  unsigned int count = buffer->len;
-
-  for (unsigned int i = 0; i < count; i++)
-    hb_font_get_glyph (font, buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
+  hb_codepoint_t space;
+  bool has_space = font->get_glyph (' ', 0, &space);
 
   buffer->clear_positions ();
 
-  for (unsigned int i = 0; i < count; i++) {
-    hb_font_get_glyph_advance_for_direction (font, buffer->info[i].codepoint,
-                                            buffer->props.direction,
-                                            &buffer->pos[i].x_advance,
-                                            &buffer->pos[i].y_advance);
-    hb_font_subtract_glyph_origin_for_direction (font, buffer->info[i].codepoint,
-                                                buffer->props.direction,
-                                                &buffer->pos[i].x_offset,
-                                                &buffer->pos[i].y_offset);
+  hb_direction_t direction = buffer->props.direction;
+  hb_unicode_funcs_t *unicode = buffer->unicode;
+  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 (has_space && unicode->is_default_ignorable (info[i].codepoint)) {
+      info[i].codepoint = space;
+      pos[i].x_advance = 0;
+      pos[i].y_advance = 0;
+      continue;
+    }
+    font->get_glyph (info[i].codepoint, 0, &info[i].codepoint);
+    font->get_glyph_advance_for_direction (info[i].codepoint,
+                                          direction,
+                                          &pos[i].x_advance,
+                                          &pos[i].y_advance);
+    font->subtract_glyph_origin_for_direction (info[i].codepoint,
+                                              direction,
+                                              &pos[i].x_offset,
+                                              &pos[i].y_offset);
   }
 
-  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+  if (HB_DIRECTION_IS_BACKWARD (direction))
     hb_buffer_reverse (buffer);
 
   return true;
index 91a4304..33bbf71 100644 (file)
@@ -31,8 +31,9 @@
 
 #include "hb-private.hh"
 
-#include "hb-font.h"
 #include "hb-object-private.hh"
+#include "hb-face-private.hh"
+#include "hb-shaper-private.hh"
 
 
 
@@ -54,7 +55,7 @@
   HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
   /* ^--- Add new callbacks here */
 
-struct _hb_font_funcs_t {
+struct hb_font_funcs_t {
   hb_object_header_t header;
   ASSERT_POD ();
 
@@ -82,32 +83,12 @@ struct _hb_font_funcs_t {
 };
 
 
-/*
- * hb_face_t
- */
-
-struct _hb_face_t {
-  hb_object_header_t header;
-  ASSERT_POD ();
-
-  hb_bool_t immutable;
-
-  hb_reference_table_func_t  reference_table;
-  void                      *user_data;
-  hb_destroy_func_t          destroy;
-
-  struct hb_ot_layout_t *ot_layout;
-
-  unsigned int index;
-  unsigned int upem;
-};
-
 
 /*
  * hb_font_t
  */
 
-struct _hb_font_t {
+struct hb_font_t {
   hb_object_header_t header;
   ASSERT_POD ();
 
@@ -126,6 +107,8 @@ struct _hb_font_t {
   void              *user_data;
   hb_destroy_func_t  destroy;
 
+  struct hb_shaper_data_t shaper_data;
+
 
   /* Convert from font-space to user-space */
   inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
@@ -134,12 +117,12 @@ struct _hb_font_t {
   /* Convert from parent-font user-space to our user-space */
   inline hb_position_t parent_scale_x_distance (hb_position_t v) {
     if (unlikely (parent && parent->x_scale != x_scale))
-      return v * (int64_t) this->x_scale / this->parent->x_scale;
+      return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
     return v;
   }
   inline hb_position_t parent_scale_y_distance (hb_position_t v) {
     if (unlikely (parent && parent->y_scale != y_scale))
-      return v * (int64_t) this->y_scale / this->parent->y_scale;
+      return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
     return v;
   }
   inline hb_position_t parent_scale_x_position (hb_position_t v) {
@@ -159,10 +142,274 @@ struct _hb_font_t {
   }
 
 
+  /* Public getters */
+
+  inline hb_bool_t has_glyph (hb_codepoint_t unicode)
+  {
+    hb_codepoint_t glyph;
+    return get_glyph (unicode, 0, &glyph);
+  }
+
+  inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+                             hb_codepoint_t *glyph)
+  {
+    *glyph = 0;
+    return klass->get.glyph (this, user_data,
+                            unicode, variation_selector, glyph,
+                            klass->user_data.glyph);
+  }
+
+  inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
+  {
+    return klass->get.glyph_h_advance (this, user_data,
+                                      glyph,
+                                      klass->user_data.glyph_h_advance);
+  }
+
+  inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
+  {
+    return klass->get.glyph_v_advance (this, user_data,
+                                      glyph,
+                                      klass->user_data.glyph_v_advance);
+  }
+
+  inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
+                                      hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_h_origin (this, user_data,
+                                     glyph, x, y,
+                                     klass->user_data.glyph_h_origin);
+  }
+
+  inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
+                                      hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_v_origin (this, user_data,
+                                     glyph, x, y,
+                                     klass->user_data.glyph_v_origin);
+  }
+
+  inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+  {
+    return klass->get.glyph_h_kerning (this, user_data,
+                                      left_glyph, right_glyph,
+                                      klass->user_data.glyph_h_kerning);
+  }
+
+  inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
+  {
+    return klass->get.glyph_v_kerning (this, user_data,
+                                      top_glyph, bottom_glyph,
+                                      klass->user_data.glyph_v_kerning);
+  }
+
+  inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
+                                     hb_glyph_extents_t *extents)
+  {
+    memset (extents, 0, sizeof (*extents));
+    return klass->get.glyph_extents (this, user_data,
+                                    glyph,
+                                    extents,
+                                    klass->user_data.glyph_extents);
+  }
+
+  inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
+                                           hb_position_t *x, hb_position_t *y)
+  {
+    *x = *y = 0;
+    return klass->get.glyph_contour_point (this, user_data,
+                                          glyph, point_index,
+                                          x, y,
+                                          klass->user_data.glyph_contour_point);
+  }
+
+  inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
+                                  char *name, unsigned int size)
+  {
+    if (size) *name = '\0';
+    return klass->get.glyph_name (this, user_data,
+                                 glyph,
+                                 name, size,
+                                 klass->user_data.glyph_name);
+  }
+
+  inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
+                                       hb_codepoint_t *glyph)
+  {
+    *glyph = 0;
+    if (len == -1) len = strlen (name);
+    return klass->get.glyph_from_name (this, user_data,
+                                      name, len,
+                                      glyph,
+                                      klass->user_data.glyph_from_name);
+  }
+
+
+  /* A bit higher-level, and with fallback */
+
+  inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
+                                              hb_direction_t direction,
+                                              hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      *x = get_glyph_h_advance (glyph);
+      *y = 0;
+    } else {
+      *x = 0;
+      *y = get_glyph_v_advance (glyph);
+    }
+  }
+
+  /* Internal only */
+  inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
+                                            hb_position_t *x, hb_position_t *y)
+  {
+    *x = get_glyph_h_advance (glyph) / 2;
+
+    /* TODO use font_metics.ascent */
+    *y = y_scale;
+  }
+
+  inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
+                                             hb_direction_t direction,
+                                             hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+    {
+      if (!get_glyph_h_origin (glyph, x, y) &&
+          get_glyph_v_origin (glyph, x, y))
+      {
+       hb_position_t dx, dy;
+       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+       *x -= dx; *y -= dy;
+      }
+    }
+    else
+    {
+      if (!get_glyph_v_origin (glyph, x, y) &&
+          get_glyph_h_origin (glyph, x, y))
+      {
+       hb_position_t dx, dy;
+       guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+       *x += dx; *y += dy;
+      }
+    }
+  }
+
+  inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
+                                             hb_direction_t direction,
+                                             hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+    *x += origin_x;
+    *y += origin_y;
+  }
+
+  inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
+                                                  hb_direction_t direction,
+                                                  hb_position_t *x, hb_position_t *y)
+  {
+    hb_position_t origin_x, origin_y;
+
+    get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+    *x -= origin_x;
+    *y -= origin_y;
+  }
+
+  inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+                                              hb_direction_t direction,
+                                              hb_position_t *x, hb_position_t *y)
+  {
+    if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+      *x = get_glyph_h_kerning (first_glyph, second_glyph);
+      *y = 0;
+    } else {
+      *x = 0;
+      *y = get_glyph_v_kerning (first_glyph, second_glyph);
+    }
+  }
+
+  inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
+                                                hb_direction_t direction,
+                                                hb_glyph_extents_t *extents)
+  {
+    hb_bool_t ret = get_glyph_extents (glyph, extents);
+
+    if (ret)
+      subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
+
+    return ret;
+  }
+
+  inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
+                                                      hb_direction_t direction,
+                                                      hb_position_t *x, hb_position_t *y)
+  {
+    hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
+
+    if (ret)
+      subtract_glyph_origin_for_direction (glyph, direction, x, y);
+
+    return ret;
+  }
+
+  /* Generates gidDDD if glyph has no name. */
+  inline void
+  glyph_to_string (hb_codepoint_t glyph,
+                  char *s, unsigned int size)
+  {
+    if (get_glyph_name (glyph, s, size)) return;
+
+    if (size && snprintf (s, size, "gid%u", glyph) < 0)
+      *s = '\0';
+  }
+
+  /* Parses gidDDD and uniUUUU strings automatically. */
+  inline hb_bool_t
+  glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
+                    hb_codepoint_t *glyph)
+  {
+    if (get_glyph_from_name (s, len, glyph)) return true;
+
+    if (len == -1) len = strlen (s);
+
+    /* Straight glyph index. */
+    if (hb_codepoint_parse (s, len, 10, glyph))
+      return true;
+
+    if (len > 3)
+    {
+      /* gidDDD syntax for glyph indices. */
+      if (0 == strncmp (s, "gid", 3) &&
+         hb_codepoint_parse (s + 3, len - 3, 10, glyph))
+       return true;
+
+      /* uniUUUU and other Unicode character indices. */
+      hb_codepoint_t unichar;
+      if (0 == strncmp (s, "uni", 3) &&
+         hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
+         get_glyph (unichar, 0, glyph))
+       return true;
+    }
+
+    return false;
+  }
+
   private:
-  inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); }
+  inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); }
 };
 
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
 
 
 #endif /* HB_FONT_PRIVATE_HH */
index 109caff..d42db59 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,6 +23,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 #include "hb-ot-layout-private.hh"
 
 #include "hb-font-private.hh"
-#include "hb-blob.h"
 #include "hb-open-file-private.hh"
 #include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
 
 #include "hb-cache-private.hh"
 
 #include <string.h>
 
 
-
 /*
  * hb_font_funcs_t
  */
@@ -52,7 +53,7 @@ hb_font_get_glyph_nil (hb_font_t *font,
                       void *user_data HB_UNUSED)
 {
   if (font->parent)
-    return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph);
+    return font->parent->get_glyph (unicode, variation_selector, glyph);
 
   *glyph = 0;
   return false;
@@ -65,7 +66,7 @@ hb_font_get_glyph_h_advance_nil (hb_font_t *font,
                                 void *user_data HB_UNUSED)
 {
   if (font->parent)
-    return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph));
+    return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
 
   return font->x_scale;
 }
@@ -77,7 +78,7 @@ hb_font_get_glyph_v_advance_nil (hb_font_t *font,
                                 void *user_data HB_UNUSED)
 {
   if (font->parent)
-    return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph));
+    return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
 
   return font->y_scale;
 }
@@ -91,7 +92,7 @@ hb_font_get_glyph_h_origin_nil (hb_font_t *font,
                                void *user_data HB_UNUSED)
 {
   if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent, glyph, x, y);
+    hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
     if (ret)
       font->parent_scale_position (x, y);
     return ret;
@@ -110,7 +111,7 @@ hb_font_get_glyph_v_origin_nil (hb_font_t *font,
                                void *user_data HB_UNUSED)
 {
   if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent, glyph, x, y);
+    hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
     if (ret)
       font->parent_scale_position (x, y);
     return ret;
@@ -128,7 +129,7 @@ hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
                                 void *user_data HB_UNUSED)
 {
   if (font->parent)
-    return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph));
+    return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
 
   return 0;
 }
@@ -141,7 +142,7 @@ hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
                                 void *user_data HB_UNUSED)
 {
   if (font->parent)
-    return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph));
+    return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
 
   return 0;
 }
@@ -154,9 +155,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font,
                               void *user_data HB_UNUSED)
 {
   if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_extents (font->parent,
-                                              glyph,
-                                              extents);
+    hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
     if (ret) {
       font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
       font->parent_scale_distance (&extents->width, &extents->height);
@@ -178,7 +177,7 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font,
                                     void *user_data HB_UNUSED)
 {
   if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent, glyph, point_index, x, y);
+    hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
     if (ret)
       font->parent_scale_position (x, y);
     return ret;
@@ -196,9 +195,9 @@ hb_font_get_glyph_name_nil (hb_font_t *font,
                            void *user_data HB_UNUSED)
 {
   if (font->parent)
-    return hb_font_get_glyph_name (font->parent, glyph, name, size);
+    return font->parent->get_glyph_name (glyph, name, size);
 
-  snprintf (name, size, "gid%u", glyph);
+  if (size) *name = '\0';
   return false;
 }
 
@@ -210,7 +209,7 @@ hb_font_get_glyph_from_name_nil (hb_font_t *font,
                                 void *user_data HB_UNUSED)
 {
   if (font->parent)
-    return hb_font_get_glyph_from_name (font->parent, name, len, glyph);
+    return font->parent->get_glyph_from_name (name, len, glyph);
 
   *glyph = 0;
   return false;
@@ -230,6 +229,15 @@ static const hb_font_funcs_t _hb_font_funcs_nil = {
 };
 
 
+/**
+ * hb_font_funcs_create: (Xconstructor)
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_funcs_t *
 hb_font_funcs_create (void)
 {
@@ -243,18 +251,45 @@ hb_font_funcs_create (void)
   return ffuncs;
 }
 
+/**
+ * hb_font_funcs_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_funcs_t *
 hb_font_funcs_get_empty (void)
 {
   return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
 }
 
+/**
+ * hb_font_funcs_reference: (skip)
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_font_funcs_t *
 hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
 {
   return hb_object_reference (ffuncs);
 }
 
+/**
+ * hb_font_funcs_destroy: (skip)
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
 {
@@ -268,6 +303,20 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
   free (ffuncs);
 }
 
+/**
+ * hb_font_funcs_set_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
                             hb_user_data_key_t *key,
@@ -278,6 +327,17 @@ hb_font_funcs_set_user_data (hb_font_funcs_t    *ffuncs,
   return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
 }
 
+/**
+ * hb_font_funcs_get_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
                             hb_user_data_key_t *key)
@@ -286,15 +346,33 @@ hb_font_funcs_get_user_data (hb_font_funcs_t    *ffuncs,
 }
 
 
+/**
+ * hb_font_funcs_make_immutable:
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
 {
-  if (hb_object_is_inert (ffuncs))
+  if (unlikely (hb_object_is_inert (ffuncs)))
     return;
 
   ffuncs->immutable = true;
 }
 
+/**
+ * hb_font_funcs_is_immutable:
+ * @ffuncs: font functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
 {
@@ -334,476 +412,424 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
 
+/* Public getters */
+
+/**
+ * hb_font_get_glyph:
+ * @font: a font.
+ * @unicode: 
+ * @variation_selector: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph (hb_font_t *font,
                   hb_codepoint_t unicode, hb_codepoint_t variation_selector,
                   hb_codepoint_t *glyph)
 {
-  *glyph = 0;
-  return font->klass->get.glyph (font, font->user_data,
-                                unicode, variation_selector, glyph,
-                                font->klass->user_data.glyph);
+  return font->get_glyph (unicode, variation_selector, glyph);
 }
 
+/**
+ * hb_font_get_glyph_h_advance:
+ * @font: a font.
+ * @glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_h_advance (hb_font_t *font,
                             hb_codepoint_t glyph)
 {
-  return font->klass->get.glyph_h_advance (font, font->user_data,
-                                          glyph,
-                                          font->klass->user_data.glyph_h_advance);
+  return font->get_glyph_h_advance (glyph);
 }
 
+/**
+ * hb_font_get_glyph_v_advance:
+ * @font: a font.
+ * @glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_v_advance (hb_font_t *font,
                             hb_codepoint_t glyph)
 {
-  return font->klass->get.glyph_v_advance (font, font->user_data,
-                                          glyph,
-                                          font->klass->user_data.glyph_v_advance);
+  return font->get_glyph_v_advance (glyph);
 }
 
+/**
+ * hb_font_get_glyph_h_origin:
+ * @font: a font.
+ * @glyph: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_h_origin (hb_font_t *font,
                            hb_codepoint_t glyph,
                            hb_position_t *x, hb_position_t *y)
 {
-  *x = *y = 0;
-  return font->klass->get.glyph_h_origin (font, font->user_data,
-                                          glyph, x, y,
-                                          font->klass->user_data.glyph_h_origin);
+  return font->get_glyph_h_origin (glyph, x, y);
 }
 
+/**
+ * hb_font_get_glyph_v_origin:
+ * @font: a font.
+ * @glyph: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_v_origin (hb_font_t *font,
                            hb_codepoint_t glyph,
                            hb_position_t *x, hb_position_t *y)
 {
-  *x = *y = 0;
-  return font->klass->get.glyph_v_origin (font, font->user_data,
-                                          glyph, x, y,
-                                          font->klass->user_data.glyph_v_origin);
+  return font->get_glyph_v_origin (glyph, x, y);
 }
 
+/**
+ * hb_font_get_glyph_h_kerning:
+ * @font: a font.
+ * @left_glyph: 
+ * @right_glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_h_kerning (hb_font_t *font,
                             hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
 {
-  return font->klass->get.glyph_h_kerning (font, font->user_data,
-                                          left_glyph, right_glyph,
-                                          font->klass->user_data.glyph_h_kerning);
+  return font->get_glyph_h_kerning (left_glyph, right_glyph);
 }
 
+/**
+ * hb_font_get_glyph_v_kerning:
+ * @font: a font.
+ * @top_glyph: 
+ * @bottom_glyph: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_position_t
 hb_font_get_glyph_v_kerning (hb_font_t *font,
-                            hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+                            hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
 {
-  return font->klass->get.glyph_v_kerning (font, font->user_data,
-                                    left_glyph, right_glyph,
-                                    font->klass->user_data.glyph_v_kerning);
+  return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
 }
 
+/**
+ * hb_font_get_glyph_extents:
+ * @font: a font.
+ * @glyph: 
+ * @extents: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_extents (hb_font_t *font,
                           hb_codepoint_t glyph,
                           hb_glyph_extents_t *extents)
 {
-  memset (extents, 0, sizeof (*extents));
-  return font->klass->get.glyph_extents (font, font->user_data,
-                                        glyph,
-                                        extents,
-                                        font->klass->user_data.glyph_extents);
+  return font->get_glyph_extents (glyph, extents);
 }
 
+/**
+ * hb_font_get_glyph_contour_point:
+ * @font: a font.
+ * @glyph: 
+ * @point_index: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_contour_point (hb_font_t *font,
                                 hb_codepoint_t glyph, unsigned int point_index,
                                 hb_position_t *x, hb_position_t *y)
 {
-  *x = *y = 0;
-  return font->klass->get.glyph_contour_point (font, font->user_data,
-                                              glyph, point_index,
-                                              x, y,
-                                              font->klass->user_data.glyph_contour_point);
+  return font->get_glyph_contour_point (glyph, point_index, x, y);
 }
 
+/**
+ * hb_font_get_glyph_name:
+ * @font: a font.
+ * @glyph: 
+ * @name: (array length=size): 
+ * @size: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_name (hb_font_t *font,
                        hb_codepoint_t glyph,
                        char *name, unsigned int size)
 {
-  return font->klass->get.glyph_name (font, font->user_data,
-                                     glyph,
-                                     name, size,
-                                     font->klass->user_data.glyph_name);
+  return font->get_glyph_name (glyph, name, size);
 }
 
+/**
+ * hb_font_get_glyph_from_name:
+ * @font: a font.
+ * @name: (array length=len): 
+ * @len: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_from_name (hb_font_t *font,
                             const char *name, int len, /* -1 means nul-terminated */
                             hb_codepoint_t *glyph)
 {
-  return font->klass->get.glyph_from_name (font, font->user_data,
-                                          name, len,
-                                          glyph,
-                                          font->klass->user_data.glyph_from_name);
+  return font->get_glyph_from_name (name, len, glyph);
 }
 
 
 /* A bit higher-level, and with fallback */
 
+/**
+ * hb_font_get_glyph_advance_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_glyph_advance_for_direction (hb_font_t *font,
                                         hb_codepoint_t glyph,
                                         hb_direction_t direction,
                                         hb_position_t *x, hb_position_t *y)
 {
-  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-    *x = hb_font_get_glyph_h_advance (font, glyph);
-    *y = 0;
-  } else {
-    *x = 0;
-    *y = hb_font_get_glyph_v_advance (font, glyph);
-  }
+  return font->get_glyph_advance_for_direction (glyph, direction, x, y);
 }
 
-static void
-guess_v_origin_minus_h_origin (hb_font_t *font,
-                              hb_codepoint_t glyph,
-                              hb_position_t *x, hb_position_t *y)
-{
-  *x = hb_font_get_glyph_h_advance (font, glyph) / 2;
-
-  /* TODO use font_metics.ascent */
-  *y = font->y_scale;
-}
-
-
+/**
+ * hb_font_get_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_glyph_origin_for_direction (hb_font_t *font,
                                        hb_codepoint_t glyph,
                                        hb_direction_t direction,
                                        hb_position_t *x, hb_position_t *y)
 {
-  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-    hb_bool_t ret = hb_font_get_glyph_h_origin (font, glyph, x, y);
-    if (!ret && (ret = hb_font_get_glyph_v_origin (font, glyph, x, y))) {
-      hb_position_t dx, dy;
-      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
-      *x -= dx; *y -= dy;
-    }
-  } else {
-    hb_bool_t ret = hb_font_get_glyph_v_origin (font, glyph, x, y);
-    if (!ret && (ret = hb_font_get_glyph_h_origin (font, glyph, x, y))) {
-      hb_position_t dx, dy;
-      guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
-      *x += dx; *y += dy;
-    }
-  }
+  return font->get_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
+/**
+ * hb_font_add_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_add_glyph_origin_for_direction (hb_font_t *font,
                                        hb_codepoint_t glyph,
                                        hb_direction_t direction,
                                        hb_position_t *x, hb_position_t *y)
 {
-  hb_position_t origin_x, origin_y;
-
-  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
-
-  *x += origin_x;
-  *y += origin_y;
+  return font->add_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
+/**
+ * hb_font_subtract_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
                                             hb_codepoint_t glyph,
                                             hb_direction_t direction,
                                             hb_position_t *x, hb_position_t *y)
 {
-  hb_position_t origin_x, origin_y;
-
-  hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
-
-  *x -= origin_x;
-  *y -= origin_y;
+  return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
 }
 
+/**
+ * hb_font_get_glyph_kerning_for_direction:
+ * @font: a font.
+ * @first_glyph: 
+ * @second_glyph: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
                                         hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
                                         hb_direction_t direction,
                                         hb_position_t *x, hb_position_t *y)
 {
-  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
-    *x = hb_font_get_glyph_h_kerning (font, first_glyph, second_glyph);
-    *y = 0;
-  } else {
-    *x = 0;
-    *y = hb_font_get_glyph_v_kerning (font, first_glyph, second_glyph);
-  }
+  return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
 }
 
+/**
+ * hb_font_get_glyph_extents_for_origin:
+ * @font: a font.
+ * @glyph: 
+ * @direction: 
+ * @extents: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_extents_for_origin (hb_font_t *font,
                                      hb_codepoint_t glyph,
                                      hb_direction_t direction,
                                      hb_glyph_extents_t *extents)
 {
-  hb_bool_t ret = hb_font_get_glyph_extents (font, glyph, extents);
-
-  if (ret)
-    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, &extents->x_bearing, &extents->y_bearing);
-
-  return ret;
+  return font->get_glyph_extents_for_origin (glyph, direction, extents);
 }
 
+/**
+ * hb_font_get_glyph_contour_point_for_origin:
+ * @font: a font.
+ * @glyph: 
+ * @point_index: 
+ * @direction: 
+ * @x: (out): 
+ * @y: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
                                            hb_codepoint_t glyph, unsigned int point_index,
                                            hb_direction_t direction,
                                            hb_position_t *x, hb_position_t *y)
 {
-  hb_bool_t ret = hb_font_get_glyph_contour_point (font, glyph, point_index, x, y);
-
-  if (ret)
-    hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, x, y);
-
-  return ret;
-}
-
-
-/*
- * hb_face_t
- */
-
-static const hb_face_t _hb_face_nil = {
-  HB_OBJECT_HEADER_STATIC,
-
-  true, /* immutable */
-
-  NULL, /* reference_table */
-  NULL, /* user_data */
-  NULL, /* destroy */
-
-  NULL, /* ot_layout */
-
-  0,    /* index */
-  1000  /* upem */
-};
-
-
-hb_face_t *
-hb_face_create_for_tables (hb_reference_table_func_t  reference_table,
-                          void                      *user_data,
-                          hb_destroy_func_t          destroy)
-{
-  hb_face_t *face;
-
-  if (!reference_table || !(face = hb_object_create<hb_face_t> ())) {
-    if (destroy)
-      destroy (user_data);
-    return hb_face_get_empty ();
-  }
-
-  face->reference_table = reference_table;
-  face->user_data = user_data;
-  face->destroy = destroy;
-
-  face->ot_layout = _hb_ot_layout_create (face);
-
-  face->upem = 0;
-
-  return face;
-}
-
-
-typedef struct _hb_face_for_data_closure_t {
-  hb_blob_t *blob;
-  unsigned int  index;
-} hb_face_for_data_closure_t;
-
-static hb_face_for_data_closure_t *
-_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
-{
-  hb_face_for_data_closure_t *closure;
-
-  closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
-  if (unlikely (!closure))
-    return NULL;
-
-  closure->blob = blob;
-  closure->index = index;
-
-  return closure;
-}
-
-static void
-_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
-{
-  hb_blob_destroy (closure->blob);
-  free (closure);
-}
-
-static hb_blob_t *
-_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
-{
-  hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
-
-  if (tag == HB_TAG_NONE)
-    return hb_blob_reference (data->blob);
-
-  const OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob);
-  const OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
-
-  const OpenTypeTable &table = ot_face.get_table_by_tag (tag);
-
-  hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
-
-  return blob;
-}
-
-hb_face_t *
-hb_face_create (hb_blob_t    *blob,
-               unsigned int  index)
-{
-  hb_face_t *face;
-
-  if (unlikely (!blob || !hb_blob_get_length (blob)))
-    return hb_face_get_empty ();
-
-  hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
-
-  if (unlikely (!closure))
-    return hb_face_get_empty ();
-
-  face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
-                                   closure,
-                                   (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
-
-  hb_face_set_index (face, index);
-
-  return face;
-}
-
-hb_face_t *
-hb_face_get_empty (void)
-{
-  return const_cast<hb_face_t *> (&_hb_face_nil);
-}
-
-
-hb_face_t *
-hb_face_reference (hb_face_t *face)
-{
-  return hb_object_reference (face);
-}
-
-void
-hb_face_destroy (hb_face_t *face)
-{
-  if (!hb_object_destroy (face)) return;
-
-  _hb_ot_layout_destroy (face->ot_layout);
-
-  if (face->destroy)
-    face->destroy (face->user_data);
-
-  free (face);
-}
-
-hb_bool_t
-hb_face_set_user_data (hb_face_t          *face,
-                      hb_user_data_key_t *key,
-                      void *              data,
-                      hb_destroy_func_t   destroy,
-                      hb_bool_t           replace)
-{
-  return hb_object_set_user_data (face, key, data, destroy, replace);
-}
-
-void *
-hb_face_get_user_data (hb_face_t          *face,
-                      hb_user_data_key_t *key)
-{
-  return hb_object_get_user_data (face, key);
+  return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y);
 }
 
+/* Generates gidDDD if glyph has no name. */
+/**
+ * hb_font_glyph_to_string:
+ * @font: a font.
+ * @glyph: 
+ * @s: (array length=size): 
+ * @size: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
-hb_face_make_immutable (hb_face_t *face)
+hb_font_glyph_to_string (hb_font_t *font,
+                        hb_codepoint_t glyph,
+                        char *s, unsigned int size)
 {
-  if (hb_object_is_inert (face))
-    return;
-
-  face->immutable = true;
+  font->glyph_to_string (glyph, s, size);
 }
 
+/* Parses gidDDD and uniUUUU strings automatically. */
+/**
+ * hb_font_glyph_from_string:
+ * @font: a font.
+ * @s: (array length=len) (element-type uint8_t): 
+ * @len: 
+ * @glyph: (out): 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_face_is_immutable (hb_face_t *face)
+hb_font_glyph_from_string (hb_font_t *font,
+                          const char *s, int len, /* -1 means nul-terminated */
+                          hb_codepoint_t *glyph)
 {
-  return face->immutable;
-}
-
-
-hb_blob_t *
-hb_face_reference_table (hb_face_t *face,
-                        hb_tag_t   tag)
-{
-  hb_blob_t *blob;
-
-  if (unlikely (!face || !face->reference_table))
-    return hb_blob_get_empty ();
-
-  blob = face->reference_table (face, tag, face->user_data);
-  if (unlikely (!blob))
-    return hb_blob_get_empty ();
-
-  return blob;
-}
-
-hb_blob_t *
-hb_face_reference_blob (hb_face_t *face)
-{
-  return hb_face_reference_table (face, HB_TAG_NONE);
-}
-
-void
-hb_face_set_index (hb_face_t    *face,
-                  unsigned int  index)
-{
-  if (hb_object_is_inert (face))
-    return;
-
-  face->index = index;
-}
-
-unsigned int
-hb_face_get_index (hb_face_t    *face)
-{
-  return face->index;
-}
-
-void
-hb_face_set_upem (hb_face_t    *face,
-                 unsigned int  upem)
-{
-  if (hb_object_is_inert (face))
-    return;
-
-  face->upem = upem;
-}
-
-unsigned int
-hb_face_get_upem (hb_face_t *face)
-{
-  if (unlikely (!face->upem)) {
-    hb_blob_t *head_blob = Sanitizer<head>::sanitize (hb_face_reference_table (face, HB_OT_TAG_head));
-    const head *head_table = Sanitizer<head>::lock_instance (head_blob);
-    face->upem = head_table->get_upem ();
-    hb_blob_destroy (head_blob);
-  }
-  return face->upem;
+  return font->glyph_from_string (s, len, glyph);
 }
 
 
@@ -811,6 +837,16 @@ hb_face_get_upem (hb_face_t *face)
  * hb_font_t
  */
 
+/**
+ * hb_font_create: (Xconstructor)
+ * @face: a face.
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_create (hb_face_t *face)
 {
@@ -830,6 +866,16 @@ hb_font_create (hb_face_t *face)
   return font;
 }
 
+/**
+ * hb_font_create_sub_font:
+ * @parent: parent font.
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_create_sub_font (hb_font_t *parent)
 {
@@ -852,6 +898,15 @@ hb_font_create_sub_font (hb_font_t *parent)
   return font;
 }
 
+/**
+ * hb_font_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_get_empty (void)
 {
@@ -871,32 +926,75 @@ hb_font_get_empty (void)
 
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
     NULL, /* user_data */
-    NULL  /* destroy */
+    NULL, /* destroy */
+
+    {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+    }
   };
 
   return const_cast<hb_font_t *> (&_hb_font_nil);
 }
 
+/**
+ * hb_font_reference: (skip)
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_reference (hb_font_t *font)
 {
   return hb_object_reference (font);
 }
 
+/**
+ * hb_font_destroy: (skip)
+ * @font: a font.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_destroy (hb_font_t *font)
 {
   if (!hb_object_destroy (font)) return;
 
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  if (font->destroy)
+    font->destroy (font->user_data);
+
   hb_font_destroy (font->parent);
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
-  if (font->destroy)
-    font->destroy (font->user_data);
 
   free (font);
 }
 
+/**
+ * hb_font_set_user_data: (skip)
+ * @font: a font.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_set_user_data (hb_font_t          *font,
                       hb_user_data_key_t *key,
@@ -907,6 +1005,17 @@ hb_font_set_user_data (hb_font_t          *font,
   return hb_object_set_user_data (font, key, data, destroy, replace);
 }
 
+/**
+ * hb_font_get_user_data: (skip)
+ * @font: a font.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 void *
 hb_font_get_user_data (hb_font_t          *font,
                       hb_user_data_key_t *key)
@@ -914,27 +1023,65 @@ hb_font_get_user_data (hb_font_t          *font,
   return hb_object_get_user_data (font, key);
 }
 
+/**
+ * hb_font_make_immutable:
+ * @font: a font.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_make_immutable (hb_font_t *font)
 {
-  if (hb_object_is_inert (font))
+  if (unlikely (hb_object_is_inert (font)))
     return;
 
   font->immutable = true;
 }
 
+/**
+ * hb_font_is_immutable:
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_font_is_immutable (hb_font_t *font)
 {
   return font->immutable;
 }
 
+/**
+ * hb_font_get_parent:
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_font_get_parent (hb_font_t *font)
 {
   return font->parent;
 }
 
+/**
+ * hb_font_get_face:
+ * @font: a font.
+ *
+ * 
+ *
+ * Return value: (transfer none): 
+ *
+ * Since: 1.0
+ **/
 hb_face_t *
 hb_font_get_face (hb_font_t *font)
 {
@@ -942,15 +1089,26 @@ hb_font_get_face (hb_font_t *font)
 }
 
 
+/**
+ * hb_font_set_funcs:
+ * @font: a font.
+ * @klass: (closure font_data) (destroy destroy) (scope notified):
+ * @font_data: 
+ * @destroy: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_funcs (hb_font_t         *font,
                   hb_font_funcs_t   *klass,
-                  void              *user_data,
+                  void              *font_data,
                   hb_destroy_func_t  destroy)
 {
   if (font->immutable) {
     if (destroy)
-      destroy (user_data);
+      destroy (font_data);
     return;
   }
 
@@ -963,30 +1121,50 @@ hb_font_set_funcs (hb_font_t         *font,
   hb_font_funcs_reference (klass);
   hb_font_funcs_destroy (font->klass);
   font->klass = klass;
-  font->user_data = user_data;
+  font->user_data = font_data;
   font->destroy = destroy;
 }
 
+/**
+ * hb_font_set_funcs_data:
+ * @font: a font.
+ * @font_data: (destroy destroy) (scope notified):
+ * @destroy: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_funcs_data (hb_font_t         *font,
-                       void              *user_data,
+                       void              *font_data,
                        hb_destroy_func_t  destroy)
 {
   /* Destroy user_data? */
   if (font->immutable) {
     if (destroy)
-      destroy (user_data);
+      destroy (font_data);
     return;
   }
 
   if (font->destroy)
     font->destroy (font->user_data);
 
-  font->user_data = user_data;
+  font->user_data = font_data;
   font->destroy = destroy;
 }
 
 
+/**
+ * hb_font_set_scale:
+ * @font: a font.
+ * @x_scale: 
+ * @y_scale: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_scale (hb_font_t *font,
                   int x_scale,
@@ -999,6 +1177,16 @@ hb_font_set_scale (hb_font_t *font,
   font->y_scale = y_scale;
 }
 
+/**
+ * hb_font_get_scale:
+ * @font: a font.
+ * @x_scale: (out): 
+ * @y_scale: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_scale (hb_font_t *font,
                   int *x_scale,
@@ -1008,6 +1196,16 @@ hb_font_get_scale (hb_font_t *font,
   if (y_scale) *y_scale = font->y_scale;
 }
 
+/**
+ * hb_font_set_ppem:
+ * @font: a font.
+ * @x_ppem: 
+ * @y_ppem: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_set_ppem (hb_font_t *font,
                  unsigned int x_ppem,
@@ -1020,6 +1218,16 @@ hb_font_set_ppem (hb_font_t *font,
   font->y_ppem = y_ppem;
 }
 
+/**
+ * hb_font_get_ppem:
+ * @font: a font.
+ * @x_ppem: (out): 
+ * @y_ppem: (out): 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_get_ppem (hb_font_t *font,
                  unsigned int *x_ppem,
@@ -1028,5 +1236,3 @@ hb_font_get_ppem (hb_font_t *font,
   if (x_ppem) *x_ppem = font->x_ppem;
   if (y_ppem) *y_ppem = font->y_ppem;
 }
-
-
index b98759b..7273db4 100644 (file)
 #define HB_FONT_H
 
 #include "hb-common.h"
-#include "hb-blob.h"
+#include "hb-face.h"
 
 HB_BEGIN_DECLS
 
 
-typedef struct _hb_face_t hb_face_t;
-typedef struct _hb_font_t hb_font_t;
-
-/*
- * hb_face_t
- */
-
-hb_face_t *
-hb_face_create (hb_blob_t    *blob,
-               unsigned int  index);
-
-typedef hb_blob_t * (*hb_reference_table_func_t)  (hb_face_t *face, hb_tag_t tag, void *user_data);
-
-/* calls destroy() when not needing user_data anymore */
-hb_face_t *
-hb_face_create_for_tables (hb_reference_table_func_t  reference_table,
-                          void                      *user_data,
-                          hb_destroy_func_t          destroy);
-
-hb_face_t *
-hb_face_get_empty (void);
-
-hb_face_t *
-hb_face_reference (hb_face_t *face);
-
-void
-hb_face_destroy (hb_face_t *face);
-
-hb_bool_t
-hb_face_set_user_data (hb_face_t          *face,
-                      hb_user_data_key_t *key,
-                      void *              data,
-                      hb_destroy_func_t   destroy,
-                      hb_bool_t           replace);
-
-
-void *
-hb_face_get_user_data (hb_face_t          *face,
-                      hb_user_data_key_t *key);
-
-void
-hb_face_make_immutable (hb_face_t *face);
-
-hb_bool_t
-hb_face_is_immutable (hb_face_t *face);
-
-
-hb_blob_t *
-hb_face_reference_table (hb_face_t *face,
-                        hb_tag_t   tag);
-
-hb_blob_t *
-hb_face_reference_blob (hb_face_t *face);
-
-void
-hb_face_set_index (hb_face_t    *face,
-                  unsigned int  index);
-
-unsigned int
-hb_face_get_index (hb_face_t    *face);
-
-void
-hb_face_set_upem (hb_face_t    *face,
-                 unsigned int  upem);
-
-unsigned int
-hb_face_get_upem (hb_face_t *face);
+typedef struct hb_font_t hb_font_t;
 
 
 /*
  * hb_font_funcs_t
  */
 
-typedef struct _hb_font_funcs_t hb_font_funcs_t;
+typedef struct hb_font_funcs_t hb_font_funcs_t;
 
 hb_font_funcs_t *
 hb_font_funcs_create (void);
@@ -143,9 +77,10 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
 hb_bool_t
 hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
 
-/* funcs */
 
-typedef struct _hb_glyph_extents_t
+/* glyph extents */
+
+typedef struct hb_glyph_extents_t
 {
   hb_position_t x_bearing;
   hb_position_t y_bearing;
@@ -204,54 +139,180 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
 
 /* func setters */
 
+/**
+ * hb_font_funcs_set_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
-                             hb_font_get_glyph_func_t glyph_func,
+                             hb_font_get_glyph_func_t func,
                              void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_h_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
                                        hb_font_get_glyph_h_advance_func_t func,
                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
                                        hb_font_get_glyph_v_advance_func_t func,
                                        void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_h_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
                                       hb_font_get_glyph_h_origin_func_t func,
                                       void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
                                       hb_font_get_glyph_v_origin_func_t func,
                                       void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
                                        hb_font_get_glyph_h_kerning_func_t func,
                                        void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
                                        hb_font_get_glyph_v_kerning_func_t func,
                                        void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
                                      hb_font_get_glyph_extents_func_t func,
                                      void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_contour_point_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
                                            hb_font_get_glyph_contour_point_func_t func,
                                            void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_font_funcs_set_glyph_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
-                                  hb_font_get_glyph_name_func_t glyph_func,
+                                  hb_font_get_glyph_name_func_t func,
                                   void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_from_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
-                                       hb_font_get_glyph_from_name_func_t glyph_func,
+                                       hb_font_get_glyph_from_name_func_t func,
                                        void *user_data, hb_destroy_func_t destroy);
 
 
@@ -346,6 +407,17 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
                                            hb_direction_t direction,
                                            hb_position_t *x, hb_position_t *y);
 
+/* Generates gidDDD if glyph has no name. */
+void
+hb_font_glyph_to_string (hb_font_t *font,
+                        hb_codepoint_t glyph,
+                        char *s, unsigned int size);
+/* Parses gidDDD and uniUUUU strings automatically. */
+hb_bool_t
+hb_font_glyph_from_string (hb_font_t *font,
+                          const char *s, int len, /* -1 means nul-terminated */
+                          hb_codepoint_t *glyph);
+
 
 /*
  * hb_font_t
index 0589c9e..322f93a 100644 (file)
  *     In particular, FT_Get_Advance() without the NO_HINTING flag seems to be
  *     buggy.
  *
- *   - We don't handle / allow for emboldening / obliqueing.
- *
- *   - Rounding, etc?
- *
- *   - In the future, we should add constructors to create fonts in font space.
+ *     FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
+ *     would work fine.  However, we also abuse this API for performing in font-space,
+ *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
+ *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
+ *     pass NO_HINTING around.  This seems to work best, until we go ahead and add a full
+ *     load_flags API.
  *
- *   - I believe transforms are not correctly implemented.  FreeType does not
- *     provide any API to get to the transform/delta set on the face. :(
+ *   - We don't handle / allow for emboldening / obliqueing.
  *
- *   - Always use FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH?
+ *   - In the future, we should add constructors to create fonts in font space?
  *
  *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
  */
@@ -77,13 +77,10 @@ hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
 {
   FT_Face ft_face = (FT_Face) font_data;
 
-#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
   if (unlikely (variation_selector)) {
     *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
-    if (*glyph)
-      return true;
+    return *glyph != 0;
   }
-#endif
 
   *glyph = FT_Get_Char_Index (ft_face, unicode);
   return *glyph != 0;
@@ -102,7 +99,10 @@ hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
   if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
     return 0;
 
-  return v >> 10;
+  if (font->x_scale < 0)
+    v = -v;
+
+  return (v + (1<<9)) >> 10;
 }
 
 static hb_position_t
@@ -118,9 +118,12 @@ hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
   if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
     return 0;
 
+  if (font->y_scale < 0)
+    v = -v;
+
   /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
    * have a Y growing upward.  Hence the extra negation. */
-  return -v >> 10;
+  return (-v + (1<<9)) >> 10;
 }
 
 static hb_bool_t
@@ -144,7 +147,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
                          void *user_data HB_UNUSED)
 {
   FT_Face ft_face = (FT_Face) font_data;
-  int load_flags = FT_LOAD_DEFAULT;
+  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
     return false;
@@ -154,11 +157,16 @@ hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
   *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;
+
   return true;
 }
 
 static hb_position_t
-hb_ft_get_glyph_h_kerning (hb_font_t *font HB_UNUSED,
+hb_ft_get_glyph_h_kerning (hb_font_t *font,
                           void *font_data,
                           hb_codepoint_t left_glyph,
                           hb_codepoint_t right_glyph,
@@ -167,7 +175,8 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font HB_UNUSED,
   FT_Face ft_face = (FT_Face) font_data;
   FT_Vector kerningv;
 
-  if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerningv))
+  FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
+  if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv))
     return 0;
 
   return kerningv.x;
@@ -192,7 +201,7 @@ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
                         void *user_data HB_UNUSED)
 {
   FT_Face ft_face = (FT_Face) font_data;
-  int load_flags = FT_LOAD_DEFAULT;
+  int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
 
   if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
     return false;
@@ -200,7 +209,7 @@ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
   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;
+  extents->height = -ft_face->glyph->metrics.height;
   return true;
 }
 
@@ -232,7 +241,7 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
 }
 
 static hb_bool_t
-hb_ft_get_glyph_name (hb_font_t *font,
+hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
                      void *font_data,
                      hb_codepoint_t glyph,
                      char *name, unsigned int size,
@@ -241,14 +250,14 @@ hb_ft_get_glyph_name (hb_font_t *font,
   FT_Face ft_face = (FT_Face) font_data;
 
   hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
-  if (!ret)
-    snprintf (name, size, "gid%u", glyph);
+  if (ret && (size && !*name))
+    ret = false;
 
   return ret;
 }
 
 static hb_bool_t
-hb_ft_get_glyph_from_name (hb_font_t *font,
+hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
                           void *font_data,
                           const char *name, int len, /* -1 means nul-terminated */
                           hb_codepoint_t *glyph,
@@ -267,6 +276,15 @@ hb_ft_get_glyph_from_name (hb_font_t *font,
     *glyph = FT_Get_Name_Index (ft_face, buf);
   }
 
+  if (*glyph == 0)
+  {
+    /* Check whether the given name was actually the name of glyph 0. */
+    char buf[128];
+    if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
+        len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
+      return true;
+  }
+
   return *glyph != 0;
 }
 
@@ -317,7 +335,16 @@ reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
                         buffer, free);
 }
 
-
+/**
+ * hb_ft_face_create:
+ * @ft_face: (destroy destroy) (scope notified): 
+ * @destroy:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
 hb_face_t *
 hb_ft_face_create (FT_Face           ft_face,
                   hb_destroy_func_t destroy)
@@ -329,11 +356,7 @@ hb_ft_face_create (FT_Face           ft_face,
 
     blob = hb_blob_create ((const char *) ft_face->stream->base,
                           (unsigned int) ft_face->stream->size,
-                          /* TODO: We assume that it's mmap()'ed, but FreeType code
-                           * suggests that there are cases we reach here but font is
-                           * not mmapped.  For example, when mmap() fails.  No idea
-                           * how to deal with it better here. */
-                          HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
+                          HB_MEMORY_MODE_READONLY,
                           ft_face, destroy);
     face = hb_face_create (blob, ft_face->face_index);
     hb_blob_destroy (blob);
@@ -347,12 +370,37 @@ hb_ft_face_create (FT_Face           ft_face,
   return face;
 }
 
+/**
+ * hb_ft_face_create_referenced:
+ * @ft_face:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_ft_face_create_referenced (FT_Face ft_face)
+{
+  FT_Reference_Face (ft_face);
+  return hb_ft_face_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
+}
+
 static void
 hb_ft_face_finalize (FT_Face ft_face)
 {
   hb_face_destroy ((hb_face_t *) ft_face->generic.data);
 }
 
+/**
+ * hb_ft_face_create_cached:
+ * @ft_face: 
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
 hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face)
 {
@@ -374,6 +422,16 @@ _do_nothing (void)
 }
 
 
+/**
+ * hb_ft_font_create:
+ * @ft_face: (destroy destroy) (scope notified): 
+ * @destroy:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
 hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
                   hb_destroy_func_t destroy)
@@ -388,25 +446,45 @@ hb_ft_font_create (FT_Face           ft_face,
                     _hb_ft_get_font_funcs (),
                     ft_face, (hb_destroy_func_t) _do_nothing);
   hb_font_set_scale (font,
-                    ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
-                    ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
+                    (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16),
+                    (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16));
+#if 0 /* hb-ft works in no-hinting model */
   hb_font_set_ppem (font,
                    ft_face->size->metrics.x_ppem,
                    ft_face->size->metrics.y_ppem);
+#endif
 
   return font;
 }
 
+/**
+ * hb_ft_font_create_referenced:
+ * @ft_face:
+ *
+ * 
+ *
+ * Return value: (transfer full): 
+ * Since: 1.0
+ **/
+hb_font_t *
+hb_ft_font_create_referenced (FT_Face ft_face)
+{
+  FT_Reference_Face (ft_face);
+  return hb_ft_font_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
+}
+
 
 /* Thread-safe, lock-free, FT_Library */
 
 static FT_Library ft_library;
 
+#ifdef HB_USE_ATEXIT
 static
 void free_ft_library (void)
 {
   FT_Done_FreeType (ft_library);
 }
+#endif
 
 static FT_Library
 get_ft_library (void)
@@ -425,7 +503,7 @@ retry:
       goto retry;
     }
 
-#ifdef HAVE_ATEXIT
+#ifdef HB_USE_ATEXIT
     atexit (free_ft_library); /* First person registers atexit() callback. */
 #endif
   }
@@ -464,9 +542,18 @@ hb_ft_font_set_funcs (hb_font_t *font)
   FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
 
   FT_Set_Char_Size (ft_face,
-                   font->x_scale, font->y_scale,
+                   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, NULL);
+  }
 
   ft_face->generic.data = blob;
   ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
index 696251e..92f4b36 100644 (file)
 
 HB_BEGIN_DECLS
 
-/* Note: FreeType is not thread-safe.  Hence, these functions are not either. */
+/*
+ * Note: FreeType is not thread-safe.
+ * Hence, these functions are not either.
+ */
+
+/*
+ * hb-face from ft-face.
+ */
 
+/* This one creates a new hb-face for given ft-face.
+ * When the returned hb-face is destroyed, the destroy
+ * callback is called (if not NULL), with the ft-face passed
+ * to it.
+ *
+ * The client is responsible to make sure that ft-face is
+ * destroyed after hb-face is destroyed.
+ *
+ * Most often you don't want this function.  You should use either
+ * hb_ft_face_create_cached(), or hb_ft_face_create_referenced().
+ * In particular, if you are going to pass NULL as destroy, you
+ * probably should use (the more recent) hb_ft_face_create_referenced()
+ * instead.
+ */
 hb_face_t *
 hb_ft_face_create (FT_Face           ft_face,
                   hb_destroy_func_t destroy);
 
+/* This version is like hb_ft_face_create(), except that it caches
+ * the hb-face using the generic pointer of the ft-face.  This means
+ * that subsequent calls to this function with the same ft-face will
+ * return the same hb-face (correctly referenced).
+ *
+ * Client is still responsible for making sure that ft-face is destroyed
+ * after hb-face is.
+ */
 hb_face_t *
 hb_ft_face_create_cached (FT_Face ft_face);
 
+/* This version is like hb_ft_face_create(), except that it calls
+ * FT_Reference_Face() on ft-face, as such keeping ft-face alive
+ * as long as the hb-face is.
+ *
+ * This is the most convenient version to use.  Use it unless you have
+ * very good reasons not to.
+ */
+hb_face_t *
+hb_ft_face_create_referenced (FT_Face ft_face);
+
+
+/*
+ * hb-font from ft-face.
+ */
+
+/*
+ * Note:
+ *
+ * Set face size on ft-face before creating hb-font from it.
+ * Otherwise hb-ft would NOT pick up the font size correctly.
+ */
+
+/* See notes on hb_ft_face_create().  Same issues re lifecycle-management
+ * apply here.  Use hb_ft_font_create_referenced() if you can. */
 hb_font_t *
 hb_ft_font_create (FT_Face           ft_face,
                   hb_destroy_func_t destroy);
 
+/* See notes on hb_ft_face_create_referenced() re lifecycle-management
+ * issues. */
+hb_font_t *
+hb_ft_font_create_referenced (FT_Face ft_face);
 
 
 /* Makes an hb_font_t use FreeType internally to implement font functions. */
index 6b655dd..61dff5e 100644 (file)
@@ -77,7 +77,7 @@ glib_script_to_script[] =
   HB_SCRIPT_THAANA,
   HB_SCRIPT_THAI,
   HB_SCRIPT_TIBETAN,
-  HB_SCRIPT_CANADIAN_ABORIGINAL,
+  HB_SCRIPT_CANADIAN_SYLLABICS,
   HB_SCRIPT_YI,
   HB_SCRIPT_TAGALOG,
   HB_SCRIPT_HANUNOO,
@@ -192,13 +192,13 @@ hb_glib_script_from_script (hb_script_t script)
 }
 
 
-static unsigned int
+static hb_unicode_combining_class_t
 hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
                                 hb_codepoint_t      unicode,
                                 void               *user_data HB_UNUSED)
 
 {
-  return g_unichar_combining_class (unicode);
+  return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode);
 }
 
 static unsigned int
@@ -250,12 +250,9 @@ hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   /* We don't ifdef-out the fallback code such that compiler always
    * sees it and makes sure it's compilable. */
 
-  if (!a || !b)
-    return false;
-
   gchar utf8[12];
   gchar *normalized;
-  gint len;
+  int len;
   hb_bool_t ret;
 
   len = g_unichar_to_utf8 (a, utf8);
@@ -292,7 +289,7 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 
   gchar utf8[6];
   gchar *normalized;
-  gint len;
+  int len;
   hb_bool_t ret;
 
   len = g_unichar_to_utf8 (ab, utf8);
@@ -336,23 +333,63 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   return ret;
 }
 
+static unsigned int
+hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+                                        hb_codepoint_t      u,
+                                        hb_codepoint_t     *decomposed,
+                                        void               *user_data HB_UNUSED)
+{
+#if GLIB_CHECK_VERSION(2,29,12)
+  return g_unichar_fully_decompose (u, true, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN);
+#endif
 
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_glib_unicode_funcs;
-const hb_unicode_funcs_t _hb_glib_unicode_funcs = {
-  HB_OBJECT_HEADER_STATIC,
+  /* If the user doesn't have GLib >= 2.29.12 we have to perform
+   * a round trip to UTF-8 and the associated memory management dance. */
+  gchar utf8[6];
+  gchar *utf8_decomposed, *c;
+  gsize utf8_len, utf8_decomposed_len, i;
 
-  NULL, /* parent */
-  true, /* immutable */
-  {
-#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
-    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
-  }
-};
+  /* Convert @u to UTF-8 and normalise it in NFKD mode. This performs the compatibility decomposition. */
+  utf8_len = g_unichar_to_utf8 (u, utf8);
+  utf8_decomposed = g_utf8_normalize (utf8, utf8_len, G_NORMALIZE_NFKD);
+  utf8_decomposed_len = g_utf8_strlen (utf8_decomposed, -1);
+
+  assert (utf8_decomposed_len <= HB_UNICODE_MAX_DECOMPOSITION_LEN);
+
+  for (i = 0, c = utf8_decomposed; i < utf8_decomposed_len; i++, c = g_utf8_next_char (c))
+    *decomposed++ = g_utf8_get_char (c);
+
+  g_free (utf8_decomposed);
+
+  return utf8_decomposed_len;
+}
 
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void)
 {
+  static const hb_unicode_funcs_t _hb_glib_unicode_funcs = {
+    HB_OBJECT_HEADER_STATIC,
+
+    NULL, /* parent */
+    true, /* immutable */
+    {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
+      HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+    }
+  };
+
   return const_cast<hb_unicode_funcs_t *> (&_hb_glib_unicode_funcs);
 }
 
+hb_blob_t *
+hb_glib_blob_create (GBytes *gbytes)
+{
+  gsize size = 0;
+  gconstpointer data = g_bytes_get_data (gbytes, &size);
+  return hb_blob_create ((const char *) data,
+                        size,
+                        HB_MEMORY_MODE_READONLY,
+                        g_bytes_ref (gbytes),
+                        (hb_destroy_func_t) g_bytes_unref);
+}
index 63a9d33..1a8f42e 100644 (file)
@@ -46,6 +46,9 @@ hb_glib_script_from_script (hb_script_t script);
 hb_unicode_funcs_t *
 hb_glib_get_unicode_funcs (void);
 
+hb_blob_t *
+hb_glib_blob_create (GBytes *gbytes);
+
 
 HB_END_DECLS
 
index 05abd89..ca458a3 100644 (file)
 /*** END file-production ***/
 
 /*** BEGIN value-header ***/
-inline static /* TODO(behdad) disable these for now until we fix them... */
 GType
 @enum_name@_get_type (void)
 {
-  static volatile gsize g_define_type_id__volatile = 0;
+  static gsize type_id = 0;
 
-  if (g_once_init_enter (&g_define_type_id__volatile))
+  if (g_once_init_enter (&type_id))
     {
       static const G@Type@Value values[] = {
 /*** END value-header ***/
@@ -63,12 +62,12 @@ GType
 /*** BEGIN value-tail ***/
         { 0, NULL, NULL }
       };
-      GType g_define_type_id =
+      GType id =
         g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
-      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+      g_once_init_leave (&type_id, id);
     }
 
-  return g_define_type_id__volatile;
+  return type_id;
 }
 
 /*** END value-tail ***/
similarity index 66%
rename from src/indic.cc
rename to src/hb-gobject-enums.h.tmpl
index 3b44076..6ecda06 100644 (file)
@@ -1,5 +1,6 @@
+/*** BEGIN file-header ***/
 /*
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-ot-shape-complex-indic-private.hh"
+#ifndef HB_GOBJECT_H_IN
+#error "Include <hb-gobject.h> instead."
+#endif
 
-int
-main (void)
-{
-  hb_unicode_funcs_t *funcs = hb_unicode_funcs_get_default ();
+#ifndef HB_GOBJECT_ENUMS_H
+#define HB_GOBJECT_ENUMS_H
 
-  printf ("There are split matras without a Unicode decomposition:\n");
-  for (hb_codepoint_t u = 0; u < 0x110000; u++)
-  {
-    unsigned int type = get_indic_categories (u);
+#include "hb.h"
 
-    unsigned int category = type & 0x0F;
-    unsigned int position = type >> 4;
+#include <glib-object.h>
 
-    hb_codepoint_t a, b;
-    if (!hb_unicode_decompose (funcs, u, &a, &b))
-      printf ("U+%04X %x %x\n", u, category, position);
-  }
-}
+HB_BEGIN_DECLS
+
+
+/*** END file-header ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+
+HB_END_DECLS
+
+#endif /* HB_GOBJECT_ENUMS_H */
+/*** END file-tail ***/
index cec4854..2451b66 100644 (file)
 
 #include "hb-gobject.h"
 
-#define _HB_DEFINE_BOXED_TYPE(Name,underscore_name,copy_func,free_func) \
+#define HB_DEFINE_BOXED_TYPE(name,copy_func,free_func) \
 GType \
-underscore_name##_get_type (void) \
+hb_gobject_##name##_get_type (void) \
 { \
-   static volatile gsize type = 0; \
-   if (g_once_init_enter (&type)) { \
-      GType t = g_boxed_type_register_static (g_intern_static_string (#Name), \
-                                             (GBoxedCopyFunc) copy_func, \
-                                             (GBoxedFreeFunc) free_func); \
-      g_once_init_leave (&type, t); \
+   static gsize type_id = 0; \
+   if (g_once_init_enter (&type_id)) { \
+      GType id = g_boxed_type_register_static (g_intern_static_string ("hb_" #name "_t"), \
+                                              (GBoxedCopyFunc) copy_func, \
+                                              (GBoxedFreeFunc) free_func); \
+      g_once_init_leave (&type_id, id); \
    } \
-   return type; \
+   return type_id; \
 }
 
-#define HB_DEFINE_BOXED_TYPE(name) \
-       _HB_DEFINE_BOXED_TYPE (hb_##name, hb_gobject_##name, hb_##name##_reference, hb_##name##_destroy);
+#define HB_DEFINE_OBJECT_TYPE(name) \
+       HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
 
-HB_DEFINE_BOXED_TYPE (buffer)
-HB_DEFINE_BOXED_TYPE (blob)
-HB_DEFINE_BOXED_TYPE (face)
-HB_DEFINE_BOXED_TYPE (font)
-HB_DEFINE_BOXED_TYPE (font_funcs)
-HB_DEFINE_BOXED_TYPE (unicode_funcs)
+HB_DEFINE_OBJECT_TYPE (buffer)
+HB_DEFINE_OBJECT_TYPE (blob)
+HB_DEFINE_OBJECT_TYPE (face)
+HB_DEFINE_OBJECT_TYPE (font)
+HB_DEFINE_OBJECT_TYPE (font_funcs)
+HB_DEFINE_OBJECT_TYPE (set)
+HB_DEFINE_OBJECT_TYPE (shape_plan)
+HB_DEFINE_OBJECT_TYPE (unicode_funcs)
 
+
+static hb_feature_t *feature_reference (hb_feature_t *g)
+{
+  hb_feature_t *c = (hb_feature_t *) calloc (1, sizeof (hb_feature_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void feature_destroy (hb_feature_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (feature, feature_reference, feature_destroy)
+
+static hb_glyph_info_t *glyph_info_reference (hb_glyph_info_t *g)
+{
+  hb_glyph_info_t *c = (hb_glyph_info_t *) calloc (1, sizeof (hb_glyph_info_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void glyph_info_destroy (hb_glyph_info_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (glyph_info, glyph_info_reference, glyph_info_destroy)
+
+static hb_glyph_position_t *glyph_position_reference (hb_glyph_position_t *g)
+{
+  hb_glyph_position_t *c = (hb_glyph_position_t *) calloc (1, sizeof (hb_glyph_position_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void glyph_position_destroy (hb_glyph_position_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (glyph_position, glyph_position_reference, glyph_position_destroy)
+
+static hb_segment_properties_t *segment_properties_reference (hb_segment_properties_t *g)
+{
+  hb_segment_properties_t *c = (hb_segment_properties_t *) calloc (1, sizeof (hb_segment_properties_t));
+  if (unlikely (!c)) return NULL;
+  *c = *g;
+  return c;
+}
+static void segment_properties_destroy (hb_segment_properties_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (segment_properties, segment_properties_reference, segment_properties_destroy)
+
+static hb_user_data_key_t user_data_key_reference (hb_user_data_key_t l) { return l; }
+static void user_data_key_destroy (hb_user_data_key_t l) { }
+HB_DEFINE_BOXED_TYPE (user_data_key, user_data_key_reference, user_data_key_destroy)
+
+
+static hb_language_t *language_reference (hb_language_t *l)
+{
+  hb_language_t *c = (hb_language_t *) calloc (1, sizeof (hb_language_t));
+  if (unlikely (!c)) return NULL;
+  *c = *l;
+  return c;
+}
+static void language_destroy (hb_language_t *l) { free (l); }
+HB_DEFINE_BOXED_TYPE (language, language_reference, language_destroy)
diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h
new file mode 100644 (file)
index 0000000..4a88d56
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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
+ */
+
+#ifndef HB_GOBJECT_H_IN
+#error "Include <hb-gobject.h> instead."
+#endif
+
+#ifndef HB_GOBJECT_STRUCTS_H
+#define HB_GOBJECT_STRUCTS_H
+
+#include "hb.h"
+
+#include <glib-object.h>
+
+HB_BEGIN_DECLS
+
+
+/* Object types */
+
+GType hb_gobject_blob_get_type (void);
+#define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
+
+GType hb_gobject_buffer_get_type (void);
+#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
+
+GType hb_gobject_face_get_type (void);
+#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
+
+GType hb_gobject_font_get_type (void);
+#define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
+
+GType hb_gobject_font_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
+
+GType hb_gobject_set_get_type (void);
+#define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
+
+GType hb_gobject_shape_plan_get_type (void);
+#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
+
+GType hb_gobject_unicode_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
+
+/* Value types */
+
+GType hb_gobject_feature_get_type (void);
+#define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ())
+
+GType hb_gobject_glyph_info_get_type (void);
+#define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ())
+
+GType hb_gobject_glyph_position_get_type (void);
+#define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ())
+
+GType hb_gobject_segment_properties_get_type (void);
+#define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
+
+GType hb_gobject_user_data_key_get_type (void);
+#define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
+
+/* Currently gobject-introspection doesn't understand that hb_language_t
+ * can be passed by-value.  As such we box it up.  May remove in the
+ * future.
+ *
+ *   https://bugzilla.gnome.org/show_bug.cgi?id=707656
+ */
+GType hb_gobject_language_get_type (void);
+#define HB_GOBJECT_TYPE_LANGUAGE (hb_gobject_language_get_type ())
+
+HB_END_DECLS
+
+#endif /* HB_GOBJECT_H */
index 4f23fdd..ea1bd25 100644 (file)
 
 #ifndef HB_GOBJECT_H
 #define HB_GOBJECT_H
+#define HB_GOBJECT_H_IN
 
 #include "hb.h"
 
-#include <glib-object.h>
+#include "hb-gobject-enums.h"
+#include "hb-gobject-structs.h"
 
 HB_BEGIN_DECLS
-
-
-/* Objects */
-
-#define HB_GOBJECT_TYPE_BLOB hb_gobject_blob_get_type ()
-GType
-hb_gobject_blob_get_type (void);
-
-#define HB_GOBJECT_TYPE_BUFFER hb_gobject_buffer_get_type ()
-GType
-hb_gobject_buffer_get_type (void);
-
-#define HB_GOBJECT_TYPE_FACE hb_gobject_face_get_type ()
-GType
-hb_gobject_face_get_type (void);
-
-#define HB_GOBJECT_TYPE_FONT hb_gobject_font_get_type ()
-GType
-hb_gobject_font_get_type (void);
-
-#define HB_GOBJECT_TYPE_FONT_FUNCS hb_gobject_font_funcs_get_type ()
-GType
-hb_gobject_font_funcs_get_type (void);
-
-#define HB_GOBJECT_TYPE_UNICODE_FUNCS hb_gobject_unicode_funcs_get_type ()
-GType
-hb_gobject_unicode_funcs_get_type (void);
-
-
-/* Enums */
-
-
 HB_END_DECLS
 
+#undef HB_GOBJECT_H_IN
 #endif /* HB_GOBJECT_H */
index 3fa9f79..807c330 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright © 2011  Martin Hosken
  * Copyright © 2011  SIL International
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
-#include "hb-private.hh"
+#define HB_SHAPER graphite2
+#define hb_graphite2_shaper_font_data_t gr_font
+#include "hb-shaper-impl-private.hh"
 
 #include "hb-graphite2.h"
 
-#include "hb-buffer-private.hh"
-#include "hb-font-private.hh"
-#include "hb-ot-tag.h"
-
-#include <graphite2/Font.h>
 #include <graphite2/Segment.h>
 
 
-struct hb_gr_cluster_t {
-  unsigned int base_char;
-  unsigned int num_chars;
-  unsigned int base_glyph;
-  unsigned int num_glyphs;
-};
+HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
 
 
-typedef struct hb_gr_tablelist_t {
-  hb_blob_t   *blob;
-  struct hb_gr_tablelist_t *next;
-  unsigned int tag;
-} hb_gr_tablelist_t;
+/*
+ * shaper face data
+ */
 
-static struct hb_gr_face_data_t {
-  hb_face_t         *face;
-  gr_face           *grface;
-  hb_gr_tablelist_t *tlist;
-} _hb_gr_face_data_nil = {NULL, NULL};
+typedef struct hb_graphite2_tablelist_t {
+  struct hb_graphite2_tablelist_t *next;
+  hb_blob_t *blob;
+  unsigned int tag;
+} hb_graphite2_tablelist_t;
 
-static struct hb_gr_font_data_t {
-  gr_font   *grfont;
+struct hb_graphite2_shaper_face_data_t {
+  hb_face_t *face;
   gr_face   *grface;
-} _hb_gr_font_data_nil = {NULL, NULL};
-
+  hb_graphite2_tablelist_t *tlist;
+};
 
-static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *len)
+static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
 {
-  hb_gr_tablelist_t *pl = NULL, *p;
-  hb_gr_face_data_t *face = (hb_gr_face_data_t *) data;
-  hb_gr_tablelist_t *tlist = face->tlist;
-
-  for (p = tlist; p; p = p->next)
-    if (p->tag == tag ) {
-      unsigned int tlen;
-      const char *d = hb_blob_get_data (p->blob, &tlen);
-      *len = tlen;
-      return d;
-    } else
-      pl = p;
-
-  if (!face->face)
-    return NULL;
-  hb_blob_t *blob = hb_face_reference_table (face->face, tag);
+  hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
+  hb_graphite2_tablelist_t *tlist = face_data->tlist;
 
-  if (!pl || pl->blob)
+  hb_blob_t *blob = NULL;
+
+  for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
+    if (p->tag == tag) {
+      blob = p->blob;
+      break;
+    }
+
+  if (unlikely (!blob))
   {
-    p = (hb_gr_tablelist_t *) malloc (sizeof (hb_gr_tablelist_t));
-    if (!p) {
+    blob = face_data->face->reference_table (tag);
+
+    hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
+    if (unlikely (!p)) {
       hb_blob_destroy (blob);
       return NULL;
     }
-    p->next = NULL;
-    if (pl)
-      pl->next = p;
-    else
-      face->tlist = p;
-    pl = p;
+    p->blob = blob;
+    p->tag = tag;
+
+    /* TODO Not thread-safe, but fairly harmless.
+     * We can do the double-chcked pointer cmpexch thing here. */
+    p->next = face_data->tlist;
+    face_data->tlist = p;
   }
-  pl->blob = blob;
-  pl->tag = tag;
 
   unsigned int tlen;
   const char *d = hb_blob_get_data (blob, &tlen);
@@ -106,183 +92,215 @@ static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *
   return d;
 }
 
-static float hb_gr_get_advance (const void *hb_font, unsigned short gid)
+hb_graphite2_shaper_face_data_t *
+_hb_graphite2_shaper_face_data_create (hb_face_t *face)
 {
-  return hb_font_get_glyph_h_advance ((hb_font_t *) hb_font, gid);
+  hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
+  /* Umm, we just reference the table to check whether it exists.
+   * Maybe add better API for this? */
+  if (!hb_blob_get_length (silf_blob))
+  {
+    hb_blob_destroy (silf_blob);
+    return NULL;
+  }
+  hb_blob_destroy (silf_blob);
+
+  hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
+  if (unlikely (!data))
+    return NULL;
+
+  data->face = face;
+  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
+
+  if (unlikely (!data->grface)) {
+    free (data);
+    return NULL;
+  }
+
+  return data;
 }
 
-static void _hb_gr_face_data_destroy (void *data)
+void
+_hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data)
 {
-  hb_gr_face_data_t *f = (hb_gr_face_data_t *) data;
-  hb_gr_tablelist_t *tlist = f->tlist;
+  hb_graphite2_tablelist_t *tlist = data->tlist;
+
   while (tlist)
   {
-    hb_gr_tablelist_t *old = tlist;
+    hb_graphite2_tablelist_t *old = tlist;
     hb_blob_destroy (tlist->blob);
     tlist = tlist->next;
     free (old);
   }
-  gr_face_destroy (f->grface);
-}
 
-static void _hb_gr_font_data_destroy (void *data)
-{
-  hb_gr_font_data_t *f = (hb_gr_font_data_t *) data;
+  gr_face_destroy (data->grface);
 
-  gr_font_destroy (f->grfont);
-  free (f);
+  free (data);
 }
 
-static hb_user_data_key_t hb_gr_data_key;
-
-static hb_gr_face_data_t *
-_hb_gr_face_get_data (hb_face_t *face)
+gr_face *
+hb_graphite2_face_get_gr_face (hb_face_t *face)
 {
-  hb_gr_face_data_t *data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
-  if (likely (data)) return data;
-
-  data = (hb_gr_face_data_t *) calloc (1, sizeof (hb_gr_face_data_t));
-  if (unlikely (!data))
-    return &_hb_gr_face_data_nil;
+  if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
+  return HB_SHAPER_DATA_GET (face)->grface;
+}
 
 
-  hb_blob_t *silf_blob = hb_face_reference_table (face, HB_GRAPHITE_TAG_Silf);
-  if (!hb_blob_get_length (silf_blob))
-  {
-    hb_blob_destroy (silf_blob);
-    return &_hb_gr_face_data_nil;
-  }
+/*
+ * shaper font data
+ */
 
-  data->face = face;
-  data->grface = gr_make_face (data, &hb_gr_get_table, gr_face_default);
+static float hb_graphite2_get_advance (const void *hb_font, unsigned short gid)
+{
+  return ((hb_font_t *) hb_font)->get_glyph_h_advance (gid);
+}
 
+hb_graphite2_shaper_font_data_t *
+_hb_graphite2_shaper_font_data_create (hb_font_t *font)
+{
+  if (unlikely (!hb_graphite2_shaper_face_data_ensure (font->face))) return NULL;
 
-  if (unlikely (!hb_face_set_user_data (face, &hb_gr_data_key, data,
-                                       (hb_destroy_func_t) _hb_gr_face_data_destroy,
-                                       false)))
-  {
-    _hb_gr_face_data_destroy (data);
-    data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
-    if (data)
-      return data;
-    else
-      return &_hb_gr_face_data_nil;
-  }
+  hb_face_t *face = font->face;
+  hb_graphite2_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
 
-  return data;
+  return gr_make_font_with_advance_fn (font->x_scale, font, &hb_graphite2_get_advance, face_data->grface);
 }
 
-static hb_gr_font_data_t *
-_hb_gr_font_get_data (hb_font_t *font)
+void
+_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
 {
-  hb_gr_font_data_t *data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
-  if (likely (data)) return data;
-
-  data = (hb_gr_font_data_t *) calloc (1, sizeof (hb_gr_font_data_t));
-  if (unlikely (!data))
-    return &_hb_gr_font_data_nil;
-
+  gr_font_destroy (data);
+}
 
-  hb_blob_t *silf_blob = hb_face_reference_table (font->face, HB_GRAPHITE_TAG_Silf);
-  if (!hb_blob_get_length (silf_blob))
-  {
-    hb_blob_destroy (silf_blob);
-    return &_hb_gr_font_data_nil;
-  }
+gr_font *
+hb_graphite2_font_get_gr_font (hb_font_t *font)
+{
+  if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL;
+  return HB_SHAPER_DATA_GET (font);
+}
 
-  data->grface = _hb_gr_face_get_data (font->face)->grface;
-  int scale;
-  hb_font_get_scale (font, &scale, NULL);
-  data->grfont = gr_make_font_with_advance_fn (scale, font, &hb_gr_get_advance, data->grface);
 
+/*
+ * shaper shape_plan data
+ */
 
-  if (unlikely (!hb_font_set_user_data (font, &hb_gr_data_key, data,
-                                       (hb_destroy_func_t) _hb_gr_font_data_destroy,
-                                       false)))
-  {
-    _hb_gr_font_data_destroy (data);
-    data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
-    if (data)
-      return data;
-    else
-      return &_hb_gr_font_data_nil;
-  }
+struct hb_graphite2_shaper_shape_plan_data_t {};
 
-  return data;
+hb_graphite2_shaper_shape_plan_data_t *
+_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                            const hb_feature_t *user_features HB_UNUSED,
+                                            unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
 }
 
-
-hb_bool_t
-_hb_graphite_shape (hb_font_t          *font,
-                  hb_buffer_t        *buffer,
-                  const hb_feature_t *features,
-                  unsigned int        num_features)
+void
+_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shaper_shape_plan_data_t *data HB_UNUSED)
 {
+}
 
-  buffer->guess_properties ();
-
-  /* XXX We do a hell of a lot of stuff just to figure out this font
-   * is not graphite!  Shouldn't do. */
-
-  hb_gr_font_data_t *data = _hb_gr_font_get_data (font);
-  if (!data->grface) return false;
 
-  unsigned int charlen;
-  hb_glyph_info_t *bufferi = hb_buffer_get_glyph_infos (buffer, &charlen);
+/*
+ * shaper
+ */
 
-  int success = 0;
+struct hb_graphite2_cluster_t {
+  unsigned int base_char;
+  unsigned int num_chars;
+  unsigned int base_glyph;
+  unsigned int num_glyphs;
+  unsigned int cluster;
+};
 
-  if (!charlen) return true;
+hb_bool_t
+_hb_graphite2_shape (hb_shape_plan_t    *shape_plan,
+                    hb_font_t          *font,
+                    hb_buffer_t        *buffer,
+                    const hb_feature_t *features,
+                    unsigned int        num_features)
+{
+  hb_face_t *face = font->face;
+  gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
+  gr_font *grfont = HB_SHAPER_DATA_GET (font);
 
   const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
-  const char *lang_end = strchr (lang, '-');
+  const char *lang_end = lang ? strchr (lang, '-') : NULL;
   int lang_len = lang_end ? lang_end - lang : -1;
-  gr_feature_val *feats = gr_face_featureval_for_lang (data->grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
+  gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
 
   while (num_features--)
   {
-    const gr_feature_ref *fref = gr_face_find_fref (data->grface, features->tag);
+    const gr_feature_ref *fref = gr_face_find_fref (grface, features->tag);
     if (fref)
       gr_fref_set_feature_value (fref, features->value, feats);
     features++;
   }
 
-  hb_codepoint_t *gids = NULL, *pg;
-  hb_gr_cluster_t *clusters = NULL;
   gr_segment *seg = NULL;
-  uint32_t *text = NULL;
   const gr_slot *is;
   unsigned int ci = 0, ic = 0;
   float curradvx = 0., curradvy = 0.;
-  unsigned int glyphlen = 0;
-  unsigned int *p;
 
-  text = (uint32_t *) malloc ((charlen + 1) * sizeof (uint32_t));
-  if (!text) goto dieout;
+  unsigned int scratch_size;
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+
+  uint32_t *chars = (uint32_t *) scratch;
 
-  p = text;
-  for (unsigned int i = 0; i < charlen; ++i)
-    *p++ = bufferi++->codepoint;
-  *p = 0;
+  for (unsigned int i = 0; i < buffer->len; ++i)
+    chars[i] = buffer->info[i].codepoint;
 
   hb_tag_t script_tag[2];
   hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
 
-  seg = gr_make_seg (data->grfont, data->grface,
+  seg = gr_make_seg (grfont, grface,
                     script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
                     feats,
-                    gr_utf32, text, charlen,
+                    gr_utf32, chars, buffer->len,
                     2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
-  if (!seg) goto dieout;
 
-  glyphlen = gr_seg_n_slots (seg);
-  clusters = (hb_gr_cluster_t *) calloc (charlen, sizeof (hb_gr_cluster_t));
-  if (!glyphlen || !clusters) goto dieout;
+  if (unlikely (!seg)) {
+    if (feats) gr_featureval_destroy (feats);
+    return false;
+  }
+
+  unsigned int glyph_count = gr_seg_n_slots (seg);
+  if (unlikely (!glyph_count)) {
+    if (feats) gr_featureval_destroy (feats);
+    gr_seg_destroy (seg);
+    return false;
+  }
+
+  scratch = buffer->get_scratch_buffer (&scratch_size);
+  while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
+         DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
+  {
+    if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+    {
+      if (feats) gr_featureval_destroy (feats);
+      gr_seg_destroy (seg);
+      return false;
+    }
+    scratch = buffer->get_scratch_buffer (&scratch_size);
+  }
+
+#define ALLOCATE_ARRAY(Type, name, len) \
+  Type *name = (Type *) scratch; \
+  { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    assert (_consumed <= scratch_size); \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  }
+
+  ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
+  ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
 
-  gids = (hb_codepoint_t *) malloc (glyphlen * sizeof (hb_codepoint_t));
-  if (!gids) goto dieout;
+#undef ALLOCATE_ARRAY
 
-  pg = gids;
+  memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
+
+  hb_codepoint_t *pg = gids;
+  clusters[0].cluster = buffer->info[0].cluster;
   for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
   {
     unsigned int before = gr_slot_before (is);
@@ -298,8 +316,9 @@ _hb_graphite_shape (hb_font_t          *font,
 
     if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
     {
-      hb_gr_cluster_t *c = clusters + ci + 1;
+      hb_graphite2_cluster_t *c = clusters + ci + 1;
       c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
+      c->cluster = buffer->info[c->base_char].cluster;
       c->num_chars = before - c->base_char;
       c->base_glyph = ic;
       c->num_glyphs = 0;
@@ -312,39 +331,46 @@ _hb_graphite_shape (hb_font_t          *font,
   }
   ci++;
 
-  buffer->clear_output ();
+  //buffer->clear_output ();
   for (unsigned int i = 0; i < ci; ++i)
-    buffer->replace_glyphs (clusters[i].num_chars, clusters[i].num_glyphs, gids + clusters[i].base_glyph);
-  buffer->swap_buffers ();
+  {
+    for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
+    {
+      hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
+      info->codepoint = gids[clusters[i].base_glyph + j];
+      info->cluster = clusters[i].cluster;
+    }
+  }
+  buffer->len = glyph_count;
+  //buffer->swap_buffers ();
+
+  if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+    curradvx = gr_seg_advance_X(seg);
 
   hb_glyph_position_t *pPos;
   for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
        is; pPos++, is = gr_slot_next_in_segment (is))
   {
-    pPos->x_offset = gr_slot_origin_X(is) - curradvx;
-    pPos->y_offset = gr_slot_origin_Y(is) - curradvy;
-    pPos->x_advance = gr_slot_advance_X(is, data->grface, data->grfont);
-    pPos->y_advance = gr_slot_advance_Y(is, data->grface, data->grfont);
-//    if (pPos->x_advance < 0 && gr_slot_attached_to(is))
-//      pPos->x_advance = 0;
-    curradvx += pPos->x_advance;
+    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
+    pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
+    pPos->y_advance = gr_slot_advance_Y (is, grface, grfont);
+    if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+      curradvx -= pPos->x_advance;
+    pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+    if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+      curradvx += pPos->x_advance;
+    pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
     curradvy += pPos->y_advance;
   }
-  pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
-
-  /* TODO(behdad):
-   * This shaper is badly broken with RTL text.  It returns glyphs
-   * in the logical order!
-   */
-//  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
-//    hb_buffer_reverse (buffer);
-
-  success = 1;
-
-dieout:
-  if (gids) free (gids);
-  if (clusters) free (clusters);
-  if (seg) gr_seg_destroy (seg);
-  if (text) free (text);
-  return success;
+  if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+    pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
+
+  if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+    hb_buffer_reverse_clusters (buffer);
+
+  if (feats) gr_featureval_destroy (feats);
+  gr_seg_destroy (seg);
+
+  return true;
 }
index 2d16cc8..3eae54a 100644 (file)
 
 #include "hb.h"
 
+#include <graphite2/Font.h>
+
 HB_BEGIN_DECLS
 
 
-#define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f')
+#define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
+
+
+gr_face *
+hb_graphite2_face_get_gr_face (hb_face_t *face);
+
+gr_font *
+hb_graphite2_font_get_gr_font (hb_font_t *font);
 
-/* TODO add gr_font/face etc getters and other glue API */
 
 HB_END_DECLS
 
index aead6dd..24cec9d 100644 (file)
 
 #include "hb-unicode-private.hh"
 
-#include <unicode/uversion.h>
 #include <unicode/uchar.h>
 #include <unicode/unorm.h>
 #include <unicode/ustring.h>
-
+#include <unicode/uversion.h>
 
 
 hb_script_t
@@ -63,13 +62,13 @@ hb_icu_script_from_script (hb_script_t script)
 }
 
 
-static unsigned int
+static hb_unicode_combining_class_t
 hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
                                hb_codepoint_t      unicode,
                                void               *user_data HB_UNUSED)
 
 {
-  return u_getCombiningClass (unicode);
+  return (hb_unicode_combining_class_t) u_getCombiningClass (unicode);
 }
 
 static unsigned int
@@ -164,6 +163,10 @@ hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   return hb_icu_script_to_script (scriptCode);
 }
 
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+static const UNormalizer2 *normalizer;
+#endif
+
 static hb_bool_t
 hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
                        hb_codepoint_t      a,
@@ -171,11 +174,20 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
                        hb_codepoint_t     *ab,
                        void               *user_data HB_UNUSED)
 {
-  if (!a || !b)
-    return false;
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+  {
+    UChar32 ret = unorm2_composePair (normalizer, a, b);
+    if (ret < 0) return false;
+    *ab = ret;
+    return true;
+  }
+#endif
+
+  /* We don't ifdef-out the fallback code such that compiler always
+   * sees it and makes sure it's compilable. */
 
   UChar utf16[4], normalized[5];
-  int len;
+  unsigned int len;
   hb_bool_t ret, err;
   UErrorCode icu_err;
 
@@ -207,8 +219,34 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
                          hb_codepoint_t     *b,
                          void               *user_data HB_UNUSED)
 {
-  UChar utf16[2], normalized[20];
-  int len;
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+  {
+    UChar decomposed[4];
+    int len;
+    UErrorCode icu_err = U_ZERO_ERROR;
+    len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
+                                     ARRAY_LENGTH (decomposed), &icu_err);
+    if (U_FAILURE (icu_err) || len < 0) return false;
+
+    len = u_countChar32 (decomposed, len);
+    if (len == 1) {
+      U16_GET_UNSAFE (decomposed, 0, *a);
+      *b = 0;
+      return *a != ab;
+    } else if (len == 2) {
+      len =0;
+      U16_NEXT_UNSAFE (decomposed, len, *a);
+      U16_NEXT_UNSAFE (decomposed, len, *b);
+    }
+    return true;
+  }
+#endif
+
+  /* We don't ifdef-out the fallback code such that compiler always
+   * sees it and makes sure it's compilable. */
+
+  UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
+  unsigned int len;
   hb_bool_t ret, err;
   UErrorCode icu_err;
 
@@ -255,13 +293,15 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   } else {
     /* If decomposed to more than two characters, take the last one,
      * and recompose the rest to get the first component. */
-    U16_PREV_UNSAFE (normalized, len, *b);
-    UChar recomposed[20];
+    U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */
+    UChar recomposed[18 * 2];
     icu_err = U_ZERO_ERROR;
     len = unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
     if (U_FAILURE (icu_err))
       return false;
     /* We expect that recomposed has exactly one character now. */
+    if (unlikely (u_countChar32 (recomposed, len) != 1))
+      return false;
     U16_GET_UNSAFE (recomposed, 0, *a);
     ret = true;
   }
@@ -269,24 +309,62 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
   return ret;
 }
 
+static unsigned int
+hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+                                       hb_codepoint_t      u,
+                                       hb_codepoint_t     *decomposed,
+                                       void               *user_data HB_UNUSED)
+{
+  UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
+  unsigned int len;
+  int32_t utf32_len;
+  hb_bool_t err;
+  UErrorCode icu_err;
+
+  /* Copy @u into a UTF-16 array to be passed to ICU. */
+  len = 0;
+  err = false;
+  U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err);
+  if (err)
+    return 0;
 
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_icu_unicode_funcs;
-const hb_unicode_funcs_t _hb_icu_unicode_funcs = {
-  HB_OBJECT_HEADER_STATIC,
+  /* Normalise the codepoint using NFKD mode. */
+  icu_err = U_ZERO_ERROR;
+  len = unorm_normalize (utf16, len, UNORM_NFKD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
+  if (icu_err)
+    return 0;
+
+  /* Convert the decomposed form from UTF-16 to UTF-32. */
+  icu_err = U_ZERO_ERROR;
+  u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err);
+  if (icu_err)
+    return 0;
+
+  return utf32_len;
+}
 
-  NULL, /* parent */
-  true, /* immutable */
-  {
-#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
-    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
-  }
-};
 
 hb_unicode_funcs_t *
 hb_icu_get_unicode_funcs (void)
 {
-  return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
-}
+  static const hb_unicode_funcs_t _hb_icu_unicode_funcs = {
+    HB_OBJECT_HEADER_STATIC,
 
+    NULL, /* parent */
+    true, /* immutable */
+    {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
+      HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+    }
+  };
 
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+  if (!hb_atomic_ptr_get (&normalizer)) {
+    UErrorCode icu_err = U_ZERO_ERROR;
+    /* We ignore failure in getNFCInstace(). */
+    (void) hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err));
+  }
+#endif
+  return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
+}
index d22a8e1..f2f35f0 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <unicode/uscript.h>
 
-
 HB_BEGIN_DECLS
 
 
index f9bd679..a8ea39c 100644 (file)
 #if 0
 
 
-#elif !defined(HB_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
+#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
 
 #include <windows.h>
 typedef CRITICAL_SECTION hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT     { NULL, 0, 0, NULL, NULL, 0 }
+#define HB_MUTEX_IMPL_INIT     {0}
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#define hb_mutex_impl_init(M)  InitializeCriticalSectionEx (M, 0, 0)
+#else
 #define hb_mutex_impl_init(M)  InitializeCriticalSection (M)
+#endif
 #define hb_mutex_impl_lock(M)  EnterCriticalSection (M)
 #define hb_mutex_impl_unlock(M)        LeaveCriticalSection (M)
 #define hb_mutex_impl_finish(M)        DeleteCriticalSection (M)
@@ -64,17 +68,6 @@ typedef pthread_mutex_t hb_mutex_impl_t;
 #define hb_mutex_impl_finish(M)        pthread_mutex_destroy (M)
 
 
-#elif !defined(HB_NO_MT) && defined(HAVE_GLIB)
-
-#include <glib.h>
-typedef GStaticMutex hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT     G_STATIC_MUTEX_INIT
-#define hb_mutex_impl_init(M)  g_static_mutex_init (M)
-#define hb_mutex_impl_lock(M)  g_static_mutex_lock (M)
-#define hb_mutex_impl_unlock(M)        g_static_mutex_unlock (M)
-#define hb_mutex_impl_finish(M)        g_static_mutex_free (M)
-
-
 #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
 
 #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
index 96d1bd3..7bd0f16 100644 (file)
@@ -65,11 +65,9 @@ struct hb_reference_count_t
 
 /* user_data */
 
-#define HB_USER_DATA_ARRAY_INIT {HB_LOCKABLE_SET_INIT}
+#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT}
 struct hb_user_data_array_t
 {
-  /* TODO Add tracing. */
-
   struct hb_user_data_item_t {
     hb_user_data_key_t *key;
     void *data;
@@ -81,20 +79,19 @@ struct hb_user_data_array_t
     void finish (void) { if (destroy) destroy (data); }
   };
 
+  hb_mutex_t lock;
   hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items;
 
-  inline void init (void) { items.init (); }
+  inline void init (void) { lock.init (); items.init (); }
 
   HB_INTERNAL bool set (hb_user_data_key_t *key,
                        void *              data,
                        hb_destroy_func_t   destroy,
-                       hb_bool_t           replace,
-                       hb_mutex_t         &lock);
+                       hb_bool_t           replace);
 
-  HB_INTERNAL void *get (hb_user_data_key_t *key,
-                       hb_mutex_t          &lock);
+  HB_INTERNAL void *get (hb_user_data_key_t *key);
 
-  HB_INTERNAL void finish (hb_mutex_t &lock);
+  inline void finish (void) { items.finish (lock); lock.finish (); }
 };
 
 
@@ -103,75 +100,9 @@ struct hb_user_data_array_t
 struct hb_object_header_t
 {
   hb_reference_count_t ref_count;
-  hb_mutex_t lock;
   hb_user_data_array_t user_data;
 
-#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_MUTEX_INIT, HB_USER_DATA_ARRAY_INIT}
-
-  static inline void *create (unsigned int size) {
-    hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size);
-
-    if (likely (obj))
-      obj->init ();
-
-    return obj;
-  }
-
-  inline void init (void) {
-    ref_count.init (1);
-    lock.init ();
-    user_data.init ();
-  }
-
-  inline bool is_inert (void) const {
-    return unlikely (ref_count.is_invalid ());
-  }
-
-  inline void reference (void) {
-    if (unlikely (!this || this->is_inert ()))
-      return;
-    ref_count.inc ();
-  }
-
-  inline bool destroy (void) {
-    if (unlikely (!this || this->is_inert ()))
-      return false;
-    if (ref_count.dec () != 1)
-      return false;
-
-    ref_count.finish (); /* Do this before user_data */
-    user_data.finish (lock);
-    lock.finish ();
-
-    return true;
-  }
-
-  inline bool set_user_data (hb_user_data_key_t *key,
-                            void *              data,
-                            hb_destroy_func_t   destroy_func,
-                            hb_bool_t           replace) {
-    if (unlikely (!this || this->is_inert ()))
-      return false;
-
-    return user_data.set (key, data, destroy_func, replace, lock);
-  }
-
-  inline void *get_user_data (hb_user_data_key_t *key) {
-    if (unlikely (!this || this->is_inert ()))
-      return NULL;
-
-    return user_data.get (key, lock);
-  }
-
-  inline void trace (const char *function) const {
-    if (unlikely (!this)) return;
-    /* XXX We cannot use DEBUG_MSG_FUNC here since that one currecntly only
-     * prints the class name and throws away the template info. */
-    DEBUG_MSG (OBJECT, (void *) this,
-              "%s refcount=%d",
-              function,
-              this ? ref_count.ref_count : 0);
-  }
+#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT}
 
   private:
   ASSERT_POD ();
@@ -183,32 +114,56 @@ struct hb_object_header_t
 template <typename Type>
 static inline void hb_object_trace (const Type *obj, const char *function)
 {
-  obj->header.trace (function);
+  DEBUG_MSG (OBJECT, (void *) obj,
+            "%s refcount=%d",
+            function,
+            obj ? obj->header.ref_count.ref_count : 0);
 }
+
 template <typename Type>
 static inline Type *hb_object_create (void)
 {
-  Type *obj = (Type *) hb_object_header_t::create (sizeof (Type));
+  Type *obj = (Type *) calloc (1, sizeof (Type));
+
+  if (unlikely (!obj))
+    return obj;
+
+  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 (1);
+  obj->header.user_data.init ();
+}
+template <typename Type>
 static inline bool hb_object_is_inert (const Type *obj)
 {
-  return unlikely (obj->header.is_inert ());
+  return unlikely (obj->header.ref_count.is_invalid ());
 }
 template <typename Type>
 static inline Type *hb_object_reference (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  obj->header.reference ();
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return obj;
+  obj->header.ref_count.inc ();
   return obj;
 }
 template <typename Type>
 static inline bool hb_object_destroy (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  return obj->header.destroy ();
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return false;
+  if (obj->header.ref_count.dec () != 1)
+    return false;
+
+  obj->header.ref_count.finish (); /* Do this before user_data */
+  obj->header.user_data.finish ();
+  return true;
 }
 template <typename Type>
 static inline bool hb_object_set_user_data (Type               *obj,
@@ -217,14 +172,18 @@ static inline bool hb_object_set_user_data (Type               *obj,
                                            hb_destroy_func_t   destroy,
                                            hb_bool_t           replace)
 {
-  return obj->header.set_user_data (key, data, destroy, replace);
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return false;
+  return obj->header.user_data.set (key, data, destroy, replace);
 }
 
 template <typename Type>
 static inline void *hb_object_get_user_data (Type               *obj,
                                             hb_user_data_key_t *key)
 {
-  return obj->header.get_user_data (key);
+  if (unlikely (!obj || hb_object_is_inert (obj)))
+    return NULL;
+  return obj->header.user_data.get (key);
 }
 
 
index ce18580..178bc7c 100644 (file)
@@ -32,6 +32,8 @@
 #include "hb-open-type-private.hh"
 
 
+namespace OT {
+
 
 /*
  *
@@ -51,8 +53,9 @@ struct TTCHeader;
 
 typedef struct TableRecord
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -100,17 +103,18 @@ typedef struct OffsetTable
   }
 
   public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
   }
 
-  private:
+  protected:
   Tag          sfnt_version;   /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
   USHORT       numTables;      /* Number of tables. */
-  USHORT       searchRange   /* (Maximum power of 2 <= numTables) x 16 */
-  USHORT       entrySelector /* Log2(maximum power of 2 <= numTables). */
-  USHORT       rangeShift    /* NumTables x 16-searchRange. */
+  USHORT       searchRangeZ;   /* (Maximum power of 2 <= numTables) x 16 */
+  USHORT       entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */
+  USHORT       rangeShiftZ;    /* NumTables x 16-searchRange. */
   TableRecord  tables[VAR];    /* TableRecord entries. numTables items */
   public:
   DEFINE_SIZE_ARRAY (12, tables);
@@ -128,16 +132,17 @@ struct TTCHeaderVersion1
   inline unsigned int get_face_count (void) const { return table.len; }
   inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (table.sanitize (c, this));
   }
 
-  private:
+  protected:
   Tag          ttcTag;         /* TrueType Collection ID string: 'ttcf' */
   FixedVersion version;        /* Version of the TTC Header (1.0),
-                                * 0x00010000 */
-  LongOffsetLongArrayOf<OffsetTable>
+                                * 0x00010000u */
+  ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
                table;          /* Array of offsets to the OffsetTable for each font
                                 * from the beginning of the file */
   public:
@@ -167,8 +172,9 @@ struct TTCHeader
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false);
     switch (u.header.version.major) {
     case 2: /* version 2 is compatible with version 1 */
@@ -177,12 +183,12 @@ struct TTCHeader
     }
   }
 
-  private:
+  protected:
   union {
   struct {
   Tag          ttcTag;         /* TrueType Collection ID string: 'ttcf' */
   FixedVersion version;        /* Version of the TTC Header (1.0 or 2.0),
-                                * 0x00010000 or 0x00020000 */
+                                * 0x00010000u or 0x00020000u */
   }                    header;
   TTCHeaderVersion1    version1;
   } u;
@@ -195,6 +201,8 @@ struct TTCHeader
 
 struct OpenTypeFontFile
 {
+  static const hb_tag_t tableTag       = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
+
   static const hb_tag_t CFFTag         = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */
   static const hb_tag_t TrueTypeTag    = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */
   static const hb_tag_t TTCTag         = HB_TAG ('t','t','c','f'); /* TrueType Collection */
@@ -229,8 +237,9 @@ struct OpenTypeFontFile
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false);
     switch (u.tag) {
     case CFFTag:       /* All the non-collection tags */
@@ -242,7 +251,7 @@ struct OpenTypeFontFile
     }
   }
 
-  private:
+  protected:
   union {
   Tag                  tag;            /* 4-byte identifier. */
   OpenTypeFontFace     fontFace;
@@ -253,5 +262,7 @@ struct OpenTypeFontFile
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OPEN_FILE_PRIVATE_HH */
index 5d90e5b..75a0f56 100644 (file)
@@ -31,7 +31,8 @@
 
 #include "hb-private.hh"
 
-#include "hb-blob.h"
+
+namespace OT {
 
 
 
 
 /* Cast to struct T, reference to reference */
 template<typename Type, typename TObject>
-inline const Type& CastR(const TObject &X)
+static inline const Type& CastR(const TObject &X)
 { return reinterpret_cast<const Type&> (X); }
 template<typename Type, typename TObject>
-inline Type& CastR(TObject &X)
+static inline Type& CastR(TObject &X)
 { return reinterpret_cast<Type&> (X); }
 
 /* Cast to struct T, pointer to pointer */
 template<typename Type, typename TObject>
-inline const Type* CastP(const TObject *X)
+static inline const Type* CastP(const TObject *X)
 { return reinterpret_cast<const Type*> (X); }
 template<typename Type, typename TObject>
-inline Type* CastP(TObject *X)
+static inline Type* CastP(TObject *X)
 { return reinterpret_cast<Type*> (X); }
 
 /* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
  * location pointed to by P plus Ofs bytes. */
 template<typename Type>
-inline const Type& StructAtOffset(const void *P, unsigned int offset)
+static inline const Type& StructAtOffset(const void *P, unsigned int offset)
 { return * reinterpret_cast<const Type*> ((const char *) P + offset); }
 template<typename Type>
-inline Type& StructAtOffset(void *P, unsigned int offset)
+static inline Type& StructAtOffset(void *P, unsigned int offset)
 { return * reinterpret_cast<Type*> ((char *) P + offset); }
 
 /* StructAfter<T>(X) returns the struct T& that is placed after X.
  * Works with X of variable size also.  X must implement get_size() */
 template<typename Type, typename TObject>
-inline const Type& StructAfter(const TObject &X)
+static inline const Type& StructAfter(const TObject &X)
 { return StructAtOffset<Type>(&X, X.get_size()); }
 template<typename Type, typename TObject>
-inline Type& StructAfter(TObject &X)
+static inline Type& StructAfter(TObject &X)
 { return StructAtOffset<Type>(&X, X.get_size()); }
 
 
@@ -130,20 +131,21 @@ inline Type& StructAfter(TObject &X)
  */
 
 /* Global nul-content Null pool.  Enlarge as necessary. */
-static const void *_NullPool[64 / sizeof (void *)];
+/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
+static const void *_NullPool[(256+8) / sizeof (void *)];
 
 /* Generic nul-content Null objects. */
 template <typename Type>
 static inline const Type& Null (void) {
-  ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
+  ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
   return *CastP<Type> (_NullPool);
 }
 
 /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
 #define DEFINE_NULL_DATA(Type, data) \
-static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
+static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
 template <> \
-inline const Type& Null<Type> (void) { \
+/*static*/ inline const Type& Null<Type> (void) { \
   return *CastP<Type> (_Null##Type); \
 } /* The following line really exists such that we end in a place needing semicolon */ \
 ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
@@ -162,12 +164,29 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
 #endif
 
 
-#define TRACE_SANITIZE() \
-       hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, "");
+#define TRACE_SANITIZE(this) \
+       hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
+       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+        "");
 
+/* This limits sanitizing time on really broken fonts. */
+#ifndef HB_SANITIZE_MAX_EDITS
+#define HB_SANITIZE_MAX_EDITS 100
+#endif
 
 struct hb_sanitize_context_t
 {
+  inline const char *get_name (void) { return "SANITIZE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
+  typedef bool return_t;
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format)
+  { return format->sanitize (this); }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
+  static return_t default_return_value (void) { return true; }
+  bool stop_sublookup_iteration (const return_t r) const { return !r; }
+
   inline void init (hb_blob_t *b)
   {
     this->blob = hb_blob_reference (b);
@@ -178,10 +197,11 @@ struct hb_sanitize_context_t
   {
     this->start = hb_blob_get_data (this->blob, NULL);
     this->end = this->start + hb_blob_get_length (this->blob);
+    assert (this->start <= this->end); /* Must not overflow. */
     this->edit_count = 0;
     this->debug_depth = 0;
 
-    DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1,
+    DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
                     "start [%p..%p] (%lu bytes)",
                     this->start, this->end,
                     (unsigned long) (this->end - this->start));
@@ -189,7 +209,7 @@ struct hb_sanitize_context_t
 
   inline void end_processing (void)
   {
-    DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1,
+    DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
                     "end [%p..%p] %u edit requests",
                     this->start, this->end, this->edit_count);
 
@@ -201,26 +221,31 @@ struct hb_sanitize_context_t
   inline bool check_range (const void *base, unsigned int len) const
   {
     const char *p = (const char *) base;
+    bool ok = this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len;
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-                                             "check_range [%p..%p] (%d bytes) in [%p..%p]",
-                                             p, p + len, len,
-                                             this->start, this->end);
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       p, p + len, len,
+       this->start, this->end,
+       ok ? "OK" : "OUT-OF-RANGE");
 
-    return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
+    return likely (ok);
   }
 
   inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
   {
     const char *p = (const char *) base;
     bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
+    unsigned int array_size = record_size * len;
+    bool ok = !overflows && this->check_range (base, array_size);
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-                                             "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
-                                             p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
-                                             this->start, this->end);
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
+       p, p + (record_size * len), record_size, len, (unsigned int) array_size,
+       this->start, this->end,
+       overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
 
-    return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
+    return likely (ok);
   }
 
   template <typename Type>
@@ -231,16 +256,29 @@ struct hb_sanitize_context_t
 
   inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
   {
+    if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
+      return false;
+
     const char *p = (const char *) base;
     this->edit_count++;
 
-    hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
-                                             "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
-                                             this->edit_count,
-                                             p, p + len, len,
-                                             this->start, this->end);
+    DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+       "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+       this->edit_count,
+       p, p + len, len,
+       this->start, this->end,
+       this->writable ? "GRANTED" : "DENIED");
+
+    return this->writable;
+  }
 
-    return TRACE_RETURN (this->writable);
+  template <typename Type, typename ValueType>
+  inline bool try_set (const Type *obj, const ValueType &v) {
+    if (this->may_edit (obj, obj->static_size)) {
+      const_cast<Type *> (obj)->set (v);
+      return true;
+    }
+    return false;
   }
 
   mutable unsigned int debug_depth;
@@ -257,7 +295,7 @@ template <typename Type>
 struct Sanitizer
 {
   static hb_blob_t *sanitize (hb_blob_t *blob) {
-    hb_sanitize_context_t c[1] = {{0}};
+    hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}};
     bool sane;
 
     /* TODO is_sane() stuff */
@@ -265,7 +303,7 @@ struct Sanitizer
     c->init (blob);
 
   retry:
-    DEBUG_MSG_FUNC (SANITIZE, blob, "start");
+    DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
 
     c->start_processing ();
 
@@ -279,13 +317,13 @@ struct Sanitizer
     sane = t->sanitize (c);
     if (sane) {
       if (c->edit_count) {
-       DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count);
+       DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count);
 
         /* sanitize again to ensure no toe-stepping */
         c->edit_count = 0;
        sane = t->sanitize (c);
        if (c->edit_count) {
-         DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count);
+         DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
          sane = false;
        }
       }
@@ -298,7 +336,7 @@ struct Sanitizer
        if (c->start) {
          c->writable = true;
          /* ok, we made it writable by relocating.  try again */
-         DEBUG_MSG_FUNC (SANITIZE, blob, "retry");
+         DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
          goto retry;
        }
       }
@@ -306,7 +344,7 @@ struct Sanitizer
 
     c->end_processing ();
 
-    DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED");
+    DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
     if (sane)
       return blob;
     else {
@@ -324,6 +362,162 @@ struct Sanitizer
 
 
 
+/*
+ * Serialize
+ */
+
+#ifndef HB_DEBUG_SERIALIZE
+#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
+#endif
+
+
+#define TRACE_SERIALIZE(this) \
+       hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
+       (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
+        "");
+
+
+struct hb_serialize_context_t
+{
+  inline hb_serialize_context_t (void *start, unsigned int size)
+  {
+    this->start = (char *) start;
+    this->end = this->start + size;
+
+    this->ran_out_of_room = false;
+    this->head = this->start;
+    this->debug_depth = 0;
+  }
+
+  template <typename Type>
+  inline Type *start_serialize (void)
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
+                    "start [%p..%p] (%lu bytes)",
+                    this->start, this->end,
+                    (unsigned long) (this->end - this->start));
+
+    return start_embed<Type> ();
+  }
+
+  inline void end_serialize (void)
+  {
+    DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
+                    "end [%p..%p] serialized %d bytes; %s",
+                    this->start, this->end,
+                    (int) (this->head - this->start),
+                    this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
+
+  }
+
+  template <typename Type>
+  inline Type *copy (void)
+  {
+    assert (!this->ran_out_of_room);
+    unsigned int len = this->head - this->start;
+    void *p = malloc (len);
+    if (p)
+      memcpy (p, this->start, len);
+    return reinterpret_cast<Type *> (p);
+  }
+
+  template <typename Type>
+  inline Type *allocate_size (unsigned int size)
+  {
+    if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
+      this->ran_out_of_room = true;
+      return NULL;
+    }
+    memset (this->head, 0, size);
+    char *ret = this->head;
+    this->head += size;
+    return reinterpret_cast<Type *> (ret);
+  }
+
+  template <typename Type>
+  inline Type *allocate_min (void)
+  {
+    return this->allocate_size<Type> (Type::min_size);
+  }
+
+  template <typename Type>
+  inline Type *start_embed (void)
+  {
+    Type *ret = reinterpret_cast<Type *> (this->head);
+    return ret;
+  }
+
+  template <typename Type>
+  inline Type *embed (const Type &obj)
+  {
+    unsigned int size = obj.get_size ();
+    Type *ret = this->allocate_size<Type> (size);
+    if (unlikely (!ret)) return NULL;
+    memcpy (ret, obj, size);
+    return ret;
+  }
+
+  template <typename Type>
+  inline Type *extend_min (Type &obj)
+  {
+    unsigned int size = obj.min_size;
+    assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    return reinterpret_cast<Type *> (&obj);
+  }
+
+  template <typename Type>
+  inline Type *extend (Type &obj)
+  {
+    unsigned int size = obj.get_size ();
+    assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
+    if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+    return reinterpret_cast<Type *> (&obj);
+  }
+
+  inline void truncate (void *head)
+  {
+    assert (this->start < head && head <= this->head);
+    this->head = (char *) head;
+  }
+
+  unsigned int debug_depth;
+  char *start, *end, *head;
+  bool ran_out_of_room;
+};
+
+template <typename Type>
+struct Supplier
+{
+  inline Supplier (const Type *array, unsigned int len_)
+  {
+    head = array;
+    len = len_;
+  }
+  inline const Type operator [] (unsigned int i) const
+  {
+    if (unlikely (i >= len)) return Type ();
+    return head[i];
+  }
+
+  inline void advance (unsigned int count)
+  {
+    if (unlikely (count > len))
+      count = len;
+    len -= count;
+    head += count;
+  }
+
+  private:
+  inline Supplier (const Supplier<Type> &); /* Disallow copy */
+  inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
+
+  unsigned int len;
+  const Type *head;
+};
+
+
+
 
 /*
  *
@@ -341,57 +535,95 @@ struct Sanitizer
 
 template <typename Type, int Bytes> struct BEInt;
 
-/* LONGTERMTODO: On machines allowing unaligned access, we can make the
- * following tighter by using byteswap instructions on ints directly. */
 template <typename Type>
 struct BEInt<Type, 2>
 {
   public:
-  inline void set (Type i) { hb_be_uint16_put (v,i); }
-  inline operator Type (void) const { return hb_be_uint16_get (v); }
-  inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); }
-  inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
+  inline void set (Type V)
+  {
+    v[0] = (V >>  8) & 0xFF;
+    v[1] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[0] <<  8)
+         + (v[1]      );
+  }
   private: uint8_t v[2];
 };
 template <typename Type>
+struct BEInt<Type, 3>
+{
+  public:
+  inline void set (Type V)
+  {
+    v[0] = (V >> 16) & 0xFF;
+    v[1] = (V >>  8) & 0xFF;
+    v[2] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[0] << 16)
+         + (v[1] <<  8)
+         + (v[2]      );
+  }
+  private: uint8_t v[3];
+};
+template <typename Type>
 struct BEInt<Type, 4>
 {
   public:
-  inline void set (Type i) { hb_be_uint32_put (v,i); }
-  inline operator Type (void) const { return hb_be_uint32_get (v); }
-  inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
-  inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
+  inline void set (Type V)
+  {
+    v[0] = (V >> 24) & 0xFF;
+    v[1] = (V >> 16) & 0xFF;
+    v[2] = (V >>  8) & 0xFF;
+    v[3] = (V      ) & 0xFF;
+  }
+  inline operator Type (void) const
+  {
+    return (v[0] << 24)
+         + (v[1] << 16)
+         + (v[2] <<  8)
+         + (v[3]      );
+  }
   private: uint8_t v[4];
 };
 
 /* Integer types in big-endian order and no alignment requirement */
-template <typename Type>
+template <typename Type, unsigned int Size>
 struct IntType
 {
   inline void set (Type i) { v.set (i); }
   inline operator Type(void) const { return v; }
-  inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
-  inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
-  inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
+  inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
+  static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+  inline int cmp (Type a) const
+  {
+    Type b = v;
+    if (sizeof (Type) < sizeof (int))
+      return (int) a - (int) b;
+    else
+      return a < b ? -1 : a == b ? 0 : +1;
+  }
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (likely (c->check_struct (this)));
   }
   protected:
-  BEInt<Type, sizeof (Type)> v;
+  BEInt<Type, Size> v;
   public:
-  DEFINE_SIZE_STATIC (sizeof (Type));
+  DEFINE_SIZE_STATIC (Size);
 };
 
-/* Typedef these to avoid clash with windows.h */
-#define USHORT HB_USHORT
-#define SHORT  HB_SHORT
-#define ULONG  HB_ULONG
-#define LONG   HB_LONG
-typedef IntType<uint16_t> USHORT;      /* 16-bit unsigned integer. */
-typedef IntType<int16_t>  SHORT;       /* 16-bit signed integer. */
-typedef IntType<uint32_t> ULONG;       /* 32-bit unsigned integer. */
-typedef IntType<int32_t>  LONG;                /* 32-bit signed integer. */
+typedef                uint8_t      BYTE;      /* 8-bit unsigned integer. */
+typedef IntType<uint16_t, 2> USHORT;   /* 16-bit unsigned integer. */
+typedef IntType<int16_t,  2> SHORT;    /* 16-bit signed integer. */
+typedef IntType<uint32_t, 4> ULONG;    /* 32-bit unsigned integer. */
+typedef IntType<int32_t,  4> LONG;     /* 32-bit signed integer. */
+typedef IntType<uint32_t, 3> UINT24;   /* 24-bit unsigned integer. */
 
 /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
 typedef SHORT FWORD;
@@ -403,11 +635,12 @@ typedef USHORT UFWORD;
  * 1904. The value is represented as a signed 64-bit integer. */
 struct LONGDATETIME
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (likely (c->check_struct (this)));
   }
-  private:
+  protected:
   LONG major;
   ULONG minor;
   public:
@@ -427,33 +660,45 @@ struct Tag : ULONG
 DEFINE_NULL_DATA (Tag, "    ");
 
 /* Glyph index number, same as uint16 (length = 16 bits) */
-typedef USHORT GlyphID;
+struct GlyphID : USHORT {
+  static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); }
+  inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; }
+};
 
 /* Script/language-system/feature index */
 struct Index : USHORT {
-  static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
+  static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
 };
 DEFINE_NULL_DATA (Index, "\xff\xff");
 
-/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
-typedef USHORT Offset;
-
-/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
-typedef ULONG LongOffset;
+/* Offset, Null offset = 0 */
+template <typename Type=USHORT>
+struct Offset : Type
+{
+  inline bool is_null (void) const { return 0 == *this; }
+  public:
+  DEFINE_SIZE_STATIC (sizeof(Type));
+};
 
 
 /* CheckSum */
 struct CheckSum : ULONG
 {
-  static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
+  /* This is reference implementation from the spec. */
+  static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
   {
     uint32_t Sum = 0L;
-    ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
+    const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
 
     while (Table < EndPtr)
       Sum += *Table++;
     return Sum;
   }
+
+  /* Note: data should be 4byte aligned and have 4byte padding at the end. */
+  inline void set_for_data (const void *data, unsigned int length)
+  { set (CalcTableChecksum ((const ULONG *) data, length)); }
+
   public:
   DEFINE_SIZE_STATIC (4);
 };
@@ -467,8 +712,9 @@ struct FixedVersion
 {
   inline uint32_t to_int (void) const { return (major << 16) + minor; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -481,12 +727,12 @@ struct FixedVersion
 
 
 /*
- * Template subclasses of Offset and LongOffset that do the dereferencing.
+ * Template subclasses of Offset that do the dereferencing.
  * Use: (base+offset)
  */
 
-template <typename OffsetType, typename Type>
-struct GenericOffsetTo : OffsetType
+template <typename Type, typename OffsetType=USHORT>
+struct OffsetTo : Offset<OffsetType>
 {
   inline const Type& operator () (const void *base) const
   {
@@ -495,50 +741,52 @@ struct GenericOffsetTo : OffsetType
     return StructAtOffset<Type> (base, offset);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+  inline Type& serialize (hb_serialize_context_t *c, const void *base)
+  {
+    Type *t = c->start_embed<Type> ();
+    this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
+    return *t;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return TRACE_RETURN (true);
-    Type &obj = StructAtOffset<Type> (base, offset);
+    const Type &obj = StructAtOffset<Type> (base, offset);
     return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
     unsigned int offset = *this;
     if (unlikely (!offset)) return TRACE_RETURN (true);
-    Type &obj = StructAtOffset<Type> (base, offset);
+    const Type &obj = StructAtOffset<Type> (base, offset);
     return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
   }
 
-  private:
   /* Set the offset to Null */
-  inline bool neuter (hb_sanitize_context_t *c) {
-    if (c->may_edit (this, this->static_size)) {
-      this->set (0); /* 0 is Null offset */
-      return true;
-    }
-    return false;
+  inline bool neuter (hb_sanitize_context_t *c) const {
+    return c->try_set (this, 0);
   }
+  DEFINE_SIZE_STATIC (sizeof(OffsetType));
 };
 template <typename Base, typename OffsetType, typename Type>
-inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
-
-template <typename Type>
-struct OffsetTo : GenericOffsetTo<Offset, Type> {};
-
-template <typename Type>
-struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
+static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
+template <typename Base, typename OffsetType, typename Type>
+static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
 
 
 /*
  * Array Types
  */
 
-template <typename LenType, typename Type>
-struct GenericArrayOf
+/* An array with a number of elements. */
+template <typename Type, typename LenType=USHORT>
+struct ArrayOf
 {
   const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
   {
@@ -557,11 +805,38 @@ struct GenericArrayOf
     if (unlikely (i >= len)) return Null(Type);
     return array[i];
   }
+  inline Type& operator [] (unsigned int i)
+  {
+    return array[i];
+  }
   inline unsigned int get_size (void) const
   { return len.static_size + len * Type::static_size; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    len.set (items_len); /* TODO(serialize) Overflow? */
+    if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<Type> &items,
+                        unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
+    for (unsigned int i = 0; i < items_len; i++)
+      array[i] = items[i];
+    items.advance (items_len);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
 
     /* Note: for structs that do not reference other structs,
@@ -575,8 +850,9 @@ struct GenericArrayOf
 
     return TRACE_RETURN (true);
   }
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
@@ -585,8 +861,9 @@ struct GenericArrayOf
     return TRACE_RETURN (true);
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
     unsigned int count = len;
     for (unsigned int i = 0; i < count; i++)
@@ -595,9 +872,20 @@ struct GenericArrayOf
     return TRACE_RETURN (true);
   }
 
+  template <typename SearchType>
+  inline int lsearch (const SearchType &x) const
+  {
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!this->array[i].cmp (x))
+        return i;
+    return -1;
+  }
+
   private:
-  inline bool sanitize_shallow (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
   }
 
@@ -608,26 +896,10 @@ struct GenericArrayOf
   DEFINE_SIZE_ARRAY (sizeof (LenType), array);
 };
 
-/* An array with a USHORT number of elements. */
-template <typename Type>
-struct ArrayOf : GenericArrayOf<USHORT, Type> {};
-
-/* An array with a ULONG number of elements. */
-template <typename Type>
-struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
-
 /* Array of Offset's */
 template <typename Type>
 struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
 
-/* Array of LongOffset's */
-template <typename Type>
-struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
-
-/* LongArray of LongOffset's */
-template <typename Type>
-struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
-
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
 struct OffsetListOf : OffsetArrayOf<Type>
@@ -638,21 +910,22 @@ struct OffsetListOf : OffsetArrayOf<Type>
     return this+this->array[i];
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
   }
   template <typename T>
-  inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
   }
 };
 
 
-/* An array with a USHORT number of elements,
- * starting at second element. */
-template <typename Type>
+/* An array starting at second element. */
+template <typename Type, typename LenType=USHORT>
 struct HeadlessArrayOf
 {
   inline const Type& operator [] (unsigned int i) const
@@ -663,13 +936,30 @@ struct HeadlessArrayOf
   inline unsigned int get_size (void) const
   { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
 
-  inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<Type> &items,
+                        unsigned int items_len)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    len.set (items_len); /* TODO(serialize) Overflow? */
+    if (unlikely (!items_len)) return TRACE_RETURN (true);
+    if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
+    for (unsigned int i = 0; i < items_len - 1; i++)
+      array[i] = items[i];
+    items.advance (items_len - 1);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+  {
     return c->check_struct (this)
        && c->check_array (this, Type::static_size, len);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
 
     /* Note: for structs that do not reference other structs,
@@ -684,27 +974,39 @@ struct HeadlessArrayOf
     return TRACE_RETURN (true);
   }
 
-  USHORT len;
+  LenType len;
   Type array[VAR];
   public:
-  DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
+  DEFINE_SIZE_ARRAY (sizeof (LenType), array);
 };
 
 
 /* An array with sorted elements.  Supports binary searching. */
-template <typename Type>
-struct SortedArrayOf : ArrayOf<Type> {
-
+template <typename Type, typename LenType=USHORT>
+struct SortedArrayOf : ArrayOf<Type, LenType>
+{
   template <typename SearchType>
-  inline int search (const SearchType &x) const {
-    struct Cmp {
-      static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); }
-    };
-    const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp);
-    return p ? p - this->array : -1;
+  inline int bsearch (const SearchType &x) const
+  {
+    /* Hand-coded bsearch here since this is in the hot inner loop. */
+    int min = 0, max = (int) this->len - 1;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      int c = this->array[mid].cmp (x);
+      if (c < 0)
+        max = mid - 1;
+      else if (c > 0)
+        min = mid + 1;
+      else
+        return mid;
+    }
+    return -1;
   }
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OPEN_TYPE_PRIVATE_HH */
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
new file mode 100644 (file)
index 0000000..0482312
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * 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
+ */
+
+#ifndef HB_OT_CMAP_TABLE_HH
+#define HB_OT_CMAP_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * cmap -- Character To Glyph Index Mapping Table
+ */
+
+#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
+
+
+struct CmapSubtableFormat0
+{
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
+    if (!gid)
+      return false;
+    *glyph = gid;
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this));
+  }
+
+  protected:
+  USHORT       format;         /* Format number is set to 0. */
+  USHORT       lengthZ;        /* Byte length of this subtable. */
+  USHORT       languageZ;      /* Ignore. */
+  BYTE         glyphIdArray[256];/* An array that maps character
+                                * code to glyph index values. */
+  public:
+  DEFINE_SIZE_STATIC (6 + 256);
+};
+
+struct CmapSubtableFormat4
+{
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    unsigned int segCount;
+    const USHORT *endCount;
+    const USHORT *startCount;
+    const USHORT *idDelta;
+    const USHORT *idRangeOffset;
+    const USHORT *glyphIdArray;
+    unsigned int glyphIdArrayLength;
+
+    segCount = this->segCountX2 / 2;
+    endCount = this->values;
+    startCount = endCount + segCount + 1;
+    idDelta = startCount + segCount;
+    idRangeOffset = idDelta + segCount;
+    glyphIdArray = idRangeOffset + segCount;
+    glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2;
+
+    /* Custom two-array bsearch. */
+    int min = 0, max = (int) segCount - 1;
+    unsigned int i;
+    while (min <= max)
+    {
+      int mid = (min + max) / 2;
+      if (codepoint < startCount[mid])
+        max = mid - 1;
+      else if (codepoint > endCount[mid])
+        min = mid + 1;
+      else
+      {
+       i = mid;
+       goto found;
+      }
+    }
+    return false;
+
+  found:
+    hb_codepoint_t gid;
+    unsigned int rangeOffset = idRangeOffset[i];
+    if (rangeOffset == 0)
+      gid = codepoint + idDelta[i];
+    else
+    {
+      /* Somebody has been smoking... */
+      unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount;
+      if (unlikely (index >= glyphIdArrayLength))
+       return false;
+      gid = glyphIdArray[index];
+      if (unlikely (!gid))
+       return false;
+      gid += idDelta[i];
+    }
+
+    *glyph = gid & 0xFFFFu;
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this)))
+      return TRACE_RETURN (false);
+
+    if (unlikely (!c->check_range (this, length)))
+    {
+      /* Some broken fonts have too long of a "length" value.
+       * If that is the case, just change the value to truncate
+       * the subtable at the end of the blob. */
+      uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
+                                           (uintptr_t) (c->end -
+                                                        (char *) this));
+      if (!c->try_set (&length, new_length))
+       return TRACE_RETURN (false);
+    }
+
+    return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length);
+  }
+
+  protected:
+  USHORT       format;         /* Format number is set to 4. */
+  USHORT       length;         /* This is the length in bytes of the
+                                * subtable. */
+  USHORT       languageZ;      /* Ignore. */
+  USHORT       segCountX2;     /* 2 x segCount. */
+  USHORT       searchRangeZ;   /* 2 * (2**floor(log2(segCount))) */
+  USHORT       entrySelectorZ; /* log2(searchRange/2) */
+  USHORT       rangeShiftZ;    /* 2 x segCount - searchRange */
+
+  USHORT       values[VAR];
+#if 0
+  USHORT       endCount[segCount];     /* End characterCode for each segment,
+                                        * last=0xFFFFu. */
+  USHORT       reservedPad;            /* Set to 0. */
+  USHORT       startCount[segCount];   /* Start character code for each segment. */
+  SHORT                idDelta[segCount];      /* Delta for all character codes in segment. */
+  USHORT       idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
+  USHORT       glyphIdArray[VAR];      /* Glyph index array (arbitrary length) */
+#endif
+
+  public:
+  DEFINE_SIZE_ARRAY (14, values);
+};
+
+struct CmapSubtableLongGroup
+{
+  friend struct CmapSubtableFormat12;
+  friend struct CmapSubtableFormat13;
+
+  int cmp (hb_codepoint_t codepoint) const
+  {
+    if (codepoint < startCharCode) return -1;
+    if (codepoint > endCharCode)   return +1;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this));
+  }
+
+  private:
+  ULONG                startCharCode;  /* First character code in this group. */
+  ULONG                endCharCode;    /* Last character code in this group. */
+  ULONG                glyphID;        /* Glyph index; interpretation depends on
+                                * subtable format. */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+template <typename UINT>
+struct CmapSubtableTrimmed
+{
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    /* Rely on our implicit array bound-checking. */
+    hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
+    if (!gid)
+      return false;
+    *glyph = gid;
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c));
+  }
+
+  protected:
+  UINT         formatReserved; /* Subtable format and (maybe) padding. */
+  UINT         lengthZ;        /* Byte length of this subtable. */
+  UINT         languageZ;      /* Ignore. */
+  UINT         startCharCode;  /* First character code covered. */
+  ArrayOf<GlyphID, UINT>
+               glyphIdArray;   /* Array of glyph index values for character
+                                * codes in the range. */
+  public:
+  DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
+};
+
+struct CmapSubtableFormat6  : CmapSubtableTrimmed<USHORT> {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {};
+
+template <typename T>
+struct CmapSubtableLongSegmented
+{
+  inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+  {
+    int i = groups.bsearch (codepoint);
+    if (i == -1)
+      return false;
+    *glyph = T::group_get_glyph (groups[i], codepoint);
+    return true;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
+  }
+
+  protected:
+  USHORT       format;         /* Subtable format; set to 12. */
+  USHORT       reservedZ;      /* Reserved; set to 0. */
+  ULONG                lengthZ;        /* Byte length of this subtable. */
+  ULONG                languageZ;      /* Ignore. */
+  SortedArrayOf<CmapSubtableLongGroup, ULONG>
+               groups;         /* Groupings. */
+  public:
+  DEFINE_SIZE_ARRAY (16, groups);
+};
+
+struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
+{
+  static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+                                               hb_codepoint_t u)
+  { return group.glyphID + (u - group.startCharCode); }
+};
+
+struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
+{
+  static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+                                               hb_codepoint_t u HB_UNUSED)
+  { return group.glyphID; }
+};
+
+typedef enum
+{
+  GLYPH_VARIANT_NOT_FOUND = 0,
+  GLYPH_VARIANT_FOUND = 1,
+  GLYPH_VARIANT_USE_DEFAULT = 2
+} glyph_variant_t;
+
+struct UnicodeValueRange
+{
+  inline int cmp (const hb_codepoint_t &codepoint) const
+  {
+    if (codepoint < startUnicodeValue) return -1;
+    if (codepoint > startUnicodeValue + additionalCount) return +1;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this));
+  }
+
+  UINT24       startUnicodeValue;      /* First value in this range. */
+  BYTE         additionalCount;        /* Number of additional values in this
+                                        * range. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS;
+
+struct UVSMapping
+{
+  inline int cmp (const hb_codepoint_t &codepoint) const
+  {
+    return unicodeValue.cmp (codepoint);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this));
+  }
+
+  UINT24       unicodeValue;   /* Base Unicode value of the UVS */
+  GlyphID      glyphID;        /* Glyph ID of the UVS */
+  public:
+  DEFINE_SIZE_STATIC (5);
+};
+
+typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS;
+
+struct VariationSelectorRecord
+{
+  inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
+                                   hb_codepoint_t *glyph,
+                                   const void *base) const
+  {
+    int i;
+    const DefaultUVS &defaults = base+defaultUVS;
+    i = defaults.bsearch (codepoint);
+    if (i != -1)
+      return GLYPH_VARIANT_USE_DEFAULT;
+    const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
+    i = nonDefaults.bsearch (codepoint);
+    if (i != -1)
+    {
+      *glyph = nonDefaults[i].glyphID;
+       return GLYPH_VARIANT_FOUND;
+    }
+    return GLYPH_VARIANT_NOT_FOUND;
+  }
+
+  inline int cmp (const hb_codepoint_t &variation_selector) const
+  {
+    return varSelector.cmp (variation_selector);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+                        defaultUVS.sanitize (c, base) &&
+                        nonDefaultUVS.sanitize (c, base));
+  }
+
+  UINT24       varSelector;    /* Variation selector. */
+  OffsetTo<DefaultUVS, ULONG>
+               defaultUVS;     /* Offset to Default UVS Table. May be 0. */
+  OffsetTo<NonDefaultUVS, ULONG>
+               nonDefaultUVS;  /* Offset to Non-Default UVS Table. May be 0. */
+  public:
+  DEFINE_SIZE_STATIC (11);
+};
+
+struct CmapSubtableFormat14
+{
+  inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
+                                           hb_codepoint_t variation_selector,
+                                           hb_codepoint_t *glyph) const
+  {
+    return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+                        record.sanitize (c, this));
+  }
+
+  protected:
+  USHORT       format;         /* Format number is set to 0. */
+  ULONG                lengthZ;        /* Byte length of this subtable. */
+  SortedArrayOf<VariationSelectorRecord, ULONG>
+               record;         /* Variation selector records; sorted
+                                * in increasing order of `varSelector'. */
+  public:
+  DEFINE_SIZE_ARRAY (10, record);
+};
+
+struct CmapSubtable
+{
+  /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
+
+  inline bool get_glyph (hb_codepoint_t codepoint,
+                        hb_codepoint_t *glyph) const
+  {
+    switch (u.format) {
+    case  0: return u.format0 .get_glyph(codepoint, glyph);
+    case  4: return u.format4 .get_glyph(codepoint, glyph);
+    case  6: return u.format6 .get_glyph(codepoint, glyph);
+    case 10: return u.format10.get_glyph(codepoint, glyph);
+    case 12: return u.format12.get_glyph(codepoint, glyph);
+    case 13: return u.format13.get_glyph(codepoint, glyph);
+    case 14:
+    default: return false;
+    }
+  }
+
+  inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
+                                           hb_codepoint_t variation_selector,
+                                           hb_codepoint_t *glyph) const
+  {
+    switch (u.format) {
+    case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph);
+    default: return GLYPH_VARIANT_NOT_FOUND;
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    switch (u.format) {
+    case  0: return TRACE_RETURN (u.format0 .sanitize (c));
+    case  4: return TRACE_RETURN (u.format4 .sanitize (c));
+    case  6: return TRACE_RETURN (u.format6 .sanitize (c));
+    case 10: return TRACE_RETURN (u.format10.sanitize (c));
+    case 12: return TRACE_RETURN (u.format12.sanitize (c));
+    case 13: return TRACE_RETURN (u.format13.sanitize (c));
+    case 14: return TRACE_RETURN (u.format14.sanitize (c));
+    default:return TRACE_RETURN (true);
+    }
+  }
+
+  protected:
+  union {
+  USHORT               format;         /* Format identifier */
+  CmapSubtableFormat0  format0;
+  CmapSubtableFormat4  format4;
+  CmapSubtableFormat6  format6;
+  CmapSubtableFormat10 format10;
+  CmapSubtableFormat12 format12;
+  CmapSubtableFormat13 format13;
+  CmapSubtableFormat14 format14;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+struct EncodingRecord
+{
+  inline int cmp (const EncodingRecord &other) const
+  {
+    int ret;
+    ret = platformID.cmp (other.platformID);
+    if (ret) return ret;
+    ret = encodingID.cmp (other.encodingID);
+    if (ret) return ret;
+    return 0;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+                        subtable.sanitize (c, base));
+  }
+
+  USHORT       platformID;     /* Platform ID. */
+  USHORT       encodingID;     /* Platform-specific encoding ID. */
+  OffsetTo<CmapSubtable, ULONG>
+               subtable;       /* Byte offset from beginning of table to the subtable for this encoding. */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct cmap
+{
+  static const hb_tag_t tableTag       = HB_OT_TAG_cmap;
+
+  inline const CmapSubtable *find_subtable (unsigned int platform_id,
+                                           unsigned int encoding_id) const
+  {
+    EncodingRecord key;
+    key.platformID.set (platform_id);
+    key.encodingID.set (encoding_id);
+
+    /* Note: We can use bsearch, but since it has no performance
+     * implications, we use lsearch and as such accept fonts with
+     * unsorted subtable list. */
+    int result = encodingRecord./*bsearch*/lsearch (key);
+    if (result == -1 || !encodingRecord[result].subtable)
+      return NULL;
+
+    return &(this+encodingRecord[result].subtable);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+                        likely (version == 0) &&
+                        encodingRecord.sanitize (c, this));
+  }
+
+  USHORT               version;        /* Table version number (0). */
+  SortedArrayOf<EncodingRecord>
+                       encodingRecord; /* Encoding tables. */
+  public:
+  DEFINE_SIZE_ARRAY (4, encodingRecord);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_CMAP_TABLE_HH */
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
new file mode 100644 (file)
index 0000000..2af2f54
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot.h"
+
+#include "hb-font-private.hh"
+
+#include "hb-ot-cmap-table.hh"
+#include "hb-ot-hhea-table.hh"
+#include "hb-ot-hmtx-table.hh"
+
+
+struct hb_ot_face_metrics_accelerator_t
+{
+  unsigned int num_metrics;
+  unsigned int num_advances;
+  unsigned int default_advance;
+  const OT::_mtx *table;
+  hb_blob_t *blob;
+
+  inline void init (hb_face_t *face,
+                   hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
+                   unsigned int default_advance)
+  {
+    this->default_advance = default_advance;
+    this->num_metrics = face->get_num_glyphs ();
+
+    hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
+    const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
+    this->num_advances = _hea->numberOfLongMetrics;
+    hb_blob_destroy (_hea_blob);
+
+    this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
+    if (unlikely (!this->num_advances ||
+                 2 * (this->num_advances + this->num_metrics) < hb_blob_get_length (this->blob)))
+    {
+      this->num_metrics = this->num_advances = 0;
+      hb_blob_destroy (this->blob);
+      this->blob = hb_blob_get_empty ();
+    }
+    this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
+  }
+
+  inline void fini (void)
+  {
+    hb_blob_destroy (this->blob);
+  }
+
+  inline unsigned int get_advance (hb_codepoint_t glyph) const
+  {
+    if (unlikely (glyph >= this->num_metrics))
+    {
+      /* If this->num_metrics is zero, it means we don't have the metrics table
+       * for this direction: return one EM.  Otherwise, it means that the glyph
+       * index is out of bound: return zero. */
+      if (this->num_metrics)
+       return 0;
+      else
+       return this->default_advance;
+    }
+
+    if (glyph >= this->num_advances)
+      glyph = this->num_advances - 1;
+
+    return this->table->longMetric[glyph].advance;
+  }
+};
+
+struct hb_ot_face_cmap_accelerator_t
+{
+  const OT::CmapSubtable *table;
+  const OT::CmapSubtable *uvs_table;
+  hb_blob_t *blob;
+
+  inline void init (hb_face_t *face)
+  {
+    this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
+    const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
+    const OT::CmapSubtable *subtable = NULL;
+    const OT::CmapSubtable *subtable_uvs = NULL;
+
+    /* 32-bit subtables. */
+    if (!subtable) subtable = cmap->find_subtable (3, 10);
+    if (!subtable) subtable = cmap->find_subtable (0, 6);
+    if (!subtable) subtable = cmap->find_subtable (0, 4);
+    /* 16-bit subtables. */
+    if (!subtable) subtable = cmap->find_subtable (3, 1);
+    if (!subtable) subtable = cmap->find_subtable (0, 3);
+    if (!subtable) subtable = cmap->find_subtable (0, 2);
+    if (!subtable) subtable = cmap->find_subtable (0, 1);
+    if (!subtable) subtable = cmap->find_subtable (0, 0);
+    /* Meh. */
+    if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
+
+    /* UVS subtable. */
+    if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5);
+    /* Meh. */
+    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable);
+
+    this->table = subtable;
+    this->uvs_table = subtable_uvs;
+  }
+
+  inline void fini (void)
+  {
+    hb_blob_destroy (this->blob);
+  }
+
+  inline bool get_glyph (hb_codepoint_t  unicode,
+                        hb_codepoint_t  variation_selector,
+                        hb_codepoint_t *glyph) const
+  {
+    if (unlikely (variation_selector))
+    {
+      switch (this->uvs_table->get_glyph_variant (unicode,
+                                                 variation_selector,
+                                                 glyph))
+      {
+       case OT::GLYPH_VARIANT_NOT_FOUND:       return false;
+       case OT::GLYPH_VARIANT_FOUND:           return true;
+       case OT::GLYPH_VARIANT_USE_DEFAULT:     break;
+      }
+    }
+
+    return this->table->get_glyph (unicode, glyph);
+  }
+};
+
+
+struct hb_ot_font_t
+{
+  hb_ot_face_cmap_accelerator_t cmap;
+  hb_ot_face_metrics_accelerator_t h_metrics;
+  hb_ot_face_metrics_accelerator_t v_metrics;
+};
+
+
+static hb_ot_font_t *
+_hb_ot_font_create (hb_font_t *font)
+{
+  hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
+  hb_face_t *face = font->face;
+
+  if (unlikely (!ot_font))
+    return NULL;
+
+  unsigned int upem = face->get_upem ();
+
+  ot_font->cmap.init (face);
+  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
+  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
+
+  return ot_font;
+}
+
+static void
+_hb_ot_font_destroy (hb_ot_font_t *ot_font)
+{
+  ot_font->cmap.fini ();
+  ot_font->h_metrics.fini ();
+  ot_font->v_metrics.fini ();
+
+  free (ot_font);
+}
+
+
+static hb_bool_t
+hb_ot_get_glyph (hb_font_t *font HB_UNUSED,
+                void *font_data,
+                hb_codepoint_t unicode,
+                hb_codepoint_t variation_selector,
+                hb_codepoint_t *glyph,
+                void *user_data HB_UNUSED)
+
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return ot_font->cmap.get_glyph (unicode, variation_selector, glyph);
+}
+
+static hb_position_t
+hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+                          void *font_data,
+                          hb_codepoint_t glyph,
+                          void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
+}
+
+static hb_position_t
+hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+                          void *font_data,
+                          hb_codepoint_t glyph,
+                          void *user_data HB_UNUSED)
+{
+  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+  return font->em_scale_y (-ot_font->v_metrics.get_advance (glyph));
+}
+
+static hb_bool_t
+hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
+                         void *font_data HB_UNUSED,
+                         hb_codepoint_t glyph HB_UNUSED,
+                         hb_position_t *x HB_UNUSED,
+                         hb_position_t *y HB_UNUSED,
+                         void *user_data HB_UNUSED)
+{
+  /* We always work in the horizontal coordinates. */
+  return true;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+                         void *font_data,
+                         hb_codepoint_t glyph,
+                         hb_position_t *x,
+                         hb_position_t *y,
+                         void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
+static hb_position_t
+hb_ot_get_glyph_h_kerning (hb_font_t *font,
+                          void *font_data,
+                          hb_codepoint_t left_glyph,
+                          hb_codepoint_t right_glyph,
+                          void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return 0;
+}
+
+static hb_position_t
+hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+                          void *font_data HB_UNUSED,
+                          hb_codepoint_t top_glyph HB_UNUSED,
+                          hb_codepoint_t bottom_glyph HB_UNUSED,
+                          void *user_data HB_UNUSED)
+{
+  /* OpenType doesn't have vertical-kerning other than GPOS. */
+  return 0;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
+                        void *font_data,
+                        hb_codepoint_t glyph,
+                        hb_glyph_extents_t *extents,
+                        void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
+                              void *font_data,
+                              hb_codepoint_t glyph,
+                              unsigned int point_index,
+                              hb_position_t *x,
+                              hb_position_t *y,
+                              void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
+                     void *font_data,
+                     hb_codepoint_t glyph,
+                     char *name, unsigned int size,
+                     void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
+                          void *font_data,
+                          const char *name, int len, /* -1 means nul-terminated */
+                          hb_codepoint_t *glyph,
+                          void *user_data HB_UNUSED)
+{
+  /* TODO */
+  return false;
+}
+
+
+static hb_font_funcs_t *
+_hb_ot_get_font_funcs (void)
+{
+  static const hb_font_funcs_t ot_ffuncs = {
+    HB_OBJECT_HEADER_STATIC,
+
+    true, /* immutable */
+
+    {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
+      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+    }
+  };
+
+  return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
+}
+
+
+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 (),
+                    ot_font,
+                    (hb_destroy_func_t) _hb_ot_font_destroy);
+}
similarity index 72%
rename from src/hb-fallback-shape-private.hh
rename to src/hb-ot-font.h
index 159456d..7a8c04a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2014  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * 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
+ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
  */
 
-#ifndef HB_FALLBACK_SHAPE_PRIVATE_HH
-#define HB_FALLBACK_SHAPE_PRIVATE_HH
-
-#include "hb-private.hh"
-
-#include "hb-shape.h"
+#ifndef HB_OT_FONT_H
+#define HB_OT_FONT_H
 
+#include "hb.h"
 
 HB_BEGIN_DECLS
 
 
-HB_INTERNAL hb_bool_t
-_hb_fallback_shape (hb_font_t          *font,
-                   hb_buffer_t        *buffer,
-                   const hb_feature_t *features,
-                   unsigned int        num_features);
+void
+hb_ot_font_set_funcs (hb_font_t *font);
 
 
 HB_END_DECLS
 
-#endif /* HB_FALLBACK_SHAPE_PRIVATE_HH */
+#endif /* HB_OT_FONT_H */
index 32d64ca..268f133 100644 (file)
@@ -32,6 +32,8 @@
 #include "hb-open-type-private.hh"
 
 
+namespace OT {
+
 
 /*
  * head -- Font Header
 
 struct head
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_head;
+  static const hb_tag_t tableTag       = HB_OT_TAG_head;
 
-  inline unsigned int get_upem (void) const {
+  inline unsigned int get_upem (void) const
+  {
     unsigned int upem = unitsPerEm;
-    /* If no valid head table found, assume 1000, which matches typicaly Type1 usage. */
+    /* If no valid head table found, assume 1000, which matches typical Type1 usage. */
     return 16 <= upem && upem <= 16384 ? upem : 1000;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
-  private:
+  protected:
   FixedVersion version;                /* Version of the head table--currently
-                                        * 0x00010000 for version 1.0. */
+                                        * 0x00010000u for version 1.0. */
   FixedVersion fontRevision;           /* Set by font manufacturer. */
   ULONG                checkSumAdjustment;     /* To compute: set it to 0, sum the
                                         * entire font as ULONG, then store
-                                        * 0xB1B0AFBA - sum. */
-  ULONG                magicNumber;            /* Set to 0x5F0F3CF5. */
+                                        * 0xB1B0AFBAu - sum. */
+  ULONG                magicNumber;            /* Set to 0x5F0F3CF5u. */
   USHORT       flags;                  /* Bit 0: Baseline for font at y=0;
                                         * Bit 1: Left sidebearing point at x=0;
                                         * Bit 2: Instructions may depend on point size;
@@ -141,5 +145,7 @@ struct head
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_HEAD_TABLE_HH */
index 2eea05a..992fe55 100644 (file)
 #include "hb-open-type-private.hh"
 
 
+namespace OT {
+
 
 /*
  * hhea -- The Horizontal Header Table
+ * vhea -- The Vertical Header Table
  */
 
 #define HB_OT_TAG_hhea HB_TAG('h','h','e','a')
+#define HB_OT_TAG_vhea HB_TAG('v','h','e','a')
 
 
-struct hhea
+struct _hea
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_hhea;
+  static const hb_tag_t tableTag = HB_TAG('_','h','e','a');
+
+  static const hb_tag_t hheaTag        = HB_OT_TAG_hhea;
+  static const hb_tag_t vheaTag        = HB_OT_TAG_vhea;
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
   }
 
-  private:
-  FixedVersion version;                /* 0x00010000 for version 1.0. */
-  FWORD                ascender;               /* Typographic ascent. <a
-                                        * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
-                                        * (Distance from baseline of highest
-                                        * ascender)</a> */
-  FWORD                descender;              /* Typographic descent. <a
-                                        * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
-                                        * (Distance from baseline of lowest
-                                        * descender)</a> */
-  FWORD                lineGap;                /* Typographic line gap. Negative
-                                        * LineGap values are treated as zero
-                                        * in Windows 3.1, System 6, and
-                                        * System 7. */
-  UFWORD       advanceWidthMax;        /* Maximum advance width value in
-                                        * 'hmtx' table. */
-  FWORD                minLeftSideBearing;     /* Minimum left sidebearing value in
-                                        * 'hmtx' table. */
-  FWORD                minRightSideBearing;    /* Minimum right sidebearing value;
+  public:
+  FixedVersion version;                /* 0x00010000u for version 1.0. */
+  FWORD                ascender;               /* Typographic ascent. */
+  FWORD                descender;              /* Typographic descent. */
+  FWORD                lineGap;                /* Typographic line gap. */
+  UFWORD       advanceMax;             /* Maximum advance width/height value in
+                                        * metrics table. */
+  FWORD                minLeadingBearing;      /* Minimum left/top sidebearing value in
+                                        * metrics table. */
+  FWORD                minTrailingBearing;     /* Minimum right/bottom sidebearing value;
                                         * calculated as Min(aw - lsb -
-                                        * (xMax - xMin)). */
-  FWORD                xMaxExtent;             /* Max(lsb + (xMax - xMin)). */
+                                        * (xMax - xMin)) for horizontal. */
+  FWORD                maxExtent;              /* horizontal: Max(lsb + (xMax - xMin)),
+                                        * vertical: minLeadingBearing+(yMax-yMin). */
   SHORT                caretSlopeRise;         /* Used to calculate the slope of the
-                                        * cursor (rise/run); 1 for vertical. */
-  SHORT                caretSlopeRun;          /* 0 for vertical. */
+                                        * cursor (rise/run); 1 for vertical caret,
+                                        * 0 for horizontal.*/
+  SHORT                caretSlopeRun;          /* 0 for vertical caret, 1 for horizontal. */
   SHORT                caretOffset;            /* The amount by which a slanted
                                         * highlight on a glyph needs
                                         * to be shifted to produce the
                                         * best appearance. Set to 0 for
-                                        * non--slanted fonts */
-  SHORT                reserved1;              /* set to 0 */
-  SHORT                reserved2;              /* set to 0 */
-  SHORT                reserved3;              /* set to 0 */
-  SHORT                reserved4;              /* set to 0 */
+                                        * non-slanted fonts. */
+  SHORT                reserved1;              /* Set to 0. */
+  SHORT                reserved2;              /* Set to 0. */
+  SHORT                reserved3;              /* Set to 0. */
+  SHORT                reserved4;              /* Set to 0. */
   SHORT                metricDataFormat;       /* 0 for current format. */
-  USHORT       numberOfHMetrics;       /* Number of hMetric entries in 'hmtx'
-                                        * table */
+  USHORT       numberOfLongMetrics;    /* Number of LongMetric entries in metric
+                                        * table. */
   public:
   DEFINE_SIZE_STATIC (36);
 };
 
+struct hhea : _hea {
+  static const hb_tag_t tableTag       = HB_OT_TAG_hhea;
+};
+struct vhea : _hea {
+  static const hb_tag_t tableTag       = HB_OT_TAG_vhea;
+};
+
+
+} /* namespace OT */
+
 
 #endif /* HB_OT_HHEA_TABLE_HH */
index 35cfb48..a0e3855 100644 (file)
 #include "hb-open-type-private.hh"
 
 
+namespace OT {
+
 
 /*
  * hmtx -- The Horizontal Metrics Table
+ * vmtx -- The Vertical Metrics Table
  */
 
 #define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
+#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
 
 
-struct LongHorMetric
+struct LongMetric
 {
-  USHORT       advanceWidth;
-  SHORT                lsb;
+  USHORT       advance; /* Advance width/height. */
+  SHORT                lsb; /* Leading (left/top) side bearing. */
   public:
   DEFINE_SIZE_STATIC (4);
 };
 
-struct hmtx
+struct _mtx
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_hmtx;
+  static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
+
+  static const hb_tag_t hmtxTag        = HB_OT_TAG_hmtx;
+  static const hb_tag_t vmtxTag        = HB_OT_TAG_vmtx;
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     /* We don't check for anything specific here.  The users of the
      * struct do all the hard work... */
     return TRACE_RETURN (true);
   }
 
-  private:
-  LongHorMetric        longHorMetric[VAR];     /* Paired advance width and left side
+  public:
+  LongMetric   longMetric[VAR];        /* Paired advance width and leading
                                         * bearing values for each glyph. The
                                         * value numOfHMetrics comes from
                                         * the 'hhea' table. If the font is
@@ -66,21 +74,31 @@ struct hmtx
                                         * be in the array, but that entry is
                                         * required. The last entry applies to
                                         * all subsequent glyphs. */
-  SHORT                leftSideBearingX[VAR];  /* Here the advanceWidth is assumed
-                                        * to be the same as the advanceWidth
+  SHORT                leadingBearingX[VAR];   /* Here the advance is assumed
+                                        * to be the same as the advance
                                         * for the last entry above. The
                                         * number of entries in this array is
                                         * derived from numGlyphs (from 'maxp'
-                                        * table) minus numberOfHMetrics. This
-                                        * generally is used with a run of
-                                        * monospaced glyphs (e.g., Kanji
+                                        * table) minus numberOfLongMetrics.
+                                        * This generally is used with a run
+                                        * of monospaced glyphs (e.g., Kanji
                                         * fonts or Courier fonts). Only one
                                         * run is allowed and it must be at
                                         * the end. This allows a monospaced
-                                        * font to vary the left side bearing
+                                        * font to vary the side bearing
                                         * values for each glyph. */
   public:
-  DEFINE_SIZE_ARRAY2 (0, longHorMetric, leftSideBearingX);
+  DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
+};
+
+struct hmtx : _mtx {
+  static const hb_tag_t tableTag       = HB_OT_TAG_hmtx;
+};
+struct vmtx : _mtx {
+  static const hb_tag_t tableTag       = HB_OT_TAG_vmtx;
 };
 
+} /* namespace OT */
+
+
 #endif /* HB_OT_HMTX_TABLE_HH */
index 2943a7f..3db7f57 100644 (file)
 #include "hb-set-private.hh"
 
 
-#define NOT_COVERED            ((unsigned int) 0x110000)
+namespace OT {
+
+
+#define TRACE_DISPATCH(this, format) \
+       hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
+       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+        "format %d", (int) format);
+
+
+#define NOT_COVERED            ((unsigned int) -1)
 #define MAX_NESTING_LEVEL      8
+#define MAX_CONTEXT_LENGTH     64
 
 
 
@@ -57,9 +67,15 @@ struct Record
     return tag.cmp (a);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
-    return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base));
+  struct sanitize_closure_t {
+    hb_tag_t tag;
+    const void *list_base;
+  };
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    const sanitize_closure_t closure = {tag, base};
+    return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
   }
 
   Tag          tag;            /* 4-byte Tag identifier */
@@ -94,7 +110,8 @@ struct RecordArrayOf : SortedArrayOf<Record<Type> > {
   }
   inline bool find_index (hb_tag_t tag, unsigned int *index) const
   {
-    int i = this->search (tag);
+    /* If we want to allow non-sorted data, we can lsearch(). */
+    int i = this->/*lsearch*/bsearch (tag);
     if (i != -1) {
         if (index) *index = i;
         return true;
@@ -111,8 +128,9 @@ struct RecordListOf : RecordArrayOf<Type>
   inline const Type& operator [] (unsigned int i) const
   { return this+RecordArrayOf<Type>::operator [](i).offset; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
   }
 };
@@ -121,12 +139,12 @@ struct RecordListOf : RecordArrayOf<Type>
 struct RangeRecord
 {
   inline int cmp (hb_codepoint_t g) const {
-    hb_codepoint_t a = start, b = end;
-    return g < a ? -1 : g <= b ? 0 : +1 ;
+    return g < start ? -1 : g <= end ? 0 : +1 ;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -134,6 +152,11 @@ struct RangeRecord
     return glyphs->intersects (start, end);
   }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    glyphs->add_range (start, end);
+  }
+
   GlyphID      start;          /* First GlyphID in the range */
   GlyphID      end;            /* Last GlyphID in the range */
   USHORT       value;          /* Value */
@@ -176,24 +199,26 @@ struct LangSys
                                           unsigned int *feature_indexes /* OUT */) const
   { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
 
-  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
+  inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
   inline unsigned int get_required_feature_index (void) const
   {
-    if (reqFeatureIndex == 0xffff)
+    if (reqFeatureIndex == 0xFFFFu)
       return Index::NOT_FOUND_INDEX;
    return reqFeatureIndex;;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c,
+                       const Record<LangSys>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
   }
 
-  Offset       lookupOrder;    /* = Null (reserved for an offset to a
+  Offset<>     lookupOrderZ;   /* = Null (reserved for an offset to a
                                 * reordering table) */
   USHORT       reqFeatureIndex;/* Index of a feature required for this
                                 * language system--if no required features
-                                * = 0xFFFF */
+                                * = 0xFFFFu */
   IndexArray   featureIndex;   /* Array of indices into the FeatureList */
   public:
   DEFINE_SIZE_ARRAY (6, featureIndex);
@@ -222,12 +247,14 @@ struct Script
   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c,
+                       const Record<Script>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
   }
 
-  private:
+  protected:
   OffsetTo<LangSys>
                defaultLangSys; /* Offset to DefaultLangSys table--from
                                 * beginning of Script table--may be Null */
@@ -241,6 +268,224 @@ struct Script
 typedef RecordListOf<Script> ScriptList;
 
 
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+struct FeatureParamsSize
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
+
+    /* This subtable has some "history", if you will.  Some earlier versions of
+     * Adobe tools calculated the offset of the FeatureParams sutable from the
+     * beginning of the FeatureList table!  Now, that is dealt with in the
+     * Feature implementation.  But we still need to be able to tell junk from
+     * real data.  Note: We don't check that the nameID actually exists.
+     *
+     * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
+     *
+     * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
+     * coming out soon, and that the makeotf program will build a font with a
+     * 'size' feature that is correct by the specification.
+     *
+     * The specification for this feature tag is in the "OpenType Layout Tag
+     * Registry". You can see a copy of this at:
+     * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
+     *
+     * Here is one set of rules to determine if the 'size' feature is built
+     * correctly, or as by the older versions of MakeOTF. You may be able to do
+     * better.
+     *
+     * Assume that the offset to the size feature is according to specification,
+     * and make the following value checks. If it fails, assume the the size
+     * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
+     * If this fails, reject the 'size' feature. The older makeOTF's calculated the
+     * offset from the beginning of the FeatureList table, rather than from the
+     * beginning of the 'size' Feature table.
+     *
+     * If "design size" == 0:
+     *     fails check
+     *
+     * Else if ("subfamily identifier" == 0 and
+     *     "range start" == 0 and
+     *     "range end" == 0 and
+     *     "range start" == 0 and
+     *     "menu name ID" == 0)
+     *     passes check: this is the format used when there is a design size
+     * specified, but there is no recommended size range.
+     *
+     * Else if ("design size" <  "range start" or
+     *     "design size" >   "range end" or
+     *     "range end" <= "range start" or
+     *     "menu name ID"  < 256 or
+     *     "menu name ID"  > 32767 or
+     *     menu name ID is not a name ID which is actually in the name table)
+     *     fails test
+     * Else
+     *     passes test.
+     */
+
+    if (!designSize)
+      return TRACE_RETURN (false);
+    else if (subfamilyID == 0 &&
+            subfamilyNameID == 0 &&
+            rangeStart == 0 &&
+            rangeEnd == 0)
+      return TRACE_RETURN (true);
+    else if (designSize < rangeStart ||
+            designSize > rangeEnd ||
+            subfamilyNameID < 256 ||
+            subfamilyNameID > 32767)
+      return TRACE_RETURN (false);
+    else
+      return TRACE_RETURN (true);
+  }
+
+  USHORT       designSize;     /* Represents the design size in 720/inch
+                                * units (decipoints).  The design size entry
+                                * must be non-zero.  When there is a design
+                                * size but no recommended size range, the
+                                * rest of the array will consist of zeros. */
+  USHORT       subfamilyID;    /* Has no independent meaning, but serves
+                                * as an identifier that associates fonts
+                                * in a subfamily. All fonts which share a
+                                * Preferred or Font Family name and which
+                                * differ only by size range shall have the
+                                * same subfamily value, and no fonts which
+                                * differ in weight or style shall have the
+                                * same subfamily value. If this value is
+                                * zero, the remaining fields in the array
+                                * will be ignored. */
+  USHORT       subfamilyNameID;/* If the preceding value is non-zero, this
+                                * value must be set in the range 256 - 32767
+                                * (inclusive). It records the value of a
+                                * field in the name table, which must
+                                * contain English-language strings encoded
+                                * in Windows Unicode and Macintosh Roman,
+                                * and may contain additional strings
+                                * localized to other scripts and languages.
+                                * Each of these strings is the name an
+                                * application should use, in combination
+                                * with the family name, to represent the
+                                * subfamily in a menu.  Applications will
+                                * choose the appropriate version based on
+                                * their selection criteria. */
+  USHORT       rangeStart;     /* Large end of the recommended usage range
+                                * (inclusive), stored in 720/inch units
+                                * (decipoints). */
+  USHORT       rangeEnd;       /* Small end of the recommended usage range
+                                  (exclusive), stored in 720/inch units
+                                * (decipoints). */
+  public:
+  DEFINE_SIZE_STATIC (10);
+};
+
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
+struct FeatureParamsStylisticSet
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    /* Right now minorVersion is at zero.  Which means, any table supports
+     * the uiNameID field. */
+    return TRACE_RETURN (c->check_struct (this));
+  }
+
+  USHORT       version;        /* (set to 0): This corresponds to a “minor”
+                                * version number. Additional data may be
+                                * added to the end of this Feature Parameters
+                                * table in the future. */
+
+  USHORT       uiNameID;       /* The 'name' table name ID that specifies a
+                                * string (or strings, for multiple languages)
+                                * for a user-interface label for this
+                                * feature.  The values of uiLabelNameId and
+                                * sampleTextNameId are expected to be in the
+                                * font-specific name ID range (256-32767),
+                                * though that is not a requirement in this
+                                * Feature Parameters specification. The
+                                * user-interface label for the feature can
+                                * be provided in multiple languages. An
+                                * English string should be included as a
+                                * fallback. The string should be kept to a
+                                * minimal length to fit comfortably with
+                                * different application interfaces. */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
+struct FeatureParamsCharacterVariants
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+                        characters.sanitize (c));
+  }
+
+  USHORT       format;                 /* Format number is set to 0. */
+  USHORT       featUILableNameID;      /* The ‘name’ table name ID that
+                                        * specifies a string (or strings,
+                                        * for multiple languages) for a
+                                        * user-interface label for this
+                                        * feature. (May be NULL.) */
+  USHORT       featUITooltipTextNameID;/* The ‘name’ table name ID that
+                                        * specifies a string (or strings,
+                                        * for multiple languages) that an
+                                        * application can use for tooltip
+                                        * text for this feature. (May be
+                                        * NULL.) */
+  USHORT       sampleTextNameID;       /* The ‘name’ table name ID that
+                                        * specifies sample text that
+                                        * illustrates the effect of this
+                                        * feature. (May be NULL.) */
+  USHORT       numNamedParameters;     /* Number of named parameters. (May
+                                        * be zero.) */
+  USHORT       firstParamUILabelNameID;/* The first ‘name’ table name ID
+                                        * used to specify strings for
+                                        * user-interface labels for the
+                                        * feature parameters. (Must be zero
+                                        * if numParameters is zero.) */
+  ArrayOf<UINT24>
+               characters;             /* Array of the Unicode Scalar Value
+                                        * of the characters for which this
+                                        * feature provides glyph variants.
+                                        * (May be zero.) */
+  public:
+  DEFINE_SIZE_ARRAY (14, characters);
+};
+
+struct FeatureParams
+{
+  inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
+  {
+    TRACE_SANITIZE (this);
+    if (tag == HB_TAG ('s','i','z','e'))
+      return TRACE_RETURN (u.size.sanitize (c));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+      return TRACE_RETURN (u.stylisticSet.sanitize (c));
+    if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+      return TRACE_RETURN (u.characterVariants.sanitize (c));
+    return TRACE_RETURN (true);
+  }
+
+  inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
+  {
+    if (tag == HB_TAG ('s','i','z','e'))
+      return u.size;
+    return Null(FeatureParamsSize);
+  }
+
+  private:
+  union {
+  FeatureParamsSize                    size;
+  FeatureParamsStylisticSet            stylisticSet;
+  FeatureParamsCharacterVariants       characterVariants;
+  } u;
+  DEFINE_SIZE_STATIC (17);
+};
+
 struct Feature
 {
   inline unsigned int get_lookup_count (void) const
@@ -252,12 +497,55 @@ struct Feature
                                          unsigned int *lookup_tags /* OUT */) const
   { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    return TRACE_RETURN (c->check_struct (this) && lookupIndex.sanitize (c));
+  inline const FeatureParams &get_feature_params (void) const
+  { return this+featureParams; }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+                       const Record<Feature>::sanitize_closure_t *closure) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
+      return TRACE_RETURN (false);
+
+    /* Some earlier versions of Adobe tools calculated the offset of the
+     * FeatureParams subtable from the beginning of the FeatureList table!
+     *
+     * If sanitizing "failed" for the FeatureParams subtable, try it with the
+     * alternative location.  We would know sanitize "failed" if old value
+     * of the offset was non-zero, but it's zeroed now.
+     *
+     * Only do this for the 'size' feature, since at the time of the faulty
+     * Adobe tools, only the 'size' feature had FeatureParams defined.
+     */
+
+    OffsetTo<FeatureParams> orig_offset = featureParams;
+    if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
+      return TRACE_RETURN (false);
+
+    if (likely (orig_offset.is_null ()))
+      return TRACE_RETURN (true);
+
+    if (featureParams == 0 && closure &&
+       closure->tag == HB_TAG ('s','i','z','e') &&
+       closure->list_base && closure->list_base < this)
+    {
+      unsigned int new_offset_int = (unsigned int) orig_offset -
+                                   (((char *) this) - ((char *) closure->list_base));
+
+      OffsetTo<FeatureParams> new_offset;
+      /* Check that it did not overflow. */
+      new_offset.set (new_offset_int);
+      if (new_offset == new_offset_int &&
+         c->try_set (&featureParams, new_offset) &&
+         !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
+       return TRACE_RETURN (false);
+    }
+
+    return TRACE_RETURN (true);
   }
 
-  Offset       featureParams;  /* Offset to Feature Parameters table (if one
+  OffsetTo<FeatureParams>
+                featureParams; /* Offset to Feature Parameters table (if one
                                 * has been defined for the feature), relative
                                 * to the beginning of the Feature Table; = Null
                                 * if not required */
@@ -289,6 +577,17 @@ struct Lookup
 {
   inline unsigned int get_subtable_count (void) const { return subTable.len; }
 
+  template <typename SubTableType>
+  inline const SubTableType& get_subtable (unsigned int i) const
+  { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
+
+  template <typename SubTableType>
+  inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
+  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+  template <typename SubTableType>
+  inline OffsetArrayOf<SubTableType>& get_subtables (void)
+  { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+
   inline unsigned int get_type (void) const { return lookupType; }
 
   /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
@@ -305,21 +604,55 @@ struct Lookup
     return flag;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  template <typename SubTableType, typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    unsigned int lookup_type = get_type ();
+    TRACE_DISPATCH (this, lookup_type);
+    unsigned int count = get_subtable_count ();
+    for (unsigned int i = 0; i < count; i++) {
+      typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
+      if (c->stop_sublookup_iteration (r))
+        return TRACE_RETURN (r);
+    }
+    return TRACE_RETURN (c->default_return_value ());
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                        unsigned int lookup_type,
+                        uint32_t lookup_props,
+                        unsigned int num_subtables)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    lookupType.set (lookup_type);
+    lookupFlag.set (lookup_props & 0xFFFFu);
+    if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
+    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+    {
+      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      markFilteringSet.set (lookup_props >> 16);
+    }
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     /* Real sanitize of the subtables is done by GSUB/GPOS/... */
     if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
-    if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
+    if (lookupFlag & LookupFlag::UseMarkFilteringSet)
     {
-      USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+      const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
       if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
     }
     return TRACE_RETURN (true);
   }
 
+  private:
   USHORT       lookupType;             /* Different enumerations for GSUB and GPOS */
   USHORT       lookupFlag;             /* Lookup qualifiers */
-  ArrayOf<Offset>
+  ArrayOf<Offset<> >
                subTable;               /* Array of SubTables */
   USHORT       markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
                                         * structure. This field is only present if bit
@@ -342,14 +675,28 @@ struct CoverageFormat1
   private:
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
-    int i = glyphArray.search (glyph_id);
-    if (i != -1)
-        return i;
-    return NOT_COVERED;
+    int i = glyphArray.bsearch (glyph_id);
+    ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
+    return i;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    glyphArray.len.set (num_glyphs);
+    if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
+    for (unsigned int i = 0; i < num_glyphs; i++)
+      glyphArray[i] = glyphs[i];
+    glyphs.advance (num_glyphs);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (glyphArray.sanitize (c));
   }
 
@@ -357,6 +704,15 @@ struct CoverageFormat1
     return glyphs->has (glyphArray[index]);
   }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    unsigned int count = glyphArray.len;
+    for (unsigned int i = 0; i < count; i++)
+      glyphs->add (glyphArray[i]);
+  }
+
+  public:
+  /* Older compilers need this to be public. */
   struct Iter {
     inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
     inline bool more (void) { return i < c->glyphArray.len; }
@@ -368,8 +724,9 @@ struct CoverageFormat1
     const struct CoverageFormat1 *c;
     unsigned int i;
   };
-
   private:
+
+  protected:
   USHORT       coverageFormat; /* Format identifier--format = 1 */
   SortedArrayOf<GlyphID>
                glyphArray;     /* Array of GlyphIDs--in numerical order */
@@ -384,7 +741,7 @@ struct CoverageFormat2
   private:
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
-    int i = rangeRecord.search (glyph_id);
+    int i = rangeRecord.bsearch (glyph_id);
     if (i != -1) {
       const RangeRecord &range = rangeRecord[i];
       return (unsigned int) range.value + (glyph_id - range.start);
@@ -392,8 +749,41 @@ struct CoverageFormat2
     return NOT_COVERED;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+
+    if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
+
+    unsigned int num_ranges = 1;
+    for (unsigned int i = 1; i < num_glyphs; i++)
+      if (glyphs[i - 1] + 1 != glyphs[i])
+        num_ranges++;
+    rangeRecord.len.set (num_ranges);
+    if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
+
+    unsigned int range = 0;
+    rangeRecord[range].start = glyphs[0];
+    rangeRecord[range].value.set (0);
+    for (unsigned int i = 1; i < num_glyphs; i++)
+      if (glyphs[i - 1] + 1 != glyphs[i]) {
+       range++;
+       rangeRecord[range].start = glyphs[i];
+       rangeRecord[range].value.set (i);
+        rangeRecord[range].end = glyphs[i];
+      } else {
+        rangeRecord[range].end = glyphs[i];
+      }
+    glyphs.advance (num_glyphs);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rangeRecord.sanitize (c));
   }
 
@@ -412,6 +802,15 @@ struct CoverageFormat2
     return false;
   }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      rangeRecord[i].add_coverage (glyphs);
+  }
+
+  public:
+  /* Older compilers need this to be public. */
   struct Iter {
     inline void init (const CoverageFormat2 &c_) {
       c = &c_;
@@ -437,8 +836,9 @@ struct CoverageFormat2
     const struct CoverageFormat2 *c;
     unsigned int i, j, coverage;
   };
-
   private:
+
+  protected:
   USHORT       coverageFormat; /* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
                rangeRecord;    /* Array of glyph ranges--ordered by
@@ -450,8 +850,6 @@ struct CoverageFormat2
 
 struct Coverage
 {
-  inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
-
   inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
@@ -461,8 +859,27 @@ struct Coverage
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    unsigned int num_ranges = 1;
+    for (unsigned int i = 1; i < num_glyphs; i++)
+      if (glyphs[i - 1] + 1 != glyphs[i])
+        num_ranges++;
+    u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
+    switch (u.format) {
+    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
+    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
+    default:return TRACE_RETURN (false);
+    }
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -489,21 +906,30 @@ struct Coverage
     }
   }
 
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const {
+    switch (u.format) {
+    case 1: u.format1.add_coverage (glyphs); break;
+    case 2: u.format2.add_coverage (glyphs); break;
+    default:                                 break;
+    }
+  }
+
   struct Iter {
     Iter (void) : format (0) {};
     inline void init (const Coverage &c_) {
       format = c_.u.format;
       switch (format) {
-      case 1: return u.format1.init (c_.u.format1);
-      case 2: return u.format2.init (c_.u.format2);
-      default:return;
+      case 1: u.format1.init (c_.u.format1); return;
+      case 2: u.format2.init (c_.u.format2); return;
+      default:                               return;
       }
     }
     inline bool more (void) {
       switch (format) {
       case 1: return u.format1.more ();
       case 2: return u.format2.more ();
-      default:return true;
+      default:return false;
       }
     }
     inline void next (void) {
@@ -517,14 +943,14 @@ struct Coverage
       switch (format) {
       case 1: return u.format1.get_glyph ();
       case 2: return u.format2.get_glyph ();
-      default:return true;
+      default:return 0;
       }
     }
     inline uint16_t get_coverage (void) {
       switch (format) {
       case 1: return u.format1.get_coverage ();
       case 2: return u.format2.get_coverage ();
-      default:return true;
+      default:return -1;
       }
     }
 
@@ -536,7 +962,7 @@ struct Coverage
     } u;
   };
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   CoverageFormat1      format1;
@@ -558,24 +984,48 @@ struct ClassDefFormat1
   private:
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
-    if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
-      return classValue[glyph_id - startGlyph];
+    unsigned int i = (unsigned int) (glyph_id - startGlyph);
+    if (unlikely (i < classValue.len))
+      return classValue[i];
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
   }
 
+  template <typename set_t>
+  inline void add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = classValue.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (classValue[i] == klass)
+        glyphs->add (startGlyph + i);
+  }
+
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     unsigned int count = classValue.len;
+    if (klass == 0)
+    {
+      /* Match if there's any glyph that is not listed! */
+      hb_codepoint_t g = -1;
+      if (!hb_set_next (glyphs, &g))
+        return false;
+      if (g < startGlyph)
+        return true;
+      g = startGlyph + count - 1;
+      if (hb_set_next (glyphs, &g))
+        return true;
+      /* Fall through. */
+    }
     for (unsigned int i = 0; i < count; i++)
       if (classValue[i] == klass && glyphs->has (startGlyph + i))
         return true;
     return false;
   }
 
+  protected:
   USHORT       classFormat;            /* Format identifier--format = 1 */
   GlyphID      startGlyph;             /* First GlyphID of the classValueArray */
   ArrayOf<USHORT>
@@ -591,25 +1041,51 @@ struct ClassDefFormat2
   private:
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
-    int i = rangeRecord.search (glyph_id);
-    if (i != -1)
+    int i = rangeRecord.bsearch (glyph_id);
+    if (unlikely (i != -1))
       return rangeRecord[i].value;
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rangeRecord.sanitize (c));
   }
 
+  template <typename set_t>
+  inline void add_class (set_t *glyphs, unsigned int klass) const {
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].value == klass)
+        rangeRecord[i].add_coverage (glyphs);
+  }
+
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int 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_codepoint_t) -1;
+      for (unsigned int i = 0; i < count; i++)
+      {
+       if (!hb_set_next (glyphs, &g))
+         break;
+       if (g < rangeRecord[i].start)
+         return true;
+       g = rangeRecord[i].end;
+      }
+      if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g))
+        return true;
+      /* Fall through. */
+    }
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
         return true;
     return false;
   }
 
+  protected:
   USHORT       classFormat;    /* Format identifier--format = 2 */
   SortedArrayOf<RangeRecord>
                rangeRecord;    /* Array of glyph ranges--ordered by
@@ -620,8 +1096,6 @@ struct ClassDefFormat2
 
 struct ClassDef
 {
-  inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
-
   inline unsigned int get_class (hb_codepoint_t glyph_id) const
   {
     switch (u.format) {
@@ -631,8 +1105,9 @@ struct ClassDef
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -641,6 +1116,14 @@ struct ClassDef
     }
   }
 
+  inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
+    switch (u.format) {
+    case 1: u.format1.add_class (glyphs, klass); return;
+    case 2: u.format2.add_class (glyphs, klass); return;
+    default:return;
+    }
+  }
+
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     switch (u.format) {
     case 1: return u.format1.intersects_class (glyphs, klass);
@@ -649,7 +1132,7 @@ struct ClassDef
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   ClassDefFormat1      format1;
@@ -681,7 +1164,7 @@ struct Device
 
     if (!pixels) return 0;
 
-    return pixels * (int64_t) scale / ppem;
+    return (int) (pixels * (int64_t) scale / ppem);
   }
 
 
@@ -698,7 +1181,7 @@ struct Device
 
     unsigned int byte = deltaValue[s >> (4 - f)];
     unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
-    unsigned int mask = (0xFFFF >> (16 - (1 << f)));
+    unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
 
     int delta = bits & mask;
 
@@ -715,12 +1198,13 @@ struct Device
     return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
   }
 
-  private:
+  protected:
   USHORT       startSize;              /* Smallest size to correct--in ppem */
   USHORT       endSize;                /* Largest size to correct--in ppem */
   USHORT       deltaFormat;            /* Format of DeltaValue array data: 1, 2, or 3
@@ -734,5 +1218,7 @@ struct Device
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
index f29fc14..7a6c04d 100644 (file)
@@ -34,6 +34,8 @@
 #include "hb-font-private.hh"
 
 
+namespace OT {
+
 
 /*
  * Attachment List Table
@@ -49,7 +51,7 @@ struct AttachList
                                         unsigned int *point_count /* IN/OUT */,
                                         unsigned int *point_array /* OUT */) const
   {
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (index == NOT_COVERED)
     {
       if (point_count)
@@ -69,12 +71,13 @@ struct AttachList
     return points.len;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
   }
 
-  private:
+  protected:
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table -- from
                                         * beginning of AttachList table */
@@ -99,12 +102,13 @@ struct CaretValueFormat1
     return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
-  private:
+  protected:
   USHORT       caretValueFormat;       /* Format identifier--format = 1 */
   SHORT                coordinate;             /* X or Y value, in design units */
   public:
@@ -119,18 +123,19 @@ struct CaretValueFormat2
   inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
   {
     hb_position_t x, y;
-    if (hb_font_get_glyph_contour_point_for_origin (font, glyph_id, caretValuePoint, direction, &x, &y))
+    if (font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y))
       return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
     else
       return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
-  private:
+  protected:
   USHORT       caretValueFormat;       /* Format identifier--format = 2 */
   USHORT       caretValuePoint;        /* Contour point index on glyph */
   public:
@@ -148,12 +153,13 @@ struct CaretValueFormat3
            font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       caretValueFormat;       /* Format identifier--format = 3 */
   SHORT                coordinate;             /* X or Y value, in design units */
   OffsetTo<Device>
@@ -176,8 +182,9 @@ struct CaretValue
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -187,7 +194,7 @@ struct CaretValue
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   CaretValueFormat1    format1;
@@ -217,12 +224,13 @@ struct LigGlyph
     return carets.len;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (carets.sanitize (c, this));
   }
 
-  private:
+  protected:
   OffsetArrayOf<CaretValue>
                carets;                 /* Offset array of CaretValue tables
                                         * --from beginning of LigGlyph table
@@ -240,7 +248,7 @@ struct LigCaretList
                                      unsigned int *caret_count /* IN/OUT */,
                                      hb_position_t *caret_array /* OUT */) const
   {
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (index == NOT_COVERED)
     {
       if (caret_count)
@@ -251,12 +259,13 @@ struct LigCaretList
     return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
   }
 
-  private:
+  protected:
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of LigCaretList table */
@@ -273,14 +282,15 @@ struct MarkGlyphSetsFormat1
   inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
   { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
-  LongOffsetArrayOf<Coverage>
+  ArrayOf<OffsetTo<Coverage, ULONG> >
                coverage;               /* Array of long offsets to mark set
                                         * coverage tables */
   public:
@@ -297,8 +307,9 @@ struct MarkGlyphSets
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -306,7 +317,7 @@ struct MarkGlyphSets
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   MarkGlyphSetsFormat1 format1;
@@ -322,7 +333,7 @@ struct MarkGlyphSets
 
 struct GDEF
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_GDEF;
+  static const hb_tag_t tableTag       = HB_OT_TAG_GDEF;
 
   enum GlyphClasses {
     UnclassifiedGlyph  = 0,
@@ -335,6 +346,8 @@ struct GDEF
   inline bool has_glyph_classes (void) const { return glyphClassDef != 0; }
   inline unsigned int get_glyph_class (hb_codepoint_t glyph) const
   { return (this+glyphClassDef).get_class (glyph); }
+  inline void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
+  { (this+glyphClassDef).add_class (glyphs, klass); }
 
   inline bool has_mark_attachment_types (void) const { return markAttachClassDef != 0; }
   inline unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
@@ -356,19 +369,20 @@ struct GDEF
                                      hb_position_t *caret_array /* OUT */) const
   { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
 
-  inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002 && markGlyphSetsDef[0] != 0; }
+  inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
   inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
-  { return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+  { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (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 () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this)));
+                        (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
   }
 
 
@@ -379,22 +393,24 @@ struct GDEF
   {
     unsigned int klass = get_glyph_class (glyph);
 
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs);
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures);
+    ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks);
+
     switch (klass) {
-    default:
-    case UnclassifiedGlyph:    return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
-    case BaseGlyph:            return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
-    case LigatureGlyph:                return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
-    case ComponentGlyph:       return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
+    default:                   return 0;
+    case BaseGlyph:            return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
+    case LigatureGlyph:                return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
     case MarkGlyph:
          klass = get_mark_attachment_type (glyph);
-         return HB_OT_LAYOUT_GLYPH_CLASS_MARK | (klass << 8);
+         return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
     }
   }
 
 
-  private:
+  protected:
   FixedVersion version;                /* Version of the GDEF table--currently
-                                        * 0x00010002 */
+                                        * 0x00010002u */
   OffsetTo<ClassDef>
                glyphClassDef;          /* Offset to class definition table
                                         * for glyph type--from beginning of
@@ -421,5 +437,7 @@ struct GDEF
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */
index 71c13a2..d88f787 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
- * Copyright © 2010,2012  Google, Inc.
+ * Copyright © 2010,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -32,6 +32,8 @@
 #include "hb-ot-layout-gsubgpos-private.hh"
 
 
+namespace OT {
+
 
 /* buffer **position** var allocations */
 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
@@ -47,18 +49,18 @@ typedef Value ValueRecord[VAR];
 struct ValueFormat : USHORT
 {
   enum Flags {
-    xPlacement = 0x0001      /* Includes horizontal adjustment for placement */
-    yPlacement = 0x0002      /* Includes vertical adjustment for placement */
-    xAdvance   = 0x0004      /* Includes horizontal adjustment for advance */
-    yAdvance   = 0x0008      /* Includes vertical adjustment for advance */
-    xPlaDevice = 0x0010      /* Includes horizontal Device table for placement */
-    yPlaDevice = 0x0020      /* Includes vertical Device table for placement */
-    xAdvDevice = 0x0040      /* Includes horizontal Device table for advance */
-    yAdvDevice = 0x0080      /* Includes vertical Device table for advance */
-    ignored    = 0x0F00      /* Was used in TrueType Open for MM fonts */
-    reserved   = 0xF000      /* For future use */
-
-    devices    = 0x00F0        /* Mask for having any Device table */
+    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. */
@@ -107,11 +109,13 @@ struct ValueFormat : USHORT
     if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
     if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
     if (format & xAdvance) {
-      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
+      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
+      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++)); else values++;
+      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
+      values++;
     }
 
     if (!has_device ()) return;
@@ -123,22 +127,27 @@ struct ValueFormat : USHORT
 
     /* pixel -> fractional pixel */
     if (format & xPlaDevice) {
-      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values++)).get_x_delta (font); else values++;
+      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
+      values++;
     }
     if (format & yPlaDevice) {
-      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values++)).get_y_delta (font); else values++;
+      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
+      values++;
     }
     if (format & xAdvDevice) {
-      if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
+      if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
+      values++;
     }
     if (format & yAdvDevice) {
       /* y_advance values grow downward but font-space grows upward, hence negation */
-      if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
+      if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
+      values++;
     }
   }
 
   private:
-  inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
+  inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
     unsigned int format = *this;
 
     if (format & xPlacement) values++;
@@ -169,13 +178,15 @@ struct ValueFormat : USHORT
     return (format & devices) != 0;
   }
 
-  inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
-    TRACE_SANITIZE ();
+  inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
   }
 
-  inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
-    TRACE_SANITIZE ();
+  inline 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_array (values, get_size (), count)) return TRACE_RETURN (false);
@@ -192,8 +203,9 @@ struct ValueFormat : USHORT
   }
 
   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
-  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
-    TRACE_SANITIZE ();
+  inline 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_RETURN (true);
 
@@ -210,9 +222,6 @@ struct ValueFormat : USHORT
 
 struct AnchorFormat1
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
                          hb_position_t *x, hb_position_t *y) const
   {
@@ -220,12 +229,13 @@ struct AnchorFormat1
       *y = font->em_scale_y (yCoordinate);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   SHORT                xCoordinate;            /* Horizontal value--in design units */
   SHORT                yCoordinate;            /* Vertical value--in design units */
@@ -235,29 +245,27 @@ struct AnchorFormat1
 
 struct AnchorFormat2
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
                          hb_position_t *x, hb_position_t *y) const
   {
       unsigned int x_ppem = font->x_ppem;
       unsigned int y_ppem = font->y_ppem;
       hb_position_t cx, cy;
-      hb_bool_t ret = false;
+      hb_bool_t ret;
 
-      if (x_ppem || y_ppem)
-       ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
-      *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
-      *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
+      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_scale_x (xCoordinate);
+      *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 2 */
   SHORT                xCoordinate;            /* Horizontal value--in design units */
   SHORT                yCoordinate;            /* Vertical value--in design units */
@@ -268,9 +276,6 @@ struct AnchorFormat2
 
 struct AnchorFormat3
 {
-  friend struct Anchor;
-
-  private:
   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
                          hb_position_t *x, hb_position_t *y) const
   {
@@ -283,12 +288,13 @@ struct AnchorFormat3
        *y += (this+yDeviceTable).get_x_delta (font);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 3 */
   SHORT                xCoordinate;            /* Horizontal value--in design units */
   SHORT                yCoordinate;            /* Vertical value--in design units */
@@ -318,8 +324,9 @@ struct Anchor
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
     switch (u.format) {
     case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -329,7 +336,7 @@ struct Anchor
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   AnchorFormat1                format1;
@@ -343,29 +350,32 @@ struct Anchor
 
 struct AnchorMatrix
 {
-  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
+  inline 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);
-    return this+matrix[row * cols + col];
+    *found = !matrixZ[row * cols + col].is_null ();
+    return this+matrixZ[row * cols + col];
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
+  {
+    TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return TRACE_RETURN (false);
     if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
     unsigned int count = rows * cols;
-    if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
+    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < count; i++)
-      if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
+      if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   USHORT       rows;                   /* Number of rows */
-  private:
+  protected:
   OffsetTo<Anchor>
-               matrix[VAR];            /* Matrix of offsets to Anchor tables--
+               matrixZ[VAR];           /* Matrix of offsets to Anchor tables--
                                         * from beginning of AnchorMatrix table */
   public:
-  DEFINE_SIZE_ARRAY (2, matrix);
+  DEFINE_SIZE_ARRAY (2, matrixZ);
 };
 
 
@@ -373,12 +383,13 @@ struct MarkRecord
 {
   friend struct MarkArray;
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
   }
 
-  private:
+  protected:
   USHORT       klass;                  /* Class defined for this mark */
   OffsetTo<Anchor>
                markAnchor;             /* Offset to Anchor table--from
@@ -394,29 +405,35 @@ struct MarkArray : ArrayOf<MarkRecord>    /* Array of MarkRecords--in Coverage orde
                     const AnchorMatrix &anchors, unsigned int class_count,
                     unsigned int glyph_pos) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
     unsigned int mark_class = record.klass;
 
     const Anchor& mark_anchor = this + record.markAnchor;
-    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
+    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_RETURN (false);
 
     hb_position_t mark_x, mark_y, base_x, base_y;
 
-    mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y);
-    glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+    mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
+    glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
 
-    hb_glyph_position_t &o = c->buffer->cur_pos();
+    hb_glyph_position_t &o = buffer->cur_pos();
     o.x_offset = base_x - mark_x;
     o.y_offset = base_y - mark_y;
-    o.attach_lookback() = c->buffer->idx - glyph_pos;
+    o.attach_lookback() = buffer->idx - glyph_pos;
 
-    c->buffer->idx++;
+    buffer->idx++;
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
   }
 };
@@ -426,28 +443,40 @@ struct MarkArray : ArrayOf<MarkRecord>    /* Array of MarkRecords--in Coverage orde
 
 struct SinglePosFormat1
 {
-  friend struct SinglePos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
 
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    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_RETURN (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
-                            values, c->buffer->cur_pos());
+                            values, buffer->cur_pos());
 
-    c->buffer->idx++;
+    buffer->idx++;
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this)
+        && coverage.sanitize (c, this)
+       && valueFormat.sanitize_value (c, this, values));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -463,31 +492,43 @@ struct SinglePosFormat1
 
 struct SinglePosFormat2
 {
-  friend struct SinglePos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
 
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    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_RETURN (false);
 
     if (likely (index >= valueCount)) return TRACE_RETURN (false);
 
     valueFormat.apply_value (c->font, c->direction, this,
                             &values[index * valueFormat.get_len ()],
-                            c->buffer->cur_pos());
+                            buffer->cur_pos());
 
-    c->buffer->idx++;
+    buffer->idx++;
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this)
+       && coverage.sanitize (c, this)
+       && valueFormat.sanitize_values (c, this, values, valueCount));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -503,30 +544,19 @@ struct SinglePosFormat2
 
 struct SinglePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    case 2: return TRACE_RETURN (c->dispatch (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
-    }
-  }
-
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   SinglePosFormat1     format1;
@@ -539,7 +569,7 @@ struct PairValueRecord
 {
   friend struct PairSet;
 
-  private:
+  protected:
   GlyphID      secondGlyph;            /* GlyphID of second glyph in the
                                         * pair--first glyph is listed in the
                                         * Coverage table */
@@ -553,83 +583,126 @@ struct PairSet
 {
   friend struct PairPosFormat1;
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
+                             const ValueFormat *valueFormats) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      c->input->add (record->secondGlyph);
+      record = &StructAtOffset<PairValueRecord> (record, record_size);
+    }
+  }
+
   inline bool apply (hb_apply_context_t *c,
                     const ValueFormat *valueFormats,
                     unsigned int pos) const
   {
-    TRACE_APPLY ();
+    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 = USHORT::static_size * (1 + len1 + len2);
 
+    const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
     unsigned int count = len;
-    const PairValueRecord *record = CastP<PairValueRecord> (array);
-    for (unsigned int i = 0; i < count; i++)
+
+    /* Hand-coded bsearch. */
+    if (unlikely (!count))
+      return TRACE_RETURN (false);
+    hb_codepoint_t x = buffer->info[pos].codepoint;
+    int min = 0, max = (int) count - 1;
+    while (min <= max)
     {
-      if (c->buffer->info[pos].codepoint == record->secondGlyph)
+      int mid = (min + max) / 2;
+      const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
+      hb_codepoint_t mid_x = record->secondGlyph;
+      if (x < mid_x)
+        max = mid - 1;
+      else if (x > mid_x)
+        min = mid + 1;
+      else
       {
        valueFormats[0].apply_value (c->font, c->direction, this,
-                                    &record->values[0], c->buffer->cur_pos());
+                                    &record->values[0], buffer->cur_pos());
        valueFormats[1].apply_value (c->font, c->direction, this,
-                                    &record->values[len1], c->buffer->pos[pos]);
+                                    &record->values[len1], buffer->pos[pos]);
        if (len2)
          pos++;
-       c->buffer->idx = pos;
+       buffer->idx = pos;
        return TRACE_RETURN (true);
       }
-      record = &StructAtOffset<PairValueRecord> (record, record_size);
     }
 
     return TRACE_RETURN (false);
   }
 
   struct sanitize_closure_t {
-    void *base;
-    ValueFormat *valueFormats;
+    const void *base;
+    const ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int stride; /* 1 + len1 + len2 */
   };
 
-  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+  {
+    TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
-       && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
+       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
 
     unsigned int count = len;
-    PairValueRecord *record = CastP<PairValueRecord> (array);
+    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
     return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
                      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
   }
 
-  private:
+  protected:
   USHORT       len;                    /* Number of PairValueRecords */
-  USHORT       array[VAR];             /* Array of PairValueRecords--ordered
+  USHORT       arrayZ[VAR];            /* Array of PairValueRecords--ordered
                                         * by GlyphID of the second glyph */
   public:
-  DEFINE_SIZE_ARRAY (2, array);
+  DEFINE_SIZE_ARRAY (2, arrayZ);
 };
 
 struct PairPosFormat1
 {
-  friend struct PairPos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+    unsigned int count = pairSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
+  }
 
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+    return this+coverage;
+  }
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+  inline bool apply (hb_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_RETURN (false);
 
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
@@ -643,7 +716,7 @@ struct PairPosFormat1
     return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -663,43 +736,62 @@ struct PairPosFormat1
 
 struct PairPosFormat2
 {
-  friend struct PairPos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    /* (this+coverage).add_coverage (c->input); // Don't need this. */
+
+    unsigned int count1 = class1Count;
+    const ClassDef &klass1 = this+classDef1;
+    for (unsigned int i = 0; i < count1; i++)
+      klass1.add_class (c->input, i);
+
+    unsigned int count2 = class2Count;
+    const ClassDef &klass2 = this+classDef2;
+    for (unsigned int i = 0; i < count2; i++)
+      klass2.add_class (c->input, i);
+  }
 
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+    return this+coverage;
+  }
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+  inline bool apply (hb_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_RETURN (false);
 
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int record_len = len1 + len2;
 
-    unsigned int klass1 = (this+classDef1) (c->buffer->cur().codepoint);
-    unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint);
+    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_RETURN (false);
 
     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
     valueFormat1.apply_value (c->font, c->direction, this,
-                             v, c->buffer->cur_pos());
+                             v, buffer->cur_pos());
     valueFormat2.apply_value (c->font, c->direction, this,
-                             v + len1, c->buffer->pos[skippy_iter.idx]);
+                             v + len1, buffer->pos[skippy_iter.idx]);
 
-    c->buffer->idx = skippy_iter.idx;
+    buffer->idx = skippy_iter.idx;
     if (len2)
-      c->buffer->idx++;
+      buffer->idx++;
 
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!(c->check_struct (this)
        && coverage.sanitize (c, this)
        && classDef1.sanitize (c, this)
@@ -715,7 +807,7 @@ struct PairPosFormat2
                         valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -747,30 +839,19 @@ struct PairPosFormat2
 
 struct PairPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    case 2: return TRACE_RETURN (c->dispatch (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
-    }
-  }
-
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   PairPosFormat1       format1;
@@ -783,12 +864,13 @@ struct EntryExitRecord
 {
   friend struct CursivePosFormat1;
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   }
 
-  private:
+  protected:
   OffsetTo<Anchor>
                entryAnchor;            /* Offset to EntryAnchor table--from
                                         * beginning of CursivePos
@@ -803,35 +885,43 @@ struct EntryExitRecord
 
 struct CursivePosFormat1
 {
-  friend struct CursivePos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
 
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
+    hb_buffer_t *buffer = c->buffer;
 
     /* We don't handle mark glyphs here. */
-    if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) return TRACE_RETURN (false);
+    if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
 
-    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
-    const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->cur().codepoint)];
+    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
     if (!this_record.exitAnchor) return TRACE_RETURN (false);
 
+    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+    skippy_iter.reset (buffer->idx, 1);
     if (!skippy_iter.next ()) return TRACE_RETURN (false);
 
-    const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)];
+    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
     if (!next_record.entryAnchor) return TRACE_RETURN (false);
 
-    unsigned int i = c->buffer->idx;
+    unsigned int i = buffer->idx;
     unsigned int j = skippy_iter.idx;
 
     hb_position_t entry_x, entry_y, exit_x, exit_y;
-    (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
-    (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
+    (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
+    (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
 
-    hb_glyph_position_t *pos = c->buffer->pos;
+    hb_glyph_position_t *pos = buffer->pos;
 
     hb_position_t d;
     /* Main-direction adjustment */
@@ -884,16 +974,17 @@ struct CursivePosFormat1
        pos[j].x_offset = exit_x - entry_x;
     }
 
-    c->buffer->idx = j;
+    buffer->idx = j;
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -907,28 +998,18 @@ struct CursivePosFormat1
 
 struct CursivePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
-    }
-  }
-
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   CursivePosFormat1    format1;
@@ -943,36 +1024,53 @@ typedef AnchorMatrix BaseArray;          /* base-major--
 
 struct MarkBasePosFormat1
 {
-  friend struct MarkBasePos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (c->input);
+    (this+baseCoverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+markCoverage;
+  }
 
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
+    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_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
-    unsigned int property;
-    hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
-
-    /* The following assertion is too strong, so we've disabled it. */
-    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
-
-    unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint);
+    hb_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_RETURN (false);
+      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
+      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
+      skippy_iter.reject ();
+    } while (1);
+
+    /* 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_RETURN (false);*/ }
+
+    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
     if (base_index == NOT_COVERED) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
                         markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                markCoverage;           /* Offset to MarkCoverage table--from
@@ -993,28 +1091,18 @@ struct MarkBasePosFormat1
 
 struct MarkBasePos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   MarkBasePosFormat1   format1;
@@ -1034,25 +1122,36 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
 
 struct MarkLigPosFormat1
 {
-  friend struct MarkLigPos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+markCoverage).add_coverage (c->input);
+    (this+ligatureCoverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+markCoverage;
+  }
 
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
+    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_RETURN (false);
 
     /* now we search backwards for a non-mark glyph */
-    unsigned int property;
-    hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
+    hb_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_RETURN (false);
 
-    /* The following assertion is too strong, so we've disabled it. */
-    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) {/*return TRACE_RETURN (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_RETURN (false);*/ }
 
     unsigned int j = skippy_iter.idx;
-    unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
+    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
     if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
 
     const LigatureArray& lig_array = this+ligatureArray;
@@ -1062,32 +1161,30 @@ struct MarkLigPosFormat1
     unsigned int comp_count = lig_attach.rows;
     if (unlikely (!comp_count)) return TRACE_RETURN (false);
 
-    unsigned int comp_index;
     /* 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. */
-    if (get_lig_id (c->buffer->info[j]) &&
-       get_lig_id (c->buffer->cur()) &&
-       get_lig_comp (c->buffer->cur()) > 0)
-    {
-      comp_index = get_lig_comp (c->buffer->cur()) - 1;
-      if (comp_index >= comp_count)
-       comp_index = comp_count - 1;
-    }
+    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 = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
     else
       comp_index = comp_count - 1;
 
     return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
                         markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                markCoverage;           /* Offset to Mark Coverage table--from
@@ -1109,28 +1206,18 @@ struct MarkLigPosFormat1
 
 struct MarkLigPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   MarkLigPosFormat1    format1;
@@ -1145,46 +1232,71 @@ typedef AnchorMatrix Mark2Array;        /* mark2-major--
 
 struct MarkMarkPosFormat1
 {
-  friend struct MarkMarkPos;
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+mark1Coverage).add_coverage (c->input);
+    (this+mark2Coverage).add_coverage (c->input);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+mark1Coverage;
+  }
 
-  private:
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int mark1_index = (this+mark1Coverage) (c->buffer->cur().codepoint);
+    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_RETURN (false);
 
     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
-    unsigned int property;
-    hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
-    if (!skippy_iter.prev (&property)) return TRACE_RETURN (false);
+    hb_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_RETURN (false);
 
-    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return TRACE_RETURN (false);
+    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
 
     unsigned int j = skippy_iter.idx;
 
-    /* Two marks match only if they belong to the same base, or same component
-     * of the same ligature.  That is, the component numbers must match, and
-     * if those are non-zero, the ligid number should also match. */
-    if ((get_lig_comp (c->buffer->cur())) ||
-       (get_lig_comp (c->buffer->info[j]) > 0 &&
-        get_lig_id (c->buffer->cur())))
-      return TRACE_RETURN (false);
+    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_RETURN (false);
 
-    unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
+    good:
+    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
     if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
                         mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
                         && mark2Array.sanitize (c, this, (unsigned int) classCount));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                mark1Coverage;          /* Offset to Combining Mark1 Coverage
@@ -1207,28 +1319,18 @@ struct MarkMarkPosFormat1
 
 struct MarkMarkPos
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
-    }
-  }
-
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   MarkMarkPosFormat1   format1;
@@ -1236,48 +1338,13 @@ struct MarkMarkPos
 };
 
 
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-
-struct ContextPos : Context
-{
-  friend struct PosLookupSubTable;
+struct ContextPos : Context {};
 
-  private:
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (Context::apply (c, position_lookup));
-  }
-};
+struct ChainContextPos : ChainContext {};
 
-struct ChainContextPos : ChainContext
+struct ExtensionPos : Extension<ExtensionPos>
 {
-  friend struct PosLookupSubTable;
-
-  private:
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (ChainContext::apply (c, position_lookup));
-  }
-};
-
-
-struct ExtensionPos : Extension
-{
-  friend struct PosLookupSubTable;
-
-  private:
-  inline const struct PosLookupSubTable& get_subtable (void) const
-  {
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return Null(PosLookupSubTable);
-    return StructAtOffset<PosLookupSubTable> (this, offset);
-  }
-
-  inline bool apply (hb_apply_context_t *c) const;
-
-  inline bool sanitize (hb_sanitize_context_t *c);
+  typedef struct PosLookupSubTable LookupSubTable;
 };
 
 
@@ -1303,40 +1370,27 @@ struct PosLookupSubTable
     Extension          = 9
   };
 
-  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
   {
-    TRACE_APPLY ();
-    switch (lookup_type) {
-    case Single:               return TRACE_RETURN (u.single.apply (c));
-    case Pair:                 return TRACE_RETURN (u.pair.apply (c));
-    case Cursive:              return TRACE_RETURN (u.cursive.apply (c));
-    case MarkBase:             return TRACE_RETURN (u.markBase.apply (c));
-    case MarkLig:              return TRACE_RETURN (u.markLig.apply (c));
-    case MarkMark:             return TRACE_RETURN (u.markMark.apply (c));
-    case Context:              return TRACE_RETURN (u.c.apply (c));
-    case ChainContext:         return TRACE_RETURN (u.chainContext.apply (c));
-    case Extension:            return TRACE_RETURN (u.extension.apply (c));
-    default:                   return TRACE_RETURN (false);
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE ();
+    TRACE_DISPATCH (this, lookup_type);
+    /* The sub_format passed to may_dispatch is unnecessary but harmless. */
+    if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
     switch (lookup_type) {
-    case Single:               return TRACE_RETURN (u.single.sanitize (c));
-    case Pair:                 return TRACE_RETURN (u.pair.sanitize (c));
-    case Cursive:              return TRACE_RETURN (u.cursive.sanitize (c));
-    case MarkBase:             return TRACE_RETURN (u.markBase.sanitize (c));
-    case MarkLig:              return TRACE_RETURN (u.markLig.sanitize (c));
-    case MarkMark:             return TRACE_RETURN (u.markMark.sanitize (c));
-    case Context:              return TRACE_RETURN (u.c.sanitize (c));
-    case ChainContext:         return TRACE_RETURN (u.chainContext.sanitize (c));
-    case Extension:            return TRACE_RETURN (u.extension.sanitize (c));
-    default:                   return TRACE_RETURN (true);
+    case Single:               return TRACE_RETURN (u.single.dispatch (c));
+    case Pair:                 return TRACE_RETURN (u.pair.dispatch (c));
+    case Cursive:              return TRACE_RETURN (u.cursive.dispatch (c));
+    case MarkBase:             return TRACE_RETURN (u.markBase.dispatch (c));
+    case MarkLig:              return TRACE_RETURN (u.markLig.dispatch (c));
+    case MarkMark:             return TRACE_RETURN (u.markMark.dispatch (c));
+    case Context:              return TRACE_RETURN (u.context.dispatch (c));
+    case ChainContext:         return TRACE_RETURN (u.chainContext.dispatch (c));
+    case Extension:            return TRACE_RETURN (u.extension.dispatch (c));
+    default:                   return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               sub_format;
   SinglePos            single;
@@ -1345,7 +1399,7 @@ struct PosLookupSubTable
   MarkBasePos          markBase;
   MarkLigPos           markLig;
   MarkMarkPos          markMark;
-  ContextPos           c;
+  ContextPos           context;
   ChainContextPos      chainContext;
   ExtensionPos         extension;
   } u;
@@ -1357,48 +1411,47 @@ struct PosLookupSubTable
 struct PosLookup : Lookup
 {
   inline const PosLookupSubTable& get_subtable (unsigned int i) const
-  { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
+  { return Lookup::get_subtable<PosLookupSubTable> (i); }
 
-  inline bool apply_once (hb_apply_context_t *c) const
+  inline bool is_reverse (void) const
   {
-    unsigned int lookup_type = get_type ();
-
-    if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property))
-      return false;
-
-    for (unsigned int i = 0; i < get_subtable_count (); i++)
-      if (get_subtable (i).apply (c, lookup_type))
-       return true;
-
     return false;
   }
 
-  inline bool apply_string (hb_apply_context_t *c) const
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    return TRACE_RETURN (dispatch (c));
+  }
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    bool ret = false;
+    TRACE_COLLECT_GLYPHS (this);
+    return TRACE_RETURN (dispatch (c));
+  }
 
-    if (unlikely (!c->buffer->len))
-      return false;
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const
+  {
+    hb_add_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
 
-    c->set_lookup (*this);
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
 
-    c->buffer->idx = 0;
-    while (c->buffer->idx < c->buffer->len)
-    {
-      if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
-       ret = true;
-      else
-       c->buffer->idx++;
-    }
+  template <typename context_t>
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-    return ret;
-  }
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  { return Lookup::dispatch<PosLookupSubTable> (c); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
-    OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
-    return TRACE_RETURN (list.sanitize (c, this, get_type ()));
+    const OffsetArrayOf<PosLookupSubTable> &list = get_subtables<PosLookupSubTable> ();
+    return TRACE_RETURN (dispatch (c));
   }
 };
 
@@ -1410,21 +1463,19 @@ typedef OffsetListOf<PosLookup> PosLookupList;
 
 struct GPOS : GSUBGPOS
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_GPOS;
+  static const hb_tag_t tableTag       = HB_OT_TAG_GPOS;
 
   inline const PosLookup& get_lookup (unsigned int i) const
   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
 
-  inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
-  { return get_lookup (lookup_index).apply_string (c); }
+  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-  static inline void position_start (hb_buffer_t *buffer);
-  static inline void position_finish (hb_buffer_t *buffer);
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
-    OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
+    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
     return TRACE_RETURN (list.sanitize (c, this));
   }
   public:
@@ -1435,20 +1486,20 @@ struct GPOS : GSUBGPOS
 static void
 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
 {
-    unsigned int j = pos[i].cursive_chain();
-    if (likely (!j))
-      return;
+  unsigned int j = pos[i].cursive_chain();
+  if (likely (!j))
+    return;
 
-    j += i;
+  j += i;
 
-    pos[i].cursive_chain() = 0;
+  pos[i].cursive_chain() = 0;
 
-    fix_cursive_minor_offset (pos, j, direction);
+  fix_cursive_minor_offset (pos, j, direction);
 
-    if (HB_DIRECTION_IS_HORIZONTAL (direction))
-      pos[i].y_offset += pos[j].y_offset;
-    else
-      pos[i].x_offset += pos[j].x_offset;
+  if (HB_DIRECTION_IS_HORIZONTAL (direction))
+    pos[i].y_offset += pos[j].y_offset;
+  else
+    pos[i].x_offset += pos[j].x_offset;
 }
 
 static void
@@ -1459,8 +1510,6 @@ fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t di
 
   unsigned int j = i - pos[i].attach_lookback();
 
-  pos[i].x_advance = 0;
-  pos[i].y_advance = 0;
   pos[i].x_offset += pos[j].x_offset;
   pos[i].y_offset += pos[j].y_offset;
 
@@ -1477,7 +1526,7 @@ fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t di
 }
 
 void
-GPOS::position_start (hb_buffer_t *buffer)
+GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
 {
   buffer->clear_positions ();
 
@@ -1487,8 +1536,10 @@ GPOS::position_start (hb_buffer_t *buffer)
 }
 
 void
-GPOS::position_finish (hb_buffer_t *buffer)
+GPOS::position_finish (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;
@@ -1500,42 +1551,28 @@ GPOS::position_finish (hb_buffer_t *buffer)
   /* Handle attachments */
   for (unsigned int i = 0; i < len; i++)
     fix_mark_attachment (pos, i, direction);
-
-  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
-  HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
-  HB_BUFFER_DEALLOCATE_VAR (buffer, props_cache);
 }
 
 
 /* Out-of-class implementation for methods recursing */
 
-inline bool ExtensionPos::apply (hb_apply_context_t *c) const
+template <typename context_t>
+/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
-  TRACE_APPLY ();
-  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
-inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
-{
-  TRACE_SANITIZE ();
-  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
-  unsigned int offset = get_offset ();
-  if (unlikely (!offset)) return TRACE_RETURN (true);
-  return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()));
+  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
+  const PosLookup &l = gpos.get_lookup (lookup_index);
+  return l.dispatch (c);
 }
 
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
-  const GPOS &gpos = *(c->face->ot_layout->gpos);
+  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
   const PosLookup &l = gpos.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return false;
-
-  hb_apply_context_t new_c (*c);
-  new_c.nesting_level_left--;
-  new_c.set_lookup (l);
-  return l.apply_once (&new_c);
+  unsigned int saved_lookup_props = c->lookup_props;
+  c->set_lookup (l);
+  bool ret = l.dispatch (c);
+  c->set_lookup_props (saved_lookup_props);
+  return ret;
 }
 
 
@@ -1543,5 +1580,7 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i
 #undef cursive_chain
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
index f6a7575..ebe4c9e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
- * Copyright © 2010,2012  Google, Inc.
+ * Copyright © 2010,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 #include "hb-ot-layout-gsubgpos-private.hh"
 
 
+namespace OT {
+
 
 struct SingleSubstFormat1
 {
-  friend struct SingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       hb_codepoint_t glyph_id = iter.get_glyph ();
       if (c->glyphs->has (glyph_id))
-       c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
+       c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
+    }
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      hb_codepoint_t glyph_id = iter.get_glyph ();
+      c->input->add (glyph_id);
+      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
     }
   }
 
-  inline bool would_apply (hb_codepoint_t glyph_id) const
+  inline const Coverage &get_coverage (void) const
   {
-    return (this+coverage) (glyph_id) != NOT_COVERED;
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     /* According to the Adobe Annotated OpenType Suite, result is always
      * limited to 16bit. */
-    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
+    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
     c->replace_glyph (glyph_id);
 
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        unsigned int num_glyphs,
+                        int delta)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -88,13 +116,9 @@ struct SingleSubstFormat1
 
 struct SingleSubstFormat2
 {
-  friend struct SingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
@@ -102,16 +126,32 @@ struct SingleSubstFormat2
     }
   }
 
-  inline bool would_apply (hb_codepoint_t glyph_id) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    return (this+coverage) (glyph_id) != NOT_COVERED;
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      c->output->add (substitute[iter.get_coverage ()]);
+    }
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
@@ -122,12 +162,25 @@ struct SingleSubstFormat2
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        Supplier<GlyphID> &substitutes,
+                        unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -141,50 +194,46 @@ struct SingleSubstFormat2
 
 struct SingleSubst
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        Supplier<GlyphID> &substitutes,
+                        unsigned int num_glyphs)
   {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    case 2: u.format2.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline bool would_apply (hb_codepoint_t glyph_id) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (glyph_id);
-    case 2: return u.format2.would_apply (glyph_id);
-    default:return false;
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    unsigned int format = 2;
+    int delta = 0;
+    if (num_glyphs) {
+      format = 1;
+      /* TODO(serialize) check for wrap-around */
+      delta = substitutes[0] - glyphs[0];
+      for (unsigned int i = 1; i < num_glyphs; i++)
+       if (delta != substitutes[i] - glyphs[i]) {
+         format = 2;
+         break;
+       }
     }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
+    u.format.set (format);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    case 2: return TRACE_RETURN (u.format2.apply (c));
+    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
+    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
     default:return TRACE_RETURN (false);
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    case 2: return TRACE_RETURN (c->dispatch (u.format2));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   SingleSubstFormat1   format1;
@@ -195,36 +244,74 @@ struct SingleSubst
 
 struct Sequence
 {
-  friend struct MultipleSubstFormat1;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int count = substitute.len;
     for (unsigned int i = 0; i < count; i++)
       c->glyphs->add (substitute[i]);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int count = substitute.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->output->add (substitute[i]);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    if (unlikely (!substitute.len)) return TRACE_RETURN (false);
+    TRACE_APPLY (this);
+    unsigned int count = substitute.len;
 
-    unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0;
-    c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array, klass);
+    /* TODO:
+     * Testing shows that Uniscribe actually allows zero-len susbstitute,
+     * which essentially deletes a glyph.  We don't allow for now.  It
+     * can be confusing to the client since the cluster from the deleted
+     * glyph won't be merged with any output cluster...  Also, currently
+     * buffer->move_to() makes assumptions about this too.  Perhaps fix
+     * in the future after figuring out what to do with the clusters.
+     */
+    if (unlikely (!count)) return TRACE_RETURN (false);
+
+    /* Special-case to make it in-place and not consider this
+     * as a "multiplied" substitution. */
+    if (unlikely (count == 1))
+    {
+      c->replace_glyph (substitute.array[0]);
+      return TRACE_RETURN (true);
+    }
+
+    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+                        HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+
+    for (unsigned int i = 0; i < count; i++) {
+      _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+      c->output_glyph_for_component (substitute.array[i], klass);
+    }
+    c->buffer->skip_glyph ();
 
     return TRACE_RETURN (true);
   }
 
-  public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (substitute.sanitize (c));
   }
 
-  private:
+  protected:
   ArrayOf<GlyphID>
                substitute;             /* String of GlyphIDs to substitute */
   public:
@@ -233,13 +320,9 @@ struct Sequence
 
 struct MultipleSubstFormat1
 {
-  friend struct MultipleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
@@ -247,27 +330,61 @@ struct MultipleSubstFormat1
     }
   }
 
-  inline bool would_apply (hb_codepoint_t glyph_id) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    return (this+coverage) (glyph_id) != NOT_COVERED;
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+    unsigned int count = sequence.len;
+    for (unsigned int i = 0; i < count; i++)
+       (this+sequence[i]).collect_glyphs (c);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     return TRACE_RETURN ((this+sequence[index]).apply (c));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        Supplier<unsigned int> &substitute_len_list,
+                        unsigned int num_glyphs,
+                        Supplier<GlyphID> &substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
+    for (unsigned int i = 0; i < num_glyphs; i++)
+      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
+                                                               substitute_glyphs_list,
+                                                               substitute_len_list[i]))) return TRACE_RETURN (false);
+    substitute_len_list.advance (num_glyphs);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -281,46 +398,34 @@ struct MultipleSubstFormat1
 
 struct MultipleSubst
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        Supplier<unsigned int> &substitute_len_list,
+                        unsigned int num_glyphs,
+                        Supplier<GlyphID> &substitute_glyphs_list)
   {
-    TRACE_CLOSURE ();
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    unsigned int format = 1;
+    u.format.set (format);
     switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline bool would_apply (hb_codepoint_t glyph_id) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (glyph_id);
-    default:return false;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
+    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
     default:return TRACE_RETURN (false);
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   MultipleSubstFormat1 format1;
@@ -333,13 +438,9 @@ typedef ArrayOf<GlyphID> AlternateSet;     /* Array of alternate GlyphIDs--in
 
 struct AlternateSubstFormat1
 {
-  friend struct AlternateSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ())) {
@@ -351,17 +452,36 @@ struct AlternateSubstFormat1
     }
   }
 
-  inline bool would_apply (hb_codepoint_t glyph_id) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    return (this+coverage) (glyph_id) != NOT_COVERED;
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
+      unsigned int count = alt_set.len;
+      for (unsigned int i = 0; i < count; i++)
+       c->output->add (alt_set[i]);
+    }
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const AlternateSet &alt_set = this+alternateSet[index];
@@ -384,12 +504,31 @@ struct AlternateSubstFormat1
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        Supplier<unsigned int> &alternate_len_list,
+                        unsigned int num_glyphs,
+                        Supplier<GlyphID> &alternate_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
+    for (unsigned int i = 0; i < num_glyphs; i++)
+      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
+                                                                   alternate_glyphs_list,
+                                                                   alternate_len_list[i]))) return TRACE_RETURN (false);
+    alternate_len_list.advance (num_glyphs);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -403,46 +542,34 @@ struct AlternateSubstFormat1
 
 struct AlternateSubst
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline bool would_apply (hb_codepoint_t glyph_id) const
-  {
-    switch (u.format) {
-    case 1: return u.format1.would_apply (glyph_id);
-    default:return false;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        Supplier<unsigned int> &alternate_len_list,
+                        unsigned int num_glyphs,
+                        Supplier<GlyphID> &alternate_glyphs_list)
   {
-    TRACE_APPLY ();
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    unsigned int format = 1;
+    u.format.set (format);
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
+    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
     default:return TRACE_RETURN (false);
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   AlternateSubstFormat1        format1;
@@ -452,13 +579,9 @@ struct AlternateSubst
 
 struct Ligature
 {
-  friend struct LigatureSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int count = component.len;
     for (unsigned int i = 1; i < count; i++)
       if (!c->glyphs->has (component[i]))
@@ -466,78 +589,90 @@ struct Ligature
     c->glyphs->add (ligGlyph);
   }
 
-  inline bool would_apply (hb_codepoint_t second) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    return component.len == 2 && component[1] == second;
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int count = component.len;
+    for (unsigned int i = 1; i < count; i++)
+      c->input->add (component[i]);
+    c->output->add (ligGlyph);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool would_apply (hb_would_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int count = component.len;
-    if (unlikely (count < 2)) return TRACE_RETURN (false);
-
-    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
-    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+    TRACE_WOULD_APPLY (this);
+    if (c->len != component.len)
+      return TRACE_RETURN (false);
 
-    bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
-    bool found_non_mark = false;
+    for (unsigned int i = 1; i < c->len; i++)
+      if (likely (c->glyphs[i] != component[i]))
+       return TRACE_RETURN (false);
 
-    for (unsigned int i = 1; i < count; i++)
-    {
-      unsigned int property;
+    return TRACE_RETURN (true);
+  }
 
-      if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
+  inline bool apply (hb_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = component.len;
 
-      found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
+    if (unlikely (!count)) return TRACE_RETURN (false);
 
-      if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return TRACE_RETURN (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_RETURN (true);
     }
 
-    unsigned int klass = first_was_mark && found_non_mark ? HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE : 0;
-
-    /* Allocate new ligature id */
-    unsigned int lig_id = allocate_lig_id (c->buffer);
-    set_lig_props (c->buffer->cur(), lig_id, 0);
+    bool is_mark_ligature = false;
+    unsigned int total_component_count = 0;
 
-    if (skippy_iter.idx < c->buffer->idx + count) /* No input glyphs skipped */
-    {
-      c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph, klass);
-    }
-    else
-    {
-      c->replace_glyph (ligGlyph);
+    unsigned int match_length = 0;
+    unsigned int match_positions[MAX_CONTEXT_LENGTH];
 
-      /* Now we must do a second loop to copy the skipped glyphs to
-        `out' and assign component values to it.  We start with the
-        glyph after the first component.  Glyphs between component
-        i and i+1 belong to component i.  Together with the lig_id
-        value it is later possible to check whether a specific
-        component value really belongs to a given ligature. */
+    if (likely (!match_input (c, count,
+                             &component[1],
+                             match_glyph,
+                             NULL,
+                             &match_length,
+                             match_positions,
+                             &is_mark_ligature,
+                             &total_component_count)))
+      return TRACE_RETURN (false);
 
-      for (unsigned int i = 1; i < count; i++)
-      {
-       while (c->should_mark_skip_current_glyph ())
-       {
-         set_lig_props (c->buffer->cur(),  lig_id, i);
-         c->replace_glyph (c->buffer->cur().codepoint);
-       }
+    ligate_input (c,
+                 count,
+                 match_positions,
+                 match_length,
+                 ligGlyph,
+                 is_mark_ligature,
+                 total_component_count);
 
-       /* Skip the base glyph */
-       c->buffer->idx++;
-      }
-    }
+    return TRACE_RETURN (true);
+  }
 
+  inline bool serialize (hb_serialize_context_t *c,
+                        GlyphID ligature,
+                        Supplier<GlyphID> &components, /* Starting from second */
+                        unsigned int num_components /* Including first component */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    ligGlyph = ligature;
+    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
     return TRACE_RETURN (true);
   }
 
   public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
   }
 
-  private:
+  protected:
   GlyphID      ligGlyph;               /* GlyphID of ligature to substitute */
   HeadlessArrayOf<GlyphID>
                component;              /* Array of component GlyphIDs--start
@@ -549,33 +684,38 @@ struct Ligature
 
 struct LigatureSet
 {
-  friend struct LigatureSubstFormat1;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
       (this+ligature[i]).closure (c);
   }
 
-  inline bool would_apply (hb_codepoint_t second) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+      (this+ligature[i]).collect_glyphs (c);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
   {
+    TRACE_WOULD_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.would_apply (second))
-        return true;
+      if (lig.would_apply (c))
+        return TRACE_RETURN (true);
     }
-    return false;
+    return TRACE_RETURN (false);
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_ligs = ligature.len;
     for (unsigned int i = 0; i < num_ligs; i++)
     {
@@ -586,13 +726,32 @@ struct LigatureSet
     return TRACE_RETURN (false);
   }
 
-  public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &ligatures,
+                        Supplier<unsigned int> &component_count_list,
+                        unsigned int num_ligatures,
+                        Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
+    for (unsigned int i = 0; i < num_ligatures; i++)
+      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
+                                                               ligatures[i],
+                                                               component_list,
+                                                               component_count_list[i]))) return TRACE_RETURN (false);
+    ligatures.advance (num_ligatures);
+    component_count_list.advance (num_ligatures);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (ligature.sanitize (c, this));
   }
 
-  private:
+  protected:
   OffsetArrayOf<Ligature>
                ligature;               /* Array LigatureSet tables
                                         * ordered by preference */
@@ -602,13 +761,9 @@ struct LigatureSet
 
 struct LigatureSubstFormat1
 {
-  friend struct LigatureSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     Coverage::Iter iter;
     for (iter.init (this+coverage); iter.more (); iter.next ()) {
       if (c->glyphs->has (iter.get_glyph ()))
@@ -616,31 +771,72 @@ struct LigatureSubstFormat1
     }
   }
 
-  inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    unsigned int index;
-    return (index = (this+coverage) (first)) != NOT_COVERED &&
-          (this+ligatureSet[index]).would_apply (second);
+    TRACE_COLLECT_GLYPHS (this);
+    Coverage::Iter iter;
+    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+      c->input->add (iter.get_glyph ());
+      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
+    }
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+
+    const LigatureSet &lig_set = this+ligatureSet[index];
+    return TRACE_RETURN (lig_set.would_apply (c));
   }
 
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage) (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
     return TRACE_RETURN (lig_set.apply (c));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &first_glyphs,
+                        Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+                        unsigned int num_first_glyphs,
+                        Supplier<GlyphID> &ligatures_list,
+                        Supplier<unsigned int> &component_count_list,
+                        Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
+    for (unsigned int i = 0; i < num_first_glyphs; i++)
+      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
+                                                                  ligatures_list,
+                                                                  component_count_list,
+                                                                  ligature_per_first_glyph_count_list[i],
+                                                                  component_list))) return TRACE_RETURN (false);
+    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
+    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
+    return TRACE_RETURN (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -654,46 +850,37 @@ struct LigatureSubstFormat1
 
 struct LigatureSubst
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &first_glyphs,
+                        Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+                        unsigned int num_first_glyphs,
+                        Supplier<GlyphID> &ligatures_list,
+                        Supplier<unsigned int> &component_count_list,
+                        Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
   {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+    unsigned int format = 1;
+    u.format.set (format);
     switch (u.format) {
-    case 1: return u.format1.would_apply (first, second);
-    default:return false;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
+    case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
+                                                     ligatures_list, component_count_list, component_list));
     default:return TRACE_RETURN (false);
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   LigatureSubstFormat1 format1;
@@ -701,68 +888,13 @@ struct LigatureSubst
 };
 
 
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
-
-struct ContextSubst : Context
-{
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    return Context::closure (c, closure_lookup);
-  }
+struct ContextSubst : Context {};
 
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (Context::apply (c, substitute_lookup));
-  }
-};
+struct ChainContextSubst : ChainContext {};
 
-struct ChainContextSubst : ChainContext
+struct ExtensionSubst : Extension<ExtensionSubst>
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    return ChainContext::closure (c, closure_lookup);
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
-  {
-    TRACE_APPLY ();
-    return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
-  }
-};
-
-
-struct ExtensionSubst : Extension
-{
-  friend struct SubstLookupSubTable;
-  friend struct SubstLookup;
-
-  private:
-  inline const struct SubstLookupSubTable& get_subtable (void) const
-  {
-    unsigned int offset = get_offset ();
-    if (unlikely (!offset)) return Null(SubstLookupSubTable);
-    return StructAtOffset<SubstLookupSubTable> (this, offset);
-  }
-
-  inline void closure (hb_closure_context_t *c) const;
-  inline bool would_apply (hb_codepoint_t glyph_id) const;
-  inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const;
-
-  inline bool apply (hb_apply_context_t *c) const;
-
-  inline bool sanitize (hb_sanitize_context_t *c);
+  typedef struct SubstLookupSubTable LookupSubTable;
 
   inline bool is_reverse (void) const;
 };
@@ -770,13 +902,9 @@ struct ExtensionSubst : Extension
 
 struct ReverseChainSingleSubstFormat1
 {
-  friend struct ReverseChainSingleSubst;
-
-  private:
-
   inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     unsigned int count;
@@ -799,13 +927,48 @@ struct ReverseChainSingleSubstFormat1
     }
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    unsigned int count;
+
+    (this+coverage).add_coverage (c->input);
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+backtrack[i]).add_coverage (c->before);
+
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+lookahead[i]).add_coverage (c->after);
+
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    count = substitute.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->output->add (substitute[i]);
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+  }
+
   inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
       return TRACE_RETURN (false); /* No chaining to this type */
 
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -819,26 +982,29 @@ struct ReverseChainSingleSubstFormat1
                         match_coverage, this,
                         1))
     {
-      c->buffer->cur().codepoint = substitute[index];
-      c->buffer->idx--; /* Reverse! */
+      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_RETURN (true);
     }
 
     return TRACE_RETURN (false);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return TRACE_RETURN (false);
-    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!lookahead.sanitize (c, this))
       return TRACE_RETURN (false);
-    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     return TRACE_RETURN (substitute.sanitize (c));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -860,38 +1026,18 @@ struct ReverseChainSingleSubstFormat1
 
 struct ReverseChainSingleSubst
 {
-  friend struct SubstLookupSubTable;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c); break;
-    default:                       break;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c));
-    default:return TRACE_RETURN (false);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
-    }
-  }
-
-  private:
+  protected:
   union {
   USHORT                               format;         /* Format identifier */
   ReverseChainSingleSubstFormat1       format1;
@@ -919,84 +1065,33 @@ struct SubstLookupSubTable
     ReverseChainSingle = 8
   };
 
-  inline void closure (hb_closure_context_t *c,
-                      unsigned int    lookup_type) const
-  {
-    TRACE_CLOSURE ();
-    switch (lookup_type) {
-    case Single:               u.single.closure (c); break;
-    case Multiple:             u.multiple.closure (c); break;
-    case Alternate:            u.alternate.closure (c); break;
-    case Ligature:             u.ligature.closure (c); break;
-    case Context:              u.c.closure (c); break;
-    case ChainContext:         u.chainContext.closure (c); break;
-    case Extension:            u.extension.closure (c); break;
-    case ReverseChainSingle:   u.reverseChainContextSingle.closure (c); break;
-    default:                    break;
-    }
-  }
-
-  inline bool would_apply (hb_codepoint_t glyph_id,
-                          unsigned int lookup_type) const
-  {
-    switch (lookup_type) {
-    case Single:               return u.single.would_apply (glyph_id);
-    case Multiple:             return u.multiple.would_apply (glyph_id);
-    case Alternate:            return u.alternate.would_apply (glyph_id);
-    case Extension:            return u.extension.would_apply (glyph_id);
-    default:                   return false;
-    }
-  }
-  inline bool would_apply (hb_codepoint_t first,
-                          hb_codepoint_t second,
-                          unsigned int lookup_type) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
   {
+    TRACE_DISPATCH (this, lookup_type);
+    /* The sub_format passed to may_dispatch is unnecessary but harmless. */
+    if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
     switch (lookup_type) {
-    case Ligature:             return u.ligature.would_apply (first, second);
-    case Extension:            return u.extension.would_apply (first, second);
-    default:                   return false;
+    case Single:               return TRACE_RETURN (u.single.dispatch (c));
+    case Multiple:             return TRACE_RETURN (u.multiple.dispatch (c));
+    case Alternate:            return TRACE_RETURN (u.alternate.dispatch (c));
+    case Ligature:             return TRACE_RETURN (u.ligature.dispatch (c));
+    case Context:              return TRACE_RETURN (u.context.dispatch (c));
+    case ChainContext:         return TRACE_RETURN (u.chainContext.dispatch (c));
+    case Extension:            return TRACE_RETURN (u.extension.dispatch (c));
+    case ReverseChainSingle:   return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
+    default:                   return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
-  {
-    TRACE_APPLY ();
-    switch (lookup_type) {
-    case Single:               return TRACE_RETURN (u.single.apply (c));
-    case Multiple:             return TRACE_RETURN (u.multiple.apply (c));
-    case Alternate:            return TRACE_RETURN (u.alternate.apply (c));
-    case Ligature:             return TRACE_RETURN (u.ligature.apply (c));
-    case Context:              return TRACE_RETURN (u.c.apply (c));
-    case ChainContext:         return TRACE_RETURN (u.chainContext.apply (c));
-    case Extension:            return TRACE_RETURN (u.extension.apply (c));
-    case ReverseChainSingle:   return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
-    default:                   return TRACE_RETURN (false);
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
-    TRACE_SANITIZE ();
-    switch (lookup_type) {
-    case Single:               return TRACE_RETURN (u.single.sanitize (c));
-    case Multiple:             return TRACE_RETURN (u.multiple.sanitize (c));
-    case Alternate:            return TRACE_RETURN (u.alternate.sanitize (c));
-    case Ligature:             return TRACE_RETURN (u.ligature.sanitize (c));
-    case Context:              return TRACE_RETURN (u.c.sanitize (c));
-    case ChainContext:         return TRACE_RETURN (u.chainContext.sanitize (c));
-    case Extension:            return TRACE_RETURN (u.extension.sanitize (c));
-    case ReverseChainSingle:   return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
-    default:                   return TRACE_RETURN (true);
-    }
-  }
-
-  private:
+  protected:
   union {
   USHORT                       sub_format;
   SingleSubst                  single;
   MultipleSubst                        multiple;
   AlternateSubst               alternate;
   LigatureSubst                        ligature;
-  ContextSubst                 c;
+  ContextSubst                 context;
   ChainContextSubst            chainContext;
   ExtensionSubst               extension;
   ReverseChainSingleSubst      reverseChainContextSingle;
@@ -1009,7 +1104,7 @@ struct SubstLookupSubTable
 struct SubstLookup : Lookup
 {
   inline const SubstLookupSubTable& get_subtable (unsigned int i) const
-  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
+  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
 
   inline static bool lookup_type_is_reverse (unsigned int lookup_type)
   { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
@@ -1022,110 +1117,126 @@ struct SubstLookup : Lookup
     return lookup_type_is_reverse (type);
   }
 
-  inline void closure (hb_closure_context_t *c) const
+  inline bool apply (hb_apply_context_t *c) const
   {
-    unsigned int lookup_type = get_type ();
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      get_subtable (i).closure (c, lookup_type);
+    TRACE_APPLY (this);
+    return TRACE_RETURN (dispatch (c));
   }
 
-  inline bool would_apply (hb_codepoint_t glyph_id) const
+  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
   {
-    unsigned int lookup_type = get_type ();
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).would_apply (glyph_id, lookup_type))
-       return true;
-    return false;
+    TRACE_CLOSURE (this);
+    c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
+    return TRACE_RETURN (dispatch (c));
   }
-  inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
+
+  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
-    unsigned int lookup_type = get_type ();
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).would_apply (first, second, lookup_type))
-       return true;
-    return false;
+    TRACE_COLLECT_GLYPHS (this);
+    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
+    return TRACE_RETURN (dispatch (c));
   }
 
-  inline bool apply_once (hb_apply_context_t *c) const
+  template <typename set_t>
+  inline void add_coverage (set_t *glyphs) const
   {
-    unsigned int lookup_type = get_type ();
+    hb_add_coverage_context_t<set_t> c (glyphs);
+    dispatch (&c);
+  }
 
-    if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property))
-      return false;
+  inline bool would_apply (hb_would_apply_context_t *c,
+                          const hb_ot_layout_lookup_accelerator_t *accel) const
+  {
+    TRACE_WOULD_APPLY (this);
+    if (unlikely (!c->len))  return TRACE_RETURN (false);
+    if (!accel->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
+      return TRACE_RETURN (dispatch (c));
+  }
 
-    if (unlikely (lookup_type == SubstLookupSubTable::Extension))
-    {
-      /* The spec says all subtables should have the same type.
-       * This is specially important if one has a reverse type!
-       *
-       * This is rather slow to do this here for every glyph,
-       * but it's easiest, and who uses extension lookups anyway?!*/
-      unsigned int type = get_subtable(0).u.extension.get_type ();
-      unsigned int count = get_subtable_count ();
-      for (unsigned int i = 1; i < count; i++)
-        if (get_subtable(i).u.extension.get_type () != type)
-         return false;
-    }
+  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
 
-    unsigned int count = get_subtable_count ();
-    for (unsigned int i = 0; i < count; i++)
-      if (get_subtable (i).apply (c, lookup_type))
-       return true;
+  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
+                                                 unsigned int i)
+  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
 
-    return false;
+  inline bool serialize_single (hb_serialize_context_t *c,
+                               uint32_t lookup_props,
+                               Supplier<GlyphID> &glyphs,
+                               Supplier<GlyphID> &substitutes,
+                               unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
+    return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
   }
 
-  inline bool apply_string (hb_apply_context_t *c) const
+  inline bool serialize_multiple (hb_serialize_context_t *c,
+                                 uint32_t lookup_props,
+                                 Supplier<GlyphID> &glyphs,
+                                 Supplier<unsigned int> &substitute_len_list,
+                                 unsigned int num_glyphs,
+                                 Supplier<GlyphID> &substitute_glyphs_list)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
+    return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
+                                                                        substitute_glyphs_list));
+  }
+
+  inline bool serialize_alternate (hb_serialize_context_t *c,
+                                  uint32_t lookup_props,
+                                  Supplier<GlyphID> &glyphs,
+                                  Supplier<unsigned int> &alternate_len_list,
+                                  unsigned int num_glyphs,
+                                  Supplier<GlyphID> &alternate_glyphs_list)
   {
-    bool ret = false;
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
+    return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
+                                                                         alternate_glyphs_list));
+  }
+
+  inline bool serialize_ligature (hb_serialize_context_t *c,
+                                 uint32_t lookup_props,
+                                 Supplier<GlyphID> &first_glyphs,
+                                 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+                                 unsigned int num_first_glyphs,
+                                 Supplier<GlyphID> &ligatures_list,
+                                 Supplier<unsigned int> &component_count_list,
+                                 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
+    return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
+                                                                        ligatures_list, component_count_list, component_list));
+  }
 
-    if (unlikely (!c->buffer->len))
-      return false;
+  template <typename context_t>
+  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-    c->set_lookup (*this);
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  { return Lookup::dispatch<SubstLookupSubTable> (c); }
 
-    if (likely (!is_reverse ()))
-    {
-       /* in/out forward substitution */
-       c->buffer->clear_output ();
-       c->buffer->idx = 0;
-       while (c->buffer->idx < c->buffer->len)
-       {
-         if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
-           ret = true;
-         else
-           c->buffer->next_glyph ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
+    const OffsetArrayOf<SubstLookupSubTable> &list = get_subtables<SubstLookupSubTable> ();
+    if (unlikely (!dispatch (c))) return TRACE_RETURN (false);
 
-       }
-       if (ret)
-         c->buffer->swap_buffers ();
-    }
-    else
+    if (unlikely (get_type () == SubstLookupSubTable::Extension))
     {
-       /* in-place backward substitution */
-       c->buffer->idx = c->buffer->len - 1;
-       do
-       {
-         if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
-           ret = true;
-         else
-           c->buffer->idx--;
-
-       }
-       while ((int) c->buffer->idx >= 0);
+      /* The spec says all subtables of an Extension lookup should
+       * have the same type.  This is specially important if one has
+       * a reverse type! */
+      unsigned int type = get_subtable (0).u.extension.get_type ();
+      unsigned int count = get_subtable_count ();
+      for (unsigned int i = 1; i < count; i++)
+        if (get_subtable (i).u.extension.get_type () != type)
+         return TRACE_RETURN (false);
     }
-
-    return ret;
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
-    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
-    return TRACE_RETURN (list.sanitize (c, this, get_type ()));
+    return TRACE_RETURN (true);
   }
 };
 
@@ -1137,25 +1248,19 @@ typedef OffsetListOf<SubstLookup> SubstLookupList;
 
 struct GSUB : GSUBGPOS
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_GSUB;
+  static const hb_tag_t tableTag       = HB_OT_TAG_GSUB;
 
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
-  inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
-  { return get_lookup (lookup_index).apply_string (c); }
-
-  static inline void substitute_start (hb_buffer_t *buffer);
-  static inline void substitute_finish (hb_buffer_t *buffer);
+  static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
+  static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
 
-  inline void closure_lookup (hb_closure_context_t *c,
-                             unsigned int          lookup_index) const
-  { return get_lookup (lookup_index).closure (c); }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
-    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
+    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
     return TRACE_RETURN (list.sanitize (c, this));
   }
   public:
@@ -1164,90 +1269,57 @@ struct GSUB : GSUBGPOS
 
 
 void
-GSUB::substitute_start (hb_buffer_t *buffer)
+GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
 {
-  HB_BUFFER_ALLOCATE_VAR (buffer, props_cache);
-  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
-  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
+  _hb_buffer_assert_gsubgpos_vars (buffer);
 
+  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
   unsigned int count = buffer->len;
   for (unsigned int i = 0; i < count; i++)
-    buffer->info[i].props_cache() = buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
+  {
+    _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;
+  }
 }
 
 void
-GSUB::substitute_finish (hb_buffer_t *buffer HB_UNUSED)
+GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
 {
 }
 
 
 /* Out-of-class implementation for methods recursing */
 
-inline void ExtensionSubst::closure (hb_closure_context_t *c) const
-{
-  get_subtable ().closure (c, get_type ());
-}
-
-inline bool ExtensionSubst::would_apply (hb_codepoint_t glyph_id) const
-{
-  return get_subtable ().would_apply (glyph_id, get_type ());
-}
-
-inline bool ExtensionSubst::would_apply (hb_codepoint_t first, hb_codepoint_t second) const
-{
-  return get_subtable ().would_apply (first, second, get_type ());
-}
-
-inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
-{
-  TRACE_APPLY ();
-  return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
-inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
-{
-  TRACE_SANITIZE ();
-  if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
-  unsigned int offset = get_offset ();
-  if (unlikely (!offset)) return TRACE_RETURN (true);
-  return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
-}
-
-inline bool ExtensionSubst::is_reverse (void) const
+/*static*/ inline bool ExtensionSubst::is_reverse (void) const
 {
   unsigned int type = get_type ();
   if (unlikely (type == SubstLookupSubTable::Extension))
-    return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
+    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
   return SubstLookup::lookup_type_is_reverse (type);
 }
 
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
+template <typename context_t>
+/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
 {
-  const GSUB &gsub = *(c->face->ot_layout->gsub);
+  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return;
-
-  c->nesting_level_left--;
-  l.closure (c);
-  c->nesting_level_left++;
+  return l.dispatch (c);
 }
 
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
 {
-  const GSUB &gsub = *(c->face->ot_layout->gsub);
+  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);
-
-  if (unlikely (c->nesting_level_left == 0))
-    return false;
-
-  hb_apply_context_t new_c (*c);
-  new_c.nesting_level_left--;
-  new_c.set_lookup (l);
-  return l.apply_once (&new_c);
+  unsigned int saved_lookup_props = c->lookup_props;
+  c->set_lookup (l);
+  bool ret = l.dispatch (c);
+  c->set_lookup_props (saved_lookup_props);
+  return ret;
 }
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
index 12cb694..cbc6840 100644 (file)
 
 #include "hb-buffer-private.hh"
 #include "hb-ot-layout-gdef-table.hh"
+#include "hb-set-private.hh"
 
 
-
-/* unique ligature id */
-/* component number in the ligature (0 = base) */
-static inline void
-set_lig_props (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp)
-{
-  info.lig_props() = (lig_id << 4) | (lig_comp & 0x0F);
-}
-static inline unsigned int
-get_lig_id (hb_glyph_info_t &info)
-{
-  return info.lig_props() >> 4;
-}
-static inline unsigned int
-get_lig_comp (hb_glyph_info_t &info)
-{
-  return info.lig_props() & 0x0F;
-}
-
-static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
-  uint8_t lig_id = buffer->next_serial () & 0x0F;
-  if (unlikely (!lig_id))
-    lig_id = allocate_lig_id (buffer); /* in case of overflow */
-  return lig_id;
-}
-
+namespace OT {
 
 
 #ifndef HB_DEBUG_CLOSURE
 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
 #endif
 
-#define TRACE_CLOSURE() \
-       hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
-
-
-/* TODO Add TRACE_RETURN annotation for would_apply */
-
+#define TRACE_CLOSURE(this) \
+       hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
+       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+        "");
 
 struct hb_closure_context_t
 {
+  inline const char *get_name (void) { return "CLOSURE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
+  typedef hb_void_t return_t;
+  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return HB_VOID;
+  }
+
   hb_face_t *face;
   hb_set_t *glyphs;
+  recurse_func_t recurse_func;
   unsigned int nesting_level_left;
   unsigned int debug_depth;
 
-
   hb_closure_context_t (hb_face_t *face_,
                        hb_set_t *glyphs_,
                        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
-                         face (face_), glyphs (glyphs_),
+                         face (face_),
+                         glyphs (glyphs_),
+                         recurse_func (NULL),
                          nesting_level_left (nesting_level_left_),
                          debug_depth (0) {}
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
 
-#ifndef HB_DEBUG_APPLY
-#define HB_DEBUG_APPLY (HB_DEBUG+0)
+#ifndef HB_DEBUG_WOULD_APPLY
+#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
 #endif
 
-#define TRACE_APPLY() \
-       hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->cur().codepoint);
+#define TRACE_WOULD_APPLY(this) \
+       hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
+       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+        "%d glyphs", c->len);
 
+struct hb_would_apply_context_t
+{
+  inline const char *get_name (void) { return "WOULD_APPLY"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
+  typedef bool return_t;
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
 
+  hb_face_t *face;
+  const hb_codepoint_t *glyphs;
+  unsigned int len;
+  bool zero_context;
+  unsigned int debug_depth;
 
-struct hb_apply_context_t
+  hb_would_apply_context_t (hb_face_t *face_,
+                           const hb_codepoint_t *glyphs_,
+                           unsigned int len_,
+                           bool zero_context_) :
+                             face (face_),
+                             glyphs (glyphs_),
+                             len (len_),
+                             zero_context (zero_context_),
+                             debug_depth (0) {}
+};
+
+
+
+#ifndef HB_DEBUG_COLLECT_GLYPHS
+#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
+#endif
+
+#define TRACE_COLLECT_GLYPHS(this) \
+       hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
+       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+        "");
+
+struct hb_collect_glyphs_context_t
 {
-  hb_font_t *font;
+  inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
+  typedef hb_void_t return_t;
+  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
+  static return_t default_return_value (void) { return HB_VOID; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+  return_t recurse (unsigned int lookup_index)
+  {
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
+     * past the previous check.  For GSUB, we only want to collect the output
+     * glyphs in the recursion.  If output is not requested, we can go home now.
+     *
+     * Note further, that the above is not exactly correct.  A recursed lookup
+     * is allowed to match input that is not matched in the context, but that's
+     * not how most fonts are built.  It's possible to relax that and recurse
+     * with all sets here if it proves to be an issue.
+     */
+
+    if (output == hb_set_get_empty ())
+      return HB_VOID;
+
+    /* Return if new lookup was recursed to before. */
+    if (recursed_lookups.has (lookup_index))
+      return HB_VOID;
+
+    hb_set_t *old_before = before;
+    hb_set_t *old_input  = input;
+    hb_set_t *old_after  = after;
+    before = input = after = hb_set_get_empty ();
+
+    nesting_level_left--;
+    recurse_func (this, lookup_index);
+    nesting_level_left++;
+
+    before = old_before;
+    input  = old_input;
+    after  = old_after;
+
+    recursed_lookups.add (lookup_index);
+
+    return HB_VOID;
+  }
+
   hb_face_t *face;
-  hb_buffer_t *buffer;
-  hb_direction_t direction;
-  hb_mask_t lookup_mask;
+  hb_set_t *before;
+  hb_set_t *input;
+  hb_set_t *after;
+  hb_set_t *output;
+  recurse_func_t recurse_func;
+  hb_set_t recursed_lookups;
   unsigned int nesting_level_left;
-  unsigned int lookup_props;
-  unsigned int property; /* propety of first glyph */
   unsigned int debug_depth;
 
+  hb_collect_glyphs_context_t (hb_face_t *face_,
+                              hb_set_t  *glyphs_before, /* OUT. May be NULL */
+                              hb_set_t  *glyphs_input,  /* OUT. May be NULL */
+                              hb_set_t  *glyphs_after,  /* OUT. May be NULL */
+                              hb_set_t  *glyphs_output, /* OUT. May be NULL */
+                              unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+                             face (face_),
+                             before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
+                             input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
+                             after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
+                             output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
+                             recurse_func (NULL),
+                             recursed_lookups (),
+                             nesting_level_left (nesting_level_left_),
+                             debug_depth (0)
+  {
+    recursed_lookups.init ();
+  }
+  ~hb_collect_glyphs_context_t (void)
+  {
+    recursed_lookups.fini ();
+  }
+
+  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+};
 
-  hb_apply_context_t (hb_font_t *font_,
-                     hb_face_t *face_,
-                     hb_buffer_t *buffer_,
-                     hb_mask_t lookup_mask_) :
-                       font (font_), face (face_), buffer (buffer_),
-                       direction (buffer_->props.direction),
-                       lookup_mask (lookup_mask_),
-                       nesting_level_left (MAX_NESTING_LEVEL),
-                       lookup_props (0), property (0), debug_depth (0) {}
 
-  void set_lookup (const Lookup &l) {
-    lookup_props = l.get_props ();
+
+#ifndef HB_DEBUG_GET_COVERAGE
+#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
+#endif
+
+template <typename set_t>
+struct hb_add_coverage_context_t
+{
+  inline const char *get_name (void) { return "GET_COVERAGE"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE;
+  typedef const Coverage &return_t;
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
+  static return_t default_return_value (void) { return Null(Coverage); }
+  bool stop_sublookup_iteration (return_t r) const
+  {
+    r.add_coverage (set);
+    return false;
   }
 
-  struct mark_skipping_forward_iterator_t
+  hb_add_coverage_context_t (set_t *set_) :
+                           set (set_),
+                           debug_depth (0) {}
+
+  set_t *set;
+  unsigned int debug_depth;
+};
+
+
+
+#ifndef HB_DEBUG_APPLY
+#define HB_DEBUG_APPLY (HB_DEBUG+0)
+#endif
+
+#define TRACE_APPLY(this) \
+       hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
+       (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+        "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+
+struct hb_apply_context_t
+{
+  struct matcher_t
   {
-    inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
-                                            unsigned int start_index_,
-                                            unsigned int num_items_,
-                                            bool context_match = false)
-    {
-      c = c_;
-      idx = start_index_;
-      num_items = num_items_;
-      mask = context_match ? -1 : c->lookup_mask;
-      syllable = context_match ? 0 : c->buffer->cur().syllable ();
-      end = c->buffer->len;
-    }
-    inline bool has_no_chance (void) const
-    {
-      return unlikely (num_items && idx + num_items >= end);
-    }
-    inline bool next (unsigned int *property_out,
-                     unsigned int lookup_props)
+    inline matcher_t (void) :
+            lookup_props (0),
+            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
+            match_func (NULL),
+            match_data (NULL) {};
+
+    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+
+    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
+    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
+    inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+    inline void set_mask (hb_mask_t mask_) { mask = mask_; }
+    inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
+    inline void set_match_func (match_func_t match_func_,
+                               const void *match_data_)
+    { match_func = match_func_; match_data = match_data_; }
+
+    enum may_match_t {
+      MATCH_NO,
+      MATCH_YES,
+      MATCH_MAYBE
+    };
+
+    inline may_match_t may_match (const hb_glyph_info_t &info,
+                                 const USHORT          *glyph_data) const
     {
-      assert (num_items > 0);
-      do
-      {
-       if (has_no_chance ())
-         return false;
-       idx++;
-      } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out));
-      num_items--;
-      return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
+      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_MAYBE;
     }
-    inline bool next (unsigned int *property_out = NULL)
+
+    enum may_skip_t {
+      SKIP_NO,
+      SKIP_YES,
+      SKIP_MAYBE
+    };
+
+    inline may_skip_t
+    may_skip (const hb_apply_context_t *c,
+             const hb_glyph_info_t    &info) const
     {
-      return next (property_out, c->lookup_props);
+      if (!c->check_glyph_property (&info, lookup_props))
+       return SKIP_YES;
+
+      if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
+                   (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
+                   (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
+                   !_hb_glyph_info_ligated (&info)))
+       return SKIP_MAYBE;
+
+      return SKIP_NO;
     }
 
-    unsigned int idx;
-    private:
-    hb_apply_context_t *c;
-    unsigned int num_items;
+    protected:
+    unsigned int lookup_props;
+    bool ignore_zwnj;
+    bool ignore_zwj;
     hb_mask_t mask;
     uint8_t syllable;
-    unsigned int end;
+    match_func_t match_func;
+    const void *match_data;
   };
 
-  struct mark_skipping_backward_iterator_t
+  struct skipping_iterator_t
   {
-    inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_,
-                                             unsigned int start_index_,
-                                             unsigned int num_items_,
-                                             hb_mask_t mask_ = 0,
-                                             bool match_syllable_ = true)
+    inline void init (hb_apply_context_t *c_, bool context_match = false)
     {
       c = c_;
-      idx = start_index_;
-      num_items = num_items_;
-      mask = mask_ ? mask_ : c->lookup_mask;
-      syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
+      match_glyph_data = NULL,
+      matcher.set_match_func (NULL, NULL);
+      matcher.set_lookup_props (c->lookup_props);
+      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+      /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
+      matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
+      matcher.set_mask (context_match ? -1 : c->lookup_mask);
+    }
+    inline void set_lookup_props (unsigned int lookup_props)
+    {
+      matcher.set_lookup_props (lookup_props);
+    }
+    inline void set_match_func (matcher_t::match_func_t match_func,
+                               const void *match_data,
+                               const USHORT glyph_data[])
+    {
+      matcher.set_match_func (match_func, match_data);
+      match_glyph_data = glyph_data;
     }
-    inline bool has_no_chance (void) const
+
+    inline void reset (unsigned int start_index_,
+                      unsigned int num_items_)
     {
-      return unlikely (idx < num_items);
+      idx = start_index_;
+      num_items = num_items_;
+      end = c->buffer->len;
+      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
     }
-    inline bool prev (unsigned int *property_out,
-                     unsigned int lookup_props)
+
+    inline void reject (void) { num_items++; match_glyph_data--; }
+
+    inline bool next (void)
     {
       assert (num_items > 0);
-      do
+      while (idx + num_items < end)
       {
-       if (has_no_chance ())
+       idx++;
+       const 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);
+       if (match == matcher_t::MATCH_YES ||
+           (match == matcher_t::MATCH_MAYBE &&
+            skip == matcher_t::SKIP_NO))
+       {
+         num_items--;
+         match_glyph_data++;
+         return true;
+       }
+
+       if (skip == matcher_t::SKIP_NO)
          return false;
-       idx--;
-      } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out));
-      num_items--;
-      return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
+      }
+      return false;
     }
-    inline bool prev (unsigned int *property_out = NULL)
+    inline bool prev (void)
     {
-      return prev (property_out, c->lookup_props);
+      assert (num_items > 0);
+      while (idx >= num_items)
+      {
+       idx--;
+       const 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);
+       if (match == matcher_t::MATCH_YES ||
+           (match == matcher_t::MATCH_MAYBE &&
+            skip == matcher_t::SKIP_NO))
+       {
+         num_items--;
+         match_glyph_data++;
+         return true;
+       }
+
+       if (skip == matcher_t::SKIP_NO)
+         return false;
+      }
+      return false;
     }
 
     unsigned int idx;
-    private:
+    protected:
     hb_apply_context_t *c;
+    matcher_t matcher;
+    const USHORT *match_glyph_data;
+
     unsigned int num_items;
-    hb_mask_t mask;
-    uint8_t syllable;
+    unsigned int end;
   };
 
-  inline bool should_mark_skip_current_glyph (void) const
+
+  inline const char *get_name (void) { return "APPLY"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+  typedef bool return_t;
+  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.apply (this); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+  return_t recurse (unsigned int lookup_index)
   {
-    return _hb_ot_layout_skip_mark (face, &buffer->cur(), lookup_props, NULL);
+    if (unlikely (nesting_level_left == 0 || !recurse_func))
+      return default_return_value ();
+
+    nesting_level_left--;
+    bool ret = recurse_func (this, lookup_index);
+    nesting_level_left++;
+    return ret;
   }
 
+  unsigned int table_index; /* GSUB/GPOS */
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t *buffer;
+  hb_direction_t direction;
+  hb_mask_t lookup_mask;
+  bool auto_zwj;
+  recurse_func_t recurse_func;
+  unsigned int nesting_level_left;
+  unsigned int lookup_props;
+  const GDEF &gdef;
+  bool has_glyph_classes;
+  skipping_iterator_t iter_input, iter_context;
+  unsigned int debug_depth;
+
+
+  hb_apply_context_t (unsigned int table_index_,
+                     hb_font_t *font_,
+                     hb_buffer_t *buffer_) :
+                       table_index (table_index_),
+                       font (font_), face (font->face), buffer (buffer_),
+                       direction (buffer_->props.direction),
+                       lookup_mask (1),
+                       auto_zwj (true),
+                       recurse_func (NULL),
+                       nesting_level_left (MAX_NESTING_LEVEL),
+                       lookup_props (0),
+                       gdef (*hb_ot_layout_from_face (face)->gdef),
+                       has_glyph_classes (gdef.has_glyph_classes ()),
+                       iter_input (),
+                       iter_context (),
+                       debug_depth (0) {}
+
+  inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
+  inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
+  inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+  inline void set_lookup (const Lookup &l) { set_lookup_props (l.get_props ()); }
+  inline void set_lookup_props (unsigned int lookup_props_)
+  {
+    lookup_props = lookup_props_;
+    iter_input.init (this, false);
+    iter_context.init (this, true);
+  }
+
+  inline bool
+  match_properties_mark (hb_codepoint_t  glyph,
+                        unsigned int    glyph_props,
+                        unsigned int    lookup_props) const
+  {
+    /* If using mark filtering sets, the high short of
+     * lookup_props has the set index.
+     */
+    if (lookup_props & LookupFlag::UseMarkFilteringSet)
+      return gdef.mark_set_covers (lookup_props >> 16, glyph);
+
+    /* The second byte of lookup_props has the meaning
+     * "ignore marks of attachment type different than
+     * the attachment type specified."
+     */
+    if (lookup_props & LookupFlag::MarkAttachmentType)
+      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
+
+    return true;
+  }
+
+  inline bool
+  check_glyph_property (const hb_glyph_info_t *info,
+                       unsigned int  lookup_props) const
+  {
+    hb_codepoint_t glyph = info->codepoint;
+    unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
+
+    /* Not covered, if, for example, glyph class is ligature and
+     * lookup_props includes LookupFlags::IgnoreLigatures
+     */
+    if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
+      return false;
+
+    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
+      return match_properties_mark (glyph, glyph_props, lookup_props);
 
+    return true;
+  }
 
-  inline void replace_glyph (hb_codepoint_t glyph_index,
-                            unsigned int klass = 0) const
+  inline void _set_glyph_props (hb_codepoint_t glyph_index,
+                         unsigned int class_guess = 0,
+                         bool ligature = false,
+                         bool component = false) const
+  {
+    unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
+                         HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
+    add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
+    if (ligature)
+    {
+      add_in |= 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 substitions.  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;
+    }
+    if (component)
+      add_in |= 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));
+    else if (class_guess)
+      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
+  }
+
+  inline void replace_glyph (hb_codepoint_t glyph_index) const
+  {
+    _set_glyph_props (glyph_index);
+    buffer->replace_glyph (glyph_index);
+  }
+  inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
   {
-    buffer->cur().props_cache() = klass; /*XXX if has gdef? */
+    _set_glyph_props (glyph_index);
+    buffer->cur().codepoint = glyph_index;
+  }
+  inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
+                                          unsigned int class_guess) const
+  {
+    _set_glyph_props (glyph_index, class_guess, true);
     buffer->replace_glyph (glyph_index);
   }
-  inline void replace_glyphs_be16 (unsigned int num_in,
-                                  unsigned int num_out,
-                                  const uint16_t *glyph_data_be,
-                                  unsigned int klass = 0) const
+  inline void output_glyph_for_component (hb_codepoint_t glyph_index,
+                                         unsigned int class_guess) const
   {
-    buffer->cur().props_cache() = klass; /* XXX if has gdef? */
-    buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be);
+    _set_glyph_props (glyph_index, class_guess, false, true);
+    buffer->output_glyph (glyph_index);
   }
 };
 
 
 
 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
-typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
-typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
 
 struct ContextClosureFuncs
 {
   intersects_func_t intersects;
-  closure_lookup_func_t closure;
+};
+struct ContextCollectGlyphsFuncs
+{
+  collect_glyphs_func_t collect;
 };
 struct ContextApplyFuncs
 {
   match_func_t match;
-  apply_lookup_func_t apply;
 };
 
+
 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
@@ -284,48 +652,237 @@ static inline bool intersects_array (hb_closure_context_t *c,
 }
 
 
+static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+{
+  glyphs->add (value);
+}
+static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+  class_def.add_class (glyphs, value);
+}
+static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+  (data+coverage).add_coverage (glyphs);
+}
+static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
+                                 hb_set_t *glyphs,
+                                 unsigned int count,
+                                 const USHORT values[],
+                                 collect_glyphs_func_t collect_func,
+                                 const void *collect_data)
+{
+  for (unsigned int i = 0; i < count; i++)
+    collect_func (glyphs, values[i], collect_data);
+}
+
+
 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
 {
   return glyph_id == value;
 }
-
 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.get_class (glyph_id) == value;
 }
-
 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
 }
 
+static inline bool would_match_input (hb_would_apply_context_t *c,
+                                     unsigned int count, /* Including the first glyph (not matched) */
+                                     const USHORT input[], /* Array of input values--start with second glyph */
+                                     match_func_t match_func,
+                                     const void *match_data)
+{
+  if (count != c->len)
+    return false;
 
+  for (unsigned int i = 1; i < count; i++)
+    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
+      return false;
+
+  return true;
+}
 static inline bool match_input (hb_apply_context_t *c,
                                unsigned int count, /* Including the first glyph (not matched) */
                                const USHORT input[], /* Array of input values--start with second glyph */
                                match_func_t match_func,
                                const void *match_data,
-                               unsigned int *end_offset = NULL)
+                               unsigned int *end_offset,
+                               unsigned int match_positions[MAX_CONTEXT_LENGTH],
+                               bool *p_is_mark_ligature = NULL,
+                               unsigned int *p_total_component_count = NULL)
 {
-  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
-  if (skippy_iter.has_no_chance ())
-    return false;
+  TRACE_APPLY (NULL);
+
+  if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
+
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_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);
+
+  /*
+   * This is perhaps the trickiest part of OpenType...  Remarks:
+   *
+   * - If all components of the ligature were marks, we call this a mark ligature.
+   *
+   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
+   *   it as a ligature glyph.
+   *
+   * - Ligatures cannot be formed across glyphs attached to different components
+   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
+   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
+   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
+   *   There is an exception to this: If a ligature tries ligating with marks that
+   *   belong to it itself, go ahead, assuming that the font designer knows what
+   *   they are doing (otherwise it can break Indic stuff when a matra wants to
+   *   ligate with a conjunct...)
+   */
+
+  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
+
+  unsigned int total_component_count = 0;
+  total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+
+  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
 
+  match_positions[0] = buffer->idx;
   for (unsigned int i = 1; i < count; i++)
   {
-    if (!skippy_iter.next ())
-      return false;
+    if (!skippy_iter.next ()) return TRACE_RETURN (false);
+
+    match_positions[i] = skippy_iter.idx;
+
+    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
+    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
+
+    if (first_lig_id && first_lig_comp) {
+      /* If first component was attached to a previous ligature component,
+       * all subsequent components should be attached to the same ligature
+       * component, otherwise we shouldn't ligate them. */
+      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
+       return TRACE_RETURN (false);
+    } else {
+      /* If first component was NOT attached to a previous ligature component,
+       * all subsequent components should also NOT be attached to any ligature
+       * component, unless they are attached to the first component itself! */
+      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
+       return TRACE_RETURN (false);
+    }
 
-    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data)))
-      return false;
+    is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
+    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
   }
 
-  if (end_offset)
-    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
+  *end_offset = skippy_iter.idx - buffer->idx + 1;
 
-  return true;
+  if (p_is_mark_ligature)
+    *p_is_mark_ligature = is_mark_ligature;
+
+  if (p_total_component_count)
+    *p_total_component_count = total_component_count;
+
+  return TRACE_RETURN (true);
+}
+static inline void ligate_input (hb_apply_context_t *c,
+                                unsigned int count, /* Including the first glyph */
+                                unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+                                unsigned int match_length,
+                                hb_codepoint_t lig_glyph,
+                                bool is_mark_ligature,
+                                unsigned int total_component_count)
+{
+  TRACE_APPLY (NULL);
+
+  hb_buffer_t *buffer = c->buffer;
+
+  buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
+
+  /*
+   * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
+   *   the ligature to keep its old ligature id.  This will allow it to attach to
+   *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
+   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
+   *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
+   *   later, we don't want them to lose their ligature id/component, otherwise
+   *   GPOS will fail to correctly position the mark ligature on top of the
+   *   LAM,LAM,HEH ligature.  See:
+   *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
+   *
+   * - If a ligature is formed of components that some of which are also ligatures
+   *   themselves, and those ligature components had marks attached to *their*
+   *   components, we have to attach the marks to the new ligature component
+   *   positions!  Now *that*'s tricky!  And these marks may be following the
+   *   last component of the whole sequence, so we should loop forward looking
+   *   for them and update them.
+   *
+   *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
+   *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
+   *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
+   *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
+   *   the new ligature with a component value of 2.
+   *
+   *   This in fact happened to a font...  See:
+   *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
+   */
+
+  unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
+  unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
+  unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+  unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+  unsigned int components_so_far = last_num_components;
+
+  if (!is_mark_ligature)
+  {
+    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
+    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    {
+      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+      _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
+    }
+  }
+  c->replace_glyph_with_ligature (lig_glyph, klass);
+
+  for (unsigned int i = 1; i < count; i++)
+  {
+    while (buffer->idx < match_positions[i])
+    {
+      if (!is_mark_ligature) {
+       unsigned int new_lig_comp = components_so_far - last_num_components +
+                                   MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
+       _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
+      }
+      buffer->next_glyph ();
+    }
+
+    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+    components_so_far += last_num_components;
+
+    /* Skip the base glyph */
+    buffer->idx++;
+  }
+
+  if (!is_mark_ligature && last_lig_id) {
+    /* Re-adjust components for any marks following. */
+    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
+      if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
+       unsigned int new_lig_comp = components_so_far - last_num_components +
+                                   MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
+       _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
+      } else
+       break;
+    }
+  }
+  TRACE_RETURN (true);
 }
 
 static inline bool match_backtrack (hb_apply_context_t *c,
@@ -334,20 +891,17 @@ static inline bool match_backtrack (hb_apply_context_t *c,
                                    match_func_t match_func,
                                    const void *match_data)
 {
-  hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
-  if (skippy_iter.has_no_chance ())
-    return false;
+  TRACE_APPLY (NULL);
+
+  hb_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);
 
   for (unsigned int i = 0; i < count; i++)
-  {
     if (!skippy_iter.prev ())
-      return false;
-
-    if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
-      return false;
-  }
+      return TRACE_RETURN (false);
 
-  return true;
+  return TRACE_RETURN (true);
 }
 
 static inline bool match_lookahead (hb_apply_context_t *c,
@@ -357,28 +911,26 @@ static inline bool match_lookahead (hb_apply_context_t *c,
                                    const void *match_data,
                                    unsigned int offset)
 {
-  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
-  if (skippy_iter.has_no_chance ())
-    return false;
+  TRACE_APPLY (NULL);
+
+  hb_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);
 
   for (unsigned int i = 0; i < count; i++)
-  {
     if (!skippy_iter.next ())
-      return false;
-
-    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
-      return false;
-  }
+      return TRACE_RETURN (false);
 
-  return true;
+  return TRACE_RETURN (true);
 }
 
 
 
 struct LookupRecord
 {
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this));
   }
 
@@ -391,71 +943,96 @@ struct LookupRecord
 };
 
 
-static inline void closure_lookup (hb_closure_context_t *c,
-                                  unsigned int lookupCount,
-                                  const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
-                                  closure_lookup_func_t closure_func)
+template <typename context_t>
+static inline void recurse_lookups (context_t *c,
+                                   unsigned int lookupCount,
+                                   const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
 {
   for (unsigned int i = 0; i < lookupCount; i++)
-    closure_func (c, lookupRecord->lookupListIndex);
+    c->recurse (lookupRecord[i].lookupListIndex);
 }
 
 static inline bool apply_lookup (hb_apply_context_t *c,
                                 unsigned int count, /* Including the first glyph */
+                                unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
                                 unsigned int lookupCount,
                                 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
-                                apply_lookup_func_t apply_func)
+                                unsigned int match_length)
 {
-  unsigned int end = c->buffer->len;
-  if (unlikely (count == 0 || c->buffer->idx + count > end))
-    return false;
+  TRACE_APPLY (NULL);
 
-  /* TODO We don't support lookupRecord arrays that are not increasing:
-   *      Should be easy for in_place ones at least. */
+  hb_buffer_t *buffer = c->buffer;
+  unsigned int end;
 
-  /* Note: If sublookup is reverse, it will underflow after the first loop
-   * and we jump out of it.  Not entirely disastrous.  So we don't check
-   * for reverse lookup here.
-   */
-  for (unsigned int i = 0; i < count; /* NOP */)
+  /* All positions are distance from beginning of *output* buffer.
+   * Adjust. */
   {
-    if (unlikely (c->buffer->idx == end))
-      return true;
-    while (c->should_mark_skip_current_glyph ())
-    {
-      /* No lookup applied for this index */
-      c->buffer->next_glyph ();
-      if (unlikely (c->buffer->idx == end))
-       return true;
-    }
+    unsigned int bl = buffer->backtrack_len ();
+    end = bl + match_length;
 
-    if (lookupCount && i == lookupRecord->sequenceIndex)
-    {
-      unsigned int old_pos = c->buffer->idx;
+    int delta = bl - buffer->idx;
+    /* Convert positions to new indexing. */
+    for (unsigned int j = 0; j < count; j++)
+      match_positions[j] += delta;
+  }
+
+  for (unsigned int i = 0; i < lookupCount; i++)
+  {
+    unsigned int idx = lookupRecord[i].sequenceIndex;
+    if (idx >= count)
+      continue;
+
+    buffer->move_to (match_positions[idx]);
 
-      /* Apply a lookup */
-      bool done = apply_func (c, lookupRecord->lookupListIndex);
+    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+    if (!c->recurse (lookupRecord[i].lookupListIndex))
+      continue;
 
-      lookupRecord++;
-      lookupCount--;
-      /* Err, this is wrong if the lookup jumped over some glyphs */
-      i += c->buffer->idx - old_pos;
-      if (unlikely (c->buffer->idx == end))
-       return true;
+    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
+    int delta = new_len - orig_len;
 
-      if (!done)
-       goto not_applied;
+    if (!delta)
+        continue;
+
+    /* Recursed lookup changed buffer len.  Adjust. */
+
+    /* end can't go back past the current match position.
+     * Note: this is only true because we do NOT allow MultipleSubst
+     * with zero sequence len. */
+    end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
+
+    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
+
+    if (delta > 0)
+    {
+      if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
+       break;
     }
     else
     {
-    not_applied:
-      /* No lookup applied for this index */
-      c->buffer->next_glyph ();
-      i++;
+      /* NOTE: delta is negative. */
+      delta = MAX (delta, (int) next - (int) count);
+      next -= delta;
     }
+
+    /* Shift! */
+    memmove (match_positions + next + delta, match_positions + next,
+            (count - next) * sizeof (match_positions[0]));
+    next += delta;
+    count += delta;
+
+    /* Fill in new entries. */
+    for (unsigned int j = idx + 1; j < next; j++)
+      match_positions[j] = match_positions[j - 1] + 1;
+
+    /* And fixup the rest. */
+    for (; next < count; next++)
+      match_positions[next] += delta;
   }
 
-  return true;
+  buffer->move_to (end);
+
+  return TRACE_RETURN (true);
 }
 
 
@@ -468,6 +1045,12 @@ struct ContextClosureLookupContext
   const void *intersects_data;
 };
 
+struct ContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data;
+};
+
 struct ContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
@@ -484,12 +1067,35 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
   if (intersects_array (c,
                        inputCount ? inputCount - 1 : 0, input,
                        lookup_context.funcs.intersects, lookup_context.intersects_data))
-    closure_lookup (c,
-                   lookupCount, lookupRecord,
-                   lookup_context.funcs.closure);
+    recurse_lookups (c,
+                    lookupCount, lookupRecord);
 }
 
+static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+                                                 unsigned int inputCount, /* Including the first glyph (not matched) */
+                                                 const USHORT input[], /* Array of input values--start with second glyph */
+                                                 unsigned int lookupCount,
+                                                 const LookupRecord lookupRecord[],
+                                                 ContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c, c->input,
+                inputCount ? inputCount - 1 : 0, input,
+                lookup_context.funcs.collect, lookup_context.collect_data);
+  recurse_lookups (c,
+                  lookupCount, lookupRecord);
+}
 
+static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
+                                              unsigned int inputCount, /* Including the first glyph (not matched) */
+                                              const USHORT input[], /* Array of input values--start with second glyph */
+                                              unsigned int lookupCount HB_UNUSED,
+                                              const LookupRecord lookupRecord[] HB_UNUSED,
+                                              ContextApplyLookupContext &lookup_context)
+{
+  return would_match_input (c,
+                           inputCount, input,
+                           lookup_context.funcs.match, lookup_context.match_data);
+}
 static inline bool context_apply_lookup (hb_apply_context_t *c,
                                         unsigned int inputCount, /* Including the first glyph (not matched) */
                                         const USHORT input[], /* Array of input values--start with second glyph */
@@ -497,74 +1103,111 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
                                         const LookupRecord lookupRecord[],
                                         ContextApplyLookupContext &lookup_context)
 {
+  unsigned int match_length = 0;
+  unsigned int match_positions[MAX_CONTEXT_LENGTH];
   return match_input (c,
                      inputCount, input,
-                     lookup_context.funcs.match, lookup_context.match_data)
+                     lookup_context.funcs.match, lookup_context.match_data,
+                     &match_length, match_positions)
       && apply_lookup (c,
-                      inputCount,
+                      inputCount, match_positions,
                       lookupCount, lookupRecord,
-                      lookup_context.funcs.apply);
+                      match_length);
 }
 
 struct Rule
 {
-  friend struct RuleSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
-    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
+    TRACE_CLOSURE (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
     context_closure_lookup (c,
-                           inputCount, input,
+                           inputCount, inputZ,
                            lookupCount, lookupRecord,
                            lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+    context_collect_glyphs_lookup (c,
+                                  inputCount, inputZ,
+                                  lookupCount, lookupRecord,
+                                  lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+    return TRACE_RETURN (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+  }
+
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
-    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
-    return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
+    TRACE_APPLY (this);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+    return TRACE_RETURN (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
   }
 
   public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return inputCount.sanitize (c)
        && lookupCount.sanitize (c)
-       && c->check_range (input,
-                          input[0].static_size * inputCount
+       && c->check_range (inputZ,
+                          inputZ[0].static_size * inputCount
                           + lookupRecordX[0].static_size * lookupCount);
   }
 
-  private:
+  protected:
   USHORT       inputCount;             /* Total number of glyphs in input
                                         * glyph sequence--includes the first
                                         * glyph */
   USHORT       lookupCount;            /* Number of LookupRecords */
-  USHORT       input[VAR];             /* Array of match inputs--start with
+  USHORT       inputZ[VAR];            /* Array of match inputs--start with
                                         * second glyph */
   LookupRecord lookupRecordX[VAR];     /* Array of LookupRecords--in
                                         * design order */
   public:
-  DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
+  DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
 };
 
 struct RuleSet
 {
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+    {
+      if ((this+rule[i]).would_apply (c, lookup_context))
+        return TRACE_RETURN (true);
+    }
+    return TRACE_RETURN (false);
+  }
+
   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
     {
@@ -574,12 +1217,13 @@ struct RuleSet
     return TRACE_RETURN (false);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rule.sanitize (c, this));
   }
 
-  private:
+  protected:
   OffsetArrayOf<Rule>
                rule;                   /* Array of Rule tables
                                         * ordered by preference */
@@ -590,18 +1234,14 @@ struct RuleSet
 
 struct ContextFormat1
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
 
     const Coverage &cov = (this+coverage);
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_glyph, closure_func},
+      {intersects_glyph},
       NULL
     };
 
@@ -613,27 +1253,60 @@ struct ContextFormat1
       }
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      NULL
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
+    struct ContextApplyLookupContext lookup_context = {
+      {match_glyph},
+      NULL
+    };
+    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED))
       return TRACE_RETURN (false);
 
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_glyph, apply_func},
+      {match_glyph},
       NULL
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -648,21 +1321,17 @@ struct ContextFormat1
 
 struct ContextFormat2
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
     const ClassDef &class_def = this+classDef;
 
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_class, closure_func},
-      NULL
+      {intersects_class},
+      &class_def
     };
 
     unsigned int count = ruleSet.len;
@@ -673,28 +1342,64 @@ struct ContextFormat2
       }
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    const ClassDef &class_def = this+classDef;
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      &class_def
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const ClassDef &class_def = this+classDef;
+    unsigned int index = class_def.get_class (c->glyphs[0]);
+    const RuleSet &rule_set = this+ruleSet[index];
+    struct ContextApplyLookupContext lookup_context = {
+      {match_class},
+      &class_def
+    };
+    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverage;
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const ClassDef &class_def = this+classDef;
-    index = class_def (c->buffer->cur().codepoint);
+    index = class_def.get_class (c->buffer->cur().codepoint);
     const RuleSet &rule_set = this+ruleSet[index];
     struct ContextApplyLookupContext lookup_context = {
-      {match_class, apply_func},
+      {match_class},
       &class_def
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -712,104 +1417,114 @@ struct ContextFormat2
 
 struct ContextFormat3
 {
-  friend struct Context;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
-    if (!(this+coverage[0]).intersects (c->glyphs))
+    TRACE_CLOSURE (this);
+    if (!(this+coverageZ[0]).intersects (c->glyphs))
       return;
 
-    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextClosureLookupContext lookup_context = {
-      {intersects_coverage, closure_func},
+      {intersects_coverage},
       this
     };
     context_closure_lookup (c,
-                           glyphCount, (const USHORT *) (coverage + 1),
+                           glyphCount, (const USHORT *) (coverageZ + 1),
                            lookupCount, lookupRecord,
                            lookup_context);
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverageZ[0]).add_coverage (c->input);
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+    struct ContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      this
+    };
+
+    context_collect_glyphs_lookup (c,
+                                  glyphCount, (const USHORT *) (coverageZ + 1),
+                                  lookupCount, lookupRecord,
+                                  lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+    struct ContextApplyLookupContext lookup_context = {
+      {match_coverage},
+      this
+    };
+    return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    return this+coverageZ[0];
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
+    TRACE_APPLY (this);
+    unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
-    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
     struct ContextApplyLookupContext lookup_context = {
-      {match_coverage, apply_func},
+      {match_coverage},
       this
     };
-    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
+    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!c->check_struct (this)) return TRACE_RETURN (false);
     unsigned int count = glyphCount;
-    if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
+    if (!count) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */
+    if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false);
     for (unsigned int i = 0; i < count; i++)
-      if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
-    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
+      if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false);
+    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
     return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 3 */
   USHORT       glyphCount;             /* Number of glyphs in the input glyph
                                         * sequence */
   USHORT       lookupCount;            /* Number of LookupRecords */
   OffsetTo<Coverage>
-               coverage[VAR];          /* Array of offsets to Coverage
+               coverageZ[VAR];         /* Array of offsets to Coverage
                                         * table in glyph sequence order */
   LookupRecord lookupRecordX[VAR];     /* Array of LookupRecords--in
                                         * design order */
   public:
-  DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
+  DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
 };
 
 struct Context
 {
-  protected:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c, closure_func); break;
-    case 2: u.format2.closure (c, closure_func); break;
-    case 3: u.format3.closure (c, closure_func); break;
-    default:                                     break;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
-    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
-    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    case 3: return TRACE_RETURN (u.format3.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    case 2: return TRACE_RETURN (c->dispatch (u.format2));
+    case 3: return TRACE_RETURN (c->dispatch (u.format3));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
   ContextFormat1       format1;
@@ -827,6 +1542,12 @@ struct ChainContextClosureLookupContext
   const void *intersects_data[3];
 };
 
+struct ChainContextCollectGlyphsLookupContext
+{
+  ContextCollectGlyphsFuncs funcs;
+  const void *collect_data[3];
+};
+
 struct ChainContextApplyLookupContext
 {
   ContextApplyFuncs funcs;
@@ -850,12 +1571,52 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
    && intersects_array (c,
                        inputCount ? inputCount - 1 : 0, input,
                        lookup_context.funcs.intersects, lookup_context.intersects_data[1])
-  && intersects_array (c,
+   && intersects_array (c,
                       lookaheadCount, lookahead,
                       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
-    closure_lookup (c,
-                   lookupCount, lookupRecord,
-                   lookup_context.funcs.closure);
+    recurse_lookups (c,
+                    lookupCount, lookupRecord);
+}
+
+static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+                                                       unsigned int backtrackCount,
+                                                       const USHORT backtrack[],
+                                                       unsigned int inputCount, /* Including the first glyph (not matched) */
+                                                       const USHORT input[], /* Array of input values--start with second glyph */
+                                                       unsigned int lookaheadCount,
+                                                       const USHORT lookahead[],
+                                                       unsigned int lookupCount,
+                                                       const LookupRecord lookupRecord[],
+                                                       ChainContextCollectGlyphsLookupContext &lookup_context)
+{
+  collect_array (c, c->before,
+                backtrackCount, backtrack,
+                lookup_context.funcs.collect, lookup_context.collect_data[0]);
+  collect_array (c, c->input,
+                inputCount ? inputCount - 1 : 0, input,
+                lookup_context.funcs.collect, lookup_context.collect_data[1]);
+  collect_array (c, c->after,
+                lookaheadCount, lookahead,
+                lookup_context.funcs.collect, lookup_context.collect_data[2]);
+  recurse_lookups (c,
+                  lookupCount, lookupRecord);
+}
+
+static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
+                                                    unsigned int backtrackCount,
+                                                    const USHORT backtrack[] HB_UNUSED,
+                                                    unsigned int inputCount, /* Including the first glyph (not matched) */
+                                                    const USHORT input[], /* Array of input values--start with second glyph */
+                                                    unsigned int lookaheadCount,
+                                                    const USHORT lookahead[] HB_UNUSED,
+                                                    unsigned int lookupCount HB_UNUSED,
+                                                    const LookupRecord lookupRecord[] HB_UNUSED,
+                                                    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]);
 }
 
 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
@@ -869,33 +1630,30 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
                                               const LookupRecord lookupRecord[],
                                               ChainContextApplyLookupContext &lookup_context)
 {
-  unsigned int lookahead_offset;
-  return match_backtrack (c,
-                         backtrackCount, backtrack,
-                         lookup_context.funcs.match, lookup_context.match_data[0])
-      && match_input (c,
+  unsigned int match_length = 0;
+  unsigned int match_positions[MAX_CONTEXT_LENGTH];
+  return match_input (c,
                      inputCount, input,
                      lookup_context.funcs.match, lookup_context.match_data[1],
-                     &lookahead_offset)
+                     &match_length, match_positions)
+      && match_backtrack (c,
+                         backtrackCount, backtrack,
+                         lookup_context.funcs.match, lookup_context.match_data[0])
       && match_lookahead (c,
                          lookaheadCount, lookahead,
                          lookup_context.funcs.match, lookup_context.match_data[2],
-                         lookahead_offset)
+                         match_length)
       && apply_lookup (c,
-                      inputCount,
+                      inputCount, match_positions,
                       lookupCount, lookupRecord,
-                      lookup_context.funcs.apply);
+                      match_length);
 }
 
 struct ChainRule
 {
-  friend struct ChainRuleSet;
-
-  private:
-
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -907,9 +1665,36 @@ struct ChainRule
                                  lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    chain_context_collect_glyphs_lookup (c,
+                                        backtrack.len, backtrack.array,
+                                        input.len, input.array,
+                                        lookahead.len, lookahead.array,
+                                        lookup.len, lookup.array,
+                                        lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    return TRACE_RETURN (chain_context_would_apply_lookup (c,
+                                                          backtrack.len, backtrack.array,
+                                                          input.len, input.array,
+                                                          lookahead.len, lookahead.array, lookup.len,
+                                                          lookup.array, lookup_context));
+  }
+
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -920,19 +1705,19 @@ struct ChainRule
                                                     lookup.array, lookup_context));
   }
 
-  public:
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
-    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
     if (!input.sanitize (c)) return TRACE_RETURN (false);
-    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
     if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
-    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return TRACE_RETURN (lookup.sanitize (c));
   }
 
-  private:
+  protected:
   ArrayOf<USHORT>
                backtrack;              /* Array of backtracking values
                                         * (to be matched before the input
@@ -954,15 +1739,34 @@ struct ChainRuleSet
 {
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       (this+rule[i]).closure (c, lookup_context);
   }
 
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      (this+rule[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+  {
+    TRACE_WOULD_APPLY (this);
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if ((this+rule[i]).would_apply (c, lookup_context))
+        return TRACE_RETURN (true);
+
+    return TRACE_RETURN (false);
+  }
+
   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     unsigned int num_rules = rule.len;
     for (unsigned int i = 0; i < num_rules; i++)
       if ((this+rule[i]).apply (c, lookup_context))
@@ -971,12 +1775,13 @@ struct ChainRuleSet
     return TRACE_RETURN (false);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (rule.sanitize (c, this));
   }
 
-  private:
+  protected:
   OffsetArrayOf<ChainRule>
                rule;                   /* Array of ChainRule tables
                                         * ordered by preference */
@@ -986,17 +1791,13 @@ struct ChainRuleSet
 
 struct ChainContextFormat1
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_glyph, closure_func},
+      {intersects_glyph},
       {NULL, NULL, NULL}
     };
 
@@ -1008,26 +1809,59 @@ struct ChainContextFormat1
       }
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_glyph},
+      {NULL, NULL, NULL}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_glyph},
+      {NULL, NULL, NULL}
+    };
+    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    return this+coverage;
+  }
+
+  inline bool apply (hb_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_RETURN (false);
 
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_glyph, apply_func},
+      {match_glyph},
       {NULL, NULL, NULL}
     };
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -1041,13 +1875,9 @@ struct ChainContextFormat1
 
 struct ChainContextFormat2
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     if (!(this+coverage).intersects (c->glyphs))
       return;
 
@@ -1056,7 +1886,7 @@ struct ChainContextFormat2
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_class, closure_func},
+      {intersects_class},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
@@ -1070,20 +1900,65 @@ struct ChainContextFormat2
       }
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    (this+coverage).add_coverage (c->input);
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    unsigned int index = input_class_def.get_class (c->glyphs[0]);
+    const ChainRuleSet &rule_set = this+ruleSet[index];
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
   {
-    TRACE_APPLY ();
-    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+    return this+coverage;
+  }
+
+  inline bool apply (hb_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_RETURN (false);
 
     const ClassDef &backtrack_class_def = this+backtrackClassDef;
     const ClassDef &input_class_def = this+inputClassDef;
     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
 
-    index = input_class_def (c->buffer->cur().codepoint);
+    index = input_class_def.get_class (c->buffer->cur().codepoint);
     const ChainRuleSet &rule_set = this+ruleSet[index];
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_class, apply_func},
+      {match_class},
       {&backtrack_class_def,
        &input_class_def,
        &lookahead_class_def}
@@ -1091,14 +1966,15 @@ struct ChainContextFormat2
     return TRACE_RETURN (rule_set.apply (c, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
                         inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
                         ruleSet.sanitize (c, this));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
@@ -1124,13 +2000,9 @@ struct ChainContextFormat2
 
 struct ChainContextFormat3
 {
-  friend struct ChainContext;
-
-  private:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+  inline void closure (hb_closure_context_t *c) const
   {
-    TRACE_CLOSURE ();
+    TRACE_CLOSURE (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
     if (!(this+input[0]).intersects (c->glyphs))
@@ -1139,7 +2011,7 @@ struct ChainContextFormat3
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextClosureLookupContext lookup_context = {
-      {intersects_coverage, closure_func},
+      {intersects_coverage},
       {this, this, this}
     };
     chain_context_closure_lookup (c,
@@ -1150,18 +2022,63 @@ struct ChainContextFormat3
                                  lookup_context);
   }
 
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    (this+input[0]).add_coverage (c->input);
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextCollectGlyphsLookupContext lookup_context = {
+      {collect_coverage},
+      {this, this, this}
+    };
+    chain_context_collect_glyphs_lookup (c,
+                                        backtrack.len, (const USHORT *) backtrack.array,
+                                        input.len, (const USHORT *) input.array + 1,
+                                        lookahead.len, (const USHORT *) lookahead.array,
+                                        lookup.len, lookup.array,
+                                        lookup_context);
+  }
+
+  inline bool would_apply (hb_would_apply_context_t *c) const
+  {
+    TRACE_WOULD_APPLY (this);
+
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    struct ChainContextApplyLookupContext lookup_context = {
+      {match_coverage},
+      {this, this, this}
+    };
+    return TRACE_RETURN (chain_context_would_apply_lookup (c,
+                                                          backtrack.len, (const USHORT *) backtrack.array,
+                                                          input.len, (const USHORT *) input.array + 1,
+                                                          lookahead.len, (const USHORT *) lookahead.array,
+                                                          lookup.len, lookup.array, lookup_context));
+  }
+
+  inline const Coverage &get_coverage (void) const
+  {
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    return this+input[0];
+  }
+
+  inline bool apply (hb_apply_context_t *c) const
   {
-    TRACE_APPLY ();
+    TRACE_APPLY (this);
     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
 
-    unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
+    unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
 
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     struct ChainContextApplyLookupContext lookup_context = {
-      {match_coverage, apply_func},
+      {match_coverage},
       {this, this, this}
     };
     return TRACE_RETURN (chain_context_apply_lookup (c,
@@ -1171,18 +2088,20 @@ struct ChainContextFormat3
                                                     lookup.len, lookup.array, lookup_context));
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
-    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     if (!input.sanitize (c, this)) return TRACE_RETURN (false);
-    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
     if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
-    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
     return TRACE_RETURN (lookup.sanitize (c));
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier--format = 3 */
   OffsetArrayOf<Coverage>
                backtrack;              /* Array of coverage tables
@@ -1205,42 +2124,20 @@ struct ChainContextFormat3
 
 struct ChainContext
 {
-  protected:
-
-  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
-  {
-    TRACE_CLOSURE ();
-    switch (u.format) {
-    case 1: u.format1.closure (c, closure_func); break;
-    case 2: u.format2.closure (c, closure_func); break;
-    case 3: u.format3.closure (c, closure_func); break;
-    default:                                     break;
-    }
-  }
-
-  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
   {
-    TRACE_APPLY ();
-    switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
-    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
-    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
-    default:return TRACE_RETURN (false);
-    }
-  }
-
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    case 2: return TRACE_RETURN (u.format2.sanitize (c));
-    case 3: return TRACE_RETURN (u.format3.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (c->dispatch (u.format1));
+    case 2: return TRACE_RETURN (c->dispatch (u.format2));
+    case 3: return TRACE_RETURN (c->dispatch (u.format3));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format; /* Format identifier */
   ChainContextFormat1  format1;
@@ -1250,20 +2147,35 @@ struct ChainContext
 };
 
 
+template <typename T>
 struct ExtensionFormat1
 {
-  friend struct Extension;
-
-  protected:
   inline unsigned int get_type (void) const { return extensionLookupType; }
-  inline unsigned int get_offset (void) const { return extensionOffset; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    return TRACE_RETURN (c->check_struct (this));
+  template <typename X>
+  inline const X& get_subtable (void) const
+  {
+    unsigned int offset = extensionOffset;
+    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+    return StructAtOffset<typename T::LookupSubTable> (this, offset);
+  }
+
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, format);
+    if (unlikely (!c->may_dispatch (this, this))) TRACE_RETURN (c->default_return_value ());
+    return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
+  }
+
+  /* This is called from may_dispatch() above with hb_sanitize_context_t. */
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) && extensionOffset != 0);
   }
 
-  private:
+  protected:
   USHORT       format;                 /* Format identifier. Set to 1. */
   USHORT       extensionLookupType;    /* Lookup type of subtable referenced
                                         * by ExtensionOffset (i.e. the
@@ -1274,6 +2186,7 @@ struct ExtensionFormat1
   DEFINE_SIZE_STATIC (8);
 };
 
+template <typename T>
 struct Extension
 {
   inline unsigned int get_type (void) const
@@ -1283,27 +2196,30 @@ struct Extension
     default:return 0;
     }
   }
-  inline unsigned int get_offset (void) const
+  template <typename X>
+  inline const X& get_subtable (void) const
   {
     switch (u.format) {
-    case 1: return u.format1.get_offset ();
-    default:return 0;
+    case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
+    default:return Null(typename T::LookupSubTable);
     }
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
-    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+  template <typename context_t>
+  inline typename context_t::return_t dispatch (context_t *c) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
     switch (u.format) {
-    case 1: return TRACE_RETURN (u.format1.sanitize (c));
-    default:return TRACE_RETURN (true);
+    case 1: return TRACE_RETURN (u.format1.dispatch (c));
+    default:return TRACE_RETURN (c->default_return_value ());
     }
   }
 
-  private:
+  protected:
   union {
   USHORT               format;         /* Format identifier */
-  ExtensionFormat1     format1;
+  ExtensionFormat1<T>  format1;
   } u;
 };
 
@@ -1332,8 +2248,8 @@ struct GSUBGPOS
 
   inline unsigned int get_feature_count (void) const
   { return (this+featureList).len; }
-  inline const Tag& get_feature_tag (unsigned int i) const
-  { return (this+featureList).get_tag (i); }
+  inline hb_tag_t get_feature_tag (unsigned int i) const
+  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
   inline unsigned int get_feature_tags (unsigned int start_offset,
                                        unsigned int *feature_count /* IN/OUT */,
                                        hb_tag_t     *feature_tags /* OUT */) const
@@ -1348,8 +2264,9 @@ struct GSUBGPOS
   inline const Lookup& get_lookup (unsigned int i) const
   { return (this+lookupList)[i]; }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
                         scriptList.sanitize (c, this) &&
                         featureList.sanitize (c, this) &&
@@ -1358,7 +2275,7 @@ struct GSUBGPOS
 
   protected:
   FixedVersion version;        /* Version of the GSUB/GPOS table--initially set
-                                * to 0x00010000 */
+                                * to 0x00010000u */
   OffsetTo<ScriptList>
                scriptList;     /* ScriptList table */
   OffsetTo<FeatureList>
@@ -1370,5 +2287,7 @@ struct GSUBGPOS
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
new file mode 100644 (file)
index 0000000..739dfd9
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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
+ */
+
+#ifndef HB_OT_LAYOUT_JSTF_TABLE_HH
+#define HB_OT_LAYOUT_JSTF_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-gpos-table.hh"
+
+
+namespace OT {
+
+
+/*
+ * JstfModList -- Justification Modification List Tables
+ */
+
+typedef IndexArray JstfModList;
+
+
+/*
+ * JstfMax -- Justification Maximum Table
+ */
+
+typedef OffsetListOf<PosLookup> JstfMax;
+
+
+/*
+ * JstfPriority -- Justification Priority Table
+ */
+
+struct JstfPriority
+{
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (c->check_struct (this) &&
+                        shrinkageEnableGSUB.sanitize (c, this) &&
+                        shrinkageDisableGSUB.sanitize (c, this) &&
+                        shrinkageEnableGPOS.sanitize (c, this) &&
+                        shrinkageDisableGPOS.sanitize (c, this) &&
+                        shrinkageJstfMax.sanitize (c, this) &&
+                        extensionEnableGSUB.sanitize (c, this) &&
+                        extensionDisableGSUB.sanitize (c, this) &&
+                        extensionEnableGPOS.sanitize (c, this) &&
+                        extensionDisableGPOS.sanitize (c, this) &&
+                        extensionJstfMax.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<JstfModList>
+               shrinkageEnableGSUB;    /* Offset to Shrinkage Enable GSUB
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+               shrinkageDisableGSUB;   /* Offset to Shrinkage Disable GSUB
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+               shrinkageEnableGPOS;    /* Offset to Shrinkage Enable GPOS
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+               shrinkageDisableGPOS;   /* Offset to Shrinkage Disable GPOS
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfMax>
+               shrinkageJstfMax;       /* Offset to Shrinkage JstfMax table--
+                                        * from beginning of JstfPriority table
+                                        * --may be NULL */
+  OffsetTo<JstfModList>
+               extensionEnableGSUB;    /* Offset to Extension Enable GSUB
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+               extensionDisableGSUB;   /* Offset to Extension Disable GSUB
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+               extensionEnableGPOS;    /* Offset to Extension Enable GPOS
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfModList>
+               extensionDisableGPOS;   /* Offset to Extension Disable GPOS
+                                        * JstfModList table--from beginning of
+                                        * JstfPriority table--may be NULL */
+  OffsetTo<JstfMax>
+               extensionJstfMax;       /* Offset to Extension JstfMax table--
+                                        * from beginning of JstfPriority table
+                                        * --may be NULL */
+
+  public:
+  DEFINE_SIZE_STATIC (20);
+};
+
+
+/*
+ * JstfLangSys -- Justification Language System Table
+ */
+
+struct JstfLangSys : OffsetListOf<JstfPriority>
+{
+  inline bool sanitize (hb_sanitize_context_t *c,
+                       const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (OffsetListOf<JstfPriority>::sanitize (c));
+  }
+};
+
+
+/*
+ * ExtenderGlyphs -- Extender Glyph Table
+ */
+
+typedef SortedArrayOf<GlyphID> ExtenderGlyphs;
+
+
+/*
+ * JstfScript -- The Justification Table
+ */
+
+struct JstfScript
+{
+  inline unsigned int get_lang_sys_count (void) const
+  { return langSys.len; }
+  inline const Tag& get_lang_sys_tag (unsigned int i) const
+  { return langSys.get_tag (i); }
+  inline 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); }
+  inline const JstfLangSys& get_lang_sys (unsigned int i) const
+  {
+    if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
+    return this+langSys[i].offset;
+  }
+  inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
+  { return langSys.find_index (tag, index); }
+
+  inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
+  inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+  inline bool sanitize (hb_sanitize_context_t *c,
+                       const Record<JstfScript>::sanitize_closure_t * = NULL) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (extenderGlyphs.sanitize (c, this) &&
+                        defaultLangSys.sanitize (c, this) &&
+                        langSys.sanitize (c, this));
+  }
+
+  protected:
+  OffsetTo<ExtenderGlyphs>
+               extenderGlyphs; /* Offset to ExtenderGlyph table--from beginning
+                                * of JstfScript table-may be NULL */
+  OffsetTo<JstfLangSys>
+               defaultLangSys; /* Offset to DefaultJstfLangSys table--from
+                                * beginning of JstfScript table--may be Null */
+  RecordArrayOf<JstfLangSys>
+               langSys;        /* Array of JstfLangSysRecords--listed
+                                * alphabetically by LangSysTag */
+  public:
+  DEFINE_SIZE_ARRAY (6, langSys);
+};
+
+
+/*
+ * JSTF -- The Justification Table
+ */
+
+struct JSTF
+{
+  static const hb_tag_t tableTag       = HB_OT_TAG_JSTF;
+
+  inline unsigned int get_script_count (void) const
+  { return scriptList.len; }
+  inline const Tag& get_script_tag (unsigned int i) const
+  { return scriptList.get_tag (i); }
+  inline unsigned int get_script_tags (unsigned int start_offset,
+                                      unsigned int *script_count /* IN/OUT */,
+                                      hb_tag_t     *script_tags /* OUT */) const
+  { return scriptList.get_tags (start_offset, script_count, script_tags); }
+  inline const JstfScript& get_script (unsigned int i) const
+  { return this+scriptList[i].offset; }
+  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
+  { return scriptList.find_index (tag, index); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
+                        scriptList.sanitize (c, this));
+  }
+
+  protected:
+  FixedVersion version;        /* Version of the JSTF table--initially set
+                                * to 0x00010000u */
+  RecordArrayOf<JstfScript>
+               scriptList;     /* Array of JstfScripts--listed
+                                * alphabetically by ScriptTag */
+  public:
+  DEFINE_SIZE_ARRAY (6, scriptList);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_JSTF_TABLE_HH */
index f860e7b..47fecd2 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,6 +23,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_OT_LAYOUT_PRIVATE_HH
 
 #include "hb-private.hh"
 
-#include "hb-ot-layout.h"
-
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
-#include "hb-ot-shape-complex-private.hh"
-
+#include "hb-set-private.hh"
 
 
 /*
  * GDEF
  */
 
-/* XXX cleanup */
-typedef enum {
-  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED        = 0x0001,
-  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH  = 0x0002,
-  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE    = 0x0004,
-  HB_OT_LAYOUT_GLYPH_CLASS_MARK                = 0x0008,
-  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT   = 0x0010
-} hb_ot_layout_glyph_class_t;
+typedef enum
+{
+  /* The following three match LookupFlags::Ignore* numbers. */
+  HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH  = 0x02u,
+  HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE    = 0x04u,
+  HB_OT_LAYOUT_GLYPH_PROPS_MARK                = 0x08u,
 
+  /* The following are used internally; not derived from GDEF. */
+  HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u,
+  HB_OT_LAYOUT_GLYPH_PROPS_LIGATED     = 0x20u,
+  HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED  = 0x40u,
 
-HB_INTERNAL unsigned int
-_hb_ot_layout_get_glyph_property (hb_face_t       *face,
-                                 hb_glyph_info_t *info);
+  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE     = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
+                                         HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+                                         HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
+} hb_ot_layout_glyph_class_mask_t;
 
-HB_INTERNAL hb_bool_t
-_hb_ot_layout_check_glyph_property (hb_face_t    *face,
-                                   hb_glyph_info_t *ginfo,
-                                   unsigned int  lookup_props,
-                                   unsigned int *property_out);
+
+/*
+ * GSUB/GPOS
+ */
 
 HB_INTERNAL hb_bool_t
-_hb_ot_layout_skip_mark (hb_face_t    *face,
-                        hb_glyph_info_t *ginfo,
-                        unsigned int  lookup_props,
-                        unsigned int *property_out);
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
+                                          unsigned int          lookup_index,
+                                          const hb_codepoint_t *glyphs,
+                                          unsigned int          glyphs_length,
+                                          hb_bool_t             zero_context);
+
+
+/* Should be called before all the substitute_lookup's are done. */
+HB_INTERNAL void
+hb_ot_layout_substitute_start (hb_font_t    *font,
+                              hb_buffer_t  *buffer);
+
+
+struct hb_ot_layout_lookup_accelerator_t;
+
+namespace OT {
+  struct hb_apply_context_t;
+  struct SubstLookup;
+}
+
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+                               const OT::SubstLookup &lookup,
+                               const hb_ot_layout_lookup_accelerator_t &accel);
+
+
+/* Should be called after all the substitute_lookup's are done */
+HB_INTERNAL void
+hb_ot_layout_substitute_finish (hb_font_t    *font,
+                               hb_buffer_t  *buffer);
+
+
+/* Should be called before all the position_lookup's are done.  Resets positions to zero. */
+HB_INTERNAL void
+hb_ot_layout_position_start (hb_font_t    *font,
+                            hb_buffer_t  *buffer);
+
+/* Should be called after all the position_lookup's are done */
+HB_INTERNAL void
+hb_ot_layout_position_finish (hb_font_t    *font,
+                             hb_buffer_t  *buffer);
 
 
 
@@ -73,15 +111,48 @@ _hb_ot_layout_skip_mark (hb_face_t    *face,
  * hb_ot_layout_t
  */
 
+namespace OT {
+  struct GDEF;
+  struct GSUB;
+  struct GPOS;
+}
+
+struct hb_ot_layout_lookup_accelerator_t
+{
+  template <typename TLookup>
+  inline void init (const TLookup &lookup)
+  {
+    digest.init ();
+    lookup.add_coverage (&digest);
+  }
+
+  inline void fini (void)
+  {
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return digest.may_have (g);
+  }
+
+  private:
+  hb_set_digest_t digest;
+};
+
 struct hb_ot_layout_t
 {
   hb_blob_t *gdef_blob;
   hb_blob_t *gsub_blob;
   hb_blob_t *gpos_blob;
 
-  const struct GDEF *gdef;
-  const struct GSUB *gsub;
-  const struct GPOS *gpos;
+  const struct OT::GDEF *gdef;
+  const struct OT::GSUB *gsub;
+  const struct OT::GPOS *gpos;
+
+  unsigned int gsub_lookup_count;
+  unsigned int gpos_lookup_count;
+
+  hb_ot_layout_lookup_accelerator_t *gsub_accels;
+  hb_ot_layout_lookup_accelerator_t *gpos_accels;
 };
 
 
@@ -92,5 +163,302 @@ HB_INTERNAL void
 _hb_ot_layout_destroy (hb_ot_layout_t *layout);
 
 
+#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
+
+
+/*
+ * Buffer var routines.
+ */
+
+/* buffer var allocations, used during the entire shaping process */
+#define unicode_props0()       var2.u8[0]
+#define unicode_props1()       var2.u8[1]
+
+/* buffer var allocations, used during the GSUB/GPOS processing */
+#define glyph_props()          var1.u16[0] /* GDEF glyph properties */
+#define lig_props()            var1.u8[2] /* GSUB/GPOS ligature tracking */
+#define syllable()             var1.u8[3] /* GSUB/GPOS shaping boundaries */
+
+/* unicode_props */
+
+enum {
+  MASK0_ZWJ       = 0x20u,
+  MASK0_ZWNJ      = 0x40u,
+  MASK0_IGNORABLE = 0x80u,
+  MASK0_GEN_CAT   = 0x1Fu
+};
+
+static inline void
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+{
+  /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
+  info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
+                          (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
+                          (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
+                          (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
+  info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
+}
+
+static inline void
+_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
+                                    hb_unicode_general_category_t gen_cat)
+{
+  info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
+}
+
+static inline hb_unicode_general_category_t
+_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
+{
+  return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
+}
+
+static inline void
+_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
+                                            unsigned int modified_class)
+{
+  info->unicode_props1() = modified_class;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
+{
+  return info->unicode_props1();
+}
+
+static inline hb_bool_t
+_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & MASK0_IGNORABLE);
+}
+
+static inline hb_bool_t
+_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & MASK0_ZWNJ);
+}
+
+static inline hb_bool_t
+_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
+{
+  return !!(info->unicode_props0() & MASK0_ZWJ);
+}
+
+static inline void
+_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
+{
+  info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
+}
+
+/* lig_props: aka lig_id / lig_comp
+ *
+ * When a ligature is formed:
+ *
+ *   - The ligature glyph and any marks in between all the same newly allocated
+ *     lig_id,
+ *   - The ligature glyph will get lig_num_comps set to the number of components
+ *   - The marks get lig_comp > 0, reflecting which component of the ligature
+ *     they were applied to.
+ *   - This is used in GPOS to attach marks to the right component of a ligature
+ *     in MarkLigPos,
+ *   - Note that when marks are ligated together, much of the above is skipped
+ *     and the current lig_id reused.
+ *
+ * When a multiple-substitution is done:
+ *
+ *   - All resulting glyphs will have lig_id = 0,
+ *   - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
+ *   - This is used in GPOS to attach marks to the first component of a
+ *     multiple substitution in MarkBasePos.
+ *
+ * The numbers are also used in GPOS to do mark-to-mark positioning only
+ * to marks that belong to the same component of the same ligature.
+ */
+
+static inline void
+_hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
+{
+  info->lig_props() = 0;
+}
+
+#define IS_LIG_BASE 0x10
+
+static inline void
+_hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
+                                          unsigned int lig_id,
+                                          unsigned int lig_num_comps)
+{
+  info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
+                                      unsigned int lig_id,
+                                      unsigned int lig_comp)
+{
+  info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
+{
+  _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
+{
+  return info->lig_props() >> 5;
+}
+
+static inline bool
+_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
+{
+  return !!(info->lig_props() & IS_LIG_BASE);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
+{
+  if (_hb_glyph_info_ligated_internal (info))
+    return 0;
+  else
+    return info->lig_props() & 0x0F;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
+{
+  if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
+      _hb_glyph_info_ligated_internal (info))
+    return info->lig_props() & 0x0F;
+  else
+    return 1;
+}
+
+static inline uint8_t
+_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 */
+  return lig_id;
+}
+
+/* glyph_props: */
+
+static inline void
+_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
+{
+  info->glyph_props() = props;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
+{
+  return info->glyph_props();
+}
+
+static inline bool
+_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
+}
+
+static inline bool
+_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
+}
+
+static inline bool
+_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+}
+
+static inline bool
+_hb_glyph_info_substituted (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+}
+
+static inline bool
+_hb_glyph_info_ligated (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
+}
+
+static inline bool
+_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
+{
+  return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+}
+
+static inline bool
+_hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
+{
+  return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
+}
+
+static inline void
+_hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
+{
+  info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+                          HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+}
+
+
+/* Allocation / deallocation. */
+
+static inline void
+_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
+  HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
+}
+
+static inline void
+_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
+}
+
+static inline void
+_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
+{
+  HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
+  HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
+}
+
+static inline void
+_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);
+}
+
+static inline void
+_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... */
+#undef unicode_props0
+#undef unicode_props1
+#undef lig_props
+#undef glyph_props
+
 
 #endif /* HB_OT_LAYOUT_PRIVATE_HH */
index 0621f86..b1e69e8 100644 (file)
@@ -2,6 +2,7 @@
  * 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.
  *
@@ -24,6 +25,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-ot-layout-private.hh"
 #include "hb-ot-layout-gdef-table.hh"
 #include "hb-ot-layout-gsub-table.hh"
 #include "hb-ot-layout-gpos-table.hh"
-#include "hb-ot-maxp-table.hh"
+#include "hb-ot-layout-jstf-table.hh"
 
+#include "hb-ot-map-private.hh"
 
 #include <stdlib.h>
 #include <string.h>
 
 
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
 
 hb_ot_layout_t *
 _hb_ot_layout_create (hb_face_t *face)
 {
-  /* TODO Remove this object altogether */
   hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
+  if (unlikely (!layout))
+    return NULL;
 
-  layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GDEF));
-  layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
+  layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
+  layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
 
-  layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GSUB));
-  layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
+  layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
+  layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
 
-  layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
-  layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
+  layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
+  layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
+
+  layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
+  layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
+
+  layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+  layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+
+  if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
+               (layout->gpos_lookup_count && !layout->gpos_accels)))
+  {
+    _hb_ot_layout_destroy (layout);
+    return NULL;
+  }
+
+  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+    layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
+  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+    layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
 
   return layout;
 }
@@ -60,6 +83,14 @@ _hb_ot_layout_create (hb_face_t *face)
 void
 _hb_ot_layout_destroy (hb_ot_layout_t *layout)
 {
+  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+    layout->gsub_accels[i].fini ();
+  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+    layout->gpos_accels[i].fini ();
+
+  free (layout->gsub_accels);
+  free (layout->gpos_accels);
+
   hb_blob_destroy (layout->gdef_blob);
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
@@ -67,20 +98,23 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
   free (layout);
 }
 
-static inline const GDEF&
+static inline const OT::GDEF&
 _get_gdef (hb_face_t *face)
 {
-  return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
+  return *hb_ot_layout_from_face (face)->gdef;
 }
-static inline const GSUB&
+static inline const OT::GSUB&
 _get_gsub (hb_face_t *face)
 {
-  return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
+  return *hb_ot_layout_from_face (face)->gsub;
 }
-static inline const GPOS&
+static inline const OT::GPOS&
 _get_gpos (hb_face_t *face)
 {
-  return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
+  return *hb_ot_layout_from_face (face)->gpos;
 }
 
 
@@ -94,85 +128,21 @@ hb_ot_layout_has_glyph_classes (hb_face_t *face)
   return _get_gdef (face).has_glyph_classes ();
 }
 
-unsigned int
-_hb_ot_layout_get_glyph_property (hb_face_t       *face,
-                                 hb_glyph_info_t *info)
-{
-  if (!info->props_cache())
-  {
-    const GDEF &gdef = _get_gdef (face);
-    info->props_cache() = gdef.get_glyph_props (info->codepoint);
-  }
-
-  return info->props_cache();
-}
-
-static hb_bool_t
-_hb_ot_layout_match_properties (hb_face_t      *face,
-                               hb_codepoint_t  codepoint,
-                               unsigned int    glyph_props,
-                               unsigned int    lookup_props)
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_face_t      *face,
+                             hb_codepoint_t  glyph)
 {
-  /* Not covered, if, for example, glyph class is ligature and
-   * lookup_props includes LookupFlags::IgnoreLigatures
-   */
-  if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
-    return false;
-
-  if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
-  {
-    /* If using mark filtering sets, the high short of
-     * lookup_props has the set index.
-     */
-    if (lookup_props & LookupFlag::UseMarkFilteringSet)
-      return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
-
-    /* The second byte of lookup_props has the meaning
-     * "ignore marks of attachment type different than
-     * the attachment type specified."
-     */
-    if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
-      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
-  }
-
-  return true;
+  return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
 }
 
-hb_bool_t
-_hb_ot_layout_check_glyph_property (hb_face_t    *face,
-                                   hb_glyph_info_t *ginfo,
-                                   unsigned int  lookup_props,
-                                   unsigned int *property_out)
-{
-  unsigned int property;
-
-  property = _hb_ot_layout_get_glyph_property (face, ginfo);
-  (void) (property_out && (*property_out = property));
-
-  return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
-}
-
-hb_bool_t
-_hb_ot_layout_skip_mark (hb_face_t    *face,
-                        hb_glyph_info_t *ginfo,
-                        unsigned int  lookup_props,
-                        unsigned int *property_out)
+void
+hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
+                                 hb_ot_layout_glyph_class_t  klass,
+                                 hb_set_t                   *glyphs /* OUT */)
 {
-  unsigned int property;
-
-  property = _hb_ot_layout_get_glyph_property (face, ginfo);
-  (void) (property_out && (*property_out = property));
-
-  /* If it's a mark, skip it we don't accept it. */
-  if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
-    return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
-
-  /* If not a mark, don't skip. */
-  return false;
+  return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
 }
 
-
-
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
                                hb_codepoint_t  glyph,
@@ -194,18 +164,19 @@ hb_ot_layout_get_ligature_carets (hb_font_t      *font,
   return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
 }
 
+
 /*
  * GSUB/GPOS
  */
 
-static const GSUBGPOS&
+static const OT::GSUBGPOS&
 get_gsubgpos_table (hb_face_t *face,
                    hb_tag_t   table_tag)
 {
   switch (table_tag) {
     case HB_OT_TAG_GSUB: return _get_gsub (face);
     case HB_OT_TAG_GPOS: return _get_gpos (face);
-    default:             return Null(GSUBGPOS);
+    default:             return OT::Null(OT::GSUBGPOS);
   }
 }
 
@@ -217,19 +188,21 @@ hb_ot_layout_table_get_script_tags (hb_face_t    *face,
                                    unsigned int *script_count /* IN/OUT */,
                                    hb_tag_t     *script_tags /* OUT */)
 {
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   return g.get_script_tags (start_offset, script_count, script_tags);
 }
 
+#define HB_OT_TAG_LATIN_SCRIPT         HB_TAG ('l', 'a', 't', 'n')
+
 hb_bool_t
 hb_ot_layout_table_find_script (hb_face_t    *face,
                                hb_tag_t      table_tag,
                                hb_tag_t      script_tag,
                                unsigned int *script_index)
 {
-  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   if (g.find_script_index (script_tag, script_index))
     return true;
@@ -243,6 +216,11 @@ hb_ot_layout_table_find_script (hb_face_t    *face,
   if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
     return false;
 
+  /* try with 'latn'; some old fonts put their features there even though
+     they're really trying to support Thai, for example :( */
+  if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
+    return false;
+
   if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
   return false;
 }
@@ -254,8 +232,8 @@ hb_ot_layout_table_choose_script (hb_face_t      *face,
                                  unsigned int   *script_index,
                                  hb_tag_t       *chosen_script)
 {
-  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   while (*script_tags)
   {
@@ -283,7 +261,6 @@ hb_ot_layout_table_choose_script (hb_face_t      *face,
 
   /* try with 'latn'; some old fonts put their features there even though
      they're really trying to support Thai, for example :( */
-#define HB_OT_TAG_LATIN_SCRIPT         HB_TAG ('l', 'a', 't', 'n')
   if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
     if (chosen_script)
       *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
@@ -303,7 +280,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
                                     unsigned int *feature_count /* IN/OUT */,
                                     hb_tag_t     *feature_tags /* OUT */)
 {
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
 
   return g.get_feature_tags (start_offset, feature_count, feature_tags);
 }
@@ -317,7 +294,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t    *face,
                                       unsigned int *language_count /* IN/OUT */,
                                       hb_tag_t     *language_tags /* OUT */)
 {
-  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
+  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
 
   return s.get_lang_sys_tags (start_offset, language_count, language_tags);
 }
@@ -329,8 +306,8 @@ hb_ot_layout_script_find_language (hb_face_t    *face,
                                   hb_tag_t      language_tag,
                                   unsigned int *language_index)
 {
-  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
-  const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
 
   if (s.find_lang_sys_index (language_tag, language_index))
     return true;
@@ -350,9 +327,28 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
                                                  unsigned int  language_index,
                                                  unsigned int *feature_index)
 {
-  const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
+  return hb_ot_layout_language_get_required_feature (face,
+                                                    table_tag,
+                                                    script_index,
+                                                    language_index,
+                                                    feature_index,
+                                                    NULL);
+}
 
-  if (feature_index) *feature_index = l.get_required_feature_index ();
+hb_bool_t
+hb_ot_layout_language_get_required_feature (hb_face_t    *face,
+                                           hb_tag_t      table_tag,
+                                           unsigned int  script_index,
+                                           unsigned int  language_index,
+                                           unsigned int *feature_index,
+                                           hb_tag_t     *feature_tag)
+{
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+  unsigned int index = l.get_required_feature_index ();
+  if (feature_index) *feature_index = index;
+  if (feature_tag) *feature_tag = g.get_feature_tag (index);
 
   return l.has_required_feature ();
 }
@@ -366,8 +362,8 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
                                           unsigned int *feature_count /* IN/OUT */,
                                           unsigned int *feature_indexes /* OUT */)
 {
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
-  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
   return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
 }
@@ -381,8 +377,8 @@ hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
                                        unsigned int *feature_count /* IN/OUT */,
                                        hb_tag_t     *feature_tags /* OUT */)
 {
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
-  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
   ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
   unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
@@ -405,9 +401,9 @@ hb_ot_layout_language_find_feature (hb_face_t    *face,
                                    hb_tag_t      feature_tag,
                                    unsigned int *feature_index)
 {
-  ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
-  const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
 
   unsigned int num_features = l.get_feature_count ();
   for (unsigned int i = 0; i < num_features; i++) {
@@ -424,91 +420,576 @@ hb_ot_layout_language_find_feature (hb_face_t    *face,
 }
 
 unsigned int
-hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
-                                        hb_tag_t      table_tag,
-                                        unsigned int  feature_index,
-                                        unsigned int  start_offset,
-                                        unsigned int *lookup_count /* IN/OUT */,
-                                        unsigned int *lookup_indexes /* OUT */)
+hb_ot_layout_feature_get_lookups (hb_face_t    *face,
+                                 hb_tag_t      table_tag,
+                                 unsigned int  feature_index,
+                                 unsigned int  start_offset,
+                                 unsigned int *lookup_count /* IN/OUT */,
+                                 unsigned int *lookup_indexes /* OUT */)
 {
-  const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
-  const Feature &f = g.get_feature (feature_index);
+  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+  const OT::Feature &f = g.get_feature (feature_index);
 
   return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
 }
 
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
+                                    hb_tag_t      table_tag)
+{
+  switch (table_tag)
+  {
+    case HB_OT_TAG_GSUB:
+    {
+      return hb_ot_layout_from_face (face)->gsub_lookup_count;
+    }
+    case HB_OT_TAG_GPOS:
+    {
+      return hb_ot_layout_from_face (face)->gpos_lookup_count;
+    }
+  }
+  return 0;
+}
+
+static void
+_hb_ot_layout_collect_lookups_lookups (hb_face_t      *face,
+                                      hb_tag_t        table_tag,
+                                      unsigned int    feature_index,
+                                      hb_set_t       *lookup_indexes /* OUT */)
+{
+  unsigned int lookup_indices[32];
+  unsigned int offset, len;
+
+  offset = 0;
+  do {
+    len = ARRAY_LENGTH (lookup_indices);
+    hb_ot_layout_feature_get_lookups (face,
+                                     table_tag,
+                                     feature_index,
+                                     offset, &len,
+                                     lookup_indices);
+
+    for (unsigned int i = 0; i < len; i++)
+      lookup_indexes->add (lookup_indices[i]);
+
+    offset += len;
+  } while (len == ARRAY_LENGTH (lookup_indices));
+}
+
+static void
+_hb_ot_layout_collect_lookups_features (hb_face_t      *face,
+                                       hb_tag_t        table_tag,
+                                       unsigned int    script_index,
+                                       unsigned int    language_index,
+                                       const hb_tag_t *features,
+                                       hb_set_t       *lookup_indexes /* OUT */)
+{
+  if (!features)
+  {
+    unsigned int required_feature_index;
+    if (hb_ot_layout_language_get_required_feature (face,
+                                                   table_tag,
+                                                   script_index,
+                                                   language_index,
+                                                   &required_feature_index,
+                                                   NULL))
+      _hb_ot_layout_collect_lookups_lookups (face,
+                                            table_tag,
+                                            required_feature_index,
+                                            lookup_indexes);
+
+    /* All features */
+    unsigned int feature_indices[32];
+    unsigned int offset, len;
+
+    offset = 0;
+    do {
+      len = ARRAY_LENGTH (feature_indices);
+      hb_ot_layout_language_get_feature_indexes (face,
+                                                table_tag,
+                                                script_index,
+                                                language_index,
+                                                offset, &len,
+                                                feature_indices);
+
+      for (unsigned int i = 0; i < len; i++)
+       _hb_ot_layout_collect_lookups_lookups (face,
+                                              table_tag,
+                                              feature_indices[i],
+                                              lookup_indexes);
+
+      offset += len;
+    } while (len == ARRAY_LENGTH (feature_indices));
+  }
+  else
+  {
+    for (; *features; features++)
+    {
+      unsigned int feature_index;
+      if (hb_ot_layout_language_find_feature (face,
+                                             table_tag,
+                                             script_index,
+                                             language_index,
+                                             *features,
+                                             &feature_index))
+        _hb_ot_layout_collect_lookups_lookups (face,
+                                              table_tag,
+                                              feature_index,
+                                              lookup_indexes);
+    }
+  }
+}
+
+static void
+_hb_ot_layout_collect_lookups_languages (hb_face_t      *face,
+                                        hb_tag_t        table_tag,
+                                        unsigned int    script_index,
+                                        const hb_tag_t *languages,
+                                        const hb_tag_t *features,
+                                        hb_set_t       *lookup_indexes /* OUT */)
+{
+  _hb_ot_layout_collect_lookups_features (face,
+                                         table_tag,
+                                         script_index,
+                                         HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+                                         features,
+                                         lookup_indexes);
+
+  if (!languages)
+  {
+    /* All languages */
+    unsigned int count = hb_ot_layout_script_get_language_tags (face,
+                                                               table_tag,
+                                                               script_index,
+                                                               0, NULL, NULL);
+    for (unsigned int language_index = 0; language_index < count; language_index++)
+      _hb_ot_layout_collect_lookups_features (face,
+                                             table_tag,
+                                             script_index,
+                                             language_index,
+                                             features,
+                                             lookup_indexes);
+  }
+  else
+  {
+    for (; *languages; languages++)
+    {
+      unsigned int language_index;
+      if (hb_ot_layout_script_find_language (face,
+                                            table_tag,
+                                            script_index,
+                                            *languages,
+                                            &language_index))
+        _hb_ot_layout_collect_lookups_features (face,
+                                               table_tag,
+                                               script_index,
+                                               language_index,
+                                               features,
+                                               lookup_indexes);
+    }
+  }
+}
+
+void
+hb_ot_layout_collect_lookups (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 */)
+{
+  if (!scripts)
+  {
+    /* All scripts */
+    unsigned int count = hb_ot_layout_table_get_script_tags (face,
+                                                            table_tag,
+                                                            0, NULL, NULL);
+    for (unsigned int script_index = 0; script_index < count; script_index++)
+      _hb_ot_layout_collect_lookups_languages (face,
+                                              table_tag,
+                                              script_index,
+                                              languages,
+                                              features,
+                                              lookup_indexes);
+  }
+  else
+  {
+    for (; *scripts; scripts++)
+    {
+      unsigned int script_index;
+      if (hb_ot_layout_table_find_script (face,
+                                         table_tag,
+                                         *scripts,
+                                         &script_index))
+        _hb_ot_layout_collect_lookups_languages (face,
+                                                table_tag,
+                                                script_index,
+                                                languages,
+                                                features,
+                                                lookup_indexes);
+    }
+  }
+}
+
+void
+hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
+                                   hb_tag_t      table_tag,
+                                   unsigned int  lookup_index,
+                                   hb_set_t     *glyphs_before, /* OUT. May be NULL */
+                                   hb_set_t     *glyphs_input,  /* OUT. May be NULL */
+                                   hb_set_t     *glyphs_after,  /* OUT. May be NULL */
+                                   hb_set_t     *glyphs_output  /* OUT. May be NULL */)
+{
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
+
+  OT::hb_collect_glyphs_context_t c (face,
+                                    glyphs_before,
+                                    glyphs_input,
+                                    glyphs_after,
+                                    glyphs_output);
+
+  switch (table_tag)
+  {
+    case HB_OT_TAG_GSUB:
+    {
+      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+      l.collect_glyphs (&c);
+      return;
+    }
+    case HB_OT_TAG_GPOS:
+    {
+      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
+      l.collect_glyphs (&c);
+      return;
+    }
+  }
+}
+
 
 /*
- * GSUB
+ * OT::GSUB
  */
 
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face)
 {
-  return &_get_gsub (face) != &Null(GSUB);
+  return &_get_gsub (face) != &OT::Null(OT::GSUB);
 }
 
-void
-hb_ot_layout_substitute_start (hb_buffer_t  *buffer)
+hb_bool_t
+hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
+                                     unsigned int          lookup_index,
+                                     const hb_codepoint_t *glyphs,
+                                     unsigned int          glyphs_length,
+                                     hb_bool_t             zero_context)
 {
-  GSUB::substitute_start (buffer);
+  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
+  return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
 }
 
 hb_bool_t
-hb_ot_layout_substitute_lookup (hb_face_t    *face,
-                               hb_buffer_t  *buffer,
-                               unsigned int  lookup_index,
-                               hb_mask_t     mask)
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
+                                          unsigned int          lookup_index,
+                                          const hb_codepoint_t *glyphs,
+                                          unsigned int          glyphs_length,
+                                          hb_bool_t             zero_context)
 {
-  hb_apply_context_t c (NULL, face, buffer, mask);
-  return _get_gsub (face).substitute_lookup (&c, lookup_index);
+  if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
+  OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
+
+  const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+
+  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
 }
 
 void
-hb_ot_layout_substitute_finish (hb_buffer_t  *buffer HB_UNUSED)
+hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
 {
-  GSUB::substitute_finish (buffer);
+  OT::GSUB::substitute_start (font, buffer);
 }
 
 void
-hb_ot_layout_substitute_closure_lookup (hb_face_t    *face,
-                                       hb_set_t     *glyphs,
-                                       unsigned int  lookup_index)
+hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
 {
-  hb_closure_context_t c (face, glyphs);
-  _get_gsub (face).closure_lookup (&c, lookup_index);
+  OT::GSUB::substitute_finish (font, buffer);
+}
+
+void
+hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
+                                       unsigned int  lookup_index,
+                                       hb_set_t     *glyphs)
+{
+  OT::hb_closure_context_t c (face, glyphs);
+
+  const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
+
+  l.closure (&c);
 }
 
 /*
- * GPOS
+ * OT::GPOS
  */
 
 hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face)
 {
-  return &_get_gpos (face) != &Null(GPOS);
+  return &_get_gpos (face) != &OT::Null(OT::GPOS);
 }
 
 void
-hb_ot_layout_position_start (hb_buffer_t  *buffer)
+hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
 {
-  GPOS::position_start (buffer);
+  OT::GPOS::position_start (font, buffer);
+}
+
+void
+hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
+{
+  OT::GPOS::position_finish (font, buffer);
 }
 
 hb_bool_t
-hb_ot_layout_position_lookup   (hb_font_t    *font,
-                               hb_buffer_t  *buffer,
-                               unsigned int  lookup_index,
-                               hb_mask_t     mask)
+hb_ot_layout_get_size_params (hb_face_t    *face,
+                             unsigned int *design_size,       /* OUT.  May be NULL */
+                             unsigned int *subfamily_id,      /* OUT.  May be NULL */
+                             unsigned int *subfamily_name_id, /* OUT.  May be NULL */
+                             unsigned int *range_start,       /* OUT.  May be NULL */
+                             unsigned int *range_end          /* OUT.  May be NULL */)
+{
+  const OT::GPOS &gpos = _get_gpos (face);
+  const hb_tag_t tag = HB_TAG ('s','i','z','e');
+
+  unsigned int num_features = gpos.get_feature_count ();
+  for (unsigned int i = 0; i < num_features; i++)
+  {
+    if (tag == gpos.get_feature_tag (i))
+    {
+      const OT::Feature &f = gpos.get_feature (i);
+      const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
+
+      if (params.designSize)
+      {
+#define PARAM(a, A) if (a) *a = params.A
+       PARAM (design_size, designSize);
+       PARAM (subfamily_id, subfamilyID);
+       PARAM (subfamily_name_id, subfamilyNameID);
+       PARAM (range_start, rangeStart);
+       PARAM (range_end, rangeEnd);
+#undef PARAM
+
+       return true;
+      }
+    }
+  }
+
+#define PARAM(a, A) if (a) *a = 0
+  PARAM (design_size, designSize);
+  PARAM (subfamily_id, subfamilyID);
+  PARAM (subfamily_name_id, subfamilyNameID);
+  PARAM (range_start, rangeStart);
+  PARAM (range_end, rangeEnd);
+#undef PARAM
+
+  return false;
+}
+
+
+/*
+ * Parts of different types are implemented here such that they have direct
+ * access to GSUB/GPOS lookups.
+ */
+
+
+struct GSUBProxy
 {
-  hb_apply_context_t c (font, font->face, buffer, mask);
-  return _get_gpos (font->face).position_lookup (&c, lookup_index);
+  static const unsigned int table_index = 0;
+  static const bool inplace = false;
+  typedef OT::SubstLookup Lookup;
+
+  GSUBProxy (hb_face_t *face) :
+    table (*hb_ot_layout_from_face (face)->gsub),
+    accels (hb_ot_layout_from_face (face)->gsub_accels) {}
+
+  const OT::GSUB &table;
+  const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+struct GPOSProxy
+{
+  static const unsigned int table_index = 1;
+  static const bool inplace = true;
+  typedef OT::PosLookup Lookup;
+
+  GPOSProxy (hb_face_t *face) :
+    table (*hb_ot_layout_from_face (face)->gpos),
+    accels (hb_ot_layout_from_face (face)->gpos_accels) {}
+
+  const OT::GPOS &table;
+  const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+
+template <typename Obj>
+static inline bool
+apply_forward (OT::hb_apply_context_t *c,
+              const Obj &obj,
+              const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  bool ret = false;
+  hb_buffer_t *buffer = c->buffer;
+  while (buffer->idx < buffer->len)
+  {
+    if (accel.may_have (buffer->cur().codepoint) &&
+       (buffer->cur().mask & c->lookup_mask) &&
+       c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
+       obj.apply (c))
+      ret = true;
+    else
+      buffer->next_glyph ();
+  }
+  return ret;
 }
 
-void
-hb_ot_layout_position_finish (hb_buffer_t  *buffer)
+template <typename Obj>
+static inline bool
+apply_backward (OT::hb_apply_context_t *c,
+               const Obj &obj,
+               const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  bool ret = false;
+  hb_buffer_t *buffer = c->buffer;
+  do
+  {
+    if (accel.may_have (buffer->cur().codepoint) &&
+       (buffer->cur().mask & c->lookup_mask) &&
+       c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
+       obj.apply (c))
+      ret = true;
+    /* The reverse lookup doesn't "advance" cursor (for good reason). */
+    buffer->idx--;
+
+  }
+  while ((int) buffer->idx >= 0);
+  return ret;
+}
+
+struct hb_apply_forward_context_t
+{
+  inline const char *get_name (void) { return "APPLY_FORWARD"; }
+  static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+  typedef bool return_t;
+  template <typename T, typename F>
+  inline bool may_dispatch (const T *obj, const F *format) { return true; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
+
+  hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
+                             const hb_ot_layout_lookup_accelerator_t &accel_) :
+                               c (c_),
+                               accel (accel_),
+                               debug_depth (0) {}
+
+  OT::hb_apply_context_t *c;
+  const hb_ot_layout_lookup_accelerator_t &accel;
+  unsigned int debug_depth;
+};
+
+template <typename Proxy>
+static inline void
+apply_string (OT::hb_apply_context_t *c,
+             const typename Proxy::Lookup &lookup,
+             const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  hb_buffer_t *buffer = c->buffer;
+
+  if (unlikely (!buffer->len || !c->lookup_mask))
+    return;
+
+  c->set_lookup (lookup);
+
+  if (likely (!lookup.is_reverse ()))
+  {
+    /* in/out forward substitution/positioning */
+    if (Proxy::table_index == 0)
+      buffer->clear_output ();
+    buffer->idx = 0;
+
+    bool ret;
+    if (lookup.get_subtable_count () == 1)
+    {
+      hb_apply_forward_context_t c_forward (c, accel);
+      ret = lookup.dispatch (&c_forward);
+    }
+    else
+      ret = apply_forward (c, lookup, accel);
+    if (ret)
+    {
+      if (!Proxy::inplace)
+       buffer->swap_buffers ();
+      else
+       assert (!buffer->has_separate_output ());
+    }
+  }
+  else
+  {
+    /* in-place backward substitution/positioning */
+    if (Proxy::table_index == 0)
+      buffer->remove_output ();
+    buffer->idx = buffer->len - 1;
+
+    apply_backward (c, lookup, accel);
+  }
+}
+
+template <typename Proxy>
+inline void hb_ot_map_t::apply (const Proxy &proxy,
+                               const hb_ot_shape_plan_t *plan,
+                               hb_font_t *font,
+                               hb_buffer_t *buffer) const
+{
+  const unsigned int table_index = proxy.table_index;
+  unsigned int i = 0;
+  OT::hb_apply_context_t c (table_index, font, buffer);
+  c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+
+  for (unsigned int stage_index = 0; stage_index < stages[table_index].len; 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;
+      c.set_lookup_mask (lookups[table_index][i].mask);
+      c.set_auto_zwj (lookups[table_index][i].auto_zwj);
+      apply_string<Proxy> (&c,
+                          proxy.table.get_lookup (lookup_index),
+                          proxy.accels[lookup_index]);
+    }
+
+    if (stage->pause_func)
+    {
+      buffer->clear_output ();
+      stage->pause_func (plan, font, buffer);
+    }
+  }
+}
+
+void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
 {
-  GPOS::position_finish (buffer);
+  GSUBProxy proxy (font->face);
+  apply (proxy, plan, font, buffer);
 }
 
+void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+  GPOSProxy proxy (font->face);
+  apply (proxy, plan, font, buffer);
+}
 
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+                               const OT::SubstLookup &lookup,
+                               const hb_ot_layout_lookup_accelerator_t &accel)
+{
+  apply_string<GSUBProxy> (c, lookup, accel);
+}
index b8b5baf..949678a 100644 (file)
@@ -41,6 +41,8 @@ HB_BEGIN_DECLS
 #define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
 #define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
 #define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
+#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
+
 
 /*
  * GDEF
@@ -49,6 +51,24 @@ HB_BEGIN_DECLS
 hb_bool_t
 hb_ot_layout_has_glyph_classes (hb_face_t *face);
 
+typedef enum {
+  HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED        = 0,
+  HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH  = 1,
+  HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE    = 2,
+  HB_OT_LAYOUT_GLYPH_CLASS_MARK                = 3,
+  HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT   = 4
+} hb_ot_layout_glyph_class_t;
+
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_face_t      *face,
+                             hb_codepoint_t  glyph);
+
+void
+hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
+                                 hb_ot_layout_glyph_class_t  klass,
+                                 hb_set_t                   *glyphs /* OUT */);
+
+
 /* Not that useful.  Provides list of attach points for a glyph that a
  * client may want to cache */
 unsigned int
@@ -72,9 +92,9 @@ hb_ot_layout_get_ligature_carets (hb_font_t      *font,
  * GSUB/GPOS feature query and enumeration interface
  */
 
-#define HB_OT_LAYOUT_NO_SCRIPT_INDEX           ((unsigned int) 0xFFFF)
-#define HB_OT_LAYOUT_NO_FEATURE_INDEX          ((unsigned int) 0xFFFF)
-#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX    ((unsigned int) 0xFFFF)
+#define HB_OT_LAYOUT_NO_SCRIPT_INDEX           0xFFFFu
+#define HB_OT_LAYOUT_NO_FEATURE_INDEX          0xFFFFu
+#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX    0xFFFFu
 
 unsigned int
 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
@@ -126,6 +146,14 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
                                                  unsigned int  language_index,
                                                  unsigned int *feature_index);
 
+hb_bool_t
+hb_ot_layout_language_get_required_feature (hb_face_t    *face,
+                                           hb_tag_t      table_tag,
+                                           unsigned int  script_index,
+                                           unsigned int  language_index,
+                                           unsigned int *feature_index,
+                                           hb_tag_t     *feature_tag);
+
 unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
                                           hb_tag_t      table_tag,
@@ -153,12 +181,60 @@ hb_ot_layout_language_find_feature (hb_face_t    *face,
                                    unsigned int *feature_index);
 
 unsigned int
-hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
+hb_ot_layout_feature_get_lookups (hb_face_t    *face,
+                                 hb_tag_t      table_tag,
+                                 unsigned int  feature_index,
+                                 unsigned int  start_offset,
+                                 unsigned int *lookup_count /* IN/OUT */,
+                                 unsigned int *lookup_indexes /* OUT */);
+
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
+                                    hb_tag_t      table_tag);
+
+
+void
+hb_ot_layout_collect_lookups (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 */);
+
+void
+hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
+                                   hb_tag_t      table_tag,
+                                   unsigned int  lookup_index,
+                                   hb_set_t     *glyphs_before, /* OUT. May be NULL */
+                                   hb_set_t     *glyphs_input,  /* OUT. May be NULL */
+                                   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);
+
+void
+Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t    *face,
                                         hb_tag_t      table_tag,
-                                        unsigned int  feature_index,
-                                        unsigned int  start_offset,
-                                        unsigned int *lookup_count /* IN/OUT */,
-                                        unsigned int *lookup_indexes /* OUT */);
+                                        unsigned int  lookup_index,
+                                        hb_ot_layout_glyph_sequence_func_t callback,
+                                        void         *user_data);
+#endif
 
 
 /*
@@ -168,25 +244,31 @@ hb_ot_layout_feature_get_lookup_indexes (hb_face_t    *face,
 hb_bool_t
 hb_ot_layout_has_substitution (hb_face_t *face);
 
-/* Should be called before all the substitute_lookup's are done. */
-void
-hb_ot_layout_substitute_start (hb_buffer_t  *buffer);
-
 hb_bool_t
-hb_ot_layout_substitute_lookup (hb_face_t    *face,
-                               hb_buffer_t  *buffer,
-                               unsigned int  lookup_index,
-                               hb_mask_t     mask);
+hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
+                                     unsigned int          lookup_index,
+                                     const hb_codepoint_t *glyphs,
+                                     unsigned int          glyphs_length,
+                                     hb_bool_t             zero_context);
 
-/* Should be called after all the substitute_lookup's are done */
 void
-hb_ot_layout_substitute_finish (hb_buffer_t  *buffer);
+hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
+                                       unsigned int  lookup_index,
+                                       hb_set_t     *glyphs
+                                       /*TODO , hb_bool_t  inclusive */);
 
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
+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
 
-void
-hb_ot_layout_substitute_closure_lookup (hb_face_t    *face,
-                                       hb_set_t     *glyphs,
-                                       unsigned int  lookup_index);
 
 /*
  * GPOS
@@ -195,19 +277,24 @@ hb_ot_layout_substitute_closure_lookup (hb_face_t    *face,
 hb_bool_t
 hb_ot_layout_has_positioning (hb_face_t *face);
 
-/* Should be called before all the position_lookup's are done.  Resets positions to zero. */
-void
-hb_ot_layout_position_start (hb_buffer_t  *buffer);
-
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
 hb_bool_t
-hb_ot_layout_position_lookup (hb_font_t    *font,
-                             hb_buffer_t  *buffer,
-                             unsigned int  lookup_index,
-                             hb_mask_t     mask);
+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
 
-/* Should be called after all the position_lookup's are done */
-void
-hb_ot_layout_position_finish (hb_buffer_t  *buffer);
+/* Optical 'size' feature info.  Returns true if found.
+ * http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+hb_bool_t
+hb_ot_layout_get_size_params (hb_face_t    *face,
+                             unsigned int *design_size,       /* OUT.  May be NULL */
+                             unsigned int *subfamily_id,      /* OUT.  May be NULL */
+                             unsigned int *subfamily_name_id, /* OUT.  May be NULL */
+                             unsigned int *range_start,       /* OUT.  May be NULL */
+                             unsigned int *range_end          /* OUT.  May be NULL */);
 
 
 HB_END_DECLS
index 3811206..86b7e9f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2009,2010  Red Hat, Inc.
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2010,2011,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -31,9 +31,8 @@
 
 #include "hb-buffer-private.hh"
 
-#include "hb-ot-layout.h"
-
 
+struct hb_ot_shape_plan_t;
 
 static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
 
@@ -43,46 +42,6 @@ struct hb_ot_map_t
 
   public:
 
-  hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
-
-  typedef void (*gsub_pause_func_t) (const hb_ot_map_t *map, hb_face_t *face, hb_buffer_t *buffer, void *user_data);
-  typedef void (*gpos_pause_func_t) (const hb_ot_map_t *map, hb_font_t *font, hb_buffer_t *buffer, void *user_data);
-
-  inline hb_mask_t get_global_mask (void) const { return global_mask; }
-
-  inline hb_mask_t get_mask (hb_tag_t tag, unsigned int *shift = NULL) const {
-    const feature_map_t *map = features.bsearch (&tag);
-    if (shift) *shift = map ? map->shift : 0;
-    return map ? map->mask : 0;
-  }
-
-  inline hb_mask_t get_1_mask (hb_tag_t tag) const {
-    const feature_map_t *map = features.bsearch (&tag);
-    return map ? map->_1_mask : 0;
-  }
-
-  inline hb_tag_t get_chosen_script (unsigned int table_index) const
-  { return chosen_script[table_index]; }
-
-  inline void substitute (hb_face_t *face, hb_buffer_t *buffer) const
-  { apply (0, (hb_ot_map_t::apply_lookup_func_t) hb_ot_layout_substitute_lookup, face, buffer); }
-  inline void position (hb_font_t *font, hb_buffer_t *buffer) const
-  { apply (1, (hb_ot_map_t::apply_lookup_func_t) hb_ot_layout_position_lookup, font, buffer); }
-
-  HB_INTERNAL void substitute_closure (hb_face_t *face,
-                                      hb_set_t *glyphs) const;
-
-
-  inline void finish (void) {
-    features.finish ();
-    lookups[0].finish ();
-    lookups[1].finish ();
-    pauses[0].finish ();
-    pauses[1].finish ();
-  }
-
-  private:
-
   struct feature_map_t {
     hb_tag_t tag; /* should be first for our bsearch to work */
     unsigned int index[2]; /* GSUB/GPOS */
@@ -90,78 +49,160 @@ struct hb_ot_map_t
     unsigned int shift;
     hb_mask_t mask;
     hb_mask_t _1_mask; /* mask for value=1, for quick access */
+    unsigned int needs_fallback : 1;
+    unsigned int auto_zwj : 1;
 
     static int cmp (const feature_map_t *a, const feature_map_t *b)
     { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
   };
 
   struct lookup_map_t {
-    unsigned int index;
+    unsigned short index;
+    unsigned short auto_zwj : 1;
     hb_mask_t mask;
 
     static int cmp (const lookup_map_t *a, const lookup_map_t *b)
     { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
   };
 
-  typedef void (*pause_func_t) (const hb_ot_map_t *map, void *face_or_font, hb_buffer_t *buffer, void *user_data);
-  typedef struct {
-    pause_func_t func;
-    void *user_data;
-  } pause_callback_t;
+  typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
 
-  struct pause_map_t {
-    unsigned int num_lookups; /* Cumulative */
-    pause_callback_t callback;
+  struct stage_map_t {
+    unsigned int last_lookup; /* Cumulative */
+    pause_func_t pause_func;
   };
 
-  typedef hb_bool_t (*apply_lookup_func_t) (void *face_or_font,
-                                           hb_buffer_t  *buffer,
-                                           unsigned int  lookup_index,
-                                           hb_mask_t     mask);
+
+  hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
+
+  inline hb_mask_t get_global_mask (void) const { return global_mask; }
+
+  inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = NULL) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    if (shift) *shift = map ? map->shift : 0;
+    return map ? map->mask : 0;
+  }
+
+  inline bool needs_fallback (hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->needs_fallback : false;
+  }
+
+  inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->_1_mask : 0;
+  }
+
+  inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
+  }
+
+  inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
+    const feature_map_t *map = features.bsearch (&feature_tag);
+    return map ? map->stage[table_index] : (unsigned int) -1;
+  }
+
+  inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
+                                const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
+    if (unlikely (stage == (unsigned int) -1)) {
+      *plookups = NULL;
+      *lookup_count = 0;
+      return;
+    }
+    assert (stage <= stages[table_index].len);
+    unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
+    unsigned int end   = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
+    *plookups = &lookups[table_index][start];
+    *lookup_count = end - start;
+  }
+
+  HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
+  template <typename Proxy>
+  HB_INTERNAL inline void apply (const Proxy &proxy,
+                                const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+  HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+
+  inline void finish (void) {
+    features.finish ();
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      lookups[table_index].finish ();
+      stages[table_index].finish ();
+    }
+  }
+
+  public:
+  hb_tag_t chosen_script[2];
+  bool found_script[2];
+
+  private:
 
   HB_INTERNAL void add_lookups (hb_face_t    *face,
                                unsigned int  table_index,
                                unsigned int  feature_index,
-                               hb_mask_t     mask);
-
-  HB_INTERNAL void apply (unsigned int table_index,
-                         hb_ot_map_t::apply_lookup_func_t apply_lookup_func,
-                         void *face_or_font,
-                         hb_buffer_t *buffer) const;
+                               hb_mask_t     mask,
+                               bool          auto_zwj);
 
   hb_mask_t global_mask;
 
-  hb_tag_t chosen_script[2];
   hb_prealloced_array_t<feature_map_t, 8> features;
   hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */
-  hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */
+  hb_prealloced_array_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
+};
+
+enum hb_ot_map_feature_flags_t {
+  F_NONE               = 0x0000u,
+  F_GLOBAL             = 0x0001u,
+  F_HAS_FALLBACK       = 0x0002u,
+  F_MANUAL_ZWJ         = 0x0004u
 };
+/* Macro version for where const is desired. */
+#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
+static inline hb_ot_map_feature_flags_t
+operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
+static inline hb_ot_map_feature_flags_t
+operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
+static inline hb_ot_map_feature_flags_t
+operator ~ (hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
+static inline hb_ot_map_feature_flags_t&
+operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
+{ l = l | r; return l; }
+static inline hb_ot_map_feature_flags_t&
+operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
+{ l = l & r; return l; }
 
 
 struct hb_ot_map_builder_t
 {
   public:
 
-  hb_ot_map_builder_t (void) { memset (this, 0, sizeof (*this)); }
+  HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
+                                  const hb_segment_properties_t *props_);
 
-  HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global);
+  HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value,
+                               hb_ot_map_feature_flags_t flags);
 
-  inline void add_bool_feature (hb_tag_t tag, bool global = true)
-  { add_feature (tag, 1, global); }
+  inline void add_global_bool_feature (hb_tag_t tag)
+  { add_feature (tag, 1, F_GLOBAL); }
 
-  inline void add_gsub_pause (hb_ot_map_t::gsub_pause_func_t pause_func, void *user_data)
-  { add_pause (0, (hb_ot_map_t::pause_func_t) pause_func, user_data); }
-  inline void add_gpos_pause (hb_ot_map_t::gpos_pause_func_t pause_func, void *user_data)
-  { add_pause (1, (hb_ot_map_t::pause_func_t) pause_func, user_data); }
+  inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
+  { add_pause (0, pause_func); }
+  inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
+  { add_pause (1, pause_func); }
 
-  HB_INTERNAL void compile (hb_face_t *face,
-                           const hb_segment_properties_t *props,
-                           struct hb_ot_map_t &m);
+  HB_INTERNAL void compile (struct hb_ot_map_t &m);
 
   inline void finish (void) {
     feature_infos.finish ();
-    pauses[0].finish ();
-    pauses[1].finish ();
+    for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      stages[table_index].finish ();
+    }
   }
 
   private:
@@ -170,7 +211,7 @@ struct hb_ot_map_builder_t
     hb_tag_t tag;
     unsigned int seq; /* sequence#, used for stable sorting only */
     unsigned int max_value;
-    bool global; /* whether the feature applies value to every glyph in the buffer */
+    hb_ot_map_feature_flags_t flags;
     unsigned int default_value; /* for non-global features, what should the unset glyphs take */
     unsigned int stage[2]; /* GSUB/GPOS */
 
@@ -178,16 +219,27 @@ struct hb_ot_map_builder_t
     { return (a->tag != b->tag) ?  (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); }
   };
 
-  struct pause_info_t {
-    unsigned int stage;
-    hb_ot_map_t::pause_callback_t callback;
+  struct stage_info_t {
+    unsigned int index;
+    hb_ot_map_t::pause_func_t pause_func;
   };
 
-  HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data);
+  HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
+
+  public:
+
+  hb_face_t *face;
+  hb_segment_properties_t props;
+
+  hb_tag_t chosen_script[2];
+  bool found_script[2];
+  unsigned int script_index[2], language_index[2];
+
+  private:
 
   unsigned int current_stage[2]; /* GSUB/GPOS */
-  hb_prealloced_array_t<feature_info_t,16> feature_infos;
-  hb_prealloced_array_t<pause_info_t, 1> pauses[2]; /* GSUB/GPOS */
+  hb_prealloced_array_t<feature_info_t, 32> feature_infos;
+  hb_prealloced_array_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */
 };
 
 
index bebf3ed..4985eb2 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2009,2010  Red Hat, Inc.
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2010,2011,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 
 #include "hb-ot-map-private.hh"
 
-#include "hb-ot-shape-private.hh"
-
+#include "hb-ot-layout-private.hh"
 
 
 void
 hb_ot_map_t::add_lookups (hb_face_t    *face,
                          unsigned int  table_index,
                          unsigned int  feature_index,
-                         hb_mask_t     mask)
+                         hb_mask_t     mask,
+                         bool          auto_zwj)
 {
   unsigned int lookup_indices[32];
   unsigned int offset, len;
+  unsigned int table_lookup_count;
+
+  table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
 
   offset = 0;
   do {
     len = ARRAY_LENGTH (lookup_indices);
-    hb_ot_layout_feature_get_lookup_indexes (face,
-                                            table_tags[table_index],
-                                            feature_index,
-                                            offset, &len,
-                                            lookup_indices);
+    hb_ot_layout_feature_get_lookups (face,
+                                     table_tags[table_index],
+                                     feature_index,
+                                     offset, &len,
+                                     lookup_indices);
 
-    for (unsigned int i = 0; i < len; i++) {
+    for (unsigned int i = 0; i < len; i++)
+    {
+      if (lookup_indices[i] >= table_lookup_count)
+       continue;
       hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
       if (unlikely (!lookup))
         return;
       lookup->mask = mask;
       lookup->index = lookup_indices[i];
+      lookup->auto_zwj = auto_zwj;
     }
 
     offset += len;
   } while (len == ARRAY_LENGTH (lookup_indices));
 }
 
+hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
+                                         const hb_segment_properties_t *props_)
+{
+  memset (this, 0, sizeof (*this));
+
+  face = face_;
+  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. */
+
+  hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
+  hb_tag_t language_tag;
+
+  hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
+  language_tag = hb_ot_tag_from_language (props.language);
+
+  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+    hb_tag_t table_tag = table_tags[table_index];
+    found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
+    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+  }
+}
 
-void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global)
+void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
+                                      hb_ot_map_feature_flags_t flags)
 {
   feature_info_t *info = feature_infos.push();
   if (unlikely (!info)) return;
+  if (unlikely (!tag)) return;
   info->tag = tag;
   info->seq = feature_infos.len;
   info->max_value = value;
-  info->global = global;
-  info->default_value = global ? value : 0;
+  info->flags = flags;
+  info->default_value = (flags & F_GLOBAL) ? value : 0;
   info->stage[0] = current_stage[0];
   info->stage[1] = current_stage[1];
 }
 
-void hb_ot_map_t::apply (unsigned int table_index,
-                        hb_ot_map_t::apply_lookup_func_t apply_lookup_func,
-                        void *face_or_font,
-                        hb_buffer_t *buffer) const
-{
-  unsigned int i = 0;
-
-  for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
-    const pause_map_t *pause = &pauses[table_index][pause_index];
-    for (; i < pause->num_lookups; i++)
-      apply_lookup_func (face_or_font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
-
-    pause->callback.func (this, face_or_font, buffer, pause->callback.user_data);
-  }
-
-  for (; i < lookups[table_index].len; i++)
-    apply_lookup_func (face_or_font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
-}
 
-void hb_ot_map_t::substitute_closure (hb_face_t *face,
-                                     hb_set_t *glyphs) const
+void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
 {
-  unsigned int table_index = 0;
-  unsigned int i = 0;
-
-  for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
-    const pause_map_t *pause = &pauses[table_index][pause_index];
-    for (; i < pause->num_lookups; i++)
-      hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index);
-  }
-
-  for (; i < lookups[table_index].len; i++)
-    hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index);
+  for (unsigned int i = 0; i < lookups[table_index].len; i++)
+    hb_set_add (lookups_out, lookups[table_index][i].index);
 }
 
-void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data)
+void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
 {
-  if (pause_func) {
-    pause_info_t *p = pauses[table_index].push ();
-    if (likely (p)) {
-      p->stage = current_stage[table_index];
-      p->callback.func = pause_func;
-      p->callback.user_data = user_data;
-    }
+  stage_info_t *s = stages[table_index].push ();
+  if (likely (s)) {
+    s->index = current_stage[table_index];
+    s->pause_func = pause_func;
   }
 
   current_stage[table_index]++;
 }
 
 void
-hb_ot_map_builder_t::compile (hb_face_t *face,
-                             const hb_segment_properties_t *props,
-                             hb_ot_map_t &m)
+hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 {
- m.global_mask = 1;
 m.global_mask = 1;
 
-  if (!feature_infos.len)
-    return;
-
-
-  /* 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. */
-
-  hb_tag_t script_tags[3] = {HB_TAG_NONE};
-  hb_tag_t language_tag;
-
-  hb_ot_tags_from_script (props->script, &script_tags[0], &script_tags[1]);
-  language_tag = hb_ot_tag_from_language (props->language);
+  unsigned int required_feature_index[2];
+  hb_tag_t required_feature_tag[2];
+  /* We default to applying required feature in stage 0.  If the required
+   * feature has a tag that is known to the shaper, we apply required feature
+   * in the stage for that tag.
+   */
+  unsigned int required_feature_stage[2] = {0, 0};
 
-  unsigned int script_index[2], language_index[2];
-  for (unsigned int table_index = 0; table_index < 2; table_index++) {
-    hb_tag_t table_tag = table_tags[table_index];
-    hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &m.chosen_script[table_index]);
-    hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
+    m.chosen_script[table_index] = chosen_script[table_index];
+    m.found_script[table_index] = found_script[table_index];
+
+    hb_ot_layout_language_get_required_feature (face,
+                                               table_tags[table_index],
+                                               script_index[table_index],
+                                               language_index[table_index],
+                                               &required_feature_index[table_index],
+                                               &required_feature_tag[table_index]);
   }
 
+  if (!feature_infos.len)
+    return;
 
   /* Sort features and merge duplicates */
   {
-    feature_infos.sort ();
+    feature_infos.qsort ();
     unsigned int j = 0;
     for (unsigned int i = 1; i < feature_infos.len; i++)
       if (feature_infos[i].tag != feature_infos[j].tag)
        feature_infos[++j] = feature_infos[i];
       else {
-       if (feature_infos[i].global) {
-         feature_infos[j].global = true;
+       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;
        } else {
-         feature_infos[j].global = false;
+         feature_infos[j].flags &= ~F_GLOBAL;
          feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
+         /* Inherit default_value from j */
        }
+       feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
        feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
        feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
-       /* Inherit default_value from j */
       }
     feature_infos.shrink (j + 1);
   }
@@ -179,12 +183,13 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
 
   /* Allocate bits now */
   unsigned int next_bit = 1;
-  for (unsigned int i = 0; i < feature_infos.len; i++) {
+  for (unsigned int i = 0; i < feature_infos.len; i++)
+  {
     const feature_info_t *info = &feature_infos[i];
 
     unsigned int bits_needed;
 
-    if (info->global && info->max_value == 1)
+    if ((info->flags & F_GLOBAL) && info->max_value == 1)
       /* Uses the global bit */
       bits_needed = 0;
     else
@@ -194,16 +199,24 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
       continue; /* Feature disabled, or not enough bits. */
 
 
-    bool found = false;
+    hb_bool_t found = false;
     unsigned int feature_index[2];
     for (unsigned int table_index = 0; table_index < 2; table_index++)
+    {
+      if (required_feature_tag[table_index] == info->tag)
+      {
+       required_feature_stage[table_index] = info->stage[table_index];
+       found = true;
+       continue;
+      }
       found |= hb_ot_layout_language_find_feature (face,
                                                   table_tags[table_index],
                                                   script_index[table_index],
                                                   language_index[table_index],
                                                   info->tag,
                                                   &feature_index[table_index]);
-    if (!found)
+    }
+    if (!found && !(info->flags & F_HAS_FALLBACK))
       continue;
 
 
@@ -216,7 +229,8 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
     map->index[1] = feature_index[1];
     map->stage[0] = info->stage[0];
     map->stage[1] = info->stage[1];
-    if (info->global && info->max_value == 1) {
+    map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
+    if ((info->flags & F_GLOBAL) && info->max_value == 1) {
       /* Uses the global bit */
       map->shift = 0;
       map->mask = 1;
@@ -224,66 +238,68 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
       map->shift = next_bit;
       map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
       next_bit += bits_needed;
-      if (info->global)
-       m.global_mask |= (info->default_value << map->shift) & map->mask;
+      m.global_mask |= (info->default_value << map->shift) & map->mask;
     }
     map->_1_mask = (1 << map->shift) & map->mask;
+    map->needs_fallback = !found;
 
   }
   feature_infos.shrink (0); /* Done with these */
 
 
-  add_gsub_pause (NULL, NULL);
-  add_gpos_pause (NULL, NULL);
-
-  for (unsigned int table_index = 0; table_index < 2; table_index++) {
-    hb_tag_t table_tag = table_tags[table_index];
+  add_gsub_pause (NULL);
+  add_gpos_pause (NULL);
 
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
     /* Collect lookup indices for features */
 
-    unsigned int required_feature_index;
-    if (hb_ot_layout_language_get_required_feature_index (face,
-                                                         table_tag,
-                                                         script_index[table_index],
-                                                         language_index[table_index],
-                                                         &required_feature_index))
-      m.add_lookups (face, table_index, required_feature_index, 1);
-
-    unsigned int pause_index = 0;
+    unsigned int stage_index = 0;
     unsigned int last_num_lookups = 0;
     for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
     {
+      if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
+         required_feature_stage[table_index] == stage)
+       m.add_lookups (face, table_index,
+                      required_feature_index[table_index],
+                      1 /* mask */,
+                      true /* auto_zwj */);
+
       for (unsigned i = 0; i < m.features.len; i++)
         if (m.features[i].stage[table_index] == stage)
-         m.add_lookups (face, table_index, m.features[i].index[table_index], m.features[i].mask);
+         m.add_lookups (face, table_index,
+                        m.features[i].index[table_index],
+                        m.features[i].mask,
+                        m.features[i].auto_zwj);
 
       /* Sort lookups and merge duplicates */
       if (last_num_lookups < m.lookups[table_index].len)
       {
-       m.lookups[table_index].sort (last_num_lookups, m.lookups[table_index].len);
+       m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len);
 
        unsigned int j = last_num_lookups;
        for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)
          if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
            m.lookups[table_index][++j] = m.lookups[table_index][i];
          else
+         {
            m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
+           m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
+         }
        m.lookups[table_index].shrink (j + 1);
       }
 
       last_num_lookups = m.lookups[table_index].len;
 
-      if (pause_index < pauses[table_index].len && pauses[table_index][pause_index].stage == stage) {
-       hb_ot_map_t::pause_map_t *pause_map = m.pauses[table_index].push ();
-       if (likely (pause_map)) {
-         pause_map->num_lookups = last_num_lookups;
-         pause_map->callback = pauses[table_index][pause_index].callback;
+      if (stage_index < stages[table_index].len && stages[table_index][stage_index].index == stage) {
+       hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
+       if (likely (stage_map)) {
+         stage_map->last_lookup = last_num_lookups;
+         stage_map->pause_func = stages[table_index][stage_index].pause_func;
        }
 
-       pause_index++;
+       stage_index++;
       }
     }
   }
 }
-
-
index e270490..0d9a0fa 100644 (file)
@@ -30,6 +30,8 @@
 #include "hb-open-type-private.hh"
 
 
+namespace OT {
+
 
 /*
  * maxp -- The Maximum Profile Table
 
 struct maxp
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_maxp;
+  static const hb_tag_t tableTag       = HB_OT_TAG_maxp;
 
-  inline unsigned int get_num_glyphs (void) const {
+  inline unsigned int get_num_glyphs (void) const
+  {
     return numGlyphs;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
-                        likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000)));
+                        likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000u)));
   }
 
   /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
-  private:
+  protected:
   FixedVersion version;                /* Version of the maxp table (0.5 or 1.0),
-                                        * 0x00005000 or 0x00010000. */
+                                        * 0x00005000u or 0x00010000u. */
   USHORT       numGlyphs;              /* The number of glyphs in the font. */
   public:
   DEFINE_SIZE_STATIC (6);
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_MAXP_TABLE_HH */
index 9077c8c..21450c6 100644 (file)
@@ -30,6 +30,8 @@
 #include "hb-open-type-private.hh"
 
 
+namespace OT {
+
 
 /*
  * name -- The Naming Table
@@ -54,8 +56,9 @@ struct NameRecord
     return 0;
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
     /* We can check from base all the way up to the end of string... */
     return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
   }
@@ -72,7 +75,7 @@ struct NameRecord
 
 struct name
 {
-  static const hb_tag_t Tag    = HB_OT_TAG_name;
+  static const hb_tag_t tableTag       = HB_OT_TAG_name;
 
   inline unsigned int get_name (unsigned int platform_id,
                                unsigned int encoding_id,
@@ -96,8 +99,11 @@ struct name
     return length;
   }
 
-  inline bool sanitize_records (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline unsigned int get_size (void) const
+  { return min_size + count * nameRecord[0].min_size; }
+
+  inline bool sanitize_records (hb_sanitize_context_t *c) const {
+    TRACE_SANITIZE (this);
     char *string_pool = (char *) this + stringOffset;
     unsigned int _count = count;
     for (unsigned int i = 0; i < _count; i++)
@@ -105,8 +111,9 @@ struct name
     return TRACE_RETURN (true);
   }
 
-  inline bool sanitize (hb_sanitize_context_t *c) {
-    TRACE_SANITIZE ();
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
     return TRACE_RETURN (c->check_struct (this) &&
                         likely (format == 0 || format == 1) &&
                         c->check_array (nameRecord, nameRecord[0].static_size, count) &&
@@ -114,15 +121,16 @@ struct name
   }
 
   /* We only implement format 0 for now. */
-  private:
   USHORT       format;                 /* Format selector (=0/1). */
   USHORT       count;                  /* Number of name records. */
-  Offset       stringOffset;           /* Offset to start of string storage (from start of table). */
+  Offset<>     stringOffset;           /* Offset to start of string storage (from start of table). */
   NameRecord   nameRecord[VAR];        /* The name records where count is the number of records. */
   public:
   DEFINE_SIZE_ARRAY (6, nameRecord);
 };
 
 
+} /* namespace OT */
+
 
 #endif /* HB_OT_NAME_TABLE_HH */
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
new file mode 100644 (file)
index 0000000..a77f24e
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * 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_ARABIC_FALLBACK_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-private.hh"
+#include "hb-ot-layout-gsub-table.hh"
+
+
+/* Features ordered the same as the entries in shaping_table rows,
+ * followed by rlig.  Don't change. */
+static const hb_tag_t arabic_fallback_features[] =
+{
+  HB_TAG('i','n','i','t'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('f','i','n','a'),
+  HB_TAG('i','s','o','l'),
+  HB_TAG('r','l','i','g'),
+};
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                         hb_font_t *font,
+                                         unsigned int feature_index)
+{
+  OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+  unsigned int num_glyphs = 0;
+
+  /* Populate arrays */
+  for (hb_codepoint_t u = SHAPING_TABLE_FIRST; u < SHAPING_TABLE_LAST + 1; u++)
+  {
+    hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST][feature_index];
+    hb_codepoint_t u_glyph, s_glyph;
+
+    if (!s ||
+       !hb_font_get_glyph (font, u, 0, &u_glyph) ||
+       !hb_font_get_glyph (font, s, 0, &s_glyph) ||
+       u_glyph == s_glyph ||
+       u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
+      continue;
+
+    glyphs[num_glyphs].set (u_glyph);
+    substitutes[num_glyphs].set (s_glyph);
+
+    num_glyphs++;
+  }
+
+  if (!num_glyphs)
+    return NULL;
+
+  /* Bubble-sort!
+   * May not be good-enough for presidential candidate interviews, but good-enough for us... */
+  hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
+
+  OT::Supplier<OT::GlyphID> glyphs_supplier      (glyphs, num_glyphs);
+  OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
+
+  /* Each glyph takes four bytes max, and there's some overhead. */
+  char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128];
+  OT::hb_serialize_context_t c (buf, sizeof (buf));
+  OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
+  bool ret = lookup->serialize_single (&c,
+                                      OT::LookupFlag::IgnoreMarks,
+                                      glyphs_supplier,
+                                      substitutes_supplier,
+                                      num_glyphs);
+  c.end_serialize ();
+  /* TODO sanitize the results? */
+
+  return ret ? c.copy<OT::SubstLookup> () : NULL;
+}
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                           hb_font_t *font)
+{
+  OT::GlyphID 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 */
+  OT::GlyphID 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::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+  unsigned int num_ligatures = 0;
+
+  /* Populate arrays */
+
+  /* Sort out the first-glyphs */
+  for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++)
+  {
+    hb_codepoint_t first_u = ligature_table[first_glyph_idx].first;
+    hb_codepoint_t first_glyph;
+    if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
+      continue;
+    first_glyphs[num_first_glyphs].set (first_glyph);
+    ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
+    first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
+    num_first_glyphs++;
+  }
+  hb_bubble_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+
+  /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
+  for (unsigned int i = 0; i < num_first_glyphs; i++)
+  {
+    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++)
+    {
+      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))
+       continue;
+
+      ligature_per_first_glyph_count_list[i]++;
+
+      ligature_list[num_ligatures].set (ligature_glyph);
+      component_count_list[num_ligatures] = 2;
+      component_list[num_ligatures].set (second_glyph);
+      num_ligatures++;
+    }
+  }
+
+  if (!num_ligatures)
+    return NULL;
+
+  OT::Supplier<OT::GlyphID>   first_glyphs_supplier                      (first_glyphs, num_first_glyphs);
+  OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier    (ligature_per_first_glyph_count_list, num_first_glyphs);
+  OT::Supplier<OT::GlyphID>   ligatures_supplier                         (ligature_list, num_ligatures);
+  OT::Supplier<unsigned int > component_count_supplier                   (component_count_list, num_ligatures);
+  OT::Supplier<OT::GlyphID>   component_supplier                         (component_list, num_ligatures);
+
+  /* 16 bytes per ligature ought to be enough... */
+  char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128];
+  OT::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,
+                                        first_glyphs_supplier,
+                                        ligature_per_first_glyph_count_supplier,
+                                        num_first_glyphs,
+                                        ligatures_supplier,
+                                        component_count_supplier,
+                                        component_supplier);
+
+  c.end_serialize ();
+  /* TODO sanitize the results? */
+
+  return ret ? c.copy<OT::SubstLookup> () : NULL;
+}
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
+                                  hb_font_t *font,
+                                  unsigned int feature_index)
+{
+  if (feature_index < 4)
+    return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
+  else
+    return arabic_fallback_synthesize_lookup_ligature (plan, font);
+}
+
+#define ARABIC_FALLBACK_MAX_LOOKUPS 5
+
+struct arabic_fallback_plan_t
+{
+  ASSERT_POD ();
+
+  unsigned int num_lookups;
+  bool free_lookups;
+
+  hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+  OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+  hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+};
+
+static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
+
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
+#define HB_WITH_WIN1256
+#endif
+
+#ifdef HB_WITH_WIN1256
+#include "hb-ot-shape-complex-arabic-win1256.hh"
+#endif
+
+struct ManifestLookup {
+  OT::Tag tag;
+  OT::OffsetTo<OT::SubstLookup> lookupOffset;
+};
+typedef OT::ArrayOf<ManifestLookup> Manifest;
+
+static bool
+arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
+                                  const hb_ot_shape_plan_t *plan,
+                                  hb_font_t *font)
+{
+#ifdef HB_WITH_WIN1256
+  /* Does this font look like it's Windows-1256-encoded? */
+  hb_codepoint_t g;
+  if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
+       hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
+       hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
+       hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
+       hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
+    return false;
+
+  const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
+  ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
+                <= ARABIC_FALLBACK_MAX_LOOKUPS);
+  /* TODO sanitize the table? */
+
+  unsigned j = 0;
+  unsigned int count = manifest.len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
+    if (fallback_plan->mask_array[j])
+    {
+      fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
+      if (fallback_plan->lookup_array[j])
+      {
+       fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+       j++;
+      }
+    }
+  }
+
+  fallback_plan->num_lookups = j;
+  fallback_plan->free_lookups = false;
+
+  return j > 0;
+#else
+  return false;
+#endif
+}
+
+static bool
+arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
+                                  const hb_ot_shape_plan_t *plan,
+                                  hb_font_t *font)
+{
+  ASSERT_STATIC (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++)
+  {
+    fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
+    if (fallback_plan->mask_array[j])
+    {
+      fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
+      if (fallback_plan->lookup_array[j])
+      {
+       fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+       j++;
+      }
+    }
+  }
+
+  fallback_plan->num_lookups = j;
+  fallback_plan->free_lookups = true;
+
+  return j > 0;
+}
+
+static arabic_fallback_plan_t *
+arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
+                            hb_font_t *font)
+{
+  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
+  if (unlikely (!fallback_plan))
+    return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
+
+  fallback_plan->num_lookups = 0;
+  fallback_plan->free_lookups = false;
+
+  /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
+   * in case the font has cmap entries for the presentation-forms characters. */
+  if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
+    return fallback_plan;
+
+  /* See if this looks like a Windows-1256-encoded font.  If it does, use a
+   * hand-coded GSUB table. */
+  if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
+    return fallback_plan;
+
+  free (fallback_plan);
+  return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
+}
+
+static void
+arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
+{
+  if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
+    return;
+
+  for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
+    if (fallback_plan->lookup_array[i])
+    {
+      fallback_plan->accel_array[i].fini ();
+      if (fallback_plan->free_lookups)
+       free (fallback_plan->lookup_array[i]);
+    }
+
+  free (fallback_plan);
+}
+
+static void
+arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
+                           hb_font_t *font,
+                           hb_buffer_t *buffer)
+{
+  OT::hb_apply_context_t c (0, font, buffer);
+  for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
+    if (fallback_plan->lookup_array[i]) {
+      c.set_lookup_mask (fallback_plan->mask_array[i]);
+      hb_ot_layout_substitute_lookup (&c,
+                                     *fallback_plan->lookup_array[i],
+                                     fallback_plan->accel_array[i]);
+    }
+}
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */
index df85086..1710049 100644 (file)
@@ -2,12 +2,14 @@
 /*
  * The following table is generated by running:
  *
- *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
+ *   ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
  *
  * on files with these headers:
  *
- * # ArabicShaping-6.1.0.txt
- * # Date: 2011-04-15, 23:16:00 GMT [KW]
+ * # ArabicShaping-7.0.0.txt
+ * # Date: 2014-02-14, 21:00:00 GMT [RP, KW, LI]
+ * # Blocks-7.0.0.txt
+ * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
  * UnicodeData.txt does not have a header.
  */
 
 #define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
 
 
+#define X      JOINING_TYPE_X
+#define R      JOINING_TYPE_R
+#define U      JOINING_TYPE_U
+#define A      JOINING_GROUP_ALAPH
+#define DR     JOINING_GROUP_DALATH_RISH
+#define L      JOINING_TYPE_L
+#define C      JOINING_TYPE_C
+#define D      JOINING_TYPE_D
+
 static const uint8_t joining_table[] =
 {
 
-  /* Arabic Characters */
-
-  JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0601; ARABIC SIGN SANAH; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0602; ARABIC FOOTNOTE MARKER; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0603; ARABIC SIGN SAFHA; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0604; ARABIC SIGN SAMVAT; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 0605 */
-  JOINING_TYPE_X, /* 0606 */
-  JOINING_TYPE_X, /* 0607 */
-  JOINING_TYPE_U, /* 0608; ARABIC RAY; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 0609 */
-  JOINING_TYPE_X, /* 060A */
-  JOINING_TYPE_U, /* 060B; AFGHANI SIGN; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 060C */
-  JOINING_TYPE_X, /* 060D */
-  JOINING_TYPE_X, /* 060E */
-  JOINING_TYPE_X, /* 060F */
-  JOINING_TYPE_X, /* 0610 */
-  JOINING_TYPE_X, /* 0611 */
-  JOINING_TYPE_X, /* 0612 */
-  JOINING_TYPE_X, /* 0613 */
-  JOINING_TYPE_X, /* 0614 */
-  JOINING_TYPE_X, /* 0615 */
-  JOINING_TYPE_X, /* 0616 */
-  JOINING_TYPE_X, /* 0617 */
-  JOINING_TYPE_X, /* 0618 */
-  JOINING_TYPE_X, /* 0619 */
-  JOINING_TYPE_X, /* 061A */
-  JOINING_TYPE_X, /* 061B */
-  JOINING_TYPE_X, /* 061C */
-  JOINING_TYPE_X, /* 061D */
-  JOINING_TYPE_X, /* 061E */
-  JOINING_TYPE_X, /* 061F */
-  JOINING_TYPE_D, /* 0620; DOTLESS YEH WITH SEPARATE RING BELOW; D; YEH */
-  JOINING_TYPE_U, /* 0621; HAMZA; U; No_Joining_Group */
-  JOINING_TYPE_R, /* 0622; ALEF WITH MADDA ABOVE; R; ALEF */
-  JOINING_TYPE_R, /* 0623; ALEF WITH HAMZA ABOVE; R; ALEF */
-  JOINING_TYPE_R, /* 0624; WAW WITH HAMZA ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 0625; ALEF WITH HAMZA BELOW; R; ALEF */
-  JOINING_TYPE_D, /* 0626; DOTLESS YEH WITH HAMZA ABOVE; D; YEH */
-  JOINING_TYPE_R, /* 0627; ALEF; R; ALEF */
-  JOINING_TYPE_D, /* 0628; BEH; D; BEH */
-  JOINING_TYPE_R, /* 0629; TEH MARBUTA; R; TEH MARBUTA */
-  JOINING_TYPE_D, /* 062A; DOTLESS BEH WITH 2 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 062B; DOTLESS BEH WITH 3 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 062C; HAH WITH DOT BELOW; D; HAH */
-  JOINING_TYPE_D, /* 062D; HAH; D; HAH */
-  JOINING_TYPE_D, /* 062E; HAH WITH DOT ABOVE; D; HAH */
-  JOINING_TYPE_R, /* 062F; DAL; R; DAL */
-  JOINING_TYPE_R, /* 0630; DAL WITH DOT ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 0631; REH; R; REH */
-  JOINING_TYPE_R, /* 0632; REH WITH DOT ABOVE; R; REH */
-  JOINING_TYPE_D, /* 0633; SEEN; D; SEEN */
-  JOINING_TYPE_D, /* 0634; SEEN WITH 3 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 0635; SAD; D; SAD */
-  JOINING_TYPE_D, /* 0636; SAD WITH DOT ABOVE; D; SAD */
-  JOINING_TYPE_D, /* 0637; TAH; D; TAH */
-  JOINING_TYPE_D, /* 0638; TAH WITH DOT ABOVE; D; TAH */
-  JOINING_TYPE_D, /* 0639; AIN; D; AIN */
-  JOINING_TYPE_D, /* 063A; AIN WITH DOT ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 063B; KEHEH WITH 2 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 063C; KEHEH WITH 3 DOTS BELOW; D; GAF */
-  JOINING_TYPE_D, /* 063D; FARSI YEH WITH INVERTED V ABOVE; D; FARSI YEH */
-  JOINING_TYPE_D, /* 063E; FARSI YEH WITH 2 DOTS ABOVE; D; FARSI YEH */
-  JOINING_TYPE_D, /* 063F; FARSI YEH WITH 3 DOTS ABOVE; D; FARSI YEH */
-  JOINING_TYPE_C, /* 0640; TATWEEL; C; No_Joining_Group */
-  JOINING_TYPE_D, /* 0641; FEH; D; FEH */
-  JOINING_TYPE_D, /* 0642; QAF; D; QAF */
-  JOINING_TYPE_D, /* 0643; KAF; D; KAF */
-  JOINING_TYPE_D, /* 0644; LAM; D; LAM */
-  JOINING_TYPE_D, /* 0645; MEEM; D; MEEM */
-  JOINING_TYPE_D, /* 0646; NOON; D; NOON */
-  JOINING_TYPE_D, /* 0647; HEH; D; HEH */
-  JOINING_TYPE_R, /* 0648; WAW; R; WAW */
-  JOINING_TYPE_D, /* 0649; DOTLESS YEH; D; YEH */
-  JOINING_TYPE_D, /* 064A; YEH; D; YEH */
-  JOINING_TYPE_X, /* 064B */
-  JOINING_TYPE_X, /* 064C */
-  JOINING_TYPE_X, /* 064D */
-  JOINING_TYPE_X, /* 064E */
-  JOINING_TYPE_X, /* 064F */
-  JOINING_TYPE_X, /* 0650 */
-  JOINING_TYPE_X, /* 0651 */
-  JOINING_TYPE_X, /* 0652 */
-  JOINING_TYPE_X, /* 0653 */
-  JOINING_TYPE_X, /* 0654 */
-  JOINING_TYPE_X, /* 0655 */
-  JOINING_TYPE_X, /* 0656 */
-  JOINING_TYPE_X, /* 0657 */
-  JOINING_TYPE_X, /* 0658 */
-  JOINING_TYPE_X, /* 0659 */
-  JOINING_TYPE_X, /* 065A */
-  JOINING_TYPE_X, /* 065B */
-  JOINING_TYPE_X, /* 065C */
-  JOINING_TYPE_X, /* 065D */
-  JOINING_TYPE_X, /* 065E */
-  JOINING_TYPE_X, /* 065F */
-  JOINING_TYPE_X, /* 0660 */
-  JOINING_TYPE_X, /* 0661 */
-  JOINING_TYPE_X, /* 0662 */
-  JOINING_TYPE_X, /* 0663 */
-  JOINING_TYPE_X, /* 0664 */
-  JOINING_TYPE_X, /* 0665 */
-  JOINING_TYPE_X, /* 0666 */
-  JOINING_TYPE_X, /* 0667 */
-  JOINING_TYPE_X, /* 0668 */
-  JOINING_TYPE_X, /* 0669 */
-  JOINING_TYPE_X, /* 066A */
-  JOINING_TYPE_X, /* 066B */
-  JOINING_TYPE_X, /* 066C */
-  JOINING_TYPE_X, /* 066D */
-  JOINING_TYPE_D, /* 066E; DOTLESS BEH; D; BEH */
-  JOINING_TYPE_D, /* 066F; DOTLESS QAF; D; QAF */
-  JOINING_TYPE_X, /* 0670 */
-  JOINING_TYPE_R, /* 0671; ALEF WITH WASLA ABOVE; R; ALEF */
-  JOINING_TYPE_R, /* 0672; ALEF WITH WAVY HAMZA ABOVE; R; ALEF */
-  JOINING_TYPE_R, /* 0673; ALEF WITH WAVY HAMZA BELOW; R; ALEF */
-  JOINING_TYPE_U, /* 0674; HIGH HAMZA; U; No_Joining_Group */
-  JOINING_TYPE_R, /* 0675; HIGH HAMZA ALEF; R; ALEF */
-  JOINING_TYPE_R, /* 0676; HIGH HAMZA WAW; R; WAW */
-  JOINING_TYPE_R, /* 0677; HIGH HAMZA WAW WITH DAMMA ABOVE; R; WAW */
-  JOINING_TYPE_D, /* 0678; HIGH HAMZA DOTLESS YEH; D; YEH */
-  JOINING_TYPE_D, /* 0679; DOTLESS BEH WITH TAH ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 067A; DOTLESS BEH WITH VERTICAL 2 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 067B; DOTLESS BEH WITH VERTICAL 2 DOTS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 067C; DOTLESS BEH WITH ATTACHED RING BELOW AND 2 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 067D; DOTLESS BEH WITH INVERTED 3 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 067E; DOTLESS BEH WITH 3 DOTS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 067F; DOTLESS BEH WITH 4 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0680; DOTLESS BEH WITH 4 DOTS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0681; HAH WITH HAMZA ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 0682; HAH WITH VERTICAL 2 DOTS ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 0683; HAH WITH 2 DOTS BELOW; D; HAH */
-  JOINING_TYPE_D, /* 0684; HAH WITH VERTICAL 2 DOTS BELOW; D; HAH */
-  JOINING_TYPE_D, /* 0685; HAH WITH 3 DOTS ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 0686; HAH WITH 3 DOTS BELOW; D; HAH */
-  JOINING_TYPE_D, /* 0687; HAH WITH 4 DOTS BELOW; D; HAH */
-  JOINING_TYPE_R, /* 0688; DAL WITH TAH ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 0689; DAL WITH ATTACHED RING BELOW; R; DAL */
-  JOINING_TYPE_R, /* 068A; DAL WITH DOT BELOW; R; DAL */
-  JOINING_TYPE_R, /* 068B; DAL WITH DOT BELOW AND TAH ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 068C; DAL WITH 2 DOTS ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 068D; DAL WITH 2 DOTS BELOW; R; DAL */
-  JOINING_TYPE_R, /* 068E; DAL WITH 3 DOTS ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 068F; DAL WITH INVERTED 3 DOTS ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 0690; DAL WITH 4 DOTS ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 0691; REH WITH TAH ABOVE; R; REH */
-  JOINING_TYPE_R, /* 0692; REH WITH V ABOVE; R; REH */
-  JOINING_TYPE_R, /* 0693; REH WITH ATTACHED RING BELOW; R; REH */
-  JOINING_TYPE_R, /* 0694; REH WITH DOT BELOW; R; REH */
-  JOINING_TYPE_R, /* 0695; REH WITH V BELOW; R; REH */
-  JOINING_TYPE_R, /* 0696; REH WITH DOT BELOW AND DOT WITHIN; R; REH */
-  JOINING_TYPE_R, /* 0697; REH WITH 2 DOTS ABOVE; R; REH */
-  JOINING_TYPE_R, /* 0698; REH WITH 3 DOTS ABOVE; R; REH */
-  JOINING_TYPE_R, /* 0699; REH WITH 4 DOTS ABOVE; R; REH */
-  JOINING_TYPE_D, /* 069A; SEEN WITH DOT BELOW AND DOT ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 069B; SEEN WITH 3 DOTS BELOW; D; SEEN */
-  JOINING_TYPE_D, /* 069C; SEEN WITH 3 DOTS BELOW AND 3 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 069D; SAD WITH 2 DOTS BELOW; D; SAD */
-  JOINING_TYPE_D, /* 069E; SAD WITH 3 DOTS ABOVE; D; SAD */
-  JOINING_TYPE_D, /* 069F; TAH WITH 3 DOTS ABOVE; D; TAH */
-  JOINING_TYPE_D, /* 06A0; AIN WITH 3 DOTS ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 06A1; DOTLESS FEH; D; FEH */
-  JOINING_TYPE_D, /* 06A2; DOTLESS FEH WITH DOT BELOW; D; FEH */
-  JOINING_TYPE_D, /* 06A3; FEH WITH DOT BELOW; D; FEH */
-  JOINING_TYPE_D, /* 06A4; DOTLESS FEH WITH 3 DOTS ABOVE; D; FEH */
-  JOINING_TYPE_D, /* 06A5; DOTLESS FEH WITH 3 DOTS BELOW; D; FEH */
-  JOINING_TYPE_D, /* 06A6; DOTLESS FEH WITH 4 DOTS ABOVE; D; FEH */
-  JOINING_TYPE_D, /* 06A7; DOTLESS QAF WITH DOT ABOVE; D; QAF */
-  JOINING_TYPE_D, /* 06A8; DOTLESS QAF WITH 3 DOTS ABOVE; D; QAF */
-  JOINING_TYPE_D, /* 06A9; KEHEH; D; GAF */
-  JOINING_TYPE_D, /* 06AA; SWASH KAF; D; SWASH KAF */
-  JOINING_TYPE_D, /* 06AB; KEHEH WITH ATTACHED RING BELOW; D; GAF */
-  JOINING_TYPE_D, /* 06AC; KAF WITH DOT ABOVE; D; KAF */
-  JOINING_TYPE_D, /* 06AD; KAF WITH 3 DOTS ABOVE; D; KAF */
-  JOINING_TYPE_D, /* 06AE; KAF WITH 3 DOTS BELOW; D; KAF */
-  JOINING_TYPE_D, /* 06AF; GAF; D; GAF */
-  JOINING_TYPE_D, /* 06B0; GAF WITH ATTACHED RING BELOW; D; GAF */
-  JOINING_TYPE_D, /* 06B1; GAF WITH 2 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 06B2; GAF WITH 2 DOTS BELOW; D; GAF */
-  JOINING_TYPE_D, /* 06B3; GAF WITH VERTICAL 2 DOTS BELOW; D; GAF */
-  JOINING_TYPE_D, /* 06B4; GAF WITH 3 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 06B5; LAM WITH V ABOVE; D; LAM */
-  JOINING_TYPE_D, /* 06B6; LAM WITH DOT ABOVE; D; LAM */
-  JOINING_TYPE_D, /* 06B7; LAM WITH 3 DOTS ABOVE; D; LAM */
-  JOINING_TYPE_D, /* 06B8; LAM WITH 3 DOTS BELOW; D; LAM */
-  JOINING_TYPE_D, /* 06B9; NOON WITH DOT BELOW; D; NOON */
-  JOINING_TYPE_D, /* 06BA; DOTLESS NOON; D; NOON */
-  JOINING_TYPE_D, /* 06BB; DOTLESS NOON WITH TAH ABOVE; D; NOON */
-  JOINING_TYPE_D, /* 06BC; NOON WITH ATTACHED RING BELOW; D; NOON */
-  JOINING_TYPE_D, /* 06BD; NYA; D; NYA */
-  JOINING_TYPE_D, /* 06BE; KNOTTED HEH; D; KNOTTED HEH */
-  JOINING_TYPE_D, /* 06BF; HAH WITH 3 DOTS BELOW AND DOT ABOVE; D; HAH */
-  JOINING_TYPE_R, /* 06C0; DOTLESS TEH MARBUTA WITH HAMZA ABOVE; R; TEH MARBUTA */
-  JOINING_TYPE_D, /* 06C1; HEH GOAL; D; HEH GOAL */
-  JOINING_TYPE_D, /* 06C2; HEH GOAL WITH HAMZA ABOVE; D; HEH GOAL */
-  JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL */
-  JOINING_TYPE_R, /* 06C4; WAW WITH ATTACHED RING WITHIN; R; WAW */
-  JOINING_TYPE_R, /* 06C5; WAW WITH BAR; R; WAW */
-  JOINING_TYPE_R, /* 06C6; WAW WITH V ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 06C7; WAW WITH DAMMA ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 06C8; WAW WITH ALEF ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 06C9; WAW WITH INVERTED V ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 06CA; WAW WITH 2 DOTS ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 06CB; WAW WITH 3 DOTS ABOVE; R; WAW */
-  JOINING_TYPE_D, /* 06CC; FARSI YEH; D; FARSI YEH */
-  JOINING_TYPE_R, /* 06CD; YEH WITH TAIL; R; YEH WITH TAIL */
-  JOINING_TYPE_D, /* 06CE; FARSI YEH WITH V ABOVE; D; FARSI YEH */
-  JOINING_TYPE_R, /* 06CF; WAW WITH DOT ABOVE; R; WAW */
-  JOINING_TYPE_D, /* 06D0; DOTLESS YEH WITH VERTICAL 2 DOTS BELOW; D; YEH */
-  JOINING_TYPE_D, /* 06D1; DOTLESS YEH WITH 3 DOTS BELOW; D; YEH */
-  JOINING_TYPE_R, /* 06D2; YEH BARREE; R; YEH BARREE */
-  JOINING_TYPE_R, /* 06D3; YEH BARREE WITH HAMZA ABOVE; R; YEH BARREE */
-  JOINING_TYPE_X, /* 06D4 */
-  JOINING_TYPE_R, /* 06D5; DOTLESS TEH MARBUTA; R; TEH MARBUTA */
-  JOINING_TYPE_X, /* 06D6 */
-  JOINING_TYPE_X, /* 06D7 */
-  JOINING_TYPE_X, /* 06D8 */
-  JOINING_TYPE_X, /* 06D9 */
-  JOINING_TYPE_X, /* 06DA */
-  JOINING_TYPE_X, /* 06DB */
-  JOINING_TYPE_X, /* 06DC */
-  JOINING_TYPE_U, /* 06DD; ARABIC END OF AYAH; U; No_Joining_Group */
-  JOINING_TYPE_X, /* 06DE */
-  JOINING_TYPE_X, /* 06DF */
-  JOINING_TYPE_X, /* 06E0 */
-  JOINING_TYPE_X, /* 06E1 */
-  JOINING_TYPE_X, /* 06E2 */
-  JOINING_TYPE_X, /* 06E3 */
-  JOINING_TYPE_X, /* 06E4 */
-  JOINING_TYPE_X, /* 06E5 */
-  JOINING_TYPE_X, /* 06E6 */
-  JOINING_TYPE_X, /* 06E7 */
-  JOINING_TYPE_X, /* 06E8 */
-  JOINING_TYPE_X, /* 06E9 */
-  JOINING_TYPE_X, /* 06EA */
-  JOINING_TYPE_X, /* 06EB */
-  JOINING_TYPE_X, /* 06EC */
-  JOINING_TYPE_X, /* 06ED */
-  JOINING_TYPE_R, /* 06EE; DAL WITH INVERTED V ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 06EF; REH WITH INVERTED V ABOVE; R; REH */
-  JOINING_TYPE_X, /* 06F0 */
-  JOINING_TYPE_X, /* 06F1 */
-  JOINING_TYPE_X, /* 06F2 */
-  JOINING_TYPE_X, /* 06F3 */
-  JOINING_TYPE_X, /* 06F4 */
-  JOINING_TYPE_X, /* 06F5 */
-  JOINING_TYPE_X, /* 06F6 */
-  JOINING_TYPE_X, /* 06F7 */
-  JOINING_TYPE_X, /* 06F8 */
-  JOINING_TYPE_X, /* 06F9 */
-  JOINING_TYPE_D, /* 06FA; SEEN WITH DOT BELOW AND 3 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 06FB; SAD WITH DOT BELOW AND DOT ABOVE; D; SAD */
-  JOINING_TYPE_D, /* 06FC; AIN WITH DOT BELOW AND DOT ABOVE; D; AIN */
-  JOINING_TYPE_X, /* 06FD */
-  JOINING_TYPE_X, /* 06FE */
-  JOINING_TYPE_D, /* 06FF; KNOTTED HEH WITH INVERTED V ABOVE; D; KNOTTED HEH */
-
-  /* Syriac Characters */
-
-  JOINING_TYPE_X, /* 0700 */
-  JOINING_TYPE_X, /* 0701 */
-  JOINING_TYPE_X, /* 0702 */
-  JOINING_TYPE_X, /* 0703 */
-  JOINING_TYPE_X, /* 0704 */
-  JOINING_TYPE_X, /* 0705 */
-  JOINING_TYPE_X, /* 0706 */
-  JOINING_TYPE_X, /* 0707 */
-  JOINING_TYPE_X, /* 0708 */
-  JOINING_TYPE_X, /* 0709 */
-  JOINING_TYPE_X, /* 070A */
-  JOINING_TYPE_X, /* 070B */
-  JOINING_TYPE_X, /* 070C */
-  JOINING_TYPE_X, /* 070D */
-  JOINING_TYPE_X, /* 070E */
-  JOINING_TYPE_X, /* 070F */
-  JOINING_GROUP_ALAPH, /* 0710; ALAPH; R; ALAPH */
-  JOINING_TYPE_X, /* 0711 */
-  JOINING_TYPE_D, /* 0712; BETH; D; BETH */
-  JOINING_TYPE_D, /* 0713; GAMAL; D; GAMAL */
-  JOINING_TYPE_D, /* 0714; GAMAL GARSHUNI; D; GAMAL */
-  JOINING_GROUP_DALATH_RISH, /* 0715; DALATH; R; DALATH RISH */
-  JOINING_GROUP_DALATH_RISH, /* 0716; DOTLESS DALATH RISH; R; DALATH RISH */
-  JOINING_TYPE_R, /* 0717; HE; R; HE */
-  JOINING_TYPE_R, /* 0718; WAW; R; SYRIAC WAW */
-  JOINING_TYPE_R, /* 0719; ZAIN; R; ZAIN */
-  JOINING_TYPE_D, /* 071A; HETH; D; HETH */
-  JOINING_TYPE_D, /* 071B; TETH; D; TETH */
-  JOINING_TYPE_D, /* 071C; TETH GARSHUNI; D; TETH */
-  JOINING_TYPE_D, /* 071D; YUDH; D; YUDH */
-  JOINING_TYPE_R, /* 071E; YUDH HE; R; YUDH HE */
-  JOINING_TYPE_D, /* 071F; KAPH; D; KAPH */
-  JOINING_TYPE_D, /* 0720; LAMADH; D; LAMADH */
-  JOINING_TYPE_D, /* 0721; MIM; D; MIM */
-  JOINING_TYPE_D, /* 0722; NUN; D; NUN */
-  JOINING_TYPE_D, /* 0723; SEMKATH; D; SEMKATH */
-  JOINING_TYPE_D, /* 0724; FINAL SEMKATH; D; FINAL SEMKATH */
-  JOINING_TYPE_D, /* 0725; E; D; E */
-  JOINING_TYPE_D, /* 0726; PE; D; PE */
-  JOINING_TYPE_D, /* 0727; REVERSED PE; D; REVERSED PE */
-  JOINING_TYPE_R, /* 0728; SADHE; R; SADHE */
-  JOINING_TYPE_D, /* 0729; QAPH; D; QAPH */
-  JOINING_GROUP_DALATH_RISH, /* 072A; RISH; R; DALATH RISH */
-  JOINING_TYPE_D, /* 072B; SHIN; D; SHIN */
-  JOINING_TYPE_R, /* 072C; TAW; R; TAW */
-  JOINING_TYPE_D, /* 072D; PERSIAN BHETH; D; BETH */
-  JOINING_TYPE_D, /* 072E; PERSIAN GHAMAL; D; GAMAL */
-  JOINING_GROUP_DALATH_RISH, /* 072F; PERSIAN DHALATH; R; DALATH RISH */
-  JOINING_TYPE_X, /* 0730 */
-  JOINING_TYPE_X, /* 0731 */
-  JOINING_TYPE_X, /* 0732 */
-  JOINING_TYPE_X, /* 0733 */
-  JOINING_TYPE_X, /* 0734 */
-  JOINING_TYPE_X, /* 0735 */
-  JOINING_TYPE_X, /* 0736 */
-  JOINING_TYPE_X, /* 0737 */
-  JOINING_TYPE_X, /* 0738 */
-  JOINING_TYPE_X, /* 0739 */
-  JOINING_TYPE_X, /* 073A */
-  JOINING_TYPE_X, /* 073B */
-  JOINING_TYPE_X, /* 073C */
-  JOINING_TYPE_X, /* 073D */
-  JOINING_TYPE_X, /* 073E */
-  JOINING_TYPE_X, /* 073F */
-  JOINING_TYPE_X, /* 0740 */
-  JOINING_TYPE_X, /* 0741 */
-  JOINING_TYPE_X, /* 0742 */
-  JOINING_TYPE_X, /* 0743 */
-  JOINING_TYPE_X, /* 0744 */
-  JOINING_TYPE_X, /* 0745 */
-  JOINING_TYPE_X, /* 0746 */
-  JOINING_TYPE_X, /* 0747 */
-  JOINING_TYPE_X, /* 0748 */
-  JOINING_TYPE_X, /* 0749 */
-  JOINING_TYPE_X, /* 074A */
-  JOINING_TYPE_X, /* 074B */
-  JOINING_TYPE_X, /* 074C */
-  JOINING_TYPE_R, /* 074D; SOGDIAN ZHAIN; R; ZHAIN */
-  JOINING_TYPE_D, /* 074E; SOGDIAN KHAPH; D; KHAPH */
-  JOINING_TYPE_D, /* 074F; SOGDIAN FE; D; FE */
-
-  /* Arabic Supplement Characters */
-
-  JOINING_TYPE_D, /* 0750; DOTLESS BEH WITH HORIZONTAL 3 DOTS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0751; BEH WITH 3 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0752; DOTLESS BEH WITH INVERTED 3 DOTS BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0753; DOTLESS BEH WITH INVERTED 3 DOTS BELOW AND 2 DOTS ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0754; DOTLESS BEH WITH 2 DOTS BELOW AND DOT ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0755; DOTLESS BEH WITH INVERTED V BELOW; D; BEH */
-  JOINING_TYPE_D, /* 0756; DOTLESS BEH WITH V ABOVE; D; BEH */
-  JOINING_TYPE_D, /* 0757; HAH WITH 2 DOTS ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 0758; HAH WITH INVERTED 3 DOTS BELOW; D; HAH */
-  JOINING_TYPE_R, /* 0759; DAL WITH VERTICAL 2 DOTS BELOW AND TAH ABOVE; R; DAL */
-  JOINING_TYPE_R, /* 075A; DAL WITH INVERTED V BELOW; R; DAL */
-  JOINING_TYPE_R, /* 075B; REH WITH BAR; R; REH */
-  JOINING_TYPE_D, /* 075C; SEEN WITH 4 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 075D; AIN WITH 2 DOTS ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 075E; AIN WITH INVERTED 3 DOTS ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 075F; AIN WITH VERTICAL 2 DOTS ABOVE; D; AIN */
-  JOINING_TYPE_D, /* 0760; DOTLESS FEH WITH 2 DOTS BELOW; D; FEH */
-  JOINING_TYPE_D, /* 0761; DOTLESS FEH WITH INVERTED 3 DOTS BELOW; D; FEH */
-  JOINING_TYPE_D, /* 0762; KEHEH WITH DOT ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 0763; KEHEH WITH 3 DOTS ABOVE; D; GAF */
-  JOINING_TYPE_D, /* 0764; KEHEH WITH INVERTED 3 DOTS BELOW; D; GAF */
-  JOINING_TYPE_D, /* 0765; MEEM WITH DOT ABOVE; D; MEEM */
-  JOINING_TYPE_D, /* 0766; MEEM WITH DOT BELOW; D; MEEM */
-  JOINING_TYPE_D, /* 0767; NOON WITH 2 DOTS BELOW; D; NOON */
-  JOINING_TYPE_D, /* 0768; NOON WITH TAH ABOVE; D; NOON */
-  JOINING_TYPE_D, /* 0769; NOON WITH V ABOVE; D; NOON */
-  JOINING_TYPE_D, /* 076A; LAM WITH BAR; D; LAM */
-  JOINING_TYPE_R, /* 076B; REH WITH VERTICAL 2 DOTS ABOVE; R; REH */
-  JOINING_TYPE_R, /* 076C; REH WITH HAMZA ABOVE; R; REH */
-  JOINING_TYPE_D, /* 076D; SEEN WITH VERTICAL 2 DOTS ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 076E; HAH WITH TAH BELOW; D; HAH */
-  JOINING_TYPE_D, /* 076F; HAH WITH TAH AND 2 DOTS BELOW; D; HAH */
-  JOINING_TYPE_D, /* 0770; SEEN WITH 2 DOTS AND TAH ABOVE; D; SEEN */
-  JOINING_TYPE_R, /* 0771; REH WITH 2 DOTS AND TAH ABOVE; R; REH */
-  JOINING_TYPE_D, /* 0772; HAH WITH TAH ABOVE; D; HAH */
-  JOINING_TYPE_R, /* 0773; ALEF WITH DIGIT TWO ABOVE; R; ALEF */
-  JOINING_TYPE_R, /* 0774; ALEF WITH DIGIT THREE ABOVE; R; ALEF */
-  JOINING_TYPE_D, /* 0775; FARSI YEH WITH DIGIT TWO ABOVE; D; FARSI YEH */
-  JOINING_TYPE_D, /* 0776; FARSI YEH WITH DIGIT THREE ABOVE; D; FARSI YEH */
-  JOINING_TYPE_D, /* 0777; DOTLESS YEH WITH DIGIT FOUR BELOW; D; YEH */
-  JOINING_TYPE_R, /* 0778; WAW WITH DIGIT TWO ABOVE; R; WAW */
-  JOINING_TYPE_R, /* 0779; WAW WITH DIGIT THREE ABOVE; R; WAW */
-  JOINING_TYPE_D, /* 077A; BURUSHASKI YEH BARREE WITH DIGIT TWO ABOVE; D; BURUSHASKI YEH BARREE */
-  JOINING_TYPE_D, /* 077B; BURUSHASKI YEH BARREE WITH DIGIT THREE ABOVE; D; BURUSHASKI YEH BARREE */
-  JOINING_TYPE_D, /* 077C; HAH WITH DIGIT FOUR BELOW; D; HAH */
-  JOINING_TYPE_D, /* 077D; SEEN WITH DIGIT FOUR ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 077E; SEEN WITH INVERTED V ABOVE; D; SEEN */
-  JOINING_TYPE_D, /* 077F; KAF WITH 2 DOTS ABOVE; D; KAF */
-
-  /* N'Ko Characters */
-
-  JOINING_TYPE_X, /* 0780 */
-  JOINING_TYPE_X, /* 0781 */
-  JOINING_TYPE_X, /* 0782 */
-  JOINING_TYPE_X, /* 0783 */
-  JOINING_TYPE_X, /* 0784 */
-  JOINING_TYPE_X, /* 0785 */
-  JOINING_TYPE_X, /* 0786 */
-  JOINING_TYPE_X, /* 0787 */
-  JOINING_TYPE_X, /* 0788 */
-  JOINING_TYPE_X, /* 0789 */
-  JOINING_TYPE_X, /* 078A */
-  JOINING_TYPE_X, /* 078B */
-  JOINING_TYPE_X, /* 078C */
-  JOINING_TYPE_X, /* 078D */
-  JOINING_TYPE_X, /* 078E */
-  JOINING_TYPE_X, /* 078F */
-  JOINING_TYPE_X, /* 0790 */
-  JOINING_TYPE_X, /* 0791 */
-  JOINING_TYPE_X, /* 0792 */
-  JOINING_TYPE_X, /* 0793 */
-  JOINING_TYPE_X, /* 0794 */
-  JOINING_TYPE_X, /* 0795 */
-  JOINING_TYPE_X, /* 0796 */
-  JOINING_TYPE_X, /* 0797 */
-  JOINING_TYPE_X, /* 0798 */
-  JOINING_TYPE_X, /* 0799 */
-  JOINING_TYPE_X, /* 079A */
-  JOINING_TYPE_X, /* 079B */
-  JOINING_TYPE_X, /* 079C */
-  JOINING_TYPE_X, /* 079D */
-  JOINING_TYPE_X, /* 079E */
-  JOINING_TYPE_X, /* 079F */
-  JOINING_TYPE_X, /* 07A0 */
-  JOINING_TYPE_X, /* 07A1 */
-  JOINING_TYPE_X, /* 07A2 */
-  JOINING_TYPE_X, /* 07A3 */
-  JOINING_TYPE_X, /* 07A4 */
-  JOINING_TYPE_X, /* 07A5 */
-  JOINING_TYPE_X, /* 07A6 */
-  JOINING_TYPE_X, /* 07A7 */
-  JOINING_TYPE_X, /* 07A8 */
-  JOINING_TYPE_X, /* 07A9 */
-  JOINING_TYPE_X, /* 07AA */
-  JOINING_TYPE_X, /* 07AB */
-  JOINING_TYPE_X, /* 07AC */
-  JOINING_TYPE_X, /* 07AD */
-  JOINING_TYPE_X, /* 07AE */
-  JOINING_TYPE_X, /* 07AF */
-  JOINING_TYPE_X, /* 07B0 */
-  JOINING_TYPE_X, /* 07B1 */
-  JOINING_TYPE_X, /* 07B2 */
-  JOINING_TYPE_X, /* 07B3 */
-  JOINING_TYPE_X, /* 07B4 */
-  JOINING_TYPE_X, /* 07B5 */
-  JOINING_TYPE_X, /* 07B6 */
-  JOINING_TYPE_X, /* 07B7 */
-  JOINING_TYPE_X, /* 07B8 */
-  JOINING_TYPE_X, /* 07B9 */
-  JOINING_TYPE_X, /* 07BA */
-  JOINING_TYPE_X, /* 07BB */
-  JOINING_TYPE_X, /* 07BC */
-  JOINING_TYPE_X, /* 07BD */
-  JOINING_TYPE_X, /* 07BE */
-  JOINING_TYPE_X, /* 07BF */
-  JOINING_TYPE_X, /* 07C0 */
-  JOINING_TYPE_X, /* 07C1 */
-  JOINING_TYPE_X, /* 07C2 */
-  JOINING_TYPE_X, /* 07C3 */
-  JOINING_TYPE_X, /* 07C4 */
-  JOINING_TYPE_X, /* 07C5 */
-  JOINING_TYPE_X, /* 07C6 */
-  JOINING_TYPE_X, /* 07C7 */
-  JOINING_TYPE_X, /* 07C8 */
-  JOINING_TYPE_X, /* 07C9 */
-  JOINING_TYPE_D, /* 07CA; NKO A; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CB; NKO EE; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CC; NKO I; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CD; NKO E; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CE; NKO U; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07CF; NKO OO; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D0; NKO O; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D1; NKO DAGBASINNA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D2; NKO N; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D3; NKO BA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D4; NKO PA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D5; NKO TA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D6; NKO JA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D7; NKO CHA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D8; NKO DA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07D9; NKO RA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DA; NKO RRA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DB; NKO SA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DC; NKO GBA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DD; NKO FA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DE; NKO KA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07DF; NKO LA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E0; NKO NA WOLOSO; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E1; NKO MA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E2; NKO NYA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E3; NKO NA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E4; NKO HA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E5; NKO WA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E6; NKO YA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E7; NKO NYA WOLOSO; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E8; NKO JONA JA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07E9; NKO JONA CHA; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 07EA; NKO JONA RA; D; No_Joining_Group */
-  JOINING_TYPE_X, /* 07EB */
-  JOINING_TYPE_X, /* 07EC */
-  JOINING_TYPE_X, /* 07ED */
-  JOINING_TYPE_X, /* 07EE */
-  JOINING_TYPE_X, /* 07EF */
-  JOINING_TYPE_X, /* 07F0 */
-  JOINING_TYPE_X, /* 07F1 */
-  JOINING_TYPE_X, /* 07F2 */
-  JOINING_TYPE_X, /* 07F3 */
-  JOINING_TYPE_X, /* 07F4 */
-  JOINING_TYPE_X, /* 07F5 */
-  JOINING_TYPE_X, /* 07F6 */
-  JOINING_TYPE_X, /* 07F7 */
-  JOINING_TYPE_X, /* 07F8 */
-  JOINING_TYPE_X, /* 07F9 */
-  JOINING_TYPE_C, /* 07FA; NKO LAJANYALAN; C; No_Joining_Group */
-
-  /* Mandaic Characters */
-
-  JOINING_TYPE_X, /* 07FB */
-  JOINING_TYPE_X, /* 07FC */
-  JOINING_TYPE_X, /* 07FD */
-  JOINING_TYPE_X, /* 07FE */
-  JOINING_TYPE_X, /* 07FF */
-  JOINING_TYPE_X, /* 0800 */
-  JOINING_TYPE_X, /* 0801 */
-  JOINING_TYPE_X, /* 0802 */
-  JOINING_TYPE_X, /* 0803 */
-  JOINING_TYPE_X, /* 0804 */
-  JOINING_TYPE_X, /* 0805 */
-  JOINING_TYPE_X, /* 0806 */
-  JOINING_TYPE_X, /* 0807 */
-  JOINING_TYPE_X, /* 0808 */
-  JOINING_TYPE_X, /* 0809 */
-  JOINING_TYPE_X, /* 080A */
-  JOINING_TYPE_X, /* 080B */
-  JOINING_TYPE_X, /* 080C */
-  JOINING_TYPE_X, /* 080D */
-  JOINING_TYPE_X, /* 080E */
-  JOINING_TYPE_X, /* 080F */
-  JOINING_TYPE_X, /* 0810 */
-  JOINING_TYPE_X, /* 0811 */
-  JOINING_TYPE_X, /* 0812 */
-  JOINING_TYPE_X, /* 0813 */
-  JOINING_TYPE_X, /* 0814 */
-  JOINING_TYPE_X, /* 0815 */
-  JOINING_TYPE_X, /* 0816 */
-  JOINING_TYPE_X, /* 0817 */
-  JOINING_TYPE_X, /* 0818 */
-  JOINING_TYPE_X, /* 0819 */
-  JOINING_TYPE_X, /* 081A */
-  JOINING_TYPE_X, /* 081B */
-  JOINING_TYPE_X, /* 081C */
-  JOINING_TYPE_X, /* 081D */
-  JOINING_TYPE_X, /* 081E */
-  JOINING_TYPE_X, /* 081F */
-  JOINING_TYPE_X, /* 0820 */
-  JOINING_TYPE_X, /* 0821 */
-  JOINING_TYPE_X, /* 0822 */
-  JOINING_TYPE_X, /* 0823 */
-  JOINING_TYPE_X, /* 0824 */
-  JOINING_TYPE_X, /* 0825 */
-  JOINING_TYPE_X, /* 0826 */
-  JOINING_TYPE_X, /* 0827 */
-  JOINING_TYPE_X, /* 0828 */
-  JOINING_TYPE_X, /* 0829 */
-  JOINING_TYPE_X, /* 082A */
-  JOINING_TYPE_X, /* 082B */
-  JOINING_TYPE_X, /* 082C */
-  JOINING_TYPE_X, /* 082D */
-  JOINING_TYPE_X, /* 082E */
-  JOINING_TYPE_X, /* 082F */
-  JOINING_TYPE_X, /* 0830 */
-  JOINING_TYPE_X, /* 0831 */
-  JOINING_TYPE_X, /* 0832 */
-  JOINING_TYPE_X, /* 0833 */
-  JOINING_TYPE_X, /* 0834 */
-  JOINING_TYPE_X, /* 0835 */
-  JOINING_TYPE_X, /* 0836 */
-  JOINING_TYPE_X, /* 0837 */
-  JOINING_TYPE_X, /* 0838 */
-  JOINING_TYPE_X, /* 0839 */
-  JOINING_TYPE_X, /* 083A */
-  JOINING_TYPE_X, /* 083B */
-  JOINING_TYPE_X, /* 083C */
-  JOINING_TYPE_X, /* 083D */
-  JOINING_TYPE_X, /* 083E */
-  JOINING_TYPE_X, /* 083F */
-  JOINING_TYPE_R, /* 0840; MANDAIC HALQA; R; No_Joining_Group */
-  JOINING_TYPE_D, /* 0841; MANDAIC AB; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0842; MANDAIC AG; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0843; MANDAIC AD; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0844; MANDAIC AH; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0845; MANDAIC USHENNA; D; No_Joining_Group */
-  JOINING_TYPE_R, /* 0846; MANDAIC AZ; R; No_Joining_Group */
-  JOINING_TYPE_D, /* 0847; MANDAIC IT; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0848; MANDAIC ATT; D; No_Joining_Group */
-  JOINING_TYPE_R, /* 0849; MANDAIC AKSA; R; No_Joining_Group */
-  JOINING_TYPE_D, /* 084A; MANDAIC AK; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 084B; MANDAIC AL; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 084C; MANDAIC AM; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 084D; MANDAIC AN; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 084E; MANDAIC AS; D; No_Joining_Group */
-  JOINING_TYPE_R, /* 084F; MANDAIC IN; R; No_Joining_Group */
-  JOINING_TYPE_D, /* 0850; MANDAIC AP; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0851; MANDAIC ASZ; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0852; MANDAIC AQ; D; No_Joining_Group */
-  JOINING_TYPE_D, /* 0853; MANDAIC AR; D; No_Joining_Group */
-  JOINING_TYPE_R, /* 0854; MANDAIC ASH; R; No_Joining_Group */
-  JOINING_TYPE_D, /* 0855; MANDAIC AT; D; No_Joining_Group */
-  JOINING_TYPE_U, /* 0856; MANDAIC DUSHENNA; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0857; MANDAIC KAD; U; No_Joining_Group */
-  JOINING_TYPE_U, /* 0858; MANDAIC AIN; U; No_Joining_Group */
-
-  /* Arabic Extended-A Characters */
-
-  JOINING_TYPE_X, /* 0859 */
-  JOINING_TYPE_X, /* 085A */
-  JOINING_TYPE_X, /* 085B */
-  JOINING_TYPE_X, /* 085C */
-  JOINING_TYPE_X, /* 085D */
-  JOINING_TYPE_X, /* 085E */
-  JOINING_TYPE_X, /* 085F */
-  JOINING_TYPE_X, /* 0860 */
-  JOINING_TYPE_X, /* 0861 */
-  JOINING_TYPE_X, /* 0862 */
-  JOINING_TYPE_X, /* 0863 */
-  JOINING_TYPE_X, /* 0864 */
-  JOINING_TYPE_X, /* 0865 */
-  JOINING_TYPE_X, /* 0866 */
-  JOINING_TYPE_X, /* 0867 */
-  JOINING_TYPE_X, /* 0868 */
-  JOINING_TYPE_X, /* 0869 */
-  JOINING_TYPE_X, /* 086A */
-  JOINING_TYPE_X, /* 086B */
-  JOINING_TYPE_X, /* 086C */
-  JOINING_TYPE_X, /* 086D */
-  JOINING_TYPE_X, /* 086E */
-  JOINING_TYPE_X, /* 086F */
-  JOINING_TYPE_X, /* 0870 */
-  JOINING_TYPE_X, /* 0871 */
-  JOINING_TYPE_X, /* 0872 */
-  JOINING_TYPE_X, /* 0873 */
-  JOINING_TYPE_X, /* 0874 */
-  JOINING_TYPE_X, /* 0875 */
-  JOINING_TYPE_X, /* 0876 */
-  JOINING_TYPE_X, /* 0877 */
-  JOINING_TYPE_X, /* 0878 */
-  JOINING_TYPE_X, /* 0879 */
-  JOINING_TYPE_X, /* 087A */
-  JOINING_TYPE_X, /* 087B */
-  JOINING_TYPE_X, /* 087C */
-  JOINING_TYPE_X, /* 087D */
-  JOINING_TYPE_X, /* 087E */
-  JOINING_TYPE_X, /* 087F */
-  JOINING_TYPE_X, /* 0880 */
-  JOINING_TYPE_X, /* 0881 */
-  JOINING_TYPE_X, /* 0882 */
-  JOINING_TYPE_X, /* 0883 */
-  JOINING_TYPE_X, /* 0884 */
-  JOINING_TYPE_X, /* 0885 */
-  JOINING_TYPE_X, /* 0886 */
-  JOINING_TYPE_X, /* 0887 */
-  JOINING_TYPE_X, /* 0888 */
-  JOINING_TYPE_X, /* 0889 */
-  JOINING_TYPE_X, /* 088A */
-  JOINING_TYPE_X, /* 088B */
-  JOINING_TYPE_X, /* 088C */
-  JOINING_TYPE_X, /* 088D */
-  JOINING_TYPE_X, /* 088E */
-  JOINING_TYPE_X, /* 088F */
-  JOINING_TYPE_X, /* 0890 */
-  JOINING_TYPE_X, /* 0891 */
-  JOINING_TYPE_X, /* 0892 */
-  JOINING_TYPE_X, /* 0893 */
-  JOINING_TYPE_X, /* 0894 */
-  JOINING_TYPE_X, /* 0895 */
-  JOINING_TYPE_X, /* 0896 */
-  JOINING_TYPE_X, /* 0897 */
-  JOINING_TYPE_X, /* 0898 */
-  JOINING_TYPE_X, /* 0899 */
-  JOINING_TYPE_X, /* 089A */
-  JOINING_TYPE_X, /* 089B */
-  JOINING_TYPE_X, /* 089C */
-  JOINING_TYPE_X, /* 089D */
-  JOINING_TYPE_X, /* 089E */
-  JOINING_TYPE_X, /* 089F */
-  JOINING_TYPE_D, /* 08A0; DOTLESS BEH WITH V BELOW; D; BEH */
-  JOINING_TYPE_X, /* 08A1 */
-  JOINING_TYPE_D, /* 08A2; HAH WITH DOT BELOW AND 2 DOTS ABOVE; D; HAH */
-  JOINING_TYPE_D, /* 08A3; TAH WITH 2 DOTS ABOVE; D; TAH */
-  JOINING_TYPE_D, /* 08A4; DOTLESS FEH WITH DOT BELOW AND 3 DOTS ABOVE; D; FEH */
-  JOINING_TYPE_D, /* 08A5; QAF WITH DOT BELOW; D; QAF */
-  JOINING_TYPE_D, /* 08A6; LAM WITH DOUBLE BAR; D; LAM */
-  JOINING_TYPE_D, /* 08A7; MEEM WITH 3 DOTS ABOVE; D; MEEM */
-  JOINING_TYPE_D, /* 08A8; YEH WITH HAMZA ABOVE; D; YEH */
-  JOINING_TYPE_D, /* 08A9; YEH WITH DOT ABOVE; D; YEH */
-  JOINING_TYPE_R, /* 08AA; REH WITH LOOP; R; REH */
-  JOINING_TYPE_R, /* 08AB; WAW WITH DOT WITHIN; R; WAW */
-  JOINING_TYPE_R, /* 08AC; ROHINGYA YEH; R; ROHINGYA YEH */
+#define joining_offset_0x0600u 0
 
-};
+  /* Arabic */
+
+  /* 0600 */ U,U,U,U,U,U,X,X,U,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0620 */ D,U,R,R,R,R,D,R,D,R,D,D,D,D,D,R,R,R,R,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 0640 */ C,D,D,D,D,D,D,D,R,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0660 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,D,D,X,R,R,R,U,R,R,R,D,D,D,D,D,D,D,D,
+  /* 0680 */ D,D,D,D,D,D,D,D,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,D,D,D,D,D,D,
+  /* 06A0 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 06C0 */ R,D,D,R,R,R,R,R,R,R,R,R,D,R,D,R,D,D,R,R,X,R,X,X,X,X,X,X,X,U,X,X,
+  /* 06E0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,R,R,X,X,X,X,X,X,X,X,X,X,D,D,D,X,X,D,
+
+  /* Syriac */
+
+  /* 0700 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,A,X,D,D,D,DR,DR,R,R,R,D,D,D,D,R,D,
+  /* 0720 */ D,D,D,D,D,D,D,D,R,D,DR,D,R,D,D,DR,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0740 */ X,X,X,X,X,X,X,X,X,X,X,X,X,R,D,D,
+
+  /* Arabic Supplement */
+
+  /* 0740 */                                 D,D,D,D,D,D,D,D,D,R,R,R,D,D,D,D,
+  /* 0760 */ D,D,D,D,D,D,D,D,D,D,D,R,R,D,D,D,D,R,D,R,R,D,D,D,R,R,D,D,D,D,D,D,
+
+  /* FILLER */
+
+  /* 0780 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 07A0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* NKo */
+
+  /* 07C0 */ X,X,X,X,X,X,X,X,X,X,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 07E0 */ D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,C,X,X,X,X,X,
+
+  /* FILLER */
+
+  /* 0800 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0820 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* Mandaic */
+
+  /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
+  /* 0860 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* Arabic Extended-A */
+
+  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,
+
+#define joining_offset_0x1806u 691
+
+  /* Mongolian */
+
+  /* 1800 */             U,D,X,X,C,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 1820 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 1840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 1860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,
+  /* 1880 */ U,U,U,U,U,U,U,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* 18A0 */ D,D,D,D,D,D,D,D,D,X,D,
+
+#define joining_offset_0x200cu 856
+
+  /* General Punctuation */
+
+  /* 2000 */                         U,C,
+
+#define joining_offset_0x2066u 858
+
+  /* General Punctuation */
+
+  /* 2060 */             U,U,U,U,
+
+#define joining_offset_0xa840u 862
+
+  /* Phags-pa */
+
+  /* A840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+  /* A860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,L,U,
+
+#define joining_offset_0x10ac0u 914
+
+  /* Manichaean */
+
+  /* 10AC0 */ D,D,D,D,D,R,U,R,U,R,R,U,U,L,R,R,R,R,R,D,D,D,D,L,D,D,D,D,D,R,D,D,
+  /* 10AE0 */ D,R,U,U,R,X,X,X,X,X,X,D,D,D,D,R,
+
+#define joining_offset_0x10b80u 962
+
+  /* Psalter Pahlavi */
+
+  /* 10B80 */ D,R,D,R,R,R,D,D,D,R,D,D,R,D,R,R,D,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 10BA0 */ X,X,X,X,X,X,X,X,X,R,R,R,R,D,D,U,
+
+}; /* Table items: 1010; occupancy: 57% */
+
+
+static unsigned int
+joining_type (hb_codepoint_t u)
+{
+  switch (u >> 12)
+  {
+    case 0x0u:
+      if (hb_in_range (u, 0x0600u, 0x08B2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
+      break;
+
+    case 0x1u:
+      if (hb_in_range (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u];
+      break;
+
+    case 0x2u:
+      if (hb_in_range (u, 0x200Cu, 0x200Du)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
+      if (hb_in_range (u, 0x2066u, 0x2069u)) return joining_table[u - 0x2066u + joining_offset_0x2066u];
+      break;
+
+    case 0xAu:
+      if (hb_in_range (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u];
+      break;
+
+    case 0x10u:
+      if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
+      if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
+      break;
+
+    default:
+      break;
+  }
+  return X;
+}
 
-#define JOINING_TABLE_FIRST    0x0600
-#define JOINING_TABLE_LAST     0x08AC
+#undef X
+#undef R
+#undef U
+#undef A
+#undef DR
+#undef L
+#undef C
+#undef D
 
 
 static const uint16_t shaping_table[][4] =
 {
-  {0x0621, 0x0621, 0x0621, 0xFE80}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
-  {0x0622, 0x0622, 0xFE82, 0xFE81}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
-  {0x0623, 0x0623, 0xFE84, 0xFE83}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
-  {0x0624, 0x0624, 0xFE86, 0xFE85}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
-  {0x0625, 0x0625, 0xFE88, 0xFE87}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
-  {0xFE8B, 0xFE8C, 0xFE8A, 0xFE89}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
-  {0x0627, 0x0627, 0xFE8E, 0xFE8D}, /* U+0627 ARABIC LETTER ALEF */
-  {0xFE91, 0xFE92, 0xFE90, 0xFE8F}, /* U+0628 ARABIC LETTER BEH */
-  {0x0629, 0x0629, 0xFE94, 0xFE93}, /* U+0629 ARABIC LETTER TEH MARBUTA */
-  {0xFE97, 0xFE98, 0xFE96, 0xFE95}, /* U+062A ARABIC LETTER TEH */
-  {0xFE9B, 0xFE9C, 0xFE9A, 0xFE99}, /* U+062B ARABIC LETTER THEH */
-  {0xFE9F, 0xFEA0, 0xFE9E, 0xFE9D}, /* U+062C ARABIC LETTER JEEM */
-  {0xFEA3, 0xFEA4, 0xFEA2, 0xFEA1}, /* U+062D ARABIC LETTER HAH */
-  {0xFEA7, 0xFEA8, 0xFEA6, 0xFEA5}, /* U+062E ARABIC LETTER KHAH */
-  {0x062F, 0x062F, 0xFEAA, 0xFEA9}, /* U+062F ARABIC LETTER DAL */
-  {0x0630, 0x0630, 0xFEAC, 0xFEAB}, /* U+0630 ARABIC LETTER THAL */
-  {0x0631, 0x0631, 0xFEAE, 0xFEAD}, /* U+0631 ARABIC LETTER REH */
-  {0x0632, 0x0632, 0xFEB0, 0xFEAF}, /* U+0632 ARABIC LETTER ZAIN */
-  {0xFEB3, 0xFEB4, 0xFEB2, 0xFEB1}, /* U+0633 ARABIC LETTER SEEN */
-  {0xFEB7, 0xFEB8, 0xFEB6, 0xFEB5}, /* U+0634 ARABIC LETTER SHEEN */
-  {0xFEBB, 0xFEBC, 0xFEBA, 0xFEB9}, /* U+0635 ARABIC LETTER SAD */
-  {0xFEBF, 0xFEC0, 0xFEBE, 0xFEBD}, /* U+0636 ARABIC LETTER DAD */
-  {0xFEC3, 0xFEC4, 0xFEC2, 0xFEC1}, /* U+0637 ARABIC LETTER TAH */
-  {0xFEC7, 0xFEC8, 0xFEC6, 0xFEC5}, /* U+0638 ARABIC LETTER ZAH */
-  {0xFECB, 0xFECC, 0xFECA, 0xFEC9}, /* U+0639 ARABIC LETTER AIN */
-  {0xFECF, 0xFED0, 0xFECE, 0xFECD}, /* U+063A ARABIC LETTER GHAIN */
-  {0x063B, 0x063B, 0x063B, 0x063B}, /* U+063B  */
-  {0x063C, 0x063C, 0x063C, 0x063C}, /* U+063C  */
-  {0x063D, 0x063D, 0x063D, 0x063D}, /* U+063D  */
-  {0x063E, 0x063E, 0x063E, 0x063E}, /* U+063E  */
-  {0x063F, 0x063F, 0x063F, 0x063F}, /* U+063F  */
-  {0x0640, 0x0640, 0x0640, 0x0640}, /* U+0640  */
-  {0xFED3, 0xFED4, 0xFED2, 0xFED1}, /* U+0641 ARABIC LETTER FEH */
-  {0xFED7, 0xFED8, 0xFED6, 0xFED5}, /* U+0642 ARABIC LETTER QAF */
-  {0xFEDB, 0xFEDC, 0xFEDA, 0xFED9}, /* U+0643 ARABIC LETTER KAF */
-  {0xFEDF, 0xFEE0, 0xFEDE, 0xFEDD}, /* U+0644 ARABIC LETTER LAM */
-  {0xFEE3, 0xFEE4, 0xFEE2, 0xFEE1}, /* U+0645 ARABIC LETTER MEEM */
-  {0xFEE7, 0xFEE8, 0xFEE6, 0xFEE5}, /* U+0646 ARABIC LETTER NOON */
-  {0xFEEB, 0xFEEC, 0xFEEA, 0xFEE9}, /* U+0647 ARABIC LETTER HEH */
-  {0x0648, 0x0648, 0xFEEE, 0xFEED}, /* U+0648 ARABIC LETTER WAW */
-  {0xFBE8, 0xFBE9, 0xFEF0, 0xFEEF}, /* U+0649 ARABIC LETTER */
-  {0xFEF3, 0xFEF4, 0xFEF2, 0xFEF1}, /* U+064A ARABIC LETTER YEH */
-  {0x064B, 0x064B, 0x064B, 0x064B}, /* U+064B  */
-  {0x064C, 0x064C, 0x064C, 0x064C}, /* U+064C  */
-  {0x064D, 0x064D, 0x064D, 0x064D}, /* U+064D  */
-  {0x064E, 0x064E, 0x064E, 0x064E}, /* U+064E  */
-  {0x064F, 0x064F, 0x064F, 0x064F}, /* U+064F  */
-  {0x0650, 0x0650, 0x0650, 0x0650}, /* U+0650  */
-  {0x0651, 0x0651, 0x0651, 0x0651}, /* U+0651  */
-  {0x0652, 0x0652, 0x0652, 0x0652}, /* U+0652  */
-  {0x0653, 0x0653, 0x0653, 0x0653}, /* U+0653  */
-  {0x0654, 0x0654, 0x0654, 0x0654}, /* U+0654  */
-  {0x0655, 0x0655, 0x0655, 0x0655}, /* U+0655  */
-  {0x0656, 0x0656, 0x0656, 0x0656}, /* U+0656  */
-  {0x0657, 0x0657, 0x0657, 0x0657}, /* U+0657  */
-  {0x0658, 0x0658, 0x0658, 0x0658}, /* U+0658  */
-  {0x0659, 0x0659, 0x0659, 0x0659}, /* U+0659  */
-  {0x065A, 0x065A, 0x065A, 0x065A}, /* U+065A  */
-  {0x065B, 0x065B, 0x065B, 0x065B}, /* U+065B  */
-  {0x065C, 0x065C, 0x065C, 0x065C}, /* U+065C  */
-  {0x065D, 0x065D, 0x065D, 0x065D}, /* U+065D  */
-  {0x065E, 0x065E, 0x065E, 0x065E}, /* U+065E  */
-  {0x065F, 0x065F, 0x065F, 0x065F}, /* U+065F  */
-  {0x0660, 0x0660, 0x0660, 0x0660}, /* U+0660  */
-  {0x0661, 0x0661, 0x0661, 0x0661}, /* U+0661  */
-  {0x0662, 0x0662, 0x0662, 0x0662}, /* U+0662  */
-  {0x0663, 0x0663, 0x0663, 0x0663}, /* U+0663  */
-  {0x0664, 0x0664, 0x0664, 0x0664}, /* U+0664  */
-  {0x0665, 0x0665, 0x0665, 0x0665}, /* U+0665  */
-  {0x0666, 0x0666, 0x0666, 0x0666}, /* U+0666  */
-  {0x0667, 0x0667, 0x0667, 0x0667}, /* U+0667  */
-  {0x0668, 0x0668, 0x0668, 0x0668}, /* U+0668  */
-  {0x0669, 0x0669, 0x0669, 0x0669}, /* U+0669  */
-  {0x066A, 0x066A, 0x066A, 0x066A}, /* U+066A  */
-  {0x066B, 0x066B, 0x066B, 0x066B}, /* U+066B  */
-  {0x066C, 0x066C, 0x066C, 0x066C}, /* U+066C  */
-  {0x066D, 0x066D, 0x066D, 0x066D}, /* U+066D  */
-  {0x066E, 0x066E, 0x066E, 0x066E}, /* U+066E  */
-  {0x066F, 0x066F, 0x066F, 0x066F}, /* U+066F  */
-  {0x0670, 0x0670, 0x0670, 0x0670}, /* U+0670  */
-  {0x0671, 0x0671, 0xFB51, 0xFB50}, /* U+0671 ARABIC LETTER ALEF WASLA */
-  {0x0672, 0x0672, 0x0672, 0x0672}, /* U+0672  */
-  {0x0673, 0x0673, 0x0673, 0x0673}, /* U+0673  */
-  {0x0674, 0x0674, 0x0674, 0x0674}, /* U+0674  */
-  {0x0675, 0x0675, 0x0675, 0x0675}, /* U+0675  */
-  {0x0676, 0x0676, 0x0676, 0x0676}, /* U+0676  */
-  {0x0677, 0x0677, 0x0677, 0xFBDD}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
-  {0x0678, 0x0678, 0x0678, 0x0678}, /* U+0678  */
-  {0xFB68, 0xFB69, 0xFB67, 0xFB66}, /* U+0679 ARABIC LETTER TTEH */
-  {0xFB60, 0xFB61, 0xFB5F, 0xFB5E}, /* U+067A ARABIC LETTER TTEHEH */
-  {0xFB54, 0xFB55, 0xFB53, 0xFB52}, /* U+067B ARABIC LETTER BEEH */
-  {0x067C, 0x067C, 0x067C, 0x067C}, /* U+067C  */
-  {0x067D, 0x067D, 0x067D, 0x067D}, /* U+067D  */
-  {0xFB58, 0xFB59, 0xFB57, 0xFB56}, /* U+067E ARABIC LETTER PEH */
-  {0xFB64, 0xFB65, 0xFB63, 0xFB62}, /* U+067F ARABIC LETTER TEHEH */
-  {0xFB5C, 0xFB5D, 0xFB5B, 0xFB5A}, /* U+0680 ARABIC LETTER BEHEH */
-  {0x0681, 0x0681, 0x0681, 0x0681}, /* U+0681  */
-  {0x0682, 0x0682, 0x0682, 0x0682}, /* U+0682  */
-  {0xFB78, 0xFB79, 0xFB77, 0xFB76}, /* U+0683 ARABIC LETTER NYEH */
-  {0xFB74, 0xFB75, 0xFB73, 0xFB72}, /* U+0684 ARABIC LETTER DYEH */
-  {0x0685, 0x0685, 0x0685, 0x0685}, /* U+0685  */
-  {0xFB7C, 0xFB7D, 0xFB7B, 0xFB7A}, /* U+0686 ARABIC LETTER TCHEH */
-  {0xFB80, 0xFB81, 0xFB7F, 0xFB7E}, /* U+0687 ARABIC LETTER TCHEHEH */
-  {0x0688, 0x0688, 0xFB89, 0xFB88}, /* U+0688 ARABIC LETTER DDAL */
-  {0x0689, 0x0689, 0x0689, 0x0689}, /* U+0689  */
-  {0x068A, 0x068A, 0x068A, 0x068A}, /* U+068A  */
-  {0x068B, 0x068B, 0x068B, 0x068B}, /* U+068B  */
-  {0x068C, 0x068C, 0xFB85, 0xFB84}, /* U+068C ARABIC LETTER DAHAL */
-  {0x068D, 0x068D, 0xFB83, 0xFB82}, /* U+068D ARABIC LETTER DDAHAL */
-  {0x068E, 0x068E, 0xFB87, 0xFB86}, /* U+068E ARABIC LETTER DUL */
-  {0x068F, 0x068F, 0x068F, 0x068F}, /* U+068F  */
-  {0x0690, 0x0690, 0x0690, 0x0690}, /* U+0690  */
-  {0x0691, 0x0691, 0xFB8D, 0xFB8C}, /* U+0691 ARABIC LETTER RREH */
-  {0x0692, 0x0692, 0x0692, 0x0692}, /* U+0692  */
-  {0x0693, 0x0693, 0x0693, 0x0693}, /* U+0693  */
-  {0x0694, 0x0694, 0x0694, 0x0694}, /* U+0694  */
-  {0x0695, 0x0695, 0x0695, 0x0695}, /* U+0695  */
-  {0x0696, 0x0696, 0x0696, 0x0696}, /* U+0696  */
-  {0x0697, 0x0697, 0x0697, 0x0697}, /* U+0697  */
-  {0x0698, 0x0698, 0xFB8B, 0xFB8A}, /* U+0698 ARABIC LETTER JEH */
-  {0x0699, 0x0699, 0x0699, 0x0699}, /* U+0699  */
-  {0x069A, 0x069A, 0x069A, 0x069A}, /* U+069A  */
-  {0x069B, 0x069B, 0x069B, 0x069B}, /* U+069B  */
-  {0x069C, 0x069C, 0x069C, 0x069C}, /* U+069C  */
-  {0x069D, 0x069D, 0x069D, 0x069D}, /* U+069D  */
-  {0x069E, 0x069E, 0x069E, 0x069E}, /* U+069E  */
-  {0x069F, 0x069F, 0x069F, 0x069F}, /* U+069F  */
-  {0x06A0, 0x06A0, 0x06A0, 0x06A0}, /* U+06A0  */
-  {0x06A1, 0x06A1, 0x06A1, 0x06A1}, /* U+06A1  */
-  {0x06A2, 0x06A2, 0x06A2, 0x06A2}, /* U+06A2  */
-  {0x06A3, 0x06A3, 0x06A3, 0x06A3}, /* U+06A3  */
-  {0xFB6C, 0xFB6D, 0xFB6B, 0xFB6A}, /* U+06A4 ARABIC LETTER VEH */
-  {0x06A5, 0x06A5, 0x06A5, 0x06A5}, /* U+06A5  */
-  {0xFB70, 0xFB71, 0xFB6F, 0xFB6E}, /* U+06A6 ARABIC LETTER PEHEH */
-  {0x06A7, 0x06A7, 0x06A7, 0x06A7}, /* U+06A7  */
-  {0x06A8, 0x06A8, 0x06A8, 0x06A8}, /* U+06A8  */
-  {0xFB90, 0xFB91, 0xFB8F, 0xFB8E}, /* U+06A9 ARABIC LETTER KEHEH */
-  {0x06AA, 0x06AA, 0x06AA, 0x06AA}, /* U+06AA  */
-  {0x06AB, 0x06AB, 0x06AB, 0x06AB}, /* U+06AB  */
-  {0x06AC, 0x06AC, 0x06AC, 0x06AC}, /* U+06AC  */
-  {0xFBD5, 0xFBD6, 0xFBD4, 0xFBD3}, /* U+06AD ARABIC LETTER NG */
-  {0x06AE, 0x06AE, 0x06AE, 0x06AE}, /* U+06AE  */
-  {0xFB94, 0xFB95, 0xFB93, 0xFB92}, /* U+06AF ARABIC LETTER GAF */
-  {0x06B0, 0x06B0, 0x06B0, 0x06B0}, /* U+06B0  */
-  {0xFB9C, 0xFB9D, 0xFB9B, 0xFB9A}, /* U+06B1 ARABIC LETTER NGOEH */
-  {0x06B2, 0x06B2, 0x06B2, 0x06B2}, /* U+06B2  */
-  {0xFB98, 0xFB99, 0xFB97, 0xFB96}, /* U+06B3 ARABIC LETTER GUEH */
-  {0x06B4, 0x06B4, 0x06B4, 0x06B4}, /* U+06B4  */
-  {0x06B5, 0x06B5, 0x06B5, 0x06B5}, /* U+06B5  */
-  {0x06B6, 0x06B6, 0x06B6, 0x06B6}, /* U+06B6  */
-  {0x06B7, 0x06B7, 0x06B7, 0x06B7}, /* U+06B7  */
-  {0x06B8, 0x06B8, 0x06B8, 0x06B8}, /* U+06B8  */
-  {0x06B9, 0x06B9, 0x06B9, 0x06B9}, /* U+06B9  */
-  {0x06BA, 0x06BA, 0xFB9F, 0xFB9E}, /* U+06BA ARABIC LETTER NOON GHUNNA */
-  {0xFBA2, 0xFBA3, 0xFBA1, 0xFBA0}, /* U+06BB ARABIC LETTER RNOON */
-  {0x06BC, 0x06BC, 0x06BC, 0x06BC}, /* U+06BC  */
-  {0x06BD, 0x06BD, 0x06BD, 0x06BD}, /* U+06BD  */
-  {0xFBAC, 0xFBAD, 0xFBAB, 0xFBAA}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
-  {0x06BF, 0x06BF, 0x06BF, 0x06BF}, /* U+06BF  */
-  {0x06C0, 0x06C0, 0xFBA5, 0xFBA4}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
-  {0xFBA8, 0xFBA9, 0xFBA7, 0xFBA6}, /* U+06C1 ARABIC LETTER HEH GOAL */
-  {0x06C2, 0x06C2, 0x06C2, 0x06C2}, /* U+06C2  */
-  {0x06C3, 0x06C3, 0x06C3, 0x06C3}, /* U+06C3  */
-  {0x06C4, 0x06C4, 0x06C4, 0x06C4}, /* U+06C4  */
-  {0x06C5, 0x06C5, 0xFBE1, 0xFBE0}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
-  {0x06C6, 0x06C6, 0xFBDA, 0xFBD9}, /* U+06C6 ARABIC LETTER OE */
-  {0x06C7, 0x06C7, 0xFBD8, 0xFBD7}, /* U+06C7 ARABIC LETTER U */
-  {0x06C8, 0x06C8, 0xFBDC, 0xFBDB}, /* U+06C8 ARABIC LETTER YU */
-  {0x06C9, 0x06C9, 0xFBE3, 0xFBE2}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
-  {0x06CA, 0x06CA, 0x06CA, 0x06CA}, /* U+06CA  */
-  {0x06CB, 0x06CB, 0xFBDF, 0xFBDE}, /* U+06CB ARABIC LETTER VE */
-  {0xFBFE, 0xFBFF, 0xFBFD, 0xFBFC}, /* U+06CC ARABIC LETTER FARSI YEH */
-  {0x06CD, 0x06CD, 0x06CD, 0x06CD}, /* U+06CD  */
-  {0x06CE, 0x06CE, 0x06CE, 0x06CE}, /* U+06CE  */
-  {0x06CF, 0x06CF, 0x06CF, 0x06CF}, /* U+06CF  */
-  {0xFBE6, 0xFBE7, 0xFBE5, 0xFBE4}, /* U+06D0 ARABIC LETTER E */
-  {0x06D1, 0x06D1, 0x06D1, 0x06D1}, /* U+06D1  */
-  {0x06D2, 0x06D2, 0xFBAF, 0xFBAE}, /* U+06D2 ARABIC LETTER YEH BARREE */
-  {0x06D3, 0x06D3, 0xFBB1, 0xFBB0}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
+  {0x0000u, 0x0000u, 0x0000u, 0xFE80u}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
+  {0x0000u, 0x0000u, 0xFE82u, 0xFE81u}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
+  {0x0000u, 0x0000u, 0xFE84u, 0xFE83u}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
+  {0x0000u, 0x0000u, 0xFE86u, 0xFE85u}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
+  {0x0000u, 0x0000u, 0xFE88u, 0xFE87u}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
+  {0xFE8Bu, 0xFE8Cu, 0xFE8Au, 0xFE89u}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
+  {0x0000u, 0x0000u, 0xFE8Eu, 0xFE8Du}, /* U+0627 ARABIC LETTER ALEF */
+  {0xFE91u, 0xFE92u, 0xFE90u, 0xFE8Fu}, /* U+0628 ARABIC LETTER BEH */
+  {0x0000u, 0x0000u, 0xFE94u, 0xFE93u}, /* U+0629 ARABIC LETTER TEH MARBUTA */
+  {0xFE97u, 0xFE98u, 0xFE96u, 0xFE95u}, /* U+062A ARABIC LETTER TEH */
+  {0xFE9Bu, 0xFE9Cu, 0xFE9Au, 0xFE99u}, /* U+062B ARABIC LETTER THEH */
+  {0xFE9Fu, 0xFEA0u, 0xFE9Eu, 0xFE9Du}, /* U+062C ARABIC LETTER JEEM */
+  {0xFEA3u, 0xFEA4u, 0xFEA2u, 0xFEA1u}, /* U+062D ARABIC LETTER HAH */
+  {0xFEA7u, 0xFEA8u, 0xFEA6u, 0xFEA5u}, /* U+062E ARABIC LETTER KHAH */
+  {0x0000u, 0x0000u, 0xFEAAu, 0xFEA9u}, /* U+062F ARABIC LETTER DAL */
+  {0x0000u, 0x0000u, 0xFEACu, 0xFEABu}, /* U+0630 ARABIC LETTER THAL */
+  {0x0000u, 0x0000u, 0xFEAEu, 0xFEADu}, /* U+0631 ARABIC LETTER REH */
+  {0x0000u, 0x0000u, 0xFEB0u, 0xFEAFu}, /* U+0632 ARABIC LETTER ZAIN */
+  {0xFEB3u, 0xFEB4u, 0xFEB2u, 0xFEB1u}, /* U+0633 ARABIC LETTER SEEN */
+  {0xFEB7u, 0xFEB8u, 0xFEB6u, 0xFEB5u}, /* U+0634 ARABIC LETTER SHEEN */
+  {0xFEBBu, 0xFEBCu, 0xFEBAu, 0xFEB9u}, /* U+0635 ARABIC LETTER SAD */
+  {0xFEBFu, 0xFEC0u, 0xFEBEu, 0xFEBDu}, /* U+0636 ARABIC LETTER DAD */
+  {0xFEC3u, 0xFEC4u, 0xFEC2u, 0xFEC1u}, /* U+0637 ARABIC LETTER TAH */
+  {0xFEC7u, 0xFEC8u, 0xFEC6u, 0xFEC5u}, /* U+0638 ARABIC LETTER ZAH */
+  {0xFECBu, 0xFECCu, 0xFECAu, 0xFEC9u}, /* U+0639 ARABIC LETTER AIN */
+  {0xFECFu, 0xFED0u, 0xFECEu, 0xFECDu}, /* U+063A ARABIC LETTER GHAIN */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0640  */
+  {0xFED3u, 0xFED4u, 0xFED2u, 0xFED1u}, /* U+0641 ARABIC LETTER FEH */
+  {0xFED7u, 0xFED8u, 0xFED6u, 0xFED5u}, /* U+0642 ARABIC LETTER QAF */
+  {0xFEDBu, 0xFEDCu, 0xFEDAu, 0xFED9u}, /* U+0643 ARABIC LETTER KAF */
+  {0xFEDFu, 0xFEE0u, 0xFEDEu, 0xFEDDu}, /* U+0644 ARABIC LETTER LAM */
+  {0xFEE3u, 0xFEE4u, 0xFEE2u, 0xFEE1u}, /* U+0645 ARABIC LETTER MEEM */
+  {0xFEE7u, 0xFEE8u, 0xFEE6u, 0xFEE5u}, /* U+0646 ARABIC LETTER NOON */
+  {0xFEEBu, 0xFEECu, 0xFEEAu, 0xFEE9u}, /* U+0647 ARABIC LETTER HEH */
+  {0x0000u, 0x0000u, 0xFEEEu, 0xFEEDu}, /* U+0648 ARABIC LETTER WAW */
+  {0xFBE8u, 0xFBE9u, 0xFEF0u, 0xFEEFu}, /* U+0649 ARABIC LETTER */
+  {0xFEF3u, 0xFEF4u, 0xFEF2u, 0xFEF1u}, /* U+064A ARABIC LETTER YEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0650  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0651  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0652  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0653  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0654  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0655  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0656  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0657  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0658  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0659  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0660  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0661  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0662  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0663  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0664  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0665  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0666  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0667  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0668  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0669  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0670  */
+  {0x0000u, 0x0000u, 0xFB51u, 0xFB50u}, /* U+0671 ARABIC LETTER ALEF WASLA */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0672  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0673  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0674  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0675  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0676  */
+  {0x0000u, 0x0000u, 0x0000u, 0xFBDDu}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0678  */
+  {0xFB68u, 0xFB69u, 0xFB67u, 0xFB66u}, /* U+0679 ARABIC LETTER TTEH */
+  {0xFB60u, 0xFB61u, 0xFB5Fu, 0xFB5Eu}, /* U+067A ARABIC LETTER TTEHEH */
+  {0xFB54u, 0xFB55u, 0xFB53u, 0xFB52u}, /* U+067B ARABIC LETTER BEEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+067C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+067D  */
+  {0xFB58u, 0xFB59u, 0xFB57u, 0xFB56u}, /* U+067E ARABIC LETTER PEH */
+  {0xFB64u, 0xFB65u, 0xFB63u, 0xFB62u}, /* U+067F ARABIC LETTER TEHEH */
+  {0xFB5Cu, 0xFB5Du, 0xFB5Bu, 0xFB5Au}, /* U+0680 ARABIC LETTER BEHEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0681  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0682  */
+  {0xFB78u, 0xFB79u, 0xFB77u, 0xFB76u}, /* U+0683 ARABIC LETTER NYEH */
+  {0xFB74u, 0xFB75u, 0xFB73u, 0xFB72u}, /* U+0684 ARABIC LETTER DYEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0685  */
+  {0xFB7Cu, 0xFB7Du, 0xFB7Bu, 0xFB7Au}, /* U+0686 ARABIC LETTER TCHEH */
+  {0xFB80u, 0xFB81u, 0xFB7Fu, 0xFB7Eu}, /* U+0687 ARABIC LETTER TCHEHEH */
+  {0x0000u, 0x0000u, 0xFB89u, 0xFB88u}, /* U+0688 ARABIC LETTER DDAL */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0689  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068B  */
+  {0x0000u, 0x0000u, 0xFB85u, 0xFB84u}, /* U+068C ARABIC LETTER DAHAL */
+  {0x0000u, 0x0000u, 0xFB83u, 0xFB82u}, /* U+068D ARABIC LETTER DDAHAL */
+  {0x0000u, 0x0000u, 0xFB87u, 0xFB86u}, /* U+068E ARABIC LETTER DUL */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0690  */
+  {0x0000u, 0x0000u, 0xFB8Du, 0xFB8Cu}, /* U+0691 ARABIC LETTER RREH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0692  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0693  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0694  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0695  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0696  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0697  */
+  {0x0000u, 0x0000u, 0xFB8Bu, 0xFB8Au}, /* U+0698 ARABIC LETTER JEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0699  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069A  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069B  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069C  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069D  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069E  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069F  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A0  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A1  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A2  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A3  */
+  {0xFB6Cu, 0xFB6Du, 0xFB6Bu, 0xFB6Au}, /* U+06A4 ARABIC LETTER VEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A5  */
+  {0xFB70u, 0xFB71u, 0xFB6Fu, 0xFB6Eu}, /* U+06A6 ARABIC LETTER PEHEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A7  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A8  */
+  {0xFB90u, 0xFB91u, 0xFB8Fu, 0xFB8Eu}, /* U+06A9 ARABIC LETTER KEHEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AA  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AB  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AC  */
+  {0xFBD5u, 0xFBD6u, 0xFBD4u, 0xFBD3u}, /* U+06AD ARABIC LETTER NG */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AE  */
+  {0xFB94u, 0xFB95u, 0xFB93u, 0xFB92u}, /* U+06AF ARABIC LETTER GAF */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B0  */
+  {0xFB9Cu, 0xFB9Du, 0xFB9Bu, 0xFB9Au}, /* U+06B1 ARABIC LETTER NGOEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B2  */
+  {0xFB98u, 0xFB99u, 0xFB97u, 0xFB96u}, /* U+06B3 ARABIC LETTER GUEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B4  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B5  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B6  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B7  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B8  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B9  */
+  {0x0000u, 0x0000u, 0xFB9Fu, 0xFB9Eu}, /* U+06BA ARABIC LETTER NOON GHUNNA */
+  {0xFBA2u, 0xFBA3u, 0xFBA1u, 0xFBA0u}, /* U+06BB ARABIC LETTER RNOON */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BC  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BD  */
+  {0xFBACu, 0xFBADu, 0xFBABu, 0xFBAAu}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BF  */
+  {0x0000u, 0x0000u, 0xFBA5u, 0xFBA4u}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
+  {0xFBA8u, 0xFBA9u, 0xFBA7u, 0xFBA6u}, /* U+06C1 ARABIC LETTER HEH GOAL */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C2  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C3  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C4  */
+  {0x0000u, 0x0000u, 0xFBE1u, 0xFBE0u}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
+  {0x0000u, 0x0000u, 0xFBDAu, 0xFBD9u}, /* U+06C6 ARABIC LETTER OE */
+  {0x0000u, 0x0000u, 0xFBD8u, 0xFBD7u}, /* U+06C7 ARABIC LETTER U */
+  {0x0000u, 0x0000u, 0xFBDCu, 0xFBDBu}, /* U+06C8 ARABIC LETTER YU */
+  {0x0000u, 0x0000u, 0xFBE3u, 0xFBE2u}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CA  */
+  {0x0000u, 0x0000u, 0xFBDFu, 0xFBDEu}, /* U+06CB ARABIC LETTER VE */
+  {0xFBFEu, 0xFBFFu, 0xFBFDu, 0xFBFCu}, /* U+06CC ARABIC LETTER FARSI YEH */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CD  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CE  */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CF  */
+  {0xFBE6u, 0xFBE7u, 0xFBE5u, 0xFBE4u}, /* U+06D0 ARABIC LETTER E */
+  {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06D1  */
+  {0x0000u, 0x0000u, 0xFBAFu, 0xFBAEu}, /* U+06D2 ARABIC LETTER YEH BARREE */
+  {0x0000u, 0x0000u, 0xFBB1u, 0xFBB0u}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
 };
 
-#define SHAPING_TABLE_FIRST    0x0621
-#define SHAPING_TABLE_LAST     0x06D3
+#define SHAPING_TABLE_FIRST    0x0621u
+#define SHAPING_TABLE_LAST     0x06D3u
 
 
-static const struct {
+static const struct ligature_set_t {
  uint16_t first;
- struct {
+ struct ligature_pairs_t {
    uint16_t second;
    uint16_t ligature;
  } ligatures[4];
 } ligature_table[] =
 {
-  { 0xFEDF, {
-    { 0xFE88, 0xFEF9 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
-    { 0xFE82, 0xFEF5 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
-    { 0xFE8E, 0xFEFB }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
-    { 0xFE84, 0xFEF7 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
+  { 0xFEDFu, {
+    { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
+    { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
+    { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
+    { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
   }},
-  { 0xFEE0, {
-    { 0xFE88, 0xFEFA }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
-    { 0xFE82, 0xFEF6 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
-    { 0xFE8E, 0xFEFC }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
-    { 0xFE84, 0xFEF8 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
+  { 0xFEE0u, {
+    { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
+    { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
+    { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+    { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
   }},
 };
 
diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh
new file mode 100644 (file)
index 0000000..8edd3ba
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * 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
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+
+
+/*
+ * The macros in the first part of this file are generic macros that can
+ * be used to define the bytes for OpenType table data in code in a
+ * readable manner.  We can move the macros to reside with their respective
+ * struct types, but since we only use these to define one data table, the
+ * Windows-1256 Arabic shaping table in this file, we keep them here.
+ */
+
+
+/* First we measure, then we cut. */
+#ifndef OT_MEASURE
+#define OT_MEASURE
+#define OT_TABLE_START                 static const struct TABLE_NAME {
+#define OT_TABLE_END                   }
+#define OT_LABEL_START(Name)           unsigned char Name[
+#define OT_LABEL_END                   ];
+#define OT_BYTE(u8)                    +1/*byte*/
+#define OT_USHORT(u16)                 +2/*bytes*/
+#else
+#undef  OT_MEASURE
+#define OT_TABLE_START                 TABLE_NAME = {
+#define OT_TABLE_END                   };
+#define OT_LABEL_START(Name)           {
+#define OT_LABEL_END                   },
+#define OT_BYTE(u8)                    (u8),
+#define OT_USHORT(u16)                 (unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
+#define OT_COUNT(Name, ItemSize)       ((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
+                                        / (unsigned int)(ItemSize) \
+                                        /* OT_ASSERT it's divisible (and positive). */)
+#define OT_DISTANCE(From,To)           ((unsigned int) \
+                                        ((char*)(&((struct TABLE_NAME*)0)->To) - \
+                                         (char*)(&((struct TABLE_NAME*)0)->From)) \
+                                        /* OT_ASSERT it's positive. */)
+#endif
+
+
+#define OT_LABEL(Name) \
+       OT_LABEL_END \
+       OT_LABEL_START(Name)
+
+/* Whenever we receive an argument that is a list, it will expand to
+ * contain commas.  That cannot be passed to another macro because the
+ * commas will throw off the preprocessor.  The solution is to wrap
+ * the passed-in argument in OT_LIST() before passing to the next macro.
+ * Unfortunately this trick requires vararg macros. */
+#define OT_LIST(...) __VA_ARGS__
+
+
+/*
+ * Basic Types
+ */
+
+#define OT_TAG(a,b,c,d) \
+       OT_BYTE(a) OT_BYTE(b) OT_BYTE(c) OT_BYTE(d)
+
+#define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
+       OT_USHORT(OT_DISTANCE(From, To))
+
+#define OT_GLYPHID /* GlyphID */ \
+       OT_USHORT
+
+#define OT_UARRAY(Name, Items) \
+       OT_LABEL_START(Name) \
+       OT_USHORT(OT_COUNT(Name##Data, 2)) \
+       OT_LABEL(Name##Data) \
+       Items \
+       OT_LABEL_END
+
+#define OT_UHEADLESSARRAY(Name, Items) \
+       OT_LABEL_START(Name) \
+       OT_USHORT(OT_COUNT(Name##Data, 2) + 1) \
+       OT_LABEL(Name##Data) \
+       Items \
+       OT_LABEL_END
+
+
+/*
+ * Common Types
+ */
+
+#define OT_LOOKUP_FLAG_IGNORE_MARKS    0x08u
+
+#define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
+       OT_LABEL_START(Name) \
+       OT_USHORT(LookupType) \
+       OT_USHORT(LookupFlag) \
+       OT_LABEL_END \
+       OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))
+
+#define OT_SUBLOOKUP(Name, SubFormat, Items) \
+       OT_LABEL_START(Name) \
+       OT_USHORT(SubFormat) \
+       Items
+
+#define OT_COVERAGE1(Name, Items) \
+       OT_LABEL_START(Name) \
+       OT_USHORT(1) \
+       OT_LABEL_END \
+       OT_UARRAY(Name##Glyphs, OT_LIST(Items))
+
+
+/*
+ * GSUB
+ */
+
+#define OT_LOOKUP_TYPE_SUBST_SINGLE    1u
+#define OT_LOOKUP_TYPE_SUBST_LIGATURE  4u
+
+#define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
+       OT_SUBLOOKUP(Name, 2, \
+               OT_OFFSET(Name, Name##Coverage) \
+               OT_LABEL_END \
+               OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
+       ) \
+       OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
+       /* ASSERT_STATIC_EXPR len(FromGlyphs) == len(ToGlyphs) */
+
+#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
+       OT_SUBLOOKUP(Name, 1, \
+               OT_OFFSET(Name, Name##Coverage) \
+               OT_LABEL_END \
+               OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
+       ) \
+       OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
+       /* ASSERT_STATIC_EXPR len(FirstGlyphs) == len(LigatureSetOffsets) */
+
+#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
+       OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
+
+#define OT_LIGATURE(Name, Components, LigGlyph) \
+       OT_LABEL_START(Name) \
+       LigGlyph \
+       OT_LABEL_END \
+       OT_UHEADLESSARRAY(Name##ComponentsArray, OT_LIST(Components))
+
+/*
+ *
+ * Start of Windows-1256 shaping table.
+ *
+ */
+
+/* Table name. */
+#define TABLE_NAME arabic_win1256_gsub_lookups
+
+/* Table manifest. */
+#define MANIFEST(Items) \
+       OT_LABEL_START(manifest) \
+       OT_USHORT(OT_COUNT(manifestData, 6)) \
+       OT_LABEL(manifestData) \
+       Items \
+       OT_LABEL_END
+
+#define MANIFEST_LOOKUP(Tag, Name) \
+       Tag \
+       OT_OFFSET(manifest, Name)
+
+/* Shorthand. */
+#define G      OT_GLYPHID
+
+/*
+ * Table Start
+ */
+OT_TABLE_START
+
+
+/*
+ * Manifest
+ */
+MANIFEST(
+       MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligLookup)
+       MANIFEST_LOOKUP(OT_TAG('i','n','i','t'), initLookup)
+       MANIFEST_LOOKUP(OT_TAG('m','e','d','i'), mediLookup)
+       MANIFEST_LOOKUP(OT_TAG('f','i','n','a'), finaLookup)
+       MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligMarksLookup)
+)
+
+/*
+ * Lookups
+ */
+OT_LOOKUP(initLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+       OT_OFFSET(initLookup, initmediSubLookup)
+       OT_OFFSET(initLookup, initSubLookup)
+)
+OT_LOOKUP(mediLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+       OT_OFFSET(mediLookup, initmediSubLookup)
+       OT_OFFSET(mediLookup, mediSubLookup)
+       OT_OFFSET(mediLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(finaLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+       OT_OFFSET(finaLookup, finaSubLookup)
+       /* We don't need this one currently as the sequence inherits masks
+        * from the first item.  Just in case we change that in the future
+        * to be smart about Arabic masks when ligating... */
+       OT_OFFSET(finaLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(rligLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+       OT_OFFSET(rligLookup, lamAlefLigaturesSubLookup)
+)
+OT_LOOKUP(rligMarksLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, 0,
+       OT_OFFSET(rligMarksLookup, shaddaLigaturesSubLookup)
+)
+
+/*
+ * init/medi/fina forms
+ */
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initmediSubLookup,
+       G(198)  G(200)  G(201)  G(202)  G(203)  G(204)  G(205)  G(206)  G(211)
+       G(212)  G(213)  G(214)  G(223)  G(225)  G(227)  G(228)  G(236)  G(237),
+       G(162)  G(4)    G(5)    G(5)    G(6)    G(7)    G(9)    G(11)   G(13)
+       G(14)   G(15)   G(26)   G(140)  G(141)  G(142)  G(143)  G(154)  G(154)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initSubLookup,
+       G(218)  G(219)  G(221)  G(222)  G(229),
+       G(27)   G(30)   G(128)  G(131)  G(144)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(mediSubLookup,
+       G(218)  G(219)  G(221)  G(222)  G(229),
+       G(28)   G(31)   G(129)  G(138)  G(149)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(finaSubLookup,
+       G(194)  G(195)  G(197)  G(198)  G(199)  G(201)  G(204)  G(205)  G(206)
+       G(218)  G(219)  G(229)  G(236)  G(237),
+       G(2)    G(1)    G(3)    G(181)  G(0)    G(159)  G(8)    G(10)   G(12)
+       G(29)   G(127)  G(152) G(160)   G(156)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(medifinaLamAlefSubLookup,
+       G(165)  G(178)  G(180)  G(252),
+       G(170)  G(179)  G(185)  G(255)
+)
+
+/*
+ * Lam+Alef ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(lamAlefLigaturesSubLookup,
+       G(225),
+       OT_OFFSET(lamAlefLigaturesSubLookup, lamLigatureSet)
+)
+OT_LIGATURE_SET(lamLigatureSet,
+       OT_OFFSET(lamLigatureSet, lamInitLigature1)
+       OT_OFFSET(lamLigatureSet, lamInitLigature2)
+       OT_OFFSET(lamLigatureSet, lamInitLigature3)
+       OT_OFFSET(lamLigatureSet, lamInitLigature4)
+)
+OT_LIGATURE(lamInitLigature1, G(199), G(165))
+OT_LIGATURE(lamInitLigature2, G(195), G(178))
+OT_LIGATURE(lamInitLigature3, G(194), G(180))
+OT_LIGATURE(lamInitLigature4, G(197), G(252))
+
+/*
+ * Shadda ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(shaddaLigaturesSubLookup,
+       G(248),
+       OT_OFFSET(shaddaLigaturesSubLookup, shaddaLigatureSet)
+)
+OT_LIGATURE_SET(shaddaLigatureSet,
+       OT_OFFSET(shaddaLigatureSet, shaddaLigature1)
+       OT_OFFSET(shaddaLigatureSet, shaddaLigature2)
+       OT_OFFSET(shaddaLigatureSet, shaddaLigature3)
+)
+OT_LIGATURE(shaddaLigature1, G(243), G(172))
+OT_LIGATURE(shaddaLigature2, G(245), G(173))
+OT_LIGATURE(shaddaLigature3, G(246), G(175))
+
+/*
+ * Table end
+ */
+OT_TABLE_END
+
+
+/*
+ * Clean up
+ */
+#undef OT_TABLE_START
+#undef OT_TABLE_END
+#undef OT_LABEL_START
+#undef OT_LABEL_END
+#undef OT_BYTE
+#undef OT_USHORT
+#undef OT_DISTANCE
+#undef OT_COUNT
+
+/*
+ * Include a second time to get the table data...
+ */
+#if 0
+#include "hb-private.hh" /* Make check-includes.sh happy. */
+#endif
+#ifdef OT_MEASURE
+#include "hb-ot-shape-complex-arabic-win1256.hh"
+#endif
+
+#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */
index 54460f0..ae90864 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2010  Google, Inc.
+ * Copyright © 2010,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -28,9 +28,8 @@
 #include "hb-ot-shape-private.hh"
 
 
-
 /* buffer var allocations */
-#define arabic_shaping_action() complex_var_temporary_u8() /* arabic shaping action */
+#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
 
 
 /*
  */
 enum {
   JOINING_TYPE_U               = 0,
-  JOINING_TYPE_R               = 1,
-  JOINING_TYPE_D               = 2,
+  JOINING_TYPE_L               = 1,
+  JOINING_TYPE_R               = 2,
+  JOINING_TYPE_D               = 3,
   JOINING_TYPE_C               = JOINING_TYPE_D,
-  JOINING_GROUP_ALAPH          = 3,
-  JOINING_GROUP_DALATH_RISH    = 4,
-  NUM_STATE_MACHINE_COLS       = 5,
-
-  /* We deliberately don't have a JOINING_TYPE_L since that's unused in Unicode. */
+  JOINING_GROUP_ALAPH          = 4,
+  JOINING_GROUP_DALATH_RISH    = 5,
+  NUM_STATE_MACHINE_COLS       = 6,
 
-  JOINING_TYPE_T = 6,
-  JOINING_TYPE_X = 7  /* means: use general-category to choose between U or T. */
+  JOINING_TYPE_T = 7,
+  JOINING_TYPE_X = 8  /* means: use general-category to choose between U or T. */
 };
 
 /*
@@ -59,77 +57,45 @@ enum {
 
 static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
 {
-  if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, JOINING_TABLE_LAST))) {
-    unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST];
-    if (likely (j_type != JOINING_TYPE_X))
-      return j_type;
-  }
-
-  /* Mongolian joining data is not in ArabicJoining.txt yet */
-  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF)))
-  {
-    /* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */
-    if (gen_cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A)
-      return JOINING_TYPE_D;
-  }
-
-  if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) {
-    return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
-  }
-
-  return (FLAG(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))) ?
-        JOINING_TYPE_T : JOINING_TYPE_U;
-}
-
-static hb_codepoint_t get_arabic_shape (hb_codepoint_t u, unsigned int shape)
-{
-  if (likely (hb_in_range<hb_codepoint_t> (u, SHAPING_TABLE_FIRST, SHAPING_TABLE_LAST)) && shape < 4)
-    return shaping_table[u - SHAPING_TABLE_FIRST][shape];
-  return u;
+  unsigned int j_type = joining_type(u);
+  if (likely (j_type != JOINING_TYPE_X))
+    return j_type;
+
+  return (FLAG(gen_cat) &
+         (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
+          FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
+          FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
+        ) ?  JOINING_TYPE_T : JOINING_TYPE_U;
 }
 
-static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second)
-{
-  if (unlikely (!second)) return 0;
-  for (unsigned i = 0; i < ARRAY_LENGTH (ligature_table); i++)
-    if (ligature_table[i].first == first)
-      for (unsigned j = 0; j < ARRAY_LENGTH (ligature_table[i].ligatures); j++)
-       if (ligature_table[i].ligatures[j].second == second)
-         return ligature_table[i].ligatures[j].ligature;
-  return 0;
-}
+#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
 
-static const hb_tag_t arabic_syriac_features[] =
+static const hb_tag_t arabic_features[] =
 {
-  HB_TAG('i','n','i','t'),
-  HB_TAG('m','e','d','i'),
-  HB_TAG('f','i','n','a'),
   HB_TAG('i','s','o','l'),
-  /* Syriac */
-  HB_TAG('m','e','d','2'),
+  HB_TAG('f','i','n','a'),
   HB_TAG('f','i','n','2'),
   HB_TAG('f','i','n','3'),
+  HB_TAG('m','e','d','i'),
+  HB_TAG('m','e','d','2'),
+  HB_TAG('i','n','i','t'),
   HB_TAG_NONE
 };
 
 
 /* Same order as the feature array */
 enum {
-  INIT,
-  MEDI,
-  FINA,
   ISOL,
-
-  /* Syriac */
-  MED2,
+  FINA,
   FIN2,
   FIN3,
+  MEDI,
+  MED2,
+  INIT,
 
   NONE,
 
-  COMMON_NUM_FEATURES = 4,
-  SYRIAC_NUM_FEATURES = 7,
-  TOTAL_NUM_FEATURES = NONE
+  ARABIC_NUM_FEATURES = NONE
 };
 
 static const struct arabic_state_table_entry {
@@ -138,162 +104,279 @@ static const struct arabic_state_table_entry {
        uint16_t next_state;
 } arabic_state_table[][NUM_STATE_MACHINE_COLS] =
 {
-  /*   jt_U,          jt_R,          jt_D,          jg_ALAPH,      jg_DALATH_RISH */
+  /*   jt_U,          jt_L,          jt_R,          jt_D,          jg_ALAPH,      jg_DALATH_RISH */
 
   /* State 0: prev was U, not willing to join. */
-  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
 
   /* State 1: prev was R or ISOL/ALAPH, not willing to join. */
-  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
 
-  /* State 2: prev was D/ISOL, willing to join. */
-  { {NONE,NONE,0}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
+  /* State 2: prev was D/L in ISOL form, willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
 
-  /* State 3: prev was D/FINA, willing to join. */
-  { {NONE,NONE,0}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
+  /* State 3: prev was D in FINA form, willing to join. */
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
 
   /* State 4: prev was FINA ALAPH, not willing to join. */
-  { {NONE,NONE,0}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
 
   /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
-  { {NONE,NONE,0}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
 
   /* State 6: prev was DALATH/RISH, not willing to join. */
-  { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
+  { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
 };
 
 
+static void
+nuke_joiners (const hb_ot_shape_plan_t *plan,
+             hb_font_t *font,
+             hb_buffer_t *buffer);
 
-void
-_hb_ot_shape_complex_collect_features_arabic (hb_ot_map_builder_t *map,
-                                             const hb_segment_properties_t *props)
+static void
+arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer);
+
+static void
+collect_features_arabic (hb_ot_shape_planner_t *plan)
 {
-  /* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together,
-   * then rlig and calt each in their own stage.  This makes IranNastaliq's ALLAH
-   * ligature work correctly. It's unfortunate though...
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* We apply features according to the Arabic spec, with pauses
+   * in between most.
    *
-   * This also makes Arial Bold in Windows7 work.  See:
+   * The pause between init/medi/... and rlig is required.  See eg:
    * https://bugzilla.mozilla.org/show_bug.cgi?id=644184
    *
-   * TODO: Add test cases for these two.
+   * The pauses between init/medi/... themselves are not necessarily
+   * needed as only one of those features is applied to any character.
+   * The only difference it makes is when fonts have contextual
+   * substitutions.  We now follow the order of the spec, which makes
+   * for better experience if that's what Uniscribe is doing.
+   *
+   * At least for Arabic, looks like Uniscribe has a pause between
+   * rlig and calt.  Otherwise the IranNastaliq's ALLAH ligature won't
+   * 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.
    */
 
-  map->add_bool_feature (HB_TAG('c','c','m','p'));
-  map->add_bool_feature (HB_TAG('l','o','c','l'));
-
-  map->add_gsub_pause (NULL, NULL);
-
-  unsigned int num_features = props->script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
-  for (unsigned int i = 0; i < num_features; i++)
-    map->add_bool_feature (arabic_syriac_features[i], false);
+  map->add_gsub_pause (nuke_joiners);
 
-  map->add_gsub_pause (NULL, NULL);
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
 
-  map->add_bool_feature (HB_TAG('r','l','i','g'));
-  map->add_gsub_pause (NULL, NULL);
+  map->add_gsub_pause (NULL);
 
-  map->add_bool_feature (HB_TAG('c','a','l','t'));
-  map->add_gsub_pause (NULL, NULL);
+  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], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
+    map->add_gsub_pause (NULL);
+  }
 
-  /* ArabicOT spec enables 'cswh' for Arabic where as for basic shaper it's disabled by default. */
-  map->add_bool_feature (HB_TAG('c','s','w','h'));
+  map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
+  if (plan->props.script == HB_SCRIPT_ARABIC)
+    map->add_gsub_pause (arabic_fallback_shape);
+
+  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+  map->add_gsub_pause (NULL);
+
+  /* The spec includes 'cswh'.  Earlier versions of Windows
+   * used to enable this by default, but testing suggests
+   * that Windows 8 and later do not enable it by default,
+   * and spec now says 'Off by default'.
+   * We disabled this in ae23c24c32.
+   * Note that IranNastaliq uses this feature extensively
+   * to fixup broken glyph sequences.  Oh well...
+   * Test case: U+0643,U+0640,U+0631. */
+  //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
+  map->add_global_bool_feature (HB_TAG('m','s','e','t'));
 }
 
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_arabic (void)
+#include "hb-ot-shape-complex-arabic-fallback.hh"
+
+struct arabic_shape_plan_t
 {
-  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
-}
+  ASSERT_POD ();
 
+  /* The "+ 1" in the next array is to accommodate for the "NONE" command,
+   * which is not an OpenType feature, but this simplifies the code by not
+   * having to do a "if (... < NONE) ..." and just rely on the fact that
+   * mask_array[NONE] == 0. */
+  hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
 
-static void
-arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
+  bool do_fallback;
+  arabic_fallback_plan_t *fallback_plan;
+};
+
+static void *
+data_create_arabic (const hb_ot_shape_plan_t *plan)
 {
-  unsigned int count = buffer->len;
-  hb_codepoint_t glyph;
-
-  /* Shape to presentation forms */
-  for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t u = buffer->info[i].codepoint;
-    hb_codepoint_t shaped = get_arabic_shape (u, buffer->info[i].arabic_shaping_action());
-    if (shaped != u && hb_font_get_glyph (font, shaped, 0, &glyph))
-      buffer->info[i].codepoint = shaped;
+  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
+  if (unlikely (!arabic_plan))
+    return NULL;
+
+  arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
+  for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
+    arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
+    arabic_plan->do_fallback = arabic_plan->do_fallback &&
+                              (FEATURE_IS_SYRIAC (arabic_features[i]) ||
+                               plan->map.needs_fallback (arabic_features[i]));
   }
 
-  /* Mandatory ligatures */
-  buffer->clear_output ();
-  for (buffer->idx = 0; buffer->idx + 1 < count;) {
-    hb_codepoint_t ligature = get_ligature (buffer->cur().codepoint,
-                                           buffer->cur(+1).codepoint);
-    if (likely (!ligature) || !(hb_font_get_glyph (font, ligature, 0, &glyph))) {
-      buffer->next_glyph ();
-      continue;
-    }
+  return arabic_plan;
+}
+
+static void
+data_destroy_arabic (void *data)
+{
+  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
 
-    buffer->replace_glyphs (2, 1, &ligature);
+  arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
 
-    /* Technically speaking we can skip marks and stuff, like the GSUB path does.
-     * But who cares, we're in fallback! */
-  }
-  for (; buffer->idx < count;)
-      buffer->next_glyph ();
-  buffer->swap_buffers ();
+  free (data);
 }
 
-void
-_hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map,
-                                        hb_buffer_t *buffer,
-                                        hb_font_t *font)
+static void
+arabic_joining (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
-  unsigned int prev = 0, state = 0;
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int prev = (unsigned int) -1, state = 0;
 
-  HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
+  /* Check pre-context */
+  for (unsigned int i = 0; i < buffer->context_len[0]; i++)
+  {
+    unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
+
+    if (unlikely (this_type == JOINING_TYPE_T))
+      continue;
+
+    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+    state = entry->next_state;
+    break;
+  }
 
   for (unsigned int i = 0; i < count; i++)
   {
-    unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i]));
+    unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
 
     if (unlikely (this_type == JOINING_TYPE_T)) {
-      buffer->info[i].arabic_shaping_action() = NONE;
+      info[i].arabic_shaping_action() = NONE;
       continue;
     }
 
     const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
 
-    if (entry->prev_action != NONE)
-      buffer->info[prev].arabic_shaping_action() = entry->prev_action;
+    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+      info[prev].arabic_shaping_action() = entry->prev_action;
 
-    buffer->info[i].arabic_shaping_action() = entry->curr_action;
+    info[i].arabic_shaping_action() = entry->curr_action;
 
     prev = i;
     state = entry->next_state;
   }
 
-  hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0};
-  hb_mask_t total_masks = 0;
-  unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
-  for (unsigned int i = 0; i < num_masks; i++) {
-    mask_array[i] = map->get_1_mask (arabic_syriac_features[i]);
-    total_masks |= mask_array[i];
-  }
+  for (unsigned int i = 0; i < buffer->context_len[1]; i++)
+  {
+    unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
+
+    if (unlikely (this_type == JOINING_TYPE_T))
+      continue;
 
-  if (total_masks) {
-    /* Has OpenType tables */
-    for (unsigned int i = 0; i < count; i++)
-      buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()];
-  } else if (buffer->props.script == HB_SCRIPT_ARABIC) {
-    /* Fallback Arabic shaping to Presentation Forms */
-    /* Pitfalls:
-     * - This path fires if user force-set init/medi/fina/isol off,
-     * - If font does not declare script 'arab', well, what to do?
-     *   Most probably it's safe to assume that init/medi/fina/isol
-     *   still mean Arabic shaping, although they do not have to.
-     */
-    arabic_fallback_shape (font, buffer);
+    const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+    if (entry->prev_action != NONE && prev != (unsigned int) -1)
+      info[prev].arabic_shaping_action() = entry->prev_action;
+    break;
   }
+}
+
+static void
+mongolian_variation_selectors (hb_buffer_t *buffer)
+{
+  /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 1; i < count; i++)
+    if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
+      info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
+}
+
+static void
+setup_masks_arabic (const hb_ot_shape_plan_t *plan,
+                   hb_buffer_t              *buffer,
+                   hb_font_t                *font HB_UNUSED)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
+
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+
+  arabic_joining (buffer);
+  if (plan->props.script == HB_SCRIPT_MONGOLIAN)
+    mongolian_variation_selectors (buffer);
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
 }
 
 
+static void
+nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
+             hb_font_t *font HB_UNUSED,
+             hb_buffer_t *buffer)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_is_zwj (&info[i]))
+      _hb_glyph_info_flip_joiners (&info[i]);
+}
+
+static void
+arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer)
+{
+  const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+
+  if (!arabic_plan->do_fallback)
+    return;
+
+retry:
+  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
+  if (unlikely (!fallback_plan))
+  {
+    /* This sucks.  We need a font to build the fallback plan... */
+    fallback_plan = arabic_fallback_plan_create (plan, font);
+    if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
+      arabic_fallback_plan_destroy (fallback_plan);
+      goto retry;
+    }
+  }
+
+  arabic_fallback_plan_shape (fallback_plan, font, buffer);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
+{
+  "arabic",
+  collect_features_arabic,
+  NULL, /* override_features */
+  data_create_arabic,
+  data_destroy_arabic,
+  NULL, /* preprocess_text_arabic */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  setup_masks_arabic,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
similarity index 68%
rename from src/hb-uniscribe-private.hh
rename to src/hb-ot-shape-complex-default.cc
index 239ab0c..f7f097e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2012  Google, Inc.
+ * Copyright © 2010,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_UNISCRIBE_PRIVATE_HH
-#define HB_UNISCRIBE_PRIVATE_HH
+#include "hb-ot-shape-complex-private.hh"
 
-#include "hb-private.hh"
 
-#include "hb-uniscribe.h"
-
-
-HB_INTERNAL hb_bool_t
-_hb_uniscribe_shape (hb_font_t          *font,
-                    hb_buffer_t        *buffer,
-                    const hb_feature_t *features,
-                    unsigned int        num_features);
-
-
-#endif /* HB_UNISCRIBE_PRIVATE_HH */
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
+{
+  "default",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+  true, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
new file mode 100644 (file)
index 0000000..6ac18b0
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* Hangul shaper */
+
+
+/* Same order as the feature array below */
+enum {
+  NONE,
+
+  LJMO,
+  VJMO,
+  TJMO,
+
+  FIRST_HANGUL_FEATURE = LJMO,
+  HANGUL_FEATURE_COUNT = TJMO + 1
+};
+
+static const hb_tag_t hangul_features[HANGUL_FEATURE_COUNT] =
+{
+  HB_TAG_NONE,
+  HB_TAG('l','j','m','o'),
+  HB_TAG('v','j','m','o'),
+  HB_TAG('t','j','m','o')
+};
+
+static void
+collect_features_hangul (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++)
+    map->add_feature (hangul_features[i], 1, F_NONE);
+}
+
+static void
+override_features_hangul (hb_ot_shape_planner_t *plan)
+{
+  /* Uniscribe does not apply 'calt' for Hangul, and certain fonts
+   * (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups
+   * in calt, which is not desirable. */
+  plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL);
+}
+
+struct hangul_shape_plan_t
+{
+  ASSERT_POD ();
+
+  hb_mask_t mask_array[HANGUL_FEATURE_COUNT];
+};
+
+static void *
+data_create_hangul (const hb_ot_shape_plan_t *plan)
+{
+  hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
+  if (unlikely (!hangul_plan))
+    return NULL;
+
+  for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++)
+    hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]);
+
+  return hangul_plan;
+}
+
+static void
+data_destroy_hangul (void *data)
+{
+  free (data);
+}
+
+/* Constants for algorithmic hangul syllable [de]composition. */
+#define LBase 0x1100u
+#define VBase 0x1161u
+#define TBase 0x11A7u
+#define LCount 19u
+#define VCount 21u
+#define TCount 28u
+#define SBase 0xAC00u
+#define NCount (VCount * TCount)
+#define SCount (LCount * NCount)
+
+#define isCombiningL(u) (hb_in_range ((u), LBase, LBase+LCount-1))
+#define isCombiningV(u) (hb_in_range ((u), VBase, VBase+VCount-1))
+#define isCombiningT(u) (hb_in_range ((u), TBase+1, TBase+TCount-1))
+#define isCombinedS(u) (hb_in_range ((u), SBase, SBase+SCount-1))
+
+#define isL(u) (hb_in_ranges ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
+#define isV(u) (hb_in_ranges ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
+#define isT(u) (hb_in_ranges ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
+
+#define isHangulTone(u) (hb_in_range ((u), 0x302Eu, 0x302Fu))
+
+/* buffer var allocations */
+#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
+
+static bool
+is_zero_width_char (hb_font_t *font,
+                   hb_codepoint_t unicode)
+{
+  hb_codepoint_t glyph;
+  return hb_font_get_glyph (font, unicode, 0, &glyph) && hb_font_get_glyph_h_advance (font, glyph) == 0;
+}
+
+static void
+preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
+                       hb_buffer_t              *buffer,
+                       hb_font_t                *font)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, hangul_shaping_feature);
+
+  /* Hangul syllables come in two shapes: LV, and LVT.  Of those:
+   *
+   *   - LV can be precomposed, or decomposed.  Lets call those
+   *     <LV> and <L,V>,
+   *   - LVT can be fully precomposed, partically precomposed, or
+   *     fully decomposed.  Ie. <LVT>, <LV,T>, or <L,V,T>.
+   *
+   * The composition / decomposition is mechanical.  However, not
+   * all <L,V> sequences compose, and not all <LV,T> sequences
+   * compose.
+   *
+   * Here are the specifics:
+   *
+   *   - <L>: U+1100..115F, U+A960..A97F
+   *   - <V>: U+1160..11A7, U+D7B0..D7C7
+   *   - <T>: U+11A8..11FF, U+D7CB..D7FB
+   *
+   *   - Only the <L,V> sequences for the 11xx ranges combine.
+   *   - Only <LV,T> sequences for T in U+11A8..11C3 combine.
+   *
+   * Here is what we want to accomplish in this shaper:
+   *
+   *   - If the whole syllable can be precomposed, do that,
+   *   - Otherwise, fully decompose and apply ljmo/vjmo/tjmo features.
+   *   - If a valid syllable is followed by a Hangul tone mark, reorder the tone
+   *     mark to precede the whole syllable - unless it is a zero-width glyph, in
+   *     which case we leave it untouched, assuming it's designed to overstrike.
+   *
+   * That is, of the different possible syllables:
+   *
+   *   <L>
+   *   <L,V>
+   *   <L,V,T>
+   *   <LV>
+   *   <LVT>
+   *   <LV, T>
+   *
+   * - <L> needs no work.
+   *
+   * - <LV> and <LVT> can stay the way they are if the font supports them, otherwise we
+   *   should fully decompose them if font supports.
+   *
+   * - <L,V> and <L,V,T> we should compose if the whole thing can be composed.
+   *
+   * - <LV,T> we should compose if the whole thing can be composed, otherwise we should
+   *   decompose.
+   */
+
+  buffer->clear_output ();
+  unsigned int start = 0, end = 0; /* Extent of most recently seen syllable;
+                                   * valid only if start < end
+                                   */
+  unsigned int count = buffer->len;
+
+  for (buffer->idx = 0; buffer->idx < count;)
+  {
+    hb_codepoint_t u = buffer->cur().codepoint;
+
+    if (isHangulTone (u))
+    {
+      /*
+       * We could cache the width of the tone marks and the existence of dotted-circle,
+       * but the use of the Hangul tone mark characters seems to be rare enough that
+       * I didn't bother for now.
+       */
+      if (start < end && end == buffer->out_len)
+      {
+       /* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
+       buffer->next_glyph ();
+       if (!is_zero_width_char (font, u))
+       {
+         hb_glyph_info_t *info = buffer->out_info;
+         hb_glyph_info_t tone = info[end];
+         memmove (&info[start + 1], &info[start], (end - start) * sizeof (hb_glyph_info_t));
+         info[start] = tone;
+       }
+       /* Merge clusters across the (possibly reordered) syllable+tone.
+        * We want to merge even in the zero-width tone mark case here,
+        * so that clustering behavior isn't dependent on how the tone mark
+        * is handled by the font.
+        */
+       buffer->merge_out_clusters (start, end + 1);
+      }
+      else
+      {
+       /* No valid syllable as base for tone mark; try to insert dotted circle. */
+       if (font->has_glyph (0x25CCu))
+       {
+         hb_codepoint_t chars[2];
+         if (!is_zero_width_char (font, u)) {
+           chars[0] = u;
+           chars[1] = 0x25CCu;
+         } else {
+           chars[0] = 0x25CCu;
+           chars[1] = u;
+         }
+         buffer->replace_glyphs (1, 2, chars);
+       }
+       else
+       {
+         /* No dotted circle available in the font; just leave tone mark untouched. */
+         buffer->next_glyph ();
+       }
+      }
+      start = end = buffer->out_len;
+      continue;
+    }
+
+    start = buffer->out_len; /* Remember current position as a potential syllable start;
+                             * will only be used if we set end to a later position.
+                             */
+
+    if (isL (u) && buffer->idx + 1 < count)
+    {
+      hb_codepoint_t l = u;
+      hb_codepoint_t v = buffer->cur(+1).codepoint;
+      if (isV (v))
+      {
+       /* Have <L,V> or <L,V,T>. */
+       hb_codepoint_t t = 0;
+       unsigned int tindex = 0;
+       if (buffer->idx + 2 < count)
+       {
+         t = buffer->cur(+2).codepoint;
+         if (isT (t))
+           tindex = t - TBase; /* Only used if isCombiningT (t); otherwise invalid. */
+         else
+           t = 0; /* The next character was not a trailing jamo. */
+       }
+
+       /* We've got a syllable <L,V,T?>; see if it can potentially be composed. */
+       if (isCombiningL (l) && isCombiningV (v) && (t == 0 || isCombiningT (t)))
+       {
+         /* Try to compose; if this succeeds, end is set to start+1. */
+         hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
+         if (font->has_glyph (s))
+         {
+           buffer->replace_glyphs (t ? 3 : 2, 1, &s);
+           if (unlikely (buffer->in_error))
+             return;
+           end = start + 1;
+           continue;
+         }
+       }
+
+       /* We didn't compose, either because it's an Old Hangul syllable without a
+        * precomposed character in Unicode, or because the font didn't support the
+        * necessary precomposed glyph.
+        * Set jamo features on the individual glyphs, and advance past them.
+        */
+       buffer->cur().hangul_shaping_feature() = LJMO;
+       buffer->next_glyph ();
+       buffer->cur().hangul_shaping_feature() = VJMO;
+       buffer->next_glyph ();
+       if (t)
+       {
+         buffer->cur().hangul_shaping_feature() = TJMO;
+         buffer->next_glyph ();
+         end = start + 3;
+       }
+       else
+         end = start + 2;
+       buffer->merge_out_clusters (start, end);
+       continue;
+      }
+    }
+
+    else if (isCombinedS (u))
+    {
+      /* Have <LV>, <LVT>, or <LV,T> */
+      hb_codepoint_t s = u;
+      bool has_glyph = font->has_glyph (s);
+      unsigned int lindex = (s - SBase) / NCount;
+      unsigned int nindex = (s - SBase) % NCount;
+      unsigned int vindex = nindex / TCount;
+      unsigned int tindex = nindex % TCount;
+
+      if (!tindex &&
+         buffer->idx + 1 < count &&
+         isCombiningT (buffer->cur(+1).codepoint))
+      {
+       /* <LV,T>, try to combine. */
+       unsigned int new_tindex = buffer->cur(+1).codepoint - TBase;
+       hb_codepoint_t new_s = s + new_tindex;
+       if (font->has_glyph (new_s))
+       {
+         buffer->replace_glyphs (2, 1, &new_s);
+         if (unlikely (buffer->in_error))
+           return;
+         end = start + 1;
+         continue;
+       }
+      }
+
+      /* Otherwise, decompose if font doesn't support <LV> or <LVT>,
+       * or if having non-combining <LV,T>.  Note that we already handled
+       * combining <LV,T> above. */
+      if (!has_glyph ||
+         (!tindex &&
+          buffer->idx + 1 < count &&
+          isT (buffer->cur(+1).codepoint)))
+      {
+       hb_codepoint_t decomposed[3] = {LBase + lindex,
+                                       VBase + vindex,
+                                       TBase + tindex};
+       if (font->has_glyph (decomposed[0]) &&
+           font->has_glyph (decomposed[1]) &&
+           (!tindex || font->has_glyph (decomposed[2])))
+       {
+         unsigned int s_len = tindex ? 3 : 2;
+         buffer->replace_glyphs (1, s_len, decomposed);
+         if (unlikely (buffer->in_error))
+           return;
+
+         /* We decomposed S: apply jamo features to the individual glyphs
+          * that are now in buffer->out_info.
+          */
+         hb_glyph_info_t *info = buffer->out_info;
+
+         /* If we decomposed an LV because of a non-combining T following,
+          * we want to include this T in the syllable.
+          */
+         if (has_glyph && !tindex)
+         {
+            buffer->next_glyph ();
+            s_len++;
+          }
+          end = start + s_len;
+
+         unsigned int i = start;
+         info[i++].hangul_shaping_feature() = LJMO;
+         info[i++].hangul_shaping_feature() = VJMO;
+         if (i < end)
+           info[i++].hangul_shaping_feature() = TJMO;
+         buffer->merge_out_clusters (start, end);
+         continue;
+       }
+      }
+
+      if (has_glyph)
+      {
+        /* We didn't decompose the S, so just advance past it. */
+       end = start + 1;
+       buffer->next_glyph ();
+       continue;
+      }
+    }
+
+    /* Didn't find a recognizable syllable, so we leave end <= start;
+     * this will prevent tone-mark reordering happening.
+     */
+    buffer->next_glyph ();
+  }
+  buffer->swap_buffers ();
+}
+
+static void
+setup_masks_hangul (const hb_ot_shape_plan_t *plan,
+                   hb_buffer_t              *buffer,
+                   hb_font_t                *font HB_UNUSED)
+{
+  const hangul_shape_plan_t *hangul_plan = (const hangul_shape_plan_t *) plan->data;
+
+  if (likely (hangul_plan))
+  {
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 0; i < count; i++, info++)
+      info->mask |= hangul_plan->mask_array[info->hangul_shaping_feature()];
+  }
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, hangul_shaping_feature);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
+{
+  "hangul",
+  collect_features_hangul,
+  override_features_hangul,
+  data_create_hangul, /* data_create */
+  data_destroy_hangul, /* data_destroy */
+  preprocess_text_hangul,
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
+  NULL, /* decompose */
+  NULL, /* compose */
+  setup_masks_hangul, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shape-complex-hebrew.cc
new file mode 100644 (file)
index 0000000..c7b7a5e
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+static bool
+compose_hebrew (const hb_ot_shape_normalize_context_t *c,
+               hb_codepoint_t  a,
+               hb_codepoint_t  b,
+               hb_codepoint_t *ab)
+{
+  /* Hebrew presentation-form shaping.
+   * https://bugzilla.mozilla.org/show_bug.cgi?id=728866
+   * Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
+   * Note that some letters do not have a dagesh presForm encoded.
+   */
+  static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = {
+    0xFB30u, /* ALEF */
+    0xFB31u, /* BET */
+    0xFB32u, /* GIMEL */
+    0xFB33u, /* DALET */
+    0xFB34u, /* HE */
+    0xFB35u, /* VAV */
+    0xFB36u, /* ZAYIN */
+    0x0000u, /* HET */
+    0xFB38u, /* TET */
+    0xFB39u, /* YOD */
+    0xFB3Au, /* FINAL KAF */
+    0xFB3Bu, /* KAF */
+    0xFB3Cu, /* LAMED */
+    0x0000u, /* FINAL MEM */
+    0xFB3Eu, /* MEM */
+    0x0000u, /* FINAL NUN */
+    0xFB40u, /* NUN */
+    0xFB41u, /* SAMEKH */
+    0x0000u, /* AYIN */
+    0xFB43u, /* FINAL PE */
+    0xFB44u, /* PE */
+    0x0000u, /* FINAL TSADI */
+    0xFB46u, /* TSADI */
+    0xFB47u, /* QOF */
+    0xFB48u, /* RESH */
+    0xFB49u, /* SHIN */
+    0xFB4Au /* TAV */
+  };
+
+  bool found = c->unicode->compose (a, b, ab);
+
+  if (!found && !c->plan->has_mark)
+  {
+      /* Special-case Hebrew presentation forms that are excluded from
+       * standard normalization, but wanted for old fonts. */
+      switch (b) {
+      case 0x05B4u: /* HIRIQ */
+         if (a == 0x05D9u) { /* YOD */
+             *ab = 0xFB1Du;
+             found = true;
+         }
+         break;
+      case 0x05B7u: /* patah */
+         if (a == 0x05F2u) { /* YIDDISH YOD YOD */
+             *ab = 0xFB1Fu;
+             found = true;
+         } else if (a == 0x05D0u) { /* ALEF */
+             *ab = 0xFB2Eu;
+             found = true;
+         }
+         break;
+      case 0x05B8u: /* QAMATS */
+         if (a == 0x05D0u) { /* ALEF */
+             *ab = 0xFB2Fu;
+             found = true;
+         }
+         break;
+      case 0x05B9u: /* HOLAM */
+         if (a == 0x05D5u) { /* VAV */
+             *ab = 0xFB4Bu;
+             found = true;
+         }
+         break;
+      case 0x05BCu: /* DAGESH */
+         if (a >= 0x05D0u && a <= 0x05EAu) {
+             *ab = sDageshForms[a - 0x05D0u];
+             found = (*ab != 0);
+         } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */
+             *ab = 0xFB2Cu;
+             found = true;
+         } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */
+             *ab = 0xFB2Du;
+             found = true;
+         }
+         break;
+      case 0x05BFu: /* RAFE */
+         switch (a) {
+         case 0x05D1u: /* BET */
+             *ab = 0xFB4Cu;
+             found = true;
+             break;
+         case 0x05DBu: /* KAF */
+             *ab = 0xFB4Du;
+             found = true;
+             break;
+         case 0x05E4u: /* PE */
+             *ab = 0xFB4Eu;
+             found = true;
+             break;
+         }
+         break;
+      case 0x05C1u: /* SHIN DOT */
+         if (a == 0x05E9u) { /* SHIN */
+             *ab = 0xFB2Au;
+             found = true;
+         } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
+             *ab = 0xFB2Cu;
+             found = true;
+         }
+         break;
+      case 0x05C2u: /* SIN DOT */
+         if (a == 0x05E9u) { /* SHIN */
+             *ab = 0xFB2Bu;
+             found = true;
+         } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
+             *ab = 0xFB2Du;
+             found = true;
+         }
+         break;
+      }
+  }
+
+  return found;
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
+{
+  "hebrew",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  compose_hebrew,
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh
deleted file mode 100644 (file)
index db1396b..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-
-#line 1 "../../src/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-private.hh"
-
-HB_BEGIN_DECLS
-
-
-#line 38 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
-static const unsigned char _indic_syllable_machine_trans_keys[] = {
-       5u, 5u, 1u, 2u, 1u, 2u, 5u, 5u, 1u, 5u, 1u, 2u, 5u, 5u, 1u, 13u, 
-       4u, 11u, 4u, 11u, 5u, 11u, 1u, 10u, 1u, 10u, 10u, 10u, 10u, 10u, 4u, 10u, 
-       5u, 10u, 8u, 10u, 5u, 10u, 6u, 10u, 9u, 10u, 4u, 11u, 1u, 13u, 4u, 10u, 
-       4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 8u, 10u, 10u, 10u, 10u, 10u, 4u, 10u, 
-       4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 8u, 10u, 10u, 10u, 10u, 10u, 0
-};
-
-static const char _indic_syllable_machine_key_spans[] = {
-       1, 2, 2, 1, 5, 2, 1, 13, 
-       8, 8, 7, 10, 10, 1, 1, 7, 
-       6, 3, 6, 5, 2, 8, 13, 7, 
-       7, 6, 7, 6, 3, 1, 1, 7, 
-       7, 6, 7, 6, 3, 1, 1
-};
-
-static const unsigned char _indic_syllable_machine_index_offsets[] = {
-       0, 2, 5, 8, 10, 16, 19, 21, 
-       35, 44, 53, 61, 72, 83, 85, 87, 
-       95, 102, 106, 113, 119, 122, 131, 145, 
-       153, 161, 168, 176, 183, 187, 189, 191, 
-       199, 207, 214, 222, 229, 233, 235
-};
-
-static const char _indic_syllable_machine_indicies[] = {
-       1, 0, 2, 2, 0, 4, 4, 3, 
-       5, 3, 4, 4, 3, 3, 5, 3, 
-       7, 7, 6, 8, 6, 2, 10, 11, 
-       9, 9, 9, 9, 9, 9, 9, 9, 
-       12, 12, 9, 14, 15, 16, 16, 17, 
-       18, 19, 20, 13, 21, 15, 16, 16, 
-       17, 18, 19, 20, 13, 15, 16, 16, 
-       17, 18, 19, 20, 13, 2, 2, 13, 
-       13, 13, 22, 22, 13, 18, 19, 13, 
-       2, 2, 13, 13, 13, 13, 13, 13, 
-       18, 19, 13, 19, 13, 23, 13, 24, 
-       25, 13, 13, 17, 18, 19, 13, 25, 
-       13, 13, 17, 18, 19, 13, 17, 18, 
-       19, 13, 26, 13, 13, 17, 18, 19, 
-       13, 27, 27, 13, 18, 19, 13, 18, 
-       19, 13, 14, 28, 16, 16, 17, 18, 
-       19, 20, 13, 2, 2, 11, 13, 13, 
-       22, 22, 13, 18, 19, 13, 12, 12, 
-       13, 30, 5, 31, 32, 33, 34, 35, 
-       29, 4, 5, 31, 32, 33, 34, 35, 
-       29, 5, 31, 32, 33, 34, 35, 29, 
-       36, 37, 29, 29, 33, 34, 35, 29, 
-       37, 29, 29, 33, 34, 35, 29, 33, 
-       34, 35, 29, 35, 29, 38, 29, 40, 
-       8, 41, 41, 42, 43, 44, 39, 7, 
-       8, 41, 41, 42, 43, 44, 39, 8, 
-       41, 41, 42, 43, 44, 39, 45, 46, 
-       39, 39, 42, 43, 44, 39, 46, 39, 
-       39, 42, 43, 44, 39, 42, 43, 44, 
-       39, 44, 39, 47, 39, 0
-};
-
-static const char _indic_syllable_machine_trans_targs[] = {
-       7, 1, 8, 7, 25, 2, 7, 33, 
-       5, 7, 21, 23, 31, 7, 9, 11, 
-       0, 15, 13, 14, 18, 10, 12, 7, 
-       16, 17, 19, 20, 22, 7, 24, 3, 
-       4, 26, 29, 30, 27, 28, 7, 7, 
-       32, 6, 34, 37, 38, 35, 36, 7
-};
-
-static const char _indic_syllable_machine_trans_actions[] = {
-       1, 0, 2, 3, 2, 0, 4, 2, 
-       0, 7, 2, 2, 2, 8, 2, 0, 
-       0, 0, 0, 0, 0, 2, 0, 9, 
-       0, 0, 0, 0, 0, 10, 2, 0, 
-       0, 0, 0, 0, 0, 0, 11, 12, 
-       2, 0, 0, 0, 0, 0, 0, 13
-};
-
-static const char _indic_syllable_machine_to_state_actions[] = {
-       0, 0, 0, 0, 0, 0, 0, 5, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0
-};
-
-static const char _indic_syllable_machine_from_state_actions[] = {
-       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, 0, 0, 0, 
-       0, 0, 0, 0, 0, 0, 0
-};
-
-static const unsigned char _indic_syllable_machine_eof_trans[] = {
-       1, 1, 4, 4, 4, 7, 7, 0, 
-       14, 14, 14, 14, 14, 14, 14, 14, 
-       14, 14, 14, 14, 14, 14, 14, 30, 
-       30, 30, 30, 30, 30, 30, 30, 40, 
-       40, 40, 40, 40, 40, 40, 40
-};
-
-static const int indic_syllable_machine_start = 7;
-static const int indic_syllable_machine_first_final = 7;
-static const int indic_syllable_machine_error = -1;
-
-static const int indic_syllable_machine_en_main = 7;
-
-
-#line 38 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-
-
-#line 79 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-
-#define process_syllable(func) \
-  HB_STMT_START { \
-    /* fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); */ \
-    for (unsigned int i = last; i < p+1; i++) \
-      info[i].syllable() = syllable_serial; \
-    PASTE (initial_reordering_, func) (map, buffer, mask_array, last, p+1); \
-    last = p+1; \
-    syllable_serial++; \
-    if (unlikely (!syllable_serial)) syllable_serial++; \
-  } HB_STMT_END
-
-static void
-find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array)
-{
-  unsigned int p, pe, eof, ts, te, act;
-  int cs;
-  hb_glyph_info_t *info = buffer->info;
-  
-#line 170 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
-       {
-       cs = indic_syllable_machine_start;
-       ts = 0;
-       te = 0;
-       act = 0;
-       }
-
-#line 101 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-
-  p = 0;
-  pe = eof = buffer->len;
-
-  unsigned int last = 0;
-  uint8_t syllable_serial = 1;
-  
-#line 187 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
-       {
-       int _slen;
-       int _trans;
-       const unsigned char *_keys;
-       const char *_inds;
-       if ( p == pe )
-               goto _test_eof;
-_resume:
-       switch ( _indic_syllable_machine_from_state_actions[cs] ) {
-       case 6:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {ts = p;}
-       break;
-#line 201 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
-       }
-
-       _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 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p+1;}
-       break;
-       case 9:
-#line 72 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p+1;{ process_syllable (consonant_syllable); }}
-       break;
-       case 11:
-#line 73 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p+1;{ process_syllable (vowel_syllable); }}
-       break;
-       case 13:
-#line 74 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p+1;{ process_syllable (standalone_cluster); }}
-       break;
-       case 7:
-#line 75 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p+1;{ process_syllable (non_indic); }}
-       break;
-       case 8:
-#line 72 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ process_syllable (consonant_syllable); }}
-       break;
-       case 10:
-#line 73 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ process_syllable (vowel_syllable); }}
-       break;
-       case 12:
-#line 74 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {te = p;p--;{ process_syllable (standalone_cluster); }}
-       break;
-       case 1:
-#line 72 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ process_syllable (consonant_syllable); }}
-       break;
-       case 3:
-#line 73 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ process_syllable (vowel_syllable); }}
-       break;
-       case 4:
-#line 74 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {{p = ((te))-1;}{ process_syllable (standalone_cluster); }}
-       break;
-#line 263 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
-       }
-
-_again:
-       switch ( _indic_syllable_machine_to_state_actions[cs] ) {
-       case 5:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
-       {ts = 0;}
-       break;
-#line 272 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
-       }
-
-       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 110 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-}
-
-HB_END_DECLS
-
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
index 93ca29a..694b235 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "hb-private.hh"
 
-HB_BEGIN_DECLS
-
 %%{
   machine indic_syllable_machine;
   alphtype unsigned char;
@@ -42,57 +40,76 @@ HB_BEGIN_DECLS
 # Same order as enum indic_category_t.  Not sure how to avoid duplication.
 X    = 0;
 C    = 1;
-Ra   = 2;
-V    = 3;
-N    = 4;
-H    = 5;
-ZWNJ = 6;
-ZWJ  = 7;
-M    = 8;
-SM   = 9;
-VD   = 10;
-A    = 11;
-NBSP = 12;
-DOTTEDCIRCLE = 13;
-
-c = C | Ra;
-n = N N?;
-z = ZWJ|ZWNJ;
-matra_group = M N? H?;
-syllable_tail = SM? (VD VD?)?;
-place_holder = NBSP | DOTTEDCIRCLE;
-
-
-consonant_syllable =   (c.n? (H.z?|z.H))* c.n? A? (H.z? | matra_group*)? syllable_tail;
-vowel_syllable =       (Ra H)? V n? (z?.H.c | ZWJ.c)* matra_group* syllable_tail;
-standalone_cluster =   (Ra H)? place_holder n? (z? H c)* matra_group* syllable_tail;
+V    = 2;
+N    = 3;
+H    = 4;
+ZWNJ = 5;
+ZWJ  = 6;
+M    = 7;
+SM   = 8;
+VD   = 9;
+A    = 10;
+PLACEHOLDER = 11;
+DOTTEDCIRCLE = 12;
+RS    = 13;
+Coeng = 14;
+Repha = 15;
+Ra    = 16;
+CM    = 17;
+Symbol= 18;
+CM2   = 31;
+
+c = (C | Ra);                  # is_consonant
+n = ((ZWNJ?.RS)? (N.N?)?);     # is_consonant_modifier
+z = ZWJ|ZWNJ;                  # is_joiner
+h = H | Coeng;                 # is_halant_or_coeng
+reph = (Ra H | Repha);         # possible reph
+
+cn = c.ZWJ?.n?;
+forced_rakar = ZWJ H ZWJ Ra;
+symbol = Symbol.N?;
+matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
+syllable_tail = (z?.SM.SM?.ZWNJ?)? A{0,3}? VD{0,2};
+place_holder = PLACEHOLDER | DOTTEDCIRCLE;
+halant_group = (z?.h.(ZWJ.N?)?);
+final_halant_group = halant_group | h.ZWNJ;
+medial_group = CM?.CM2?;
+halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4}) (Coeng (cn|V))?;
+
+
+consonant_syllable =   Repha? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail;
+vowel_syllable =       reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail);
+standalone_cluster =   (Repha? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
+symbol_cluster =       symbol syllable_tail;
+broken_cluster =       reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
 other =                        any;
 
 main := |*
-       consonant_syllable      => { process_syllable (consonant_syllable); };
-       vowel_syllable          => { process_syllable (vowel_syllable); };
-       standalone_cluster      => { process_syllable (standalone_cluster); };
-       other                   => { process_syllable (non_indic); };
+       consonant_syllable      => { found_syllable (consonant_syllable); };
+       vowel_syllable          => { found_syllable (vowel_syllable); };
+       standalone_cluster      => { found_syllable (standalone_cluster); };
+       symbol_cluster          => { found_syllable (symbol_cluster); };
+       broken_cluster          => { found_syllable (broken_cluster); };
+       other                   => { found_syllable (non_indic_cluster); };
 *|;
 
 
 }%%
 
-#define process_syllable(func) \
+#define found_syllable(syllable_type) \
   HB_STMT_START { \
-    /* fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); */ \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
     for (unsigned int i = last; i < p+1; i++) \
-      info[i].syllable() = syllable_serial; \
-    PASTE (initial_reordering_, func) (map, buffer, mask_array, last, p+1); \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
     last = p+1; \
     syllable_serial++; \
-    if (unlikely (!syllable_serial)) syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
   } HB_STMT_END
 
 static void
-find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array)
+find_syllables (hb_buffer_t *buffer)
 {
-  unsigned int p, pe, eof, ts, te, act;
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
   int cs;
   hb_glyph_info_t *info = buffer->info;
   %%{
@@ -104,12 +121,10 @@ find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_arr
   pe = eof = buffer->len;
 
   unsigned int last = 0;
-  uint8_t syllable_serial = 1;
+  unsigned int syllable_serial = 1;
   %%{
     write exec;
   }%%
 }
 
-HB_END_DECLS
-
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
index 64af0da..d8dfc65 100644 (file)
 
 
 #include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-private.hh" /* XXX Remove */
 
 
-/* buffer var allocations */
-#define indic_category() complex_var_persistent_u8_0() /* indic_category_t */
-#define indic_position() complex_var_persistent_u8_1() /* indic_matra_category_t */
-
-#define INDIC_TABLE_ELEMENT_TYPE uint8_t
+#define INDIC_TABLE_ELEMENT_TYPE uint16_t
 
 /* Cateories used in the OpenType spec:
  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx
  * Not sure how to avoid duplication. */
 enum indic_category_t {
   OT_X = 0,
-  OT_C,
-  OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */
-  OT_V,
-  OT_N,
-  OT_H,
-  OT_ZWNJ,
-  OT_ZWJ,
-  OT_M,
-  OT_SM,
-  OT_VD,
-  OT_A,
-  OT_NBSP,
-  OT_DOTTEDCIRCLE /* Not in the spec, but special in Uniscribe. /Very very/ special! */
+  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,
+  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_CM2 = 31 /* Consonant-Medial, second slot. */
 };
 
+#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
+
+/* 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_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
+#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
+#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
+
+
 /* Visual positions in a syllable from left to right. */
 enum indic_position_t {
+  POS_START,
+
   POS_RA_TO_BECOME_REPH,
   POS_PRE_M,
   POS_PRE_C,
+
   POS_BASE_C,
+  POS_AFTER_MAIN,
+
   POS_ABOVE_C,
+
+  POS_BEFORE_SUB,
   POS_BELOW_C,
-  POS_ABOVE_M,
-  POS_BELOW_M,
+  POS_AFTER_SUB,
+
+  POS_BEFORE_POST,
   POS_POST_C,
-  POS_POST_M,
-  POS_SMVD
+  POS_AFTER_POST,
+
+  POS_FINAL_C,
+  POS_SMVD,
+
+  POS_END
 };
 
 /* Categories used in IndicSyllabicCategory.txt from UCD. */
 enum indic_syllabic_category_t {
-  INDIC_SYLLABIC_CATEGORY_OTHER                        = OT_X,
-
-  INDIC_SYLLABIC_CATEGORY_AVAGRAHA             = OT_X,
-  INDIC_SYLLABIC_CATEGORY_BINDU                        = OT_SM,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT            = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD       = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL      = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER        = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL     = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER        = OT_NBSP,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED  = OT_C,
-  INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA      = OT_C,
-  INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER     = OT_X,
-  INDIC_SYLLABIC_CATEGORY_NUKTA                        = OT_N,
-  INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER     = OT_X,
-  INDIC_SYLLABIC_CATEGORY_TONE_LETTER          = OT_X,
-  INDIC_SYLLABIC_CATEGORY_TONE_MARK            = OT_X,
-  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
+  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, /* TODO */
+  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_MEDIAL             = OT_CM,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER                = OT_PLACEHOLDER,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA    = OT_Repha,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED          = OT_CM,
+  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA   = OT_N,
+  INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK              = OT_SM,
+  INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER            = OT_H, /* TODO */
+  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, /* TODO */
+  INDIC_SYLLABIC_CATEGORY_PURE_KILLER                  = OT_H, /* TODO */
+  INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER             = OT_RS,
+  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_BASE_C,
-
-  INDIC_MATRA_CATEGORY_LEFT                    = POS_PRE_M,
-  INDIC_MATRA_CATEGORY_TOP                     = POS_ABOVE_M,
-  INDIC_MATRA_CATEGORY_BOTTOM                  = POS_BELOW_M,
-  INDIC_MATRA_CATEGORY_RIGHT                   = POS_POST_M,
-
-  /* We don't really care much about these since we decompose them
-   * in the generic pre-shaping layer.  They will only be used if
-   * the font does not cover the decomposition.  In which case, we
-   * define these as aliases to the place we want the split-matra
-   * glyph to show up.  Quite arbitrary.
-   *
-   * TODO: There are some split matras without Unicode decompositions.
-   * We have to figure out what to do with them.
-   */
-  INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT                = POS_POST_M,
-  INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT          = POS_PRE_M,
-  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM          = POS_BELOW_M,
-  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT        = POS_POST_M,
-  INDIC_MATRA_CATEGORY_TOP_AND_LEFT            = POS_PRE_M,
-  INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT  = POS_PRE_M,
-  INDIC_MATRA_CATEGORY_TOP_AND_RIGHT           = POS_POST_M,
-
-  INDIC_MATRA_CATEGORY_INVISIBLE               = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
-  INDIC_MATRA_CATEGORY_OVERSTRUCK              = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
-  INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT       = INDIC_MATRA_CATEGORY_NOT_APPLICABLE
+  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_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
 };
 
 /* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
  * because gcc fails to optimize the latter and fills the table in at runtime. */
 #define INDIC_COMBINE_CATEGORIES(S,M) \
-  (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \
-   ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \
-   ((M << 4) | S))
-
-
-#include "hb-ot-shape-complex-indic-table.hh"
-
-/* XXX
- * This is a hack for now.  We should:
- * 1. Move this data into the main Indic table,
- * and/or
- * 2. Probe font lookups to determine consonant positions.
- */
-static const struct consonant_position_t {
-  hb_codepoint_t u;
-  indic_position_t position;
-} consonant_positions[] = {
-  {0x0930, POS_BELOW_C},
-  {0x09AC, POS_BELOW_C},
-  {0x09AF, POS_POST_C},
-  {0x09B0, POS_BELOW_C},
-  {0x09F0, POS_BELOW_C},
-  {0x0A2F, POS_POST_C},
-  {0x0A30, POS_BELOW_C},
-  {0x0A35, POS_BELOW_C},
-  {0x0A39, POS_BELOW_C},
-  {0x0AB0, POS_BELOW_C},
-  {0x0B24, POS_BELOW_C},
-  {0x0B28, POS_BELOW_C},
-  {0x0B2C, POS_BELOW_C},
-  {0x0B2D, POS_BELOW_C},
-  {0x0B2E, POS_BELOW_C},
-  {0x0B2F, POS_POST_C},
-  {0x0B30, POS_BELOW_C},
-  {0x0B32, POS_BELOW_C},
-  {0x0B33, POS_BELOW_C},
-  {0x0B5F, POS_POST_C},
-  {0x0B71, POS_BELOW_C},
-  {0x0C15, POS_BELOW_C},
-  {0x0C16, POS_BELOW_C},
-  {0x0C17, POS_BELOW_C},
-  {0x0C18, POS_BELOW_C},
-  {0x0C19, POS_BELOW_C},
-  {0x0C1A, POS_BELOW_C},
-  {0x0C1B, POS_BELOW_C},
-  {0x0C1C, POS_BELOW_C},
-  {0x0C1D, POS_BELOW_C},
-  {0x0C1E, POS_BELOW_C},
-  {0x0C1F, POS_BELOW_C},
-  {0x0C20, POS_BELOW_C},
-  {0x0C21, POS_BELOW_C},
-  {0x0C22, POS_BELOW_C},
-  {0x0C23, POS_BELOW_C},
-  {0x0C24, POS_BELOW_C},
-  {0x0C25, POS_BELOW_C},
-  {0x0C26, POS_BELOW_C},
-  {0x0C27, POS_BELOW_C},
-  {0x0C28, POS_BELOW_C},
-  {0x0C2A, POS_BELOW_C},
-  {0x0C2B, POS_BELOW_C},
-  {0x0C2C, POS_BELOW_C},
-  {0x0C2D, POS_BELOW_C},
-  {0x0C2E, POS_BELOW_C},
-  {0x0C2F, POS_BELOW_C},
-  {0x0C30, POS_BELOW_C},
-  {0x0C32, POS_BELOW_C},
-  {0x0C33, POS_BELOW_C},
-  {0x0C35, POS_BELOW_C},
-  {0x0C36, POS_BELOW_C},
-  {0x0C37, POS_BELOW_C},
-  {0x0C38, POS_BELOW_C},
-  {0x0C39, POS_BELOW_C},
-  {0x0C95, POS_BELOW_C},
-  {0x0C96, POS_BELOW_C},
-  {0x0C97, POS_BELOW_C},
-  {0x0C98, POS_BELOW_C},
-  {0x0C99, POS_BELOW_C},
-  {0x0C9A, POS_BELOW_C},
-  {0x0C9B, POS_BELOW_C},
-  {0x0C9C, POS_BELOW_C},
-  {0x0C9D, POS_BELOW_C},
-  {0x0C9E, POS_BELOW_C},
-  {0x0C9F, POS_BELOW_C},
-  {0x0CA0, POS_BELOW_C},
-  {0x0CA1, POS_BELOW_C},
-  {0x0CA2, POS_BELOW_C},
-  {0x0CA3, POS_BELOW_C},
-  {0x0CA4, POS_BELOW_C},
-  {0x0CA5, POS_BELOW_C},
-  {0x0CA6, POS_BELOW_C},
-  {0x0CA7, POS_BELOW_C},
-  {0x0CA8, POS_BELOW_C},
-  {0x0CAA, POS_BELOW_C},
-  {0x0CAB, POS_BELOW_C},
-  {0x0CAC, POS_BELOW_C},
-  {0x0CAD, POS_BELOW_C},
-  {0x0CAE, POS_BELOW_C},
-  {0x0CAF, POS_BELOW_C},
-  {0x0CB0, POS_BELOW_C},
-  {0x0CB2, POS_BELOW_C},
-  {0x0CB3, POS_BELOW_C},
-  {0x0CB5, POS_BELOW_C},
-  {0x0CB6, POS_BELOW_C},
-  {0x0CB7, POS_BELOW_C},
-  {0x0CB8, POS_BELOW_C},
-  {0x0CB9, POS_BELOW_C},
-  {0x0CDE, POS_BELOW_C},
-  {0x0D2F, POS_POST_C},
-  {0x0D30, POS_POST_C},
-  {0x0D32, POS_BELOW_C},
-  {0x0D35, POS_POST_C},
-};
-
-/* 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[] = {
-  0x0930, /* Devanagari */
-  0x09B0, /* Bengali */
-  0x09F0, /* Bengali */
-  0x0A30, /* Gurmukhi */       /* No Reph */
-  0x0AB0, /* Gujarati */
-  0x0B30, /* Oriya */
-  0x0BB0, /* Tamil */          /* No Reph */
-  0x0C30, /* Telugu */         /* No Reph */
-  0x0CB0, /* Kannada */
-  0x0D30, /* Malayalam */      /* No Reph */
-};
-
+  (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
+                           ( \
+                            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)) + \
+   ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+   ((M << 8) | S))
+
+HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+hb_indic_get_categories (hb_codepoint_t u);
 
 #endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */
similarity index 63%
rename from src/hb-ot-shape-complex-indic-table.hh
rename to src/hb-ot-shape-complex-indic-table.cc
index 5b4b344..2e159a1 100644 (file)
@@ -6,55 +6,63 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-6.1.0.txt
- * # Date: 2011-08-31, 23:54:00 GMT [KW]
- * # IndicMatraCategory-6.1.0.txt
- * # Date: 2011-08-31, 23:50:00 GMT [KW]
- * # Blocks-6.1.0.txt
- * # Date: 2011-06-14, 18:26:00 GMT [KW, LI]
+ * # IndicSyllabicCategory-7.0.0.txt
+ * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+ * # IndicMatraCategory-7.0.0.txt
+ * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+ * # Blocks-7.0.0.txt
+ * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
  */
 
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
-
-
-#define ISC_A  INDIC_SYLLABIC_CATEGORY_AVAGRAHA                /*  11 chars; Avagraha */
-#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU                   /*  34 chars; Bindu */
-#define ISC_C  INDIC_SYLLABIC_CATEGORY_CONSONANT               /* 123 chars; Consonant */
-#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD          /*   2 chars; Consonant_Dead */
-#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL         /*  17 chars; Consonant_Final */
-#define ISC_CHL        INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER   /*   1 chars; Consonant_Head_Letter */
-#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL        /*  12 chars; Consonant_Medial */
-#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER   /*   4 chars; Consonant_Placeholder */
-#define ISC_CR INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA         /*   5 chars; Consonant_Repha */
-#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED     /*  10 chars; Consonant_Subjoined */
+#include "hb-ot-shape-complex-indic-private.hh"
+
+
+#define ISC_A  INDIC_SYLLABIC_CATEGORY_AVAGRAHA                /*  13 chars; Avagraha */
+#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU                   /*  59 chars; Bindu */
+#define ISC_BJN        INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER   /*  20 chars; Brahmi_Joining_Number */
+#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK       /*  30 chars; Cantillation_Mark */
+#define ISC_C  INDIC_SYLLABIC_CATEGORY_CONSONANT               /* 1744 chars; Consonant */
+#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD          /*   7 chars; Consonant_Dead */
+#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL         /*  61 chars; Consonant_Final */
+#define ISC_CHL        INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER   /*   5 chars; Consonant_Head_Letter */
+#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL        /*  19 chars; Consonant_Medial */
+#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER   /*  11 chars; Consonant_Placeholder */
+#define ISC_CPR        INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA       /*   1 chars; Consonant_Preceding_Repha */
+#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED     /*  61 chars; Consonant_Subjoined */
+#define ISC_CSR        INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA      /*   4 chars; Consonant_Succeeding_Repha */
+#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK         /*   2 chars; Gemination_Mark */
+#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER       /*   7 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_N  INDIC_SYLLABIC_CATEGORY_NUKTA                   /*  12 chars; Nukta */
+#define ISC_ZWNJ       INDIC_SYLLABIC_CATEGORY_NON_JOINER              /*   1 chars; Non_Joiner */
+#define ISC_N  INDIC_SYLLABIC_CATEGORY_NUKTA                   /*  18 chars; Nukta */
+#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER                  /* 408 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_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER        /*   1 chars; Register_Shifter */
-#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER             /*   3 chars; Tone_Letter */
-#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK               /*  16 chars; Tone_Mark */
-#define ISC_V  INDIC_SYLLABIC_CATEGORY_VIRAMA                  /*  34 chars; Virama */
-#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA                 /*  25 chars; Visarga */
-#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL                   /*   5 chars; Vowel */
-#define ISC_M  INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT         /* 165 chars; Vowel_Dependent */
-#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT       /*  59 chars; Vowel_Independent */
-
-#define IMC_B  INDIC_MATRA_CATEGORY_BOTTOM                     /*  65 chars; Bottom */
+#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER             /*  15 chars; Pure_Killer */
+#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER        /*   3 chars; Register_Shifter */
+#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER             /*   7 chars; Tone_Letter */
+#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK               /*  62 chars; Tone_Mark */
+#define ISC_V  INDIC_SYLLABIC_CATEGORY_VIRAMA                  /*  22 chars; Virama */
+#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA                 /*  29 chars; Visarga */
+#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL                   /*  30 chars; Vowel */
+#define ISC_M  INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT         /* 553 chars; Vowel_Dependent */
+#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT       /* 395 chars; Vowel_Independent */
+
+#define IMC_B  INDIC_MATRA_CATEGORY_BOTTOM                     /* 142 chars; Bottom */
 #define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT           /*   2 chars; Bottom_And_Right */
-#define IMC_I  INDIC_MATRA_CATEGORY_INVISIBLE                  /*   6 chars; Invisible */
-#define IMC_L  INDIC_MATRA_CATEGORY_LEFT                       /*  30 chars; Left */
-#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT             /*   8 chars; Left_And_Right */
+#define IMC_L  INDIC_MATRA_CATEGORY_LEFT                       /*  57 chars; Left */
+#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT             /*  21 chars; Left_And_Right */
 #define IMC_x  INDIC_MATRA_CATEGORY_NOT_APPLICABLE             /*   1 chars; Not_Applicable */
 #define IMC_O  INDIC_MATRA_CATEGORY_OVERSTRUCK                 /*   2 chars; Overstruck */
-#define IMC_R  INDIC_MATRA_CATEGORY_RIGHT                      /*  75 chars; Right */
-#define IMC_T  INDIC_MATRA_CATEGORY_TOP                        /*  83 chars; Top */
-#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM             /*   6 chars; Top_And_Bottom */
+#define IMC_R  INDIC_MATRA_CATEGORY_RIGHT                      /* 163 chars; Right */
+#define IMC_T  INDIC_MATRA_CATEGORY_TOP                        /* 169 chars; Top */
+#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM             /*  10 chars; Top_And_Bottom */
 #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               /*   4 chars; Top_And_Left */
-#define IMC_TLR        INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT     /*   2 chars; Top_And_Left_And_Right */
-#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT              /*   8 chars; Top_And_Right */
-#define IMC_VOL        INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT          /*   5 chars; Visual_Order_Left */
+#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          /*  15 chars; Visual_Order_Left */
 
 #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
 
 static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
 
 
-#define indic_offset_0x0900 0
+#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_0x00d0u 24
+
 
+  /* Latin-1 Supplement */
 
-  /* Devanagari  (0900..097F) */
+  /* 00D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CP,x),
+
+#define indic_offset_0x0900u 32
+
+
+  /* Devanagari */
 
   /* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(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),
@@ -77,14 +101,14 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 0938 */  _(C,x),  _(C,x),  _(M,T),  _(M,R),  _(N,x),  _(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),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),  _(M,B),  _(M,B),
+  /* 0950 */  _(x,x), _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(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),  _(x,x),  _(x,x),
-  /* 0968 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,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 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 0978 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
 
-  /* Bengali  (0980..09FF) */
+  /* Bengali */
 
   /* 0980 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(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),
@@ -98,12 +122,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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),  _(x,x),  _(x,x),
-  /* 09E8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,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),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Gurmukhi  (0A00..0A7F) */
+  /* Gurmukhi */
 
   /* 0A00 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(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),
@@ -117,12 +141,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 0A48 */  _(M,T),  _(x,x),  _(x,x),  _(M,T),  _(M,T),  _(V,B),  _(x,x),  _(x,x),
   /* 0A50 */  _(x,x),  _(x,x),  _(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),  _(x,x),  _(x,x),
-  /* 0A68 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0A70 */ _(Bi,x),  _(x,x), _(CP,x), _(CP,x),  _(x,x), _(CM,x),  _(x,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,x), _(GM,T), _(CP,x), _(CP,x),  _(x,x), _(CM,x),  _(x,x),  _(x,x),
   /* 0A78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Gujarati  (0A80..0AFF) */
+  /* Gujarati */
 
   /* 0A80 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(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),
@@ -136,12 +160,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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),  _(x,x),  _(x,x),
-  /* 0AE8 */  _(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),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Oriya  (0B00..0B7F) */
+  /* Oriya */
 
   /* 0B00 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(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),
@@ -155,12 +179,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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),  _(x,x),  _(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),  _(x,x),  _(x,x),
-  /* 0B68 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,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..0BFF) */
+  /* Tamil */
 
   /* 0B80 */  _(x,x),  _(x,x), _(Bi,x), _(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),
@@ -174,33 +198,33 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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),  _(x,x),  _(x,x),
-  /* 0BE8 */  _(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..0C7F) */
+  /* Telugu */
 
-  /* 0C00 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(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),  _(x,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),  _(x,x),  _(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),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0C60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0C68 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,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..0CFF) */
+  /* Kannada */
 
-  /* 0C80 */  _(x,x),  _(x,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0C80 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(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),
@@ -212,14 +236,14 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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),  _(x,x),  _(C,x),  _(x,x),
-  /* 0CE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0CE8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,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),  _(x,x),  _(x,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..0D7F) */
+  /* Malayalam */
 
-  /* 0D00 */  _(x,x),  _(x,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 0D00 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,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),
@@ -228,15 +252,15 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 0D30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0D38 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(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), _(CR,x),  _(x,x),
+  /* 0D48 */  _(M,L),  _(x,x), _(M,LR), _(M,LR), _(M,LR),  _(V,T),_(CPR,x),  _(x,x),
   /* 0D50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
   /* 0D58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0D60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0D68 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,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..0DFF) */
+  /* Sinhala */
 
   /* 0D80 */  _(x,x),  _(x,x), _(Bi,x), _(Vs,x),  _(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),
@@ -249,86 +273,15 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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,LR), _(M,LR),  _(M,R),
-  /* 0DE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0DE8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(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),
-  /* 0DF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Thai  (0E00..0E7F) */
-
-  /* 0E00 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0E08 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0E10 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0E18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0E20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0E28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
-  /* 0E30 */  _(M,R),  _(M,T),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,T),  _(M,T),
-  /* 0E38 */  _(M,B),  _(M,B),  _(V,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0E40 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),  _(M,R),  _(x,x),  _(M,T),
-  /* 0E48 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x),  _(x,x), _(Bi,x),  _(V,T),  _(x,x),
-  /* 0E50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0E58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0E60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0E68 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0E70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0E78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Lao  (0E80..0EFF) */
-
-  /* 0E80 */  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(C,x),
-  /* 0E88 */  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),  _(C,x),  _(x,x),  _(x,x),
-  /* 0E90 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0E98 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0EA0 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(x,x),  _(C,x),
-  /* 0EA8 */  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),
-  /* 0EB0 */  _(M,R),  _(M,T),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,T),  _(M,T),
-  /* 0EB8 */  _(M,B),  _(M,B),  _(x,x),  _(M,T), _(CM,x), _(CM,x),  _(x,x),  _(x,x),
-  /* 0EC0 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),  _(x,x),  _(x,x),  _(x,x),
-  /* 0EC8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x),  _(x,x), _(Bi,x),  _(x,x),  _(x,x),
-  /* 0ED0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0ED8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),
-  /* 0EE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0EE8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0EF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0EF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Tibetan  (0F00..0FFF) */
-
-  /* 0F00 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F08 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F10 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F18 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F20 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F28 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F30 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F40 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0F48 */  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0F50 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0F58 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0F60 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0F68 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0F70 */  _(x,x),  _(M,B),  _(M,T), _(M,TB),  _(M,B),  _(M,B), _(M,TB), _(M,TB),
-  /* 0F78 */ _(M,TB), _(M,TB),  _(M,T),  _(M,T),  _(M,T),  _(M,T), _(Bi,x), _(Vs,x),
-  /* 0F80 */  _(M,T), _(M,TB), _(Bi,x), _(Bi,x),  _(V,B),  _(A,x),  _(x,x),  _(x,x),
-  /* 0F88 */_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x), _(CS,x), _(CS,x), _(CS,x),
-  /* 0F90 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
-  /* 0F98 */  _(x,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
-  /* 0FA0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
-  /* 0FA8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
-  /* 0FB0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
-  /* 0FB8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FC0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FC8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FE8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 0FF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* Myanmar  (1000..109F) */
+
+#define indic_offset_0x1000u 1304
+
+
+  /* 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),
@@ -337,9 +290,9 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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,x), _(TM,x),
-  /* 1038 */ _(Vs,x),  _(V,I),  _(V,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x),  _(C,x),
-  /* 1040 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1048 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1038 */ _(Vs,x), _(IS,x), _(PK,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x),  _(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),  _(x,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,x), _(CM,x),
   /* 1060 */ _(CM,x),  _(C,x),  _(M,R), _(TM,x), _(TM,x),  _(C,x),  _(C,x),  _(M,R),
@@ -348,41 +301,41 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 1078 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1080 */  _(C,x),  _(C,x), _(CM,x),  _(M,R),  _(M,L),  _(M,T),  _(M,T), _(TM,x),
   /* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),  _(C,x), _(TM,x),
-  /* 1090 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1098 */  _(x,x),  _(x,x), _(TM,x), _(TM,x),  _(M,R),  _(M,T),  _(x,x),  _(x,x),
+  /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1098 */ _(Nd,x), _(Nd,x), _(TM,x), _(TM,x),  _(M,R),  _(M,T),  _(x,x),  _(x,x),
 
-#define indic_offset_0x1700 1952
+#define indic_offset_0x1700u 1464
 
 
-  /* Tagalog  (1700..171F) */
+  /* Tagalog */
 
   /* 1700 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1708 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),
-  /* 1710 */  _(C,x),  _(C,x),  _(M,T),  _(M,B),  _(V,B),  _(x,x),  _(x,x),  _(x,x),
+  /* 1710 */  _(C,x),  _(C,x),  _(M,T),  _(M,B), _(PK,B),  _(x,x),  _(x,x),  _(x,x),
   /* 1718 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Hanunoo  (1720..173F) */
+  /* Hanunoo */
 
   /* 1720 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1728 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1730 */  _(C,x),  _(C,x),  _(M,T),  _(M,B),  _(V,B),  _(x,x),  _(x,x),  _(x,x),
+  /* 1730 */  _(C,x),  _(C,x),  _(M,T),  _(M,B), _(PK,B),  _(x,x),  _(x,x),  _(x,x),
   /* 1738 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Buhid  (1740..175F) */
+  /* Buhid */
 
   /* 1740 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1748 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1750 */  _(C,x),  _(C,x),  _(M,T),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1758 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Tagbanwa  (1760..177F) */
+  /* Tagbanwa */
 
   /* 1760 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1768 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),
   /* 1770 */  _(C,x),  _(x,x),  _(M,T),  _(M,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1778 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Khmer  (1780..17FF) */
+  /* 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),
@@ -393,31 +346,29 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 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,x), _(Vs,x),
-  /* 17C8 */  _(M,R), _(RS,x), _(RS,x),  _(x,x), _(CR,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 17D0 */  _(x,x),  _(V,T),  _(V,I),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 17C8 */  _(M,R), _(RS,T), _(RS,T), _(RS,T),_(CSR,T),  _(M,T),  _(M,T),  _(M,T),
+  /* 17D0 */  _(M,T), _(PK,T), _(IS,x),  _(M,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 17D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(A,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 17E0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 17E8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 17F0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 17F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(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_0x1900 2208
+#define indic_offset_0x1900u 1704
 
 
-  /* Limbu  (1900..194F) */
+  /* Limbu */
 
   /* 1900 */ _(CP,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1908 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1910 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),
   /* 1920 */  _(M,T),  _(M,T),  _(M,B),  _(M,R),  _(M,R), _(M,TR), _(M,TR),  _(M,T),
   /* 1928 */  _(M,T), _(CS,x), _(CS,x), _(CS,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
   /* 1938 */ _(CF,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1940 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1948 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1940 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 1948 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
 
-  /* Tai Le  (1950..197F) */
+  /* Tai Le */
 
   /* 1950 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1958 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -426,7 +377,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 1970 */ _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(TL,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1978 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* New Tai Lue  (1980..19DF) */
+  /* New Tai Lue */
 
   /* 1980 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1988 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -438,24 +389,21 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 19B8 */  _(M,R),  _(M,R),  _(M,L),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),
   /* 19C0 */  _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
   /* 19C8 */ _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 19D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 19D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* FILLER  (19E0..19FF) */
-
+  /* 19D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 19D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 19E0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 19E8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 19F0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 19F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Buginese  (1A00..1A1F) */
+  /* Buginese */
 
   /* 1A00 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1A08 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1A10 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,T),
-  /* 1A18 */  _(M,B),  _(M,L),  _(M,R),  _(M,L),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1A18 */  _(M,B),  _(M,L),  _(M,R),  _(M,T),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Tai Tham  (1A20..1AAF) */
+  /* Tai Tham */
 
   /* 1A20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1A28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -463,25 +411,23 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 1A38 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1A40 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1A48 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x),
-  /* 1A50 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x), _(CM,x), _(CM,x), _(CF,x),
+  /* 1A50 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x), _(CM,L), _(CM,x), _(CF,x),
   /* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),  _(x,x),
-  /* 1A60 */  _(V,I),  _(M,R),  _(M,T),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,T),
+  /* 1A60 */ _(IS,x),  _(M,R),  _(M,T),  _(M,R),  _(M,R),  _(M,T),  _(M,T),  _(M,T),
   /* 1A68 */  _(M,T),  _(M,B),  _(M,B),  _(M,T),  _(M,B),  _(M,R),  _(M,L),  _(M,L),
   /* 1A70 */  _(M,L),  _(M,L),  _(M,L),  _(M,T),  _(M,T), _(TM,x), _(TM,x), _(TM,x),
   /* 1A78 */ _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1A80 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1A88 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1A90 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1A98 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1AA0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1AA8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1A80 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1A88 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1A90 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1A98 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x1b00 2640
+#define indic_offset_0x1b00u 2120
 
 
-  /* Balinese  (1B00..1B7F) */
+  /* Balinese */
 
-  /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
   /* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 1B10 */ _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -491,36 +437,36 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 1B38 */  _(M,B),  _(M,B),  _(M,B), _(M,BR), _(M,TB),_(M,TBR),  _(M,L),  _(M,L),
   /* 1B40 */ _(M,LR), _(M,LR),  _(M,T), _(M,TR),  _(V,R),  _(C,x),  _(C,x),  _(C,x),
   /* 1B48 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1B50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1B58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1B50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1B58 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1B60 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1B68 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1B70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1B78 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Sundanese  (1B80..1BBF) */
+  /* Sundanese */
 
-  /* 1B80 */ _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 1B80 */ _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 1B88 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B90 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1B98 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BA0 */  _(C,x), _(CS,x), _(CS,x), _(CS,x),  _(M,T),  _(M,B),  _(M,L),  _(M,R),
-  /* 1BA8 */  _(M,T),  _(M,T),  _(V,R),  _(V,x), _(CS,x), _(CS,x),  _(C,x),  _(C,x),
-  /* 1BB0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1BB8 */  _(x,x),  _(x,x),  _(A,x),  _(C,x),  _(C,x),  _(C,x), _(CF,x), _(CF,x),
+  /* 1BA8 */  _(M,T),  _(M,T), _(PK,R), _(IS,x), _(CS,x), _(CS,x),  _(C,x),  _(C,x),
+  /* 1BB0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1BB8 */ _(Nd,x), _(Nd,x),  _(A,x),  _(C,x),  _(C,x),  _(C,x), _(CF,x), _(CF,x),
 
-  /* Batak  (1BC0..1BFF) */
+  /* Batak */
 
   /* 1BC0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BC8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BD0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1BD8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 1BE0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x),  _(N,x),  _(M,x),
-  /* 1BE8 */  _(M,x),  _(M,x),  _(M,x),  _(M,x),  _(M,x),  _(M,x),  _(M,x),  _(M,x),
-  /* 1BF0 */ _(CF,x), _(CF,x),  _(V,R),  _(V,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1BE0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x),  _(N,x),  _(M,R),
+  /* 1BE8 */  _(M,T),  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,T),  _(M,R),  _(M,T),
+  /* 1BF0 */ _(CF,x), _(CF,x), _(PK,R), _(PK,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1BF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Lepcha  (1C00..1C4F) */
+  /* Lepcha */
 
   /* 1C00 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1C08 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -528,41 +474,45 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 1C18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 1C20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(CS,x), _(CS,x),  _(M,R),  _(M,L),
   /* 1C28 */  _(M,L), _(M,TL),  _(M,R),  _(M,R),  _(M,B), _(CF,x), _(CF,x), _(CF,x),
-  /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,x), _(Bi,x),  _(x,x),  _(N,x),
+  /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,L), _(Bi,L),  _(x,x),  _(N,x),
   /* 1C38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1C40 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1C48 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 1C40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 1C48 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
 
-#define indic_offset_0x1cd0 2976
+#define indic_offset_0x1cd0u 2456
 
 
-  /* Vedic Extensions  (1CD0..1CFF) */
+  /* Vedic Extensions */
 
-  /* 1CD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1CD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1CE0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CD0 */ _(TM,x), _(TM,x), _(TM,x),  _(x,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+  /* 1CD8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+  /* 1CE0 */ _(TM,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 1CE8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 1CF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 1CF0 */  _(x,x),  _(x,x), _(Vs,x), _(Vs,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x2008u 2496
+
+
+  /* General Punctuation */
 
-#define indic_offset_0xa800 3024
+  /* 2008 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),_(ZWNJ,x),_(ZWJ,x),  _(x,x),  _(x,x),
+  /* 2010 */  _(x,x),  _(x,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),  _(x,x),  _(x,x),
 
+#define indic_offset_0xa800u 2512
 
-  /* Syloti Nagri  (A800..A82F) */
 
-  /* A800 */ _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),  _(V,T),  _(C,x),
+  /* Syloti Nagri */
+
+  /* A800 */ _(VI,x), _(VI,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x), _(PK,T),  _(C,x),
   /* A808 */  _(C,x),  _(C,x),  _(C,x), _(Bi,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A810 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A818 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A820 */  _(C,x),  _(C,x),  _(C,x),  _(M,R),  _(M,R),  _(M,B),  _(M,T),  _(M,R),
   /* A828 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* FILLER  (A830..A83F) */
-
   /* A830 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A838 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Phags-pa  (A840..A87F) */
+  /* Phags-pa */
 
   /* A840 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A848 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -573,7 +523,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* A870 */  _(C,x), _(CS,x),  _(C,x), _(Bi,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A878 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Saurashtra  (A880..A8DF) */
+  /* Saurashtra */
 
   /* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -585,44 +535,41 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* A8B8 */  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(M,R),
   /* A8C0 */  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(V,B),  _(x,x),  _(x,x),  _(x,x),
   /* A8C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A8D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A8D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* A8D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* A8D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* FILLER  (A8E0..A8FF) */
+  /* Devanagari Extended */
 
-  /* A8E0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A8E8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A8F0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* A8E0 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+  /* A8E8 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+  /* A8F0 */ _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A8F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Kayah Li  (A900..A92F) */
+  /* Kayah Li */
 
-  /* A900 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A908 */  _(x,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* A900 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* A908 */ _(Nd,x), _(Nd,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A910 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A918 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A920 */  _(C,x),  _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
   /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x),  _(x,x),  _(x,x),
 
-  /* Rejang  (A930..A95F) */
+  /* Rejang */
 
   /* A930 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A938 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A940 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,B),
   /* A948 */  _(M,B),  _(M,B),  _(M,T),  _(M,B),  _(M,B),  _(M,B),  _(M,B), _(CF,x),
-  /* A950 */ _(CF,x), _(CF,x), _(CF,x),  _(V,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(PK,R),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A958 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-  /* FILLER  (A960..A97F) */
-
   /* A960 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A968 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A970 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A978 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Javanese  (A980..A9DF) */
+  /* Javanese */
 
-  /* A980 */ _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* A980 */ _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* A988 */ _(VI,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),
   /* A990 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* A998 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -632,17 +579,17 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* A9B8 */  _(M,B),  _(M,B),  _(M,L),  _(M,L),  _(M,T), _(CS,x), _(CM,x), _(CM,x),
   /* A9C0 */ _(V,BR),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* A9C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A9D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A9D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* A9D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* A9D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* FILLER  (A9E0..A9FF) */
+  /* Myanmar Extended-B */
 
-  /* A9E0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A9E8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A9F0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* A9F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* A9E0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(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),
 
-  /* Cham  (AA00..AA5F) */
+  /* Cham */
 
   /* AA00 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),
   /* AA08 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -650,21 +597,21 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* AA18 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AA20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AA28 */  _(C,x),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(M,B),  _(M,T),  _(M,L),
-  /* AA30 */  _(M,L),  _(M,T),  _(M,B), _(CM,x), _(CM,x), _(CM,x), _(CM,x),  _(x,x),
+  /* AA30 */  _(M,L),  _(M,T),  _(M,B), _(CM,x), _(CM,L), _(CM,x), _(CM,x),  _(x,x),
   /* AA38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
   /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),  _(x,x),  _(x,x),
-  /* AA50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* AA58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* AA50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* AA58 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Myanmar Extended-A  (AA60..AA7F) */
+  /* 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),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,x), _(TM,x), _(TM,x),  _(C,x),  _(C,x),
 
-  /* Tai Viet  (AA80..AADF) */
+  /* Tai Viet */
 
   /* AA80 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AA88 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -679,31 +626,30 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* AAD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* AAD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Meetei Mayek Extensions  (AAE0..AAFF) */
+  /* Meetei Mayek Extensions */
 
   /* AAE0 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* AAE8 */  _(C,x),  _(C,x),  _(C,x),  _(M,L),  _(M,B),  _(M,T),  _(M,L),  _(M,R),
-  /* AAF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Vs,x),  _(V,I),  _(x,x),
-  /* AAF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* AAF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(Vs,x), _(IS,x),  _(x,x),
 
-#define indic_offset_0xabc0 3792
+#define indic_offset_0xabc0u 3272
 
 
-  /* Meetei Mayek  (ABC0..ABFF) */
+  /* Meetei Mayek */
 
   /* ABC0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* ABC8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(VI,x), _(VI,x),
   /* ABD0 */  _(C,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* ABD8 */  _(C,x),  _(C,x),  _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
   /* ABE0 */ _(CF,x), _(CF,x), _(CF,x),  _(M,R),  _(M,R),  _(M,T),  _(M,R),  _(M,R),
-  /* ABE8 */  _(M,B),  _(M,R),  _(M,R),  _(x,x), _(TM,x),  _(V,B),  _(x,x),  _(x,x),
-  /* ABF0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* ABF8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* ABE8 */  _(M,B),  _(M,R),  _(M,R),  _(x,x), _(TM,x), _(PK,B),  _(x,x),  _(x,x),
+  /* ABF0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* ABF8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x10a00 3856
+#define indic_offset_0x10a00u 3336
 
 
-  /* Kharoshthi  (10A00..10A5F) */
+  /* Kharoshthi */
 
   /* 10A00 */  _(C,x),  _(M,O),  _(M,B),  _(M,B),  _(x,x),  _(M,T),  _(M,O),  _(x,x),
   /* 10A08 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,B),  _(x,x), _(Bi,x), _(Vs,x),
@@ -712,16 +658,13 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 10A20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A28 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 10A30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 10A38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(V,I),
-  /* 10A40 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 10A48 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 10A50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 10A58 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 10A38 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(IS,x),
+  /* 10A40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
 
-#define indic_offset_0x11000 3952
+#define indic_offset_0x11000u 3408
 
 
-  /* Brahmi  (11000..1107F) */
+  /* Brahmi */
 
   /* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -733,14 +676,14 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 11038 */  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(M,B),  _(M,B),  _(M,B),  _(M,B),
   /* 11040 */  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(x,x),
   /* 11048 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 11050 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 11058 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 11060 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 11068 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11050 */  _(x,x),  _(x,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),
+  /* 11058 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),
+  /* 11060 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x), _(Nd,x), _(Nd,x),
+  /* 11068 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 11070 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 11078 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11078 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(NJ,x),
 
-  /* Kaithi  (11080..110CF) */
+  /* Kaithi */
 
   /* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
@@ -750,13 +693,11 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 110A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 110B0 */  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,R),
   /* 110B8 */  _(M,R),  _(V,B),  _(N,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 110C0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 110C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x11100 4160
+#define indic_offset_0x11100u 3600
 
 
-  /* Chakma  (11100..1114F) */
+  /* Chakma */
 
   /* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),
   /* 11108 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -764,15 +705,21 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 11118 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 11120 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,T),
   /* 11128 */  _(M,T),  _(M,T),  _(M,B),  _(M,B),  _(M,L),  _(M,T), _(M,TB), _(M,TB),
-  /* 11130 */  _(M,T),  _(M,B),  _(M,B),  _(V,I),  _(V,T),  _(x,x),  _(x,x),  _(x,x),
-  /* 11138 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11130 */  _(M,T),  _(M,B),  _(M,B), _(IS,x), _(PK,T),  _(x,x), _(Nd,x), _(Nd,x),
+  /* 11138 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 11140 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 11148 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-#define indic_offset_0x11180 4240
+  /* Mahajani */
 
+  /* 11150 */ _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11158 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11160 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11168 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11170 */  _(C,x),  _(C,x),  _(C,x),  _(N,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11178 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-  /* Sharada  (11180..111DF) */
+  /* Sharada */
 
   /* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -784,13 +731,116 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 111B8 */  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T), _(M,TR),
   /* 111C0 */  _(V,R),  _(A,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
   /* 111C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 111D0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 111D8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_0x11680 4336
-
-
-  /* Takri  (11680..116CF) */
+  /* 111D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 111D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Sinhala Archaic Numbers */
+
+  /* 111E0 */  _(x,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 111E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 111F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 111F8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Khojki */
+
+  /* 11200 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11208 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11210 */  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11218 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11220 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11228 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,R),  _(M,R),  _(M,R),  _(M,B),
+  /* 11230 */  _(M,T),  _(M,T), _(M,TR), _(M,TR), _(Bi,x),  _(V,R),  _(N,x), _(GM,T),
+
+#define indic_offset_0x112b0u 3912
+
+
+  /* Khudawadi */
+
+  /* 112B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 112B8 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 112C0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 112C8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 112D0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 112D8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x), _(Bi,x),
+  /* 112E0 */  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),
+  /* 112E8 */  _(M,T),  _(N,x), _(PK,B),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 112F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 112F8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Grantha */
+
+  /* 11300 */  _(x,x), _(Bi,x), _(Bi,x), _(Vs,x),  _(x,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11308 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(x,x),  _(x,x), _(VI,x),
+  /* 11310 */ _(VI,x),  _(x,x),  _(x,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11318 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11320 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11328 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11330 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11338 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,x),  _(A,x),  _(M,R),  _(M,R),
+  /* 11340 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(x,x),  _(M,L),
+  /* 11348 */  _(M,L),  _(x,x),  _(x,x), _(M,LR), _(M,LR),  _(V,R),  _(x,x),  _(x,x),
+  /* 11350 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),
+  /* 11358 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11360 */ _(VI,x), _(VI,x),  _(M,R),  _(M,R),  _(x,x),  _(x,x), _(Ca,x), _(Ca,x),
+  /* 11368 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11370 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x11480u 4112
+
+
+  /* Tirhuta */
+
+  /* 11480 */  _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11488 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),
+  /* 11490 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11498 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 114A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 114A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 114B0 */  _(M,R),  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,B),
+  /* 114B8 */  _(M,B),  _(M,L),  _(M,T), _(M,TL), _(M,LR),  _(M,R), _(M,LR), _(Bi,x),
+  /* 114C0 */ _(Bi,x), _(Vs,x),  _(V,B),  _(N,x),  _(A,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 114C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 114D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 114D8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x11580u 4208
+
+
+  /* Siddham */
+
+  /* 11580 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11588 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),
+  /* 11590 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11598 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 115A0 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 115A8 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(M,R),
+  /* 115B0 */  _(M,L),  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(x,x),  _(x,x),
+  /* 115B8 */  _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,x), _(Bi,x), _(Vs,x),  _(V,B),
+  /* 115C0 */  _(N,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+#define indic_offset_0x11600u 4280
+
+
+  /* Modi */
+
+  /* 11600 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+  /* 11608 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),  _(C,x),  _(C,x),
+  /* 11610 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11618 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11620 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11628 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
+  /* 11630 */  _(M,R),  _(M,R),  _(M,R),  _(M,B),  _(M,B),  _(M,B),  _(M,B),  _(M,B),
+  /* 11638 */  _(M,B),  _(M,T),  _(M,T),  _(M,R),  _(M,R), _(Bi,x), _(Vs,x),  _(V,B),
+  /* 11640 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11648 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11650 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 11658 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11660 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11668 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11670 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 11678 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+
+  /* Takri */
 
   /* 11680 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
   /* 11688 */ _(VI,x), _(VI,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
@@ -800,30 +850,57 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
   /* 116A8 */  _(C,x),  _(C,x),  _(C,x), _(Bi,x), _(Vs,x),  _(M,T),  _(M,L),  _(M,R),
   /* 116B0 */  _(M,B),  _(M,B),  _(M,T),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(N,x),
   /* 116B8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 116C0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-  /* 116C8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
-
-#define indic_offset_total 4416
+  /* 116C0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+  /* 116C8 */ _(Nd,x), _(Nd,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
 
-}; /* Table occupancy: 60% */
+}; /* Table items: 4488; occupancy: 73% */
 
-static INDIC_TABLE_ELEMENT_TYPE
-get_indic_categories (hb_codepoint_t u)
+INDIC_TABLE_ELEMENT_TYPE
+hb_indic_get_categories (hb_codepoint_t u)
 {
-  if (0x0900 <= u && u <= 0x10A0) return indic_table[u - 0x0900 + indic_offset_0x0900];
-  if (0x1700 <= u && u <= 0x1800) return indic_table[u - 0x1700 + indic_offset_0x1700];
-  if (0x1900 <= u && u <= 0x1AB0) return indic_table[u - 0x1900 + indic_offset_0x1900];
-  if (0x1B00 <= u && u <= 0x1C50) return indic_table[u - 0x1B00 + indic_offset_0x1b00];
-  if (0x1CD0 <= u && u <= 0x1D00) return indic_table[u - 0x1CD0 + indic_offset_0x1cd0];
-  if (0xA800 <= u && u <= 0xAB00) return indic_table[u - 0xA800 + indic_offset_0xa800];
-  if (0xABC0 <= u && u <= 0xAC00) return indic_table[u - 0xABC0 + indic_offset_0xabc0];
-  if (0x10A00 <= u && u <= 0x10A60) return indic_table[u - 0x10A00 + indic_offset_0x10a00];
-  if (0x11000 <= u && u <= 0x110D0) return indic_table[u - 0x11000 + indic_offset_0x11000];
-  if (0x11100 <= u && u <= 0x11150) return indic_table[u - 0x11100 + indic_offset_0x11100];
-  if (0x11180 <= u && u <= 0x111E0) return indic_table[u - 0x11180 + indic_offset_0x11180];
-  if (0x11680 <= u && u <= 0x116D0) return indic_table[u - 0x11680 + indic_offset_0x11680];
-  if (unlikely (u == 0x00A0)) return _(CP,x);
-  if (unlikely (u == 0x25CC)) return _(CP,x);
+  switch (u >> 12)
+  {
+    case 0x0u:
+      if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+      if (hb_in_range (u, 0x00D0u, 0x00D7u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
+      if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+      if (unlikely (u == 0x00A0u)) return _(CP,x);
+      break;
+
+    case 0x1u:
+      if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+      if (hb_in_range (u, 0x1700u, 0x17EFu)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
+      if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
+      if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
+      if (hb_in_range (u, 0x1CD0u, 0x1CF7u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+      break;
+
+    case 0x2u:
+      if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
+      if (unlikely (u == 0x25CCu)) return _(CP,x);
+      break;
+
+    case 0xAu:
+      if (hb_in_range (u, 0xA800u, 0xAAF7u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
+      if (hb_in_range (u, 0xABC0u, 0xABFFu)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
+      break;
+
+    case 0x10u:
+      if (hb_in_range (u, 0x10A00u, 0x10A47u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
+      break;
+
+    case 0x11u:
+      if (hb_in_range (u, 0x11000u, 0x110BFu)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
+      if (hb_in_range (u, 0x11100u, 0x11237u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
+      if (hb_in_range (u, 0x112B0u, 0x11377u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
+      if (hb_in_range (u, 0x11480u, 0x114DFu)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
+      if (hb_in_range (u, 0x11580u, 0x115C7u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
+      if (hb_in_range (u, 0x11600u, 0x116CFu)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
+      break;
+
+    default:
+      break;
+  }
   return _(x,x);
 }
 
@@ -831,17 +908,27 @@ get_indic_categories (hb_codepoint_t u)
 
 #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_CM
 #undef ISC_CP
-#undef ISC_CR
+#undef ISC_CPR
 #undef ISC_CS
+#undef ISC_CSR
+#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_TL
 #undef ISC_TM
@@ -853,7 +940,6 @@ get_indic_categories (hb_codepoint_t u)
 
 #undef IMC_B
 #undef IMC_BR
-#undef IMC_I
 #undef IMC_L
 #undef IMC_LR
 #undef IMC_x
@@ -867,6 +953,4 @@ get_indic_categories (hb_codepoint_t u)
 #undef IMC_TR
 #undef IMC_VOL
 
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */
-
 /* == End of generated table == */
index f168fe1..7723600 100644 (file)
  */
 
 #include "hb-ot-shape-complex-indic-private.hh"
-#include "hb-ot-shape-private.hh"
+#include "hb-ot-layout-private.hh"
 
-struct indic_options_t
+/* buffer var allocations */
+#define indic_category() complex_var_u8_0() /* indic_category_t */
+#define indic_position() complex_var_u8_1() /* indic_position_t */
+
+
+/*
+ * Indic shaper.
+ */
+
+
+#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 IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780u))
+
+
+#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  : \
+                                 IS_KHMR(u) ? POS_AFTER_POST : \
+                                 /*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  : \
+                                 IS_KHMR(u) ? POS_AFTER_POST : \
+                                 /*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  : \
+                                 IS_KHMR(u) ? POS_AFTER_POST : \
+                                 /*default*/  POS_AFTER_SUB    \
+                               )
+
+static inline indic_position_t
+matra_position (hb_codepoint_t u, indic_position_t side)
 {
-  int initialized : 1;
-  int uniscribe_bug_compatible : 1;
-};
+  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;
+}
 
-union indic_options_union_t {
-  int i;
-  indic_options_t opts;
+/* 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 */
+
+  0x179Au, /* Khmer */         /* No Reph, Visual Repha */
 };
-ASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t));
 
-static indic_options_union_t
-indic_options_init (void)
+static inline bool
+is_ra (hb_codepoint_t u)
 {
-  indic_options_union_t u;
-  u.i = 0;
-  u.opts.initialized = 1;
+  for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
+    if (u == ra_chars[i])
+      return true;
+  return false;
+}
 
-  char *c = getenv ("HB_OT_INDIC_OPTIONS");
-  u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
+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 (info.indic_category()) & flags);
+}
 
-  return u;
+static inline bool
+is_joiner (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, JOINER_FLAGS);
 }
 
-inline indic_options_t
-indic_options (void)
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
 {
-  static indic_options_union_t options;
+  return is_one_of (info, CONSONANT_FLAGS);
+}
+
+static inline bool
+is_halant_or_coeng (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, HALANT_OR_COENG_FLAGS);
+}
+
+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 & 0x7Fu);
+  indic_position_t pos = (indic_position_t) (type >> 8);
+
+
+  /*
+   * Re-assign category
+   */
+
 
-  if (unlikely (!options.i)) {
-    /* This is idempotent and threadsafe. */
-    options = indic_options_init ();
+  /* The spec says U+0952 is OT_A.  However, testing shows that Uniscribe
+   * treats a whole bunch of characters similarly.
+   * TESTS: For example, for U+0951:
+   * U+092E,U+0947,U+0952
+   * U+092E,U+0952,U+0947
+   * U+092E,U+0947,U+0951
+   * U+092E,U+0951,U+0947
+   * U+092E,U+0951,U+0952
+   * U+092E,U+0952,U+0951
+   */
+  if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u,
+                                0x1CD0u, 0x1CD2u,
+                                0x1CD4u, 0x1CE1u) ||
+                           u == 0x1CF4u))
+    cat = OT_A;
+  /* The following act more like the Bindus. */
+  else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
+    cat = OT_SM;
+  /* The following act like consonants. */
+  else if (unlikely (hb_in_ranges (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 (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 (u, 0xA8F2u, 0xA8F7u,
+                                     0x1CE9u, 0x1CECu,
+                                     0x1CEEu, 0x1CF1u)))
+  {
+    cat = OT_Symbol;
+    ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
+  }
+  else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) ||
+                    u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
+  {
+    /* These are like Top Matras. */
+    cat = OT_M;
+    pos = POS_ABOVE_C;
   }
+  else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
+  else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */
+  else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
+                                   cat = OT_PLACEHOLDER;
+  else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
+  else if (unlikely (u == 0xA982u)) cat = OT_SM; /* Javanese repha. */
+  else if (unlikely (u == 0xA9BEu)) cat = OT_CM2; /* Javanese medial ya. */
+  else if (unlikely (u == 0xA9BDu)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
+
+
+  /*
+   * Re-assign position.
+   */
 
-  return options.opts;
-}
+  if ((FLAG (cat) & CONSONANT_FLAGS))
+  {
+    pos = POS_BASE_C;
+    if (is_ra (u))
+      cat = OT_Ra;
+  }
+  else if (cat == OT_M)
+  {
+    pos = matra_position (u, pos);
+  }
+  else if ((FLAG (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. */
 
-static int
-compare_codepoint (const void *pa, const void *pb)
-{
-  hb_codepoint_t a = * (hb_codepoint_t *) pa;
-  hb_codepoint_t b = * (hb_codepoint_t *) pb;
 
-  return a < b ? -1 : a == b ? 0 : +1;
+
+  info.indic_category() = cat;
+  info.indic_position() = pos;
 }
 
-static indic_position_t
-consonant_position (hb_codepoint_t u)
-{
-  consonant_position_t *record;
+/*
+ * Things above this line should ideally be moved to the Indic table itself.
+ */
 
-  record = (consonant_position_t *) bsearch (&u, consonant_positions,
-                                            ARRAY_LENGTH (consonant_positions),
-                                            sizeof (consonant_positions[0]),
-                                            compare_codepoint);
 
-  return record ? record->position : POS_BASE_C;
-}
+/*
+ * 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
+ * properties that are cheaper keeping here, than in the code.  Ie. if, say, one and
+ * only one script has an exception, that one script can be if'ed directly in the code,
+ * instead of adding a new flag in these structs.
+ */
 
-static bool
-is_ra (hb_codepoint_t u)
+enum base_position_t {
+  BASE_POS_FIRST,
+  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,
+  REPH_POS_AFTER_SUB   = POS_AFTER_SUB,
+  REPH_POS_BEFORE_POST = POS_BEFORE_POST,
+  REPH_POS_AFTER_POST  = POS_AFTER_POST,
+  REPH_POS_DONT_CARE   = POS_RA_TO_BECOME_REPH
+};
+enum reph_mode_t {
+  REPH_MODE_IMPLICIT,  /* Reph formed out of initial Ra,H sequence. */
+  REPH_MODE_EXPLICIT,  /* Reph formed out of initial Ra,H,ZWJ sequence. */
+  REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
+  REPH_MODE_LOG_REPHA  /* Encoded Repha character, needs reordering. */
+};
+enum blwf_mode_t {
+  BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
+  BLWF_MODE_POST_ONLY     /* Below-forms feature applied to post-base only. */
+};
+enum pref_len_t {
+  PREF_LEN_1 = 1,
+  PREF_LEN_2 = 2,
+  PREF_LEN_DONT_CARE = PREF_LEN_2
+};
+struct indic_config_t
 {
-  return !!bsearch (&u, ra_chars,
-                   ARRAY_LENGTH (ra_chars),
-                   sizeof (ra_chars[0]),
-                   compare_codepoint);
-}
+  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;
+  pref_len_t      pref_len;
+};
 
-static bool
-is_joiner (const hb_glyph_info_t &info)
+static const indic_config_t indic_configs[] =
 {
-  return !!(FLAG (info.indic_category()) & (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)));
-}
+  /* Default.  Should be first. */
+  {HB_SCRIPT_INVALID,  false,      0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+  {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_BENGALI,  true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_ORIYA,    true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_TAMIL,    true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_TELUGU,   true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY,    PREF_LEN_2},
+  {HB_SCRIPT_KANNADA,  true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY,    PREF_LEN_2},
+  {HB_SCRIPT_MALAYALAM,        true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_SINHALA,  false,0x0DCAu,BASE_POS_LAST_SINHALA,
+                                                    REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+  {HB_SCRIPT_KHMER,    false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+  {HB_SCRIPT_JAVANESE, false,0xA9C0u,BASE_POS_FIRST,REPH_POS_DONT_CARE,  REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+};
 
-static bool
-is_consonant (const hb_glyph_info_t &info)
-{
-  /* 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! */
-  return !!(FLAG (info.indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)));
-}
+
+
+/*
+ * Indic shaper.
+ */
 
 struct feature_list_t {
   hb_tag_t tag;
-  hb_bool_t is_global;
+  hb_ot_map_feature_flags_t flags;
 };
 
 static const feature_list_t
-indic_basic_features[] =
-{
-  {HB_TAG('n','u','k','t'), true},
-  {HB_TAG('a','k','h','n'), false},
-  {HB_TAG('r','p','h','f'), false},
-  {HB_TAG('r','k','r','f'), true},
-  {HB_TAG('p','r','e','f'), false},
-  {HB_TAG('b','l','w','f'), false},
-  {HB_TAG('h','a','l','f'), false},
-  {HB_TAG('p','s','t','f'), false},
-  {HB_TAG('c','j','c','t'), false},
-  {HB_TAG('v','a','t','u'), true},
+indic_features[] =
+{
+  /*
+   * Basic features.
+   * These features are applied in order, one at a time, after initial_reordering.
+   */
+  {HB_TAG('n','u','k','t'), F_GLOBAL},
+  {HB_TAG('a','k','h','n'), F_GLOBAL},
+  {HB_TAG('r','p','h','f'), F_NONE},
+  {HB_TAG('r','k','r','f'), F_GLOBAL},
+  {HB_TAG('p','r','e','f'), F_NONE},
+  {HB_TAG('b','l','w','f'), F_NONE},
+  {HB_TAG('a','b','v','f'), F_NONE},
+  {HB_TAG('h','a','l','f'), F_NONE},
+  {HB_TAG('p','s','t','f'), F_NONE},
+  {HB_TAG('v','a','t','u'), F_GLOBAL},
+  {HB_TAG('c','j','c','t'), F_GLOBAL},
+  {HB_TAG('c','f','a','r'), F_NONE},
+  /*
+   * Other features.
+   * These features are applied all at once, after final_reordering.
+   * Default Bengali font in Windows for example has intermixed
+   * lookups for init,pres,abvs,blws features.
+   */
+  {HB_TAG('i','n','i','t'), F_NONE},
+  {HB_TAG('p','r','e','s'), F_GLOBAL},
+  {HB_TAG('a','b','v','s'), F_GLOBAL},
+  {HB_TAG('b','l','w','s'), F_GLOBAL},
+  {HB_TAG('p','s','t','s'), F_GLOBAL},
+  {HB_TAG('h','a','l','n'), F_GLOBAL},
+  /* Positioning features, though we don't care about the types. */
+  {HB_TAG('d','i','s','t'), F_GLOBAL},
+  {HB_TAG('a','b','v','m'), F_GLOBAL},
+  {HB_TAG('b','l','w','m'), F_GLOBAL},
 };
 
-/* Same order as the indic_basic_features array */
+/*
+ * Must be in the same order as the indic_features array.
+ */
 enum {
   _NUKT,
-  AKHN,
+  _AKHN,
   RPHF,
   _RKRF,
   PREF,
   BLWF,
+  ABVF,
   HALF,
   PSTF,
-  CJCT,
-  VATU
-};
-
-static const feature_list_t
-indic_other_features[] =
-{
-  {HB_TAG('i','n','i','t'), false},
-  {HB_TAG('p','r','e','s'), true},
-  {HB_TAG('a','b','v','s'), true},
-  {HB_TAG('b','l','w','s'), true},
-  {HB_TAG('p','s','t','s'), true},
-  {HB_TAG('h','a','l','n'), true},
-
-  {HB_TAG('d','i','s','t'), true},
-  {HB_TAG('a','b','v','m'), true},
-  {HB_TAG('b','l','w','m'), true},
-};
-
-/* Same order as the indic_other_features array */
-enum {
-  INIT
+  _VATU,
+  _CJCT,
+  CFAR,
+
+  INIT,
+  _PRES,
+  _ABVS,
+  _BLWS,
+  _PSTS,
+  _HALN,
+  _DIST,
+  _ABVM,
+  _BLWM,
+
+  INDIC_NUM_FEATURES,
+  INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
 };
 
-
 static void
-initial_reordering (const hb_ot_map_t *map,
-                   hb_face_t *face,
-                   hb_buffer_t *buffer,
-                   void *user_data HB_UNUSED);
+setup_syllables (const hb_ot_shape_plan_t *plan,
+                hb_font_t *font,
+                hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                   hb_font_t *font,
+                   hb_buffer_t *buffer);
 static void
-final_reordering (const hb_ot_map_t *map,
-                 hb_face_t *face,
-                 hb_buffer_t *buffer,
-                 void *user_data HB_UNUSED);
+final_reordering (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer);
+static void
+clear_syllables (const hb_ot_shape_plan_t *plan,
+                hb_font_t *font,
+                hb_buffer_t *buffer);
 
-void
-_hb_ot_shape_complex_collect_features_indic (hb_ot_map_builder_t *map,
-                                            const hb_segment_properties_t *props HB_UNUSED)
+static void
+collect_features_indic (hb_ot_shape_planner_t *plan)
 {
-  map->add_bool_feature (HB_TAG('l','o','c','l'));
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* Do this before any lookups have been applied. */
+  map->add_gsub_pause (setup_syllables);
+
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
   /* 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->add_bool_feature (HB_TAG('c','c','m','p'));
+  map->add_global_bool_feature (HB_TAG('c','c','m','p'));
 
-  map->add_gsub_pause (initial_reordering, NULL);
 
-  for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) {
-    map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global);
-    map->add_gsub_pause (NULL, NULL);
+  unsigned int i = 0;
+  map->add_gsub_pause (initial_reordering);
+  for (; i < INDIC_BASIC_FEATURES; i++) {
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
+    map->add_gsub_pause (NULL);
+  }
+  map->add_gsub_pause (final_reordering);
+  for (; i < INDIC_NUM_FEATURES; i++) {
+    map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
   }
 
-  map->add_gsub_pause (final_reordering, NULL);
+  map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+  map->add_global_bool_feature (HB_TAG('c','l','i','g'));
+
+  map->add_gsub_pause (clear_syllables);
+}
 
-  for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++) {
-    map->add_bool_feature (indic_other_features[i].tag, indic_other_features[i].is_global);
-    map->add_gsub_pause (NULL, NULL);
+static void
+override_features_indic (hb_ot_shape_planner_t *plan)
+{
+  /* Uniscribe does not apply 'kern' in Khmer. */
+  if (hb_options ().uniscribe_bug_compatible)
+  {
+    switch ((hb_tag_t) plan->props.script)
+    {
+      case HB_SCRIPT_KHMER:
+       plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
+       break;
+    }
   }
+
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
 }
 
 
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_indic (void)
+struct would_substitute_feature_t
+{
+  inline 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);
+  }
+
+  inline 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_fast (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;
+};
+
+struct indic_shape_plan_t
 {
-  /* We want split matras decomposed by the common shaping logic. */
-  return HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
+  ASSERT_POD ();
+
+  inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
+  {
+    hb_codepoint_t glyph = virama_glyph;
+    if (unlikely (virama_glyph == (hb_codepoint_t) -1))
+    {
+      if (!config->virama || !font->get_glyph (config->virama, 0, &glyph))
+       glyph = 0;
+      /* Technically speaking, the spec says we should apply 'locl' to virama too.
+       * Maybe one day... */
+
+      /* Our get_glyph() function needs a font, so we can't get the virama glyph
+       * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
+      (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
+    }
+
+    *pglyph = glyph;
+    return glyph != 0;
+  }
+
+  const indic_config_t *config;
+
+  bool is_old_spec;
+  hb_codepoint_t virama_glyph;
+
+  would_substitute_feature_t rphf;
+  would_substitute_feature_t pref;
+  would_substitute_feature_t blwf;
+  would_substitute_feature_t pstf;
+
+  hb_mask_t mask_array[INDIC_NUM_FEATURES];
+};
+
+static void *
+data_create_indic (const hb_ot_shape_plan_t *plan)
+{
+  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
+  if (unlikely (!indic_plan))
+    return NULL;
+
+  indic_plan->config = &indic_configs[0];
+  for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
+    if (plan->props.script == indic_configs[i].script) {
+      indic_plan->config = &indic_configs[i];
+      break;
+    }
+
+  indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
+  indic_plan->virama_glyph = (hb_codepoint_t) -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. */
+  bool zero_context = !indic_plan->is_old_spec;
+  indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
+  indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
+  indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
+  indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
+
+  for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
+    indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
+                                0 : plan->map.get_1_mask (indic_features[i].tag);
+
+  return indic_plan;
+}
+
+static void
+data_destroy_indic (void *data)
+{
+  free (data);
+}
+
+static indic_position_t
+consonant_position_from_face (const indic_shape_plan_t *indic_plan,
+                             const hb_codepoint_t consonant,
+                             const hb_codepoint_t virama,
+                             hb_face_t *face)
+{
+  /* For old-spec, the order of glyphs is Consonant,Virama,
+   * whereas for new-spec, it's Virama,Consonant.  However,
+   * some broken fonts (like Free Sans) simply copied lookups
+   * from old-spec to new-spec without modification.
+   * And oddly enough, Uniscribe seems to respect those lookups.
+   * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds
+   * base at 0.  The font however, only has lookups matching
+   * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
+   * table).  As such, we simply match both sequences.  Seems
+   * to work. */
+  hb_codepoint_t glyphs[3] = {virama, consonant, virama};
+  if (indic_plan->blwf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->blwf.would_substitute (glyphs+1, 2, face))
+    return POS_BELOW_C;
+  if (indic_plan->pstf.would_substitute (glyphs  , 2, face) ||
+      indic_plan->pstf.would_substitute (glyphs+1, 2, face))
+    return POS_POST_C;
+  unsigned int pref_len = indic_plan->config->pref_len;
+  if ((pref_len == PREF_LEN_2 &&
+       (indic_plan->pref.would_substitute (glyphs  , 2, face) ||
+        indic_plan->pref.would_substitute (glyphs+1, 2, face)))
+   || (pref_len == PREF_LEN_1 &&
+       indic_plan->pref.would_substitute (glyphs+1, 1, face)))
+    return POS_POST_C;
+  return POS_BASE_C;
 }
 
 
-void
-_hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map HB_UNUSED,
-                                       hb_buffer_t *buffer,
-                                       hb_font_t *font HB_UNUSED)
+enum syllable_type_t {
+  consonant_syllable,
+  vowel_syllable,
+  standalone_cluster,
+  symbol_cluster,
+  broken_cluster,
+  non_indic_cluster,
+};
+
+#include "hb-ot-shape-complex-indic-machine.hh"
+
+
+static void
+setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                  hb_buffer_t              *buffer,
+                  hb_font_t                *font HB_UNUSED)
 {
   HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
@@ -225,39 +635,17 @@ _hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map HB_UNUSED,
    * and setup masks later on in a pause-callback. */
 
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-  {
-    hb_glyph_info_t &info = buffer->info[i];
-    unsigned int type = get_indic_categories (info.codepoint);
-
-    info.indic_category() = type & 0x0F;
-    info.indic_position() = type >> 4;
-
-    /* The spec says U+0952 is OT_A.  However, testing shows that Uniscribe
-     * treats U+0951..U+0952 all as OT_VD.
-     * TESTS:
-     * U+092E,U+0947,U+0952
-     * U+092E,U+0952,U+0947
-     * U+092E,U+0947,U+0951
-     * U+092E,U+0951,U+0947
-     * */
-    if (unlikely (hb_in_range<hb_codepoint_t> (info.codepoint, 0x0951, 0x0954)))
-      info.indic_category() = OT_VD;
-
-    if (info.indic_category() == OT_C) {
-      info.indic_position() = consonant_position (info.codepoint);
-      if (is_ra (info.codepoint))
-       info.indic_category() = OT_Ra;
-    } else if (info.indic_category() == OT_SM ||
-              info.indic_category() == OT_VD) {
-      info.indic_position() = POS_SMVD;
-    } else if (unlikely (info.codepoint == 0x200C))
-      info.indic_category() = OT_ZWNJ;
-    else if (unlikely (info.codepoint == 0x200D))
-      info.indic_category() = OT_ZWJ;
-    else if (unlikely (info.codepoint == 0x25CC))
-      info.indic_category() = OT_DOTTEDCIRCLE;
-  }
+    set_indic_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                hb_font_t *font HB_UNUSED,
+                hb_buffer_t *buffer)
+{
+  find_syllables (buffer);
 }
 
 static int
@@ -269,13 +657,44 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
   return a < b ? -1 : a == b ? 0 : +1;
 }
 
+
+
+static void
+update_consonant_positions (const hb_ot_shape_plan_t *plan,
+                           hb_font_t         *font,
+                           hb_buffer_t       *buffer)
+{
+  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->get_virama_glyph (font, &virama))
+  {
+    hb_face_t *face = font->face;
+    unsigned int count = buffer->len;
+    hb_glyph_info_t *info = buffer->info;
+    for (unsigned int i = 0; i < count; i++)
+      if (info[i].indic_position() == POS_BASE_C)
+      {
+       hb_codepoint_t consonant = info[i].codepoint;
+       info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
+      }
+  }
+}
+
+
 /* Rules from:
  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
 
 static void
-initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array,
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+                                      hb_face_t *face,
+                                      hb_buffer_t *buffer,
                                       unsigned int start, unsigned int end)
 {
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
 
 
@@ -301,54 +720,144 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
      *    and has more than one consonant, Ra is excluded from candidates for
      *    base consonants. */
     unsigned int limit = start;
-    if (mask_array[RPHF] &&
+    if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE &&
+       indic_plan->mask_array[RPHF] &&
        start + 3 <= end &&
-       info[start].indic_category() == OT_Ra &&
-       info[start + 1].indic_category() == OT_H &&
-       !is_joiner (info[start + 2]))
+       (
+        (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)
+       ))
     {
-      limit += 2;
-      base = start;
-      has_reph = true;
-    };
-
-    /* -> starting from the end of the syllable, move backwards */
-    unsigned int i = end;
-    do {
-      i--;
-      /* -> until a consonant is found */
-      if (is_consonant (info[i]))
+      /* See if it matches the 'rphf' feature. */
+      hb_codepoint_t glyphs[3] = {info[start].codepoint,
+                                 info[start + 1].codepoint,
+                                 indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ?
+                                   info[start + 2].codepoint : 0};
+      if (indic_plan->rphf.would_substitute (glyphs, 2, face) ||
+         (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT &&
+          indic_plan->rphf.would_substitute (glyphs, 3, face)))
       {
-       /* -> 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)
-       {
-         base = i;
-         break;
-       }
+       limit += 2;
+       while (limit < end && is_joiner (info[limit]))
+         limit++;
+       base = start;
+       has_reph = true;
+      }
+    } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha)
+    {
+       limit += 1;
+       while (limit < end && is_joiner (info[limit]))
+         limit++;
+       base = start;
+       has_reph = true;
+    }
 
-       /* -> or that is not a pre-base reordering Ra,
-        *
-        * TODO
+    switch (indic_plan->config->base_pos)
+    {
+      default:
+        assert (false);
+       /* fallthrough */
+
+      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]))
+         {
+           /* -> 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;
+         }
+         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.
         */
 
-       /* -> or arrive at the first consonant. The consonant stopped at will
-        * be the base. */
-       base = i;
+       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;
+         }
+
+       /* 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;
       }
-      else
-       if (is_joiner (info[i]))
-         break;
-    } while (i > limit);
-    if (base < start)
-      base = start; /* Just in case... */
+      break;
+
+      case BASE_POS_FIRST:
+      {
+       /* The first consonant is always the base. */
 
+       assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
+       assert (!has_reph);
+
+       base = start;
+
+       /* 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;
+    }
 
     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
      *    and has more than one consonant, Ra is excluded from candidates for
-     *    base consonants. */
-    if (has_reph && base == start) {
+     *    base consonants.
+     *
+     *  Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */
+    if (has_reph && base == start && limit - base <= 2) {
       /* Have no other consonant, so Reph is not formed and Ra becomes base. */
       has_reph = false;
     }
@@ -390,24 +899,56 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
   /* Reorder characters */
 
   for (unsigned int i = start; i < base; i++)
-    info[i].indic_position() = POS_PRE_C;
-  info[base].indic_position() = POS_BASE_C;
+    info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position());
+
+  if (base < end)
+    info[base].indic_position() = POS_BASE_C;
+
+  /* Mark final consonants.  A final consonant is one appearing after a matra,
+   * like in Khmer. */
+  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;
 
   /* For old-style Indic script tags, move the first post-base Halant after
-   * last consonant. */
-  if ((map->get_chosen_script (0) & 0x000000FF) != '2') {
-    /* We should only do this for Indic scripts which have a version two I guess. */
+   * last consonant.
+   *
+   * Reports suggest that in some scripts Uniscribe does this only if there
+   * is *not* a Halant after last consonant already (eg. Kannada), while it
+   * does it unconditionally in other scripts (eg. Malayalam).  We don't
+   * currently know about other scripts, so we single out Malayalam for now.
+   *
+   * Kannada test case:
+   * U+0C9A,U+0CCD,U+0C9A,U+0CCD
+   * With some versions of Lohit Kannada.
+   * https://bugs.freedesktop.org/show_bug.cgi?id=59118
+   *
+   * Malayalam test case:
+   * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
+   * With lohit-ttf-20121122/Lohit-Malayalam.ttf
+   */
+  if (indic_plan->is_old_spec)
+  {
+    bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
     for (unsigned int i = base + 1; i < end; i++)
-      if (info[i].indic_category() == OT_H) {
+      if (info[i].indic_category() == OT_H)
+      {
         unsigned int j;
         for (j = end - 1; j > i; j--)
-         if (is_consonant (info[j]))
+         if (is_consonant (info[j]) ||
+             (disallow_double_halants && info[j].indic_category() == OT_H))
            break;
-       if (j > i) {
+       if (info[j].indic_category() != OT_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]));
@@ -417,43 +958,99 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
       }
   }
 
-  /* Attach ZWJ, ZWNJ, nukta, and halant to previous char to move with them. */
-  if (!indic_options ().uniscribe_bug_compatible)
+  /* Attach misc marks to previous char to move with them. */
   {
-    /* Please update the Uniscribe branch when touching this! */
-    for (unsigned int i = start + 1; i < end; i++)
-      if ((FLAG (info[i].indic_category()) & (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H))))
-       info[i].indic_position() = info[i - 1].indic_position();
-  } else {
-    /*
-     * Uniscribe doesn't move the Halant with Left Matra.
-     * TEST: U+092B,U+093F,U+094DE
-     */
-    /* Please update the non-Uniscribe branch when touching this! */
-    for (unsigned int i = start + 1; i < end; i++)
-      if ((FLAG (info[i].indic_category()) & (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H)))) {
-       info[i].indic_position() = info[i - 1].indic_position();
-       if (info[i].indic_category() == OT_H && info[i].indic_position() == POS_PRE_M)
+    indic_position_t last_pos = POS_START;
+    for (unsigned int i = start; i < end; i++)
+    {
+      if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
+      {
+       info[i].indic_position() = last_pos;
+       if (unlikely (info[i].indic_category() == OT_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
+          */
          for (unsigned int j = i; j > start; j--)
            if (info[j - 1].indic_position() != POS_PRE_M) {
              info[i].indic_position() = info[j - 1].indic_position();
              break;
            }
+       }
+      } else if (info[i].indic_position() != POS_SMVD) {
+        last_pos = (indic_position_t) info[i].indic_position();
       }
+    }
+  }
+  /* For post-base consonants let them own anything before them
+   * since the last consonant or matra. */
+  {
+    unsigned int last = base;
+    for (unsigned int i = base + 1; i < end; i++)
+      if (is_consonant (info[i]))
+      {
+       for (unsigned int j = last + 1; j < i; j++)
+         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)
+        last = i;
   }
 
-  /* We do bubble-sort, skip malicious clusters attempts */
-  if (end - start < 64)
+
   {
+    /* Use syllable() for sort accounting temporarily. */
+    unsigned int syllable = info[start].syllable();
+    for (unsigned int i = start; i < end; i++)
+      info[i].syllable() = i - start;
+
     /* Sit tight, rock 'n roll! */
     hb_bubble_sort (info + start, end - start, compare_indic_order);
     /* Find base again */
     base = end;
     for (unsigned int i = start; i < end; i++)
-      if (info[i].indic_position() == POS_BASE_C) {
-        base = i;
+      if (info[i].indic_position() == POS_BASE_C)
+      {
+       base = i;
        break;
       }
+    /* 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
+     * order and merge as needed.
+     * For pre-base stuff, we handle cluster issues in final reordering. */
+    if (indic_plan->is_old_spec || end - base > 127)
+      buffer->merge_clusters (base, end);
+    else
+    {
+      /* Note!  syllable() is a one-byte field. */
+      for (unsigned int i = base; i < end; i++)
+        if (info[i].syllable() != 255)
+       {
+         unsigned int max = i;
+         unsigned int j = start + info[i].syllable();
+         while (j != i)
+         {
+           max = MAX (max, j);
+           unsigned int next = start + info[j].syllable();
+           info[j].syllable() = 255; /* So we don't process j later again. */
+           j = next;
+         }
+         if (i != max)
+           buffer->merge_clusters (i, max + 1);
+       }
+    }
+
+    /* Put syllable back in. */
+    for (unsigned int i = start; i < end; i++)
+      info[i].syllable() = syllable;
   }
 
   /* Setup masks now */
@@ -463,21 +1060,86 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
 
     /* Reph */
     for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
-      info[i].mask |= mask_array[RPHF];
+      info[i].mask |= indic_plan->mask_array[RPHF];
 
     /* Pre-base */
-    mask = mask_array[HALF] | mask_array[AKHN] | mask_array[CJCT];
+    mask = indic_plan->mask_array[HALF];
+    if (!indic_plan->is_old_spec &&
+       indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
+      mask |= indic_plan->mask_array[BLWF];
     for (unsigned int i = start; i < base; i++)
       info[i].mask  |= mask;
     /* Base */
-    mask = mask_array[AKHN] | mask_array[CJCT];
-    info[base].mask |= mask;
+    mask = 0;
+    if (base < end)
+      info[base].mask |= mask;
     /* Post-base */
-    mask = mask_array[BLWF] | mask_array[PSTF] | mask_array[CJCT];
+    mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
     for (unsigned int i = base + 1; i < end; i++)
       info[i].mask  |= mask;
   }
 
+  if (indic_plan->is_old_spec &&
+      buffer->props.script == HB_SCRIPT_DEVANAGARI)
+  {
+    /* Old-spec eye-lash Ra needs special handling.  From the
+     * spec:
+     *
+     * "The feature 'below-base form' is applied to consonants
+     * having below-base forms and following the base consonant.
+     * The exception is vattu, which may appear below half forms
+     * as well as below the base glyph. The feature 'below-base
+     * form' will be applied to all such occurrences of Ra as well."
+     *
+     * Test case: U+0924,U+094D,U+0930,U+094d,U+0915
+     * with Sanskrit 2003 font.
+     *
+     * However, note that Ra,Halant,ZWJ is the correct way to
+     * request eyelash form of Ra, so we wouldbn't inhibit it
+     * in that sequence.
+     *
+     * 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  &&
+         (i + 2 == base ||
+          info[i+2].indic_category() != OT_ZWJ))
+      {
+       info[i  ].mask |= indic_plan->mask_array[BLWF];
+       info[i+1].mask |= indic_plan->mask_array[BLWF];
+      }
+  }
+
+  unsigned int pref_len = indic_plan->config->pref_len;
+  if (indic_plan->mask_array[PREF] && base + pref_len < end)
+  {
+    assert (1 <= pref_len && pref_len <= 2);
+    /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
+    for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
+      hb_codepoint_t glyphs[2];
+      for (unsigned int j = 0; j < pref_len; j++)
+        glyphs[j] = info[i + j].codepoint;
+      if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
+      {
+       for (unsigned int j = 0; j < pref_len; j++)
+         info[i++].mask |= indic_plan->mask_array[PREF];
+
+       /* Mark the subsequent stuff with 'cfar'.  Used in Khmer.
+        * Read the feature spec.
+        * This allows distinguishing the following cases with MS Khmer fonts:
+        * U+1784,U+17D2,U+179A,U+17D2,U+1782
+        * U+1784,U+17D2,U+1782,U+17D2,U+179A
+        */
+       if (indic_plan->mask_array[CFAR])
+         for (; i < end; i++)
+           info[i].mask |= indic_plan->mask_array[CFAR];
+
+       break;
+      }
+    }
+  }
+
   /* Apply ZWJ/ZWNJ effects */
   for (unsigned int i = start + 1; i < end; i++)
     if (is_joiner (info[i])) {
@@ -487,9 +1149,13 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
       do {
        j--;
 
-       info[j].mask &= ~mask_array[CJCT];
+       /* ZWJ/ZWNJ should disable CJCT.  They do that by simply
+        * being there, since we don't skip them for the CJCT
+        * feature (ie. F_MANUAL_ZWJ) */
+
+       /* A ZWNJ disables HALF. */
        if (non_joiner)
-         info[j].mask &= ~mask_array[HALF];
+         info[j].mask &= ~indic_plan->mask_array[HALF];
 
       } while (j > start && !is_consonant (info[j]));
     }
@@ -497,25 +1163,25 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
 
 
 static void
-initial_reordering_vowel_syllable (const hb_ot_map_t *map,
+initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
+                                  hb_face_t *face,
                                   hb_buffer_t *buffer,
-                                  hb_mask_t *mask_array,
                                   unsigned int start, unsigned int end)
 {
   /* We made the vowels look like consonants.  So let's call the consonant logic! */
-  initial_reordering_consonant_syllable (map, buffer, mask_array, start, end);
+  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
 }
 
 static void
-initial_reordering_standalone_cluster (const hb_ot_map_t *map,
+initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
+                                      hb_face_t *face,
                                       hb_buffer_t *buffer,
-                                      hb_mask_t *mask_array,
                                       unsigned int start, unsigned int end)
 {
-  /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain.
-   * Only if not in compatibility mode that is... */
+  /* We treat placeholder/dotted-circle as if they are consonants, so we
+   * should just chain.  Only if not in compatibility mode that is... */
 
-  if (indic_options ().uniscribe_bug_compatible)
+  if (hb_options ().uniscribe_bug_compatible)
   {
     /* For dotted-circle, this is what Uniscribe does:
      * If dotted-circle is the last glyph, it just does nothing.
@@ -524,41 +1190,169 @@ initial_reordering_standalone_cluster (const hb_ot_map_t *map,
       return;
   }
 
-  initial_reordering_consonant_syllable (map, buffer, mask_array, start, end);
+  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
 }
 
 static void
-initial_reordering_non_indic (const hb_ot_map_t *map HB_UNUSED,
-                             hb_buffer_t *buffer HB_UNUSED,
-                             hb_mask_t *mask_array HB_UNUSED,
-                             unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+                                  hb_face_t *face,
+                                  hb_buffer_t *buffer,
+                                  unsigned int start, unsigned int end)
+{
+  /* We already inserted dotted-circles, so just call the standalone_cluster. */
+  initial_reordering_standalone_cluster (plan, face, buffer, start, end);
+}
+
+static void
+initial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                  hb_face_t *face HB_UNUSED,
+                                  hb_buffer_t *buffer HB_UNUSED,
+                                  unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+  /* Nothing to do right now.  If we ever switch to using the output
+   * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+static void
+initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                     hb_face_t *face HB_UNUSED,
+                                     hb_buffer_t *buffer HB_UNUSED,
+                                     unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
 {
   /* Nothing to do right now.  If we ever switch to using the output
    * buffer in the reordering process, we'd need to next_glyph() here. */
 }
 
-#include "hb-ot-shape-complex-indic-machine.hh"
 
 static void
-initial_reordering (const hb_ot_map_t *map,
-                   hb_face_t *face HB_UNUSED,
-                   hb_buffer_t *buffer,
-                   void *user_data HB_UNUSED)
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+                            hb_face_t *face,
+                            hb_buffer_t *buffer,
+                            unsigned int start, unsigned int end)
 {
-  hb_mask_t mask_array[ARRAY_LENGTH (indic_basic_features)] = {0};
-  unsigned int num_masks = ARRAY_LENGTH (indic_basic_features);
-  for (unsigned int i = 0; i < num_masks; i++)
-    mask_array[i] = map->get_1_mask (indic_basic_features[i].tag);
+  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  switch (syllable_type) {
+  case consonant_syllable:     initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+  case vowel_syllable:         initial_reordering_vowel_syllable     (plan, face, buffer, start, end); return;
+  case standalone_cluster:     initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
+  case symbol_cluster:         initial_reordering_symbol_cluster     (plan, face, buffer, start, end); return;
+  case broken_cluster:         initial_reordering_broken_cluster     (plan, face, buffer, start, end); return;
+  case non_indic_cluster:      initial_reordering_non_indic_cluster  (plan, face, buffer, start, end); return;
+  }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer)
+{
+  /* Note: This loop is extra overhead, but should not be measurable. */
+  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_cluster)
+    {
+      has_broken_syllables = true;
+      break;
+    }
+  if (likely (!has_broken_syllables))
+    return;
+
+
+  hb_codepoint_t dottedcircle_glyph;
+  if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  set_indic_properties (dottedcircle);
+  dottedcircle.codepoint = dottedcircle_glyph;
 
-  find_syllables (map, buffer, mask_array);
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t info = dottedcircle;
+      info.cluster = buffer->cur().cluster;
+      info.mask = buffer->cur().mask;
+      info.syllable() = buffer->cur().syllable();
+      /* TODO Set glyph_props? */
+
+      /* Insert dottedcircle after possible Repha. */
+      while (buffer->idx < buffer->len &&
+            last_syllable == buffer->cur().syllable() &&
+            buffer->cur().indic_category() == OT_Repha)
+        buffer->next_glyph ();
+
+      buffer->output_info (info);
+    }
+    else
+      buffer->next_glyph ();
+  }
+
+  buffer->swap_buffers ();
 }
 
 static void
-final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                   hb_font_t *font,
+                   hb_buffer_t *buffer)
+{
+  update_consonant_positions (plan, font, buffer);
+  insert_dotted_circles (plan, font, buffer);
+
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  if (unlikely (!count)) return;
+  unsigned int last = 0;
+  unsigned int last_syllable = info[0].syllable();
+  for (unsigned int i = 1; i < count; i++)
+    if (last_syllable != info[i].syllable()) {
+      initial_reordering_syllable (plan, font->face, buffer, last, i);
+      last = i;
+      last_syllable = info[last].syllable();
+    }
+  initial_reordering_syllable (plan, font->face, buffer, last, count);
+}
+
+static void
+final_reordering_syllable (const hb_ot_shape_plan_t *plan,
+                          hb_buffer_t *buffer,
                           unsigned int start, unsigned int end)
 {
+  const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
   hb_glyph_info_t *info = buffer->info;
 
+
+  /* This function relies heavily on halant glyphs.  Lots of ligation
+   * and possibly multiplication 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. */
+  if (indic_plan->virama_glyph)
+  {
+    unsigned int virama_glyph = indic_plan->virama_glyph;
+    for (unsigned int i = start; i < end; i++)
+      if (info[i].codepoint == virama_glyph &&
+         _hb_glyph_info_ligated (&info[i]) &&
+         _hb_glyph_info_multiplied (&info[i]))
+      {
+        /* This will make sure that this glyph passes is_halant_or_coeng() test. */
+       info[i].indic_category() = OT_H;
+       _hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
+      }
+  }
+
+
   /* 4. Final reordering:
    *
    * After the localized forms and basic shaping forms GSUB features have been
@@ -567,22 +1361,46 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
    * cluster.
    */
 
+  bool try_pref = !!indic_plan->mask_array[PREF];
+
   /* Find base again */
-  unsigned int base = end;
-  for (unsigned int i = start; i < end; i++)
-    if (info[i].indic_position() == POS_BASE_C) {
-      base = i;
+  unsigned int base;
+  for (base = start; base < end; base++)
+    if (info[base].indic_position() >= POS_BASE_C)
+    {
+      if (try_pref && base + 1 < end && indic_plan->config->pref_len == 2)
+      {
+       for (unsigned int i = base + 1; i < end; i++)
+         if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+         {
+           if (!(_hb_glyph_info_substituted (&info[i]) &&
+                 _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
+           {
+             /* Ok, this was a 'pref' candidate but didn't form any.
+              * Base is around here... */
+             base = i;
+             while (base < end && is_halant_or_coeng (info[base]))
+               base++;
+             info[base].indic_position() = POS_BASE_C;
+
+             try_pref = false;
+           }
+           break;
+         }
+      }
+
+      if (start < base && info[base].indic_position() > POS_BASE_C)
+        base--;
       break;
     }
+  if (base == end && start < base &&
+      is_one_of (info[base - 1], FLAG (OT_ZWJ)))
+    base--;
+  if (base < end)
+    while (start < base &&
+          is_one_of (info[base], (FLAG (OT_N) | HALANT_OR_COENG_FLAGS)))
+      base--;
 
-  if (base == start) {
-    /* There's no Reph, and no left Matra to reposition.  Just merge the cluster
-     * and go home. */
-    buffer->merge_clusters (start, end);
-    return;
-  }
-
-  unsigned int start_of_last_cluster = base;
 
   /*   o Reorder matras:
    *
@@ -594,29 +1412,55 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
    *     halant, position is moved after it.
    */
 
+  if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
   {
-    unsigned int new_matra_pos = base - 1;
-    while (new_matra_pos > start &&
-          !(FLAG (info[new_matra_pos].indic_category()) & (FLAG (OT_M) | FLAG (OT_H))))
-      new_matra_pos--;
-    /* If we found no Halant we are done.  Otherwise only proceed if the Halant does
-     * not belong to the Matra itself! */
-    if (info[new_matra_pos].indic_category() == OT_H &&
-       info[new_matra_pos].indic_position() != POS_PRE_M) {
-      /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
-      if (new_matra_pos + 1 < end && is_joiner (info[new_matra_pos + 1]))
-       new_matra_pos++;
+    /* If we lost track of base, alas, position before last thingy. */
+    unsigned int new_pos = base == end ? base - 2 : base - 1;
+
+    /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
+     * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
+     * We want to position matra after them.
+     */
+    if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
+    {
+      while (new_pos > start &&
+            !(is_one_of (info[new_pos], (FLAG (OT_M) | HALANT_OR_COENG_FLAGS))))
+       new_pos--;
+
+      /* If we found no Halant we are done.
+       * Otherwise only proceed if the Halant does
+       * not belong to the Matra itself! */
+      if (is_halant_or_coeng (info[new_pos]) &&
+         info[new_pos].indic_position() != POS_PRE_M)
+      {
+       /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
+       if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
+         new_pos++;
+      }
+      else
+        new_pos = start; /* No move. */
+    }
 
+    if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M)
+    {
       /* Now go see if there's actually any matras... */
-      for (unsigned int i = new_matra_pos; i > start; i--)
+      for (unsigned int i = new_pos; i > start; i--)
        if (info[i - 1].indic_position () == POS_PRE_M)
        {
-         unsigned int old_matra_pos = i - 1;
-         hb_glyph_info_t matra = info[old_matra_pos];
-         memmove (&info[old_matra_pos], &info[old_matra_pos + 1], (new_matra_pos - old_matra_pos) * sizeof (info[0]));
-         info[new_matra_pos] = matra;
-         start_of_last_cluster = MIN (new_matra_pos, start_of_last_cluster);
-         new_matra_pos--;
+         unsigned int old_pos = i - 1;
+         hb_glyph_info_t tmp = info[old_pos];
+         memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
+         info[new_pos] = tmp;
+         if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
+           base--;
+         buffer->merge_clusters (new_pos, MIN (end, base + 1));
+         new_pos--;
+       }
+    } else {
+      for (unsigned int i = start; i < base; i++)
+       if (info[i].indic_position () == POS_PRE_M) {
+         buffer->merge_clusters (i, MIN (end, base + 1));
+         break;
        }
     }
   }
@@ -631,56 +1475,29 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
    *     before post-base consonant forms, and after post-base consonant forms.
    */
 
-  /* If there's anything after the Ra that has the REPH pos, it ought to be halant.
-   * Which means that the font has failed to ligate the Reph.  In which case, we
-   * shouldn't move. */
+  /* Two cases:
+   *
+   * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then
+   *   we should only move it if the sequence ligated to the repha form.
+   *
+   * - If repha is encoded separately and in the logical position, we should only
+   *   move it if it did NOT ligate.  If it ligated, it's probably the font trying
+   *   to make it work without the reordering.
+   */
   if (start + 1 < end &&
       info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
-      info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH)
+      ((info[start].indic_category() == OT_Repha) ^
+       _hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
   {
-      unsigned int new_reph_pos;
-
-     enum reph_position_t {
-       REPH_AFTER_MAIN,
-       REPH_BEFORE_SUBSCRIPT,
-       REPH_AFTER_SUBSCRIPT,
-       REPH_BEFORE_POSTSCRIPT,
-       REPH_AFTER_POSTSCRIPT
-     } reph_pos;
-
-     /* XXX Figure out old behavior too */
-     switch ((hb_tag_t) buffer->props.script)
-     {
-       case HB_SCRIPT_MALAYALAM:
-       case HB_SCRIPT_ORIYA:
-        reph_pos = REPH_AFTER_MAIN;
-        break;
-
-       case HB_SCRIPT_GURMUKHI:
-        reph_pos = REPH_BEFORE_SUBSCRIPT;
-        break;
-
-       case HB_SCRIPT_BENGALI:
-        reph_pos = REPH_AFTER_SUBSCRIPT;
-        break;
-
-       default:
-       case HB_SCRIPT_DEVANAGARI:
-       case HB_SCRIPT_GUJARATI:
-        reph_pos = REPH_BEFORE_POSTSCRIPT;
-        break;
-
-       case HB_SCRIPT_KANNADA:
-       case HB_SCRIPT_TAMIL:
-       case HB_SCRIPT_TELUGU:
-        reph_pos = REPH_AFTER_POSTSCRIPT;
-        break;
-     }
+    unsigned int new_reph_pos;
+    reph_position_t reph_pos = indic_plan->config->reph_pos;
+
+    assert (reph_pos != REPH_POS_DONT_CARE);
 
     /*       1. If reph should be positioned after post-base consonant forms,
      *          proceed to step 5.
      */
-    if (reph_pos == REPH_AFTER_POSTSCRIPT)
+    if (reph_pos == REPH_POS_AFTER_POST)
     {
       goto reph_step_5;
     }
@@ -698,10 +1515,11 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
      */
     {
       new_reph_pos = start + 1;
-      while (new_reph_pos < base && info[new_reph_pos].indic_category() != OT_H)
+      while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
        new_reph_pos++;
 
-      if (new_reph_pos < base && info[new_reph_pos].indic_category() == OT_H) {
+      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+      {
        /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
        if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
          new_reph_pos++;
@@ -713,9 +1531,13 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
      *          first consonant not ligated with main, or find the first
      *          consonant that is not a potential pre-base reordering Ra.
      */
-    if (reph_pos == REPH_AFTER_MAIN)
+    if (reph_pos == REPH_POS_AFTER_MAIN)
     {
-      /* XXX */
+      new_reph_pos = base;
+      while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
+       new_reph_pos++;
+      if (new_reph_pos < end)
+        goto reph_move;
     }
 
     /*       4. If reph should be positioned before post-base consonant, find
@@ -724,11 +1546,11 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
      *          first matra, syllable modifier sign or vedic sign.
      */
     /* This is our take on what step 4 is trying to say (and failing, BADLY). */
-    if (reph_pos == REPH_AFTER_SUBSCRIPT)
+    if (reph_pos == REPH_POS_AFTER_SUB)
     {
       new_reph_pos = base;
       while (new_reph_pos < end &&
-            !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_POST_M) | FLAG (POS_SMVD))))
+            !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
        new_reph_pos++;
       if (new_reph_pos < end)
         goto reph_move;
@@ -743,7 +1565,18 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
      */
     reph_step_5:
     {
-      /* XXX */
+      /* Copied from step 2. */
+      new_reph_pos = start + 1;
+      while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
+       new_reph_pos++;
+
+      if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+      {
+       /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
+       if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
+         new_reph_pos++;
+       goto reph_move;
+      }
     }
 
     /*       6. Otherwise, reorder reph to the end of the syllable.
@@ -760,8 +1593,8 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
        * Uniscribe doesn't do this.
        * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
        */
-      if (!indic_options ().uniscribe_bug_compatible &&
-         unlikely (info[new_reph_pos].indic_category() == OT_H)) {
+      if (!hb_options ().uniscribe_bug_compatible &&
+         unlikely (is_halant_or_coeng (info[new_reph_pos]))) {
        for (unsigned int i = base + 1; i < new_reph_pos; i++)
          if (info[i].indic_category() == OT_M) {
            /* Ok, got it. */
@@ -773,11 +1606,14 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
 
     reph_move:
     {
+      buffer->merge_clusters (start, new_reph_pos + 1);
+
       /* Move */
       hb_glyph_info_t reph = info[start];
       memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
       info[new_reph_pos] = reph;
-      start_of_last_cluster = start; /* Yay, one big cluster! */
+      if (start < base && base <= new_reph_pos)
+       base--;
     }
   }
 
@@ -786,88 +1622,263 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
    *
    *     If a pre-base reordering consonant is found, reorder it according to
    *     the following rules:
-   *
-   *       1. Only reorder a glyph produced by substitution during application
-   *          of the feature. (Note that a font may shape a Ra consonant with
-   *          the feature generally but block it in certain contexts.)
-   *
-   *       2. Try to find a target position the same way as for pre-base matra.
-   *          If it is found, reorder pre-base consonant glyph.
-   *
-   *       3. If position is not found, reorder immediately before main
-   *          consonant.
    */
 
-  /* TODO */
+  if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
+  {
+    unsigned int pref_len = indic_plan->config->pref_len;
+    for (unsigned int i = base + 1; i < end; i++)
+      if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+      {
+       /*       1. Only reorder a glyph produced by substitution during application
+        *          of the <pref> feature. (Note that a font may shape a Ra consonant with
+        *          the feature generally but block it in certain contexts.)
+        */
+        /* Note: We just check that something got substituted.  We don't check that
+        * the <pref> feature actually did it...
+        *
+        * If pref len is longer than one, then only reorder if it ligated.  If
+        * pref len is one, only reorder if it didn't ligate with other things. */
+       if (_hb_glyph_info_substituted (&info[i]) &&
+           ((pref_len == 1) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
+       {
+         /*
+          *       2. Try to find a target position the same way as for pre-base matra.
+          *          If it is found, reorder pre-base consonant glyph.
+          *
+          *       3. If position is not found, reorder immediately before main
+          *          consonant.
+          */
+
+         unsigned int new_pos = base;
+         /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
+          * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
+          * We want to position matra after them.
+          */
+         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) | HALANT_OR_COENG_FLAGS)))
+             new_pos--;
+
+           /* In Khmer coeng model, a H,Ra can go *after* matras.  If it goes after a
+            * split matra, it should be reordered to *before* the left part of such matra. */
+           if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
+           {
+             unsigned int old_pos = i;
+             for (unsigned int i = base + 1; i < old_pos; i++)
+               if (info[i].indic_category() == OT_M)
+               {
+                 new_pos--;
+                 break;
+               }
+           }
+         }
 
+         if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
+         {
+           /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
+           if (new_pos < end && is_joiner (info[new_pos]))
+             new_pos++;
+         }
+
+         {
+           unsigned int old_pos = i;
+           buffer->merge_clusters (new_pos, old_pos + 1);
+           hb_glyph_info_t tmp = info[old_pos];
+           memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
+           info[new_pos] = tmp;
+           if (new_pos <= base && base < old_pos)
+             base++;
+         }
+       }
+
+        break;
+      }
+  }
 
 
   /* Apply 'init' to the Left Matra if it's a word start. */
   if (info[start].indic_position () == POS_PRE_M &&
       (!start ||
        !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) &
-        (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |
-         FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) |
-         FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
-         FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |
-         FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |
-         FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
-         FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
-         FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))))
-    info[start].mask |= mask_array[INIT];
-
-
+        FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
+    info[start].mask |= indic_plan->mask_array[INIT];
 
-  /* Finish off the clusters and go home! */
 
-  if (!indic_options ().uniscribe_bug_compatible)
+  /*
+   * Finish off the clusters and go home!
+   */
+  if (hb_options ().uniscribe_bug_compatible)
   {
-    /* This is what Uniscribe does.  Ie. add cluster boundaries after Halant,ZWNJ.
-     * This means, half forms are submerged into the main consonants cluster.
-     * This is unnecessary, and makes cursor positioning harder, but that's what
-     * Uniscribe does. */
-    unsigned int cluster_start = start;
-    for (unsigned int i = start + 1; i < start_of_last_cluster; i++)
-      if (info[i - 1].indic_category() == OT_H && info[i].indic_category() == OT_ZWNJ) {
-        i++;
-       buffer->merge_clusters (cluster_start, i);
-       cluster_start = i;
-      }
-    start_of_last_cluster = cluster_start;
-  }
+    switch ((hb_tag_t) plan->props.script)
+    {
+      case HB_SCRIPT_TAMIL:
+      case HB_SCRIPT_SINHALA:
+        break;
 
-  buffer->merge_clusters (start_of_last_cluster, end);
+      default:
+       /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
+        * This means, half forms are submerged into the main consonants cluster.
+        * This is unnecessary, and makes cursor positioning harder, but that's what
+        * Uniscribe does. */
+       buffer->merge_clusters (start, end);
+       break;
+    }
+  }
 }
 
 
 static void
-final_reordering (const hb_ot_map_t *map,
-                 hb_face_t *face HB_UNUSED,
-                 hb_buffer_t *buffer,
-                 void *user_data HB_UNUSED)
+final_reordering (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
-  if (!count) return;
-
-  hb_mask_t mask_array[ARRAY_LENGTH (indic_other_features)] = {0};
-  unsigned int num_masks = ARRAY_LENGTH (indic_other_features);
-  for (unsigned int i = 0; i < num_masks; i++)
-    mask_array[i] = map->get_1_mask (indic_other_features[i].tag);
+  if (unlikely (!count)) return;
 
   hb_glyph_info_t *info = buffer->info;
   unsigned int last = 0;
   unsigned int last_syllable = info[0].syllable();
   for (unsigned int i = 1; i < count; i++)
     if (last_syllable != info[i].syllable()) {
-      final_reordering_syllable (buffer, mask_array, last, i);
+      final_reordering_syllable (plan, buffer, last, i);
       last = i;
       last_syllable = info[last].syllable();
     }
-  final_reordering_syllable (buffer, mask_array, last, count);
+  final_reordering_syllable (plan, buffer, last, count);
 
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
 }
 
 
+static void
+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;
+}
+
+
+static bool
+decompose_indic (const hb_ot_shape_normalize_context_t *c,
+                hb_codepoint_t  ab,
+                hb_codepoint_t *a,
+                hb_codepoint_t *b)
+{
+  switch (ab)
+  {
+    /* Don't decompose these. */
+    case 0x0931u  : return false;
+    case 0x0B94u  : return false;
+
 
+    /*
+     * Decompose split matras that don't have Unicode decompositions.
+     */
+
+    case 0x0F77u  : *a = 0x0FB2u; *b= 0x0F81u; return true;
+    case 0x0F79u  : *a = 0x0FB3u; *b= 0x0F81u; return true;
+    case 0x17BEu  : *a = 0x17C1u; *b= 0x17BEu; return true;
+    case 0x17BFu  : *a = 0x17C1u; *b= 0x17BFu; return true;
+    case 0x17C0u  : *a = 0x17C1u; *b= 0x17C0u; return true;
+    case 0x17C4u  : *a = 0x17C1u; *b= 0x17C4u; return true;
+    case 0x17C5u  : *a = 0x17C1u; *b= 0x17C5u; return true;
+    case 0x1925u  : *a = 0x1920u; *b= 0x1923u; return true;
+    case 0x1926u  : *a = 0x1920u; *b= 0x1924u; return true;
+    case 0x1B3Cu  : *a = 0x1B42u; *b= 0x1B3Cu; return true;
+    case 0x1112Eu  : *a = 0x11127u; *b= 0x11131u; return true;
+    case 0x1112Fu  : *a = 0x11127u; *b= 0x11132u; return true;
+#if 0
+    /* This one has no decomposition in Unicode, but needs no decomposition either. */
+    /* case 0x0AC9u  : return false; */
+    case 0x0B57u  : *a = no decomp, -> RIGHT; return true;
+    case 0x1C29u  : *a = no decomp, -> LEFT; return true;
+    case 0xA9C0u  : *a = no decomp, -> RIGHT; return true;
+    case 0x111BuF  : *a = no decomp, -> ABOVE; return true;
+#endif
+  }
+
+  if ((ab == 0x0DDAu || hb_in_range (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:
+     *
+     *   http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping
+     */
+
+    const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
+
+    hb_codepoint_t glyph;
+
+    if (hb_options ().uniscribe_bug_compatible ||
+       (c->font->get_glyph (ab, 0, &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 c->unicode->decompose (ab, a, b);
+}
+
+static bool
+compose_indic (const hb_ot_shape_normalize_context_t *c,
+              hb_codepoint_t  a,
+              hb_codepoint_t  b,
+              hb_codepoint_t *ab)
+{
+  /* Avoid recomposing split matras. */
+  if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+    return false;
+
+  /* Composition-exclusion exceptions that we want to recompose. */
+  if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
+
+  return c->unicode->compose (a, b, ab);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
+{
+  "indic",
+  collect_features_indic,
+  override_features_indic,
+  data_create_indic,
+  data_destroy_indic,
+  NULL, /* preprocess_text */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+  decompose_indic,
+  compose_indic,
+  setup_masks_indic,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-misc.cc b/src/hb-ot-shape-complex-misc.cc
deleted file mode 100644 (file)
index d93d4c6..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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
- */
-
-#include "hb-ot-shape-complex-private.hh"
-
-
-/* TODO Add kana, and other small shapers here */
-
-/* When adding trivial shapers, eg. kana, hangul, etc, we can either
- * add a full shaper enum value for them, or switch on the script in
- * the default complex shaper.  The former is faster, so I think that's
- * what we would do, and hence the default complex shaper shall remain
- * empty.
- */
-
-void
-_hb_ot_shape_complex_collect_features_default (hb_ot_map_builder_t *map HB_UNUSED,
-                                              const hb_segment_properties_t *props HB_UNUSED)
-{
-}
-
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_default (void)
-{
-  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
-}
-
-void
-_hb_ot_shape_complex_setup_masks_default (hb_ot_map_t *map HB_UNUSED,
-                                         hb_buffer_t *buffer HB_UNUSED,
-                                         hb_font_t *font HB_UNUSED)
-{
-}
-
-
-
-/* Hangul shaper */
-
-static const hb_tag_t hangul_features[] =
-{
-  HB_TAG('l','j','m','o'),
-  HB_TAG('v','j','m','o'),
-  HB_TAG('t','j','m','o'),
-};
-
-void
-_hb_ot_shape_complex_collect_features_hangul (hb_ot_map_builder_t *map,
-                                             const hb_segment_properties_t *props HB_UNUSED)
-{
-  for (unsigned int i = 0; i < ARRAY_LENGTH (hangul_features); i++)
-    map->add_bool_feature (hangul_features[i]);
-}
-
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_hangul (void)
-{
-  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
-}
-
-void
-_hb_ot_shape_complex_setup_masks_hangul (hb_ot_map_t *map HB_UNUSED,
-                                        hb_buffer_t *buffer HB_UNUSED,
-                                        hb_font_t *font HB_UNUSED)
-{
-}
-
-
-
-/* Thai / Lao shaper */
-
-void
-_hb_ot_shape_complex_collect_features_thai (hb_ot_map_builder_t *map HB_UNUSED,
-                                           const hb_segment_properties_t *props HB_UNUSED)
-{
-}
-
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_thai (void)
-{
-  return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
-}
-
-void
-_hb_ot_shape_complex_setup_masks_thai (hb_ot_map_t *map HB_UNUSED,
-                                      hb_buffer_t *buffer,
-                                      hb_font_t *font HB_UNUSED)
-{
-  /* The following is NOT specified in the MS OT Thai spec, however, it seems
-   * to be what Uniscribe and other engines implement.  According to Eric Muller:
-   *
-   * When you have a sara am, decompose it in nikhahit + sara a, *and* mode the
-   * nihka hit backwards over any *tone* mark (0E48-0E4B).
-   *
-   * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
-   *
-   * This reordering is legit only when the nikhahit comes from a sara am, not
-   * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
-   * not what a u↪ser wanted, but the rendering is nevertheless nikhahit above
-   * chattawa.
-   *
-   * Same for Lao.
-   */
-
-  /*
-   * Here are the characters of significance:
-   *
-   *                   Thai    Lao
-   * SARA AM:          U+0E33  U+0EB3
-   * SARA AA:          U+0E32  U+0EB2
-   * Nikhahit:         U+0E4D  U+0ECD
-   *
-   * Tone marks:
-   * Thai:     <0E48..0E4B> CCC=107
-   * Lao:      <0EC8..0ECB> CCC=122
-   *
-   * Note how the Lao versions are the same as Thai + 0x80.
-   */
-
-  /* We only get one script at a time, so a script-agnostic implementation
-   * is adequate here. */
-#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
-#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
-#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
-#define IS_TONE_MARK(x) (((x) & ~0x0083) == 0x0E48)
-
-  buffer->clear_output ();
-  unsigned int count = buffer->len;
-  for (buffer->idx = 0; buffer->idx < count;)
-  {
-    hb_codepoint_t u = buffer->cur().codepoint;
-    if (likely (!IS_SARA_AM (u))) {
-      buffer->next_glyph ();
-      continue;
-    }
-
-    /* Is SARA AM. Decompose and reorder. */
-    hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
-                                   hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
-    buffer->replace_glyphs (1, 2, decomposed);
-    if (unlikely (buffer->in_error))
-      return;
-
-    /* Ok, let's see... */
-    unsigned int end = buffer->out_len;
-    unsigned int start = end - 2;
-    while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
-      start--;
-
-    /* Move Nikhahit (end-2) to the beginning */
-    hb_glyph_info_t t = buffer->out_info[end - 2];
-    memmove (buffer->out_info + start + 1,
-            buffer->out_info + start,
-            sizeof (buffer->out_info[0]) * (end - start - 2));
-    buffer->out_info[start] = t;
-
-    /* XXX Make this easier! */
-    /* Make cluster */
-    for (; start > 0 && buffer->out_info[start - 1].cluster == buffer->out_info[start].cluster; start--)
-      ;
-    for (; buffer->idx < count;)
-      if (buffer->cur().cluster == buffer->prev().cluster)
-        buffer->next_glyph ();
-      else
-        break;
-    end = buffer->out_len;
-
-    buffer->merge_out_clusters (start, end);
-  }
-  buffer->swap_buffers ();
-}
diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl
new file mode 100644 (file)
index 0000000..9649a91
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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-private.hh"
+
+%%{
+  machine myanmar_syllable_machine;
+  alphtype unsigned char;
+  write data;
+}%%
+
+%%{
+
+# Same order as enum myanmar_category_t.  Not sure how to avoid duplication.
+A    = 10;
+As   = 18;
+C    = 1;
+D    = 19;
+D0   = 20;
+DB   = 3;
+GB   = 11;
+H    = 4;
+IV   = 2;
+MH   = 21;
+MR   = 22;
+MW   = 23;
+MY   = 24;
+PT   = 25;
+V    = 8;
+VAbv = 26;
+VBlw = 27;
+VPre = 28;
+VPst = 29;
+VS   = 30;
+ZWJ  = 6;
+ZWNJ = 5;
+Ra   = 16;
+P    = 31;
+
+j = ZWJ|ZWNJ;                  # Joiners
+k = (Ra As H);                 # Kinzi
+
+c = C|Ra;                      # is_consonant
+
+medial_group = MY? MR? MW? MH? As?;
+main_vowel_group = VPre* VAbv* VBlw* A* (DB As?)?;
+post_vowel_group = VPst MH? 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?;
+syllable_tail = (H | complex_syllable_tail);
+
+consonant_syllable =   k? (c|IV|D|GB).VS? (H (c|IV).VS?)* syllable_tail;
+punctuation_cluster =  P V;
+broken_cluster =       k? VS? syllable_tail;
+other =                        any;
+
+main := |*
+       consonant_syllable      => { found_syllable (consonant_syllable); };
+       j                       => { found_syllable (non_myanmar_cluster); };
+       punctuation_cluster     => { found_syllable (punctuation_cluster); };
+       broken_cluster          => { found_syllable (broken_cluster); };
+       other                   => { found_syllable (non_myanmar_cluster); };
+*|;
+
+
+}%%
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+    for (unsigned int i = last; i < p+1; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    last = p+1; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  %%{
+    write init;
+    getkey info[p].myanmar_category();
+  }%%
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int last = 0;
+  unsigned int syllable_serial = 1;
+  %%{
+    write exec;
+  }%%
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
new file mode 100644 (file)
index 0000000..d016380
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-complex-indic-private.hh"
+
+/* buffer var allocations */
+#define myanmar_category() complex_var_u8_0() /* myanmar_category_t */
+#define myanmar_position() complex_var_u8_1() /* myanmar_position_t */
+
+
+/*
+ * Myanmar shaper.
+ */
+
+static const hb_tag_t
+basic_features[] =
+{
+  /*
+   * Basic features.
+   * These features are applied in order, one at a time, after initial_reordering.
+   */
+  HB_TAG('r','p','h','f'),
+  HB_TAG('p','r','e','f'),
+  HB_TAG('b','l','w','f'),
+  HB_TAG('p','s','t','f'),
+};
+static const hb_tag_t
+other_features[] =
+{
+  /*
+   * Other features.
+   * These features are applied all at once, after final_reordering.
+   */
+  HB_TAG('p','r','e','s'),
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('p','s','t','s'),
+  /* Positioning features, though we don't care about the types. */
+  HB_TAG('d','i','s','t'),
+  /* Pre-release version of Windows 8 Myanmar font had abvm,blwm
+   * features.  The released Windows 8 version of the font (as well
+   * as the released spec) used 'mark' instead.  The Windows 8
+   * shaper however didn't apply 'mark' but did apply 'mkmk'.
+   * Perhaps it applied abvm/blwm.  This was fixed in a Windows 8
+   * update, so now it applies mark/mkmk.  We are guessing that
+   * it still applies abvm/blwm too.
+   */
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+                hb_font_t *font,
+                hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                   hb_font_t *font,
+                   hb_buffer_t *buffer);
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer);
+
+static void
+collect_features_myanmar (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* Do this before any lookups have been applied. */
+  map->add_gsub_pause (setup_syllables);
+
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+  /* 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->add_global_bool_feature (HB_TAG('c','c','m','p'));
+
+
+  map->add_gsub_pause (initial_reordering);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+  {
+    map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+    map->add_gsub_pause (NULL);
+  }
+  map->add_gsub_pause (final_reordering);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+    map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+}
+
+static void
+override_features_myanmar (hb_ot_shape_planner_t *plan)
+{
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+}
+
+
+enum syllable_type_t {
+  consonant_syllable,
+  punctuation_cluster,
+  broken_cluster,
+  non_myanmar_cluster,
+};
+
+#include "hb-ot-shape-complex-myanmar-machine.hh"
+
+
+/* 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_D   = 19, /* Digits except zero */
+  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 */
+};
+
+
+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 (info.myanmar_category()) & flags);
+}
+
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
+{
+  return is_one_of (info, CONSONANT_FLAGS);
+}
+
+
+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);
+  indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+  indic_position_t pos = (indic_position_t) (type >> 8);
+
+  /* Myanmar
+   * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
+   */
+  if (unlikely (hb_in_range (u, 0xFE00u, 0xFE0Fu)))
+    cat = (indic_category_t) OT_VS;
+
+  switch (u)
+  {
+    case 0x104Eu:
+      cat = (indic_category_t) 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 = (indic_category_t) OT_GB;
+      break;
+
+    case 0x1004u: case 0x101Bu: case 0x105Au:
+      cat = (indic_category_t) OT_Ra;
+      break;
+
+    case 0x1032u: case 0x1036u:
+      cat = (indic_category_t) OT_A;
+      break;
+
+    case 0x103Au:
+      cat = (indic_category_t) 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 = (indic_category_t) OT_D;
+      break;
+
+    case 0x1040u:
+      cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
+      break;
+
+    case 0x103Eu: case 0x1060u:
+      cat = (indic_category_t) OT_MH;
+      break;
+
+    case 0x103Cu:
+      cat = (indic_category_t) OT_MR;
+      break;
+
+    case 0x103Du: case 0x1082u:
+      cat = (indic_category_t) OT_MW;
+      break;
+
+    case 0x103Bu: case 0x105Eu: case 0x105Fu:
+      cat = (indic_category_t) OT_MY;
+      break;
+
+    case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au:
+    case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu:
+      cat = (indic_category_t) 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 = (indic_category_t) OT_SM;
+      break;
+
+    case 0x104Au: case 0x104Bu:
+      cat = (indic_category_t) OT_P;
+      break;
+  }
+
+  if (cat == OT_M)
+  {
+    switch ((int) pos)
+    {
+      case POS_PRE_C:  cat = (indic_category_t) OT_VPre;
+                       pos = POS_PRE_M;                  break;
+      case POS_ABOVE_C:        cat = (indic_category_t) OT_VAbv; break;
+      case POS_BELOW_C:        cat = (indic_category_t) OT_VBlw; break;
+      case POS_POST_C: cat = (indic_category_t) OT_VPst; break;
+    }
+  }
+
+  info.myanmar_category() = (myanmar_category_t) cat;
+  info.myanmar_position() = pos;
+}
+
+
+
+static void
+setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                  hb_buffer_t              *buffer,
+                  hb_font_t                *font 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. */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    set_myanmar_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                hb_font_t *font HB_UNUSED,
+                hb_buffer_t *buffer)
+{
+  find_syllables (buffer);
+}
+
+static int
+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;
+}
+
+
+/* Rules from:
+ * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm */
+
+static void
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+                                      hb_face_t *face,
+                                      hb_buffer_t *buffer,
+                                      unsigned int start, unsigned int end)
+{
+  hb_glyph_info_t *info = buffer->info;
+
+  unsigned int base = end;
+  bool has_reph = false;
+
+  {
+    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)
+    {
+      limit += 3;
+      base = start;
+      has_reph = true;
+    }
+
+    {
+      if (!has_reph)
+       base = limit;
+
+      for (unsigned int i = limit; i < end; i++)
+       if (is_consonant (info[i]))
+       {
+         base = i;
+         break;
+       }
+    }
+  }
+
+  /* Reorder! */
+  {
+    unsigned int i = start;
+    for (; i < start + (has_reph ? 3 : 0); i++)
+      info[i].myanmar_position() = POS_AFTER_MAIN;
+    for (; i < base; i++)
+      info[i].myanmar_position() = POS_PRE_C;
+    if (i < end)
+    {
+      info[i].myanmar_position() = POS_BASE_C;
+      i++;
+    }
+    indic_position_t pos = POS_AFTER_MAIN;
+    /* The following loop may be ugly, but it implements all of
+     * Myanmar reordering! */
+    for (; i < end; i++)
+    {
+      if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */
+      {
+       info[i].myanmar_position() = POS_PRE_C;
+       continue;
+      }
+      if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */
+      {
+       continue;
+      }
+
+      if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw)
+      {
+       pos = POS_BELOW_C;
+       info[i].myanmar_position() = pos;
+       continue;
+      }
+
+      if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A)
+      {
+       info[i].myanmar_position() = POS_BEFORE_SUB;
+       continue;
+      }
+      if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw)
+      {
+       info[i].myanmar_position() = pos;
+       continue;
+      }
+      if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
+      {
+        pos = POS_AFTER_SUB;
+       info[i].myanmar_position() = pos;
+       continue;
+      }
+      info[i].myanmar_position() = pos;
+    }
+  }
+
+  buffer->merge_clusters (start, end);
+  /* Sit tight, rock 'n roll! */
+  hb_bubble_sort (info + start, end - start, compare_myanmar_order);
+}
+
+static void
+initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+                                  hb_face_t *face,
+                                  hb_buffer_t *buffer,
+                                  unsigned int start, unsigned int end)
+{
+  /* We already inserted dotted-circles, so just call the consonant_syllable. */
+  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+}
+
+static void
+initial_reordering_punctuation_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                       hb_face_t *face HB_UNUSED,
+                                       hb_buffer_t *buffer HB_UNUSED,
+                                       unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+  /* Nothing to do right now.  If we ever switch to using the output
+   * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+static void
+initial_reordering_non_myanmar_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                       hb_face_t *face HB_UNUSED,
+                                       hb_buffer_t *buffer HB_UNUSED,
+                                       unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+  /* Nothing to do right now.  If we ever switch to using the output
+   * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+
+static void
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+                            hb_face_t *face,
+                            hb_buffer_t *buffer,
+                            unsigned int start, unsigned int end)
+{
+  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  switch (syllable_type) {
+  case consonant_syllable:     initial_reordering_consonant_syllable  (plan, face, buffer, start, end); return;
+  case punctuation_cluster:    initial_reordering_punctuation_cluster (plan, face, buffer, start, end); return;
+  case broken_cluster:         initial_reordering_broken_cluster      (plan, face, buffer, start, end); return;
+  case non_myanmar_cluster:    initial_reordering_non_myanmar_cluster (plan, face, buffer, start, end); return;
+  }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer)
+{
+  /* Note: This loop is extra overhead, but should not be measurable. */
+  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_cluster)
+    {
+      has_broken_syllables = true;
+      break;
+    }
+  if (likely (!has_broken_syllables))
+    return;
+
+
+  hb_codepoint_t dottedcircle_glyph;
+  if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  set_myanmar_properties (dottedcircle);
+  dottedcircle.codepoint = dottedcircle_glyph;
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t info = dottedcircle;
+      info.cluster = buffer->cur().cluster;
+      info.mask = buffer->cur().mask;
+      info.syllable() = buffer->cur().syllable();
+
+      buffer->output_info (info);
+    }
+    else
+      buffer->next_glyph ();
+  }
+
+  buffer->swap_buffers ();
+}
+
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                   hb_font_t *font,
+                   hb_buffer_t *buffer)
+{
+  insert_dotted_circles (plan, font, buffer);
+
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  if (unlikely (!count)) return;
+  unsigned int last = 0;
+  unsigned int last_syllable = info[0].syllable();
+  for (unsigned int i = 1; i < count; i++)
+    if (last_syllable != info[i].syllable()) {
+      initial_reordering_syllable (plan, font->face, buffer, last, i);
+      last = i;
+      last_syllable = info[last].syllable();
+    }
+  initial_reordering_syllable (plan, font->face, buffer, last, count);
+}
+
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+
+  /* Zero syllables now... */
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
+}
+
+
+/* Uniscribe seems to have a shaper for 'mymr' that is like the
+ * generic shaper, except that it zeros mark advances GDEF_LATE. */
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
+{
+  "default",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+  true, /* fallback_position */
+};
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
+{
+  "myanmar",
+  collect_features_myanmar,
+  override_features_myanmar,
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  setup_masks_myanmar,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+  false, /* fallback_position */
+};
index e0d93a6..e268933 100644 (file)
 
 #include "hb-private.hh"
 
-#include "hb-ot-map-private.hh"
+#include "hb-ot-shape-private.hh"
 #include "hb-ot-shape-normalize-private.hh"
 
 
 
-/* buffer var allocations, used during the entire shaping process */
-#define unicode_props0()       var1.u8[0]
-#define unicode_props1()       var1.u8[1]
+/* buffer var allocations, used by complex shapers */
+#define complex_var_u8_0()     var2.u8[2]
+#define complex_var_u8_1()     var2.u8[3]
 
-/* buffer var allocations, used during the GSUB/GPOS processing */
-#define props_cache()          var1.u16[1] /* GSUB/GPOS glyph_props cache */
-#define syllable()             var2.u8[0] /* GSUB/GPOS shaping boundaries */
-#define lig_props()            var2.u8[1] /* GSUB/GPOS ligature tracking */
 
-/* buffer var allocations, used by complex shapers */
-#define complex_var_persistent_u8_0()  var2.u8[2]
-#define complex_var_persistent_u8_1()  var2.u8[3]
-#define complex_var_temporary_u8()     var2.u8[0]
+enum hb_ot_shape_zero_width_marks_type_t {
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+//  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
+};
 
 
+/* Master OT shaper list */
 #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
   HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
   HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
   HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
   HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
   HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
+  HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
   /* ^--- Add new shapers here */
 
-enum hb_ot_complex_shaper_t {
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) hb_ot_complex_shaper_##name,
-  HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-  /* Just here to avoid enum trailing comma: */
-  hb_ot_complex_shaper_generic = hb_ot_complex_shaper_default
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+
+struct hb_ot_complex_shaper_t
+{
+  char name[8];
+
+  /* collect_features()
+   * Called during shape_plan().
+   * Shapers should use plan->map to add their features and callbacks.
+   * May be NULL.
+   */
+  void (*collect_features) (hb_ot_shape_planner_t *plan);
+
+  /* override_features()
+   * Called during shape_plan().
+   * Shapers should use plan->map to override features and add callbacks after
+   * common features are added.
+   * May be NULL.
+   */
+  void (*override_features) (hb_ot_shape_planner_t *plan);
+
+
+  /* data_create()
+   * Called at the end of shape_plan().
+   * Whatever shapers return will be accessible through plan->data later.
+   * If NULL is returned, means a plan failure.
+   */
+  void *(*data_create) (const hb_ot_shape_plan_t *plan);
+
+  /* data_destroy()
+   * Called when the shape_plan is being destroyed.
+   * plan->data is passed here for destruction.
+   * If NULL is returned, means a plan failure.
+   * May be NULL.
+   */
+  void (*data_destroy) (void *data);
+
+
+  /* preprocess_text()
+   * Called during shape().
+   * Shapers can use to modify text before shaping starts.
+   * May be NULL.
+   */
+  void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
+                          hb_buffer_t              *buffer,
+                          hb_font_t                *font);
+
+
+  hb_ot_shape_normalization_mode_t normalization_preference;
+
+  /* decompose()
+   * Called during shape()'s normalization.
+   * May be NULL.
+   */
+  bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+                    hb_codepoint_t  ab,
+                    hb_codepoint_t *a,
+                    hb_codepoint_t *b);
+
+  /* compose()
+   * Called during shape()'s normalization.
+   * May be NULL.
+   */
+  bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+                  hb_codepoint_t  a,
+                  hb_codepoint_t  b,
+                  hb_codepoint_t *ab);
+
+  /* setup_masks()
+   * Called during shape().
+   * Shapers should use map to get feature masks and set on buffer.
+   * Shapers may NOT modify characters.
+   * May be NULL.
+   */
+  void (*setup_masks) (const hb_ot_shape_plan_t *plan,
+                      hb_buffer_t              *buffer,
+                      hb_font_t                *font);
+
+  hb_ot_shape_zero_width_marks_type_t zero_width_marks;
+
+  bool fallback_position;
 };
 
-static inline hb_ot_complex_shaper_t
-hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
+#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
+
+
+static inline const hb_ot_complex_shaper_t *
+hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
 {
-  switch ((hb_tag_t) props->script)
+  switch ((hb_tag_t) planner->props.script)
   {
     default:
-      return hb_ot_complex_shaper_default;
+      return &_hb_ot_complex_shaper_default;
 
 
     /* Unicode-1.1 additions */
     case HB_SCRIPT_ARABIC:
+
+    /* Unicode-3.0 additions */
     case HB_SCRIPT_MONGOLIAN:
     case HB_SCRIPT_SYRIAC:
 
     /* Unicode-5.0 additions */
     case HB_SCRIPT_NKO:
+    case HB_SCRIPT_PHAGS_PA:
 
     /* Unicode-6.0 additions */
     case HB_SCRIPT_MANDAIC:
 
-      return hb_ot_complex_shaper_arabic;
+    /* Unicode-7.0 additions */
+    case HB_SCRIPT_MANICHAEAN:
+    case HB_SCRIPT_PSALTER_PAHLAVI:
+
+      /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
+       * This is because we do fallback shaping for Arabic script (and not others). */
+      if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
+         planner->props.script == HB_SCRIPT_ARABIC)
+       return &_hb_ot_complex_shaper_arabic;
+      else
+       return &_hb_ot_complex_shaper_default;
 
 
     /* Unicode-1.1 additions */
-    case HB_SCRIPT_HANGUL:
+    case HB_SCRIPT_THAI:
+    case HB_SCRIPT_LAO:
 
-      return hb_ot_complex_shaper_hangul;
+      return &_hb_ot_complex_shaper_thai;
 
 
     /* Unicode-1.1 additions */
-    case HB_SCRIPT_THAI:
-    case HB_SCRIPT_LAO:
+    case HB_SCRIPT_HANGUL:
 
-      return hb_ot_complex_shaper_thai;
+      return &_hb_ot_complex_shaper_hangul;
 
 
+    /* Unicode-2.0 additions */
+    case HB_SCRIPT_TIBETAN:
+
+      return &_hb_ot_complex_shaper_tibetan;
+
+
+    /* Unicode-1.1 additions */
+    case HB_SCRIPT_HEBREW:
+
+      return &_hb_ot_complex_shaper_hebrew;
+
 
     /* ^--- Add new shapers here */
 
@@ -127,9 +237,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
     /* Unicode-5.1 additions */
     case HB_SCRIPT_SAURASHTRA:
 
-    /* Unicode-5.2 additions */
-    case HB_SCRIPT_MEETEI_MAYEK:
-
     /* Unicode-6.0 additions */
     case HB_SCRIPT_BATAK:
     case HB_SCRIPT_BRAHMI:
@@ -142,9 +249,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
     case HB_SCRIPT_LAO:
     case HB_SCRIPT_THAI:
 
-    /* Unicode-2.0 additions */
-    case HB_SCRIPT_TIBETAN:
-
     /* Unicode-3.2 additions */
     case HB_SCRIPT_TAGALOG:
     case HB_SCRIPT_TAGBANWA:
@@ -154,11 +258,10 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
     case HB_SCRIPT_TAI_LE:
 
     /* Unicode-4.1 additions */
+    case HB_SCRIPT_KHAROSHTHI:
+    case HB_SCRIPT_NEW_TAI_LUE:
     case HB_SCRIPT_SYLOTI_NAGRI:
 
-    /* Unicode-5.0 additions */
-    case HB_SCRIPT_PHAGS_PA:
-
     /* Unicode-5.1 additions */
     case HB_SCRIPT_KAYAH_LI:
 
@@ -166,12 +269,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
     case HB_SCRIPT_TAI_VIET:
 
 
-    /* May need Indic treatment in the future? */
-
-    /* Unicode-3.0 additions */
-    case HB_SCRIPT_MYANMAR:
-
-
 #endif
 
     /* Unicode-1.1 additions */
@@ -186,19 +283,12 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
     case HB_SCRIPT_TELUGU:
 
     /* Unicode-3.0 additions */
-    case HB_SCRIPT_KHMER:
     case HB_SCRIPT_SINHALA:
 
-    /* Unicode-4.1 additions */
-    case HB_SCRIPT_BUGINESE:
-    case HB_SCRIPT_KHAROSHTHI:
-    case HB_SCRIPT_NEW_TAI_LUE:
-
     /* Unicode-5.0 additions */
     case HB_SCRIPT_BALINESE:
 
     /* Unicode-5.1 additions */
-    case HB_SCRIPT_CHAM:
     case HB_SCRIPT_LEPCHA:
     case HB_SCRIPT_REJANG:
     case HB_SCRIPT_SUNDANESE:
@@ -206,105 +296,67 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
     /* Unicode-5.2 additions */
     case HB_SCRIPT_JAVANESE:
     case HB_SCRIPT_KAITHI:
-    case HB_SCRIPT_TAI_THAM:
+    case HB_SCRIPT_MEETEI_MAYEK:
+
+    /* Unicode-6.0 additions */
 
     /* Unicode-6.1 additions */
     case HB_SCRIPT_CHAKMA:
     case HB_SCRIPT_SHARADA:
     case HB_SCRIPT_TAKRI:
 
-      return hb_ot_complex_shaper_indic;
-
-    /* ^--- Add new shapers here */
-  }
-}
-
-
-
-/*
- * collect_features()
- *
- * Called during shape_plan().
- *
- * Shapers should use map to add their features and callbacks.
- */
-
-typedef void hb_ot_shape_complex_collect_features_func_t (hb_ot_map_builder_t *map, const hb_segment_properties_t  *props);
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-  HB_INTERNAL hb_ot_shape_complex_collect_features_func_t _hb_ot_shape_complex_collect_features_##name;
-  HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+      /* If the designer designed the font for the 'DFLT' script,
+       * use the default shaper.  Otherwise, use the Indic shaper.
+       * Note that for some simple scripts, there may not be *any*
+       * GSUB/GPOS needed, so there may be no scripts found! */
+      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+       return &_hb_ot_complex_shaper_default;
+      else
+       return &_hb_ot_complex_shaper_indic;
 
-static inline void
-hb_ot_shape_complex_collect_features (hb_ot_complex_shaper_t shaper,
-                                     hb_ot_map_builder_t *map,
-                                     const hb_segment_properties_t  *props)
-{
-  switch (shaper) {
-    default:
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-    case hb_ot_complex_shaper_##name:  _hb_ot_shape_complex_collect_features_##name (map, props); return;
-    HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
-  }
-}
-
-
-/*
- * normalization_preference()
- *
- * Called during shape_execute().
- *
- * Shapers should return true if it prefers decomposed (NFD) input rather than precomposed (NFC).
- */
-
-typedef hb_ot_shape_normalization_mode_t hb_ot_shape_complex_normalization_preference_func_t (void);
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-  HB_INTERNAL hb_ot_shape_complex_normalization_preference_func_t _hb_ot_shape_complex_normalization_preference_##name;
-  HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+    case HB_SCRIPT_KHMER:
+      /* A number of Khmer fonts in the wild don't have a 'pref' feature,
+       * and as such won't shape properly via the Indic shaper;
+       * however, they typically have 'liga' / 'clig' features that implement
+       * the necessary "reordering" by means of ligature substitutions.
+       * So we send such pref-less fonts through the generic shaper instead. */
+      if (planner->map.found_script[0] &&
+         hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB,
+                                             planner->map.script_index[0],
+                                             planner->map.language_index[0],
+                                             HB_TAG ('p','r','e','f'),
+                                             NULL))
+       return &_hb_ot_complex_shaper_indic;
+      else
+       return &_hb_ot_complex_shaper_default;
 
-static inline hb_ot_shape_normalization_mode_t
-hb_ot_shape_complex_normalization_preference (hb_ot_complex_shaper_t shaper)
-{
-  switch (shaper) {
-    default:
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-    case hb_ot_complex_shaper_##name:  return _hb_ot_shape_complex_normalization_preference_##name ();
-    HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
-  }
-}
+    case HB_SCRIPT_MYANMAR:
+      if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
+       return &_hb_ot_complex_shaper_myanmar;
+      else if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
+       return &_hb_ot_complex_shaper_myanmar_old;
+      else
+       return &_hb_ot_complex_shaper_default;
 
+    /* Unicode-4.1 additions */
+    case HB_SCRIPT_BUGINESE:
 
-/* setup_masks()
- *
- * Called during shape_execute().
- *
- * Shapers should use map to get feature masks and set on buffer.
- */
+    /* Unicode-5.1 additions */
+    case HB_SCRIPT_CHAM:
 
-typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font);
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-  HB_INTERNAL hb_ot_shape_complex_setup_masks_func_t _hb_ot_shape_complex_setup_masks_##name;
-  HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+    /* Unicode-5.2 additions */
+    case HB_SCRIPT_TAI_THAM:
 
-static inline void
-hb_ot_shape_complex_setup_masks (hb_ot_complex_shaper_t shaper,
-                                hb_ot_map_t *map,
-                                hb_buffer_t *buffer,
-                                hb_font_t *font)
-{
-  switch (shaper) {
-    default:
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
-    case hb_ot_complex_shaper_##name:  _hb_ot_shape_complex_setup_masks_##name (map, buffer, font); return;
-    HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+      /* If the designer designed the font for the 'DFLT' script,
+       * use the default shaper.  Otherwise, use the Indic shaper.
+       * Note that for some simple scripts, there may not be *any*
+       * GSUB/GPOS needed, so there may be no scripts found! */
+      if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+       return &_hb_ot_complex_shaper_default;
+      else
+       return &_hb_ot_complex_shaper_sea;
   }
 }
 
 
-
 #endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
diff --git a/src/hb-ot-shape-complex-sea-machine.rl b/src/hb-ot-shape-complex-sea-machine.rl
new file mode 100644 (file)
index 0000000..46140fc
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+
+#include "hb-private.hh"
+
+%%{
+  machine sea_syllable_machine;
+  alphtype unsigned char;
+  write data;
+}%%
+
+%%{
+
+# Same order as enum sea_category_t.  Not sure how to avoid duplication.
+C    = 1;
+GB   = 12; # Generic Base
+H    = 4;  # Halant
+IV   = 2;  # Independent Vowel
+MR   = 22; # Medial Ra
+CM   = 17; # Consonant Medial
+VAbv = 26;
+VBlw = 27;
+VPre = 28;
+VPst = 29;
+T    = 3;  # Tone Marks
+A    = 10; # Anusvara
+
+syllable_tail = (VPre|VAbv|VBlw|VPst|H.C|CM|MR|T|A)*;
+
+consonant_syllable =   (C|IV|GB) syllable_tail;
+broken_cluster =       syllable_tail;
+other =                        any;
+
+main := |*
+       consonant_syllable      => { found_syllable (consonant_syllable); };
+       broken_cluster          => { found_syllable (broken_cluster); };
+       other                   => { found_syllable (non_sea_cluster); };
+*|;
+
+
+}%%
+
+#define found_syllable(syllable_type) \
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+    for (unsigned int i = last; i < p+1; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    last = p+1; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+  unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  %%{
+    write init;
+    getkey info[p].sea_category();
+  }%%
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int last = 0;
+  unsigned int syllable_serial = 1;
+  %%{
+    write exec;
+  }%%
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc
new file mode 100644 (file)
index 0000000..f08b7cc
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-complex-indic-private.hh"
+
+/* buffer var allocations */
+#define sea_category() complex_var_u8_0() /* indic_category_t */
+#define sea_position() complex_var_u8_1() /* indic_position_t */
+
+
+/*
+ * South-East Asian shaper.
+ * Loosely based on the Myanmar spec / shaper.
+ * There is no OpenType spec for this.
+ */
+
+static const hb_tag_t
+basic_features[] =
+{
+  /*
+   * Basic features.
+   * These features are applied in order, one at a time, after initial_reordering.
+   */
+  HB_TAG('p','r','e','f'),
+  HB_TAG('a','b','v','f'),
+  HB_TAG('b','l','w','f'),
+  HB_TAG('p','s','t','f'),
+};
+static const hb_tag_t
+other_features[] =
+{
+  /*
+   * Other features.
+   * These features are applied all at once, after final_reordering.
+   */
+  HB_TAG('p','r','e','s'),
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('p','s','t','s'),
+  /* Positioning features, though we don't care about the types. */
+  HB_TAG('d','i','s','t'),
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+                hb_font_t *font,
+                hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                   hb_font_t *font,
+                   hb_buffer_t *buffer);
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t *buffer);
+
+static void
+collect_features_sea (hb_ot_shape_planner_t *plan)
+{
+  hb_ot_map_builder_t *map = &plan->map;
+
+  /* Do this before any lookups have been applied. */
+  map->add_gsub_pause (setup_syllables);
+
+  map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+  /* 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->add_global_bool_feature (HB_TAG('c','c','m','p'));
+
+  map->add_gsub_pause (initial_reordering);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+  {
+    map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+    map->add_gsub_pause (NULL);
+  }
+  map->add_gsub_pause (final_reordering);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+    map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+}
+
+static void
+override_features_sea (hb_ot_shape_planner_t *plan)
+{
+  plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+}
+
+
+enum syllable_type_t {
+  consonant_syllable,
+  broken_cluster,
+  non_sea_cluster,
+};
+
+#include "hb-ot-shape-complex-sea-machine.hh"
+
+
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum sea_category_t {
+//  OT_C    = 1,
+  OT_GB   = 12, /* Generic Base XXX DOTTED CIRCLE only for now */
+//  OT_H    = 4,  /* Halant */
+  OT_IV   = 2,  /* Independent Vowel */
+  OT_MR   = 22, /* Medial Ra */
+//  OT_CM   = 17, /* Consonant Medial */
+  OT_VAbv = 26,
+  OT_VBlw = 27,
+  OT_VPre = 28,
+  OT_VPst = 29,
+  OT_T    = 3,  /* Tone Marks */
+//  OT_A    = 10, /* Anusvara */
+};
+
+static inline void
+set_sea_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 & 0x7Fu);
+  indic_position_t pos = (indic_position_t) (type >> 8);
+
+  /* Medial Ra */
+  if (u == 0x1A55u || u == 0xAA34u)
+    cat = (indic_category_t) OT_MR;
+
+  if (cat == OT_M)
+  {
+    switch ((int) pos)
+    {
+      case POS_PRE_C:  cat = (indic_category_t) OT_VPre; break;
+      case POS_ABOVE_C:        cat = (indic_category_t) OT_VAbv; break;
+      case POS_BELOW_C:        cat = (indic_category_t) OT_VBlw; break;
+      case POS_POST_C: cat = (indic_category_t) OT_VPst; break;
+    }
+  }
+
+  info.sea_category() = (sea_category_t) cat;
+  info.sea_position() = pos;
+}
+
+
+static void
+setup_masks_sea (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                hb_buffer_t              *buffer,
+                hb_font_t                *font HB_UNUSED)
+{
+  HB_BUFFER_ALLOCATE_VAR (buffer, sea_category);
+  HB_BUFFER_ALLOCATE_VAR (buffer, sea_position);
+
+  /* We cannot setup masks here.  We save information about characters
+   * and setup masks later on in a pause-callback. */
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    set_sea_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                hb_font_t *font HB_UNUSED,
+                hb_buffer_t *buffer)
+{
+  find_syllables (buffer);
+}
+
+static int
+compare_sea_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+{
+  int a = pa->sea_position();
+  int b = pb->sea_position();
+
+  return a < b ? -1 : a == b ? 0 : +1;
+}
+
+
+static void
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+                                      hb_face_t *face,
+                                      hb_buffer_t *buffer,
+                                      unsigned int start, unsigned int end)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int base = start;
+
+  /* Reorder! */
+  unsigned int i = start;
+  for (; i < base; i++)
+    info[i].sea_position() = POS_PRE_C;
+  if (i < end)
+  {
+    info[i].sea_position() = POS_BASE_C;
+    i++;
+  }
+  for (; i < end; i++)
+  {
+    if (info[i].sea_category() == OT_MR) /* Pre-base reordering */
+    {
+      info[i].sea_position() = POS_PRE_C;
+      continue;
+    }
+    if (info[i].sea_category() == OT_VPre) /* Left matra */
+    {
+      info[i].sea_position() = POS_PRE_M;
+      continue;
+    }
+
+    info[i].sea_position() = POS_AFTER_MAIN;
+  }
+
+  buffer->merge_clusters (start, end);
+  /* Sit tight, rock 'n roll! */
+  hb_bubble_sort (info + start, end - start, compare_sea_order);
+}
+
+static void
+initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+                                  hb_face_t *face,
+                                  hb_buffer_t *buffer,
+                                  unsigned int start, unsigned int end)
+{
+  /* We already inserted dotted-circles, so just call the consonant_syllable. */
+  initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+}
+
+static void
+initial_reordering_non_sea_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                   hb_face_t *face HB_UNUSED,
+                                   hb_buffer_t *buffer HB_UNUSED,
+                                   unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+  /* Nothing to do right now.  If we ever switch to using the output
+   * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+
+static void
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+                            hb_face_t *face,
+                            hb_buffer_t *buffer,
+                            unsigned int start, unsigned int end)
+{
+  syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+  switch (syllable_type) {
+  case consonant_syllable:     initial_reordering_consonant_syllable  (plan, face, buffer, start, end); return;
+  case broken_cluster:         initial_reordering_broken_cluster      (plan, face, buffer, start, end); return;
+  case non_sea_cluster:                initial_reordering_non_sea_cluster     (plan, face, buffer, start, end); return;
+  }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                      hb_font_t *font,
+                      hb_buffer_t *buffer)
+{
+  /* Note: This loop is extra overhead, but should not be measurable. */
+  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_cluster)
+    {
+      has_broken_syllables = true;
+      break;
+    }
+  if (likely (!has_broken_syllables))
+    return;
+
+
+  hb_codepoint_t dottedcircle_glyph;
+  if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  set_sea_properties (dottedcircle);
+  dottedcircle.codepoint = dottedcircle_glyph;
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  unsigned int last_syllable = 0;
+  while (buffer->idx < buffer->len)
+  {
+    unsigned int syllable = buffer->cur().syllable();
+    syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+    if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+    {
+      last_syllable = syllable;
+
+      hb_glyph_info_t info = dottedcircle;
+      info.cluster = buffer->cur().cluster;
+      info.mask = buffer->cur().mask;
+      info.syllable() = buffer->cur().syllable();
+
+      buffer->output_info (info);
+    }
+    else
+      buffer->next_glyph ();
+  }
+
+  buffer->swap_buffers ();
+}
+
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+                   hb_font_t *font,
+                   hb_buffer_t *buffer)
+{
+  insert_dotted_circles (plan, font, buffer);
+
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  if (unlikely (!count)) return;
+  unsigned int last = 0;
+  unsigned int last_syllable = info[0].syllable();
+  for (unsigned int i = 1; i < count; i++)
+    if (last_syllable != info[i].syllable()) {
+      initial_reordering_syllable (plan, font->face, buffer, last, i);
+      last = i;
+      last_syllable = info[last].syllable();
+    }
+  initial_reordering_syllable (plan, font->face, buffer, last, count);
+}
+
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font HB_UNUSED,
+                 hb_buffer_t *buffer)
+{
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+
+  /* Zero syllables now... */
+  for (unsigned int i = 0; i < count; i++)
+    info[i].syllable() = 0;
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, sea_category);
+  HB_BUFFER_DEALLOCATE_VAR (buffer, sea_position);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
+{
+  "sea",
+  collect_features_sea,
+  override_features_sea,
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  setup_masks_sea,
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+  false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
new file mode 100644 (file)
index 0000000..feb7fc7
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* Thai / Lao shaper */
+
+
+/* PUA shaping */
+
+
+enum thai_consonant_type_t
+{
+  NC,
+  AC,
+  RC,
+  DC,
+  NOT_CONSONANT,
+  NUM_CONSONANT_TYPES = NOT_CONSONANT
+};
+
+static thai_consonant_type_t
+get_consonant_type (hb_codepoint_t u)
+{
+  if (u == 0x0E1Bu || u == 0x0E1Du || u == 0x0E1Fu/* || u == 0x0E2Cu*/)
+    return AC;
+  if (u == 0x0E0Du || u == 0x0E10u)
+    return RC;
+  if (u == 0x0E0Eu || u == 0x0E0Fu)
+    return DC;
+  if (hb_in_range (u, 0x0E01u, 0x0E2Eu))
+    return NC;
+  return NOT_CONSONANT;
+}
+
+
+enum thai_mark_type_t
+{
+  AV,
+  BV,
+  T,
+  NOT_MARK,
+  NUM_MARK_TYPES = NOT_MARK
+};
+
+static thai_mark_type_t
+get_mark_type (hb_codepoint_t u)
+{
+  if (u == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) ||
+      u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu))
+    return AV;
+  if (hb_in_range (u, 0x0E38u, 0x0E3Au))
+    return BV;
+  if (hb_in_range (u, 0x0E48u, 0x0E4Cu))
+    return T;
+  return NOT_MARK;
+}
+
+
+enum thai_action_t
+{
+  NOP,
+  SD,  /* Shift combining-mark down */
+  SL,  /* Shift combining-mark left */
+  SDL, /* Shift combining-mark down-left */
+  RD   /* Remove descender from base */
+};
+
+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;
+  } const *pua_mappings = NULL;
+  static const thai_pua_mapping_t SD_mappings[] = {
+    {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
+    {0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */
+    {0x0E4Au, 0xF70Cu, 0xF891u}, /* MAI TRI */
+    {0x0E4Bu, 0xF70Du, 0xF894u}, /* MAI CHATTAWA */
+    {0x0E4Cu, 0xF70Eu, 0xF897u}, /* THANTHAKHAT */
+    {0x0E38u, 0xF718u, 0xF89Bu}, /* SARA U */
+    {0x0E39u, 0xF719u, 0xF89Cu}, /* SARA UU */
+    {0x0E3Au, 0xF71Au, 0xF89Du}, /* PHINTHU */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+  static const thai_pua_mapping_t SDL_mappings[] = {
+    {0x0E48u, 0xF705u, 0xF88Cu}, /* MAI EK */
+    {0x0E49u, 0xF706u, 0xF88Fu}, /* MAI THO */
+    {0x0E4Au, 0xF707u, 0xF892u}, /* MAI TRI */
+    {0x0E4Bu, 0xF708u, 0xF895u}, /* MAI CHATTAWA */
+    {0x0E4Cu, 0xF709u, 0xF898u}, /* THANTHAKHAT */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+  static const thai_pua_mapping_t SL_mappings[] = {
+    {0x0E48u, 0xF713u, 0xF88Au}, /* MAI EK */
+    {0x0E49u, 0xF714u, 0xF88Du}, /* MAI THO */
+    {0x0E4Au, 0xF715u, 0xF890u}, /* MAI TRI */
+    {0x0E4Bu, 0xF716u, 0xF893u}, /* MAI CHATTAWA */
+    {0x0E4Cu, 0xF717u, 0xF896u}, /* THANTHAKHAT */
+    {0x0E31u, 0xF710u, 0xF884u}, /* MAI HAN-AKAT */
+    {0x0E34u, 0xF701u, 0xF885u}, /* SARA I */
+    {0x0E35u, 0xF702u, 0xF886u}, /* SARA II */
+    {0x0E36u, 0xF703u, 0xF887u}, /* SARA UE */
+    {0x0E37u, 0xF704u, 0xF888u}, /* SARA UEE */
+    {0x0E47u, 0xF712u, 0xF889u}, /* MAITAIKHU */
+    {0x0E4Du, 0xF711u, 0xF899u}, /* NIKHAHIT */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+  static const thai_pua_mapping_t RD_mappings[] = {
+    {0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */
+    {0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */
+    {0x0000u, 0x0000u, 0x0000u}
+  };
+
+  switch (action) {
+    default: assert (false); /* Fallthrough */
+    case NOP: return u;
+    case SD:  pua_mappings = SD_mappings; break;
+    case SDL: pua_mappings = SDL_mappings; break;
+    case SL:  pua_mappings = SL_mappings; break;
+    case RD:  pua_mappings = RD_mappings; break;
+  }
+  for (; pua_mappings->u; pua_mappings++)
+    if (pua_mappings->u == u)
+    {
+      hb_codepoint_t glyph;
+      if (hb_font_get_glyph (font, pua_mappings->win_pua, 0, &glyph))
+       return pua_mappings->win_pua;
+      if (hb_font_get_glyph (font, pua_mappings->mac_pua, 0, &glyph))
+       return pua_mappings->mac_pua;
+      break;
+    }
+  return u;
+}
+
+
+static enum thai_above_state_t
+{     /* Cluster above looks like: */
+  T0, /*  ⣤                      */
+  T1, /*     ⣼                   */
+  T2, /*        ⣾                */
+  T3, /*           ⣿             */
+  NUM_ABOVE_STATES
+} thai_above_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+  T0, /* NC */
+  T1, /* AC */
+  T0, /* RC */
+  T0, /* DC */
+  T3, /* NOT_CONSONANT */
+};
+
+static const struct thai_above_state_machine_edge_t {
+  thai_action_t action;
+  thai_above_state_t next_state;
+} thai_above_state_machine[NUM_ABOVE_STATES][NUM_MARK_TYPES] =
+{        /*AV*/    /*BV*/    /*T*/
+/*T0*/ {{NOP,T3}, {NOP,T0}, {SD, T3}},
+/*T1*/ {{SL, T2}, {NOP,T1}, {SDL,T2}},
+/*T2*/ {{NOP,T3}, {NOP,T2}, {SL, T3}},
+/*T3*/ {{NOP,T3}, {NOP,T3}, {NOP,T3}},
+};
+
+
+static enum thai_below_state_t
+{
+  B0, /* No descender */
+  B1, /* Removable descender */
+  B2, /* Strict descender */
+  NUM_BELOW_STATES
+} thai_below_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+  B0, /* NC */
+  B0, /* AC */
+  B1, /* RC */
+  B2, /* DC */
+  B2, /* NOT_CONSONANT */
+};
+
+static const struct thai_below_state_machine_edge_t {
+  thai_action_t action;
+  thai_below_state_t next_state;
+} thai_below_state_machine[NUM_BELOW_STATES][NUM_MARK_TYPES] =
+{        /*AV*/    /*BV*/    /*T*/
+/*B0*/ {{NOP,B0}, {NOP,B2}, {NOP, B0}},
+/*B1*/ {{NOP,B1}, {RD, B2}, {NOP, B1}},
+/*B2*/ {{NOP,B2}, {SD, B2}, {NOP, B2}},
+};
+
+
+static void
+do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                    hb_buffer_t              *buffer,
+                    hb_font_t                *font)
+{
+  thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT];
+  thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT];
+  unsigned int base = 0;
+
+  hb_glyph_info_t *info = buffer->info;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    thai_mark_type_t mt = get_mark_type (info[i].codepoint);
+
+    if (mt == NOT_MARK) {
+      thai_consonant_type_t ct = get_consonant_type (info[i].codepoint);
+      above_state = thai_above_start_state[ct];
+      below_state = thai_below_start_state[ct];
+      base = i;
+      continue;
+    }
+
+    const thai_above_state_machine_edge_t &above_edge = thai_above_state_machine[above_state][mt];
+    const thai_below_state_machine_edge_t &below_edge = thai_below_state_machine[below_state][mt];
+    above_state = above_edge.next_state;
+    below_state = below_edge.next_state;
+
+    /* At least one of the above/below actions is NOP. */
+    thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action;
+
+    if (action == RD)
+      info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font);
+    else
+      info[i].codepoint = thai_pua_shape (info[i].codepoint, action, font);
+  }
+}
+
+
+static void
+preprocess_text_thai (const hb_ot_shape_plan_t *plan,
+                     hb_buffer_t              *buffer,
+                     hb_font_t                *font)
+{
+  /* This function implements the shaping logic documented here:
+   *
+   *   http://linux.thai.net/~thep/th-otf/shaping.html
+   *
+   * The first shaping rule listed there is needed even if the font has Thai
+   * OpenType tables.  The rest do fallback positioning based on PUA codepoints.
+   * We implement that only if there exist no Thai GSUB in the font.
+   */
+
+  /* The following is NOT specified in the MS OT Thai spec, however, it seems
+   * 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).
+   *
+   * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
+   *
+   * This reordering is legit only when the NIKHAHIT comes from a SARA AM, not
+   * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
+   * not what a user wanted, but the rendering is nevertheless nikhahit above
+   * chattawa.
+   *
+   * Same for Lao.
+   *
+   * Note:
+   *
+   * Uniscribe also does some below-marks reordering.  Namely, it positions U+0E3A
+   * after U+0E38 and U+0E39.  We do that by modifying the ccc for U+0E3A.
+   * See unicode->modified_combining_class ().  Lao does NOT have a U+0E3A
+   * equivalent.
+   */
+
+
+  /*
+   * Here are the characters of significance:
+   *
+   *                   Thai    Lao
+   * SARA AM:          U+0E33  U+0EB3
+   * SARA AA:          U+0E32  U+0EB2
+   * 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>
+   *
+   * Note how the Lao versions are the same as Thai + 0x80.
+   */
+
+  /* We only get one script at a time, so a script-agnostic implementation
+   * is adequate here. */
+#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 ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
+
+  buffer->clear_output ();
+  unsigned int count = buffer->len;
+  for (buffer->idx = 0; buffer->idx < count;)
+  {
+    hb_codepoint_t u = buffer->cur().codepoint;
+    if (likely (!IS_SARA_AM (u))) {
+      buffer->next_glyph ();
+      continue;
+    }
+
+    /* Is SARA AM. Decompose and reorder. */
+    hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
+                                   hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
+    buffer->replace_glyphs (1, 2, decomposed);
+    if (unlikely (buffer->in_error))
+      return;
+
+    /* Make Nikhahit be recognized as a mark when zeroing widths. */
+    unsigned int end = buffer->out_len;
+    _hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
+
+    /* Ok, let's see... */
+    unsigned int start = end - 2;
+    while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
+      start--;
+
+    if (start + 2 < end)
+    {
+      /* Move Nikhahit (end-2) to the beginning */
+      buffer->merge_out_clusters (start, end);
+      hb_glyph_info_t t = buffer->out_info[end - 2];
+      memmove (buffer->out_info + start + 1,
+              buffer->out_info + start,
+              sizeof (buffer->out_info[0]) * (end - start - 2));
+      buffer->out_info[start] = t;
+    }
+    else
+    {
+      /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
+       * previous cluster. */
+      if (start)
+       buffer->merge_out_clusters (start - 1, end);
+    }
+  }
+  buffer->swap_buffers ();
+
+  /* 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 =
+{
+  "thai",
+  NULL, /* collect_features */
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  preprocess_text_thai,
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+  false,/* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-tibetan.cc b/src/hb-ot-shape-complex-tibetan.cc
new file mode 100644 (file)
index 0000000..01465a4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+static const hb_tag_t tibetan_features[] =
+{
+  HB_TAG('a','b','v','s'),
+  HB_TAG('b','l','w','s'),
+  HB_TAG('a','b','v','m'),
+  HB_TAG('b','l','w','m'),
+  HB_TAG_NONE
+};
+
+static void
+collect_features_tibetan (hb_ot_shape_planner_t *plan)
+{
+  for (const hb_tag_t *script_features = tibetan_features; script_features && *script_features; script_features++)
+    plan->map.add_global_bool_feature (*script_features);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
+{
+  "default",
+  collect_features_tibetan,
+  NULL, /* override_features */
+  NULL, /* data_create */
+  NULL, /* data_destroy */
+  NULL, /* preprocess_text */
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+  NULL, /* decompose */
+  NULL, /* compose */
+  NULL, /* setup_masks */
+  HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+  true, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-fallback-private.hh b/src/hb-ot-shape-fallback-private.hh
new file mode 100644 (file)
index 0000000..ec65351
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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_FALLBACK_PRIVATE_HH
+#define HB_OT_SHAPE_FALLBACK_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-private.hh"
+
+
+HB_INTERNAL void _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
+                                                hb_font_t *font,
+                                                hb_buffer_t  *buffer);
+
+HB_INTERNAL void _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
+                                                                   hb_font_t *font,
+                                                                   hb_buffer_t  *buffer);
+
+
+HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
+                                            hb_font_t *font,
+                                            hb_buffer_t  *buffer);
+
+
+#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
new file mode 100644 (file)
index 0000000..53274b5
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * 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
+ */
+
+#include "hb-ot-shape-fallback-private.hh"
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+static unsigned int
+recategorize_combining_class (hb_codepoint_t u,
+                             unsigned int klass)
+{
+  if (klass >= 200)
+    return klass;
+
+  /* Thai / Lao need some per-character work. */
+  if ((u & ~0xFF) == 0x0E00u)
+  {
+    if (unlikely (klass == 0))
+    {
+      switch (u)
+      {
+        case 0x0E31u:
+        case 0x0E34u:
+        case 0x0E35u:
+        case 0x0E36u:
+        case 0x0E37u:
+        case 0x0E47u:
+        case 0x0E4Cu:
+        case 0x0E4Du:
+        case 0x0E4Eu:
+         klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+         break;
+
+        case 0x0EB1u:
+        case 0x0EB4u:
+        case 0x0EB5u:
+        case 0x0EB6u:
+        case 0x0EB7u:
+        case 0x0EBBu:
+        case 0x0ECCu:
+        case 0x0ECDu:
+         klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
+         break;
+
+        case 0x0EBCu:
+         klass = HB_UNICODE_COMBINING_CLASS_BELOW;
+         break;
+      }
+    } else {
+      /* Thai virama is below-right */
+      if (u == 0x0E3Au)
+       klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
+    }
+  }
+
+  switch (klass)
+  {
+
+    /* Hebrew */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC10: /* sheva */
+    case HB_MODIFIED_COMBINING_CLASS_CCC11: /* hataf segol */
+    case HB_MODIFIED_COMBINING_CLASS_CCC12: /* hataf patah */
+    case HB_MODIFIED_COMBINING_CLASS_CCC13: /* hataf qamats */
+    case HB_MODIFIED_COMBINING_CLASS_CCC14: /* hiriq */
+    case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
+    case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
+    case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
+    case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
+    case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
+    case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */
+      return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
+    case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */
+      break;
+
+
+    /* Arabic and Syriac */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC27: /* fathatan */
+    case HB_MODIFIED_COMBINING_CLASS_CCC28: /* dammatan */
+    case HB_MODIFIED_COMBINING_CLASS_CCC30: /* fatha */
+    case HB_MODIFIED_COMBINING_CLASS_CCC31: /* damma */
+    case HB_MODIFIED_COMBINING_CLASS_CCC33: /* shadda */
+    case HB_MODIFIED_COMBINING_CLASS_CCC34: /* sukun */
+    case HB_MODIFIED_COMBINING_CLASS_CCC35: /* superscript alef */
+    case HB_MODIFIED_COMBINING_CLASS_CCC36: /* superscript alaph */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */
+    case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+
+    /* Thai */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */
+      return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+
+
+    /* Lao */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+
+    /* Tibetan */
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
+      return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+    case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */
+      return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+  }
+
+  return klass;
+}
+
+void
+_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
+                                                  hb_font_t *font HB_UNUSED,
+                                                  hb_buffer_t  *buffer)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
+      unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
+      combining_class = recategorize_combining_class (info[i].codepoint, combining_class);
+      _hb_glyph_info_set_modified_combining_class (&info[i], combining_class);
+    }
+}
+
+
+static void
+zero_mark_advances (hb_buffer_t *buffer,
+                   unsigned int start,
+                   unsigned int end)
+{
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = start; i < end; i++)
+    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    {
+      buffer->pos[i].x_advance = 0;
+      buffer->pos[i].y_advance = 0;
+    }
+}
+
+static inline void
+position_mark (const hb_ot_shape_plan_t *plan,
+              hb_font_t *font,
+              hb_buffer_t  *buffer,
+              hb_glyph_extents_t &base_extents,
+              unsigned int i,
+              unsigned int combining_class)
+{
+  hb_glyph_extents_t mark_extents;
+  if (!font->get_glyph_extents (buffer->info[i].codepoint,
+                               &mark_extents))
+    return;
+
+  hb_position_t y_gap = font->y_scale / 16;
+
+  hb_glyph_position_t &pos = buffer->pos[i];
+  pos.x_offset = pos.y_offset = 0;
+
+
+  /* We dont position LEFT and RIGHT marks. */
+
+  /* X positioning */
+  switch (combining_class)
+  {
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
+      if (buffer->props.direction == HB_DIRECTION_LTR) {
+       pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
+        break;
+      } else if (buffer->props.direction == HB_DIRECTION_RTL) {
+       pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
+        break;
+      }
+      /* Fall through */
+
+    default:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE:
+      /* Center align. */
+      pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
+      break;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
+      /* Left align. */
+      pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing;
+      break;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
+      /* Right align. */
+      pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing;
+      break;
+  }
+
+  /* Y positioning */
+  switch (combining_class)
+  {
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_BELOW:
+    case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
+      /* Add gap, fall-through. */
+      base_extents.height -= y_gap;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+      pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
+      /* Never shift up "below" marks. */
+      if ((y_gap > 0) == (pos.y_offset > 0))
+      {
+       base_extents.height -= pos.y_offset;
+       pos.y_offset = 0;
+      }
+      base_extents.height += mark_extents.height;
+      break;
+
+    case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
+      /* Add gap, fall-through. */
+      base_extents.y_bearing += y_gap;
+      base_extents.height -= y_gap;
+
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
+    case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
+      pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
+      /* Don't shift down "above" marks too much. */
+      if ((y_gap > 0) != (pos.y_offset > 0))
+      {
+       unsigned int correction = -pos.y_offset / 2;
+       base_extents.y_bearing += correction;
+       base_extents.height -= correction;
+       pos.y_offset += correction;
+      }
+      base_extents.y_bearing -= mark_extents.height;
+      base_extents.height += mark_extents.height;
+      break;
+  }
+}
+
+static inline void
+position_around_base (const hb_ot_shape_plan_t *plan,
+                     hb_font_t *font,
+                     hb_buffer_t  *buffer,
+                     unsigned int base,
+                     unsigned int end)
+{
+  hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
+  hb_glyph_extents_t base_extents;
+  if (!font->get_glyph_extents (buffer->info[base].codepoint,
+                               &base_extents))
+  {
+    /* If extents don't work, zero marks and go home. */
+    zero_mark_advances (buffer, base + 1, end);
+    return;
+  }
+  base_extents.x_bearing += buffer->pos[base].x_offset;
+  base_extents.y_bearing += buffer->pos[base].y_offset;
+
+  unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
+  unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
+
+  hb_position_t x_offset = 0, y_offset = 0;
+  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
+    x_offset -= buffer->pos[base].x_advance;
+    y_offset -= buffer->pos[base].y_advance;
+  }
+
+  hb_glyph_extents_t component_extents = base_extents;
+  unsigned int last_lig_component = (unsigned int) -1;
+  unsigned int last_combining_class = 255;
+  hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = base + 1; i < end; i++)
+    if (_hb_glyph_info_get_modified_combining_class (&info[i]))
+    {
+      if (num_lig_components > 1) {
+       unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
+       unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
+       /* Conditions for attaching to the last component. */
+       if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
+         this_lig_component = num_lig_components - 1;
+       if (last_lig_component != this_lig_component)
+       {
+         last_lig_component = this_lig_component;
+         last_combining_class = 255;
+         component_extents = base_extents;
+         if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
+           if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
+             horiz_dir = plan->props.direction;
+           else
+             horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
+         }
+         if (horiz_dir == HB_DIRECTION_LTR)
+           component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
+         else
+           component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
+         component_extents.width /= num_lig_components;
+       }
+      }
+
+      unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
+      if (last_combining_class != this_combining_class)
+      {
+       last_combining_class = this_combining_class;
+        cluster_extents = component_extents;
+      }
+
+      position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
+
+      buffer->pos[i].x_advance = 0;
+      buffer->pos[i].y_advance = 0;
+      buffer->pos[i].x_offset += x_offset;
+      buffer->pos[i].y_offset += y_offset;
+
+    } else {
+      if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
+       x_offset -= buffer->pos[i].x_advance;
+       y_offset -= buffer->pos[i].y_advance;
+      } else {
+       x_offset += buffer->pos[i].x_advance;
+       y_offset += buffer->pos[i].y_advance;
+      }
+    }
+}
+
+static inline void
+position_cluster (const hb_ot_shape_plan_t *plan,
+                 hb_font_t *font,
+                 hb_buffer_t  *buffer,
+                 unsigned int start,
+                 unsigned int end)
+{
+  if (end - start < 2)
+    return;
+
+  /* Find the base glyph */
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = start; i < end; i++)
+    if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
+    {
+      /* Find mark glyphs */
+      unsigned int j;
+      for (j = i + 1; j < end; j++)
+       if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
+         break;
+
+      position_around_base (plan, font, buffer, i, j);
+
+      i = j - 1;
+    }
+}
+
+void
+_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
+                               hb_font_t *font,
+                               hb_buffer_t  *buffer)
+{
+  _hb_buffer_assert_gsubgpos_vars (buffer);
+
+  unsigned int start = 0;
+  unsigned int last_cluster = buffer->info[0].cluster;
+  unsigned int count = buffer->len;
+  for (unsigned int i = 1; i < count; i++)
+    if (buffer->info[i].cluster != last_cluster) {
+      position_cluster (plan, font, buffer, start, i);
+      start = i;
+      last_cluster = buffer->info[i].cluster;
+    }
+  position_cluster (plan, font, buffer, start, count);
+}
+
+
+/* Performs old-style TrueType kerning. */
+void
+_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
+                           hb_font_t *font,
+                           hb_buffer_t  *buffer)
+{
+  if (!plan->has_kern) return;
+
+  OT::hb_apply_context_t c (1, font, buffer);
+  c.set_lookup_mask (plan->kern_mask);
+  c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
+  OT::hb_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
+  skippy_iter.init (&c);
+
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  hb_glyph_position_t *pos = buffer->pos;
+  for (unsigned int idx = 0; idx < count;)
+  {
+    skippy_iter.reset (idx, 1);
+    if (!skippy_iter.next ())
+    {
+      idx++;
+      continue;
+    }
+
+    hb_position_t x_kern, y_kern;
+    font->get_glyph_kerning_for_direction (info[idx].codepoint,
+                                          info[skippy_iter.idx].codepoint,
+                                          buffer->props.direction,
+                                          &x_kern, &y_kern);
+
+    if (x_kern)
+    {
+      hb_position_t kern1 = x_kern >> 1;
+      hb_position_t kern2 = x_kern - kern1;
+      pos[idx].x_advance += kern1;
+      pos[skippy_iter.idx].x_advance += kern2;
+      pos[skippy_iter.idx].x_offset += kern2;
+    }
+
+    if (y_kern)
+    {
+      hb_position_t kern1 = y_kern >> 1;
+      hb_position_t kern2 = y_kern - kern1;
+      pos[idx].y_advance += kern1;
+      pos[skippy_iter.idx].y_advance += kern2;
+      pos[skippy_iter.idx].y_offset += kern2;
+    }
+
+    idx = skippy_iter.idx;
+  }
+}
index bb81f00..c744e26 100644 (file)
 
 #include "hb-private.hh"
 
-#include "hb-font.h"
-#include "hb-buffer.h"
 
+/* buffer var allocations, used during the normalization process */
+#define glyph_index()  var1.u32
+
+struct hb_ot_shape_plan_t;
 
 enum hb_ot_shape_normalization_mode_t {
+  HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
   HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
-  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL /* including base-to-base composition */
+  HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */
+
+  HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS
 };
 
-HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font,
+HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
                                         hb_buffer_t *buffer,
-                                        hb_ot_shape_normalization_mode_t mode);
+                                        hb_font_t *font);
+
+
+struct hb_ot_shape_normalize_context_t
+{
+  const hb_ot_shape_plan_t *plan;
+  hb_buffer_t *buffer;
+  hb_font_t *font;
+  hb_unicode_funcs_t *unicode;
+  bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+                    hb_codepoint_t  ab,
+                    hb_codepoint_t *a,
+                    hb_codepoint_t *b);
+  bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+                  hb_codepoint_t  a,
+                  hb_codepoint_t  b,
+                  hb_codepoint_t *ab);
+};
+
 
 #endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */
index 562ba88..8cc64af 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include "hb-ot-shape-normalize-private.hh"
+#include "hb-ot-shape-complex-private.hh"
 #include "hb-ot-shape-private.hh"
 
 
  *     knowledge too.  We need to provide assistance to the itemizer.
  *
  *   - When a font does not support a character but supports its decomposition,
- *     well, use the decomposition.
+ *     well, use the decomposition (preferring the canonical decomposition, but
+ *     falling back to the compatibility decomposition if necessary).  The
+ *     compatibility decomposition is really nice to have, for characters like
+ *     ellipsis, or various-sized space characters.
  *
- *   - The Indic shaper requests decomposed output.  This will handle splitting
- *     matra for the Indic shaper.
+ *   - The complex 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.
+ *
+ *   - We try compatibility decomposition if decomposing through canonical
+ *     decomposition alone failed to find a sequence that the font supports.
+ *     We don't try compatibility decomposition recursively during the canonical
+ *     decomposition phase.  This has minimal impact.  There are only a handful
+ *     of Greek letter that have canonical decompositions that include characters
+ *     with compatibility decomposition.  Those can be found using this command:
+ *
+ *     egrep  "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
  */
 
-static void
-output_glyph (hb_buffer_t *buffer, hb_codepoint_t glyph)
+static bool
+decompose_unicode (const hb_ot_shape_normalize_context_t *c,
+                  hb_codepoint_t  ab,
+                  hb_codepoint_t *a,
+                  hb_codepoint_t *b)
 {
-  buffer->output_glyph (glyph);
-  _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
+  return c->unicode->decompose (ab, a, b);
 }
 
 static bool
-decompose (hb_font_t *font, hb_buffer_t *buffer,
-          bool shortest,
-          hb_codepoint_t ab)
+compose_unicode (const hb_ot_shape_normalize_context_t *c,
+                hb_codepoint_t  a,
+                hb_codepoint_t  b,
+                hb_codepoint_t *ab)
+{
+  return c->unicode->compose (a, b, ab);
+}
+
+static inline void
+set_glyph (hb_glyph_info_t &info, hb_font_t *font)
 {
-  hb_codepoint_t a, b, glyph;
+  font->get_glyph (info.codepoint, 0, &info.glyph_index());
+}
 
-  if (!hb_unicode_decompose (buffer->unicode, ab, &a, &b) ||
-      (b && !hb_font_get_glyph (font, b, 0, &glyph)))
-    return false;
+static inline void
+output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
+{
+  buffer->cur().glyph_index() = glyph;
+  buffer->output_glyph (unichar);
+  _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
+}
 
-  bool has_a = hb_font_get_glyph (font, a, 0, &glyph);
+static inline void
+next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
+{
+  buffer->cur().glyph_index() = glyph;
+  buffer->next_glyph ();
+}
+
+static inline void
+skip_char (hb_buffer_t *buffer)
+{
+  buffer->skip_glyph ();
+}
+
+/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
+static inline unsigned int
+decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
+{
+  hb_codepoint_t a, b, a_glyph, b_glyph;
+  hb_buffer_t * const buffer = c->buffer;
+  hb_font_t * const font = c->font;
+
+  if (!c->decompose (c, ab, &a, &b) ||
+      (b && !font->get_glyph (b, 0, &b_glyph)))
+    return 0;
+
+  bool has_a = font->get_glyph (a, 0, &a_glyph);
   if (shortest && has_a) {
     /* Output a and b */
-    output_glyph (buffer, a);
-    if (b)
-      output_glyph (buffer, b);
-    return true;
+    output_char (buffer, a, a_glyph);
+    if (likely (b)) {
+      output_char (buffer, b, b_glyph);
+      return 2;
+    }
+    return 1;
   }
 
-  if (decompose (font, buffer, shortest, a)) {
-    if (b)
-      output_glyph (buffer, b);
-    return true;
+  unsigned int ret;
+  if ((ret = decompose (c, shortest, a))) {
+    if (b) {
+      output_char (buffer, b, b_glyph);
+      return ret + 1;
+    }
+    return ret;
   }
 
   if (has_a) {
-    output_glyph (buffer, a);
-    if (b)
-      output_glyph (buffer, b);
-    return true;
+    output_char (buffer, a, a_glyph);
+    if (likely (b)) {
+      output_char (buffer, b, b_glyph);
+      return 2;
+    }
+    return 1;
   }
 
-  return false;
+  return 0;
 }
 
-static void
-decompose_current_glyph (hb_font_t *font, hb_buffer_t *buffer,
-                        bool shortest)
+/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
+static inline unsigned int
+decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u)
 {
-  if (decompose (font, buffer, shortest, buffer->cur().codepoint))
-    buffer->skip_glyph ();
-  else
-    buffer->next_glyph ();
+  unsigned int len, i;
+  hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+  hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+
+  len = c->buffer->unicode->decompose_compatibility (u, decomposed);
+  if (!len)
+    return 0;
+
+  for (i = 0; i < len; i++)
+    if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
+      return 0;
+
+  for (i = 0; i < len; i++)
+    output_char (c->buffer, decomposed[i], glyphs[i]);
+
+  return len;
 }
 
-static void
-decompose_single_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
-                              bool will_recompose)
+static inline void
+decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
 {
+  hb_buffer_t * const buffer = c->buffer;
+  hb_codepoint_t u = buffer->cur().codepoint;
   hb_codepoint_t glyph;
 
-  /* If recomposing and font supports this, we're good to go */
-  if (will_recompose && hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph)) {
+  /* Kind of a cute waterfall here... */
+  if (shortest && c->font->get_glyph (u, 0, &glyph))
+    next_char (buffer, glyph);
+  else if (decompose (c, shortest, u))
+    skip_char (buffer);
+  else if (!shortest && c->font->get_glyph (u, 0, &glyph))
+    next_char (buffer, glyph);
+  else if (decompose_compatibility (c, u))
+    skip_char (buffer);
+  else
+    next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
+}
+
+static inline void
+handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
+{
+  /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
+  hb_buffer_t * const buffer = c->buffer;
+  hb_font_t * const font = c->font;
+  for (; buffer->idx < end - 1;) {
+    if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
+      /* The next two lines are some ugly lines... But work. */
+      if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+      {
+       buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+      }
+      else
+      {
+        /* Just pass on the two characters separately, let GSUB do its magic. */
+       set_glyph (buffer->cur(), font);
+       buffer->next_glyph ();
+       set_glyph (buffer->cur(), font);
+       buffer->next_glyph ();
+      }
+      /* Skip any further variation selectors. */
+      while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+      {
+       set_glyph (buffer->cur(), font);
+       buffer->next_glyph ();
+      }
+    } else {
+      set_glyph (buffer->cur(), font);
+      buffer->next_glyph ();
+    }
+  }
+  if (likely (buffer->idx < end)) {
+    set_glyph (buffer->cur(), font);
     buffer->next_glyph ();
-    return;
   }
-
-  decompose_current_glyph (font, buffer, will_recompose);
 }
 
-static void
-decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
-                             unsigned int end)
+static inline void
+decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
 {
-  /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
+  hb_buffer_t * const buffer = c->buffer;
   for (unsigned int i = buffer->idx; i < end; i++)
-    if (unlikely (_hb_unicode_is_variation_selector (buffer->info[i].codepoint))) {
-      while (buffer->idx < end)
-       buffer->next_glyph ();
+    if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
+      handle_variation_selector_cluster (c, end, short_circuit);
       return;
     }
 
   while (buffer->idx < end)
-    decompose_current_glyph (font, buffer, false);
+    decompose_current_character (c, short_circuit);
 }
 
+static inline void
+decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit)
+{
+  if (likely (c->buffer->idx + 1 == end))
+    decompose_current_character (c, might_short_circuit);
+  else
+    decompose_multi_char_cluster (c, end, always_short_circuit);
+}
+
+
 static int
 compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
 {
@@ -161,12 +284,28 @@ compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
   return a < b ? -1 : a == b ? 0 : +1;
 }
 
+
 void
-_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
-                       hb_ot_shape_normalization_mode_t mode)
+_hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
+                       hb_buffer_t *buffer,
+                       hb_font_t *font)
 {
-  bool recompose = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
-  bool has_multichar_clusters = false;
+  _hb_buffer_assert_unicode_vars (buffer);
+
+  hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
+  const hb_ot_shape_normalize_context_t c = {
+    plan,
+    buffer,
+    font,
+    buffer->unicode,
+    plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
+    plan->shaper->compose   ? plan->shaper->compose   : compose_unicode
+  };
+
+  bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
+  bool might_short_circuit = always_short_circuit ||
+                            (mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
+                             mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT);
   unsigned int count;
 
   /* We do a fairly straightforward yet custom normalization process in three
@@ -187,20 +326,11 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
       if (buffer->cur().cluster != buffer->info[end].cluster)
         break;
 
-    if (buffer->idx + 1 == end)
-      decompose_single_char_cluster (font, buffer, recompose);
-    else {
-      decompose_multi_char_cluster (font, buffer, end);
-      has_multichar_clusters = true;
-    }
+    decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
   }
   buffer->swap_buffers ();
 
 
-  if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !has_multichar_clusters)
-    return; /* Done! */
-
-
   /* Second round, reorder (inplace) */
 
   count = buffer->len;
@@ -228,7 +358,8 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
   }
 
 
-  if (!recompose)
+  if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
+      mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
     return;
 
   /* Third round, recompose */
@@ -243,28 +374,34 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
   while (buffer->idx < count)
   {
     hb_codepoint_t composed, glyph;
-    if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't try to
-        * compose a CCC=0 character with it's preceding starter. */
-       (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL ||
-        _hb_glyph_info_get_modified_combining_class (&buffer->cur()) != 0) &&
+    if (/* We don't try to compose a non-mark character with it's preceding starter.
+        * This is both an optimization to avoid trying to compose every two neighboring
+        * glyphs in most scripts AND a desired feature for Hangul.  Apparently Hangul
+        * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
+       HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) &&
        /* If there's anything between the starter and this char, they should have CCC
         * smaller than this character's. */
        (starter == buffer->out_len - 1 ||
         _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
        /* And compose. */
-       hb_unicode_compose (buffer->unicode,
-                           buffer->out_info[starter].codepoint,
-                           buffer->cur().codepoint,
-                           &composed) &&
+       c.compose (&c,
+                  buffer->out_info[starter].codepoint,
+                  buffer->cur().codepoint,
+                  &composed) &&
        /* And the font has glyph for the composite. */
-       hb_font_get_glyph (font, composed, 0, &glyph))
+       font->get_glyph (composed, 0, &glyph))
     {
-      /* Composes. Modify starter and carry on. */
+      /* Composes. */
+      buffer->next_glyph (); /* Copy to out-buffer. */
+      if (unlikely (buffer->in_error))
+        return;
+      buffer->merge_out_clusters (starter, buffer->out_len);
+      buffer->out_len--; /* Remove the second composable. */
+      /* Modify starter and carry on. */
       buffer->out_info[starter].codepoint = composed;
-      /* XXX update cluster */
+      buffer->out_info[starter].glyph_index() = glyph;
       _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
 
-      buffer->skip_glyph ();
       continue;
     }
 
index df0c705..54ac2c3 100644 (file)
 #include "hb-private.hh"
 
 #include "hb-ot-map-private.hh"
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-layout-private.hh"
+
 
 
 struct hb_ot_shape_plan_t
 {
+  hb_segment_properties_t props;
+  const struct hb_ot_complex_shaper_t *shaper;
   hb_ot_map_t map;
-  hb_ot_complex_shaper_t shaper;
-
-  hb_ot_shape_plan_t (void) : map () {}
-  ~hb_ot_shape_plan_t (void) { map.finish (); }
-
-  private:
-  NO_COPY (hb_ot_shape_plan_t);
+  const void *data;
+  hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask;
+  hb_mask_t kern_mask;
+  unsigned int has_frac : 1;
+  unsigned int has_kern : 1;
+  unsigned int has_mark : 1;
+
+  inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
+  {
+    unsigned int table_index;
+    switch (table_tag) {
+      case HB_OT_TAG_GSUB: table_index = 0; break;
+      case HB_OT_TAG_GPOS: table_index = 1; break;
+      default: return;
+    }
+    map.collect_lookups (table_index, lookups);
+  }
+  inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
+  inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); }
+
+  void finish (void) { map.finish (); }
 };
 
-
-
-HB_INTERNAL hb_bool_t
-_hb_ot_shape (hb_font_t          *font,
-             hb_buffer_t        *buffer,
-             const hb_feature_t *features,
-             unsigned int        num_features);
-
-
-inline void
-_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
-{
-  info->unicode_props0() = ((unsigned int) hb_unicode_general_category (unicode, info->codepoint)) |
-                          (_hb_unicode_is_zero_width (info->codepoint) ? 0x80 : 0);
-  info->unicode_props1() = _hb_unicode_modified_combining_class (unicode, info->codepoint);
-}
-
-inline hb_unicode_general_category_t
-_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
+struct hb_ot_shape_planner_t
 {
-  return (hb_unicode_general_category_t) (info->unicode_props0() & 0x7F);
-}
+  /* In the order that they are filled in. */
+  hb_face_t *face;
+  hb_segment_properties_t props;
+  const struct hb_ot_complex_shaper_t *shaper;
+  hb_ot_map_builder_t map;
+
+  hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
+                        face (master_plan->face_unsafe),
+                        props (master_plan->props),
+                        shaper (NULL),
+                        map (face, &props) {}
+  ~hb_ot_shape_planner_t (void) { map.finish (); }
+
+  inline void compile (hb_ot_shape_plan_t &plan)
+  {
+    plan.props = props;
+    plan.shaper = shaper;
+    map.compile (plan.map);
+
+    plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
+    plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
+    plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
+    plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
+
+    plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
+                                       HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
+
+    plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
+    plan.has_kern = !!plan.kern_mask;
+    plan.has_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
+  }
 
-inline unsigned int
-_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
-{
-  return info->unicode_props1();
-}
+  private:
+  NO_COPY (hb_ot_shape_planner_t);
+};
 
-inline hb_bool_t
-_hb_glyph_info_is_zero_width (const hb_glyph_info_t *info)
-{
-  return !!(info->unicode_props0() & 0x80);
-}
 
 #endif /* HB_OT_SHAPE_PRIVATE_HH */
index 19cf680..07adb04 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright © 2009,2010  Red Hat, Inc.
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2010,2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
+#define HB_SHAPER ot
+#define hb_ot_shaper_face_data_t hb_ot_layout_t
+#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
+#include "hb-shaper-impl-private.hh"
+
 #include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-fallback-private.hh"
 #include "hb-ot-shape-normalize-private.hh"
 
-#include "hb-font-private.hh"
+#include "hb-ot-layout-private.hh"
+#include "hb-unicode-private.hh"
 #include "hb-set-private.hh"
 
 
-
-hb_tag_t common_features[] = {
+static hb_tag_t common_features[] = {
   HB_TAG('c','c','m','p'),
-  HB_TAG('l','i','g','a'),
   HB_TAG('l','o','c','l'),
   HB_TAG('m','a','r','k'),
   HB_TAG('m','k','m','k'),
@@ -44,62 +50,37 @@ hb_tag_t common_features[] = {
 };
 
 
-hb_tag_t horizontal_features[] = {
+static hb_tag_t horizontal_features[] = {
   HB_TAG('c','a','l','t'),
   HB_TAG('c','l','i','g'),
   HB_TAG('c','u','r','s'),
   HB_TAG('k','e','r','n'),
+  HB_TAG('l','i','g','a'),
+  HB_TAG('r','c','l','t'),
 };
 
-/* Note:
- * Technically speaking, vrt2 and vert are mutually exclusive.
- * According to the spec, valt and vpal are also mutually exclusive.
- * But we apply them all for now.
- */
-hb_tag_t vertical_features[] = {
-  HB_TAG('v','a','l','t'),
+static hb_tag_t vertical_features[] = {
   HB_TAG('v','e','r','t'),
-  HB_TAG('v','k','r','n'),
-  HB_TAG('v','p','a','l'),
-  HB_TAG('v','r','t','2'),
 };
 
 
 
-struct hb_ot_shape_planner_t
-{
-  hb_ot_map_builder_t map;
-  hb_ot_complex_shaper_t shaper;
-
-  hb_ot_shape_planner_t (void) : map () {}
-  ~hb_ot_shape_planner_t (void) { map.finish (); }
-
-  inline void compile (hb_face_t *face,
-                      const hb_segment_properties_t *props,
-                      struct hb_ot_shape_plan_t &plan)
-  {
-    plan.shaper = shaper;
-    map.compile (face, props, plan.map);
-  }
-
-  private:
-  NO_COPY (hb_ot_shape_planner_t);
-};
-
 static void
 hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
                              const hb_segment_properties_t  *props,
                              const hb_feature_t             *user_features,
                              unsigned int                    num_user_features)
 {
+  hb_ot_map_builder_t *map = &planner->map;
+
   switch (props->direction) {
     case HB_DIRECTION_LTR:
-      planner->map.add_bool_feature (HB_TAG ('l','t','r','a'));
-      planner->map.add_bool_feature (HB_TAG ('l','t','r','m'));
+      map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
+      map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
       break;
     case HB_DIRECTION_RTL:
-      planner->map.add_bool_feature (HB_TAG ('r','t','l','a'));
-      planner->map.add_bool_feature (HB_TAG ('r','t','l','m'), false);
+      map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
+      map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
       break;
     case HB_DIRECTION_TTB:
     case HB_DIRECTION_BTT:
@@ -108,33 +89,122 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t          *planner,
       break;
   }
 
-#define ADD_FEATURES(array) \
-  HB_STMT_START { \
-    for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \
-      planner->map.add_bool_feature (array[i]); \
-  } HB_STMT_END
+  map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
+  map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
+  map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
 
-  hb_ot_shape_complex_collect_features (planner->shaper, &planner->map, props);
+  if (planner->shaper->collect_features)
+    planner->shaper->collect_features (planner);
 
-  ADD_FEATURES (common_features);
+  for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
+    map->add_global_bool_feature (common_features[i]);
 
   if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
-    ADD_FEATURES (horizontal_features);
+    for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
+      map->add_feature (horizontal_features[i], 1, F_GLOBAL |
+                       (horizontal_features[i] == HB_TAG('k','e','r','n') ?
+                        F_HAS_FALLBACK : F_NONE));
   else
-    ADD_FEATURES (vertical_features);
+    for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++)
+      map->add_feature (vertical_features[i], 1, F_GLOBAL |
+                       (vertical_features[i] == HB_TAG('v','k','r','n') ?
+                        F_HAS_FALLBACK : F_NONE));
 
-#undef ADD_FEATURES
+  if (planner->shaper->override_features)
+    planner->shaper->override_features (planner);
 
   for (unsigned int i = 0; i < num_user_features; i++) {
     const hb_feature_t *feature = &user_features[i];
-    planner->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
+    map->add_feature (feature->tag, feature->value,
+                     (feature->start == 0 && feature->end == (unsigned int) -1) ?
+                      F_GLOBAL : F_NONE);
   }
 }
 
 
+/*
+ * shaper face data
+ */
+
+hb_ot_shaper_face_data_t *
+_hb_ot_shaper_face_data_create (hb_face_t *face)
+{
+  return _hb_ot_layout_create (face);
+}
+
+void
+_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
+{
+  _hb_ot_layout_destroy (data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_ot_shaper_font_data_t {};
+
+hb_ot_shaper_font_data_t *
+_hb_ot_shaper_font_data_create (hb_font_t *font)
+{
+  return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+hb_ot_shaper_shape_plan_data_t *
+_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan,
+                                     const hb_feature_t *user_features,
+                                     unsigned int        num_user_features)
+{
+  hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
+  if (unlikely (!plan))
+    return NULL;
+
+  hb_ot_shape_planner_t planner (shape_plan);
+
+  planner.shaper = hb_ot_shape_complex_categorize (&planner);
+
+  hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
+
+  planner.compile (*plan);
+
+  if (plan->shaper->data_create) {
+    plan->data = plan->shaper->data_create (plan);
+    if (unlikely (!plan->data))
+      return NULL;
+  }
+
+  return plan;
+}
+
+void
+_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
+{
+  if (plan->shaper->data_destroy)
+    plan->shaper->data_destroy (const_cast<void *> (plan->data));
+
+  plan->finish ();
+
+  free (plan);
+}
+
+
+/*
+ * shaper
+ */
+
 struct hb_ot_shape_context_t
 {
-  /* Input to hb_ot_shape_execute() */
   hb_ot_shape_plan_t *plan;
   hb_font_t *font;
   hb_face_t *face;
@@ -144,51 +214,61 @@ struct hb_ot_shape_context_t
 
   /* Transient stuff */
   hb_direction_t target_direction;
-  hb_bool_t applied_position_complex;
 };
 
-static void
-hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
-{
-  hb_mask_t global_mask = c->plan->map.get_global_mask ();
-  c->buffer->reset_masks (global_mask);
-
-  hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer, c->font);
-
-  for (unsigned int i = 0; i < c->num_user_features; i++)
-  {
-    const hb_feature_t *feature = &c->user_features[i];
-    if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
-      unsigned int shift;
-      hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
-      c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
-    }
-  }
-}
 
 
 /* Main shaper */
 
+
 /* Prepare */
 
 static void
 hb_set_unicode_props (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
+    _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
+}
+
+static void
+hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
+{
+  if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
+      buffer->context_len[0] ||
+      _hb_glyph_info_get_general_category (&buffer->info[0]) !=
+      HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    return;
+
+  if (!font->has_glyph (0x25CCu))
+    return;
+
+  hb_glyph_info_t dottedcircle = {0};
+  dottedcircle.codepoint = 0x25CCu;
+  _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
+
+  buffer->clear_output ();
+
+  buffer->idx = 0;
+  hb_glyph_info_t info = dottedcircle;
+  info.cluster = buffer->cur().cluster;
+  info.mask = buffer->cur().mask;
+  buffer->output_info (info);
+  while (buffer->idx < buffer->len)
+    buffer->next_glyph ();
+
+  buffer->swap_buffers ();
 }
 
 static void
 hb_form_clusters (hb_buffer_t *buffer)
 {
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 1; i < count; i++)
-    if (FLAG (_hb_glyph_info_get_general_category (&buffer->info[i])) &
-       (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
-        FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
-        FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
-      buffer->info[i].cluster = buffer->info[i - 1].cluster; /* XXX do the min() here */
+    if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
+      buffer->merge_clusters (i - 1, i + 1);
 }
 
 static void
@@ -211,286 +291,478 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
 
 /* Substitute */
 
-static void
-hb_mirror_chars (hb_ot_shape_context_t *c)
+static inline void
+hb_ot_mirror_chars (hb_ot_shape_context_t *c)
 {
-  hb_unicode_funcs_t *unicode = c->buffer->unicode;
-
   if (HB_DIRECTION_IS_FORWARD (c->target_direction))
     return;
 
-  hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
+  hb_buffer_t *buffer = c->buffer;
+  hb_unicode_funcs_t *unicode = buffer->unicode;
+  hb_mask_t rtlm_mask = c->plan->rtlm_mask;
 
-  unsigned int count = c->buffer->len;
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++) {
-    hb_codepoint_t codepoint = hb_unicode_mirroring (unicode, c->buffer->info[i].codepoint);
-    if (likely (codepoint == c->buffer->info[i].codepoint))
-      c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
+    hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
+    if (likely (codepoint == info[i].codepoint))
+      info[i].mask |= rtlm_mask;
     else
-      c->buffer->info[i].codepoint = codepoint;
+      info[i].codepoint = codepoint;
   }
 }
 
-static void
-hb_map_glyphs (hb_font_t    *font,
-              hb_buffer_t  *buffer)
+static inline void
+hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
 {
-  hb_codepoint_t glyph;
-
-  if (unlikely (!buffer->len))
+  if (!c->plan->has_frac)
     return;
 
-  buffer->clear_output ();
+  hb_buffer_t *buffer = c->buffer;
 
-  unsigned int count = buffer->len - 1;
-  for (buffer->idx = 0; buffer->idx < count;) {
-    if (unlikely (_hb_unicode_is_variation_selector (buffer->cur(+1).codepoint))) {
-      hb_font_get_glyph (font, buffer->cur().codepoint, buffer->cur(+1).codepoint, &glyph);
-      buffer->replace_glyphs (2, 1, &glyph);
-    } else {
-      hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph);
-      buffer->replace_glyph (glyph);
+  /* TODO look in pre/post context text also. */
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
+    {
+      unsigned int start = i, end = i + 1;
+      while (start &&
+            _hb_glyph_info_get_general_category (&info[start - 1]) ==
+            HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+        start--;
+      while (end < count &&
+            _hb_glyph_info_get_general_category (&info[end]) ==
+            HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+        end++;
+
+      for (unsigned int j = start; j < i; j++)
+        info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
+      info[i].mask |= c->plan->frac_mask;
+      for (unsigned int j = i + 1; j < end; j++)
+        info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
+
+      i = end - 1;
     }
   }
-  if (likely (buffer->idx < buffer->len)) {
-    hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph);
-    buffer->replace_glyph (glyph);
+}
+
+static inline void
+hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
+{
+  hb_ot_map_t *map = &c->plan->map;
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_mask_t global_mask = map->get_global_mask ();
+  buffer->reset_masks (global_mask);
+}
+
+static inline void
+hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
+{
+  hb_ot_map_t *map = &c->plan->map;
+  hb_buffer_t *buffer = c->buffer;
+
+  hb_ot_shape_setup_masks_fraction (c);
+
+  if (c->plan->shaper->setup_masks)
+    c->plan->shaper->setup_masks (c->plan, buffer, c->font);
+
+  for (unsigned int i = 0; i < c->num_user_features; i++)
+  {
+    const hb_feature_t *feature = &c->user_features[i];
+    if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
+      unsigned int shift;
+      hb_mask_t mask = map->get_mask (feature->tag, &shift);
+      buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
+    }
   }
-  buffer->swap_buffers ();
 }
 
-static void
-hb_substitute_default (hb_ot_shape_context_t *c)
+static inline void
+hb_ot_map_glyphs_fast (hb_buffer_t  *buffer)
+{
+  /* Normalization process sets up glyph_index(), we just copy it. */
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    info[i].codepoint = info[i].glyph_index();
+}
+
+static inline void
+hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
+{
+  unsigned int count = c->buffer->len;
+  hb_glyph_info_t *info = c->buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    hb_ot_layout_glyph_class_mask_t klass;
+
+    /* Never mark default-ignorables as marks.
+     * They won't get in the way of lookups anyway,
+     * but having them as mark will cause them to be skipped
+     * over if the lookup-flag says so, but at least for the
+     * Mongolian variation selectors, looks like Uniscribe
+     * marks them as non-mark.  Some Mongolian fonts without
+     * GDEF rely on this.  Another notable character that
+     * this applies to is COMBINING GRAPHEME JOINER. */
+    klass = (_hb_glyph_info_get_general_category (&info[i]) !=
+            HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
+            _hb_glyph_info_is_default_ignorable (&info[i])) ?
+           HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
+           HB_OT_LAYOUT_GLYPH_PROPS_MARK;
+    _hb_glyph_info_set_glyph_props (&info[i], klass);
+  }
+}
+
+static inline void
+hb_ot_substitute_default (hb_ot_shape_context_t *c)
 {
-  hb_ot_layout_substitute_start (c->buffer);
+  hb_buffer_t *buffer = c->buffer;
+
+  if (c->plan->shaper->preprocess_text)
+    c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
+
+  hb_ot_shape_initialize_masks (c);
+
+  hb_ot_mirror_chars (c);
+
+  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
+
+  _hb_ot_shape_normalize (c->plan, buffer, c->font);
 
-  hb_mirror_chars (c);
+  hb_ot_shape_setup_masks (c);
+
+  /* This is unfortunate to go here, but necessary... */
+  if (!hb_ot_layout_has_positioning (c->face))
+    _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
 
-  hb_map_glyphs (c->font, c->buffer);
+  hb_ot_map_glyphs_fast (buffer);
+
+  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
 }
 
-static void
+static inline void
 hb_ot_substitute_complex (hb_ot_shape_context_t *c)
 {
-  if (hb_ot_layout_has_substitution (c->face)) {
-    c->plan->map.substitute (c->face, c->buffer);
-  }
+  hb_buffer_t *buffer = c->buffer;
+
+  _hb_buffer_allocate_gsubgpos_vars (buffer);
+  hb_ot_layout_substitute_start (c->font, buffer);
+
+  if (!hb_ot_layout_has_glyph_classes (c->face))
+    hb_synthesize_glyph_classes (c);
+
+  c->plan->substitute (c->font, buffer);
 
-  hb_ot_layout_substitute_finish (c->buffer);
+  hb_ot_layout_substitute_finish (c->font, buffer);
 
   return;
 }
 
+static inline void
+hb_ot_substitute (hb_ot_shape_context_t *c)
+{
+  hb_ot_substitute_default (c);
+  hb_ot_substitute_complex (c);
+}
 
 /* Position */
 
-static void
-hb_position_default (hb_ot_shape_context_t *c)
+static inline void
+adjust_mark_offsets (hb_glyph_position_t *pos)
+{
+  pos->x_offset -= pos->x_advance;
+  pos->y_offset -= pos->y_advance;
+}
+
+static inline void
+zero_mark_width (hb_glyph_position_t *pos)
+{
+  pos->x_advance = 0;
+  pos->y_advance = 0;
+}
+
+static inline void
+zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
 {
-  hb_ot_layout_position_start (c->buffer);
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+    {
+      if (adjust_offsets)
+        adjust_mark_offsets (&buffer->pos[i]);
+      zero_mark_width (&buffer->pos[i]);
+    }
+}
 
+static inline void
+zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
+{
+  unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
+  for (unsigned int i = 0; i < count; i++)
+    if (_hb_glyph_info_is_mark (&info[i]))
+    {
+      if (adjust_offsets)
+        adjust_mark_offsets (&buffer->pos[i]);
+      zero_mark_width (&buffer->pos[i]);
+    }
+}
+
+static inline void
+hb_ot_position_default (hb_ot_shape_context_t *c)
+{
+  hb_direction_t direction = c->buffer->props.direction;
   unsigned int count = c->buffer->len;
-  for (unsigned int i = 0; i < count; i++) {
-    hb_font_get_glyph_advance_for_direction (c->font, c->buffer->info[i].codepoint,
-                                            c->buffer->props.direction,
-                                            &c->buffer->pos[i].x_advance,
-                                            &c->buffer->pos[i].y_advance);
-    hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
-                                                c->buffer->props.direction,
-                                                &c->buffer->pos[i].x_offset,
-                                                &c->buffer->pos[i].y_offset);
+  hb_glyph_info_t *info = c->buffer->info;
+  hb_glyph_position_t *pos = c->buffer->pos;
+  for (unsigned int i = 0; i < count; i++)
+  {
+    c->font->get_glyph_advance_for_direction (info[i].codepoint,
+                                             direction,
+                                             &pos[i].x_advance,
+                                             &pos[i].y_advance);
+    c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+                                                 direction,
+                                                 &pos[i].x_offset,
+                                                 &pos[i].y_offset);
+
   }
 }
 
-static void
+static inline bool
 hb_ot_position_complex (hb_ot_shape_context_t *c)
 {
+  bool ret = false;
+  unsigned int count = c->buffer->len;
+  bool has_positioning = hb_ot_layout_has_positioning (c->face);
+  /* If the font has no GPOS, AND, no fallback positioning will
+   * happen, AND, direction is forward, then when zeroing mark
+   * widths, we shift the mark with it, such that the mark
+   * is positioned hanging over the previous glyph.  When
+   * direction is backward we don't shift and it will end up
+   * hanging over the next glyph after the final reordering.
+   * If fallback positinoing happens or GPOS is present, we don't
+   * care.
+   */
+  bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
+                                       HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
+
+  switch (c->plan->shaper->zero_width_marks)
+  {
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
+      zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
+      break;
 
-  if (hb_ot_layout_has_positioning (c->face))
+    /* Not currently used for any shaper:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
+      zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
+      break;
+    */
+
+    default:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+      break;
+  }
+
+  if (has_positioning)
   {
+    hb_glyph_info_t *info = c->buffer->info;
+    hb_glyph_position_t *pos = c->buffer->pos;
+
     /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
 
-    unsigned int count = c->buffer->len;
     for (unsigned int i = 0; i < count; i++) {
-      hb_font_add_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
-                                             HB_DIRECTION_LTR,
-                                             &c->buffer->pos[i].x_offset,
-                                             &c->buffer->pos[i].y_offset);
+      c->font->add_glyph_origin_for_direction (info[i].codepoint,
+                                              HB_DIRECTION_LTR,
+                                              &pos[i].x_offset,
+                                              &pos[i].y_offset);
     }
 
-    c->plan->map.position (c->font, c->buffer);
+    c->plan->position (c->font, c->buffer);
 
     for (unsigned int i = 0; i < count; i++) {
-      hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
-                                                  HB_DIRECTION_LTR,
-                                                  &c->buffer->pos[i].x_offset,
-                                                  &c->buffer->pos[i].y_offset);
+      c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+                                                   HB_DIRECTION_LTR,
+                                                   &pos[i].x_offset,
+                                                   &pos[i].y_offset);
     }
 
-    c->applied_position_complex = true;
+    ret = true;
   }
 
-  hb_ot_layout_position_finish (c->buffer);
-
-  return;
-}
+  switch (c->plan->shaper->zero_width_marks)
+  {
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
+      zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
+      break;
 
-static void
-hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
-{
-  /* TODO Mark pos */
-}
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+      zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
+      break;
 
-static void
-hb_truetype_kern (hb_ot_shape_context_t *c)
-{
-  /* TODO Check for kern=0 */
-  unsigned int count = c->buffer->len;
-  for (unsigned int i = 1; i < count; i++) {
-    hb_position_t x_kern, y_kern, kern1, kern2;
-    hb_font_get_glyph_kerning_for_direction (c->font,
-                                            c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint,
-                                            c->buffer->props.direction,
-                                            &x_kern, &y_kern);
-
-    kern1 = x_kern >> 1;
-    kern2 = x_kern - kern1;
-    c->buffer->pos[i - 1].x_advance += kern1;
-    c->buffer->pos[i].x_advance += kern2;
-    c->buffer->pos[i].x_offset += kern2;
-
-    kern1 = y_kern >> 1;
-    kern2 = y_kern - kern1;
-    c->buffer->pos[i - 1].y_advance += kern1;
-    c->buffer->pos[i].y_advance += kern2;
-    c->buffer->pos[i].y_offset += kern2;
+    default:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+    //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
+    case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
+      break;
   }
+
+  return ret;
 }
 
-static void
-hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
+static inline void
+hb_ot_position (hb_ot_shape_context_t *c)
 {
-  hb_truetype_kern (c);
+  hb_ot_layout_position_start (c->font, c->buffer);
+
+  hb_ot_position_default (c);
+
+  hb_bool_t fallback = !hb_ot_position_complex (c);
+
+  hb_ot_layout_position_finish (c->font, c->buffer);
+
+  if (fallback && c->plan->shaper->fallback_position)
+    _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
+
+  if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
+    hb_buffer_reverse (c->buffer);
+
+  /* Visual fallback goes here. */
+
+  if (fallback)
+    _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
+
+  _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
 }
 
+
+/* Post-process */
+
 static void
-hb_hide_zerowidth (hb_ot_shape_context_t *c)
+hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
 {
-  /* TODO Save the space character in the font? */
+  if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
+    return;
+
   hb_codepoint_t space;
-  if (!hb_font_get_glyph (c->font, ' ', 0, &space))
-    return; /* No point! */
+  enum {
+    SPACE_DONT_KNOW,
+    SPACE_AVAILABLE,
+    SPACE_UNAVAILABLE
+  } space_status = SPACE_DONT_KNOW;
 
   unsigned int count = c->buffer->len;
+  hb_glyph_info_t *info = c->buffer->info;
+  hb_glyph_position_t *pos = c->buffer->pos;
+  unsigned int j = 0;
   for (unsigned int i = 0; i < count; i++)
-    if (unlikely (_hb_glyph_info_is_zero_width (&c->buffer->info[i]))) {
-      c->buffer->info[i].codepoint = space;
-      c->buffer->pos[i].x_advance = 0;
-      c->buffer->pos[i].y_advance = 0;
+  {
+    if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
+                 _hb_glyph_info_is_default_ignorable (&info[i])))
+    {
+      if (space_status == SPACE_DONT_KNOW)
+       space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
+
+      if (space_status == SPACE_AVAILABLE)
+      {
+       info[i].codepoint = space;
+       pos[i].x_advance = 0;
+       pos[i].y_advance = 0;
+      }
+      else
+       continue; /* Delete it. XXX Merge clusters? */
+    }
+    if (j != i)
+    {
+      info[j] = info[i];
+      pos[j] = pos[i];
     }
+    j++;
+  }
+  c->buffer->len = j;
 }
 
 
-/* Do it! */
+/* Pull it all together! */
 
 static void
-hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
+hb_ot_shape_internal (hb_ot_shape_context_t *c)
 {
   c->buffer->deallocate_var_all ();
 
   /* Save the original direction, we use it later. */
   c->target_direction = c->buffer->props.direction;
 
-  HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props0);
-  HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props1);
+  _hb_buffer_allocate_unicode_vars (c->buffer);
 
-  hb_set_unicode_props (c->buffer);
+  c->buffer->clear_output ();
 
+  hb_set_unicode_props (c->buffer);
+  hb_insert_dotted_circle (c->buffer, c->font);
   hb_form_clusters (c->buffer);
 
   hb_ensure_native_direction (c->buffer);
 
-  _hb_ot_shape_normalize (c->font, c->buffer, hb_ot_shape_complex_normalization_preference (c->plan->shaper));
-
-  hb_ot_shape_setup_masks (c);
-
-  /* SUBSTITUTE */
-  {
-    hb_substitute_default (c);
-
-    hb_ot_substitute_complex (c);
-  }
-
-  /* POSITION */
-  {
-    hb_position_default (c);
-
-    hb_ot_position_complex (c);
+  hb_ot_substitute (c);
+  hb_ot_position (c);
 
-    hb_bool_t position_fallback = !c->applied_position_complex;
-    if (position_fallback)
-      hb_position_complex_fallback (c);
+  hb_ot_hide_default_ignorables (c);
 
-    if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
-      hb_buffer_reverse (c->buffer);
-
-    if (position_fallback)
-      hb_position_complex_fallback_visual (c);
-  }
-
-  hb_hide_zerowidth (c);
-
-  HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1);
-  HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0);
+  _hb_buffer_deallocate_unicode_vars (c->buffer);
 
   c->buffer->props.direction = c->target_direction;
 
   c->buffer->deallocate_var_all ();
 }
 
-static void
-hb_ot_shape_plan_internal (hb_ot_shape_plan_t       *plan,
-                          hb_face_t                *face,
-                          const hb_segment_properties_t  *props,
-                          const hb_feature_t       *user_features,
-                          unsigned int              num_user_features)
-{
-  hb_ot_shape_planner_t planner;
-
-  assert (HB_DIRECTION_IS_VALID (props->direction));
-
-  planner.shaper = hb_ot_shape_complex_categorize (props);
-
-  hb_ot_shape_collect_features (&planner, props, user_features, num_user_features);
-
-  planner.compile (face, props, *plan);
-}
-
-static void
-hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
-                    hb_font_t          *font,
-                    hb_buffer_t        *buffer,
-                    const hb_feature_t *user_features,
-                    unsigned int        num_user_features)
-{
-  hb_ot_shape_context_t c = {plan, font, font->face, buffer, user_features, num_user_features};
-  hb_ot_shape_execute_internal (&c);
-}
 
 hb_bool_t
-_hb_ot_shape (hb_font_t          *font,
+_hb_ot_shape (hb_shape_plan_t    *shape_plan,
+             hb_font_t          *font,
              hb_buffer_t        *buffer,
              const hb_feature_t *features,
              unsigned int        num_features)
 {
-  hb_ot_shape_plan_t plan;
+  hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
+  hb_ot_shape_internal (&c);
 
-  buffer->guess_properties ();
+  return true;
+}
 
-  hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
-  hb_ot_shape_execute (&plan, font, buffer, features, num_features);
 
-  return true;
+void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+                                 hb_tag_t         table_tag,
+                                 hb_set_t        *lookup_indexes /* OUT */)
+{
+  /* XXX Does the first part always succeed? */
+  HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
+}
+
+
+/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
+static void
+add_char (hb_font_t          *font,
+         hb_unicode_funcs_t *unicode,
+         hb_bool_t           mirror,
+         hb_codepoint_t      u,
+         hb_set_t           *glyphs)
+{
+  hb_codepoint_t glyph;
+  if (font->get_glyph (u, 0, &glyph))
+    glyphs->add (glyph);
+  if (mirror)
+  {
+    hb_codepoint_t m = unicode->mirroring (u);
+    if (m != u && font->get_glyph (m, 0, &glyph))
+      glyphs->add (glyph);
+  }
 }
 
 
@@ -503,26 +775,29 @@ hb_ot_shape_glyphs_closure (hb_font_t          *font,
 {
   hb_ot_shape_plan_t plan;
 
-  buffer->guess_properties ();
-
-  hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
+  const char *shapers[] = {"ot", NULL};
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
+                                                            features, num_features, shapers);
 
-  /* TODO: normalization? have shapers do closure()? */
-  /* TODO: Deal with mirrored chars? */
-  hb_map_glyphs (font, buffer);
+  bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
 
-  /* Seed it.  It's user's responsibility to have cleard glyphs
-   * if that's what they desire. */
   unsigned int count = buffer->len;
+  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
-    hb_set_add (glyphs, buffer->info[i].codepoint);
+    add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
+
+  hb_set_t lookups;
+  lookups.init ();
+  hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
 
   /* And find transitive closure. */
   hb_set_t copy;
   copy.init ();
-
   do {
     copy.set (glyphs);
-    plan.map.substitute_closure (font->face, glyphs);
-  } while (!copy.equal (glyphs));
+    for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
+      hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
+  } while (!copy.is_equal (glyphs));
+
+  hb_shape_plan_destroy (shape_plan);
 }
diff --git a/src/hb-ot-shape.h b/src/hb-ot-shape.h
new file mode 100644 (file)
index 0000000..1402f54
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_SHAPE_H
+#define HB_OT_SHAPE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+/* TODO port to shape-plan / set. */
+void
+hb_ot_shape_glyphs_closure (hb_font_t          *font,
+                           hb_buffer_t        *buffer,
+                           const hb_feature_t *features,
+                           unsigned int        num_features,
+                           hb_set_t           *glyphs);
+
+void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+                                 hb_tag_t         table_tag,
+                                 hb_set_t        *lookup_indexes /* OUT */);
+
+HB_END_DECLS
+
+#endif /* HB_OT_SHAPE_H */
index ac60e96..878dd79 100644 (file)
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
- * Google Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
  */
 
 #include "hb-private.hh"
-#include "hb-ot.h"
 
 #include <string.h>
 
@@ -38,6 +37,8 @@
 static hb_tag_t
 hb_ot_old_tag_from_script (hb_script_t script)
 {
+  /* This seems to be accurate as of end of 2012. */
+
   switch ((hb_tag_t) script) {
     case HB_SCRIPT_INVALID:            return HB_OT_TAG_DEFAULT_SCRIPT;
 
@@ -56,7 +57,7 @@ hb_ot_old_tag_from_script (hb_script_t script)
   }
 
   /* Else, just change first char to lowercase and return */
-  return ((hb_tag_t) script) | 0x20000000;
+  return ((hb_tag_t) script) | 0x20000000u;
 }
 
 static hb_script_t
@@ -69,13 +70,13 @@ hb_ot_old_tag_to_script (hb_tag_t tag)
 
   /* Any spaces at the end of the tag are replaced by repeating the last
    * letter.  Eg 'nko ' -> 'Nkoo' */
-  if (unlikely ((tag & 0x0000FF00) == 0x00002000))
-    tag |= (tag >> 8) & 0x0000FF00; /* Copy second letter to third */
-  if (unlikely ((tag & 0x000000FF) == 0x00000020))
-    tag |= (tag >> 8) & 0x000000FF; /* Copy third letter to fourth */
+  if (unlikely ((tag & 0x0000FF00u) == 0x00002000u))
+    tag |= (tag >> 8) & 0x0000FF00u; /* Copy second letter to third */
+  if (unlikely ((tag & 0x000000FFu) == 0x00000020u))
+    tag |= (tag >> 8) & 0x000000FFu; /* Copy third letter to fourth */
 
   /* Change first char to uppercase and return */
-  return (hb_script_t) (tag & ~0x20000000);
+  return (hb_script_t) (tag & ~0x20000000u);
 }
 
 static hb_tag_t
@@ -91,6 +92,7 @@ hb_ot_new_tag_from_script (hb_script_t script)
     case HB_SCRIPT_ORIYA:              return HB_TAG('o','r','y','2');
     case HB_SCRIPT_TAMIL:              return HB_TAG('t','m','l','2');
     case HB_SCRIPT_TELUGU:             return HB_TAG('t','e','l','2');
+    case HB_SCRIPT_MYANMAR:            return HB_TAG('m','y','m','2');
   }
 
   return HB_OT_TAG_DEFAULT_SCRIPT;
@@ -109,6 +111,7 @@ hb_ot_new_tag_to_script (hb_tag_t tag)
     case HB_TAG('o','r','y','2'):      return HB_SCRIPT_ORIYA;
     case HB_TAG('t','m','l','2'):      return HB_SCRIPT_TAMIL;
     case HB_TAG('t','e','l','2'):      return HB_SCRIPT_TELUGU;
+    case HB_TAG('m','y','m','2'):      return HB_SCRIPT_MYANMAR;
   }
 
   return HB_SCRIPT_UNKNOWN;
@@ -143,7 +146,7 @@ hb_ot_tags_from_script (hb_script_t  script,
 hb_script_t
 hb_ot_tag_to_script (hb_tag_t tag)
 {
-  if (unlikely ((tag & 0x000000FF) == '2'))
+  if (unlikely ((tag & 0x000000FFu) == '2'))
     return hb_ot_new_tag_to_script (tag);
 
   return hb_ot_old_tag_to_script (tag);
@@ -153,7 +156,7 @@ hb_ot_tag_to_script (hb_tag_t tag)
 /* hb_language_t */
 
 typedef struct {
-  char language[6];
+  char language[4];
   hb_tag_t tag;
 } LangTag;
 
@@ -163,9 +166,14 @@ typedef struct {
  *
  * Generated by intersecting the OpenType language tag list from
  * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from
- * 2008/08/04, matching on name, and finally adjusted manually.
+ * 2008-08-04, matching on name, and finally adjusted manually.
+ *
+ * Updated on 2012-12-07 with more research into remaining codes.
+ *
+ * Updated on 2013-11-23 based on usage in SIL and Microsoft fonts,
+ * the new proposal from Microsoft, and latest ISO 639-3 names.
  *
- * Many items still missing.  Those are commented out at the end.
+ * Some items still missing.  Those are commented out at the end.
  * Keep sorted for bsearch.
  */
 
@@ -173,46 +181,102 @@ static const LangTag ot_languages[] = {
   {"aa",       HB_TAG('A','F','R',' ')},       /* Afar */
   {"ab",       HB_TAG('A','B','K',' ')},       /* Abkhazian */
   {"abq",      HB_TAG('A','B','A',' ')},       /* Abaza */
+  {"ach",      HB_TAG('A','C','H',' ')},       /* Acoli */
+  {"ada",      HB_TAG('D','N','G',' ')},       /* Dangme */
   {"ady",      HB_TAG('A','D','Y',' ')},       /* Adyghe */
   {"af",       HB_TAG('A','F','K',' ')},       /* Afrikaans */
+  {"aii",      HB_TAG('S','W','A',' ')},       /* Swadaya Aramaic */
+  {"aio",      HB_TAG('A','I','O',' ')},       /* Aiton */
   {"aiw",      HB_TAG('A','R','I',' ')},       /* Aari */
+  {"ak",       HB_TAG('T','W','I',' ')},       /* Akan [macrolanguage] */
+  {"alt",      HB_TAG('A','L','T',' ')},       /* [Southern] Altai */
   {"am",       HB_TAG('A','M','H',' ')},       /* Amharic */
-  {"ar",       HB_TAG('A','R','A',' ')},       /* Arabic */
+  {"amf",      HB_TAG('H','B','N',' ')},       /* Hammer-Banna */
+  {"an",       HB_TAG('A','R','G',' ')},       /* Aragonese */
+  {"ang",      HB_TAG('A','N','G',' ')},       /* Old English (ca. 450-1100) */
+  {"ar",       HB_TAG('A','R','A',' ')},       /* Arabic [macrolanguage] */
+  {"arb",      HB_TAG('A','R','A',' ')},       /* Standard Arabic */
   {"arn",      HB_TAG('M','A','P',' ')},       /* Mapudungun */
+  {"ary",      HB_TAG('M','O','R',' ')},       /* Moroccan Arabic */
   {"as",       HB_TAG('A','S','M',' ')},       /* Assamese */
+  {"ast",      HB_TAG('A','S','T',' ')},       /* Asturian/Asturleonese/Bable/Leonese */
+  {"ath",      HB_TAG('A','T','H',' ')},       /* Athapaskan [family] */
+  {"atv",      HB_TAG('A','L','T',' ')},       /* [Northern] Altai */
   {"av",       HB_TAG('A','V','R',' ')},       /* Avaric */
   {"awa",      HB_TAG('A','W','A',' ')},       /* Awadhi */
-  {"ay",       HB_TAG('A','Y','M',' ')},       /* Aymara */
-  {"az",       HB_TAG('A','Z','E',' ')},       /* Azerbaijani */
+  {"ay",       HB_TAG('A','Y','M',' ')},       /* Aymara [macrolanguage] */
+  {"az",       HB_TAG('A','Z','E',' ')},       /* Azerbaijani [macrolanguage] */
+  {"azb",      HB_TAG('A','Z','B',' ')},       /* South Azerbaijani */
+  {"azj",      HB_TAG('A','Z','E',' ')},       /* North Azerbaijani */
   {"ba",       HB_TAG('B','S','H',' ')},       /* Bashkir */
-  {"bal",      HB_TAG('B','L','I',' ')},       /* Baluchi */
+  {"bai",      HB_TAG('B','M','L',' ')},       /* Bamileke [family] */
+  {"bal",      HB_TAG('B','L','I',' ')},       /* Baluchi [macrolangauge] */
+  {"ban",      HB_TAG('B','A','N',' ')},       /* Balinese */
+  {"bar",      HB_TAG('B','A','R',' ')},       /* Bavarian */
+  {"bbc",      HB_TAG('B','B','C',' ')},       /* Batak Toba */
+  {"bci",      HB_TAG('B','A','U',' ')},       /* Baoulé */
+  {"bcl",      HB_TAG('B','I','K',' ')},       /* Central Bikol */
   {"bcq",      HB_TAG('B','C','H',' ')},       /* Bench */
+  {"be",       HB_TAG('B','E','L',' ')},       /* Belarusian */
   {"bem",      HB_TAG('B','E','M',' ')},       /* Bemba (Zambia) */
+  {"ber",      HB_TAG('B','E','R',' ')},       /* Berber [family] */
   {"bfq",      HB_TAG('B','A','D',' ')},       /* Badaga */
   {"bft",      HB_TAG('B','L','T',' ')},       /* Balti */
+  {"bfy",      HB_TAG('B','A','G',' ')},       /* Baghelkhandi */
   {"bg",       HB_TAG('B','G','R',' ')},       /* Bulgarian */
+  {"bgc",      HB_TAG('B','G','C',' ')},       /* Haryanvi */
+  {"bgq",      HB_TAG('B','G','Q',' ')},       /* Bagri */
   {"bhb",      HB_TAG('B','H','I',' ')},       /* Bhili */
+  {"bhk",      HB_TAG('B','I','K',' ')},       /* Albay Bicolano (retired code) */
   {"bho",      HB_TAG('B','H','O',' ')},       /* Bhojpuri */
-  {"bik",      HB_TAG('B','I','K',' ')},       /* Bikol */
+  {"bi",       HB_TAG('B','I','S',' ')},       /* Bislama */
+  {"bik",      HB_TAG('B','I','K',' ')},       /* Bikol [macrolanguage] */
   {"bin",      HB_TAG('E','D','O',' ')},       /* Bini */
+  {"bjj",      HB_TAG('B','J','J',' ')},       /* Kanauji */
+  {"bjt",      HB_TAG('B','L','N',' ')},       /* Balanta-Ganja */
+  {"bla",      HB_TAG('B','K','F',' ')},       /* Blackfoot */
+  {"ble",      HB_TAG('B','L','N',' ')},       /* Balanta-Kentohe */
+  {"blk",      HB_TAG('B','L','K',' ')},       /* Pa'O/Pa'o Karen */
+  {"bln",      HB_TAG('B','I','K',' ')},       /* Southern Catanduanes Bikol */
   {"bm",       HB_TAG('B','M','B',' ')},       /* Bambara */
   {"bn",       HB_TAG('B','E','N',' ')},       /* Bengali */
   {"bo",       HB_TAG('T','I','B',' ')},       /* Tibetan */
+  {"bpy",      HB_TAG('B','P','Y',' ')},       /* Bishnupriya */
+  {"bqi",      HB_TAG('L','R','C',' ')},       /* Bakhtiari */
   {"br",       HB_TAG('B','R','E',' ')},       /* Breton */
+  {"bra",      HB_TAG('B','R','I',' ')},       /* Braj Bhasha */
   {"brh",      HB_TAG('B','R','H',' ')},       /* Brahui */
+  {"brx",      HB_TAG('B','R','X',' ')},       /* Bodo (India) */
   {"bs",       HB_TAG('B','O','S',' ')},       /* Bosnian */
   {"btb",      HB_TAG('B','T','I',' ')},       /* Beti (Cameroon) */
+  {"bto",      HB_TAG('B','I','K',' ')},       /* Rinconada Bikol */
+  {"bts",      HB_TAG('B','T','S',' ')},       /* Batak Simalungun */
+  {"bug",      HB_TAG('B','U','G',' ')},       /* Buginese */
+  {"bxr",      HB_TAG('R','B','U',' ')},       /* Russian Buriat */
+  {"byn",      HB_TAG('B','I','L',' ')},       /* Bilen */
   {"ca",       HB_TAG('C','A','T',' ')},       /* Catalan */
+  {"cbk",      HB_TAG('C','B','K',' ')},       /* Chavacano */
   {"ce",       HB_TAG('C','H','E',' ')},       /* Chechen */
   {"ceb",      HB_TAG('C','E','B',' ')},       /* Cebuano */
+  {"cgg",      HB_TAG('C','G','G',' ')},       /* Chiga */
+  {"ch",       HB_TAG('C','H','A',' ')},       /* Chamorro */
+  {"cho",      HB_TAG('C','H','O',' ')},       /* Choctaw */
   {"chp",      HB_TAG('C','H','P',' ')},       /* Chipewyan */
   {"chr",      HB_TAG('C','H','R',' ')},       /* Cherokee */
+  {"chy",      HB_TAG('C','H','Y',' ')},       /* Cheyenne */
+  {"ckb",      HB_TAG('K','U','R',' ')},       /* Central Kurdish (Sorani) */
+  {"ckt",      HB_TAG('C','H','K',' ')},       /* Chukchi */
   {"cop",      HB_TAG('C','O','P',' ')},       /* Coptic */
   {"cr",       HB_TAG('C','R','E',' ')},       /* Cree */
   {"crh",      HB_TAG('C','R','T',' ')},       /* Crimean Tatar */
+  {"crj",      HB_TAG('E','C','R',' ')},       /* [Southern] East Cree */
+  {"crl",      HB_TAG('E','C','R',' ')},       /* [Northern] East Cree */
   {"crm",      HB_TAG('M','C','R',' ')},       /* Moose Cree */
   {"crx",      HB_TAG('C','R','R',' ')},       /* Carrier */
   {"cs",       HB_TAG('C','S','Y',' ')},       /* Czech */
+  {"csb",      HB_TAG('C','S','B',' ')},       /* Kashubian */
+  {"ctg",      HB_TAG('C','T','G',' ')},       /* Chittagonian */
+  {"cts",      HB_TAG('B','I','K',' ')},       /* Northern Catanduanes Bikol */
   {"cu",       HB_TAG('C','S','L',' ')},       /* Church Slavic */
   {"cv",       HB_TAG('C','H','U',' ')},       /* Chuvash */
   {"cwd",      HB_TAG('D','C','R',' ')},       /* Woods Cree */
@@ -221,123 +285,210 @@ static const LangTag ot_languages[] = {
   {"dap",      HB_TAG('N','I','S',' ')},       /* Nisi (India) */
   {"dar",      HB_TAG('D','A','R',' ')},       /* Dargwa */
   {"de",       HB_TAG('D','E','U',' ')},       /* German */
-  {"din",      HB_TAG('D','N','K',' ')},       /* Dinka */
+  {"dgo",      HB_TAG('D','G','O',' ')},       /* Dogri */
+  {"dhd",      HB_TAG('M','A','W',' ')},       /* Dhundari */
+  {"din",      HB_TAG('D','N','K',' ')},       /* Dinka [macrolanguage] */
+  {"diq",      HB_TAG('D','I','Q',' ')},       /* Dimli */
+  {"dje",      HB_TAG('D','J','R',' ')},       /* Zarma */
   {"dng",      HB_TAG('D','U','N',' ')},       /* Dungan */
-  {"doi",      HB_TAG('D','G','R',' ')},       /* Dogri */
+  {"doi",      HB_TAG('D','G','R',' ')},       /* Dogri [macrolanguage] */
   {"dsb",      HB_TAG('L','S','B',' ')},       /* Lower Sorbian */
-  {"dv",       HB_TAG('D','I','V',' ')},       /* Dhivehi */
+  {"dv",       HB_TAG('D','I','V',' ')},       /* Dhivehi/Divehi/Maldivian */
+  {"dyu",      HB_TAG('J','U','L',' ')},       /* Jula */
   {"dz",       HB_TAG('D','Z','N',' ')},       /* Dzongkha */
   {"ee",       HB_TAG('E','W','E',' ')},       /* Ewe */
   {"efi",      HB_TAG('E','F','I',' ')},       /* Efik */
+  {"ekk",      HB_TAG('E','T','I',' ')},       /* Standard Estonian */
   {"el",       HB_TAG('E','L','L',' ')},       /* Modern Greek (1453-) */
+  {"emk",      HB_TAG('M','N','K',' ')},       /* Eastern Maninkakan */
   {"en",       HB_TAG('E','N','G',' ')},       /* English */
   {"eo",       HB_TAG('N','T','O',' ')},       /* Esperanto */
   {"eot",      HB_TAG('B','T','I',' ')},       /* Beti (Côte d'Ivoire) */
   {"es",       HB_TAG('E','S','P',' ')},       /* Spanish */
-  {"et",       HB_TAG('E','T','I',' ')},       /* Estonian */
+  {"et",       HB_TAG('E','T','I',' ')},       /* Estonian [macrolanguage] */
   {"eu",       HB_TAG('E','U','Q',' ')},       /* Basque */
   {"eve",      HB_TAG('E','V','N',' ')},       /* Even */
   {"evn",      HB_TAG('E','V','K',' ')},       /* Evenki */
-  {"fa",       HB_TAG('F','A','R',' ')},       /* Persian */
-  {"ff",       HB_TAG('F','U','L',' ')},       /* Fulah */
+  {"fa",       HB_TAG('F','A','R',' ')},       /* Persian [macrolanguage] */
+  {"ff",       HB_TAG('F','U','L',' ')},       /* Fulah [macrolanguage] */
   {"fi",       HB_TAG('F','I','N',' ')},       /* Finnish */
   {"fil",      HB_TAG('P','I','L',' ')},       /* Filipino */
   {"fj",       HB_TAG('F','J','I',' ')},       /* Fijian */
   {"fo",       HB_TAG('F','O','S',' ')},       /* Faroese */
   {"fon",      HB_TAG('F','O','N',' ')},       /* Fon */
   {"fr",       HB_TAG('F','R','A',' ')},       /* French */
+  {"frc",      HB_TAG('F','R','C',' ')},       /* Cajun French */
+  {"frp",      HB_TAG('F','R','P',' ')},       /* Arpitan/Francoprovençal */
   {"fur",      HB_TAG('F','R','L',' ')},       /* Friulian */
+  {"fuv",      HB_TAG('F','U','V',' ')},       /* Nigerian Fulfulde */
   {"fy",       HB_TAG('F','R','I',' ')},       /* Western Frisian */
   {"ga",       HB_TAG('I','R','I',' ')},       /* Irish */
   {"gaa",      HB_TAG('G','A','D',' ')},       /* Ga */
   {"gag",      HB_TAG('G','A','G',' ')},       /* Gagauz */
   {"gbm",      HB_TAG('G','A','W',' ')},       /* Garhwali */
   {"gd",       HB_TAG('G','A','E',' ')},       /* Scottish Gaelic */
+  {"gez",      HB_TAG('G','E','Z',' ')},       /* Ge'ez */
+  {"ggo",      HB_TAG('G','O','N',' ')},       /* Southern Gondi */
   {"gl",       HB_TAG('G','A','L',' ')},       /* Galician */
   {"gld",      HB_TAG('N','A','N',' ')},       /* Nanai */
-  {"gn",       HB_TAG('G','U','A',' ')},       /* Guarani */
-  {"gon",      HB_TAG('G','O','N',' ')},       /* Gondi */
+  {"glk",      HB_TAG('G','L','K',' ')},       /* Gilaki */
+  {"gn",       HB_TAG('G','U','A',' ')},       /* Guarani [macrolanguage] */
+  {"gno",      HB_TAG('G','O','N',' ')},       /* Northern Gondi */
+  {"gog",      HB_TAG('G','O','G',' ')},       /* Gogo */
+  {"gon",      HB_TAG('G','O','N',' ')},       /* Gondi [macrolanguage] */
   {"grt",      HB_TAG('G','R','O',' ')},       /* Garo */
+  {"gru",      HB_TAG('S','O','G',' ')},       /* Sodo Gurage */
   {"gu",       HB_TAG('G','U','J',' ')},       /* Gujarati */
+  {"guc",      HB_TAG('G','U','C',' ')},       /* Wayuu */
   {"guk",      HB_TAG('G','M','Z',' ')},       /* Gumuz */
-  {"gv",       HB_TAG('M','N','X',' ')},       /* Manx Gaelic */
+/*{"guk",      HB_TAG('G','U','K',' ')},*/     /* Gumuz (in SIL fonts) */
+  {"guz",      HB_TAG('G','U','Z',' ')},       /* Ekegusii/Gusii */
+  {"gv",       HB_TAG('M','N','X',' ')},       /* Manx */
   {"ha",       HB_TAG('H','A','U',' ')},       /* Hausa */
   {"har",      HB_TAG('H','R','I',' ')},       /* Harari */
+  {"haw",      HB_TAG('H','A','W',' ')},       /* Hawaiian */
+  {"hay",      HB_TAG('H','A','Y',' ')},       /* Haya */
+  {"haz",      HB_TAG('H','A','Z',' ')},       /* Hazaragi */
   {"he",       HB_TAG('I','W','R',' ')},       /* Hebrew */
+  {"hz",       HB_TAG('H','E','R',' ')},       /* Herero */
   {"hi",       HB_TAG('H','I','N',' ')},       /* Hindi */
   {"hil",      HB_TAG('H','I','L',' ')},       /* Hiligaynon */
+  {"hnd",      HB_TAG('H','N','D',' ')},       /* [Southern] Hindko */
+  {"hne",      HB_TAG('C','H','H',' ')},       /* Chattisgarhi */
+  {"hno",      HB_TAG('H','N','D',' ')},       /* [Northern] Hindko */
+  {"ho",       HB_TAG('H','M','O',' ')},       /* Hiri Motu */
   {"hoc",      HB_TAG('H','O',' ',' ')},       /* Ho */
+  {"hoj",      HB_TAG('H','A','R',' ')},       /* Harauti */
   {"hr",       HB_TAG('H','R','V',' ')},       /* Croatian */
   {"hsb",      HB_TAG('U','S','B',' ')},       /* Upper Sorbian */
-  {"ht",       HB_TAG('H','A','I',' ')},       /* Haitian */
+  {"ht",       HB_TAG('H','A','I',' ')},       /* Haitian/Haitian Creole */
   {"hu",       HB_TAG('H','U','N',' ')},       /* Hungarian */
   {"hy",       HB_TAG('H','Y','E',' ')},       /* Armenian */
+  {"hz",       HB_TAG('H','E','R',' ')},       /* Herero */
+  {"ia",       HB_TAG('I','N','A',' ')},       /* Interlingua (International Auxiliary Language Association) */
+  {"ibb",      HB_TAG('I','B','B',' ')},       /* Ibibio */
   {"id",       HB_TAG('I','N','D',' ')},       /* Indonesian */
+  {"ie",       HB_TAG('I','L','E',' ')},       /* Interlingue/Occidental */
   {"ig",       HB_TAG('I','B','O',' ')},       /* Igbo */
   {"igb",      HB_TAG('E','B','I',' ')},       /* Ebira */
+  {"ijc",      HB_TAG('I','J','O',' ')},       /* Izon */
+  {"ijo",      HB_TAG('I','J','O',' ')},       /* Ijo [family] */
+  {"ik",       HB_TAG('I','P','K',' ')},       /* Inupiaq [macrolanguage] */
+  {"ilo",      HB_TAG('I','L','O',' ')},       /* Ilokano */
   {"inh",      HB_TAG('I','N','G',' ')},       /* Ingush */
+  {"io",       HB_TAG('I','D','O',' ')},       /* Ido */
   {"is",       HB_TAG('I','S','L',' ')},       /* Icelandic */
   {"it",       HB_TAG('I','T','A',' ')},       /* Italian */
-  {"iu",       HB_TAG('I','N','U',' ')},       /* Inuktitut */
+  {"iu",       HB_TAG('I','N','U',' ')},       /* Inuktitut [macrolanguage] */
   {"ja",       HB_TAG('J','A','N',' ')},       /* Japanese */
+  {"jam",      HB_TAG('J','A','M',' ')},       /* Jamaican Creole English */
+  {"jbo",      HB_TAG('J','B','O',' ')},       /* Lojban */
   {"jv",       HB_TAG('J','A','V',' ')},       /* Javanese */
   {"ka",       HB_TAG('K','A','T',' ')},       /* Georgian */
+  {"kaa",      HB_TAG('K','R','K',' ')},       /* Karakalpak */
+  {"kab",      HB_TAG('K','A','B',' ')},       /* Kabyle */
   {"kam",      HB_TAG('K','M','B',' ')},       /* Kamba (Kenya) */
+  {"kar",      HB_TAG('K','R','N',' ')},       /* Karen [family] */
   {"kbd",      HB_TAG('K','A','B',' ')},       /* Kabardian */
+  {"kde",      HB_TAG('K','D','E',' ')},       /* Makonde */
   {"kdr",      HB_TAG('K','R','M',' ')},       /* Karaim */
   {"kdt",      HB_TAG('K','U','Y',' ')},       /* Kuy */
+  {"kex",      HB_TAG('K','K','N',' ')},       /* Kokni */
   {"kfr",      HB_TAG('K','A','C',' ')},       /* Kachchi */
   {"kfy",      HB_TAG('K','M','N',' ')},       /* Kumaoni */
+  {"kg",       HB_TAG('K','O','N',' ')},       /* Kongo [macrolanguage] */
   {"kha",      HB_TAG('K','S','I',' ')},       /* Khasi */
+  {"khb",      HB_TAG('X','B','D',' ')},       /* Lü */
+  {"kht",      HB_TAG('K','H','N',' ')},       /* Khamti (Microsoft fonts) */
+/*{"kht",      HB_TAG('K','H','T',' ')},*/     /* Khamti (OpenType spec and SIL fonts) */
   {"khw",      HB_TAG('K','H','W',' ')},       /* Khowar */
-  {"ki",       HB_TAG('K','I','K',' ')},       /* Kikuyu */
+  {"ki",       HB_TAG('K','I','K',' ')},       /* Gikuyu/Kikuyu */
+  {"kj",       HB_TAG('K','U','A',' ')},       /* Kuanyama/Kwanyama */
+  {"kjh",      HB_TAG('K','H','A',' ')},       /* Khakass */
+  {"kjp",      HB_TAG('K','J','P',' ')},       /* Pwo Eastern Karen */
   {"kk",       HB_TAG('K','A','Z',' ')},       /* Kazakh */
   {"kl",       HB_TAG('G','R','N',' ')},       /* Kalaallisut */
   {"kln",      HB_TAG('K','A','L',' ')},       /* Kalenjin */
   {"km",       HB_TAG('K','H','M',' ')},       /* Central Khmer */
+  {"kmb",      HB_TAG('M','B','N',' ')},       /* Kimbundu */
   {"kmw",      HB_TAG('K','M','O',' ')},       /* Komo (Democratic Republic of Congo) */
   {"kn",       HB_TAG('K','A','N',' ')},       /* Kannada */
+  {"knn",      HB_TAG('K','O','K',' ')},       /* Konkani */
   {"ko",       HB_TAG('K','O','R',' ')},       /* Korean */
   {"koi",      HB_TAG('K','O','P',' ')},       /* Komi-Permyak */
-  {"kok",      HB_TAG('K','O','K',' ')},       /* Konkani */
-  {"kpe",      HB_TAG('K','P','L',' ')},       /* Kpelle */
+  {"kok",      HB_TAG('K','O','K',' ')},       /* Konkani [macrolanguage] */
+  {"kpe",      HB_TAG('K','P','L',' ')},       /* Kpelle [macrolanguage] */
   {"kpv",      HB_TAG('K','O','Z',' ')},       /* Komi-Zyrian */
   {"kpy",      HB_TAG('K','Y','K',' ')},       /* Koryak */
   {"kqy",      HB_TAG('K','R','T',' ')},       /* Koorete */
-  {"kr",       HB_TAG('K','N','R',' ')},       /* Kanuri */
+  {"kr",       HB_TAG('K','N','R',' ')},       /* Kanuri [macrolanguage] */
   {"kri",      HB_TAG('K','R','I',' ')},       /* Krio */
   {"krl",      HB_TAG('K','R','L',' ')},       /* Karelian */
   {"kru",      HB_TAG('K','U','U',' ')},       /* Kurukh */
   {"ks",       HB_TAG('K','S','H',' ')},       /* Kashmiri */
-  {"ku",       HB_TAG('K','U','R',' ')},       /* Kurdish */
+  {"ksh",      HB_TAG('K','S','H',' ')},       /* Kölsch */
+/*{"ksw",      HB_TAG('K','R','N',' ')},*/     /* S'gaw Karen (Microsoft fonts?) */
+  {"ksw",      HB_TAG('K','S','W',' ')},       /* S'gaw Karen (OpenType spec and SIL fonts) */
+  {"ku",       HB_TAG('K','U','R',' ')},       /* Kurdish [macrolanguage] */
   {"kum",      HB_TAG('K','U','M',' ')},       /* Kumyk */
+  {"kv",       HB_TAG('K','O','M',' ')},       /* Komi [macrolanguage] */
   {"kvd",      HB_TAG('K','U','I',' ')},       /* Kui (Indonesia) */
+  {"kw",       HB_TAG('C','O','R',' ')},       /* Cornish */
+  {"kxc",      HB_TAG('K','M','S',' ')},       /* Komso */
   {"kxu",      HB_TAG('K','U','I',' ')},       /* Kui (India) */
-  {"ky",       HB_TAG('K','I','R',' ')},       /* Kirghiz */
+  {"ky",       HB_TAG('K','I','R',' ')},       /* Kirghiz/Kyrgyz */
+  {"kyu",      HB_TAG('K','Y','U',' ')},       /* Western Kayah */
   {"la",       HB_TAG('L','A','T',' ')},       /* Latin */
   {"lad",      HB_TAG('J','U','D',' ')},       /* Ladino */
   {"lb",       HB_TAG('L','T','Z',' ')},       /* Luxembourgish */
   {"lbe",      HB_TAG('L','A','K',' ')},       /* Lak */
   {"lbj",      HB_TAG('L','D','K',' ')},       /* Ladakhi */
+  {"lez",      HB_TAG('L','E','Z',' ')},       /* Lezgi */
+  {"lg",       HB_TAG('L','U','G',' ')},       /* Ganda */
+  {"li",       HB_TAG('L','I','M',' ')},       /* Limburgan/Limburger/Limburgish */
   {"lif",      HB_TAG('L','M','B',' ')},       /* Limbu */
+  {"lij",      HB_TAG('L','I','J',' ')},       /* Ligurian */
+  {"lis",      HB_TAG('L','I','S',' ')},       /* Lisu */
+  {"ljp",      HB_TAG('L','J','P',' ')},       /* Lampung Api */
+  {"lki",      HB_TAG('L','K','I',' ')},       /* Laki */
   {"lld",      HB_TAG('L','A','D',' ')},       /* Ladin */
+  {"lmn",      HB_TAG('L','A','M',' ')},       /* Lambani */
+  {"lmo",      HB_TAG('L','M','O',' ')},       /* Lombard */
   {"ln",       HB_TAG('L','I','N',' ')},       /* Lingala */
   {"lo",       HB_TAG('L','A','O',' ')},       /* Lao */
+  {"lrc",      HB_TAG('L','R','C',' ')},       /* Northern Luri */
   {"lt",       HB_TAG('L','T','H',' ')},       /* Lithuanian */
+  {"lu",       HB_TAG('L','U','B',' ')},       /* Luba-Katanga */
+  {"lua",      HB_TAG('L','U','B',' ')},       /* Luba-Kasai */
   {"luo",      HB_TAG('L','U','O',' ')},       /* Luo (Kenya and Tanzania) */
-  {"luw",      HB_TAG('L','U','O',' ')},       /* Luo (Cameroon) */
+  {"lus",      HB_TAG('M','I','Z',' ')},       /* Mizo */
+  {"luy",      HB_TAG('L','U','H',' ')},       /* Luyia/Oluluyia [macrolanguage] */
+  {"luz",      HB_TAG('L','R','C',' ')},       /* Southern Luri */
   {"lv",       HB_TAG('L','V','I',' ')},       /* Latvian */
   {"lzz",      HB_TAG('L','A','Z',' ')},       /* Laz */
+  {"mad",      HB_TAG('M','A','D',' ')},       /* Madurese */
+  {"mag",      HB_TAG('M','A','G',' ')},       /* Magahi */
   {"mai",      HB_TAG('M','T','H',' ')},       /* Maithili */
+  {"mak",      HB_TAG('M','K','R',' ')},       /* Makasar */
+  {"man",      HB_TAG('M','N','K',' ')},       /* Manding/Mandingo [macrolanguage] */
   {"mdc",      HB_TAG('M','L','E',' ')},       /* Male (Papua New Guinea) */
   {"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) */
-  {"mg",       HB_TAG('M','L','G',' ')},       /* Malagasy */
+  {"mer",      HB_TAG('M','E','R',' ')},       /* Meru */
+  {"mfe",      HB_TAG('M','F','E',' ')},       /* Morisyen */
+  {"mg",       HB_TAG('M','L','G',' ')},       /* Malagasy [macrolanguage] */
+  {"mh",       HB_TAG('M','A','H',' ')},       /* Marshallese */
+  {"mhr",      HB_TAG('L','M','A',' ')},       /* Low Mari */
   {"mi",       HB_TAG('M','R','I',' ')},       /* Maori */
+  {"min",      HB_TAG('M','I','N',' ')},       /* Minangkabau */
   {"mk",       HB_TAG('M','K','D',' ')},       /* Macedonian */
+  {"mku",      HB_TAG('M','N','K',' ')},       /* Konyanka Maninka */
+  {"mkw",      HB_TAG('M','K','W',' ')},       /* Kituba (Congo) */
   {"ml",       HB_TAG('M','L','R',' ')},       /* Malayalam */
-  {"mn",       HB_TAG('M','N','G',' ')},       /* Mongolian */
+  {"mlq",      HB_TAG('M','N','K',' ')},       /* Western Maninkakan */
+  {"mn",       HB_TAG('M','N','G',' ')},       /* Mongolian [macrolanguage] */
   {"mnc",      HB_TAG('M','C','H',' ')},       /* Manchu */
   {"mni",      HB_TAG('M','N','I',' ')},       /* Manipuri */
   {"mnk",      HB_TAG('M','N','D',' ')},       /* Mandinka */
@@ -345,57 +496,119 @@ static const LangTag ot_languages[] = {
   {"mnw",      HB_TAG('M','O','N',' ')},       /* Mon */
   {"mo",       HB_TAG('M','O','L',' ')},       /* Moldavian */
   {"moh",      HB_TAG('M','O','H',' ')},       /* Mohawk */
+  {"mos",      HB_TAG('M','O','S',' ')},       /* Mossi */
   {"mpe",      HB_TAG('M','A','J',' ')},       /* Majang */
   {"mr",       HB_TAG('M','A','R',' ')},       /* Marathi */
-  {"ms",       HB_TAG('M','L','Y',' ')},       /* Malay */
+  {"mrj",      HB_TAG('H','M','A',' ')},       /* High Mari */
+  {"ms",       HB_TAG('M','L','Y',' ')},       /* Malay [macrolanguage] */
+  {"msc",      HB_TAG('M','N','K',' ')},       /* Sankaran Maninka */
   {"mt",       HB_TAG('M','T','S',' ')},       /* Maltese */
-  {"mwr",      HB_TAG('M','A','W',' ')},       /* Marwari */
+  {"mtr",      HB_TAG('M','A','W',' ')},       /* Mewari */
+  {"mus",      HB_TAG('M','U','S',' ')},       /* Creek */
+  {"mve",      HB_TAG('M','A','W',' ')},       /* Marwari (Pakistan) */
+  {"mwk",      HB_TAG('M','N','K',' ')},       /* Kita Maninkakan */
+  {"mwl",      HB_TAG('M','W','L',' ')},       /* Mirandese */
+  {"mwr",      HB_TAG('M','A','W',' ')},       /* Marwari [macrolanguage] */
+  {"mww",      HB_TAG('M','W','W',' ')},       /* Hmong Daw */
   {"my",       HB_TAG('B','R','M',' ')},       /* Burmese */
   {"mym",      HB_TAG('M','E','N',' ')},       /* Me'en */
+  {"myq",      HB_TAG('M','N','K',' ')},       /* Forest Maninka (retired code) */
   {"myv",      HB_TAG('E','R','Z',' ')},       /* Erzya */
+  {"mzn",      HB_TAG('M','Z','N',' ')},       /* Mazanderani */
+  {"na",       HB_TAG('N','A','U',' ')},       /* Nauru */
+  {"nag",      HB_TAG('N','A','G',' ')},       /* Naga-Assamese */
+  {"nah",      HB_TAG('N','A','H',' ')},       /* Nahuatl [family] */
+  {"nap",      HB_TAG('N','A','P',' ')},       /* Neapolitan */
   {"nb",       HB_TAG('N','O','R',' ')},       /* Norwegian Bokmål */
   {"nco",      HB_TAG('S','I','B',' ')},       /* Sibe */
+  {"nd",       HB_TAG('N','D','B',' ')},       /* [North] Ndebele */
+  {"ndc",      HB_TAG('N','D','C',' ')},       /* Ndau */
+  {"nds",      HB_TAG('N','D','S',' ')},       /* Low German/Low Saxon */
   {"ne",       HB_TAG('N','E','P',' ')},       /* Nepali */
   {"new",      HB_TAG('N','E','W',' ')},       /* Newari */
   {"ng",       HB_TAG('N','D','G',' ')},       /* Ndonga */
+  {"nga",      HB_TAG('N','G','A',' ')},       /* Ngabaka */
   {"ngl",      HB_TAG('L','M','W',' ')},       /* Lomwe */
   {"niu",      HB_TAG('N','I','U',' ')},       /* Niuean */
   {"niv",      HB_TAG('G','I','L',' ')},       /* Gilyak */
   {"nl",       HB_TAG('N','L','D',' ')},       /* Dutch */
   {"nn",       HB_TAG('N','Y','N',' ')},       /* Norwegian Nynorsk */
-  {"no",       HB_TAG('N','O','R',' ')},       /* Norwegian (deprecated) */
+  {"no",       HB_TAG('N','O','R',' ')},       /* Norwegian [macrolanguage] */
+  {"nod",      HB_TAG('N','T','A',' ')},       /* Northern Thai */
+  {"noe",      HB_TAG('N','O','E',' ')},       /* Nimadi */
   {"nog",      HB_TAG('N','O','G',' ')},       /* Nogai */
+  {"nov",      HB_TAG('N','O','V',' ')},       /* Novial */
   {"nqo",      HB_TAG('N','K','O',' ')},       /* N'Ko */
+  {"nr",       HB_TAG('N','D','B',' ')},       /* [South] Ndebele */
   {"nsk",      HB_TAG('N','A','S',' ')},       /* Naskapi */
-  {"ny",       HB_TAG('C','H','I',' ')},       /* Nyanja */
+  {"nso",      HB_TAG('S','O','T',' ')},       /* [Northern] Sotho */
+  {"ny",       HB_TAG('C','H','I',' ')},       /* Chewa/Chichwa/Nyanja */
+  {"nym",      HB_TAG('N','Y','M',' ')},       /* Nyamwezi */
+  {"nyn",      HB_TAG('N','K','L',' ')},       /* Nyankole */
   {"oc",       HB_TAG('O','C','I',' ')},       /* Occitan (post 1500) */
-  {"oj",       HB_TAG('O','J','B',' ')},       /* Ojibwa */
-  {"om",       HB_TAG('O','R','O',' ')},       /* Oromo */
+  {"oj",       HB_TAG('O','J','B',' ')},       /* Ojibwa [macrolanguage] */
+  {"ojs",      HB_TAG('O','C','R',' ')},       /* Oji-Cree */
+  {"om",       HB_TAG('O','R','O',' ')},       /* Oromo [macrolanguage] */
   {"or",       HB_TAG('O','R','I',' ')},       /* Oriya */
   {"os",       HB_TAG('O','S','S',' ')},       /* Ossetian */
   {"pa",       HB_TAG('P','A','N',' ')},       /* Panjabi */
+  {"pag",      HB_TAG('P','A','G',' ')},       /* Pangasinan */
+  {"pam",      HB_TAG('P','A','M',' ')},       /* Kapampangan/Pampanga */
+  {"pap",      HB_TAG('P','A','P',' ')},       /* Papiamento */
+  {"pcc",      HB_TAG('P','C','C',' ')},       /* Bouyei */
+  {"pcd",      HB_TAG('P','C','D',' ')},       /* Picard */
+  {"pce",      HB_TAG('P','L','G',' ')},       /* [Ruching] Palaung */
+  {"pdc",      HB_TAG('P','D','C',' ')},       /* Pennsylvania German */
+  {"pes",      HB_TAG('F','A','R',' ')},       /* Iranian Persian */
+  {"phk",      HB_TAG('P','H','K',' ')},       /* Phake */
   {"pi",       HB_TAG('P','A','L',' ')},       /* Pali */
+  {"pih",      HB_TAG('P','I','H',' ')},       /* Pitcairn-Norfolk */
   {"pl",       HB_TAG('P','L','K',' ')},       /* Polish */
+  {"pll",      HB_TAG('P','L','G',' ')},       /* [Shwe] Palaung */
   {"plp",      HB_TAG('P','A','P',' ')},       /* Palpa */
-  {"prs",      HB_TAG('D','R','I',' ')},       /* Dari */
-  {"ps",       HB_TAG('P','A','S',' ')},       /* Pushto */
+  {"pms",      HB_TAG('P','M','S',' ')},       /* Piemontese */
+  {"pnb",      HB_TAG('P','N','B',' ')},       /* Western Panjabi */
+  {"prs",      HB_TAG('D','R','I',' ')},       /* Afghan Persian/Dari */
+  {"ps",       HB_TAG('P','A','S',' ')},       /* Pashto/Pushto [macrolanguage] */
   {"pt",       HB_TAG('P','T','G',' ')},       /* Portuguese */
-  {"raj",      HB_TAG('R','A','J',' ')},       /* Rajasthani */
+  {"pwo",      HB_TAG('P','W','O',' ')},       /* Pwo Western Karen */
+  {"qu",       HB_TAG('Q','U','Z',' ')},       /* Quechua [macrolanguage] */
+  {"quc",      HB_TAG('Q','U','C',' ')},       /* K'iche'/Quiché */
+  {"quz",      HB_TAG('Q','U','Z',' ')},       /* Cusco Quechua */
+  {"raj",      HB_TAG('R','A','J',' ')},       /* Rajasthani [macrolanguage] */
+  {"rbb",      HB_TAG('P','L','G',' ')},       /* Rumai Palaung */
+  {"rej",      HB_TAG('R','E','J',' ')},       /* Rejang */
   {"ria",      HB_TAG('R','I','A',' ')},       /* Riang (India) */
   {"ril",      HB_TAG('R','I','A',' ')},       /* Riang (Myanmar) */
+  {"rki",      HB_TAG('A','R','K',' ')},       /* Rakhine */
+  {"rm",       HB_TAG('R','M','S',' ')},       /* Romansh */
+  {"rmy",      HB_TAG('R','M','Y',' ')},       /* Vlax Romani */
+  {"rn",       HB_TAG('R','U','N',' ')},       /* Rundi */
   {"ro",       HB_TAG('R','O','M',' ')},       /* Romanian */
-  {"rom",      HB_TAG('R','O','Y',' ')},       /* Romany */
+  {"rom",      HB_TAG('R','O','Y',' ')},       /* Romany [macrolanguage] */
   {"ru",       HB_TAG('R','U','S',' ')},       /* Russian */
   {"rue",      HB_TAG('R','S','Y',' ')},       /* Rusyn */
+  {"rup",      HB_TAG('R','U','P',' ')},       /* Aromanian/Arumanian/Macedo-Romanian */
+  {"rw",       HB_TAG('R','U','A',' ')},       /* Kinyarwanda */
+  {"rwr",      HB_TAG('M','A','W',' ')},       /* Marwari (India) */
   {"sa",       HB_TAG('S','A','N',' ')},       /* Sanskrit */
   {"sah",      HB_TAG('Y','A','K',' ')},       /* Yakut */
+  {"sas",      HB_TAG('S','A','S',' ')},       /* Sasak */
   {"sat",      HB_TAG('S','A','T',' ')},       /* Santali */
   {"sck",      HB_TAG('S','A','D',' ')},       /* Sadri */
+  {"sc",       HB_TAG('S','R','D',' ')},       /* Sardinian [macrolanguage] */
+  {"scn",      HB_TAG('S','C','N',' ')},       /* Sicilian */
+  {"sco",      HB_TAG('S','C','O',' ')},       /* Scots */
+  {"scs",      HB_TAG('S','L','A',' ')},       /* [North] Slavey */
   {"sd",       HB_TAG('S','N','D',' ')},       /* Sindhi */
   {"se",       HB_TAG('N','S','M',' ')},       /* Northern Sami */
   {"seh",      HB_TAG('S','N','A',' ')},       /* Sena */
   {"sel",      HB_TAG('S','E','L',' ')},       /* Selkup */
   {"sg",       HB_TAG('S','G','O',' ')},       /* Sango */
+  {"sga",      HB_TAG('S','G','A',' ')},       /* Old Irish (to 900) */
+  {"sgs",      HB_TAG('S','G','S',' ')},       /* Samogitian */
+  {"sgw",      HB_TAG('C','H','G',' ')},       /* Sebat Bet Gurage */
+/*{"sgw",      HB_TAG('S','G','W',' ')},*/     /* Sebat Bet Gurage (in SIL fonts) */
   {"shn",      HB_TAG('S','H','N',' ')},       /* Shan */
   {"si",       HB_TAG('S','N','H',' ')},       /* Sinhala */
   {"sid",      HB_TAG('S','I','D',' ')},       /* Sidamo */
@@ -408,174 +621,160 @@ static const LangTag ot_languages[] = {
   {"smj",      HB_TAG('L','S','M',' ')},       /* Lule Sami */
   {"smn",      HB_TAG('I','S','M',' ')},       /* Inari Sami */
   {"sms",      HB_TAG('S','K','S',' ')},       /* Skolt Sami */
+  {"sn",       HB_TAG('S','N','A',' ')},       /* Shona */
   {"snk",      HB_TAG('S','N','K',' ')},       /* Soninke */
   {"so",       HB_TAG('S','M','L',' ')},       /* Somali */
-  {"sq",       HB_TAG('S','Q','I',' ')},       /* Albanian */
+  {"sop",      HB_TAG('S','O','P',' ')},       /* Songe */
+  {"sq",       HB_TAG('S','Q','I',' ')},       /* Albanian [macrolanguage] */
   {"sr",       HB_TAG('S','R','B',' ')},       /* Serbian */
   {"srr",      HB_TAG('S','R','R',' ')},       /* Serer */
+  {"ss",       HB_TAG('S','W','Z',' ')},       /* Swati */
+  {"st",       HB_TAG('S','O','T',' ')},       /* [Southern] Sotho */
+  {"stq",      HB_TAG('S','T','Q',' ')},       /* Saterfriesisch */
+  {"stv",      HB_TAG('S','I','G',' ')},       /* Silt'e */
+  {"su",       HB_TAG('S','U','N',' ')},       /* Sundanese */
+  {"suk",      HB_TAG('S','U','K',' ')},       /* Sukama */
   {"suq",      HB_TAG('S','U','R',' ')},       /* Suri */
   {"sv",       HB_TAG('S','V','E',' ')},       /* Swedish */
   {"sva",      HB_TAG('S','V','A',' ')},       /* Svan */
-  {"sw",       HB_TAG('S','W','K',' ')},       /* Swahili */
+  {"sw",       HB_TAG('S','W','K',' ')},       /* Swahili [macrolanguage] */
   {"swb",      HB_TAG('C','M','R',' ')},       /* Comorian */
-  {"syr",      HB_TAG('S','Y','R',' ')},       /* Syriac */
+  {"swh",      HB_TAG('S','W','K',' ')},       /* Kiswahili/Swahili */
+  {"swv",      HB_TAG('M','A','W',' ')},       /* Shekhawati */
+  {"sxu",      HB_TAG('S','X','U',' ')},       /* Upper Saxon */
+  {"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 */
+  {"tab",      HB_TAG('T','A','B',' ')},       /* Tabasaran */
   {"tcy",      HB_TAG('T','U','L',' ')},       /* Tulu */
+  {"tdd",      HB_TAG('T','D','D',' ')},       /* Tai Nüa */
   {"te",       HB_TAG('T','E','L',' ')},       /* Telugu */
+  {"tem",      HB_TAG('T','M','N',' ')},       /* Temne */
+  {"tet",      HB_TAG('T','E','T',' ')},       /* Tetum */
   {"tg",       HB_TAG('T','A','J',' ')},       /* Tajik */
   {"th",       HB_TAG('T','H','A',' ')},       /* Thai */
   {"ti",       HB_TAG('T','G','Y',' ')},       /* Tigrinya */
   {"tig",      HB_TAG('T','G','R',' ')},       /* Tigre */
+  {"tiv",      HB_TAG('T','I','V',' ')},       /* Tiv */
   {"tk",       HB_TAG('T','K','M',' ')},       /* Turkmen */
+  {"tl",       HB_TAG('T','G','L',' ')},       /* Tagalog */
+  {"tmh",      HB_TAG('t','m','h',' ')},       /* Tamashek [macrolanguage] */
   {"tn",       HB_TAG('T','N','A',' ')},       /* Tswana */
-  {"tnz",      HB_TAG('T','N','G',' ')},       /* Tonga (Thailand) */
-  {"to",       HB_TAG('T','N','G',' ')},       /* Tonga (Tonga Islands) */
-  {"tog",      HB_TAG('T','N','G',' ')},       /* Tonga (Nyasa) */
-  {"toi",      HB_TAG('T','N','G',' ')},       /* Tonga (Zambia) */
+  {"to",       HB_TAG('T','G','N',' ')},       /* Tonga (Tonga Islands) */
+  {"tpi",      HB_TAG('T','P','I',' ')},       /* Tok Pisin */
   {"tr",       HB_TAG('T','R','K',' ')},       /* Turkish */
+  {"tru",      HB_TAG('T','U','A',' ')},       /* Turoyo Aramaic */
   {"ts",       HB_TAG('T','S','G',' ')},       /* Tsonga */
   {"tt",       HB_TAG('T','A','T',' ')},       /* Tatar */
+  {"tum",      HB_TAG('T','U','M',' ')},       /* Tumbuka */
   {"tw",       HB_TAG('T','W','I',' ')},       /* Twi */
   {"ty",       HB_TAG('T','H','T',' ')},       /* Tahitian */
+  {"tyv",      HB_TAG('T','U','V',' ')},       /* Tuvin */
+  {"tyz",      HB_TAG('T','Y','Z',' ')},       /* Tày */
+  {"tzm",      HB_TAG('T','Z','M',' ')},       /* Central Atlas Tamazight */
   {"udm",      HB_TAG('U','D','M',' ')},       /* Udmurt */
   {"ug",       HB_TAG('U','Y','G',' ')},       /* Uighur */
   {"uk",       HB_TAG('U','K','R',' ')},       /* Ukrainian */
+  {"umb",      HB_TAG('U','M','B',' ')},       /* Umbundu */
   {"unr",      HB_TAG('M','U','N',' ')},       /* Mundari */
   {"ur",       HB_TAG('U','R','D',' ')},       /* Urdu */
-  {"uz",       HB_TAG('U','Z','B',' ')},       /* Uzbek */
+  {"uz",       HB_TAG('U','Z','B',' ')},       /* Uzbek [macrolanguage] */
+  {"uzn",      HB_TAG('U','Z','B',' ')},       /* Northern Uzbek */
+  {"uzs",      HB_TAG('U','Z','B',' ')},       /* Southern Uzbek */
   {"ve",       HB_TAG('V','E','N',' ')},       /* Venda */
+  {"vec",      HB_TAG('V','E','C',' ')},       /* Venetian */
+  {"vls",      HB_TAG('F','L','E',' ')},       /* Vlaams */
   {"vi",       HB_TAG('V','I','T',' ')},       /* Vietnamese */
+  {"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 */
+  {"war",      HB_TAG('W','A','R',' ')},       /* Waray (Philippines) */
   {"wbm",      HB_TAG('W','A',' ',' ')},       /* Wa */
   {"wbr",      HB_TAG('W','A','G',' ')},       /* Wagdi */
+  {"wle",      HB_TAG('S','I','G',' ')},       /* Wolane */
+  {"wry",      HB_TAG('M','A','W',' ')},       /* Merwari */
+  {"wtm",      HB_TAG('W','T','M',' ')},       /* Mewati */
   {"wo",       HB_TAG('W','L','F',' ')},       /* Wolof */
   {"xal",      HB_TAG('K','L','M',' ')},       /* Kalmyk */
   {"xh",       HB_TAG('X','H','S',' ')},       /* Xhosa */
+  {"xog",      HB_TAG('X','O','G',' ')},       /* Soga */
   {"xom",      HB_TAG('K','M','O',' ')},       /* Komo (Sudan) */
   {"xsl",      HB_TAG('S','S','L',' ')},       /* South Slavey */
-  {"yi",       HB_TAG('J','I','I',' ')},       /* Yiddish */
+  {"xst",      HB_TAG('S','I','G',' ')},       /* Silt'e (retired code) */
+  {"xwo",      HB_TAG('T','O','D',' ')},       /* Written Oirat (Todo) */
+  {"yao",      HB_TAG('Y','A','O',' ')},       /* Yao */
+  {"yi",       HB_TAG('J','I','I',' ')},       /* Yiddish [macrolanguage] */
   {"yo",       HB_TAG('Y','B','A',' ')},       /* Yoruba */
   {"yso",      HB_TAG('N','I','S',' ')},       /* Nisi (China) */
+  {"za",       HB_TAG('Z','H','A',' ')},       /* Chuang/Zhuang [macrolanguage] */
+  {"zea",      HB_TAG('Z','E','A',' ')},       /* Zeeuws */
   {"zne",      HB_TAG('Z','N','D',' ')},       /* Zande */
-  {"zu",       HB_TAG('Z','U','L',' ')}        /* Zulu */
-
-  /* I couldn't find the language id for these */
-
-/*{"??",       HB_TAG('A','G','W',' ')},*/     /* Agaw */
-/*{"??",       HB_TAG('A','L','S',' ')},*/     /* Alsatian */
-/*{"??",       HB_TAG('A','L','T',' ')},*/     /* Altai */
-/*{"??",       HB_TAG('A','R','K',' ')},*/     /* Arakanese */
-/*{"??",       HB_TAG('A','T','H',' ')},*/     /* Athapaskan */
-/*{"??",       HB_TAG('B','A','G',' ')},*/     /* Baghelkhandi */
-/*{"??",       HB_TAG('B','A','L',' ')},*/     /* Balkar */
-/*{"??",       HB_TAG('B','A','U',' ')},*/     /* Baule */
-/*{"??",       HB_TAG('B','B','R',' ')},*/     /* Berber */
+  {"zu",       HB_TAG('Z','U','L',' ')},       /* Zulu */
+  {"zum",      HB_TAG('L','R','C',' ')}        /* Kumzari */
+
+  /* The corresponding languages IDs for the following IDs are unclear,
+   * overlap, or are architecturally weird. Needs more research. */
+
+/*{"ahg/awn/xan?",     HB_TAG('A','G','W',' ')},*/     /* Agaw */
+/*{"gsw?/gsw-FR?",     HB_TAG('A','L','S',' ')},*/     /* Alsatian */
+/*{"krc",      HB_TAG('B','A','L',' ')},*/     /* Balkar */
 /*{"??",       HB_TAG('B','C','R',' ')},*/     /* Bible Cree */
-/*{"??",       HB_TAG('B','E','L',' ')},*/     /* Belarussian */
-/*{"??",       HB_TAG('B','I','L',' ')},*/     /* Bilen */
-/*{"??",       HB_TAG('B','K','F',' ')},*/     /* Blackfoot */
-/*{"??",       HB_TAG('B','L','N',' ')},*/     /* Balante */
-/*{"??",       HB_TAG('B','M','L',' ')},*/     /* Bamileke */
-/*{"??",       HB_TAG('B','R','I',' ')},*/     /* Braj Bhasha */
-/*{"??",       HB_TAG('C','H','G',' ')},*/     /* Chaha Gurage */
-/*{"??",       HB_TAG('C','H','H',' ')},*/     /* Chattisgarhi */
-/*{"??",       HB_TAG('C','H','K',' ')},*/     /* Chukchi */
-/*{"??",       HB_TAG('D','J','R',' ')},*/     /* Djerma */
-/*{"??",       HB_TAG('D','N','G',' ')},*/     /* Dangme */
-/*{"??",       HB_TAG('E','C','R',' ')},*/     /* Eastern Cree */
-/*{"??",       HB_TAG('F','A','N',' ')},*/     /* French Antillean */
-/*{"??",       HB_TAG('F','L','E',' ')},*/     /* Flemish */
-/*{"??",       HB_TAG('F','N','E',' ')},*/     /* Forest Nenets */
-/*{"??",       HB_TAG('F','T','A',' ')},*/     /* Futa */
-/*{"??",       HB_TAG('G','A','R',' ')},*/     /* Garshuni */
-/*{"??",       HB_TAG('G','E','Z',' ')},*/     /* Ge'ez */
-/*{"??",       HB_TAG('H','A','L',' ')},*/     /* Halam */
-/*{"??",       HB_TAG('H','A','R',' ')},*/     /* Harauti */
-/*{"??",       HB_TAG('H','A','W',' ')},*/     /* Hawaiin */
-/*{"??",       HB_TAG('H','B','N',' ')},*/     /* Hammer-Banna */
-/*{"??",       HB_TAG('H','M','A',' ')},*/     /* High Mari */
-/*{"??",       HB_TAG('H','N','D',' ')},*/     /* Hindko */
-/*{"??",       HB_TAG('I','J','O',' ')},*/     /* Ijo */
-/*{"??",       HB_TAG('I','L','O',' ')},*/     /* Ilokano */
-/*{"??",       HB_TAG('I','R','T',' ')},*/     /* Irish Traditional */
-/*{"??",       HB_TAG('J','U','L',' ')},*/     /* Jula */
-/*{"??",       HB_TAG('K','A','R',' ')},*/     /* Karachay */
-/*{"??",       HB_TAG('K','E','B',' ')},*/     /* Kebena */
-/*{"??",       HB_TAG('K','G','E',' ')},*/     /* Khutsuri Georgian */
-/*{"??",       HB_TAG('K','H','A',' ')},*/     /* Khakass */
-/*{"??",       HB_TAG('K','H','K',' ')},*/     /* Khanty-Kazim */
-/*{"??",       HB_TAG('K','H','S',' ')},*/     /* Khanty-Shurishkar */
-/*{"??",       HB_TAG('K','H','V',' ')},*/     /* Khanty-Vakhi */
-/*{"??",       HB_TAG('K','I','S',' ')},*/     /* Kisii */
-/*{"??",       HB_TAG('K','K','N',' ')},*/     /* Kokni */
-/*{"??",       HB_TAG('K','M','S',' ')},*/     /* Komso */
-/*{"??",       HB_TAG('K','O','D',' ')},*/     /* Kodagu */
-/*{"??",       HB_TAG('K','O','H',' ')},*/     /* Korean Old Hangul */
-/*{"??",       HB_TAG('K','O','N',' ')},*/     /* Kikongo */
-/*{"??",       HB_TAG('K','R','K',' ')},*/     /* Karakalpak */
-/*{"??",       HB_TAG('K','R','N',' ')},*/     /* Karen */
-/*{"??",       HB_TAG('K','U','L',' ')},*/     /* Kulvi */
+/*{"zh?",      HB_TAG('C','H','N',' ')},*/     /* Chinese (seen in Microsoft fonts) */
+/*{"acf/gcf?", HB_TAG('F','A','N',' ')},*/     /* French Antillean */
+/*{"enf?/yrk?",        HB_TAG('F','N','E',' ')},*/     /* Forest Nenets */
+/*{"fuf?",     HB_TAG('F','T','A',' ')},*/     /* Futa */
+/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/     /* Garshuni */
+/*{"cfm/rnl?", HB_TAG('H','A','L',' ')},*/     /* Halam */
+/*{"fonipa",   HB_TAG('I','P','P','H')},*/     /* Phonetic transcription—IPA conventions */
+/*{"ga-Latg?/Latg?",   HB_TAG('I','R','T',' ')},*/     /* Irish Traditional */
+/*{"krc",      HB_TAG('K','A','R',' ')},*/     /* Karachay */
+/*{"alw?/ktb?",        HB_TAG('K','E','B',' ')},*/     /* Kebena */
+/*{"Geok",     HB_TAG('K','G','E',' ')},*/     /* Khutsuri Georgian */
+/*{"kca",      HB_TAG('K','H','K',' ')},*/     /* Khanty-Kazim */
+/*{"kca",      HB_TAG('K','H','S',' ')},*/     /* Khanty-Shurishkar */
+/*{"kca",      HB_TAG('K','H','V',' ')},*/     /* Khanty-Vakhi */
+/*{"guz?/kqs?/kss?",   HB_TAG('K','I','S',' ')},*/     /* Kisii */
+/*{"kfa/kfi?/kpb?/xua?/xuj?",  HB_TAG('K','O','D',' ')},*/     /* Kodagu */
+/*{"okm?/oko?",        HB_TAG('K','O','H',' ')},*/     /* Korean Old Hangul */
+/*{"kon?/ktu?/...",    HB_TAG('K','O','N',' ')},*/     /* Kikongo */
+/*{"kfx?",     HB_TAG('K','U','L',' ')},*/     /* Kulvi */
 /*{"??",       HB_TAG('L','A','H',' ')},*/     /* Lahuli */
-/*{"??",       HB_TAG('L','A','M',' ')},*/     /* Lambani */
 /*{"??",       HB_TAG('L','C','R',' ')},*/     /* L-Cree */
-/*{"??",       HB_TAG('L','E','Z',' ')},*/     /* Lezgi */
-/*{"??",       HB_TAG('L','M','A',' ')},*/     /* Low Mari */
-/*{"??",       HB_TAG('L','U','B',' ')},*/     /* Luba */
-/*{"??",       HB_TAG('L','U','G',' ')},*/     /* Luganda */
-/*{"??",       HB_TAG('L','U','H',' ')},*/     /* Luhya */
-/*{"??",       HB_TAG('M','A','K',' ')},*/     /* Makua */
 /*{"??",       HB_TAG('M','A','L',' ')},*/     /* Malayalam Traditional */
-/*{"??",       HB_TAG('M','B','N',' ')},*/     /* Mbundu */
-/*{"??",       HB_TAG('M','I','Z',' ')},*/     /* Mizo */
-/*{"??",       HB_TAG('M','L','N',' ')},*/     /* Malinke */
-/*{"??",       HB_TAG('M','N','K',' ')},*/     /* Maninka */
-/*{"??",       HB_TAG('M','O','R',' ')},*/     /* Moroccan */
-/*{"??",       HB_TAG('N','A','G',' ')},*/     /* Naga-Assamese */
+/*{"mnk?/mlq?/...",    HB_TAG('M','L','N',' ')},*/     /* Malinke */
 /*{"??",       HB_TAG('N','C','R',' ')},*/     /* N-Cree */
-/*{"??",       HB_TAG('N','D','B',' ')},*/     /* Ndebele */
-/*{"??",       HB_TAG('N','G','R',' ')},*/     /* Nagari */
 /*{"??",       HB_TAG('N','H','C',' ')},*/     /* Norway House Cree */
-/*{"??",       HB_TAG('N','K','L',' ')},*/     /* Nkole */
-/*{"??",       HB_TAG('N','T','A',' ')},*/     /* Northern Tai */
-/*{"??",       HB_TAG('O','C','R',' ')},*/     /* Oji-Cree */
-/*{"??",       HB_TAG('P','A','A',' ')},*/     /* Palestinian Aramaic */
-/*{"??",       HB_TAG('P','G','R',' ')},*/     /* Polytonic Greek */
-/*{"??",       HB_TAG('P','L','G',' ')},*/     /* Palaung */
-/*{"??",       HB_TAG('Q','I','N',' ')},*/     /* Chin */
-/*{"??",       HB_TAG('R','B','U',' ')},*/     /* Russian Buriat */
+/*{"jpa?/sam?",        HB_TAG('P','A','A',' ')},*/     /* Palestinian Aramaic */
+/*{"polyton",  HB_TAG('P','G','R',' ')},*/     /* Polytonic Greek */
+/*{"??",       HB_TAG('Q','I','N',' ')},*/     /* Asho Chin */
 /*{"??",       HB_TAG('R','C','R',' ')},*/     /* R-Cree */
-/*{"??",       HB_TAG('R','M','S',' ')},*/     /* Rhaeto-Romanic */
-/*{"??",       HB_TAG('R','U','A',' ')},*/     /* Ruanda */
-/*{"??",       HB_TAG('S','A','Y',' ')},*/     /* Sayisi */
-/*{"??",       HB_TAG('S','E','K',' ')},*/     /* Sekota */
-/*{"??",       HB_TAG('S','I','G',' ')},*/     /* Silte Gurage */
-/*{"??",       HB_TAG('S','L','A',' ')},*/     /* Slavey */
-/*{"??",       HB_TAG('S','O','G',' ')},*/     /* Sodo Gurage */
-/*{"??",       HB_TAG('S','O','T',' ')},*/     /* Sotho */
-/*{"??",       HB_TAG('S','W','A',' ')},*/     /* Swadaya Aramaic */
-/*{"??",       HB_TAG('S','W','Z',' ')},*/     /* Swazi */
-/*{"??",       HB_TAG('S','X','T',' ')},*/     /* Sutu */
-/*{"??",       HB_TAG('T','A','B',' ')},*/     /* Tabasaran */
+/*{"chp?",     HB_TAG('S','A','Y',' ')},*/     /* Sayisi */
+/*{"xan?",     HB_TAG('S','E','K',' ')},*/     /* Sekota */
+/*{"ngo?",     HB_TAG('S','X','T',' ')},*/     /* Sutu */
 /*{"??",       HB_TAG('T','C','R',' ')},*/     /* TH-Cree */
-/*{"??",       HB_TAG('T','G','N',' ')},*/     /* Tongan */
-/*{"??",       HB_TAG('T','M','N',' ')},*/     /* Temne */
-/*{"??",       HB_TAG('T','N','E',' ')},*/     /* Tundra Nenets */
-/*{"??",       HB_TAG('T','O','D',' ')},*/     /* Todo */
-/*{"??",       HB_TAG('T','U','A',' ')},*/     /* Turoyo Aramaic */
-/*{"??",       HB_TAG('T','U','V',' ')},*/     /* Tuvin */
+/*{"tnz?/tog?/toi?",   HB_TAG('T','N','G',' ')},*/     /* Tonga */
+/*{"enh?/yrk?",        HB_TAG('T','N','E',' ')},*/     /* Tundra Nenets */
 /*{"??",       HB_TAG('W','C','R',' ')},*/     /* West-Cree */
-/*{"??",       HB_TAG('X','B','D',' ')},*/     /* Tai Lue */
-/*{"??",       HB_TAG('Y','C','R',' ')},*/     /* Y-Cree */
+/*{"cre?",     HB_TAG('Y','C','R',' ')},*/     /* Y-Cree */
 /*{"??",       HB_TAG('Y','I','C',' ')},*/     /* Yi Classic */
-/*{"??",       HB_TAG('Y','I','M',' ')},*/     /* Yi Modern */
+/*{"ii?/Yiii?",        HB_TAG('Y','I','M',' ')},*/     /* Yi Modern */
 /*{"??",       HB_TAG('Z','H','P',' ')},*/     /* Chinese Phonetic */
 };
 
-static const LangTag ot_languages_zh[] = {
+typedef struct {
+  char language[8];
+  hb_tag_t tag;
+} LangTagLong;
+static const LangTagLong ot_languages_zh[] = {
   {"zh-cn",    HB_TAG('Z','H','S',' ')},       /* Chinese (China) */
   {"zh-hk",    HB_TAG('Z','H','H',' ')},       /* Chinese (Hong Kong) */
   {"zh-mo",    HB_TAG('Z','H','T',' ')},       /* Chinese (Macao) */
   {"zh-sg",    HB_TAG('Z','H','S',' ')},       /* Chinese (Singapore) */
-  {"zh-tw",    HB_TAG('Z','H','T',' ')}        /* Chinese (Taiwan) */
+  {"zh-tw",    HB_TAG('Z','H','T',' ')},       /* Chinese (Taiwan) */
+  {"zh-hans",  HB_TAG('Z','H','S',' ')},       /* Chinese (Simplified) */
+  {"zh-hant",  HB_TAG('Z','H','T',' ')},       /* Chinese (Traditional) */
 };
 
 static int
@@ -607,7 +806,6 @@ hb_tag_t
 hb_ot_tag_from_language (hb_language_t language)
 {
   const char *lang_str, *s;
-  const LangTag *lang_tag;
 
   if (language == HB_LANGUAGE_INVALID)
     return HB_OT_TAG_DEFAULT_LANGUAGE;
@@ -629,11 +827,14 @@ hb_ot_tag_from_language (hb_language_t language)
   }
 
   /* Find a language matching in the first component */
-  lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
-                                 ARRAY_LENGTH (ot_languages), sizeof (LangTag),
-                                 (hb_compare_func_t) lang_compare_first_component);
-  if (lang_tag)
-    return lang_tag->tag;
+  {
+    const LangTag *lang_tag;
+    lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
+                                   ARRAY_LENGTH (ot_languages), sizeof (LangTag),
+                                   (hb_compare_func_t) lang_compare_first_component);
+    if (lang_tag)
+      return lang_tag->tag;
+  }
 
   /* Otherwise, check the Chinese ones */
   if (0 == lang_compare_first_component (lang_str, "zh"))
@@ -642,8 +843,9 @@ hb_ot_tag_from_language (hb_language_t language)
 
     for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
     {
+      const LangTagLong *lang_tag;
       lang_tag = &ot_languages_zh[i];
-      if (lang_matches (lang_tag->language, lang_str))
+      if (lang_matches (lang_str, lang_tag->language))
        return lang_tag->tag;
     }
 
@@ -656,7 +858,7 @@ hb_ot_tag_from_language (hb_language_t language)
     s = lang_str + strlen (lang_str);
   if (s - lang_str == 3) {
     /* Assume it's ISO-639-3 and upper-case and use it. */
-    return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000;
+    return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u;
   }
 
   return HB_OT_TAG_DEFAULT_LANGUAGE;
@@ -675,21 +877,12 @@ hb_ot_tag_to_language (hb_tag_t tag)
       return hb_language_from_string (ot_languages[i].language, -1);
 
   /* If tag starts with ZH, it's Chinese */
-  if ((tag & 0xFFFF0000)  == 0x5A480000) {
+  if ((tag & 0xFFFF0000u)  == 0x5A480000u) {
     switch (tag) {
       case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
-      default: {
-        /* Encode the tag... */
-       unsigned char buf[14] = "zh-x-hbot";
-       buf[9] = tag >> 24;
-       buf[10] = (tag >> 16) & 0xFF;
-       buf[11] = (tag >> 8) & 0xFF;
-       buf[12] = tag & 0xFF;
-       if (buf[12] == 0x20)
-         buf[12] = '\0';
-       buf[13] = '\0';
-       return hb_language_from_string ((char *) buf, -1);
-      }
+      case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */
+      case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */
+      default: break; /* Fall through */
     }
   }
 
index 2d750c3..47c92a5 100644 (file)
 
 #include "hb.h"
 
+#include "hb-ot-font.h"
 #include "hb-ot-layout.h"
 #include "hb-ot-tag.h"
+#include "hb-ot-shape.h"
 
 HB_BEGIN_DECLS
 
-void
-hb_ot_shape_glyphs_closure (hb_font_t          *font,
-                           hb_buffer_t        *buffer,
-                           const hb_feature_t *features,
-                           unsigned int        num_features,
-                           hb_set_t           *glyphs);
-
 HB_END_DECLS
 
 #undef HB_OT_H_IN
index 0cb049e..6505238 100644 (file)
 #include <stdarg.h>
 
 
+/* Compiler attributes */
 
-/* Essentials */
 
-#ifndef NULL
-# define NULL ((void *) 0)
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
+#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
+#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
+#else
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#endif
+
+#ifndef __GNUC__
+#undef __attribute__
+#define __attribute__(x)
+#endif
+
+#if __GNUC__ >= 3
+#define HB_PURE_FUNC   __attribute__((pure))
+#define HB_CONST_FUNC  __attribute__((const))
+#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
+#else
+#define HB_PURE_FUNC
+#define HB_CONST_FUNC
+#define HB_PRINTF_FUNC(format_idx, arg_idx)
+#endif
+#if __GNUC__ >= 4
+#define HB_UNUSED      __attribute__((unused))
+#else
+#define HB_UNUSED
+#endif
+
+#ifndef HB_INTERNAL
+# if !defined(__MINGW32__) && !defined(__CYGWIN__)
+#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
+# else
+#  define HB_INTERNAL
+# endif
 #endif
 
+#if __GNUC__ >= 3
+#define HB_FUNC __PRETTY_FUNCTION__
+#elif defined(_MSC_VER)
+#define HB_FUNC __FUNCSIG__
+#else
+#define HB_FUNC __func__
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+   /* We need Windows Vista for both Uniscribe backend and for
+    * MemoryBarrier.  We don't support compiling on Windows XP,
+    * though we run on it fine. */
+#  if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
+#    undef _WIN32_WINNT
+#  endif
+#  ifndef _WIN32_WINNT
+#    define _WIN32_WINNT 0x0600
+#  endif
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN 1
+#  endif
+#  ifndef STRICT
+#    define STRICT 1
+#  endif
+
+#  if defined(_WIN32_WCE)
+     /* Some things not defined on Windows CE. */
+#    define strdup _strdup
+#    define getenv(Name) NULL
+#    define setlocale(Category, Locale) "C"
+static int errno = 0; /* Use something better? */
+#  elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#    define getenv(Name) NULL
+#  endif
+#  if defined(_MSC_VER) && _MSC_VER < 1900
+#    define snprintf _snprintf
+#  endif
+#endif
+
+#if HAVE_ATEXIT
+/* atexit() is only safe to be called from shared libraries on certain
+ * platforms.  Whitelist.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
+#  if defined(__linux) && defined(__GLIBC_PREREQ)
+#    if __GLIBC_PREREQ(2,3)
+/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
+#      define HB_USE_ATEXIT 1
+#    endif
+#  elif defined(_MSC_VER) || defined(__MINGW32__)
+/* For MSVC:
+ * http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
+ * http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
+ * mingw32 headers say atexit is safe to use in shared libraries.
+ */
+#    define HB_USE_ATEXIT 1
+#  elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+/* This was fixed in Android NKD r8 or r8b:
+ * https://code.google.com/p/android/issues/detail?id=6455
+ * which introduced GCC 4.6:
+ * https://developer.android.com/tools/sdk/ndk/index.html
+ */
+#    define HB_USE_ATEXIT 1
+#  endif
+#endif
 
 /* Basics */
 
 
+#ifndef NULL
+# define NULL ((void *) 0)
+#endif
+
 #undef MIN
-template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
+template <typename Type>
+static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
 
 #undef MAX
-template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
+template <typename Type>
+static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
+
+static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
+{ return (a + (b - 1)) / b; }
 
 
 #undef  ARRAY_LENGTH
-#define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
+/* A const version, but does not detect erratically being called on pointers. */
+#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
 
 #define HB_STMT_START do
 #define HB_STMT_END   while (0)
 
-#define _ASSERT_STATIC1(_line, _cond)  typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC1(_line, _cond)  HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
 #define _ASSERT_STATIC0(_line, _cond)  _ASSERT_STATIC1 (_line, (_cond))
 #define ASSERT_STATIC(_cond)           _ASSERT_STATIC0 (__LINE__, (_cond))
 
@@ -125,7 +234,7 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
 
 /* Check _assertion in a method environment */
 #define _ASSERT_POD1(_line) \
-       inline void _static_assertion_on_line_##_line (void) const \
+       HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
        { _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
 # define _ASSERT_POD0(_line)   _ASSERT_POD1 (_line)
 # define ASSERT_POD()          _ASSERT_POD0 (__LINE__)
@@ -134,68 +243,10 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
 
 /* Misc */
 
-
-#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
-#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
-#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
-#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
-#else
-#define likely(expr) (expr)
-#define unlikely(expr) (expr)
-#endif
-
-#ifndef __GNUC__
-#undef __attribute__
-#define __attribute__(x)
-#endif
-
-#if __GNUC__ >= 3
-#define HB_PURE_FUNC   __attribute__((pure))
-#define HB_CONST_FUNC  __attribute__((const))
-#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
-#else
-#define HB_PURE_FUNC
-#define HB_CONST_FUNC
-#define HB_PRINTF_FUNC(format_idx, arg_idx)
-#endif
-#if __GNUC__ >= 4
-#define HB_UNUSED      __attribute__((unused))
-#else
-#define HB_UNUSED
-#endif
-
-#ifndef HB_INTERNAL
-# ifndef __MINGW32__
-#  define HB_INTERNAL __attribute__((__visibility__("hidden")))
-# else
-#  define HB_INTERNAL
-# endif
-#endif
-
-
-#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
-#define snprintf _snprintf
-#endif
-
-#ifdef _MSC_VER
-#undef inline
-#define inline __inline
-#endif
-
-#ifdef __STRICT_ANSI__
-#undef inline
-#define inline __inline__
-#endif
-
-
-#if __GNUC__ >= 3
-#define HB_FUNC __PRETTY_FUNCTION__
-#elif defined(_MSC_VER)
-#define HB_FUNC __FUNCSIG__
-#else
-#define HB_FUNC __func__
-#endif
-
+/* Void! */
+struct _hb_void_t {};
+typedef const _hb_void_t &hb_void_t;
+#define HB_VOID (* (const _hb_void_t *) NULL)
 
 /* Return the number of 1 bits in mask. */
 static inline HB_CONST_FUNC unsigned int
@@ -205,7 +256,7 @@ _hb_popcount32 (uint32_t mask)
   return __builtin_popcount (mask);
 #else
   /* "HACKMEM 169" */
-  register uint32_t y;
+  uint32_t y;
   y = (mask >> 1) &033333333333;
   y = mask - y - ((y >>1) & 033333333333);
   return (((y + (y >> 3)) & 030707070707) % 077);
@@ -219,7 +270,7 @@ _hb_bit_storage (unsigned int number)
 #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
   return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
 #else
-  register unsigned int n_bits = 0;
+  unsigned int n_bits = 0;
   while (number) {
     n_bits++;
     number >>= 1;
@@ -235,7 +286,7 @@ _hb_ctz (unsigned int number)
 #if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
   return likely (number) ? __builtin_ctz (number) : 0;
 #else
-  register unsigned int n_bits = 0;
+  unsigned int n_bits = 0;
   if (unlikely (!number)) return 0;
   while (!(number & 1)) {
     n_bits++;
@@ -261,8 +312,8 @@ typedef int (*hb_compare_func_t) (const void *, const void *);
 /* arrays and maps */
 
 
-#define HB_PREALLOCED_ARRAY_INIT {0}
-template <typename Type, unsigned int StaticSize>
+#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
+template <typename Type, unsigned int StaticSize=16>
 struct hb_prealloced_array_t
 {
   unsigned int len;
@@ -310,14 +361,22 @@ struct hb_prealloced_array_t
   inline void pop (void)
   {
     len--;
-    /* TODO: shrink array if needed */
+  }
+
+  inline void remove (unsigned int i)
+  {
+     if (unlikely (i >= len))
+       return;
+     memmove (static_cast<void *> (&array[i]),
+             static_cast<void *> (&array[i + 1]),
+             (len - i - 1) * sizeof (Type));
+     len--;
   }
 
   inline void shrink (unsigned int l)
   {
      if (l < len)
        len = l;
-    /* TODO: shrink array if needed */
   }
 
   template <typename T>
@@ -335,14 +394,14 @@ struct hb_prealloced_array_t
     return NULL;
   }
 
-  inline void sort (void)
+  inline void qsort (void)
   {
-    qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
   }
 
-  inline void sort (unsigned int start, unsigned int end)
+  inline void qsort (unsigned int start, unsigned int end)
   {
-    qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
+    ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
   }
 
   template <typename T>
@@ -365,6 +424,13 @@ struct hb_prealloced_array_t
   }
 };
 
+template <typename Type>
+struct hb_auto_array_t : hb_prealloced_array_t <Type>
+{
+  hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
+  ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
+};
+
 
 #define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
 template <typename item_t, typename lock_t>
@@ -442,6 +508,11 @@ struct hb_lockable_set_t
 
   inline void finish (lock_t &l)
   {
+    if (!items.len) {
+      /* No need for locking. */
+      items.finish ();
+      return;
+    }
     l.lock ();
     while (items.len) {
       item_t old = items[items.len - 1];
@@ -457,39 +528,14 @@ struct hb_lockable_set_t
 };
 
 
-
-
-/* Big-endian handling */
-
-static inline uint16_t hb_be_uint16 (const uint16_t v)
-{
-  const uint8_t *V = (const uint8_t *) &v;
-  return (uint16_t) (V[0] << 8) + V[1];
-}
-
-/* Note, of the following macros, uint16_get is the one called many many times.
- * If there is any optimizations to be done, it's in that macro.  However, I
- * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
- * results in a single ror instruction, does NOT speed this up.  In fact, it
- * resulted in a minor slowdown.  At any rate, note that v may not be correctly
- * aligned, so I think the current implementation is optimal.
- */
-
-#define hb_be_uint16_put(v,V)  HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
-#define hb_be_uint16_get(v)    (uint16_t) ((v[0] << 8) + v[1])
-#define hb_be_uint16_eq(a,b)   (a[0] == b[0] && a[1] == b[1])
-
-#define hb_be_uint32_put(v,V)  HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END
-#define hb_be_uint32_get(v)    (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
-#define hb_be_uint32_eq(a,b)   (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
-
-
 /* ASCII tag/character handling */
 
-static inline unsigned char ISALPHA (unsigned char c)
+static inline bool ISALPHA (unsigned char c)
 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
-static inline unsigned char ISALNUM (unsigned char c)
+static inline bool ISALNUM (unsigned char c)
 { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
+static inline bool ISSPACE (unsigned char c)
+{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
 static inline unsigned char TOUPPER (unsigned char c)
 { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
 static inline unsigned char TOLOWER (unsigned char c)
@@ -523,10 +569,43 @@ _hb_debug (unsigned int level,
   return level < max_level;
 }
 
-#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
-#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))
+#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
+#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
+
+static inline void
+_hb_print_func (const char *func)
+{
+  if (func)
+  {
+    unsigned int func_len = strlen (func);
+    /* Skip "static" */
+    if (0 == strncmp (func, "static ", 7))
+      func += 7;
+    /* Skip "typename" */
+    if (0 == strncmp (func, "typename ", 9))
+      func += 9;
+    /* Skip return type */
+    const char *space = strchr (func, ' ');
+    if (space)
+      func = space + 1;
+    /* Skip parameter list */
+    const char *paren = strchr (func, '(');
+    if (paren)
+      func_len = paren - func;
+    fprintf (stderr, "%.*s", func_len, func);
+  }
+}
 
-template <int max_level> inline void
+template <int max_level> static inline void
+_hb_debug_msg_va (const char *what,
+                 const void *obj,
+                 const char *func,
+                 bool indented,
+                 unsigned int level,
+                 int level_dir,
+                 const char *message,
+                 va_list ap) HB_PRINTF_FUNC(7, 0);
+template <int max_level> static inline void
 _hb_debug_msg_va (const char *what,
                  const void *obj,
                  const char *func,
@@ -547,26 +626,28 @@ _hb_debug_msg_va (const char *what,
     fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
 
   if (indented) {
-    static const char bars[] = "││││││││││││││││││││││││││││││││││││││││";
-    fprintf (stderr, "%2d %s├%s",
+/* One may want to add ASCII version of these.  See:
+ * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
+#define VBAR   "\342\224\202"  /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
+#define VRBAR  "\342\224\234"  /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+#define DLBAR  "\342\225\256"  /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
+#define ULBAR  "\342\225\257"  /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
+#define LBAR   "\342\225\264"  /* U+2574 BOX DRAWINGS LIGHT LEFT */
+    static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
+    fprintf (stderr, "%2u %s" VRBAR "%s",
             level,
-            bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), 3 * level),
-            level_dir ? (level_dir > 0 ? "╮" : "╯") : "╴");
+            bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
+            level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
   } else
-    fprintf (stderr, "   ├╴");
+    fprintf (stderr, "   " VRBAR LBAR);
 
-  if (func) {
-    /* If there's a class name, just write that. */
-    const char *dotdot = strstr (func, "::");
-    const char *space = strchr (func, ' ');
-    if (space && dotdot && space < dotdot)
-      func = space + 1;
-    unsigned int func_len = dotdot ? dotdot - func : strlen (func);
-    fprintf (stderr, "%.*s: ", func_len, func);
-  }
+  _hb_print_func (func);
 
   if (message)
+  {
+    fprintf (stderr, ": ");
     vfprintf (stderr, message, ap);
+  }
 
   fprintf (stderr, "\n");
 }
@@ -580,7 +661,7 @@ _hb_debug_msg_va<0> (const char *what HB_UNUSED,
                     const char *message HB_UNUSED,
                     va_list ap HB_UNUSED) {}
 
-template <int max_level> inline void
+template <int max_level> static inline void
 _hb_debug_msg (const char *what,
               const void *obj,
               const char *func,
@@ -589,7 +670,7 @@ _hb_debug_msg (const char *what,
               int level_dir,
               const char *message,
               ...) HB_PRINTF_FUNC(7, 8);
-template <int max_level> inline void
+template <int max_level> static inline void
 _hb_debug_msg (const char *what,
               const void *obj,
               const char *func,
@@ -629,10 +710,41 @@ _hb_debug_msg<0> (const char *what HB_UNUSED,
 
 
 /*
+ * Printer
+ */
+
+template <typename T>
+struct hb_printer_t {
+  const char *print (const T&) { return "something"; }
+};
+
+template <>
+struct hb_printer_t<bool> {
+  const char *print (bool v) { return v ? "true" : "false"; }
+};
+
+template <>
+struct hb_printer_t<hb_void_t> {
+  const char *print (hb_void_t) { return ""; }
+};
+
+
+/*
  * Trace
  */
 
-template <int max_level>
+template <typename T>
+static inline void _hb_warn_no_return (bool returned)
+{
+  if (unlikely (!returned)) {
+    fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.\n");
+  }
+}
+template <>
+/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
+{}
+
+template <int max_level, typename ret_t>
 struct hb_auto_trace_t {
   explicit inline hb_auto_trace_t (unsigned int *plevel_,
                                   const char *what_,
@@ -650,23 +762,23 @@ struct hb_auto_trace_t {
   }
   inline ~hb_auto_trace_t (void)
   {
-    if (unlikely (!returned)) {
-      fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN.  This is a bug, please report.  Level was %d.\n", plevel ? *plevel : -1);
+    _hb_warn_no_return<ret_t> (returned);
+    if (!returned) {
       _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
-      return;
     }
-
     if (plevel) --*plevel;
   }
 
-  inline bool ret (bool v)
+  inline ret_t ret (ret_t v, unsigned int line = 0)
   {
     if (unlikely (returned)) {
       fprintf (stderr, "OUCH, double calls to TRACE_RETURN.  This is a bug, please report.\n");
       return v;
     }
 
-    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, "return %s", v ? "true" : "false");
+    _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
+                             "return %s (line %d)",
+                             hb_printer_t<ret_t>().print (v), line);
     if (plevel) --*plevel;
     plevel = NULL;
     returned = true;
@@ -675,12 +787,12 @@ struct hb_auto_trace_t {
 
   private:
   unsigned int *plevel;
-  bool returned;
   const char *what;
   const void *obj;
+  bool returned;
 };
-template <> /* Optimize when tracing is disabled */
-struct hb_auto_trace_t<0> {
+template <typename ret_t> /* Optimize when tracing is disabled */
+struct hb_auto_trace_t<0, ret_t> {
   explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
                                   const char *what HB_UNUSED,
                                   const void *obj HB_UNUSED,
@@ -688,28 +800,44 @@ struct hb_auto_trace_t<0> {
                                   const char *message HB_UNUSED,
                                   ...) {}
 
-  template <typename T>
-  inline T ret (T v) { return v; }
+  inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
 };
 
-#define TRACE_RETURN(RET) trace.ret (RET)
+#define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
 
 /* Misc */
 
+template <typename T> class hb_assert_unsigned_t;
+template <> class hb_assert_unsigned_t<unsigned char> {};
+template <> class hb_assert_unsigned_t<unsigned short> {};
+template <> class hb_assert_unsigned_t<unsigned int> {};
+template <> class hb_assert_unsigned_t<unsigned long> {};
 
-/* Pre-mature optimization:
- * Checks for lo <= u <= hi but with an optimization if lo and hi
- * are only different in a contiguous set of lower-most bits.
- */
-template <typename T> inline bool
+template <typename T> static inline bool
 hb_in_range (T u, T lo, T hi)
 {
-  if ( ((lo^hi) & lo) == 0 &&
-       ((lo^hi) & hi) == (lo^hi) &&
-       ((lo^hi) & ((lo^hi) + 1)) == 0 )
-    return (u & ~(lo^hi)) == lo;
-  else
-    return lo <= u && u <= hi;
+  /* The sizeof() is here to force template instantiation.
+   * I'm sure there are better ways to do this but can't think of
+   * one right now.  Declaring a variable won't work as HB_UNUSED
+   * is unusable on some platforms and unused types are less likely
+   * to generate a warning than unused variables. */
+  ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
+
+  /* The casts below are important as if T is smaller than int,
+   * the subtract results will become a signed int! */
+  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)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+}
+
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+{
+  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
 }
 
 
@@ -718,10 +846,11 @@ hb_in_range (T u, T lo, T hi)
  * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
  */
 #define FLAG(x) (1<<(x))
+#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
 
 
-template <typename T> inline void
-hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+template <typename T, typename T2> static inline void
+hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
 {
   if (unlikely (!len))
     return;
@@ -731,11 +860,21 @@ hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
     unsigned int new_k = 0;
 
     for (unsigned int j = 0; j < k; j++)
-      if (compar (&array[j], &array[j+1]) > 0) {
-        T t;
-       t = array[j];
-       array[j] = array[j + 1];
-       array[j + 1] = t;
+      if (compar (&array[j], &array[j+1]) > 0)
+      {
+        {
+         T t;
+         t = array[j];
+         array[j] = array[j + 1];
+         array[j + 1] = t;
+       }
+        if (array2)
+        {
+         T2 t;
+         t = array2[j];
+         array2[j] = array2[j + 1];
+         array2[j + 1] = t;
+       }
 
        new_k = j;
       }
@@ -743,7 +882,58 @@ hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
   } while (k);
 }
 
+template <typename T> static inline void
+hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+{
+  hb_bubble_sort (array, len, compar, (int *) NULL);
+}
+
+static inline hb_bool_t
+hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
+{
+  /* Pain because we don't know whether s is nul-terminated. */
+  char buf[64];
+  len = MIN (ARRAY_LENGTH (buf) - 1, len);
+  strncpy (buf, s, len);
+  buf[len] = '\0';
+
+  char *end;
+  errno = 0;
+  unsigned long v = strtoul (buf, &end, base);
+  if (errno) return false;
+  if (*end) return false;
+  *out = v;
+  return true;
+}
+
 
+/* Global runtime options. */
+
+struct hb_options_t
+{
+  unsigned int initialized : 1;
+  unsigned int uniscribe_bug_compatible : 1;
+};
+
+union hb_options_union_t {
+  unsigned int i;
+  hb_options_t opts;
+};
+ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));
+
+HB_INTERNAL void
+_hb_options_init (void);
+
+extern HB_INTERNAL hb_options_union_t _hb_options;
+
+static inline hb_options_t
+hb_options (void)
+{
+  if (unlikely (!_hb_options.i))
+    _hb_options_init ();
+
+  return _hb_options.opts;
+}
 
 
 #endif /* HB_PRIVATE_HH */
index 5cdf8a0..acba4e9 100644 (file)
 #define HB_SET_PRIVATE_HH
 
 #include "hb-private.hh"
-#include "hb-set.h"
 #include "hb-object-private.hh"
 
 
+/*
+ * 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
+ * queries.  As a result, our filters have much higher.
+ */
+
+template <typename mask_t, unsigned int shift>
+struct hb_set_digest_lowest_bits_t
+{
+  ASSERT_POD ();
+
+  static const unsigned int mask_bytes = sizeof (mask_t);
+  static const unsigned int mask_bits = sizeof (mask_t) * 8;
+  static const unsigned int num_bits = 0
+                                    + (mask_bytes >= 1 ? 3 : 0)
+                                    + (mask_bytes >= 2 ? 1 : 0)
+                                    + (mask_bytes >= 4 ? 1 : 0)
+                                    + (mask_bytes >= 8 ? 1 : 0)
+                                    + (mask_bytes >= 16? 1 : 0)
+                                    + 0;
+
+  ASSERT_STATIC (shift < sizeof (hb_codepoint_t) * 8);
+  ASSERT_STATIC (shift + num_bits <= sizeof (hb_codepoint_t) * 8);
+
+  inline void init (void) {
+    mask = 0;
+  }
+
+  inline void add (hb_codepoint_t g) {
+    mask |= mask_for (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+      mask = (mask_t) -1;
+    else {
+      mask_t ma = mask_for (a);
+      mask_t mb = mask_for (b);
+      mask |= mb + (mb - ma) - (mb < ma);
+    }
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return !!(mask & mask_for (g));
+  }
+
+  private:
+
+  static inline mask_t mask_for (hb_codepoint_t g) {
+    return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
+  }
+  mask_t mask;
+};
+
+template <typename head_t, typename tail_t>
+struct hb_set_digest_combiner_t
+{
+  ASSERT_POD ();
+
+  inline void init (void) {
+    head.init ();
+    tail.init ();
+  }
+
+  inline void add (hb_codepoint_t g) {
+    head.add (g);
+    tail.add (g);
+  }
+
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+    head.add_range (a, b);
+    tail.add_range (a, b);
+  }
+
+  inline bool may_have (hb_codepoint_t g) const {
+    return head.may_have (g) && tail.may_have (g);
+  }
+
+  private:
+  head_t head;
+  tail_t tail;
+};
+
+
+/*
+ * hb_set_digest_t
+ *
+ * This is a combination of digests that performs "best".
+ * There is not much science to this: it's a result of intuition
+ * and testing.
+ */
+typedef hb_set_digest_combiner_t
+<
+  hb_set_digest_lowest_bits_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_t;
+
+
+
+/*
+ * hb_set_t
+ */
+
+
 /* TODO Make this faster and memmory efficient. */
 
-struct _hb_set_t
+struct hb_set_t
 {
+  friend struct hb_frozen_set_t;
+
   hb_object_header_t header;
   ASSERT_POD ();
+  bool in_error;
 
   inline void init (void) {
-    header.init ();
+    hb_object_init (this);
     clear ();
   }
   inline void fini (void) {
   }
   inline void clear (void) {
+    if (unlikely (hb_object_is_inert (this)))
+      return;
+    in_error = false;
     memset (elts, 0, sizeof elts);
   }
-  inline bool empty (void) const {
+  inline bool is_empty (void) const {
     for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
       if (elts[i])
         return false;
@@ -56,15 +171,31 @@ struct _hb_set_t
   }
   inline void add (hb_codepoint_t g)
   {
-    if (unlikely (g == SENTINEL)) return;
+    if (unlikely (in_error)) return;
+    if (unlikely (g == INVALID)) return;
     if (unlikely (g > MAX_G)) return;
     elt (g) |= mask (g);
   }
+  inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (in_error)) return;
+    /* TODO Speedup */
+    for (unsigned int i = a; i < b + 1; i++)
+      add (i);
+  }
   inline void del (hb_codepoint_t g)
   {
+    if (unlikely (in_error)) return;
     if (unlikely (g > MAX_G)) return;
     elt (g) &= ~mask (g);
   }
+  inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (in_error)) return;
+    /* TODO Speedup */
+    for (unsigned int i = a; i < b + 1; i++)
+      del (i);
+  }
   inline bool has (hb_codepoint_t g) const
   {
     if (unlikely (g > MAX_G)) return false;
@@ -81,7 +212,7 @@ struct _hb_set_t
         return true;
     return false;
   }
-  inline bool equal (const hb_set_t *other) const
+  inline bool is_equal (const hb_set_t *other) const
   {
     for (unsigned int i = 0; i < ELTS; i++)
       if (elts[i] != other->elts[i])
@@ -90,54 +221,93 @@ struct _hb_set_t
   }
   inline void set (const hb_set_t *other)
   {
+    if (unlikely (in_error)) return;
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] = other->elts[i];
   }
   inline void union_ (const hb_set_t *other)
   {
+    if (unlikely (in_error)) return;
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] |= other->elts[i];
   }
   inline void intersect (const hb_set_t *other)
   {
+    if (unlikely (in_error)) return;
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] &= other->elts[i];
   }
   inline void subtract (const hb_set_t *other)
   {
+    if (unlikely (in_error)) return;
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] &= ~other->elts[i];
   }
   inline void symmetric_difference (const hb_set_t *other)
   {
+    if (unlikely (in_error)) return;
     for (unsigned int i = 0; i < ELTS; i++)
       elts[i] ^= other->elts[i];
   }
-  inline bool next (hb_codepoint_t *codepoint)
+  inline void invert (void)
+  {
+    if (unlikely (in_error)) return;
+    for (unsigned int i = 0; i < ELTS; i++)
+      elts[i] = ~elts[i];
+  }
+  inline bool next (hb_codepoint_t *codepoint) const
   {
-    if (unlikely (*codepoint == SENTINEL)) {
+    if (unlikely (*codepoint == INVALID)) {
       hb_codepoint_t i = get_min ();
-      if (i != SENTINEL) {
+      if (i != INVALID) {
         *codepoint = i;
        return true;
-      } else
+      } else {
+       *codepoint = INVALID;
         return false;
+      }
     }
     for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
       if (has (i)) {
         *codepoint = i;
        return true;
       }
+    *codepoint = INVALID;
     return false;
   }
+  inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *last;
+    if (!next (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *last = *first = i;
+    while (next (&i) && i == *last + 1)
+      (*last)++;
+
+    return true;
+  }
+
+  inline unsigned int get_population (void) const
+  {
+    unsigned int count = 0;
+    for (unsigned int i = 0; i < ELTS; i++)
+      count += _hb_popcount32 (elts[i]);
+    return count;
+  }
   inline hb_codepoint_t get_min (void) const
   {
     for (unsigned int i = 0; i < ELTS; i++)
       if (elts[i])
-       for (unsigned int j = 0; i < BITS; j++)
+       for (unsigned int j = 0; j < BITS; j++)
          if (elts[i] & (1 << j))
            return i * BITS + j;
-    return SENTINEL;
+    return INVALID;
   }
   inline hb_codepoint_t get_max (void) const
   {
@@ -146,7 +316,7 @@ struct _hb_set_t
        for (unsigned int j = BITS; j; j--)
          if (elts[i - 1] & (1 << (j - 1)))
            return (i - 1) * BITS + (j - 1);
-    return SENTINEL;
+    return INVALID;
   }
 
   typedef uint32_t elt_t;
@@ -155,10 +325,10 @@ struct _hb_set_t
   static const unsigned int BITS = (1 << SHIFT);
   static const unsigned int MASK = BITS - 1;
   static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
-  static  const hb_codepoint_t SENTINEL = (hb_codepoint_t) -1;
+  static  const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
   elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
-  elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
   elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
 
   elt_t elts[ELTS]; /* XXX 8kb */
@@ -167,6 +337,59 @@ struct _hb_set_t
   ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
 };
 
+struct hb_frozen_set_t
+{
+  static const unsigned int SHIFT = hb_set_t::SHIFT;
+  static const unsigned int BITS = hb_set_t::BITS;
+  static const unsigned int MASK = hb_set_t::MASK;
+  typedef hb_set_t::elt_t elt_t;
+
+  inline void init (const hb_set_t &set)
+  {
+    start = count = 0;
+    elts = NULL;
+
+    unsigned int max = set.get_max ();
+    if (max == set.INVALID)
+      return;
+    unsigned int min = set.get_min ();
+    const elt_t &min_elt = set.elt (min);
+    const elt_t &max_elt = set.elt (max);
+
+    start = min & ~MASK;
+    count = max - start + 1;
+    unsigned int num_elts = (count + BITS - 1) / BITS;
+    unsigned int elts_size = num_elts * sizeof (elt_t);
+    elts = (elt_t *) malloc (elts_size);
+    if (unlikely (!elts))
+    {
+      start = count = 0;
+      return;
+    }
+    memcpy (elts, &min_elt, elts_size);
+  }
+
+  inline void fini (void)
+  {
+    if (elts)
+      free (elts);
+  }
+
+  inline bool has (hb_codepoint_t g) const
+  {
+    /* hb_codepoint_t is unsigned. */
+    g -= start;
+    if (unlikely (g > count)) return false;
+    return !!(elt (g) & mask (g));
+  }
+
+  elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+  elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
+
+  private:
+  hb_codepoint_t start, count;
+  elt_t *elts;
+};
 
 
 #endif /* HB_SET_PRIVATE_HH */
index 4225e3c..59a0af4 100644 (file)
 #include "hb-set-private.hh"
 
 
-
 /* Public API */
 
 
+/**
+ * hb_set_create: (Xconstructor)
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_set_t *
-hb_set_create ()
+hb_set_create (void)
 {
   hb_set_t *set;
 
@@ -44,11 +50,19 @@ hb_set_create ()
   return set;
 }
 
+/**
+ * hb_set_get_empty:
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_set_t *
 hb_set_get_empty (void)
 {
   static const hb_set_t _hb_set_nil = {
     HB_OBJECT_HEADER_STATIC,
+    true, /* in_error */
 
     {0} /* elts */
   };
@@ -56,12 +70,26 @@ hb_set_get_empty (void)
   return const_cast<hb_set_t *> (&_hb_set_nil);
 }
 
+/**
+ * hb_set_reference: (skip)
+ * @set: a set.
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_set_t *
 hb_set_reference (hb_set_t *set)
 {
   return hb_object_reference (set);
 }
 
+/**
+ * hb_set_destroy: (skip)
+ * @set: a set.
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_destroy (hb_set_t *set)
 {
@@ -72,49 +100,118 @@ hb_set_destroy (hb_set_t *set)
   free (set);
 }
 
+/**
+ * hb_set_set_user_data: (skip)
+ * @set: a set.
+ * @key:
+ * @data:
+ * @destroy (closure data):
+ * @replace:
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_set_set_user_data (hb_set_t        *set,
-                        hb_user_data_key_t *key,
-                        void *              data,
-                        hb_destroy_func_t   destroy,
-                        hb_bool_t           replace)
+hb_set_set_user_data (hb_set_t           *set,
+                     hb_user_data_key_t *key,
+                     void *              data,
+                     hb_destroy_func_t   destroy,
+                     hb_bool_t           replace)
 {
   return hb_object_set_user_data (set, key, data, destroy, replace);
 }
 
+/**
+ * hb_set_get_user_data: (skip)
+ * @set: a set.
+ * @key:
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 void *
-hb_set_get_user_data (hb_set_t        *set,
-                        hb_user_data_key_t *key)
+hb_set_get_user_data (hb_set_t           *set,
+                     hb_user_data_key_t *key)
 {
   return hb_object_get_user_data (set, key);
 }
 
 
+/**
+ * hb_set_allocation_successful:
+ * @set: a set.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_set_allocation_successful (hb_set_t  *set HB_UNUSED)
+hb_set_allocation_successful (const hb_set_t  *set HB_UNUSED)
 {
-  return true;
+  return !set->in_error;
 }
 
+/**
+ * hb_set_clear:
+ * @set: a set.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_clear (hb_set_t *set)
 {
   set->clear ();
 }
 
+/**
+ * hb_set_is_empty:
+ * @set: a set.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_set_empty (hb_set_t *set)
+hb_set_is_empty (const hb_set_t *set)
 {
-  return set->empty ();
+  return set->is_empty ();
 }
 
+/**
+ * hb_set_has:
+ * @set: a set.
+ * @codepoint: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_set_has (hb_set_t       *set,
+hb_set_has (const hb_set_t *set,
            hb_codepoint_t  codepoint)
 {
   return set->has (codepoint);
 }
 
+/**
+ * hb_set_add:
+ * @set: a set.
+ * @codepoint: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_add (hb_set_t       *set,
            hb_codepoint_t  codepoint)
@@ -122,6 +219,33 @@ hb_set_add (hb_set_t       *set,
   set->add (codepoint);
 }
 
+/**
+ * hb_set_add_range:
+ * @set: a set.
+ * @first: 
+ * @last: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_set_add_range (hb_set_t       *set,
+                 hb_codepoint_t  first,
+                 hb_codepoint_t  last)
+{
+  set->add_range (first, last);
+}
+
+/**
+ * hb_set_del:
+ * @set: a set.
+ * @codepoint: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_set_del (hb_set_t       *set,
            hb_codepoint_t  codepoint)
@@ -129,63 +253,219 @@ hb_set_del (hb_set_t       *set,
   set->del (codepoint);
 }
 
+/**
+ * hb_set_del_range:
+ * @set: a set.
+ * @first: 
+ * @last: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_set_del_range (hb_set_t       *set,
+                 hb_codepoint_t  first,
+                 hb_codepoint_t  last)
+{
+  set->del_range (first, last);
+}
+
+/**
+ * hb_set_is_equal:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_set_equal (hb_set_t *set,
-             hb_set_t *other)
+hb_set_is_equal (const hb_set_t *set,
+                const hb_set_t *other)
 {
-  return set->equal (other);
+  return set->is_equal (other);
 }
 
+/**
+ * hb_set_set:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
-hb_set_set (hb_set_t *set,
-           hb_set_t *other)
+hb_set_set (hb_set_t       *set,
+           const hb_set_t *other)
 {
   set->set (other);
 }
 
+/**
+ * hb_set_union:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
-hb_set_union (hb_set_t *set,
-             hb_set_t *other)
+hb_set_union (hb_set_t       *set,
+             const hb_set_t *other)
 {
   set->union_ (other);
 }
 
+/**
+ * hb_set_intersect:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
-hb_set_intersect (hb_set_t *set,
-                 hb_set_t *other)
+hb_set_intersect (hb_set_t       *set,
+                 const hb_set_t *other)
 {
   set->intersect (other);
 }
 
+/**
+ * hb_set_subtract:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
-hb_set_subtract (hb_set_t *set,
-                hb_set_t *other)
+hb_set_subtract (hb_set_t       *set,
+                const hb_set_t *other)
 {
   set->subtract (other);
 }
 
+/**
+ * hb_set_symmetric_difference:
+ * @set: a set.
+ * @other: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
-hb_set_symmetric_difference (hb_set_t *set,
-                            hb_set_t *other)
+hb_set_symmetric_difference (hb_set_t       *set,
+                            const hb_set_t *other)
 {
   set->symmetric_difference (other);
 }
 
+/**
+ * hb_set_invert:
+ * @set: a set.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_set_invert (hb_set_t *set)
+{
+  set->invert ();
+}
+
+/**
+ * hb_set_get_population:
+ * @set: a set.
+ *
+ * Returns the number of numbers in the set.
+ *
+ * Return value: set population.
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_set_get_population (const hb_set_t *set)
+{
+  return set->get_population ();
+}
+
+/**
+ * hb_set_get_min:
+ * @set: a set.
+ *
+ * Finds the minimum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 1.0
+ **/
 hb_codepoint_t
-hb_set_min (hb_set_t *set)
+hb_set_get_min (const hb_set_t *set)
 {
   return set->get_min ();
 }
 
+/**
+ * hb_set_get_max:
+ * @set: a set.
+ *
+ * Finds the maximum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 1.0
+ **/
 hb_codepoint_t
-hb_set_max (hb_set_t *set)
+hb_set_get_max (const hb_set_t *set)
 {
   return set->get_max ();
 }
 
+/**
+ * hb_set_next:
+ * @set: a set.
+ * @codepoint: (inout):
+ *
+ * 
+ *
+ * Return value: whether there was a next value.
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
-hb_set_next (hb_set_t       *set,
+hb_set_next (const hb_set_t *set,
             hb_codepoint_t *codepoint)
 {
   return set->next (codepoint);
 }
+
+/**
+ * hb_set_next_range:
+ * @set: a set.
+ * @first: (out): output first codepoint in the range.
+ * @last: (inout): input current last and output last codepoint in the range.
+ *
+ * Gets the next consecutive range of numbers in @set that
+ * are greater than current value of @last.
+ *
+ * Return value: whether there was a next range.
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+                  hb_codepoint_t *first,
+                  hb_codepoint_t *last)
+{
+  return set->next_range (first, last);
+}
index 9f849cf..bafdae9 100644 (file)
@@ -36,7 +36,9 @@
 HB_BEGIN_DECLS
 
 
-typedef struct _hb_set_t hb_set_t;
+#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+
+typedef struct hb_set_t hb_set_t;
 
 
 hb_set_t *
@@ -65,16 +67,16 @@ hb_set_get_user_data (hb_set_t           *set,
 
 /* Returns false if allocation has failed before */
 hb_bool_t
-hb_set_allocation_successful (hb_set_t  *set);
+hb_set_allocation_successful (const hb_set_t *set);
 
 void
 hb_set_clear (hb_set_t *set);
 
 hb_bool_t
-hb_set_empty (hb_set_t *set);
+hb_set_is_empty (const hb_set_t *set);
 
 hb_bool_t
-hb_set_has (hb_set_t       *set,
+hb_set_has (const hb_set_t *set,
            hb_codepoint_t  codepoint);
 
 /* Right now limited to 16-bit integers.  Eventually will do full codepoint range, sans -1
@@ -84,47 +86,67 @@ hb_set_add (hb_set_t       *set,
            hb_codepoint_t  codepoint);
 
 void
+hb_set_add_range (hb_set_t       *set,
+                 hb_codepoint_t  first,
+                 hb_codepoint_t  last);
+
+void
 hb_set_del (hb_set_t       *set,
            hb_codepoint_t  codepoint);
 
+void
+hb_set_del_range (hb_set_t       *set,
+                 hb_codepoint_t  first,
+                 hb_codepoint_t  last);
+
 hb_bool_t
-hb_set_equal (hb_set_t *set,
-             hb_set_t *other);
+hb_set_is_equal (const hb_set_t *set,
+                const hb_set_t *other);
 
 void
-hb_set_set (hb_set_t *set,
-           hb_set_t *other);
+hb_set_set (hb_set_t       *set,
+           const hb_set_t *other);
 
 void
-hb_set_union (hb_set_t *set,
-             hb_set_t *other);
+hb_set_union (hb_set_t       *set,
+             const hb_set_t *other);
 
 void
-hb_set_intersect (hb_set_t *set,
-                 hb_set_t *other);
+hb_set_intersect (hb_set_t       *set,
+                 const hb_set_t *other);
 
 void
-hb_set_subtract (hb_set_t *set,
-                hb_set_t *other);
+hb_set_subtract (hb_set_t       *set,
+                const hb_set_t *other);
 
 void
-hb_set_symmetric_difference (hb_set_t *set,
-                            hb_set_t *other);
+hb_set_symmetric_difference (hb_set_t       *set,
+                            const hb_set_t *other);
+
+void
+hb_set_invert (hb_set_t *set);
+
+unsigned int
+hb_set_get_population (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
 hb_codepoint_t
-hb_set_min (hb_set_t *set);
+hb_set_get_min (const hb_set_t *set);
 
 /* Returns -1 if set empty. */
 hb_codepoint_t
-hb_set_max (hb_set_t *set);
+hb_set_get_max (const hb_set_t *set);
 
 /* Pass -1 in to get started. */
 hb_bool_t
-hb_set_next (hb_set_t       *set,
+hb_set_next (const hb_set_t *set,
             hb_codepoint_t *codepoint);
 
-/* TODO: Add faster iteration API? */
+/* Pass -1 for first and last to get started. */
+hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+                  hb_codepoint_t *first,
+                  hb_codepoint_t *last);
 
 
 HB_END_DECLS
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
new file mode 100644 (file)
index 0000000..607da5e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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_SHAPE_PLAN_PRIVATE_HH
+#define HB_SHAPE_PLAN_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
+
+
+struct hb_shape_plan_t
+{
+  hb_object_header_t header;
+  ASSERT_POD ();
+
+  hb_bool_t default_shaper_list;
+  hb_face_t *face_unsafe; /* We don't carry a reference to face. */
+  hb_segment_properties_t props;
+
+  hb_shape_func_t *shaper_func;
+  const char *shaper_name;
+
+  hb_feature_t *user_features;
+  unsigned int num_user_features;
+
+  struct hb_shaper_data_t shaper_data;
+};
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
+       , const hb_feature_t            *user_features \
+       , unsigned int                   num_user_features
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_SHAPE_PLAN_PRIVATE_HH */
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
new file mode 100644 (file)
index 0000000..2166173
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * 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
+ */
+
+#include "hb-shape-plan-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
+
+
+#ifndef HB_DEBUG_SHAPE_PLAN
+#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
+#endif
+
+
+#define HB_SHAPER_IMPLEMENT(shaper) \
+       HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
+       HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+
+static void
+hb_shape_plan_plan (hb_shape_plan_t    *shape_plan,
+                   const hb_feature_t *user_features,
+                   unsigned int        num_user_features,
+                   const char * const *shaper_list)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
+                 "num_features=%d shaper_list=%p",
+                 num_user_features,
+                 shaper_list);
+
+  const hb_shaper_pair_t *shapers = _hb_shapers_get ();
+
+#define HB_SHAPER_PLAN(shaper) \
+       HB_STMT_START { \
+         if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
+           HB_SHAPER_DATA (shaper, shape_plan) = \
+             HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
+           shape_plan->shaper_func = _hb_##shaper##_shape; \
+           shape_plan->shaper_name = #shaper; \
+           return; \
+         } \
+       } HB_STMT_END
+
+  if (likely (!shaper_list)) {
+    for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
+      if (0)
+       ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (shapers[i].func == _hb_##shaper##_shape) \
+       HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  } else {
+    for (; *shaper_list; shaper_list++)
+      if (0)
+       ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (0 == strcmp (*shaper_list, #shaper)) \
+       HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+  }
+
+#undef HB_SHAPER_PLAN
+}
+
+
+/*
+ * hb_shape_plan_t
+ */
+
+/**
+ * hb_shape_plan_create: (Xconstructor)
+ * @face: 
+ * @props: 
+ * @user_features: (array length=num_user_features):
+ * @num_user_features: 
+ * @shaper_list: (array zero-terminated=1):
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t                     *face,
+                     const hb_segment_properties_t *props,
+                     const hb_feature_t            *user_features,
+                     unsigned int                   num_user_features,
+                     const char * const            *shaper_list)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+                 "face=%p num_features=%d shaper_list=%p",
+                 face,
+                 num_user_features,
+                 shaper_list);
+
+  hb_shape_plan_t *shape_plan;
+  hb_feature_t *features = NULL;
+
+  if (unlikely (!face))
+    face = hb_face_get_empty ();
+  if (unlikely (!props || hb_object_is_inert (face)))
+    return hb_shape_plan_get_empty ();
+  if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t))))
+    return hb_shape_plan_get_empty ();
+  if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+    free (features);
+    return hb_shape_plan_get_empty ();
+  }
+
+  assert (props->direction != HB_DIRECTION_INVALID);
+
+  hb_face_make_immutable (face);
+  shape_plan->default_shaper_list = shaper_list == NULL;
+  shape_plan->face_unsafe = face;
+  shape_plan->props = *props;
+  shape_plan->num_user_features = num_user_features;
+  shape_plan->user_features = features;
+  if (num_user_features)
+    memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+
+  hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
+
+  return shape_plan;
+}
+
+/**
+ * hb_shape_plan_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_get_empty (void)
+{
+  static const hb_shape_plan_t _hb_shape_plan_nil = {
+    HB_OBJECT_HEADER_STATIC,
+
+    true, /* default_shaper_list */
+    NULL, /* face */
+    HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
+
+    NULL, /* shaper_func */
+    NULL, /* shaper_name */
+
+    NULL, /* user_features */
+    0,    /* num_user_featurs */
+
+    {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+    }
+  };
+
+  return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
+}
+
+/**
+ * hb_shape_plan_reference: (skip)
+ * @shape_plan: a shape plan.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
+{
+  return hb_object_reference (shape_plan);
+}
+
+/**
+ * hb_shape_plan_destroy: (skip)
+ * @shape_plan: a shape plan.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
+{
+  if (!hb_object_destroy (shape_plan)) return;
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+  free (shape_plan->user_features);
+
+  free (shape_plan);
+}
+
+/**
+ * hb_shape_plan_set_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
+                            hb_user_data_key_t *key,
+                            void *              data,
+                            hb_destroy_func_t   destroy,
+                            hb_bool_t           replace)
+{
+  return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
+}
+
+/**
+ * hb_shape_plan_get_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+void *
+hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
+                            hb_user_data_key_t *key)
+{
+  return hb_object_get_user_data (shape_plan, key);
+}
+
+
+/**
+ * hb_shape_plan_execute:
+ * @shape_plan: a shape plan.
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
+                      hb_font_t          *font,
+                      hb_buffer_t        *buffer,
+                      const hb_feature_t *features,
+                      unsigned int        num_features)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
+                 "num_features=%d shaper_func=%p",
+                 num_features,
+                 shape_plan->shaper_func);
+
+  if (unlikely (hb_object_is_inert (shape_plan) ||
+               hb_object_is_inert (font) ||
+               hb_object_is_inert (buffer)))
+    return false;
+
+  assert (shape_plan->face_unsafe == font->face);
+  assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
+
+#define HB_SHAPER_EXECUTE(shaper) \
+       HB_STMT_START { \
+         return HB_SHAPER_DATA (shaper, shape_plan) && \
+                hb_##shaper##_shaper_font_data_ensure (font) && \
+                _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
+       } HB_STMT_END
+
+  if (0)
+    ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+  else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
+    HB_SHAPER_EXECUTE (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+#undef HB_SHAPER_EXECUTE
+
+  return false;
+}
+
+
+/*
+ * caching
+ */
+
+#if 0
+static unsigned int
+hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
+{
+  return hb_segment_properties_hash (&shape_plan->props) +
+        shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
+}
+#endif
+
+/* User-feature caching is currently somewhat dumb:
+ * it only finds matches where the feature array is identical,
+ * not cases where the feature lists would be compatible for plan purposes
+ * but have different ranges, for example.
+ */
+struct hb_shape_plan_proposal_t
+{
+  const hb_segment_properties_t  props;
+  const char * const            *shaper_list;
+  const hb_feature_t            *user_features;
+  unsigned int                   num_user_features;
+  hb_shape_func_t               *shaper_func;
+};
+
+static inline hb_bool_t
+hb_shape_plan_user_features_match (const hb_shape_plan_t          *shape_plan,
+                                  const hb_shape_plan_proposal_t *proposal)
+{
+  if (proposal->num_user_features != shape_plan->num_user_features) return false;
+  for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
+    if (proposal->user_features[i].tag   != shape_plan->user_features[i].tag   ||
+        proposal->user_features[i].value != shape_plan->user_features[i].value ||
+        proposal->user_features[i].start != shape_plan->user_features[i].start ||
+        proposal->user_features[i].end   != shape_plan->user_features[i].end) return false;
+  return true;
+}
+
+static hb_bool_t
+hb_shape_plan_matches (const hb_shape_plan_t          *shape_plan,
+                      const hb_shape_plan_proposal_t *proposal)
+{
+  return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
+        hb_shape_plan_user_features_match (shape_plan, proposal) &&
+        ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
+         (shape_plan->shaper_func == proposal->shaper_func));
+}
+
+static inline hb_bool_t
+hb_non_global_user_features_present (const hb_feature_t *user_features,
+                                    unsigned int        num_user_features)
+{
+  while (num_user_features)
+    if (user_features->start != 0 || user_features->end != (unsigned int) -1)
+      return true;
+    else
+      num_user_features--, user_features++;
+  return false;
+}
+
+/**
+ * hb_shape_plan_create_cached:
+ * @face: 
+ * @props: 
+ * @user_features: (array length=num_user_features):
+ * @num_user_features: 
+ * @shaper_list: (array zero-terminated=1):
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t                     *face,
+                            const hb_segment_properties_t *props,
+                            const hb_feature_t            *user_features,
+                            unsigned int                   num_user_features,
+                            const char * const            *shaper_list)
+{
+  DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+                 "face=%p num_features=%d shaper_list=%p",
+                 face,
+                 num_user_features,
+                 shaper_list);
+
+  hb_shape_plan_proposal_t proposal = {
+    *props,
+    shaper_list,
+    user_features,
+    num_user_features,
+    NULL
+  };
+
+  if (shaper_list) {
+    /* Choose shaper.  Adapted from hb_shape_plan_plan().
+     * Must choose shaper exactly the same way as that function. */
+    for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
+      if (0)
+       ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+      else if (0 == strcmp (*shaper_item, #shaper) && \
+              hb_##shaper##_shaper_face_data_ensure (face)) \
+      { \
+       proposal.shaper_func = _hb_##shaper##_shape; \
+       break; \
+      }
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+    if (unlikely (!proposal.shaper_func))
+      return hb_shape_plan_get_empty ();
+  }
+
+
+retry:
+  hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
+  for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
+    if (hb_shape_plan_matches (node->shape_plan, &proposal))
+    {
+      DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
+      return hb_shape_plan_reference (node->shape_plan);
+    }
+
+  /* Not found. */
+
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+
+  /* Don't add the plan to the cache if there were user features with non-global ranges */
+
+  if (hb_non_global_user_features_present (user_features, num_user_features))
+    return shape_plan;
+
+  hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
+  if (unlikely (!node))
+    return shape_plan;
+
+  node->shape_plan = shape_plan;
+  node->next = cached_plan_nodes;
+
+  if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
+    hb_shape_plan_destroy (shape_plan);
+    free (node);
+    goto retry;
+  }
+  DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
+
+  return hb_shape_plan_reference (shape_plan);
+}
+
+/**
+ * hb_shape_plan_get_shaper:
+ * @shape_plan: a shape plan.
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+const char *
+hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
+{
+  return shape_plan->shaper_name;
+}
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
new file mode 100644 (file)
index 0000000..8f54552
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_SHAPE_PLAN_H
+#define HB_SHAPE_PLAN_H
+
+#include "hb-common.h"
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+typedef struct hb_shape_plan_t hb_shape_plan_t;
+
+hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t                     *face,
+                     const hb_segment_properties_t *props,
+                     const hb_feature_t            *user_features,
+                     unsigned int                   num_user_features,
+                     const char * const            *shaper_list);
+
+hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t                     *face,
+                            const hb_segment_properties_t *props,
+                            const hb_feature_t            *user_features,
+                            unsigned int                   num_user_features,
+                            const char * const            *shaper_list);
+
+hb_shape_plan_t *
+hb_shape_plan_get_empty (void);
+
+hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
+
+void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
+
+hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t    *shape_plan,
+                            hb_user_data_key_t *key,
+                            void *              data,
+                            hb_destroy_func_t   destroy,
+                            hb_bool_t           replace);
+
+void *
+hb_shape_plan_get_user_data (hb_shape_plan_t    *shape_plan,
+                            hb_user_data_key_t *key);
+
+
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t    *shape_plan,
+                      hb_font_t          *font,
+                      hb_buffer_t        *buffer,
+                      const hb_feature_t *features,
+                      unsigned int        num_features);
+
+const char *
+hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
+
+
+HB_END_DECLS
+
+#endif /* HB_SHAPE_PLAN_H */
index 163a5bf..4e22c61 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #include "hb-private.hh"
 
-#include "hb-shape.h"
-
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
 #include "hb-buffer-private.hh"
+#include "hb-font-private.hh"
 
-#ifdef HAVE_GRAPHITE
-#include "hb-graphite2-private.hh"
-#endif
-#ifdef HAVE_UNISCRIBE
-# include "hb-uniscribe-private.hh"
-#endif
-#ifdef HAVE_OT
-# include "hb-ot-shape-private.hh"
-#endif
-#include "hb-fallback-shape-private.hh"
-
-typedef hb_bool_t (*hb_shape_func_t) (hb_font_t          *font,
-                                     hb_buffer_t        *buffer,
-                                     const hb_feature_t *features,
-                                     unsigned int        num_features);
-
-#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}
-static const struct hb_shaper_pair_t {
-  char name[16];
-  hb_shape_func_t func;
-} all_shapers[] = {
-  /* v--- Add new shapers in the right place here */
-#ifdef HAVE_GRAPHITE
-  HB_SHAPER_IMPLEMENT (graphite2),
-#endif
-#ifdef HAVE_UNISCRIBE
-  HB_SHAPER_IMPLEMENT (uniscribe),
-#endif
-#ifdef HAVE_OT
-  HB_SHAPER_IMPLEMENT (ot),
-#endif
-  HB_SHAPER_IMPLEMENT (fallback) /* should be last */
-};
-#undef HB_SHAPER_IMPLEMENT
 
+static bool
+parse_space (const char **pp, const char *end)
+{
+  while (*pp < end && ISSPACE (**pp))
+    (*pp)++;
+  return true;
+}
 
-/* Thread-safe, lock-free, shapers */
+static bool
+parse_char (const char **pp, const char *end, char c)
+{
+  parse_space (pp, end);
 
-static hb_shaper_pair_t *static_shapers;
+  if (*pp == end || **pp != c)
+    return false;
 
-static
-void free_static_shapers (void)
+  (*pp)++;
+  return true;
+}
+
+static bool
+parse_uint (const char **pp, const char *end, unsigned int *pv)
 {
-  if (unlikely (static_shapers != all_shapers))
-    free (static_shapers);
+  char buf[32];
+  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
+  strncpy (buf, *pp, len);
+  buf[len] = '\0';
+
+  char *p = buf;
+  char *pend = p;
+  unsigned int v;
+
+  /* Intentionally use strtol instead of strtoul, such that
+   * -1 turns into "big number"... */
+  errno = 0;
+  v = strtol (p, &pend, 0);
+  if (errno || p == pend)
+    return false;
+
+  *pv = v;
+  *pp += pend - p;
+  return true;
 }
 
-static const hb_shaper_pair_t *
-get_shapers (void)
+static bool
+parse_bool (const char **pp, const char *end, unsigned int *pv)
 {
-retry:
-  hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
+  parse_space (pp, end);
+
+  const char *p = *pp;
+  while (*pp < end && ISALPHA(**pp))
+    (*pp)++;
+
+  /* CSS allows on/off as aliases 1/0. */
+  if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
+    *pv = 1;
+  else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
+    *pv = 0;
+  else
+    return false;
+
+  return true;
+}
+
+static bool
+parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
+{
+  if (parse_char (pp, end, '-'))
+    feature->value = 0;
+  else {
+    parse_char (pp, end, '+');
+    feature->value = 1;
+  }
+
+  return true;
+}
 
-  if (unlikely (!shapers))
+static bool
+parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
+{
+  parse_space (pp, end);
+
+  char quote = 0;
+
+  if (*pp < end && (**pp == '\'' || **pp == '"'))
   {
-    char *env = getenv ("HB_SHAPER_LIST");
-    if (!env || !*env) {
-      hb_atomic_ptr_cmpexch (&static_shapers, NULL, (const hb_shaper_pair_t *) all_shapers);
-      return (const hb_shaper_pair_t *) all_shapers;
-    }
+    quote = **pp;
+    (*pp)++;
+  }
 
-    /* Not found; allocate one. */
-    shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
-    if (unlikely (!shapers))
-      return (const hb_shaper_pair_t *) all_shapers;
-     memcpy (shapers, all_shapers, sizeof (all_shapers));
-
-     /* Reorder shaper list to prefer requested shapers. */
-    unsigned int i = 0;
-    char *end, *p = env;
-    for (;;) {
-      end = strchr (p, ',');
-      if (!end)
-       end = p + strlen (p);
-
-      for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
-       if (end - p == (int) strlen (shapers[j].name) &&
-           0 == strncmp (shapers[j].name, p, end - p))
-       {
-         /* Reorder this shaper to position i */
-        struct hb_shaper_pair_t t = shapers[j];
-        memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
-        shapers[i] = t;
-        i++;
-       }
-
-      if (!*end)
-       break;
-      else
-       p = end + 1;
-    }
+  const char *p = *pp;
+  while (*pp < end && ISALNUM(**pp))
+    (*pp)++;
 
-    if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
-      free (shapers);
-      goto retry;
-    }
+  if (p == *pp || *pp - p > 4)
+    return false;
 
-#ifdef HAVE_ATEXIT
-    atexit (free_static_shapers); /* First person registers atexit() callback. */
-#endif
+  feature->tag = hb_tag_from_string (p, *pp - p);
+
+  if (quote)
+  {
+    /* CSS expects exactly four bytes.  And we only allow quotations for
+     * CSS compatibility.  So, enforce the length. */
+     if (*pp - p != 4)
+       return false;
+    if (*pp == end || **pp != quote)
+      return false;
+    (*pp)++;
+  }
+
+  return true;
+}
+
+static bool
+parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
+{
+  parse_space (pp, end);
+
+  bool has_start;
+
+  feature->start = 0;
+  feature->end = (unsigned int) -1;
+
+  if (!parse_char (pp, end, '['))
+    return true;
+
+  has_start = parse_uint (pp, end, &feature->start);
+
+  if (parse_char (pp, end, ':')) {
+    parse_uint (pp, end, &feature->end);
+  } else {
+    if (has_start)
+      feature->end = feature->start + 1;
   }
 
-  return shapers;
+  return parse_char (pp, end, ']');
+}
+
+static bool
+parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
+{
+  bool had_equal = parse_char (pp, end, '=');
+  bool had_value = parse_uint (pp, end, &feature->value) ||
+                   parse_bool (pp, end, &feature->value);
+  /* CSS doesn't use equal-sign between tag and value.
+   * If there was an equal-sign, then there *must* be a value.
+   * A value without an eqaul-sign is ok, but not required. */
+  return !had_equal || had_value;
+}
+
+
+static bool
+parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
+{
+  return parse_feature_value_prefix (pp, end, feature) &&
+        parse_feature_tag (pp, end, feature) &&
+        parse_feature_indices (pp, end, feature) &&
+        parse_feature_value_postfix (pp, end, feature) &&
+        parse_space (pp, end) &&
+        *pp == end;
+}
+
+/**
+ * hb_feature_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len: 
+ * @feature: (out) (optional):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+                       hb_feature_t *feature)
+{
+  hb_feature_t feat;
+
+  if (len < 0)
+    len = strlen (str);
+
+  if (likely (parse_one_feature (&str, str + len, &feat)))
+  {
+    if (feature)
+      *feature = feat;
+    return true;
+  }
+
+  if (feature)
+    memset (feature, 0, sizeof (*feature));
+  return false;
+}
+
+/**
+ * hb_feature_to_string:
+ * @feature: 
+ * @buf: (array length=size):
+ * @size: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_feature_to_string (hb_feature_t *feature,
+                     char *buf, unsigned int size)
+{
+  if (unlikely (!size)) return;
+
+  char s[128];
+  unsigned int len = 0;
+  if (feature->value == 0)
+    s[len++] = '-';
+  hb_tag_to_string (feature->tag, s + len);
+  len += 4;
+  while (len && s[len - 1] == ' ')
+    len--;
+  if (feature->start != 0 || feature->end != (unsigned int) -1)
+  {
+    s[len++] = '[';
+    if (feature->start)
+      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
+    if (feature->end != feature->start + 1) {
+      s[len++] = ':';
+      if (feature->end != (unsigned int) -1)
+       len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
+    }
+    s[len++] = ']';
+  }
+  if (feature->value > 1)
+  {
+    s[len++] = '=';
+    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+  }
+  assert (len < ARRAY_LENGTH (s));
+  len = MIN (len, size - 1);
+  memcpy (buf, s, len);
+  buf[len] = '\0';
 }
 
 
 static const char **static_shaper_list;
 
+#ifdef HB_USE_ATEXIT
 static
 void free_static_shaper_list (void)
 {
   free (static_shaper_list);
 }
+#endif
 
+/**
+ * hb_shape_list_shapers:
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 const char **
 hb_shape_list_shapers (void)
 {
@@ -153,15 +305,15 @@ retry:
   if (unlikely (!shaper_list))
   {
     /* Not found; allocate one. */
-    shaper_list = (const char **) calloc (1 + ARRAY_LENGTH (all_shapers), sizeof (const char *));
+    shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
     if (unlikely (!shaper_list)) {
       static const char *nil_shaper_list[] = {NULL};
       return nil_shaper_list;
     }
 
-    const hb_shaper_pair_t *shapers = get_shapers ();
+    const hb_shaper_pair_t *shapers = _hb_shapers_get ();
     unsigned int i;
-    for (i = 0; i < ARRAY_LENGTH (all_shapers); i++)
+    for (i = 0; i < HB_SHAPERS_COUNT; i++)
       shaper_list[i] = shapers[i].name;
     shaper_list[i] = NULL;
 
@@ -170,7 +322,7 @@ retry:
       goto retry;
     }
 
-#ifdef HAVE_ATEXIT
+#ifdef HB_USE_ATEXIT
     atexit (free_static_shaper_list); /* First person registers atexit() callback. */
 #endif
   }
@@ -179,6 +331,20 @@ retry:
 }
 
 
+/**
+ * hb_shape_full:
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features: 
+ * @shaper_list: (array zero-terminated=1):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_shape_full (hb_font_t          *font,
               hb_buffer_t        *buffer,
@@ -186,27 +352,31 @@ hb_shape_full (hb_font_t          *font,
               unsigned int        num_features,
               const char * const *shaper_list)
 {
-  hb_font_make_immutable (font); /* So we can safely cache stuff on it */
+  if (unlikely (!buffer->len))
+    return true;
 
-  if (likely (!shaper_list)) {
-    const hb_shaper_pair_t *shapers = get_shapers ();
-    for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
-      if (likely (shapers[i].func (font, buffer, features, num_features)))
-        return true;
-  } else {
-    while (*shaper_list) {
-      for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
-       if (0 == strcmp (*shaper_list, all_shapers[i].name)) {
-         if (likely (all_shapers[i].func (font, buffer, features, num_features)))
-           return true;
-         break;
-       }
-      shaper_list++;
-    }
-  }
-  return false;
+  assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
+
+  hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
+  hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
+  hb_shape_plan_destroy (shape_plan);
+
+  if (res)
+    buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+  return res;
 }
 
+/**
+ * hb_shape:
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features: 
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_shape (hb_font_t           *font,
          hb_buffer_t         *buffer,
index 1a0d6cf..10a35cb 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
@@ -22,6 +23,7 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
  */
 
 #ifndef HB_H_IN
 HB_BEGIN_DECLS
 
 
-typedef struct _hb_feature_t {
+typedef struct hb_feature_t {
   hb_tag_t      tag;
   uint32_t      value;
   unsigned int  start;
   unsigned int  end;
 } hb_feature_t;
 
+/* len=-1 means str is NUL-terminated */
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+                       hb_feature_t *feature);
+
+/* Something like 128 bytes is more than enough.
+ * nul-terminates. */
+void
+hb_feature_to_string (hb_feature_t *feature,
+                     char *buf, unsigned int size);
+
 
 void
 hb_shape (hb_font_t           *font,
similarity index 77%
rename from src/hb-graphite2-private.hh
rename to src/hb-shaper-impl-private.hh
index 644ea75..7844081 100644 (file)
  * Google Author(s): Behdad Esfahbod
  */
 
-#ifndef HB_GRAPHITE2_PRIVATE_HH
-#define HB_GRAPHITE2_PRIVATE_HH
+#ifndef HB_SHAPER_IMPL_PRIVATE_HH
+#define HB_SHAPER_IMPL_PRIVATE_HH
 
 #include "hb-private.hh"
 
-#include "hb-graphite2.h"
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
 
 
-HB_INTERNAL hb_bool_t
-_hb_graphite2_shape (hb_font_t          *font,
-                    hb_buffer_t        *buffer,
-                    const hb_feature_t *features,
-                    unsigned int        num_features);
+#ifdef HB_SHAPER
+#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object)
+#endif
 
 
-#endif /* HB_GRAPHITE2_PRIVATE_HH */
+#endif /* HB_SHAPER_IMPL_PRIVATE_HH */
diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh
new file mode 100644 (file)
index 0000000..6c537d4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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_SHAPER_LIST_HH
+#define HB_SHAPER_LIST_HH
+#endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
+
+/* v--- Add new shapers in the right place here. */
+
+#ifdef HAVE_GRAPHITE2
+/* Only picks up fonts that have a "Silf" table. */
+HB_SHAPER_IMPLEMENT (graphite2)
+#endif
+#ifdef HAVE_CORETEXT
+/* Only picks up fonts that have a "mort" or "morx" table. */
+HB_SHAPER_IMPLEMENT (coretext_aat)
+#endif
+
+#ifdef HAVE_OT
+HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+#endif
+
+#ifdef HAVE_UNISCRIBE
+HB_SHAPER_IMPLEMENT (uniscribe)
+#endif
+#ifdef HAVE_CORETEXT
+HB_SHAPER_IMPLEMENT (coretext)
+#endif
+
+#ifdef HAVE_FALLBACK
+HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
+#endif
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
new file mode 100644 (file)
index 0000000..d1d1146
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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_SHAPER_PRIVATE_HH
+#define HB_SHAPER_PRIVATE_HH
+
+#include "hb-private.hh"
+
+typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t    *shape_plan,
+                                  hb_font_t          *font,
+                                  hb_buffer_t        *buffer,
+                                  const hb_feature_t *features,
+                                  unsigned int        num_features);
+
+#define HB_SHAPER_IMPLEMENT(name) \
+       extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+struct hb_shaper_pair_t {
+  char name[16];
+  hb_shape_func_t *func;
+};
+
+HB_INTERNAL const hb_shaper_pair_t *
+_hb_shapers_get (void);
+
+
+/* For embedding in face / font / ... */
+struct hb_shaper_data_t {
+#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
+
+/* Means: succeeded, but don't need to keep any data. */
+#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
+
+/* Means: tried but failed to create. */
+#define HB_SHAPER_DATA_INVALID ((void *) -1)
+#define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
+
+#define HB_SHAPER_DATA_TYPE(shaper, object)            struct hb_##shaper##_shaper_##object##_data_t
+#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance)      (* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
+#define HB_SHAPER_DATA(shaper, object)                 HB_SHAPER_DATA_INSTANCE (shaper, object, object)
+#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object)     _hb_##shaper##_shaper_##object##_data_create
+#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object)    _hb_##shaper##_shaper_##object##_data_destroy
+
+#define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
+       HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
+       extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
+       HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
+       extern "C" HB_INTERNAL void \
+       HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
+
+#define HB_SHAPER_DATA_DESTROY(shaper, object) \
+    if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \
+      if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \
+        HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data);
+
+#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
+static inline bool \
+hb_##shaper##_shaper_##object##_data_ensure (hb_##object##_t *object) \
+{\
+  retry: \
+  HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
+  if (unlikely (!data)) { \
+    data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
+    if (unlikely (!data)) \
+      data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
+    if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
+      if (data && \
+         data != HB_SHAPER_DATA_INVALID && \
+         data != HB_SHAPER_DATA_SUCCEEDED) \
+       HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
+      goto retry; \
+    } \
+  } \
+  return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
+}
+
+
+#endif /* HB_SHAPER_PRIVATE_HH */
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
new file mode 100644 (file)
index 0000000..580b95c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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
+ */
+
+#include "hb-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-atomic-private.hh"
+
+
+static const hb_shaper_pair_t all_shapers[] = {
+#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+
+/* Thread-safe, lock-free, shapers */
+
+static const hb_shaper_pair_t *static_shapers;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_shapers (void)
+{
+  if (unlikely (static_shapers != all_shapers))
+    free ((void *) static_shapers);
+}
+#endif
+
+const hb_shaper_pair_t *
+_hb_shapers_get (void)
+{
+retry:
+  hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
+
+  if (unlikely (!shapers))
+  {
+    char *env = getenv ("HB_SHAPER_LIST");
+    if (!env || !*env) {
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      return (const hb_shaper_pair_t *) all_shapers;
+    }
+
+    /* Not found; allocate one. */
+    shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
+    if (unlikely (!shapers)) {
+      (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+      return (const hb_shaper_pair_t *) all_shapers;
+    }
+
+    memcpy (shapers, all_shapers, sizeof (all_shapers));
+
+     /* Reorder shaper list to prefer requested shapers. */
+    unsigned int i = 0;
+    char *end, *p = env;
+    for (;;) {
+      end = strchr (p, ',');
+      if (!end)
+       end = p + strlen (p);
+
+      for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
+       if (end - p == (int) strlen (shapers[j].name) &&
+           0 == strncmp (shapers[j].name, p, end - p))
+       {
+         /* Reorder this shaper to position i */
+        struct hb_shaper_pair_t t = shapers[j];
+        memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
+        shapers[i] = t;
+        i++;
+       }
+
+      if (!*end)
+       break;
+      else
+       p = end + 1;
+    }
+
+    if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
+      free (shapers);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_static_shapers); /* First person registers atexit() callback. */
+#endif
+  }
+
+  return shapers;
+}
diff --git a/src/hb-tt-font.cc b/src/hb-tt-font.cc
deleted file mode 100644 (file)
index 0055ae9..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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
- */
-
-#include "hb-font-private.hh" /* Shall be first since may include windows.h */
-
-#include "hb-open-type-private.hh"
-
-#include "hb-ot-hhea-table.hh"
-#include "hb-ot-hmtx-table.hh"
-
-#include "hb-blob.h"
-
-#include <string.h>
-
-
-
-#if 0
-struct hb_tt_font_t
-{
-  const struct hhea *hhea;
-  hb_blob_t *hhea_blob;
-};
-
-
-static hb_tt_font_t *
-_hb_tt_font_create (hb_font_t *font)
-{
-  /* TODO Remove this object altogether */
-  hb_tt_font_t *tt = (hb_tt_font_t *) calloc (1, sizeof (hb_tt_font_t));
-
-  tt->hhea_blob = Sanitizer<hhea>::sanitize (hb_face_reference_table (font->face, HB_OT_TAG_hhea));
-  tt->hhea = Sanitizer<hhea>::lock_instance (tt->hhea_blob);
-
-  return tt;
-}
-
-static void
-_hb_tt_font_destroy (hb_tt_font_t *tt)
-{
-  hb_blob_destroy (tt->hhea_blob);
-
-  free (tt);
-}
-
-static inline const hhea&
-_get_hhea (hb_face_t *face)
-{
-//  return likely (face->tt && face->tt->hhea) ? *face->tt->hhea : Null(hhea);
-}
-
-
-/*
- * hb_tt_font_funcs_t
- */
-
-static hb_bool_t
-hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
-                      void *font_data HB_UNUSED,
-                      hb_codepoint_t unicode,
-                      hb_codepoint_t variation_selector,
-                      hb_codepoint_t *glyph,
-                      void *user_data HB_UNUSED)
-{
-  if (font->parent)
-    return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph);
-
-  *glyph = 0;
-  return false;
-}
-
-static hb_position_t
-hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
-                                void *font_data HB_UNUSED,
-                                hb_codepoint_t glyph,
-                                void *user_data HB_UNUSED)
-{
-  if (font->parent)
-    return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph));
-
-  return font->x_scale;
-}
-
-static hb_position_t
-hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
-                                void *font_data HB_UNUSED,
-                                hb_codepoint_t glyph,
-                                void *user_data HB_UNUSED)
-{
-  if (font->parent)
-    return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph));
-
-  return font->y_scale;
-}
-
-static hb_bool_t
-hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
-                               void *font_data HB_UNUSED,
-                               hb_codepoint_t glyph,
-                               hb_position_t *x,
-                               hb_position_t *y,
-                               void *user_data HB_UNUSED)
-{
-  if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent,
-                                               glyph,
-                                               x, y);
-    if (ret)
-      font->parent_scale_position (x, y);
-    return ret;
-  }
-
-  *x = *y = 0;
-  return false;
-}
-
-static hb_bool_t
-hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
-                               void *font_data HB_UNUSED,
-                               hb_codepoint_t glyph,
-                               hb_position_t *x,
-                               hb_position_t *y,
-                               void *user_data HB_UNUSED)
-{
-  if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent,
-                                               glyph,
-                                               x, y);
-    if (ret)
-      font->parent_scale_position (x, y);
-    return ret;
-  }
-
-  *x = *y = 0;
-  return false;
-}
-
-static hb_position_t
-hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
-                                void *font_data HB_UNUSED,
-                                hb_codepoint_t left_glyph,
-                                hb_codepoint_t right_glyph,
-                                void *user_data HB_UNUSED)
-{
-  if (font->parent)
-    return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph));
-
-  return 0;
-}
-
-static hb_position_t
-hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
-                                void *font_data HB_UNUSED,
-                                hb_codepoint_t top_glyph,
-                                hb_codepoint_t bottom_glyph,
-                                void *user_data HB_UNUSED)
-{
-  if (font->parent)
-    return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph));
-
-  return 0;
-}
-
-static hb_bool_t
-hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
-                              void *font_data HB_UNUSED,
-                              hb_codepoint_t glyph,
-                              hb_glyph_extents_t *extents,
-                              void *user_data HB_UNUSED)
-{
-  if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_extents (font->parent,
-                                              glyph,
-                                              extents);
-    if (ret) {
-      font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
-      font->parent_scale_distance (&extents->width, &extents->height);
-    }
-    return ret;
-  }
-
-  memset (extents, 0, sizeof (*extents));
-  return false;
-}
-
-static hb_bool_t
-hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
-                                    void *font_data HB_UNUSED,
-                                    hb_codepoint_t glyph,
-                                    unsigned int point_index,
-                                    hb_position_t *x,
-                                    hb_position_t *y,
-                                    void *user_data HB_UNUSED)
-{
-  if (font->parent) {
-    hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent,
-                                                    glyph, point_index,
-                                                    x, y);
-    if (ret)
-      font->parent_scale_position (x, y);
-    return ret;
-  }
-
-  *x = *y = 0;
-  return false;
-}
-
-
-static hb_font_funcs_t _hb_font_funcs_nil = {
-  HB_OBJECT_HEADER_STATIC,
-
-  true, /* immutable */
-
-  {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
-    HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
-  }
-};
-#endif
-
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
new file mode 100644 (file)
index 0000000..5b53821
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ */
+
+#include "hb-private.hh"
+
+#include "hb-unicode-private.hh"
+
+#include "ucdn.h"
+
+static const hb_script_t ucdn_script_translate[] =
+{
+    HB_SCRIPT_COMMON,
+    HB_SCRIPT_LATIN,
+    HB_SCRIPT_GREEK,
+    HB_SCRIPT_CYRILLIC,
+    HB_SCRIPT_ARMENIAN,
+    HB_SCRIPT_HEBREW,
+    HB_SCRIPT_ARABIC,
+    HB_SCRIPT_SYRIAC,
+    HB_SCRIPT_THAANA,
+    HB_SCRIPT_DEVANAGARI,
+    HB_SCRIPT_BENGALI,
+    HB_SCRIPT_GURMUKHI,
+    HB_SCRIPT_GUJARATI,
+    HB_SCRIPT_ORIYA,
+    HB_SCRIPT_TAMIL,
+    HB_SCRIPT_TELUGU,
+    HB_SCRIPT_KANNADA,
+    HB_SCRIPT_MALAYALAM,
+    HB_SCRIPT_SINHALA,
+    HB_SCRIPT_THAI,
+    HB_SCRIPT_LAO,
+    HB_SCRIPT_TIBETAN,
+    HB_SCRIPT_MYANMAR,
+    HB_SCRIPT_GEORGIAN,
+    HB_SCRIPT_HANGUL,
+    HB_SCRIPT_ETHIOPIC,
+    HB_SCRIPT_CHEROKEE,
+    HB_SCRIPT_CANADIAN_SYLLABICS,
+    HB_SCRIPT_OGHAM,
+    HB_SCRIPT_RUNIC,
+    HB_SCRIPT_KHMER,
+    HB_SCRIPT_MONGOLIAN,
+    HB_SCRIPT_HIRAGANA,
+    HB_SCRIPT_KATAKANA,
+    HB_SCRIPT_BOPOMOFO,
+    HB_SCRIPT_HAN,
+    HB_SCRIPT_YI,
+    HB_SCRIPT_OLD_ITALIC,
+    HB_SCRIPT_GOTHIC,
+    HB_SCRIPT_DESERET,
+    HB_SCRIPT_INHERITED,
+    HB_SCRIPT_TAGALOG,
+    HB_SCRIPT_HANUNOO,
+    HB_SCRIPT_BUHID,
+    HB_SCRIPT_TAGBANWA,
+    HB_SCRIPT_LIMBU,
+    HB_SCRIPT_TAI_LE,
+    HB_SCRIPT_LINEAR_B,
+    HB_SCRIPT_UGARITIC,
+    HB_SCRIPT_SHAVIAN,
+    HB_SCRIPT_OSMANYA,
+    HB_SCRIPT_CYPRIOT,
+    HB_SCRIPT_BRAILLE,
+    HB_SCRIPT_BUGINESE,
+    HB_SCRIPT_COPTIC,
+    HB_SCRIPT_NEW_TAI_LUE,
+    HB_SCRIPT_GLAGOLITIC,
+    HB_SCRIPT_TIFINAGH,
+    HB_SCRIPT_SYLOTI_NAGRI,
+    HB_SCRIPT_OLD_PERSIAN,
+    HB_SCRIPT_KHAROSHTHI,
+    HB_SCRIPT_BALINESE,
+    HB_SCRIPT_CUNEIFORM,
+    HB_SCRIPT_PHOENICIAN,
+    HB_SCRIPT_PHAGS_PA,
+    HB_SCRIPT_NKO,
+    HB_SCRIPT_SUNDANESE,
+    HB_SCRIPT_LEPCHA,
+    HB_SCRIPT_OL_CHIKI,
+    HB_SCRIPT_VAI,
+    HB_SCRIPT_SAURASHTRA,
+    HB_SCRIPT_KAYAH_LI,
+    HB_SCRIPT_REJANG,
+    HB_SCRIPT_LYCIAN,
+    HB_SCRIPT_CARIAN,
+    HB_SCRIPT_LYDIAN,
+    HB_SCRIPT_CHAM,
+    HB_SCRIPT_TAI_THAM,
+    HB_SCRIPT_TAI_VIET,
+    HB_SCRIPT_AVESTAN,
+    HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
+    HB_SCRIPT_SAMARITAN,
+    HB_SCRIPT_LISU,
+    HB_SCRIPT_BAMUM,
+    HB_SCRIPT_JAVANESE,
+    HB_SCRIPT_MEETEI_MAYEK,
+    HB_SCRIPT_IMPERIAL_ARAMAIC,
+    HB_SCRIPT_OLD_SOUTH_ARABIAN,
+    HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
+    HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
+    HB_SCRIPT_OLD_TURKIC,
+    HB_SCRIPT_KAITHI,
+    HB_SCRIPT_BATAK,
+    HB_SCRIPT_BRAHMI,
+    HB_SCRIPT_MANDAIC,
+    HB_SCRIPT_CHAKMA,
+    HB_SCRIPT_MEROITIC_CURSIVE,
+    HB_SCRIPT_MEROITIC_HIEROGLYPHS,
+    HB_SCRIPT_MIAO,
+    HB_SCRIPT_SHARADA,
+    HB_SCRIPT_SORA_SOMPENG,
+    HB_SCRIPT_TAKRI,
+    HB_SCRIPT_UNKNOWN,
+    HB_SCRIPT_BASSA_VAH,
+    HB_SCRIPT_CAUCASIAN_ALBANIAN,
+    HB_SCRIPT_DUPLOYAN,
+    HB_SCRIPT_ELBASAN,
+    HB_SCRIPT_GRANTHA,
+    HB_SCRIPT_KHOJKI,
+    HB_SCRIPT_KHUDAWADI,
+    HB_SCRIPT_LINEAR_A,
+    HB_SCRIPT_MAHAJANI,
+    HB_SCRIPT_MANICHAEAN,
+    HB_SCRIPT_MENDE_KIKAKUI,
+    HB_SCRIPT_MODI,
+    HB_SCRIPT_MRO,
+    HB_SCRIPT_NABATAEAN,
+    HB_SCRIPT_OLD_NORTH_ARABIAN,
+    HB_SCRIPT_OLD_PERMIC,
+    HB_SCRIPT_PAHAWH_HMONG,
+    HB_SCRIPT_PALMYRENE,
+    HB_SCRIPT_PAU_CIN_HAU,
+    HB_SCRIPT_PSALTER_PAHLAVI,
+    HB_SCRIPT_SIDDHAM,
+    HB_SCRIPT_TIRHUTA,
+    HB_SCRIPT_WARANG_CITI,
+};
+
+static hb_unicode_combining_class_t
+hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                       void *user_data HB_UNUSED)
+{
+    return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode);
+}
+
+static unsigned int
+hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                       void *user_data HB_UNUSED)
+{
+    int w = ucdn_get_east_asian_width(unicode);
+    return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1;
+}
+
+static hb_unicode_general_category_t
+hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                        void *user_data HB_UNUSED)
+{
+    return (hb_unicode_general_category_t)ucdn_get_general_category(unicode);
+}
+
+static hb_codepoint_t
+hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+                 void *user_data HB_UNUSED)
+{
+    return ucdn_mirror(unicode);
+}
+
+static hb_script_t
+hb_ucdn_script(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+              void *user_data HB_UNUSED)
+{
+    return ucdn_script_translate[ucdn_get_script(unicode)];
+}
+
+static hb_bool_t
+hb_ucdn_compose(hb_unicode_funcs_t *ufuncs,
+               hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
+               void *user_data HB_UNUSED)
+{
+    return ucdn_compose(ab, a, b);
+}
+
+static hb_bool_t
+hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs,
+                 hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
+                 void *user_data HB_UNUSED)
+{
+    return ucdn_decompose(ab, a, b);
+}
+
+static unsigned int
+hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs,
+                               hb_codepoint_t u, hb_codepoint_t *decomposed,
+                               void *user_data HB_UNUSED)
+{
+    return ucdn_compat_decompose(u, decomposed);
+}
+
+extern "C" HB_INTERNAL
+hb_unicode_funcs_t *
+hb_ucdn_get_unicode_funcs (void)
+{
+  static const hb_unicode_funcs_t _hb_ucdn_unicode_funcs = {
+    HB_OBJECT_HEADER_STATIC,
+
+    NULL, /* parent */
+    true, /* immutable */
+    {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_ucdn_##name,
+      HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+    }
+  };
+
+  return const_cast<hb_unicode_funcs_t *> (&_hb_ucdn_unicode_funcs);
+}
+
diff --git a/src/hb-ucdn/COPYING b/src/hb-ucdn/COPYING
new file mode 100644 (file)
index 0000000..be5205c
--- /dev/null
@@ -0,0 +1,13 @@
+The contents of this directory are licensed under the following terms:
+
+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.
diff --git a/src/hb-ucdn/Makefile.am b/src/hb-ucdn/Makefile.am
new file mode 100644 (file)
index 0000000..0670b5c
--- /dev/null
@@ -0,0 +1,18 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LTLIBRARIES = libhb-ucdn.la
+
+
+libhb_ucdn_la_SOURCES = \
+       ucdn.h \
+       ucdn.c \
+       unicodedata_db.h
+libhb_ucdn_la_CPPFLAGS = \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/src \
+       -I$(top_builddir)/src
+libhb_ucdn_la_LIBADD =
+
+EXTRA_DIST = README COPYING
+
+-include $(top_srcdir)/git.mk
similarity index 53%
rename from test/shaping/Makefile.in
rename to src/hb-ucdn/Makefile.in
index c1969c4..64e16d2 100644 (file)
@@ -1,9 +1,9 @@
-# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
-# Inc.
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -15,7 +15,6 @@
 
 @SET_MAKE@
 
-# Process this file with automake to produce Makefile.in
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
@@ -35,24 +34,58 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-subdir = test/shaping
-DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+subdir = src/hb-ucdn
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       COPYING
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+       $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+       $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+       $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = $(top_builddir)/config.h
 CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
-AM_V_GEN = $(am__v_GEN_$(V))
-am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
-am__v_GEN_0 = @echo "  GEN   " $@;
-AM_V_at = $(am__v_at_$(V))
-am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libhb_ucdn_la_DEPENDENCIES =
+am_libhb_ucdn_la_OBJECTS = ucdn.lo
+libhb_ucdn_la_OBJECTS = $(am_libhb_ucdn_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC    " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
 am__v_at_0 = @
-SOURCES =
-DIST_SOURCES =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD  " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN   " $@;
+SOURCES = $(libhb_ucdn_la_SOURCES)
+DIST_SOURCES = $(libhb_ucdn_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
 AMTAR = @AMTAR@
@@ -69,6 +102,8 @@ CAIRO_LIBS = @CAIRO_LIBS@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
+CORETEXT_CFLAGS = @CORETEXT_CFLAGS@
+CORETEXT_LIBS = @CORETEXT_LIBS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CXX = @CXX@
@@ -78,6 +113,7 @@ CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@
 ECHO_C = @ECHO_C@
@@ -104,6 +140,8 @@ HB_VERSION_MAJOR = @HB_VERSION_MAJOR@
 HB_VERSION_MICRO = @HB_VERSION_MICRO@
 HB_VERSION_MINOR = @HB_VERSION_MINOR@
 ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LE_CFLAGS = @ICU_LE_CFLAGS@
+ICU_LE_LIBS = @ICU_LE_LIBS@
 ICU_LIBS = @ICU_LIBS@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
@@ -119,6 +157,7 @@ LIPO = @LIPO@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
 NM = @NM@
 NMEDIT = @NMEDIT@
@@ -135,6 +174,9 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 PKG_CONFIG = @PKG_CONFIG@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
 RANLIB = @RANLIB@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
@@ -147,6 +189,7 @@ abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
 ac_ct_CC = @ac_ct_CC@
 ac_ct_CXX = @ac_ct_CXX@
 ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
@@ -155,6 +198,7 @@ am__leading_dot = @am__leading_dot@
 am__quote = @am__quote@
 am__tar = @am__tar@
 am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
 bindir = @bindir@
 build = @build@
 build_alias = @build_alias@
@@ -180,7 +224,6 @@ libdir = @libdir@
 libexecdir = @libexecdir@
 localedir = @localedir@
 localstatedir = @localstatedir@
-lt_ECHO = @lt_ECHO@
 mandir = @mandir@
 mkdir_p = @mkdir_p@
 oldincludedir = @oldincludedir@
@@ -196,19 +239,23 @@ target_alias = @target_alias@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-NULL = 
-
-# TODO Figure out Python stuff
-EXTRA_DIST = hb-diff hb-diff-colorize hb-diff-filter-failures \
-       hb-diff-ngrams hb-diff-stat hb-manifest-read \
-       hb-manifest-update hb-unicode-decode hb-unicode-encode \
-       hb-unicode-prettyname $(NULL) hb_test_tools.py $(NULL)
-CLEANFILES = hb_test_tools.py[co] $(NULL)
-DISTCLEANFILES = 
-MAINTAINERCLEANFILES = 
+noinst_LTLIBRARIES = libhb-ucdn.la
+libhb_ucdn_la_SOURCES = \
+       ucdn.h \
+       ucdn.c \
+       unicodedata_db.h
+
+libhb_ucdn_CPPFLAGS = \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/src \
+       -I$(top_builddir)/src
+
+libhb_ucdn_la_LIBADD = 
+EXTRA_DIST = README COPYING
 all: all-am
 
 .SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
 $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
@@ -218,9 +265,9 @@ $(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
              exit 1;; \
          esac; \
        done; \
-       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu test/shaping/Makefile'; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/hb-ucdn/Makefile'; \
        $(am__cd) $(top_srcdir) && \
-         $(AUTOMAKE) --gnu test/shaping/Makefile
+         $(AUTOMAKE) --gnits src/hb-ucdn/Makefile
 .PRECIOUS: Makefile
 Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
        @case '$?' in \
@@ -240,17 +287,103 @@ $(ACLOCAL_M4):  $(am__aclocal_m4_deps)
        cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
 $(am__aclocal_m4_deps):
 
+clean-noinstLTLIBRARIES:
+       -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+       @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+         test "$$dir" != "$$p" || dir=.; \
+         echo "rm -f \"$${dir}/so_locations\""; \
+         rm -f "$${dir}/so_locations"; \
+       done
+libhb-ucdn.la: $(libhb_ucdn_la_OBJECTS) $(libhb_ucdn_la_DEPENDENCIES) $(EXTRA_libhb_ucdn_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(LINK)  $(libhb_ucdn_la_OBJECTS) $(libhb_ucdn_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucdn.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
 mostlyclean-libtool:
        -rm -f *.lo
 
 clean-libtool:
        -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       mkid -fID $$unique
 tags: TAGS
-TAGS:
 
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       set x; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       shift; \
+       if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+         test -n "$$unique" || unique=$$empty_fix; \
+         if test $$# -gt 0; then \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             "$$@" $$unique; \
+         else \
+           $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+             $$unique; \
+         fi; \
+       fi
 ctags: CTAGS
-CTAGS:
-
+CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+             END { if (nonempty) { for (i in files) print i; }; }'`; \
+       test -z "$(CTAGS_ARGS)$$unique" \
+         || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+            $$unique
+
+GTAGS:
+       here=`$(am__cd) $(top_builddir) && pwd` \
+         && $(am__cd) $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 
 distdir: $(DISTFILES)
        @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
@@ -284,7 +417,7 @@ distdir: $(DISTFILES)
        done
 check-am: all-am
 check: check-am
-all-am: Makefile
+all-am: Makefile $(LTLIBRARIES)
 installdirs:
 install: install-am
 install-exec: install-exec-am
@@ -296,31 +429,36 @@ install-am: all-am
 
 installcheck: installcheck-am
 install-strip:
-       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
-         install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
-         `test -z '$(STRIP)' || \
-           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
 mostlyclean-generic:
 
 clean-generic:
-       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
 
 distclean-generic:
        -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
        -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-       -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
 
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
-       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
 clean: clean-am
 
-clean-am: clean-generic clean-libtool mostlyclean-am
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+       mostlyclean-am
 
 distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
        -rm -f Makefile
-distclean-am: clean-am distclean-generic
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
 
 dvi: dvi-am
 
@@ -363,12 +501,14 @@ install-ps-am:
 installcheck-am:
 
 maintainer-clean: maintainer-clean-am
+       -rm -rf ./$(DEPDIR)
        -rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
 mostlyclean: mostlyclean-am
 
-mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
 
 pdf: pdf-am
 
@@ -382,22 +522,19 @@ uninstall-am:
 
 .MAKE: install-am install-strip
 
-.PHONY: all all-am check check-am clean clean-generic clean-libtool \
-       distclean distclean-generic distclean-libtool distdir dvi \
-       dvi-am html html-am info info-am install install-am \
-       install-data install-data-am install-dvi install-dvi-am \
-       install-exec install-exec-am install-html install-html-am \
-       install-info install-info-am install-man install-pdf \
-       install-pdf-am install-ps install-ps-am install-strip \
-       installcheck installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-generic \
-       mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
-
-
-manifests:
-       @$(srcdir)/hb-manifest-update "$(srcdir)/texts" "$(srcdir)/fonts"
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+       clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+       distclean-compile distclean-generic distclean-libtool \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags uninstall uninstall-am
 
-.PHONY: manifests
 
 -include $(top_srcdir)/git.mk
 
diff --git a/src/hb-ucdn/README b/src/hb-ucdn/README
new file mode 100644 (file)
index 0000000..2f3c552
--- /dev/null
@@ -0,0 +1,41 @@
+Contents of this directory are derived from UCDN:
+
+  https://github.com/grigorig/ucdn
+  https://github.com/behdad/ucdn
+
+The original README follows:
+
+
+UCDN - Unicode Database and Normalization
+
+UCDN is a Unicode support library. Currently, it provides access
+to basic character properties contained in the Unicode Character
+Database and low-level normalization functions (pairwise canonical
+composition/decomposition and compatibility decomposition). More
+functionality might be provided in the future, such as additional
+properties, string normalization and encoding conversion.
+
+UCDN uses standard C89 with no particular dependencies or requirements
+except for stdint.h, and can be easily integrated into existing
+projects. However, it can also be used as a standalone library,
+and a CMake build script is provided for this. The first motivation
+behind UCDN development was to provide a standalone set of Unicode
+functions for the HarfBuzz OpenType shaping library. For this purpose,
+a HarfBuzz-specific wrapper is shipped along with it (hb-ucdn.h).
+
+UCDN is published under the ISC license, please see the license header
+in the C source code for more information. The makeunicodata.py script
+required for parsing Unicode database files is licensed under the
+PSF license, please see PYTHON-LICENSE for more information.
+
+UCDN was written by Grigori Goronzy <greg@kinoho.net>.
+
+How to Use
+
+Include ucdn.c, ucdn.h and unicodedata_db.h in your project. Now,
+just use the functions as documented in ucdn.h.
+
+In some cases, it might be necessary to regenerate the Unicode
+database file. The script makeunicodedata.py (Python 3.x required)
+fetches the appropriate files and dumps the compressed database into
+unicodedata_db.h.
diff --git a/src/hb-ucdn/ucdn.c b/src/hb-ucdn/ucdn.c
new file mode 100644 (file)
index 0000000..d1a4195
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ucdn.h"
+
+typedef struct {
+    unsigned char category;
+    unsigned char combining;
+    unsigned char bidi_class;
+    unsigned char mirrored;
+    unsigned char east_asian_width;
+    unsigned char normalization_check;
+    unsigned char script;
+} UCDRecord;
+
+typedef struct {
+    unsigned short from, to;
+} MirrorPair;
+
+typedef struct {
+    unsigned int start;
+    short count, index;
+} Reindex;
+
+#include "unicodedata_db.h"
+
+/* constants required for Hangul (de)composition */
+#define SBASE 0xAC00
+#define LBASE 0x1100
+#define VBASE 0x1161
+#define TBASE 0x11A7
+#define SCOUNT 11172
+#define LCOUNT 19
+#define VCOUNT 21
+#define TCOUNT 28
+#define NCOUNT (VCOUNT * TCOUNT)
+
+static const UCDRecord *get_ucd_record(uint32_t code)
+{
+    int index, offset;
+
+    if (code >= 0x110000)
+        index = 0;
+    else {
+        index  = index0[code >> (SHIFT1+SHIFT2)] << SHIFT1;
+        offset = (code >> SHIFT2) & ((1<<SHIFT1) - 1);
+        index  = index1[index + offset] << SHIFT2;
+        offset = code & ((1<<SHIFT2) - 1);
+        index  = index2[index + offset];
+    }
+
+    return &ucd_records[index];
+}
+
+static const unsigned short *get_decomp_record(uint32_t code)
+{
+    int index, offset;
+
+    if (code >= 0x110000)
+        index = 0;
+    else {
+        index  = decomp_index0[code >> (DECOMP_SHIFT1+DECOMP_SHIFT2)]
+            << DECOMP_SHIFT1;
+        offset = (code >> DECOMP_SHIFT2) & ((1<<DECOMP_SHIFT1) - 1);
+        index  = decomp_index1[index + offset] << DECOMP_SHIFT2;
+        offset = code & ((1<<DECOMP_SHIFT2) - 1);
+        index  = decomp_index2[index + offset];
+    }
+
+    return &decomp_data[index];
+}
+
+static int get_comp_index(uint32_t code, const Reindex *idx)
+{
+    int i;
+
+    for (i = 0; idx[i].start; i++) {
+        const Reindex *cur = &idx[i];
+        if (code < cur->start)
+            return -1;
+        if (code <= cur->start + cur->count) {
+            return cur->index + (code - cur->start);
+        }
+    }
+
+    return -1;
+}
+
+static int compare_mp(const void *a, const void *b)
+{
+    MirrorPair *mpa = (MirrorPair *)a;
+    MirrorPair *mpb = (MirrorPair *)b;
+    return mpa->from - mpb->from;
+}
+
+static int hangul_pair_decompose(uint32_t code, uint32_t *a, uint32_t *b)
+{
+    int si = code - SBASE;
+
+    if (si < 0 || si >= SCOUNT)
+        return 0;
+
+    if (si % TCOUNT) {
+        /* LV,T */
+        *a = SBASE + (si / TCOUNT) * TCOUNT;
+        *b = TBASE + (si % TCOUNT);
+        return 3;
+    } else {
+        /* L,V */
+        *a = LBASE + (si / NCOUNT);
+        *b = VBASE + (si % NCOUNT) / TCOUNT;
+        return 2;
+    }
+}
+
+static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b)
+{
+    if (b < VBASE || b >= (TBASE + TCOUNT))
+        return 0;
+
+    if ((a < LBASE || a >= (LBASE + LCOUNT))
+            && (a < SBASE || a >= (SBASE + SCOUNT)))
+        return 0;
+
+    if (a >= SBASE) {
+        /* LV,T */
+        *code = a + (b - TBASE);
+        return 3;
+    } else {
+        /* L,V */
+        int li = a - LBASE;
+        int vi = b - VBASE;
+        *code = SBASE + li * NCOUNT + vi * TCOUNT;
+        return 2;
+    }
+}
+
+static uint32_t decode_utf16(const unsigned short **code_ptr)
+{
+    const unsigned short *code = *code_ptr;
+
+    if ((code[0] & 0xd800) != 0xd800) {
+        *code_ptr += 1;
+        return (uint32_t)code[0];
+    } else {
+        *code_ptr += 2;
+        return 0x10000 + ((uint32_t)code[1] - 0xdc00) +
+            (((uint32_t)code[0] - 0xd800) << 10);
+    }
+}
+
+const char *ucdn_get_unicode_version(void)
+{
+    return UNIDATA_VERSION;
+}
+
+int ucdn_get_combining_class(uint32_t code)
+{
+    return get_ucd_record(code)->combining;
+}
+
+int ucdn_get_east_asian_width(uint32_t code)
+{
+    return get_ucd_record(code)->east_asian_width;
+}
+
+int ucdn_get_general_category(uint32_t code)
+{
+    return get_ucd_record(code)->category;
+}
+
+int ucdn_get_bidi_class(uint32_t code)
+{
+    return get_ucd_record(code)->bidi_class;
+}
+
+int ucdn_get_mirrored(uint32_t code)
+{
+    return get_ucd_record(code)->mirrored;
+}
+
+int ucdn_get_script(uint32_t code)
+{
+    return get_ucd_record(code)->script;
+}
+
+uint32_t ucdn_mirror(uint32_t code)
+{
+    MirrorPair mp = {0};
+    MirrorPair *res;
+
+    if (get_ucd_record(code)->mirrored == 0)
+        return code;
+
+    mp.from = code;
+    res = bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN, sizeof(MirrorPair),
+            compare_mp);
+
+    if (res == NULL)
+        return code;
+    else
+        return res->to;
+}
+
+int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b)
+{
+    const unsigned short *rec;
+    int len;
+
+    if (hangul_pair_decompose(code, a, b))
+        return 1;
+
+    rec = get_decomp_record(code);
+    len = rec[0] >> 8;
+
+    if ((rec[0] & 0xff) != 0 || len == 0)
+        return 0;
+
+    rec++;
+    *a = decode_utf16(&rec);
+    if (len > 1)
+        *b = decode_utf16(&rec);
+    else
+        *b = 0;
+
+    return 1;
+}
+
+int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b)
+{
+    int l, r, index, indexi, offset;
+
+    if (hangul_pair_compose(code, a, b))
+        return 1;
+
+    l = get_comp_index(a, nfc_first);
+    r = get_comp_index(b, nfc_last);
+
+    if (l < 0 || r < 0)
+        return 0;
+
+    indexi = l * TOTAL_LAST + r;
+    index  = comp_index0[indexi >> (COMP_SHIFT1+COMP_SHIFT2)] << COMP_SHIFT1;
+    offset = (indexi >> COMP_SHIFT2) & ((1<<COMP_SHIFT1) - 1);
+    index  = comp_index1[index + offset] << COMP_SHIFT2;
+    offset = indexi & ((1<<COMP_SHIFT2) - 1);
+    *code  = comp_data[index + offset];
+
+    return *code != 0;
+}
+
+int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed)
+{
+    int i, len;
+    const unsigned short *rec = get_decomp_record(code);
+    len = rec[0] >> 8;
+
+    if (len == 0)
+        return 0;
+
+    rec++;
+    for (i = 0; i < len; i++)
+        decomposed[i] = decode_utf16(&rec);
+
+    return len;
+}
diff --git a/src/hb-ucdn/ucdn.h b/src/hb-ucdn/ucdn.h
new file mode 100644 (file)
index 0000000..ec8085b
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * 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.
+ */
+
+#ifndef UCDN_H
+#define UCDN_H
+
+#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
+# define HB_BEGIN_VISIBILITY _Pragma ("GCC visibility push(hidden)")
+# define HB_END_VISIBILITY _Pragma ("GCC visibility pop")
+#else
+# define HB_BEGIN_VISIBILITY
+# define HB_END_VISIBILITY
+#endif
+#ifdef __cplusplus
+# define HB_BEGIN_HEADER  extern "C" { HB_BEGIN_VISIBILITY
+# define HB_END_HEADER  HB_END_VISIBILITY }
+#else
+# define HB_BEGIN_HEADER  HB_BEGIN_VISIBILITY
+# define HB_END_HEADER  HB_END_VISIBILITY
+#endif
+
+HB_BEGIN_HEADER
+
+#if !defined (HB_DONT_DEFINE_STDINT)
+
+#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
+    defined (_sgi) || defined (__sun) || defined (sun) || \
+    defined (__digital__) || defined (__HP_cc)
+#  include <inttypes.h>
+#elif defined (_AIX)
+#  include <sys/inttypes.h>
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
+#elif defined (_MSC_VER) && _MSC_VER < 1600
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+#  include <stdint.h>
+#endif
+
+#endif
+
+#define UCDN_EAST_ASIAN_F 0
+#define UCDN_EAST_ASIAN_H 1
+#define UCDN_EAST_ASIAN_W 2
+#define UCDN_EAST_ASIAN_NA 3
+#define UCDN_EAST_ASIAN_A 4
+#define UCDN_EAST_ASIAN_N 5
+
+#define UCDN_SCRIPT_COMMON 0
+#define UCDN_SCRIPT_LATIN 1
+#define UCDN_SCRIPT_GREEK 2
+#define UCDN_SCRIPT_CYRILLIC 3
+#define UCDN_SCRIPT_ARMENIAN 4
+#define UCDN_SCRIPT_HEBREW 5
+#define UCDN_SCRIPT_ARABIC 6
+#define UCDN_SCRIPT_SYRIAC 7
+#define UCDN_SCRIPT_THAANA 8
+#define UCDN_SCRIPT_DEVANAGARI 9
+#define UCDN_SCRIPT_BENGALI 10
+#define UCDN_SCRIPT_GURMUKHI 11
+#define UCDN_SCRIPT_GUJARATI 12
+#define UCDN_SCRIPT_ORIYA 13
+#define UCDN_SCRIPT_TAMIL 14
+#define UCDN_SCRIPT_TELUGU 15
+#define UCDN_SCRIPT_KANNADA 16
+#define UCDN_SCRIPT_MALAYALAM 17
+#define UCDN_SCRIPT_SINHALA 18
+#define UCDN_SCRIPT_THAI 19
+#define UCDN_SCRIPT_LAO 20
+#define UCDN_SCRIPT_TIBETAN 21
+#define UCDN_SCRIPT_MYANMAR 22
+#define UCDN_SCRIPT_GEORGIAN 23
+#define UCDN_SCRIPT_HANGUL 24
+#define UCDN_SCRIPT_ETHIOPIC 25
+#define UCDN_SCRIPT_CHEROKEE 26
+#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
+#define UCDN_SCRIPT_OGHAM 28
+#define UCDN_SCRIPT_RUNIC 29
+#define UCDN_SCRIPT_KHMER 30
+#define UCDN_SCRIPT_MONGOLIAN 31
+#define UCDN_SCRIPT_HIRAGANA 32
+#define UCDN_SCRIPT_KATAKANA 33
+#define UCDN_SCRIPT_BOPOMOFO 34
+#define UCDN_SCRIPT_HAN 35
+#define UCDN_SCRIPT_YI 36
+#define UCDN_SCRIPT_OLD_ITALIC 37
+#define UCDN_SCRIPT_GOTHIC 38
+#define UCDN_SCRIPT_DESERET 39
+#define UCDN_SCRIPT_INHERITED 40
+#define UCDN_SCRIPT_TAGALOG 41
+#define UCDN_SCRIPT_HANUNOO 42
+#define UCDN_SCRIPT_BUHID 43
+#define UCDN_SCRIPT_TAGBANWA 44
+#define UCDN_SCRIPT_LIMBU 45
+#define UCDN_SCRIPT_TAI_LE 46
+#define UCDN_SCRIPT_LINEAR_B 47
+#define UCDN_SCRIPT_UGARITIC 48
+#define UCDN_SCRIPT_SHAVIAN 49
+#define UCDN_SCRIPT_OSMANYA 50
+#define UCDN_SCRIPT_CYPRIOT 51
+#define UCDN_SCRIPT_BRAILLE 52
+#define UCDN_SCRIPT_BUGINESE 53
+#define UCDN_SCRIPT_COPTIC 54
+#define UCDN_SCRIPT_NEW_TAI_LUE 55
+#define UCDN_SCRIPT_GLAGOLITIC 56
+#define UCDN_SCRIPT_TIFINAGH 57
+#define UCDN_SCRIPT_SYLOTI_NAGRI 58
+#define UCDN_SCRIPT_OLD_PERSIAN 59
+#define UCDN_SCRIPT_KHAROSHTHI 60
+#define UCDN_SCRIPT_BALINESE 61
+#define UCDN_SCRIPT_CUNEIFORM 62
+#define UCDN_SCRIPT_PHOENICIAN 63
+#define UCDN_SCRIPT_PHAGS_PA 64
+#define UCDN_SCRIPT_NKO 65
+#define UCDN_SCRIPT_SUNDANESE 66
+#define UCDN_SCRIPT_LEPCHA 67
+#define UCDN_SCRIPT_OL_CHIKI 68
+#define UCDN_SCRIPT_VAI 69
+#define UCDN_SCRIPT_SAURASHTRA 70
+#define UCDN_SCRIPT_KAYAH_LI 71
+#define UCDN_SCRIPT_REJANG 72
+#define UCDN_SCRIPT_LYCIAN 73
+#define UCDN_SCRIPT_CARIAN 74
+#define UCDN_SCRIPT_LYDIAN 75
+#define UCDN_SCRIPT_CHAM 76
+#define UCDN_SCRIPT_TAI_THAM 77
+#define UCDN_SCRIPT_TAI_VIET 78
+#define UCDN_SCRIPT_AVESTAN 79
+#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
+#define UCDN_SCRIPT_SAMARITAN 81
+#define UCDN_SCRIPT_LISU 82
+#define UCDN_SCRIPT_BAMUM 83
+#define UCDN_SCRIPT_JAVANESE 84
+#define UCDN_SCRIPT_MEETEI_MAYEK 85
+#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
+#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
+#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
+#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
+#define UCDN_SCRIPT_OLD_TURKIC 90
+#define UCDN_SCRIPT_KAITHI 91
+#define UCDN_SCRIPT_BATAK 92
+#define UCDN_SCRIPT_BRAHMI 93
+#define UCDN_SCRIPT_MANDAIC 94
+#define UCDN_SCRIPT_CHAKMA 95
+#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
+#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
+#define UCDN_SCRIPT_MIAO 98
+#define UCDN_SCRIPT_SHARADA 99
+#define UCDN_SCRIPT_SORA_SOMPENG 100
+#define UCDN_SCRIPT_TAKRI 101
+#define UCDN_SCRIPT_UNKNOWN 102
+#define UCDN_SCRIPT_BASSA_VAH 103
+#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
+#define UCDN_SCRIPT_DUPLOYAN 105
+#define UCDN_SCRIPT_ELBASAN 106
+#define UCDN_SCRIPT_GRANTHA 107
+#define UCDN_SCRIPT_KHOJKI 108
+#define UCDN_SCRIPT_KHUDAWADI 109
+#define UCDN_SCRIPT_LINEAR_A 110
+#define UCDN_SCRIPT_MAHAJANI 111
+#define UCDN_SCRIPT_MANICHAEAN 112
+#define UCDN_SCRIPT_MENDE_KIKAKUI 113
+#define UCDN_SCRIPT_MODI 114
+#define UCDN_SCRIPT_MRO 115
+#define UCDN_SCRIPT_NABATAEAN 116
+#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
+#define UCDN_SCRIPT_OLD_PERMIC 118
+#define UCDN_SCRIPT_PAHAWH_HMONG 119
+#define UCDN_SCRIPT_PALMYRENE 120
+#define UCDN_SCRIPT_PAU_CIN_HAU 121
+#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
+#define UCDN_SCRIPT_SIDDHAM 123
+#define UCDN_SCRIPT_TIRHUTA 124
+#define UCDN_SCRIPT_WARANG_CITI 125
+
+#define UCDN_GENERAL_CATEGORY_CC 0
+#define UCDN_GENERAL_CATEGORY_CF 1
+#define UCDN_GENERAL_CATEGORY_CN 2
+#define UCDN_GENERAL_CATEGORY_CO 3
+#define UCDN_GENERAL_CATEGORY_CS 4
+#define UCDN_GENERAL_CATEGORY_LL 5
+#define UCDN_GENERAL_CATEGORY_LM 6
+#define UCDN_GENERAL_CATEGORY_LO 7
+#define UCDN_GENERAL_CATEGORY_LT 8
+#define UCDN_GENERAL_CATEGORY_LU 9
+#define UCDN_GENERAL_CATEGORY_MC 10
+#define UCDN_GENERAL_CATEGORY_ME 11
+#define UCDN_GENERAL_CATEGORY_MN 12
+#define UCDN_GENERAL_CATEGORY_ND 13
+#define UCDN_GENERAL_CATEGORY_NL 14
+#define UCDN_GENERAL_CATEGORY_NO 15
+#define UCDN_GENERAL_CATEGORY_PC 16
+#define UCDN_GENERAL_CATEGORY_PD 17
+#define UCDN_GENERAL_CATEGORY_PE 18
+#define UCDN_GENERAL_CATEGORY_PF 19
+#define UCDN_GENERAL_CATEGORY_PI 20
+#define UCDN_GENERAL_CATEGORY_PO 21
+#define UCDN_GENERAL_CATEGORY_PS 22
+#define UCDN_GENERAL_CATEGORY_SC 23
+#define UCDN_GENERAL_CATEGORY_SK 24
+#define UCDN_GENERAL_CATEGORY_SM 25
+#define UCDN_GENERAL_CATEGORY_SO 26
+#define UCDN_GENERAL_CATEGORY_ZL 27
+#define UCDN_GENERAL_CATEGORY_ZP 28
+#define UCDN_GENERAL_CATEGORY_ZS 29
+
+#define UCDN_BIDI_CLASS_L 0
+#define UCDN_BIDI_CLASS_LRE 1
+#define UCDN_BIDI_CLASS_LRO 2
+#define UCDN_BIDI_CLASS_R 3
+#define UCDN_BIDI_CLASS_AL 4
+#define UCDN_BIDI_CLASS_RLE 5
+#define UCDN_BIDI_CLASS_RLO 6
+#define UCDN_BIDI_CLASS_PDF 7
+#define UCDN_BIDI_CLASS_EN 8
+#define UCDN_BIDI_CLASS_ES 9
+#define UCDN_BIDI_CLASS_ET 10
+#define UCDN_BIDI_CLASS_AN 11
+#define UCDN_BIDI_CLASS_CS 12
+#define UCDN_BIDI_CLASS_NSM 13
+#define UCDN_BIDI_CLASS_BN 14
+#define UCDN_BIDI_CLASS_B 15
+#define UCDN_BIDI_CLASS_S 16
+#define UCDN_BIDI_CLASS_WS 17
+#define UCDN_BIDI_CLASS_ON 18
+#define UCDN_BIDI_CLASS_LRI 19
+#define UCDN_BIDI_CLASS_RLI 20
+#define UCDN_BIDI_CLASS_FSI 21
+#define UCDN_BIDI_CLASS_PDI 22
+
+/**
+ * Return version of the Unicode database.
+ *
+ * @return Unicode database version
+ */
+const char *ucdn_get_unicode_version(void);
+
+/**
+ * Get combining class of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return combining class value, as defined in UAX#44
+ */
+int ucdn_get_combining_class(uint32_t code);
+
+/**
+ * Get east-asian width of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_EAST_ASIAN_* and as defined in UAX#11.
+ */
+int ucdn_get_east_asian_width(uint32_t code);
+
+/**
+ * Get general category of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_GENERAL_CATEGORY_* and as defined in
+ * UAX#44.
+ */
+int ucdn_get_general_category(uint32_t code);
+
+/**
+ * Get bidirectional class of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_BIDI_CLASS_* and as defined in UAX#44.
+ */
+int ucdn_get_bidi_class(uint32_t code);
+
+/**
+ * Get script of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_SCRIPT_* and as defined in UAX#24.
+ */
+int ucdn_get_script(uint32_t code);
+
+/**
+ * Check if codepoint can be mirrored.
+ *
+ * @param code Unicode codepoint
+ * @return 1 if mirrored character exists, otherwise 0
+ */
+int ucdn_get_mirrored(uint32_t code);
+
+/**
+ * Mirror a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return mirrored codepoint or the original codepoint if no
+ * mirrored character exists
+ */
+uint32_t ucdn_mirror(uint32_t code);
+
+/**
+ * Pairwise canonical decomposition of a codepoint. This includes
+ * Hangul Jamo decomposition (see chapter 3.12 of the Unicode core
+ * specification).
+ *
+ * Hangul is decomposed into L and V jamos for LV forms, and an
+ * LV precomposed syllable and a T jamo for LVT forms.
+ *
+ * @param code Unicode codepoint
+ * @param a filled with first codepoint of decomposition
+ * @param b filled with second codepoint of decomposition, or 0
+ * @return success
+ */
+int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b);
+
+/**
+ * Compatibility decomposition of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @param decomposed filled with decomposition, must be able to hold 18
+ * characters
+ * @return length of decomposition or 0 in case none exists
+ */
+int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed);
+
+/**
+ * Pairwise canonical composition of two codepoints. This includes
+ * Hangul Jamo composition (see chapter 3.12 of the Unicode core
+ * specification).
+ *
+ * Hangul composition expects either L and V jamos, or an LV
+ * precomposed syllable and a T jamo. This is exactly the inverse
+ * of pairwise Hangul decomposition.
+ *
+ * @param code filled with composition
+ * @param a first codepoint
+ * @param b second codepoint
+ * @return success
+ */
+int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b);
+
+HB_END_HEADER
+
+#endif
diff --git a/src/hb-ucdn/unicodedata_db.h b/src/hb-ucdn/unicodedata_db.h
new file mode 100644 (file)
index 0000000..a78d2e6
--- /dev/null
@@ -0,0 +1,5017 @@
+/* this file was generated by makeunicodedata.py 3.2 */
+
+#define UNIDATA_VERSION "7.0.0"
+/* a list of unique database records */
+static const UCDRecord ucd_records[] = {
+    {2, 0, 18, 0, 5, 0, 102},
+    {0, 0, 14, 0, 5, 0, 0},
+    {0, 0, 16, 0, 5, 0, 0},
+    {0, 0, 15, 0, 5, 0, 0},
+    {0, 0, 17, 0, 5, 0, 0},
+    {29, 0, 17, 0, 3, 0, 0},
+    {21, 0, 18, 0, 3, 0, 0},
+    {21, 0, 10, 0, 3, 0, 0},
+    {23, 0, 10, 0, 3, 0, 0},
+    {22, 0, 18, 1, 3, 0, 0},
+    {18, 0, 18, 1, 3, 0, 0},
+    {25, 0, 9, 0, 3, 0, 0},
+    {21, 0, 12, 0, 3, 0, 0},
+    {17, 0, 9, 0, 3, 0, 0},
+    {13, 0, 8, 0, 3, 0, 0},
+    {25, 0, 18, 1, 3, 0, 0},
+    {25, 0, 18, 0, 3, 0, 0},
+    {9, 0, 0, 0, 3, 0, 1},
+    {24, 0, 18, 0, 3, 0, 0},
+    {16, 0, 18, 0, 3, 0, 0},
+    {5, 0, 0, 0, 3, 0, 1},
+    {29, 0, 12, 0, 5, 0, 0},
+    {21, 0, 18, 0, 4, 0, 0},
+    {23, 0, 10, 0, 4, 0, 0},
+    {26, 0, 18, 0, 3, 0, 0},
+    {24, 0, 18, 0, 4, 0, 0},
+    {26, 0, 18, 0, 5, 0, 0},
+    {7, 0, 0, 0, 4, 0, 1},
+    {20, 0, 18, 1, 5, 0, 0},
+    {1, 0, 14, 0, 4, 0, 0},
+    {26, 0, 18, 0, 4, 0, 0},
+    {26, 0, 10, 0, 4, 0, 0},
+    {25, 0, 10, 0, 4, 0, 0},
+    {15, 0, 8, 0, 4, 0, 0},
+    {5, 0, 0, 0, 5, 0, 0},
+    {19, 0, 18, 1, 5, 0, 0},
+    {15, 0, 18, 0, 4, 0, 0},
+    {9, 0, 0, 0, 5, 0, 1},
+    {9, 0, 0, 0, 4, 0, 1},
+    {25, 0, 18, 0, 4, 0, 0},
+    {5, 0, 0, 0, 4, 0, 1},
+    {5, 0, 0, 0, 5, 0, 1},
+    {7, 0, 0, 0, 5, 0, 1},
+    {8, 0, 0, 0, 5, 0, 1},
+    {6, 0, 0, 0, 5, 0, 1},
+    {6, 0, 18, 0, 5, 0, 0},
+    {6, 0, 0, 0, 5, 0, 0},
+    {24, 0, 18, 0, 5, 0, 0},
+    {6, 0, 18, 0, 4, 0, 0},
+    {6, 0, 0, 0, 4, 0, 0},
+    {24, 0, 18, 0, 5, 0, 34},
+    {12, 230, 13, 0, 4, 0, 40},
+    {12, 232, 13, 0, 4, 0, 40},
+    {12, 220, 13, 0, 4, 0, 40},
+    {12, 216, 13, 0, 4, 0, 40},
+    {12, 202, 13, 0, 4, 0, 40},
+    {12, 1, 13, 0, 4, 0, 40},
+    {12, 240, 13, 0, 4, 0, 40},
+    {12, 0, 13, 0, 4, 0, 40},
+    {12, 233, 13, 0, 4, 0, 40},
+    {12, 234, 13, 0, 4, 0, 40},
+    {9, 0, 0, 0, 5, 0, 2},
+    {5, 0, 0, 0, 5, 0, 2},
+    {24, 0, 18, 0, 5, 0, 2},
+    {2, 0, 18, 0, 5, 0, 102},
+    {6, 0, 0, 0, 5, 0, 2},
+    {21, 0, 18, 0, 5, 0, 0},
+    {9, 0, 0, 0, 4, 0, 2},
+    {5, 0, 0, 0, 4, 0, 2},
+    {9, 0, 0, 0, 5, 0, 54},
+    {5, 0, 0, 0, 5, 0, 54},
+    {25, 0, 18, 0, 5, 0, 2},
+    {9, 0, 0, 0, 5, 0, 3},
+    {9, 0, 0, 0, 4, 0, 3},
+    {5, 0, 0, 0, 4, 0, 3},
+    {5, 0, 0, 0, 5, 0, 3},
+    {26, 0, 0, 0, 5, 0, 3},
+    {12, 230, 13, 0, 5, 0, 3},
+    {12, 230, 13, 0, 5, 0, 40},
+    {11, 0, 13, 0, 5, 0, 3},
+    {9, 0, 0, 0, 5, 0, 4},
+    {6, 0, 0, 0, 5, 0, 4},
+    {21, 0, 0, 0, 5, 0, 4},
+    {5, 0, 0, 0, 5, 0, 4},
+    {21, 0, 0, 0, 5, 0, 0},
+    {17, 0, 18, 0, 5, 0, 4},
+    {26, 0, 18, 0, 5, 0, 4},
+    {23, 0, 10, 0, 5, 0, 4},
+    {12, 220, 13, 0, 5, 0, 5},
+    {12, 230, 13, 0, 5, 0, 5},
+    {12, 222, 13, 0, 5, 0, 5},
+    {12, 228, 13, 0, 5, 0, 5},
+    {12, 10, 13, 0, 5, 0, 5},
+    {12, 11, 13, 0, 5, 0, 5},
+    {12, 12, 13, 0, 5, 0, 5},
+    {12, 13, 13, 0, 5, 0, 5},
+    {12, 14, 13, 0, 5, 0, 5},
+    {12, 15, 13, 0, 5, 0, 5},
+    {12, 16, 13, 0, 5, 0, 5},
+    {12, 17, 13, 0, 5, 0, 5},
+    {12, 18, 13, 0, 5, 0, 5},
+    {12, 19, 13, 0, 5, 0, 5},
+    {12, 20, 13, 0, 5, 0, 5},
+    {12, 21, 13, 0, 5, 0, 5},
+    {12, 22, 13, 0, 5, 0, 5},
+    {17, 0, 3, 0, 5, 0, 5},
+    {12, 23, 13, 0, 5, 0, 5},
+    {21, 0, 3, 0, 5, 0, 5},
+    {12, 24, 13, 0, 5, 0, 5},
+    {12, 25, 13, 0, 5, 0, 5},
+    {7, 0, 3, 0, 5, 0, 5},
+    {1, 0, 11, 0, 5, 0, 6},
+    {1, 0, 11, 0, 5, 0, 0},
+    {25, 0, 18, 0, 5, 0, 6},
+    {25, 0, 4, 0, 5, 0, 6},
+    {21, 0, 10, 0, 5, 0, 6},
+    {23, 0, 4, 0, 5, 0, 6},
+    {21, 0, 12, 0, 5, 0, 0},
+    {21, 0, 4, 0, 5, 0, 6},
+    {26, 0, 18, 0, 5, 0, 6},
+    {12, 230, 13, 0, 5, 0, 6},
+    {12, 30, 13, 0, 5, 0, 6},
+    {12, 31, 13, 0, 5, 0, 6},
+    {12, 32, 13, 0, 5, 0, 6},
+    {21, 0, 4, 0, 5, 0, 0},
+    {1, 0, 4, 0, 5, 0, 0},
+    {7, 0, 4, 0, 5, 0, 6},
+    {6, 0, 4, 0, 5, 0, 0},
+    {12, 27, 13, 0, 5, 0, 40},
+    {12, 28, 13, 0, 5, 0, 40},
+    {12, 29, 13, 0, 5, 0, 40},
+    {12, 30, 13, 0, 5, 0, 40},
+    {12, 31, 13, 0, 5, 0, 40},
+    {12, 32, 13, 0, 5, 0, 40},
+    {12, 33, 13, 0, 5, 0, 40},
+    {12, 34, 13, 0, 5, 0, 40},
+    {12, 220, 13, 0, 5, 0, 40},
+    {12, 220, 13, 0, 5, 0, 6},
+    {13, 0, 11, 0, 5, 0, 0},
+    {21, 0, 11, 0, 5, 0, 6},
+    {12, 35, 13, 0, 5, 0, 40},
+    {6, 0, 4, 0, 5, 0, 6},
+    {13, 0, 8, 0, 5, 0, 6},
+    {26, 0, 4, 0, 5, 0, 6},
+    {21, 0, 4, 0, 5, 0, 7},
+    {1, 0, 4, 0, 5, 0, 7},
+    {7, 0, 4, 0, 5, 0, 7},
+    {12, 36, 13, 0, 5, 0, 7},
+    {12, 230, 13, 0, 5, 0, 7},
+    {12, 220, 13, 0, 5, 0, 7},
+    {7, 0, 4, 0, 5, 0, 8},
+    {12, 0, 13, 0, 5, 0, 8},
+    {13, 0, 3, 0, 5, 0, 65},
+    {7, 0, 3, 0, 5, 0, 65},
+    {12, 230, 13, 0, 5, 0, 65},
+    {12, 220, 13, 0, 5, 0, 65},
+    {6, 0, 3, 0, 5, 0, 65},
+    {26, 0, 18, 0, 5, 0, 65},
+    {21, 0, 18, 0, 5, 0, 65},
+    {7, 0, 3, 0, 5, 0, 81},
+    {12, 230, 13, 0, 5, 0, 81},
+    {6, 0, 3, 0, 5, 0, 81},
+    {21, 0, 3, 0, 5, 0, 81},
+    {7, 0, 3, 0, 5, 0, 94},
+    {12, 220, 13, 0, 5, 0, 94},
+    {21, 0, 3, 0, 5, 0, 94},
+    {12, 27, 13, 0, 5, 0, 6},
+    {12, 28, 13, 0, 5, 0, 6},
+    {12, 29, 13, 0, 5, 0, 6},
+    {12, 0, 13, 0, 5, 0, 9},
+    {10, 0, 0, 0, 5, 0, 9},
+    {7, 0, 0, 0, 5, 0, 9},
+    {12, 7, 13, 0, 5, 0, 9},
+    {12, 9, 13, 0, 5, 0, 9},
+    {12, 230, 13, 0, 5, 0, 9},
+    {13, 0, 0, 0, 5, 0, 9},
+    {21, 0, 0, 0, 5, 0, 9},
+    {6, 0, 0, 0, 5, 0, 9},
+    {7, 0, 0, 0, 5, 0, 10},
+    {12, 0, 13, 0, 5, 0, 10},
+    {10, 0, 0, 0, 5, 0, 10},
+    {12, 7, 13, 0, 5, 0, 10},
+    {12, 9, 13, 0, 5, 0, 10},
+    {13, 0, 0, 0, 5, 0, 10},
+    {23, 0, 10, 0, 5, 0, 10},
+    {15, 0, 0, 0, 5, 0, 10},
+    {26, 0, 0, 0, 5, 0, 10},
+    {12, 0, 13, 0, 5, 0, 11},
+    {10, 0, 0, 0, 5, 0, 11},
+    {7, 0, 0, 0, 5, 0, 11},
+    {12, 7, 13, 0, 5, 0, 11},
+    {12, 9, 13, 0, 5, 0, 11},
+    {13, 0, 0, 0, 5, 0, 11},
+    {12, 0, 13, 0, 5, 0, 12},
+    {10, 0, 0, 0, 5, 0, 12},
+    {7, 0, 0, 0, 5, 0, 12},
+    {12, 7, 13, 0, 5, 0, 12},
+    {12, 9, 13, 0, 5, 0, 12},
+    {13, 0, 0, 0, 5, 0, 12},
+    {21, 0, 0, 0, 5, 0, 12},
+    {23, 0, 10, 0, 5, 0, 12},
+    {12, 0, 13, 0, 5, 0, 13},
+    {10, 0, 0, 0, 5, 0, 13},
+    {7, 0, 0, 0, 5, 0, 13},
+    {12, 7, 13, 0, 5, 0, 13},
+    {12, 9, 13, 0, 5, 0, 13},
+    {13, 0, 0, 0, 5, 0, 13},
+    {26, 0, 0, 0, 5, 0, 13},
+    {15, 0, 0, 0, 5, 0, 13},
+    {12, 0, 13, 0, 5, 0, 14},
+    {7, 0, 0, 0, 5, 0, 14},
+    {10, 0, 0, 0, 5, 0, 14},
+    {12, 9, 13, 0, 5, 0, 14},
+    {13, 0, 0, 0, 5, 0, 14},
+    {15, 0, 0, 0, 5, 0, 14},
+    {26, 0, 18, 0, 5, 0, 14},
+    {23, 0, 10, 0, 5, 0, 14},
+    {12, 0, 13, 0, 5, 0, 15},
+    {10, 0, 0, 0, 5, 0, 15},
+    {7, 0, 0, 0, 5, 0, 15},
+    {12, 9, 13, 0, 5, 0, 15},
+    {12, 84, 13, 0, 5, 0, 15},
+    {12, 91, 13, 0, 5, 0, 15},
+    {13, 0, 0, 0, 5, 0, 15},
+    {15, 0, 18, 0, 5, 0, 15},
+    {26, 0, 0, 0, 5, 0, 15},
+    {12, 0, 13, 0, 5, 0, 16},
+    {10, 0, 0, 0, 5, 0, 16},
+    {7, 0, 0, 0, 5, 0, 16},
+    {12, 7, 13, 0, 5, 0, 16},
+    {12, 0, 0, 0, 5, 0, 16},
+    {12, 9, 13, 0, 5, 0, 16},
+    {13, 0, 0, 0, 5, 0, 16},
+    {12, 0, 13, 0, 5, 0, 17},
+    {10, 0, 0, 0, 5, 0, 17},
+    {7, 0, 0, 0, 5, 0, 17},
+    {12, 9, 13, 0, 5, 0, 17},
+    {13, 0, 0, 0, 5, 0, 17},
+    {15, 0, 0, 0, 5, 0, 17},
+    {26, 0, 0, 0, 5, 0, 17},
+    {10, 0, 0, 0, 5, 0, 18},
+    {7, 0, 0, 0, 5, 0, 18},
+    {12, 9, 13, 0, 5, 0, 18},
+    {12, 0, 13, 0, 5, 0, 18},
+    {13, 0, 0, 0, 5, 0, 18},
+    {21, 0, 0, 0, 5, 0, 18},
+    {7, 0, 0, 0, 5, 0, 19},
+    {12, 0, 13, 0, 5, 0, 19},
+    {12, 103, 13, 0, 5, 0, 19},
+    {12, 9, 13, 0, 5, 0, 19},
+    {23, 0, 10, 0, 5, 0, 0},
+    {6, 0, 0, 0, 5, 0, 19},
+    {12, 107, 13, 0, 5, 0, 19},
+    {21, 0, 0, 0, 5, 0, 19},
+    {13, 0, 0, 0, 5, 0, 19},
+    {7, 0, 0, 0, 5, 0, 20},
+    {12, 0, 13, 0, 5, 0, 20},
+    {12, 118, 13, 0, 5, 0, 20},
+    {6, 0, 0, 0, 5, 0, 20},
+    {12, 122, 13, 0, 5, 0, 20},
+    {13, 0, 0, 0, 5, 0, 20},
+    {7, 0, 0, 0, 5, 0, 21},
+    {26, 0, 0, 0, 5, 0, 21},
+    {21, 0, 0, 0, 5, 0, 21},
+    {12, 220, 13, 0, 5, 0, 21},
+    {13, 0, 0, 0, 5, 0, 21},
+    {15, 0, 0, 0, 5, 0, 21},
+    {12, 216, 13, 0, 5, 0, 21},
+    {22, 0, 18, 1, 5, 0, 21},
+    {18, 0, 18, 1, 5, 0, 21},
+    {10, 0, 0, 0, 5, 0, 21},
+    {12, 129, 13, 0, 5, 0, 21},
+    {12, 130, 13, 0, 5, 0, 21},
+    {12, 0, 13, 0, 5, 0, 21},
+    {12, 132, 13, 0, 5, 0, 21},
+    {12, 230, 13, 0, 5, 0, 21},
+    {12, 9, 13, 0, 5, 0, 21},
+    {26, 0, 0, 0, 5, 0, 0},
+    {7, 0, 0, 0, 5, 0, 22},
+    {10, 0, 0, 0, 5, 0, 22},
+    {12, 0, 13, 0, 5, 0, 22},
+    {12, 7, 13, 0, 5, 0, 22},
+    {12, 9, 13, 0, 5, 0, 22},
+    {13, 0, 0, 0, 5, 0, 22},
+    {21, 0, 0, 0, 5, 0, 22},
+    {12, 220, 13, 0, 5, 0, 22},
+    {26, 0, 0, 0, 5, 0, 22},
+    {9, 0, 0, 0, 5, 0, 23},
+    {7, 0, 0, 0, 5, 0, 23},
+    {6, 0, 0, 0, 5, 0, 23},
+    {7, 0, 0, 0, 2, 0, 24},
+    {7, 0, 0, 0, 5, 0, 24},
+    {7, 0, 0, 0, 5, 0, 25},
+    {12, 230, 13, 0, 5, 0, 25},
+    {21, 0, 0, 0, 5, 0, 25},
+    {15, 0, 0, 0, 5, 0, 25},
+    {26, 0, 18, 0, 5, 0, 25},
+    {7, 0, 0, 0, 5, 0, 26},
+    {17, 0, 18, 0, 5, 0, 27},
+    {7, 0, 0, 0, 5, 0, 27},
+    {21, 0, 0, 0, 5, 0, 27},
+    {29, 0, 17, 0, 5, 0, 28},
+    {7, 0, 0, 0, 5, 0, 28},
+    {22, 0, 18, 1, 5, 0, 28},
+    {18, 0, 18, 1, 5, 0, 28},
+    {7, 0, 0, 0, 5, 0, 29},
+    {14, 0, 0, 0, 5, 0, 29},
+    {7, 0, 0, 0, 5, 0, 41},
+    {12, 0, 13, 0, 5, 0, 41},
+    {12, 9, 13, 0, 5, 0, 41},
+    {7, 0, 0, 0, 5, 0, 42},
+    {12, 0, 13, 0, 5, 0, 42},
+    {12, 9, 13, 0, 5, 0, 42},
+    {7, 0, 0, 0, 5, 0, 43},
+    {12, 0, 13, 0, 5, 0, 43},
+    {7, 0, 0, 0, 5, 0, 44},
+    {12, 0, 13, 0, 5, 0, 44},
+    {7, 0, 0, 0, 5, 0, 30},
+    {12, 0, 13, 0, 5, 0, 30},
+    {10, 0, 0, 0, 5, 0, 30},
+    {12, 9, 13, 0, 5, 0, 30},
+    {21, 0, 0, 0, 5, 0, 30},
+    {6, 0, 0, 0, 5, 0, 30},
+    {23, 0, 10, 0, 5, 0, 30},
+    {12, 230, 13, 0, 5, 0, 30},
+    {13, 0, 0, 0, 5, 0, 30},
+    {15, 0, 18, 0, 5, 0, 30},
+    {21, 0, 18, 0, 5, 0, 31},
+    {17, 0, 18, 0, 5, 0, 31},
+    {12, 0, 13, 0, 5, 0, 31},
+    {1, 0, 14, 0, 5, 0, 31},
+    {13, 0, 0, 0, 5, 0, 31},
+    {7, 0, 0, 0, 5, 0, 31},
+    {6, 0, 0, 0, 5, 0, 31},
+    {12, 228, 13, 0, 5, 0, 31},
+    {7, 0, 0, 0, 5, 0, 45},
+    {12, 0, 13, 0, 5, 0, 45},
+    {10, 0, 0, 0, 5, 0, 45},
+    {12, 222, 13, 0, 5, 0, 45},
+    {12, 230, 13, 0, 5, 0, 45},
+    {12, 220, 13, 0, 5, 0, 45},
+    {26, 0, 18, 0, 5, 0, 45},
+    {21, 0, 18, 0, 5, 0, 45},
+    {13, 0, 0, 0, 5, 0, 45},
+    {7, 0, 0, 0, 5, 0, 46},
+    {7, 0, 0, 0, 5, 0, 55},
+    {10, 0, 0, 0, 5, 0, 55},
+    {13, 0, 0, 0, 5, 0, 55},
+    {15, 0, 0, 0, 5, 0, 55},
+    {26, 0, 18, 0, 5, 0, 55},
+    {26, 0, 18, 0, 5, 0, 30},
+    {7, 0, 0, 0, 5, 0, 53},
+    {12, 230, 13, 0, 5, 0, 53},
+    {12, 220, 13, 0, 5, 0, 53},
+    {10, 0, 0, 0, 5, 0, 53},
+    {12, 0, 13, 0, 5, 0, 53},
+    {21, 0, 0, 0, 5, 0, 53},
+    {7, 0, 0, 0, 5, 0, 77},
+    {10, 0, 0, 0, 5, 0, 77},
+    {12, 0, 13, 0, 5, 0, 77},
+    {12, 9, 13, 0, 5, 0, 77},
+    {12, 230, 13, 0, 5, 0, 77},
+    {12, 220, 13, 0, 5, 0, 77},
+    {13, 0, 0, 0, 5, 0, 77},
+    {21, 0, 0, 0, 5, 0, 77},
+    {6, 0, 0, 0, 5, 0, 77},
+    {11, 0, 13, 0, 5, 0, 40},
+    {12, 0, 13, 0, 5, 0, 61},
+    {10, 0, 0, 0, 5, 0, 61},
+    {7, 0, 0, 0, 5, 0, 61},
+    {12, 7, 13, 0, 5, 0, 61},
+    {10, 9, 0, 0, 5, 0, 61},
+    {13, 0, 0, 0, 5, 0, 61},
+    {21, 0, 0, 0, 5, 0, 61},
+    {26, 0, 0, 0, 5, 0, 61},
+    {12, 230, 13, 0, 5, 0, 61},
+    {12, 220, 13, 0, 5, 0, 61},
+    {12, 0, 13, 0, 5, 0, 66},
+    {10, 0, 0, 0, 5, 0, 66},
+    {7, 0, 0, 0, 5, 0, 66},
+    {10, 9, 0, 0, 5, 0, 66},
+    {12, 9, 13, 0, 5, 0, 66},
+    {13, 0, 0, 0, 5, 0, 66},
+    {7, 0, 0, 0, 5, 0, 92},
+    {12, 7, 13, 0, 5, 0, 92},
+    {10, 0, 0, 0, 5, 0, 92},
+    {12, 0, 13, 0, 5, 0, 92},
+    {10, 9, 0, 0, 5, 0, 92},
+    {21, 0, 0, 0, 5, 0, 92},
+    {7, 0, 0, 0, 5, 0, 67},
+    {10, 0, 0, 0, 5, 0, 67},
+    {12, 0, 13, 0, 5, 0, 67},
+    {12, 7, 13, 0, 5, 0, 67},
+    {21, 0, 0, 0, 5, 0, 67},
+    {13, 0, 0, 0, 5, 0, 67},
+    {13, 0, 0, 0, 5, 0, 68},
+    {7, 0, 0, 0, 5, 0, 68},
+    {6, 0, 0, 0, 5, 0, 68},
+    {21, 0, 0, 0, 5, 0, 68},
+    {21, 0, 0, 0, 5, 0, 66},
+    {12, 1, 13, 0, 5, 0, 40},
+    {10, 0, 0, 0, 5, 0, 0},
+    {7, 0, 0, 0, 5, 0, 0},
+    {6, 0, 0, 0, 5, 0, 3},
+    {12, 234, 13, 0, 5, 0, 40},
+    {12, 214, 13, 0, 5, 0, 40},
+    {12, 202, 13, 0, 5, 0, 40},
+    {12, 233, 13, 0, 5, 0, 40},
+    {8, 0, 0, 0, 5, 0, 2},
+    {29, 0, 17, 0, 5, 0, 0},
+    {1, 0, 14, 0, 5, 0, 0},
+    {1, 0, 14, 0, 5, 0, 40},
+    {1, 0, 0, 0, 5, 0, 0},
+    {1, 0, 3, 0, 5, 0, 0},
+    {17, 0, 18, 0, 4, 0, 0},
+    {17, 0, 18, 0, 5, 0, 0},
+    {20, 0, 18, 0, 4, 0, 0},
+    {19, 0, 18, 0, 4, 0, 0},
+    {22, 0, 18, 0, 5, 0, 0},
+    {20, 0, 18, 0, 5, 0, 0},
+    {27, 0, 17, 0, 5, 0, 0},
+    {28, 0, 15, 0, 5, 0, 0},
+    {1, 0, 1, 0, 5, 0, 0},
+    {1, 0, 5, 0, 5, 0, 0},
+    {1, 0, 7, 0, 5, 0, 0},
+    {1, 0, 2, 0, 5, 0, 0},
+    {1, 0, 6, 0, 5, 0, 0},
+    {21, 0, 10, 0, 4, 0, 0},
+    {21, 0, 10, 0, 5, 0, 0},
+    {16, 0, 18, 0, 5, 0, 0},
+    {25, 0, 12, 0, 5, 0, 0},
+    {22, 0, 18, 1, 5, 0, 0},
+    {18, 0, 18, 1, 5, 0, 0},
+    {25, 0, 18, 0, 5, 0, 0},
+    {1, 0, 19, 0, 5, 0, 0},
+    {1, 0, 20, 0, 5, 0, 0},
+    {1, 0, 21, 0, 5, 0, 0},
+    {1, 0, 22, 0, 5, 0, 0},
+    {15, 0, 8, 0, 5, 0, 0},
+    {25, 0, 9, 0, 5, 0, 0},
+    {6, 0, 0, 0, 4, 0, 1},
+    {23, 0, 10, 0, 1, 0, 0},
+    {9, 0, 0, 0, 5, 0, 0},
+    {5, 0, 0, 0, 4, 0, 0},
+    {26, 0, 10, 0, 5, 0, 0},
+    {25, 0, 18, 1, 5, 0, 0},
+    {15, 0, 18, 0, 5, 0, 0},
+    {14, 0, 0, 0, 4, 0, 1},
+    {14, 0, 0, 0, 5, 0, 1},
+    {25, 0, 18, 1, 4, 0, 0},
+    {25, 0, 10, 0, 5, 0, 0},
+    {22, 0, 18, 1, 2, 0, 0},
+    {18, 0, 18, 1, 2, 0, 0},
+    {26, 0, 0, 0, 4, 0, 0},
+    {26, 0, 0, 0, 5, 0, 52},
+    {9, 0, 0, 0, 5, 0, 56},
+    {5, 0, 0, 0, 5, 0, 56},
+    {26, 0, 18, 0, 5, 0, 54},
+    {12, 230, 13, 0, 5, 0, 54},
+    {21, 0, 18, 0, 5, 0, 54},
+    {15, 0, 18, 0, 5, 0, 54},
+    {5, 0, 0, 0, 5, 0, 23},
+    {7, 0, 0, 0, 5, 0, 57},
+    {6, 0, 0, 0, 5, 0, 57},
+    {21, 0, 0, 0, 5, 0, 57},
+    {12, 9, 13, 0, 5, 0, 57},
+    {26, 0, 18, 0, 2, 0, 35},
+    {26, 0, 18, 0, 2, 0, 0},
+    {29, 0, 17, 0, 0, 0, 0},
+    {21, 0, 18, 0, 2, 0, 0},
+    {6, 0, 0, 0, 2, 0, 35},
+    {7, 0, 0, 0, 2, 0, 0},
+    {14, 0, 0, 0, 2, 0, 35},
+    {17, 0, 18, 0, 2, 0, 0},
+    {22, 0, 18, 0, 2, 0, 0},
+    {18, 0, 18, 0, 2, 0, 0},
+    {12, 218, 13, 0, 2, 0, 40},
+    {12, 228, 13, 0, 2, 0, 40},
+    {12, 232, 13, 0, 2, 0, 40},
+    {12, 222, 13, 0, 2, 0, 40},
+    {10, 224, 0, 0, 2, 0, 24},
+    {6, 0, 0, 0, 2, 0, 0},
+    {7, 0, 0, 0, 2, 0, 32},
+    {12, 8, 13, 0, 2, 0, 40},
+    {24, 0, 18, 0, 2, 0, 0},
+    {6, 0, 0, 0, 2, 0, 32},
+    {7, 0, 0, 0, 2, 0, 33},
+    {6, 0, 0, 0, 2, 0, 33},
+    {7, 0, 0, 0, 2, 0, 34},
+    {26, 0, 0, 0, 2, 0, 0},
+    {15, 0, 0, 0, 2, 0, 0},
+    {26, 0, 0, 0, 2, 0, 24},
+    {26, 0, 18, 0, 2, 0, 24},
+    {15, 0, 0, 0, 4, 0, 0},
+    {15, 0, 18, 0, 2, 0, 0},
+    {26, 0, 0, 0, 2, 0, 33},
+    {7, 0, 0, 0, 2, 0, 35},
+    {2, 0, 18, 0, 2, 0, 35},
+    {2, 0, 18, 0, 2, 0, 102},
+    {7, 0, 0, 0, 2, 0, 36},
+    {6, 0, 0, 0, 2, 0, 36},
+    {26, 0, 18, 0, 2, 0, 36},
+    {7, 0, 0, 0, 5, 0, 82},
+    {6, 0, 0, 0, 5, 0, 82},
+    {21, 0, 0, 0, 5, 0, 82},
+    {7, 0, 0, 0, 5, 0, 69},
+    {6, 0, 0, 0, 5, 0, 69},
+    {21, 0, 18, 0, 5, 0, 69},
+    {13, 0, 0, 0, 5, 0, 69},
+    {7, 0, 0, 0, 5, 0, 3},
+    {21, 0, 18, 0, 5, 0, 3},
+    {6, 0, 18, 0, 5, 0, 3},
+    {7, 0, 0, 0, 5, 0, 83},
+    {14, 0, 0, 0, 5, 0, 83},
+    {12, 230, 13, 0, 5, 0, 83},
+    {21, 0, 0, 0, 5, 0, 83},
+    {24, 0, 0, 0, 5, 0, 0},
+    {7, 0, 0, 0, 5, 0, 58},
+    {12, 0, 13, 0, 5, 0, 58},
+    {12, 9, 13, 0, 5, 0, 58},
+    {10, 0, 0, 0, 5, 0, 58},
+    {26, 0, 18, 0, 5, 0, 58},
+    {15, 0, 0, 0, 5, 0, 0},
+    {7, 0, 0, 0, 5, 0, 64},
+    {21, 0, 18, 0, 5, 0, 64},
+    {10, 0, 0, 0, 5, 0, 70},
+    {7, 0, 0, 0, 5, 0, 70},
+    {12, 9, 13, 0, 5, 0, 70},
+    {21, 0, 0, 0, 5, 0, 70},
+    {13, 0, 0, 0, 5, 0, 70},
+    {13, 0, 0, 0, 5, 0, 71},
+    {7, 0, 0, 0, 5, 0, 71},
+    {12, 0, 13, 0, 5, 0, 71},
+    {12, 220, 13, 0, 5, 0, 71},
+    {21, 0, 0, 0, 5, 0, 71},
+    {7, 0, 0, 0, 5, 0, 72},
+    {12, 0, 13, 0, 5, 0, 72},
+    {10, 0, 0, 0, 5, 0, 72},
+    {10, 9, 0, 0, 5, 0, 72},
+    {21, 0, 0, 0, 5, 0, 72},
+    {12, 0, 13, 0, 5, 0, 84},
+    {10, 0, 0, 0, 5, 0, 84},
+    {7, 0, 0, 0, 5, 0, 84},
+    {12, 7, 13, 0, 5, 0, 84},
+    {10, 9, 0, 0, 5, 0, 84},
+    {21, 0, 0, 0, 5, 0, 84},
+    {13, 0, 0, 0, 5, 0, 84},
+    {6, 0, 0, 0, 5, 0, 22},
+    {7, 0, 0, 0, 5, 0, 76},
+    {12, 0, 13, 0, 5, 0, 76},
+    {10, 0, 0, 0, 5, 0, 76},
+    {13, 0, 0, 0, 5, 0, 76},
+    {21, 0, 0, 0, 5, 0, 76},
+    {7, 0, 0, 0, 5, 0, 78},
+    {12, 230, 13, 0, 5, 0, 78},
+    {12, 220, 13, 0, 5, 0, 78},
+    {6, 0, 0, 0, 5, 0, 78},
+    {21, 0, 0, 0, 5, 0, 78},
+    {7, 0, 0, 0, 5, 0, 85},
+    {10, 0, 0, 0, 5, 0, 85},
+    {12, 0, 13, 0, 5, 0, 85},
+    {21, 0, 0, 0, 5, 0, 85},
+    {6, 0, 0, 0, 5, 0, 85},
+    {12, 9, 13, 0, 5, 0, 85},
+    {13, 0, 0, 0, 5, 0, 85},
+    {2, 0, 18, 0, 2, 0, 24},
+    {4, 0, 0, 0, 5, 0, 102},
+    {3, 0, 0, 0, 4, 0, 102},
+    {2, 0, 18, 0, 4, 0, 102},
+    {12, 26, 13, 0, 5, 0, 5},
+    {25, 0, 9, 0, 5, 0, 5},
+    {24, 0, 4, 0, 5, 0, 6},
+    {18, 0, 18, 0, 5, 0, 0},
+    {16, 0, 18, 0, 2, 0, 0},
+    {21, 0, 12, 0, 2, 0, 0},
+    {21, 0, 10, 0, 2, 0, 0},
+    {25, 0, 9, 0, 2, 0, 0},
+    {17, 0, 9, 0, 2, 0, 0},
+    {25, 0, 18, 1, 2, 0, 0},
+    {25, 0, 18, 0, 2, 0, 0},
+    {23, 0, 10, 0, 2, 0, 0},
+    {21, 0, 18, 0, 0, 0, 0},
+    {21, 0, 10, 0, 0, 0, 0},
+    {23, 0, 10, 0, 0, 0, 0},
+    {22, 0, 18, 1, 0, 0, 0},
+    {18, 0, 18, 1, 0, 0, 0},
+    {25, 0, 9, 0, 0, 0, 0},
+    {21, 0, 12, 0, 0, 0, 0},
+    {17, 0, 9, 0, 0, 0, 0},
+    {13, 0, 8, 0, 0, 0, 0},
+    {25, 0, 18, 1, 0, 0, 0},
+    {25, 0, 18, 0, 0, 0, 0},
+    {9, 0, 0, 0, 0, 0, 1},
+    {24, 0, 18, 0, 0, 0, 0},
+    {16, 0, 18, 0, 0, 0, 0},
+    {5, 0, 0, 0, 0, 0, 1},
+    {21, 0, 18, 0, 1, 0, 0},
+    {22, 0, 18, 1, 1, 0, 0},
+    {18, 0, 18, 1, 1, 0, 0},
+    {7, 0, 0, 0, 1, 0, 33},
+    {6, 0, 0, 0, 1, 0, 0},
+    {7, 0, 0, 0, 1, 0, 24},
+    {26, 0, 18, 0, 0, 0, 0},
+    {26, 0, 18, 0, 1, 0, 0},
+    {25, 0, 18, 0, 1, 0, 0},
+    {1, 0, 18, 0, 5, 0, 0},
+    {7, 0, 0, 0, 5, 0, 47},
+    {14, 0, 18, 0, 5, 0, 2},
+    {15, 0, 18, 0, 5, 0, 2},
+    {26, 0, 18, 0, 5, 0, 2},
+    {7, 0, 0, 0, 5, 0, 73},
+    {7, 0, 0, 0, 5, 0, 74},
+    {7, 0, 0, 0, 5, 0, 37},
+    {15, 0, 0, 0, 5, 0, 37},
+    {7, 0, 0, 0, 5, 0, 38},
+    {14, 0, 0, 0, 5, 0, 38},
+    {7, 0, 0, 0, 5, 0, 118},
+    {12, 230, 13, 0, 5, 0, 118},
+    {7, 0, 0, 0, 5, 0, 48},
+    {21, 0, 0, 0, 5, 0, 48},
+    {7, 0, 0, 0, 5, 0, 59},
+    {21, 0, 0, 0, 5, 0, 59},
+    {14, 0, 0, 0, 5, 0, 59},
+    {9, 0, 0, 0, 5, 0, 39},
+    {5, 0, 0, 0, 5, 0, 39},
+    {7, 0, 0, 0, 5, 0, 49},
+    {7, 0, 0, 0, 5, 0, 50},
+    {13, 0, 0, 0, 5, 0, 50},
+    {7, 0, 0, 0, 5, 0, 106},
+    {7, 0, 0, 0, 5, 0, 104},
+    {21, 0, 0, 0, 5, 0, 104},
+    {7, 0, 0, 0, 5, 0, 110},
+    {7, 0, 3, 0, 5, 0, 51},
+    {7, 0, 3, 0, 5, 0, 86},
+    {21, 0, 3, 0, 5, 0, 86},
+    {15, 0, 3, 0, 5, 0, 86},
+    {7, 0, 3, 0, 5, 0, 120},
+    {26, 0, 3, 0, 5, 0, 120},
+    {15, 0, 3, 0, 5, 0, 120},
+    {7, 0, 3, 0, 5, 0, 116},
+    {15, 0, 3, 0, 5, 0, 116},
+    {7, 0, 3, 0, 5, 0, 63},
+    {15, 0, 3, 0, 5, 0, 63},
+    {21, 0, 18, 0, 5, 0, 63},
+    {7, 0, 3, 0, 5, 0, 75},
+    {21, 0, 3, 0, 5, 0, 75},
+    {7, 0, 3, 0, 5, 0, 97},
+    {7, 0, 3, 0, 5, 0, 96},
+    {7, 0, 3, 0, 5, 0, 60},
+    {12, 0, 13, 0, 5, 0, 60},
+    {12, 220, 13, 0, 5, 0, 60},
+    {12, 230, 13, 0, 5, 0, 60},
+    {12, 1, 13, 0, 5, 0, 60},
+    {12, 9, 13, 0, 5, 0, 60},
+    {15, 0, 3, 0, 5, 0, 60},
+    {21, 0, 3, 0, 5, 0, 60},
+    {7, 0, 3, 0, 5, 0, 87},
+    {15, 0, 3, 0, 5, 0, 87},
+    {21, 0, 3, 0, 5, 0, 87},
+    {7, 0, 3, 0, 5, 0, 117},
+    {15, 0, 3, 0, 5, 0, 117},
+    {7, 0, 3, 0, 5, 0, 112},
+    {26, 0, 3, 0, 5, 0, 112},
+    {12, 230, 13, 0, 5, 0, 112},
+    {12, 220, 13, 0, 5, 0, 112},
+    {15, 0, 3, 0, 5, 0, 112},
+    {21, 0, 3, 0, 5, 0, 112},
+    {7, 0, 3, 0, 5, 0, 79},
+    {21, 0, 18, 0, 5, 0, 79},
+    {7, 0, 3, 0, 5, 0, 88},
+    {15, 0, 3, 0, 5, 0, 88},
+    {7, 0, 3, 0, 5, 0, 89},
+    {15, 0, 3, 0, 5, 0, 89},
+    {7, 0, 3, 0, 5, 0, 122},
+    {21, 0, 3, 0, 5, 0, 122},
+    {15, 0, 3, 0, 5, 0, 122},
+    {7, 0, 3, 0, 5, 0, 90},
+    {15, 0, 11, 0, 5, 0, 6},
+    {10, 0, 0, 0, 5, 0, 93},
+    {12, 0, 13, 0, 5, 0, 93},
+    {7, 0, 0, 0, 5, 0, 93},
+    {12, 9, 13, 0, 5, 0, 93},
+    {21, 0, 0, 0, 5, 0, 93},
+    {15, 0, 18, 0, 5, 0, 93},
+    {13, 0, 0, 0, 5, 0, 93},
+    {12, 0, 13, 0, 5, 0, 91},
+    {10, 0, 0, 0, 5, 0, 91},
+    {7, 0, 0, 0, 5, 0, 91},
+    {12, 9, 13, 0, 5, 0, 91},
+    {12, 7, 13, 0, 5, 0, 91},
+    {21, 0, 0, 0, 5, 0, 91},
+    {1, 0, 0, 0, 5, 0, 91},
+    {7, 0, 0, 0, 5, 0, 100},
+    {13, 0, 0, 0, 5, 0, 100},
+    {12, 230, 13, 0, 5, 0, 95},
+    {7, 0, 0, 0, 5, 0, 95},
+    {12, 0, 13, 0, 5, 0, 95},
+    {10, 0, 0, 0, 5, 0, 95},
+    {12, 9, 13, 0, 5, 0, 95},
+    {13, 0, 0, 0, 5, 0, 95},
+    {21, 0, 0, 0, 5, 0, 95},
+    {7, 0, 0, 0, 5, 0, 111},
+    {12, 7, 13, 0, 5, 0, 111},
+    {21, 0, 0, 0, 5, 0, 111},
+    {12, 0, 13, 0, 5, 0, 99},
+    {10, 0, 0, 0, 5, 0, 99},
+    {7, 0, 0, 0, 5, 0, 99},
+    {10, 9, 0, 0, 5, 0, 99},
+    {21, 0, 0, 0, 5, 0, 99},
+    {13, 0, 0, 0, 5, 0, 99},
+    {15, 0, 0, 0, 5, 0, 18},
+    {7, 0, 0, 0, 5, 0, 108},
+    {10, 0, 0, 0, 5, 0, 108},
+    {12, 0, 13, 0, 5, 0, 108},
+    {10, 9, 0, 0, 5, 0, 108},
+    {12, 7, 13, 0, 5, 0, 108},
+    {21, 0, 0, 0, 5, 0, 108},
+    {7, 0, 0, 0, 5, 0, 109},
+    {12, 0, 13, 0, 5, 0, 109},
+    {10, 0, 0, 0, 5, 0, 109},
+    {12, 7, 13, 0, 5, 0, 109},
+    {12, 9, 13, 0, 5, 0, 109},
+    {13, 0, 0, 0, 5, 0, 109},
+    {12, 0, 13, 0, 5, 0, 107},
+    {10, 0, 0, 0, 5, 0, 107},
+    {7, 0, 0, 0, 5, 0, 107},
+    {12, 7, 13, 0, 5, 0, 107},
+    {10, 9, 0, 0, 5, 0, 107},
+    {12, 230, 13, 0, 5, 0, 107},
+    {7, 0, 0, 0, 5, 0, 124},
+    {10, 0, 0, 0, 5, 0, 124},
+    {12, 0, 13, 0, 5, 0, 124},
+    {12, 9, 13, 0, 5, 0, 124},
+    {12, 7, 13, 0, 5, 0, 124},
+    {21, 0, 0, 0, 5, 0, 124},
+    {13, 0, 0, 0, 5, 0, 124},
+    {7, 0, 0, 0, 5, 0, 123},
+    {10, 0, 0, 0, 5, 0, 123},
+    {12, 0, 13, 0, 5, 0, 123},
+    {12, 9, 13, 0, 5, 0, 123},
+    {12, 7, 13, 0, 5, 0, 123},
+    {21, 0, 0, 0, 5, 0, 123},
+    {7, 0, 0, 0, 5, 0, 114},
+    {10, 0, 0, 0, 5, 0, 114},
+    {12, 0, 13, 0, 5, 0, 114},
+    {12, 9, 13, 0, 5, 0, 114},
+    {21, 0, 0, 0, 5, 0, 114},
+    {13, 0, 0, 0, 5, 0, 114},
+    {7, 0, 0, 0, 5, 0, 101},
+    {12, 0, 13, 0, 5, 0, 101},
+    {10, 0, 0, 0, 5, 0, 101},
+    {10, 9, 0, 0, 5, 0, 101},
+    {12, 7, 13, 0, 5, 0, 101},
+    {13, 0, 0, 0, 5, 0, 101},
+    {9, 0, 0, 0, 5, 0, 125},
+    {5, 0, 0, 0, 5, 0, 125},
+    {13, 0, 0, 0, 5, 0, 125},
+    {15, 0, 0, 0, 5, 0, 125},
+    {7, 0, 0, 0, 5, 0, 125},
+    {7, 0, 0, 0, 5, 0, 121},
+    {7, 0, 0, 0, 5, 0, 62},
+    {14, 0, 0, 0, 5, 0, 62},
+    {21, 0, 0, 0, 5, 0, 62},
+    {7, 0, 0, 0, 5, 0, 80},
+    {7, 0, 0, 0, 5, 0, 115},
+    {13, 0, 0, 0, 5, 0, 115},
+    {21, 0, 0, 0, 5, 0, 115},
+    {7, 0, 0, 0, 5, 0, 103},
+    {12, 1, 13, 0, 5, 0, 103},
+    {21, 0, 0, 0, 5, 0, 103},
+    {7, 0, 0, 0, 5, 0, 119},
+    {12, 230, 13, 0, 5, 0, 119},
+    {21, 0, 0, 0, 5, 0, 119},
+    {26, 0, 0, 0, 5, 0, 119},
+    {6, 0, 0, 0, 5, 0, 119},
+    {13, 0, 0, 0, 5, 0, 119},
+    {15, 0, 0, 0, 5, 0, 119},
+    {7, 0, 0, 0, 5, 0, 98},
+    {10, 0, 0, 0, 5, 0, 98},
+    {12, 0, 13, 0, 5, 0, 98},
+    {6, 0, 0, 0, 5, 0, 98},
+    {7, 0, 0, 0, 5, 0, 105},
+    {26, 0, 0, 0, 5, 0, 105},
+    {12, 0, 13, 0, 5, 0, 105},
+    {12, 1, 13, 0, 5, 0, 105},
+    {21, 0, 0, 0, 5, 0, 105},
+    {10, 216, 0, 0, 5, 0, 0},
+    {10, 226, 0, 0, 5, 0, 0},
+    {12, 230, 13, 0, 5, 0, 2},
+    {25, 0, 0, 0, 5, 0, 0},
+    {13, 0, 8, 0, 5, 0, 0},
+    {7, 0, 3, 0, 5, 0, 113},
+    {15, 0, 3, 0, 5, 0, 113},
+    {12, 220, 13, 0, 5, 0, 113},
+    {26, 0, 0, 0, 2, 0, 32},
+};
+
+#define BIDI_MIRROR_LEN 364
+static const MirrorPair mirror_pairs[] = {
+    {40, 41},
+    {41, 40},
+    {60, 62},
+    {62, 60},
+    {91, 93},
+    {93, 91},
+    {123, 125},
+    {125, 123},
+    {171, 187},
+    {187, 171},
+    {3898, 3899},
+    {3899, 3898},
+    {3900, 3901},
+    {3901, 3900},
+    {5787, 5788},
+    {5788, 5787},
+    {8249, 8250},
+    {8250, 8249},
+    {8261, 8262},
+    {8262, 8261},
+    {8317, 8318},
+    {8318, 8317},
+    {8333, 8334},
+    {8334, 8333},
+    {8712, 8715},
+    {8713, 8716},
+    {8714, 8717},
+    {8715, 8712},
+    {8716, 8713},
+    {8717, 8714},
+    {8725, 10741},
+    {8764, 8765},
+    {8765, 8764},
+    {8771, 8909},
+    {8786, 8787},
+    {8787, 8786},
+    {8788, 8789},
+    {8789, 8788},
+    {8804, 8805},
+    {8805, 8804},
+    {8806, 8807},
+    {8807, 8806},
+    {8808, 8809},
+    {8809, 8808},
+    {8810, 8811},
+    {8811, 8810},
+    {8814, 8815},
+    {8815, 8814},
+    {8816, 8817},
+    {8817, 8816},
+    {8818, 8819},
+    {8819, 8818},
+    {8820, 8821},
+    {8821, 8820},
+    {8822, 8823},
+    {8823, 8822},
+    {8824, 8825},
+    {8825, 8824},
+    {8826, 8827},
+    {8827, 8826},
+    {8828, 8829},
+    {8829, 8828},
+    {8830, 8831},
+    {8831, 8830},
+    {8832, 8833},
+    {8833, 8832},
+    {8834, 8835},
+    {8835, 8834},
+    {8836, 8837},
+    {8837, 8836},
+    {8838, 8839},
+    {8839, 8838},
+    {8840, 8841},
+    {8841, 8840},
+    {8842, 8843},
+    {8843, 8842},
+    {8847, 8848},
+    {8848, 8847},
+    {8849, 8850},
+    {8850, 8849},
+    {8856, 10680},
+    {8866, 8867},
+    {8867, 8866},
+    {8870, 10974},
+    {8872, 10980},
+    {8873, 10979},
+    {8875, 10981},
+    {8880, 8881},
+    {8881, 8880},
+    {8882, 8883},
+    {8883, 8882},
+    {8884, 8885},
+    {8885, 8884},
+    {8886, 8887},
+    {8887, 8886},
+    {8905, 8906},
+    {8906, 8905},
+    {8907, 8908},
+    {8908, 8907},
+    {8909, 8771},
+    {8912, 8913},
+    {8913, 8912},
+    {8918, 8919},
+    {8919, 8918},
+    {8920, 8921},
+    {8921, 8920},
+    {8922, 8923},
+    {8923, 8922},
+    {8924, 8925},
+    {8925, 8924},
+    {8926, 8927},
+    {8927, 8926},
+    {8928, 8929},
+    {8929, 8928},
+    {8930, 8931},
+    {8931, 8930},
+    {8932, 8933},
+    {8933, 8932},
+    {8934, 8935},
+    {8935, 8934},
+    {8936, 8937},
+    {8937, 8936},
+    {8938, 8939},
+    {8939, 8938},
+    {8940, 8941},
+    {8941, 8940},
+    {8944, 8945},
+    {8945, 8944},
+    {8946, 8954},
+    {8947, 8955},
+    {8948, 8956},
+    {8950, 8957},
+    {8951, 8958},
+    {8954, 8946},
+    {8955, 8947},
+    {8956, 8948},
+    {8957, 8950},
+    {8958, 8951},
+    {8968, 8969},
+    {8969, 8968},
+    {8970, 8971},
+    {8971, 8970},
+    {9001, 9002},
+    {9002, 9001},
+    {10088, 10089},
+    {10089, 10088},
+    {10090, 10091},
+    {10091, 10090},
+    {10092, 10093},
+    {10093, 10092},
+    {10094, 10095},
+    {10095, 10094},
+    {10096, 10097},
+    {10097, 10096},
+    {10098, 10099},
+    {10099, 10098},
+    {10100, 10101},
+    {10101, 10100},
+    {10179, 10180},
+    {10180, 10179},
+    {10181, 10182},
+    {10182, 10181},
+    {10184, 10185},
+    {10185, 10184},
+    {10187, 10189},
+    {10189, 10187},
+    {10197, 10198},
+    {10198, 10197},
+    {10205, 10206},
+    {10206, 10205},
+    {10210, 10211},
+    {10211, 10210},
+    {10212, 10213},
+    {10213, 10212},
+    {10214, 10215},
+    {10215, 10214},
+    {10216, 10217},
+    {10217, 10216},
+    {10218, 10219},
+    {10219, 10218},
+    {10220, 10221},
+    {10221, 10220},
+    {10222, 10223},
+    {10223, 10222},
+    {10627, 10628},
+    {10628, 10627},
+    {10629, 10630},
+    {10630, 10629},
+    {10631, 10632},
+    {10632, 10631},
+    {10633, 10634},
+    {10634, 10633},
+    {10635, 10636},
+    {10636, 10635},
+    {10637, 10640},
+    {10638, 10639},
+    {10639, 10638},
+    {10640, 10637},
+    {10641, 10642},
+    {10642, 10641},
+    {10643, 10644},
+    {10644, 10643},
+    {10645, 10646},
+    {10646, 10645},
+    {10647, 10648},
+    {10648, 10647},
+    {10680, 8856},
+    {10688, 10689},
+    {10689, 10688},
+    {10692, 10693},
+    {10693, 10692},
+    {10703, 10704},
+    {10704, 10703},
+    {10705, 10706},
+    {10706, 10705},
+    {10708, 10709},
+    {10709, 10708},
+    {10712, 10713},
+    {10713, 10712},
+    {10714, 10715},
+    {10715, 10714},
+    {10741, 8725},
+    {10744, 10745},
+    {10745, 10744},
+    {10748, 10749},
+    {10749, 10748},
+    {10795, 10796},
+    {10796, 10795},
+    {10797, 10798},
+    {10798, 10797},
+    {10804, 10805},
+    {10805, 10804},
+    {10812, 10813},
+    {10813, 10812},
+    {10852, 10853},
+    {10853, 10852},
+    {10873, 10874},
+    {10874, 10873},
+    {10877, 10878},
+    {10878, 10877},
+    {10879, 10880},
+    {10880, 10879},
+    {10881, 10882},
+    {10882, 10881},
+    {10883, 10884},
+    {10884, 10883},
+    {10891, 10892},
+    {10892, 10891},
+    {10897, 10898},
+    {10898, 10897},
+    {10899, 10900},
+    {10900, 10899},
+    {10901, 10902},
+    {10902, 10901},
+    {10903, 10904},
+    {10904, 10903},
+    {10905, 10906},
+    {10906, 10905},
+    {10907, 10908},
+    {10908, 10907},
+    {10913, 10914},
+    {10914, 10913},
+    {10918, 10919},
+    {10919, 10918},
+    {10920, 10921},
+    {10921, 10920},
+    {10922, 10923},
+    {10923, 10922},
+    {10924, 10925},
+    {10925, 10924},
+    {10927, 10928},
+    {10928, 10927},
+    {10931, 10932},
+    {10932, 10931},
+    {10939, 10940},
+    {10940, 10939},
+    {10941, 10942},
+    {10942, 10941},
+    {10943, 10944},
+    {10944, 10943},
+    {10945, 10946},
+    {10946, 10945},
+    {10947, 10948},
+    {10948, 10947},
+    {10949, 10950},
+    {10950, 10949},
+    {10957, 10958},
+    {10958, 10957},
+    {10959, 10960},
+    {10960, 10959},
+    {10961, 10962},
+    {10962, 10961},
+    {10963, 10964},
+    {10964, 10963},
+    {10965, 10966},
+    {10966, 10965},
+    {10974, 8870},
+    {10979, 8873},
+    {10980, 8872},
+    {10981, 8875},
+    {10988, 10989},
+    {10989, 10988},
+    {10999, 11000},
+    {11000, 10999},
+    {11001, 11002},
+    {11002, 11001},
+    {11778, 11779},
+    {11779, 11778},
+    {11780, 11781},
+    {11781, 11780},
+    {11785, 11786},
+    {11786, 11785},
+    {11788, 11789},
+    {11789, 11788},
+    {11804, 11805},
+    {11805, 11804},
+    {11808, 11809},
+    {11809, 11808},
+    {11810, 11811},
+    {11811, 11810},
+    {11812, 11813},
+    {11813, 11812},
+    {11814, 11815},
+    {11815, 11814},
+    {11816, 11817},
+    {11817, 11816},
+    {12296, 12297},
+    {12297, 12296},
+    {12298, 12299},
+    {12299, 12298},
+    {12300, 12301},
+    {12301, 12300},
+    {12302, 12303},
+    {12303, 12302},
+    {12304, 12305},
+    {12305, 12304},
+    {12308, 12309},
+    {12309, 12308},
+    {12310, 12311},
+    {12311, 12310},
+    {12312, 12313},
+    {12313, 12312},
+    {12314, 12315},
+    {12315, 12314},
+    {65113, 65114},
+    {65114, 65113},
+    {65115, 65116},
+    {65116, 65115},
+    {65117, 65118},
+    {65118, 65117},
+    {65124, 65125},
+    {65125, 65124},
+    {65288, 65289},
+    {65289, 65288},
+    {65308, 65310},
+    {65310, 65308},
+    {65339, 65341},
+    {65341, 65339},
+    {65371, 65373},
+    {65373, 65371},
+    {65375, 65376},
+    {65376, 65375},
+    {65378, 65379},
+    {65379, 65378},
+};
+
+/* Reindexing of NFC first characters. */
+#define TOTAL_FIRST 376
+#define TOTAL_LAST 62
+static const Reindex nfc_first[] = {
+  { 60, 2, 0},
+  { 65, 15, 3},
+  { 82, 8, 19},
+  { 97, 15, 28},
+  { 114, 8, 44},
+  { 168, 0, 53},
+  { 194, 0, 54},
+  { 196, 3, 55},
+  { 202, 0, 59},
+  { 207, 0, 60},
+  { 212, 2, 61},
+  { 216, 0, 64},
+  { 220, 0, 65},
+  { 226, 0, 66},
+  { 228, 3, 67},
+  { 234, 0, 71},
+  { 239, 0, 72},
+  { 244, 2, 73},
+  { 248, 0, 76},
+  { 252, 0, 77},
+  { 258, 1, 78},
+  { 274, 1, 80},
+  { 332, 1, 82},
+  { 346, 1, 84},
+  { 352, 1, 86},
+  { 360, 3, 88},
+  { 383, 0, 92},
+  { 416, 1, 93},
+  { 431, 1, 95},
+  { 439, 0, 97},
+  { 490, 1, 98},
+  { 550, 3, 100},
+  { 558, 1, 104},
+  { 658, 0, 106},
+  { 913, 0, 107},
+  { 917, 0, 108},
+  { 919, 0, 109},
+  { 921, 0, 110},
+  { 927, 0, 111},
+  { 929, 0, 112},
+  { 933, 0, 113},
+  { 937, 0, 114},
+  { 940, 0, 115},
+  { 942, 0, 116},
+  { 945, 0, 117},
+  { 949, 0, 118},
+  { 951, 0, 119},
+  { 953, 0, 120},
+  { 959, 0, 121},
+  { 961, 0, 122},
+  { 965, 0, 123},
+  { 969, 2, 124},
+  { 974, 0, 127},
+  { 978, 0, 128},
+  { 1030, 0, 129},
+  { 1040, 0, 130},
+  { 1043, 0, 131},
+  { 1045, 3, 132},
+  { 1050, 0, 136},
+  { 1054, 0, 137},
+  { 1059, 0, 138},
+  { 1063, 0, 139},
+  { 1067, 0, 140},
+  { 1069, 0, 141},
+  { 1072, 0, 142},
+  { 1075, 0, 143},
+  { 1077, 3, 144},
+  { 1082, 0, 148},
+  { 1086, 0, 149},
+  { 1091, 0, 150},
+  { 1095, 0, 151},
+  { 1099, 0, 152},
+  { 1101, 0, 153},
+  { 1110, 0, 154},
+  { 1140, 1, 155},
+  { 1240, 1, 157},
+  { 1256, 1, 159},
+  { 1575, 0, 161},
+  { 1608, 0, 162},
+  { 1610, 0, 163},
+  { 1729, 0, 164},
+  { 1746, 0, 165},
+  { 1749, 0, 166},
+  { 2344, 0, 167},
+  { 2352, 0, 168},
+  { 2355, 0, 169},
+  { 2503, 0, 170},
+  { 2887, 0, 171},
+  { 2962, 0, 172},
+  { 3014, 1, 173},
+  { 3142, 0, 175},
+  { 3263, 0, 176},
+  { 3270, 0, 177},
+  { 3274, 0, 178},
+  { 3398, 1, 179},
+  { 3545, 0, 181},
+  { 3548, 0, 182},
+  { 4133, 0, 183},
+  { 6917, 0, 184},
+  { 6919, 0, 185},
+  { 6921, 0, 186},
+  { 6923, 0, 187},
+  { 6925, 0, 188},
+  { 6929, 0, 189},
+  { 6970, 0, 190},
+  { 6972, 0, 191},
+  { 6974, 1, 192},
+  { 6978, 0, 194},
+  { 7734, 1, 195},
+  { 7770, 1, 197},
+  { 7778, 1, 199},
+  { 7840, 1, 201},
+  { 7864, 1, 203},
+  { 7884, 1, 205},
+  { 7936, 17, 207},
+  { 7960, 1, 225},
+  { 7968, 17, 227},
+  { 7992, 1, 245},
+  { 8000, 1, 247},
+  { 8008, 1, 249},
+  { 8016, 1, 251},
+  { 8025, 0, 253},
+  { 8032, 16, 254},
+  { 8052, 0, 271},
+  { 8060, 0, 272},
+  { 8118, 0, 273},
+  { 8127, 0, 274},
+  { 8134, 0, 275},
+  { 8182, 0, 276},
+  { 8190, 0, 277},
+  { 8592, 0, 278},
+  { 8594, 0, 279},
+  { 8596, 0, 280},
+  { 8656, 0, 281},
+  { 8658, 0, 282},
+  { 8660, 0, 283},
+  { 8707, 0, 284},
+  { 8712, 0, 285},
+  { 8715, 0, 286},
+  { 8739, 0, 287},
+  { 8741, 0, 288},
+  { 8764, 0, 289},
+  { 8771, 0, 290},
+  { 8773, 0, 291},
+  { 8776, 0, 292},
+  { 8781, 0, 293},
+  { 8801, 0, 294},
+  { 8804, 1, 295},
+  { 8818, 1, 297},
+  { 8822, 1, 299},
+  { 8826, 3, 301},
+  { 8834, 1, 305},
+  { 8838, 1, 307},
+  { 8849, 1, 309},
+  { 8866, 0, 311},
+  { 8872, 1, 312},
+  { 8875, 0, 314},
+  { 8882, 3, 315},
+  { 12358, 0, 319},
+  { 12363, 0, 320},
+  { 12365, 0, 321},
+  { 12367, 0, 322},
+  { 12369, 0, 323},
+  { 12371, 0, 324},
+  { 12373, 0, 325},
+  { 12375, 0, 326},
+  { 12377, 0, 327},
+  { 12379, 0, 328},
+  { 12381, 0, 329},
+  { 12383, 0, 330},
+  { 12385, 0, 331},
+  { 12388, 0, 332},
+  { 12390, 0, 333},
+  { 12392, 0, 334},
+  { 12399, 0, 335},
+  { 12402, 0, 336},
+  { 12405, 0, 337},
+  { 12408, 0, 338},
+  { 12411, 0, 339},
+  { 12445, 0, 340},
+  { 12454, 0, 341},
+  { 12459, 0, 342},
+  { 12461, 0, 343},
+  { 12463, 0, 344},
+  { 12465, 0, 345},
+  { 12467, 0, 346},
+  { 12469, 0, 347},
+  { 12471, 0, 348},
+  { 12473, 0, 349},
+  { 12475, 0, 350},
+  { 12477, 0, 351},
+  { 12479, 0, 352},
+  { 12481, 0, 353},
+  { 12484, 0, 354},
+  { 12486, 0, 355},
+  { 12488, 0, 356},
+  { 12495, 0, 357},
+  { 12498, 0, 358},
+  { 12501, 0, 359},
+  { 12504, 0, 360},
+  { 12507, 0, 361},
+  { 12527, 3, 362},
+  { 12541, 0, 366},
+  { 69785, 0, 367},
+  { 69787, 0, 368},
+  { 69797, 0, 369},
+  { 69937, 1, 370},
+  { 70471, 0, 372},
+  { 70841, 0, 373},
+  { 71096, 1, 374},
+  {0,0,0}
+};
+
+static const Reindex nfc_last[] = {
+  { 768, 4, 0},
+  { 774, 6, 5},
+  { 783, 0, 12},
+  { 785, 0, 13},
+  { 787, 1, 14},
+  { 795, 0, 16},
+  { 803, 5, 17},
+  { 813, 1, 23},
+  { 816, 1, 25},
+  { 824, 0, 27},
+  { 834, 0, 28},
+  { 837, 0, 29},
+  { 1619, 2, 30},
+  { 2364, 0, 33},
+  { 2494, 0, 34},
+  { 2519, 0, 35},
+  { 2878, 0, 36},
+  { 2902, 1, 37},
+  { 3006, 0, 39},
+  { 3031, 0, 40},
+  { 3158, 0, 41},
+  { 3266, 0, 42},
+  { 3285, 1, 43},
+  { 3390, 0, 45},
+  { 3415, 0, 46},
+  { 3530, 0, 47},
+  { 3535, 0, 48},
+  { 3551, 0, 49},
+  { 4142, 0, 50},
+  { 6965, 0, 51},
+  { 12441, 1, 52},
+  { 69818, 0, 54},
+  { 69927, 0, 55},
+  { 70462, 0, 56},
+  { 70487, 0, 57},
+  { 70832, 0, 58},
+  { 70842, 0, 59},
+  { 70845, 0, 60},
+  { 71087, 0, 61},
+  {0,0,0}
+};
+
+#define UCDN_EAST_ASIAN_F 0
+#define UCDN_EAST_ASIAN_H 1
+#define UCDN_EAST_ASIAN_W 2
+#define UCDN_EAST_ASIAN_NA 3
+#define UCDN_EAST_ASIAN_A 4
+#define UCDN_EAST_ASIAN_N 5
+
+#define UCDN_SCRIPT_COMMON 0
+#define UCDN_SCRIPT_LATIN 1
+#define UCDN_SCRIPT_GREEK 2
+#define UCDN_SCRIPT_CYRILLIC 3
+#define UCDN_SCRIPT_ARMENIAN 4
+#define UCDN_SCRIPT_HEBREW 5
+#define UCDN_SCRIPT_ARABIC 6
+#define UCDN_SCRIPT_SYRIAC 7
+#define UCDN_SCRIPT_THAANA 8
+#define UCDN_SCRIPT_DEVANAGARI 9
+#define UCDN_SCRIPT_BENGALI 10
+#define UCDN_SCRIPT_GURMUKHI 11
+#define UCDN_SCRIPT_GUJARATI 12
+#define UCDN_SCRIPT_ORIYA 13
+#define UCDN_SCRIPT_TAMIL 14
+#define UCDN_SCRIPT_TELUGU 15
+#define UCDN_SCRIPT_KANNADA 16
+#define UCDN_SCRIPT_MALAYALAM 17
+#define UCDN_SCRIPT_SINHALA 18
+#define UCDN_SCRIPT_THAI 19
+#define UCDN_SCRIPT_LAO 20
+#define UCDN_SCRIPT_TIBETAN 21
+#define UCDN_SCRIPT_MYANMAR 22
+#define UCDN_SCRIPT_GEORGIAN 23
+#define UCDN_SCRIPT_HANGUL 24
+#define UCDN_SCRIPT_ETHIOPIC 25
+#define UCDN_SCRIPT_CHEROKEE 26
+#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
+#define UCDN_SCRIPT_OGHAM 28
+#define UCDN_SCRIPT_RUNIC 29
+#define UCDN_SCRIPT_KHMER 30
+#define UCDN_SCRIPT_MONGOLIAN 31
+#define UCDN_SCRIPT_HIRAGANA 32
+#define UCDN_SCRIPT_KATAKANA 33
+#define UCDN_SCRIPT_BOPOMOFO 34
+#define UCDN_SCRIPT_HAN 35
+#define UCDN_SCRIPT_YI 36
+#define UCDN_SCRIPT_OLD_ITALIC 37
+#define UCDN_SCRIPT_GOTHIC 38
+#define UCDN_SCRIPT_DESERET 39
+#define UCDN_SCRIPT_INHERITED 40
+#define UCDN_SCRIPT_TAGALOG 41
+#define UCDN_SCRIPT_HANUNOO 42
+#define UCDN_SCRIPT_BUHID 43
+#define UCDN_SCRIPT_TAGBANWA 44
+#define UCDN_SCRIPT_LIMBU 45
+#define UCDN_SCRIPT_TAI_LE 46
+#define UCDN_SCRIPT_LINEAR_B 47
+#define UCDN_SCRIPT_UGARITIC 48
+#define UCDN_SCRIPT_SHAVIAN 49
+#define UCDN_SCRIPT_OSMANYA 50
+#define UCDN_SCRIPT_CYPRIOT 51
+#define UCDN_SCRIPT_BRAILLE 52
+#define UCDN_SCRIPT_BUGINESE 53
+#define UCDN_SCRIPT_COPTIC 54
+#define UCDN_SCRIPT_NEW_TAI_LUE 55
+#define UCDN_SCRIPT_GLAGOLITIC 56
+#define UCDN_SCRIPT_TIFINAGH 57
+#define UCDN_SCRIPT_SYLOTI_NAGRI 58
+#define UCDN_SCRIPT_OLD_PERSIAN 59
+#define UCDN_SCRIPT_KHAROSHTHI 60
+#define UCDN_SCRIPT_BALINESE 61
+#define UCDN_SCRIPT_CUNEIFORM 62
+#define UCDN_SCRIPT_PHOENICIAN 63
+#define UCDN_SCRIPT_PHAGS_PA 64
+#define UCDN_SCRIPT_NKO 65
+#define UCDN_SCRIPT_SUNDANESE 66
+#define UCDN_SCRIPT_LEPCHA 67
+#define UCDN_SCRIPT_OL_CHIKI 68
+#define UCDN_SCRIPT_VAI 69
+#define UCDN_SCRIPT_SAURASHTRA 70
+#define UCDN_SCRIPT_KAYAH_LI 71
+#define UCDN_SCRIPT_REJANG 72
+#define UCDN_SCRIPT_LYCIAN 73
+#define UCDN_SCRIPT_CARIAN 74
+#define UCDN_SCRIPT_LYDIAN 75
+#define UCDN_SCRIPT_CHAM 76
+#define UCDN_SCRIPT_TAI_THAM 77
+#define UCDN_SCRIPT_TAI_VIET 78
+#define UCDN_SCRIPT_AVESTAN 79
+#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
+#define UCDN_SCRIPT_SAMARITAN 81
+#define UCDN_SCRIPT_LISU 82
+#define UCDN_SCRIPT_BAMUM 83
+#define UCDN_SCRIPT_JAVANESE 84
+#define UCDN_SCRIPT_MEETEI_MAYEK 85
+#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
+#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
+#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
+#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
+#define UCDN_SCRIPT_OLD_TURKIC 90
+#define UCDN_SCRIPT_KAITHI 91
+#define UCDN_SCRIPT_BATAK 92
+#define UCDN_SCRIPT_BRAHMI 93
+#define UCDN_SCRIPT_MANDAIC 94
+#define UCDN_SCRIPT_CHAKMA 95
+#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
+#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
+#define UCDN_SCRIPT_MIAO 98
+#define UCDN_SCRIPT_SHARADA 99
+#define UCDN_SCRIPT_SORA_SOMPENG 100
+#define UCDN_SCRIPT_TAKRI 101
+#define UCDN_SCRIPT_UNKNOWN 102
+#define UCDN_SCRIPT_BASSA_VAH 103
+#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
+#define UCDN_SCRIPT_DUPLOYAN 105
+#define UCDN_SCRIPT_ELBASAN 106
+#define UCDN_SCRIPT_GRANTHA 107
+#define UCDN_SCRIPT_KHOJKI 108
+#define UCDN_SCRIPT_KHUDAWADI 109
+#define UCDN_SCRIPT_LINEAR_A 110
+#define UCDN_SCRIPT_MAHAJANI 111
+#define UCDN_SCRIPT_MANICHAEAN 112
+#define UCDN_SCRIPT_MENDE_KIKAKUI 113
+#define UCDN_SCRIPT_MODI 114
+#define UCDN_SCRIPT_MRO 115
+#define UCDN_SCRIPT_NABATAEAN 116
+#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
+#define UCDN_SCRIPT_OLD_PERMIC 118
+#define UCDN_SCRIPT_PAHAWH_HMONG 119
+#define UCDN_SCRIPT_PALMYRENE 120
+#define UCDN_SCRIPT_PAU_CIN_HAU 121
+#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
+#define UCDN_SCRIPT_SIDDHAM 123
+#define UCDN_SCRIPT_TIRHUTA 124
+#define UCDN_SCRIPT_WARANG_CITI 125
+
+#define UCDN_GENERAL_CATEGORY_CC 0
+#define UCDN_GENERAL_CATEGORY_CF 1
+#define UCDN_GENERAL_CATEGORY_CN 2
+#define UCDN_GENERAL_CATEGORY_CO 3
+#define UCDN_GENERAL_CATEGORY_CS 4
+#define UCDN_GENERAL_CATEGORY_LL 5
+#define UCDN_GENERAL_CATEGORY_LM 6
+#define UCDN_GENERAL_CATEGORY_LO 7
+#define UCDN_GENERAL_CATEGORY_LT 8
+#define UCDN_GENERAL_CATEGORY_LU 9
+#define UCDN_GENERAL_CATEGORY_MC 10
+#define UCDN_GENERAL_CATEGORY_ME 11
+#define UCDN_GENERAL_CATEGORY_MN 12
+#define UCDN_GENERAL_CATEGORY_ND 13
+#define UCDN_GENERAL_CATEGORY_NL 14
+#define UCDN_GENERAL_CATEGORY_NO 15
+#define UCDN_GENERAL_CATEGORY_PC 16
+#define UCDN_GENERAL_CATEGORY_PD 17
+#define UCDN_GENERAL_CATEGORY_PE 18
+#define UCDN_GENERAL_CATEGORY_PF 19
+#define UCDN_GENERAL_CATEGORY_PI 20
+#define UCDN_GENERAL_CATEGORY_PO 21
+#define UCDN_GENERAL_CATEGORY_PS 22
+#define UCDN_GENERAL_CATEGORY_SC 23
+#define UCDN_GENERAL_CATEGORY_SK 24
+#define UCDN_GENERAL_CATEGORY_SM 25
+#define UCDN_GENERAL_CATEGORY_SO 26
+#define UCDN_GENERAL_CATEGORY_ZL 27
+#define UCDN_GENERAL_CATEGORY_ZP 28
+#define UCDN_GENERAL_CATEGORY_ZS 29
+
+#define UCDN_BIDI_CLASS_L 0
+#define UCDN_BIDI_CLASS_LRE 1
+#define UCDN_BIDI_CLASS_LRO 2
+#define UCDN_BIDI_CLASS_R 3
+#define UCDN_BIDI_CLASS_AL 4
+#define UCDN_BIDI_CLASS_RLE 5
+#define UCDN_BIDI_CLASS_RLO 6
+#define UCDN_BIDI_CLASS_PDF 7
+#define UCDN_BIDI_CLASS_EN 8
+#define UCDN_BIDI_CLASS_ES 9
+#define UCDN_BIDI_CLASS_ET 10
+#define UCDN_BIDI_CLASS_AN 11
+#define UCDN_BIDI_CLASS_CS 12
+#define UCDN_BIDI_CLASS_NSM 13
+#define UCDN_BIDI_CLASS_BN 14
+#define UCDN_BIDI_CLASS_B 15
+#define UCDN_BIDI_CLASS_S 16
+#define UCDN_BIDI_CLASS_WS 17
+#define UCDN_BIDI_CLASS_ON 18
+#define UCDN_BIDI_CLASS_LRI 19
+#define UCDN_BIDI_CLASS_RLI 20
+#define UCDN_BIDI_CLASS_FSI 21
+#define UCDN_BIDI_CLASS_PDI 22
+
+/* index tables for the database records */
+#define SHIFT1 5
+#define SHIFT2 3
+static const unsigned char index0[] = {
+    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, 35, 36, 37, 38, 
+    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 53, 53, 53, 
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 
+    53, 53, 54, 52, 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, 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, 53, 53, 53, 53, 53, 53, 53, 53, 
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 55, 56, 57, 57, 57, 58, 
+    59, 60, 61, 62, 63, 64, 65, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 
+    67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 
+    67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 68, 69, 70, 70, 
+    71, 69, 70, 70, 72, 73, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 76, 77, 78, 79, 80, 81, 
+    82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 70, 96, 70, 97, 
+    98, 99, 100, 101, 102, 103, 70, 104, 70, 105, 70, 70, 70, 70, 70, 106, 
+    106, 106, 107, 108, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 109, 109, 
+    109, 109, 110, 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, 111, 111, 112, 113, 70, 70, 70, 114, 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, 70, 70, 70, 70, 70, 
+    70, 70, 115, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 116, 70, 70, 70, 
+    70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 117, 118, 
+    119, 120, 121, 122, 123, 124, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 
+    70, 70, 70, 70, 70, 125, 70, 70, 70, 70, 70, 126, 70, 127, 128, 129, 130, 
+    131, 132, 133, 134, 135, 70, 70, 70, 70, 70, 70, 70, 52, 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, 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, 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, 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, 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, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 136, 
+    52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 137, 138, 
+    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, 
+    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, 
+    139, 139, 139, 139, 139, 139, 139, 76, 76, 140, 139, 139, 139, 139, 141, 
+    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, 
+    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, 
+    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, 
+    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, 
+    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, 
+    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, 
+    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, 
+    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, 
+    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, 
+    139, 139, 139, 141, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 142, 143, 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, 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, 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, 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, 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, 73, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 144, 73, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 
+    74, 74, 144, 
+};
+
+static const unsigned short index1[] = {
+    0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 0, 0, 0, 14, 15, 
+    16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 31, 32, 
+    33, 34, 35, 27, 30, 29, 27, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 
+    47, 48, 27, 27, 49, 27, 27, 27, 27, 27, 27, 27, 50, 51, 52, 27, 53, 54, 
+    53, 54, 54, 54, 54, 54, 55, 54, 54, 54, 56, 57, 58, 59, 60, 61, 62, 63, 
+    64, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 65, 77, 78, 
+    79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 
+    97, 97, 97, 97, 98, 98, 98, 98, 99, 100, 101, 101, 101, 101, 102, 103, 
+    101, 101, 101, 101, 101, 101, 104, 105, 101, 101, 101, 101, 101, 101, 
+    101, 101, 101, 101, 101, 101, 106, 107, 107, 107, 108, 109, 110, 111, 
+    111, 111, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 121, 
+    121, 122, 123, 120, 124, 125, 126, 127, 128, 128, 128, 128, 129, 130, 
+    131, 132, 133, 134, 135, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 145, 145, 
+    146, 147, 148, 149, 128, 128, 128, 128, 128, 128, 150, 150, 150, 150, 
+    151, 152, 153, 120, 154, 155, 156, 156, 156, 157, 158, 159, 160, 160, 
+    161, 162, 163, 164, 165, 166, 167, 167, 167, 168, 120, 120, 120, 120, 
+    120, 120, 120, 120, 128, 128, 169, 120, 120, 120, 120, 120, 170, 171, 
+    172, 173, 174, 175, 175, 175, 175, 175, 175, 176, 177, 178, 179, 175, 
+    180, 181, 182, 175, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 
+    192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204, 
+    205, 206, 207, 208, 209, 210, 211, 120, 212, 213, 214, 215, 215, 216, 
+    217, 218, 219, 220, 221, 120, 222, 223, 224, 120, 225, 226, 227, 228, 
+    228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 120, 239, 240, 
+    241, 242, 243, 240, 244, 245, 246, 247, 248, 120, 249, 250, 251, 252, 
+    253, 254, 255, 256, 256, 255, 256, 257, 258, 259, 260, 261, 262, 263, 
+    120, 264, 265, 266, 267, 268, 268, 267, 269, 270, 271, 272, 273, 274, 
+    275, 276, 277, 120, 278, 279, 280, 281, 281, 281, 281, 282, 283, 284, 
+    285, 120, 286, 287, 288, 289, 290, 291, 292, 293, 291, 291, 294, 295, 
+    292, 296, 297, 298, 299, 300, 301, 120, 302, 303, 303, 303, 303, 303, 
+    304, 305, 306, 307, 308, 309, 120, 120, 120, 120, 310, 311, 312, 313, 
+    314, 315, 316, 317, 318, 319, 320, 321, 120, 120, 120, 120, 322, 323, 
+    324, 325, 326, 327, 328, 329, 330, 331, 330, 330, 330, 332, 333, 334, 
+    335, 336, 337, 338, 337, 337, 337, 339, 340, 341, 342, 343, 120, 120, 
+    120, 120, 344, 344, 344, 344, 344, 345, 346, 347, 348, 349, 350, 351, 
+    352, 353, 354, 344, 355, 356, 348, 357, 358, 358, 358, 358, 359, 360, 
+    361, 361, 361, 361, 361, 362, 363, 363, 363, 363, 363, 363, 363, 363, 
+    363, 363, 363, 363, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 
+    364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 365, 365, 365, 365, 
+    365, 365, 365, 365, 365, 366, 367, 366, 365, 365, 365, 365, 365, 366, 
+    365, 365, 365, 365, 366, 367, 366, 365, 367, 365, 365, 365, 365, 365, 
+    365, 365, 366, 365, 365, 365, 365, 365, 365, 365, 365, 368, 369, 370, 
+    371, 372, 365, 365, 373, 374, 375, 375, 375, 375, 375, 375, 375, 375, 
+    375, 375, 376, 120, 377, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
+    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
+    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
+    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
+    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 
+    378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 379, 378, 378, 
+    380, 381, 381, 382, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 
+    385, 386, 387, 388, 389, 120, 390, 390, 391, 120, 392, 392, 393, 120, 
+    394, 395, 396, 120, 397, 397, 397, 397, 397, 397, 398, 399, 400, 401, 
+    402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 412, 412, 412, 
+    413, 412, 412, 412, 412, 412, 412, 120, 412, 412, 412, 412, 412, 414, 
+    378, 378, 378, 378, 378, 378, 378, 378, 415, 120, 416, 416, 416, 417, 
+    418, 419, 420, 421, 422, 423, 424, 424, 424, 425, 426, 120, 427, 427, 
+    427, 427, 427, 428, 429, 429, 430, 431, 432, 433, 434, 434, 434, 434, 
+    435, 435, 436, 437, 438, 438, 438, 438, 438, 438, 439, 440, 441, 442, 
+    443, 444, 445, 446, 445, 446, 447, 448, 449, 450, 120, 120, 120, 120, 
+    120, 120, 120, 120, 451, 452, 452, 452, 452, 452, 453, 454, 455, 456, 
+    457, 458, 459, 460, 461, 462, 463, 464, 464, 464, 465, 466, 467, 468, 
+    469, 469, 469, 469, 470, 471, 472, 473, 474, 474, 474, 474, 475, 476, 
+    477, 478, 479, 480, 481, 482, 483, 483, 483, 484, 120, 120, 120, 120, 
+    120, 120, 120, 120, 485, 120, 486, 487, 488, 489, 490, 491, 54, 54, 54, 
+    54, 492, 493, 56, 56, 56, 56, 56, 494, 495, 496, 54, 497, 54, 54, 54, 
+    498, 56, 56, 56, 499, 500, 501, 502, 503, 503, 503, 504, 505, 27, 27, 27, 
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 506, 507, 27, 
+    27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 508, 509, 510, 511, 508, 509, 
+    508, 509, 510, 511, 508, 512, 508, 509, 508, 510, 508, 513, 508, 513, 
+    508, 513, 514, 515, 516, 517, 518, 519, 508, 520, 521, 522, 523, 524, 
+    525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 
+    539, 540, 56, 541, 542, 543, 542, 544, 120, 120, 545, 546, 547, 548, 549, 
+    120, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 
+    563, 562, 564, 565, 566, 567, 568, 569, 570, 571, 572, 571, 573, 574, 
+    571, 575, 571, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 
+    587, 588, 589, 590, 591, 586, 586, 592, 593, 594, 595, 596, 586, 586, 
+    597, 577, 598, 599, 586, 586, 600, 586, 586, 571, 601, 602, 571, 603, 
+    604, 605, 606, 606, 606, 606, 606, 606, 606, 606, 607, 571, 571, 608, 
+    609, 577, 577, 610, 571, 571, 571, 571, 576, 611, 571, 571, 612, 571, 
+    571, 571, 571, 613, 120, 120, 120, 571, 612, 120, 120, 614, 614, 614, 
+    614, 614, 615, 615, 616, 617, 617, 617, 617, 617, 617, 617, 617, 617, 
+    618, 614, 614, 619, 619, 619, 619, 619, 619, 619, 619, 619, 620, 619, 
+    619, 619, 619, 620, 571, 619, 619, 621, 571, 622, 572, 623, 624, 625, 
+    626, 572, 571, 621, 575, 571, 577, 627, 628, 624, 629, 571, 571, 571, 
+    571, 630, 571, 571, 571, 631, 632, 571, 571, 571, 571, 571, 633, 571, 
+    634, 571, 633, 635, 636, 619, 619, 637, 619, 619, 619, 571, 571, 571, 
+    571, 571, 571, 571, 638, 571, 571, 575, 571, 571, 639, 640, 614, 641, 
+    641, 642, 571, 571, 571, 571, 571, 643, 644, 645, 646, 647, 648, 577, 
+    577, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 
+    649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 
+    649, 649, 649, 649, 649, 577, 577, 577, 577, 577, 577, 577, 577, 577, 
+    577, 577, 577, 577, 577, 577, 577, 650, 651, 651, 652, 586, 586, 577, 
+    653, 600, 654, 655, 656, 657, 658, 659, 660, 577, 661, 586, 662, 663, 
+    664, 665, 646, 577, 577, 589, 653, 665, 666, 667, 668, 586, 586, 586, 
+    586, 669, 670, 586, 586, 586, 586, 671, 672, 673, 646, 674, 675, 571, 
+    571, 571, 571, 571, 571, 577, 577, 676, 677, 678, 572, 571, 571, 679, 
+    571, 571, 571, 680, 571, 571, 571, 571, 681, 571, 682, 683, 120, 120, 
+    120, 120, 120, 684, 684, 684, 684, 684, 685, 686, 686, 686, 686, 686, 
+    687, 688, 689, 690, 691, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 
+    692, 693, 694, 695, 696, 696, 696, 696, 697, 698, 699, 699, 699, 699, 
+    699, 699, 699, 700, 701, 702, 365, 365, 367, 120, 367, 367, 367, 367, 
+    367, 367, 367, 367, 703, 703, 703, 703, 704, 705, 706, 707, 708, 709, 
+    532, 710, 711, 120, 120, 120, 120, 120, 120, 120, 712, 712, 712, 713, 
+    712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 714, 120, 712, 712, 
+    712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 
+    712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 715, 120, 120, 120, 
+    716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 727, 727, 
+    727, 727, 727, 727, 727, 727, 728, 729, 730, 731, 731, 731, 731, 731, 
+    731, 731, 731, 731, 731, 732, 733, 734, 734, 734, 734, 735, 736, 363, 
+    363, 363, 363, 363, 363, 363, 363, 363, 363, 737, 738, 739, 734, 734, 
+    734, 740, 716, 716, 716, 716, 717, 120, 731, 731, 741, 741, 741, 742, 
+    743, 744, 739, 739, 739, 745, 746, 747, 741, 741, 741, 748, 743, 744, 
+    739, 739, 739, 739, 749, 747, 739, 750, 751, 751, 751, 751, 751, 752, 
+    751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 739, 739, 739, 
+    753, 754, 739, 739, 739, 739, 739, 739, 739, 739, 739, 739, 739, 755, 
+    739, 739, 739, 753, 756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 758, 759, 571, 571, 571, 571, 571, 571, 
+    571, 571, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 760, 
+    759, 759, 759, 759, 759, 759, 761, 761, 762, 761, 761, 761, 761, 761, 
+    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
+    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
+    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
+    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
+    761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
+    761, 761, 761, 763, 764, 764, 764, 764, 764, 764, 765, 120, 766, 766, 
+    766, 766, 766, 767, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 
+    768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 
+    768, 768, 768, 768, 768, 768, 768, 768, 768, 769, 768, 768, 770, 771, 
+    120, 120, 101, 101, 101, 101, 101, 772, 773, 774, 101, 101, 101, 775, 
+    776, 776, 776, 776, 776, 776, 776, 776, 777, 778, 779, 120, 64, 64, 780, 
+    781, 782, 27, 783, 27, 27, 27, 27, 27, 27, 27, 784, 785, 27, 786, 787, 
+    27, 27, 788, 789, 120, 120, 120, 120, 120, 120, 120, 790, 791, 792, 793, 
+    794, 794, 795, 796, 797, 798, 799, 799, 799, 799, 799, 799, 800, 120, 
+    801, 802, 802, 802, 802, 802, 803, 804, 805, 806, 807, 808, 809, 809, 
+    810, 811, 812, 813, 814, 814, 815, 816, 817, 817, 818, 819, 820, 821, 
+    363, 363, 363, 822, 823, 824, 824, 824, 824, 824, 825, 826, 827, 828, 
+    829, 830, 831, 344, 348, 832, 833, 833, 833, 833, 833, 834, 835, 120, 
+    836, 837, 838, 839, 344, 344, 840, 841, 842, 842, 842, 842, 842, 842, 
+    843, 844, 845, 120, 120, 846, 847, 848, 849, 120, 850, 850, 850, 120, 
+    367, 367, 54, 54, 54, 54, 54, 851, 852, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 847, 847, 847, 847, 853, 854, 855, 856, 857, 
+    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
+    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
+    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
+    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
+    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 
+    858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 859, 
+    120, 364, 364, 860, 861, 364, 364, 364, 364, 364, 862, 863, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 864, 863, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 864, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 864, 865, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 867, 868, 868, 868, 
+    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
+    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
+    868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
+    869, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 
+    870, 759, 759, 759, 759, 871, 120, 872, 873, 121, 874, 875, 876, 877, 
+    121, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 878, 
+    879, 880, 120, 881, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 128, 128, 128, 128, 882, 120, 120, 128, 128, 128, 128, 128, 
+    128, 128, 128, 883, 128, 128, 128, 128, 128, 128, 120, 120, 120, 120, 
+    120, 128, 884, 885, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 
+    895, 896, 897, 898, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
+    128, 128, 128, 128, 128, 128, 899, 900, 901, 902, 903, 904, 905, 905, 
+    906, 907, 908, 908, 909, 910, 911, 912, 911, 911, 911, 911, 913, 914, 
+    914, 914, 915, 916, 916, 916, 917, 918, 919, 120, 920, 921, 922, 921, 
+    921, 923, 921, 921, 924, 921, 925, 921, 925, 120, 120, 120, 120, 921, 
+    921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 
+    926, 927, 928, 928, 928, 928, 928, 929, 606, 930, 930, 930, 930, 930, 
+    930, 931, 932, 933, 934, 571, 935, 936, 120, 120, 120, 120, 120, 606, 
+    606, 606, 606, 606, 937, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 938, 938, 938, 939, 940, 940, 940, 
+    940, 940, 940, 941, 120, 942, 943, 943, 944, 945, 945, 945, 945, 946, 
+    120, 947, 947, 948, 949, 950, 950, 950, 950, 951, 952, 953, 953, 953, 
+    954, 955, 955, 955, 955, 956, 955, 957, 120, 120, 120, 120, 120, 958, 
+    958, 958, 958, 958, 959, 959, 959, 959, 959, 960, 960, 960, 960, 960, 
+    960, 961, 961, 961, 962, 963, 964, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 965, 965, 965, 965, 965, 120, 966, 966, 966, 966, 966, 
+    966, 967, 968, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 969, 969, 969, 969, 969, 969, 969, 
+    969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 
+    969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 
+    969, 969, 969, 970, 120, 969, 969, 971, 120, 969, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 972, 973, 974, 974, 974, 974, 975, 976, 977, 977, 978, 979, 980, 
+    980, 981, 982, 983, 983, 983, 984, 985, 986, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 987, 987, 988, 989, 990, 990, 990, 991, 120, 
+    120, 120, 120, 120, 120, 120, 120, 992, 992, 992, 992, 993, 993, 993, 
+    994, 120, 120, 120, 120, 120, 120, 120, 120, 995, 996, 997, 998, 999, 
+    999, 1000, 1001, 1002, 120, 1003, 1004, 1005, 1005, 1005, 1006, 1007, 
+    1007, 1007, 1008, 120, 120, 120, 120, 1009, 1010, 1009, 1009, 1011, 1012, 
+    1013, 120, 1014, 1014, 1014, 1014, 1014, 1014, 1015, 1016, 1017, 1017, 
+    1018, 1019, 1020, 1020, 1021, 1022, 1023, 1023, 1024, 1025, 120, 1026, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1027, 1027, 1027, 1027, 
+    1027, 1027, 1027, 1027, 1027, 1028, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1029, 
+    1029, 1029, 1030, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 1031, 1032, 1032, 1032, 1032, 1032, 1032, 1033, 
+    1034, 1035, 1036, 1037, 1038, 1039, 120, 1040, 1041, 1042, 1042, 1042, 
+    1042, 1042, 1043, 1044, 1045, 120, 1046, 1046, 1046, 1047, 1048, 1049, 
+    1050, 1051, 1051, 1051, 1052, 1053, 1054, 1055, 1056, 120, 1057, 1057, 
+    1057, 1057, 1058, 120, 1059, 1060, 1060, 1060, 1060, 1060, 1061, 1062, 
+    1063, 1064, 1065, 1066, 1067, 1068, 1069, 120, 1070, 1070, 1071, 1070, 
+    1070, 1072, 1073, 1074, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 1075, 1075, 1075, 1075, 1075, 1076, 1077, 1078, 1079, 
+    1080, 1081, 1082, 1083, 1084, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 
+    1091, 1092, 1093, 1093, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 1094, 1094, 1094, 1094, 
+    1094, 1094, 1095, 1096, 1097, 120, 1098, 1099, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 1100, 1100, 1100, 1100, 1100, 1101, 1102, 1103, 1104, 1105, 120, 
+    120, 120, 120, 120, 120, 1106, 1106, 1106, 1106, 1106, 1106, 1107, 1108, 
+    1109, 120, 1110, 1111, 120, 120, 120, 120, 1112, 1112, 1112, 1112, 1112, 
+    1113, 1114, 120, 1115, 1116, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 1117, 1117, 1117, 1117, 1118, 1118, 1118, 1118, 1119, 
+    1120, 1121, 1122, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1123, 
+    1123, 1123, 1123, 1123, 1123, 1123, 1124, 1125, 1125, 1125, 1125, 1125, 
+    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 
+    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 
+    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 
+    1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1126, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1127, 1127, 1127, 
+    1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1128, 1129, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 
+    1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 
+    1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 
+    1130, 1130, 1130, 1130, 1131, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
+    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
+    776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 
+    776, 1132, 1133, 1133, 1133, 1134, 1135, 1136, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 1137, 1137, 1137, 1138, 1139, 120, 
+    1140, 1140, 1140, 1140, 1140, 1140, 1141, 1142, 1143, 120, 1144, 1145, 
+    1146, 1140, 1140, 1147, 1140, 1140, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 1148, 1148, 1148, 1148, 1148, 1148, 
+    1148, 1148, 1149, 120, 1150, 1151, 1151, 1151, 1151, 1152, 120, 1153, 
+    1154, 1155, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    1156, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 
+    1157, 1157, 1157, 1157, 1158, 1157, 1159, 1157, 1160, 1157, 1161, 1162, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 606, 606, 606, 
+    606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 
+    606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 1163, 
+    120, 606, 606, 606, 606, 1164, 1165, 606, 606, 606, 606, 606, 606, 1166, 
+    1167, 1168, 1169, 1170, 1171, 606, 606, 606, 1172, 606, 606, 606, 606, 
+    606, 1163, 120, 120, 120, 120, 933, 933, 933, 933, 933, 933, 933, 933, 
+    1173, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 571, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 613, 120, 928, 928, 1174, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    1175, 1175, 1175, 1176, 1177, 1177, 1178, 1175, 1175, 1179, 1180, 1177, 
+    1177, 1175, 1175, 1175, 1176, 1177, 1177, 1181, 1182, 1183, 1179, 1184, 
+    1185, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1186, 1187, 1188, 1189, 
+    1177, 1177, 1177, 1190, 1191, 1192, 1193, 1177, 1177, 1178, 1175, 1175, 
+    1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1178, 1175, 
+    1175, 1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1178, 
+    1175, 1175, 1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 
+    1194, 1175, 1175, 1175, 1195, 1177, 1177, 1196, 1197, 1175, 1175, 1198, 
+    1177, 1177, 1199, 1178, 1175, 1175, 1200, 1177, 1177, 1201, 1202, 1175, 
+    1175, 1203, 1177, 1177, 1177, 1204, 1175, 1175, 1175, 1195, 1177, 1177, 
+    1196, 1205, 1206, 1206, 1206, 1206, 1206, 1206, 1207, 1207, 1207, 1207, 
+    1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 
+    1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1208, 1209, 1210, 120, 
+    120, 120, 120, 120, 1211, 128, 128, 128, 1212, 1213, 1214, 1215, 1216, 
+    1217, 1212, 1218, 1212, 1214, 1214, 1219, 128, 1220, 128, 1221, 1222, 
+    1220, 128, 1221, 120, 120, 120, 120, 120, 120, 1223, 120, 571, 571, 571, 
+    571, 571, 935, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
+    571, 935, 120, 571, 613, 1224, 571, 1224, 571, 1224, 571, 571, 571, 680, 
+    120, 615, 1225, 617, 617, 617, 1226, 617, 617, 617, 617, 617, 617, 617, 
+    1227, 617, 617, 617, 617, 617, 1228, 120, 120, 120, 120, 120, 120, 120, 
+    120, 1229, 606, 606, 606, 1230, 120, 739, 739, 739, 739, 739, 1231, 739, 
+    1232, 1233, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 120, 571, 571, 571, 571, 571, 
+    1234, 571, 571, 571, 571, 571, 571, 571, 571, 571, 680, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 613, 1235, 571, 571, 571, 571, 120, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
+    571, 571, 613, 571, 571, 571, 571, 571, 571, 571, 571, 571, 612, 571, 
+    571, 571, 571, 571, 1236, 571, 571, 571, 571, 1237, 571, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
+    571, 1238, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 
+    571, 571, 571, 571, 571, 120, 120, 571, 1234, 935, 120, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 935, 120, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 571, 1234, 120, 120, 120, 120, 
+    120, 571, 935, 571, 571, 571, 571, 571, 571, 571, 120, 571, 683, 571, 
+    571, 571, 571, 571, 120, 571, 571, 571, 680, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 1239, 759, 759, 759, 759, 759, 757, 757, 757, 757, 757, 
+    757, 760, 759, 756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 
+    757, 757, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 868, 868, 868, 869, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 
+    1240, 1241, 120, 120, 120, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 
+    1242, 1242, 1242, 1242, 1242, 120, 120, 120, 120, 120, 120, 120, 120, 
+    120, 120, 120, 120, 120, 120, 120, 120, 885, 885, 885, 885, 885, 885, 
+    885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 
+    885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 120, 120, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 
+    866, 1243, 
+};
+
+static const unsigned short index2[] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 4, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 2, 
+    5, 6, 6, 7, 8, 7, 6, 6, 9, 10, 6, 11, 12, 13, 12, 12, 14, 14, 14, 14, 14, 
+    14, 14, 14, 14, 14, 12, 6, 15, 16, 15, 6, 6, 17, 17, 17, 17, 17, 17, 17, 
+    17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 9, 6, 10, 18, 19, 18, 20, 20, 
+    20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 9, 16, 
+    10, 16, 1, 1, 1, 1, 1, 1, 3, 1, 1, 21, 22, 8, 8, 23, 8, 24, 22, 25, 26, 
+    27, 28, 16, 29, 30, 18, 31, 32, 33, 33, 25, 34, 22, 22, 25, 33, 27, 35, 
+    36, 36, 36, 22, 37, 37, 37, 37, 37, 37, 38, 37, 37, 37, 37, 37, 37, 37, 
+    37, 37, 38, 37, 37, 37, 37, 37, 37, 39, 38, 37, 37, 37, 37, 37, 38, 40, 
+    40, 40, 41, 41, 41, 41, 40, 41, 40, 40, 40, 41, 40, 40, 41, 41, 40, 41, 
+    40, 40, 41, 41, 41, 39, 40, 40, 40, 41, 40, 41, 40, 41, 37, 40, 37, 41, 
+    37, 41, 37, 41, 37, 41, 37, 41, 37, 41, 37, 41, 37, 40, 37, 40, 37, 41, 
+    37, 41, 37, 41, 37, 40, 37, 41, 37, 41, 37, 41, 37, 41, 37, 41, 38, 40, 
+    37, 40, 38, 40, 37, 41, 37, 41, 40, 37, 41, 37, 41, 37, 41, 38, 40, 38, 
+    40, 37, 40, 37, 41, 37, 40, 40, 38, 40, 37, 40, 37, 41, 37, 41, 38, 40, 
+    37, 41, 37, 41, 37, 37, 41, 37, 41, 37, 41, 41, 41, 37, 37, 41, 37, 41, 
+    37, 37, 41, 37, 37, 37, 41, 41, 37, 37, 37, 37, 41, 37, 37, 41, 37, 37, 
+    37, 41, 41, 41, 37, 37, 41, 37, 37, 41, 37, 41, 37, 41, 37, 37, 41, 37, 
+    41, 41, 37, 41, 37, 37, 41, 37, 37, 37, 41, 37, 41, 37, 37, 41, 41, 42, 
+    37, 41, 41, 41, 42, 42, 42, 42, 37, 43, 41, 37, 43, 41, 37, 43, 41, 37, 
+    40, 37, 40, 37, 40, 37, 40, 37, 40, 37, 40, 37, 40, 37, 40, 41, 37, 41, 
+    41, 37, 43, 41, 37, 41, 37, 37, 37, 41, 37, 41, 41, 41, 41, 41, 41, 41, 
+    37, 37, 41, 37, 37, 41, 41, 37, 41, 37, 37, 37, 37, 41, 41, 40, 41, 41, 
+    41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 41, 
+    41, 41, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 46, 46, 46, 46, 46, 
+    46, 46, 47, 47, 25, 47, 45, 48, 45, 48, 48, 48, 45, 48, 45, 45, 49, 46, 
+    47, 47, 47, 47, 47, 47, 25, 25, 25, 25, 47, 25, 47, 25, 44, 44, 44, 44, 
+    44, 47, 47, 47, 47, 47, 50, 50, 45, 47, 46, 47, 47, 47, 47, 47, 47, 47, 
+    47, 47, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53, 53, 
+    53, 53, 52, 54, 53, 53, 53, 53, 53, 55, 55, 53, 53, 53, 53, 55, 55, 53, 
+    53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 56, 56, 56, 56, 56, 53, 53, 53, 
+    53, 51, 51, 51, 51, 51, 51, 51, 51, 57, 51, 53, 53, 53, 51, 51, 51, 53, 
+    53, 58, 51, 51, 51, 53, 53, 53, 53, 51, 52, 53, 53, 51, 59, 60, 60, 59, 
+    60, 60, 59, 51, 51, 51, 51, 51, 61, 62, 61, 62, 45, 63, 61, 62, 64, 64, 
+    65, 62, 62, 62, 66, 61, 64, 64, 64, 64, 63, 47, 61, 66, 61, 61, 61, 64, 
+    61, 64, 61, 61, 62, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 
+    67, 67, 67, 67, 64, 67, 67, 67, 67, 67, 67, 67, 61, 61, 62, 62, 62, 62, 
+    62, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 
+    62, 68, 68, 68, 68, 68, 68, 68, 62, 62, 62, 62, 62, 61, 62, 62, 61, 61, 
+    61, 62, 62, 62, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 69, 70, 69, 70, 
+    69, 70, 69, 70, 69, 70, 69, 70, 69, 70, 62, 62, 62, 62, 61, 62, 71, 61, 
+    62, 61, 61, 62, 62, 61, 61, 61, 72, 73, 72, 72, 72, 72, 72, 72, 72, 72, 
+    72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, 
+    74, 74, 74, 74, 75, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 
+    75, 75, 72, 75, 72, 75, 72, 75, 72, 75, 72, 75, 76, 77, 77, 78, 78, 77, 
+    79, 79, 72, 75, 72, 75, 72, 75, 72, 72, 75, 72, 75, 72, 75, 72, 75, 72, 
+    75, 72, 75, 72, 75, 75, 64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 
+    80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 81, 82, 82, 82, 82, 
+    82, 82, 64, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 
+    64, 84, 85, 64, 64, 86, 86, 87, 64, 88, 89, 89, 89, 89, 88, 89, 89, 89, 
+    90, 88, 89, 89, 89, 89, 89, 89, 88, 88, 88, 88, 88, 88, 89, 89, 88, 89, 
+    89, 90, 91, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 101, 102, 103, 
+    104, 105, 106, 107, 108, 109, 107, 89, 88, 107, 100, 64, 64, 64, 64, 64, 
+    64, 64, 64, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 64, 
+    64, 64, 64, 64, 110, 110, 110, 107, 107, 64, 64, 64, 111, 111, 111, 111, 
+    111, 112, 113, 113, 114, 115, 115, 116, 117, 118, 119, 119, 120, 120, 
+    120, 120, 120, 120, 120, 120, 121, 122, 123, 124, 125, 64, 118, 124, 126, 
+    126, 126, 126, 126, 126, 126, 126, 127, 126, 126, 126, 126, 126, 126, 
+    126, 126, 126, 126, 128, 129, 130, 131, 132, 133, 134, 135, 78, 78, 136, 
+    137, 120, 120, 120, 120, 120, 137, 120, 120, 137, 138, 138, 138, 138, 
+    138, 138, 138, 138, 138, 138, 115, 139, 139, 118, 126, 126, 140, 126, 
+    126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 118, 126, 120, 120, 
+    120, 120, 120, 120, 120, 112, 119, 120, 120, 120, 120, 137, 120, 141, 
+    141, 120, 120, 119, 137, 120, 120, 137, 126, 126, 142, 142, 142, 142, 
+    142, 142, 142, 142, 142, 142, 126, 126, 126, 143, 143, 126, 144, 144, 
+    144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 64, 145, 146, 
+    147, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 
+    146, 148, 149, 148, 148, 149, 148, 148, 149, 149, 149, 148, 149, 149, 
+    148, 149, 148, 148, 148, 149, 148, 149, 148, 149, 148, 149, 148, 148, 64, 
+    64, 146, 146, 146, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 
+    150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 
+    150, 64, 64, 64, 64, 64, 64, 152, 152, 152, 152, 152, 152, 152, 152, 152, 
+    152, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 
+    153, 153, 153, 153, 154, 154, 154, 154, 154, 154, 154, 155, 154, 156, 
+    156, 157, 158, 158, 158, 156, 64, 64, 64, 64, 64, 159, 159, 159, 159, 
+    159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 160, 160, 160, 160, 
+    161, 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 160, 160, 160, 
+    161, 160, 160, 160, 160, 160, 64, 64, 162, 162, 162, 162, 162, 162, 162, 
+    162, 162, 162, 162, 162, 162, 162, 162, 64, 163, 163, 163, 163, 163, 163, 
+    163, 163, 163, 164, 164, 164, 64, 64, 165, 64, 126, 126, 126, 64, 64, 64, 
+    64, 64, 64, 64, 64, 64, 120, 120, 137, 120, 120, 137, 120, 120, 120, 137, 
+    137, 137, 166, 167, 168, 120, 120, 120, 137, 120, 120, 137, 137, 120, 
+    120, 120, 120, 120, 169, 169, 169, 170, 171, 171, 171, 171, 171, 171, 
+    171, 171, 171, 171, 171, 171, 171, 171, 169, 170, 172, 171, 170, 170, 
+    170, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 173, 
+    170, 170, 171, 78, 136, 174, 174, 169, 169, 169, 171, 171, 169, 169, 84, 
+    84, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 177, 171, 171, 
+    171, 171, 171, 171, 178, 179, 180, 180, 64, 178, 178, 178, 178, 178, 178, 
+    178, 178, 64, 64, 178, 178, 64, 64, 178, 178, 178, 178, 178, 178, 178, 
+    178, 178, 178, 178, 178, 178, 178, 64, 178, 178, 178, 178, 178, 178, 178, 
+    64, 178, 64, 64, 64, 178, 178, 178, 178, 64, 64, 181, 178, 180, 180, 180, 
+    179, 179, 179, 179, 64, 64, 180, 180, 64, 64, 180, 180, 182, 178, 64, 64, 
+    64, 64, 64, 64, 64, 64, 180, 64, 64, 64, 64, 178, 178, 64, 178, 178, 178, 
+    179, 179, 64, 64, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 178, 
+    178, 184, 184, 185, 185, 185, 185, 185, 185, 186, 184, 64, 64, 64, 64, 
+    64, 187, 187, 188, 64, 189, 189, 189, 189, 189, 189, 64, 64, 64, 64, 189, 
+    189, 64, 64, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 
+    189, 189, 64, 189, 189, 189, 189, 189, 189, 189, 64, 189, 189, 64, 189, 
+    189, 64, 189, 189, 64, 64, 190, 64, 188, 188, 188, 187, 187, 64, 64, 64, 
+    64, 187, 187, 64, 64, 187, 187, 191, 64, 64, 64, 187, 64, 64, 64, 64, 64, 
+    64, 64, 189, 189, 189, 189, 64, 189, 64, 64, 64, 64, 64, 64, 64, 192, 
+    192, 192, 192, 192, 192, 192, 192, 192, 192, 187, 187, 189, 189, 189, 
+    187, 64, 64, 64, 193, 193, 194, 64, 195, 195, 195, 195, 195, 195, 195, 
+    195, 195, 64, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 195, 
+    195, 195, 195, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 64, 
+    195, 195, 64, 195, 195, 195, 195, 195, 64, 64, 196, 195, 194, 194, 194, 
+    193, 193, 193, 193, 193, 64, 193, 193, 194, 64, 194, 194, 197, 64, 64, 
+    195, 64, 64, 64, 64, 64, 64, 64, 195, 195, 193, 193, 64, 64, 198, 198, 
+    198, 198, 198, 198, 198, 198, 198, 198, 199, 200, 64, 64, 64, 64, 64, 64, 
+    64, 201, 202, 202, 64, 203, 203, 203, 203, 203, 203, 203, 203, 64, 64, 
+    203, 203, 64, 64, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 
+    203, 203, 203, 64, 203, 203, 203, 203, 203, 203, 203, 64, 203, 203, 64, 
+    203, 203, 203, 203, 203, 64, 64, 204, 203, 202, 201, 202, 201, 201, 201, 
+    201, 64, 64, 202, 202, 64, 64, 202, 202, 205, 64, 64, 64, 64, 64, 64, 64, 
+    64, 201, 202, 64, 64, 64, 64, 203, 203, 64, 203, 203, 203, 201, 201, 64, 
+    64, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 203, 208, 208, 
+    208, 208, 208, 208, 64, 64, 209, 210, 64, 210, 210, 210, 210, 210, 210, 
+    64, 64, 64, 210, 210, 210, 64, 210, 210, 210, 210, 64, 64, 64, 210, 210, 
+    64, 210, 64, 210, 210, 64, 64, 64, 210, 210, 64, 64, 64, 210, 210, 210, 
+    210, 210, 210, 210, 210, 210, 210, 64, 64, 64, 64, 211, 211, 209, 211, 
+    211, 64, 64, 64, 211, 211, 211, 64, 211, 211, 211, 212, 64, 64, 210, 64, 
+    64, 64, 64, 64, 64, 211, 64, 64, 64, 64, 64, 64, 213, 213, 213, 213, 213, 
+    213, 213, 213, 213, 213, 214, 214, 214, 215, 215, 215, 215, 215, 215, 
+    216, 215, 64, 64, 64, 64, 64, 217, 218, 218, 218, 64, 219, 219, 219, 219, 
+    219, 219, 219, 219, 64, 219, 219, 219, 64, 219, 219, 219, 219, 219, 219, 
+    219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 64, 64, 64, 219, 217, 
+    217, 217, 218, 218, 218, 218, 64, 217, 217, 217, 64, 217, 217, 217, 220, 
+    64, 64, 64, 64, 64, 64, 64, 221, 222, 64, 219, 219, 64, 64, 64, 64, 64, 
+    64, 219, 219, 217, 217, 64, 64, 223, 223, 223, 223, 223, 223, 223, 223, 
+    223, 223, 224, 224, 224, 224, 224, 224, 224, 225, 64, 226, 227, 227, 64, 
+    228, 228, 228, 228, 228, 228, 228, 228, 64, 228, 228, 228, 64, 228, 228, 
+    228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 
+    228, 228, 64, 228, 228, 228, 228, 228, 64, 64, 229, 228, 227, 230, 227, 
+    227, 227, 227, 227, 64, 230, 227, 227, 64, 227, 227, 226, 231, 64, 64, 
+    64, 64, 64, 64, 64, 227, 227, 64, 64, 64, 64, 64, 64, 64, 228, 64, 228, 
+    228, 226, 226, 64, 64, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 
+    64, 228, 228, 64, 64, 64, 64, 64, 64, 233, 234, 234, 64, 235, 235, 235, 
+    235, 235, 235, 235, 235, 64, 235, 235, 235, 64, 235, 235, 235, 235, 235, 
+    235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 64, 64, 235, 
+    234, 234, 234, 233, 233, 233, 233, 64, 234, 234, 234, 64, 234, 234, 234, 
+    236, 235, 64, 64, 64, 64, 64, 64, 64, 64, 234, 235, 235, 233, 233, 64, 
+    64, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 238, 
+    238, 238, 64, 64, 64, 239, 235, 235, 235, 235, 235, 235, 64, 64, 240, 
+    240, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 
+    241, 241, 241, 241, 241, 64, 64, 64, 241, 241, 241, 241, 241, 241, 241, 
+    241, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 64, 241, 64, 64, 
+    64, 64, 242, 64, 64, 64, 64, 240, 240, 240, 243, 243, 243, 64, 243, 64, 
+    240, 240, 240, 240, 240, 240, 240, 240, 64, 64, 64, 64, 64, 64, 244, 244, 
+    244, 244, 244, 244, 244, 244, 244, 244, 64, 64, 240, 240, 245, 64, 64, 
+    64, 64, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 
+    246, 246, 246, 247, 246, 246, 247, 247, 247, 247, 248, 248, 249, 64, 64, 
+    64, 64, 250, 246, 246, 246, 246, 246, 246, 251, 247, 252, 252, 252, 252, 
+    247, 247, 247, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 
+    253, 253, 64, 64, 64, 64, 64, 255, 255, 64, 255, 64, 64, 255, 255, 64, 
+    255, 64, 64, 255, 64, 64, 64, 64, 64, 64, 255, 255, 255, 255, 64, 255, 
+    255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 64, 255, 64, 255, 64, 
+    64, 255, 255, 64, 255, 255, 255, 255, 256, 255, 255, 256, 256, 256, 256, 
+    257, 257, 64, 256, 256, 255, 64, 64, 255, 255, 255, 255, 255, 64, 258, 
+    64, 259, 259, 259, 259, 256, 256, 64, 64, 260, 260, 260, 260, 260, 260, 
+    260, 260, 260, 260, 64, 64, 255, 255, 255, 255, 261, 262, 262, 262, 263, 
+    263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 
+    262, 263, 262, 262, 262, 264, 264, 262, 262, 262, 262, 262, 262, 265, 
+    265, 265, 265, 265, 265, 265, 265, 265, 265, 266, 266, 266, 266, 266, 
+    266, 266, 266, 266, 266, 262, 264, 262, 264, 262, 267, 268, 269, 268, 
+    269, 270, 270, 261, 261, 261, 261, 261, 261, 261, 261, 64, 261, 261, 261, 
+    261, 261, 261, 261, 261, 261, 261, 261, 261, 64, 64, 64, 64, 271, 272, 
+    273, 274, 273, 273, 273, 273, 273, 272, 272, 272, 272, 273, 270, 272, 
+    273, 275, 275, 276, 263, 275, 275, 261, 261, 261, 261, 261, 273, 273, 
+    273, 273, 273, 273, 273, 273, 273, 273, 273, 64, 273, 273, 273, 273, 273, 
+    273, 273, 273, 273, 273, 273, 273, 64, 262, 262, 262, 262, 262, 262, 262, 
+    262, 264, 262, 262, 262, 262, 262, 262, 64, 262, 262, 263, 263, 263, 263, 
+    263, 277, 277, 277, 277, 263, 263, 64, 64, 64, 64, 64, 278, 278, 278, 
+    278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 280, 280, 
+    279, 280, 280, 280, 280, 280, 281, 279, 282, 282, 279, 279, 280, 280, 
+    278, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284, 
+    284, 284, 284, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 278, 
+    278, 278, 278, 280, 280, 280, 278, 279, 279, 279, 278, 278, 279, 279, 
+    279, 279, 279, 279, 279, 278, 278, 278, 280, 280, 280, 280, 278, 278, 
+    278, 278, 278, 280, 279, 279, 280, 280, 279, 279, 279, 279, 279, 279, 
+    285, 278, 279, 283, 283, 279, 279, 279, 280, 286, 286, 287, 287, 287, 
+    287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 64, 287, 64, 64, 
+    64, 64, 64, 287, 64, 64, 288, 288, 288, 288, 288, 288, 288, 288, 288, 
+    288, 288, 84, 289, 288, 288, 288, 290, 290, 290, 290, 290, 290, 290, 290, 
+    291, 291, 291, 291, 291, 291, 291, 291, 292, 292, 292, 292, 292, 292, 
+    292, 292, 292, 64, 292, 292, 292, 292, 64, 64, 292, 292, 292, 292, 292, 
+    292, 292, 64, 292, 292, 292, 64, 64, 293, 293, 293, 294, 294, 294, 294, 
+    294, 294, 294, 294, 294, 295, 295, 295, 295, 295, 295, 295, 295, 295, 
+    295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 64, 64, 64, 296, 
+    296, 296, 296, 296, 296, 296, 296, 296, 296, 64, 64, 64, 64, 64, 64, 297, 
+    297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 64, 64, 64, 
+    298, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 
+    299, 299, 299, 299, 299, 299, 299, 300, 300, 299, 301, 302, 302, 302, 
+    302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 
+    302, 303, 304, 64, 64, 64, 305, 305, 305, 305, 305, 305, 305, 305, 305, 
+    305, 305, 84, 84, 84, 306, 306, 306, 305, 305, 305, 305, 305, 305, 305, 
+    305, 64, 64, 64, 64, 64, 64, 64, 307, 307, 307, 307, 307, 307, 307, 307, 
+    307, 307, 307, 307, 307, 64, 307, 307, 307, 307, 308, 308, 309, 64, 64, 
+    64, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 311, 311, 312, 84, 
+    84, 64, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 314, 314, 64, 
+    64, 64, 64, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 
+    315, 64, 315, 315, 315, 64, 316, 316, 64, 64, 64, 64, 317, 317, 317, 317, 
+    317, 317, 317, 317, 317, 317, 317, 317, 318, 318, 319, 318, 318, 318, 
+    318, 318, 318, 318, 319, 319, 319, 319, 319, 319, 319, 319, 318, 319, 
+    319, 318, 318, 318, 318, 318, 318, 318, 318, 318, 320, 318, 321, 321, 
+    321, 322, 321, 321, 321, 323, 317, 324, 64, 64, 325, 325, 325, 325, 325, 
+    325, 325, 325, 325, 325, 64, 64, 64, 64, 64, 64, 326, 326, 326, 326, 326, 
+    326, 326, 326, 326, 326, 64, 64, 64, 64, 64, 64, 327, 327, 66, 66, 327, 
+    66, 328, 327, 327, 327, 327, 329, 329, 329, 330, 64, 331, 331, 331, 331, 
+    331, 331, 331, 331, 331, 331, 64, 64, 64, 64, 64, 64, 332, 332, 332, 332, 
+    332, 332, 332, 332, 332, 332, 332, 333, 332, 332, 332, 332, 332, 334, 
+    332, 64, 64, 64, 64, 64, 299, 299, 299, 299, 299, 299, 64, 64, 335, 335, 
+    335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 64, 336, 
+    336, 336, 337, 337, 337, 337, 336, 336, 337, 337, 337, 64, 64, 64, 64, 
+    337, 337, 336, 337, 337, 337, 337, 337, 337, 338, 339, 340, 64, 64, 64, 
+    64, 341, 64, 64, 64, 342, 342, 343, 343, 343, 343, 343, 343, 343, 343, 
+    343, 343, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 
+    344, 344, 64, 64, 344, 344, 344, 344, 344, 64, 64, 64, 345, 345, 345, 
+    345, 345, 345, 345, 345, 345, 345, 345, 345, 64, 64, 64, 64, 346, 346, 
+    346, 346, 346, 346, 346, 346, 346, 345, 345, 345, 345, 345, 345, 345, 
+    346, 346, 64, 64, 64, 64, 64, 64, 347, 347, 347, 347, 347, 347, 347, 347, 
+    347, 347, 348, 64, 64, 64, 349, 349, 350, 350, 350, 350, 350, 350, 350, 
+    350, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 
+    351, 351, 352, 353, 354, 354, 355, 64, 64, 356, 356, 357, 357, 357, 357, 
+    357, 357, 357, 357, 357, 357, 357, 357, 357, 358, 359, 358, 359, 359, 
+    359, 359, 359, 359, 359, 64, 360, 358, 359, 358, 358, 359, 359, 359, 359, 
+    359, 359, 359, 359, 358, 358, 358, 358, 358, 358, 359, 359, 361, 361, 
+    361, 361, 361, 361, 361, 361, 64, 64, 362, 363, 363, 363, 363, 363, 363, 
+    363, 363, 363, 363, 64, 64, 64, 64, 64, 64, 364, 364, 364, 364, 364, 364, 
+    364, 365, 364, 364, 364, 364, 364, 364, 64, 64, 78, 78, 78, 78, 78, 136, 
+    136, 136, 136, 136, 136, 78, 78, 136, 366, 64, 367, 367, 367, 367, 368, 
+    369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 
+    369, 370, 368, 367, 367, 367, 367, 367, 368, 367, 368, 368, 368, 368, 
+    368, 367, 368, 371, 369, 369, 369, 369, 369, 369, 369, 64, 64, 64, 64, 
+    372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 373, 373, 373, 373, 
+    373, 373, 373, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 375, 
+    376, 375, 375, 375, 375, 375, 375, 375, 374, 374, 374, 374, 374, 374, 
+    374, 374, 374, 64, 64, 64, 377, 377, 378, 379, 379, 379, 379, 379, 379, 
+    379, 379, 379, 379, 379, 379, 379, 379, 378, 377, 377, 377, 377, 378, 
+    378, 377, 377, 380, 381, 377, 377, 379, 379, 382, 382, 382, 382, 382, 
+    382, 382, 382, 382, 382, 379, 379, 379, 379, 379, 379, 383, 383, 383, 
+    383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 385, 386, 
+    386, 385, 385, 385, 386, 385, 386, 386, 386, 387, 387, 64, 64, 64, 64, 
+    64, 64, 64, 64, 388, 388, 388, 388, 389, 389, 389, 389, 389, 389, 389, 
+    389, 389, 389, 389, 389, 390, 390, 390, 390, 390, 390, 390, 390, 391, 
+    391, 391, 391, 391, 391, 391, 391, 390, 390, 391, 392, 64, 64, 64, 393, 
+    393, 393, 393, 393, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 64, 
+    64, 64, 389, 389, 389, 395, 395, 395, 395, 395, 395, 395, 395, 395, 395, 
+    396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 
+    397, 397, 397, 397, 397, 397, 398, 398, 399, 399, 399, 399, 399, 399, 
+    399, 399, 78, 78, 78, 84, 400, 136, 136, 136, 136, 136, 78, 78, 136, 136, 
+    136, 136, 78, 401, 400, 400, 400, 400, 400, 400, 400, 402, 402, 402, 402, 
+    136, 402, 402, 402, 402, 401, 401, 78, 402, 402, 64, 78, 78, 64, 64, 64, 
+    64, 64, 64, 41, 41, 41, 41, 41, 41, 62, 62, 62, 62, 62, 75, 44, 44, 44, 
+    44, 44, 44, 44, 44, 44, 65, 65, 65, 65, 65, 44, 44, 44, 44, 65, 65, 65, 
+    65, 65, 41, 41, 41, 41, 41, 403, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 
+    44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 65, 78, 78, 136, 78, 78, 
+    78, 78, 78, 78, 78, 136, 78, 78, 404, 405, 136, 406, 78, 78, 78, 78, 78, 
+    78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 64, 64, 
+    64, 64, 64, 64, 407, 136, 78, 136, 37, 41, 37, 41, 37, 41, 41, 41, 41, 
+    41, 41, 41, 41, 41, 37, 41, 62, 62, 62, 62, 62, 62, 62, 62, 61, 61, 61, 
+    61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 64, 64, 61, 61, 61, 61, 61, 
+    61, 64, 64, 64, 61, 64, 61, 64, 61, 64, 61, 408, 408, 408, 408, 408, 408, 
+    408, 408, 62, 62, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 63, 62, 
+    63, 63, 63, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 63, 63, 63, 62, 
+    62, 62, 62, 64, 64, 62, 62, 61, 61, 61, 61, 64, 63, 63, 63, 61, 61, 61, 
+    61, 61, 63, 63, 63, 64, 64, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 
+    63, 63, 64, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 410, 
+    411, 411, 412, 413, 414, 415, 415, 414, 414, 414, 22, 66, 416, 417, 418, 
+    419, 416, 417, 418, 419, 22, 22, 22, 66, 22, 22, 22, 22, 420, 421, 422, 
+    423, 424, 425, 426, 21, 427, 428, 427, 427, 428, 22, 66, 66, 66, 28, 35, 
+    22, 66, 66, 22, 429, 429, 66, 66, 66, 430, 431, 432, 66, 66, 66, 66, 66, 
+    66, 66, 66, 66, 66, 66, 433, 66, 429, 66, 66, 66, 66, 66, 66, 66, 66, 66, 
+    66, 409, 410, 410, 410, 410, 410, 64, 434, 435, 436, 437, 410, 410, 410, 
+    410, 410, 410, 438, 44, 64, 64, 33, 438, 438, 438, 438, 438, 439, 439, 
+    433, 431, 432, 440, 438, 33, 33, 33, 33, 438, 438, 438, 438, 438, 439, 
+    439, 433, 431, 432, 64, 44, 44, 44, 44, 44, 64, 64, 64, 250, 250, 250, 
+    250, 250, 250, 250, 250, 250, 441, 250, 250, 23, 250, 250, 250, 250, 250, 
+    250, 250, 250, 250, 64, 64, 78, 78, 400, 400, 78, 78, 78, 78, 400, 400, 
+    400, 78, 78, 366, 366, 366, 366, 78, 366, 366, 366, 400, 400, 78, 136, 
+    78, 400, 400, 136, 136, 136, 136, 78, 64, 64, 64, 64, 64, 64, 64, 26, 26, 
+    442, 30, 26, 30, 26, 442, 26, 30, 34, 442, 442, 442, 34, 34, 442, 442, 
+    442, 443, 26, 442, 30, 26, 433, 442, 442, 442, 442, 442, 26, 26, 26, 30, 
+    30, 26, 442, 26, 67, 26, 442, 26, 37, 38, 442, 442, 444, 34, 442, 442, 
+    37, 442, 34, 402, 402, 402, 402, 34, 26, 26, 34, 34, 442, 442, 445, 433, 
+    433, 433, 433, 442, 34, 34, 34, 34, 26, 433, 26, 26, 41, 277, 446, 446, 
+    446, 36, 36, 446, 446, 446, 446, 446, 446, 36, 36, 36, 36, 446, 447, 447, 
+    447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 448, 448, 448, 448, 
+    447, 447, 448, 448, 448, 448, 448, 448, 448, 448, 448, 37, 41, 448, 448, 
+    448, 448, 36, 64, 64, 64, 64, 64, 64, 39, 39, 39, 39, 39, 30, 30, 30, 30, 
+    30, 433, 433, 26, 26, 26, 26, 433, 26, 26, 433, 26, 26, 433, 26, 26, 26, 
+    26, 26, 26, 26, 433, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 
+    26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 433, 433, 26, 26, 39, 26, 39, 26, 
+    26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 26, 26, 433, 433, 433, 
+    433, 433, 433, 433, 433, 433, 433, 433, 433, 39, 445, 449, 449, 445, 433, 
+    433, 39, 449, 445, 445, 449, 445, 445, 433, 39, 433, 449, 439, 450, 433, 
+    449, 445, 433, 433, 433, 449, 445, 445, 449, 39, 449, 449, 445, 445, 39, 
+    445, 39, 445, 39, 39, 39, 39, 449, 449, 445, 449, 445, 445, 445, 445, 
+    445, 39, 39, 39, 39, 433, 445, 433, 445, 449, 449, 445, 445, 445, 445, 
+    445, 445, 445, 445, 445, 445, 449, 445, 445, 445, 449, 433, 433, 433, 
+    433, 433, 449, 445, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433, 
+    433, 445, 449, 39, 445, 433, 449, 449, 449, 449, 445, 445, 449, 449, 433, 
+    433, 449, 449, 445, 445, 449, 449, 445, 445, 449, 449, 445, 445, 445, 
+    445, 445, 433, 433, 445, 445, 445, 445, 433, 433, 39, 433, 433, 445, 39, 
+    433, 433, 433, 433, 433, 433, 433, 433, 445, 445, 433, 39, 445, 445, 445, 
+    433, 433, 433, 433, 433, 445, 449, 433, 445, 445, 445, 445, 445, 433, 
+    433, 445, 445, 433, 433, 433, 433, 445, 445, 445, 445, 445, 445, 445, 
+    445, 433, 433, 431, 432, 431, 432, 26, 26, 26, 26, 26, 26, 30, 26, 26, 
+    26, 26, 26, 445, 445, 26, 26, 26, 26, 26, 26, 26, 451, 452, 26, 26, 26, 
+    26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, 
+    277, 277, 277, 277, 277, 26, 433, 26, 26, 26, 26, 26, 26, 26, 26, 277, 
+    26, 26, 26, 26, 26, 433, 433, 433, 433, 433, 433, 433, 433, 433, 26, 26, 
+    26, 26, 433, 433, 26, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 64, 64, 64, 
+    26, 26, 26, 26, 26, 26, 26, 64, 36, 36, 36, 36, 36, 36, 36, 36, 33, 33, 
+    33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 453, 453, 453, 453, 453, 453, 
+    453, 453, 453, 453, 453, 453, 453, 453, 446, 36, 36, 36, 36, 36, 30, 30, 
+    30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 26, 26, 26, 26, 26, 30, 30, 
+    30, 30, 26, 26, 30, 30, 26, 30, 30, 30, 30, 30, 26, 26, 30, 30, 26, 26, 
+    30, 39, 26, 26, 26, 26, 30, 30, 26, 26, 30, 39, 26, 26, 26, 26, 30, 30, 
+    30, 26, 26, 30, 26, 26, 30, 30, 26, 26, 26, 26, 26, 30, 30, 26, 26, 30, 
+    26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 30, 26, 30, 26, 30, 26, 30, 26, 
+    26, 26, 26, 26, 30, 30, 26, 30, 30, 30, 26, 30, 30, 30, 30, 26, 30, 30, 
+    26, 39, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 277, 26, 26, 26, 
+    26, 26, 26, 26, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 30, 30, 30, 
+    26, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 431, 432, 431, 
+    432, 431, 432, 431, 432, 431, 432, 431, 432, 431, 432, 36, 36, 446, 446, 
+    446, 446, 446, 446, 446, 446, 446, 446, 446, 446, 26, 26, 26, 26, 445, 
+    433, 433, 445, 445, 431, 432, 433, 445, 445, 433, 445, 445, 445, 433, 
+    433, 433, 433, 433, 445, 445, 445, 445, 433, 433, 433, 433, 433, 445, 
+    445, 445, 433, 433, 433, 445, 445, 445, 445, 9, 10, 9, 10, 9, 10, 9, 10, 
+    431, 432, 454, 454, 454, 454, 454, 454, 454, 454, 433, 433, 433, 431, 
+    432, 9, 10, 431, 432, 431, 432, 431, 432, 431, 432, 431, 432, 433, 433, 
+    445, 445, 445, 445, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433, 
+    445, 433, 433, 433, 433, 445, 445, 445, 445, 445, 433, 445, 445, 433, 
+    433, 431, 432, 431, 432, 445, 433, 433, 433, 433, 445, 433, 445, 445, 
+    445, 433, 433, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433, 433, 
+    433, 445, 445, 445, 445, 445, 445, 433, 433, 431, 432, 433, 433, 433, 
+    433, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 433, 445, 
+    445, 445, 445, 433, 433, 445, 433, 445, 433, 433, 445, 433, 445, 445, 
+    445, 445, 433, 433, 433, 433, 433, 445, 445, 433, 433, 433, 433, 445, 
+    445, 445, 445, 433, 445, 445, 433, 433, 445, 445, 433, 433, 433, 433, 
+    445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 433, 433, 445, 
+    445, 445, 445, 445, 445, 445, 445, 433, 445, 445, 445, 445, 445, 445, 
+    445, 445, 433, 433, 433, 433, 433, 445, 433, 445, 433, 433, 433, 445, 
+    445, 445, 445, 445, 433, 433, 433, 433, 445, 433, 433, 433, 445, 445, 
+    445, 445, 445, 433, 445, 433, 433, 433, 433, 433, 433, 433, 26, 26, 433, 
+    433, 433, 433, 433, 433, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 30, 26, 
+    26, 26, 26, 64, 64, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 26, 26, 64, 
+    64, 64, 26, 26, 26, 26, 64, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 64, 
+    64, 64, 64, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 
+    455, 455, 455, 64, 456, 456, 456, 456, 456, 456, 456, 456, 456, 456, 456, 
+    456, 456, 456, 456, 64, 37, 41, 37, 37, 37, 41, 41, 37, 41, 37, 41, 37, 
+    41, 37, 37, 37, 37, 41, 37, 41, 41, 37, 41, 41, 41, 41, 41, 41, 44, 44, 
+    37, 37, 69, 70, 69, 70, 70, 457, 457, 457, 457, 457, 457, 69, 70, 69, 70, 
+    458, 458, 458, 69, 70, 64, 64, 64, 64, 64, 459, 459, 459, 459, 460, 459, 
+    459, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 
+    461, 64, 461, 64, 64, 64, 64, 64, 461, 64, 64, 462, 462, 462, 462, 462, 
+    462, 462, 462, 64, 64, 64, 64, 64, 64, 64, 463, 464, 64, 64, 64, 64, 64, 
+    64, 64, 64, 64, 64, 64, 64, 64, 64, 465, 77, 77, 77, 77, 77, 77, 77, 77, 
+    66, 66, 28, 35, 28, 35, 66, 66, 66, 28, 35, 66, 28, 35, 66, 66, 66, 66, 
+    66, 66, 66, 66, 66, 415, 66, 66, 415, 66, 28, 35, 66, 66, 28, 35, 431, 
+    432, 431, 432, 431, 432, 431, 432, 66, 66, 66, 66, 66, 45, 66, 66, 415, 
+    415, 66, 66, 66, 66, 415, 66, 418, 64, 64, 64, 64, 64, 466, 466, 466, 
+    466, 466, 466, 466, 466, 466, 466, 64, 466, 466, 466, 466, 466, 466, 466, 
+    466, 466, 64, 64, 64, 64, 466, 466, 466, 466, 466, 466, 64, 64, 467, 467, 
+    467, 467, 467, 467, 467, 467, 467, 467, 467, 467, 64, 64, 64, 64, 468, 
+    469, 469, 469, 467, 470, 471, 472, 451, 452, 451, 452, 451, 452, 451, 
+    452, 451, 452, 467, 467, 451, 452, 451, 452, 451, 452, 451, 452, 473, 
+    474, 475, 475, 467, 472, 472, 472, 472, 472, 472, 472, 472, 472, 476, 
+    477, 478, 479, 480, 480, 473, 481, 481, 481, 481, 481, 467, 467, 472, 
+    472, 472, 470, 471, 469, 467, 26, 64, 482, 482, 482, 482, 482, 482, 482, 
+    482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 
+    482, 64, 64, 483, 483, 484, 484, 485, 485, 482, 473, 486, 486, 486, 486, 
+    486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 
+    469, 481, 487, 487, 486, 64, 64, 64, 64, 64, 488, 488, 488, 488, 488, 
+    488, 488, 488, 488, 488, 488, 488, 488, 488, 488, 488, 488, 64, 64, 64, 
+    290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 64, 
+    489, 489, 490, 490, 490, 490, 489, 489, 489, 489, 489, 489, 489, 489, 
+    489, 489, 488, 488, 488, 64, 64, 64, 64, 64, 491, 491, 491, 491, 491, 
+    491, 491, 491, 491, 491, 491, 491, 491, 492, 492, 64, 490, 490, 490, 490, 
+    490, 490, 490, 490, 490, 490, 489, 489, 489, 489, 489, 489, 493, 493, 
+    493, 493, 493, 493, 493, 493, 467, 494, 494, 494, 494, 494, 494, 494, 
+    494, 494, 494, 494, 494, 494, 494, 494, 491, 491, 491, 491, 492, 492, 
+    492, 489, 489, 494, 494, 494, 494, 494, 494, 494, 489, 489, 489, 489, 
+    467, 467, 467, 467, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495, 
+    495, 495, 495, 495, 495, 64, 489, 489, 489, 489, 489, 489, 489, 467, 467, 
+    467, 467, 489, 489, 489, 489, 489, 489, 489, 489, 489, 489, 489, 467, 
+    467, 496, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 
+    497, 497, 497, 497, 497, 497, 497, 497, 496, 498, 498, 498, 498, 498, 
+    498, 498, 498, 498, 498, 497, 497, 497, 497, 496, 498, 498, 498, 499, 
+    499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 500, 499, 
+    499, 499, 499, 499, 499, 499, 64, 64, 64, 501, 501, 501, 501, 501, 501, 
+    501, 501, 501, 501, 501, 501, 501, 501, 501, 64, 502, 502, 502, 502, 502, 
+    502, 502, 502, 503, 503, 503, 503, 503, 503, 504, 504, 505, 505, 505, 
+    505, 505, 505, 505, 505, 505, 505, 505, 505, 506, 507, 507, 507, 508, 
+    508, 508, 508, 508, 508, 508, 508, 508, 508, 505, 505, 64, 64, 64, 64, 
+    72, 75, 72, 75, 72, 75, 509, 77, 79, 79, 79, 510, 77, 77, 77, 77, 77, 77, 
+    77, 77, 77, 77, 510, 511, 72, 75, 72, 75, 403, 403, 64, 77, 512, 512, 
+    512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 513, 513, 
+    513, 513, 513, 513, 513, 513, 513, 513, 514, 514, 515, 515, 515, 515, 
+    515, 515, 47, 47, 47, 47, 47, 47, 47, 45, 45, 45, 45, 45, 45, 45, 45, 45, 
+    47, 47, 37, 41, 37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 41, 44, 41, 
+    41, 41, 41, 41, 41, 41, 41, 37, 41, 37, 41, 37, 37, 41, 45, 516, 516, 37, 
+    41, 37, 41, 64, 37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 37, 37, 37, 
+    64, 64, 37, 37, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 42, 
+    44, 44, 41, 42, 42, 42, 42, 42, 517, 517, 518, 517, 517, 517, 519, 517, 
+    517, 517, 517, 518, 517, 517, 517, 517, 517, 517, 517, 517, 517, 517, 
+    517, 517, 517, 517, 517, 520, 520, 518, 518, 520, 521, 521, 521, 521, 64, 
+    64, 64, 64, 522, 522, 522, 522, 522, 522, 277, 277, 250, 444, 64, 64, 64, 
+    64, 64, 64, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 
+    524, 524, 524, 524, 525, 525, 526, 526, 526, 526, 526, 526, 526, 526, 
+    526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 525, 525, 525, 525, 
+    525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 527, 64, 64, 
+    64, 64, 64, 64, 64, 64, 64, 528, 528, 529, 529, 529, 529, 529, 529, 529, 
+    529, 529, 529, 64, 64, 64, 64, 64, 64, 174, 174, 174, 174, 174, 174, 174, 
+    174, 174, 174, 171, 171, 171, 171, 171, 171, 176, 176, 176, 171, 64, 64, 
+    64, 64, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 531, 531, 531, 
+    531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 
+    531, 531, 531, 532, 532, 532, 532, 532, 533, 533, 533, 84, 534, 535, 535, 
+    535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 536, 
+    536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 537, 538, 64, 64, 64, 
+    64, 64, 64, 64, 64, 64, 64, 64, 539, 290, 290, 290, 290, 290, 64, 64, 64, 
+    540, 540, 540, 541, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 
+    542, 542, 542, 542, 542, 543, 541, 541, 540, 540, 540, 540, 541, 541, 
+    540, 541, 541, 541, 544, 545, 545, 545, 545, 545, 545, 545, 545, 545, 
+    545, 545, 545, 545, 64, 46, 546, 546, 546, 546, 546, 546, 546, 546, 546, 
+    546, 64, 64, 64, 64, 545, 545, 278, 278, 278, 278, 278, 280, 547, 278, 
+    283, 283, 278, 278, 278, 278, 278, 64, 548, 548, 548, 548, 548, 548, 548, 
+    548, 548, 549, 549, 549, 549, 549, 549, 550, 550, 549, 549, 550, 550, 
+    549, 549, 64, 548, 548, 548, 549, 548, 548, 548, 548, 548, 548, 548, 548, 
+    549, 550, 64, 64, 551, 551, 551, 551, 551, 551, 551, 551, 551, 551, 64, 
+    64, 552, 552, 552, 552, 547, 278, 278, 278, 278, 278, 278, 286, 286, 286, 
+    278, 279, 280, 279, 278, 278, 553, 553, 553, 553, 553, 553, 553, 553, 
+    554, 553, 554, 554, 555, 553, 553, 554, 554, 553, 553, 553, 553, 553, 
+    554, 554, 553, 554, 553, 64, 64, 64, 64, 64, 64, 64, 64, 553, 553, 556, 
+    557, 557, 558, 558, 558, 558, 558, 558, 558, 558, 558, 558, 558, 559, 
+    560, 560, 559, 559, 561, 561, 558, 562, 562, 559, 563, 64, 64, 292, 292, 
+    292, 292, 292, 292, 64, 41, 41, 41, 516, 44, 44, 44, 44, 64, 64, 64, 64, 
+    41, 62, 64, 64, 558, 558, 558, 559, 559, 560, 559, 559, 560, 559, 559, 
+    561, 559, 563, 64, 64, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, 
+    64, 64, 64, 64, 64, 64, 290, 565, 565, 565, 565, 565, 565, 565, 565, 565, 
+    565, 565, 565, 565, 565, 565, 565, 565, 565, 290, 64, 64, 64, 64, 291, 
+    291, 291, 291, 291, 291, 291, 64, 64, 64, 64, 291, 291, 291, 291, 291, 
+    291, 291, 291, 291, 64, 64, 64, 64, 566, 64, 64, 64, 64, 64, 64, 64, 64, 
+    64, 64, 64, 64, 64, 64, 566, 567, 568, 568, 568, 568, 568, 568, 568, 568, 
+    568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 
+    567, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 
+    496, 498, 498, 496, 496, 498, 498, 498, 498, 498, 498, 41, 41, 41, 41, 
+    41, 41, 41, 64, 64, 64, 64, 83, 83, 83, 83, 83, 64, 64, 64, 64, 64, 110, 
+    569, 110, 110, 570, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 
+    110, 110, 110, 64, 110, 110, 110, 110, 110, 64, 110, 64, 110, 110, 64, 
+    110, 110, 64, 110, 110, 126, 126, 571, 571, 571, 571, 571, 571, 571, 571, 
+    571, 571, 571, 571, 571, 571, 571, 571, 64, 64, 64, 64, 64, 64, 64, 64, 
+    64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 572, 418, 64, 
+    64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 116, 119, 64, 64, 
+    58, 58, 58, 58, 58, 58, 58, 58, 469, 469, 469, 469, 469, 469, 469, 474, 
+    475, 469, 64, 64, 64, 64, 64, 64, 78, 78, 78, 78, 78, 78, 78, 136, 136, 
+    136, 136, 136, 136, 136, 64, 64, 469, 473, 473, 573, 573, 474, 475, 474, 
+    475, 474, 475, 474, 475, 474, 475, 474, 475, 474, 475, 474, 475, 469, 
+    469, 474, 475, 469, 469, 469, 469, 573, 573, 573, 574, 469, 574, 64, 469, 
+    574, 469, 469, 473, 451, 452, 451, 452, 451, 452, 575, 469, 469, 576, 
+    577, 578, 578, 579, 64, 469, 580, 575, 469, 64, 64, 64, 64, 126, 126, 
+    126, 126, 126, 64, 126, 126, 126, 126, 126, 126, 126, 64, 64, 410, 64, 
+    581, 581, 582, 583, 582, 581, 581, 584, 585, 581, 586, 587, 588, 587, 
+    587, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 587, 581, 590, 
+    591, 590, 581, 581, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 
+    592, 592, 592, 592, 592, 592, 592, 592, 584, 581, 585, 593, 594, 593, 
+    595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 
+    595, 595, 595, 595, 584, 591, 585, 591, 584, 585, 596, 597, 598, 596, 
+    596, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 599, 599, 
+    599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 600, 601, 
+    601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 64, 
+    64, 64, 601, 601, 601, 601, 601, 601, 64, 64, 601, 601, 601, 64, 64, 64, 
+    583, 583, 591, 593, 602, 583, 583, 64, 603, 604, 604, 604, 604, 603, 603, 
+    64, 64, 605, 605, 605, 26, 30, 64, 64, 606, 606, 606, 606, 606, 606, 606, 
+    606, 606, 606, 606, 606, 64, 606, 606, 606, 606, 606, 606, 606, 606, 606, 
+    606, 64, 606, 606, 606, 64, 606, 606, 64, 606, 606, 606, 606, 606, 606, 
+    606, 64, 64, 606, 606, 606, 64, 64, 64, 64, 64, 84, 66, 84, 64, 64, 64, 
+    64, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 64, 
+    64, 64, 277, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 
+    607, 608, 608, 608, 608, 609, 609, 609, 609, 609, 609, 609, 609, 609, 
+    609, 609, 609, 609, 609, 609, 609, 609, 608, 608, 609, 64, 64, 64, 26, 
+    26, 26, 26, 64, 64, 64, 64, 609, 64, 64, 64, 64, 64, 64, 64, 277, 277, 
+    277, 277, 277, 136, 64, 64, 610, 610, 610, 610, 610, 610, 610, 610, 610, 
+    610, 610, 610, 610, 64, 64, 64, 611, 611, 611, 611, 611, 611, 611, 611, 
+    611, 64, 64, 64, 64, 64, 64, 64, 136, 438, 438, 438, 438, 438, 438, 438, 
+    438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 64, 64, 64, 
+    64, 612, 612, 612, 612, 612, 612, 612, 612, 613, 613, 613, 613, 64, 64, 
+    64, 64, 614, 614, 614, 614, 614, 614, 614, 614, 614, 615, 614, 614, 614, 
+    614, 614, 614, 614, 614, 615, 64, 64, 64, 64, 64, 616, 616, 616, 616, 
+    616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 617, 617, 617, 
+    617, 64, 64, 64, 64, 64, 618, 618, 618, 618, 618, 618, 618, 618, 618, 
+    618, 618, 618, 618, 618, 64, 619, 620, 620, 620, 620, 620, 620, 620, 620, 
+    620, 620, 620, 620, 64, 64, 64, 64, 621, 622, 622, 622, 622, 622, 64, 64, 
+    623, 623, 623, 623, 623, 623, 623, 623, 624, 624, 624, 624, 624, 624, 
+    624, 624, 625, 625, 625, 625, 625, 625, 625, 625, 626, 626, 626, 626, 
+    626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 64, 64, 627, 627, 627, 
+    627, 627, 627, 627, 627, 627, 627, 64, 64, 64, 64, 64, 64, 628, 628, 628, 
+    628, 628, 628, 628, 628, 629, 629, 629, 629, 629, 629, 629, 629, 629, 
+    629, 629, 629, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 630, 631, 631, 
+    631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 64, 631, 
+    631, 631, 631, 631, 631, 64, 64, 632, 632, 632, 632, 632, 632, 64, 64, 
+    632, 64, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 
+    632, 632, 632, 632, 632, 632, 632, 64, 632, 632, 64, 64, 64, 632, 64, 64, 
+    632, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 
+    633, 64, 634, 635, 635, 635, 635, 635, 635, 635, 635, 636, 636, 636, 636, 
+    636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 637, 638, 
+    638, 638, 638, 638, 638, 638, 639, 639, 639, 639, 639, 639, 639, 639, 
+    639, 639, 639, 639, 639, 639, 639, 64, 64, 64, 64, 64, 64, 64, 64, 640, 
+    640, 640, 640, 640, 640, 640, 640, 640, 641, 641, 641, 641, 641, 641, 
+    641, 641, 641, 641, 641, 641, 641, 641, 642, 642, 642, 642, 642, 642, 64, 
+    64, 64, 643, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 64, 64, 
+    64, 64, 64, 645, 646, 646, 646, 646, 646, 646, 646, 646, 647, 647, 647, 
+    647, 647, 647, 647, 647, 64, 64, 64, 64, 64, 64, 647, 647, 648, 649, 649, 
+    649, 64, 649, 649, 64, 64, 64, 64, 64, 649, 650, 649, 651, 648, 648, 648, 
+    648, 64, 648, 648, 648, 64, 648, 648, 648, 648, 648, 648, 648, 648, 648, 
+    648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 64, 64, 64, 64, 651, 
+    652, 650, 64, 64, 64, 64, 653, 654, 654, 654, 654, 654, 654, 654, 654, 
+    655, 655, 655, 655, 655, 655, 655, 655, 655, 64, 64, 64, 64, 64, 64, 64, 
+    656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 
+    657, 658, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 
+    659, 660, 660, 660, 661, 661, 661, 661, 661, 661, 661, 661, 662, 661, 
+    661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 663, 664, 64, 64, 
+    64, 64, 665, 665, 665, 665, 665, 666, 666, 666, 666, 666, 666, 666, 64, 
+    667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 64, 
+    64, 64, 668, 668, 668, 668, 668, 668, 668, 669, 669, 669, 669, 669, 669, 
+    669, 669, 669, 669, 669, 669, 669, 669, 64, 64, 670, 670, 670, 670, 670, 
+    670, 670, 670, 671, 671, 671, 671, 671, 671, 671, 671, 671, 671, 671, 64, 
+    64, 64, 64, 64, 672, 672, 672, 672, 672, 672, 672, 672, 673, 673, 673, 
+    673, 673, 673, 673, 673, 673, 673, 64, 64, 64, 64, 64, 64, 64, 674, 674, 
+    674, 674, 64, 64, 64, 64, 675, 675, 675, 675, 675, 675, 675, 676, 676, 
+    676, 676, 676, 676, 676, 676, 676, 64, 64, 64, 64, 64, 64, 64, 677, 677, 
+    677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 64, 678, 
+    679, 678, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 
+    680, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 
+    679, 681, 682, 682, 682, 682, 682, 682, 682, 64, 64, 64, 64, 683, 683, 
+    683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 
+    683, 683, 683, 683, 684, 684, 684, 684, 684, 684, 684, 684, 684, 684, 64, 
+    64, 64, 64, 64, 64, 64, 681, 685, 685, 686, 687, 687, 687, 687, 687, 687, 
+    687, 687, 687, 687, 687, 687, 687, 686, 686, 686, 685, 685, 685, 685, 
+    686, 686, 688, 689, 690, 690, 691, 690, 690, 690, 690, 64, 64, 64, 64, 
+    64, 64, 692, 692, 692, 692, 692, 692, 692, 692, 692, 64, 64, 64, 64, 64, 
+    64, 64, 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, 64, 64, 64, 64, 
+    64, 64, 694, 694, 694, 695, 695, 695, 695, 695, 695, 695, 695, 695, 695, 
+    695, 695, 695, 695, 695, 695, 695, 695, 695, 695, 696, 696, 696, 696, 
+    696, 697, 696, 696, 696, 696, 696, 696, 698, 698, 64, 699, 699, 699, 699, 
+    699, 699, 699, 699, 699, 699, 700, 700, 700, 700, 64, 64, 64, 64, 701, 
+    701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 702, 703, 703, 701, 64, 
+    704, 704, 705, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 
+    706, 706, 706, 706, 706, 705, 705, 705, 704, 704, 704, 704, 704, 704, 
+    704, 704, 704, 705, 707, 706, 706, 706, 706, 708, 708, 708, 708, 64, 64, 
+    64, 64, 708, 64, 64, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709, 
+    706, 64, 64, 64, 64, 64, 64, 710, 710, 710, 710, 710, 710, 710, 710, 710, 
+    710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 64, 64, 64, 711, 
+    711, 711, 711, 711, 711, 711, 711, 711, 711, 64, 711, 711, 711, 711, 711, 
+    711, 711, 711, 711, 712, 712, 712, 713, 713, 713, 712, 712, 713, 714, 
+    715, 713, 716, 716, 716, 716, 716, 716, 64, 64, 717, 717, 717, 717, 717, 
+    717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 718, 719, 719, 719, 
+    718, 718, 718, 718, 718, 718, 720, 721, 64, 64, 64, 64, 64, 722, 722, 
+    722, 722, 722, 722, 722, 722, 722, 722, 64, 64, 64, 64, 64, 64, 64, 723, 
+    724, 724, 64, 725, 725, 725, 725, 725, 725, 725, 725, 64, 64, 725, 725, 
+    64, 64, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 
+    725, 64, 725, 725, 725, 725, 725, 725, 725, 64, 725, 725, 64, 725, 725, 
+    725, 725, 725, 64, 64, 726, 725, 724, 724, 723, 724, 724, 724, 724, 64, 
+    64, 724, 724, 64, 64, 724, 724, 727, 64, 64, 64, 64, 64, 64, 64, 64, 64, 
+    724, 64, 64, 64, 64, 64, 725, 725, 725, 725, 725, 724, 724, 64, 64, 728, 
+    728, 728, 728, 728, 728, 728, 64, 64, 64, 729, 729, 729, 729, 729, 729, 
+    729, 729, 730, 730, 730, 731, 731, 731, 731, 731, 731, 730, 731, 730, 
+    730, 730, 730, 731, 731, 730, 732, 733, 729, 729, 734, 729, 735, 735, 
+    735, 735, 735, 735, 735, 735, 735, 735, 64, 64, 64, 64, 64, 64, 736, 736, 
+    736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 737, 
+    737, 737, 738, 738, 738, 738, 64, 64, 737, 737, 737, 737, 738, 738, 737, 
+    739, 740, 741, 741, 741, 741, 741, 741, 741, 741, 741, 64, 64, 64, 64, 
+    64, 64, 742, 742, 742, 742, 742, 742, 742, 742, 743, 743, 743, 744, 744, 
+    744, 744, 744, 744, 744, 744, 743, 743, 744, 743, 745, 744, 746, 746, 
+    746, 742, 64, 64, 64, 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 
+    64, 64, 64, 64, 64, 64, 748, 748, 748, 748, 748, 748, 748, 748, 748, 748, 
+    748, 749, 750, 749, 750, 750, 749, 749, 749, 749, 749, 749, 751, 752, 
+    753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 64, 64, 64, 64, 64, 64, 
+    754, 754, 754, 754, 754, 754, 754, 754, 755, 755, 755, 755, 755, 755, 
+    755, 755, 756, 756, 756, 756, 756, 756, 756, 756, 756, 756, 757, 757, 
+    757, 757, 757, 757, 757, 757, 757, 64, 64, 64, 64, 64, 64, 64, 64, 64, 
+    64, 64, 64, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 64, 64, 64, 
+    64, 64, 64, 64, 760, 760, 760, 760, 760, 760, 760, 760, 760, 64, 64, 64, 
+    64, 64, 64, 64, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 
+    761, 761, 761, 761, 64, 762, 762, 762, 762, 762, 64, 64, 64, 763, 763, 
+    763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 64, 512, 
+    64, 64, 64, 64, 64, 64, 64, 764, 764, 764, 764, 764, 764, 764, 764, 764, 
+    764, 764, 764, 764, 764, 764, 64, 765, 765, 765, 765, 765, 765, 765, 765, 
+    765, 765, 64, 64, 64, 64, 766, 766, 767, 767, 767, 767, 767, 767, 767, 
+    767, 767, 767, 767, 767, 767, 767, 64, 64, 768, 768, 768, 768, 768, 769, 
+    64, 64, 770, 770, 770, 770, 770, 770, 770, 770, 771, 771, 771, 771, 771, 
+    771, 771, 772, 772, 772, 772, 772, 773, 773, 773, 773, 774, 774, 774, 
+    774, 772, 773, 64, 64, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 
+    64, 776, 776, 776, 776, 776, 776, 776, 64, 770, 770, 770, 770, 770, 64, 
+    64, 64, 64, 64, 770, 770, 770, 777, 777, 777, 777, 777, 777, 777, 777, 
+    777, 777, 777, 777, 777, 64, 64, 64, 777, 778, 778, 778, 778, 778, 778, 
+    778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 
+    778, 778, 64, 64, 64, 64, 64, 64, 64, 64, 779, 779, 779, 779, 780, 780, 
+    780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 486, 482, 64, 64, 
+    64, 64, 64, 64, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 
+    64, 64, 64, 64, 64, 781, 781, 781, 781, 781, 64, 64, 64, 781, 64, 64, 64, 
+    64, 64, 64, 64, 781, 781, 64, 64, 782, 783, 784, 785, 410, 410, 410, 410, 
+    64, 64, 64, 64, 277, 277, 277, 277, 277, 277, 64, 64, 277, 277, 277, 277, 
+    277, 277, 277, 64, 64, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 
+    277, 277, 786, 786, 400, 400, 400, 277, 277, 277, 787, 786, 786, 786, 
+    786, 786, 410, 410, 410, 410, 410, 410, 410, 410, 136, 136, 136, 136, 
+    136, 136, 136, 136, 277, 277, 78, 78, 78, 78, 78, 136, 136, 277, 277, 
+    277, 277, 277, 277, 78, 78, 78, 78, 277, 277, 609, 609, 788, 788, 788, 
+    609, 64, 64, 522, 522, 64, 64, 64, 64, 64, 64, 442, 442, 442, 442, 442, 
+    442, 442, 442, 442, 442, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 
+    34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 442, 442, 442, 
+    34, 34, 34, 34, 34, 34, 34, 64, 34, 34, 34, 34, 34, 34, 442, 64, 442, 
+    442, 64, 64, 442, 64, 64, 442, 442, 64, 64, 442, 442, 442, 442, 64, 442, 
+    442, 34, 34, 64, 34, 64, 34, 34, 34, 34, 34, 34, 34, 64, 34, 34, 34, 34, 
+    34, 34, 34, 442, 442, 64, 442, 442, 442, 442, 64, 64, 442, 442, 442, 442, 
+    442, 442, 442, 442, 64, 442, 442, 442, 442, 442, 442, 442, 64, 34, 34, 
+    442, 442, 64, 442, 442, 442, 442, 64, 442, 442, 442, 442, 442, 64, 442, 
+    64, 64, 64, 442, 442, 442, 442, 442, 442, 442, 64, 34, 34, 34, 34, 34, 
+    34, 34, 34, 34, 34, 34, 34, 64, 64, 442, 789, 34, 34, 34, 34, 34, 34, 34, 
+    34, 34, 445, 34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 
+    442, 442, 789, 34, 34, 34, 34, 34, 34, 34, 34, 34, 445, 34, 34, 442, 442, 
+    442, 442, 442, 789, 34, 34, 34, 34, 34, 34, 34, 34, 34, 445, 34, 34, 34, 
+    34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 442, 442, 789, 34, 445, 
+    34, 34, 34, 34, 34, 34, 34, 34, 442, 34, 64, 64, 790, 790, 790, 790, 790, 
+    790, 790, 790, 790, 790, 791, 791, 791, 791, 791, 791, 791, 791, 791, 
+    791, 791, 791, 791, 64, 64, 792, 792, 792, 792, 792, 792, 792, 792, 792, 
+    793, 793, 793, 793, 793, 793, 793, 64, 126, 126, 126, 126, 64, 126, 126, 
+    126, 64, 126, 126, 64, 126, 64, 64, 126, 64, 126, 126, 126, 126, 126, 
+    126, 126, 126, 126, 126, 64, 126, 126, 126, 126, 64, 126, 64, 126, 64, 
+    64, 64, 64, 64, 64, 126, 64, 64, 64, 64, 126, 64, 126, 64, 126, 64, 126, 
+    126, 126, 64, 126, 64, 126, 64, 126, 64, 126, 64, 126, 126, 126, 126, 64, 
+    126, 64, 126, 126, 64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 64, 
+    64, 64, 64, 64, 126, 126, 126, 64, 126, 126, 126, 113, 113, 64, 64, 64, 
+    64, 64, 64, 64, 26, 26, 26, 26, 26, 26, 26, 33, 33, 33, 446, 446, 64, 64, 
+    64, 453, 453, 453, 453, 453, 453, 277, 64, 453, 453, 26, 26, 64, 64, 64, 
+    64, 453, 453, 453, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 277, 277, 
+    794, 489, 489, 64, 64, 64, 64, 64, 489, 489, 489, 64, 64, 64, 64, 64, 
+    489, 64, 64, 64, 64, 64, 64, 64, 489, 489, 64, 64, 64, 64, 64, 64, 26, 
+    26, 26, 26, 26, 64, 64, 64, 64, 64, 64, 64, 26, 26, 26, 26, 26, 26, 64, 
+    26, 26, 26, 26, 26, 26, 26, 26, 26, 64, 26, 26, 26, 26, 26, 26, 64, 64, 
+    26, 26, 26, 497, 497, 497, 497, 497, 497, 496, 498, 498, 498, 498, 498, 
+    498, 498, 64, 64, 64, 410, 64, 64, 64, 64, 64, 64, 410, 410, 410, 410, 
+    410, 410, 410, 410, 568, 568, 568, 568, 568, 567, 64, 64, 
+};
+
+/* decomposition data */
+static const unsigned short decomp_data[] = {
+    0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514, 
+    32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52, 
+    772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512, 
+    65, 770, 512, 65, 771, 512, 65, 776, 512, 65, 778, 512, 67, 807, 512, 69, 
+    768, 512, 69, 769, 512, 69, 770, 512, 69, 776, 512, 73, 768, 512, 73, 
+    769, 512, 73, 770, 512, 73, 776, 512, 78, 771, 512, 79, 768, 512, 79, 
+    769, 512, 79, 770, 512, 79, 771, 512, 79, 776, 512, 85, 768, 512, 85, 
+    769, 512, 85, 770, 512, 85, 776, 512, 89, 769, 512, 97, 768, 512, 97, 
+    769, 512, 97, 770, 512, 97, 771, 512, 97, 776, 512, 97, 778, 512, 99, 
+    807, 512, 101, 768, 512, 101, 769, 512, 101, 770, 512, 101, 776, 512, 
+    105, 768, 512, 105, 769, 512, 105, 770, 512, 105, 776, 512, 110, 771, 
+    512, 111, 768, 512, 111, 769, 512, 111, 770, 512, 111, 771, 512, 111, 
+    776, 512, 117, 768, 512, 117, 769, 512, 117, 770, 512, 117, 776, 512, 
+    121, 769, 512, 121, 776, 512, 65, 772, 512, 97, 772, 512, 65, 774, 512, 
+    97, 774, 512, 65, 808, 512, 97, 808, 512, 67, 769, 512, 99, 769, 512, 67, 
+    770, 512, 99, 770, 512, 67, 775, 512, 99, 775, 512, 67, 780, 512, 99, 
+    780, 512, 68, 780, 512, 100, 780, 512, 69, 772, 512, 101, 772, 512, 69, 
+    774, 512, 101, 774, 512, 69, 775, 512, 101, 775, 512, 69, 808, 512, 101, 
+    808, 512, 69, 780, 512, 101, 780, 512, 71, 770, 512, 103, 770, 512, 71, 
+    774, 512, 103, 774, 512, 71, 775, 512, 103, 775, 512, 71, 807, 512, 103, 
+    807, 512, 72, 770, 512, 104, 770, 512, 73, 771, 512, 105, 771, 512, 73, 
+    772, 512, 105, 772, 512, 73, 774, 512, 105, 774, 512, 73, 808, 512, 105, 
+    808, 512, 73, 775, 514, 73, 74, 514, 105, 106, 512, 74, 770, 512, 106, 
+    770, 512, 75, 807, 512, 107, 807, 512, 76, 769, 512, 108, 769, 512, 76, 
+    807, 512, 108, 807, 512, 76, 780, 512, 108, 780, 514, 76, 183, 514, 108, 
+    183, 512, 78, 769, 512, 110, 769, 512, 78, 807, 512, 110, 807, 512, 78, 
+    780, 512, 110, 780, 514, 700, 110, 512, 79, 772, 512, 111, 772, 512, 79, 
+    774, 512, 111, 774, 512, 79, 779, 512, 111, 779, 512, 82, 769, 512, 114, 
+    769, 512, 82, 807, 512, 114, 807, 512, 82, 780, 512, 114, 780, 512, 83, 
+    769, 512, 115, 769, 512, 83, 770, 512, 115, 770, 512, 83, 807, 512, 115, 
+    807, 512, 83, 780, 512, 115, 780, 512, 84, 807, 512, 116, 807, 512, 84, 
+    780, 512, 116, 780, 512, 85, 771, 512, 117, 771, 512, 85, 772, 512, 117, 
+    772, 512, 85, 774, 512, 117, 774, 512, 85, 778, 512, 117, 778, 512, 85, 
+    779, 512, 117, 779, 512, 85, 808, 512, 117, 808, 512, 87, 770, 512, 119, 
+    770, 512, 89, 770, 512, 121, 770, 512, 89, 776, 512, 90, 769, 512, 122, 
+    769, 512, 90, 775, 512, 122, 775, 512, 90, 780, 512, 122, 780, 258, 115, 
+    512, 79, 795, 512, 111, 795, 512, 85, 795, 512, 117, 795, 514, 68, 381, 
+    514, 68, 382, 514, 100, 382, 514, 76, 74, 514, 76, 106, 514, 108, 106, 
+    514, 78, 74, 514, 78, 106, 514, 110, 106, 512, 65, 780, 512, 97, 780, 
+    512, 73, 780, 512, 105, 780, 512, 79, 780, 512, 111, 780, 512, 85, 780, 
+    512, 117, 780, 512, 220, 772, 512, 252, 772, 512, 220, 769, 512, 252, 
+    769, 512, 220, 780, 512, 252, 780, 512, 220, 768, 512, 252, 768, 512, 
+    196, 772, 512, 228, 772, 512, 550, 772, 512, 551, 772, 512, 198, 772, 
+    512, 230, 772, 512, 71, 780, 512, 103, 780, 512, 75, 780, 512, 107, 780, 
+    512, 79, 808, 512, 111, 808, 512, 490, 772, 512, 491, 772, 512, 439, 780, 
+    512, 658, 780, 512, 106, 780, 514, 68, 90, 514, 68, 122, 514, 100, 122, 
+    512, 71, 769, 512, 103, 769, 512, 78, 768, 512, 110, 768, 512, 197, 769, 
+    512, 229, 769, 512, 198, 769, 512, 230, 769, 512, 216, 769, 512, 248, 
+    769, 512, 65, 783, 512, 97, 783, 512, 65, 785, 512, 97, 785, 512, 69, 
+    783, 512, 101, 783, 512, 69, 785, 512, 101, 785, 512, 73, 783, 512, 105, 
+    783, 512, 73, 785, 512, 105, 785, 512, 79, 783, 512, 111, 783, 512, 79, 
+    785, 512, 111, 785, 512, 82, 783, 512, 114, 783, 512, 82, 785, 512, 114, 
+    785, 512, 85, 783, 512, 117, 783, 512, 85, 785, 512, 117, 785, 512, 83, 
+    806, 512, 115, 806, 512, 84, 806, 512, 116, 806, 512, 72, 780, 512, 104, 
+    780, 512, 65, 775, 512, 97, 775, 512, 69, 807, 512, 101, 807, 512, 214, 
+    772, 512, 246, 772, 512, 213, 772, 512, 245, 772, 512, 79, 775, 512, 111, 
+    775, 512, 558, 772, 512, 559, 772, 512, 89, 772, 512, 121, 772, 259, 104, 
+    259, 614, 259, 106, 259, 114, 259, 633, 259, 635, 259, 641, 259, 119, 
+    259, 121, 514, 32, 774, 514, 32, 775, 514, 32, 778, 514, 32, 808, 514, 
+    32, 771, 514, 32, 779, 259, 611, 259, 108, 259, 115, 259, 120, 259, 661, 
+    256, 768, 256, 769, 256, 787, 512, 776, 769, 256, 697, 514, 32, 837, 256, 
+    59, 514, 32, 769, 512, 168, 769, 512, 913, 769, 256, 183, 512, 917, 769, 
+    512, 919, 769, 512, 921, 769, 512, 927, 769, 512, 933, 769, 512, 937, 
+    769, 512, 970, 769, 512, 921, 776, 512, 933, 776, 512, 945, 769, 512, 
+    949, 769, 512, 951, 769, 512, 953, 769, 512, 971, 769, 512, 953, 776, 
+    512, 965, 776, 512, 959, 769, 512, 965, 769, 512, 969, 769, 258, 946, 
+    258, 952, 258, 933, 512, 978, 769, 512, 978, 776, 258, 966, 258, 960, 
+    258, 954, 258, 961, 258, 962, 258, 920, 258, 949, 258, 931, 512, 1045, 
+    768, 512, 1045, 776, 512, 1043, 769, 512, 1030, 776, 512, 1050, 769, 512, 
+    1048, 768, 512, 1059, 774, 512, 1048, 774, 512, 1080, 774, 512, 1077, 
+    768, 512, 1077, 776, 512, 1075, 769, 512, 1110, 776, 512, 1082, 769, 512, 
+    1080, 768, 512, 1091, 774, 512, 1140, 783, 512, 1141, 783, 512, 1046, 
+    774, 512, 1078, 774, 512, 1040, 774, 512, 1072, 774, 512, 1040, 776, 512, 
+    1072, 776, 512, 1045, 774, 512, 1077, 774, 512, 1240, 776, 512, 1241, 
+    776, 512, 1046, 776, 512, 1078, 776, 512, 1047, 776, 512, 1079, 776, 512, 
+    1048, 772, 512, 1080, 772, 512, 1048, 776, 512, 1080, 776, 512, 1054, 
+    776, 512, 1086, 776, 512, 1256, 776, 512, 1257, 776, 512, 1069, 776, 512, 
+    1101, 776, 512, 1059, 772, 512, 1091, 772, 512, 1059, 776, 512, 1091, 
+    776, 512, 1059, 779, 512, 1091, 779, 512, 1063, 776, 512, 1095, 776, 512, 
+    1067, 776, 512, 1099, 776, 514, 1381, 1410, 512, 1575, 1619, 512, 1575, 
+    1620, 512, 1608, 1620, 512, 1575, 1621, 512, 1610, 1620, 514, 1575, 1652, 
+    514, 1608, 1652, 514, 1735, 1652, 514, 1610, 1652, 512, 1749, 1620, 512, 
+    1729, 1620, 512, 1746, 1620, 512, 2344, 2364, 512, 2352, 2364, 512, 2355, 
+    2364, 512, 2325, 2364, 512, 2326, 2364, 512, 2327, 2364, 512, 2332, 2364, 
+    512, 2337, 2364, 512, 2338, 2364, 512, 2347, 2364, 512, 2351, 2364, 512, 
+    2503, 2494, 512, 2503, 2519, 512, 2465, 2492, 512, 2466, 2492, 512, 2479, 
+    2492, 512, 2610, 2620, 512, 2616, 2620, 512, 2582, 2620, 512, 2583, 2620, 
+    512, 2588, 2620, 512, 2603, 2620, 512, 2887, 2902, 512, 2887, 2878, 512, 
+    2887, 2903, 512, 2849, 2876, 512, 2850, 2876, 512, 2962, 3031, 512, 3014, 
+    3006, 512, 3015, 3006, 512, 3014, 3031, 512, 3142, 3158, 512, 3263, 3285, 
+    512, 3270, 3285, 512, 3270, 3286, 512, 3270, 3266, 512, 3274, 3285, 512, 
+    3398, 3390, 512, 3399, 3390, 512, 3398, 3415, 512, 3545, 3530, 512, 3545, 
+    3535, 512, 3548, 3530, 512, 3545, 3551, 514, 3661, 3634, 514, 3789, 3762, 
+    514, 3755, 3737, 514, 3755, 3745, 257, 3851, 512, 3906, 4023, 512, 3916, 
+    4023, 512, 3921, 4023, 512, 3926, 4023, 512, 3931, 4023, 512, 3904, 4021, 
+    512, 3953, 3954, 512, 3953, 3956, 512, 4018, 3968, 514, 4018, 3969, 512, 
+    4019, 3968, 514, 4019, 3969, 512, 3953, 3968, 512, 3986, 4023, 512, 3996, 
+    4023, 512, 4001, 4023, 512, 4006, 4023, 512, 4011, 4023, 512, 3984, 4021, 
+    512, 4133, 4142, 259, 4316, 512, 6917, 6965, 512, 6919, 6965, 512, 6921, 
+    6965, 512, 6923, 6965, 512, 6925, 6965, 512, 6929, 6965, 512, 6970, 6965, 
+    512, 6972, 6965, 512, 6974, 6965, 512, 6975, 6965, 512, 6978, 6965, 259, 
+    65, 259, 198, 259, 66, 259, 68, 259, 69, 259, 398, 259, 71, 259, 72, 259, 
+    73, 259, 74, 259, 75, 259, 76, 259, 77, 259, 78, 259, 79, 259, 546, 259, 
+    80, 259, 82, 259, 84, 259, 85, 259, 87, 259, 97, 259, 592, 259, 593, 259, 
+    7426, 259, 98, 259, 100, 259, 101, 259, 601, 259, 603, 259, 604, 259, 
+    103, 259, 107, 259, 109, 259, 331, 259, 111, 259, 596, 259, 7446, 259, 
+    7447, 259, 112, 259, 116, 259, 117, 259, 7453, 259, 623, 259, 118, 259, 
+    7461, 259, 946, 259, 947, 259, 948, 259, 966, 259, 967, 261, 105, 261, 
+    114, 261, 117, 261, 118, 261, 946, 261, 947, 261, 961, 261, 966, 261, 
+    967, 259, 1085, 259, 594, 259, 99, 259, 597, 259, 240, 259, 604, 259, 
+    102, 259, 607, 259, 609, 259, 613, 259, 616, 259, 617, 259, 618, 259, 
+    7547, 259, 669, 259, 621, 259, 7557, 259, 671, 259, 625, 259, 624, 259, 
+    626, 259, 627, 259, 628, 259, 629, 259, 632, 259, 642, 259, 643, 259, 
+    427, 259, 649, 259, 650, 259, 7452, 259, 651, 259, 652, 259, 122, 259, 
+    656, 259, 657, 259, 658, 259, 952, 512, 65, 805, 512, 97, 805, 512, 66, 
+    775, 512, 98, 775, 512, 66, 803, 512, 98, 803, 512, 66, 817, 512, 98, 
+    817, 512, 199, 769, 512, 231, 769, 512, 68, 775, 512, 100, 775, 512, 68, 
+    803, 512, 100, 803, 512, 68, 817, 512, 100, 817, 512, 68, 807, 512, 100, 
+    807, 512, 68, 813, 512, 100, 813, 512, 274, 768, 512, 275, 768, 512, 274, 
+    769, 512, 275, 769, 512, 69, 813, 512, 101, 813, 512, 69, 816, 512, 101, 
+    816, 512, 552, 774, 512, 553, 774, 512, 70, 775, 512, 102, 775, 512, 71, 
+    772, 512, 103, 772, 512, 72, 775, 512, 104, 775, 512, 72, 803, 512, 104, 
+    803, 512, 72, 776, 512, 104, 776, 512, 72, 807, 512, 104, 807, 512, 72, 
+    814, 512, 104, 814, 512, 73, 816, 512, 105, 816, 512, 207, 769, 512, 239, 
+    769, 512, 75, 769, 512, 107, 769, 512, 75, 803, 512, 107, 803, 512, 75, 
+    817, 512, 107, 817, 512, 76, 803, 512, 108, 803, 512, 7734, 772, 512, 
+    7735, 772, 512, 76, 817, 512, 108, 817, 512, 76, 813, 512, 108, 813, 512, 
+    77, 769, 512, 109, 769, 512, 77, 775, 512, 109, 775, 512, 77, 803, 512, 
+    109, 803, 512, 78, 775, 512, 110, 775, 512, 78, 803, 512, 110, 803, 512, 
+    78, 817, 512, 110, 817, 512, 78, 813, 512, 110, 813, 512, 213, 769, 512, 
+    245, 769, 512, 213, 776, 512, 245, 776, 512, 332, 768, 512, 333, 768, 
+    512, 332, 769, 512, 333, 769, 512, 80, 769, 512, 112, 769, 512, 80, 775, 
+    512, 112, 775, 512, 82, 775, 512, 114, 775, 512, 82, 803, 512, 114, 803, 
+    512, 7770, 772, 512, 7771, 772, 512, 82, 817, 512, 114, 817, 512, 83, 
+    775, 512, 115, 775, 512, 83, 803, 512, 115, 803, 512, 346, 775, 512, 347, 
+    775, 512, 352, 775, 512, 353, 775, 512, 7778, 775, 512, 7779, 775, 512, 
+    84, 775, 512, 116, 775, 512, 84, 803, 512, 116, 803, 512, 84, 817, 512, 
+    116, 817, 512, 84, 813, 512, 116, 813, 512, 85, 804, 512, 117, 804, 512, 
+    85, 816, 512, 117, 816, 512, 85, 813, 512, 117, 813, 512, 360, 769, 512, 
+    361, 769, 512, 362, 776, 512, 363, 776, 512, 86, 771, 512, 118, 771, 512, 
+    86, 803, 512, 118, 803, 512, 87, 768, 512, 119, 768, 512, 87, 769, 512, 
+    119, 769, 512, 87, 776, 512, 119, 776, 512, 87, 775, 512, 119, 775, 512, 
+    87, 803, 512, 119, 803, 512, 88, 775, 512, 120, 775, 512, 88, 776, 512, 
+    120, 776, 512, 89, 775, 512, 121, 775, 512, 90, 770, 512, 122, 770, 512, 
+    90, 803, 512, 122, 803, 512, 90, 817, 512, 122, 817, 512, 104, 817, 512, 
+    116, 776, 512, 119, 778, 512, 121, 778, 514, 97, 702, 512, 383, 775, 512, 
+    65, 803, 512, 97, 803, 512, 65, 777, 512, 97, 777, 512, 194, 769, 512, 
+    226, 769, 512, 194, 768, 512, 226, 768, 512, 194, 777, 512, 226, 777, 
+    512, 194, 771, 512, 226, 771, 512, 7840, 770, 512, 7841, 770, 512, 258, 
+    769, 512, 259, 769, 512, 258, 768, 512, 259, 768, 512, 258, 777, 512, 
+    259, 777, 512, 258, 771, 512, 259, 771, 512, 7840, 774, 512, 7841, 774, 
+    512, 69, 803, 512, 101, 803, 512, 69, 777, 512, 101, 777, 512, 69, 771, 
+    512, 101, 771, 512, 202, 769, 512, 234, 769, 512, 202, 768, 512, 234, 
+    768, 512, 202, 777, 512, 234, 777, 512, 202, 771, 512, 234, 771, 512, 
+    7864, 770, 512, 7865, 770, 512, 73, 777, 512, 105, 777, 512, 73, 803, 
+    512, 105, 803, 512, 79, 803, 512, 111, 803, 512, 79, 777, 512, 111, 777, 
+    512, 212, 769, 512, 244, 769, 512, 212, 768, 512, 244, 768, 512, 212, 
+    777, 512, 244, 777, 512, 212, 771, 512, 244, 771, 512, 7884, 770, 512, 
+    7885, 770, 512, 416, 769, 512, 417, 769, 512, 416, 768, 512, 417, 768, 
+    512, 416, 777, 512, 417, 777, 512, 416, 771, 512, 417, 771, 512, 416, 
+    803, 512, 417, 803, 512, 85, 803, 512, 117, 803, 512, 85, 777, 512, 117, 
+    777, 512, 431, 769, 512, 432, 769, 512, 431, 768, 512, 432, 768, 512, 
+    431, 777, 512, 432, 777, 512, 431, 771, 512, 432, 771, 512, 431, 803, 
+    512, 432, 803, 512, 89, 768, 512, 121, 768, 512, 89, 803, 512, 121, 803, 
+    512, 89, 777, 512, 121, 777, 512, 89, 771, 512, 121, 771, 512, 945, 787, 
+    512, 945, 788, 512, 7936, 768, 512, 7937, 768, 512, 7936, 769, 512, 7937, 
+    769, 512, 7936, 834, 512, 7937, 834, 512, 913, 787, 512, 913, 788, 512, 
+    7944, 768, 512, 7945, 768, 512, 7944, 769, 512, 7945, 769, 512, 7944, 
+    834, 512, 7945, 834, 512, 949, 787, 512, 949, 788, 512, 7952, 768, 512, 
+    7953, 768, 512, 7952, 769, 512, 7953, 769, 512, 917, 787, 512, 917, 788, 
+    512, 7960, 768, 512, 7961, 768, 512, 7960, 769, 512, 7961, 769, 512, 951, 
+    787, 512, 951, 788, 512, 7968, 768, 512, 7969, 768, 512, 7968, 769, 512, 
+    7969, 769, 512, 7968, 834, 512, 7969, 834, 512, 919, 787, 512, 919, 788, 
+    512, 7976, 768, 512, 7977, 768, 512, 7976, 769, 512, 7977, 769, 512, 
+    7976, 834, 512, 7977, 834, 512, 953, 787, 512, 953, 788, 512, 7984, 768, 
+    512, 7985, 768, 512, 7984, 769, 512, 7985, 769, 512, 7984, 834, 512, 
+    7985, 834, 512, 921, 787, 512, 921, 788, 512, 7992, 768, 512, 7993, 768, 
+    512, 7992, 769, 512, 7993, 769, 512, 7992, 834, 512, 7993, 834, 512, 959, 
+    787, 512, 959, 788, 512, 8000, 768, 512, 8001, 768, 512, 8000, 769, 512, 
+    8001, 769, 512, 927, 787, 512, 927, 788, 512, 8008, 768, 512, 8009, 768, 
+    512, 8008, 769, 512, 8009, 769, 512, 965, 787, 512, 965, 788, 512, 8016, 
+    768, 512, 8017, 768, 512, 8016, 769, 512, 8017, 769, 512, 8016, 834, 512, 
+    8017, 834, 512, 933, 788, 512, 8025, 768, 512, 8025, 769, 512, 8025, 834, 
+    512, 969, 787, 512, 969, 788, 512, 8032, 768, 512, 8033, 768, 512, 8032, 
+    769, 512, 8033, 769, 512, 8032, 834, 512, 8033, 834, 512, 937, 787, 512, 
+    937, 788, 512, 8040, 768, 512, 8041, 768, 512, 8040, 769, 512, 8041, 769, 
+    512, 8040, 834, 512, 8041, 834, 512, 945, 768, 256, 940, 512, 949, 768, 
+    256, 941, 512, 951, 768, 256, 942, 512, 953, 768, 256, 943, 512, 959, 
+    768, 256, 972, 512, 965, 768, 256, 973, 512, 969, 768, 256, 974, 512, 
+    7936, 837, 512, 7937, 837, 512, 7938, 837, 512, 7939, 837, 512, 7940, 
+    837, 512, 7941, 837, 512, 7942, 837, 512, 7943, 837, 512, 7944, 837, 512, 
+    7945, 837, 512, 7946, 837, 512, 7947, 837, 512, 7948, 837, 512, 7949, 
+    837, 512, 7950, 837, 512, 7951, 837, 512, 7968, 837, 512, 7969, 837, 512, 
+    7970, 837, 512, 7971, 837, 512, 7972, 837, 512, 7973, 837, 512, 7974, 
+    837, 512, 7975, 837, 512, 7976, 837, 512, 7977, 837, 512, 7978, 837, 512, 
+    7979, 837, 512, 7980, 837, 512, 7981, 837, 512, 7982, 837, 512, 7983, 
+    837, 512, 8032, 837, 512, 8033, 837, 512, 8034, 837, 512, 8035, 837, 512, 
+    8036, 837, 512, 8037, 837, 512, 8038, 837, 512, 8039, 837, 512, 8040, 
+    837, 512, 8041, 837, 512, 8042, 837, 512, 8043, 837, 512, 8044, 837, 512, 
+    8045, 837, 512, 8046, 837, 512, 8047, 837, 512, 945, 774, 512, 945, 772, 
+    512, 8048, 837, 512, 945, 837, 512, 940, 837, 512, 945, 834, 512, 8118, 
+    837, 512, 913, 774, 512, 913, 772, 512, 913, 768, 256, 902, 512, 913, 
+    837, 514, 32, 787, 256, 953, 514, 32, 787, 514, 32, 834, 512, 168, 834, 
+    512, 8052, 837, 512, 951, 837, 512, 942, 837, 512, 951, 834, 512, 8134, 
+    837, 512, 917, 768, 256, 904, 512, 919, 768, 256, 905, 512, 919, 837, 
+    512, 8127, 768, 512, 8127, 769, 512, 8127, 834, 512, 953, 774, 512, 953, 
+    772, 512, 970, 768, 256, 912, 512, 953, 834, 512, 970, 834, 512, 921, 
+    774, 512, 921, 772, 512, 921, 768, 256, 906, 512, 8190, 768, 512, 8190, 
+    769, 512, 8190, 834, 512, 965, 774, 512, 965, 772, 512, 971, 768, 256, 
+    944, 512, 961, 787, 512, 961, 788, 512, 965, 834, 512, 971, 834, 512, 
+    933, 774, 512, 933, 772, 512, 933, 768, 256, 910, 512, 929, 788, 512, 
+    168, 768, 256, 901, 256, 96, 512, 8060, 837, 512, 969, 837, 512, 974, 
+    837, 512, 969, 834, 512, 8182, 837, 512, 927, 768, 256, 908, 512, 937, 
+    768, 256, 911, 512, 937, 837, 256, 180, 514, 32, 788, 256, 8194, 256, 
+    8195, 258, 32, 258, 32, 258, 32, 258, 32, 258, 32, 257, 32, 258, 32, 258, 
+    32, 258, 32, 257, 8208, 514, 32, 819, 258, 46, 514, 46, 46, 770, 46, 46, 
+    46, 257, 32, 514, 8242, 8242, 770, 8242, 8242, 8242, 514, 8245, 8245, 
+    770, 8245, 8245, 8245, 514, 33, 33, 514, 32, 773, 514, 63, 63, 514, 63, 
+    33, 514, 33, 63, 1026, 8242, 8242, 8242, 8242, 258, 32, 259, 48, 259, 
+    105, 259, 52, 259, 53, 259, 54, 259, 55, 259, 56, 259, 57, 259, 43, 259, 
+    8722, 259, 61, 259, 40, 259, 41, 259, 110, 261, 48, 261, 49, 261, 50, 
+    261, 51, 261, 52, 261, 53, 261, 54, 261, 55, 261, 56, 261, 57, 261, 43, 
+    261, 8722, 261, 61, 261, 40, 261, 41, 261, 97, 261, 101, 261, 111, 261, 
+    120, 261, 601, 261, 104, 261, 107, 261, 108, 261, 109, 261, 110, 261, 
+    112, 261, 115, 261, 116, 514, 82, 115, 770, 97, 47, 99, 770, 97, 47, 115, 
+    262, 67, 514, 176, 67, 770, 99, 47, 111, 770, 99, 47, 117, 258, 400, 514, 
+    176, 70, 262, 103, 262, 72, 262, 72, 262, 72, 262, 104, 262, 295, 262, 
+    73, 262, 73, 262, 76, 262, 108, 262, 78, 514, 78, 111, 262, 80, 262, 81, 
+    262, 82, 262, 82, 262, 82, 515, 83, 77, 770, 84, 69, 76, 515, 84, 77, 
+    262, 90, 256, 937, 262, 90, 256, 75, 256, 197, 262, 66, 262, 67, 262, 
+    101, 262, 69, 262, 70, 262, 77, 262, 111, 258, 1488, 258, 1489, 258, 
+    1490, 258, 1491, 262, 105, 770, 70, 65, 88, 262, 960, 262, 947, 262, 915, 
+    262, 928, 262, 8721, 262, 68, 262, 100, 262, 101, 262, 105, 262, 106, 
+    772, 49, 8260, 55, 772, 49, 8260, 57, 1028, 49, 8260, 49, 48, 772, 49, 
+    8260, 51, 772, 50, 8260, 51, 772, 49, 8260, 53, 772, 50, 8260, 53, 772, 
+    51, 8260, 53, 772, 52, 8260, 53, 772, 49, 8260, 54, 772, 53, 8260, 54, 
+    772, 49, 8260, 56, 772, 51, 8260, 56, 772, 53, 8260, 56, 772, 55, 8260, 
+    56, 516, 49, 8260, 258, 73, 514, 73, 73, 770, 73, 73, 73, 514, 73, 86, 
+    258, 86, 514, 86, 73, 770, 86, 73, 73, 1026, 86, 73, 73, 73, 514, 73, 88, 
+    258, 88, 514, 88, 73, 770, 88, 73, 73, 258, 76, 258, 67, 258, 68, 258, 
+    77, 258, 105, 514, 105, 105, 770, 105, 105, 105, 514, 105, 118, 258, 118, 
+    514, 118, 105, 770, 118, 105, 105, 1026, 118, 105, 105, 105, 514, 105, 
+    120, 258, 120, 514, 120, 105, 770, 120, 105, 105, 258, 108, 258, 99, 258, 
+    100, 258, 109, 772, 48, 8260, 51, 512, 8592, 824, 512, 8594, 824, 512, 
+    8596, 824, 512, 8656, 824, 512, 8660, 824, 512, 8658, 824, 512, 8707, 
+    824, 512, 8712, 824, 512, 8715, 824, 512, 8739, 824, 512, 8741, 824, 514, 
+    8747, 8747, 770, 8747, 8747, 8747, 514, 8750, 8750, 770, 8750, 8750, 
+    8750, 512, 8764, 824, 512, 8771, 824, 512, 8773, 824, 512, 8776, 824, 
+    512, 61, 824, 512, 8801, 824, 512, 8781, 824, 512, 60, 824, 512, 62, 824, 
+    512, 8804, 824, 512, 8805, 824, 512, 8818, 824, 512, 8819, 824, 512, 
+    8822, 824, 512, 8823, 824, 512, 8826, 824, 512, 8827, 824, 512, 8834, 
+    824, 512, 8835, 824, 512, 8838, 824, 512, 8839, 824, 512, 8866, 824, 512, 
+    8872, 824, 512, 8873, 824, 512, 8875, 824, 512, 8828, 824, 512, 8829, 
+    824, 512, 8849, 824, 512, 8850, 824, 512, 8882, 824, 512, 8883, 824, 512, 
+    8884, 824, 512, 8885, 824, 256, 12296, 256, 12297, 263, 49, 263, 50, 263, 
+    51, 263, 52, 263, 53, 263, 54, 263, 55, 263, 56, 263, 57, 519, 49, 48, 
+    519, 49, 49, 519, 49, 50, 519, 49, 51, 519, 49, 52, 519, 49, 53, 519, 49, 
+    54, 519, 49, 55, 519, 49, 56, 519, 49, 57, 519, 50, 48, 770, 40, 49, 41, 
+    770, 40, 50, 41, 770, 40, 51, 41, 770, 40, 52, 41, 770, 40, 53, 41, 770, 
+    40, 54, 41, 770, 40, 55, 41, 770, 40, 56, 41, 770, 40, 57, 41, 1026, 40, 
+    49, 48, 41, 1026, 40, 49, 49, 41, 1026, 40, 49, 50, 41, 1026, 40, 49, 51, 
+    41, 1026, 40, 49, 52, 41, 1026, 40, 49, 53, 41, 1026, 40, 49, 54, 41, 
+    1026, 40, 49, 55, 41, 1026, 40, 49, 56, 41, 1026, 40, 49, 57, 41, 1026, 
+    40, 50, 48, 41, 514, 49, 46, 514, 50, 46, 514, 51, 46, 514, 52, 46, 514, 
+    53, 46, 514, 54, 46, 514, 55, 46, 514, 56, 46, 514, 57, 46, 770, 49, 48, 
+    46, 770, 49, 49, 46, 770, 49, 50, 46, 770, 49, 51, 46, 770, 49, 52, 46, 
+    770, 49, 53, 46, 770, 49, 54, 46, 770, 49, 55, 46, 770, 49, 56, 46, 770, 
+    49, 57, 46, 770, 50, 48, 46, 770, 40, 97, 41, 770, 40, 98, 41, 770, 40, 
+    99, 41, 770, 40, 100, 41, 770, 40, 101, 41, 770, 40, 102, 41, 770, 40, 
+    103, 41, 770, 40, 104, 41, 770, 40, 105, 41, 770, 40, 106, 41, 770, 40, 
+    107, 41, 770, 40, 108, 41, 770, 40, 109, 41, 770, 40, 110, 41, 770, 40, 
+    111, 41, 770, 40, 112, 41, 770, 40, 113, 41, 770, 40, 114, 41, 770, 40, 
+    115, 41, 770, 40, 116, 41, 770, 40, 117, 41, 770, 40, 118, 41, 770, 40, 
+    119, 41, 770, 40, 120, 41, 770, 40, 121, 41, 770, 40, 122, 41, 263, 65, 
+    263, 66, 263, 67, 263, 68, 263, 69, 263, 70, 263, 71, 263, 72, 263, 73, 
+    263, 74, 263, 75, 263, 76, 263, 77, 263, 78, 263, 79, 263, 80, 263, 81, 
+    263, 82, 263, 83, 263, 84, 263, 85, 263, 86, 263, 87, 263, 88, 263, 89, 
+    263, 90, 263, 97, 263, 98, 263, 99, 263, 100, 263, 101, 263, 102, 263, 
+    103, 263, 104, 263, 105, 263, 106, 263, 107, 263, 108, 263, 109, 263, 
+    110, 263, 111, 263, 112, 263, 113, 263, 114, 263, 115, 263, 116, 263, 
+    117, 263, 118, 263, 119, 263, 120, 263, 121, 263, 122, 263, 48, 1026, 
+    8747, 8747, 8747, 8747, 770, 58, 58, 61, 514, 61, 61, 770, 61, 61, 61, 
+    512, 10973, 824, 261, 106, 259, 86, 259, 11617, 258, 27597, 258, 40863, 
+    258, 19968, 258, 20008, 258, 20022, 258, 20031, 258, 20057, 258, 20101, 
+    258, 20108, 258, 20128, 258, 20154, 258, 20799, 258, 20837, 258, 20843, 
+    258, 20866, 258, 20886, 258, 20907, 258, 20960, 258, 20981, 258, 20992, 
+    258, 21147, 258, 21241, 258, 21269, 258, 21274, 258, 21304, 258, 21313, 
+    258, 21340, 258, 21353, 258, 21378, 258, 21430, 258, 21448, 258, 21475, 
+    258, 22231, 258, 22303, 258, 22763, 258, 22786, 258, 22794, 258, 22805, 
+    258, 22823, 258, 22899, 258, 23376, 258, 23424, 258, 23544, 258, 23567, 
+    258, 23586, 258, 23608, 258, 23662, 258, 23665, 258, 24027, 258, 24037, 
+    258, 24049, 258, 24062, 258, 24178, 258, 24186, 258, 24191, 258, 24308, 
+    258, 24318, 258, 24331, 258, 24339, 258, 24400, 258, 24417, 258, 24435, 
+    258, 24515, 258, 25096, 258, 25142, 258, 25163, 258, 25903, 258, 25908, 
+    258, 25991, 258, 26007, 258, 26020, 258, 26041, 258, 26080, 258, 26085, 
+    258, 26352, 258, 26376, 258, 26408, 258, 27424, 258, 27490, 258, 27513, 
+    258, 27571, 258, 27595, 258, 27604, 258, 27611, 258, 27663, 258, 27668, 
+    258, 27700, 258, 28779, 258, 29226, 258, 29238, 258, 29243, 258, 29247, 
+    258, 29255, 258, 29273, 258, 29275, 258, 29356, 258, 29572, 258, 29577, 
+    258, 29916, 258, 29926, 258, 29976, 258, 29983, 258, 29992, 258, 30000, 
+    258, 30091, 258, 30098, 258, 30326, 258, 30333, 258, 30382, 258, 30399, 
+    258, 30446, 258, 30683, 258, 30690, 258, 30707, 258, 31034, 258, 31160, 
+    258, 31166, 258, 31348, 258, 31435, 258, 31481, 258, 31859, 258, 31992, 
+    258, 32566, 258, 32593, 258, 32650, 258, 32701, 258, 32769, 258, 32780, 
+    258, 32786, 258, 32819, 258, 32895, 258, 32905, 258, 33251, 258, 33258, 
+    258, 33267, 258, 33276, 258, 33292, 258, 33307, 258, 33311, 258, 33390, 
+    258, 33394, 258, 33400, 258, 34381, 258, 34411, 258, 34880, 258, 34892, 
+    258, 34915, 258, 35198, 258, 35211, 258, 35282, 258, 35328, 258, 35895, 
+    258, 35910, 258, 35925, 258, 35960, 258, 35997, 258, 36196, 258, 36208, 
+    258, 36275, 258, 36523, 258, 36554, 258, 36763, 258, 36784, 258, 36789, 
+    258, 37009, 258, 37193, 258, 37318, 258, 37324, 258, 37329, 258, 38263, 
+    258, 38272, 258, 38428, 258, 38582, 258, 38585, 258, 38632, 258, 38737, 
+    258, 38750, 258, 38754, 258, 38761, 258, 38859, 258, 38893, 258, 38899, 
+    258, 38913, 258, 39080, 258, 39131, 258, 39135, 258, 39318, 258, 39321, 
+    258, 39340, 258, 39592, 258, 39640, 258, 39647, 258, 39717, 258, 39727, 
+    258, 39730, 258, 39740, 258, 39770, 258, 40165, 258, 40565, 258, 40575, 
+    258, 40613, 258, 40635, 258, 40643, 258, 40653, 258, 40657, 258, 40697, 
+    258, 40701, 258, 40718, 258, 40723, 258, 40736, 258, 40763, 258, 40778, 
+    258, 40786, 258, 40845, 258, 40860, 258, 40864, 264, 32, 258, 12306, 258, 
+    21313, 258, 21316, 258, 21317, 512, 12363, 12441, 512, 12365, 12441, 512, 
+    12367, 12441, 512, 12369, 12441, 512, 12371, 12441, 512, 12373, 12441, 
+    512, 12375, 12441, 512, 12377, 12441, 512, 12379, 12441, 512, 12381, 
+    12441, 512, 12383, 12441, 512, 12385, 12441, 512, 12388, 12441, 512, 
+    12390, 12441, 512, 12392, 12441, 512, 12399, 12441, 512, 12399, 12442, 
+    512, 12402, 12441, 512, 12402, 12442, 512, 12405, 12441, 512, 12405, 
+    12442, 512, 12408, 12441, 512, 12408, 12442, 512, 12411, 12441, 512, 
+    12411, 12442, 512, 12358, 12441, 514, 32, 12441, 514, 32, 12442, 512, 
+    12445, 12441, 521, 12424, 12426, 512, 12459, 12441, 512, 12461, 12441, 
+    512, 12463, 12441, 512, 12465, 12441, 512, 12467, 12441, 512, 12469, 
+    12441, 512, 12471, 12441, 512, 12473, 12441, 512, 12475, 12441, 512, 
+    12477, 12441, 512, 12479, 12441, 512, 12481, 12441, 512, 12484, 12441, 
+    512, 12486, 12441, 512, 12488, 12441, 512, 12495, 12441, 512, 12495, 
+    12442, 512, 12498, 12441, 512, 12498, 12442, 512, 12501, 12441, 512, 
+    12501, 12442, 512, 12504, 12441, 512, 12504, 12442, 512, 12507, 12441, 
+    512, 12507, 12442, 512, 12454, 12441, 512, 12527, 12441, 512, 12528, 
+    12441, 512, 12529, 12441, 512, 12530, 12441, 512, 12541, 12441, 521, 
+    12467, 12488, 258, 4352, 258, 4353, 258, 4522, 258, 4354, 258, 4524, 258, 
+    4525, 258, 4355, 258, 4356, 258, 4357, 258, 4528, 258, 4529, 258, 4530, 
+    258, 4531, 258, 4532, 258, 4533, 258, 4378, 258, 4358, 258, 4359, 258, 
+    4360, 258, 4385, 258, 4361, 258, 4362, 258, 4363, 258, 4364, 258, 4365, 
+    258, 4366, 258, 4367, 258, 4368, 258, 4369, 258, 4370, 258, 4449, 258, 
+    4450, 258, 4451, 258, 4452, 258, 4453, 258, 4454, 258, 4455, 258, 4456, 
+    258, 4457, 258, 4458, 258, 4459, 258, 4460, 258, 4461, 258, 4462, 258, 
+    4463, 258, 4464, 258, 4465, 258, 4466, 258, 4467, 258, 4468, 258, 4469, 
+    258, 4448, 258, 4372, 258, 4373, 258, 4551, 258, 4552, 258, 4556, 258, 
+    4558, 258, 4563, 258, 4567, 258, 4569, 258, 4380, 258, 4573, 258, 4575, 
+    258, 4381, 258, 4382, 258, 4384, 258, 4386, 258, 4387, 258, 4391, 258, 
+    4393, 258, 4395, 258, 4396, 258, 4397, 258, 4398, 258, 4399, 258, 4402, 
+    258, 4406, 258, 4416, 258, 4423, 258, 4428, 258, 4593, 258, 4594, 258, 
+    4439, 258, 4440, 258, 4441, 258, 4484, 258, 4485, 258, 4488, 258, 4497, 
+    258, 4498, 258, 4500, 258, 4510, 258, 4513, 259, 19968, 259, 20108, 259, 
+    19977, 259, 22235, 259, 19978, 259, 20013, 259, 19979, 259, 30002, 259, 
+    20057, 259, 19993, 259, 19969, 259, 22825, 259, 22320, 259, 20154, 770, 
+    40, 4352, 41, 770, 40, 4354, 41, 770, 40, 4355, 41, 770, 40, 4357, 41, 
+    770, 40, 4358, 41, 770, 40, 4359, 41, 770, 40, 4361, 41, 770, 40, 4363, 
+    41, 770, 40, 4364, 41, 770, 40, 4366, 41, 770, 40, 4367, 41, 770, 40, 
+    4368, 41, 770, 40, 4369, 41, 770, 40, 4370, 41, 1026, 40, 4352, 4449, 41, 
+    1026, 40, 4354, 4449, 41, 1026, 40, 4355, 4449, 41, 1026, 40, 4357, 4449, 
+    41, 1026, 40, 4358, 4449, 41, 1026, 40, 4359, 4449, 41, 1026, 40, 4361, 
+    4449, 41, 1026, 40, 4363, 4449, 41, 1026, 40, 4364, 4449, 41, 1026, 40, 
+    4366, 4449, 41, 1026, 40, 4367, 4449, 41, 1026, 40, 4368, 4449, 41, 1026, 
+    40, 4369, 4449, 41, 1026, 40, 4370, 4449, 41, 1026, 40, 4364, 4462, 41, 
+    1794, 40, 4363, 4457, 4364, 4453, 4523, 41, 1538, 40, 4363, 4457, 4370, 
+    4462, 41, 770, 40, 19968, 41, 770, 40, 20108, 41, 770, 40, 19977, 41, 
+    770, 40, 22235, 41, 770, 40, 20116, 41, 770, 40, 20845, 41, 770, 40, 
+    19971, 41, 770, 40, 20843, 41, 770, 40, 20061, 41, 770, 40, 21313, 41, 
+    770, 40, 26376, 41, 770, 40, 28779, 41, 770, 40, 27700, 41, 770, 40, 
+    26408, 41, 770, 40, 37329, 41, 770, 40, 22303, 41, 770, 40, 26085, 41, 
+    770, 40, 26666, 41, 770, 40, 26377, 41, 770, 40, 31038, 41, 770, 40, 
+    21517, 41, 770, 40, 29305, 41, 770, 40, 36001, 41, 770, 40, 31069, 41, 
+    770, 40, 21172, 41, 770, 40, 20195, 41, 770, 40, 21628, 41, 770, 40, 
+    23398, 41, 770, 40, 30435, 41, 770, 40, 20225, 41, 770, 40, 36039, 41, 
+    770, 40, 21332, 41, 770, 40, 31085, 41, 770, 40, 20241, 41, 770, 40, 
+    33258, 41, 770, 40, 33267, 41, 263, 21839, 263, 24188, 263, 25991, 263, 
+    31631, 778, 80, 84, 69, 519, 50, 49, 519, 50, 50, 519, 50, 51, 519, 50, 
+    52, 519, 50, 53, 519, 50, 54, 519, 50, 55, 519, 50, 56, 519, 50, 57, 519, 
+    51, 48, 519, 51, 49, 519, 51, 50, 519, 51, 51, 519, 51, 52, 519, 51, 53, 
+    263, 4352, 263, 4354, 263, 4355, 263, 4357, 263, 4358, 263, 4359, 263, 
+    4361, 263, 4363, 263, 4364, 263, 4366, 263, 4367, 263, 4368, 263, 4369, 
+    263, 4370, 519, 4352, 4449, 519, 4354, 4449, 519, 4355, 4449, 519, 4357, 
+    4449, 519, 4358, 4449, 519, 4359, 4449, 519, 4361, 4449, 519, 4363, 4449, 
+    519, 4364, 4449, 519, 4366, 4449, 519, 4367, 4449, 519, 4368, 4449, 519, 
+    4369, 4449, 519, 4370, 4449, 1287, 4366, 4449, 4535, 4352, 4457, 1031, 
+    4364, 4462, 4363, 4468, 519, 4363, 4462, 263, 19968, 263, 20108, 263, 
+    19977, 263, 22235, 263, 20116, 263, 20845, 263, 19971, 263, 20843, 263, 
+    20061, 263, 21313, 263, 26376, 263, 28779, 263, 27700, 263, 26408, 263, 
+    37329, 263, 22303, 263, 26085, 263, 26666, 263, 26377, 263, 31038, 263, 
+    21517, 263, 29305, 263, 36001, 263, 31069, 263, 21172, 263, 31192, 263, 
+    30007, 263, 22899, 263, 36969, 263, 20778, 263, 21360, 263, 27880, 263, 
+    38917, 263, 20241, 263, 20889, 263, 27491, 263, 19978, 263, 20013, 263, 
+    19979, 263, 24038, 263, 21491, 263, 21307, 263, 23447, 263, 23398, 263, 
+    30435, 263, 20225, 263, 36039, 263, 21332, 263, 22812, 519, 51, 54, 519, 
+    51, 55, 519, 51, 56, 519, 51, 57, 519, 52, 48, 519, 52, 49, 519, 52, 50, 
+    519, 52, 51, 519, 52, 52, 519, 52, 53, 519, 52, 54, 519, 52, 55, 519, 52, 
+    56, 519, 52, 57, 519, 53, 48, 514, 49, 26376, 514, 50, 26376, 514, 51, 
+    26376, 514, 52, 26376, 514, 53, 26376, 514, 54, 26376, 514, 55, 26376, 
+    514, 56, 26376, 514, 57, 26376, 770, 49, 48, 26376, 770, 49, 49, 26376, 
+    770, 49, 50, 26376, 522, 72, 103, 778, 101, 114, 103, 522, 101, 86, 778, 
+    76, 84, 68, 263, 12450, 263, 12452, 263, 12454, 263, 12456, 263, 12458, 
+    263, 12459, 263, 12461, 263, 12463, 263, 12465, 263, 12467, 263, 12469, 
+    263, 12471, 263, 12473, 263, 12475, 263, 12477, 263, 12479, 263, 12481, 
+    263, 12484, 263, 12486, 263, 12488, 263, 12490, 263, 12491, 263, 12492, 
+    263, 12493, 263, 12494, 263, 12495, 263, 12498, 263, 12501, 263, 12504, 
+    263, 12507, 263, 12510, 263, 12511, 263, 12512, 263, 12513, 263, 12514, 
+    263, 12516, 263, 12518, 263, 12520, 263, 12521, 263, 12522, 263, 12523, 
+    263, 12524, 263, 12525, 263, 12527, 263, 12528, 263, 12529, 263, 12530, 
+    1034, 12450, 12497, 12540, 12488, 1034, 12450, 12523, 12501, 12449, 1034, 
+    12450, 12531, 12506, 12450, 778, 12450, 12540, 12523, 1034, 12452, 12491, 
+    12531, 12464, 778, 12452, 12531, 12481, 778, 12454, 12457, 12531, 1290, 
+    12456, 12473, 12463, 12540, 12489, 1034, 12456, 12540, 12459, 12540, 778, 
+    12458, 12531, 12473, 778, 12458, 12540, 12512, 778, 12459, 12452, 12522, 
+    1034, 12459, 12521, 12483, 12488, 1034, 12459, 12525, 12522, 12540, 778, 
+    12460, 12525, 12531, 778, 12460, 12531, 12510, 522, 12462, 12460, 778, 
+    12462, 12491, 12540, 1034, 12461, 12517, 12522, 12540, 1034, 12462, 
+    12523, 12480, 12540, 522, 12461, 12525, 1290, 12461, 12525, 12464, 12521, 
+    12512, 1546, 12461, 12525, 12513, 12540, 12488, 12523, 1290, 12461, 
+    12525, 12527, 12483, 12488, 778, 12464, 12521, 12512, 1290, 12464, 12521, 
+    12512, 12488, 12531, 1290, 12463, 12523, 12476, 12452, 12525, 1034, 
+    12463, 12525, 12540, 12493, 778, 12465, 12540, 12473, 778, 12467, 12523, 
+    12490, 778, 12467, 12540, 12509, 1034, 12469, 12452, 12463, 12523, 1290, 
+    12469, 12531, 12481, 12540, 12512, 1034, 12471, 12522, 12531, 12464, 778, 
+    12475, 12531, 12481, 778, 12475, 12531, 12488, 778, 12480, 12540, 12473, 
+    522, 12487, 12471, 522, 12489, 12523, 522, 12488, 12531, 522, 12490, 
+    12494, 778, 12494, 12483, 12488, 778, 12495, 12452, 12484, 1290, 12497, 
+    12540, 12475, 12531, 12488, 778, 12497, 12540, 12484, 1034, 12496, 12540, 
+    12524, 12523, 1290, 12500, 12450, 12473, 12488, 12523, 778, 12500, 12463, 
+    12523, 522, 12500, 12467, 522, 12499, 12523, 1290, 12501, 12449, 12521, 
+    12483, 12489, 1034, 12501, 12451, 12540, 12488, 1290, 12502, 12483, 
+    12471, 12455, 12523, 778, 12501, 12521, 12531, 1290, 12504, 12463, 12479, 
+    12540, 12523, 522, 12506, 12477, 778, 12506, 12491, 12498, 778, 12504, 
+    12523, 12484, 778, 12506, 12531, 12473, 778, 12506, 12540, 12472, 778, 
+    12505, 12540, 12479, 1034, 12509, 12452, 12531, 12488, 778, 12508, 12523, 
+    12488, 522, 12507, 12531, 778, 12509, 12531, 12489, 778, 12507, 12540, 
+    12523, 778, 12507, 12540, 12531, 1034, 12510, 12452, 12463, 12525, 778, 
+    12510, 12452, 12523, 778, 12510, 12483, 12495, 778, 12510, 12523, 12463, 
+    1290, 12510, 12531, 12471, 12519, 12531, 1034, 12511, 12463, 12525, 
+    12531, 522, 12511, 12522, 1290, 12511, 12522, 12496, 12540, 12523, 522, 
+    12513, 12460, 1034, 12513, 12460, 12488, 12531, 1034, 12513, 12540, 
+    12488, 12523, 778, 12516, 12540, 12489, 778, 12516, 12540, 12523, 778, 
+    12518, 12450, 12531, 1034, 12522, 12483, 12488, 12523, 522, 12522, 12521, 
+    778, 12523, 12500, 12540, 1034, 12523, 12540, 12502, 12523, 522, 12524, 
+    12512, 1290, 12524, 12531, 12488, 12466, 12531, 778, 12527, 12483, 12488, 
+    514, 48, 28857, 514, 49, 28857, 514, 50, 28857, 514, 51, 28857, 514, 52, 
+    28857, 514, 53, 28857, 514, 54, 28857, 514, 55, 28857, 514, 56, 28857, 
+    514, 57, 28857, 770, 49, 48, 28857, 770, 49, 49, 28857, 770, 49, 50, 
+    28857, 770, 49, 51, 28857, 770, 49, 52, 28857, 770, 49, 53, 28857, 770, 
+    49, 54, 28857, 770, 49, 55, 28857, 770, 49, 56, 28857, 770, 49, 57, 
+    28857, 770, 50, 48, 28857, 770, 50, 49, 28857, 770, 50, 50, 28857, 770, 
+    50, 51, 28857, 770, 50, 52, 28857, 778, 104, 80, 97, 522, 100, 97, 522, 
+    65, 85, 778, 98, 97, 114, 522, 111, 86, 522, 112, 99, 522, 100, 109, 778, 
+    100, 109, 178, 778, 100, 109, 179, 522, 73, 85, 522, 24179, 25104, 522, 
+    26157, 21644, 522, 22823, 27491, 522, 26126, 27835, 1034, 26666, 24335, 
+    20250, 31038, 522, 112, 65, 522, 110, 65, 522, 956, 65, 522, 109, 65, 
+    522, 107, 65, 522, 75, 66, 522, 77, 66, 522, 71, 66, 778, 99, 97, 108, 
+    1034, 107, 99, 97, 108, 522, 112, 70, 522, 110, 70, 522, 956, 70, 522, 
+    956, 103, 522, 109, 103, 522, 107, 103, 522, 72, 122, 778, 107, 72, 122, 
+    778, 77, 72, 122, 778, 71, 72, 122, 778, 84, 72, 122, 522, 956, 8467, 
+    522, 109, 8467, 522, 100, 8467, 522, 107, 8467, 522, 102, 109, 522, 110, 
+    109, 522, 956, 109, 522, 109, 109, 522, 99, 109, 522, 107, 109, 778, 109, 
+    109, 178, 778, 99, 109, 178, 522, 109, 178, 778, 107, 109, 178, 778, 109, 
+    109, 179, 778, 99, 109, 179, 522, 109, 179, 778, 107, 109, 179, 778, 109, 
+    8725, 115, 1034, 109, 8725, 115, 178, 522, 80, 97, 778, 107, 80, 97, 778, 
+    77, 80, 97, 778, 71, 80, 97, 778, 114, 97, 100, 1290, 114, 97, 100, 8725, 
+    115, 1546, 114, 97, 100, 8725, 115, 178, 522, 112, 115, 522, 110, 115, 
+    522, 956, 115, 522, 109, 115, 522, 112, 86, 522, 110, 86, 522, 956, 86, 
+    522, 109, 86, 522, 107, 86, 522, 77, 86, 522, 112, 87, 522, 110, 87, 522, 
+    956, 87, 522, 109, 87, 522, 107, 87, 522, 77, 87, 522, 107, 937, 522, 77, 
+    937, 1034, 97, 46, 109, 46, 522, 66, 113, 522, 99, 99, 522, 99, 100, 
+    1034, 67, 8725, 107, 103, 778, 67, 111, 46, 522, 100, 66, 522, 71, 121, 
+    522, 104, 97, 522, 72, 80, 522, 105, 110, 522, 75, 75, 522, 75, 77, 522, 
+    107, 116, 522, 108, 109, 522, 108, 110, 778, 108, 111, 103, 522, 108, 
+    120, 522, 109, 98, 778, 109, 105, 108, 778, 109, 111, 108, 522, 80, 72, 
+    1034, 112, 46, 109, 46, 778, 80, 80, 77, 522, 80, 82, 522, 115, 114, 522, 
+    83, 118, 522, 87, 98, 778, 86, 8725, 109, 778, 65, 8725, 109, 514, 49, 
+    26085, 514, 50, 26085, 514, 51, 26085, 514, 52, 26085, 514, 53, 26085, 
+    514, 54, 26085, 514, 55, 26085, 514, 56, 26085, 514, 57, 26085, 770, 49, 
+    48, 26085, 770, 49, 49, 26085, 770, 49, 50, 26085, 770, 49, 51, 26085, 
+    770, 49, 52, 26085, 770, 49, 53, 26085, 770, 49, 54, 26085, 770, 49, 55, 
+    26085, 770, 49, 56, 26085, 770, 49, 57, 26085, 770, 50, 48, 26085, 770, 
+    50, 49, 26085, 770, 50, 50, 26085, 770, 50, 51, 26085, 770, 50, 52, 
+    26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, 26085, 770, 
+    50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, 51, 49, 
+    26085, 778, 103, 97, 108, 259, 1098, 259, 1100, 259, 42863, 259, 294, 
+    259, 339, 259, 42791, 259, 43831, 259, 619, 259, 43858, 256, 35912, 256, 
+    26356, 256, 36554, 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256, 
+    40860, 256, 40860, 256, 22865, 256, 37329, 256, 21895, 256, 22856, 256, 
+    25078, 256, 30313, 256, 32645, 256, 34367, 256, 34746, 256, 35064, 256, 
+    37007, 256, 27138, 256, 27931, 256, 28889, 256, 29662, 256, 33853, 256, 
+    37226, 256, 39409, 256, 20098, 256, 21365, 256, 27396, 256, 29211, 256, 
+    34349, 256, 40478, 256, 23888, 256, 28651, 256, 34253, 256, 35172, 256, 
+    25289, 256, 33240, 256, 34847, 256, 24266, 256, 26391, 256, 28010, 256, 
+    29436, 256, 37070, 256, 20358, 256, 20919, 256, 21214, 256, 25796, 256, 
+    27347, 256, 29200, 256, 30439, 256, 32769, 256, 34310, 256, 34396, 256, 
+    36335, 256, 38706, 256, 39791, 256, 40442, 256, 30860, 256, 31103, 256, 
+    32160, 256, 33737, 256, 37636, 256, 40575, 256, 35542, 256, 22751, 256, 
+    24324, 256, 31840, 256, 32894, 256, 29282, 256, 30922, 256, 36034, 256, 
+    38647, 256, 22744, 256, 23650, 256, 27155, 256, 28122, 256, 28431, 256, 
+    32047, 256, 32311, 256, 38475, 256, 21202, 256, 32907, 256, 20956, 256, 
+    20940, 256, 31260, 256, 32190, 256, 33777, 256, 38517, 256, 35712, 256, 
+    25295, 256, 27138, 256, 35582, 256, 20025, 256, 23527, 256, 24594, 256, 
+    29575, 256, 30064, 256, 21271, 256, 30971, 256, 20415, 256, 24489, 256, 
+    19981, 256, 27852, 256, 25976, 256, 32034, 256, 21443, 256, 22622, 256, 
+    30465, 256, 33865, 256, 35498, 256, 27578, 256, 36784, 256, 27784, 256, 
+    25342, 256, 33509, 256, 25504, 256, 30053, 256, 20142, 256, 20841, 256, 
+    20937, 256, 26753, 256, 31975, 256, 33391, 256, 35538, 256, 37327, 256, 
+    21237, 256, 21570, 256, 22899, 256, 24300, 256, 26053, 256, 28670, 256, 
+    31018, 256, 38317, 256, 39530, 256, 40599, 256, 40654, 256, 21147, 256, 
+    26310, 256, 27511, 256, 36706, 256, 24180, 256, 24976, 256, 25088, 256, 
+    25754, 256, 28451, 256, 29001, 256, 29833, 256, 31178, 256, 32244, 256, 
+    32879, 256, 36646, 256, 34030, 256, 36899, 256, 37706, 256, 21015, 256, 
+    21155, 256, 21693, 256, 28872, 256, 35010, 256, 35498, 256, 24265, 256, 
+    24565, 256, 25467, 256, 27566, 256, 31806, 256, 29557, 256, 20196, 256, 
+    22265, 256, 23527, 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256, 
+    32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256, 
+    20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256, 
+    20698, 256, 23534, 256, 23615, 256, 26009, 256, 27138, 256, 29134, 256, 
+    30274, 256, 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256, 
+    21129, 256, 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256, 
+    30041, 256, 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256, 
+    38520, 256, 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256, 
+    24900, 256, 26647, 256, 29575, 256, 38534, 256, 21033, 256, 21519, 256, 
+    23653, 256, 26131, 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256, 
+    30178, 256, 32633, 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256, 
+    21311, 256, 28346, 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256, 
+    38563, 256, 40023, 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256, 
+    31435, 256, 31520, 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256, 
+    20160, 256, 33590, 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256, 
+    31958, 256, 23429, 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256, 
+    38477, 256, 35211, 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256, 
+    26228, 256, 20958, 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256, 
+    31077, 256, 31119, 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256, 
+    35576, 256, 36920, 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256, 
+    40372, 256, 37086, 256, 38583, 256, 20398, 256, 20711, 256, 20813, 256, 
+    21193, 256, 21220, 256, 21329, 256, 21917, 256, 22022, 256, 22120, 256, 
+    22592, 256, 22696, 256, 23652, 256, 23662, 256, 24724, 256, 24936, 256, 
+    24974, 256, 25074, 256, 25935, 256, 26082, 256, 26257, 256, 26757, 256, 
+    28023, 256, 28186, 256, 28450, 256, 29038, 256, 29227, 256, 29730, 256, 
+    30865, 256, 31038, 256, 31049, 256, 31048, 256, 31056, 256, 31062, 256, 
+    31069, 256, 31117, 256, 31118, 256, 31296, 256, 31361, 256, 31680, 256, 
+    32244, 256, 32265, 256, 32321, 256, 32626, 256, 32773, 256, 33261, 256, 
+    33401, 256, 33401, 256, 33879, 256, 35088, 256, 35222, 256, 35585, 256, 
+    35641, 256, 36051, 256, 36104, 256, 36790, 256, 36920, 256, 38627, 256, 
+    38911, 256, 38971, 256, 24693, 256, 55376, 57070, 256, 33304, 256, 20006, 
+    256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, 21191, 
+    256, 21242, 256, 21917, 256, 21845, 256, 21913, 256, 21986, 256, 22618, 
+    256, 22707, 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274, 
+    256, 24281, 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840, 
+    256, 24974, 256, 24928, 256, 25074, 256, 25140, 256, 25540, 256, 25628, 
+    256, 25682, 256, 25942, 256, 26228, 256, 26391, 256, 26395, 256, 26454, 
+    256, 27513, 256, 27578, 256, 27969, 256, 28379, 256, 28363, 256, 28450, 
+    256, 28702, 256, 29038, 256, 30631, 256, 29237, 256, 29359, 256, 29482, 
+    256, 29809, 256, 29958, 256, 30011, 256, 30237, 256, 30239, 256, 30410, 
+    256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, 31409, 
+    256, 31680, 256, 31867, 256, 32091, 256, 32244, 256, 32574, 256, 32773, 
+    256, 33618, 256, 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35222, 
+    256, 35519, 256, 35576, 256, 35531, 256, 35585, 256, 35582, 256, 35565, 
+    256, 35641, 256, 35722, 256, 36104, 256, 36664, 256, 36978, 256, 37273, 
+    256, 37494, 256, 38524, 256, 38627, 256, 38742, 256, 38875, 256, 38911, 
+    256, 38923, 256, 38971, 256, 39698, 256, 40860, 256, 55370, 56394, 256, 
+    55370, 56388, 256, 55372, 57301, 256, 15261, 256, 16408, 256, 16441, 256, 
+    55380, 56905, 256, 55383, 56528, 256, 55391, 57043, 256, 40771, 256, 
+    40846, 514, 102, 102, 514, 102, 105, 514, 102, 108, 770, 102, 102, 105, 
+    770, 102, 102, 108, 514, 383, 116, 514, 115, 116, 514, 1396, 1398, 514, 
+    1396, 1381, 514, 1396, 1387, 514, 1406, 1398, 514, 1396, 1389, 512, 1497, 
+    1460, 512, 1522, 1463, 262, 1506, 262, 1488, 262, 1491, 262, 1492, 262, 
+    1499, 262, 1500, 262, 1501, 262, 1512, 262, 1514, 262, 43, 512, 1513, 
+    1473, 512, 1513, 1474, 512, 64329, 1473, 512, 64329, 1474, 512, 1488, 
+    1463, 512, 1488, 1464, 512, 1488, 1468, 512, 1489, 1468, 512, 1490, 1468, 
+    512, 1491, 1468, 512, 1492, 1468, 512, 1493, 1468, 512, 1494, 1468, 512, 
+    1496, 1468, 512, 1497, 1468, 512, 1498, 1468, 512, 1499, 1468, 512, 1500, 
+    1468, 512, 1502, 1468, 512, 1504, 1468, 512, 1505, 1468, 512, 1507, 1468, 
+    512, 1508, 1468, 512, 1510, 1468, 512, 1511, 1468, 512, 1512, 1468, 512, 
+    1513, 1468, 512, 1514, 1468, 512, 1493, 1465, 512, 1489, 1471, 512, 1499, 
+    1471, 512, 1508, 1471, 514, 1488, 1500, 267, 1649, 268, 1649, 267, 1659, 
+    268, 1659, 269, 1659, 270, 1659, 267, 1662, 268, 1662, 269, 1662, 270, 
+    1662, 267, 1664, 268, 1664, 269, 1664, 270, 1664, 267, 1658, 268, 1658, 
+    269, 1658, 270, 1658, 267, 1663, 268, 1663, 269, 1663, 270, 1663, 267, 
+    1657, 268, 1657, 269, 1657, 270, 1657, 267, 1700, 268, 1700, 269, 1700, 
+    270, 1700, 267, 1702, 268, 1702, 269, 1702, 270, 1702, 267, 1668, 268, 
+    1668, 269, 1668, 270, 1668, 267, 1667, 268, 1667, 269, 1667, 270, 1667, 
+    267, 1670, 268, 1670, 269, 1670, 270, 1670, 267, 1671, 268, 1671, 269, 
+    1671, 270, 1671, 267, 1677, 268, 1677, 267, 1676, 268, 1676, 267, 1678, 
+    268, 1678, 267, 1672, 268, 1672, 267, 1688, 268, 1688, 267, 1681, 268, 
+    1681, 267, 1705, 268, 1705, 269, 1705, 270, 1705, 267, 1711, 268, 1711, 
+    269, 1711, 270, 1711, 267, 1715, 268, 1715, 269, 1715, 270, 1715, 267, 
+    1713, 268, 1713, 269, 1713, 270, 1713, 267, 1722, 268, 1722, 267, 1723, 
+    268, 1723, 269, 1723, 270, 1723, 267, 1728, 268, 1728, 267, 1729, 268, 
+    1729, 269, 1729, 270, 1729, 267, 1726, 268, 1726, 269, 1726, 270, 1726, 
+    267, 1746, 268, 1746, 267, 1747, 268, 1747, 267, 1709, 268, 1709, 269, 
+    1709, 270, 1709, 267, 1735, 268, 1735, 267, 1734, 268, 1734, 267, 1736, 
+    268, 1736, 267, 1655, 267, 1739, 268, 1739, 267, 1733, 268, 1733, 267, 
+    1737, 268, 1737, 267, 1744, 268, 1744, 269, 1744, 270, 1744, 269, 1609, 
+    270, 1609, 523, 1574, 1575, 524, 1574, 1575, 523, 1574, 1749, 524, 1574, 
+    1749, 523, 1574, 1608, 524, 1574, 1608, 523, 1574, 1735, 524, 1574, 1735, 
+    523, 1574, 1734, 524, 1574, 1734, 523, 1574, 1736, 524, 1574, 1736, 523, 
+    1574, 1744, 524, 1574, 1744, 525, 1574, 1744, 523, 1574, 1609, 524, 1574, 
+    1609, 525, 1574, 1609, 267, 1740, 268, 1740, 269, 1740, 270, 1740, 523, 
+    1574, 1580, 523, 1574, 1581, 523, 1574, 1605, 523, 1574, 1609, 523, 1574, 
+    1610, 523, 1576, 1580, 523, 1576, 1581, 523, 1576, 1582, 523, 1576, 1605, 
+    523, 1576, 1609, 523, 1576, 1610, 523, 1578, 1580, 523, 1578, 1581, 523, 
+    1578, 1582, 523, 1578, 1605, 523, 1578, 1609, 523, 1578, 1610, 523, 1579, 
+    1580, 523, 1579, 1605, 523, 1579, 1609, 523, 1579, 1610, 523, 1580, 1581, 
+    523, 1580, 1605, 523, 1581, 1580, 523, 1581, 1605, 523, 1582, 1580, 523, 
+    1582, 1581, 523, 1582, 1605, 523, 1587, 1580, 523, 1587, 1581, 523, 1587, 
+    1582, 523, 1587, 1605, 523, 1589, 1581, 523, 1589, 1605, 523, 1590, 1580, 
+    523, 1590, 1581, 523, 1590, 1582, 523, 1590, 1605, 523, 1591, 1581, 523, 
+    1591, 1605, 523, 1592, 1605, 523, 1593, 1580, 523, 1593, 1605, 523, 1594, 
+    1580, 523, 1594, 1605, 523, 1601, 1580, 523, 1601, 1581, 523, 1601, 1582, 
+    523, 1601, 1605, 523, 1601, 1609, 523, 1601, 1610, 523, 1602, 1581, 523, 
+    1602, 1605, 523, 1602, 1609, 523, 1602, 1610, 523, 1603, 1575, 523, 1603, 
+    1580, 523, 1603, 1581, 523, 1603, 1582, 523, 1603, 1604, 523, 1603, 1605, 
+    523, 1603, 1609, 523, 1603, 1610, 523, 1604, 1580, 523, 1604, 1581, 523, 
+    1604, 1582, 523, 1604, 1605, 523, 1604, 1609, 523, 1604, 1610, 523, 1605, 
+    1580, 523, 1605, 1581, 523, 1605, 1582, 523, 1605, 1605, 523, 1605, 1609, 
+    523, 1605, 1610, 523, 1606, 1580, 523, 1606, 1581, 523, 1606, 1582, 523, 
+    1606, 1605, 523, 1606, 1609, 523, 1606, 1610, 523, 1607, 1580, 523, 1607, 
+    1605, 523, 1607, 1609, 523, 1607, 1610, 523, 1610, 1580, 523, 1610, 1581, 
+    523, 1610, 1582, 523, 1610, 1605, 523, 1610, 1609, 523, 1610, 1610, 523, 
+    1584, 1648, 523, 1585, 1648, 523, 1609, 1648, 779, 32, 1612, 1617, 779, 
+    32, 1613, 1617, 779, 32, 1614, 1617, 779, 32, 1615, 1617, 779, 32, 1616, 
+    1617, 779, 32, 1617, 1648, 524, 1574, 1585, 524, 1574, 1586, 524, 1574, 
+    1605, 524, 1574, 1606, 524, 1574, 1609, 524, 1574, 1610, 524, 1576, 1585, 
+    524, 1576, 1586, 524, 1576, 1605, 524, 1576, 1606, 524, 1576, 1609, 524, 
+    1576, 1610, 524, 1578, 1585, 524, 1578, 1586, 524, 1578, 1605, 524, 1578, 
+    1606, 524, 1578, 1609, 524, 1578, 1610, 524, 1579, 1585, 524, 1579, 1586, 
+    524, 1579, 1605, 524, 1579, 1606, 524, 1579, 1609, 524, 1579, 1610, 524, 
+    1601, 1609, 524, 1601, 1610, 524, 1602, 1609, 524, 1602, 1610, 524, 1603, 
+    1575, 524, 1603, 1604, 524, 1603, 1605, 524, 1603, 1609, 524, 1603, 1610, 
+    524, 1604, 1605, 524, 1604, 1609, 524, 1604, 1610, 524, 1605, 1575, 524, 
+    1605, 1605, 524, 1606, 1585, 524, 1606, 1586, 524, 1606, 1605, 524, 1606, 
+    1606, 524, 1606, 1609, 524, 1606, 1610, 524, 1609, 1648, 524, 1610, 1585, 
+    524, 1610, 1586, 524, 1610, 1605, 524, 1610, 1606, 524, 1610, 1609, 524, 
+    1610, 1610, 525, 1574, 1580, 525, 1574, 1581, 525, 1574, 1582, 525, 1574, 
+    1605, 525, 1574, 1607, 525, 1576, 1580, 525, 1576, 1581, 525, 1576, 1582, 
+    525, 1576, 1605, 525, 1576, 1607, 525, 1578, 1580, 525, 1578, 1581, 525, 
+    1578, 1582, 525, 1578, 1605, 525, 1578, 1607, 525, 1579, 1605, 525, 1580, 
+    1581, 525, 1580, 1605, 525, 1581, 1580, 525, 1581, 1605, 525, 1582, 1580, 
+    525, 1582, 1605, 525, 1587, 1580, 525, 1587, 1581, 525, 1587, 1582, 525, 
+    1587, 1605, 525, 1589, 1581, 525, 1589, 1582, 525, 1589, 1605, 525, 1590, 
+    1580, 525, 1590, 1581, 525, 1590, 1582, 525, 1590, 1605, 525, 1591, 1581, 
+    525, 1592, 1605, 525, 1593, 1580, 525, 1593, 1605, 525, 1594, 1580, 525, 
+    1594, 1605, 525, 1601, 1580, 525, 1601, 1581, 525, 1601, 1582, 525, 1601, 
+    1605, 525, 1602, 1581, 525, 1602, 1605, 525, 1603, 1580, 525, 1603, 1581, 
+    525, 1603, 1582, 525, 1603, 1604, 525, 1603, 1605, 525, 1604, 1580, 525, 
+    1604, 1581, 525, 1604, 1582, 525, 1604, 1605, 525, 1604, 1607, 525, 1605, 
+    1580, 525, 1605, 1581, 525, 1605, 1582, 525, 1605, 1605, 525, 1606, 1580, 
+    525, 1606, 1581, 525, 1606, 1582, 525, 1606, 1605, 525, 1606, 1607, 525, 
+    1607, 1580, 525, 1607, 1605, 525, 1607, 1648, 525, 1610, 1580, 525, 1610, 
+    1581, 525, 1610, 1582, 525, 1610, 1605, 525, 1610, 1607, 526, 1574, 1605, 
+    526, 1574, 1607, 526, 1576, 1605, 526, 1576, 1607, 526, 1578, 1605, 526, 
+    1578, 1607, 526, 1579, 1605, 526, 1579, 1607, 526, 1587, 1605, 526, 1587, 
+    1607, 526, 1588, 1605, 526, 1588, 1607, 526, 1603, 1604, 526, 1603, 1605, 
+    526, 1604, 1605, 526, 1606, 1605, 526, 1606, 1607, 526, 1610, 1605, 526, 
+    1610, 1607, 782, 1600, 1614, 1617, 782, 1600, 1615, 1617, 782, 1600, 
+    1616, 1617, 523, 1591, 1609, 523, 1591, 1610, 523, 1593, 1609, 523, 1593, 
+    1610, 523, 1594, 1609, 523, 1594, 1610, 523, 1587, 1609, 523, 1587, 1610, 
+    523, 1588, 1609, 523, 1588, 1610, 523, 1581, 1609, 523, 1581, 1610, 523, 
+    1580, 1609, 523, 1580, 1610, 523, 1582, 1609, 523, 1582, 1610, 523, 1589, 
+    1609, 523, 1589, 1610, 523, 1590, 1609, 523, 1590, 1610, 523, 1588, 1580, 
+    523, 1588, 1581, 523, 1588, 1582, 523, 1588, 1605, 523, 1588, 1585, 523, 
+    1587, 1585, 523, 1589, 1585, 523, 1590, 1585, 524, 1591, 1609, 524, 1591, 
+    1610, 524, 1593, 1609, 524, 1593, 1610, 524, 1594, 1609, 524, 1594, 1610, 
+    524, 1587, 1609, 524, 1587, 1610, 524, 1588, 1609, 524, 1588, 1610, 524, 
+    1581, 1609, 524, 1581, 1610, 524, 1580, 1609, 524, 1580, 1610, 524, 1582, 
+    1609, 524, 1582, 1610, 524, 1589, 1609, 524, 1589, 1610, 524, 1590, 1609, 
+    524, 1590, 1610, 524, 1588, 1580, 524, 1588, 1581, 524, 1588, 1582, 524, 
+    1588, 1605, 524, 1588, 1585, 524, 1587, 1585, 524, 1589, 1585, 524, 1590, 
+    1585, 525, 1588, 1580, 525, 1588, 1581, 525, 1588, 1582, 525, 1588, 1605, 
+    525, 1587, 1607, 525, 1588, 1607, 525, 1591, 1605, 526, 1587, 1580, 526, 
+    1587, 1581, 526, 1587, 1582, 526, 1588, 1580, 526, 1588, 1581, 526, 1588, 
+    1582, 526, 1591, 1605, 526, 1592, 1605, 524, 1575, 1611, 523, 1575, 1611, 
+    781, 1578, 1580, 1605, 780, 1578, 1581, 1580, 781, 1578, 1581, 1580, 781, 
+    1578, 1581, 1605, 781, 1578, 1582, 1605, 781, 1578, 1605, 1580, 781, 
+    1578, 1605, 1581, 781, 1578, 1605, 1582, 780, 1580, 1605, 1581, 781, 
+    1580, 1605, 1581, 780, 1581, 1605, 1610, 780, 1581, 1605, 1609, 781, 
+    1587, 1581, 1580, 781, 1587, 1580, 1581, 780, 1587, 1580, 1609, 780, 
+    1587, 1605, 1581, 781, 1587, 1605, 1581, 781, 1587, 1605, 1580, 780, 
+    1587, 1605, 1605, 781, 1587, 1605, 1605, 780, 1589, 1581, 1581, 781, 
+    1589, 1581, 1581, 780, 1589, 1605, 1605, 780, 1588, 1581, 1605, 781, 
+    1588, 1581, 1605, 780, 1588, 1580, 1610, 780, 1588, 1605, 1582, 781, 
+    1588, 1605, 1582, 780, 1588, 1605, 1605, 781, 1588, 1605, 1605, 780, 
+    1590, 1581, 1609, 780, 1590, 1582, 1605, 781, 1590, 1582, 1605, 780, 
+    1591, 1605, 1581, 781, 1591, 1605, 1581, 781, 1591, 1605, 1605, 780, 
+    1591, 1605, 1610, 780, 1593, 1580, 1605, 780, 1593, 1605, 1605, 781, 
+    1593, 1605, 1605, 780, 1593, 1605, 1609, 780, 1594, 1605, 1605, 780, 
+    1594, 1605, 1610, 780, 1594, 1605, 1609, 780, 1601, 1582, 1605, 781, 
+    1601, 1582, 1605, 780, 1602, 1605, 1581, 780, 1602, 1605, 1605, 780, 
+    1604, 1581, 1605, 780, 1604, 1581, 1610, 780, 1604, 1581, 1609, 781, 
+    1604, 1580, 1580, 780, 1604, 1580, 1580, 780, 1604, 1582, 1605, 781, 
+    1604, 1582, 1605, 780, 1604, 1605, 1581, 781, 1604, 1605, 1581, 781, 
+    1605, 1581, 1580, 781, 1605, 1581, 1605, 780, 1605, 1581, 1610, 781, 
+    1605, 1580, 1581, 781, 1605, 1580, 1605, 781, 1605, 1582, 1580, 781, 
+    1605, 1582, 1605, 781, 1605, 1580, 1582, 781, 1607, 1605, 1580, 781, 
+    1607, 1605, 1605, 781, 1606, 1581, 1605, 780, 1606, 1581, 1609, 780, 
+    1606, 1580, 1605, 781, 1606, 1580, 1605, 780, 1606, 1580, 1609, 780, 
+    1606, 1605, 1610, 780, 1606, 1605, 1609, 780, 1610, 1605, 1605, 781, 
+    1610, 1605, 1605, 780, 1576, 1582, 1610, 780, 1578, 1580, 1610, 780, 
+    1578, 1580, 1609, 780, 1578, 1582, 1610, 780, 1578, 1582, 1609, 780, 
+    1578, 1605, 1610, 780, 1578, 1605, 1609, 780, 1580, 1605, 1610, 780, 
+    1580, 1581, 1609, 780, 1580, 1605, 1609, 780, 1587, 1582, 1609, 780, 
+    1589, 1581, 1610, 780, 1588, 1581, 1610, 780, 1590, 1581, 1610, 780, 
+    1604, 1580, 1610, 780, 1604, 1605, 1610, 780, 1610, 1581, 1610, 780, 
+    1610, 1580, 1610, 780, 1610, 1605, 1610, 780, 1605, 1605, 1610, 780, 
+    1602, 1605, 1610, 780, 1606, 1581, 1610, 781, 1602, 1605, 1581, 781, 
+    1604, 1581, 1605, 780, 1593, 1605, 1610, 780, 1603, 1605, 1610, 781, 
+    1606, 1580, 1581, 780, 1605, 1582, 1610, 781, 1604, 1580, 1605, 780, 
+    1603, 1605, 1605, 780, 1604, 1580, 1605, 780, 1606, 1580, 1581, 780, 
+    1580, 1581, 1610, 780, 1581, 1580, 1610, 780, 1605, 1580, 1610, 780, 
+    1601, 1605, 1610, 780, 1576, 1581, 1610, 781, 1603, 1605, 1605, 781, 
+    1593, 1580, 1605, 781, 1589, 1605, 1605, 780, 1587, 1582, 1610, 780, 
+    1606, 1580, 1610, 779, 1589, 1604, 1746, 779, 1602, 1604, 1746, 1035, 
+    1575, 1604, 1604, 1607, 1035, 1575, 1603, 1576, 1585, 1035, 1605, 1581, 
+    1605, 1583, 1035, 1589, 1604, 1593, 1605, 1035, 1585, 1587, 1608, 1604, 
+    1035, 1593, 1604, 1610, 1607, 1035, 1608, 1587, 1604, 1605, 779, 1589, 
+    1604, 1609, 4619, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, 1593, 
+    1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 2059, 1580, 1604, 32, 1580, 
+    1604, 1575, 1604, 1607, 1035, 1585, 1740, 1575, 1604, 265, 44, 265, 
+    12289, 265, 12290, 265, 58, 265, 59, 265, 33, 265, 63, 265, 12310, 265, 
+    12311, 265, 8230, 265, 8229, 265, 8212, 265, 8211, 265, 95, 265, 95, 265, 
+    40, 265, 41, 265, 123, 265, 125, 265, 12308, 265, 12309, 265, 12304, 265, 
+    12305, 265, 12298, 265, 12299, 265, 12296, 265, 12297, 265, 12300, 265, 
+    12301, 265, 12302, 265, 12303, 265, 91, 265, 93, 258, 8254, 258, 8254, 
+    258, 8254, 258, 8254, 258, 95, 258, 95, 258, 95, 271, 44, 271, 12289, 
+    271, 46, 271, 59, 271, 58, 271, 63, 271, 33, 271, 8212, 271, 40, 271, 41, 
+    271, 123, 271, 125, 271, 12308, 271, 12309, 271, 35, 271, 38, 271, 42, 
+    271, 43, 271, 45, 271, 60, 271, 62, 271, 61, 271, 92, 271, 36, 271, 37, 
+    271, 64, 523, 32, 1611, 526, 1600, 1611, 523, 32, 1612, 523, 32, 1613, 
+    523, 32, 1614, 526, 1600, 1614, 523, 32, 1615, 526, 1600, 1615, 523, 32, 
+    1616, 526, 1600, 1616, 523, 32, 1617, 526, 1600, 1617, 523, 32, 1618, 
+    526, 1600, 1618, 267, 1569, 267, 1570, 268, 1570, 267, 1571, 268, 1571, 
+    267, 1572, 268, 1572, 267, 1573, 268, 1573, 267, 1574, 268, 1574, 269, 
+    1574, 270, 1574, 267, 1575, 268, 1575, 267, 1576, 268, 1576, 269, 1576, 
+    270, 1576, 267, 1577, 268, 1577, 267, 1578, 268, 1578, 269, 1578, 270, 
+    1578, 267, 1579, 268, 1579, 269, 1579, 270, 1579, 267, 1580, 268, 1580, 
+    269, 1580, 270, 1580, 267, 1581, 268, 1581, 269, 1581, 270, 1581, 267, 
+    1582, 268, 1582, 269, 1582, 270, 1582, 267, 1583, 268, 1583, 267, 1584, 
+    268, 1584, 267, 1585, 268, 1585, 267, 1586, 268, 1586, 267, 1587, 268, 
+    1587, 269, 1587, 270, 1587, 267, 1588, 268, 1588, 269, 1588, 270, 1588, 
+    267, 1589, 268, 1589, 269, 1589, 270, 1589, 267, 1590, 268, 1590, 269, 
+    1590, 270, 1590, 267, 1591, 268, 1591, 269, 1591, 270, 1591, 267, 1592, 
+    268, 1592, 269, 1592, 270, 1592, 267, 1593, 268, 1593, 269, 1593, 270, 
+    1593, 267, 1594, 268, 1594, 269, 1594, 270, 1594, 267, 1601, 268, 1601, 
+    269, 1601, 270, 1601, 267, 1602, 268, 1602, 269, 1602, 270, 1602, 267, 
+    1603, 268, 1603, 269, 1603, 270, 1603, 267, 1604, 268, 1604, 269, 1604, 
+    270, 1604, 267, 1605, 268, 1605, 269, 1605, 270, 1605, 267, 1606, 268, 
+    1606, 269, 1606, 270, 1606, 267, 1607, 268, 1607, 269, 1607, 270, 1607, 
+    267, 1608, 268, 1608, 267, 1609, 268, 1609, 267, 1610, 268, 1610, 269, 
+    1610, 270, 1610, 523, 1604, 1570, 524, 1604, 1570, 523, 1604, 1571, 524, 
+    1604, 1571, 523, 1604, 1573, 524, 1604, 1573, 523, 1604, 1575, 524, 1604, 
+    1575, 264, 33, 264, 34, 264, 35, 264, 36, 264, 37, 264, 38, 264, 39, 264, 
+    40, 264, 41, 264, 42, 264, 43, 264, 44, 264, 45, 264, 46, 264, 47, 264, 
+    48, 264, 49, 264, 50, 264, 51, 264, 52, 264, 53, 264, 54, 264, 55, 264, 
+    56, 264, 57, 264, 58, 264, 59, 264, 60, 264, 61, 264, 62, 264, 63, 264, 
+    64, 264, 65, 264, 66, 264, 67, 264, 68, 264, 69, 264, 70, 264, 71, 264, 
+    72, 264, 73, 264, 74, 264, 75, 264, 76, 264, 77, 264, 78, 264, 79, 264, 
+    80, 264, 81, 264, 82, 264, 83, 264, 84, 264, 85, 264, 86, 264, 87, 264, 
+    88, 264, 89, 264, 90, 264, 91, 264, 92, 264, 93, 264, 94, 264, 95, 264, 
+    96, 264, 97, 264, 98, 264, 99, 264, 100, 264, 101, 264, 102, 264, 103, 
+    264, 104, 264, 105, 264, 106, 264, 107, 264, 108, 264, 109, 264, 110, 
+    264, 111, 264, 112, 264, 113, 264, 114, 264, 115, 264, 116, 264, 117, 
+    264, 118, 264, 119, 264, 120, 264, 121, 264, 122, 264, 123, 264, 124, 
+    264, 125, 264, 126, 264, 10629, 264, 10630, 272, 12290, 272, 12300, 272, 
+    12301, 272, 12289, 272, 12539, 272, 12530, 272, 12449, 272, 12451, 272, 
+    12453, 272, 12455, 272, 12457, 272, 12515, 272, 12517, 272, 12519, 272, 
+    12483, 272, 12540, 272, 12450, 272, 12452, 272, 12454, 272, 12456, 272, 
+    12458, 272, 12459, 272, 12461, 272, 12463, 272, 12465, 272, 12467, 272, 
+    12469, 272, 12471, 272, 12473, 272, 12475, 272, 12477, 272, 12479, 272, 
+    12481, 272, 12484, 272, 12486, 272, 12488, 272, 12490, 272, 12491, 272, 
+    12492, 272, 12493, 272, 12494, 272, 12495, 272, 12498, 272, 12501, 272, 
+    12504, 272, 12507, 272, 12510, 272, 12511, 272, 12512, 272, 12513, 272, 
+    12514, 272, 12516, 272, 12518, 272, 12520, 272, 12521, 272, 12522, 272, 
+    12523, 272, 12524, 272, 12525, 272, 12527, 272, 12531, 272, 12441, 272, 
+    12442, 272, 12644, 272, 12593, 272, 12594, 272, 12595, 272, 12596, 272, 
+    12597, 272, 12598, 272, 12599, 272, 12600, 272, 12601, 272, 12602, 272, 
+    12603, 272, 12604, 272, 12605, 272, 12606, 272, 12607, 272, 12608, 272, 
+    12609, 272, 12610, 272, 12611, 272, 12612, 272, 12613, 272, 12614, 272, 
+    12615, 272, 12616, 272, 12617, 272, 12618, 272, 12619, 272, 12620, 272, 
+    12621, 272, 12622, 272, 12623, 272, 12624, 272, 12625, 272, 12626, 272, 
+    12627, 272, 12628, 272, 12629, 272, 12630, 272, 12631, 272, 12632, 272, 
+    12633, 272, 12634, 272, 12635, 272, 12636, 272, 12637, 272, 12638, 272, 
+    12639, 272, 12640, 272, 12641, 272, 12642, 272, 12643, 264, 162, 264, 
+    163, 264, 172, 264, 175, 264, 166, 264, 165, 264, 8361, 272, 9474, 272, 
+    8592, 272, 8593, 272, 8594, 272, 8595, 272, 9632, 272, 9675, 512, 55300, 
+    56473, 55300, 56506, 512, 55300, 56475, 55300, 56506, 512, 55300, 56485, 
+    55300, 56506, 512, 55300, 56625, 55300, 56615, 512, 55300, 56626, 55300, 
+    56615, 512, 55300, 57159, 55300, 57150, 512, 55300, 57159, 55300, 57175, 
+    512, 55301, 56505, 55301, 56506, 512, 55301, 56505, 55301, 56496, 512, 
+    55301, 56505, 55301, 56509, 512, 55301, 56760, 55301, 56751, 512, 55301, 
+    56761, 55301, 56751, 512, 55348, 56663, 55348, 56677, 512, 55348, 56664, 
+    55348, 56677, 512, 55348, 56671, 55348, 56686, 512, 55348, 56671, 55348, 
+    56687, 512, 55348, 56671, 55348, 56688, 512, 55348, 56671, 55348, 56689, 
+    512, 55348, 56671, 55348, 56690, 512, 55348, 56761, 55348, 56677, 512, 
+    55348, 56762, 55348, 56677, 512, 55348, 56763, 55348, 56686, 512, 55348, 
+    56764, 55348, 56686, 512, 55348, 56763, 55348, 56687, 512, 55348, 56764, 
+    55348, 56687, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 
+    71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 
+    79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 
+    87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 
+    101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 
+    108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 
+    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 
+    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 
+    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 
+    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 
+    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 
+    102, 262, 103, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 
+    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 
+    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 
+    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 
+    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 
+    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 
+    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 
+    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 
+    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 
+    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 67, 262, 68, 
+    262, 71, 262, 74, 262, 75, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 
+    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 
+    262, 98, 262, 99, 262, 100, 262, 102, 262, 104, 262, 105, 262, 106, 262, 
+    107, 262, 108, 262, 109, 262, 110, 262, 112, 262, 113, 262, 114, 262, 
+    115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 
+    122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 
+    72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 
+    80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 
+    88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 
+    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 
+    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 
+    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 
+    262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 74, 262, 75, 262, 76, 
+    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 262, 84, 262, 85, 
+    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, 
+    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 
+    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 
+    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 
+    262, 122, 262, 65, 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 73, 
+    262, 74, 262, 75, 262, 76, 262, 77, 262, 79, 262, 83, 262, 84, 262, 85, 
+    262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, 
+    262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 
+    262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 
+    262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 
+    262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 
+    262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 
+    262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 
+    262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 
+    262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 
+    262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 
+    262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 
+    262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 
+    262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 
+    262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 
+    262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 
+    102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 
+    109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 
+    116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 
+    262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 
+    262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 
+    262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 
+    262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 
+    103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 
+    110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 
+    117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 
+    262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 
+    262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 
+    262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 
+    262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 
+    104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 
+    111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 
+    118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 
+    262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 
+    262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 
+    262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 
+    262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 
+    105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 
+    112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 
+    119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 
+    262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 
+    262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 
+    262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 
+    262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 
+    106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 
+    113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 
+    120, 262, 121, 262, 122, 262, 305, 262, 567, 262, 913, 262, 914, 262, 
+    915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 
+    922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 
+    929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 
+    936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 
+    949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 
+    956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 
+    963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 
+    8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 
+    913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 
+    920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 
+    927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 
+    934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 
+    947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 
+    954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 
+    961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 
+    968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 
+    1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 
+    918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 
+    925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 
+    932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 
+    945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 
+    952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 
+    959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 
+    966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 
+    1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 
+    916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 
+    923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 
+    1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 
+    937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 
+    950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 
+    957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 
+    964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 
+    1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 
+    914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 
+    921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 
+    928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 
+    935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 
+    948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 
+    955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 
+    962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 
+    969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 
+    982, 262, 988, 262, 989, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 
+    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 
+    262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 
+    262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 
+    262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 
+    262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 
+    262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 1575, 262, 1576, 262, 
+    1580, 262, 1583, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 
+    262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 
+    1601, 262, 1589, 262, 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 
+    262, 1582, 262, 1584, 262, 1590, 262, 1592, 262, 1594, 262, 1646, 262, 
+    1722, 262, 1697, 262, 1647, 262, 1576, 262, 1580, 262, 1607, 262, 1581, 
+    262, 1610, 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 
+    1593, 262, 1601, 262, 1589, 262, 1602, 262, 1588, 262, 1578, 262, 1579, 
+    262, 1582, 262, 1590, 262, 1594, 262, 1580, 262, 1581, 262, 1610, 262, 
+    1604, 262, 1606, 262, 1587, 262, 1593, 262, 1589, 262, 1602, 262, 1588, 
+    262, 1582, 262, 1590, 262, 1594, 262, 1722, 262, 1647, 262, 1576, 262, 
+    1580, 262, 1607, 262, 1581, 262, 1591, 262, 1610, 262, 1603, 262, 1605, 
+    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262, 
+    1588, 262, 1578, 262, 1579, 262, 1582, 262, 1590, 262, 1592, 262, 1594, 
+    262, 1646, 262, 1697, 262, 1575, 262, 1576, 262, 1580, 262, 1583, 262, 
+    1607, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 
+    262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 
+    1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 
+    262, 1590, 262, 1592, 262, 1594, 262, 1576, 262, 1580, 262, 1583, 262, 
+    1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 262, 1605, 
+    262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262, 
+    1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 262, 1590, 
+    262, 1592, 262, 1594, 514, 48, 46, 514, 48, 44, 514, 49, 44, 514, 50, 44, 
+    514, 51, 44, 514, 52, 44, 514, 53, 44, 514, 54, 44, 514, 55, 44, 514, 56, 
+    44, 514, 57, 44, 770, 40, 65, 41, 770, 40, 66, 41, 770, 40, 67, 41, 770, 
+    40, 68, 41, 770, 40, 69, 41, 770, 40, 70, 41, 770, 40, 71, 41, 770, 40, 
+    72, 41, 770, 40, 73, 41, 770, 40, 74, 41, 770, 40, 75, 41, 770, 40, 76, 
+    41, 770, 40, 77, 41, 770, 40, 78, 41, 770, 40, 79, 41, 770, 40, 80, 41, 
+    770, 40, 81, 41, 770, 40, 82, 41, 770, 40, 83, 41, 770, 40, 84, 41, 770, 
+    40, 85, 41, 770, 40, 86, 41, 770, 40, 87, 41, 770, 40, 88, 41, 770, 40, 
+    89, 41, 770, 40, 90, 41, 770, 12308, 83, 12309, 263, 67, 263, 82, 519, 
+    67, 68, 519, 87, 90, 266, 65, 266, 66, 266, 67, 266, 68, 266, 69, 266, 
+    70, 266, 71, 266, 72, 266, 73, 266, 74, 266, 75, 266, 76, 266, 77, 266, 
+    78, 266, 79, 266, 80, 266, 81, 266, 82, 266, 83, 266, 84, 266, 85, 266, 
+    86, 266, 87, 266, 88, 266, 89, 266, 90, 522, 72, 86, 522, 77, 86, 522, 
+    83, 68, 522, 83, 83, 778, 80, 80, 86, 522, 87, 67, 515, 77, 67, 515, 77, 
+    68, 522, 68, 74, 522, 12411, 12363, 522, 12467, 12467, 266, 12469, 266, 
+    25163, 266, 23383, 266, 21452, 266, 12487, 266, 20108, 266, 22810, 266, 
+    35299, 266, 22825, 266, 20132, 266, 26144, 266, 28961, 266, 26009, 266, 
+    21069, 266, 24460, 266, 20877, 266, 26032, 266, 21021, 266, 32066, 266, 
+    29983, 266, 36009, 266, 22768, 266, 21561, 266, 28436, 266, 25237, 266, 
+    25429, 266, 19968, 266, 19977, 266, 36938, 266, 24038, 266, 20013, 266, 
+    21491, 266, 25351, 266, 36208, 266, 25171, 266, 31105, 266, 31354, 266, 
+    21512, 266, 28288, 266, 26377, 266, 26376, 266, 30003, 266, 21106, 266, 
+    21942, 770, 12308, 26412, 12309, 770, 12308, 19977, 12309, 770, 12308, 
+    20108, 12309, 770, 12308, 23433, 12309, 770, 12308, 28857, 12309, 770, 
+    12308, 25171, 12309, 770, 12308, 30423, 12309, 770, 12308, 21213, 12309, 
+    770, 12308, 25943, 12309, 263, 24471, 263, 21487, 256, 20029, 256, 20024, 
+    256, 20033, 256, 55360, 56610, 256, 20320, 256, 20398, 256, 20411, 256, 
+    20482, 256, 20602, 256, 20633, 256, 20711, 256, 20687, 256, 13470, 256, 
+    55361, 56890, 256, 20813, 256, 20820, 256, 20836, 256, 20855, 256, 55361, 
+    56604, 256, 13497, 256, 20839, 256, 20877, 256, 55361, 56651, 256, 20887, 
+    256, 20900, 256, 20172, 256, 20908, 256, 20917, 256, 55396, 56799, 256, 
+    20981, 256, 20995, 256, 13535, 256, 21051, 256, 21062, 256, 21106, 256, 
+    21111, 256, 13589, 256, 21191, 256, 21193, 256, 21220, 256, 21242, 256, 
+    21253, 256, 21254, 256, 21271, 256, 21321, 256, 21329, 256, 21338, 256, 
+    21363, 256, 21373, 256, 21375, 256, 21375, 256, 21375, 256, 55362, 56876, 
+    256, 28784, 256, 21450, 256, 21471, 256, 55362, 57187, 256, 21483, 256, 
+    21489, 256, 21510, 256, 21662, 256, 21560, 256, 21576, 256, 21608, 256, 
+    21666, 256, 21750, 256, 21776, 256, 21843, 256, 21859, 256, 21892, 256, 
+    21892, 256, 21913, 256, 21931, 256, 21939, 256, 21954, 256, 22294, 256, 
+    22022, 256, 22295, 256, 22097, 256, 22132, 256, 20999, 256, 22766, 256, 
+    22478, 256, 22516, 256, 22541, 256, 22411, 256, 22578, 256, 22577, 256, 
+    22700, 256, 55365, 56548, 256, 22770, 256, 22775, 256, 22790, 256, 22810, 
+    256, 22818, 256, 22882, 256, 55365, 57000, 256, 55365, 57066, 256, 23020, 
+    256, 23067, 256, 23079, 256, 23000, 256, 23142, 256, 14062, 256, 14076, 
+    256, 23304, 256, 23358, 256, 23358, 256, 55366, 56776, 256, 23491, 256, 
+    23512, 256, 23527, 256, 23539, 256, 55366, 57112, 256, 23551, 256, 23558, 
+    256, 24403, 256, 23586, 256, 14209, 256, 23648, 256, 23662, 256, 23744, 
+    256, 23693, 256, 55367, 56804, 256, 23875, 256, 55367, 56806, 256, 23918, 
+    256, 23915, 256, 23932, 256, 24033, 256, 24034, 256, 14383, 256, 24061, 
+    256, 24104, 256, 24125, 256, 24169, 256, 14434, 256, 55368, 56707, 256, 
+    14460, 256, 24240, 256, 24243, 256, 24246, 256, 24266, 256, 55400, 57234, 
+    256, 24318, 256, 55368, 57137, 256, 55368, 57137, 256, 33281, 256, 24354, 
+    256, 24354, 256, 14535, 256, 55372, 57016, 256, 55384, 56794, 256, 24418, 
+    256, 24427, 256, 14563, 256, 24474, 256, 24525, 256, 24535, 256, 24569, 
+    256, 24705, 256, 14650, 256, 14620, 256, 24724, 256, 55369, 57044, 256, 
+    24775, 256, 24904, 256, 24908, 256, 24910, 256, 24908, 256, 24954, 256, 
+    24974, 256, 25010, 256, 24996, 256, 25007, 256, 25054, 256, 25074, 256, 
+    25078, 256, 25104, 256, 25115, 256, 25181, 256, 25265, 256, 25300, 256, 
+    25424, 256, 55370, 57100, 256, 25405, 256, 25340, 256, 25448, 256, 25475, 
+    256, 25572, 256, 55370, 57329, 256, 25634, 256, 25541, 256, 25513, 256, 
+    14894, 256, 25705, 256, 25726, 256, 25757, 256, 25719, 256, 14956, 256, 
+    25935, 256, 25964, 256, 55372, 56330, 256, 26083, 256, 26360, 256, 26185, 
+    256, 15129, 256, 26257, 256, 15112, 256, 15076, 256, 20882, 256, 20885, 
+    256, 26368, 256, 26268, 256, 32941, 256, 17369, 256, 26391, 256, 26395, 
+    256, 26401, 256, 26462, 256, 26451, 256, 55372, 57283, 256, 15177, 256, 
+    26618, 256, 26501, 256, 26706, 256, 26757, 256, 55373, 56429, 256, 26766, 
+    256, 26655, 256, 26900, 256, 15261, 256, 26946, 256, 27043, 256, 27114, 
+    256, 27304, 256, 55373, 56995, 256, 27355, 256, 15384, 256, 27425, 256, 
+    55374, 56487, 256, 27476, 256, 15438, 256, 27506, 256, 27551, 256, 27578, 
+    256, 27579, 256, 55374, 56973, 256, 55367, 56587, 256, 55374, 57082, 256, 
+    27726, 256, 55375, 56508, 256, 27839, 256, 27853, 256, 27751, 256, 27926, 
+    256, 27966, 256, 28023, 256, 27969, 256, 28009, 256, 28024, 256, 28037, 
+    256, 55375, 56606, 256, 27956, 256, 28207, 256, 28270, 256, 15667, 256, 
+    28363, 256, 28359, 256, 55375, 57041, 256, 28153, 256, 28526, 256, 55375, 
+    57182, 256, 55375, 57230, 256, 28614, 256, 28729, 256, 28702, 256, 28699, 
+    256, 15766, 256, 28746, 256, 28797, 256, 28791, 256, 28845, 256, 55361, 
+    56613, 256, 28997, 256, 55376, 56931, 256, 29084, 256, 55376, 57259, 256, 
+    29224, 256, 29237, 256, 29264, 256, 55377, 56840, 256, 29312, 256, 29333, 
+    256, 55377, 57141, 256, 55378, 56340, 256, 29562, 256, 29579, 256, 16044, 
+    256, 29605, 256, 16056, 256, 16056, 256, 29767, 256, 29788, 256, 29809, 
+    256, 29829, 256, 29898, 256, 16155, 256, 29988, 256, 55379, 56374, 256, 
+    30014, 256, 55379, 56466, 256, 30064, 256, 55368, 56735, 256, 30224, 256, 
+    55379, 57249, 256, 55379, 57272, 256, 55380, 56388, 256, 16380, 256, 
+    16392, 256, 30452, 256, 55380, 56563, 256, 55380, 56562, 256, 55380, 
+    56601, 256, 55380, 56627, 256, 30494, 256, 30495, 256, 30495, 256, 30538, 
+    256, 16441, 256, 30603, 256, 16454, 256, 16534, 256, 55381, 56349, 256, 
+    30798, 256, 30860, 256, 30924, 256, 16611, 256, 55381, 56870, 256, 31062, 
+    256, 55381, 56986, 256, 55381, 57029, 256, 31119, 256, 31211, 256, 16687, 
+    256, 31296, 256, 31306, 256, 31311, 256, 55382, 56700, 256, 55382, 56999, 
+    256, 55382, 56999, 256, 31470, 256, 16898, 256, 55382, 57259, 256, 31686, 
+    256, 31689, 256, 16935, 256, 55383, 56448, 256, 31954, 256, 17056, 256, 
+    31976, 256, 31971, 256, 32000, 256, 55383, 57222, 256, 32099, 256, 17153, 
+    256, 32199, 256, 32258, 256, 32325, 256, 17204, 256, 55384, 56872, 256, 
+    55384, 56903, 256, 17241, 256, 55384, 57049, 256, 32634, 256, 55384, 
+    57150, 256, 32661, 256, 32762, 256, 32773, 256, 55385, 56538, 256, 55385, 
+    56611, 256, 32864, 256, 55385, 56744, 256, 32880, 256, 55372, 57183, 256, 
+    17365, 256, 32946, 256, 33027, 256, 17419, 256, 33086, 256, 23221, 256, 
+    55385, 57255, 256, 55385, 57269, 256, 55372, 57235, 256, 55372, 57244, 
+    256, 33281, 256, 33284, 256, 36766, 256, 17515, 256, 33425, 256, 33419, 
+    256, 33437, 256, 21171, 256, 33457, 256, 33459, 256, 33469, 256, 33510, 
+    256, 55386, 57148, 256, 33509, 256, 33565, 256, 33635, 256, 33709, 256, 
+    33571, 256, 33725, 256, 33767, 256, 33879, 256, 33619, 256, 33738, 256, 
+    33740, 256, 33756, 256, 55387, 56374, 256, 55387, 56683, 256, 55387, 
+    56533, 256, 17707, 256, 34033, 256, 34035, 256, 34070, 256, 55388, 57290, 
+    256, 34148, 256, 55387, 57132, 256, 17757, 256, 17761, 256, 55387, 57265, 
+    256, 55388, 56530, 256, 17771, 256, 34384, 256, 34396, 256, 34407, 256, 
+    34409, 256, 34473, 256, 34440, 256, 34574, 256, 34530, 256, 34681, 256, 
+    34600, 256, 34667, 256, 34694, 256, 17879, 256, 34785, 256, 34817, 256, 
+    17913, 256, 34912, 256, 34915, 256, 55389, 56935, 256, 35031, 256, 35038, 
+    256, 17973, 256, 35066, 256, 13499, 256, 55390, 56494, 256, 55390, 56678, 
+    256, 18110, 256, 18119, 256, 35488, 256, 35565, 256, 35722, 256, 35925, 
+    256, 55391, 56488, 256, 36011, 256, 36033, 256, 36123, 256, 36215, 256, 
+    55391, 57135, 256, 55362, 56324, 256, 36299, 256, 36284, 256, 36336, 256, 
+    55362, 56542, 256, 36564, 256, 36664, 256, 55393, 56786, 256, 55393, 
+    56813, 256, 37012, 256, 37105, 256, 37137, 256, 55393, 57134, 256, 37147, 
+    256, 37432, 256, 37591, 256, 37592, 256, 37500, 256, 37881, 256, 37909, 
+    256, 55394, 57338, 256, 38283, 256, 18837, 256, 38327, 256, 55395, 56695, 
+    256, 18918, 256, 38595, 256, 23986, 256, 38691, 256, 55396, 56645, 256, 
+    55396, 56858, 256, 19054, 256, 19062, 256, 38880, 256, 55397, 56330, 256, 
+    19122, 256, 55397, 56470, 256, 38923, 256, 38923, 256, 38953, 256, 55397, 
+    56758, 256, 39138, 256, 19251, 256, 39209, 256, 39335, 256, 39362, 256, 
+    39422, 256, 19406, 256, 55398, 57136, 256, 39698, 256, 40000, 256, 40189, 
+    256, 19662, 256, 19693, 256, 40295, 256, 55400, 56526, 256, 19704, 256, 
+    55400, 56581, 256, 55400, 56846, 256, 55400, 56977, 256, 40635, 256, 
+    19798, 256, 40697, 256, 40702, 256, 40709, 256, 40719, 256, 40726, 256, 
+    40763, 256, 55401, 56832, 
+};
+
+/* index tables for the decomposition data */
+#define DECOMP_SHIFT1 6
+#define DECOMP_SHIFT2 4
+static const unsigned char decomp_index0[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 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, 5, 5, 13, 14, 5, 5, 5, 5, 
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 16, 5, 5, 5, 5, 17, 18, 
+    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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 20, 
+    5, 5, 5, 5, 5, 21, 22, 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, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+    23, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 5, 5, 5, 
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+};
+
+static const unsigned short decomp_index1[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 
+    14, 0, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, 
+    25, 0, 26, 27, 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 32, 33, 34, 35, 0, 
+    36, 37, 38, 0, 39, 0, 40, 0, 41, 0, 0, 0, 0, 42, 43, 44, 45, 0, 0, 0, 0, 
+    0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 48, 0, 0, 0, 
+    0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 0, 53, 0, 0, 0, 0, 
+    0, 0, 54, 55, 0, 0, 0, 0, 0, 56, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 58, 59, 0, 0, 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 
+    0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 
+    0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 70, 
+    71, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 0, 
+    82, 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, 85, 86, 87, 88, 89, 0, 90, 91, 92, 0, 0, 0, 0, 
+    93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 
+    109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 
+    123, 124, 125, 126, 127, 128, 129, 130, 0, 131, 132, 133, 134, 0, 0, 0, 
+    0, 0, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 0, 146, 0, 
+    0, 0, 147, 0, 148, 149, 150, 0, 151, 152, 153, 0, 154, 0, 0, 0, 155, 0, 
+    0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, 
+    158, 159, 160, 161, 162, 163, 164, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    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, 167, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    171, 0, 0, 0, 0, 0, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 
+    182, 183, 184, 185, 186, 0, 0, 187, 0, 0, 188, 189, 190, 191, 192, 0, 
+    193, 194, 195, 196, 197, 0, 198, 0, 0, 0, 199, 200, 201, 202, 203, 204, 
+    205, 0, 0, 0, 0, 0, 0, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 
+    216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 
+    230, 231, 232, 233, 234, 235, 236, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 
+    0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 243, 244, 245, 246, 247, 
+    248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 
+    262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 0, 0, 272, 273, 274, 
+    275, 276, 277, 278, 279, 280, 281, 282, 283, 0, 284, 285, 286, 287, 288, 
+    289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 
+    303, 304, 305, 306, 0, 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, 315, 
+    0, 316, 0, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 
+    329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 
+    343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 0, 
+    347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 352, 0, 0, 0, 0, 353, 354, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 
+    365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 
+    379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 
+    393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 
+    407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 431, 432, 433, 434, 435, 0, 436, 0, 
+    0, 437, 0, 0, 0, 0, 0, 0, 438, 439, 440, 441, 442, 443, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 444, 445, 
+    446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 
+    460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 
+    474, 475, 476, 477, 0, 0, 0, 0, 0, 0, 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 unsigned short decomp_index2[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 
+    3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27, 
+    31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81, 
+    0, 84, 87, 90, 93, 96, 99, 0, 0, 102, 105, 108, 111, 114, 0, 0, 117, 120, 
+    123, 126, 129, 132, 0, 135, 138, 141, 144, 147, 150, 153, 156, 159, 0, 
+    162, 165, 168, 171, 174, 177, 0, 0, 180, 183, 186, 189, 192, 0, 195, 198, 
+    201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 
+    243, 0, 0, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, 
+    282, 285, 288, 291, 294, 297, 300, 303, 0, 0, 306, 309, 312, 315, 318, 
+    321, 324, 327, 330, 0, 333, 336, 339, 342, 345, 348, 0, 351, 354, 357, 
+    360, 363, 366, 369, 372, 0, 0, 375, 378, 381, 384, 387, 390, 393, 0, 0, 
+    396, 399, 402, 405, 408, 411, 0, 0, 414, 417, 420, 423, 426, 429, 432, 
+    435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 0, 0, 468, 471, 
+    474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, 
+    516, 519, 522, 525, 528, 531, 534, 537, 539, 542, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 545, 548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584, 587, 
+    590, 593, 596, 599, 602, 605, 608, 611, 614, 617, 620, 623, 0, 626, 629, 
+    632, 635, 638, 641, 0, 0, 644, 647, 650, 653, 656, 659, 662, 665, 668, 
+    671, 674, 677, 680, 683, 686, 689, 0, 0, 692, 695, 698, 701, 704, 707, 
+    710, 713, 716, 719, 722, 725, 728, 731, 734, 737, 740, 743, 746, 749, 
+    752, 755, 758, 761, 764, 767, 770, 773, 776, 779, 782, 785, 788, 791, 
+    794, 797, 0, 0, 800, 803, 0, 0, 0, 0, 0, 0, 806, 809, 812, 815, 818, 821, 
+    824, 827, 830, 833, 836, 839, 842, 845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 848, 850, 852, 854, 856, 858, 860, 862, 864, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 866, 869, 872, 875, 878, 881, 0, 0, 884, 886, 888, 
+    890, 892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 894, 896, 0, 898, 900, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 905, 0, 0, 0, 
+    908, 0, 0, 0, 0, 0, 910, 913, 916, 919, 921, 924, 927, 0, 930, 0, 933, 
+    936, 939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 942, 945, 948, 951, 954, 957, 960, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 963, 966, 969, 972, 975, 
+    0, 978, 980, 982, 984, 987, 990, 992, 0, 0, 0, 0, 0, 0, 0, 0, 0, 994, 
+    996, 998, 0, 1000, 1002, 0, 0, 0, 1004, 0, 0, 0, 0, 0, 0, 1006, 1009, 0, 
+    1012, 0, 0, 0, 1015, 0, 0, 0, 0, 1018, 1021, 1024, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0, 
+    0, 0, 0, 0, 1033, 1036, 0, 1039, 0, 0, 0, 1042, 0, 0, 0, 0, 1045, 1048, 
+    1051, 0, 0, 0, 0, 0, 0, 0, 1054, 1057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1060, 
+    1063, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1069, 1072, 1075, 0, 
+    0, 1078, 1081, 0, 0, 1084, 1087, 1090, 1093, 1096, 1099, 0, 0, 1102, 
+    1105, 1108, 1111, 1114, 1117, 0, 0, 1120, 1123, 1126, 1129, 1132, 1135, 
+    1138, 1141, 1144, 1147, 1150, 1153, 0, 0, 1156, 1159, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1165, 1168, 
+    1171, 1174, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1180, 1183, 
+    1186, 1189, 0, 0, 0, 0, 0, 0, 0, 1192, 0, 1195, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 1201, 0, 0, 0, 0, 0, 0, 0, 1204, 0, 0, 1207, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1210, 1213, 1216, 
+    1219, 1222, 1225, 1228, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1234, 
+    1237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1240, 1243, 0, 1246, 
+    0, 0, 0, 1249, 0, 0, 1252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 1255, 1258, 1261, 0, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1267, 
+    0, 0, 1270, 1273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1276, 
+    1279, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 1285, 1288, 1291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    1294, 0, 0, 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, 0, 0, 1300, 1303, 0, 1306, 
+    1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1315, 1318, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1321, 0, 1324, 1327, 1330, 0, 0, 0, 0, 
+    1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1336, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1339, 1342, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1345, 0, 0, 0, 0, 0, 0, 1347, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 0, 0, 0, 1353, 0, 0, 0, 0, 1356, 0, 0, 
+    0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 1365, 0, 1368, 1371, 1374, 1377, 1380, 0, 0, 0, 0, 0, 0, 0, 
+    1383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1386, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 1389, 0, 0, 0, 0, 1392, 0, 0, 0, 0, 1395, 0, 0, 0, 0, 
+    1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1401, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 1407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1409, 0, 1412, 0, 1415, 0, 
+    1418, 0, 1421, 0, 0, 0, 1424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1427, 0, 1430, 0, 0, 1433, 1436, 0, 1439, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    1442, 1444, 1446, 0, 1448, 1450, 1452, 1454, 1456, 1458, 1460, 1462, 
+    1464, 1466, 1468, 0, 1470, 1472, 1474, 1476, 1478, 1480, 1482, 1484, 
+    1486, 1488, 1490, 1492, 1494, 1496, 1498, 1500, 1502, 1504, 0, 1506, 
+    1508, 1510, 1512, 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1530, 
+    1532, 1534, 1536, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554, 
+    1556, 1558, 1560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1562, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1564, 1566, 1568, 1570, 
+    1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594, 
+    1596, 1598, 1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614, 1616, 1618, 
+    1620, 1622, 1624, 1626, 1628, 1630, 1632, 1634, 1636, 1638, 1641, 1644, 
+    1647, 1650, 1653, 1656, 1659, 1662, 1665, 1668, 1671, 1674, 1677, 1680, 
+    1683, 1686, 1689, 1692, 1695, 1698, 1701, 1704, 1707, 1710, 1713, 1716, 
+    1719, 1722, 1725, 1728, 1731, 1734, 1737, 1740, 1743, 1746, 1749, 1752, 
+    1755, 1758, 1761, 1764, 1767, 1770, 1773, 1776, 1779, 1782, 1785, 1788, 
+    1791, 1794, 1797, 1800, 1803, 1806, 1809, 1812, 1815, 1818, 1821, 1824, 
+    1827, 1830, 1833, 1836, 1839, 1842, 1845, 1848, 1851, 1854, 1857, 1860, 
+    1863, 1866, 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896, 
+    1899, 1902, 1905, 1908, 1911, 1914, 1917, 1920, 1923, 1926, 1929, 1932, 
+    1935, 1938, 1941, 1944, 1947, 1950, 1953, 1956, 1959, 1962, 1965, 1968, 
+    1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004, 
+    2007, 2010, 2013, 2016, 2019, 2022, 2025, 2028, 2031, 2034, 2037, 2040, 
+    2043, 2046, 2049, 2052, 2055, 2058, 2061, 2064, 2067, 2070, 2073, 2076, 
+    2079, 2082, 2085, 2088, 2091, 2094, 2097, 2100, 2103, 0, 0, 0, 0, 2106, 
+    2109, 2112, 2115, 2118, 2121, 2124, 2127, 2130, 2133, 2136, 2139, 2142, 
+    2145, 2148, 2151, 2154, 2157, 2160, 2163, 2166, 2169, 2172, 2175, 2178, 
+    2181, 2184, 2187, 2190, 2193, 2196, 2199, 2202, 2205, 2208, 2211, 2214, 
+    2217, 2220, 2223, 2226, 2229, 2232, 2235, 2238, 2241, 2244, 2247, 2250, 
+    2253, 2256, 2259, 2262, 2265, 2268, 2271, 2274, 2277, 2280, 2283, 2286, 
+    2289, 2292, 2295, 2298, 2301, 2304, 2307, 2310, 2313, 2316, 2319, 2322, 
+    2325, 2328, 2331, 2334, 2337, 2340, 2343, 2346, 2349, 2352, 2355, 2358, 
+    2361, 2364, 2367, 2370, 2373, 0, 0, 0, 0, 0, 0, 2376, 2379, 2382, 2385, 
+    2388, 2391, 2394, 2397, 2400, 2403, 2406, 2409, 2412, 2415, 2418, 2421, 
+    2424, 2427, 2430, 2433, 2436, 2439, 0, 0, 2442, 2445, 2448, 2451, 2454, 
+    2457, 0, 0, 2460, 2463, 2466, 2469, 2472, 2475, 2478, 2481, 2484, 2487, 
+    2490, 2493, 2496, 2499, 2502, 2505, 2508, 2511, 2514, 2517, 2520, 2523, 
+    2526, 2529, 2532, 2535, 2538, 2541, 2544, 2547, 2550, 2553, 2556, 2559, 
+    2562, 2565, 2568, 2571, 0, 0, 2574, 2577, 2580, 2583, 2586, 2589, 0, 0, 
+    2592, 2595, 2598, 2601, 2604, 2607, 2610, 2613, 0, 2616, 0, 2619, 0, 
+    2622, 0, 2625, 2628, 2631, 2634, 2637, 2640, 2643, 2646, 2649, 2652, 
+    2655, 2658, 2661, 2664, 2667, 2670, 2673, 2676, 2679, 2681, 2684, 2686, 
+    2689, 2691, 2694, 2696, 2699, 2701, 2704, 2706, 2709, 0, 0, 2711, 2714, 
+    2717, 2720, 2723, 2726, 2729, 2732, 2735, 2738, 2741, 2744, 2747, 2750, 
+    2753, 2756, 2759, 2762, 2765, 2768, 2771, 2774, 2777, 2780, 2783, 2786, 
+    2789, 2792, 2795, 2798, 2801, 2804, 2807, 2810, 2813, 2816, 2819, 2822, 
+    2825, 2828, 2831, 2834, 2837, 2840, 2843, 2846, 2849, 2852, 2855, 2858, 
+    2861, 2864, 2867, 0, 2870, 2873, 2876, 2879, 2882, 2885, 2887, 2890, 
+    2893, 2895, 2898, 2901, 2904, 2907, 2910, 0, 2913, 2916, 2919, 2922, 
+    2924, 2927, 2929, 2932, 2935, 2938, 2941, 2944, 2947, 2950, 0, 0, 2952, 
+    2955, 2958, 2961, 2964, 2967, 0, 2969, 2972, 2975, 2978, 2981, 2984, 
+    2987, 2989, 2992, 2995, 2998, 3001, 3004, 3007, 3010, 3012, 3015, 3018, 
+    3020, 0, 0, 3022, 3025, 3028, 0, 3031, 3034, 3037, 3040, 3042, 3045, 
+    3047, 3050, 3052, 0, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069, 
+    3071, 3073, 3075, 0, 0, 0, 0, 0, 0, 3077, 0, 0, 0, 0, 0, 3079, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 3082, 3084, 3087, 0, 0, 0, 0, 0, 0, 0, 0, 
+    3091, 0, 0, 0, 3093, 3096, 0, 3100, 3103, 0, 0, 0, 0, 3107, 0, 3110, 0, 
+    0, 0, 0, 0, 0, 0, 0, 3113, 3116, 3119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 3122, 0, 0, 0, 0, 0, 0, 0, 3127, 3129, 3131, 0, 0, 3133, 3135, 
+    3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159, 
+    3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183, 
+    3185, 0, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205, 
+    3207, 3209, 3211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3213, 0, 0, 0, 0, 0, 
+    0, 0, 3216, 3220, 3224, 3226, 0, 3229, 3233, 3237, 0, 3239, 3242, 3244, 
+    3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 0, 3262, 3264, 0, 0, 
+    3267, 3269, 3271, 3273, 3275, 0, 0, 3277, 3280, 3284, 0, 3287, 0, 3289, 
+    0, 3291, 0, 3293, 3295, 3297, 3299, 0, 3301, 3303, 3305, 0, 3307, 3309, 
+    3311, 3313, 3315, 3317, 3319, 0, 3321, 3325, 3327, 3329, 3331, 3333, 0, 
+    0, 0, 0, 3335, 3337, 3339, 3341, 3343, 0, 0, 0, 0, 0, 0, 3345, 3349, 
+    3353, 3358, 3362, 3366, 3370, 3374, 3378, 3382, 3386, 3390, 3394, 3398, 
+    3402, 3406, 3409, 3411, 3414, 3418, 3421, 3423, 3426, 3430, 3435, 3438, 
+    3440, 3443, 3447, 3449, 3451, 3453, 3455, 3457, 3460, 3464, 3467, 3469, 
+    3472, 3476, 3481, 3484, 3486, 3489, 3493, 3495, 3497, 3499, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 3501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    3505, 3508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3511, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3514, 3517, 3520, 0, 0, 0, 0, 
+    3523, 0, 0, 0, 0, 3526, 0, 0, 3529, 0, 0, 0, 0, 0, 0, 0, 3532, 0, 3535, 
+    0, 0, 0, 0, 0, 3538, 3541, 0, 3545, 3548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 3552, 0, 0, 3555, 0, 0, 3558, 0, 3561, 0, 0, 0, 0, 0, 
+    0, 3564, 0, 3567, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3570, 3573, 3576, 3579, 
+    3582, 0, 0, 3585, 3588, 0, 0, 3591, 3594, 0, 0, 0, 0, 0, 0, 3597, 3600, 
+    0, 0, 3603, 3606, 0, 0, 3609, 3612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 3615, 3618, 3621, 3624, 3627, 3630, 3633, 3636, 0, 0, 
+    0, 0, 0, 0, 3639, 3642, 3645, 3648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    3651, 3653, 0, 0, 0, 0, 0, 3655, 3657, 3659, 3661, 3663, 3665, 3667, 
+    3669, 3671, 3673, 3676, 3679, 3682, 3685, 3688, 3691, 3694, 3697, 3700, 
+    3703, 3706, 3710, 3714, 3718, 3722, 3726, 3730, 3734, 3738, 3742, 3747, 
+    3752, 3757, 3762, 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3800, 3803, 
+    3806, 3809, 3812, 3815, 3818, 3821, 3824, 3828, 3832, 3836, 3840, 3844, 
+    3848, 3852, 3856, 3860, 3864, 3868, 3872, 3876, 3880, 3884, 3888, 3892, 
+    3896, 3900, 3904, 3908, 3912, 3916, 3920, 3924, 3928, 3932, 3936, 3940, 
+    3944, 3948, 3952, 3956, 3960, 3964, 3968, 3972, 3974, 3976, 3978, 3980, 
+    3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, 
+    4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4024, 4026, 4028, 
+    4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046, 4048, 4050, 4052, 
+    4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4078, 0, 0, 0, 0, 0, 
+    0, 0, 4083, 4087, 4090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 4094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4097, 
+    4099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4101, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4103, 0, 0, 0, 4105, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121, 
+    4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145, 
+    4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169, 
+    4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193, 
+    4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217, 
+    4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241, 
+    4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265, 
+    4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289, 
+    4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313, 
+    4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337, 
+    4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361, 
+    4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385, 
+    4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409, 
+    4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433, 
+    4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457, 
+    4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481, 
+    4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505, 
+    4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529, 
+    4531, 4533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4535, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4537, 0, 4539, 4541, 4543, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4545, 0, 4548, 0, 4551, 0, 
+    4554, 0, 4557, 0, 4560, 0, 4563, 0, 4566, 0, 4569, 0, 4572, 0, 4575, 0, 
+    4578, 0, 0, 4581, 0, 4584, 0, 4587, 0, 0, 0, 0, 0, 0, 4590, 4593, 0, 
+    4596, 4599, 0, 4602, 4605, 0, 4608, 4611, 0, 4614, 4617, 0, 0, 0, 0, 0, 
+    0, 4620, 0, 0, 0, 0, 0, 0, 4623, 4626, 0, 4629, 4632, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 4635, 0, 4638, 0, 4641, 0, 4644, 0, 4647, 0, 4650, 0, 
+    4653, 0, 4656, 0, 4659, 0, 4662, 0, 4665, 0, 4668, 0, 0, 4671, 0, 4674, 
+    0, 4677, 0, 0, 0, 0, 0, 0, 4680, 4683, 0, 4686, 4689, 0, 4692, 4695, 0, 
+    4698, 4701, 0, 4704, 4707, 0, 0, 0, 0, 0, 0, 4710, 0, 0, 4713, 4716, 
+    4719, 4722, 0, 0, 0, 4725, 4728, 0, 4731, 4733, 4735, 4737, 4739, 4741, 
+    4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765, 
+    4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789, 
+    4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813, 
+    4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837, 
+    4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861, 
+    4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885, 
+    4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909, 
+    4911, 4913, 4915, 4917, 0, 0, 0, 4919, 4921, 4923, 4925, 4927, 4929, 
+    4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4951, 4955, 4959, 
+    4963, 4967, 4971, 4975, 4979, 4983, 4987, 4991, 4995, 4999, 5003, 5008, 
+    5013, 5018, 5023, 5028, 5033, 5038, 5043, 5048, 5053, 5058, 5063, 5068, 
+    5073, 5078, 5086, 0, 5093, 5097, 5101, 5105, 5109, 5113, 5117, 5121, 
+    5125, 5129, 5133, 5137, 5141, 5145, 5149, 5153, 5157, 5161, 5165, 5169, 
+    5173, 5177, 5181, 5185, 5189, 5193, 5197, 5201, 5205, 5209, 5213, 5217, 
+    5221, 5225, 5229, 5233, 5237, 5239, 5241, 5243, 0, 0, 0, 0, 0, 0, 0, 0, 
+    5245, 5249, 5252, 5255, 5258, 5261, 5264, 5267, 5270, 5273, 5276, 5279, 
+    5282, 5285, 5288, 5291, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308, 
+    5310, 5312, 5314, 5316, 5318, 5320, 5322, 5325, 5328, 5331, 5334, 5337, 
+    5340, 5343, 5346, 5349, 5352, 5355, 5358, 5361, 5364, 5370, 5375, 0, 
+    5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, 5396, 5398, 5400, 
+    5402, 5404, 5406, 5408, 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424, 
+    5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448, 
+    5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, 5470, 5472, 
+    5474, 5476, 5479, 5482, 5485, 5488, 5491, 5494, 5497, 5500, 5503, 5506, 
+    5509, 5512, 5515, 5518, 5521, 5524, 5527, 5530, 5533, 5536, 5539, 5542, 
+    5545, 5548, 5552, 5556, 5560, 5563, 5567, 5570, 5574, 5576, 5578, 5580, 
+    5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604, 
+    5606, 5608, 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628, 
+    5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652, 
+    5654, 5656, 5658, 5660, 5662, 5664, 5666, 0, 5668, 5673, 5678, 5683, 
+    5687, 5692, 5696, 5700, 5706, 5711, 5715, 5719, 5723, 5728, 5733, 5737, 
+    5741, 5744, 5748, 5753, 5758, 5761, 5767, 5774, 5780, 5784, 5790, 5796, 
+    5801, 5805, 5809, 5813, 5818, 5824, 5829, 5833, 5837, 5841, 5844, 5847, 
+    5850, 5853, 5857, 5861, 5867, 5871, 5876, 5882, 5886, 5889, 5892, 5898, 
+    5903, 5909, 5913, 5919, 5922, 5926, 5930, 5934, 5938, 5942, 5947, 5951, 
+    5954, 5958, 5962, 5966, 5971, 5975, 5979, 5983, 5989, 5994, 5997, 6003, 
+    6006, 6011, 6016, 6020, 6024, 6028, 6033, 6036, 6040, 6045, 6048, 6054, 
+    6058, 6061, 6064, 6067, 6070, 6073, 6076, 6079, 6082, 6085, 6088, 6092, 
+    6096, 6100, 6104, 6108, 6112, 6116, 6120, 6124, 6128, 6132, 6136, 6140, 
+    6144, 6148, 6152, 6155, 6158, 6162, 6165, 6168, 6171, 6175, 6179, 6182, 
+    6185, 6188, 6191, 6194, 6199, 6202, 6205, 6208, 6211, 6214, 6217, 6220, 
+    6223, 6227, 6232, 6235, 6238, 6241, 6244, 6247, 6250, 6253, 6257, 6261, 
+    6265, 6269, 6272, 6275, 6278, 6281, 6284, 6287, 6290, 6293, 6296, 6299, 
+    6303, 6307, 6310, 6314, 6318, 6322, 6325, 6329, 6333, 6338, 6341, 6345, 
+    6349, 6353, 6357, 6363, 6370, 6373, 6376, 6379, 6382, 6385, 6388, 6391, 
+    6394, 6397, 6400, 6403, 6406, 6409, 6412, 6415, 6418, 6421, 6424, 6429, 
+    6432, 6435, 6438, 6443, 6447, 6450, 6453, 6456, 6459, 6462, 6465, 6468, 
+    6471, 6474, 6477, 6481, 6484, 6487, 6491, 6495, 6498, 6503, 6507, 6510, 
+    6513, 6516, 6519, 6523, 6527, 6530, 6533, 6536, 6539, 6542, 6545, 6548, 
+    6551, 6554, 6558, 6562, 6566, 6570, 6574, 6578, 6582, 6586, 6590, 6594, 
+    6598, 6602, 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, 6638, 6642, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6646, 6648, 0, 0, 6650, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6652, 6654, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6656, 6658, 6660, 
+    6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684, 
+    6686, 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708, 
+    6710, 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732, 
+    6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756, 
+    6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780, 
+    6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804, 
+    6806, 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828, 
+    6830, 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852, 
+    6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876, 
+    6878, 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900, 
+    6902, 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924, 
+    6926, 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948, 
+    6950, 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972, 
+    6974, 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996, 
+    6998, 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020, 
+    7022, 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044, 
+    7046, 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068, 
+    7070, 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092, 
+    7094, 7096, 7098, 7100, 7102, 7104, 7106, 7108, 7110, 7112, 7114, 7116, 
+    7118, 7120, 7122, 7124, 7126, 7128, 7130, 7132, 7134, 7136, 7138, 7140, 
+    7142, 7144, 7146, 7148, 7150, 7152, 7154, 7156, 7158, 7160, 7162, 7164, 
+    7166, 7168, 7170, 7172, 7174, 7176, 7178, 7180, 7182, 7184, 7186, 7188, 
+    7190, 7192, 7194, 7196, 7198, 7200, 7202, 0, 0, 7204, 0, 7206, 0, 0, 
+    7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, 7224, 7226, 0, 7228, 0, 
+    7230, 0, 0, 7232, 7234, 0, 0, 0, 7236, 7238, 7240, 7242, 7244, 7246, 
+    7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 7266, 7268, 7270, 
+    7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, 7290, 7292, 7294, 
+    7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, 7314, 7316, 7318, 
+    7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, 7338, 7340, 7342, 
+    7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, 7362, 7364, 7366, 
+    7368, 7371, 0, 0, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389, 
+    7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413, 
+    7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437, 
+    7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461, 
+    7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485, 
+    7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509, 
+    7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533, 
+    7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557, 
+    7559, 7561, 7563, 7566, 7569, 7572, 7574, 7576, 7578, 7581, 7584, 7587, 
+    7589, 0, 0, 0, 0, 0, 0, 7591, 7594, 7597, 7600, 7604, 7608, 7611, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7614, 7617, 7620, 7623, 7626, 0, 0, 0, 0, 
+    0, 7629, 0, 7632, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651, 
+    7653, 7655, 7658, 7661, 7664, 7667, 7670, 7673, 7676, 7679, 7682, 7685, 
+    7688, 7691, 0, 7694, 7697, 7700, 7703, 7706, 0, 7709, 0, 7712, 7715, 0, 
+    7718, 7721, 0, 7724, 7727, 7730, 7733, 7736, 7739, 7742, 7745, 7748, 
+    7751, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 
+    7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 
+    7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 
+    7824, 7826, 7828, 7830, 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846, 
+    7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 
+    7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 
+    7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 
+    7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7936, 7938, 7940, 7942, 
+    7944, 7946, 7948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    7950, 7952, 7954, 7956, 7958, 7960, 7962, 7964, 7966, 7968, 7970, 7972, 
+    7974, 7976, 7978, 7980, 7982, 7984, 7986, 7988, 7990, 7992, 7994, 7996, 
+    7999, 8002, 8005, 8008, 8011, 8014, 8017, 8020, 8023, 8026, 8029, 8032, 
+    8035, 8038, 8041, 8044, 8047, 8050, 8052, 8054, 8056, 8058, 8061, 8064, 
+    8067, 8070, 8073, 8076, 8079, 8082, 8085, 8088, 8091, 8094, 8097, 8100, 
+    8103, 8106, 8109, 8112, 8115, 8118, 8121, 8124, 8127, 8130, 8133, 8136, 
+    8139, 8142, 8145, 8148, 8151, 8154, 8157, 8160, 8163, 8166, 8169, 8172, 
+    8175, 8178, 8181, 8184, 8187, 8190, 8193, 8196, 8199, 8202, 8205, 8208, 
+    8211, 8214, 8217, 8220, 8223, 8226, 8229, 8232, 8235, 8238, 8241, 8244, 
+    8247, 8250, 8253, 8256, 8259, 8262, 8265, 8268, 8271, 8274, 8277, 8280, 
+    8283, 8286, 8289, 8292, 8295, 8298, 8301, 8304, 8307, 8310, 8313, 8316, 
+    8319, 8322, 8325, 8328, 8331, 8334, 8337, 8340, 8344, 8348, 8352, 8356, 
+    8360, 8364, 8367, 8370, 8373, 8376, 8379, 8382, 8385, 8388, 8391, 8394, 
+    8397, 8400, 8403, 8406, 8409, 8412, 8415, 8418, 8421, 8424, 8427, 8430, 
+    8433, 8436, 8439, 8442, 8445, 8448, 8451, 8454, 8457, 8460, 8463, 8466, 
+    8469, 8472, 8475, 8478, 8481, 8484, 8487, 8490, 8493, 8496, 8499, 8502, 
+    8505, 8508, 8511, 8514, 8517, 8520, 8523, 8526, 8529, 8532, 8535, 8538, 
+    8541, 8544, 8547, 8550, 8553, 8556, 8559, 8562, 8565, 8568, 8571, 8574, 
+    8577, 8580, 8583, 8586, 8589, 8592, 8595, 8598, 8601, 8604, 8607, 8610, 
+    8613, 8616, 8619, 8622, 8625, 8628, 8631, 8634, 8637, 8640, 8643, 8646, 
+    8649, 8652, 8655, 8658, 8661, 8664, 8667, 8670, 8673, 8676, 8679, 8682, 
+    8685, 8688, 8691, 8694, 8697, 8700, 8703, 8706, 8709, 8712, 8715, 8718, 
+    8721, 8724, 8727, 8730, 8733, 8736, 8739, 8742, 8745, 8748, 8751, 8754, 
+    8757, 8760, 8763, 8766, 8769, 8772, 8775, 8778, 8781, 8784, 8787, 8790, 
+    8794, 8798, 8802, 8805, 8808, 8811, 8814, 8817, 8820, 8823, 8826, 8829, 
+    8832, 8835, 8838, 8841, 8844, 8847, 8850, 8853, 8856, 8859, 8862, 8865, 
+    8868, 8871, 8874, 8877, 8880, 8883, 8886, 8889, 8892, 8895, 8898, 8901, 
+    8904, 8907, 8910, 8913, 8916, 8919, 8922, 8925, 8928, 8931, 8934, 8937, 
+    8940, 8943, 8946, 8949, 8952, 8955, 8958, 8961, 8964, 8967, 8970, 8973, 
+    8976, 8979, 8982, 8985, 8988, 8991, 8994, 8997, 9000, 9003, 9006, 9009, 
+    9012, 9015, 9018, 0, 0, 9021, 9025, 9029, 9033, 9037, 9041, 9045, 9049, 
+    9053, 9057, 9061, 9065, 9069, 9073, 9077, 9081, 9085, 9089, 9093, 9097, 
+    9101, 9105, 9109, 9113, 9117, 9121, 9125, 9129, 9133, 9137, 9141, 9145, 
+    9149, 9153, 9157, 9161, 9165, 9169, 9173, 9177, 9181, 9185, 9189, 9193, 
+    9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9233, 9237, 9241, 
+    9245, 9249, 9253, 9257, 9261, 9265, 9269, 9273, 0, 0, 9277, 9281, 9285, 
+    9289, 9293, 9297, 9301, 9305, 9309, 9313, 9317, 9321, 9325, 9329, 9333, 
+    9337, 9341, 9345, 9349, 9353, 9357, 9361, 9365, 9369, 9373, 9377, 9381, 
+    9385, 9389, 9393, 9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429, 
+    9433, 9437, 9441, 9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477, 
+    9481, 9485, 9489, 0, 0, 0, 0, 0, 0, 0, 0, 9493, 9497, 9501, 9506, 9511, 
+    9516, 9521, 9526, 9531, 9536, 9540, 9559, 9568, 0, 0, 0, 9573, 9575, 
+    9577, 9579, 9581, 9583, 9585, 9587, 9589, 9591, 0, 0, 0, 0, 0, 0, 9593, 
+    9595, 9597, 9599, 9601, 9603, 9605, 9607, 9609, 9611, 9613, 9615, 9617, 
+    9619, 9621, 9623, 9625, 9627, 9629, 9631, 9633, 0, 0, 9635, 9637, 9639, 
+    9641, 9643, 9645, 9647, 9649, 9651, 9653, 9655, 9657, 0, 9659, 9661, 
+    9663, 9665, 9667, 9669, 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685, 
+    9687, 9689, 9691, 9693, 9695, 0, 9697, 9699, 9701, 9703, 0, 0, 0, 0, 
+    9705, 9708, 9711, 0, 9714, 0, 9717, 9720, 9723, 9726, 9729, 9732, 9735, 
+    9738, 9741, 9744, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763, 
+    9765, 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787, 
+    9789, 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811, 
+    9813, 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835, 
+    9837, 9839, 9841, 9843, 9845, 9847, 9849, 9851, 9853, 9855, 9857, 9859, 
+    9861, 9863, 9865, 9867, 9869, 9871, 9873, 9875, 9877, 9879, 9881, 9883, 
+    9885, 9887, 9889, 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907, 
+    9909, 9911, 9913, 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931, 
+    9933, 9935, 9937, 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955, 
+    9957, 9959, 9961, 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979, 
+    9981, 9984, 9987, 9990, 9993, 9996, 9999, 10002, 0, 0, 0, 0, 10005, 
+    10007, 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025, 
+    10027, 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045, 
+    10047, 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065, 
+    10067, 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085, 
+    10087, 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105, 
+    10107, 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125, 
+    10127, 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145, 
+    10147, 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165, 
+    10167, 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185, 
+    10187, 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205, 
+    10207, 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225, 
+    10227, 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245, 
+    10247, 10249, 10251, 10253, 10255, 10257, 10259, 10261, 10263, 10265, 
+    10267, 10269, 10271, 10273, 10275, 10277, 10279, 10281, 10283, 10285, 
+    10287, 10289, 10291, 10293, 10295, 10297, 10299, 10301, 10303, 10305, 
+    10307, 10309, 10311, 10313, 10315, 10317, 10319, 10321, 10323, 10325, 
+    10327, 10329, 10331, 10333, 10335, 10337, 10339, 10341, 10343, 10345, 
+    10347, 10349, 10351, 10353, 10355, 10357, 10359, 10361, 10363, 10365, 
+    10367, 10369, 10371, 10373, 10375, 10377, 10379, 10381, 10383, 0, 0, 0, 
+    10385, 10387, 10389, 10391, 10393, 10395, 0, 0, 10397, 10399, 10401, 
+    10403, 10405, 10407, 0, 0, 10409, 10411, 10413, 10415, 10417, 10419, 0, 
+    0, 10421, 10423, 10425, 0, 0, 0, 10427, 10429, 10431, 10433, 10435, 
+    10437, 10439, 0, 10441, 10443, 10445, 10447, 10449, 10451, 10453, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 10455, 0, 10460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 10465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    10470, 10475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10480, 10485, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10490, 10495, 0, 10500, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 10505, 10510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 0, 0, 10515, 10520, 10525, 10530, 10535, 10540, 10545, 0, 0, 0, 0, 0, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10550, 10555, 10560, 
+    10565, 10570, 10575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10580, 
+    10582, 10584, 10586, 10588, 10590, 10592, 10594, 10596, 10598, 10600, 
+    10602, 10604, 10606, 10608, 10610, 10612, 10614, 10616, 10618, 10620, 
+    10622, 10624, 10626, 10628, 10630, 10632, 10634, 10636, 10638, 10640, 
+    10642, 10644, 10646, 10648, 10650, 10652, 10654, 10656, 10658, 10660, 
+    10662, 10664, 10666, 10668, 10670, 10672, 10674, 10676, 10678, 10680, 
+    10682, 10684, 10686, 10688, 10690, 10692, 10694, 10696, 10698, 10700, 
+    10702, 10704, 10706, 10708, 10710, 10712, 10714, 10716, 10718, 10720, 
+    10722, 10724, 10726, 10728, 10730, 10732, 10734, 10736, 10738, 10740, 
+    10742, 10744, 10746, 10748, 0, 10750, 10752, 10754, 10756, 10758, 10760, 
+    10762, 10764, 10766, 10768, 10770, 10772, 10774, 10776, 10778, 10780, 
+    10782, 10784, 10786, 10788, 10790, 10792, 10794, 10796, 10798, 10800, 
+    10802, 10804, 10806, 10808, 10810, 10812, 10814, 10816, 10818, 10820, 
+    10822, 10824, 10826, 10828, 10830, 10832, 10834, 10836, 10838, 10840, 
+    10842, 10844, 10846, 10848, 10850, 10852, 10854, 10856, 10858, 10860, 
+    10862, 10864, 10866, 10868, 10870, 10872, 10874, 10876, 10878, 10880, 
+    10882, 10884, 10886, 10888, 10890, 0, 10892, 10894, 0, 0, 10896, 0, 0, 
+    10898, 10900, 0, 0, 10902, 10904, 10906, 10908, 0, 10910, 10912, 10914, 
+    10916, 10918, 10920, 10922, 10924, 10926, 10928, 10930, 10932, 0, 10934, 
+    0, 10936, 10938, 10940, 10942, 10944, 10946, 10948, 0, 10950, 10952, 
+    10954, 10956, 10958, 10960, 10962, 10964, 10966, 10968, 10970, 10972, 
+    10974, 10976, 10978, 10980, 10982, 10984, 10986, 10988, 10990, 10992, 
+    10994, 10996, 10998, 11000, 11002, 11004, 11006, 11008, 11010, 11012, 
+    11014, 11016, 11018, 11020, 11022, 11024, 11026, 11028, 11030, 11032, 
+    11034, 11036, 11038, 11040, 11042, 11044, 11046, 11048, 11050, 11052, 
+    11054, 11056, 11058, 11060, 11062, 11064, 11066, 11068, 11070, 11072, 
+    11074, 11076, 11078, 0, 11080, 11082, 11084, 11086, 0, 0, 11088, 11090, 
+    11092, 11094, 11096, 11098, 11100, 11102, 0, 11104, 11106, 11108, 11110, 
+    11112, 11114, 11116, 0, 11118, 11120, 11122, 11124, 11126, 11128, 11130, 
+    11132, 11134, 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150, 
+    11152, 11154, 11156, 11158, 11160, 11162, 11164, 11166, 11168, 11170, 
+    11172, 0, 11174, 11176, 11178, 11180, 0, 11182, 11184, 11186, 11188, 
+    11190, 0, 11192, 0, 0, 0, 11194, 11196, 11198, 11200, 11202, 11204, 
+    11206, 0, 11208, 11210, 11212, 11214, 11216, 11218, 11220, 11222, 11224, 
+    11226, 11228, 11230, 11232, 11234, 11236, 11238, 11240, 11242, 11244, 
+    11246, 11248, 11250, 11252, 11254, 11256, 11258, 11260, 11262, 11264, 
+    11266, 11268, 11270, 11272, 11274, 11276, 11278, 11280, 11282, 11284, 
+    11286, 11288, 11290, 11292, 11294, 11296, 11298, 11300, 11302, 11304, 
+    11306, 11308, 11310, 11312, 11314, 11316, 11318, 11320, 11322, 11324, 
+    11326, 11328, 11330, 11332, 11334, 11336, 11338, 11340, 11342, 11344, 
+    11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, 11362, 11364, 
+    11366, 11368, 11370, 11372, 11374, 11376, 11378, 11380, 11382, 11384, 
+    11386, 11388, 11390, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 
+    11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 
+    11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 
+    11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 
+    11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 
+    11486, 11488, 11490, 11492, 11494, 11496, 11498, 11500, 11502, 11504, 
+    11506, 11508, 11510, 11512, 11514, 11516, 11518, 11520, 11522, 11524, 
+    11526, 11528, 11530, 11532, 11534, 11536, 11538, 11540, 11542, 11544, 
+    11546, 11548, 11550, 11552, 11554, 11556, 11558, 11560, 11562, 11564, 
+    11566, 11568, 11570, 11572, 11574, 11576, 11578, 11580, 11582, 11584, 
+    11586, 11588, 11590, 11592, 11594, 11596, 11598, 11600, 11602, 11604, 
+    11606, 11608, 11610, 11612, 11614, 11616, 11618, 11620, 11622, 11624, 
+    11626, 11628, 11630, 11632, 11634, 11636, 11638, 11640, 11642, 11644, 
+    11646, 11648, 11650, 11652, 11654, 11656, 11658, 11660, 11662, 11664, 
+    11666, 11668, 11670, 11672, 11674, 11676, 11678, 11680, 11682, 11684, 
+    11686, 11688, 11690, 11692, 11694, 11696, 11698, 11700, 11702, 11704, 
+    11706, 11708, 11710, 11712, 11714, 11716, 11718, 11720, 11722, 11724, 
+    11726, 11728, 11730, 11732, 11734, 11736, 11738, 11740, 11742, 11744, 
+    11746, 11748, 11750, 11752, 11754, 11756, 11758, 11760, 11762, 11764, 
+    11766, 11768, 11770, 11772, 11774, 11776, 11778, 11780, 11782, 11784, 
+    11786, 11788, 11790, 11792, 11794, 11796, 11798, 11800, 11802, 11804, 
+    11806, 11808, 11810, 11812, 11814, 11816, 11818, 11820, 11822, 11824, 
+    11826, 11828, 11830, 11832, 11834, 11836, 11838, 11840, 11842, 11844, 
+    11846, 11848, 11850, 11852, 11854, 11856, 11858, 11860, 11862, 11864, 
+    11866, 11868, 11870, 11872, 11874, 11876, 11878, 11880, 11882, 11884, 
+    11886, 0, 0, 11888, 11890, 11892, 11894, 11896, 11898, 11900, 11902, 
+    11904, 11906, 11908, 11910, 11912, 11914, 11916, 11918, 11920, 11922, 
+    11924, 11926, 11928, 11930, 11932, 11934, 11936, 11938, 11940, 11942, 
+    11944, 11946, 11948, 11950, 11952, 11954, 11956, 11958, 11960, 11962, 
+    11964, 11966, 11968, 11970, 11972, 11974, 11976, 11978, 11980, 11982, 
+    11984, 11986, 11988, 11990, 11992, 11994, 11996, 11998, 12000, 12002, 
+    12004, 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022, 
+    12024, 12026, 12028, 12030, 12032, 12034, 12036, 12038, 12040, 12042, 
+    12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, 12062, 
+    12064, 12066, 12068, 12070, 12072, 12074, 12076, 12078, 12080, 12082, 
+    12084, 12086, 12088, 12090, 12092, 12094, 12096, 12098, 12100, 12102, 
+    12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, 12120, 12122, 
+    12124, 12126, 12128, 12130, 12132, 12134, 12136, 12138, 12140, 12142, 
+    12144, 12146, 12148, 12150, 12152, 12154, 12156, 12158, 12160, 12162, 
+    12164, 12166, 12168, 12170, 12172, 12174, 12176, 12178, 12180, 12182, 
+    12184, 12186, 12188, 12190, 12192, 12194, 12196, 12198, 12200, 12202, 
+    12204, 12206, 12208, 12210, 12212, 12214, 12216, 12218, 12220, 12222, 
+    12224, 12226, 12228, 12230, 12232, 12234, 12236, 12238, 12240, 12242, 
+    12244, 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262, 
+    12264, 12266, 12268, 12270, 12272, 12274, 12276, 12278, 12280, 12282, 
+    12284, 12286, 12288, 12290, 12292, 12294, 12296, 12298, 12300, 12302, 
+    12304, 12306, 12308, 12310, 12312, 12314, 12316, 12318, 12320, 12322, 
+    12324, 12326, 12328, 12330, 12332, 12334, 12336, 12338, 12340, 12342, 
+    12344, 12346, 12348, 12350, 12352, 12354, 12356, 12358, 12360, 12362, 
+    12364, 12366, 12368, 12370, 12372, 12374, 12376, 12378, 12380, 12382, 
+    12384, 12386, 12388, 12390, 12392, 12394, 12396, 12398, 12400, 12402, 
+    12404, 12406, 12408, 12410, 12412, 12414, 12416, 12418, 12420, 12422, 
+    12424, 12426, 12428, 12430, 12432, 12434, 12436, 12438, 12440, 12442, 
+    12444, 12446, 12448, 12450, 12452, 12454, 12456, 12458, 12460, 12462, 
+    12464, 12466, 12468, 12470, 0, 0, 12472, 12474, 12476, 12478, 12480, 
+    12482, 12484, 12486, 12488, 12490, 12492, 12494, 12496, 12498, 12500, 
+    12502, 12504, 12506, 12508, 12510, 12512, 12514, 12516, 12518, 12520, 
+    12522, 12524, 12526, 12528, 12530, 12532, 12534, 12536, 12538, 12540, 
+    12542, 12544, 12546, 12548, 12550, 12552, 12554, 12556, 12558, 12560, 
+    12562, 12564, 12566, 12568, 12570, 12572, 12574, 12576, 12578, 0, 12580, 
+    12582, 12584, 12586, 12588, 12590, 12592, 12594, 12596, 12598, 12600, 
+    12602, 12604, 12606, 12608, 12610, 12612, 12614, 12616, 12618, 12620, 
+    12622, 12624, 12626, 12628, 12630, 12632, 0, 12634, 12636, 0, 12638, 0, 
+    0, 12640, 0, 12642, 12644, 12646, 12648, 12650, 12652, 12654, 12656, 
+    12658, 12660, 0, 12662, 12664, 12666, 12668, 0, 12670, 0, 12672, 0, 0, 0, 
+    0, 0, 0, 12674, 0, 0, 0, 0, 12676, 0, 12678, 0, 12680, 0, 12682, 12684, 
+    12686, 0, 12688, 12690, 0, 12692, 0, 0, 12694, 0, 12696, 0, 12698, 0, 
+    12700, 0, 12702, 0, 12704, 12706, 0, 12708, 0, 0, 12710, 12712, 12714, 
+    12716, 0, 12718, 12720, 12722, 12724, 12726, 12728, 12730, 0, 12732, 
+    12734, 12736, 12738, 0, 12740, 12742, 12744, 12746, 0, 12748, 0, 12750, 
+    12752, 12754, 12756, 12758, 12760, 12762, 12764, 12766, 12768, 0, 12770, 
+    12772, 12774, 12776, 12778, 12780, 12782, 12784, 12786, 12788, 12790, 
+    12792, 12794, 12796, 12798, 12800, 12802, 0, 0, 0, 0, 0, 12804, 12806, 
+    12808, 0, 12810, 12812, 12814, 12816, 12818, 0, 12820, 12822, 12824, 
+    12826, 12828, 12830, 12832, 12834, 12836, 12838, 12840, 12842, 12844, 
+    12846, 12848, 12850, 12852, 0, 0, 0, 0, 12854, 12857, 12860, 12863, 
+    12866, 12869, 12872, 12875, 12878, 12881, 12884, 0, 0, 0, 0, 0, 12887, 
+    12891, 12895, 12899, 12903, 12907, 12911, 12915, 12919, 12923, 12927, 
+    12931, 12935, 12939, 12943, 12947, 12951, 12955, 12959, 12963, 12967, 
+    12971, 12975, 12979, 12983, 12987, 12991, 12995, 12997, 12999, 13002, 0, 
+    13005, 13007, 13009, 13011, 13013, 13015, 13017, 13019, 13021, 13023, 
+    13025, 13027, 13029, 13031, 13033, 13035, 13037, 13039, 13041, 13043, 
+    13045, 13047, 13049, 13051, 13053, 13055, 13057, 13060, 13063, 13066, 
+    13069, 13073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13076, 13079, 0, 0, 0, 0, 
+    13082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13085, 13088, 13091, 
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13093, 13095, 13097, 13099, 13101, 
+    13103, 13105, 13107, 13109, 13111, 13113, 13115, 13117, 13119, 13121, 
+    13123, 13125, 13127, 13129, 13131, 13133, 13135, 13137, 13139, 13141, 
+    13143, 13145, 13147, 13149, 13151, 13153, 13155, 13157, 13159, 13161, 
+    13163, 13165, 13167, 13169, 13171, 13173, 13175, 13177, 0, 0, 0, 0, 0, 
+    13179, 13183, 13187, 13191, 13195, 13199, 13203, 13207, 13211, 0, 0, 0, 
+    0, 0, 0, 0, 13215, 13217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    13219, 13221, 13223, 13225, 13228, 13230, 13232, 13234, 13236, 13238, 
+    13240, 13242, 13244, 13246, 13249, 13251, 13253, 13255, 13257, 13260, 
+    13262, 13264, 13266, 13269, 13271, 13273, 13275, 13277, 13279, 13282, 
+    13284, 13286, 13288, 13290, 13292, 13294, 13296, 13298, 13300, 13302, 
+    13304, 13306, 13308, 13310, 13312, 13314, 13316, 13318, 13320, 13322, 
+    13324, 13326, 13328, 13331, 13333, 13335, 13337, 13340, 13342, 13344, 
+    13346, 13348, 13350, 13352, 13354, 13356, 13358, 13360, 13362, 13364, 
+    13366, 13368, 13370, 13372, 13374, 13376, 13378, 13380, 13382, 13384, 
+    13386, 13388, 13390, 13392, 13394, 13396, 13398, 13400, 13402, 13404, 
+    13407, 13409, 13411, 13413, 13415, 13417, 13419, 13422, 13425, 13427, 
+    13429, 13431, 13433, 13435, 13437, 13439, 13441, 13443, 13445, 13448, 
+    13450, 13452, 13454, 13456, 13459, 13461, 13463, 13465, 13467, 13469, 
+    13471, 13473, 13475, 13477, 13480, 13482, 13485, 13487, 13489, 13491, 
+    13493, 13495, 13497, 13499, 13501, 13503, 13505, 13507, 13510, 13512, 
+    13514, 13516, 13518, 13520, 13523, 13525, 13528, 13531, 13533, 13535, 
+    13537, 13539, 13542, 13545, 13547, 13549, 13551, 13553, 13555, 13557, 
+    13559, 13561, 13563, 13565, 13567, 13570, 13572, 13574, 13576, 13578, 
+    13580, 13582, 13584, 13586, 13588, 13590, 13592, 13594, 13596, 13598, 
+    13600, 13602, 13604, 13606, 13608, 13611, 13613, 13615, 13617, 13619, 
+    13621, 13624, 13626, 13628, 13630, 13632, 13634, 13636, 13638, 13640, 
+    13642, 13644, 13646, 13649, 13651, 13653, 13655, 13657, 13659, 13661, 
+    13663, 13665, 13667, 13669, 13671, 13673, 13675, 13677, 13679, 13681, 
+    13683, 13685, 13688, 13690, 13692, 13694, 13696, 13698, 13701, 13703, 
+    13705, 13707, 13709, 13711, 13713, 13715, 13717, 13720, 13722, 13724, 
+    13726, 13729, 13731, 13733, 13735, 13737, 13739, 13741, 13744, 13747, 
+    13750, 13752, 13755, 13757, 13759, 13761, 13763, 13765, 13767, 13769, 
+    13771, 13773, 13775, 13778, 13780, 13782, 13784, 13786, 13788, 13790, 
+    13793, 13795, 13797, 13800, 13803, 13805, 13807, 13809, 13811, 13813, 
+    13815, 13817, 13819, 13821, 13824, 13826, 13829, 13831, 13834, 13836, 
+    13838, 13840, 13843, 13845, 13847, 13850, 13853, 13855, 13857, 13859, 
+    13861, 13863, 13865, 13867, 13869, 13871, 13873, 13875, 13877, 13879, 
+    13882, 13884, 13887, 13889, 13892, 13894, 13897, 13900, 13903, 13905, 
+    13907, 13909, 13912, 13915, 13918, 13921, 13923, 13925, 13927, 13929, 
+    13931, 13933, 13935, 13937, 13940, 13942, 13944, 13946, 13948, 13951, 
+    13953, 13956, 13959, 13961, 13963, 13965, 13967, 13969, 13971, 13974, 
+    13977, 13980, 13982, 13984, 13987, 13989, 13991, 13993, 13996, 13998, 
+    14000, 14002, 14004, 14006, 14009, 14011, 14013, 14015, 14017, 14019, 
+    14021, 14024, 14027, 14029, 14032, 14034, 14037, 14039, 14041, 14043, 
+    14046, 14049, 14051, 14054, 14056, 14059, 14061, 14063, 14065, 14067, 
+    14069, 14071, 14074, 14077, 14080, 14083, 14085, 14087, 14089, 14091, 
+    14093, 14095, 14097, 14099, 14101, 14103, 14105, 14107, 14110, 14112, 
+    14114, 14116, 14118, 14120, 14122, 14124, 14126, 14128, 14130, 14132, 
+    14134, 14137, 14140, 14143, 14145, 14147, 14149, 14151, 14154, 14156, 
+    14159, 14161, 14163, 14166, 14169, 14171, 14173, 14175, 14177, 14179, 
+    14181, 14183, 14185, 14187, 14189, 14191, 14193, 14195, 14197, 14199, 
+    14201, 14203, 14205, 14207, 14210, 14212, 14214, 14216, 14218, 14220, 
+    14223, 14226, 14228, 14230, 14232, 14234, 14236, 14238, 14241, 14243, 
+    14245, 14247, 14249, 14252, 14255, 14257, 14259, 14261, 14264, 14266, 
+    14268, 14271, 14274, 14276, 14278, 14280, 14283, 14285, 14287, 14289, 
+    14291, 14293, 14295, 14297, 14300, 14302, 14304, 14306, 14309, 14311, 
+    14313, 14315, 14317, 14320, 14323, 14325, 14327, 14329, 14332, 14334, 
+    14337, 14339, 14341, 14343, 14346, 14348, 14350, 14352, 14354, 14356, 
+    14358, 14360, 14363, 14365, 14367, 14369, 14371, 14373, 14375, 14378, 
+    14380, 14383, 14386, 14389, 14391, 14393, 14395, 14397, 14399, 14401, 
+    14403, 14405, 0, 0, 
+};
+
+/* NFC pairs */
+#define COMP_SHIFT1 2
+#define COMP_SHIFT2 1
+static const unsigned short comp_index0[] = {
+    0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, 
+    5, 6, 7, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 
+    15, 16, 17, 0, 0, 0, 0, 18, 19, 20, 21, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 
+    23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 0, 0, 0, 31, 32, 33, 34, 
+    0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 36, 0, 37, 38, 39, 0, 0, 0, 40, 41, 42, 
+    43, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 47, 48, 49, 50, 0, 0, 0, 51, 
+    52, 53, 54, 0, 0, 0, 0, 55, 56, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 0, 0, 
+    0, 0, 61, 62, 63, 0, 0, 0, 0, 0, 64, 65, 66, 67, 0, 0, 0, 68, 69, 70, 71, 
+    0, 0, 0, 0, 72, 0, 73, 0, 0, 0, 0, 0, 74, 0, 75, 0, 0, 0, 0, 0, 76, 0, 0, 
+    0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 80, 81, 82, 83, 0, 0, 0, 0, 84, 
+    85, 86, 0, 0, 0, 0, 0, 87, 88, 0, 89, 0, 0, 0, 90, 91, 0, 92, 0, 0, 0, 0, 
+    0, 93, 94, 95, 0, 0, 0, 0, 96, 97, 98, 99, 0, 0, 0, 0, 100, 0, 0, 0, 0, 
+    0, 0, 101, 102, 0, 103, 0, 0, 0, 0, 104, 105, 106, 107, 0, 0, 0, 0, 108, 
+    109, 110, 111, 0, 0, 0, 0, 112, 113, 0, 0, 0, 0, 0, 114, 115, 116, 117, 
+    0, 0, 0, 0, 118, 119, 120, 121, 0, 0, 0, 0, 122, 0, 123, 0, 0, 0, 0, 124, 
+    125, 126, 127, 128, 0, 0, 0, 129, 130, 131, 132, 0, 0, 0, 0, 133, 134, 0, 
+    0, 0, 0, 0, 0, 135, 136, 137, 138, 0, 0, 0, 139, 140, 141, 142, 0, 0, 0, 
+    0, 0, 143, 144, 145, 0, 0, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0, 150, 0, 
+    151, 0, 0, 0, 0, 152, 153, 154, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, 
+    156, 157, 158, 0, 0, 0, 0, 0, 159, 160, 161, 162, 0, 0, 0, 163, 0, 0, 0, 
+    164, 0, 0, 0, 165, 166, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 168, 
+    0, 0, 0, 0, 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, 
+    172, 173, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0, 
+    0, 0, 177, 178, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 
+    0, 0, 0, 181, 182, 183, 0, 0, 0, 0, 0, 184, 185, 0, 0, 0, 0, 0, 0, 186, 
+    0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 188, 189, 0, 0, 0, 0, 0, 0, 
+    190, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, 
+    0, 194, 195, 0, 0, 0, 0, 0, 0, 196, 197, 0, 0, 0, 0, 0, 0, 198, 0, 0, 0, 
+    0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 200, 201, 202, 0, 0, 0, 0, 0, 203, 
+    204, 0, 0, 0, 0, 0, 0, 205, 206, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, 
+    208, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 
+    0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0, 
+    0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, 
+    0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 219, 0, 
+    0, 0, 0, 0, 0, 220, 221, 222, 0, 0, 0, 0, 0, 223, 224, 225, 0, 0, 0, 0, 
+    0, 226, 227, 228, 0, 0, 0, 0, 0, 229, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0, 
+    0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 235, 0, 
+    0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 238, 
+    0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 
+    241, 0, 0, 0, 0, 0, 0, 242, 0, 243, 244, 0, 0, 0, 0, 245, 246, 0, 0, 0, 
+    0, 0, 247, 0, 248, 0, 249, 0, 0, 0, 250, 251, 252, 0, 0, 0, 0, 0, 253, 0, 
+    254, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 256, 257, 258, 0, 0, 0, 0, 0, 
+    259, 0, 260, 0, 261, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 263, 0, 
+    0, 0, 264, 265, 266, 0, 267, 0, 0, 0, 268, 0, 269, 0, 0, 0, 0, 0, 270, 0, 
+    271, 272, 0, 0, 0, 0, 273, 274, 0, 275, 0, 0, 0, 276, 0, 277, 0, 0, 0, 0, 
+    0, 0, 0, 278, 0, 0, 0, 0, 0, 279, 280, 281, 282, 0, 0, 0, 0, 283, 284, 0, 
+    285, 0, 0, 0, 286, 0, 0, 0, 287, 0, 0, 0, 288, 0, 0, 0, 289, 0, 0, 0, 0, 
+    0, 0, 290, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 0, 0, 
+    0, 293, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, 
+    0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 298, 299, 0, 0, 0, 
+    0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0, 
+    0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 305, 0, 
+    0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 308, 
+    0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0, 
+    311, 312, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, 
+    0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, 
+    0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, 
+    0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 323, 0, 
+    0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    0, 326, 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, 
+    0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0, 
+    0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 334, 0, 0, 
+    0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 336, 337, 0, 0, 0, 0, 0, 0, 0, 
+    338, 0, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 0, 
+    0, 341, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, 
+    0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0, 
+    0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 350, 0, 
+    0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 353, 
+    0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0, 
+    356, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 
+    0, 359, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 361, 0, 362, 0, 0, 0, 
+    0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 365, 0, 
+    0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 368, 
+    0, 0, 0, 0, 0, 0, 369, 370, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0, 
+    372, 0, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, 0, 0, 
+    0, 375, 0, 0, 376, 0, 0, 0, 0, 377, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 379, 
+    0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0, 
+    382, 0, 0, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 385, 0, 
+    0, 386, 0, 0, 0, 0, 387, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0, 
+    0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, 
+    0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 395, 0, 0, 0, 0, 0, 
+    0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0, 
+    0, 0, 0, 399, 0, 0, 400, 0, 0, 0, 0, 401, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, 
+    403, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 405, 0, 0, 0, 0, 0, 0, 
+    0, 406, 0, 0, 0, 0, 0, 0, 0, 407, 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, 0, 409, 
+    0, 0, 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0, 
+    0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0, 
+    0, 0, 0, 0, 0, 417, 0, 0, 0, 0, 0, 0, 0, 418, 0, 0, 0, 419, 0, 0, 420, 0, 
+    0, 0, 0, 421, 0, 0, 422, 0, 0, 0, 423, 0, 0, 0, 424, 0, 0, 0, 425, 0, 0, 
+    0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, 429, 0, 
+    0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 0, 431, 0, 0, 432, 0, 0, 0, 0, 
+    433, 0, 0, 434, 0, 0, 0, 435, 0, 0, 0, 436, 0, 0, 0, 437, 0, 0, 0, 438, 
+    0, 0, 0, 439, 0, 0, 440, 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0, 
+    442, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 444, 0, 0, 0, 0, 0, 0, 
+    0, 445, 0, 0, 0, 0, 0, 0, 0, 446, 0, 0, 0, 447, 0, 0, 0, 448, 0, 0, 0, 
+    449, 0, 0, 450, 0, 0, 0, 0, 0, 0, 0, 451, 0, 0, 0, 0, 0, 0, 0, 452, 0, 0, 
+    0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, 0, 0, 0, 0, 455, 0, 
+    0, 0, 0, 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, 458, 
+    0, 0, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0, 0, 0, 0, 460, 0, 0, 0, 461, 0, 0, 
+    0, 462, 0, 0, 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, 0, 0, 464, 0, 0, 0, 465, 0, 
+    0, 0, 466, 0, 0, 0, 0, 0, 0, 467, 0, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0, 
+    0, 0, 0, 469, 0, 0, 0, 0, 0, 0, 0, 470, 0, 0, 0, 0, 0, 0, 471, 0, 0, 0, 
+    0, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 0, 473, 0, 0, 0, 0, 0, 0, 0, 474, 0, 
+    0, 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 477, 
+    0, 0, 0, 0, 0, 0, 0, 478, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 0, 
+    480, 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0, 
+    0, 483, 0, 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 485, 0, 0, 0, 0, 
+    0, 0, 0, 486, 0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 488, 0, 0, 0, 
+    0, 0, 0, 0, 489, 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 
+    0, 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, 0, 0, 494, 
+    0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, 
+    497, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, 0, 0, 
+    0, 500, 0, 0, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 0, 502, 0, 0, 0, 0, 
+    0, 0, 503, 0, 0, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 0, 505, 0, 0, 0, 
+    0, 0, 0, 0, 506, 0, 0, 0, 0, 0, 0, 507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+    508, 0, 0, 0, 0, 0, 0, 0, 509, 0, 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 
+    0, 0, 511, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 0, 0, 
+    0, 0, 0, 514, 0, 0, 0, 0, 0, 0, 0, 515, 0, 0, 0, 0, 0, 0, 516, 0, 0, 0, 
+    0, 0, 0, 0, 517, 0, 0, 0, 0, 0, 0, 0, 518, 0, 0, 0, 0, 0, 0, 0, 519, 0, 
+    0, 0, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 0, 522, 
+    0, 0, 0, 0, 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0, 
+    525, 0, 0, 0, 0, 0, 0, 0, 526, 0, 0, 0, 0, 0, 0, 0, 527, 0, 0, 0, 0, 0, 
+    0, 528, 0, 0, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0, 0, 0, 0, 530, 0, 0, 0, 0, 
+    0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 533, 0, 0, 0, 
+    0, 0, 0, 0, 534, 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 536, 0, 0, 
+    0, 0, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 0, 539, 
+    0, 0, 0, 0, 0, 0, 540, 0, 0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, 0, 
+    542, 0, 0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0, 
+    0, 545, 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 547, 0, 0, 0, 0, 
+    0, 0, 548, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, 0, 
+    0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 0, 552, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0, 
+    0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 556, 
+    0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0, 
+    559, 0, 0, 0, 0, 0, 0, 0, 560, 0, 0, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0, 0, 
+    0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 563, 0, 0, 0, 0, 0, 0, 564, 
+};
+
+static const unsigned short comp_index1[] = {
+    0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10, 
+    0, 11, 12, 0, 13, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, 0, 0, 16, 0, 0, 0, 0, 
+    0, 17, 18, 0, 19, 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, 22, 0, 23, 0, 0, 24, 0, 
+    25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 33, 34, 0, 35, 0, 36, 37, 38, 0, 0, 
+    0, 0, 0, 39, 0, 0, 0, 40, 41, 42, 43, 0, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0, 
+    0, 46, 0, 47, 0, 48, 0, 0, 49, 0, 50, 0, 51, 0, 0, 52, 53, 54, 55, 56, 
+    57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 0, 62, 0, 0, 0, 0, 0, 63, 64, 0, 0, 
+    65, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, 70, 0, 71, 
+    72, 0, 73, 0, 74, 0, 0, 75, 0, 0, 0, 0, 76, 0, 0, 77, 78, 0, 79, 0, 80, 
+    0, 0, 81, 0, 82, 83, 0, 84, 0, 0, 0, 0, 0, 85, 86, 87, 88, 89, 90, 91, 0, 
+    92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 95, 0, 0, 0, 96, 0, 0, 97, 0, 98, 99, 0, 
+    100, 0, 101, 0, 0, 102, 0, 103, 104, 0, 105, 0, 106, 0, 0, 107, 0, 108, 
+    0, 0, 0, 109, 0, 110, 0, 0, 111, 0, 112, 113, 0, 114, 0, 0, 0, 0, 0, 115, 
+    116, 117, 118, 119, 120, 121, 0, 122, 123, 0, 124, 125, 0, 0, 0, 126, 0, 
+    0, 127, 0, 0, 128, 129, 0, 130, 131, 0, 0, 0, 0, 0, 132, 0, 0, 0, 133, 
+    134, 135, 136, 137, 0, 0, 0, 138, 0, 0, 139, 140, 0, 141, 0, 142, 0, 0, 
+    143, 0, 0, 0, 0, 144, 0, 145, 146, 147, 148, 149, 150, 151, 0, 152, 153, 
+    0, 154, 0, 0, 155, 0, 0, 0, 0, 156, 157, 0, 0, 0, 0, 0, 158, 159, 0, 160, 
+    0, 161, 162, 0, 0, 0, 163, 0, 164, 0, 0, 165, 0, 166, 167, 0, 168, 0, 
+    169, 170, 171, 172, 173, 174, 175, 0, 176, 0, 177, 178, 179, 0, 0, 0, 0, 
+    0, 180, 0, 0, 0, 181, 182, 183, 184, 0, 185, 186, 0, 0, 0, 0, 0, 187, 0, 
+    188, 0, 189, 0, 0, 190, 0, 191, 0, 192, 193, 0, 194, 195, 196, 197, 198, 
+    199, 200, 0, 201, 0, 0, 202, 203, 0, 0, 0, 204, 0, 0, 0, 205, 0, 0, 0, 0, 
+    0, 206, 0, 0, 0, 0, 207, 0, 0, 208, 0, 209, 0, 0, 210, 0, 211, 0, 0, 0, 
+    0, 212, 0, 0, 213, 0, 214, 215, 0, 216, 0, 217, 0, 0, 218, 219, 0, 0, 0, 
+    0, 0, 0, 220, 221, 0, 222, 0, 223, 0, 0, 224, 0, 225, 226, 0, 227, 0, 0, 
+    0, 0, 0, 228, 229, 230, 231, 232, 233, 234, 0, 235, 0, 0, 236, 0, 0, 0, 
+    237, 0, 0, 238, 0, 0, 0, 239, 0, 0, 240, 0, 241, 242, 0, 243, 0, 244, 0, 
+    0, 245, 0, 0, 0, 0, 0, 246, 247, 0, 248, 0, 249, 0, 0, 250, 0, 251, 0, 0, 
+    0, 252, 0, 253, 0, 0, 254, 0, 255, 256, 0, 257, 0, 258, 259, 260, 261, 
+    262, 263, 264, 0, 265, 266, 0, 267, 268, 0, 0, 0, 269, 0, 0, 270, 0, 0, 
+    0, 0, 0, 0, 271, 272, 0, 273, 274, 0, 0, 0, 275, 0, 276, 0, 0, 0, 277, 
+    278, 279, 280, 281, 0, 0, 0, 282, 0, 0, 283, 284, 0, 285, 0, 286, 0, 0, 
+    287, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 289, 0, 290, 0, 0, 0, 0, 291, 292, 
+    0, 0, 293, 0, 0, 0, 0, 294, 295, 0, 0, 0, 0, 0, 0, 296, 0, 297, 0, 0, 0, 
+    0, 298, 0, 0, 299, 300, 0, 0, 301, 0, 0, 302, 0, 0, 0, 0, 0, 0, 303, 304, 
+    0, 0, 305, 0, 0, 306, 0, 307, 308, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0, 0, 
+    0, 0, 311, 0, 312, 0, 0, 313, 0, 0, 0, 0, 0, 314, 315, 0, 0, 316, 0, 0, 
+    0, 0, 317, 318, 0, 0, 0, 0, 0, 0, 319, 0, 320, 0, 0, 0, 0, 321, 0, 0, 
+    322, 323, 0, 0, 324, 0, 0, 325, 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, 328, 0, 
+    0, 329, 0, 330, 331, 0, 0, 0, 0, 0, 332, 333, 0, 0, 0, 0, 0, 0, 334, 0, 
+    335, 0, 0, 336, 0, 0, 0, 0, 0, 337, 338, 0, 0, 339, 0, 0, 340, 341, 0, 0, 
+    342, 0, 0, 343, 0, 0, 0, 0, 0, 0, 344, 0, 0, 345, 0, 0, 346, 0, 0, 0, 0, 
+    0, 347, 0, 0, 348, 0, 0, 349, 0, 0, 350, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 
+    352, 0, 353, 0, 0, 354, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 356, 357, 0, 0, 
+    358, 0, 0, 0, 359, 0, 0, 360, 361, 0, 0, 362, 0, 0, 0, 363, 0, 0, 364, 
+    365, 0, 0, 366, 0, 0, 0, 367, 0, 0, 368, 369, 0, 0, 370, 0, 0, 0, 371, 0, 
+    0, 0, 372, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 375, 0, 0, 376, 0, 
+    0, 377, 0, 0, 0, 0, 0, 0, 378, 0, 0, 379, 0, 0, 380, 0, 0, 0, 0, 0, 381, 
+    0, 382, 0, 383, 384, 0, 0, 0, 0, 0, 0, 385, 386, 0, 0, 0, 0, 0, 0, 387, 
+    0, 0, 0, 388, 0, 0, 389, 0, 0, 390, 0, 0, 0, 0, 391, 0, 392, 393, 0, 0, 
+    0, 394, 0, 0, 0, 395, 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 398, 0, 
+    399, 400, 0, 0, 0, 401, 0, 0, 0, 402, 0, 0, 403, 0, 0, 404, 0, 0, 0, 0, 
+    0, 0, 405, 0, 0, 406, 0, 0, 0, 0, 407, 0, 408, 0, 0, 0, 0, 409, 0, 0, 
+    410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 413, 0, 0, 414, 0, 0, 0, 0, 0, 
+    0, 415, 416, 0, 417, 418, 0, 0, 0, 419, 0, 0, 420, 0, 0, 0, 0, 421, 0, 0, 
+    422, 0, 0, 423, 0, 0, 0, 424, 0, 425, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 
+    0, 428, 429, 0, 0, 0, 0, 0, 0, 430, 0, 0, 431, 0, 0, 0, 0, 432, 0, 433, 
+    0, 0, 0, 0, 434, 0, 435, 0, 0, 0, 0, 0, 0, 436, 437, 0, 0, 438, 0, 0, 
+    439, 0, 440, 441, 0, 0, 0, 442, 0, 0, 443, 0, 444, 445, 0, 446, 447, 0, 
+    0, 448, 0, 0, 0, 449, 0, 450, 451, 0, 0, 0, 452, 0, 0, 0, 0, 0, 453, 0, 
+    454, 455, 0, 456, 457, 0, 0, 0, 0, 0, 0, 458, 0, 0, 459, 0, 460, 461, 0, 
+    0, 0, 462, 0, 0, 463, 0, 464, 465, 0, 466, 467, 0, 0, 468, 0, 0, 0, 469, 
+    0, 470, 471, 0, 0, 0, 472, 0, 0, 0, 0, 0, 473, 0, 474, 475, 0, 476, 477, 
+    0, 0, 0, 0, 0, 0, 478, 0, 0, 479, 0, 0, 480, 0, 0, 0, 0, 0, 481, 0, 0, 
+    482, 0, 0, 0, 483, 0, 0, 484, 0, 0, 485, 0, 0, 0, 0, 0, 0, 486, 0, 0, 
+    487, 488, 0, 489, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 492, 0, 0, 493, 
+    0, 0, 0, 494, 0, 0, 495, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 497, 0, 0, 0, 
+    498, 499, 0, 0, 0, 500, 0, 0, 0, 0, 0, 501, 502, 0, 503, 0, 0, 0, 504, 0, 
+    0, 0, 505, 0, 0, 506, 507, 0, 0, 0, 0, 0, 508, 0, 0, 0, 509, 510, 0, 0, 
+    0, 0, 0, 511, 0, 0, 0, 512, 513, 0, 514, 0, 0, 0, 0, 515, 0, 0, 516, 0, 
+    0, 517, 0, 0, 0, 0, 0, 0, 518, 0, 0, 519, 0, 0, 520, 0, 0, 521, 0, 0, 0, 
+    0, 0, 0, 522, 0, 0, 523, 0, 0, 524, 0, 0, 525, 0, 0, 0, 0, 0, 0, 526, 0, 
+    0, 0, 527, 0, 0, 528, 0, 0, 529, 0, 0, 530, 0, 0, 0, 531, 0, 0, 0, 0, 0, 
+    0, 532, 533, 534, 0, 0, 0, 0, 0, 535, 536, 0, 0, 0, 0, 0, 537, 0, 0, 538, 
+    0, 0, 539, 0, 0, 0, 0, 0, 0, 540, 0, 541, 0, 0, 0, 0, 0, 542, 543, 0, 0, 
+    0, 0, 0, 544, 0, 0, 545, 0, 0, 546, 0, 0, 0, 0, 0, 0, 547, 0, 0, 548, 0, 
+    0, 549, 0, 0, 550, 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 552, 553, 0, 0, 0, 0, 
+    0, 554, 0, 0, 555, 0, 0, 556, 0, 0, 0, 0, 0, 0, 557, 0, 0, 558, 0, 0, 
+    559, 0, 0, 560, 0, 0, 0, 0, 561, 0, 0, 562, 0, 0, 0, 0, 0, 0, 563, 0, 0, 
+    564, 0, 0, 565, 0, 0, 0, 0, 0, 566, 567, 0, 0, 0, 0, 0, 568, 0, 0, 569, 
+    0, 0, 570, 0, 0, 0, 0, 0, 0, 571, 0, 0, 572, 0, 0, 573, 0, 0, 574, 0, 0, 
+    0, 0, 575, 0, 0, 0, 0, 0, 576, 577, 0, 0, 0, 0, 0, 578, 0, 0, 579, 0, 0, 
+    580, 0, 0, 0, 0, 0, 0, 581, 0, 0, 582, 0, 0, 583, 0, 0, 584, 0, 0, 0, 0, 
+    585, 0, 0, 0, 0, 0, 586, 587, 0, 0, 0, 0, 0, 588, 0, 0, 0, 0, 589, 0, 
+    590, 0, 0, 0, 0, 591, 0, 592, 0, 0, 0, 0, 593, 0, 0, 594, 0, 0, 0, 0, 0, 
+    0, 595, 0, 0, 596, 0, 0, 597, 0, 0, 0, 0, 0, 598, 599, 0, 0, 0, 0, 0, 
+    600, 0, 0, 0, 0, 601, 0, 602, 0, 0, 0, 0, 603, 0, 604, 0, 0, 0, 0, 605, 
+    0, 0, 0, 0, 0, 606, 0, 0, 607, 0, 0, 608, 0, 0, 609, 0, 0, 0, 0, 0, 0, 
+    610, 0, 0, 611, 0, 0, 612, 0, 0, 0, 0, 613, 0, 614, 0, 0, 0, 0, 615, 0, 
+    0, 0, 0, 0, 616, 0, 0, 617, 0, 0, 618, 0, 0, 619, 0, 0, 0, 0, 0, 0, 620, 
+    0, 0, 621, 0, 0, 622, 0, 0, 623, 0, 0, 0, 0, 0, 0, 624, 0, 0, 625, 0, 0, 
+    626, 0, 0, 0, 0, 627, 0, 628, 0, 0, 0, 0, 0, 0, 629, 0, 0, 630, 0, 0, 0, 
+    0, 631, 0, 632, 0, 0, 0, 0, 0, 633, 0, 0, 634, 0, 0, 635, 0, 0, 636, 0, 
+    0, 0, 0, 0, 0, 637, 0, 0, 638, 0, 0, 639, 0, 0, 640, 0, 0, 0, 0, 0, 0, 
+    641, 0, 0, 642, 0, 0, 643, 0, 0, 644, 0, 0, 0, 0, 0, 0, 645, 0, 0, 646, 
+    0, 0, 647, 0, 0, 648, 0, 0, 0, 0, 0, 0, 649, 0, 0, 650, 0, 0, 651, 0, 0, 
+    652, 0, 0, 0, 0, 0, 0, 653, 0, 0, 654, 0, 0, 655, 0, 0, 656, 0, 0, 0, 0, 
+    0, 0, 657, 0, 0, 658, 0, 0, 659, 0, 0, 660, 0, 0, 0, 0, 0, 0, 661, 0, 0, 
+    662, 0, 0, 663, 0, 0, 664, 0, 0, 0, 0, 0, 0, 665, 0, 0, 666, 0, 0, 667, 
+    0, 0, 668, 0, 0, 0, 0, 0, 0, 669, 0, 0, 670, 0, 0, 671, 0, 0, 672, 0, 0, 
+    0, 0, 0, 0, 673, 0, 0, 0, 674, 0, 0, 675, 0, 0, 676, 0, 0, 677, 0, 0, 0, 
+    0, 0, 0, 678, 0, 0, 679, 0, 0, 680, 0, 0, 681, 0, 0, 0, 0, 0, 0, 682, 0, 
+    0, 683, 0, 0, 684, 0, 0, 685, 0, 0, 0, 0, 0, 0, 686, 0, 0, 687, 0, 0, 
+    688, 0, 0, 689, 0, 0, 0, 0, 0, 0, 690, 0, 0, 691, 0, 0, 692, 0, 0, 693, 
+    0, 0, 0, 0, 0, 0, 694, 0, 0, 695, 0, 0, 696, 0, 0, 697, 0, 0, 0, 0, 0, 0, 
+    698, 0, 0, 699, 0, 0, 700, 0, 0, 701, 0, 0, 0, 0, 0, 0, 702, 0, 0, 703, 
+    0, 0, 704, 0, 0, 705, 0, 0, 0, 0, 0, 0, 706, 0, 0, 707, 0, 0, 708, 0, 0, 
+    709, 0, 0, 0, 0, 0, 0, 710, 0, 0, 711, 0, 0, 712, 0, 0, 713, 0, 0, 0, 0, 
+    0, 0, 714, 0, 0, 715, 0, 0, 716, 0, 0, 717, 0, 0, 0, 0, 0, 0, 718, 0, 0, 
+    719, 0, 0, 720, 0, 0, 721, 0, 0, 0, 722, 0, 0, 0, 0, 0, 0, 723, 0, 0, 
+    724, 0, 0, 725, 0, 0, 726, 0, 0, 0, 727, 0, 0, 0, 728, 729, 0, 0, 730, 0, 
+    0, 0, 0, 0, 0, 731, 
+};
+
+static const unsigned int comp_data[] = {
+    0, 0, 0, 8814, 0, 8800, 0, 8815, 192, 193, 194, 195, 256, 258, 550, 196, 
+    7842, 197, 0, 461, 512, 514, 0, 7840, 0, 7680, 260, 0, 7682, 0, 0, 7684, 
+    7686, 0, 0, 262, 264, 0, 266, 0, 0, 268, 0, 199, 7690, 0, 0, 270, 0, 
+    7692, 0, 7696, 0, 7698, 7694, 0, 200, 201, 202, 7868, 274, 276, 278, 203, 
+    7866, 0, 0, 282, 516, 518, 0, 7864, 0, 552, 280, 7704, 0, 7706, 7710, 0, 
+    0, 500, 284, 0, 7712, 286, 288, 0, 0, 486, 0, 290, 292, 0, 7714, 7718, 0, 
+    542, 0, 7716, 0, 7720, 7722, 0, 204, 205, 206, 296, 298, 300, 304, 207, 
+    7880, 0, 0, 463, 520, 522, 0, 7882, 302, 0, 0, 7724, 308, 0, 0, 7728, 0, 
+    488, 0, 7730, 0, 310, 7732, 0, 0, 313, 0, 317, 0, 7734, 0, 315, 0, 7740, 
+    7738, 0, 0, 7742, 7744, 0, 0, 7746, 504, 323, 0, 209, 7748, 0, 0, 327, 0, 
+    7750, 0, 325, 0, 7754, 7752, 0, 210, 211, 212, 213, 332, 334, 558, 214, 
+    7886, 0, 336, 465, 524, 526, 416, 7884, 490, 0, 0, 7764, 7766, 0, 0, 340, 
+    7768, 0, 0, 344, 528, 530, 0, 7770, 0, 342, 7774, 0, 0, 346, 348, 0, 
+    7776, 0, 0, 352, 0, 7778, 536, 350, 7786, 0, 0, 356, 0, 7788, 538, 354, 
+    0, 7792, 7790, 0, 217, 218, 219, 360, 362, 364, 0, 220, 7910, 366, 368, 
+    467, 532, 534, 431, 7908, 7794, 0, 370, 7798, 0, 7796, 0, 7804, 0, 7806, 
+    7808, 7810, 372, 0, 7814, 7812, 0, 7816, 7818, 7820, 7922, 221, 374, 
+    7928, 562, 0, 7822, 376, 7926, 0, 0, 7924, 0, 377, 7824, 0, 379, 0, 0, 
+    381, 0, 7826, 7828, 0, 224, 225, 226, 227, 257, 259, 551, 228, 7843, 229, 
+    0, 462, 513, 515, 0, 7841, 0, 7681, 261, 0, 7683, 0, 0, 7685, 7687, 0, 0, 
+    263, 265, 0, 267, 0, 0, 269, 0, 231, 7691, 0, 0, 271, 0, 7693, 0, 7697, 
+    0, 7699, 7695, 0, 232, 233, 234, 7869, 275, 277, 279, 235, 7867, 0, 0, 
+    283, 517, 519, 0, 7865, 0, 553, 281, 7705, 0, 7707, 7711, 0, 0, 501, 285, 
+    0, 7713, 287, 289, 0, 0, 487, 0, 291, 293, 0, 7715, 7719, 0, 543, 0, 
+    7717, 0, 7721, 7723, 0, 7830, 0, 236, 237, 238, 297, 299, 301, 0, 239, 
+    7881, 0, 0, 464, 521, 523, 0, 7883, 303, 0, 0, 7725, 309, 0, 0, 496, 0, 
+    7729, 0, 489, 0, 7731, 0, 311, 7733, 0, 0, 314, 0, 318, 0, 7735, 0, 316, 
+    0, 7741, 7739, 0, 0, 7743, 7745, 0, 0, 7747, 505, 324, 0, 241, 7749, 0, 
+    0, 328, 0, 7751, 0, 326, 0, 7755, 7753, 0, 242, 243, 244, 245, 333, 335, 
+    559, 246, 7887, 0, 337, 466, 525, 527, 417, 7885, 491, 0, 0, 7765, 7767, 
+    0, 0, 341, 7769, 0, 0, 345, 529, 531, 0, 7771, 0, 343, 7775, 0, 0, 347, 
+    349, 0, 7777, 0, 0, 353, 0, 7779, 537, 351, 7787, 7831, 0, 357, 0, 7789, 
+    539, 355, 0, 7793, 7791, 0, 249, 250, 251, 361, 363, 365, 0, 252, 7911, 
+    367, 369, 468, 533, 535, 432, 7909, 7795, 0, 371, 7799, 0, 7797, 0, 7805, 
+    0, 7807, 7809, 7811, 373, 0, 7815, 7813, 0, 7832, 0, 7817, 7819, 7821, 
+    7923, 253, 375, 7929, 563, 0, 7823, 255, 7927, 7833, 0, 7925, 0, 378, 
+    7825, 0, 380, 0, 0, 382, 0, 7827, 7829, 0, 8173, 901, 8129, 0, 7846, 
+    7844, 0, 7850, 7848, 0, 478, 0, 0, 506, 0, 508, 482, 0, 0, 7688, 7872, 
+    7870, 0, 7876, 7874, 0, 0, 7726, 7890, 7888, 0, 7894, 7892, 0, 0, 7756, 
+    556, 0, 0, 7758, 554, 0, 0, 510, 475, 471, 469, 0, 0, 473, 7847, 7845, 0, 
+    7851, 7849, 0, 479, 0, 0, 507, 0, 509, 483, 0, 0, 7689, 7873, 7871, 0, 
+    7877, 7875, 0, 0, 7727, 7891, 7889, 0, 7895, 7893, 0, 0, 7757, 557, 0, 0, 
+    7759, 555, 0, 0, 511, 476, 472, 470, 0, 0, 474, 7856, 7854, 0, 7860, 
+    7858, 0, 7857, 7855, 0, 7861, 7859, 0, 7700, 7702, 7701, 7703, 7760, 
+    7762, 7761, 7763, 7780, 0, 7781, 0, 7782, 0, 7783, 0, 0, 7800, 0, 7801, 
+    0, 7802, 0, 7803, 7835, 0, 7900, 7898, 0, 7904, 7902, 0, 0, 7906, 7901, 
+    7899, 0, 7905, 7903, 0, 0, 7907, 7914, 7912, 0, 7918, 7916, 0, 0, 7920, 
+    7915, 7913, 0, 7919, 7917, 0, 0, 7921, 0, 494, 492, 0, 493, 0, 480, 0, 
+    481, 0, 0, 7708, 0, 7709, 560, 0, 561, 0, 0, 495, 8122, 902, 8121, 8120, 
+    7944, 7945, 0, 8124, 8136, 904, 7960, 7961, 8138, 905, 7976, 7977, 0, 
+    8140, 8154, 906, 8153, 8152, 0, 938, 7992, 7993, 8184, 908, 8008, 8009, 
+    0, 8172, 8170, 910, 8169, 8168, 0, 939, 0, 8025, 8186, 911, 8040, 8041, 
+    0, 8188, 0, 8116, 0, 8132, 8048, 940, 8113, 8112, 7936, 7937, 8118, 8115, 
+    8050, 941, 7952, 7953, 8052, 942, 7968, 7969, 8134, 8131, 8054, 943, 
+    8145, 8144, 0, 970, 7984, 7985, 8150, 0, 8056, 972, 8000, 8001, 8164, 
+    8165, 8058, 973, 8161, 8160, 0, 971, 8016, 8017, 8166, 0, 8060, 974, 
+    8032, 8033, 8182, 8179, 8146, 912, 8151, 0, 8162, 944, 8167, 0, 0, 8180, 
+    0, 979, 0, 980, 0, 1031, 0, 1232, 0, 1234, 0, 1027, 1024, 0, 0, 1238, 0, 
+    1025, 0, 1217, 0, 1244, 0, 1246, 1037, 0, 1250, 1049, 0, 1252, 0, 1036, 
+    0, 1254, 1262, 1038, 0, 1264, 1266, 0, 0, 1268, 0, 1272, 0, 1260, 0, 
+    1233, 0, 1235, 0, 1107, 1104, 0, 0, 1239, 0, 1105, 0, 1218, 0, 1245, 0, 
+    1247, 1117, 0, 1251, 1081, 0, 1253, 0, 1116, 0, 1255, 1263, 1118, 0, 
+    1265, 1267, 0, 0, 1269, 0, 1273, 0, 1261, 0, 1111, 1142, 0, 1143, 0, 0, 
+    1242, 0, 1243, 0, 1258, 0, 1259, 1570, 1571, 1573, 0, 0, 1572, 0, 1574, 
+    0, 1730, 0, 1747, 0, 1728, 0, 2345, 0, 2353, 0, 2356, 2507, 2508, 2891, 
+    2888, 2892, 0, 2964, 0, 0, 3018, 3020, 0, 0, 3019, 0, 3144, 0, 3264, 
+    3274, 3271, 3272, 0, 0, 3275, 0, 3402, 3404, 0, 0, 3403, 0, 3546, 3548, 
+    3550, 0, 3549, 4134, 0, 0, 6918, 0, 6920, 0, 6922, 0, 6924, 0, 6926, 0, 
+    6930, 0, 6971, 0, 6973, 0, 6976, 0, 6977, 0, 6979, 7736, 0, 7737, 0, 
+    7772, 0, 7773, 0, 7784, 0, 7785, 0, 7852, 0, 0, 7862, 7853, 0, 0, 7863, 
+    7878, 0, 7879, 0, 7896, 0, 7897, 0, 7938, 7940, 7942, 8064, 7939, 7941, 
+    7943, 8065, 0, 8066, 0, 8067, 0, 8068, 0, 8069, 0, 8070, 0, 8071, 7946, 
+    7948, 7950, 8072, 7947, 7949, 7951, 8073, 0, 8074, 0, 8075, 0, 8076, 0, 
+    8077, 0, 8078, 0, 8079, 7954, 7956, 7955, 7957, 7962, 7964, 7963, 7965, 
+    7970, 7972, 7974, 8080, 7971, 7973, 7975, 8081, 0, 8082, 0, 8083, 0, 
+    8084, 0, 8085, 0, 8086, 0, 8087, 7978, 7980, 7982, 8088, 7979, 7981, 
+    7983, 8089, 0, 8090, 0, 8091, 0, 8092, 0, 8093, 0, 8094, 0, 8095, 7986, 
+    7988, 7990, 0, 7987, 7989, 7991, 0, 7994, 7996, 7998, 0, 7995, 7997, 
+    7999, 0, 8002, 8004, 8003, 8005, 8010, 8012, 8011, 8013, 8018, 8020, 
+    8022, 0, 8019, 8021, 8023, 0, 8027, 8029, 8031, 0, 8034, 8036, 8038, 
+    8096, 8035, 8037, 8039, 8097, 0, 8098, 0, 8099, 0, 8100, 0, 8101, 0, 
+    8102, 0, 8103, 8042, 8044, 8046, 8104, 8043, 8045, 8047, 8105, 0, 8106, 
+    0, 8107, 0, 8108, 0, 8109, 0, 8110, 0, 8111, 0, 8114, 0, 8130, 0, 8178, 
+    0, 8119, 8141, 8142, 8143, 0, 0, 8135, 0, 8183, 8157, 8158, 8159, 0, 0, 
+    8602, 0, 8603, 0, 8622, 0, 8653, 0, 8655, 0, 8654, 0, 8708, 0, 8713, 0, 
+    8716, 0, 8740, 0, 8742, 0, 8769, 0, 8772, 0, 8775, 0, 8777, 0, 8813, 0, 
+    8802, 0, 8816, 0, 8817, 0, 8820, 0, 8821, 0, 8824, 0, 8825, 0, 8832, 0, 
+    8833, 0, 8928, 0, 8929, 0, 8836, 0, 8837, 0, 8840, 0, 8841, 0, 8930, 0, 
+    8931, 0, 8876, 0, 8877, 0, 8878, 0, 8879, 0, 8938, 0, 8939, 0, 8940, 0, 
+    8941, 12436, 0, 12364, 0, 12366, 0, 12368, 0, 12370, 0, 12372, 0, 12374, 
+    0, 12376, 0, 12378, 0, 12380, 0, 12382, 0, 12384, 0, 12386, 0, 12389, 0, 
+    12391, 0, 12393, 0, 12400, 12401, 12403, 12404, 12406, 12407, 12409, 
+    12410, 12412, 12413, 12446, 0, 12532, 0, 12460, 0, 12462, 0, 12464, 0, 
+    12466, 0, 12468, 0, 12470, 0, 12472, 0, 12474, 0, 12476, 0, 12478, 0, 
+    12480, 0, 12482, 0, 12485, 0, 12487, 0, 12489, 0, 12496, 12497, 12499, 
+    12500, 12502, 12503, 12505, 12506, 12508, 12509, 12535, 0, 12536, 0, 
+    12537, 0, 12538, 0, 12542, 0, 69786, 0, 69788, 0, 69803, 0, 0, 69934, 0, 
+    69935, 70475, 70476, 70844, 70843, 70846, 0, 0, 71098, 0, 71099, 
+};
+
index fd1fd44..a2c59da 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
  * Copyright © 2011  Codethink Limited
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2010,2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 #define HB_UNICODE_PRIVATE_HH
 
 #include "hb-private.hh"
-
-#include "hb-unicode.h"
 #include "hb-object-private.hh"
 
 
+extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
 
 /*
  * hb_unicode_funcs_t
   HB_UNICODE_FUNC_IMPLEMENT (script) \
   HB_UNICODE_FUNC_IMPLEMENT (compose) \
   HB_UNICODE_FUNC_IMPLEMENT (decompose) \
+  HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility) \
   /* ^--- Add new callbacks here */
 
 /* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */
 #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \
-  HB_UNICODE_FUNC_IMPLEMENT (unsigned int, combining_class) \
+  HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_combining_class_t, combining_class) \
   HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \
   HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \
   /* ^--- Add new simple callbacks here */
 
-struct _hb_unicode_funcs_t {
+struct hb_unicode_funcs_t {
   hb_object_header_t header;
   ASSERT_POD ();
 
@@ -69,7 +69,136 @@ struct _hb_unicode_funcs_t {
 
   bool immutable;
 
-  /* Don't access these directly.  Call hb_unicode_*() instead. */
+#define HB_UNICODE_FUNC_IMPLEMENT(return_type, name) \
+  inline return_type name (hb_codepoint_t unicode) { return func.name (this, unicode, user_data.name); }
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+  inline hb_bool_t compose (hb_codepoint_t a, hb_codepoint_t b,
+                           hb_codepoint_t *ab)
+  {
+    *ab = 0;
+    if (unlikely (!a || !b)) return false;
+    return func.compose (this, a, b, ab, user_data.compose);
+  }
+
+  inline hb_bool_t decompose (hb_codepoint_t ab,
+                             hb_codepoint_t *a, hb_codepoint_t *b)
+  {
+    *a = ab; *b = 0;
+    return func.decompose (this, ab, a, b, user_data.decompose);
+  }
+
+  inline unsigned int decompose_compatibility (hb_codepoint_t  u,
+                                              hb_codepoint_t *decomposed)
+  {
+    unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility);
+    if (ret == 1 && u == decomposed[0]) {
+      decomposed[0] = 0;
+      return 0;
+    }
+    decomposed[ret] = 0;
+    return ret;
+  }
+
+
+  inline unsigned int
+  modified_combining_class (hb_codepoint_t unicode)
+  {
+    /* XXX This hack belongs to the Myanmar shaper. */
+    if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
+
+    /* XXX This hack belongs to the SEA shaper (for Tai Tham):
+     * Reorder SAKOT to ensure it comes after any tone marks. */
+    if (unlikely (unicode == 0x1A60u)) return 254;
+
+    /* XXX This hack belongs to the Tibetan shaper:
+     * Reorder PADMA to ensure it comes after any vowel marks. */
+    if (unlikely (unicode == 0x0FC6u)) return 254;
+
+    return _hb_modified_combining_class[combining_class (unicode)];
+  }
+
+  static inline hb_bool_t
+  is_variation_selector (hb_codepoint_t unicode)
+  {
+    /* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the
+     * Arabic shaper.  No need to match them here. */
+    return unlikely (hb_in_ranges (unicode,
+                                  0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
+                                  0xE0100u, 0xE01EFu));  /* VARIATION SELECTOR-17..256 */
+  }
+
+  /* Default_Ignorable codepoints:
+   *
+   * Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable,
+   * we do NOT want to hide them, as the way Uniscribe has implemented them
+   * is with regular spacing glyphs, and that's the way fonts are made to work.
+   * As such, we make exceptions for those four.
+   *
+   * Unicode 7.0:
+   * $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
+   * 00AD          # Cf       SOFT HYPHEN
+   * 034F          # Mn       COMBINING GRAPHEME JOINER
+   * 061C          # Cf       ARABIC LETTER MARK
+   * 115F..1160    # Lo   [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
+   * 17B4..17B5    # Mn   [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+   * 180B..180D    # Mn   [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+   * 180E          # Cf       MONGOLIAN VOWEL SEPARATOR
+   * 200B..200F    # Cf   [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+   * 202A..202E    # Cf   [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+   * 2060..2064    # Cf   [5] WORD JOINER..INVISIBLE PLUS
+   * 2065          # Cn       <reserved-2065>
+   * 2066..206F    # Cf  [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+   * 3164          # Lo       HANGUL FILLER
+   * FE00..FE0F    # Mn  [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+   * FEFF          # Cf       ZERO WIDTH NO-BREAK SPACE
+   * FFA0          # Lo       HALFWIDTH HANGUL FILLER
+   * FFF0..FFF8    # Cn   [9] <reserved-FFF0>..<reserved-FFF8>
+   * 1BCA0..1BCA3  # Cf   [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+   * 1D173..1D17A  # Cf   [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+   * E0000         # Cn       <reserved-E0000>
+   * E0001         # Cf       LANGUAGE TAG
+   * E0002..E001F  # Cn  [30] <reserved-E0002>..<reserved-E001F>
+   * E0020..E007F  # Cf  [96] TAG SPACE..CANCEL TAG
+   * E0080..E00FF  # Cn [128] <reserved-E0080>..<reserved-E00FF>
+   * E0100..E01EF  # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+   * E01F0..E0FFF  # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
+   */
+  static inline hb_bool_t
+  is_default_ignorable (hb_codepoint_t ch)
+  {
+    hb_codepoint_t plane = ch >> 16;
+    if (likely (plane == 0))
+    {
+      /* BMP */
+      hb_codepoint_t page = ch >> 8;
+      switch (page) {
+       case 0x00: return unlikely (ch == 0x00ADu);
+       case 0x03: return unlikely (ch == 0x034Fu);
+       case 0x06: return unlikely (ch == 0x061Cu);
+       case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u);
+       case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu);
+       case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu,
+                                                           0x202Au, 0x202Eu,
+                                                           0x2060u, 0x206Fu);
+       case 0xFE: return hb_in_range (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
+       case 0xFF: return hb_in_range (ch, 0xFFF0u, 0xFFF8u);
+       default: return false;
+      }
+    }
+    else
+    {
+      /* Other planes */
+      switch (plane) {
+       case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
+                                           0x1D173u, 0x1D17Au);
+       case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
+       default: return false;
+      }
+    }
+  }
+
 
   struct {
 #define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
@@ -91,69 +220,98 @@ struct _hb_unicode_funcs_t {
 };
 
 
-#ifdef HAVE_GLIB
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_glib_unicode_funcs;
-#define _hb_unicode_funcs_default _hb_glib_unicode_funcs
-#elif defined(HAVE_ICU)
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_icu_unicode_funcs;
-#define _hb_unicode_funcs_default _hb_icu_unicode_funcs
-#else
-#define HB_UNICODE_FUNCS_NIL 1
 extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
-#define _hb_unicode_funcs_default _hb_unicode_funcs_nil
-#endif
-
 
-HB_INTERNAL unsigned int
-_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
-                                     hb_codepoint_t      unicode);
 
-static inline hb_bool_t
-_hb_unicode_is_variation_selector (hb_codepoint_t unicode)
-{
-  return unlikely ((unicode >=  0x180B && unicode <=  0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
-                  (unicode >=  0xFE00 && unicode <=  0xFE0F) || /* VARIATION SELECTOR-1..16 */
-                  (unicode >= 0xE0100 && unicode <= 0xE01EF));  /* VARIATION SELECTOR-17..256 */
-}
+/* Modified combining marks */
 
-/* Zero-Width invisible characters:
+/* Hebrew
  *
- *  00AD  SOFT HYPHEN
- *  034F  COMBINING GRAPHEME JOINER
+ * We permute the "fixed-position" classes 10-26 into the order
+ * described in the SBL Hebrew manual:
  *
- *  200B  ZERO WIDTH SPACE
- *  200C  ZERO WIDTH NON-JOINER
- *  200D  ZERO WIDTH JOINER
- *  200E  LEFT-TO-RIGHT MARK
- *  200F  RIGHT-TO-LEFT MARK
+ * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
  *
- *  2028  LINE SEPARATOR
+ * (as recommended by:
+ *  http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
  *
- *  202A  LEFT-TO-RIGHT EMBEDDING
- *  202B  RIGHT-TO-LEFT EMBEDDING
- *  202C  POP DIRECTIONAL FORMATTING
- *  202D  LEFT-TO-RIGHT OVERRIDE
- *  202E  RIGHT-TO-LEFT OVERRIDE
+ * More details here:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC10 22 /* sheva */
+#define HB_MODIFIED_COMBINING_CLASS_CCC11 15 /* hataf segol */
+#define HB_MODIFIED_COMBINING_CLASS_CCC12 16 /* hataf patah */
+#define HB_MODIFIED_COMBINING_CLASS_CCC13 17 /* hataf qamats */
+#define HB_MODIFIED_COMBINING_CLASS_CCC14 23 /* hiriq */
+#define HB_MODIFIED_COMBINING_CLASS_CCC15 18 /* tsere */
+#define HB_MODIFIED_COMBINING_CLASS_CCC16 19 /* segol */
+#define HB_MODIFIED_COMBINING_CLASS_CCC17 20 /* patah */
+#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats */
+#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam */
+#define HB_MODIFIED_COMBINING_CLASS_CCC20 24 /* qubuts */
+#define HB_MODIFIED_COMBINING_CLASS_CCC21 12 /* dagesh */
+#define HB_MODIFIED_COMBINING_CLASS_CCC22 25 /* meteg */
+#define HB_MODIFIED_COMBINING_CLASS_CCC23 13 /* rafe */
+#define HB_MODIFIED_COMBINING_CLASS_CCC24 10 /* shin dot */
+#define HB_MODIFIED_COMBINING_CLASS_CCC25 11 /* sin dot */
+#define HB_MODIFIED_COMBINING_CLASS_CCC26 26 /* point varika */
+
+/*
+ * Arabic
  *
- *  2060  WORD JOINER
- *  2061  FUNCTION APPLICATION
- *  2062  INVISIBLE TIMES
- *  2063  INVISIBLE SEPARATOR
+ * Modify to move Shadda (ccc=33) before other marks.  See:
+ * http://unicode.org/faq/normalization.html#8
+ * http://unicode.org/faq/normalization.html#9
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC27 28 /* fathatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC28 29 /* dammatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC29 30 /* kasratan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC30 31 /* fatha */
+#define HB_MODIFIED_COMBINING_CLASS_CCC31 32 /* damma */
+#define HB_MODIFIED_COMBINING_CLASS_CCC32 33 /* kasra */
+#define HB_MODIFIED_COMBINING_CLASS_CCC33 27 /* shadda */
+#define HB_MODIFIED_COMBINING_CLASS_CCC34 34 /* sukun */
+#define HB_MODIFIED_COMBINING_CLASS_CCC35 35 /* superscript alef */
+
+/* Syriac */
+#define HB_MODIFIED_COMBINING_CLASS_CCC36 36 /* superscript alaph */
+
+/* Telugu
+ *
+ * Modify Telugu length marks (ccc=84, ccc=91).
+ * These are the only matras in the main Indic scripts range that have
+ * a non-zero ccc.  That makes them reorder with the Halant that is
+ * ccc=9.  Just zero them, we don't need them in our Indic shaper.
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC84 0 /* length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC91 0 /* ai length mark */
+
+/* Thai
  *
- *  FEFF  ZERO WIDTH NO-BREAK SPACE
+ * Modify U+0E38 and U+0E39 (ccc=103) to be reordered before U+0E3A (ccc=9).
+ * Assign 3, which is unassigned otherwise.
+ * Uniscribe does this reordering too.
  */
-static inline hb_bool_t
-_hb_unicode_is_zero_width (hb_codepoint_t ch)
-{
-  return ((ch & ~0x007F) == 0x2000 && (
-         (ch >= 0x200B && ch <= 0x200F) ||
-         (ch >= 0x202A && ch <= 0x202E) ||
-         (ch >= 0x2060 && ch <= 0x2063) ||
-         (ch == 0x2028)
-        )) || unlikely (ch == 0x0009
-                     || ch == 0x00AD
-                     || ch == 0x034F
-                     || ch == 0xFEFF);
-}
+#define HB_MODIFIED_COMBINING_CLASS_CCC103 3 /* sara u / sara uu */
+#define HB_MODIFIED_COMBINING_CLASS_CCC107 107 /* mai * */
+
+/* Lao */
+#define HB_MODIFIED_COMBINING_CLASS_CCC118 118 /* sign u / sign uu */
+#define HB_MODIFIED_COMBINING_CLASS_CCC122 122 /* mai * */
+
+/* Tibetan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC129 129 /* sign aa */
+#define HB_MODIFIED_COMBINING_CLASS_CCC130 130 /* sign i */
+#define HB_MODIFIED_COMBINING_CLASS_CCC132 132 /* sign u */
+
+
+/* Misc */
+
+#define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
+       (FLAG (gen_cat) & \
+        (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+         FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
+         FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+
 
 #endif /* HB_UNICODE_PRIVATE_HH */
index 6a21ef3..fc19006 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
- * Copyright © 2011 Codethink Limited
- * Copyright © 2010,2011  Google, Inc.
+ * Copyright © 2011  Codethink Limited
+ * Copyright © 2010,2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * hb_unicode_funcs_t
  */
 
-static unsigned int
+static hb_unicode_combining_class_t
 hb_unicode_combining_class_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
                                hb_codepoint_t      unicode   HB_UNUSED,
                                void               *user_data HB_UNUSED)
 {
-  return 0;
+  return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
 }
 
 static unsigned int
@@ -99,13 +99,72 @@ hb_unicode_decompose_nil (hb_unicode_funcs_t *ufuncs    HB_UNUSED,
 }
 
 
+static unsigned int
+hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs     HB_UNUSED,
+                                       hb_codepoint_t      u          HB_UNUSED,
+                                       hb_codepoint_t     *decomposed HB_UNUSED,
+                                       void               *user_data  HB_UNUSED)
+{
+  return 0;
+}
+
+
+#define HB_UNICODE_FUNCS_IMPLEMENT_SET \
+  HB_UNICODE_FUNCS_IMPLEMENT (glib) \
+  HB_UNICODE_FUNCS_IMPLEMENT (icu) \
+  HB_UNICODE_FUNCS_IMPLEMENT (ucdn) \
+  HB_UNICODE_FUNCS_IMPLEMENT (nil) \
+  /* ^--- Add new callbacks before nil */
+
+#define hb_nil_get_unicode_funcs hb_unicode_funcs_get_empty
+
+/* Prototype them all */
+#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
+extern "C" hb_unicode_funcs_t *hb_##set##_get_unicode_funcs (void);
+HB_UNICODE_FUNCS_IMPLEMENT_SET
+#undef HB_UNICODE_FUNCS_IMPLEMENT
+
 
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_default (void)
 {
-  return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default);
+#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
+  return hb_##set##_get_unicode_funcs ();
+
+#ifdef HAVE_GLIB
+  HB_UNICODE_FUNCS_IMPLEMENT(glib)
+#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
+  HB_UNICODE_FUNCS_IMPLEMENT(icu)
+#elif defined(HAVE_UCDN)
+  HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
+#else
+#define HB_UNICODE_FUNCS_NIL 1
+  HB_UNICODE_FUNCS_IMPLEMENT(nil)
+#endif
+
+#undef HB_UNICODE_FUNCS_IMPLEMENT
 }
 
+#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
+#ifdef _MSC_VER
+#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
+#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
+#else
+#warning "Could not find any Unicode functions implementation, you have to provide your own"
+#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
+#endif
+#endif
+
+/**
+ * hb_unicode_funcs_create: (Xconstructor)
+ * @parent: (nullable):
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
 {
@@ -131,7 +190,6 @@ hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
 }
 
 
-//extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
 const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
   HB_OBJECT_HEADER_STATIC,
 
@@ -144,18 +202,45 @@ const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
   }
 };
 
+/**
+ * hb_unicode_funcs_get_empty:
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_empty (void)
 {
   return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil);
 }
 
+/**
+ * hb_unicode_funcs_reference: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
 {
   return hb_object_reference (ufuncs);
 }
 
+/**
+ * hb_unicode_funcs_destroy: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
 {
@@ -171,6 +256,20 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
   free (ufuncs);
 }
 
+/**
+ * hb_unicode_funcs_set_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key: 
+ * @data: 
+ * @destroy: 
+ * @replace: 
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
                                hb_user_data_key_t *key,
@@ -181,6 +280,17 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
   return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
 }
 
+/**
+ * hb_unicode_funcs_get_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key: 
+ *
+ * 
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
 void *
 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
                                hb_user_data_key_t *key)
@@ -189,21 +299,49 @@ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
 }
 
 
+/**
+ * hb_unicode_funcs_make_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
 {
-  if (hb_object_is_inert (ufuncs))
+  if (unlikely (hb_object_is_inert (ufuncs)))
     return;
 
   ufuncs->immutable = true;
 }
 
+/**
+ * hb_unicode_funcs_is_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
 {
   return ufuncs->immutable;
 }
 
+/**
+ * hb_unicode_funcs_get_parent:
+ * @ufuncs: Unicode functions.
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_unicode_funcs_t *
 hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
 {
@@ -236,7 +374,7 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t                 *ufuncs,     \
   }                                                                            \
 }
 
-    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
 
@@ -246,83 +384,185 @@ return_type                                                                      \
 hb_unicode_##name (hb_unicode_funcs_t *ufuncs,                                 \
                   hb_codepoint_t      unicode)                                 \
 {                                                                              \
-  return ufuncs->func.name (ufuncs, unicode, ufuncs->user_data.name);          \
+  return ufuncs->name (unicode);                                               \
 }
-    HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
 #undef HB_UNICODE_FUNC_IMPLEMENT
 
+/**
+ * hb_unicode_compose:
+ * @ufuncs: Unicode functions.
+ * @a: 
+ * @b: 
+ * @ab: (out):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
                    hb_codepoint_t      a,
                    hb_codepoint_t      b,
                    hb_codepoint_t     *ab)
 {
-  *ab = 0;
-  return ufuncs->func.compose (ufuncs, a, b, ab, ufuncs->user_data.compose);
+  return ufuncs->compose (a, b, ab);
 }
 
+/**
+ * hb_unicode_decompose:
+ * @ufuncs: Unicode functions.
+ * @ab: 
+ * @a: (out):
+ * @b: (out):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 hb_bool_t
 hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
                      hb_codepoint_t      ab,
                      hb_codepoint_t     *a,
                      hb_codepoint_t     *b)
 {
-  *a = ab; *b = 0;
-  return ufuncs->func.decompose (ufuncs, ab, a, b, ufuncs->user_data.decompose);
+  return ufuncs->decompose (ab, a, b);
 }
 
-
-
+/**
+ * hb_unicode_decompose_compatibility:
+ * @ufuncs: Unicode functions.
+ * @u: 
+ * @decomposed: (out):
+ *
+ * 
+ *
+ * Return value: 
+ *
+ * Since: 1.0
+ **/
 unsigned int
-_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
-                                     hb_codepoint_t      unicode)
+hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+                                   hb_codepoint_t      u,
+                                   hb_codepoint_t     *decomposed)
 {
-  int c = hb_unicode_combining_class (ufuncs, unicode);
-
-  if (unlikely (hb_in_range<int> (c, 27, 33)))
-  {
-    /* Modify the combining-class to suit Arabic better.  See:
-     * http://unicode.org/faq/normalization.html#8
-     * http://unicode.org/faq/normalization.html#9
-     */
-    c = c == 33 ? 27 : c + 1;
-  }
-  else if (unlikely (hb_in_range<int> (c, 10, 25)))
-  {
-    /* The equivalent fix for Hebrew is more complex.
-     *
-     * We permute the "fixed-position" classes 10-25 into the order
-     * described in the SBL Hebrew manual:
-     *
-     * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
-     *
-     * (as recommended by:
-     *  http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
-     *
-     * More details here:
-     * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
-     */
-    static const int permuted_hebrew_classes[25 - 10 + 1] = {
-      /* 10 sheva */        22,
-      /* 11 hataf segol */  15,
-      /* 12 hataf patah */  16,
-      /* 13 hataf qamats */ 17,
-      /* 14 hiriq */        23,
-      /* 15 tsere */        18,
-      /* 16 segol */        19,
-      /* 17 patah */        20,
-      /* 18 qamats */       21,
-      /* 19 holam */        14,
-      /* 20 qubuts */       24,
-      /* 21 dagesh */       12,
-      /* 22 meteg */        25,
-      /* 23 rafe */         13,
-      /* 24 shin dot */     10,
-      /* 25 sin dot */      11,
-    };
-    c = permuted_hebrew_classes[c - 10];
-  }
-
-  return c;
+  return ufuncs->decompose_compatibility (u, decomposed);
 }
 
+
+/* See hb-unicode-private.hh for details. */
+const uint8_t
+_hb_modified_combining_class[256] =
+{
+  0, /* HB_UNICODE_COMBINING_CLASS_NOT_REORDERED */
+  1, /* HB_UNICODE_COMBINING_CLASS_OVERLAY */
+  2, 3, 4, 5, 6,
+  7, /* HB_UNICODE_COMBINING_CLASS_NUKTA */
+  8, /* HB_UNICODE_COMBINING_CLASS_KANA_VOICING */
+  9, /* HB_UNICODE_COMBINING_CLASS_VIRAMA */
+
+  /* Hebrew */
+  HB_MODIFIED_COMBINING_CLASS_CCC10,
+  HB_MODIFIED_COMBINING_CLASS_CCC11,
+  HB_MODIFIED_COMBINING_CLASS_CCC12,
+  HB_MODIFIED_COMBINING_CLASS_CCC13,
+  HB_MODIFIED_COMBINING_CLASS_CCC14,
+  HB_MODIFIED_COMBINING_CLASS_CCC15,
+  HB_MODIFIED_COMBINING_CLASS_CCC16,
+  HB_MODIFIED_COMBINING_CLASS_CCC17,
+  HB_MODIFIED_COMBINING_CLASS_CCC18,
+  HB_MODIFIED_COMBINING_CLASS_CCC19,
+  HB_MODIFIED_COMBINING_CLASS_CCC20,
+  HB_MODIFIED_COMBINING_CLASS_CCC21,
+  HB_MODIFIED_COMBINING_CLASS_CCC22,
+  HB_MODIFIED_COMBINING_CLASS_CCC23,
+  HB_MODIFIED_COMBINING_CLASS_CCC24,
+  HB_MODIFIED_COMBINING_CLASS_CCC25,
+  HB_MODIFIED_COMBINING_CLASS_CCC26,
+
+  /* Arabic */
+  HB_MODIFIED_COMBINING_CLASS_CCC27,
+  HB_MODIFIED_COMBINING_CLASS_CCC28,
+  HB_MODIFIED_COMBINING_CLASS_CCC29,
+  HB_MODIFIED_COMBINING_CLASS_CCC30,
+  HB_MODIFIED_COMBINING_CLASS_CCC31,
+  HB_MODIFIED_COMBINING_CLASS_CCC32,
+  HB_MODIFIED_COMBINING_CLASS_CCC33,
+  HB_MODIFIED_COMBINING_CLASS_CCC34,
+  HB_MODIFIED_COMBINING_CLASS_CCC35,
+
+  /* Syriac */
+  HB_MODIFIED_COMBINING_CLASS_CCC36,
+
+  37, 38, 39,
+  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, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+  80, 81, 82, 83,
+
+  /* Telugu */
+  HB_MODIFIED_COMBINING_CLASS_CCC84,
+  85, 86, 87, 88, 89, 90,
+  HB_MODIFIED_COMBINING_CLASS_CCC91,
+  92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+
+  /* Thai */
+  HB_MODIFIED_COMBINING_CLASS_CCC103,
+  104, 105, 106,
+  HB_MODIFIED_COMBINING_CLASS_CCC107,
+  108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+
+  /* Lao */
+  HB_MODIFIED_COMBINING_CLASS_CCC118,
+  119, 120, 121,
+  HB_MODIFIED_COMBINING_CLASS_CCC122,
+  123, 124, 125, 126, 127, 128,
+
+  /* Tibetan */
+  HB_MODIFIED_COMBINING_CLASS_CCC129,
+  HB_MODIFIED_COMBINING_CLASS_CCC130,
+  131,
+  HB_MODIFIED_COMBINING_CLASS_CCC132,
+  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, 158, 159,
+  160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+  170, 171, 172, 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, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT */
+  201,
+  202, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW */
+  203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+  214, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE */
+  215,
+  216, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT */
+  217,
+  218, /* HB_UNICODE_COMBINING_CLASS_BELOW_LEFT */
+  219,
+  220, /* HB_UNICODE_COMBINING_CLASS_BELOW */
+  221,
+  222, /* HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT */
+  223,
+  224, /* HB_UNICODE_COMBINING_CLASS_LEFT */
+  225,
+  226, /* HB_UNICODE_COMBINING_CLASS_RIGHT */
+  227,
+  228, /* HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT */
+  229,
+  230, /* HB_UNICODE_COMBINING_CLASS_ABOVE */
+  231,
+  232, /* HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT */
+  233, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW */
+  234, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE */
+  235, 236, 237, 238, 239,
+  240, /* HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT */
+  241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+  255, /* HB_UNICODE_COMBINING_CLASS_INVALID */
+};
index b26168f..1c4e097 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright © 2009  Red Hat, Inc.
  * Copyright © 2011  Codethink Limited
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
 HB_BEGIN_DECLS
 
 
+/* hb_unicode_general_category_t */
+
+/* Unicode Character Database property: General_Category (gc) */
+typedef enum
+{
+  HB_UNICODE_GENERAL_CATEGORY_CONTROL,                 /* Cc */
+  HB_UNICODE_GENERAL_CATEGORY_FORMAT,                  /* Cf */
+  HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED,              /* Cn */
+  HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE,             /* Co */
+  HB_UNICODE_GENERAL_CATEGORY_SURROGATE,               /* Cs */
+  HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER,                /* Ll */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER,         /* Lm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER,            /* Lo */
+  HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER,                /* Lt */
+  HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER,                /* Lu */
+  HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK,            /* Mc */
+  HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK,          /* Me */
+  HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK,                /* Mn */
+  HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER,          /* Nd */
+  HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER,           /* Nl */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER,            /* No */
+  HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION,     /* Pc */
+  HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION,                /* Pd */
+  HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION,       /* Pe */
+  HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION,       /* Pf */
+  HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION,     /* Pi */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION,       /* Po */
+  HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION,                /* Ps */
+  HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL,         /* Sc */
+  HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL,         /* Sk */
+  HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL,             /* Sm */
+  HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL,            /* So */
+  HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR,          /* Zl */
+  HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR,     /* Zp */
+  HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR          /* Zs */
+} hb_unicode_general_category_t;
+
+/* hb_unicode_combining_class_t */
+
+/* Note: newer versions of Unicode may add new values.  Clients should be ready to handle
+ * any value in the 0..254 range being returned from hb_unicode_combining_class().
+ */
+
+/* Unicode Character Database property: Canonical_Combining_Class (ccc) */
+typedef enum
+{
+  HB_UNICODE_COMBINING_CLASS_NOT_REORDERED     = 0,
+  HB_UNICODE_COMBINING_CLASS_OVERLAY           = 1,
+  HB_UNICODE_COMBINING_CLASS_NUKTA             = 7,
+  HB_UNICODE_COMBINING_CLASS_KANA_VOICING      = 8,
+  HB_UNICODE_COMBINING_CLASS_VIRAMA            = 9,
+
+  /* Hebrew */
+  HB_UNICODE_COMBINING_CLASS_CCC10     =  10,
+  HB_UNICODE_COMBINING_CLASS_CCC11     =  11,
+  HB_UNICODE_COMBINING_CLASS_CCC12     =  12,
+  HB_UNICODE_COMBINING_CLASS_CCC13     =  13,
+  HB_UNICODE_COMBINING_CLASS_CCC14     =  14,
+  HB_UNICODE_COMBINING_CLASS_CCC15     =  15,
+  HB_UNICODE_COMBINING_CLASS_CCC16     =  16,
+  HB_UNICODE_COMBINING_CLASS_CCC17     =  17,
+  HB_UNICODE_COMBINING_CLASS_CCC18     =  18,
+  HB_UNICODE_COMBINING_CLASS_CCC19     =  19,
+  HB_UNICODE_COMBINING_CLASS_CCC20     =  20,
+  HB_UNICODE_COMBINING_CLASS_CCC21     =  21,
+  HB_UNICODE_COMBINING_CLASS_CCC22     =  22,
+  HB_UNICODE_COMBINING_CLASS_CCC23     =  23,
+  HB_UNICODE_COMBINING_CLASS_CCC24     =  24,
+  HB_UNICODE_COMBINING_CLASS_CCC25     =  25,
+  HB_UNICODE_COMBINING_CLASS_CCC26     =  26,
+
+  /* Arabic */
+  HB_UNICODE_COMBINING_CLASS_CCC27     =  27,
+  HB_UNICODE_COMBINING_CLASS_CCC28     =  28,
+  HB_UNICODE_COMBINING_CLASS_CCC29     =  29,
+  HB_UNICODE_COMBINING_CLASS_CCC30     =  30,
+  HB_UNICODE_COMBINING_CLASS_CCC31     =  31,
+  HB_UNICODE_COMBINING_CLASS_CCC32     =  32,
+  HB_UNICODE_COMBINING_CLASS_CCC33     =  33,
+  HB_UNICODE_COMBINING_CLASS_CCC34     =  34,
+  HB_UNICODE_COMBINING_CLASS_CCC35     =  35,
+
+  /* Syriac */
+  HB_UNICODE_COMBINING_CLASS_CCC36     =  36,
+
+  /* Telugu */
+  HB_UNICODE_COMBINING_CLASS_CCC84     =  84,
+  HB_UNICODE_COMBINING_CLASS_CCC91     =  91,
+
+  /* Thai */
+  HB_UNICODE_COMBINING_CLASS_CCC103    = 103,
+  HB_UNICODE_COMBINING_CLASS_CCC107    = 107,
+
+  /* Lao */
+  HB_UNICODE_COMBINING_CLASS_CCC118    = 118,
+  HB_UNICODE_COMBINING_CLASS_CCC122    = 122,
+
+  /* Tibetan */
+  HB_UNICODE_COMBINING_CLASS_CCC129    = 129,
+  HB_UNICODE_COMBINING_CLASS_CCC130    = 130,
+  HB_UNICODE_COMBINING_CLASS_CCC133    = 132,
+
+
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT       = 200,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW            = 202,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE            = 214,
+  HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT      = 216,
+  HB_UNICODE_COMBINING_CLASS_BELOW_LEFT                        = 218,
+  HB_UNICODE_COMBINING_CLASS_BELOW                     = 220,
+  HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT               = 222,
+  HB_UNICODE_COMBINING_CLASS_LEFT                      = 224,
+  HB_UNICODE_COMBINING_CLASS_RIGHT                     = 226,
+  HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT                        = 228,
+  HB_UNICODE_COMBINING_CLASS_ABOVE                     = 230,
+  HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT               = 232,
+  HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW              = 233,
+  HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE              = 234,
+
+  HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT            = 240,
+
+  HB_UNICODE_COMBINING_CLASS_INVALID   = 255
+} hb_unicode_combining_class_t;
+
+
 /*
  * hb_unicode_funcs_t
  */
 
-typedef struct _hb_unicode_funcs_t hb_unicode_funcs_t;
+typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
 
 
 /*
@@ -71,7 +195,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
                                hb_user_data_key_t *key,
                                void *              data,
                                hb_destroy_func_t   destroy,
-                               hb_bool_t           replace);
+                               hb_bool_t           replace);
+
 
 void *
 hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
@@ -94,7 +219,7 @@ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
 
 /* typedefs */
 
-typedef unsigned int                   (*hb_unicode_combining_class_func_t)    (hb_unicode_funcs_t *ufuncs,
+typedef hb_unicode_combining_class_t   (*hb_unicode_combining_class_func_t)    (hb_unicode_funcs_t *ufuncs,
                                                                                 hb_codepoint_t      unicode,
                                                                                 void               *user_data);
 typedef unsigned int                   (*hb_unicode_eastasian_width_func_t)    (hb_unicode_funcs_t *ufuncs,
@@ -121,47 +246,165 @@ typedef hb_bool_t                        (*hb_unicode_decompose_func_t)          (hb_unicode_funcs_t *ufuncs,
                                                                                 hb_codepoint_t     *b,
                                                                                 void               *user_data);
 
+/**
+ * hb_unicode_decompose_compatibility_func_t:
+ * @ufuncs: a Unicode function structure
+ * @u: codepoint to decompose
+ * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
+ * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
+ *
+ * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
+ * The complete length of the decomposition will be returned.
+ *
+ * If @u has no compatibility decomposition, zero should be returned.
+ *
+ * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
+ * compatibility decomposition plus an terminating value of 0.  Consequently, @decompose must be allocated by the caller to be at least this length.  Implementations
+ * of this function type must ensure that they do not write past the provided array.
+ *
+ * Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available.
+ */
+typedef unsigned int                   (*hb_unicode_decompose_compatibility_func_t)    (hb_unicode_funcs_t *ufuncs,
+                                                                                        hb_codepoint_t      u,
+                                                                                        hb_codepoint_t     *decomposed,
+                                                                                        void               *user_data);
+
+/* See Unicode 6.1 for details on the maximum decomposition length. */
+#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */
+
 /* setters */
 
+/**
+ * hb_unicode_funcs_set_combining_class_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
-                                          hb_unicode_combining_class_func_t combining_class_func,
+                                          hb_unicode_combining_class_func_t func,
                                           void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_eastasian_width_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
-                                          hb_unicode_eastasian_width_func_t eastasian_width_func,
+                                          hb_unicode_eastasian_width_func_t func,
                                           void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_general_category_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
-                                           hb_unicode_general_category_func_t general_category_func,
+                                           hb_unicode_general_category_func_t func,
                                            void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_mirroring_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
-                                    hb_unicode_mirroring_func_t mirroring_func,
+                                    hb_unicode_mirroring_func_t func,
                                     void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_script_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
-                                 hb_unicode_script_func_t script_func,
+                                 hb_unicode_script_func_t func,
                                  void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_compose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
-                                  hb_unicode_compose_func_t compose_func,
+                                  hb_unicode_compose_func_t func,
                                   void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_decompose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
 void
 hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
-                                    hb_unicode_decompose_func_t decompose_func,
+                                    hb_unicode_decompose_func_t func,
                                     void *user_data, hb_destroy_func_t destroy);
 
+/**
+ * hb_unicode_funcs_set_decompose_compatibility_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ * 
+ *
+ * Since: 1.0
+ **/
+void
+hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
+                                                  hb_unicode_decompose_compatibility_func_t func,
+                                                  void *user_data, hb_destroy_func_t destroy);
 
 /* accessors */
 
-unsigned int
+hb_unicode_combining_class_t
 hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
                            hb_codepoint_t unicode);
 
@@ -192,6 +435,11 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
                      hb_codepoint_t     *a,
                      hb_codepoint_t     *b);
 
+unsigned int
+hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+                                   hb_codepoint_t      u,
+                                   hb_codepoint_t     *decomposed);
+
 HB_END_DECLS
 
 #endif /* HB_UNICODE_H */
index 9f84a3c..e7bcad2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2011  Google, Inc.
+ * Copyright © 2011,2012,2013  Google, Inc.
  *
  *  This is part of HarfBuzz, a text shaping library.
  *
  * Google Author(s): Behdad Esfahbod
  */
 
-#define _WIN32_WINNT 0x0500
-
-#include "hb-private.hh"
+#define HB_SHAPER uniscribe
+#include "hb-shaper-impl-private.hh"
 
 #include <windows.h>
 #include <usp10.h>
-
-typedef ULONG WIN_ULONG;
+#include <rpc.h>
 
 #include "hb-uniscribe.h"
 
+#include "hb-open-file-private.hh"
 #include "hb-ot-name-table.hh"
 #include "hb-ot-tag.h"
 
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
-
-
 
 #ifndef HB_DEBUG_UNISCRIBE
 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
 #endif
 
 
-/*
-DWORD GetFontData(
-  __in   HDC hdc,
-  __in   DWORD dwTable,
-  __in   DWORD dwOffset,
-  __out  LPVOID lpvBuffer,
-  __in   DWORD cbData
+static inline uint16_t hb_uint16_swap (const uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline uint32_t hb_uint32_swap (const uint32_t v)
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+
+
+typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
+  const WCHAR *pwcInChars,
+  int cInChars,
+  int cMaxItems,
+  const SCRIPT_CONTROL *psControl,
+  const SCRIPT_STATE *psState,
+  SCRIPT_ITEM *pItems,
+  OPENTYPE_TAG *pScriptTags,
+  int *pcItems
 );
-*/
 
-static bool
-populate_log_font (LOGFONTW  *lf,
-                  HDC        hdc,
-                  hb_font_t *font)
+typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,
+  OPENTYPE_TAG tagScript,
+  OPENTYPE_TAG tagLangSys,
+  int *rcRangeChars,
+  TEXTRANGE_PROPERTIES **rpRangeProperties,
+  int cRanges,
+  const WCHAR *pwcChars,
+  int cChars,
+  int cMaxGlyphs,
+  WORD *pwLogClust,
+  SCRIPT_CHARPROP *pCharProps,
+  WORD *pwOutGlyphs,
+  SCRIPT_GLYPHPROP *pOutGlyphProps,
+  int *pcGlyphs
+);
+
+typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,
+  OPENTYPE_TAG tagScript,
+  OPENTYPE_TAG tagLangSys,
+  int *rcRangeChars,
+  TEXTRANGE_PROPERTIES **rpRangeProperties,
+  int cRanges,
+  const WCHAR *pwcChars,
+  WORD *pwLogClust,
+  SCRIPT_CHARPROP *pCharProps,
+  int cChars,
+  const WORD *pwGlyphs,
+  const SCRIPT_GLYPHPROP *pGlyphProps,
+  int cGlyphs,
+  int *piAdvance,
+  GOFFSET *pGoffset,
+  ABC *pABC
+);
+
+
+/* Fallback implementations. */
+
+static HRESULT WINAPI
+hb_ScriptItemizeOpenType(
+  const WCHAR *pwcInChars,
+  int cInChars,
+  int cMaxItems,
+  const SCRIPT_CONTROL *psControl,
+  const SCRIPT_STATE *psState,
+  SCRIPT_ITEM *pItems,
+  OPENTYPE_TAG *pScriptTags,
+  int *pcItems
+)
 {
-  memset (lf, 0, sizeof (*lf));
-  int dpi = GetDeviceCaps (hdc, LOGPIXELSY);
-  lf->lfHeight = -font->y_scale;
+{
+  return ScriptItemize (pwcInChars,
+                       cInChars,
+                       cMaxItems,
+                       psControl,
+                       psState,
+                       pItems,
+                       pcItems);
+}
+}
 
-  hb_blob_t *blob = Sanitizer<name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e')));
-  const name *name_table = Sanitizer<name>::lock_instance (blob);
-  unsigned int len = name_table->get_name (3, 1, 0x409, 4,
-                                          lf->lfFaceName,
-                                          sizeof (lf->lfFaceName[0]) * LF_FACESIZE)
-                                         / sizeof (lf->lfFaceName[0]);
-  hb_blob_destroy (blob);
+static HRESULT WINAPI
+hb_ScriptShapeOpenType(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,
+  OPENTYPE_TAG tagScript,
+  OPENTYPE_TAG tagLangSys,
+  int *rcRangeChars,
+  TEXTRANGE_PROPERTIES **rpRangeProperties,
+  int cRanges,
+  const WCHAR *pwcChars,
+  int cChars,
+  int cMaxGlyphs,
+  WORD *pwLogClust,
+  SCRIPT_CHARPROP *pCharProps,
+  WORD *pwOutGlyphs,
+  SCRIPT_GLYPHPROP *pOutGlyphProps,
+  int *pcGlyphs
+)
+{
+  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps;
+  return ScriptShape (hdc,
+                     psc,
+                     pwcChars,
+                     cChars,
+                     cMaxGlyphs,
+                     psa,
+                     pwOutGlyphs,
+                     pwLogClust,
+                     psva,
+                     pcGlyphs);
+}
 
-  if (unlikely (!len)) {
-    DEBUG_MSG (UNISCRIBE, NULL, "Didn't find English name table entry");
-    return false;
-  }
-  if (unlikely (len >= LF_FACESIZE)) {
-    DEBUG_MSG (UNISCRIBE, NULL, "Font name too long");
-    return false;
+static HRESULT WINAPI
+hb_ScriptPlaceOpenType(
+  HDC hdc,
+  SCRIPT_CACHE *psc,
+  SCRIPT_ANALYSIS *psa,
+  OPENTYPE_TAG tagScript,
+  OPENTYPE_TAG tagLangSys,
+  int *rcRangeChars,
+  TEXTRANGE_PROPERTIES **rpRangeProperties,
+  int cRanges,
+  const WCHAR *pwcChars,
+  WORD *pwLogClust,
+  SCRIPT_CHARPROP *pCharProps,
+  int cChars,
+  const WORD *pwGlyphs,
+  const SCRIPT_GLYPHPROP *pGlyphProps,
+  int cGlyphs,
+  int *piAdvance,
+  GOFFSET *pGoffset,
+  ABC *pABC
+)
+{
+  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps;
+  return ScriptPlace (hdc,
+                     psc,
+                     pwGlyphs,
+                     cGlyphs,
+                     psva,
+                     psa,
+                     piAdvance,
+                     pGoffset,
+                     pABC);
+}
+
+
+struct hb_uniscribe_shaper_funcs_t {
+  SIOT ScriptItemizeOpenType;
+  SSOT ScriptShapeOpenType;
+  SPOT ScriptPlaceOpenType;
+
+  inline void init (void)
+  {
+    HMODULE hinstLib;
+    this->ScriptItemizeOpenType = NULL;
+    this->ScriptShapeOpenType   = NULL;
+    this->ScriptPlaceOpenType   = NULL;
+
+    hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
+    if (hinstLib)
+    {
+      this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
+      this->ScriptShapeOpenType   = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
+      this->ScriptPlaceOpenType   = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
+    }
+    if (!this->ScriptItemizeOpenType ||
+       !this->ScriptShapeOpenType   ||
+       !this->ScriptPlaceOpenType)
+    {
+      DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back.");
+      this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
+      this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
+      this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
+    }
   }
+};
+static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;
 
-  for (unsigned int i = 0; i < len; i++)
-    lf->lfFaceName[i] = hb_be_uint16 (lf->lfFaceName[i]);
-  lf->lfFaceName[len] = 0;
+static inline void
+free_uniscribe_funcs (void)
+{
+  free (uniscribe_funcs);
+}
 
-  return true;
+static hb_uniscribe_shaper_funcs_t *
+hb_uniscribe_shaper_get_funcs (void)
+{
+retry:
+  hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
+
+  if (unlikely (!funcs))
+  {
+    funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
+    if (unlikely (!funcs))
+      return NULL;
+
+    funcs->init ();
+
+    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
+      free (funcs);
+      goto retry;
+    }
+
+#ifdef HB_USE_ATEXIT
+    atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
+#endif
+  }
+
+  return funcs;
 }
 
 
-static hb_user_data_key_t hb_uniscribe_data_key;
+struct active_feature_t {
+  OPENTYPE_FEATURE_RECORD rec;
+  unsigned int order;
+
+  static int cmp (const active_feature_t *a, const active_feature_t *b) {
+    return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
+          a->order < b->order ? -1 : a->order > b->order ? 1 :
+          a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
+          0;
+  }
+  bool operator== (const active_feature_t *f) {
+    return cmp (this, f) == 0;
+  }
+};
 
+struct feature_event_t {
+  unsigned int index;
+  bool start;
+  active_feature_t feature;
 
-static struct hb_uniscribe_face_data_t {
+  static int cmp (const feature_event_t *a, const feature_event_t *b) {
+    return a->index < b->index ? -1 : a->index > b->index ? 1 :
+          a->start < b->start ? -1 : a->start > b->start ? 1 :
+          active_feature_t::cmp (&a->feature, &b->feature);
+  }
+};
+
+struct range_record_t {
+  TEXTRANGE_PROPERTIES props;
+  unsigned int index_first; /* == start */
+  unsigned int index_last;  /* == end - 1 */
+};
+
+HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
+
+
+/*
+ * shaper face data
+ */
+
+struct hb_uniscribe_shaper_face_data_t {
   HANDLE fh;
-} _hb_uniscribe_face_data_nil = {0};
+  hb_uniscribe_shaper_funcs_t *funcs;
+  wchar_t face_name[LF_FACESIZE];
+};
 
+/* face_name should point to a wchar_t[LF_FACESIZE] object. */
 static void
-_hb_uniscribe_face_data_destroy (hb_uniscribe_face_data_t *data)
+_hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
 {
-  if (data->fh)
-    RemoveFontMemResourceEx (data->fh);
-  free (data);
+  /* We'll create a private name for the font from a UUID using a simple,
+   * somewhat base64-like encoding scheme */
+  const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
+  UUID id;
+  UuidCreate ((UUID*) &id);
+  ASSERT_STATIC (2 + 3 * (16/2) < LF_FACESIZE);
+  unsigned int name_str_len = 0;
+  face_name[name_str_len++] = 'F';
+  face_name[name_str_len++] = '_';
+  unsigned char *p = (unsigned char *) &id;
+  for (unsigned int i = 0; i < 16; i += 2)
+  {
+    /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
+     * using the bits in groups of 5,5,6 to select chars from enc.
+     * This will generate 24 characters; with the 'F_' prefix we already provided,
+     * the name will be 26 chars (plus the NUL terminator), so will always fit within
+     * face_name (LF_FACESIZE = 32). */
+    face_name[name_str_len++] = enc[p[i] >> 3];
+    face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
+    face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
+  }
+  face_name[name_str_len] = 0;
+  if (plen)
+    *plen = name_str_len;
 }
 
-static hb_uniscribe_face_data_t *
-_hb_uniscribe_face_get_data (hb_face_t *face)
+/* Destroys blob. */
+static hb_blob_t *
+_hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
 {
-  hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
-  if (likely (data)) return data;
+  /* Create a copy of the font data, with the 'name' table replaced by a
+   * table that names the font with our private F_* name created above.
+   * For simplicity, we just append a new 'name' table and update the
+   * sfnt directory; the original table is left in place, but unused.
+   *
+   * The new table will contain just 5 name IDs: family, style, unique,
+   * full, PS. All of them point to the same name data with our unique name.
+   */
+
+  blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
+
+  unsigned int length, new_length, name_str_len;
+  const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
 
-  data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t));
+  _hb_generate_unique_face_name (new_name, &name_str_len);
+
+  static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
+
+  unsigned int name_table_length = OT::name::min_size +
+                                   ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
+                                   name_str_len * 2; /* for name data in UTF16BE form */
+  unsigned int name_table_offset = (length + 3) & ~3;
+
+  new_length = name_table_offset + ((name_table_length + 3) & ~3);
+  void *new_sfnt_data = calloc (1, new_length);
+  if (!new_sfnt_data)
+  {
+    hb_blob_destroy (blob);
+    return NULL;
+  }
+
+  memcpy(new_sfnt_data, orig_sfnt_data, length);
+
+  OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
+  name.format.set (0);
+  name.count.set (ARRAY_LENGTH (name_IDs));
+  name.stringOffset.set (name.get_size ());
+  for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
+  {
+    OT::NameRecord &record = name.nameRecord[i];
+    record.platformID.set (3);
+    record.encodingID.set (1);
+    record.languageID.set (0x0409u); /* English */
+    record.nameID.set (name_IDs[i]);
+    record.length.set (name_str_len * 2);
+    record.offset.set (0);
+  }
+
+  /* Copy string data from new_name, converting wchar_t to UTF16BE. */
+  unsigned char *p = &OT::StructAfter<unsigned char> (name);
+  for (unsigned int i = 0; i < name_str_len; i++)
+  {
+    *p++ = new_name[i] >> 8;
+    *p++ = new_name[i] & 0xff;
+  }
+
+  /* Adjust name table entry to point to new name table */
+  const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data);
+  unsigned int face_count = file.get_face_count ();
+  for (unsigned int face_index = 0; face_index < face_count; face_index++)
+  {
+    /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
+     * toe-stepping.  But we don't really care. */
+    const OT::OpenTypeFontFace &face = file.get_face (face_index);
+    unsigned int index;
+    if (face.find_table_index (HB_OT_TAG_name, &index))
+    {
+      OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
+      record.checkSum.set_for_data (&name, name_table_length);
+      record.offset.set (name_table_offset);
+      record.length.set (name_table_length);
+    }
+    else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
+    {
+      free (new_sfnt_data);
+      hb_blob_destroy (blob);
+      return NULL;
+    }
+  }
+
+  /* The checkSumAdjustment field in the 'head' table is now wrong,
+   * but that doesn't actually seem to cause any problems so we don't
+   * bother. */
+
+  hb_blob_destroy (blob);
+  return hb_blob_create ((const char *) new_sfnt_data, new_length,
+                        HB_MEMORY_MODE_WRITABLE, NULL, free);
+}
+
+hb_uniscribe_shaper_face_data_t *
+_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
+{
+  hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
   if (unlikely (!data))
-    return &_hb_uniscribe_face_data_nil;
+    return NULL;
 
+  data->funcs = hb_uniscribe_shaper_get_funcs ();
+  if (unlikely (!data->funcs))
+  {
+    free (data);
+    return NULL;
+  }
 
   hb_blob_t *blob = hb_face_reference_blob (face);
-  unsigned int blob_length;
-  const char *blob_data = hb_blob_get_data (blob, &blob_length);
-  if (unlikely (!blob_length))
+  if (unlikely (!hb_blob_get_length (blob)))
     DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
 
+  blob = _hb_rename_font (blob, data->face_name);
+  if (unlikely (!blob))
+  {
+    free (data);
+    return NULL;
+  }
+
   DWORD num_fonts_installed;
-  data->fh = AddFontMemResourceEx ((void *) blob_data, blob_length, 0, &num_fonts_installed);
-  hb_blob_destroy (blob);
+  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
+                                  hb_blob_get_length (blob),
+                                  0, &num_fonts_installed);
   if (unlikely (!data->fh))
-    DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
-
-
-  if (unlikely (!hb_face_set_user_data (face, &hb_uniscribe_data_key, data,
-                                       (hb_destroy_func_t) _hb_uniscribe_face_data_destroy,
-                                       false)))
   {
-    _hb_uniscribe_face_data_destroy (data);
-    data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
-    if (data)
-      return data;
-    else
-      return &_hb_uniscribe_face_data_nil;
+    DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
+    free (data);
+    return NULL;
   }
 
   return data;
 }
 
+void
+_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
+{
+  RemoveFontMemResourceEx (data->fh);
+  free (data);
+}
+
 
-static struct hb_uniscribe_font_data_t {
+/*
+ * shaper font data
+ */
+
+struct hb_uniscribe_shaper_font_data_t {
   HDC hdc;
   LOGFONTW log_font;
   HFONT hfont;
   SCRIPT_CACHE script_cache;
-} _hb_uniscribe_font_data_nil = {NULL, NULL, NULL};
+};
 
-static void
-_hb_uniscribe_font_data_destroy (hb_uniscribe_font_data_t *data)
+static bool
+populate_log_font (LOGFONTW  *lf,
+                  hb_font_t *font)
 {
-  if (data->hdc)
-    ReleaseDC (NULL, data->hdc);
-  if (data->hfont)
-    DeleteObject (data->hfont);
-  if (data->script_cache)
-    ScriptFreeCache (&data->script_cache);
-  free (data);
+  memset (lf, 0, sizeof (*lf));
+  lf->lfHeight = -font->y_scale;
+  lf->lfCharSet = DEFAULT_CHARSET;
+
+  hb_face_t *face = font->face;
+  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+  memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
+
+  return true;
 }
 
-static hb_uniscribe_font_data_t *
-_hb_uniscribe_font_get_data (hb_font_t *font)
+hb_uniscribe_shaper_font_data_t *
+_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
 {
-  hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
-  if (likely (data)) return data;
+  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
 
-  data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t));
+  hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
   if (unlikely (!data))
-    return &_hb_uniscribe_font_data_nil;
+    return NULL;
 
   data->hdc = GetDC (NULL);
 
-  if (unlikely (!populate_log_font (&data->log_font, data->hdc, font)))
+  if (unlikely (!populate_log_font (&data->log_font, font))) {
     DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
-  else {
-    data->hfont = CreateFontIndirectW (&data->log_font);
-    if (unlikely (!data->hfont))
-      DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
-    if (!SelectObject (data->hdc, data->hfont))
-      DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
+    _hb_uniscribe_shaper_font_data_destroy (data);
+    return NULL;
   }
 
-  if (unlikely (!hb_font_set_user_data (font, &hb_uniscribe_data_key, data,
-                                       (hb_destroy_func_t) _hb_uniscribe_font_data_destroy,
-                                       false)))
-  {
-    _hb_uniscribe_font_data_destroy (data);
-    data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
-    if (data)
-      return data;
-    else
-      return &_hb_uniscribe_font_data_nil;
+  data->hfont = CreateFontIndirectW (&data->log_font);
+  if (unlikely (!data->hfont)) {
+    DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
+    _hb_uniscribe_shaper_font_data_destroy (data);
+     return NULL;
+  }
+
+  if (!SelectObject (data->hdc, data->hfont)) {
+    DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
+    _hb_uniscribe_shaper_font_data_destroy (data);
+     return NULL;
   }
 
   return data;
 }
 
+void
+_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
+{
+  if (data->hdc)
+    ReleaseDC (NULL, data->hdc);
+  if (data->hfont)
+    DeleteObject (data->hfont);
+  if (data->script_cache)
+    ScriptFreeCache (&data->script_cache);
+  free (data);
+}
+
 LOGFONTW *
 hb_uniscribe_font_get_logfontw (hb_font_t *font)
 {
-  hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
-  if (unlikely (!font_data))
-    return NULL;
+  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return &font_data->log_font;
 }
 
 HFONT
 hb_uniscribe_font_get_hfont (hb_font_t *font)
 {
-  hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
-  if (unlikely (!font_data))
-    return 0;
+  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   return font_data->hfont;
 }
 
 
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_uniscribe_shaper_shape_plan_data_t {};
+
+hb_uniscribe_shaper_shape_plan_data_t *
+_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
+                                            const hb_feature_t *user_features HB_UNUSED,
+                                            unsigned int        num_user_features HB_UNUSED)
+{
+  return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+
 hb_bool_t
-_hb_uniscribe_shape (hb_font_t          *font,
+_hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
+                    hb_font_t          *font,
                     hb_buffer_t        *buffer,
                     const hb_feature_t *features,
                     unsigned int        num_features)
 {
-  buffer->guess_properties ();
+  hb_face_t *face = font->face;
+  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+  hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+  hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
+
+  /*
+   * Set up features.
+   */
+  hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records;
+  hb_auto_array_t<range_record_t> range_records;
+  if (num_features)
+  {
+    /* Sort features by start/end events. */
+    hb_auto_array_t<feature_event_t> feature_events;
+    for (unsigned int i = 0; i < num_features; i++)
+    {
+      active_feature_t feature;
+      feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
+      feature.rec.lParameter = features[i].value;
+      feature.order = i;
+
+      feature_event_t *event;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+       goto fail_features;
+      event->index = features[i].start;
+      event->start = true;
+      event->feature = feature;
+
+      event = feature_events.push ();
+      if (unlikely (!event))
+       goto fail_features;
+      event->index = features[i].end;
+      event->start = false;
+      event->feature = feature;
+    }
+    feature_events.qsort ();
+    /* Add a strategic final event. */
+    {
+      active_feature_t feature;
+      feature.rec.tagFeature = 0;
+      feature.rec.lParameter = 0;
+      feature.order = num_features + 1;
+
+      feature_event_t *event = feature_events.push ();
+      if (unlikely (!event))
+       goto fail_features;
+      event->index = 0; /* This value does magic. */
+      event->start = false;
+      event->feature = feature;
+    }
+
+    /* Scan events and save features for each range. */
+    hb_auto_array_t<active_feature_t> active_features;
+    unsigned int last_index = 0;
+    for (unsigned int i = 0; i < feature_events.len; i++)
+    {
+      feature_event_t *event = &feature_events[i];
+
+      if (event->index != last_index)
+      {
+        /* Save a snapshot of active features and the range. */
+       range_record_t *range = range_records.push ();
+       if (unlikely (!range))
+         goto fail_features;
+
+       unsigned int offset = feature_records.len;
+
+       active_features.qsort ();
+       for (unsigned int j = 0; j < active_features.len; j++)
+       {
+         if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
+         {
+           OPENTYPE_FEATURE_RECORD *feature = feature_records.push ();
+           if (unlikely (!feature))
+             goto fail_features;
+           *feature = active_features[j].rec;
+         }
+         else
+         {
+           /* Overrides value for existing feature. */
+           feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
+         }
+       }
+
+       /* Will convert to pointer after all is ready, since feature_records.array
+        * may move as we grow it. */
+       range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
+       range->props.cotfRecords = feature_records.len - offset;
+       range->index_first = last_index;
+       range->index_last  = event->index - 1;
+
+       last_index = event->index;
+      }
+
+      if (event->start) {
+        active_feature_t *feature = active_features.push ();
+       if (unlikely (!feature))
+         goto fail_features;
+       *feature = event->feature;
+      } else {
+        active_feature_t *feature = active_features.find (&event->feature);
+       if (feature)
+         active_features.remove (feature - active_features.array);
+      }
+    }
+
+    if (!range_records.len) /* No active feature found. */
+      goto fail_features;
+
+    /* Fixup the pointers. */
+    for (unsigned int i = 0; i < range_records.len; i++)
+    {
+      range_record_t *range = &range_records[i];
+      range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
+    }
+  }
+  else
+  {
+  fail_features:
+    num_features = 0;
+  }
 
 #define FAIL(...) \
   HB_STMT_START { \
@@ -236,58 +728,66 @@ _hb_uniscribe_shape (hb_font_t          *font,
     return false; \
   } HB_STMT_END;
 
-  hb_uniscribe_face_data_t *face_data = _hb_uniscribe_face_get_data (font->face);
-  if (unlikely (!face_data->fh))
-    FAIL ("Couldn't get face data");
-
-  hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
-  if (unlikely (!font_data->hfont))
-    FAIL ("Couldn't get font font");
-
-  if (unlikely (!buffer->len))
-    return true;
-
   HRESULT hr;
 
 retry:
 
   unsigned int scratch_size;
-  char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
-
-  /* Allocate char buffers; they all fit */
+  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
 
 #define ALLOCATE_ARRAY(Type, name, len) \
   Type *name = (Type *) scratch; \
-  scratch += len * sizeof (name[0]); \
-  scratch_size -= len * sizeof (name[0]);
+  { \
+    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+    assert (_consumed <= scratch_size); \
+    scratch += _consumed; \
+    scratch_size -= _consumed; \
+  }
 
 #define utf16_index() var1.u32
 
-  WCHAR *pchars = (WCHAR *) scratch;
+  ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);
+
   unsigned int chars_len = 0;
-  for (unsigned int i = 0; i < buffer->len; i++) {
+  for (unsigned int i = 0; i < buffer->len; i++)
+  {
     hb_codepoint_t c = buffer->info[i].codepoint;
     buffer->info[i].utf16_index() = chars_len;
-    if (likely (c < 0x10000))
+    if (likely (c <= 0xFFFFu))
       pchars[chars_len++] = c;
-    else if (unlikely (c >= 0x110000))
-      pchars[chars_len++] = 0xFFFD;
+    else if (unlikely (c > 0x10FFFFu))
+      pchars[chars_len++] = 0xFFFDu;
     else {
-      pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
-      pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
+      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
     }
   }
 
-  ALLOCATE_ARRAY (WCHAR, wchars, chars_len);
   ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
   ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
 
-  /* On Windows, we don't care about alignment...*/
-  unsigned int glyphs_size = scratch_size / (sizeof (WORD) +
-                                            sizeof (SCRIPT_GLYPHPROP) +
-                                            sizeof (int) +
-                                            sizeof (GOFFSET) +
-                                            sizeof (uint32_t));
+  if (num_features)
+  {
+    /* Need log_clusters to assign features. */
+    chars_len = 0;
+    for (unsigned int i = 0; i < buffer->len; i++)
+    {
+      hb_codepoint_t c = buffer->info[i].codepoint;
+      unsigned int cluster = buffer->info[i].cluster;
+      log_clusters[chars_len++] = cluster;
+      if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+       log_clusters[chars_len++] = cluster; /* Surrogates. */
+    }
+  }
+
+  /* The -2 in the following is to compensate for possible
+   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
+  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
+                          / (sizeof (WORD) +
+                             sizeof (SCRIPT_GLYPHPROP) +
+                             sizeof (int) +
+                             sizeof (GOFFSET) +
+                             sizeof (uint32_t));
 
   ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
   ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
@@ -295,13 +795,22 @@ retry:
   ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
   ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
 
+  /* Note:
+   * We can't touch the contents of glyph_props.  Our fallback
+   * implementations of Shape and Place functions use that buffer
+   * by casting it to a different type.  It works because they
+   * both agree about it, but if we want to access it here we
+   * need address that issue first.
+   */
+
+#undef ALLOCATE_ARRAY
 
-#define MAX_ITEMS 10
+#define MAX_ITEMS 256
 
   SCRIPT_ITEM items[MAX_ITEMS + 1];
   SCRIPT_CONTROL bidi_control = {0};
   SCRIPT_STATE bidi_state = {0};
-  WIN_ULONG script_tags[MAX_ITEMS];
+  ULONG script_tags[MAX_ITEMS];
   int item_count;
 
   /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
@@ -309,96 +818,147 @@ retry:
   *(uint32_t*)&bidi_control |= 1<<24;
 
   bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
-//  bidi_state.fOverrideDirection = 1;
-
-  hr = ScriptItemizeOpenType (wchars,
-                             chars_len,
-                             MAX_ITEMS,
-                             &bidi_control,
-                             &bidi_state,
-                             items,
-                             script_tags,
-                             &item_count);
+  bidi_state.fOverrideDirection = 1;
+
+  hr = funcs->ScriptItemizeOpenType (pchars,
+                                    chars_len,
+                                    MAX_ITEMS,
+                                    &bidi_control,
+                                    &bidi_state,
+                                    items,
+                                    script_tags,
+                                    &item_count);
   if (unlikely (FAILED (hr)))
     FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
 
 #undef MAX_ITEMS
 
-  int *range_char_counts = NULL;
-  TEXTRANGE_PROPERTIES **range_properties = NULL;
-  int range_count = 0;
-  if (num_features) {
-    /* TODO setup ranges */
-  }
-
-  OPENTYPE_TAG language_tag = hb_ot_tag_from_language (buffer->props.language);
+  OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
+  hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties;
+  hb_auto_array_t<int> range_char_counts;
 
   unsigned int glyphs_offset = 0;
   unsigned int glyphs_len;
+  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
   for (unsigned int i = 0; i < item_count; i++)
   {
-      unsigned int chars_offset = items[i].iCharPos;
-      unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
-      OPENTYPE_TAG script_tag = script_tags[i]; /* XXX buffer->props.script */
-
-      hr = ScriptShapeOpenType (font_data->hdc,
-                               &font_data->script_cache,
-                               &items[i].a,
-                               script_tag,
-                               language_tag,
-                               range_char_counts,
-                               range_properties,
-                               range_count,
-                               wchars + chars_offset,
-                               item_chars_len,
-                               glyphs_size - glyphs_offset,
-                               /* out */
-                               log_clusters + chars_offset,
-                               char_props + chars_offset,
-                               glyphs + glyphs_offset,
-                               glyph_props + glyphs_offset,
-                               (int *) &glyphs_len);
-
-      for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
-        log_clusters[j] += glyphs_offset;
-
-      if (unlikely (items[i].a.fNoGlyphIndex))
-       FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
-      if (unlikely (hr == E_OUTOFMEMORY))
+    unsigned int chars_offset = items[i].iCharPos;
+    unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
+
+    if (num_features)
+    {
+      range_properties.shrink (0);
+      range_char_counts.shrink (0);
+
+      range_record_t *last_range = &range_records[0];
+
+      for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
       {
-        buffer->ensure (buffer->allocated * 2);
-       if (buffer->in_error)
-         FAIL ("Buffer resize failed");
-       goto retry;
+       range_record_t *range = last_range;
+       while (log_clusters[k] < range->index_first)
+         range--;
+       while (log_clusters[k] > range->index_last)
+         range++;
+       if (!range_properties.len ||
+           &range->props != range_properties[range_properties.len - 1])
+       {
+         TEXTRANGE_PROPERTIES **props = range_properties.push ();
+         int *c = range_char_counts.push ();
+         if (unlikely (!props || !c))
+         {
+           range_properties.shrink (0);
+           range_char_counts.shrink (0);
+           break;
+         }
+         *props = &range->props;
+         *c = 1;
+       }
+       else
+       {
+         range_char_counts[range_char_counts.len - 1]++;
+       }
+
+       last_range = range;
       }
-      if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
+    }
+
+    /* Asking for glyphs in logical order circumvents at least
+     * one bug in Uniscribe. */
+    items[i].a.fLogicalOrder = true;
+
+  retry_shape:
+    hr = funcs->ScriptShapeOpenType (font_data->hdc,
+                                    &font_data->script_cache,
+                                    &items[i].a,
+                                    script_tags[i],
+                                    language_tag,
+                                    range_char_counts.array,
+                                    range_properties.array,
+                                    range_properties.len,
+                                    pchars + chars_offset,
+                                    item_chars_len,
+                                    glyphs_size - glyphs_offset,
+                                    /* out */
+                                    log_clusters + chars_offset,
+                                    char_props + chars_offset,
+                                    glyphs + glyphs_offset,
+                                    glyph_props + glyphs_offset,
+                                    (int *) &glyphs_len);
+
+    if (unlikely (items[i].a.fNoGlyphIndex))
+      FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
+    if (unlikely (hr == E_OUTOFMEMORY))
+    {
+      if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+       FAIL ("Buffer resize failed");
+      goto retry;
+    }
+    if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
+    {
+      if (items[i].a.eScript == SCRIPT_UNDEFINED)
        FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
-      if (unlikely (FAILED (hr)))
-       FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
-
-      hr = ScriptPlaceOpenType (font_data->hdc,
-                               &font_data->script_cache,
-                               &items[i].a,
-                               script_tag,
-                               language_tag,
-                               range_char_counts,
-                               range_properties,
-                               range_count,
-                               wchars + chars_offset,
-                               log_clusters + chars_offset,
-                               char_props + chars_offset,
-                               item_chars_len,
-                               glyphs + glyphs_offset,
-                               glyph_props + glyphs_offset,
-                               glyphs_len,
-                               /* out */
-                               advances + glyphs_offset,
-                               offsets + glyphs_offset,
-                               NULL);
-      if (unlikely (FAILED (hr)))
-       FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
-
-      glyphs_offset += glyphs_len;
+      items[i].a.eScript = SCRIPT_UNDEFINED;
+      goto retry_shape;
+    }
+    if (unlikely (FAILED (hr)))
+    {
+      FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
+    }
+
+    for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
+      log_clusters[j] += glyphs_offset;
+
+    hr = funcs->ScriptPlaceOpenType (font_data->hdc,
+                                    &font_data->script_cache,
+                                    &items[i].a,
+                                    script_tags[i],
+                                    language_tag,
+                                    range_char_counts.array,
+                                    range_properties.array,
+                                    range_properties.len,
+                                    pchars + chars_offset,
+                                    log_clusters + chars_offset,
+                                    char_props + chars_offset,
+                                    item_chars_len,
+                                    glyphs + glyphs_offset,
+                                    glyph_props + glyphs_offset,
+                                    glyphs_len,
+                                    /* out */
+                                    advances + glyphs_offset,
+                                    offsets + glyphs_offset,
+                                    NULL);
+    if (unlikely (FAILED (hr)))
+      FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
+
+    if (DEBUG_ENABLED (UNISCRIBE))
+      fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
+              i,
+              items[i].a.fRTL,
+              items[i].a.fLayoutRTL,
+              items[i].a.fLogicalOrder,
+              HB_UNTAG (hb_uint32_swap (script_tags[i])));
+
+    glyphs_offset += glyphs_len;
   }
   glyphs_len = glyphs_offset;
 
@@ -412,20 +972,13 @@ retry:
     uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
     *p = MIN (*p, buffer->info[i].cluster);
   }
-  if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
-    for (unsigned int i = 1; i < glyphs_len; i++)
-      if (!glyph_props[i].sva.fClusterStart)
-       vis_clusters[i] = vis_clusters[i - 1];
-  } else {
-    for (int i = glyphs_len - 2; i >= 0; i--)
-      if (!glyph_props[i].sva.fClusterStart)
-       vis_clusters[i] = vis_clusters[i + 1];
-  }
+  for (unsigned int i = 1; i < glyphs_len; i++)
+    if (vis_clusters[i] == -1)
+      vis_clusters[i] = vis_clusters[i - 1];
 
 #undef utf16_index
 
-  buffer->ensure (glyphs_len);
-  if (buffer->in_error)
+  if (unlikely (!buffer->ensure (glyphs_len)))
     FAIL ("Buffer in error");
 
 #undef FAIL
@@ -454,10 +1007,13 @@ retry:
 
     /* TODO vertical */
     pos->x_advance = info->mask;
-    pos->x_offset = info->var1.u32;
+    pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
     pos->y_offset = info->var2.u32;
   }
 
+  if (backward)
+    hb_buffer_reverse (buffer);
+
   /* Wow, done! */
   return true;
 }
index 216610e..001ab38 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "hb.h"
 
-#define _WIN32_WINNT 0x0500
 #include <windows.h>
 
 HB_BEGIN_DECLS
diff --git a/src/hb-utf-private.hh b/src/hb-utf-private.hh
new file mode 100644 (file)
index 0000000..14d3c2e
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * 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
+ */
+
+#ifndef HB_UTF_PRIVATE_HH
+#define HB_UTF_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+struct hb_utf8_t
+{
+  typedef uint8_t codepoint_t;
+
+  static inline const uint8_t *
+  next (const uint8_t *text,
+       const uint8_t *end,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement)
+  {
+    /* Written to only accept well-formed sequences.
+     * Based on ideas from ICU's U8_NEXT.
+     * Generates one "replacement" for each ill-formed byte. */
+
+    hb_codepoint_t c = *text++;
+
+    if (c > 0x7Fu)
+    {
+      if (hb_in_range (c, 0xC2u, 0xDFu)) /* Two-byte */
+      {
+       unsigned int t1;
+       if (likely (text < end &&
+                   (t1 = text[0] - 0x80u) <= 0x3Fu))
+       {
+         c = ((c&0x1Fu)<<6) | t1;
+         text++;
+       }
+       else
+         goto error;
+      }
+      else if (hb_in_range (c, 0xE0u, 0xEFu)) /* Three-byte */
+      {
+       unsigned int t1, t2;
+       if (likely (1 < end - text &&
+                   (t1 = text[0] - 0x80u) <= 0x3Fu &&
+                   (t2 = text[1] - 0x80u) <= 0x3Fu))
+       {
+         c = ((c&0xFu)<<12) | (t1<<6) | t2;
+         if (unlikely (c < 0x0800u || hb_in_range (c, 0xD800u, 0xDFFFu)))
+           goto error;
+         text += 2;
+       }
+       else
+         goto error;
+      }
+      else if (hb_in_range (c, 0xF0u, 0xF4u)) /* Four-byte */
+      {
+       unsigned int t1, t2, t3;
+       if (likely (2 < end - text &&
+                   (t1 = text[0] - 0x80u) <= 0x3Fu &&
+                   (t2 = text[1] - 0x80u) <= 0x3Fu &&
+                   (t3 = text[2] - 0x80u) <= 0x3Fu))
+       {
+         c = ((c&0x7u)<<18) | (t1<<12) | (t2<<6) | t3;
+         if (unlikely (!hb_in_range (c, 0x10000u, 0x10FFFFu)))
+           goto error;
+         text += 3;
+       }
+       else
+         goto error;
+      }
+      else
+       goto error;
+    }
+
+    *unicode = c;
+    return text;
+
+  error:
+    *unicode = replacement;
+    return text;
+  }
+
+  static inline const uint8_t *
+  prev (const uint8_t *text,
+       const uint8_t *start,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement)
+  {
+    const uint8_t *end = text--;
+    while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
+      text--;
+
+    if (likely (next (text, end, unicode, replacement) == end))
+      return text;
+
+    *unicode = replacement;
+    return end - 1;
+  }
+
+  static inline unsigned int
+  strlen (const uint8_t *text)
+  {
+    return ::strlen ((const char *) text);
+  }
+};
+
+
+struct hb_utf16_t
+{
+  typedef uint16_t codepoint_t;
+
+  static inline const uint16_t *
+  next (const uint16_t *text,
+       const uint16_t *end,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement)
+  {
+    hb_codepoint_t c = *text++;
+
+    if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+    {
+      *unicode = c;
+      return text;
+    }
+
+    if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
+    {
+      /* High-surrogate in c */
+      hb_codepoint_t l;
+      if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
+      {
+       /* Low-surrogate in l */
+       *unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+        text++;
+        return text;
+      }
+    }
+
+    /* Lonely / out-of-order surrogate. */
+    *unicode = replacement;
+    return text;
+  }
+
+  static inline const uint16_t *
+  prev (const uint16_t *text,
+       const uint16_t *start,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement)
+  {
+    const uint16_t *end = text--;
+    hb_codepoint_t c = *text;
+
+    if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+    {
+      *unicode = c;
+      return text;
+    }
+
+    if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
+      text--;
+
+    if (likely (next (text, end, unicode, replacement) == end))
+      return text;
+
+    *unicode = replacement;
+    return end - 1;
+  }
+
+
+  static inline unsigned int
+  strlen (const uint16_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+};
+
+
+template <bool validate=true>
+struct hb_utf32_t
+{
+  typedef uint32_t codepoint_t;
+
+  static inline const uint32_t *
+  next (const uint32_t *text,
+       const uint32_t *end HB_UNUSED,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement)
+  {
+    hb_codepoint_t c = *text++;
+    if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
+      goto error;
+    *unicode = c;
+    return text;
+
+  error:
+    *unicode = replacement;
+    return text;
+  }
+
+  static inline const uint32_t *
+  prev (const uint32_t *text,
+       const uint32_t *start HB_UNUSED,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement)
+  {
+    next (text - 1, text, unicode, replacement);
+    return text - 1;
+  }
+
+  static inline unsigned int
+  strlen (const uint32_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+};
+
+
+struct hb_latin1_t
+{
+  typedef uint8_t codepoint_t;
+
+  static inline const uint8_t *
+  next (const uint8_t *text,
+       const uint8_t *end HB_UNUSED,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement HB_UNUSED)
+  {
+    *unicode = *text++;
+    return text;
+  }
+
+  static inline const uint8_t *
+  prev (const uint8_t *text,
+       const uint8_t *start HB_UNUSED,
+       hb_codepoint_t *unicode,
+       hb_codepoint_t replacement)
+  {
+    *unicode = *--text;
+    return text;
+  }
+
+  static inline unsigned int
+  strlen (const uint8_t *text)
+  {
+    unsigned int l = 0;
+    while (*text++) l++;
+    return l;
+  }
+};
+
+#endif /* HB_UTF_PRIVATE_HH */
index 43634f9..2517160 100644 (file)
@@ -42,8 +42,8 @@ HB_BEGIN_DECLS
 
 #define HB_VERSION_STRING "@HB_VERSION@"
 
-#define HB_VERSION_CHECK(major,minor,micro) \
-       ((major)*10000+(minor)*100+(micro) >= \
+#define HB_VERSION_ATLEAST(major,minor,micro) \
+       ((major)*10000+(minor)*100+(micro) <= \
         HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
 
 
@@ -56,9 +56,9 @@ const char *
 hb_version_string (void);
 
 hb_bool_t
-hb_version_check (unsigned int major,
-                 unsigned int minor,
-                 unsigned int micro);
+hb_version_atleast (unsigned int major,
+                   unsigned int minor,
+                   unsigned int micro);
 
 
 HB_END_DECLS
index 4f1f65f..e0f88e2 100644 (file)
 #endif
 
 
-#include "hb-unicode-private.hh"
-
-#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
-#ifdef _MSC_VER
-#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
-#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
-#else
-#warning "Could not find any Unicode functions implementation, you have to provide your own"
-#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
-#endif
-#endif
index d36040e..c5a938a 100644 (file)
--- a/src/hb.h
+++ b/src/hb.h
 #include "hb-blob.h"
 #include "hb-buffer.h"
 #include "hb-common.h"
+#include "hb-deprecated.h"
+#include "hb-face.h"
 #include "hb-font.h"
 #include "hb-set.h"
 #include "hb-shape.h"
+#include "hb-shape-plan.h"
 #include "hb-unicode.h"
 #include "hb-version.h"
 
index 07d3d69..f9708cc 100644 (file)
@@ -36,6 +36,8 @@
 #include <stdio.h>
 
 
+using namespace OT;
+
 
 int
 main (int argc, char **argv)
@@ -129,8 +131,11 @@ main (int argc, char **argv)
            else
              printf ("      Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
                      (const char *)script.get_lang_sys_tag (n_langsys));
-           if (langsys.get_required_feature_index () == Index::NOT_FOUND_INDEX)
+           if (!langsys.has_required_feature ())
              printf ("        No required feature\n");
+           else
+             printf ("        Required feature index: %d\n",
+                     langsys.get_required_feature_index ());
 
            int num_features = langsys.get_feature_count ();
            printf ("        %d feature(s) found in language system\n", num_features);
@@ -145,11 +150,10 @@ main (int argc, char **argv)
        printf ("    %d feature(s) found in table\n", num_features);
        for (int n_feature = 0; n_feature < num_features; n_feature++) {
          const Feature &feature = g.get_feature (n_feature);
-         printf ("    Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features,
-                 (const char *)g.get_feature_tag(n_feature),
-                 feature.get_lookup_count());
-
          int num_lookups = feature.get_lookup_count ();
+         printf ("    Feature %2d of %2d: %c%c%c%c\n", n_feature, num_features,
+                 HB_UNTAG(g.get_feature_tag(n_feature)));
+
          printf ("        %d lookup(s) found in feature\n", num_lookups);
          for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
            printf ("        Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
@@ -168,7 +172,7 @@ main (int argc, char **argv)
        }
        break;
 
-      case GDEF::Tag:
+      case GDEF::tableTag:
        {
 
        const GDEF &gdef = *CastP<GDEF> (font_data + table.offset);
diff --git a/src/sample.py b/src/sample.py
new file mode 100755 (executable)
index 0000000..f8d2216
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+import sys
+from gi.repository import HarfBuzz as hb
+from gi.repository import GLib
+
+# Python 2/3 compatibility
+try:
+       unicode
+except NameError:
+       unicode = str
+
+def tounicode(s, encoding='utf-8'):
+       if not isinstance(s, unicode):
+               return s.decode(encoding)
+       else:
+               return s
+
+fontdata = open (sys.argv[1], 'rb').read ()
+text = tounicode(sys.argv[2])
+# Need to create GLib.Bytes explicitly until this bug is fixed:
+# https://bugzilla.gnome.org/show_bug.cgi?id=729541
+blob = hb.glib_blob_create (GLib.Bytes.new (fontdata))
+face = hb.face_create (blob, 0)
+del blob
+font = hb.font_create (face)
+upem = hb.face_get_upem (face)
+del face
+hb.font_set_scale (font, upem, upem)
+#hb.ft_font_set_funcs (font)
+hb.ot_font_set_funcs (font)
+
+buf = hb.buffer_create ()
+hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
+hb.buffer_guess_segment_properties (buf)
+
+hb.shape (font, buf, [])
+del font
+
+infos = hb.buffer_get_glyph_infos (buf)
+positions = hb.buffer_get_glyph_positions (buf)
+
+for info,pos in zip(infos, positions):
+       gid = info.codepoint
+       cluster = info.cluster
+       x_advance = pos.x_advance
+       x_offset = pos.x_offset
+       y_offset = pos.y_offset
+
+       print("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset))
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
new file mode 100644 (file)
index 0000000..18c46e9
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  hb_blob_t *blob = NULL;
+
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file\n", argv[0]);
+    exit (1);
+  }
+
+  /* Create the blob */
+  {
+    const char *font_data;
+    unsigned int len;
+    hb_destroy_func_t destroy;
+    void *user_data;
+    hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    font_data = g_mapped_file_get_contents (mf);
+    len = g_mapped_file_get_length (mf);
+    destroy = (hb_destroy_func_t) g_mapped_file_unref;
+    user_data = (void *) mf;
+    mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+    FILE *f = fopen (argv[1], "rb");
+    fseek (f, 0, SEEK_END);
+    len = ftell (f);
+    fseek (f, 0, SEEK_SET);
+    font_data = (const char *) malloc (len);
+    if (!font_data) len = 0;
+    len = fread ((char *) font_data, 1, len, f);
+    destroy = free;
+    user_data = (void *) font_data;
+    fclose (f);
+    mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+    blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+  }
+
+  hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+  hb_blob_destroy (blob);
+  blob = NULL;
+
+  unsigned int upem = hb_face_get_upem (face);
+  hb_font_t *font = hb_font_create (face);
+  hb_face_destroy (face);
+  hb_font_set_scale (font, upem, upem);
+#ifdef HAVE_FREETYPE
+  hb_ft_font_set_funcs (font);
+#endif
+
+  hb_buffer_t *buf;
+  buf = hb_buffer_create ();
+
+  bool ret = true;
+  char line[BUFSIZ], out[BUFSIZ];
+  while (fgets (line, sizeof(line), stdin) != 0)
+  {
+    hb_buffer_clear_contents (buf);
+
+    const char *p = line;
+    while (hb_buffer_deserialize_glyphs (buf,
+                                        p, -1, &p,
+                                        font,
+                                        HB_BUFFER_SERIALIZE_FORMAT_JSON))
+      ;
+    if (*p && *p != '\n')
+      ret = false;
+
+    hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
+                               out, sizeof (out), NULL,
+                               font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
+                               HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+    puts (out);
+  }
+
+  hb_buffer_destroy (buf);
+
+  hb_font_destroy (font);
+
+  return !ret;
+}
diff --git a/src/test-size-params.cc b/src/test-size-params.cc
new file mode 100644 (file)
index 0000000..35d9e3c
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+  hb_blob_t *blob = NULL;
+
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file\n", argv[0]);
+    exit (1);
+  }
+
+  /* Create the blob */
+  {
+    const char *font_data;
+    unsigned int len;
+    hb_destroy_func_t destroy;
+    void *user_data;
+    hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    font_data = g_mapped_file_get_contents (mf);
+    len = g_mapped_file_get_length (mf);
+    destroy = (hb_destroy_func_t) g_mapped_file_unref;
+    user_data = (void *) mf;
+    mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+    FILE *f = fopen (argv[1], "rb");
+    fseek (f, 0, SEEK_END);
+    len = ftell (f);
+    fseek (f, 0, SEEK_SET);
+    font_data = (const char *) malloc (len);
+    if (!font_data) len = 0;
+    len = fread ((char *) font_data, 1, len, f);
+    destroy = free;
+    user_data = (void *) font_data;
+    fclose (f);
+    mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+    blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+  }
+
+  /* Create the face */
+  hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+  hb_blob_destroy (blob);
+  blob = NULL;
+
+  unsigned int p[5];
+  bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4);
+
+  printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.);
+
+  return !ret;
+}
diff --git a/src/test-would-substitute.cc b/src/test-would-substitute.cc
new file mode 100644 (file)
index 0000000..8ea87cd
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+int
+main (int argc, char **argv)
+{
+  hb_blob_t *blob = NULL;
+
+  if (argc != 4 && argc != 5) {
+    fprintf (stderr, "usage: %s font-file lookup-index first-glyph [second-glyph]\n", argv[0]);
+    exit (1);
+  }
+
+  /* Create the blob */
+  {
+    const char *font_data;
+    unsigned int len;
+    hb_destroy_func_t destroy;
+    void *user_data;
+    hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    font_data = g_mapped_file_get_contents (mf);
+    len = g_mapped_file_get_length (mf);
+    destroy = (hb_destroy_func_t) g_mapped_file_unref;
+    user_data = (void *) mf;
+    mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+    FILE *f = fopen (argv[1], "rb");
+    fseek (f, 0, SEEK_END);
+    len = ftell (f);
+    fseek (f, 0, SEEK_SET);
+    font_data = (const char *) malloc (len);
+    if (!font_data) len = 0;
+    len = fread ((char *) font_data, 1, len, f);
+    destroy = free;
+    user_data = (void *) font_data;
+    fclose (f);
+    mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+    blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+  }
+
+  /* Create the face */
+  hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+  hb_blob_destroy (blob);
+  blob = NULL;
+
+  hb_font_t *font = hb_font_create (face);
+#ifdef HAVE_FREETYPE
+  hb_ft_font_set_funcs (font);
+#endif
+
+  unsigned int len = argc - 3;
+  hb_codepoint_t glyphs[2];
+  if (!hb_font_glyph_from_string (font, argv[3], -1, &glyphs[0]) ||
+      (argc > 4 &&
+       !hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1])))
+    return 2;
+  return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], NULL, 0), glyphs, len, false);
+}
diff --git a/src/test.cc b/src/test.cc
new file mode 100644 (file)
index 0000000..a8fe046
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+#  define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+int
+main (int argc, char **argv)
+{
+  hb_blob_t *blob = NULL;
+
+  if (argc != 2) {
+    fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+    exit (1);
+  }
+
+  /* Create the blob */
+  {
+    const char *font_data;
+    unsigned int len;
+    hb_destroy_func_t destroy;
+    void *user_data;
+    hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+    GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+    font_data = g_mapped_file_get_contents (mf);
+    len = g_mapped_file_get_length (mf);
+    destroy = (hb_destroy_func_t) g_mapped_file_unref;
+    user_data = (void *) mf;
+    mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+    FILE *f = fopen (argv[1], "rb");
+    fseek (f, 0, SEEK_END);
+    len = ftell (f);
+    fseek (f, 0, SEEK_SET);
+    font_data = (const char *) malloc (len);
+    if (!font_data) len = 0;
+    len = fread ((char *) font_data, 1, len, f);
+    destroy = free;
+    user_data = (void *) font_data;
+    fclose (f);
+    mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+    blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+  }
+
+  printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
+
+  /* Create the face */
+  hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+  hb_blob_destroy (blob);
+  blob = NULL;
+  unsigned int upem = hb_face_get_upem (face);
+
+  hb_font_t *font = hb_font_create (face);
+  hb_font_set_scale (font, upem, upem);
+
+#ifdef HAVE_FREETYPE
+  hb_ft_font_set_funcs (font);
+#endif
+
+  hb_buffer_t *buffer = hb_buffer_create ();
+
+  hb_buffer_add_utf8 (buffer, "\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb0\xe0\xa5\x8d\xe0\xa4\x95", -1, 0, -1);
+  hb_buffer_guess_segment_properties (buffer);
+
+  hb_shape (font, buffer, NULL, 0);
+
+  unsigned int count = hb_buffer_get_length (buffer);
+  hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);
+  hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, NULL);
+
+  for (unsigned int i = 0; i < count; i++)
+  {
+    hb_glyph_info_t *info = &infos[i];
+    hb_glyph_position_t *pos = &positions[i];
+
+    printf ("cluster %d        glyph 0x%x at   (%d,%d)+(%d,%d)\n",
+           info->cluster,
+           info->codepoint,
+           pos->x_offset,
+           pos->x_offset,
+           pos->x_advance,
+           pos->y_advance);
+
+  }
+
+  hb_buffer_destroy (buffer);
+  hb_font_destroy (font);
+  hb_face_destroy (face);
+
+  return 0;
+}
+
+
diff --git a/test/api/.valgrind-suppressions b/test/api/.valgrind-suppressions
new file mode 100644 (file)
index 0000000..e69de29
index e6c0c01..4ff14fa 100644 (file)
@@ -7,8 +7,8 @@ DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
 if HAVE_GLIB
-AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS) $(GTHREAD_CFLAGS)
-LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS) $(GTHREAD_LIBS)
+AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS)
+LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS)
 
 EXTRA_DIST += hb-test.h
 
@@ -21,11 +21,23 @@ TEST_PROGS = \
        test-common \
        test-font \
        test-object \
+       test-set \
        test-shape \
        test-unicode \
        test-version \
        $(NULL)
 
+test_unicode_CPPFLAGS = $(AM_CPPFLAGS)
+test_unicode_LDADD = $(LDADD)
+if HAVE_GLIB
+test_unicode_CPPFLAGS += $(GLIB_CFLAGS)
+endif
+if HAVE_ICU
+test_unicode_CPPFLAGS += $(ICU_CFLAGS)
+test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la
+endif
+
+
 if HAVE_OT
 TEST_PROGS += \
        test-ot-tag \
@@ -49,7 +61,6 @@ test_c_CPPFLAGS += $(FREETYPE_CFLAGS)
 test_cplusplus_CPPFLAGS += $(FREETYPE_CFLAGS)
 endif
 
-
 # Default test running environment
 TESTS = $(TEST_PROGS)
 TESTS_ENVIRONMENT = \
@@ -58,7 +69,7 @@ TESTS_ENVIRONMENT = \
        G_DEBUG=gc-friendly \
        G_SLICE=always-malloc \
        srcdir=$(srcdir) \
-       $(ENV)
+       $(NULL)
 
 
 # check-tool: Run tests under $(TOOL)
@@ -86,8 +97,8 @@ VALGRIND_FLAGS = \
        $(EXTRA_VALGRIND_FLAGS)
 #      Can't do for now: --show-reachable=yes
 CLEANFILES +=  log-valgrind.txt
-valgrind_verbose = $(valgrind_verbose_$(V))
-valgrind_verbose_ = $(valgrind_verbose_$(AM_DEFAULT_VERBOSITY))
+valgrind_verbose = $(valgrind_verbose_@AM_V@)
+valgrind_verbose_ = $(valgrind_verbose_@AM_DEFAULT_V@)
 valgrind_verbose_0 = | \
        grep '\(^[^=]\|ERROR SUMMARY\|definitely lost\|indirectly lost\)' | grep -v ': 0'
 # TODO: The following check does not fail if valgrind finds error.  It should.
index f36d53b..4d41218 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
 
 HB_BEGIN_DECLS
 
@@ -75,7 +76,6 @@ srcdir (void)
 static inline void
 hb_test_init (int *argc, char ***argv)
 {
-  g_thread_init (NULL);
   g_test_init (argc, argv, NULL);
 }
 
index 5fcb208..f671331 100644 (file)
@@ -53,6 +53,9 @@ test_blob_empty (void)
   g_assert (hb_blob_is_immutable (hb_blob_get_empty ()));
   g_assert (hb_blob_get_empty () != NULL);
   g_assert (hb_blob_get_empty () == hb_blob_create (NULL, 0, HB_MEMORY_MODE_READONLY, NULL, NULL));
+  g_assert (hb_blob_get_empty () == hb_blob_create ("asdf", 0, HB_MEMORY_MODE_READONLY, NULL, NULL));
+  g_assert (hb_blob_get_empty () == hb_blob_create (NULL, -1, HB_MEMORY_MODE_READONLY, NULL, NULL));
+  g_assert (hb_blob_get_empty () == hb_blob_create ("asdfg", -1, HB_MEMORY_MODE_READONLY, NULL, NULL));
 
   blob = hb_blob_get_empty ();
   g_assert (blob == hb_blob_get_empty ());
@@ -68,7 +71,7 @@ test_blob_empty (void)
   g_assert_cmpint (len, ==, 0);
 
   data_writable = hb_blob_get_data_writable (blob, NULL);
-  g_assert (data == NULL);
+  g_assert (data_writable == NULL);
 
   data_writable = hb_blob_get_data_writable (blob, &len);
   g_assert (data_writable == NULL);
@@ -262,16 +265,61 @@ static void
 test_blob_subblob (fixture_t *fixture, gconstpointer user_data)
 {
   hb_blob_t *b = fixture->blob;
+  hb_memory_mode_t mm = GPOINTER_TO_INT (user_data);
+  unsigned int len;
+  const char *data;
+  char *data_writable;
+  unsigned int i;
 
-  fixture->len -= 2;
-  fixture->data++;
-  fixture->blob = hb_blob_create_sub_blob (b, 1, fixture->len);
+  if (mm == HB_MEMORY_MODE_DUPLICATE) {
+    g_assert_cmpint (fixture->freed, ==, 1);
+    fixture->data = (char *) hb_blob_get_data (b, NULL);
+  } else {
+    g_assert_cmpint (fixture->freed, ==, 0);
+  }
+  fixture->blob = hb_blob_create_sub_blob (b, 1, fixture->len - 2);
   hb_blob_destroy (b);
+  b = fixture->blob;
+
+  /* A sub-blob is always created READONLY. */
+
+  g_assert (b);
 
-  test_blob (fixture, user_data);
+  len = hb_blob_get_length (b);
+  g_assert_cmpint (len, ==, fixture->len - 2);
+
+  data = hb_blob_get_data (b, &len);
+  g_assert_cmpint (len, ==, fixture->len - 2);
+  g_assert (data == fixture->data + 1);
 
-  fixture->data--;
-  fixture->len += 2;
+  data_writable = hb_blob_get_data_writable (b, &len);
+  g_assert_cmpint (len, ==, fixture->len - 2);
+  g_assert (data_writable);
+  if (mm == HB_MEMORY_MODE_READONLY)
+    g_assert (0 == memcmp (data_writable, fixture->data + 1, fixture->len - 2));
+  g_assert (data_writable != data);
+  g_assert_cmpint (fixture->freed, ==, 1);
+
+  data = hb_blob_get_data (b, &len);
+  g_assert_cmpint (len, ==, fixture->len - 2);
+  g_assert (data == data_writable);
+
+  memset (data_writable, 0, fixture->len - 2);
+
+  /* Now, make it immutable and watch get_data_writable() fail */
+
+  g_assert (!hb_blob_is_immutable (b));
+  hb_blob_make_immutable (b);
+  g_assert (hb_blob_is_immutable (b));
+
+  data_writable = hb_blob_get_data_writable (b, &len);
+  g_assert (!data_writable);
+  g_assert_cmpint (len, ==, 0);
+
+  data = hb_blob_get_data (b, &len);
+  g_assert_cmpint (len, ==, fixture->len - 2);
+  for (i = 0; i < len; i++)
+    g_assert ('\0' == data[i]);
 }
 
 
index ab818d0..17607f1 100644 (file)
@@ -71,7 +71,7 @@ fixture_init (fixture_t *fixture, gconstpointer user_data)
 
     case BUFFER_ONE_BY_ONE:
       for (i = 1; i < G_N_ELEMENTS (utf32) - 1; i++)
-       hb_buffer_add (b, utf32[i], 1, i);
+       hb_buffer_add (b, utf32[i], i);
       break;
 
     case BUFFER_UTF32:
@@ -127,8 +127,44 @@ test_buffer_properties (fixture_t *fixture, gconstpointer user_data)
   hb_buffer_set_language (b, hb_language_from_string ("fa", -1));
   g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1));
 
+  hb_buffer_set_flags (b, HB_BUFFER_FLAG_BOT);
+  g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAG_BOT);
 
-  /* test reset clears properties */
+  hb_buffer_set_replacement_codepoint (b, (unsigned int) -1);
+  g_assert (hb_buffer_get_replacement_codepoint (b) == (unsigned int) -1);
+
+
+  /* test clear_contents clears all these properties: */
+
+  hb_buffer_clear_contents (b);
+
+  g_assert (hb_buffer_get_unicode_funcs (b) == ufuncs);
+  g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID);
+  g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID);
+  g_assert (hb_buffer_get_language (b) == NULL);
+
+  /* but not these: */
+
+  g_assert (hb_buffer_get_flags (b) != HB_BUFFER_FLAGS_DEFAULT);
+  g_assert (hb_buffer_get_replacement_codepoint (b) != HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT);
+
+
+  /* test reset clears all properties */
+
+  hb_buffer_set_direction (b, HB_DIRECTION_RTL);
+  g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_RTL);
+
+  hb_buffer_set_script (b, HB_SCRIPT_ARABIC);
+  g_assert (hb_buffer_get_script (b) == HB_SCRIPT_ARABIC);
+
+  hb_buffer_set_language (b, hb_language_from_string ("fa", -1));
+  g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1));
+
+  hb_buffer_set_flags (b, HB_BUFFER_FLAG_BOT);
+  g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAG_BOT);
+
+  hb_buffer_set_replacement_codepoint (b, (unsigned int) -1);
+  g_assert (hb_buffer_get_replacement_codepoint (b) == (unsigned int) -1);
 
   hb_buffer_reset (b);
 
@@ -136,6 +172,8 @@ test_buffer_properties (fixture_t *fixture, gconstpointer user_data)
   g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID);
   g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID);
   g_assert (hb_buffer_get_language (b) == NULL);
+  g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAGS_DEFAULT);
+  g_assert (hb_buffer_get_replacement_codepoint (b) == HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT);
 }
 
 static void
@@ -152,7 +190,7 @@ test_buffer_contents (fixture_t *fixture, gconstpointer user_data)
   }
 
   len = hb_buffer_get_length (b);
-  glyphs = hb_buffer_get_glyph_infos (b, NULL); /* test NULL */
+  hb_buffer_get_glyph_infos (b, NULL); /* test NULL */
   glyphs = hb_buffer_get_glyph_infos (b, &len2);
   g_assert_cmpint (len, ==, len2);
   g_assert_cmpint (len, ==, 5);
@@ -264,7 +302,7 @@ test_buffer_positions (fixture_t *fixture, gconstpointer user_data)
 
   /* Without shaping, positions should all be zero */
   len = hb_buffer_get_length (b);
-  positions = hb_buffer_get_glyph_positions (b, NULL); /* test NULL */
+  hb_buffer_get_glyph_positions (b, NULL); /* test NULL */
   positions = hb_buffer_get_glyph_positions (b, &len2);
   g_assert_cmpint (len, ==, len2);
   for (i = 0; i < len; i++) {
@@ -345,6 +383,7 @@ test_buffer_utf8_conversion (void)
   unsigned int bytes, chars, i, j, len;
 
   b = hb_buffer_create ();
+  hb_buffer_set_replacement_codepoint (b, (hb_codepoint_t) -1);
 
   for (i = 0; i < G_N_ELEMENTS (utf8_conversion_tests); i++)
   {
@@ -359,7 +398,7 @@ test_buffer_utf8_conversion (void)
     for (chars = 0; test->codepoints[chars]; chars++)
       ;
 
-    hb_buffer_reset (b);
+    hb_buffer_clear_contents (b);
     hb_buffer_add_utf8 (b, test->utf8, bytes,  1, bytes - 2);
 
     glyphs = hb_buffer_get_glyph_infos (b, &len);
@@ -420,11 +459,15 @@ static const utf8_validity_test_t utf8_validity_tests[] = {
   { "\x7f", -1, 1, TRUE },
   { "\xdf\xbf", -1, 2, TRUE },
   { "\xef\xbf\xbf", -1, 0, TRUE },
-  { "\xf7\xbf\xbf\xbf", -1, 0, TRUE },
+  { "\xf4\x8f\xbf\xbf", -1, 0, TRUE },
+  { "\xf4\x90\xbf\xbf", -1, 0, FALSE },
+  { "\xf7\xbf\xbf\xbf", -1, 0, FALSE },
   { "\xfb\xbf\xbf\xbf\xbf", -1, 0, FALSE },
   { "\xfd\xbf\xbf\xbf\xbf\xbf", -1, 0, FALSE },
   /* other boundary conditions */
   { "\xed\x9f\xbf", -1, 3, TRUE },
+  { "\xed\xa0\x80", -1, 0, FALSE },
+  { "\xed\xbf\xbf", -1, 0, FALSE },
   { "\xee\x80\x80", -1, 3, TRUE },
   { "\xef\xbf\xbd", -1, 3, TRUE },
   { "\xf4\x8f\xbf\xbf", -1, 0, TRUE },
@@ -581,8 +624,6 @@ static const utf8_validity_test_t utf8_validity_tests[] = {
   /* impossible bytes */
   { "\x20\xfe\x20", -1, 1, FALSE },
   { "\x20\xff\x20", -1, 1, FALSE },
-#if 0
-  /* XXX fix these, or document that we don't detect them? */
   /* overlong sequences */
   { "\x20\xc0\xaf\x20", -1, 1, FALSE },
   { "\x20\xe0\x80\xaf\x20", -1, 1, FALSE },
@@ -615,6 +656,7 @@ static const utf8_validity_test_t utf8_validity_tests[] = {
   { "\x20\xed\xae\x80\xed\xbf\xbf\x20", -1, 1, FALSE },
   { "\x20\xed\xaf\xbf\xed\xb0\x80\x20", -1, 1, FALSE },
   { "\x20\xed\xaf\xbf\xed\xbf\xbf\x20", -1, 1, FALSE },
+#if 0 /* We don't consider U+FFFE / U+FFFF and similar invalid. */
   { "\x20\xef\xbf\xbe\x20", -1, 1, FALSE },
   { "\x20\xef\xbf\xbf\x20", -1, 1, FALSE },
 #endif
@@ -628,6 +670,7 @@ test_buffer_utf8_validity (void)
   unsigned int i;
 
   b = hb_buffer_create ();
+  hb_buffer_set_replacement_codepoint (b, (hb_codepoint_t) -1);
 
   for (i = 0; i < G_N_ELEMENTS (utf8_validity_tests); i++)
   {
@@ -646,7 +689,7 @@ test_buffer_utf8_validity (void)
     else
       segment_bytes = test->max_len;
 
-    hb_buffer_reset (b);
+    hb_buffer_clear_contents (b);
     hb_buffer_add_utf8 (b, test->utf8, text_bytes,  0, segment_bytes);
 
     glyphs = hb_buffer_get_glyph_infos (b, &len);
@@ -675,7 +718,8 @@ static const utf16_conversion_test_t utf16_conversion_tests[] = {
   {{0x41, 0xD800, 0xDF02}, {-1}},
   {{0x41, 0x61, 0xD800, 0xDF02}, {0x61, -1}},
   {{0x41, 0xD800, 0x61, 0xDF02}, {-1, 0x61}},
-  {{0x41, 0x61}, {}}
+  {{0x41, 0xDF00, 0x61}, {-1}},
+  {{0x41, 0x61}, {0}}
 };
 
 static void
@@ -685,6 +729,7 @@ test_buffer_utf16_conversion (void)
   unsigned int i;
 
   b = hb_buffer_create ();
+  hb_buffer_set_replacement_codepoint (b, (hb_codepoint_t) -1);
 
   for (i = 0; i < G_N_ELEMENTS (utf16_conversion_tests); i++)
   {
@@ -699,7 +744,7 @@ test_buffer_utf16_conversion (void)
     for (chars = 0; test->codepoints[chars]; chars++)
       ;
 
-    hb_buffer_reset (b);
+    hb_buffer_clear_contents (b);
     hb_buffer_add_utf16 (b, test->utf16, u_len,  1, u_len - 2);
 
     glyphs = hb_buffer_get_glyph_infos (b, &len);
@@ -711,6 +756,61 @@ test_buffer_utf16_conversion (void)
   hb_buffer_destroy (b);
 }
 
+
+typedef struct {
+  const uint32_t utf32[8];
+  const uint32_t codepoints[8];
+} utf32_conversion_test_t;
+
+/* note: we skip the first and last item from utf32 when adding to buffer */
+static const utf32_conversion_test_t utf32_conversion_tests[] = {
+  {{0x41, 0x004D, 0x0430, 0x4E8C, 0xD800, 0xDF02, 0x61} , {0x004D, 0x0430, 0x4E8C, -3, -3}},
+  {{0x41, 0x004D, 0x0430, 0x4E8C, 0x10302, 0x61} , {0x004D, 0x0430, 0x4E8C, 0x10302}},
+  {{0x41, 0xD800, 0xDF02, 0x61}, {-3, -3}},
+  {{0x41, 0xD800, 0xDF02}, {-3}},
+  {{0x41, 0x61, 0xD800, 0xDF02}, {0x61, -3}},
+  {{0x41, 0xD800, 0x61, 0xDF02}, {-3, 0x61}},
+  {{0x41, 0xDF00, 0x61}, {-3}},
+  {{0x41, 0x10FFFF, 0x61}, {0x10FFFF}},
+  {{0x41, 0x110000, 0x61}, {-3}},
+  {{0x41, 0x61}, {0}}
+};
+
+static void
+test_buffer_utf32_conversion (void)
+{
+  hb_buffer_t *b;
+  unsigned int i;
+
+  b = hb_buffer_create ();
+  hb_buffer_set_replacement_codepoint (b, (hb_codepoint_t) -3);
+
+  for (i = 0; i < G_N_ELEMENTS (utf32_conversion_tests); i++)
+  {
+    const utf32_conversion_test_t *test = &utf32_conversion_tests[i];
+    unsigned int u_len, chars, j, len;
+    hb_glyph_info_t *glyphs;
+
+    g_test_message ("UTF-32 test #%d", i);
+
+    for (u_len = 0; test->utf32[u_len]; u_len++)
+      ;
+    for (chars = 0; test->codepoints[chars]; chars++)
+      ;
+
+    hb_buffer_clear_contents (b);
+    hb_buffer_add_utf32 (b, test->utf32, u_len,  1, u_len - 2);
+
+    glyphs = hb_buffer_get_glyph_infos (b, &len);
+    g_assert_cmpint (len, ==, chars);
+    for (j = 0; j < chars; j++)
+      g_assert_cmphex (glyphs[j].codepoint, ==, test->codepoints[j]);
+  }
+
+  hb_buffer_destroy (b);
+}
+
+
 static void
 test_empty (hb_buffer_t *b)
 {
@@ -777,6 +877,7 @@ main (int argc, char **argv)
   hb_test_add (test_buffer_utf8_conversion);
   hb_test_add (test_buffer_utf8_validity);
   hb_test_add (test_buffer_utf16_conversion);
+  hb_test_add (test_buffer_utf32_conversion);
   hb_test_add (test_buffer_empty);
 
   return hb_test_run();
index 25a38e5..6e8602f 100644 (file)
 #include <hb-uniscribe.h>
 #endif
 
+#ifdef HAVE_CORETEXT
+#include <hb-coretext.h>
+#endif
+
 int
 main (int argc, char **argv)
 {
index 40540c4..6b6a503 100644 (file)
@@ -136,7 +136,6 @@ _test_font_nil_funcs (hb_font_t *font)
   g_assert (!hb_font_get_glyph (font, 17, 2, &glyph));
   g_assert_cmpint (glyph, ==, 0);
 
-  x = 13;
   x = hb_font_get_glyph_h_kerning (font, 17, 19);
   g_assert_cmpint (x, ==, 0);
 }
index 66e8d33..3afe6ae 100644 (file)
@@ -53,6 +53,17 @@ create_buffer_inert (void)
 }
 
 static void *
+create_set (void)
+{
+  return hb_set_create ();
+}
+static void *
+create_set_inert (void)
+{
+  return NULL;
+}
+
+static void *
 create_face (void)
 {
   hb_blob_t *blob = (hb_blob_t *) create_blob ();
@@ -154,6 +165,7 @@ typedef struct {
 static const object_t objects[] =
 {
   OBJECT_WITHOUT_IMMUTABILITY (buffer),
+  OBJECT_WITHOUT_IMMUTABILITY (set),
   OBJECT_WITH_IMMUTABILITY (blob),
   OBJECT_WITH_IMMUTABILITY (face),
   OBJECT_WITH_IMMUTABILITY (font),
@@ -219,7 +231,7 @@ test_object (void)
   for (i = 0; i < G_N_ELEMENTS (objects); i++) {
     const object_t *o = &objects[i];
     void *obj;
-    hb_user_data_key_t key[2];
+    hb_user_data_key_t key[1001];
 
     {
       unsigned int j;
index 81b6678..b667c7d 100644 (file)
@@ -132,6 +132,7 @@ test_ot_tag_script_indic (void)
   test_indic_tags ("ory2", "orya", HB_SCRIPT_ORIYA);
   test_indic_tags ("tml2", "taml", HB_SCRIPT_TAMIL);
   test_indic_tags ("tel2", "telu", HB_SCRIPT_TELUGU);
+  test_indic_tags ("mym2", "mymr", HB_SCRIPT_MYANMAR);
 }
 
 
@@ -194,17 +195,21 @@ test_ot_tag_language (void)
 
   test_language_two_way ("ZHH", "zh-hk"); /* Chinese (Hong Kong) */
 
+  test_tag_from_language ("ZHS", "zh"); /* Chinese */
   test_tag_from_language ("ZHS", "zh-cn"); /* Chinese (China) */
   test_tag_from_language ("ZHS", "zh-sg"); /* Chinese (Singapore) */
   test_tag_from_language ("ZHT", "zh-mo"); /* Chinese (Macao) */
   test_tag_from_language ("ZHT", "zh-tw"); /* Chinese (Taiwan) */
+  test_tag_from_language ("ZHS", "zh-Hans"); /* Chinese (Simplified) */
+  test_tag_from_language ("ZHT", "zh-Hant"); /* Chinese (Traditional) */
+  test_tag_from_language ("ZHS", "zh-xx"); /* Chinese (Other) */
 
   test_tag_from_language ("ZHS", "zh"); /* Chinese */
   test_tag_from_language ("ZHS", "zh-xx");
 
-  test_tag_to_language ("ZHS", "zh-x-hbotzhs");
-  test_tag_to_language ("ZHT", "zh-x-hbotzht");
-  test_tag_to_language ("ZHP", "zh-x-hbotzhp");
+  test_tag_to_language ("ZHS", "zh-Hans");
+  test_tag_to_language ("ZHT", "zh-Hant");
+  test_tag_to_language ("ZHP", "x-hbotzhp");
 
   test_language_two_way ("ABC", "x-hbotabc");
   test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc-zxc");
diff --git a/test/api/test-set.c b/test/api/test-set.c
new file mode 100644 (file)
index 0000000..9634951
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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
+ */
+
+#include "hb-test.h"
+
+/* Unit tests for hb-set.h */
+
+
+static void
+test_empty (hb_set_t *s)
+{
+  hb_codepoint_t next = HB_SET_VALUE_INVALID;
+  g_assert_cmpint (hb_set_get_population (s), ==, 0);
+  g_assert_cmpint (hb_set_get_min (s), ==, HB_SET_VALUE_INVALID);
+  g_assert_cmpint (hb_set_get_max (s), ==, HB_SET_VALUE_INVALID);
+  g_assert (!hb_set_has (s, 13));
+  g_assert (!hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
+  g_assert (hb_set_is_empty (s));
+}
+
+static void
+test_not_empty (hb_set_t *s)
+{
+  hb_codepoint_t next = HB_SET_VALUE_INVALID;
+  g_assert_cmpint (hb_set_get_population (s), !=, 0);
+  g_assert_cmpint (hb_set_get_min (s), !=, HB_SET_VALUE_INVALID);
+  g_assert_cmpint (hb_set_get_max (s), !=, HB_SET_VALUE_INVALID);
+  g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, !=, HB_SET_VALUE_INVALID);
+}
+
+static void
+test_set_basic (void)
+{
+  hb_set_t *s = hb_set_create ();
+
+  test_empty (s);
+  hb_set_add (s, 13);
+  test_not_empty (s);
+
+  hb_set_clear (s);
+  test_empty (s);
+
+  hb_set_add (s, 33000);
+  test_not_empty (s);
+  hb_set_clear (s);
+
+  hb_set_add_range (s, 10, 29);
+  test_not_empty (s);
+  g_assert (hb_set_has (s, 13));
+  g_assert_cmpint (hb_set_get_population (s), ==, 20);
+  g_assert_cmpint (hb_set_get_min (s), ==, 10);
+  g_assert_cmpint (hb_set_get_max (s), ==, 29);
+
+  hb_set_invert (s);
+  test_not_empty (s);
+  g_assert (!hb_set_has (s, 13));
+  g_assert_cmpint (hb_set_get_min (s), ==, 0);
+
+  hb_set_invert (s);
+  test_not_empty (s);
+  g_assert (hb_set_has (s, 13));
+  g_assert_cmpint (hb_set_get_population (s), ==, 20);
+  g_assert_cmpint (hb_set_get_min (s), ==, 10);
+  g_assert_cmpint (hb_set_get_max (s), ==, 29);
+
+  hb_set_del_range (s, 10, 18);
+  test_not_empty (s);
+  g_assert (!hb_set_has (s, 13));
+
+  hb_set_destroy (s);
+}
+
+static void
+test_set_algebra (void)
+{
+  hb_set_t *s = hb_set_create ();
+  hb_set_t *o = hb_set_create ();
+
+  hb_set_add (o, 13);
+  hb_set_add (o, 19);
+
+  test_empty (s);
+  g_assert (!hb_set_is_equal (s, o));
+  hb_set_set (s, o);
+  g_assert (hb_set_is_equal (s, o));
+  test_not_empty (s);
+  g_assert_cmpint (hb_set_get_population (s), ==, 2);
+
+  hb_set_clear (s);
+  test_empty (s);
+  hb_set_add (s, 10);
+  g_assert_cmpint (hb_set_get_population (s), ==, 1);
+  hb_set_union (s, o);
+  g_assert_cmpint (hb_set_get_population (s), ==, 3);
+  g_assert (hb_set_has (s, 10));
+  g_assert (hb_set_has (s, 13));
+
+  hb_set_clear (s);
+  test_empty (s);
+  hb_set_add_range (s, 10, 17);
+  g_assert (!hb_set_is_equal (s, o));
+  hb_set_intersect (s, o);
+  g_assert (!hb_set_is_equal (s, o));
+  test_not_empty (s);
+  g_assert_cmpint (hb_set_get_population (s), ==, 1);
+  g_assert (!hb_set_has (s, 10));
+  g_assert (hb_set_has (s, 13));
+
+  hb_set_clear (s);
+  test_empty (s);
+  hb_set_add_range (s, 10, 17);
+  g_assert (!hb_set_is_equal (s, o));
+  hb_set_subtract (s, o);
+  g_assert (!hb_set_is_equal (s, o));
+  test_not_empty (s);
+  g_assert_cmpint (hb_set_get_population (s), ==, 7);
+  g_assert (hb_set_has (s, 12));
+  g_assert (!hb_set_has (s, 13));
+  g_assert (!hb_set_has (s, 19));
+
+  hb_set_clear (s);
+  test_empty (s);
+  hb_set_add_range (s, 10, 17);
+  g_assert (!hb_set_is_equal (s, o));
+  hb_set_symmetric_difference (s, o);
+  g_assert (!hb_set_is_equal (s, o));
+  test_not_empty (s);
+  g_assert_cmpint (hb_set_get_population (s), ==, 8);
+  g_assert (hb_set_has (s, 12));
+  g_assert (!hb_set_has (s, 13));
+  g_assert (hb_set_has (s, 19));
+
+  hb_set_destroy (s);
+}
+
+static void
+test_set_iter (void)
+{
+  hb_codepoint_t next, first, last;
+  hb_set_t *s = hb_set_create ();
+
+  hb_set_add (s, 13);
+  hb_set_add_range (s, 6, 6);
+  hb_set_add_range (s, 10, 15);
+  hb_set_add (s, 20005);
+
+  test_not_empty (s);
+
+  next = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, 6);
+  g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, 10);
+  g_assert (hb_set_next (s, &next));
+  g_assert (hb_set_next (s, &next));
+  g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, 13);
+  g_assert (hb_set_next (s, &next));
+  g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, 15);
+  g_assert (hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, 20005);
+  g_assert (!hb_set_next (s, &next));
+  g_assert_cmpint (next, ==, HB_SET_VALUE_INVALID);
+
+  first = last = HB_SET_VALUE_INVALID;
+  g_assert (hb_set_next_range (s, &first, &last));
+  g_assert_cmpint (first, ==, 6);
+  g_assert_cmpint (last,  ==, 6);
+  g_assert (hb_set_next_range (s, &first, &last));
+  g_assert_cmpint (first, ==, 10);
+  g_assert_cmpint (last,  ==, 15);
+  g_assert (hb_set_next_range (s, &first, &last));
+  g_assert_cmpint (first, ==, 20005);
+  g_assert_cmpint (last,  ==, 20005);
+  g_assert (!hb_set_next_range (s, &first, &last));
+  g_assert_cmpint (first, ==, HB_SET_VALUE_INVALID);
+  g_assert_cmpint (last,  ==, HB_SET_VALUE_INVALID);
+
+  hb_set_destroy (s);
+}
+
+static void
+test_set_empty (void)
+{
+  hb_set_t *b = hb_set_get_empty ();
+
+  g_assert (hb_set_get_empty ());
+  g_assert (hb_set_get_empty () == b);
+
+  g_assert (!hb_set_allocation_successful (b));
+
+  test_empty (b);
+
+  hb_set_add (b, 13);
+
+  test_empty (b);
+
+  hb_set_invert (b);
+
+  test_empty (b);
+
+  g_assert (!hb_set_allocation_successful (b));
+
+  hb_set_clear (b);
+
+  test_empty (b);
+
+  g_assert (!hb_set_allocation_successful (b));
+
+  hb_set_destroy (b);
+}
+
+int
+main (int argc, char **argv)
+{
+  hb_test_init (&argc, &argv);
+
+  hb_test_add (test_set_basic);
+  hb_test_add (test_set_algebra);
+  hb_test_add (test_set_iter);
+  hb_test_add (test_set_empty);
+
+  return hb_test_run();
+}
diff --git a/test/api/test-shape-complex.c b/test/api/test-shape-complex.c
deleted file mode 100644 (file)
index 1963b5e..0000000
+++ /dev/null
@@ -1,1159 +0,0 @@
-/*
- * Copyright © 2011  Google, Inc.
- * Copyright © 2008  Nokia Corporation and/or its subsidiary(-ies)
- *
- *  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-test.h"
-
-/* Unit tests for complex text shaping */
-
-/*
- * This test provides a framework to test aspects of hb_shape() that are
- * font-dependent.  Please add tests for any feature that fits that
- * description.
- */
-
-#include <hb-ft.h>
-
-typedef struct
-{
-  const char *font_file;
-  unsigned int face_index;
-  /* TODO add min/max face version */
-} font_data_t;
-
-static char *
-get_font_file (const font_data_t *font_data)
-{
-  return g_strdup_printf ("%s/fonts/%s", srcdir (), font_data->font_file);
-}
-
-
-typedef struct
-{
-  char           comments[64];
-  hb_codepoint_t characters[16];
-  hb_codepoint_t glyphs[16];
-} test_data_t;
-
-typedef struct
-{
-  const font_data_t font_data;
-  const test_data_t test_datas[];
-} test_set_t;
-
-typedef struct
-{
-  const font_data_t *font_data;
-  const test_data_t *test_data;
-} test_t;
-
-
-static const test_set_t tests_devanagari1 = {
-  {"raghu.ttf", 0},
-  {
-    { "Ka",
-      { 0x0915, 0 },
-      { 0x0080, 0 }
-    },
-    { "Ka Halant",
-      { 0x0915, 0x094d, 0 },
-      { 0x0080, 0x0051, 0 }
-    },
-    { "Ka Halant Ka",
-      { 0x0915, 0x094d, 0x0915, 0 },
-      { 0x00c8, 0x0080, 0 }
-    },
-    { "Ka MatraI",
-      { 0x0915, 0x093f, 0 },
-      { 0x01d1, 0x0080, 0 }
-    },
-    { "Ra Halant Ka",
-      { 0x0930, 0x094d, 0x0915, 0 },
-      { 0x0080, 0x005b, 0 }
-    },
-    { "Ra Halant Ka MatraI",
-      { 0x0930, 0x094d, 0x0915, 0x093f, 0 },
-      { 0x01d1, 0x0080, 0x005b, 0 }
-    },
-    { "MatraI",
-      { 0x093f, 0 },
-      { 0x01d4, 0x029c, 0 }
-    },
-    { "Ka Nukta",
-      { 0x0915, 0x093c, 0 },
-      { 0x00a4, 0 }
-    },
-    { "Ka Halant Ra",
-      { 0x0915, 0x094d, 0x0930, 0 },
-      { 0x0110, 0 }
-    },
-    { "Ka Halant Ra Halant Ka",
-      { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0 },
-      { 0x0158, 0x0080, 0 }
-    },
-    { "",
-      { 0x0930, 0x094d, 0x200d, 0 },
-      { 0x00e2, 0 }
-    },
-    { "",
-      { 0x0915, 0x094d, 0x0930, 0x094d, 0x200d, 0 },
-      { 0x0158, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_devanagari2 = {
-  {"mangal.ttf", 0},
-  {
-    { "Ka",
-      { 0x0915, 0 },
-      { 0x0080, 0 }
-    },
-    { "Ka Halant",
-      { 0x0915, 0x094d, 0 },
-      { 0x0080, 0x0051, 0 }
-    },
-    { "Ka Halant Ka",
-      { 0x0915, 0x094d, 0x0915, 0 },
-      { 0x00c8, 0x0080, 0 }
-    },
-    { "Ka MatraI",
-      { 0x0915, 0x093f, 0 },
-      { 0x01d1, 0x0080, 0 }
-    },
-    { "Ra Halant Ka",
-      { 0x0930, 0x094d, 0x0915, 0 },
-      { 0x0080, 0x005b, 0 }
-    },
-    { "Ra Halant Ka MatraI",
-      { 0x0930, 0x094d, 0x0915, 0x093f, 0 },
-      { 0x01d1, 0x0080, 0x005b, 0 }
-    },
-    { "MatraI",
-      { 0x093f, 0 },
-      { 0x01d4, 0x029c, 0 }
-    },
-    { "Ka Nukta",
-      { 0x0915, 0x093c, 0 },
-      { 0x00a4, 0 }
-    },
-    { "Ka Halant Ra",
-      { 0x0915, 0x094d, 0x0930, 0 },
-      { 0x0110, 0 }
-    },
-    { "Ka Halant Ra Halant Ka",
-      { 0x0915, 0x094d, 0x0930, 0x094d, 0x0915, 0 },
-      { 0x0158, 0x0080, 0 }
-    },
-    { "",
-      { 0x92b, 0x94d, 0x930, 0 },
-      { 0x125, 0 }
-    },
-    { "",
-      { 0x92b, 0x93c, 0x94d, 0x930, 0 },
-      { 0x149, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_bengali1 = {
-  {"AkaashNormal.ttf", 0},
-  {
-    { "Ka",
-      { 0x0995, 0 },
-      { 0x0151, 0 }
-    },
-    { "Ka Halant",
-      { 0x0995, 0x09cd, 0 },
-      { 0x0151, 0x017d, 0 }
-    },
-    { "Ka Halant Ka",
-      { 0x0995, 0x09cd, 0x0995, 0 },
-      { 0x019b, 0 }
-    },
-    { "Ka MatraI",
-      { 0x0995, 0x09bf, 0 },
-      { 0x0173, 0x0151, 0 }
-    },
-    { "Ra Halant Ka",
-      { 0x09b0, 0x09cd, 0x0995, 0 },
-      { 0x0151, 0x0276, 0 }
-    },
-    { "Ra Halant Ka MatraI",
-      { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0 },
-      { 0x0173, 0x0151, 0x0276, 0 }
-    },
-    { "Ka Nukta",
-      { 0x0995, 0x09bc, 0 },
-      { 0x0151, 0x0171, 0 }
-    },
-    { "Ka Halant Ra",
-      { 0x0995, 0x09cd, 0x09b0, 0 },
-      { 0x01f4, 0 }
-    },
-    { "Ka Halant Ra Halant Ka",
-      { 0x0995, 0x09cd, 0x09b0, 0x09cd, 0x0995, 0 },
-      { 0x025c, 0x0276, 0x0151, 0 }
-    },
-    { "Ya + Halant",
-      { 0x09af, 0x09cd, 0 },
-      { 0x016a, 0x017d, 0 }
-    },
-    { "Da Halant Ya -> Da Ya-Phala",
-      { 0x09a6, 0x09cd, 0x09af, 0 },
-      { 0x01e5, 0 }
-    },
-    { "A Halant Ya -> A Ya-phala",
-      { 0x0985, 0x09cd, 0x09af, 0 },
-      { 0x0145, 0x01cf, 0 }
-    },
-    { "Na Halant Ka",
-      { 0x09a8, 0x09cd, 0x0995, 0 },
-      { 0x026f, 0x0151, 0 }
-    },
-    { "Na Halant ZWNJ Ka",
-      { 0x09a8, 0x09cd, 0x200c, 0x0995, 0 },
-      { 0x0164, 0x017d, 0x0151, 0 }
-    },
-    { "Na Halant ZWJ Ka",
-      { 0x09a8, 0x09cd, 0x200d, 0x0995, 0 },
-      { 0x026f, 0x0151, 0 }
-    },
-    { "Ka Halant ZWNJ Ka",
-      { 0x0995, 0x09cd, 0x200c, 0x0995, 0 },
-      { 0x0151, 0x017d, 0x0151, 0 }
-    },
-    { "Ka Halant ZWJ Ka",
-      { 0x0995, 0x09cd, 0x200d, 0x0995, 0 },
-      { 0x025c, 0x0151, 0 }
-    },
-    { "Na Halant Ra",
-      { 0x09a8, 0x09cd, 0x09b0, 0 },
-      { 0x0207, 0 }
-    },
-    { "Na Halant ZWNJ Ra",
-      { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0 },
-      { 0x0164, 0x017d, 0x016b, 0 }
-    },
-    { "Na Halant ZWJ Ra",
-      { 0x09a8, 0x09cd, 0x200d, 0x09b0, 0 },
-      { 0x026f, 0x016b, 0 }
-    },
-    { "Na Halant Ba",
-      { 0x09a8, 0x09cd, 0x09ac, 0 },
-      { 0x022f, 0 }
-    },
-    { "Na Halant ZWNJ Ba",
-      { 0x09a8, 0x09cd, 0x200c, 0x09ac, 0 },
-      { 0x0164, 0x017d, 0x0167, 0 }
-    },
-    { "Na Halant ZWJ Ba",
-      { 0x09a8, 0x09cd, 0x200d, 0x09ac, 0 },
-      { 0x026f, 0x0167, 0 }
-    },
-    { "Na Halant Dha",
-      { 0x09a8, 0x09cd, 0x09a7, 0 },
-      { 0x01d3, 0 }
-    },
-    { "Na Halant ZWNJ Dha",
-      { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0 },
-      { 0x0164, 0x017d, 0x0163, 0 }
-    },
-    { "Na Halant ZWJ Dha",
-      { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0 },
-      { 0x026f, 0x0163, 0 }
-    },
-    { "Ra Halant Ka MatraAU",
-      { 0x09b0, 0x09cd, 0x0995, 0x09cc, 0 },
-      { 0x0179, 0x0151, 0x0276, 0x017e, 0 }
-    },
-    { "Ra Halant Ba Halant Ba",
-      { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0 },
-      { 0x0232, 0x0276, 0 }
-    },
-    { "",
-      { 0x9b0, 0x9cd, 0x995, 0x9be, 0x982, 0 },
-      { 0x151, 0x276, 0x172, 0x143, 0 }
-    },
-    { "",
-      { 0x9b0, 0x9cd, 0x995, 0x9be, 0x983, 0 },
-      { 0x151, 0x276, 0x172, 0x144, 0 }
-    },
-    /*  Test decomposed two part matras */
-    { "",
-      { 0x995, 0x9c7, 0x9be, 0 },
-      { 0x179, 0x151, 0x172, 0 }
-    },
-    { "",
-      { 0x995, 0x9c7, 0x9d7, 0 },
-      { 0x179, 0x151, 0x17e, 0 }
-    },
-    { "",
-      { 0x9b0, 0x9cd, 0x9ad, 0 },
-      { 0x168, 0x276, 0 }
-    },
-    { "",
-      { 0x9f0, 0x9cd, 0x9ad, 0 },
-      { 0x168, 0x276, 0 }
-    },
-    { "",
-      { 0x9f1, 0x9cd, 0x9ad, 0 },
-      { 0x191, 0x17d, 0x168, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_bengali2 = {
-  {"MuktiNarrow.ttf", 0},
-  {
-    { "Ka",
-      { 0x0995, 0 },
-      { 0x0073, 0 }
-    },
-    { "Ka Halant",
-      { 0x0995, 0x09cd, 0 },
-      { 0x00b9, 0 }
-    },
-    { "Ka Halant Ka",
-      { 0x0995, 0x09cd, 0x0995, 0 },
-      { 0x0109, 0 }
-    },
-    { "Ka MatraI",
-      { 0x0995, 0x09bf, 0 },
-      { 0x0095, 0x0073, 0 }
-    },
-    { "Ra Halant Ka",
-      { 0x09b0, 0x09cd, 0x0995, 0 },
-      { 0x0073, 0x00e1, 0 }
-    },
-    { "Ra Halant Ka MatraI",
-      { 0x09b0, 0x09cd, 0x0995, 0x09bf, 0 },
-      { 0x0095, 0x0073, 0x00e1, 0 }
-    },
-    { "MatraI",
-      { 0x09bf, 0 },
-      { 0x0095, 0x01c8, 0 }
-    },
-    { "Ka Nukta",
-      { 0x0995, 0x09bc, 0 },
-      { 0x0073, 0x0093, 0 }
-    },
-    { "Ka Halant Ra",
-      { 0x0995, 0x09cd, 0x09b0, 0 },
-      { 0x00e5, 0 }
-    },
-    { "Ka Halant Ra Halant Ka",
-      { 0x995, 0x9cd, 0x9b0, 0x9cd, 0x995, 0 },
-      { 0x234, 0x24e, 0x73, 0 }
-    },
-    { "Ya + Halant",
-      { 0x09af, 0x09cd, 0 },
-      { 0x00d2, 0 }
-    },
-    { "Da Halant Ya -> Da Ya-Phala",
-      { 0x09a6, 0x09cd, 0x09af, 0 },
-      { 0x0084, 0x00e2, 0 }
-    },
-    { "A Halant Ya -> A Ya-phala",
-      { 0x0985, 0x09cd, 0x09af, 0 },
-      { 0x0067, 0x00e2, 0 }
-    },
-    { "Na Halant Ka",
-      { 0x09a8, 0x09cd, 0x0995, 0 },
-      { 0x0188, 0 }
-    },
-    { "Na Halant ZWNJ Ka",
-      { 0x9a8, 0x9cd, 0x200c, 0x995, 0 },
-      { 0xcc, 0x73, 0 }
-    },
-    { "Na Halant ZWJ Ka",
-      { 0x9a8, 0x9cd, 0x200d, 0x995, 0 },
-      { 0x247, 0x73, 0 }
-    },
-    { "Ka Halant ZWNJ Ka",
-      { 0x9a8, 0x9cd, 0x200d, 0x995, 0 },
-      { 0x247, 0x73, 0 }
-    },
-    { "Ka Halant ZWJ Ka",
-      { 0x9a8, 0x9cd, 0x200d, 0x995, 0 },
-      { 0x247, 0x73, 0 }
-    },
-    { "Na Halant Ra",
-      { 0x09a8, 0x09cd, 0x09b0, 0 },
-      { 0x00f8, 0 }
-    },
-    { "Na Halant ZWNJ Ra",
-      { 0x09a8, 0x09cd, 0x200c, 0x09b0, 0 },
-      { 0xcc, 0x8d, 0 }
-    },
-    { "Na Halant ZWJ Ra",
-      { 0x9a8, 0x9cd, 0x200d, 0x9b0, 0 },
-      { 0x247, 0x8d, 0 }
-    },
-    { "Na Halant Ba",
-      { 0x09a8, 0x09cd, 0x09ac, 0 },
-      { 0x0139, 0 }
-    },
-    { "Na Halant ZWNJ Ba",
-      { 0x9a8, 0x9cd, 0x200c, 0x9ac, 0 },
-      { 0xcc, 0x89, 0 }
-    },
-    { "Na Halant ZWJ Ba",
-      { 0x9a8, 0x9cd, 0x200d, 0x9ac, 0 },
-      { 0x247, 0x89, 0 }
-    },
-    { "Na Halant Dha",
-      { 0x09a8, 0x09cd, 0x09a7, 0 },
-      { 0x0145, 0 }
-    },
-    { "Na Halant ZWNJ Dha",
-      { 0x09a8, 0x09cd, 0x200c, 0x09a7, 0 },
-      { 0xcc, 0x85, 0 }
-    },
-    { "Na Halant ZWJ Dha",
-      { 0x09a8, 0x09cd, 0x200d, 0x09a7, 0 },
-      { 0x247, 0x85, 0 }
-    },
-    { "Ra Halant Ka MatraAU",
-      { 0x9b0, 0x9cd, 0x995, 0x9cc, 0 },
-      { 0x232, 0x73, 0xe1, 0xa0, 0 }
-    },
-    { "Ra Halant Ba Halant Ba",
-      { 0x09b0, 0x09cd, 0x09ac, 0x09cd, 0x09ac, 0 },
-      { 0x013b, 0x00e1, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_bengali3 = {
-  {"LikhanNormal.ttf", 0},
-  {
-    { "",
-      { 0x09a8, 0x09cd, 0x09af, 0 },
-      { 0x01ca, 0 }
-    },
-    { "",
-      { 0x09b8, 0x09cd, 0x09af, 0 },
-      { 0x020e, 0 }
-    },
-    { "",
-      { 0x09b6, 0x09cd, 0x09af, 0 },
-      { 0x01f4, 0 }
-    },
-    { "",
-      { 0x09b7, 0x09cd, 0x09af, 0 },
-      { 0x01fe, 0 }
-    },
-    { "",
-      { 0x09b0, 0x09cd, 0x09a8, 0x09cd, 0x200d, 0 },
-      { 0x10b, 0x167, 0 }
-    },
-    { "",
-      { 0x9b0, 0x9cd, 0x9ad, 0 },
-      { 0xa1, 0x167, 0 }
-    },
-    { "",
-      { 0x9f0, 0x9cd, 0x9ad, 0 },
-      { 0xa1, 0x167, 0 }
-    },
-    { "",
-      { 0x9f1, 0x9cd, 0x9ad, 0 },
-      { 0x11c, 0xa1, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_gurmukhi = {
-  {"lohit_pa.ttf", 0},
-  {
-    { "",
-      { 0xA15, 0xA4D, 0xa39, 0 },
-      { 0x3b, 0x8b, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_oriya = {
-  {"utkalm.ttf", 0},
-  {
-    { "",
-      { 0xb15, 0xb4d, 0xb24, 0xb4d, 0xb30, 0 },
-      { 0x150, 0x125, 0 }
-    },
-    { "",
-      { 0xb24, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0 },
-      { 0x151, 0x120, 0 }
-    },
-    { "",
-      { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0 },
-      { 0x152, 0x120, 0 }
-    },
-    { "",
-      { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb2c, 0 },
-      { 0x152, 0x120, 0 }
-    },
-    { "",
-      { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0 },
-      { 0x176, 0 }
-    },
-    { "",
-      { 0xb38, 0xb4d, 0xb24, 0xb4d, 0xb30, 0 },
-      { 0x177, 0 }
-    },
-    { "",
-      { 0xb28, 0xb4d, 0xb24, 0xb4d, 0xb30, 0xb4d, 0xb2f, 0 },
-      { 0x176, 0x124, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_tamil = {
-  {"akruti1.ttf", 0},
-  {
-    { "",
-      { 0x0b95, 0x0bc2, 0 },
-      { 0x004e, 0 }
-    },
-    { "",
-      { 0x0bae, 0x0bc2, 0 },
-      { 0x009e, 0 }
-    },
-    { "",
-      { 0x0b9a, 0x0bc2, 0 },
-      { 0x0058, 0 }
-    },
-    { "",
-      { 0x0b99, 0x0bc2, 0 },
-      { 0x0053, 0 }
-    },
-    { "",
-      { 0x0bb0, 0x0bc2, 0 },
-      { 0x00a8, 0 }
-    },
-    { "",
-      { 0x0ba4, 0x0bc2, 0 },
-      { 0x008e, 0 }
-    },
-    { "",
-      { 0x0b9f, 0x0bc2, 0 },
-      { 0x0062, 0 }
-    },
-    { "",
-      { 0x0b95, 0x0bc6, 0 },
-      { 0x000a, 0x0031, 0 }
-    },
-    { "",
-      { 0x0b95, 0x0bca, 0 },
-      { 0x000a, 0x0031, 0x0007, 0 }
-    },
-    { "",
-      { 0x0b95, 0x0bc6, 0x0bbe, 0 },
-      { 0x000a, 0x0031, 0x007, 0 }
-    },
-    { "",
-      { 0x0b95, 0x0bcd, 0x0bb7, 0 },
-      { 0x0049, 0 }
-    },
-    { "",
-      { 0x0b95, 0x0bcd, 0x0bb7, 0x0bca, 0 },
-      { 0x000a, 0x0049, 0x007, 0 }
-    },
-    { "",
-      { 0x0b95, 0x0bcd, 0x0bb7, 0x0bc6, 0x0bbe, 0 },
-      { 0x000a, 0x0049, 0x007, 0 }
-    },
-    { "",
-      { 0x0b9f, 0x0bbf, 0 },
-      { 0x005f, 0 }
-    },
-    { "",
-      { 0x0b9f, 0x0bc0, 0 },
-      { 0x0060, 0 }
-    },
-    { "",
-      { 0x0bb2, 0x0bc0, 0 },
-      { 0x00ab, 0 }
-    },
-    { "",
-      { 0x0bb2, 0x0bbf, 0 },
-      { 0x00aa, 0 }
-    },
-    { "",
-      { 0x0bb0, 0x0bcd, 0 },
-      { 0x00a4, 0 }
-    },
-    { "",
-      { 0x0bb0, 0x0bbf, 0 },
-      { 0x00a5, 0 }
-    },
-    { "",
-      { 0x0bb0, 0x0bc0, 0 },
-      { 0x00a6, 0 }
-    },
-    { "",
-      { 0x0b83, 0 },
-      { 0x0025, 0 }
-    },
-    { "",
-      { 0x0b83, 0x0b95, 0 },
-      { 0x0025, 0x0031, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_telugu = {
-  {"Pothana2000.ttf", 0},
-  {
-    { "",
-      { 0xc15, 0xc4d, 0 },
-      { 0xbb, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc37, 0 },
-      { 0x4b, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc37, 0xc4d, 0 },
-      { 0xe0, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc37, 0xc4d, 0xc23, 0 },
-      { 0x4b, 0x91, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc30, 0 },
-      { 0x5a, 0xb2, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc30, 0xc4d, 0 },
-      { 0xbb, 0xb2, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc30, 0xc4d, 0xc15, 0 },
-      { 0x5a, 0xb2, 0x83, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc30, 0xc3f, 0 },
-      { 0xe2, 0xb2, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc15, 0xc48, 0 },
-      { 0xe6, 0xb3, 0x83, 0 }
-    },
-    { "",
-      { 0xc15, 0xc4d, 0xc30, 0xc48, 0 },
-      { 0xe6, 0xb3, 0x9f, 0 }
-    },
-    { "",
-      { 0xc15, 0xc46, 0xc56, 0 },
-      { 0xe6, 0xb3, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_kannada1 = {
-  {"Sampige.ttf", 0},
-  {
-    { "",
-      { 0x0ca8, 0x0ccd, 0x0ca8, 0 },
-      { 0x0049, 0x00ba, 0 }
-    },
-    { "",
-      { 0x0ca8, 0x0ccd, 0x0ca1, 0 },
-      { 0x0049, 0x00b3, 0 }
-    },
-    { "",
-      { 0x0caf, 0x0cc2, 0 },
-      { 0x004f, 0x005d, 0 }
-    },
-    { "",
-      { 0x0ce0, 0 },
-      { 0x006a, 0 }
-    },
-    { "",
-      { 0x0ce6, 0x0ce7, 0x0ce8, 0 },
-      { 0x006b, 0x006c, 0x006d, 0 }
-    },
-    { "",
-      { 0x0cb5, 0x0ccb, 0 },
-      { 0x015f, 0x0067, 0 }
-    },
-    { "",
-      { 0x0cb0, 0x0ccd, 0x0cae, 0 },
-      { 0x004e, 0x0082, 0 }
-    },
-    { "",
-      { 0x0cb0, 0x0ccd, 0x0c95, 0 },
-      { 0x0036, 0x0082, 0 }
-    },
-    { "",
-      { 0x0c95, 0x0ccd, 0x0cb0, 0 },
-      { 0x0036, 0x00c1, 0 }
-    },
-    { "",
-      { 0x0cb0, 0x0ccd, 0x200d, 0x0c95, 0 },
-      { 0x0050, 0x00a7, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_kannada2 = {
-  {"tunga.ttf", 0},
-  {
-    { "",
-      { 0x0cb7, 0x0cc6, 0 },
-      { 0x00b0, 0x006c, 0 }
-    },
-    { "",
-      { 0x0cb7, 0x0ccd, 0 },
-      { 0x0163, 0 }
-    },
-    { "",
-      { 0xc95, 0xcbf, 0xcd5, 0 },
-      { 0x114, 0x73, 0 }
-    },
-    { "",
-      { 0xc95, 0xcc6, 0xcd5, 0 },
-      { 0x90, 0x6c, 0x73, 0 }
-    },
-    { "",
-      { 0xc95, 0xcc6, 0xcd6, 0 },
-      { 0x90, 0x6c, 0x74, 0 }
-    },
-    { "",
-      { 0xc95, 0xcc6, 0xcc2, 0 },
-      { 0x90, 0x6c, 0x69, 0 }
-    },
-    { "",
-      { 0xc95, 0xcca, 0xcd5, 0 },
-      { 0x90, 0x6c, 0x69, 0x73, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_malayalam1 = {
-  {"AkrutiMal2Normal.ttf", 0},
-  {
-    { "",
-      { 0x0d15, 0x0d46, 0 },
-      { 0x005e, 0x0034, 0 }
-    },
-    { "",
-      { 0x0d15, 0x0d47, 0 },
-      { 0x005f, 0x0034, 0 }
-    },
-    { "",
-      { 0x0d15, 0x0d4b, 0 },
-      { 0x005f, 0x0034, 0x0058, 0 }
-    },
-    { "",
-      { 0x0d15, 0x0d48, 0 },
-      { 0x0060, 0x0034, 0 }
-    },
-    { "",
-      { 0x0d15, 0x0d4a, 0 },
-      { 0x005e, 0x0034, 0x0058, 0 }
-    },
-    { "",
-      { 0x0d30, 0x0d4d, 0x0d15, 0 },
-      { 0x009e, 0x0034, 0 }
-    },
-    { "",
-      { 0x0d15, 0x0d4d, 0x0d35, 0 },
-      { 0x0034, 0x007a, 0 }
-    },
-    { "",
-      { 0x0d15, 0x0d4d, 0x0d2f, 0 },
-      { 0x0034, 0x00a2, 0 }
-    },
-    { "",
-      { 0x0d1f, 0x0d4d, 0x0d1f, 0 },
-      { 0x0069, 0 }
-    },
-    { "",
-      { 0x0d26, 0x0d4d, 0x0d26, 0 },
-      { 0x0074, 0 }
-    },
-    { "",
-      { 0x0d30, 0x0d4d, 0 },
-      { 0x009e, 0 }
-    },
-    { "",
-      { 0x0d30, 0x0d4d, 0x200c, 0 },
-      { 0x009e, 0 }
-    },
-    { "",
-      { 0x0d30, 0x0d4d, 0x200d, 0 },
-      { 0x009e, 0 }
-    },
-    { "",
-      { 0xd15, 0xd46, 0xd3e, 0 },
-      { 0x5e, 0x34, 0x58, 0 }
-    },
-    { "",
-      { 0xd15, 0xd47, 0xd3e, 0 },
-      { 0x5f, 0x34, 0x58, 0 }
-    },
-    { "",
-      { 0xd15, 0xd46, 0xd57, 0 },
-      { 0x5e, 0x34, 0x65, 0 }
-    },
-    { "",
-      { 0xd15, 0xd57, 0 },
-      { 0x34, 0x65, 0 }
-    },
-    { "",
-      { 0xd1f, 0xd4d, 0xd1f, 0xd41, 0xd4d, 0 },
-      { 0x69, 0x5b, 0x64, 0 }
-    },
-
-    {{0}}
-  }
-};
-
-static const test_set_t tests_malayalam2 = {
-  {"Rachana.ttf", 0},
-  {
-    { "",
-      { 0xd37, 0xd4d, 0xd1f, 0xd4d, 0xd30, 0xd40, 0 },
-      { 0x385, 0xa3, 0 }
-    },
-    { "",
-      { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0 },
-      { 0x2ff, 0 }
-    },
-    { "",
-      { 0xd33, 0xd4d, 0xd33, 0 },
-      { 0x3f8, 0 }
-    },
-    { "",
-      { 0xd2f, 0xd4d, 0xd15, 0xd4d, 0xd15, 0xd41, 0 },
-      { 0x2ff, 0 }
-    },
-    { "",
-      { 0xd30, 0xd4d, 0x200d, 0xd35, 0xd4d, 0xd35, 0 },
-      { 0xf3, 0x350, 0 }
-    },
-
-    {{0}}
-  }
-};
-
-static const test_set_t tests_sinhala = {
-  {"FM-MalithiUW46.ttf", 0},
-  {
-    { "",
-      { 0xd9a, 0xdd9, 0xdcf, 0 },
-      { 0x4a, 0x61, 0x42, 0 }
-    },
-    { "",
-      { 0xd9a, 0xdd9, 0xddf, 0 },
-      { 0x4a, 0x61, 0x50, 0 }
-    },
-    { "",
-      { 0xd9a, 0xdd9, 0xdca, 0 },
-      { 0x4a, 0x62, 0 }
-    },
-    { "",
-      { 0xd9a, 0xddc, 0xdca, 0 },
-      { 0x4a, 0x61, 0x42, 0x41, 0 }
-    },
-    { "",
-      { 0xd9a, 0xdda, 0 },
-      { 0x4a, 0x62, 0 }
-    },
-    { "",
-      { 0xd9a, 0xddd, 0 },
-      { 0x4a, 0x61, 0x42, 0x41, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_khmer = {
-  {"KhmerOS.ttf", 0},
-  {
-    { "",
-      { 0x179a, 0x17cd, 0 },
-      { 0x24c, 0x27f, 0 }
-    },
-    { "",
-      { 0x179f, 0x17c5, 0 },
-      { 0x273, 0x203, 0 }
-    },
-    { "",
-      { 0x1790, 0x17d2, 0x1784, 0x17c3, 0 },
-      { 0x275, 0x242, 0x182, 0 }
-    },
-    { "",
-      { 0x179a, 0 },
-      { 0x24c, 0 }
-    },
-    { "",
-      { 0x1781, 0x17d2, 0x1798, 0x17c2, 0 },
-      { 0x274, 0x233, 0x197, 0 }
-    },
-    { "",
-      { 0x1798, 0x17b6, 0 },
-      { 0x1cb, 0 }
-    },
-    { "",
-      { 0x179a, 0x17b8, 0 },
-      { 0x24c, 0x26a, 0 }
-    },
-    { "",
-      { 0x1787, 0x17b6, 0 },
-      { 0x1ba, 0 }
-    },
-    { "",
-      { 0x1798, 0x17d2, 0x1796, 0x17bb, 0 },
-      { 0x24a, 0x195, 0x26d, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_nko = {
-  {"DejaVuSans.ttf", 0},
-  {
-    { "",
-      { 0x7ca, 0 },
-      { 0x5c1, 0 }
-    },
-    { "",
-      { 0x7ca, 0x7ca, 0 },
-      { 0x14d9, 0x14db, 0 }
-    },
-    { "",
-      { 0x7ca, 0x7fa, 0x7ca, 0 },
-      { 0x14d9, 0x5ec, 0x14db, 0 }
-    },
-    { "",
-      { 0x7ca, 0x7f3, 0x7ca, 0 },
-      { 0x14d9, 0x5e7, 0x14db, 0 }
-    },
-    { "",
-      { 0x7ca, 0x7f3, 0x7fa, 0x7ca, 0 },
-      { 0x14d9, 0x5ec, 0x5e7, 0x14db, 0 }
-    },
-    {{0}}
-  }
-};
-
-static const test_set_t tests_linearb = {
-  {"penuture.ttf", 0},
-  {
-    { "",
-      { 0xd800, 0xdc01, 0xd800, 0xdc02, 0xd800, 0xdc03,  0 },
-      { 0x5, 0x6, 0x7, 0 },
-    },
-    {{0}}
-  }
-};
-
-
-
-
-
-typedef struct {
-  FT_Library ft_library;
-  FT_Face ft_face;
-  hb_font_t *font;
-} ft_fixture_t;
-
-static void
-ft_fixture_init (ft_fixture_t *f, gconstpointer user_data)
-{
-  const test_t *test = user_data;
-  char *font_file = get_font_file (test->font_data);
-  FT_Error err;
-
-  FT_Init_FreeType (&f->ft_library);
-
-  err = FT_New_Face (f->ft_library, font_file, test->font_data->face_index, &f->ft_face);
-  g_assert_cmpint (err, ==, 0);
-
-  f->font = hb_ft_font_create (f->ft_face, NULL);
-
-  g_free (font_file);
-}
-
-static void
-ft_fixture_finish (ft_fixture_t *f, gconstpointer user_data)
-{
-  hb_font_destroy (f->font);
-
-  FT_Done_Face (f->ft_face);
-  FT_Done_FreeType (f->ft_library);
-}
-
-static void
-test_shape_complex (ft_fixture_t *f, gconstpointer user_data)
-{
-  const test_t *test = user_data;
-  const test_data_t *data = test->test_data;
-  hb_buffer_t *buffer;
-  unsigned int i, len, expected_len;
-  hb_glyph_info_t *glyphs;
-  hb_bool_t fail;
-  GString *str;
-
-  g_assert (f->font);
-
-  if (data->comments[0])
-    g_test_message ("Test comments: %s", data->comments);
-
-  buffer =  hb_buffer_create (0);
-  for (len = 0; data->characters[len]; len++) ;
-  hb_buffer_add_utf32 (buffer, data->characters, len, 0, len);
-
-  hb_shape (f->font, buffer, NULL, 0);
-
-  for (len = 0; data->glyphs[len]; len++) ;
-  expected_len = len;
-
-  glyphs = hb_buffer_get_glyph_infos (buffer, &len);
-  fail = len != expected_len;
-  if (!fail)
-    for (i = 0; i < len; i++)
-      if (glyphs[i].codepoint != data->glyphs[i]) {
-        fail = TRUE;
-       break;
-      }
-
-  str = g_string_new ("");
-  for (i = 0; i < len; i++)
-    g_string_append_printf (str, " %4d", glyphs[i].codepoint);
-  g_test_message ("Received glyphs: %s", str->str);
-  g_string_truncate (str, 0);
-  for (i = 0; i < expected_len; i++)
-    g_string_append_printf (str, " %4d", data->glyphs[i]);
-  g_test_message ("Expected glyphs: %s", str->str);
-  g_string_free (str, TRUE);
-
-  if (fail) {
-    g_test_message ("FAIL");
-    /* The glib test framework is useless, lets not fail for now,
-     * we can grep for FAIL/PASS and count manually.  Sigh... */
-    /*g_test_fail ();*/
-  } else
-    g_test_message ("PASS");
-
-  hb_buffer_destroy (buffer);
-}
-
-static void
-test_shape_complex_skipped (gconstpointer user_data)
-{
-  const test_t *test = user_data;
-  const test_data_t *data = test->test_data;
-
-  if (data->comments[0])
-    g_test_message ("Test comments: %s", data->comments);
-
-  g_test_message ("Skipping test");
-}
-
-
-static void
-add_test_set (const test_set_t *test_set, const char *set_name)
-{
-  const test_data_t *data;
-  char *font_file;
-  hb_bool_t skip;
-
-  font_file = get_font_file (&test_set->font_data);
-  skip = !g_file_test (font_file, G_FILE_TEST_EXISTS);
-  g_free (font_file);
-
-  for (data = test_set->test_datas; data->characters[0]; data++) {
-    char *flavor;
-    GString *str;
-    const hb_codepoint_t *p;
-
-    test_t *test = g_slice_new0 (test_t);
-    test->font_data = &test_set->font_data;
-    test->test_data = data;
-
-    str = g_string_new ("<");
-    for (p = data->characters; *p; p++)
-      g_string_append_printf (str, "%04X,", *p);
-    str->str[str->len - 1] = '>';
-
-    flavor = g_strdup_printf ("%s/%s/%ld:%s", set_name, test_set->font_data.font_file, data - test_set->test_datas, str->str);
-
-    g_string_free (str, TRUE);
-
-    if (skip)
-      hb_test_add_data_flavor ((const void *) test, flavor, test_shape_complex_skipped);
-    else
-      hb_test_add_fixture_flavor (ft_fixture, (const void *) test, flavor, test_shape_complex);
-
-    g_free (flavor);
-  }
-}
-
-
-int
-main (int argc, char **argv)
-{
-  hb_test_init (&argc, &argv);
-
-#define TEST_SET(name) add_test_set (&tests_##name, #name)
-
-  TEST_SET (devanagari1);
-  TEST_SET (devanagari2);
-  TEST_SET (bengali1);
-  TEST_SET (bengali2);
-  TEST_SET (bengali3);
-  TEST_SET (gurmukhi);
-  TEST_SET (oriya);
-  TEST_SET (tamil);
-  TEST_SET (telugu);
-  TEST_SET (kannada1);
-  TEST_SET (kannada2);
-  TEST_SET (malayalam1);
-  TEST_SET (malayalam2);
-  TEST_SET (sinhala);
-
-  TEST_SET (khmer);
-
-  TEST_SET (nko);
-  TEST_SET (linearb);
-
-  return hb_test_run();
-}
index a420bf3..88f12e7 100644 (file)
@@ -351,7 +351,7 @@ static const test_pair_t script_tests[] =
   {   0x07B1, HB_SCRIPT_THAANA },
   {   0x0E31, HB_SCRIPT_THAI },
   {   0x0FD4, HB_SCRIPT_TIBETAN },
-  {   0x1401, HB_SCRIPT_CANADIAN_ABORIGINAL },
+  {   0x1401, HB_SCRIPT_CANADIAN_SYLLABICS },
   {   0xA015, HB_SCRIPT_YI },
   {   0x1700, HB_SCRIPT_TAGALOG },
   {   0x1720, HB_SCRIPT_HANUNOO },
@@ -786,6 +786,7 @@ test_unicode_normalization (gconstpointer user_data)
 {
   hb_unicode_funcs_t *uf = (hb_unicode_funcs_t *) user_data;
   gunichar a, b, ab;
+  hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
 
 
   /* Test compose() */
@@ -849,6 +850,55 @@ test_unicode_normalization (gconstpointer user_data)
   g_assert (hb_unicode_decompose (uf, 0xCE31, &a, &b) && a == 0xCE20 && b == 0x11B8);
   g_assert (hb_unicode_decompose (uf, 0xCE20, &a, &b) && a == 0x110E && b == 0x1173);
 
+
+  /* Test decompose_compatibility() */
+
+  /* Not decomposable */
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x0041, decomposed) == 0);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x1F632, decomposed) == 0);
+
+  /* Singletons */
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x00B5, decomposed) == 1 && decomposed[0] == 0x03BC);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x03D6, decomposed) == 1 && decomposed[0] == 0x03C0);
+
+  /* Arabic compatibility */
+  g_assert (hb_unicode_decompose_compatibility (uf, 0xFB54, decomposed) == 1 && decomposed[0] == 0x067B);
+
+  /* Longest decomposition ever */
+  g_assert (18 <= HB_UNICODE_MAX_DECOMPOSITION_LEN);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0xFDFA, decomposed) == 18 && decomposed[17] == 0x0645);
+
+  /* Note: we deliberately don't test characters that have canonical decompositions but no
+   * compatibility decomposition against the decompose_compatibility() function as that we
+   * leave up to implementations (for now). */
+
+  /* Spaces */
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2002, decomposed) == 1 && decomposed[0] == 0x0020);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2003, decomposed) == 1 && decomposed[0] == 0x0020);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2004, decomposed) == 1 && decomposed[0] == 0x0020);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2005, decomposed) == 1 && decomposed[0] == 0x0020);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2006, decomposed) == 1 && decomposed[0] == 0x0020);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2008, decomposed) == 1 && decomposed[0] == 0x0020);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2009, decomposed) == 1 && decomposed[0] == 0x0020);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x200A, decomposed) == 1 && decomposed[0] == 0x0020);
+
+  /* Pairs */
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x0587, decomposed) == 2 &&
+            decomposed[0] == 0x0565 && decomposed[1] == 0x0582);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2017, decomposed) == 2 &&
+            decomposed[0] == 0x0020 && decomposed[1] == 0x0333);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2025, decomposed) == 2 &&
+            decomposed[0] == 0x002E && decomposed[1] == 0x002E);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2033, decomposed) == 2 &&
+            decomposed[0] == 0x2032 && decomposed[1] == 0x2032);
+
+  /* Triples */
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2026, decomposed) == 3 &&
+            decomposed[0] == 0x002E && decomposed[1] == 0x002E && decomposed[2] == 0x002E);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x2034, decomposed) == 3 &&
+            decomposed[0] == 0x2032 && decomposed[1] == 0x2032 && decomposed[2] == 0x2032);
+  g_assert (hb_unicode_decompose_compatibility (uf, 0x213B, decomposed) == 3 &&
+            decomposed[0] == 0x0046 && decomposed[1] == 0x0041 && decomposed[2] == 0x0058);
 }
 
 
index 4c9bd37..e6378b6 100644 (file)
@@ -46,27 +46,28 @@ test_version (void)
   g_free (s);
   g_assert (0 == strcmp (HB_VERSION_STRING, hb_version_string ()));
 
-  g_assert (HB_VERSION_CHECK (major, minor, micro));
-  g_assert (HB_VERSION_CHECK (major+1, minor, micro));
-  g_assert (HB_VERSION_CHECK (major, minor+1, micro));
-  g_assert (HB_VERSION_CHECK (major, minor, micro+1));
+  g_assert (HB_VERSION_ATLEAST (major, minor, micro));
   if (major)
-    g_assert (!HB_VERSION_CHECK (major-1, minor, micro));
+    g_assert (HB_VERSION_ATLEAST (major-1, minor, micro));
   if (minor)
-    g_assert (!HB_VERSION_CHECK (major, minor-1, micro));
+    g_assert (HB_VERSION_ATLEAST (major, minor-1, micro));
   if (micro)
-    g_assert (!HB_VERSION_CHECK (major, minor, micro-1));
+    g_assert (HB_VERSION_ATLEAST (major, minor, micro-1));
+  g_assert (!HB_VERSION_ATLEAST (major+1, minor, micro));
+  g_assert (!HB_VERSION_ATLEAST (major, minor+1, micro));
+  g_assert (!HB_VERSION_ATLEAST (major, minor, micro+1));
+  g_assert (!HB_VERSION_ATLEAST (major, minor, micro+1));
 
-  g_assert (hb_version_check (major, minor, micro));
-  g_assert (hb_version_check (major+1, minor, micro));
-  g_assert (hb_version_check (major, minor+1, micro));
-  g_assert (hb_version_check (major, minor, micro+1));
+  g_assert (hb_version_atleast (major, minor, micro));
   if (major)
-    g_assert (!hb_version_check (major-1, minor, micro));
+    g_assert (hb_version_atleast (major-1, minor, micro));
   if (minor)
-    g_assert (!hb_version_check (major, minor-1, micro));
+    g_assert (hb_version_atleast (major, minor-1, micro));
   if (micro)
-    g_assert (!hb_version_check (major, minor, micro-1));
+    g_assert (hb_version_atleast (major, minor, micro-1));
+  g_assert (!hb_version_atleast (major+1, minor, micro));
+  g_assert (!hb_version_atleast (major, minor+1, micro));
+  g_assert (!hb_version_atleast (major, minor, micro+1));
 }
 
 int
index 4fb762c..70bcdd5 100644 (file)
@@ -7,7 +7,7 @@ DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
 manifests:
-       @$(srcdir)/hb-manifest-update "$(srcdir)/texts" "$(srcdir)/fonts"
+       @$(srcdir)/hb-manifest-update "$(srcdir)/texts" "$(srcdir)/fonts" "$(srcdir)/tests"
 
 EXTRA_DIST += \
        hb-diff \
@@ -20,6 +20,11 @@ EXTRA_DIST += \
        hb-unicode-decode \
        hb-unicode-encode \
        hb-unicode-prettyname \
+       record-test.sh \
+       run-tests.sh \
+       texts/in-tree \
+       fonts/sha1sum \
+       $(TESTS) \
        $(NULL)
 
 # TODO Figure out Python stuff
@@ -30,6 +35,40 @@ CLEANFILES += \
        hb_test_tools.py[co] \
        $(NULL)
 
+TESTS = \
+       tests/arabic-fallback-shaping.tests \
+       tests/arabic-feature-order.tests \
+       tests/context-matching.tests \
+       tests/hangul-jamo.tests \
+       tests/indic-joiner-candrabindu.tests \
+       tests/indic-old-spec.tests \
+       tests/indic-pref-blocking.tests \
+       tests/mongolian-variation-selector.tests \
+       tests/zero-width-marks.tests \
+       $(NULL)
+
+TEST_EXTENSIONS = \
+       .tests \
+       $(NULL)
+
+AM_TESTS_ENVIRONMENT = \
+       EXEEXT="$(EXEEXT)"; \
+       export EXEEXT; \
+       srcdir="$(srcdir)"; \
+       export srcdir; \
+       builddir="$(builddir)"; \
+       export builddir; \
+       $(NULL)
+
+if AUTOMAKE_OLDER_THAN_1_13
+TESTS_ENVIRONMENT = \
+       $(AM_TESTS_ENVIRONMENT) \
+       $(TESTS_LOG_COMPILER) \
+       $(NULL)
+endif
+
+TESTS_LOG_COMPILER = sh $(srcdir)/run-tests.sh
+
 .PHONY: manifests
 
 -include $(top_srcdir)/git.mk
diff --git a/test/shaping/fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf b/test/shaping/fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf
new file mode 100644 (file)
index 0000000..70c0c0a
Binary files /dev/null and b/test/shaping/fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf differ
diff --git a/test/shaping/fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf b/test/shaping/fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf
new file mode 100644 (file)
index 0000000..fc22649
Binary files /dev/null and b/test/shaping/fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf differ
diff --git a/test/shaping/fonts/sha1sum/37033cc5cf37bb223d7355153016b6ccece93b28.ttf b/test/shaping/fonts/sha1sum/37033cc5cf37bb223d7355153016b6ccece93b28.ttf
new file mode 100644 (file)
index 0000000..14defeb
Binary files /dev/null and b/test/shaping/fonts/sha1sum/37033cc5cf37bb223d7355153016b6ccece93b28.ttf differ
diff --git a/test/shaping/fonts/sha1sum/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf b/test/shaping/fonts/sha1sum/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
new file mode 100644 (file)
index 0000000..dfaead7
Binary files /dev/null and b/test/shaping/fonts/sha1sum/4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf differ
diff --git a/test/shaping/fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf b/test/shaping/fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf
new file mode 100644 (file)
index 0000000..8fb2f16
Binary files /dev/null and b/test/shaping/fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf differ
diff --git a/test/shaping/fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf b/test/shaping/fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
new file mode 100644 (file)
index 0000000..746fc60
Binary files /dev/null and b/test/shaping/fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf differ
diff --git a/test/shaping/fonts/sha1sum/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf b/test/shaping/fonts/sha1sum/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf
new file mode 100644 (file)
index 0000000..bbe2237
Binary files /dev/null and b/test/shaping/fonts/sha1sum/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf differ
diff --git a/test/shaping/fonts/sha1sum/7e14e7883ed152baa158b80e207b66114c823a8b.ttf b/test/shaping/fonts/sha1sum/7e14e7883ed152baa158b80e207b66114c823a8b.ttf
new file mode 100644 (file)
index 0000000..27efd7c
Binary files /dev/null and b/test/shaping/fonts/sha1sum/7e14e7883ed152baa158b80e207b66114c823a8b.ttf differ
diff --git a/test/shaping/fonts/sha1sum/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf b/test/shaping/fonts/sha1sum/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf
new file mode 100644 (file)
index 0000000..b728b27
Binary files /dev/null and b/test/shaping/fonts/sha1sum/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf differ
diff --git a/test/shaping/fonts/sha1sum/8454d22037f892e76614e1645d066689a0200e61.ttf b/test/shaping/fonts/sha1sum/8454d22037f892e76614e1645d066689a0200e61.ttf
new file mode 100644 (file)
index 0000000..2cbb67a
Binary files /dev/null and b/test/shaping/fonts/sha1sum/8454d22037f892e76614e1645d066689a0200e61.ttf differ
diff --git a/test/shaping/fonts/sha1sum/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf b/test/shaping/fonts/sha1sum/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf
new file mode 100644 (file)
index 0000000..875c699
Binary files /dev/null and b/test/shaping/fonts/sha1sum/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf differ
diff --git a/test/shaping/fonts/sha1sum/MANIFEST b/test/shaping/fonts/sha1sum/MANIFEST
new file mode 100644 (file)
index 0000000..924732d
--- /dev/null
@@ -0,0 +1,19 @@
+226bc2deab3846f1a682085f70c67d0421014144.ttf
+270b89df543a7e48e206a2d830c0e10e5265c630.ttf
+37033cc5cf37bb223d7355153016b6ccece93b28.ttf
+4cce528e99f600ed9c25a2b69e32eb94a03b4ae8.ttf
+5028afb650b1bb718ed2131e872fbcce57828fff.ttf
+57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf
+757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf
+7e14e7883ed152baa158b80e207b66114c823a8b.ttf
+813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf
+8454d22037f892e76614e1645d066689a0200e61.ttf
+8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf
+a919b33197965846f21074b24e30250d67277bce.ttf
+bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf
+bb9473d2403488714043bcfb946c9f78b86ad627.ttf
+d629e7fedc0b350222d7987345fe61613fa3929a.ttf
+df768b9c257e0c9c35786c47cae15c46571d56be.ttf
+e207635780b42f898d58654b65098763e340f5c7.ttf
+ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf
+f499fbc23865022234775c43503bba2e63978fe1.ttf
diff --git a/test/shaping/fonts/sha1sum/a919b33197965846f21074b24e30250d67277bce.ttf b/test/shaping/fonts/sha1sum/a919b33197965846f21074b24e30250d67277bce.ttf
new file mode 100644 (file)
index 0000000..d2f116e
Binary files /dev/null and b/test/shaping/fonts/sha1sum/a919b33197965846f21074b24e30250d67277bce.ttf differ
diff --git a/test/shaping/fonts/sha1sum/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf b/test/shaping/fonts/sha1sum/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf
new file mode 100644 (file)
index 0000000..fba200f
Binary files /dev/null and b/test/shaping/fonts/sha1sum/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf differ
diff --git a/test/shaping/fonts/sha1sum/bb9473d2403488714043bcfb946c9f78b86ad627.ttf b/test/shaping/fonts/sha1sum/bb9473d2403488714043bcfb946c9f78b86ad627.ttf
new file mode 100644 (file)
index 0000000..b16dae6
Binary files /dev/null and b/test/shaping/fonts/sha1sum/bb9473d2403488714043bcfb946c9f78b86ad627.ttf differ
diff --git a/test/shaping/fonts/sha1sum/d629e7fedc0b350222d7987345fe61613fa3929a.ttf b/test/shaping/fonts/sha1sum/d629e7fedc0b350222d7987345fe61613fa3929a.ttf
new file mode 100644 (file)
index 0000000..e674a78
Binary files /dev/null and b/test/shaping/fonts/sha1sum/d629e7fedc0b350222d7987345fe61613fa3929a.ttf differ
diff --git a/test/shaping/fonts/sha1sum/df768b9c257e0c9c35786c47cae15c46571d56be.ttf b/test/shaping/fonts/sha1sum/df768b9c257e0c9c35786c47cae15c46571d56be.ttf
new file mode 100644 (file)
index 0000000..c6d8b18
Binary files /dev/null and b/test/shaping/fonts/sha1sum/df768b9c257e0c9c35786c47cae15c46571d56be.ttf differ
diff --git a/test/shaping/fonts/sha1sum/e207635780b42f898d58654b65098763e340f5c7.ttf b/test/shaping/fonts/sha1sum/e207635780b42f898d58654b65098763e340f5c7.ttf
new file mode 100644 (file)
index 0000000..d91df57
Binary files /dev/null and b/test/shaping/fonts/sha1sum/e207635780b42f898d58654b65098763e340f5c7.ttf differ
diff --git a/test/shaping/fonts/sha1sum/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf b/test/shaping/fonts/sha1sum/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf
new file mode 100644 (file)
index 0000000..629c470
Binary files /dev/null and b/test/shaping/fonts/sha1sum/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf differ
diff --git a/test/shaping/fonts/sha1sum/f499fbc23865022234775c43503bba2e63978fe1.ttf b/test/shaping/fonts/sha1sum/f499fbc23865022234775c43503bba2e63978fe1.ttf
new file mode 100644 (file)
index 0000000..3c60593
Binary files /dev/null and b/test/shaping/fonts/sha1sum/f499fbc23865022234775c43503bba2e63978fe1.ttf differ
index 47fa6eb..a370e5e 100644 (file)
@@ -293,6 +293,14 @@ class DiffHelpers:
 
        @staticmethod
        def test_passed (lines):
+               lines = list (lines)
+               # XXX This is a hack, but does the job for now.
+               if any (l.find("space+0|space+0") >= 0 for l in lines if l[0] == '+'): return True
+               if any (l.find("uni25CC") >= 0 for l in lines if l[0] == '+'): return True
+               if any (l.find("dottedcircle") >= 0 for l in lines if l[0] == '+'): return True
+               if any (l.find("glyph0") >= 0 for l in lines if l[0] == '+'): return True
+               if any (l.find("gid0") >= 0 for l in lines if l[0] == '+'): return True
+               if any (l.find("notdef") >= 0 for l in lines if l[0] == '+'): return True
                return all (l[0] == ' ' for l in lines)
 
 
@@ -397,13 +405,13 @@ class Unicode:
 
        @staticmethod
        def decode (s):
-               return '<' + u','.join ("U+%04X" % ord (u) for u in unicode (s, 'utf-8')).encode ('utf-8') + '>'
+               return u','.join ("U+%04X" % ord (u) for u in unicode (s, 'utf-8')).encode ('utf-8')
 
        @staticmethod
        def parse (s):
-               s = re.sub (r"[<+>,\\uU\n       ]", " ", s)
                s = re.sub (r"0[xX]", " ", s)
-               return [int (x, 16) for x in s.split (' ') if len (x)]
+               s = re.sub (r"[<+>,;&#\\xXuU\n  ]", " ", s)
+               return [int (x, 16) for x in s.split ()]
 
        @staticmethod
        def encode (s):
diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh
new file mode 100755 (executable)
index 0000000..a69157f
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+dir=`mktemp --directory`
+
+hb_shape=$1
+shift
+fontfile=$1
+shift
+hb_shape="$hb_shape $@"
+unicodes=`./hb-unicode-decode`
+text=`./hb-unicode-encode "$unicodes"`
+glyphs=`echo "$text" | $hb_shape "$fontfile"`
+
+cp "$fontfile" "$dir/font.ttf"
+pyftsubset \
+       --glyph-names \
+       "$dir/font.ttf" \
+       --text="$text"
+if ! test -s "$dir/font.ttf.subset"; then
+       echo "Subsetter didn't produce nonempty subset font in $dir/font.ttf.subset" >&2
+       exit 2
+fi
+
+# Verify that subset font produces same glyphs!
+glyphs_subset=`echo "$text" | $hb_shape "$dir/font.ttf.subset"`
+
+if ! test "x$glyphs" = "x$glyphs_subset"; then
+       echo "Subset font produced different glyphs!" >&2
+       echo "Perhaps font doesn't have glyph names; checking visually..." >&2
+       hb_view=${hb_shape/shape/view}
+       echo "$text" | $hb_view "$dir/font.ttf" --output-format=png --output-file="$dir/orig.png"
+       echo "$text" | $hb_view "$dir/font.ttf.subset" --output-format=png --output-file="$dir/subset.png"
+       if ! cmp "$dir/orig.png" "$dir/subset.png"; then
+               echo "Images differ.  Please inspect $dir/*.png." >&2
+               echo "$glyphs"
+               echo "$glyphs_subset"
+               exit 2
+       fi
+       echo "Yep; all good." >&2
+       rm -f "$dir/orig.png"
+       rm -f "$dir/subset.png"
+       glyphs=$glyphs_subset
+fi
+
+sha1sum=`sha1sum "$dir/font.ttf.subset" | cut -d' ' -f1`
+subset="fonts/sha1sum/$sha1sum.ttf"
+mv "$dir/font.ttf.subset" "$subset"
+
+echo "$subset:$unicodes:$glyphs"
+
+rm -f "$dir/font.ttf"
+rmdir "$dir"
diff --git a/test/shaping/run-tests.sh b/test/shaping/run-tests.sh
new file mode 100755 (executable)
index 0000000..a2cdf32
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+test "x$srcdir" = x && srcdir=.
+test "x$builddir" = x && builddir=.
+test "x$top_builddir" = x && top_builddir=../..
+
+hb_shape=$top_builddir/util/hb-shape$EXEEXT
+
+fails=0
+
+if test $# = 0; then
+       set /dev/stdin
+fi
+
+IFS=:
+for f in "$@"; do
+       echo "Running tests in $f"
+       while read fontfile unicodes glyphs_expected; do
+               echo "Testing $fontfile:$unicodes"
+               glyphs=`$srcdir/hb-unicode-encode "$unicodes" | $hb_shape "$srcdir/$fontfile"`
+               if ! test "x$glyphs" = "x$glyphs_expected"; then
+                       echo "Actual:   $glyphs" >&2
+                       echo "Expected: $glyphs_expected" >&2
+                       fails=$((fails+1))
+               fi
+       done < "$f"
+done
+
+if test $fails != 0; then
+       echo "$fails tests failed."
+       exit 1
+else
+       echo "All tests passed."
+fi
diff --git a/test/shaping/tests/MANIFEST b/test/shaping/tests/MANIFEST
new file mode 100644 (file)
index 0000000..849ebc5
--- /dev/null
@@ -0,0 +1,9 @@
+arabic-fallback-shaping.tests
+arabic-feature-order.tests
+context-matching.tests
+hangul-jamo.tests
+indic-joiner-candrabindu.tests
+indic-old-spec.tests
+indic-pref-blocking.tests
+mongolian-variation-selector.tests
+zero-width-marks.tests
diff --git a/test/shaping/tests/arabic-fallback-shaping.tests b/test/shaping/tests/arabic-fallback-shaping.tests
new file mode 100644 (file)
index 0000000..e3eaf3f
--- /dev/null
@@ -0,0 +1 @@
+fonts/sha1sum/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@221,0+0|uni0651=2@260,736+0|uni064E=2@935,1259+0|uni0651=2@974,736+0|uni06440627.fina=2+1470|uni064F=0@558,-10+0|uni0633.init=0+1585]
diff --git a/test/shaping/tests/arabic-feature-order.tests b/test/shaping/tests/arabic-feature-order.tests
new file mode 100644 (file)
index 0000000..3e3cf6a
--- /dev/null
@@ -0,0 +1,3 @@
+fonts/sha1sum/813c2f8e5512187fd982417a7fb4286728e6f4a8.ttf:U+1820,U+180B:[uni2048.E81A=0+1550]
+fonts/sha1sum/8a9fea2a7384f2116e5b84a9b31f83be7850ce21.ttf:U+1820,U+180B:[uni2048.E81A=0+1550]
+fonts/sha1sum/a919b33197965846f21074b24e30250d67277bce.ttf:U+0644,U+0644,U+0647:[Lellah=0+1503]
diff --git a/test/shaping/tests/context-matching.tests b/test/shaping/tests/context-matching.tests
new file mode 100644 (file)
index 0000000..4c7d25f
--- /dev/null
@@ -0,0 +1,3 @@
+fonts/sha1sum/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+1212|uni1A25=3+1912|uni1A58=3+0|uni1A63=3+1212]
+fonts/sha1sum/d629e7fedc0b350222d7987345fe61613fa3929a.ttf:U+0915,U+093F,U+0915,U+093F:[ivowelsign03deva=0+530|kadeva=0+1561|ivowelsign03deva=2+530|kadeva=2+1561]
+fonts/sha1sum/f499fbc23865022234775c43503bba2e63978fe1.ttf:U+09B0,U+09CD,U+09A5,U+09CD,U+09AF,U+09C0:[gid1=0+1320|gid13=0+523|gid18=0+545]
diff --git a/test/shaping/tests/hangul-jamo.tests b/test/shaping/tests/hangul-jamo.tests
new file mode 100644 (file)
index 0000000..667a1cc
--- /dev/null
@@ -0,0 +1,2 @@
+fonts/sha1sum/757ebd573617a24aa9dfbf0b885c54875c6fe06b.ttf:U+115F,U+11A2:[gid3=0+920|gid4=0+0]
+fonts/sha1sum/7e14e7883ed152baa158b80e207b66114c823a8b.ttf:U+11A2:[gid1=0+920]
diff --git a/test/shaping/tests/indic-joiner-candrabindu.tests b/test/shaping/tests/indic-joiner-candrabindu.tests
new file mode 100644 (file)
index 0000000..351e927
--- /dev/null
@@ -0,0 +1,2 @@
+fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf:U+0B13,U+200D,U+0B01:[omorya=0+1450]
+fonts/sha1sum/5028afb650b1bb718ed2131e872fbcce57828fff.ttf:U+0B13,U+200C,U+0B01:[oorya=0+1309|space=1+0|candrabinduorya=1+0]
diff --git a/test/shaping/tests/indic-old-spec.tests b/test/shaping/tests/indic-old-spec.tests
new file mode 100644 (file)
index 0000000..96e8cdd
--- /dev/null
@@ -0,0 +1,2 @@
+fonts/sha1sum/57a9d9f83020155cbb1d2be1f43d82388cbecc88.ttf:U+0C9A,U+0CCD,U+0C9A,U+0CCD:[U0C9A_U0CCD.haln=0+1066|U0C9A_0CCD.blwf=0+0]
+fonts/sha1sum/270b89df543a7e48e206a2d830c0e10e5265c630.ttf:U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D:[glyph201=0+1183|U0D4D=0+0]
diff --git a/test/shaping/tests/indic-pref-blocking.tests b/test/shaping/tests/indic-pref-blocking.tests
new file mode 100644 (file)
index 0000000..260980a
--- /dev/null
@@ -0,0 +1,2 @@
+fonts/sha1sum/226bc2deab3846f1a682085f70c67d0421014144.ttf:U+0D2F,U+0D4D,U+0D30,U+0D46:[evowelsignmlym=0+1465|rapostmlym=0+499|yamlym=0+2120]
+fonts/sha1sum/e207635780b42f898d58654b65098763e340f5c7.ttf:U+0D2F,U+0D4D,U+0D30,U+0D46:[yamlym=0+2120|viramamlym=0+0|evowelsignmlym=0+1465|ramlym=0+1507]
diff --git a/test/shaping/tests/mongolian-variation-selector.tests b/test/shaping/tests/mongolian-variation-selector.tests
new file mode 100644 (file)
index 0000000..6b7e94a
--- /dev/null
@@ -0,0 +1,3 @@
+fonts/sha1sum/37033cc5cf37bb223d7355153016b6ccece93b28.ttf:U+1826,U+180B,U+1826:[uni1826.E85E_ue.init1=0+599|uni1826.E856_ue.fina=2+750]
+fonts/sha1sum/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf:U+1820,U+180B:[uni1820.E821_a.isol1=0+1199]
+fonts/sha1sum/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf:U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837,U+0020,U+182D,U+182D,U+180B,U+0020,U+182D,U+180C,U+0020,U+182D,U+180D,U+200D,U+0020,U+182D,U+200D,U+182D,U+180B,U+200D,U+0020,U+182D,U+180C,U+200D,U+0020,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D,U+0020,U+200D,U+182D,U+180C,U+200D,U+0020,U+200D,U+182D,U+180D,U+200D,U+0020,U+200D,U+182D,U+200D,U+182D,U+180B,U+0020,U+200D,U+182D,U+180C,U+0020,U+1820,U+200C,U+182D,U+1820,U+1837,U+0020,U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D,U+0020,U+200D,U+182D,U+1824,U+182F,U+1822,U+0020,U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni183A1823.E971_ko.init=0+950|uni182E.E904_m.medi=2+400|uni182B1822.E8A6_pi.medi=3+1150|uni1826.E854_ue.medi1=5+1100|uni1832.E916_t.medi1=7+1000|uni1827.E85C_ee.medi=9+750|uni1837.E931_r.fina=10+750|space=11+500|uni182D.E8E2_g.init=12+1000|uni182D.E8E8_g.fina1=13+1250|space=15+500|uni182D.EA1B_g.isol2=16+1000|space=18+500|uni182D.EA1E_g.init3=19+650|space=21+0|space=22+500|uni182D.E8E2_g.init=23+1000|space=24+0|uni182D.E8E5_g.medi1=25+800|space=27+0|space=28+500|uni182D.EA1D_g.init2=29+950|space=31+0|space=32+500|uni182D.EA1E_g.init3=33+650|space=35+0|space=36+500|space=37+0|uni182D.E8E4_g.medi=38+800|space=39+0|space=40+0|uni182D.E8E5_g.medi1=41+800|space=43+0|space=44+500|space=45+0|uni182D.E8E6_g.medi2=46+650|space=48+0|space=49+500|space=50+0|uni182D.E8E6_g.medi2=51+650|space=53+0|space=54+500|space=55+0|uni182D.E8E4_g.medi=56+800|space=57+0|uni182D.E8E8_g.fina1=58+1250|space=60+500|space=61+0|uni182D.E8E9_g.fina2=62+1050|space=64+500|uni1820.E820_a.isol=65+1550|space=66+0|uni182D.E8E2_g.init=67+1000|uni1820.E823_a.medi=68+400|uni1837.E931_r.fina=69+750|space=70+500|uni1830.E90B_s.init=71+850|uni1824.E844_u.medi=72+600|uni1837.E930_r.medi=73+600|space=74+0|space=75+0|uni182D.E8E5_g.medi1=76+800|uni1820.E823_a.medi=77+400|space=78+0|space=79+500|space=80+0|uni182D.E8E5_g.medi1=81+800|uni1824.E844_u.medi=82+600|uni182F.E908_l.medi=83+400|uni1822.E837_i.fina=84+600|space=85+500|uni182A1820.E875_ba.init=86+1000|uni1822.E836_i.medi2=88+1000|uni182D.E8E8_g.fina1=89+1250|space=90+0|uni1820.E827_a.fina2=91+600|uni202F.nobreak=92+500|uni1836.E92B_y.init1=93+500|uni1822.E834_i.medi=94+500|uni1828.E866_n.fina=95+850]
diff --git a/test/shaping/tests/zero-width-marks.tests b/test/shaping/tests/zero-width-marks.tests
new file mode 100644 (file)
index 0000000..be7ec96
--- /dev/null
@@ -0,0 +1,2 @@
+fonts/sha1sum/bb9473d2403488714043bcfb946c9f78b86ad627.ttf:U+1030:[circledash=0+636|u1030.med=0@-162,0+0]
+fonts/sha1sum/8454d22037f892e76614e1645d066689a0200e61.ttf:U+05E0,U+05B8,U+0591,U+05DA,U+05B0:[uni05DA05B0=3+991|uni2009=0+200|uni0591=0@75,0+0|uni05B8=0@495,0+0|uni05E0=0+683]
diff --git a/test/shaping/texts/MANIFEST b/test/shaping/texts/MANIFEST
new file mode 100644 (file)
index 0000000..26a3e67
--- /dev/null
@@ -0,0 +1 @@
+in-tree
diff --git a/test/shaping/texts/in-tree/MANIFEST b/test/shaping/texts/in-tree/MANIFEST
new file mode 100644 (file)
index 0000000..f7a7a96
--- /dev/null
@@ -0,0 +1,9 @@
+shaper-arabic
+shaper-default
+shaper-hangul
+shaper-hebrew
+shaper-indic
+shaper-myanmar
+shaper-sea
+shaper-thai
+shaper-tibetan
diff --git a/test/shaping/texts/in-tree/shaper-arabic/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/MANIFEST
new file mode 100644 (file)
index 0000000..eb8f9ec
--- /dev/null
@@ -0,0 +1,6 @@
+script-arabic
+script-mandaic
+script-mongolian
+script-nko
+script-phags-pa
+script-syriac
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/MANIFEST
new file mode 100644 (file)
index 0000000..62e050d
--- /dev/null
@@ -0,0 +1,3 @@
+language-persian
+language-urdu
+misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/MANIFEST
new file mode 100644 (file)
index 0000000..a6ac235
--- /dev/null
@@ -0,0 +1 @@
+mehran.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/mehran.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-persian/mehran.txt
new file mode 100755 (executable)
index 0000000..4be0786
--- /dev/null
@@ -0,0 +1,8 @@
+‫دَر فارسی گَچْ‌پَژْ هست. این «ی» فارسی است.‬\r
+‫حرف «ع» را به چٰهار شکلِ «ع‍» و «‍ع‍» و «‍ع» و «‌ع‌» می‌توان نشان داد.‬\r
+‫تشخیصِ اِعْ‌ًٌَُراب ناهمخوان از وظایف حروفْ‌چین است.‬\r
+‫دو اِعراب همخوان مانند « َ» و « ّ» به شکل « َّ» باهم ترکیب می‌شوند.‬\r
+‫لازم است حروف‌چین رفتار درستی با کشیدهٔ یونی‌کدی داشته باشد.‬\r
+‫مثلاً بتواند کلـمهٔ «پیِٓـــــــچ» یا حروف «ــٖٓـ» را به درستی نمایش دهد.‬\r
+‫حرف «لام» و «الف» باید به شکل لیگاتوری نمایش داده شوند.‬\r
+‫کلمهٔ «بَلَاٰ» از آزمون‌های سطح پائین حروف‌چین است.‬
\ No newline at end of file
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/MANIFEST
new file mode 100644 (file)
index 0000000..0c0a6f3
--- /dev/null
@@ -0,0 +1 @@
+crulp
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/MANIFEST
new file mode 100644 (file)
index 0000000..5786e7b
--- /dev/null
@@ -0,0 +1 @@
+ligatures
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/2grams.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/2grams.txt
new file mode 100644 (file)
index 0000000..6b59920
--- /dev/null
@@ -0,0 +1,601 @@
+با
+پا
+تا
+ٹا
+ثا
+جا
+چا
+حا
+خا
+سا
+شا
+صا
+ضا
+طا
+عا
+غا
+فا
+قا
+کا
+گا
+لا
+ما
+نا
+ہا
+ھا
+یا
+تب
+ٹب
+جب
+چب
+حب
+سب
+شب
+صب
+طب
+عب
+قب
+کب
+لب
+نب
+ہب
+ھب
+ئب
+یب
+بب
+غب
+رب
+تپ
+جپ
+چپ
+ٹپ
+شپ
+غپ
+کپ
+گپ
+لپ
+مپ
+نپ
+ہپ
+ھپ
+ئپ
+یپ
+پت
+تت
+ثت
+چت
+حت
+خت
+ست
+شت
+صت
+ضت
+طت
+ظت
+عت
+غت
+فت
+قت
+کت
+گت
+لت
+مت
+نت
+ہت
+ھت
+ئت
+یت
+ٹت
+جت
+بت
+پٹ
+ٹٹ
+جٹ
+چٹ
+سٹ
+غٹ
+فٹ
+کٹ
+گٹ
+لٹ
+مٹ
+نٹ
+ہٹ
+ھٹ
+ئٹ
+یٹ
+شٹ
+تٹ
+بٹ
+حث
+عث
+لث
+نث
+ئث
+یث
+بث
+پج
+تج
+جج
+حج
+سج
+کج
+لج
+نج
+ہج
+ھج
+ئج
+یج
+گج
+بج
+پچ
+جچ
+سچ
+کچ
+مچ
+نچ
+ئچ
+تچ
+چچ
+خچ
+غچ
+یچ
+گچ
+ٹچ
+بچ
+تح
+جح
+صح
+ضح
+لح
+مح
+نح
+یح
+شح
+فح
+ئح
+بح
+ٹخ
+چخ
+سخ
+لخ
+مخ
+نخ
+ئخ
+یخ
+پخ
+بخ
+پد
+تد
+جد
+چد
+حد
+خد
+سد
+شد
+صد
+ضد
+عد
+غد
+فد
+قد
+کد
+گد
+لد
+مد
+ند
+ہد
+ئد
+ید
+بد
+پڈ
+ٹڈ
+جڈ
+چڈ
+سڈ
+گڈ
+لڈ
+مڈ
+نڈ
+ہڈ
+ئڈ
+یڈ
+کڈ
+تڈ
+بڈ
+پذ
+تذ
+جذ
+حذ
+خذ
+شذ
+عذ
+غذ
+فذ
+قذ
+کذ
+لذ
+مذ
+نذ
+ہذ
+ئذ
+یذ
+گذ
+بذ
+پر
+تر
+ٹر
+ثر
+جر
+چر
+حر
+خر
+سر
+شر
+صر
+ضر
+طر
+ظر
+عر
+غر
+فر
+قر
+کر
+گر
+لر
+مر
+نر
+ہر
+ئر
+یر
+بر
+پڑ
+تڑ
+جڑ
+چڑ
+سڑ
+غڑ
+کڑ
+گڑ
+لڑ
+مڑ
+ہڑ
+ھڑ
+یڑ
+نڑ
+بڑ
+پز
+تز
+جز
+حز
+خز
+سز
+عز
+فز
+قز
+کز
+گز
+لز
+مز
+نز
+ہز
+ئز
+یز
+ٹز
+ٹز
+غز
+بز
+پژ
+کژ
+مژ
+نژ
+ہژ
+یژ
+پس
+تس
+ٹس
+جس
+چس
+خس
+حس
+فس
+قس
+کس
+گس
+لس
+مس
+نس
+ہس
+ئس
+یس
+ھس
+عس
+سس
+بس
+تش
+ٹش
+جش
+چش
+خش
+حش
+فش
+قش
+کش
+گش
+لش
+مش
+نش
+ہش
+ئش
+یش
+ھش
+عش
+شش
+بش
+قص
+لص
+نص
+ئص
+یص
+خص
+بص
+فض
+قض
+مض
+ئض
+یض
+غض
+کض
+بض
+خط
+سط
+قط
+ئط
+یط
+جع
+شع
+ضع
+طع
+فع
+قع
+لع
+مع
+نع
+ئع
+یع
+سع
+کع
+بع
+لغ
+یغ
+بغ
+تف
+حف
+سف
+شف
+صف
+طف
+عف
+غف
+فف
+قف
+لف
+نف
+ہف
+ئف
+یف
+خف
+کف
+گف
+بف
+چق
+حق
+سق
+شق
+طق
+فق
+لق
+مق
+نق
+ہق
+ئق
+یق
+بق
+پک
+تک
+ٹک
+جک
+چک
+سک
+شک
+فک
+کک
+لک
+مک
+ہک
+ھک
+ئک
+یک
+حک
+بک
+پگ
+تگ
+جگ
+چگ
+سگ
+لگ
+نگ
+یگ
+ہگ
+مگ
+گگ
+بگ
+پل
+تل
+ٹل
+لل
+مل
+نل
+ہل
+ھل
+ئل
+یل
+خل
+ثل
+بل
+تم
+ٹم
+ثم
+جم
+چم
+خم
+سم
+شم
+صم
+ضم
+عم
+غم
+فم
+قم
+کم
+گم
+لم
+نم
+ہم
+ھم
+ئم
+یم
+بم
+پن
+تن
+ٹن
+جن
+چن
+خن
+شن
+طن
+ظن
+عن
+فن
+قن
+کن
+گن
+لن
+من
+نن
+ہن
+ھن
+ئن
+ین
+غن
+بن
+یں
+پو
+تو
+ٹو
+ثو
+جو
+چو
+حو
+خو
+سو
+ضو
+عو
+غو
+فو
+قو
+کو
+گو
+لو
+مو
+نو
+ہو
+ھو
+ئو
+یو
+بو
+ئہ
+یئہ
+بی
+پی
+تی
+ٹی
+ثی
+جی
+چی
+حی
+خی
+سی
+شی
+صی
+ضی
+طی
+ظی
+عی
+غی
+فی
+قی
+کی
+گی
+لی
+می
+نی
+ہی
+ھی
+ئی
+بے
+پے
+تے
+ٹے
+ثے
+جے
+چے
+سے
+شے
+صے
+طے
+غے
+فے
+قے
+کے
+گے
+لے
+مے
+نے
+ہے
+ھے
+ئے
+خے
+حے
+ضے
+عے
+پہ
+تہ
+ثہ
+جہ
+چہ
+خہ
+سہ
+شہ
+صہ
+ضہ
+طہ
+عہ
+غہ
+فہ
+قہ
+کہ
+گہ
+لہ
+مہ
+یہ
+ہہ
+ٹہ
+بہ
+تھ
+ٹھ
+جھ
+چھ
+کھ
+گھ
+بھ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/3grams.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/3grams.txt
new file mode 100644 (file)
index 0000000..4da97d2
--- /dev/null
@@ -0,0 +1,3415 @@
+ببا
+بپا
+بتا
+بٹا
+بجا
+بچا
+بحا
+بخا
+بسا
+بشا
+بصا
+بضا
+بطا
+بظا
+بعا
+بغا
+بفا
+بقا
+بکا
+بگا
+بلا
+بما
+بنا
+بیا
+بہا
+بھا
+پتا
+پٹا
+پجا
+پچا
+پکا
+پسا
+پشا
+پکا
+پگا
+پلا
+پنا
+پیا
+پہا
+پھا
+تبا
+تپا
+تتا
+تٹا
+تجا
+تچا
+تحا
+تخا
+تسا
+تشا
+تصا
+تضا
+تطا
+تعا
+تغا
+تفا
+تقا
+تکا
+تگا
+تلا
+تما
+تنا
+تیا
+تہا
+تھا
+ٹبا
+ٹپا
+ٹتا
+ٹچا
+ٹکا
+ٹگا
+ٹلا
+ٹما
+ٹما
+ٹنا
+ٹیا
+ٹھا
+ثبا
+ثقا
+ثلا
+ثما
+ثنا
+ثیا
+جبا
+جپا
+جتا
+جٹا
+ججا
+جچا
+جحا
+جسا
+جغا
+جفا
+فکا
+جگا
+جلا
+جما
+جنا
+جیا
+جہا
+جھا
+چبا
+چپا
+چتا
+چٹا
+چچا
+چخا
+چخا
+چسا
+چغا
+چقا
+چکا
+چگا
+چلا
+چما
+چنا
+چیا
+چہا
+چھا
+حبا
+حجا
+حسا
+حشا
+حصا
+حضا
+حظا
+چغا
+حفا
+ھقا
+حکا
+حلا
+حما
+حنا
+حیا
+خبا
+ختا
+خٹا
+خجا
+خچا
+خحا
+خسا
+خشا
+خصا
+خضا
+خطا
+خفا
+خلا
+خما
+خنا
+خیا
+خہا
+سبا
+سپا
+ستا
+سٹا
+سجا
+سچا
+سحا
+سخا
+سسا
+سعا
+سفا
+سقا
+سکا
+سگا
+سلا
+سما
+سنا
+سیا
+سہا
+شبا
+شپا
+شتا
+شجا
+شچا
+شحا
+شخا
+شطا
+شعا
+شغا
+شفا
+شقا
+شکا
+شگا
+شما
+شنا
+شیا
+شہا
+صبا
+صحا
+صغا
+صفا
+صلا
+صما
+صنا
+صیا
+ضحا
+ضخا
+ضعا
+ضغا
+ضلا
+ضما
+ضیا
+طبا
+طپا
+طحا
+طعا
+طغا
+طفا
+طلا
+طما
+طنا
+طیا
+طہا
+ظلا
+ظہا
+عبا
+عتا
+عجا
+عسا
+عشا
+عصا
+عضا
+عطا
+عظا
+عفا
+عقا
+عکا
+علا
+عما
+عنا
+عیا
+غبا
+غپا
+غٹا
+غچا
+غسا
+غفا
+غلا
+غما
+غنا
+غیا
+فتا
+فٹا
+فجا
+فحا
+فسا
+فشا
+فصا
+فضا
+فطا
+فظا
+فعا
+فغا
+فقا
+فکا
+فگا
+فلا
+فما
+فنا
+فیا
+فہا
+قبا
+قتا
+قحا
+قسا
+قصا
+قضا
+قطا
+قعا
+قفا
+قلا
+قما
+قنا
+قیا
+قہا
+کبا
+کپا
+کتا
+کٹا
+کثا
+کجا
+کچا
+کحا
+کسا
+کشا
+کعا
+کفا
+ککا
+کگا
+کلا
+کما
+کنا
+کیا
+کہا
+کھا
+گبا
+گپا
+گتا
+گٹا
+گجا
+گچا
+گسا
+گلا
+گما
+گنا
+گیا
+گہا
+گھا
+لبا
+لپا
+لتا
+لٹا
+لثا
+لجا
+لچا
+لحا
+لخا
+لسا
+لشا
+لصا
+لطا
+لعا
+لغا
+لفا
+لقا
+لکا
+لگا
+لما
+لنا
+لیا
+لہا
+لھا
+مبا
+مپا
+متا
+مٹا
+مثا
+مجا
+مچا
+محا
+مخا
+مسا
+مشا
+مصا
+مضا
+مطا
+مظا
+معا
+مغا
+مفا
+مقا
+مکا
+مگا
+ملا
+مما
+منا
+میا
+مہا
+نبا
+نپا
+نتا
+نٹا
+نثا
+نجا
+نچا
+نحا
+نخا
+نسا
+نشا
+نصا
+نضا
+نظا
+نعا
+نفا
+نقا
+نکا
+نگا
+نلا
+مہا
+نبا
+نپا
+نتا
+نٹا
+نثا
+نجا
+نچا
+نحا
+نخا
+نسا
+نشا
+نصا
+نضا
+نما
+ننا
+نیا
+نہا
+نھا
+ئبا
+ئپا
+ئشا
+ئعا
+ئکا
+ئگا
+ئنا
+ئیا
+یبا
+یپا
+یتا
+یٹا
+یثا
+یجا
+یحا
+یخا
+یسا
+یشا
+یصا
+یضا
+یطا
+یعا
+یغا
+یفا
+یقا
+یکا
+یگا
+یلا
+یما
+ینا
+یئم
+یہا
+ہبا
+ہپا
+ہتا
+ہٹا
+ہجا
+ہچا
+ہسا
+ہشا
+ہفا
+ہقا
+ہکا
+ہگا
+ہلا
+ہما
+ہنا
+ہیا
+ھبا
+ھپا
+ھتا
+ھٹا
+ھجا
+ھسا
+ھکا
+ھگا
+ھلا
+ھما
+ھنا
+ھیا
+ھہا
+بلب
+بیب
+پھب
+تعب
+تکب
+تیب
+جست
+جلب
+جیب
+چھب
+حجب
+حسب
+حلب
+خطب
+سبب
+سلب
+سیب
+شعب
+شغب
+شیب
+صعب
+صلب
+طلب
+طیب
+عجب
+عصب
+عضب
+عقب
+عنب
+عیب
+ضصب
+غضب
+غلب
+غیب
+قطب
+قعب
+قلب
+قیب
+کتب
+کسب
+کعب
+کلب
+کیب
+کھب
+لطب
+لعب
+لقب
+لیب
+لہب
+محب
+مشب
+مطب
+نسب
+نصب
+نقب
+نیب
+یشب
+ینب
+ہیب
+بشپ
+پمپ
+پنپ
+پیپ
+تھپ
+ٹھپ
+جمپ
+جیپ
+جھپ
+چیپ
+چھپ
+سلپ
+سیپ
+فلپ
+کلپ
+کیپ
+کھپ
+گیپ
+گھپ
+لمپ
+لیپ
+میپ
+یمپ
+ینپ
+بپت
+بچت
+بخت
+بست
+بشت
+بعت
+بقت
+بنت
+بیت
+بہت
+بھت
+پتت
+پخت
+پست
+پشت
+پیت
+تبت
+تپت
+تحت
+تختتست
+تشت
+تمت
+تنت
+تیت
+ٹکت
+ثبت
+ثلت
+جست
+جعت
+جفت
+جگت
+جنت
+جیت
+جہت
+چپت
+چست
+چشت
+چکت
+چلت
+چنت
+چیت
+چھت
+حبت
+حجت
+حشت
+حفت
+حلت
+حمت
+حیت
+خست
+خشت
+کصت
+خفت
+خلت
+سبت
+سچت
+سخت
+سست
+سعت
+سفت
+سقت
+سکت
+سلت
+سمت
+سنت
+سیت
+شست
+شصت
+شفت
+شیت
+صحت
+صفت
+صلت
+صمت
+صیت
+ضیت
+طشت
+طفت
+طیت
+ظبت
+عفت
+علت
+عیت
+غبت
+غلت
+غیت
+فظت
+فعت
+فقت
+فیت
+قبت
+قعب
+قلت
+قیت
+کبت
+کپت
+کھت
+کشت
+کعت
+کلت
+کیت
+کھت
+گپت
+گست
+گشت
+گفت
+گمت
+گنت
+گیت
+لپت
+لجت
+لحت
+لخت
+لست
+لشت
+لغت
+لفت
+لگت
+للت
+لیت
+مست
+مشت
+معت
+مفت
+مکت
+ملت
+منت
+میت
+مہت
+نپت
+نست
+نعت
+نفت
+نکت
+نگت
+نیت
+ئیت
+یست
+یشت
+یعت
+یقت
+یمت
+ینت
+ہست
+ہشت
+ہفت
+ہمت
+ہیت
+ھست
+بجٹ
+بکٹ
+بلٹ
+بنٹ
+بیٹ
+بھٹ
+پسٹ
+پلٹ
+پیٹ
+پھٹ
+ٹسٹ
+ٹکٹ
+ٹنٹ
+ٹھٹ
+جسٹ
+جمٹ
+جنٹ
+جیٹ
+جھٹ
+چپٹ
+چکٹ
+چمٹ
+چنٹ
+چھٹ
+سٹٹ
+سکٹ
+سمٹ
+سیٹ
+شسٹ
+شفٹ
+شمٹ
+شیٹ
+فسٹ
+کپٹ
+کسٹ
+کشٹ
+کیٹ
+کھٹ
+گسٹ
+گشٹ
+گفٹ
+گلٹ
+گمٹ
+گیٹ
+گھٹ
+لپٹ
+لسٹ
+لشٹ
+لفٹ
+لنٹ
+لیٹ
+لہٹ
+مسٹ
+مشٹ
+مکٹ
+ملٹ
+منٹ
+میٹ
+نبٹ
+نپٹ
+نجٹ
+نسٹ
+نکٹ
+نگٹ
+نمٹ
+نیٹ
+یبٹ
+ئسٹ
+ئلٹ
+ئنٹ
+یبٹ
+یسٹ
+یکٹ
+ینٹ
+ہیٹ
+ھیٹ
+بحث
+بعث
+ثلث
+خبث
+شیث
+عبث
+نبث
+نیث
+بنج
+بیج
+بھج
+پنج
+پیج
+تہج
+تھج
+ٹیپ
+جھج
+سلج
+سیج
+سہج
+کنج
+کیج
+کھج
+گنج
+گیج
+لحج
+لنج
+لیج
+منج
+میج
+نپج
+نہج
+ینج
+ہپج
+بنچ
+بیچ
+بھچ
+پنچ
+پیچ
+پھچ
+تھچ
+ٹیج
+جکچ
+چمچ
+کلچ
+کیچ
+کھچ
+گھچ
+لنچ
+لیچ
+میچ
+نیچ
+ہیچ
+بیح
+جیح
+سطح
+سلح
+شیح
+صبح
+صلح
+صیح
+ضیح
+فتح
+فصح
+قبح
+لیح
+مسح
+ملح
+میخ
+نضح
+نفخ
+بطخ
+بلخ
+بیخ
+پٹخ
+تلخ
+تیخ
+ٹپخ
+چپخ
+چٹخ
+چیخ
+سیخ
+شیخ
+فسخ
+گٹخ
+مسخ
+مطخ
+ملخ
+میخ
+نسخ
+نفخ
+بتد
+بجد
+بحد
+بخد
+بسد
+بصد
+بضد
+بعد
+بغد
+بقد
+بگد
+بلد
+بمد
+بند
+بید
+بہد
+بھد
+پند
+پید
+پھد
+تبد
+تجد
+تحد
+تخد
+تسد
+تشد
+تصد
+تعد
+تقد
+تکد
+تمد
+تند
+تہد
+ثمد
+جسد
+جعد
+جلد
+جند
+جید
+جہد
+چغد
+چلد
+چند
+چید
+چھد
+حبد
+حسد
+حقد
+حمد
+حید
+ختہ
+خضد
+خلد
+خمد
+خند
+سبد
+ستد
+سجد
+سشد
+سعد
+سقد
+سمد
+سند
+سید
+شبد
+ششد
+شند
+شید
+شہد
+صفد
+صمد
+صند
+صید
+ضفد
+ضید
+عبد
+عتد
+عضد
+عقد
+عمد
+عند
+عید
+عہد
+غند
+غید
+فصد
+فعد
+فقد
+فند
+فید
+فہد
+قتد
+قصد
+قعد
+قند
+قید
+کند
+کید
+کھد
+گبد
+گلد
+گند
+گید
+لبد
+لحد
+لضد
+لعد
+لقد
+لکد
+لگد
+لمد
+لند
+لید
+مبد
+متد
+مجد
+محد
+محد
+مسد
+مشد
+مصد
+معد
+مقد
+مکد
+مگد
+ممد
+مند
+مید
+مہد
+نبد
+نتد
+نخد
+نسد
+نصد
+نعد
+نقد
+نگد
+نمد
+نند
+نہد
+ئمد
+ئند
+ئید
+یکد
+یگد
+یلد
+یند
+ہبد
+ہتد
+ہلد
+ہمد
+ہند
+ہید
+ھگد
+ھند
+بلڈ
+بنڈ
+بیڈ
+پگڈ
+پنڈ
+پیڈ
+پھڈ
+تکڈ
+تگڈ
+تنڈ
+ٹنڈ
+ٹھڈ
+جنڈ
+جھڈ
+چلڈ
+چنڈ
+سٹڈ
+سنڈ
+سیڈ
+شلڈ
+شیڈ
+غنڈ
+ئیڈ
+فنڈ
+فیڈ
+کبڈ
+کمڈ
+کنڈ
+کیڈ
+کھڈ
+گٹڈ
+کلڈ
+گنڈ
+گیڈ
+لنڈ
+لیڈ
+مکڈ
+مگڈ
+منڈ
+میڈ
+نیڈ
+ئٹڈ
+ئلڈ
+ئیڈ
+یجڈ
+یلڈ
+ینڈ
+ہلڈ
+ہنڈ
+ہیڈ
+ھنڈ
+بتذ
+پھڈ
+تبذ
+تحذ
+تعذ
+تغذ
+تکذ
+تلذ
+تہذ
+ٹھڈ
+جعد
+حبذ
+عتذ
+کیڈ
+لبذ
+لحز
+لقذ
+مبذ
+متذ
+مجذ
+محذ
+مخذ
+معذ
+مکذ
+ملذ
+منذ
+مہذ
+ہکذ
+ہگذ
+ببر
+بتر
+بٹر
+بجر
+بحر
+بخر
+بسر
+بشر
+بصر
+بطر
+بغر
+بفر
+بقر
+بکر
+بگر
+بلر
+بمر
+بنر
+بیر
+بہر
+بھر
+پتر
+پٹر
+پچر
+پسر
+پنر
+پیر
+پہر
+پھر
+تبر
+تپر
+تتر
+تٹر
+تجر
+تحر
+تخر
+تسر
+تشر
+تصر
+تضر
+تعر
+تغر
+تفر
+تقر
+تکر
+تگر
+تمر
+تنر
+تیر
+تہر
+تھر
+ٹبر
+ٹٹر
+ٹخر
+ٹسر
+ٹکر
+ٹمر
+ٹنر
+ٹیڈ
+ٹہر
+ٹھر
+ثمر
+ثیر
+جبر
+جتر
+جغر
+جفر
+جکر
+جگر
+جمر
+جنر
+جیر
+جہر
+جھر
+چپر
+چتر
+چٹر
+چسر
+چشر
+چفر
+چقر
+چکر
+چمر
+چنر
+چیر
+چہر
+چھر
+حتر
+حجر
+حسر
+حشر
+حصر
+حضر
+حفر
+حقر
+حمر
+حیر
+خبر
+ختر
+خچر
+خسر
+خشر
+خصر
+خضر
+خطر
+خفر
+خگر
+خمر
+خیر
+سپر
+ستر
+سٹر
+سجر
+سچر
+سحر
+سسر
+سطر
+سفر
+سقر
+سکر
+سگر
+سمر
+سیر
+سہر
+شبر
+شپر
+شتر
+شٹر
+شجر
+شطر
+شعر
+شغر
+شکر
+شگر
+شمر
+شیر
+شہر
+صبر
+صحر
+صطر
+صعر
+صغر
+صفر
+صہر
+ضطر
+طبر
+طغر
+طنز
+طیر
+طہر
+ظفر
+ظہر
+عبر
+عتر
+عسر
+عشر
+عصر
+عطر
+عفر
+عقر
+عکر
+عمر
+غٹر
+غفر
+غیر
+فتر
+فٹر
+فجر
+فخر
+فسر
+فشر
+فطر
+فغر
+ففر
+فقر
+فکر
+فلر
+فنر
+فیر
+فہر
+قبر
+قتر
+قشر
+قصر
+قطر
+قعر
+قلر
+قمر
+قیر
+قہر
+کبر
+کتر
+کٹر
+کثر
+کجر
+کچر
+کسر
+کثر
+کفر
+ککر
+کگر
+کلر
+کمر
+کیر
+کہر
+کھر
+گبر
+گٹر
+گجر
+گگر
+گلر
+گمر
+گنر
+گیر
+گہر
+گھر
+لبر
+لتر
+لٹر
+لجر
+لچر
+لھر
+لخر
+لشر
+لضر
+لطر
+لعر
+لغر
+لفر
+لقر
+لکر
+لگر
+لمر
+لنر
+لیر
+لہر
+مبر
+مپر
+متر
+مٹر
+مجر
+مچر
+محر
+مخر
+مسر
+مشر
+مصر
+مضر
+مطر
+معر
+مغر
+مفر
+مقر
+مکر
+مگر
+ملر
+ممر
+منر
+میر
+مہر
+نبر
+نتر
+نٹر
+نثر
+نجر
+نحر
+نخر
+نسر
+نشر
+نصر
+نظر
+نعر
+نفر
+نقر
+نکر
+نگر
+نمر
+نئر
+نیر
+نہر
+ئبر
+ئٹر
+ئکر
+ئمر
+ئنر
+ئیر
+ئہر
+یبر
+یپر
+یٹر
+یثر
+یجر
+یچر
+یخر
+یسر
+یشر
+یفر
+یکر
+یگر
+یلر
+یمر
+ینر
+یئر
+یہر
+ہبر
+ہتر
+ہٹر
+ہجر
+ہچر
+ہکر
+ہلر
+ہمر
+ہنر
+ہیر
+ھبر
+ھچر
+ھگر
+گیر
+بگڑ
+بنڑ
+بیڑ
+بھڑ
+پبڑ
+پٹڑ
+پجڑ
+پکڑ
+پگڑ
+پلڑ
+پیڑ
+پھڑ
+تپڑ
+تکڑ
+تگڑ
+تلڑ
+تیڑ
+تھڑ
+ٹکڑ
+ٹیر
+ٹھڑ
+جبڑ
+جکڑ
+جھڑ
+چبڑ
+چبڑ
+چپڑ
+چچڑ
+چسڑ
+چکڑ
+چمڑ
+چیڑ
+چھڑ
+سپڑ
+سکڑ
+سیڑ
+کبڑ
+کپڑ
+کچڑ
+ککڑ
+کلڑ
+کنڑ
+کیڑ
+کھڑ
+گپڑ
+گیڑ
+گھڑ
+لبڑ
+لپڑ
+لکڑ
+لگڑ
+لٹر
+لہڑ
+لھڑ
+مپڑ
+مسڑ
+مکڑ
+منڑ
+میڑ
+نبڑ
+نپڑ
+نتڑ
+نچڑ
+نسڑ
+نکڑ
+نگڑ
+نیڑ
+نہڑ
+ئیڑ
+یکڑ
+یہڑ
+ہبڑ
+ہپڑ
+ہیڑ
+ہجڑ
+ہلڑ
+ہمڑ
+ہنڑ
+ہیڑ
+ھبڑ
+ھکڑ
+ھگڑ
+ھیڑ
+بجز
+بلز
+بیز
+بہز
+پیز
+تجز
+تحز
+تعز
+تغز
+تنز
+تیز
+ٹیڑ
+چکز
+چیز
+حمز
+حیز
+خیز
+خنز
+سبز
+سلز
+سیز
+شلز
+شیز
+شہز
+طنز
+عتز
+عجز
+غمز
+فلز
+فیز
+قلز
+کبز
+کمز
+کنز
+کیز
+گلز
+گیز
+لتز
+لجز
+لحز
+لعز
+لغز
+لقز
+لنز
+لیز
+متز
+محز
+مخز
+مسز
+معز
+مغز
+ملز
+ممز
+منز
+میز
+نتز
+نغز
+نگز
+نلز
+نیز
+ئلز
+ئنز
+ئیز
+یگز
+یلز
+یمز
+ہتز
+ہلز
+ہمز
+ہیز
+لگژ
+بکس
+بلس
+بنس
+بیس
+بھس
+پٹس
+پنس
+پیس
+پھس
+تٹس
+تحس
+تکس
+تیس
+تہس
+ٹپس
+ٹکس
+ٹلس
+ٹنس
+ٹیز
+ٹھس
+جنس
+جیس
+چکس
+چیس
+حبس
+خمس
+خیس
+سٹس
+سمس
+سیس
+شپس
+شمس
+طلس
+طیس
+عکس
+فلس
+فنس
+فیس
+قفس
+قیس
+کتیس
+کلس
+کنس
+کھس
+گلس
+گیس
+گھس
+لپس
+لٹس
+لکس
+لمس
+لنس
+لیس
+مکس
+مگس
+ملس
+منس
+میس
+نٹس
+نجس
+نحس
+نسس
+نفس
+نکس
+ینس
+ئٹس
+ئنس
+ئیس
+یبس
+یٹس
+یسس
+یشس
+یکس
+یلس
+ینس
+ٹیس
+جیش
+حبش
+خفش
+سپش
+ستش
+شیش
+طپش
+طیش
+عطش
+عیش
+فحش
+فلش
+کشش
+کفش
+کنش
+کیش
+کفش
+کنش
+لکش
+منش
+میش
+نجش
+نعش
+نقش
+نگش
+نمش
+نیش
+ئیش
+یشش
+یعش
+ینش
+ہفش
+ہیش
+حصص
+حفص
+حیص
+شخص
+قصص
+نقص
+بعض
+بغض
+بیض
+حیض
+غیض
+فیض
+قبض
+محض
+میض
+نبض
+نقض
+بخط
+خبط
+خلط
+سبط
+سقط
+شخط
+ضبط
+غلط
+غیط
+فقط
+قحط
+قسط
+لخط
+لفط
+لقط
+حفظ
+غیظ
+لحظ
+لفظ
+بمع
+بیع
+تبع
+تسع
+تفع
+جمع
+جیع
+سبع
+سجع
+سمع
+سیع
+شجع
+شمع
+صطع
+صنع
+صیع
+ضلع
+ضیع
+طبع
+طمع
+فیع
+قطع
+قلع
+قمع
+قیع
+منع
+نطع
+نفع
+تیغ
+میغ
+نیغ
+بلف
+بیف
+تلف
+جیف
+چیف
+حلف
+حیف
+خلف
+خیف
+سقف
+سلف
+سیف
+شغف
+شلف
+صحف
+صنف
+صیف
+ضعف
+ضیف
+عطف
+علف
+قیف
+کتف
+کشف
+کلف
+کنف
+کیف
+کہف
+گلف
+لصف
+کطف
+کیف
+نجف
+نصف
+نیف
+بحق
+بلق
+بہق
+بھق
+پتق
+پھق
+تتق
+ثیق
+جلق
+حلق
+حمق
+حیق
+خلق
+سبق
+شفق
+شلق
+ضیق
+طبق
+عشق
+عمق
+فتق
+فسق
+سیق
+قلق
+قیق
+لحق
+لیق
+مشق
+نبق
+نسق
+نطق
+نیق
+بتک
+بٹک
+بچک
+بطک
+بلک
+بنک
+بیک
+بہک
+بھک
+پٹک
+پچک
+پلک
+پنک
+پیک
+پھک
+تپک
+تتک
+تشک
+تلک
+تنک
+تیک
+تھک
+ٹپک
+ٹسک
+ٹنک
+ٹیش
+ٹھک
+جبک
+جھک
+چبک
+چپک
+چٹک
+چسک
+چشک
+چلک
+چمک
+چنک
+چیک
+چہک
+چھک
+ختک
+خٹک
+خسک
+خشک
+خنک
+سبک
+ستک
+سٹک
+سسک
+سلک
+سمک
+سنک
+شلک
+ضحک
+غٹک
+غلک
+کبک
+کتک
+کٹک
+کسک
+کفک
+کلک
+کمک
+کنک
+کیک
+گٹک
+گجک
+گلک
+گمک
+گہم
+لپک
+لٹک
+لچل
+للک
+لنک
+لیک
+لہک
+مٹک
+مچک
+محک
+مسک
+مشک
+ملک
+میک
+مہک
+نسک
+نمک
+نیک
+ئیک
+یبک
+یپک
+یشک
+یفک
+یمک
+ینک
+ہبک
+ہتک
+ہچک
+ہلک
+ہمک
+ہنک
+کیک
+ھجک
+ھچک
+ھسک
+ھلک
+ھمک
+ھنک
+بنگ
+بیگ
+بھگ
+پلگ
+پنگ
+تنگ
+ٹنگ
+ٹیک
+جلگ
+جنگ
+چنگ
+خنگ
+سلگ
+سنگ
+سیگ
+شنگ
+کنگ
+کھگ
+گمگ
+گنگ
+لنگ
+لیگ
+منگ
+میگ
+ننگ
+نیگ
+ئنگ
+ینگ
+ہلگ
+ہنگ
+ہیگ
+ھنگ
+ببل
+بچل
+بحل
+بخل
+بصل
+بطل
+بعل
+بغل
+بقل
+بکل
+بگل
+بیل
+بہل
+بھل
+پبل
+پپل
+پتل
+پٹل
+پگل
+پیل
+پہل
+پھلتکل
+تیل
+تھل
+ٹکل
+ٹیگ
+ٹہل
+ثقل
+ثیل
+جبل
+جعل
+جکل
+جگل
+جمل
+جیل
+جہل
+جھل
+چبل
+چپل
+چغل
+چکل
+چمل
+چیل
+چہل
+چھل
+حبل
+حصل
+حلل
+حمل
+حیل
+خجل
+خلل
+خیل
+سبل
+ستل
+سٹل
+سجل
+سچل
+سفل
+سکل
+سگل
+سنل
+سیل
+سہل
+شطل
+شغل
+شکل
+شگل
+شیل
+صصل
+صنل
+صیل
+طبل
+طفل
+عسل
+عضل
+عقل
+علل
+عمل
+عیل
+غسل
+فحل
+فصل
+فضل
+فعل
+فیل
+قبل
+قتل
+قفل
+قیل
+کبل
+کپل
+کتل
+کچل
+کحل
+کسل
+کشل
+کفل
+کمل
+کیل
+کہل
+کھل
+گپل
+گٹل
+گسل
+گھل
+لعل
+لغل
+لیل
+مٹل
+مثل
+مچل
+محل
+مخل
+مضل
+مغل
+ملل
+میل
+نبل
+نپل
+نچل
+نحل
+نخل
+نسل
+نشل
+نصل
+نعل
+نفل
+نقل
+نکل
+نگل
+نیل
+ئبل
+ئٹل
+ئفل
+ئقل
+ئنل
+ئیل
+یشل
+یکل
+یگل
+ینل
+ہبل
+ہیل
+ھیل
+بسم
+بکم
+بلم
+بیم
+بہم
+پتم
+پٹم
+پچم
+پسم
+پشم
+پنم
+پیم
+پتم
+تخم
+تیم
+تھم
+ٹیل
+ثیم
+جسم
+جنم
+جیم
+جھم
+چشم
+چلم
+چھم
+حجم
+حشم
+حضم
+حکم
+حلم
+حیم
+ختم
+حشم
+خیم
+ستم
+سقم
+سکم
+سلم
+سیم
+سہم
+ششم
+شکم
+شلم
+شیم
+صنم
+طعم
+ظلم
+عجم
+عظم
+علم
+عیم
+غلم
+فلم
+فیم
+قسم
+قلم
+قیم
+کٹم
+کسم
+کلم
+کیم
+کھم
+گلم
+گیم
+گھم
+لبم
+لحم
+لکم
+لیم
+مسم
+مغم
+منم
+میم
+مہم
+نجم
+نظم
+نعم
+نکم
+نگم
+نیم
+نہم
+ئٹم
+یتم
+یٹم
+یشم
+یغم
+یکم
+ینم
+یئم
+ہضم
+ہمم
+ہیم
+ھکم
+کیم
+بٹن
+بچن
+بشن
+بطن
+بین
+بہن
+بھن
+پتن
+پٹن
+پشن
+پمن
+پین
+پہن
+پھن
+تپن
+تکن
+تلن
+تمن
+تین
+تہن
+تھن
+ٹپن
+ٹسن
+ٹفن
+ٹیم
+ٹھن
+ثمن
+ثین
+جبن
+جتن
+جشن
+جگن
+جلن
+جمن
+جین
+جھن
+چپن
+چکن
+چلن
+چمن
+چین
+چھن
+حسن
+حصن
+حین
+ختن
+خین
+سپن
+ستن
+سٹن
+سجن
+سخن
+سشن
+سقن
+سمن
+سنن
+سین
+سہن
+شکن
+شگن
+شمن
+شین
+صحن
+ضمن
+ضین
+طعن
+طین
+عین
+غبن
+غین
+فتن
+فٹن
+فگن
+فمن
+فین
+قطن
+قین
+کجن
+کچن
+کشن
+کفن
+کلن
+کین
+کہن
+کھن
+گگن
+گین
+گہن
+گھن
+لبن
+لٹن
+لجن
+لحن
+لسن
+لعن
+لفن
+لگن
+لمن
+لنن
+لین
+لہن
+لھن
+متن
+مٹن
+محن
+مسن
+مشن
+مکن
+مگن
+ملن
+منن
+مین
+نجن
+نشنر
+نگن
+نمن
+نین
+نہن
+ئین
+یپن
+یجن
+یشن
+یکن
+یگن
+یلن
+یمن
+ہمن
+ہین
+بیں
+پیں
+ٹیں
+ثین
+جیں
+چیں
+حیں
+خیں
+سیں
+شیں
+عیں
+کیں
+گیں
+لیں
+میں
+نیں
+ئیں
+ہیں
+ھیں
+ببو
+بپو
+بتو
+بٹو
+بجو
+پچو
+پسو
+پشو
+پکو
+پگو
+پلو
+پنو
+پئو
+پیو
+پھو
+تبو
+تپو
+تجو
+تچو
+تحو
+تخو
+تسو
+تشو
+تصو
+تضو
+تطو
+تعو
+تفو
+تقو
+تکو
+تگو
+تلو
+تمو
+تنو
+تیو
+تہو
+تھو
+ٹپو
+ٹٹو
+ٹچو
+ٹسو
+ٹشو
+ٹکو
+ٹلو
+ٹنو
+ٹیز
+ٹہو
+ٹھو
+ثبو
+ثپو
+ثتو
+ثمو
+جبو
+جپو
+جتو
+جٹو
+ججو
+جچو
+جسو
+جعو
+جلو
+جمو
+جنو
+جئو
+جیو
+جھو
+چبو
+چپو
+چتو
+چٹو
+چچو
+چخو
+چسو
+چقو
+چکو
+چگو
+چلو
+چمو
+چنو
+چیو
+چھو
+حبو
+حتو
+حثو
+حشو
+حصو
+حضو
+حظو
+حقو
+حکو
+حلو
+حنو
+حیو
+ختو
+خسو
+خشو
+خصو
+خضو
+خطو
+خلو
+خمو
+خنو
+خیو
+سبو
+سپو
+ستو
+سٹو
+سجو
+سچو
+سحو
+سشو
+سطو
+سعو
+سفو
+سقو
+سکو
+سگو
+سلو
+سمو
+سنو
+سیو
+سہو
+شبو
+شپو
+شتو
+ششو
+شعو
+شفو
+شقو
+شکو
+شگو
+شلو
+شمو
+شنو
+شیو
+شہو
+صبو
+صتو
+صحو
+صعو
+صفو
+صلو
+صنو
+ضتو
+ضحو
+ضعو
+طبو
+طفو
+طلو
+طنو
+طیو
+طہو
+ظتو
+ظلو
+ظنو
+ظہو
+عبو
+عتو
+عجو
+عشو
+عضو
+عطو
+عظو
+عفو
+عقو
+علو
+عمو
+عنو
+عیو
+غفو
+غلو
+غمو
+غنو
+غیو
+فتو
+فٹو
+فجو
+فحو
+فسو
+فصو
+فضو
+فظو
+فعو
+فقو
+فلو
+فنو
+فیو
+فہو
+قبو
+قپو
+قتو
+قسو
+قشو
+قصو
+قطو
+قعو
+قفو
+قلو
+قمو
+قنو
+قیو
+قہو
+کبو
+کتو
+کتو
+کٹو
+کچو
+کسو
+کشو
+کفو
+کلو
+کمو
+کنو
+کیو
+کہو
+کھو
+کو
+گپو
+گتو
+گٹو
+گجو
+گلو
+گمو
+گنو
+گئو
+گیو
+گہو
+گھو
+لبو
+لپو
+لتو
+لٹو
+لثو
+لجو
+لچو
+لحو
+لخو
+لسو
+لشو
+لصو
+لضو
+لطو
+لعو
+لغو
+لفو
+لقو
+لکو
+لگو
+للو
+لمو
+لنو
+لیو
+لہو
+لھو
+مپو
+متو
+مٹو
+مجو
+مچو
+جحو
+مخو
+مسو
+مشو
+مصو
+مطو
+مغو
+مقو
+مکو
+مگو
+ملو
+ممو
+منو
+مئو
+میو
+مہو
+مھو
+نبو
+نپو
+نتو
+نٹو
+نجو
+نچو
+نحو
+نخو
+نسو
+نشو
+نصو
+نطو
+نظو
+نعو
+نفو
+نقو
+نکو
+نگو
+نلو
+نمو
+ننو
+نیو
+نہو
+نھو
+ئبو
+ئپو
+ئتو
+ئٹو
+ئخو
+خشو
+ئفو
+ئقو
+ئکو
+ئلو
+ئنو
+ئیو
+یبو
+یپو
+یتو
+یٹو
+یثو
+یجو
+یخو
+یسو
+یشو
+یضو
+یعو
+یفو
+یقو
+یکو
+یگو
+یلو
+یمو
+ینو
+یئو
+یہو
+ہبو
+ہپو
+ہتو
+ہٹو
+ہجو
+ہشو
+ہضو
+ہفو
+ہکو
+ہگو
+ہلو
+ہمو
+ہنو
+ہیو
+ھبو
+ھپو
+ھتو
+ھجو
+ھکو
+ھگو
+ھلو
+ھنو
+ھیو
+مو
+ببی
+بتی
+بٹی
+بجی
+بچی
+بسی
+بطی
+بکی
+بلی
+بنی
+بئ
+بہی
+بھی
+بی
+پتی
+پٹی
+پجی
+پچی
+پخی
+پسی
+پشی
+پکی
+پلی
+پنی
+پئ
+تھی
+تبی
+تپی
+تتی
+تپی
+تجی
+تچی
+تشی
+تقی
+تکی
+تگی
+تلی
+تمی
+تنی
+تئ
+تہی
+تھی
+ٹپی
+ٹتی
+ٹٹی
+ٹچی
+ٹکی
+ٹگی
+ٹلی
+ٹمی
+ٹنی
+ٹھی
+ثتی
+جبی
+جپی
+جتی
+جٹی
+ججی
+جچی
+جعی
+جگی
+جلی
+جمی
+جنی
+جئ
+جہی
+جھی
+چبی
+چپی
+چتی
+چٹی
+چجی
+چچی
+چکی
+چگی
+چلی
+چنی
+چھی
+حبی
+حتی
+حسی
+حشی
+حظی
+حقی
+حلی
+حمی
+حئ
+ختی
+خشی
+خصی
+خطی
+خفی
+خلی
+خمی
+خنی
+خسپی
+ستی
+سٹی
+سجی
+سچی
+سخی
+سی
+سطی
+سعی
+سفی
+سکی
+سگی
+سلی
+سمی
+سنی
+سئ
+سہی
+سی
+شتی
+ششی
+شطی
+شقی
+شکی
+شمی
+شنی
+شہی
+صبی
+صتی
+صفی
+صگی
+صلی
+ضتی
+ضعی
+ظگی
+ضی
+طبی
+طمی
+طنی
+ظتی
+ظمی
+ظنی
+عتی
+عفی
+علی
+عمی
+عنی
+عئ
+غبی
+غپی
+غشی
+غلی
+غمی
+غنی
+فتی
+فجی
+فضی
+فعی
+فقی
+فگی
+فلی
+فمی
+فنی
+قتی
+قشی
+قصی
+قعی
+قلی
+قمی
+کبی
+کپی
+کتی
+کٹی
+کجی
+کچی
+کسی
+کشی
+کلی
+کمی
+کنی
+کہی
+کھی
+گبی
+گپی
+گتی
+گٹی
+گجی
+گچی
+گلی
+گمی
+گنی
+گئ
+گہی
+گھی
+لبی
+لپی
+لتی
+لٹی
+لثیمتی
+لجی
+لچی
+لسی
+لشی
+لعی
+لفی
+لکی
+لگی
+للی
+لمی
+لنی
+لہہ
+لی
+متی
+مٹی
+مجی
+مچی
+م]ی
+مسی
+مشی
+معی
+مکی
+مگی
+ملی
+ممی
+منی
+مہی
+نبی
+نپی
+نتی
+نٹی
+نجی
+نچی
+نسی
+نشی
+نفی
+نقی
+نکی
+نگی
+نلی
+نمی
+نلی
+نئ
+نہی
+نھی
+نی
+ئبی
+ئتی
+ئٹی
+ئچی
+ئسی
+ئشی
+ئقی
+ئکی
+ئلی
+ئمی
+ئنی
+یبی
+ہتی
+ہٹی
+ہفی
+ہکی
+ہگی
+ہلی
+ہمی
+ہنی
+ہئ
+ھپی
+ھتی
+ھجی
+ھکی
+ھگی
+ھلی
+ھنی
+ھئ
+بتے
+بٹے
+بجے
+بچے
+بسے
+بطے
+بعے
+بفے
+بقے
+بکے
+بلے
+بنے
+بۓ
+بہے
+بھے
+پتے
+پٹے
+پجے
+پچے
+پسے
+پشے
+پکے
+پلے
+پنے
+پۓ
+تبے
+تپے
+تتے
+تٹے
+تجے
+تچے
+تسے
+تشے
+تکے
+تگے
+تلے
+تمے
+تنے
+تۓ
+تھے
+ٹپے
+ٹتے
+ٹچے
+ٹکے
+ٹگے
+ٹلے
+ٹنے
+ٹۓ
+ٹھے
+جبے
+جپے
+جتے
+جٹے
+جثے
+جچے
+جسے
+جلے
+جمے
+جنے
+جۓ
+چھے
+حثے
+حصے
+حظے
+حقے
+حلے
+ختے
+حچے
+حطے
+خلے
+خہے
+ستے
+سٹے
+سجے
+سچے
+سطے
+سکے
+سکے
+سلے
+سمے
+سنے
+سۓ
+سہے
+شپے
+شتے
+شقے
+شمے
+شۓ
+صلے
+ضمے
+عشے
+علے
+غصے
+غلے
+فتے
+فٹے
+فسے
+فظے
+فلے
+قبے
+قصے
+قعے
+کپے
+کتے
+کٹے
+کجے
+کچے
+کسے
+کشے
+ککے
+کلے
+کمے
+کنے
+کۓ
+کیے
+کہے
+کھے
+گپے
+گتے
+گٹے
+گجے
+گلے
+گمے
+گنے
+گۓ
+گہے
+گھے
+لبے
+لیے
+لتے
+لٹے
+لثے
+لجے
+لچے
+لحے
+لخے
+لصے
+لعے
+لکے
+لگے
+لمے
+لنے
+لۓ
+لہے
+لھے
+متے
+مٹے
+مچے
+مسے
+مکے
+ملے
+نلے
+ننے
+نۓ
+ئٹے
+ئچے
+ئفے
+ئقے
+ئلے
+یتے
+یجے
+یچے
+یسے
+یشے
+یضے
+یعے
+یفے
+یقے
+یکے
+یگے
+یلے
+یمے
+ینے
+یۓ
+ہبے
+ہتے
+ہٹے
+ہجے
+ہکے
+ہگے
+ہلے
+ہمے
+ہنے
+ہۓ
+ھبے
+ھپے
+ھتے
+ھٹے
+ھجے
+ھکے
+ھگے
+ھلے
+ھمے
+ھۓ
+بتہ
+بچہ
+بحہ
+بطہ
+بعہ
+بغہ
+بقہ
+بلہ
+بیہ
+پتہ
+پٹہ
+پشہ
+پکہ
+پلہ
+پنہ
+پیہ
+تبہ
+تحہ
+تکہ
+تگہ
+تمہ
+تنہ
+تیہ
+تہہ
+ثقہ
+ثیم
+جبہ
+جتہ
+جثہ
+جگہ
+بلہ
+بمہ
+جنہ
+جیہ
+جہہ
+چپہ
+چغہ
+چلہ
+چنہ
+حبہ
+حثہ
+حشہ
+حصہ
+حظہ
+حقہ
+حلہ
+حمہ
+حیہ
+ختہ
+حچہ
+حطہ
+حلہ
+حمہ
+حنہ
+سبہ
+سپہ
+سبہ
+سجہ
+سخہ
+سسہ
+سطہ
+سفہ
+سقہ
+سکہ
+سلہ
+سمہ
+سنہ
+سۂ
+سیہ
+شبہ
+شتہ
+شقہ
+شلہ
+شمہ
+شنہ
+شۂ
+شیہ
+صفہ
+صلہصیہ
+ضمہ
+ظیہ
+طبہ
+طفہ
+طقہطمہ
+طیہ
+طہ
+ظلہ
+ظمہ
+عشہ
+عصہ
+عقہ
+عنہ
+عیہ
+غصہ
+غلہ
+غنہ
+فتہ
+فحہ
+فضہ
+فطہ
+فظہ
+فعہ
+فقہ
+فلہ
+فیہ
+فہہ
+قبہ
+قتہ
+قجہ
+قشہ
+قصہ
+قعہ
+قفہ
+قلہ
+قمہ
+قیہ
+کشہ
+کلہ
+کنہ
+کیہ
+کہہ
+گتہ
+گجہ
+گلہ
+گنہ
+گیہ
+گہہ
+لبہ
+لتہ
+لثہ
+لجہ
+لچہ
+لحہ
+لخہ
+لسہ
+لصہ
+لعہ
+لغہ
+لفہ
+لقہ
+لکہ
+للہ
+لمہ
+لنہ
+لیہ
+لہہ
+لہ
+متہ
+مچہ
+مطہ
+معہ
+مکہ
+ملہ
+منہ
+میہ
+مہہ
+نبہ
+نجہ
+نچہ
+نحہ
+نسہ
+نشہ
+نقہ
+نکہ
+نگہ
+نیہ
+نہہ
+ئبہ
+ئتہ
+ئٹہ
+ئچہ
+ئشہ
+ئفہ
+ئقہ
+ئکہ
+ئلہ
+ئمہ
+ئنہ
+ئیہ
+یبہ
+یجہ
+یچہ
+یحہ
+یشہ
+یضہ
+یعہ
+یفہ
+یقہ
+یکہ
+یگہ
+یلہ
+یمہ
+ینہ
+ہبہ
+ہمہ
+ہنہ
+ہیہ
+بجہھ
+بچھ
+بکھ
+پتھ
+پٹھ
+پچھ
+پکھ
+تتھ
+تجھ
+جتھ
+جٹھ
+چبھ
+چکھ
+سبھ
+سٹھ
+سجھ
+سکھ
+شبھ
+کچھ
+گتھ
+گٹھ
+گچھ
+لتھ
+لجھ
+لچھ
+لکھ
+متھ
+مٹھ
+مجھ
+مچھ
+مکھ
+منھ
+نبھ
+نتھ
+نٹھ
+نجھ
+نچھ
+نکھ
+نگھ
+نبھ
+یچھ
+یکھ
+ہتھ
+ہنھ
+طمۃ
+بی
+سی
+ضی
+بعا
+تا
+سطا
+صلا
+ظتا
+فتا
+قتا
+لبا
+متا
+معا
+ملا
+یتا
+یحا
+یضا
+نیا
+ینا
+ہلا
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/4grams.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/4grams.txt
new file mode 100644 (file)
index 0000000..e5494b7
--- /dev/null
@@ -0,0 +1,6316 @@
+ببیا
+ببھا
+بپتا
+بپھا
+بتتا
+بتخا
+بتسا
+بتغا
+بتلا
+بتما
+بتنا
+بتیا
+بتہا
+بتھا
+بٹتا
+بٹنا
+بٹیا
+بٹھا
+بجتا
+بجما
+بجنا
+بجیا
+بجھا
+بچتا
+بچکا
+بچلا
+بچنا
+بچیا
+بچھا
+بحسا
+بحفا
+بختا
+بخشا
+بخلا
+بخیا
+بستا
+بسٹا
+بسطا
+بسلا
+بسما
+بسنا
+بسیا
+بسہا
+بطحا
+بطخا
+بطلا
+بعضا
+بغیا
+بقضا
+بکتا
+بکسا
+بکشا
+بکلا
+بکما
+بکنا
+بکیا
+بکھا
+بگلا
+بگیا
+بگھا
+بلتا
+بلٹا
+بلحا
+بلطا
+بلغا
+بلفا
+بلقا
+بلکا
+بلگا
+بلما
+بلنا
+بلیا
+بلہا
+بمبا
+بمطا
+بمقا
+بمنا
+بنتا
+بنٹا
+بنجا
+بنکا
+بنگا
+بننا
+بنیا
+بیبا
+بیتا
+بیٹا
+بیجا
+بیچا
+بیسا
+بیشا
+بیضا
+بیطا
+بیعا
+بیکا
+بیگا
+بیلا
+بیما
+بینا
+بہتا
+بہکا
+بہلا
+بہنا
+بہیا
+بھپا
+بھتا
+بھٹا
+بھجا
+بھچا
+بھسا
+بھکا
+بھگا
+بھلا
+بھما
+بھنا
+بھیا
+پبیا
+پپیا
+پتتا
+پتلا
+پتنا
+پتیا
+پتھا
+پٹتا
+پٹخا
+پٹکا
+پٹلا
+پٹنا
+پٹیا
+پٹھا
+پجتا
+پجنا
+پچتا
+پچکا
+پچلا
+پچنا
+پچیا
+پچھا
+پخنا
+پخیا
+پسپا
+پستا
+پسما
+پسنا
+پشتا
+پشیا
+پغما
+پکتا
+پکما
+پکنا
+پکھا
+پگلا
+پلتا
+پلٹا
+پلکا
+پلنا
+پلیا
+پنیا
+پنجا
+پجچا
+پنچا
+پنسا
+پنگا
+پنیا
+پنہا
+پنھا
+پیپا
+پیتا
+پیٹا
+پیجا
+پیچا
+پیخا
+پیسا
+پیشا
+پیغا
+پیکا
+پیلا
+پیما
+پینا
+پہچا
+پہلا
+پہنا
+پہیا
+پھبا
+پھپا
+پھٹا
+پھچا
+پھسا
+پھکا
+پھلا
+تبخا
+تبیا
+تپتا
+تپکا
+تپنا
+تتکا
+تتلا
+تتھا
+تجتا
+تجلا
+تجنا
+تچنا
+تچتا
+تحتا
+تحیا
+تسلا
+تسما
+تشنا
+مملکتو
+تغما
+تغیا
+تفتا
+تقیا
+تکلا
+تکھا
+تگلا
+تلتا
+تلخا
+تللا
+تلنا
+تلیا
+تمبا
+تمثا
+تمغا
+تغیا
+تمنا
+تمہا
+تنبا
+تنتا
+تنکا
+تنگا
+تننا
+تنیا
+تنہا
+تیجا
+تیسا
+تیغا
+تیلا
+تیما
+تیہا
+تھپا
+تھتا
+تھجا
+تھکا
+تھلا
+تھما
+تھنا
+تھیا
+ٹپتا
+ٹپکا
+ٹپنا
+ٹٹیا
+ٹچیا
+ٹخنا
+ٹسکا
+ٹکتا
+ٹکسا
+ٹکلا
+ٹکنا
+ٹکیا
+ٹگلا
+ٹلتا
+ٹلنا
+ٹمنا
+ٹنٹا
+ٹنچا
+ٹنکا
+ٹنگا
+ٹننا
+ٹنیا
+ٹئیا
+ٹیبا
+ٹیپا
+ٹیکا
+ٹیلا
+ٹینا
+ٹہلا
+ٹہنا
+ٹھتا
+ٹھسا
+ٹھکا
+ٹھگا
+ٹھلا
+ٹھبنا
+ٹھیا
+ثعبا
+جبیا
+جبہا
+جبھا
+جپتا
+جپکا
+جپنا
+جتتا
+جتلا
+جتما
+جتنا
+جتیا
+جتہا
+جتھا
+جٹتا
+جٹنا
+جٹھا
+ججما
+جچتا
+جچنا
+جسکا
+جسما
+جفتا
+جفنا
+جکما
+چھپا
+چھٹا
+جگنا
+جگیا
+جگتا
+جلبا
+جلتا
+جلکا
+جلنا
+جلیا
+جمتا
+جلیا
+جمتا
+جمخا
+جمنا
+جنبا
+جنتا
+جنٹا
+جنکا
+جنجا
+جنگا
+جننا
+جنیا
+جیتا
+جیجا
+جیحا
+جیسا
+جیعا
+جیلا
+جینا
+جیہا
+جہتا
+جہلا
+جھبا
+جھپا
+جھتا
+جھجا
+جھکا
+جھلا
+جھما
+جھنا
+چبتا
+چبتا
+چبکا
+چبلا
+چبنا
+چبھا
+چبتا
+چپتا
+چپٹا
+چبکا
+چپلا
+چبپا
+چپنا
+چتتا
+چبھا
+چپتا
+چپکا
+چپلا
+چپنا
+چتتا
+چتلا
+چتنا
+چتھا
+چٹتا
+چٹکا
+چٹلا
+چٹنا
+چٹیا
+چٹھا
+چچکا
+چچیا
+چسپا
+چستا
+چسکا
+چسنا
+چغتا
+چقما
+چکتا
+چکٹا
+چکسا
+چکلا
+چکما
+چکنا
+چکھا
+چگتا
+چگلا
+چگنا
+چلپا
+چلتا
+چلکا
+چلنا
+چلیا
+چمپا
+چمٹا
+چمکا
+چمگا
+چملا
+چمن
+چنبا
+چنتا
+چنگا
+چننا
+چنیا
+چیپا
+چیتا
+چیخا
+چیچا
+چیلا
+چینا
+چہتا
+چہکا
+چہلا
+چھپا
+چھتا
+چھٹا
+چھجا
+چھچا
+چھکا
+چھلا
+چھما
+چھنا
+حتجا
+حتسا
+حتشا
+حتصا
+حتضا
+حتظا
+حتکا
+حتلا
+حتما
+حتیا
+حسنا
+حسنا
+حسیا
+حشیا
+حفظا
+حکما
+حمقا
+حنفا
+حیفا
+ختتا
+ختصا
+ختکا
+ختگا
+ختلا
+ختیا
+خچیا
+خشحا
+خشخا
+خشا
+خشما
+خصتا
+خصما
+خطبا
+خفتا
+خفقا
+خفنا
+خلجا
+خلخا
+خلفا
+خلکا
+خلیا
+خمیا
+خنسا
+خنگا
+خنا
+خنیا
+خیسا
+خیفا
+خیلا
+سبحا
+سبلا
+سبھا
+سپتا
+سپلا
+سپنا
+ستتا
+ستجا
+ستحا
+ستخا
+ستشا
+ستطا
+ستعا
+ستغا
+ستفا
+ستقا
+ستکا
+ستگا
+ستلا
+ستما
+ستنا
+ستیا
+ستہا
+ستھا
+سٹکا
+سٹنا
+سٹیا
+سٹھا
+سجتا
+سجلا
+سجنا
+سجھا
+سچتا
+سچلا
+سچنا
+سختا
+سستا
+سسکا
+سسنا
+سفنا
+سفیا
+سکتا
+سکشا
+سکلا
+سکنا
+سکیا
+سکھا
+سگھا
+سلتا
+سلطا
+سلفا
+سلکا
+سلگا
+سلما
+سلنا
+سلیا
+سمبا
+پنچا
+پنسا
+پنگا
+پننا
+پنیا
+پنہا
+پنھا
+پیپا
+پیتا
+پیچا
+پیخا
+پیسا
+پیشا
+پیغا
+پیکا
+پیلا
+پیما
+پینا
+پہچا
+پہلا
+پہنا
+پہیا
+پھپا
+پھچا
+پھسا
+پھکا
+پھلا
+تبخا
+تبیا
+تپتا
+تتکا
+تتلا
+تتھا
+تجتا
+تجلا
+تچتا
+تچنا
+تحتا
+تحیا
+تسلا
+تسما
+تشنا
+مملکتو
+تغما
+تغیا
+تفتا
+تقیا
+تکلا
+تکھا
+تگلا
+تلتا
+تلخا
+تللا
+تلنا
+تمبا
+تمثا
+تمغا
+تمہا
+تنتا
+تنکا
+تنگا
+تننا
+تنہا
+تیجا
+تیسا
+تیغا
+تیلا
+تیما
+تیہا
+تھپا
+تھتا
+تھجا
+تھکا
+تھلا
+تھما
+تھنا
+تھیا
+ٹپتا
+ٹپکا
+ٹٹیا
+ٹچیا
+ٹخنا
+ٹسکا
+ٹکتا
+ٹکسا
+ٹکلا
+سمپا
+سمٹا
+سمسا
+سمنا
+سمیا
+سنپا
+سنتا
+سنجا
+سنسا
+سنکا
+سنگا
+سننا
+سنیا
+سنہا
+سیپا
+سیتا
+سیٹا
+سیکا
+سیگا
+سیلا
+سیما
+سینا
+سئیا
+سیہا
+سہتا
+سہلا
+سہما
+سہنا
+شبکا
+شبہا
+شتعا
+شتکا
+شتما
+شتیا
+شتہا
+ششکا
+ششما
+شمشا
+شعبا
+شفتا
+شقیا
+شکبا
+شکشا
+شکلا
+شکنا
+شگتا
+شگنا
+شگیا
+شلتا
+شلیا
+شمشا
+شمنا
+شنیا
+شیبا
+شیخا
+شیطا
+شیلا
+شیما
+شہبا
+شہکا
+شہلا
+شہنا
+صطبا
+صطلا
+صفحا
+صفیا
+صفہا
+صلحا
+صمصا
+صمنا
+صنعا
+صہبا
+ضعفا
+ضگیا
+ضلکا
+ضمحا
+ضیحا
+طبقا
+طفلا
+طغیا
+طلبا
+طمنا
+طمیا
+طیبا
+طہما
+ظلما
+ظلہا
+عتبا
+عتصا
+عتقا
+عتکا
+عتلا
+عتما
+عتنا
+عثما
+عصیا
+عضلا
+عطیا
+عقلا
+علما
+علیا
+عنقا
+عنہا
+عیسا
+غپکا
+غثیا
+غصیا
+غلطا
+غلغا
+غلما
+غلیا
+غمنا
+غنیا
+غیبا
+غیلا
+فبہا
+فتتا
+فتخا
+فتگا
+فتنا
+فسطا
+فصحا
+فصلا
+فضلا
+فعلا
+فقہا
+فلپا
+فلما
+فنجا
+فنکا
+فیتا
+فیسا
+فیضا
+فیلا
+فیما
+فیہا
+فہما
+قبلا
+قتبا
+قتصا
+قتضا
+قتلا
+قتیا
+قحطا
+قسما
+قشلا
+قصبا
+قطعا
+قلپا
+قلفا
+قلقا
+قلما
+قلیا
+قمقا
+قیبا
+قیما
+کبجا
+کبلا
+کبھا
+کپتا
+کتسا
+کتشا
+کتفا
+کتکا
+کتلا
+کتنا
+کتیا
+کتھا
+کٹتا
+کٹکا
+کٹنا
+کٹیا
+کٹھا
+کجتا
+کجلا
+کچلا
+کچنا
+کچیا
+کچھا
+کستا
+کسلا
+کسما
+کسنا
+کسیا
+کشتا
+کشٹا
+کشیا
+کفتا
+کفنا
+کفیا
+ککیا
+کلپا
+کلتا
+کلچا
+کلسا
+کلکا
+کلما
+کلنا
+کلیا
+کلہا
+کلھا
+کمبا
+کمپا
+کمتا
+کمکا
+کملا
+کمنا
+کمیا
+کمہا
+کمنی
+کنسا
+کنعا
+کنکا
+کنگا
+کنیا
+کنہا
+کنھا
+کیسا
+کیکا
+کیلا
+کینا
+کیہا
+کہتا
+کہلا
+کہنا
+کھبا
+کھپا
+کھتا
+کھٹا
+کھجا
+کھچا
+کھسا
+کھکا
+کھلا
+کھما
+کھنا
+کھیا
+گبھا
+گپتا
+گمنا
+گپیا
+گپھا
+گتکا
+گتیا
+گتھا
+گٹکا
+گٹھا
+گجیا
+گجھا
+گچھا
+گستا
+گشتا
+گسٹا
+گستا
+گشتا
+گشٹا
+گلبا
+گفتا
+گگلا
+گلتا
+گلشا
+گلفا
+گلکا
+گلنا
+گلیا
+گلہا
+گمتا
+گمگا
+گملا
+گمنا
+گمیا
+گنتا
+گنٹا
+گنجا
+گنگا
+گننا
+گنیا
+گیپا
+گیشا
+گیلا
+گینا
+گیہا
+گہتا
+گہکا
+گہگا
+گہما
+گہنا
+گھپا
+گھتا
+گھٹا
+گھچا
+گھسا
+گیشا
+گھلا
+گھما
+گھنا
+گھیا
+لبخا
+لبفا
+لبقا
+لبنا
+لبیا
+لبھا
+لپٹا
+لپسا
+لپشا
+لپکا
+لپنا
+لپھا
+لتبا
+لتجا
+لتغا
+لتفا
+لتما
+لتیا
+لتہا
+لتھا
+لٹتا
+لٹکا
+لٹنا
+لٹیا
+لٹھا
+لجبا
+لجلا
+لجما
+لجنا
+لجہا
+لجھا
+لچتا
+لچکا
+لچنا
+لچھا
+لحجا
+لحسا
+لحقا
+لخلا
+لستا
+لسٹا
+لسقا
+لسلا
+لسنا
+لشتا
+لشفا
+لشکا
+لصبا
+لصتا
+لصفا
+لطلا
+لعبا
+لعتا
+لعشا
+لعلا
+لعنا
+لعیا
+لغفا
+لغیا
+لفتا
+لفقا
+لفگا
+لفلا
+لفن
+لفیا
+لقتا
+لقضا
+لقفا
+لقما
+لقنا
+لقیا
+لقہا
+لکتا
+لکسا
+لکسا
+لکلا
+لکما
+لکنا
+لکیا
+لکھا
+لگتا
+لگما
+لگنا
+للچا
+للع
+للغا
+للفا
+للقا
+للکا
+لمبا
+لمثا
+لمجا
+لمحا
+لمخا
+لمسا
+لمشا
+لمضا
+لمطا
+لمعا
+لمفا
+لمقا
+لمکا
+لملا
+لمنا
+لمیا
+لنبا
+لنجا
+لنسا
+لنکا
+لنگا
+لنیا
+لنہا
+لنھا
+لیبا
+لیپا
+لیٹا
+لیجا
+لیخا
+لیسا
+لیتا
+لیچا
+لیشا
+لیفا
+لیکا
+لیگا
+لیلا
+لیما
+لینا
+لہٹا
+لہکا
+لہلا
+لہنا
+للہا
+مبنا
+مبیا
+مپنا
+متتا
+متحا
+متجا
+متخا
+متسا
+متصا
+متعا
+متفا
+متشا
+متضا
+متغا
+متقا
+متگا
+متلا
+متما
+متنا
+متیا
+متہا
+متھا
+مٹتا
+مٹکا
+مٹنا
+مٹیا
+مٹھا
+مثقا
+مجلا
+مجید
+مجھا
+مچتا
+مچکا
+مچلا
+مچنا
+محبا
+محتا
+محلا
+مختا
+مستا
+مسکا
+مسلا
+مسما
+مسنا
+مشتا
+مشٹا
+مشعا
+مشغا
+مصبا
+مصفا
+مصلا
+معتا
+معلا
+معما
+معیا
+مغلا
+مفتا
+مقنا
+مقیا
+مقتا
+مکتا
+مکٹا
+مکنا
+مکھا
+مگنا
+ملتا
+ملبا
+ملیا
+ملجا
+ملکا
+ملما
+ملنا
+ملہا
+ممبا
+ممتا
+ممیا
+منتا
+منجا
+منسا
+منشا
+منقا
+منکا
+منیا
+منگا
+مننا
+منہا
+منھا
+میبا
+میتا
+میٹا
+میجا
+میخا
+میسا
+میثا
+میچا
+میشا
+میعا
+میقا
+میکا
+میگا
+میلا
+میما
+مینا
+مہبا
+مہتا
+مہکا
+مہما
+مہنا
+مہیا
+نبٹا
+نبسا
+نبیا
+نبھا
+نپتا
+نپٹا
+نپنا
+نتبا
+نتتا
+نتخا
+نتشا
+نتصا
+نتظا
+نتفا
+نتقا
+نتنا
+نتیا
+نتہا
+نتھا
+نٹتا
+نٹھا
+نثبا
+نثیا
+نجبا
+نجنا
+نجہا
+نجھا
+نچتا
+نچسا
+نچکا
+نچلا
+نچنا
+نچیا
+نچھا
+نحصا
+نحطا
+نخشا
+نخلا
+نستا
+نسقا
+نسنا
+نسیا
+نسکا
+نضبا
+نصفا
+نضما
+نظما
+نعطا
+نعطا
+نعقا
+نعکا
+نعما
+نعنا
+نغما
+نفتا
+نفسا
+نفطا
+نفعا
+نفکا
+نقسا
+نقشا
+نقصا
+نقضا
+نقلا
+نقیا
+نکتا
+نکسا
+نکشا
+نکلا
+نکما
+نکنا
+نکھا
+نگتا
+نگسا
+نگتا
+نگسا
+نگلا
+نگنا
+نگیا
+نگھا
+نلٹا
+نلکا
+نلیا
+نمٹا
+نمنا
+ننکا
+ننگا
+ننیا
+ننھا
+نیپا
+نیتا
+نیچا
+نیسا
+نیشا
+نیفا
+نیکا
+نیگا
+نیلا
+نینا
+نہتا
+نہٹا
+نہضا
+نہلا
+نہما
+ئٹیا
+ئچیا
+ئشگا
+ئشیا
+ئمقا
+ئیسا
+ئیکا
+ئیگا
+یتنا
+یتیا
+یٹنا
+یٹھا
+یحتا
+یختا
+یستا
+کٹھا
+یختا
+یسپا
+یشما
+یشیا
+یغما
+یکبا
+یکتا
+یکجا
+یکسا
+یکیا
+یکھا
+یلٹا
+یلعا
+یلغا
+یلیا
+یمیا
+ینٹا
+ینکا
+ہٹنا
+ینگا
+ینیا
+ہبلا
+ہپتا
+ہتما
+ہٹتا
+ہجہا
+ہچکا
+ہسپا
+ہسکا
+ہشتا
+ہشکا
+ہسیا
+ہفتا
+ہکتا
+ہکلا
+ہکنا
+ہگتا
+ہگنا
+ہلتا
+ہلجا
+ہلسا
+ہلکا
+ہلگا
+ہلنا
+ہلیا
+ہمتا
+ہمچا
+ہمسا
+ہمکا
+ہمنا
+ہمیا
+ہنجا
+ہنسا
+ہنشا
+ہیکا
+ہیکا
+ہنگا
+ہنما
+ہنیا
+ہیٹا
+ہیجا
+ہیگا
+ہیلا
+ہیما
+ہیہا
+ھپتا
+ھپنا
+ہتکا
+ھتگا
+ھتیا
+ھجیا
+ھچکا
+ھسکا
+ھکتا
+ھکنا
+ھلتا
+ھلکا
+ھلنا
+ھمکا
+ھملا
+ھنتا
+ھنسا
+ھنکا
+ھنگا
+ھننا
+ھنیا
+ھیکا
+ھیگا
+ھیلا
+ھیما
+بجیب
+بخیب
+بسبب
+بطیب
+بلمب
+تعجب
+تعصب
+تعقب
+تغلب
+تقلب
+ثعلب
+ثقیب
+جیکب
+چنکب
+حبیب
+حسیب
+حلیب
+خطیب
+سلیب
+شعیب
+شکیب
+صلیب
+طبیب
+ظہیب
+عجیب
+غبغب
+قضیب
+قطیب
+قلیب
+کٹمب
+لبلب
+لبیب
+لطلب
+لعجب
+لعیب
+لغیب
+لقلب
+لکتب
+مجیب
+محب
+مطلب
+مطلب
+مکتب
+مکعب
+منصب
+منیب
+مہلب
+مہیب
+نجیب
+نخشب
+نشیب
+نصیب
+نقیب
+نہیب
+چھیپ
+سٹمپ
+سکیپ
+کیمپ
+کھیپ
+گیلپ
+لچسپ
+لیمپ
+ہلک
+ہیمپ
+بلیت
+بجہت
+بسنت
+بصحت
+بعثت
+بعلت
+بعیت
+بکیت
+بلیت
+بنجو
+بیبت
+بیعت
+بہجت
+بہشت
+بھبت
+بھکت
+بھگت
+بھنت
+بھیت
+پٹیت
+پچیت
+پلیت
+پنگت
+تحیت
+تعنت
+تہمت
+جبلت
+چپیت
+چکنت
+چلنت
+چمپت
+چھیت
+حبیت
+حسنت
+حسیت
+حشمت
+حقیت
+حکمت
+حمیت
+خجلت
+خشیت
+خصلت
+خلقت
+خلیت
+سبقت
+سبیت
+سجیت
+سچیت
+سلیت
+سمبت
+سمیت
+سنگت
+سینت
+شفقت
+شکست
+شگفت
+صحبت
+صلیت
+صنعت
+طلعت
+طینت
+ظلمت
+عجلت
+عصمت
+عظمت
+غفلت
+غلظت
+غیبت
+فصلت
+قسمت
+قعیت
+قفیت
+قلت
+قلیت
+قیمت
+کسبت
+کلفت
+کلیت
+کمیت
+کنشت
+کنیت
+کیست
+کھپت
+کھیت
+گلگت
+لحیت
+لسنت
+لصلت
+لعبت
+لعنت
+لکنت
+لکھت
+لگنت
+لمست
+لمیت
+مثبت
+مچکتی
+محبت
+محنت
+مسکت
+مسیت
+مشقت
+مشیت
+معیت
+منبت
+منت
+منیت
+میت
+مہلت
+مہنت
+مہیت
+نجیت
+نچنت
+نچیت
+نخست
+نسبت
+نسیت
+نشست
+نصفت
+نعمت
+نکبت
+نکہت
+نکھت
+نگشت
+نگہت
+نمنٹ
+نیست
+نہفت
+ئینت
+یکھت
+ینیت
+ہبیت
+ہسیت
+ہلگت
+ہلیت
+ہمیت
+ہنیت
+ہیبت
+ہئیت
+بسکٹ
+بسیٹ
+بگٹٹ
+بیلٹ
+بینٹ
+بھگت
+بھیٹ
+پلیٹ
+پیسٹ
+پیکٹ
+پینٹ
+پھپٹ
+پھکٹ
+پھیٹ
+تلپٹ
+ٹمنٹ
+ٹیسٹ
+ٹینٹ
+ٹھیٹ
+جمنٹ
+جیکٹ
+جھپٹ
+چپیٹ
+چمیٹ
+چیکٹ
+چینٹ
+چھنٹ
+سٹنٹ
+سٹیٹ
+سفیٹ
+سلپٹ
+سلیٹ
+سلہٹ
+سمپٹ
+سمیٹ
+سینٹ
+شلسٹ
+فلیٹ
+فیلٹ
+کسکٹ
+کلسٹ
+کلیٹ
+کمیٹ
+کیسٹ
+منگٹ
+نٹسٹ
+نگھٹ
+نلسٹ
+نمنٹ
+ئجسٹ
+یٹنٹ
+سبید
+یجنٹ
+یکیٹ
+یگیٹ
+یلیٹ
+تحنث
+خبیث
+لبعث
+للیث
+مبحث
+مثلث
+مخنث
+مغیث
+بھیج
+پسیج
+تشنج
+جھنج
+چینج
+چھیج
+خلیج
+ستلج
+سٹیج
+سفنج
+سکنج
+قلنج
+کلنج
+منتج
+منضج
+مہیج
+نٹیج
+نگیج
+نہیج
+بینچ
+بھنچ
+بھیچ
+پہنچ
+بھنچ
+تبیچ
+سپیچ
+سکیچ
+سینچ
+قینچ
+کھپچ
+کھنچ
+کھیچ
+گھنچ
+ملیچ
+صبیح
+صحیح
+فصیح
+قبیح
+لفتح
+مسبح
+مسطح
+مسلح
+مسیح
+مصلح
+مفتح
+ملیح
+بطیخ
+لشیخ
+مسلخ
+مطبخ
+بتکد
+بجند
+بحمد
+بعید
+بعہد
+بقید
+بلند
+بلید
+بیلد
+بیند
+بھگد
+بھند
+بھید
+پسند
+پلند
+پلید
+پنشد
+پیکد
+پیند
+پھبد
+پھپد
+پھلد
+پھند
+تشہد
+تعبد
+تعہد
+تقید
+تمند
+تیند
+تہجد
+تہمد
+ٹھند
+جلند
+جمعد
+جمند
+جیند
+جھند
+چشید
+چقند
+چکند
+چمکد
+چمگد
+چنند
+چنید
+چیند
+چھند
+چھید
+حمید
+خشند
+خمید
+سبکد
+سپید
+سبید
+سپند
+ستبد
+ستعد
+ستقد
+سٹید
+سعید
+سفند
+سفید
+سکند
+سگند
+سمند
+سنگد
+سیند
+شعبد
+شقند
+شمعد
+شمند
+شمید
+شنند
+شنید
+شہید
+صعید
+ضلعد
+عبید
+عقید
+علمد
+عملد
+غمکد
+عملد
+فقید
+فیصد
+قصید
+قلمد
+قلند
+قلید
+کبید
+کتخد
+کشید
+مبتد
+کلند
+کلید
+کمید
+کنند
+کھند
+کھید
+گلبد
+گمشد
+گنبد
+گیند
+لبلد
+لبید
+لتصد
+لتعد
+لجعد
+لحمد
+لخلد
+لسجد
+لسید
+لصمد
+لعبد
+لعہد
+لقصد
+لقعد
+لقند
+لکند
+لکھد
+لمبد
+لمسد
+لمصد
+لمقد
+لمہد
+لہند
+متبد
+متحد
+متعد
+متقد
+متمد
+مجلد
+مجید
+محمد
+مخلد
+مسند
+مشہد
+معبد
+معتد
+مفسد
+مفید
+مقتد
+مقصد
+مقعد
+مقلد
+مقید
+ملحد
+ملید
+منجد
+منعد
+منہد
+میکد
+میند
+مہتد
+نبید
+نٹند
+نجید
+نشید
+نفید
+نکھد
+نگند
+نگہد
+نمکد
+نمند
+نیند
+نہند
+یقعد
+ہلحد
+ہیند
+بلیڈ
+بیکڈ
+بینڈ
+بھنڈ
+پگنڈ
+پلیڈ
+پینڈ
+پھسڈ
+پھلڈ
+تھنڈ
+ٹیچڈ
+ٹینڈ
+ٹھنڈ
+جھلڈ
+جھنڈ
+چینڈ
+چھنڈ
+سپنڈ
+سپیڈ
+سٹیڈ
+سکنڈ
+سلنڈ
+سینڈ
+فیلڈ
+کسنڈ
+کمنڈ
+کنگڈ
+کنیڈ
+کینڈ
+کھمڈ
+کھنڈ
+گینڈ
+گہگڈ
+گھنڈ
+لپنڈ
+لکنڈ
+لمنڈ
+لینڈ
+میکڈ
+محمڈ
+میگڈ
+مینڈ
+نٹنڈ
+نفیڈ
+ئٹیڈ
+ئمنڈ
+ئیٹڈ
+یپنڈ
+یٹنڈ
+یٹیڈ
+یجنڈ
+یشنڈ
+یگیڈ
+ینیڈ
+ہینڈ
+تلمذ
+کتحذ
+لہذ
+مبتذ
+نبیذ
+بپھر
+بتصر
+بتھر
+بٹلر
+بٹیر
+بجکر
+بجھر
+بچکر
+بچھر
+بحیر
+بحیر
+بستر
+بسفر
+بسیر
+بسہر
+بشیر
+بصیر
+بغیر
+بکثر
+بکیر
+بکھر
+بگیر
+بگھر
+بلغر
+بلگر
+بلیر
+بمپر
+بمتر
+بمہر
+بنجر
+بنسر
+بنصر
+بنظر
+بنکر
+بنگر
+بیٹر
+بیسر
+بیکر
+بینر
+بیئر
+بہتر
+بہیر
+بھسر
+بھقر
+بھکر
+بھگر
+بھیر
+پتھر
+پیٹر
+پچھڑ
+پکچر
+پکھر
+پمبر
+پنجر
+پنیر
+پنھر
+پیپر
+پیتر
+پیڑ
+پیسر
+پیشر
+پیکر
+پیلر
+پیہر
+پھسر
+پھیر
+تبحر
+تبصر
+تتہر
+تحیر
+تشتر
+تشکر
+تشنر
+تشہر
+پیٹر
+تعطر
+تغیر
+تفکر
+تفیر
+تکبر
+تکسر
+تکھر
+تلیر
+تمیر
+تنتر
+تنصر
+تنفر
+تیتر
+تیسر
+تہتر
+تھپر
+تھیر
+ٹیٹر
+ٹمبر
+ٹمپر
+ٹنبر
+ٹنگر
+ٹیٹر
+ٹیچر
+ٹیکر
+ٹیلر
+ٹھتر
+ٹھٹر
+ٹھکر
+ٹھمر
+ٹھیر
+ٹھہر
+جیتر
+جتیر
+جسٹر
+جعفر
+جگتر
+جگہر
+جلتر
+جلیر
+جمپر
+جمعر
+جمیر
+جنتر
+جننر
+جنجر
+جیکر
+جیلر
+جھبر
+جھجر
+جھمر
+جھیر
+چبکر
+چپکر
+چتبر
+چتیر
+چتھر
+چٹکر
+چچیر
+چلپر
+چلتر
+چنکر
+چلٹر
+چمبر
+چنبر
+چیکر
+چیئر
+چہیر
+چھپر
+چھتر
+چھیر
+چھنر
+چھہر
+حصیر
+حضیر
+حطیر
+حظیر
+حقیر
+حکمر
+حمیر
+خنصر
+خبیر
+خطیر
+خمیر
+خنجر
+خنصر
+خیبر
+سپیر
+سپہر
+ستبر
+ستتر
+ستخر
+ستغر
+ستفر
+ستقر
+ستکر
+ستمر
+ستھر
+سٹلر
+سٹیر
+سسٹر
+سعیر
+سفیر
+سکتر
+سکھر
+سلفر
+سلہر
+سمبر
+سمیر
+سنتر
+سنٹر
+سنجر
+سنچر
+سنسر
+سنکر
+سنگر
+سنہر
+سفیر
+سکتر
+سکھر
+سلفر
+سلہر
+سمبر
+سمیر
+سنتر
+سنجر
+سنکر
+سیکر
+سنچر
+سنسر
+سنگر
+سنہر
+سیسر
+سیگر
+سیلر
+سیمر
+سینر
+سہسر
+شبگر
+شبیر
+شنجر
+شعیر
+شکیر
+شنجر
+شنکر
+شنگر
+شیفر
+شیکر
+شیئر
+شہپر
+شہیر
+صغیر
+صفیر
+ضمیر
+طبغر
+طستر
+طشتر
+طمطر
+ظہیر
+عبقر
+عبیر
+عبہر
+عبتر
+عسکر
+عسیر
+عشیر
+عمیر
+عنبر
+عنصر
+عنقر
+غفیر
+فطیر
+فقیر
+فلتر
+فلٹر
+فلیر
+فیچر
+فیسر
+قصیر
+قلمر
+قمطر
+قیصر
+کبیر
+کتھر
+کٹلر
+کٹہر
+کٹھر
+کثیر
+کچہر
+کسپر
+کستر
+کسٹر
+کسکر
+کسگر
+کسیر
+کشنر
+کلچر
+کلنسر
+کلیر
+کمبر
+کمتر
+کمسر
+کمیر
+کنٹر
+کنجر
+کنسر
+کنفر
+کنکر
+کنگر
+کئیر
+کیپر
+کیتر
+کیسر
+کیفر
+کیکر
+کیلر
+کیمر
+کیئر
+کہتر
+کھپر
+کھتر
+کھسر
+کھیر
+گبھر
+گٹکر
+گٹھر
+گستر
+گلبر
+گلسر
+گلہر
+گنجر
+گیبر
+گیسر
+گیلر
+گہیر
+گبھر
+گھتر
+گھگر
+گھیر
+لبحر
+لبحر
+لبقر
+لبیر
+لبہر
+لپسر
+لتحر
+لتصر
+لتغر
+لتنر
+لیتر
+لتھر
+لٹیر
+لجبر
+لجیر
+لحجر
+لحشر
+لخمر
+لحمر
+لخیر
+لسٹر
+لشتر
+لشعر
+لشکر
+لصخر
+لعصر
+لعمر
+لفجر
+لفطر
+لفقر
+لقطر
+لقمر
+لکبر
+لکٹر
+لکچر
+لکسر
+لکیر
+لگیر
+لمبر
+لمعر
+لمکر
+لنسر
+لنصر
+لنظر
+لنگر
+لنہر
+لیبر
+لیٹر
+لیجر
+لیحر
+لیسر
+لکیر
+لیگر
+لیئر
+مبشر
+مبصر
+مپیر
+متبر
+متحر
+متشر
+متصر
+متضر
+متفر
+متمر
+متیر
+متہر
+مٹکر
+مثمر
+مجیر
+مچیر
+مچھر
+محتر
+محشر
+محضر
+محقر
+محیر
+مخبر
+مختر
+مخیر
+مستر
+مسٹر
+مسخر
+مسطر
+مسکر
+مسمر
+مسیر
+مسہر
+مشتر
+مشجر
+مشعر
+مشنر
+مشیر
+مضطر
+مضمر
+مظہر
+مظفر
+معبر
+معتر
+معطر
+معمر
+مغفر
+مغیر
+مفتر
+مفسر
+مضطر
+مفکر
+مفلر
+مقبر
+مقشر
+مقطر
+مکسر
+ملٹر
+ملکر
+ملیر
+ممبر
+ممیر
+منبر
+منٹر
+منجر
+منحر
+منخر
+منسر
+منکر
+منتر
+منخر
+منشر
+منصر
+منظر
+منفر
+منگر
+منیر
+منہر
+مئیر
+میٹر
+میجر
+میسر
+میکر
+میشر
+میگر
+میئر
+میہر
+مہتر
+نبتر
+نسٹر
+نبیر
+نبھر
+نبہر
+نتھر
+نٹیر
+نجیر
+نحضر
+نستر
+نسفر
+نسلر
+نسہر
+نشتر
+نصیر
+نضیر
+نظیر
+نفیر
+نکیر
+نکھر
+نگتر
+نگھر
+نمبر
+نمیر
+ننگر
+ننیر
+نیچر
+نیکر
+نیگر
+نیمر
+نئیر
+نیہر
+نہتر
+ئبیر
+ئسچر
+ئسکر
+ئمبر
+ئمنر
+ئمیر
+ئنگر
+ئیٹر
+ئیجر
+ئیگر
+ئیمر
+یتھر
+ییٹر
+یسٹر
+یسیر
+یشنر
+یکٹر
+یکسر
+یکطر
+یمپر
+یمنر
+یمئر
+ینٹر
+ینجر
+ینگر
+ینیر
+ہٹکر
+ہٹلر
+ہسٹر
+ہلبر
+ہمبر
+ہمسر
+ہنٹر
+ہیٹر
+ہیلر
+بتکڑ
+بچھڑ
+بنگڑ
+بنکڑ
+بیہڑ
+بھسٹر
+بھیڑ
+پچھر
+پنجڑ
+پنگڑ
+پنیڑ
+پیکڑ
+پیلڑ
+پینڑ
+پھسڑ
+پھکڑ
+پھگڑ
+پھیڑ
+تیتڑ
+تتہڑ
+تکھڑ
+تگیڑ
+تیلڑ
+تھپڑ
+تھمڑ
+تھیڑ
+جھکڑ
+جھگڑ
+جھلڑ
+چتھڑ
+چیپڑ
+چیچڑ
+چھبڑ
+چھپڑ
+چھکڑ
+چھلڑ
+چھیڑ
+سکیڑ
+سگھڑ
+سیکڑ
+شیخڑ
+غنگڑ
+کچکڑ
+کلچڑ
+کلھڑ
+کنجڑ
+کیچڑ
+کیکڑ
+کھچڑ
+کھیڑ
+گٹھڑ
+گنجڑ
+گیلڑ
+لبھڑ
+لتھڑ
+لکھڑ
+لمبڑ
+کنگڑ
+لیبڑ
+لیجڑ
+لیچڑ
+لیکڑ
+مسیر
+مکھڑ
+نبیڑ
+نبھڑ
+نچسڑ
+نکھڑ
+ہتکڑ
+ہیجڑ
+ہیکڑ
+بعجز
+بلٹز
+بیجز
+بیگز
+بینز
+پلیز
+تمیز
+ٹیمز
+جہیز
+چھیز
+ستلز
+ستمز
+ستیز
+شمیز
+سیلز
+طبعز
+کتحذ
+کنگز
+کنیز
+گلیز
+گیمز
+لمعز
+لیگز
+لیمز
+لینز
+لہمز
+مستز
+معتز
+معجز
+ملتز
+ممیز
+منیز
+منہز
+میگز
+نپلز
+نگیز
+ننگز
+نینز
+ئینز
+یٹمز
+یٹیز
+یشنز
+یلیز
+یمیز
+ہلیز
+ببیس
+بتیس
+بلیس
+بنفس
+بیطس
+بیکس
+بھلس
+بھیس
+پچیس
+پلٹس
+پلیس
+پیپس
+پتیس
+پیٹس
+پیلس
+پینس
+پھپس
+پھلس
+پھنس
+پھیس
+تجسس
+تنفس
+تئیس
+ٹیکس
+ٹیمس
+ٹینس
+ٹھنس
+ٹھیس
+جبیس
+جسٹس
+جلیس
+جیمس
+جھلس
+چکلس
+چنٹس
+چیفس
+خسیس
+خمیس
+سپیس
+سسکس
+سلیس
+سیکس
+فلپس
+فیکس
+قبیس
+ققنس
+کتیس
+کٹلس
+کسیس
+کتیس
+کھنس
+کھیس
+گیٹس
+گھٹس
+لٹمس
+لشمس
+لعکس
+لمبس
+لنفس
+لینس
+مجلس
+مخمس
+مفلس
+منٹس
+میپس
+میٹس
+میکس
+مینس
+نتیس
+نینس
+نفیس
+ئسنس
+ئیٹس
+ٹیمس
+یفنس
+یکٹس
+یلس
+یننس
+ہبیس
+ہنیں
+ھنیس
+بخشش
+بنگش
+بینش
+پیچش
+تعیش
+جنبش
+جنیش
+چکلش
+حشیش
+خشخش
+کشمش
+گنیش
+لتمش
+لعطش
+مفتش
+مقیش
+مینش
+مہیش
+نگلش
+ہمیش
+تخلص
+تشخص
+خصیص
+قمیص
+لقصص
+مختص
+مخلص
+مفیص
+ملخص
+حضیض
+سعفض
+مفیض
+نقیض
+بسیط
+تحفظ
+تسلط
+ستخط
+محیط
+مسقط
+مسلط
+مقسط
+تحفظ
+تلفظ
+حفیظ
+غلیظ
+للفظ
+مغلظ
+بلیع
+تتبع
+تشیع
+تصنع
+تضیع
+تمتع
+جمیع
+سمیع
+شفیع
+شنیع
+لجمع
+لطبع
+لطیع
+مبلع
+مبیع
+متبع
+مجمع
+مسجع
+مطبع
+مطلع
+مطمع
+مطیع
+مقطع
+ملمع
+منبع
+بلیغ
+مبلغ
+تعفف
+تکلف
+ثقیف
+حلیف
+حنیف
+خفیف
+ضعیف
+عفیف
+فکیف
+کثیف
+کسیف
+لخیف
+لسیف
+لصف
+لطیف
+لکہف
+متصف
+مخفف
+مصحف
+مصنف
+مضعف
+مکلف
+منصف
+نچیف
+نحیف
+نظیف
+یلیف
+تبلق
+تعشق
+تعلق
+تعمق
+تغلق
+تملق
+خلیق
+سحق
+شفیق
+طبلق
+عتیق
+عقیق
+عمیق
+عنیق
+لعلق
+لقلق
+لئیق
+مبیق
+متفق
+محقق
+مشتق
+مشفق
+مطلق
+معلق
+مغلق
+ملحق
+منطق
+نبیق
+ہنبق
+بٹھک
+بلیک
+بیجک
+بیشک
+بینک
+بھبک
+بھپک
+بھٹک
+بھچک
+بھسک
+بھلک
+بھنک
+بھیک
+پبلک
+پشتک
+پشمک
+پکنک
+پیٹک
+پیچک
+پینک
+پھپک
+پھبک
+پھٹک
+پھسک
+پھلک
+پھنک
+تشکک
+تمثک
+تنبک
+تہتک
+تھپک
+تھلک
+ٹیٹک
+ٹیلک
+ٹینک
+ٹھٹک
+بھکل
+ٹھسک
+ٹھمک
+ٹھنک
+ٹھیک
+جسٹک
+جھپک
+جھٹک
+جھجک
+جھلک
+جھمک
+چبلک
+چشمک
+چمبک
+چنبک
+چیٹک
+چیچک
+چیلک
+چھپک
+چھپک
+چھٹک
+چھلک
+چھمک
+چھنک
+چھیک
+خشتک
+سپلک
+سلنگ
+سلیک
+سنیک
+سینک
+صحنک
+طبلک
+علیک
+عینک
+غلطک
+کٹسک
+کلنک
+کیتک
+کھٹک
+کھسک
+کھنک
+گھٹک
+لبیک
+لمپک
+لملک
+مستک
+مسلک
+مشبک
+مضحک
+ممسک
+منسک
+میٹک
+میجک
+مینک
+مہلک
+نتھک
+نیلک
+نیمک
+یکنک
+ینفک
+بتنگ
+بٹنگ
+بجنگ
+بکنگ
+بلنگ
+بیلگ
+بینگ
+بھنگ
+بھیگ
+پتنگ
+پلنگ
+پلیگ
+پینگ
+تفنگ
+تلنگ
+تھلگ
+ٹلنگ
+ٹینگ
+جگمگ
+جننگ
+جھنگ
+چننگ
+چینگ
+سٹنگ
+سسنگ
+سلنگ
+سینگ
+شپنگ
+شلنگ
+علیگ
+فٹنگ
+فلیگ
+کٹنگ
+کسنگ
+کلنگ
+کننگ
+کھنگ
+گینگ
+لفنگ
+لہنگ
+متنگ
+ملنگ
+نٹنگ
+نچنگ
+نہنگ
+ئپنگ
+ئٹنگ
+ئلنگ
+ئننگ
+یٹنگ
+یسنگ
+یلنگ
+یننگ
+ہینگ
+ھینگت
+بخیل
+بسمل
+بشکل
+بعمل
+بفضل
+بکیل
+بکھل
+بگیل
+بلبل
+بمثل
+بنکل
+بنیل
+بیقل
+بیکل
+بھسل
+بھگل
+بھیل
+پتیل
+پتھل
+پٹیل
+پگھل
+پنسل
+پنگل
+پیبل
+پینل
+پیپل
+پیتل
+پیکل
+پھسل
+پھیل
+تجمل
+تحمل
+تخیل
+تشکل
+تعطل
+تعقل
+تفصل
+تفضل
+تکسل
+تمثل
+تنقل
+پٹیل
+ثقیل
+ٹگھل
+ٹیبل
+ٹیکل
+ٹھیل
+ثقیل
+جلیل
+جمیل
+جنبل
+جنٹل
+جنگل
+جیکل
+جھٹل
+جھجل
+جھیل
+چتھل
+چٹیل
+چسکل
+چلچل
+چنبل
+چنچل
+چنگل
+چیپل
+چیتل
+چینل
+چھیل
+حنبل
+خلیل
+سبیل
+ستیل
+سٹیل
+سطبل
+سکیل
+سگنل
+سلسل
+سمپل
+سمگل
+سنبل
+سنچل
+سنکل
+سنگل
+سیمل
+سہگل
+سہیل
+شکیل
+صطبل
+صلصل
+صیقل
+طفیل
+عقیل
+علیل
+غفیل
+غلیل
+فتیل
+فصیل
+فضیل
+فلفل
+فیشل
+فیصل
+قبیل
+قتیل
+قلقل
+قلیل
+قضل
+کتھل
+کٹھل
+کچیل
+کحیل
+کفیل
+کلبل
+کلکل
+کلیل
+کمبل
+کنجل
+کیبل
+کیچل
+کیسل
+کیہل
+کھٹل
+کھکل
+کھیل
+گٹھل
+گلگل
+گھچل
+لحیل
+لعقل
+لفصل
+لفضل
+لفعل
+لفیل
+لکحل
+لکفل
+للیل
+لمثل
+لنٹل
+لنجل
+لنمل
+لیبل
+لیگل
+متصل
+مجمل
+محصل
+محفل
+محلل
+محمل
+محیل
+مختل
+مخمل
+مسہل
+مشعل
+مشکل
+معتل
+معجل
+معطل
+مفصل
+مقبل
+مقتل
+مقفل
+مکمل
+ململ
+ممثل
+منگل
+میبل
+میٹل
+مینل
+مہمل
+نبیل
+نتھلا
+نٹھل
+نجیل
+نچھل
+نسپل
+نشیل
+نکیل
+نیمل
+ئٹیل
+ئیکل
+یٹیل
+یجنل
+یشنل
+یلغا
+یلیل
+ینٹل
+ینجل
+ینمل
+ہلبل
+ہلچل
+ہیکل
+ہیگل
+ھکیل
+ھلمل
+بچشم
+بحکم
+بستم
+بعلم
+بقلم
+بلغم
+تمیم
+بیچم
+بیگم
+بھسم
+پچھم
+پشتم
+پنجم
+پنچم
+پیتم
+پیہم
+تبسم
+تحکم
+تظلم
+تعلم
+تفہم
+تکلم
+تمیم
+تیمم
+تھکم
+جپسم
+حجیم
+جسیم
+جنتے
+جنگم
+جہلم
+جہنم
+جھلم
+چیخم
+چہلم
+چھلم
+حطیم
+حکیم
+حلکم
+حلیم
+حمیم
+سٹیم
+سسٹم
+سقیم
+سکیم
+سکھم
+سلیم
+سنگم
+سہیں
+شبنم
+شحیم
+شلجم
+شلغم
+شمیم
+شیشم
+صلعم
+صمیم
+ضخیم
+ضیغم
+طلسم
+ظلکم
+ظلہم
+عظیم
+عقیم
+علیم
+عمیم
+عنہم
+غنیم
+فہیم
+قسیم
+قلیم
+کسٹم
+کشتم
+کلیم
+کلہم
+کھلم
+کھیم
+گتھم
+گشتم
+گلیم
+گھسم
+لجہم
+لحکم
+لحیم
+لشتم
+لشٹم
+لعلم
+لفہم
+لقلم
+للحم
+للہم
+لنجم
+لئیم
+لیئم
+مبہم
+مجسم
+محکم
+مخیم
+مسلم
+مصمم
+مظلم
+معجم
+معظم
+معلم
+مغلم
+مقیم
+ملہم
+منجم
+منضم
+منظم
+منعم
+منیم
+میٹم
+میثم
+نسیم
+نعیم
+نگھم
+نیلم
+ئیٹم
+یتیم
+یلکم
+یمیم
+ینیم
+ہشتم
+ہفتم
+ہلکم
+ہنگم
+ھنگم
+بلین
+بجھن
+بچپن
+بچھن
+بحسن
+بضین
+بعین
+بقین
+بلبن
+بلین
+بئین
+بیٹن
+بیسن
+بیشن
+بیگن
+بیلن
+بہمن
+بھجن
+بھین
+پٹکن
+پٹین
+پچپن
+پچھم
+پشین
+پکین
+پلٹن
+پلین
+پنشن
+پیلن
+پھبن
+پھٹن
+پھکن
+پھننا
+پھین
+تپکن
+تسنن
+تعفن
+تعین
+تفنن
+تیقن
+تیلن
+تھکن
+ٹپکن
+ٹنگن
+ٹیشن
+ٹیکن
+ٹھکن
+ثمین
+ثنین
+جبین
+جیٹن
+جھکن
+جھلن
+جھین
+چبھن
+چپکن
+چپلن
+چپلن
+چٹخن
+چسکن
+چکٹن
+چلتن
+چلمن
+چمٹن
+چنین
+چیپن
+چھپن
+چھٹن
+چھکن
+چھنن
+چھین
+حبشن
+حسین
+حصین
+حفتن
+حقین
+حمن
+حنین
+سبین
+سپلن
+سپین
+ستین
+سٹین
+سکشن
+سکین
+سلگن
+سلین
+سمین
+سیٹن
+سیشن
+سیگن
+سیلن
+شفین
+صمین
+ضعین
+ظمین
+غضبن
+فطین
+فظین
+فقین
+فیشن
+فیمن
+کٹھن
+کلتن
+کلمن
+کلین
+کمسن
+کمین
+کنچن
+کنگن
+کنلن
+کیبن
+کیچن
+کیشن
+گلبن
+گلشن
+گیلن
+گیمن
+گھٹن
+گھسن
+لپٹن
+لٹکن
+لجین
+لجھن
+لچکن
+لچھن
+لحسن
+لحین
+لعین
+لفین
+لقین
+لکجن
+لکھن
+لمین
+لنکن
+لیٹن
+لیشن
+لیکن
+لیمن
+لینن
+لہسن
+مبین
+متحن
+متین
+مٹھن
+مثمن
+محسن
+مسکن
+مشین
+معجن
+معین
+مقنن
+مکمن
+مکین
+مکھن
+مگین
+ملٹن
+ملین
+ممکن
+منچن
+منمن
+منین
+میشن
+میگن
+میمن
+مہین
+نپین
+نٹین
+نجمن
+نچھن
+نشین
+نچھن
+نطین
+نگٹن
+نگین
+نیشن
+ئبین
+ئقین
+ئلین
+یشین
+یفین
+یقین
+یکشن
+یلین
+یمین
+ہستن
+ہلین
+ہنگن
+ہیگن
+ہیلن
+بتیں
+بٹیں
+بجیں
+پسیں
+بچیں
+پسیں
+بقیں
+بکیں
+بلیں
+بنیں
+بہیں
+پتیں
+پٹیں
+پجیں
+پچیں
+پشیں
+پکیں
+پلیں
+پئیں
+پھیں
+تپیں
+تتیں
+تچیں
+تشیں
+تکیں
+تگیں
+تلیں
+تنیں
+تئیں
+تھیں
+ٹپیں
+ٹتیں
+ٹکیں
+ٹلیں
+ٹھیں
+ثتیں
+جبیں
+جتیں
+جٹیں
+جپیں
+جچیں
+جگیں
+جلیں
+جمیں
+جنیں
+جئیں
+جھیں
+چپیں
+چبیں
+چتیں
+چٹیں
+چسیں
+چقیں
+چکیں
+چگیں
+چلیں
+چنیں
+چئیں
+چھیں
+حتیں
+حٹیں
+حسیں
+حنیں
+خسیں
+ستیں
+سچیں
+سشیں
+سکیں
+سلیں
+سمیں
+سنیں
+سہیم
+ششیں
+شقیں
+صحین
+صفیں
+صلیں
+ظتیں
+عتیں
+عظیں
+فتیں
+فطیں
+فمیں
+قتیں
+قمیں
+کتیں
+کٹیں
+کجیں
+کچیں
+کسیں
+کلیں
+کمیں
+کہیں
+کھیں
+گپیں
+گتیں
+گچیں
+گلیں
+گمیں
+گنیں
+گئیں
+لتیں
+لٹیں
+لچیں
+لفیں
+لکیں
+لگیں
+لنیں
+لیکن
+مبیں
+مٹیں
+مجیں
+متیں
+مچیں
+مسیں
+مکیں
+مگیں
+ملیں
+مہیں
+نپیں
+نتیں
+نٹیں
+نجیں
+نخیں
+نچیں
+نسیں
+نشیں
+نقیں
+نگیں
+نہیں
+نھیں
+ئٹیں
+ئشیں
+ئفیں
+ئلیں
+ئنیں
+یتیں
+یثیں
+یخیں
+یفیں
+یکیں
+یقیں
+یگیں
+یلیں
+یمیں
+ہپیں
+ہتیں
+ہٹیں
+ہشیں
+ہکیں
+ہگیں
+ہلیں
+ہمیں
+ہنیں
+ہئیں
+ھکیں
+ھلیں
+ھنیں
+بپتو
+بتیو
+بتھو
+بٹلو
+بٹنو
+بٹیو
+بٹھو
+بجنو
+بجھو
+بچتو
+بچکو
+بچلو
+بچیو
+بچھو
+بحثو
+بحصو
+بحضو
+بختو
+بخشو
+بخیو
+بشمو
+بشنو
+بطخو
+بعضو
+بعنو
+بغچو
+بغلو
+بقچو
+بقعو
+بکٹو
+بکسو
+بکلو
+بکیو
+بگلو
+بگھو
+بلبو
+بلٹو
+بلتو
+بلکو
+بلو
+بلیو
+بلہو
+بمبو
+بنٹو
+بنجو
+بنسو
+بنکو
+بیتو
+بیٹو
+بیجو
+بیحو
+بیچو
+بیسو
+بیضو
+بیکو
+بیگو
+بیلو
+بیمو
+بینو
+بیہو
+بہبو
+بہتو
+بہکو
+بہلو
+بہنو
+بھبو
+بھٹو
+بھپو
+بھجو
+بھچو
+بھسو
+بھکو
+بھگو
+بھلو
+بھنو
+پئپو
+پتلو
+پٹخو
+پٹکو
+پٹیو
+پٹھو
+پچتو
+پچکو
+پچھو
+پختو
+پستو
+پسلو
+پسیو
+پشتو
+پشیو
+پکھو
+پگلو
+پلٹو
+پلکو
+پمپو
+پنپو
+پنجو
+پنگو
+پیپو
+پیٹو
+پیچو
+پیسو
+پیشو
+پیکو
+پیلو
+پیمو
+پیئو
+پیہو
+پہلو
+پہنو
+پہیو
+پھبو
+پھپو
+پھٹو
+پھچو
+پھکو
+پھچو
+پھگو
+پھلو
+پھنو
+تپکو
+تتلو
+تحفو
+تختو
+تسلو
+تسمو
+تسنو
+تکیو
+تکھو
+تمبو
+تمغو
+تمکو
+تنبو
+تنخو
+تنکو
+تیٹو
+تیجو
+تیسو
+تیغو
+تیلو
+تیمو
+تینو
+تھجو
+تھکو
+تھلو
+تھمو
+تھنو
+تھیو
+ٹپکو
+ٹخنو
+ٹکٹو
+ٹکلو
+ٹکیو
+ٹنگو
+ٹیپو
+ٹیٹو
+ٹیسو
+ٹیکو
+ٹیشو
+ٹیگو
+ٹیلو
+ٹیمو
+ٹہلو
+ٹہنو
+ٹھسو
+ٹھکو
+ٹھگو
+ٹھلو
+ٹھنو
+ٹھئو
+ٹھیو
+ثیقو
+ثیمو
+جبھو
+جتنو
+جستو
+جسکو
+جسمو
+جشنو
+جگتو
+جگنو
+جگہو
+جلسو
+جمبو
+جملو
+جمہو
+جنتو
+جنجو
+جنسو
+جنگو
+جنمو
+جنیو
+جنہو
+جیبو
+جیپو
+جیتو
+جیحو
+جیسو
+جیشو
+جیلو
+جینو
+جیہو
+جہتو
+جھکو
+جھلو
+جھمو
+جھنو
+چبکو
+چبلو
+چبھو
+چپٹو
+چپکو
+چپلو
+چتلو
+چٹخو
+چٹکو
+چٹلو
+چٹیو
+چٹھو
+چچیو
+چسکو
+چسنو
+چشمو
+چسنو
+چکٹو
+چکلو
+چکمو
+چکنو
+چکیو
+چکھو
+چلغو
+چلمو
+چلھو
+چمبو
+چمٹو
+چمپو
+چمچو
+چمکو
+چمنو
+چنٹو
+چنیو
+چیپو
+چیتو
+چیخو
+چیکو
+چیلو
+چہکو
+چہنو
+چھپو
+چھتو
+چھٹو
+چھجو
+چھکو
+چھلو
+چھنو
+حبتو
+حجتو
+حجلو
+حشتو
+حشیو
+حکمو
+حلفو
+حلقو
+حلیو
+حمتو
+حمقو
+حملو
+حیتو
+حیلو
+ختنو
+خشبو
+خشنو
+خشیو
+خصمو
+خصیو
+خطبو
+خلتو
+خلفو
+خلقو
+خلیو
+خمیو
+خیمو
+سبعو
+سبغو
+سبکو
+سپنو
+ستخو
+ستصو
+ستکو
+ستلو
+سٹکو
+سٹلو
+سٹیو
+سٹھو
+سجنو
+سخنو
+سخیو
+سسکو
+سطحو
+سعتو
+سفلو
+سقمو
+سکتو
+سکیو
+سلحو
+سکیو
+سکھو
+سگنو
+سلجو
+سلفو
+سلکو
+سلگو
+سلیو
+سمپو
+سمتو
+سمٹو
+سمنو
+سنبو
+سنپو
+سنتو
+سنجو
+سنکو
+سنگو
+سنلو
+سیبو
+سیٹو
+سیخو
+سیسو
+سیکو
+سیلو
+سیمو
+سینو
+سہلو
+سہمو
+شبخو
+شبکو
+شبہو
+شتیو
+شخصو
+شعبو
+شغلو
+شفٹو
+شکلو
+شکنو
+شگنو
+شلفو
+شمشو
+شمعو
+شملو
+شمنو
+شنٹو
+شنیو
+شیخو
+شیشو
+شیعو
+شیلو
+شہتو
+شہسو
+صبحو
+صبہو
+صحتو
+صحنو
+صفتو
+صفحو
+صلو
+صلیو
+صلا
+صنفو
+صیتو
+صیغو
+صیلو
+صیہو
+ضگیو
+ضلعو
+طبقو
+طبلو
+طشتو
+طعنو
+طمیو
+طنبو
+طیسو
+ظمیو
+ظیفو
+عصفو
+عظمو
+عفتو
+عقلو
+عکسو
+علتو
+علمو
+عملو
+عنفو
+عیبو
+عیتو
+عیسو
+غبتو
+غبیو
+غلبو
+غنچو
+فتحو
+فتنو
+فسٹو
+فصلو
+فضلو
+فعتو
+فعلو
+فغفو
+فلمو
+فلیو
+فیتو
+فیسو
+فیقو
+فیلو
+فینو
+فہمو
+قبضو
+قبلو
+قتلو
+قتیو
+قسطو
+قسمو
+قشقو
+قصبو
+قضیو
+قطعو
+قلتو
+قلعو
+قلمو
+قلیو
+قیبو
+قیطو
+قیفو
+قیقو
+قیلو
+کبھو
+کتبو
+کتنو
+کتیو
+کتھو
+کٹکو
+کٹیو
+کٹھو
+کچکو
+کجکو
+کجلو
+کچلو
+کچھو
+کتھو
+کستو
+کسٹو
+کسفو
+کسلو
+کشتو
+کشٹو
+کشکو
+کشیو
+کعتو
+کفنو
+ککھو
+کلبو
+کلتو
+کلپو
+کلثو
+کلچو
+کلکو
+کلمو
+کلیو
+کلہو
+کمبو
+کمپو
+کمجو
+کمخو
+کملو
+کمیو
+کنبو
+کنٹو
+کنجو
+کنسو
+کنکو
+کیبو
+کنگو
+کیپو
+کیتو
+کیچو
+کیسو
+کیکو
+کیلو
+کیمو
+کینو
+کہلو
+کھپو
+کھتو
+کھٹو
+کھجو
+کھچو
+کھسو
+کھکو
+کھلو
+کھنو
+کھیو
+گپکو
+گتھو
+گٹکو
+گٹھو
+گچھو
+گسٹو
+گلگو
+گلیو
+گملو
+گنجو
+گنگو
+گنیو
+گیتو
+گیسو
+گیلو
+گیمو
+گیہو
+گہکو
+گہنو
+گھپو
+گھٹو
+گھجو
+گھچو
+گھسو
+گھگو
+گھلو
+گھنو
+گھیو
+لبمو
+لپٹو
+لپکو
+لتصو
+لتیو
+لٹکو
+لٹیو
+لثبو
+لجھو
+لچکو
+لچھو
+لحتو
+لحظو
+لحقو
+لحکو
+لخصو
+لسٹو
+لسطو
+لسلو
+لشتو
+لشعو
+لشکو
+لصبو
+لطو
+لعفو
+لعلو
+لعمو
+لغتو
+لغفو
+لغنو
+لغیو
+لفتو
+لفٹو
+لفطو
+لفظو
+لفنو
+لقلو
+لقمو
+لقیو
+لکیو
+لکھو
+لگنو
+لگیو
+لمبو
+لمپو
+لمحو
+لمصو
+لمکو
+لمیو
+لنکو
+لنگو
+لنیو
+لیپو
+لیٹو
+لیحو
+لیچو
+لیسو
+لیفو
+لیقو
+لیکو
+لیگو
+لیلو
+لیمو
+لینو
+لیہو
+لہٹو
+لہجو
+لہچو
+لہکو
+لہلو
+لہنو
+مبسو
+مبعو
+مبلو
+مبہو
+متبو
+متصو
+متلو
+متمو
+متنو
+متھو
+مٹکو
+مٹلو
+مٹیو
+مٹھو
+مثلو
+مثنو
+مجبو
+سنبھا
+مجمو
+مجنو
+مجہو
+مجھو
+مچکو
+مچلو
+مچھو
+محبو
+محتو
+محجو
+محشو
+محضو
+محظو
+محفو
+محکو
+محلو
+محمو
+مخبو
+مختو
+مخصو
+مخطو
+مخلو
+مخمو
+مسبو
+مسٹو
+مستو
+مسجو
+مسطو
+مسعو
+مسکو
+مسلو
+مسمو
+مسنو
+مسئو
+مشحو
+مشغو
+مشقو
+مشکو
+مشمو
+مشہو
+مصلو
+مصمو
+مصنو
+مصئو
+مضبو
+مضمو
+مطبو
+مطلو
+مطعو
+مظبو
+مظنو
+معبو
+معتو
+معجو
+معشو
+معصو
+معطو
+معقو
+معکو
+معلو
+معمو
+معنو
+معیو
+معہو
+مغسو
+مغشو
+مغضو
+مغفو
+مغلو
+مغمو
+مفتو
+مفعو
+مفقو
+مفلو
+مفہو
+مقبو
+مقتو
+مفسو
+مقصو
+مقلو
+مقہو
+مکتو
+مکحو
+مکسو
+مکشو
+مکنو
+مکھو
+ملبو
+ملتو
+ملحو
+ملعو
+ملغو
+ملفو
+ملکو
+ملنو
+ملیو
+مملو
+ممنو
+منتو
+منٹو
+منچو
+منحو
+منسو
+منشو
+منصو
+منطو
+منظو
+منقو
+منگو
+منکو
+منلو
+منیو
+منھو
+میتو
+میٹو
+میجو
+میخو
+میچو
+میسو
+میشو
+میکو
+میگو
+میلو
+میمو
+مینو
+مہجو
+مہکو
+مہمو
+نبٹو
+نبضو
+نبیو
+نبھو
+نپٹو
+نپجو
+نپلو
+نتھو
+نٹیو
+نٹھو
+نجسو
+نجشو
+نجنو
+نجھو
+نچلو
+نچھو
+نحضو
+نخلو
+نسپو
+نسبو
+نسٹو
+نستو
+نسخو
+نسکو
+نسلو
+نسیو
+نطفو
+نظمو
+نعتو
+نعشو
+نعلو
+نغمو
+نفسو
+نفعو
+نفلو
+نقشو
+نقصو
+نقلو
+نکتو
+نکٹو
+نکسو
+نکلو
+نکمو
+نکھو
+نگپو
+نگٹو
+نگلو
+نگیو
+نگھو
+نلکو
+نلیو
+نمٹو
+نمکو
+ننگو
+ننھو
+نیبو
+نیتو
+نیٹو
+نیجو
+نیسو
+نیشو
+نیفو
+نیکو
+نیگو
+نیلو
+نیمو
+نینو
+نہتو
+نہٹو
+نہجو
+ئٹیو
+ئچیو
+ئفلو
+ئلٹو
+ئنگو
+ئیسو
+ئیکو
+ئیلو
+ئینو
+ینپو
+یتھو
+یٹمو
+یٹئو
+یجنو
+یچھو
+یستو
+یشنو
+یشیو
+یعتو
+یعسو
+یعقو
+یکٹو
+یکسو
+یکنو
+یکیو
+یکھو
+یگچو
+یلبو
+یلٹو
+یلیو
+ینٹو
+ینکو
+ینگو
+ہچکو
+ہفتو
+ہکلو
+ہلکو
+ہلگو
+ہمتو
+ہمجو
+ہمچو
+ہمخو
+ہمکو
+ہنجو
+ہنسو
+ہیٹو
+ہیلو
+ہیمو
+ہینو
+ھتیو
+ھجیو
+ھچکو
+ھلکو
+ھمکو
+ھنکو
+ھنگو
+سقئہ
+صفحہ
+ئحئہ
+یچئہ
+ببلی
+ببئی
+بپتی
+بتتی
+بتنی
+بٹتی
+بٹلی
+بٹنی
+بجتی
+بجلی
+بجنی
+بجھی
+بچتی
+بچکی
+بچگی
+بچلی
+بچنی
+بچھی
+بحثی
+بختی
+بخشی
+بستی
+بسنی
+بطخی
+بطنی
+بعضی
+بغچی
+بغضی
+بغلی
+بقچی
+بکتی
+بکٹی
+بکسی
+بکنی
+بکئی
+بکھی
+بگتی
+بگھی
+بلتی
+بلٹی
+بلخی
+بلسی
+بلغی
+بلکی
+بللی
+بلنی
+بلہی
+بمپی
+بنتی
+بنٹی
+بنجی
+بنسی
+بنکی
+بنگی
+بننی
+بیتی
+بیٹی
+بیجی
+بیچی
+بیسی
+بیشی
+بیعی
+بیگی
+بیلی
+بینی
+بہتی
+بہکی
+بہلی
+بہنی
+بھتی
+بھٹی
+بھجی
+بھچی
+بھسی
+بھکی
+بھگی
+بھلی
+بھنی
+بھئی
+پئبی
+پپلی
+پپتی
+پتکی
+پتلی
+پتنی
+پتھی
+پٹتی
+پٹخی
+پٹکی
+پٹنی
+پٹھی
+پجتی
+پجنی
+پچتی
+پچکی
+پچنی
+پچھی
+پخنی
+پستی
+پسلی
+پسنی
+پشتی
+پکتی
+پکشی
+پکنی
+پگلی
+پلتی
+پلٹی
+پلنی
+پمپی
+پپنی
+پنجی
+پنکی
+پیتی
+پیٹی
+پیسی
+پیشی
+پیلی
+پینی
+پہلی
+پہنی
+پھبی
+پھپی
+پھٹی
+پھسی
+پھکی
+پھگی
+پھلی
+پھنی
+تبتی
+تبلی
+تبھی
+تپتی
+تپشی
+تتلی
+تتئی
+تجتی
+تجلی
+تجنی
+تجھی
+تچتی
+تچنی
+تحتی
+تحلی
+تختی
+تخمی
+تسلی
+تشتی
+تشفی
+تشکی
+تضی
+تکتی
+تکنی
+تگتی
+تگنی
+تلتی
+تلخی
+تلسی
+تلکی
+تللی
+تلنی
+تمنی
+تنتی
+تنکی
+تنگی
+تننی
+تیبی
+تیجی
+تیخی
+تیسی
+تیلی
+تہجی
+تھپی
+تھتی
+تھجی
+تھکی
+تھلی
+تھمی
+تھنی
+تھئی
+ٹپتی
+ٹپکی
+ٹپنی
+ٹخنی
+ٹکنی
+ٹکتی
+ٹکلی
+ٹکنی
+ٹگنی
+ٹلتی
+ٹلنی
+ٹمنی
+ٹنگی
+ٹیپی
+ٹیچی
+ٹیکی
+ٹیلی
+ٹیمی
+ٹینی
+ٹہلی
+ٹہنی
+ٹھتی
+ٹھسی
+ٹھگی
+ٹھلی
+ٹھنی
+ثقفی
+ثیقی
+ثیمی
+جبلی
+جبھی
+جپتی
+جپسی
+جپنی
+جتتی
+جتنی
+جٹھی
+جچتی
+جچگی
+جچنی
+جچئی
+جسکی
+جسمی
+جعتی
+جعلی
+جفتی
+جگتی
+جگنی
+جلتی
+جلقی
+جلنی
+جمتی
+جمعی
+جمنی
+جنبی
+جنمی
+جنتی
+جنجو
+جنسی
+جنکی
+جنگی
+جنمی
+جننی
+جیبی
+جیتی
+جیجی
+جیحی
+جیسی
+جیکی
+جیلی
+جیمی
+جینی
+جیہی
+جہتی
+جھتی
+جھکی
+جھگی
+جھلی
+جھنی
+چبتی
+چبکی
+چبلی
+چبنی
+چبھی
+چپتی
+چپٹی
+چپکی
+چپلی
+چپنی
+چتتی
+چتلی
+چتنی
+چٹتی
+چٹخی
+چٹکی
+چٹنی
+چٹھی
+چچلی
+چستی
+چسکی
+چسنی
+چشتی
+چشمی
+چغلی
+چکتی
+چکٹی
+چکلی
+چکنی
+چکئی
+چکھی
+چگتی
+چگنی
+چلتی
+چلنی
+چمپی
+چمٹی
+چمچی
+چمکی
+چملی
+چمنی
+چنتی
+چنگی
+چننی
+چیپی
+چیخی
+چیسی
+چیلی
+چینی
+چہکی
+چہلی
+چبھی
+چھپی
+چھٹی
+چھتی
+چھچی
+چھلی
+چھنی
+چھئی
+حبشی
+حتمی
+حتی
+حجتی
+حسبی
+حسنی
+حکمی
+حلبی
+حلفی
+حلقی
+حلمی
+حمتی
+حنفی
+حیضی
+حیمی
+خبطی
+ختگی
+ختمی
+ختنی
+ختئی
+خستی
+خشکی
+خصتی
+خصمی
+خطمی
+خفگی
+سفلی
+خلتی
+خلقی
+خلفی
+خمچی
+خنکی
+سبکی
+سبھی
+سپتی
+ستتی
+ستکی
+ستگی
+ستلی
+ستمی
+سٹکی
+سٹلی
+سٹھی
+سجتی
+سجنی
+سچلی
+سختی
+سسپی
+سستی
+سسکی
+سسلی
+سطحی
+سطی
+سفلی
+سقنی
+سکتی
+سکسی
+سکنی
+سکھی
+سگسی
+سگنی
+سلبی
+سلتی
+سلکی
+سلگی
+سلمی
+سلنی
+سمبی
+سمتی
+سمٹی
+سمسی
+سمعی
+سمنی
+سنبی
+سنتی
+سنٹی
+سنکی
+سنگی
+سنلی
+سننی
+سیبی
+سیپی
+سیتی
+سیسی
+سیفی
+سیعی
+سیقی
+سیکی
+سیلی
+سیمی
+سینی
+سیہی
+سہتی
+سہلی
+سہمی
+سہنی
+شبعی
+شبلی
+شٹمی
+شخصی
+شخطی
+شطحی
+شفقی
+شکتی
+شکلی
+شکمی
+شکنی
+شگتی
+شگنی
+شمسی
+شمعی
+شمنی
+شیخی
+شیشی
+شیعی
+شہکی
+شہنی
+ضحی
+صلبی
+صلگی
+صیتی
+صیعی
+ضبطی
+ضحی
+ضلعی
+ضمنی
+طبی
+طبعی
+طبلی
+طفلی
+طلبی
+طیبی
+طیسی
+طینی
+ظلمی
+ظہبی
+عجمی
+عشقی
+عشی
+عصبی
+عظمی
+عقبی
+عقلی
+عکسی
+علتی
+علمی
+علی
+عملی
+عمی
+عنہی
+عیبی
+عیتی
+عینی
+غبتی
+غچلی
+غضبی
+غلطی
+غلنی
+غلئی
+غیبی
+فتگی
+فتنی
+فصلی
+فضلی
+فعلی
+ففٹی
+فقہی
+فلکی
+فلمی
+فیضی
+فیقی
+فیلی
+فیمی
+فہمی
+قبطی
+قسمی
+قصی
+قطبی
+قطعی
+قفلی
+قلبی
+قلعی
+قلفی
+قلمی
+قمچی
+قیسی
+قیفی
+قیقی
+کبکی
+کبھی
+کپٹی
+کتنی
+کٹتی
+کٹکی
+کٹنی
+کٹھی
+کجلی
+کچلی
+کچھی
+کسبی
+کستی
+کسلی
+کسنی
+کشتی
+کشفی
+کعتی
+کفنی
+کلبی
+کلتی
+کلٹی
+کلچی
+کلغی
+کلفی
+کلکی
+کلنی
+کمبی
+کمپی
+کمتی
+کمٹی
+کملی
+کمنی
+کنجی
+کنکی
+کنگی
+کیتی
+کیچی
+کیسی
+کیفی
+کیکی
+کیلی
+کہتی
+کہنی
+کھبی
+کھپی
+کھتی
+کھٹی
+کھجی
+کھسی
+کھلی
+کھنی
+گپتی
+گپکی
+گتھی
+گٹکی
+گٹھی
+گجنی
+گجئی
+گجھی
+گچھی
+گشتی
+گفتی
+گلتی
+گلٹی
+گلجی
+گلنی
+گمتی
+گمٹی
+گملی
+گمنی
+گنتی
+گنجی
+گنگی
+گننی
+گیتی
+گیسی
+گیلی
+گینی
+گہکی
+گہمی
+گہنی
+گھپی
+گھٹی
+گھسی
+گھگی
+گھلی
+گھنی
+لبنی
+لپٹی
+لپسی
+لپکی
+لٹتی
+لٹکی
+لٹنی
+لجھی
+لچتی
+لچکی
+لچنی
+لچھی
+لحتی
+لحئی
+لخمی
+لسٹی
+لسکی
+لسئی
+لشتی
+لطفی
+لعلی
+لغنی
+لفظی
+لقمی
+لکتی
+لکٹی
+لکشی
+لکنی
+لکھی
+لگتی
+لگنی
+لمبی
+لمکی
+لنبی
+لنکی
+لنگی
+لیپی
+لیتی
+لیٹی
+لیچی
+لیسی
+لیفی
+لیقی
+لیکی
+لیگی
+لیمی
+لینی
+لیئی
+لیہی
+لہٹی
+لہکی
+لہی
+مبنی
+متقی
+متکی
+متلی
+متنی
+متھی
+مٹتی
+مٹکی
+مٹنی
+مٹھی
+مثنی
+مجھی
+مچتی
+مچکی
+مچلی
+مچنی
+مچھی
+محبی
+محیی
+مخفی
+مستی
+مسکی
+مسلی
+مسنی
+مشتی
+مشفی
+مشقی
+مشکی
+مصفی
+مضی
+معنی
+مغلی
+مغنی
+مفتی
+مقئی
+مکتی
+مکنی
+مکئی
+مکھی
+مگسی
+ملتی
+ملٹی
+ملکی
+ملی
+ملنی
+ممٹی
+منتی
+منجی
+منشی
+منفی
+منقی
+منکی
+منگی
+مننی
+منی
+میٹی
+میجی
+میچی
+میسی
+میشی
+میکی
+میلی
+میمی
+مینی
+مہکی
+مھیی
+نبتی
+نبٹی
+نبھی
+نپتی
+نپٹی
+نپنی
+نبچی
+نتتی
+نتنی
+نتھی
+نٹتی
+نٹنی
+نٹھی
+نجتی
+نجشی
+نجفی
+نجمی
+نجنی
+نجھی
+نچتی
+نچکی
+نچلی
+نچنی
+نچھی
+نحلی
+نسبی
+نستی
+نسٹی
+نسلی
+نسنی
+نظمی
+نغمی
+نفسی
+نفلی
+نقشی
+نقلی
+نکتی
+نکٹی
+نکسی
+نکلی
+نکمی
+نکنی
+نکھی
+نگتی
+نگلی
+نگنی
+نگہی
+نگھی
+نلکی
+نمٹی
+نمنی
+ننگی
+ننھی
+نیتی
+نیثی
+نیچی
+نیشی
+نیکی
+نیگی
+نیلی
+نیمی
+نینی
+نہٹی
+نہلی
+نہنی
+ئنسی
+ئیسی
+ئیشی
+ئیگی
+ئیلی
+ئینی
+یتنی
+یٹمی
+یحیی
+یختی
+یخنی
+یشمی
+یعتی
+یعنی
+یکتی
+یکھی
+یگچی
+یلٹی
+یلچی
+یلسی
+یلمی
+یلہی
+یمنی
+ینٹی
+ہٹتی
+ہٹنی
+ہچکی
+ہستی
+ہسکی
+ہسلی
+ہسنی
+ہضمی
+ہکتی
+ہکلی
+ہکنی
+ہگتی
+ہگلی
+ہلتی
+ہلکی
+ہلگی
+ہلنی
+ہمتی
+ہمکی
+ہمگی
+ہمنی
+ہنسی
+ہنکی
+ہنگی
+ہیتی
+ہیٹی
+ہیلی
+ہیمی
+ھپتی
+ھپنی
+ھستی
+ھسنی
+ھکتی
+ھکنی
+ھلتی
+ھلکی
+ھلنی
+ھمکی
+ھنتی
+ھنسی
+ھنکی
+ھنگی
+ھننی
+ھیلی
+ھیمی
+ھینی
+بپتے
+بتتے
+بتنے
+بتئے
+بٹتے
+بٹنے
+بٹئے
+بجتے
+بجنے
+بجئے
+بجھے
+بچتے
+بچکے
+بچلے
+بچنے
+بچئے
+بچھے
+بختے
+بخشے
+بخئے
+بخیے
+بستے
+بسکے
+بسنے
+بسئے
+بعضے
+بغچے
+بقچے
+بقعے
+بکتے
+بکٹے
+بکسے
+بکلے
+بکنے
+بکئے
+بگلے
+بگھے
+بلتے
+بلٹے
+بلسے
+بلکے
+بللے
+بلنے
+بلئے
+بنتے
+بنٹے
+بنجے
+بننے
+بنئے
+بیتے
+بیٹے
+بیجے
+بیچے
+بیضے
+بیلے
+بیمے
+بینے
+بہتے
+بہکے
+بہلے
+بہنے
+بہئے
+بھٹے
+بھجے
+بھچے
+بھکے
+بھگے
+بھلے
+بھنے
+پتتے
+پتلے
+پتنے
+پتئے
+پتھے
+پٹتے
+پٹخے
+پٹکے
+پٹنے
+پٹئے
+پٹھے
+پجتے
+پجنے
+پجئے
+پچتے
+پچکے
+پچنے
+پچئے
+پچھے
+پستے
+پسنے
+پسئے
+پشتے
+پکتے
+پکنے
+پکئے
+پگلے
+پلتے
+پلٹے
+پلنے
+پلئے
+پپنے
+پنتے
+پنجے
+پیپے
+پیتے
+پیٹے
+پیسے
+پیشے
+پیلے
+پینے
+پیئے
+پہلے
+پہنے
+پہئے
+پھبے
+پھٹے
+پھسے
+پھکے
+پھلے
+پھنے
+تپتے
+تپکے
+تپنے
+تپئے
+تتلے
+تتمے
+تجتے
+تجنے
+تجئے
+تجھے
+تچتے
+تچنے
+تچئے
+تحفے
+تختے
+تسلے
+تسمے
+تشنے
+تکتے
+تکلے
+تکنے
+تکیے
+تکئے
+تگتے
+تگنے
+تلتے
+تللے
+تلنے
+تلئے
+تمغے
+تنتے
+تنکے
+تننے
+تنئے
+تیجے
+تیشے
+تیلے
+تینے
+تھپے
+تھتے
+تھجے
+تھکے
+تھلے
+تھمے
+تھنے
+تھئے
+ٹپتے
+ٹپکے
+ٹپنے
+ٹپئے
+ٹخنے
+ٹکتے
+ٹکلے
+ٹکنے
+ٹکئے
+ٹلتے
+ٹلٹے
+ٹلنے
+ٹلئے
+ٹنٹے
+ٹنگے
+ٹیپے
+ٹیکے
+ٹیلے
+ٹینے
+ٹہلے
+ٹہنے
+ٹھتے
+ٹھٹے
+ٹھسے
+ٹھکے
+ٹھگے
+ٹھلے
+ٹھنے
+ٹھئے
+ثیقے
+جپتے
+جپنے
+جپئے
+جتتے
+جتنے
+جتئے
+جتھے
+جٹتے
+جٹھے
+جٹنے
+جٹئے
+جچتے
+جچنے
+جچئے
+جسکے
+جفتے
+جکتے
+جگتے
+جگنے
+جگئے
+جلتے
+جلسے
+جلنے
+جلئے
+جمتے
+جمعے
+جملے
+جمنے
+جمئے
+جنتے
+جنسے
+جنکے
+جننے
+جنئے
+جنھے
+جیتے
+جیسے
+جینے
+جیئے
+جھتے
+جھکے
+جھلے
+جھنے
+جھئے
+چبتے
+چبکے
+چبلے
+چبنے
+چبئے
+چبھے
+چپتے
+چپٹے
+چپکے
+چپنے
+چپئے
+چتتے
+چتنے
+چتئے
+چٹپے
+چٹتے
+چٹخے
+چٹکے
+چٹلے
+چٹنے
+چٹئے
+چٹھے
+چسکے
+چشمے
+چکتے
+چکٹے
+چکلے
+چکمے
+چکنے
+چکئے
+چکھے
+چگتے
+چگنے
+چگئے
+چلتے
+چلنے
+چلئے
+چمپے
+چمٹے
+چمچے
+چمکے
+چنتے
+چنکے
+چنگے
+چننے
+چنئے
+چیپے
+چیتے
+چیخے
+چیلے
+چہکے
+چھپے
+چھتے
+چھٹے
+چھجے
+چھچے
+چھکے
+چھلے
+چھنے
+چھئے
+حجلے
+حلقے
+حلئے
+حملے
+حیلے
+ختنے
+خشکے
+خطبے
+خلئے
+خیلے
+خیمے
+سپنے
+ستتے
+ستلے
+ستئے
+سٹکے
+سجتے
+سجنے
+سجئے
+سختے
+سخنے
+سستے
+سسکے
+سفلے
+سکتے
+سکنے
+سکئے
+سگتے
+سگنے
+سگئے
+سگلے
+سلتے
+سلحے
+سلکے
+سلگے
+سلنے
+سلئے
+سمبے
+سمٹے
+سمنے
+سنتے
+سنجے
+سنکے
+سنگے
+سنلے
+سننے
+سیتے
+سیسے
+شیشے
+سیلے
+سینے
+سیئے
+سہتے
+سہلے
+سہمے
+سہنے
+سہئے
+شخصے
+شعبے
+شعلے
+شکتے
+شکنے
+شگتے
+شگنے
+شملے
+شیشے
+شیلے
+شیئے
+صفحے
+صیغے
+ضحے
+ضلعے
+طبقے
+طبلے
+طعنے
+بقعے
+ظیفے
+علے
+عملے
+غصے
+غلبے
+غنچے
+فتنے
+فضلے
+فیتے
+فیلے
+فینے
+قبضے
+قبلے
+قتلے
+قشقے
+قصبے
+قطعے
+قعئے
+قلعے
+قیقے
+قیمے
+کبکے
+کتبے
+کتلے
+کتنے
+کتھے
+کٹتے
+کٹکے
+کٹنے
+کٹئے
+کٹھے
+کجلے
+کچلے
+کستے
+کسلے
+کسنے
+کسئے
+کعبے
+کلتے
+کلچے
+کلمے
+کلنے
+کلئے
+کملے
+کمنے
+کنبے
+کنجے
+کنکے
+کیسے
+کیفے
+کیکے
+کیئے
+کیلے
+کہتے
+کہکے
+کہنے
+کہئے
+کھبے
+کھپے
+کھتے
+کھٹے
+کھسے
+کھلے
+کھنے
+کھئے
+گپکے
+گپھے
+گتکے
+گتھے
+گٹکے
+گٹھے
+گجھے
+گلتے
+گلنے
+گلئے
+گمتے
+گملے
+گمنے
+گمئے
+گنتے
+گنجے
+گننے
+گنئے
+گیگے
+گیلے
+گہکے
+گہنے
+گھپے
+گھتے
+گھٹے
+گچھے
+گھسے
+گھلے
+گھنے
+گھئے
+لپٹے
+لپکے
+لٹتے
+لٹکے
+لٹنے
+لٹئے
+لجھے
+لچتے
+لچکے
+لچنے
+لچئے
+لچھے
+لشتے
+لقمے
+لکتے
+لکنے
+لکئے
+لکھے
+لگتے
+لگنے
+لگئے
+لمبے
+لمحے
+لمکے
+لمیے
+لنگے
+لیپے
+لیٹے
+لیجے
+لیچے
+لیسے
+لیکے
+لیگے
+لیمے
+لینے
+لیئے
+لہٹے
+لہجے
+لہکے
+متتے
+متلے
+متنے
+متھے
+مٹتے
+مٹکے
+مٹنے
+مٹئے
+مثلے
+مجلے
+مجھے
+مچتے
+مچکے
+مچلے
+مچنے
+مچئے
+مچھے
+محلے
+مستے
+مسے
+مسکے
+مسلے
+مسنے
+مسئے
+مشتے
+مشکے
+معمے
+مکتے
+مکنے
+مکئے
+ملبے
+ملتے
+ملنے
+ملئے
+منتے
+منکے
+منگے
+مننے
+میٹے
+میجے
+میچے
+میکے
+میلے
+میئے
+مہکے
+نبٹے
+نبھے
+نپتے
+نپٹے
+نپنے
+نپئے
+نتتے
+نٹتے
+نٹنے
+نٹئے
+نجتے
+نجنے
+نجھے
+نچتے
+نچکے
+نچلے
+نچنے
+نچھے
+نحلے
+نخشے
+نستے
+نسخے
+نسلے
+نسنے
+نسئے
+نشچے
+نطفے
+نغمے
+نفعے
+نقشے
+نقطے
+نکتے
+نکٹے
+نکسے
+نکلے
+نکمے
+نکنے
+نکئے
+نکھے
+نگتے
+نگٹے
+نگلے
+نگنے
+نگئے
+نگھے
+نلکے
+نمٹے
+ننگے
+ننھے
+نیٹے
+نیچے
+نیفے
+نیلے
+نہتے
+نہلے
+ئینے
+یتنے
+یٹھے
+یجئے
+یکتے
+یکھے
+یگچے
+یلٹے
+ہپتے
+ہپنے
+ہپئے
+ہٹتے
+ہٹنے
+ہٹئے
+ہچکے
+ہفتے
+ہکتے
+ہکلے
+ہکنے
+ہکئے
+ہگتے
+ہگنے
+ہگئے
+ہلتے
+ہلکے
+ہلگے
+ہلنے
+ہلئے
+ہمتے
+ہمکے
+ہمنے
+ہنسے
+ہٹیے
+ہیضے
+ھپتے
+ھپنے
+ھپئے
+ھچکے
+ھکتے
+ھکنے
+ھکئے
+ھلتے
+ھلکے
+ھلنے
+ھلئے
+ھمکے
+ھنتے
+ھنسے
+ھنکے
+ھنگے
+ھننے
+ھنئے
+ھنیے
+ھیلے
+ھیمے
+ھینے
+بخیہ
+بستہ
+بسکہ
+بغچہ
+بقچہ
+بقعہ
+بقیہ
+بلکہ
+بلیہ
+بمعہ
+بغچہ
+بیحہ
+بیشہ
+بیضہ
+بیعہ
+بیگہ
+بیلہ
+بیمہ
+بینہ
+پٹنہ
+پختہ
+پستہ
+پسنہ
+پشتہ
+پنبہ
+پنجہ
+پیسہ
+پیشہ
+پہیہ
+تتمہ
+تتیہ
+تحفہ
+تحیہ
+تختہ
+تخمہ
+تسمہ
+تشتہ
+تشنہ
+تغمہ
+تفتہ
+تقیہ
+تکمہ
+تکیہ
+تلخہ
+تلہہ
+تمغہ
+تنبہ
+تنگہ
+تیجہ
+تیشہ
+تیغہ
+تہیہ
+ٹکیہ
+ٹیکہ
+ٹیلہ
+ثیبہ
+جبکہ
+جبہہ
+جستہ
+جفتہ
+جلسہ
+جمعہ
+جملہ
+جنبہ
+جیعہ
+جیہہ
+چستہ
+چشمہ
+چکمہ
+چلتہ
+چمبہ
+چمچہ
+چیچہ
+چیمہ
+حبشہ
+حجتہ
+حجفہ
+حجلہ
+حسنہ
+حشفہ
+حقنہ
+حلقہ
+حلیہ
+حمتہ
+حملہ
+حمنہ
+حیطہ
+حیلہ
+حیمہ
+ختنہ
+خستہ
+خشکہ
+خصیہ
+خطبہ
+خطحہ
+خفتہ
+خفیہ
+خلیفہ
+خلیہ
+خمسہ
+خیمہ
+سبحہ
+ستمہ
+سفلہ
+سقہ
+سکتہ
+سکنہ
+سلحہ
+سلمہ
+سنبہ
+سیسہ
+سیفہ
+سیلہ
+سینہ
+شبکہ
+شبیہ
+شحنہ
+شستہ
+شعبہ
+شعفہ
+شغفہ
+شفتہ
+شفعہ
+شمسہ
+شملہ
+شنبہ
+شیبہ
+شیتہ
+شیشہ
+شیعہ
+شیلہ
+صبیہ
+صفحہ
+صفیہ
+صلچہ
+صیحہ
+صیعہ
+صیغہ
+ضحیہ
+ضعطہ
+ضیکہ
+ضیمہ
+ضیلہ
+طبقہ
+طبلہ
+طعمہ
+طعنہ
+طلبہ
+طمتہ
+طمیہ
+طنجہ
+طیبہ
+طیسو
+طیکہ
+ظیفہ
+عتبہ
+عشبہ
+عصبہ
+عضلہ
+عطیہ
+علفہ
+علیہ
+عملہ
+غبطہ
+غشتہ
+غلبہ
+غلطہ
+غنچہ
+فتحہ
+فتنہ
+فضلہ
+فعیہ
+فغفو
+فقیہ
+فیعہ
+فیقہ
+فینہ
+قبضہ
+قتلہ
+قحبہ
+قشقہ
+قصبہ
+قضیہ
+قطعہ
+قلبہ
+قلعہ
+قلیہ
+قمشہ
+قیقہ
+قیمہ
+کپچہ
+کتبہ
+کشتہ
+کعبہ
+کفچہ
+کلبہ
+کلچہ
+کلمہ
+کلیہ
+کنبہ
+کنیہ
+کیسہ
+کینہ
+کہنہ
+گنجفہ
+گستہ
+گشتہ
+گفتہ
+گینہ
+گہنہ
+لبتہ
+لجثہ
+لحجہ
+لحظہ
+لصفہ
+لطمہ
+لطہ
+لفتہ
+لقصہ
+لقطہ
+لقمہ
+للہ
+للھ
+لمحہ
+لمعہ
+لمیہ
+لیچہ
+لیلہ
+لیمہ
+لہجہ
+متعہ
+مثلہ
+مجلہ
+محلہ
+مسکہ
+معمہ
+مقلہ
+ملبہ
+ملکہ
+میلہ
+میمہ
+نبیہ
+نجمہ
+نستہ
+نسخہ
+نسیہ
+نطفہ
+نغمہ
+نفقہ
+نقشہ
+نقطہ
+نقیہ
+نکتہ
+نگیہ
+نملہ
+نیفہ
+نیلہ
+ئستہ
+ئنچہ
+ئیسہ
+ئیکہ
+ئیلہ
+ئینہ
+یبیہ
+یجتہ
+یختہ
+یفتہ
+یقظہ
+یگچہ
+ینکہ
+ہستہ
+ہفتہ
+ہلیہ
+ہیضہ
+ہیمہ
+ہینہ
+ھنیہ
+ھیلہ
+بیٹھ
+پنتھ
+پنکھ
+پیتھ
+ٹھٹھ
+جیتھ
+جیٹھ
+جھٹھ
+چیتھ
+چھٹھ
+سکچھ
+سلجھ
+سمجھ
+سنکھ
+سنگھ
+سیٹھ
+سیکھ
+کسٹھ
+کمبھ
+لنگھ
+لیتھ
+لیٹھ
+لیکھ
+ملچھ
+منجھ
+میٹھ
+میکھ
+میگھ
+مینھ
+نسٹھ
+یسٹھ
+ینٹھ
+ہیتھ
+بقیہ
+حتی
+صلو
+ضحی
+عشی
+علی
+منی
+یحیی
+بطنا
+جیہا
+حلفا
+خصتا
+سہلا
+ضمنا
+طبعا
+عبید
+غصبا
+عقلا
+عملا
+فعلا
+قطعا
+قعتا
+لصتا
+لفظا
+مثلا
+نسلا
+نسیا
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/5grams.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/5grams.txt
new file mode 100644 (file)
index 0000000..f61dbce
--- /dev/null
@@ -0,0 +1,5029 @@
+ببیسا
+بپتنا
+بتکتا
+بتیسا
+بتیلا
+بتھلا
+بجبجا
+بجلیا
+بجھتا
+بجھیا
+بچپنا
+بچکتا
+بچلتا
+بچھتا
+بچھیا
+بحثیا
+بختیا
+بخشتا
+بستگا
+بستیا
+بسیما
+بطگیا
+بغچیا
+بقچیا
+بکبکا
+بکستا
+بکسلا
+بکسیا
+بکیلا
+بگستا
+بگھیا
+بلبلا
+بلٹتا
+بلٹیا
+بلکتا
+بللا
+بلنگا
+بلیسا
+بلیغا
+بلیلا
+بنٹتا
+بنجتا
+بنگلا
+بیتتا
+بیتلا
+بیتیا
+بیٹھا
+بیجتا
+بیچتا
+بیسیا
+بیشما
+بیکسا
+بیکلا
+بیگما
+بیلتا
+بینتا
+بینکا
+بیننا
+بھبھا
+بہکتا
+بہلتا
+بہنیا
+بہئیا
+بہیما
+بھبکا
+بھبھا
+بھلتا
+بھپکا
+بھتنا
+بھٹکا
+بھٹیا
+بھجتا
+بھجیا
+بھچتا
+بھچکا
+بھچنا
+بھسکا
+بھکتا
+بھکیا
+بھگتا
+بھگیا
+بھلیا
+بھینا
+پپلیا
+پپیتا
+پپیہا
+پتلیا
+پتنگا
+پتنیا
+پتیلا
+پتھتا
+پتھنا
+پٹپٹا
+پٹختا
+پٹخیا
+پٹکتا
+پٹیلا
+پٹیما
+پٹھیا
+پچپچا
+پچکتا
+پچھتا
+پچلج
+پچیا
+پستیا
+پسلیا
+پسنگا
+پسیجا
+پسینا
+پشیما
+پکپکا
+پگلتا
+پگلیا
+پگھلا
+پلپلا
+پلٹتا
+پلٹیا
+پلیتا
+پنپتا
+پنجتا
+پنجسا
+پنجنا
+پنچسا
+پنکھا
+پنیلا
+پنیھا
+پنھیا
+پیپٹا
+پیپگا
+پیپلا
+پیٹتا
+پیٹیا
+پیٹھا
+پیچھا
+پیستا
+پیشتا
+پیشکا
+پیشیا
+پیلبا
+پیلپا
+پیلتا
+پیلیا
+پینتا
+پہنتا
+پہنچا
+پہننا
+پھبتا
+پھبکا
+پھبنا
+پھپسا
+پھپکا
+پھپیا
+پھپھا
+پھٹتا
+پھٹکا
+پھٹگا
+پھٹنا
+پھسکا
+پھسلا
+پھکتا
+پھلتا
+پھلکا
+پھلنا
+پھنتا
+پھنسا
+پھنکا
+پھننا
+پھنیا
+پھیکا
+پھیلا
+تپسیا
+تپکتا
+تتلیا
+تتئیا
+تثینا
+تجلیا
+تجملا
+تحفظا
+تحکما
+تختیا
+تسلیا
+تشنگا
+تعصبا
+تعلقا
+تعلا
+تعیشا
+تعینا
+تکتکا
+تکلفا
+تکلیا
+تلتلا
+تلخیا
+تلملا
+تلنگا
+تمتما
+تمسکا
+تمکنا
+تنبیا
+تنتنا
+تنکتا
+تنگیا
+تیجتا
+تیکھا
+تیلیا
+تینتا
+تھپتا
+تھپکا
+تھپنا
+تھتکا
+تھتھا
+تھجتا
+تھکتا
+تھلتا
+تھلکا
+تھلنا
+تھلیا
+تھمتا
+تھنچا
+تھیا
+تھیلا
+ٹپٹپا
+ٹپکتا
+ٹپیلا
+ٹخنیا
+ٹکٹکا
+ٹکسٹا
+ٹکسلا
+ٹکلیا
+ٹگھلا
+ٹلٹلا
+ٹمٹما
+ٹنٹنا
+ٹنگتا
+ٹیپتا
+ٹیکتا
+ٹیکسا
+ٹیکنا
+ٹیکتا
+ٹینٹا
+ٹہلتا
+ٹہلیا
+ٹہنیا
+ٹھپنا
+ٹھٹکا
+ٹھٹھا
+ٹھستا
+ٹھسکا
+ٹھسنا
+ٹھکتا
+ٹھگتا
+ٹھگیا
+ٹھلتا
+ٹھلیا
+ٹھمکا
+ٹھنتا
+ٹھنسا
+ٹھنکا
+ٹھننا
+ٹھیبا
+ٹھیکا
+ٹھیگا
+ٹھیلا
+جیتتا
+جستھا
+جسیلا
+جعلسا
+جعلیا
+جگتیا
+جگجگا
+جگمگا
+جلبلا
+جلیبا
+جمیکا
+جنٹیا
+جنجنا
+جنسیا
+جنگلا
+جیتتا
+جیٹھا
+جینیا
+جھپٹا
+جھپکا
+جھٹکا
+جھٹلا
+جھٹنا
+جھجکا
+جھجلا
+جھجنا
+جھکتا
+جھکیا
+جھگیا
+جھلتا
+جھلسا
+جھلکا
+جھلما
+جھلنا
+جھلیا
+جھمکا
+جھجنا
+جھنکا
+جھنگا
+جھیلا
+جھینا
+چبکتا
+چبینا
+چبھتا
+چپتیا
+چپٹتا
+چپچپا
+چپکتا
+چپکیا
+چپیٹا
+چتھلا
+چٹختا
+چٹکتا
+چٹکلا
+چٹکیا
+چٹنیا
+چٹیلا
+چٹھیا
+چسکتا
+چسکیا
+چسنیا
+چشتیا
+چغلیا
+چکٹتا
+چکلتا
+چکنیا
+چکھتا
+چلبلا
+چلچلا
+چلکنا
+چلیپا
+چمٹتا
+چمٹیا
+چمچما
+چمچیا
+چمکتا
+چمنیا
+چنبھا
+چنچنا
+چنکیا
+چنگلا
+چنگنا
+چنگیا
+چنگھا
+چیپتا
+چیتپا
+چیختا
+چیستا
+چیلکا
+چینٹا
+چینگا
+چہچہا
+چہکتا
+چہیتا
+چھپتا
+چھپکا
+چھپنا
+چھتیا
+چھٹتا
+چھٹکا
+چھٹنا
+چھٹیا
+چھچکا
+چھلتا
+چھلکا
+چھلیا
+چھنتا
+چھنگا
+چھننا
+چھیجا
+چھیکا
+چھیلا
+چھینا
+حتینا
+حسینا
+حکیما
+حنفیا
+حیتنا
+حیثیا
+خصتیا
+خطیبا
+خفتگا
+خلفشا
+خمچیا
+خمیسا
+خنخنا
+سبکسا
+سبکنا
+سبکیا
+سبلیا
+سبیتا
+ستبصا
+ستبعا
+ستثنا
+ستحسا
+ستحصا
+ستحقا
+ستحکا
+ستخفا
+ستخلا
+ستسقا
+ستشہا
+ستعجا
+ستعقا
+ستعلا
+ستعما
+ستغفا
+ستغنا
+ستفتا
+ستفسا
+ستفہا
+ستقبا
+ستقلا
+ستکبا
+ستکشا
+ستکما
+ستلیا
+ستنبا
+ستنجا
+ستیصا
+ستیعا
+ستیلا
+ستیہا
+ستھیا
+سٹکتا
+سٹنہا
+سٹھیا
+سجنیا
+سجیلا
+سختیا
+سسکتا
+سسکیا
+سکیلا
+سکھلا
+سکھیا
+سلٹنا
+سلجھا
+سلسلا
+سلگتا
+سلمہا
+سلنگا
+سلیکا
+سلیما
+سمٹتا
+سمجھا
+سمیٹا
+سنبھا
+سنجتا
+سنجھا
+سنچکا
+سنسنا
+سنکتا
+سنکیا
+سنگسا
+سنگلا
+سنگھا
+سنیگا
+سنیما
+سیپیا
+سیتلا
+سیٹھا
+سیستا
+سیکھا
+سیلتا
+سیمیا
+سینتا
+سینچا
+سینکا
+سینگا
+سینما
+سینیا
+سہلتا
+سہمتا
+شتیہا
+شخصیا
+شطحیا
+شکیبا
+شگنیا
+شلنگا
+شلیتا
+شمنیا
+شنگھا
+شیخیا
+شیشیا
+شہنشا
+ضعیفا
+ضمحلا
+طبیعا
+طلبگا
+طلسما
+طمینا
+طیلسا
+عسقلا
+عصبیا
+عملیا
+عنہما
+غسلخا
+غصیلا
+غضبنا
+غلبلا
+غلطیا
+غمگسا
+غنغنا
+فتحیا
+فتینا
+فسنجا
+فضیتا
+فعلیا
+فلکیا
+فلمسا
+فلیپا
+فیضیا
+فیلبا
+فیلپا
+فہمیا
+قلتیا
+قلفیا
+قلمکا
+قلیما
+کپکپا
+کٹکتا
+کٹنیا
+کٹیکا
+کٹیلا
+کٹھلا
+کٹھنا
+کچکچا
+کچلتا
+کچیلا
+کچھنا
+کسبیا
+کسلتا
+کسلیا
+کسنبا
+کسیلا
+کشتگا
+کشتیا
+ککھلا
+کلبلا
+کلپنا
+کلتکا
+کلٹیا
+کلچیا
+کلسنا
+کلغیا
+کلکتا
+کلکلا
+کلکنا
+کلیجا
+کلیسا
+کلھیا
+کمٹھا
+کملتا
+کمیسا
+کمیلا
+کمھلا
+کنٹھا
+کنجیا
+کنکتا
+کنکیا
+کنگلا
+کنگنا
+کنگھا
+کنلیا
+کنمنا
+کنہیا
+کیتیا
+کیتھا
+کیٹلا
+کیخلا
+کیسیا
+کیشیا
+کیفیا
+کیقبا
+کیکبا
+کیکتا
+کیلتا
+کیمیا
+کینیا
+کیہلا
+کہکشا
+کھپٹا
+کھپلا
+کھپنا
+کھتیا
+کھٹکا
+کھٹلا
+کھٹنا
+کھٹیا
+کھجلا
+کھستا
+کھسکا
+کھسلا
+کھسنا
+کھسیا
+کھکھا
+کھلتا
+کھلگا
+کھلنا
+کھلیا
+کھمبا
+کھما
+کھنچا
+کھنسا
+کھنگا
+کھتیا
+کھیسا
+کھیلا
+کھینا
+گپکتا
+گتھتا
+گتھیا
+گٹکتا
+گٹکیا
+گٹھتا
+گٹھیا
+گجگجا
+گچھیا
+گشتپا
+گلبہا
+گلٹیا
+گلستا
+گلگلا
+گنتیا
+گنٹھا
+گنجیا
+گنگنا
+گنہگا
+گیگلا
+گہکتا
+گھپتا
+گھپلا
+گھپنا
+گھٹتا
+گھٹکا
+گھٹنا
+گھٹیا
+گھچلا
+گھستا
+گھسیا
+گھگیا
+گھلتا
+گھلیا
+گھمسا
+گھنٹا
+گھنسا
+گھنیا
+گھیگا
+گھیلا
+لبلبا
+لبیلا
+لپٹتا
+لپکتا
+لپلپا
+لپیٹا
+لٹکتا
+لیٹنا
+لٹھیا
+لجلجا
+لجھتا
+لجھیا
+لچکتا
+لچلچا
+لچھتا
+لچھیا
+لحمقا
+لحمیا
+لخلخا
+لسبحا
+لسلسا
+لشعشا
+لشہبا
+لطلا
+لعلما
+لفظیا
+لفنگا
+لکشیا
+لکلیا
+لکھتا
+لکھیا
+لگنیا
+لگیلا
+للبقا
+لمپیا
+لمتعا
+لمتخا
+لمکتا
+لمیعا
+لنجھا
+لنگتا
+لنگیا
+لنگھا
+لیپتا
+لیٹتا
+لیچتا
+لیچیا
+لیستا
+لیسیا
+لیکھا
+لہکتا
+لہلہا
+لہنگا
+لہنیا
+لہیا
+مبتلا
+مبہیا
+متصفا
+متھتا
+مٹکتا
+مٹکیا
+مٹھیا
+مجسما
+مجلا
+مچکتا
+مچلتا
+محسنا
+محصنا
+محققا
+محکما
+محنتا
+مختیا
+مخلصا
+مخمسا
+مسبحا
+مستجا
+مستعا
+مشفقا
+مشکبا
+مشکلا
+مشکیا
+مصلحا
+معلقا
+معلما
+مغلظا
+مغیلا
+مفصلا
+مفلسا
+مقتضا
+مقطعا
+مکھنا
+مکھیا
+ملگجا
+ملنسا
+ملیسا
+ممکنا
+منجلا
+منجنا
+منجھا
+منچلا
+منشیا
+منصفا
+منگتا
+منگلا
+منگنا
+منگیا
+منمنا
+منیلا
+منہنا
+منہیا
+میٹتا
+میٹیا
+میٹھا
+میجتا
+میچتا
+میگھا
+میلیا
+میمنا
+میہما
+مہکتا
+مہملا
+مہنتا
+مہنگا
+مہیلا
+مہینا
+نبٹتا
+ننجتا
+نبھتا
+نپٹتا
+نپجتا
+نتیلا
+نتھلا
+نتھنا
+نتھیا
+نٹنیا
+نٹینا
+نٹھتا
+نجمنا
+نجھتا
+نچنیا
+نچھتا
+نشیلا
+نظمیا
+نفسیا
+نکسلا
+نکلتا
+نکمیا
+نکیلا
+نکھتا
+نکھیا
+نگستا
+نگلتا
+نگلیا
+نگیلا
+نگہبا
+نگھتا
+نمٹتا
+نمسکا
+نمکیا
+ننھیا
+نیٹنا
+نیشیا
+نیکیا
+نیکھا
+نیمیا
+ئیشیا
+ئیگیا
+یپلکا
+یتیلا
+یخنیا
+یستبا
+یکھتا
+یگچیا
+یگستا
+یمپلا
+ینٹھا
+ینکتا
+ینگتا
+ینگیا
+ہپہپا
+ہتھیا
+ہٹکنا
+ہٹیلا
+ہٹھیا
+ہچکتا
+ہچکچا
+ہچکیا
+ہسپتا
+ہستیا
+ہلبلا
+ہلپھا
+ہلگتا
+ہلینا
+ہلہلا
+ہمپشا
+ہمکتا
+ہمکیا
+ہنستا
+ہنسیا
+ہنگیا
+ہنہنا
+ہیلنا
+ہینسا
+ہینگا
+ھکنیا
+ھکیلا
+ھلکتا
+ھلکیا
+ھلملا
+ھمکتا
+ھمکیا
+ھنستا
+ھنسیا
+ھنکتا
+ھنکیا
+ھینگا
+بطیب
+تشبیب
+تصلیب
+تنصیب
+کینٹب
+لجیب
+لحسیب
+لحصیب
+لمجیب
+متعجب
+متعصب
+مجتنب
+محتسب
+مسبب
+مستجب
+مسیب
+منتخب
+منتسب
+جھینپ
+سٹیمپ
+سنکلپ
+گھینپ
+بشکست
+بعجلت
+ٹھینگے
+تبنیت
+تمکنت
+تہنیت
+جمعیت
+جنبیت
+جنسیت
+جھٹنت
+حقیقت
+حیثیت
+سلطنت
+سنگیت
+شخصیت
+شیطنت
+شیعیت
+طبیعت
+طیسیت
+عصبیت
+عظیمت
+عقلیت
+علمیت
+غنیمت
+فضیلت
+فضیحت
+فضیلت
+قطبیت
+قطعیت
+کمیت
+کیفیت
+کیمخت
+گھٹنت
+لپھیت
+لٹھیٹ
+لحکمت
+لخلقت
+لعصمت
+لکھپت
+لمقیت
+لممیت
+مسکنت
+مصلحت
+مصیبت
+معصیت
+معیشت
+معیئت
+ملتفت
+ملکیت
+مملکت
+منفعت
+منقبت
+میمنت
+نصیحت
+ئیلیت
+یکلخت
+یکمشت
+ہلسنت
+بیسنٹ
+بھینٹ
+پمفلٹ
+پنگھٹ
+پیٹنٹ
+پھینٹ
+تلچھٹ
+ٹسٹنٹ
+ٹیکسٹ
+جھپیٹ
+جھنجٹ
+چھینٹ
+سٹمنٹ
+سسپنٹ
+سسٹنٹ
+سلفیٹ
+سلیکٹ
+سیمنٹ
+شپمنٹ
+کیبنٹ
+کیمسٹ
+گھسیٹ
+گھینٹ
+لپٹنٹ
+لپمنٹ
+لٹھیٹ
+لجئیٹ
+لفٹنٹ
+میگنٹ
+نیٹنٹ
+ئنٹسٹ
+ہیلمٹ
+بھتیج
+چیلنج
+بھینچ
+پھینچ
+کھینچ
+تسبیح
+تصحیح
+تلمیح
+تنقیح
+مصطلح
+تنسیخ
+بخشند
+بسیند
+بینند
+پنجند
+پیجند
+پیچید
+تجلید
+تحمید
+تصعید
+تعقید
+تفسید
+تقلید
+تکسید
+تمجید
+تمحید
+تمہید
+تنفید
+تنقید
+تہبند
+جتمند
+جمشید
+چھلبد
+خشکید
+سمبند
+سمجھد
+سنجید
+علیحد
+فہمید
+کھلند
+لتمند
+لحمید
+لسعید
+لشہید
+لعقید
+لکھند
+لمجید
+لمسجد
+لمیعد
+لمقتد
+مجتہد
+مچھند
+مستبد
+مستعد
+مستند
+معتضد
+معتمد
+منجمد
+منجھد
+منعقد
+مہمند
+نشمند
+ہشمند
+بلینڈ
+بھٹنڈ
+پیگنڈ
+تلینڈ
+چچینڈ
+سٹینڈ
+سیکنڈ
+سگمنڈ
+شفیلڈ
+کلینڈ
+کنفیڈ
+کیتھڈ
+کیلنڈ
+کیلیڈ
+کینیڈ
+کھلنڈ
+گلینڈ
+گھمنڈ
+لمیٹڈ
+مشٹنڈ
+میتھڈ
+یمبلڈ
+ہسبنڈ
+تلمیذ
+فلہذ
+بجھبر
+بچھیر
+بکٹیر
+بکھیر
+بگستر
+بلیچر
+بیچلر
+بینجر
+بیشتر
+بینٹر
+بینکر
+بہتیر
+بھسٹر
+بھمبر
+بھیتر
+بھیکر
+پبلشر
+پتمبر
+پچھتر
+پسنجر
+پکھیر
+پلستر
+پلمبر
+پلیئر
+پنجیر
+پنشنر
+پنکچر
+پیسٹر
+پیشتر
+پیمبر
+پینتر
+پھپیر
+پھٹکر
+پھلسر
+تبختر
+تحقیر
+تخمیر
+تسخیر
+تسطیر
+تشہیر
+تصغیر
+تطہیر
+تظہیر
+تعبیر
+تعمیر
+تغیر
+تفسیر
+تقصیر
+تقطیر
+تکبیر
+تکثیر
+تکسیر
+تکفیر
+تمسخر
+تنکیر
+تینیر
+تھپیر
+تھمبر
+تھیٹر
+تھیچر
+ٹنکچر
+ٹیسٹر
+ٹیلگر
+ٹیمبر
+ٹینکر
+ٹھپکر
+ٹھیٹر
+ٹھٹھر
+ٹھیکر
+جمبیر
+جیکٹر
+جینیر
+جھجھر
+جھنجر
+جھنگر
+چمچیر
+چنگیر
+چنیسر
+چیٹھر
+چیکٹر
+چیمبر
+چھہتر
+سپنسر
+سپئیر
+سپیکر
+ستغفر
+ستگیر
+ستمبر
+ستمگر
+سٹمپر
+سٹینر
+سٹیکر
+سٹیمر
+سٹیئر
+سکیٹر
+سکیسر
+سکیلر
+سکینر
+سگنلر
+سلیپر
+سلیٹر
+سمسٹر
+سمگلر
+سنپٹر
+سنپیر
+سنتگر
+سنسکر
+سنگتر
+سنئیر
+سنیٹر
+سنیچر
+سکیٹر
+سینٹر
+سینسر
+سینئر
+شلیپر
+شمشیر
+شیلٹر
+علمبر
+غضنفر
+فیکٹر
+فیکچر
+قطمیر
+کبیسر
+کبیشر
+کٹیٹر
+کسٹمر
+کسمپر
+کسنجر
+کشمیر
+کفگیر
+کلکٹر
+کلنسر
+کلینر
+کمشنر
+کمنٹر
+کنٹھر
+کنستر
+کیتھر
+کیسٹر
+کیمبر
+کینبر
+کینسر
+کھنجر
+کھنکر
+کھنگر
+کھچر
+گلیسر
+گلیمر
+گنینر
+گھبیر
+گھگر
+گھمیر
+گھنگر
+گھنیر
+لبصیر
+لتھیر
+لخبیر
+لصغیر
+لکبیر
+لکھیر
+لمطہر
+لمگیر
+لمنظر
+لنٹیر
+لنصیر
+لیسٹر
+لیکٹر
+لیکچر
+لینبر
+لینٹر
+متبحر
+متحیر
+متشکر
+متغیر
+متفکر
+متکبر
+متنفر
+مجسٹر
+مختصر
+مخیر
+مستتر
+مسخر
+مستشر
+مستغر
+مستقر
+مستمر
+مشتہر
+مشینر
+معتبر
+مکسچر
+منتشر
+منتظر
+منجیر
+منچھر
+منحصر
+منسٹر
+منگسر
+منیجر
+میکنز
+منیجر
+نٹسیر
+نچسٹر
+نچھتر
+نخچیر
+نسسٹر
+نکسیر
+نکھتر
+نگسیر
+نگشتر
+نیشتر
+نیکلر
+ئیجیر
+یفلگر
+یکسپر
+یکلچر
+یمسٹر
+ینسٹر
+ینکفر
+ہمشیر
+ہمعصر
+ہیتھر
+ہیمبر
+ہینگر
+بتنگڑ
+بکھیڑ
+بلکھڑ
+بھیکڑ
+پلنگڑ
+پھسکڑ
+پھکڑ
+پھیپڑ
+تھپیڑ
+جھمکڑ
+جھنگڑ
+چمچیڑ
+چیتھڑ
+چیٹھڑ
+چیلھڑ
+چھچھڑ
+چھیچڑ
+سینکڑ
+سینگڑ
+علیگڑ
+کلنگڑ
+کلیگڑ
+کھچیڑ
+کھکیڑ
+کھنگڑ
+گنٹھڑ
+گھسیڑ
+لتھیڑ
+مسکیڑ
+ہتھکڑ
+پیپلز
+پیکلز
+تجہیز
+ٹیشنز
+ٹیکلز
+چنگیز
+سکیچز
+سگنلز
+سنگلز
+کسٹمز
+کشنیز
+متمیز
+مستلز
+مستیز
+مشکیز
+ممیز
+میکنز
+مہمیز
+نیپلز
+نیشنز
+ئیکلز
+یتھنز
+ینجلز
+بلقیس
+بیلنس
+بھینس
+پچیس
+پلیکس
+پینٹس
+تجسس
+تجنیس
+ٹمنٹس
+ٹیلکس
+چھبیس
+چھتیس
+خلیفہ
+سپکٹس
+سٹیٹس
+سمٹکش
+سنگلس
+سنیکس
+فٹنگس
+فلیٹس
+کلپٹس
+کیمپس
+گھنیس
+لخمیس
+لشمس
+لمپکس
+لیٹکس
+لیمپس
+متجسس
+متنفس
+ملتمس
+منعکس
+نلسٹس
+ئمیکس
+ئیسنس
+یجنٹس
+یلیکس
+ینجلس
+پیچکش
+پیشکش
+تفتیش
+چپقلش
+کشمکش
+گھنیش
+تخصیص
+تخلیص
+تشخیص
+تلخیص
+تمحیص
+تنقیص
+لتخلص
+متخلص
+تخلیط
+ٹپن
+لقلیط
+لمقسط
+منضبط
+تحفظ
+لحفیظ
+تشنیع
+تقطیع
+لسمیع
+لشفیع
+لمبلغ
+لمطیع
+لمقطع
+متمتع
+مجتمع
+ممتنع
+منقطع
+تبلیغ
+بللی
+تصحیف
+تصنیف
+تعطف
+تقشف
+تکثیف
+تکلیف
+تنصیف
+سنحیف
+للطیف
+متکلف
+مختلف
+مسقف
+مکلف
+منعطف
+منکشف
+تحقیق
+تخلیق
+تطبیق
+تعلیق
+لعتیق
+لمنطق
+متعلق
+مستحق
+منطبق
+ہنبق
+بیٹھک
+بھننک
+پیتھک
+پیسفک
+پھینک
+تشکیک
+تضحیک
+تکنیک
+تملیک
+ٹیکنک
+جھلنک
+جھینک
+چھینک
+کلینک
+کنجشک
+کھٹیک
+گنجلک
+مجسٹک
+منسلک
+منہمک
+ئنٹفک
+یپبلک
+بیٹنگ
+بیجنگ
+بھجنگ
+بھننگ
+پکٹنگ
+پمپنگ
+پئیگ
+پیکنگ
+پھننگ
+تھلنگ
+ٹیچنگ
+جمپنگ
+جیکنگ
+چیکنگ
+سپننگ
+سیکنگ
+فکسنگ
+فنشنگ
+کیپنگ
+کیٹنگ
+میپنگ
+میٹنگ
+میچنگ
+میکنگ
+میلنگ
+ئٹینگ
+ئٹینگ
+یشننگ
+یکٹنگ
+بسبیل
+بمشکل
+بیمثل
+پھٹکل
+پھلیل
+تجہیل
+تحصیل
+تحلیل
+تخلیل
+تخئیل
+تسلسل
+تسہیل
+تشکیل
+تعجیل
+تعطیل
+تعلیل
+تعمیل
+تفصل
+تفصیل
+تفضل
+تقلیل
+تکفیل
+تکمیل
+تمثیل
+تہلیل
+تھکیل
+ٹیمپل
+جھٹیل
+جھلمل
+جھمیل
+چھیچھڑ
+سپیشل
+سنججل
+سنبھل
+سنپتل
+سیمپل
+فیشنل
+فیشیل
+قیفیں
+کتھیل
+کیپٹل
+کیشنل
+کیمبل
+کینچل
+کینسل
+کینگل
+کھٹمل
+کھکھل
+لجلیل
+لجمیل
+لخلیل
+متحمل
+متکفل
+مچھیل
+محتمل
+مستقل
+مسجل
+مسلسل
+مشتعل
+مشتغل
+مشتمل
+مشخیل
+مضمحل
+معجل
+منتقل
+منفعل
+مینٹل
+مینگل
+نٹیبل
+نسٹبل
+نیشنل
+نینٹل
+ئیسکل
+ہینگل
+بلجیم
+بہنگم
+پچھم
+تجسیم
+تحکیم
+تسلیم
+تسنیم
+تصمیم
+تعظیم
+تعلم
+تعلیم
+تفہیم
+تقسیم
+تنجیم
+تنظیم
+تنعم
+تیمم
+ٹنگھم
+ٹھیکم
+جھیلم
+علیکم
+علیہم
+لبعلم
+لحکیم
+لحلیم
+لعظیم
+لعلیم
+لکلیم
+لمعظم
+لنعیم
+لیتیم
+تبسم
+متبسم
+متعلم
+متکلم
+محتشم
+مختتم
+معتصم
+منتظم
+منتقم
+منظم
+منقسم
+منگھم
+منمنا
+منہضم
+میکسم
+مہتمم
+نشینم
+بجکشن
+بلیٹن
+بینگن
+بھبکن
+بھپکن
+پھسلن
+بھنگن
+پبلکن
+پچھم
+پنجتن
+پیشین
+پھپکن
+پھٹکن
+پھسلن
+تھیلیا
+تبیین
+تحسین
+تخمین
+تسکین
+تضمین
+تکفین
+تلقین
+تلئیں
+تلیئن
+تمکین
+تیئین
+تھپکن
+ٹھٹکن
+ثقلین
+جنکشن
+جیکشن
+جھپٹن
+جھپکن
+جھٹکن
+چھلکن
+چھیجن
+چھیلن
+حسنین
+سبطین
+سٹفین
+سٹیشن
+سلجھن
+سلکشن
+سلکھن
+سنگین
+سیٹھن
+سیکشن
+سیمین
+سینچن
+سینکن
+شنگٹن
+شیخین
+علیین
+غمگین
+فنکشن
+قطبین
+کسیجن
+کلفٹن
+کلیمن
+کمیشن
+کنکشن
+کیپٹن
+کیپشن
+کیٹشن
+کیٹین
+کھٹکن
+کھنجن
+کھنچن
+گھسٹن
+لپیٹن
+لچھمن
+لحسین
+لحصین
+لستشن
+لمتین
+لمکین
+لنشین
+لنگٹن
+لیسین
+لیکسن
+لیکشن
+متعفن
+متعین
+متقین
+متمکن
+متنجن
+لمکین
+لنشین
+مسکین
+مطمئن
+ممتحن
+منقش
+میگلن
+مینشن
+نجبین
+نجکشن
+نشیمن
+نعلین
+نقشین
+نگبین
+نمکین
+نیپکن
+نیلشن
+ئمکین
+ئیشین
+یٹکشن
+یکسین
+یملین
+یسین
+ہمپٹن
+ہملٹن
+بپتیں
+بتتیں
+بتکیں
+بتیس
+بٹتیں
+بجبیں
+بجتیں
+بجھیں
+بچتیں
+بچکیں
+بچلیں
+بچھیں
+بحثیں
+بخشیں
+بستیں
+بطخیں
+بغلیں
+بکتیں
+بلتیں
+بلکیں
+بنتیں
+بنچیں
+بیتیں
+بیچیں
+بیلیں
+بینیں
+بہتیں
+بہکیں
+بہلیں
+بہنیں
+بھچیں
+بھکیں
+بھلیں
+بھنیں
+پتتیں
+پتھیں
+پٹتیں
+پٹخیں
+پٹکیں
+پچتیں
+پچکیں
+پچھیں
+پستیں
+پکتیں
+پگلیں
+پلتیں
+پلکیں
+پنپیں
+پیتیں
+پیشیں
+پیلیں
+پہنیں
+پھبیں
+پھکیں
+پھلیں
+تپتیں
+تپکیں
+تچتیں
+تگتیں
+تلتیں
+تلئیں
+تمہیں
+تنتیں
+تنکیں
+تیغیں
+تھپیں
+تھتیں
+تھجیں
+تھکیں
+تھلیں
+تھمیں
+ٹپتیں
+ٹپکیں
+ٹکتیں
+ٹکٹیں
+ٹلتیں
+ٹنگیں
+ٹیپیں
+ٹیکیں
+ٹیمیں
+ٹہلیں
+ٹھتیں
+ٹھسیں
+ٹھگیں
+ٹھلیں
+ٹھنیں
+جپتیں
+جتتیں
+جچتیں
+جگتیں
+جگہیں
+جلتیں
+جلیس
+جمپیں
+جنتیں
+جنسیں
+جنگیں
+جنہیں
+جنھیں
+جیپیں
+جیتیں
+جیلیں
+جیہیں
+جہتیں
+جھتیں
+جھکیں
+جھلیں
+چبتیں
+چبکیں
+چبلیں
+چبھیں
+چپتیں
+چپٹیں
+چپکیں
+چپلیں
+چتتیں
+چٹخیں
+چٹکیں
+چسکیں
+چکلیں
+چکھیں
+چگتیں
+چلتیں
+چمٹیں
+چمکیں
+چنتیں
+چیپیں
+چیخیں
+چیلیں
+چہکیں
+چھپیں
+چھتیں
+چھلیں
+چھنیں
+حبتیں
+حجتیں
+حشتیں
+حمتیں
+حیتیں
+خلتیں
+ستتیں
+سٹکیں
+سجتیں
+سسکیں
+سعتیں
+سکتیں
+سلتیں
+سلگیں
+سمتیں
+سنتیں
+سنگیں
+سیتیں
+سیجیں
+سیخیں
+سیکیں
+سیلیں
+سیمیں
+چیلنج
+سہتیں
+سہلیں
+سہمیں
+شفٹیں
+شکلیں
+شکنیں
+شلفیں
+شمعیں
+صحتیں
+صفتیں
+صیتیں
+شفٹیں
+علتیں
+غمگیں
+عنیں
+عیتیں
+غبتیں
+غمگیں
+فصلیں
+فعتیں
+فلمیں
+فیسیں
+قسطیں
+قسمیں
+قلتیں
+قلمیں
+کٹتیں
+کٹکیں
+کچلیں
+کستیں
+کسلیں
+کعتیں
+کلتیں
+کملیں
+کیبیں
+کیکیں
+کیلیں
+کہتیں
+کھپیں
+کھتیں
+کھٹیں
+کھلیں
+گپکیں
+گتھیں
+گٹکیں
+گٹھیں
+گلتیں
+گنتیں
+گیسیں
+گہکیں
+گھٹیں
+گھچیں
+گھسیں
+گھلیں
+لپٹیں
+لپکیں
+لٹتیں
+لٹکیں
+لجھیں
+لچتیں
+لچکیں
+لچھیں
+لحتیں
+لسٹیں
+لشتیں
+لغتیں
+لکتیں
+لکھیں
+لگتیں
+لگنیں
+لمکیں
+لنشیں
+لنگیں
+لیپیں
+لیتیں
+لیٹیں
+لیچیں
+لیفیں
+لیقیں
+لیکیں
+لیلیں
+لہکیں
+لہنیں
+مٹتیں
+مٹکیں
+مثلیں
+مچتیں
+مچکیں
+مچلیں
+مسکیں
+مسلیں
+مشقیں
+مشکیں
+مکتیں
+ملتیں
+منتیں
+منکیں
+منگیں
+میتیں
+میٹیں
+میجیں
+میچیں
+میخیں
+میمیں
+مہکیں
+نبٹیں
+نبضیں
+نبھیں
+نپتیں
+نپٹیں
+نتتیں
+نتیس
+نتھیں
+نٹتیں
+نٹھیں
+نجبیں
+نجتیں
+نجشیں
+نجھیں
+نچتیں
+نچھیں
+نستیں
+نسلیں
+نظمیں
+نعتیں
+نسٹھو
+لچسپیا
+مطمع
+ثیق
+مغلظ
+پیچک
+فظے
+محنت
+نعشیں
+نعلیں
+نفلیں
+نقلیں
+نکتیں
+نکلیں
+نکھیں
+نگبیں
+نگتیں
+نگلیں
+نگئیں
+نگھیں
+نمٹیں
+نیتیں
+ئینس
+یشنیں
+یعتیں
+یکھیں
+یلتیں
+ینکیں
+ینگیں
+ہٹتیں
+ہچکیں
+ہکتیں
+ہگتیں
+ہلتیں
+ہلگیں
+ہمتیں
+ہمکیں
+ہمگیں
+ہنسیں
+ھکتیں
+ھلتیں
+ھلکیں
+ھمکیں
+ھنتیں
+ھنسیں
+ھنکیں
+بتیسو
+بٹینو
+بجلیو
+بچھیو
+بحثیو
+بختیو
+بخششو
+بخیلو
+بستیو
+بسکٹو
+بسملو
+بطگیو
+بقچیو
+بکسنو
+بکسیو
+بکیلو
+بگیلو
+بگینو
+بگھیو
+بلبلو
+بلٹیو
+بلخیو
+بلنگو
+بلیمو
+بمبیو
+بنگلو
+بیبیو
+بیتیو
+بیٹیو
+بیٹھو
+بیعتو
+بیکسو
+بیگمو
+بیگنو
+بیلٹو
+بیلچو
+بیلنو
+بینجو
+بینکو
+بھبکو
+بھبو
+بھپکو
+بھتنو
+بھٹکو
+بھٹیو
+بھسکو
+بھشکو
+بھگتو
+بھلسو
+بھمبو
+بھنکو
+بھنگو
+بھیجو
+بھیسو
+بھیگو
+بھیلو
+پپیتو
+پپیہو
+پتلیو
+پتنگو
+پتنیو
+پتیلو
+پٹیلو
+پچپنو
+پچیسو
+پچھلو
+پستیو
+پسلیو
+پسیجو
+پسینو
+پگلیو
+پگھلو
+پلپلو
+پلٹنو
+پلٹیو
+پلنگو
+پنسلو
+پنکھو
+پیٹیو
+پیٹھو
+پھٹکو
+پیچھو
+پیکٹو
+پینٹو
+پیکٹو
+پینٹو
+پینگو
+پہنچو
+پھبکو
+پھنسو
+پھپکو
+پھپھو
+پھٹکو
+پھسکو
+پھسلو
+پھلکو
+پھلیو
+پھنسو
+پھنکو
+پھیکو
+پھیلو
+تبتیو
+تتلیو
+تجلیو
+تختیو
+تسلیو
+تشفیو
+تصفیو
+تعلقو
+تلتلو
+تلخیو
+تنتنو
+تیلتو
+تیلیو
+تینہو
+تہمتو
+تھپکو
+تھنچو
+تھنیو
+تھلو
+ٹکلیو
+ٹگھلو
+ٹلٹلو
+ٹمنٹو
+ٹیبلو
+ٹیسٹو
+ٹیکسو
+ٹیلبو
+ٹیلیو
+ٹینٹو
+ٹینکو
+ٹہنیو
+ٹھٹکو
+ٹھٹھو
+ٹھسکو
+ٹھگنو
+ٹھلیو
+ٹھمکو
+ٹھنسو
+ٹھنکو
+ٹھنیو
+ٹھیکو
+ٹھیلو
+جبینو
+جپسیو
+جثیمو
+جستجو
+جنبشو
+جنبیو
+جنتیو
+جنگلو
+جنئیو
+جیٹھو
+جنیو
+جھپٹو
+جھپکو
+جھٹکن
+جھجکو
+جھکیو
+جھگیو
+جھلسو
+جھلکو
+جھمکو
+جھنجو
+جھنکو
+جھیلو
+چپٹیو
+چٹھیو
+چٹکلو
+چٹکیو
+چٹنیو
+چٹیلو
+چسکیو
+چسنیو
+چشتیو
+چغلیو
+چلبلو
+چلمنو
+چمٹیو
+چمچیو
+چمنیو
+چنکٹو
+چنگیو
+چنگھو
+چنٹو
+چینٹو
+چینگو
+چینیو
+چہچہو
+چہیتو
+چھپنو
+چھٹکو
+چھٹیو
+چھچھل
+چھلکو
+چھنٹو
+چھنکو
+چھیکو
+چھیلو
+چھینو
+حبشنو
+حبشیو
+حبیبو
+حسنیو
+حسینو
+حشتیو
+حشمتو
+حکمتو
+حکیمو
+حلیفو
+حنفیو
+حیتیو
+خبطیو
+خبیثو
+خصتیو
+خصلتو
+خطیبو
+خلفیو
+خلقیو
+خلیجو
+خلیقو
+خمچیو
+خمیسو
+خنکیو
+سبکیو
+سبیلو
+ستخطو
+ستعفو
+ستلیو
+ستنبو
+ستنجو
+سٹیجو
+سٹیچو
+سٹیفو
+سٹینو
+سجنیو
+سختیو
+سسکیو
+سطبلو
+سفینو
+سقنقو
+سقیفو
+سسکچیو
+سیکچو
+سکیلو
+سکیمو
+سگنلو
+سلجھو
+سلسلو
+سلفیو
+سلیٹو
+سلیقو
+سمجھو
+سمیٹو
+سنجیو
+سنجھو
+سنکیو
+سنگتو
+سنگیو
+سنیو
+سیپیو
+سیٹھو
+سیشنو
+سیکھو
+سینتو
+سینٹو
+سینچو
+سینکو
+سینگو
+سینیو
+شبیہو
+شفقتو
+شکستو
+شکنجو
+شکیو
+شلغمو
+شمنیو
+شیخیو
+شیشیو
+شیمپو
+صحبتو
+صحیفو
+صطبلو
+صنعتو
+ضبطیو
+ضعیفو
+ضمیمو
+طبلقو
+طبیبو
+طلعتو
+طنطنو
+طینتو
+ظلمتو
+عجمیو
+عصبیو
+عصمتو
+عظمتو
+علتو
+عملیو
+عنکبو
+عیبیو
+عیلیو
+فیسٹو
+فیصلو
+فیلسو
+فہمیو
+قبطیو
+قبیلو
+قسمتو
+قفیتو
+قلفیو
+قلیتو
+قلیمو
+قمچیو
+قمقمو
+قمیصو
+قیمتو
+قہقہو
+کپکپو
+کتیسو
+کٹکٹو
+کٹنیو
+کسبیو
+کستیو
+کسٹھو
+کلغیو
+کلفتو
+کلیجو
+کلیلو
+کلیمو
+کلھیو
+کمبلو
+کمپیو
+کمسنو
+کمیتو
+کمیلو
+کمنو
+کنٹھو
+کنجیو
+کنکٹو
+کنکئو
+کنگفو
+کنگلو
+کنگنو
+کنگھو
+کیبنو
+کیتیو
+کیسٹو
+کیسیو
+کیمپو
+کینچو
+کھٹکو
+کھٹلو
+کھٹیو
+کھسکو
+کھسلو
+کھکھو
+کھمبو
+کھنچو
+کھنکو
+کھیپو
+کھیتو
+کھیلو
+کھیئو
+گتھنو
+گتھیو
+گٹکیو
+گشتیو
+گفتگو
+گلٹیو
+گلگلو
+گنتیو
+گنٹھو
+گنجیو
+گنگنو
+گھپلو
+گھٹکو
+گھٹنو
+گھسٹو
+گھگھو
+گھنٹو
+گھنگو
+گھیکو
+لبلبو
+لبیلو
+لپیٹو
+لٹکنو
+لجھنو
+لچھنو
+لشتیو
+لطیفو
+لعنتو
+لعینو
+لفینگو
+لکشیو
+لگنیو
+لمحمو
+لمختو
+لمخلو
+لمعبو
+لمعمو
+لمکتو
+لمنظو
+لنگیو
+لنگھو
+لیبلو
+لیتھو
+لیچیو
+لیسیو
+لیگیو
+لیمپو
+لہنگو
+مبلغو
+متقیو
+مٹکیو
+مٹھیو
+مثلثو
+مجسمو
+مجلسو
+مجمعو
+مچلکو
+محبتو
+محسنو
+محفلو
+محققو
+محکمو
+محملو
+محنتو
+مخلصو
+مخمصو
+مخملو
+مخنثو
+مسکنو
+مسلکو
+مسلمو
+مسئلو
+مشعلو
+مشغلو
+مشفقو
+مشقتو
+مشکبو
+مشکلو
+مشکیو
+مشکو
+مشینو
+مصطفو
+مصلحو
+مصنفو
+مطلعو
+معلمو
+مغلپو
+مغنیو
+مفلسو
+مکتبو
+مکینو
+مکھنو
+مکھیو
+ملکیو
+منجمو
+منجنو
+منچلو
+منشیو
+منصبو
+منصبو
+منصفو
+منطقو
+منگنو
+منگھو
+میٹھو
+میکلو
+میمنو
+مہینو
+نتیجو
+نتھنو
+نٹنیو
+نٹیٹو
+نٹھلو
+نجمنو
+نجیبو
+نجیلو
+نچلیو
+نسبتو
+نسٹھو
+نسسکو
+نشستو
+نشیبو
+نشینو
+نصیبو
+نظمیو
+نعمتو
+نقیبو
+نکمو
+نکمیو
+نکیلو
+نکھتو
+نکھٹو
+نکھیو
+نگلیو
+نگینو
+نگیلو
+نلسٹو
+نلکیو
+نمکخو
+نیپچو
+نیسکو
+نیکیو
+نیلگو
+نیمچو
+ئجسٹو
+ئیسکو
+ئیکلو
+ئیگیو
+ئینچو
+یتیمو
+یجنٹو
+یخنیو
+یسٹھو
+یکھیو
+یگچیو
+یلچیو
+یلیمو
+ھکینو
+ھمکیو
+بصیغئہ
+سینئہ
+شعبئہ
+صیغئہ
+عطیئہ
+غنچئہ
+فیقئہ
+قبلئہ
+قلعئہ
+نقطعئہ
+نیمئہ
+ہفتئہ
+ببیسی
+بپتنی
+بتکتی
+بتکنی
+بتیسی
+بجھتی
+بجھنی
+بچکتی
+بچکنی
+بچلتی
+بچلنی
+بچھتی
+بچھنی
+بخشتی
+بخششی
+بخشنی
+بخیلی
+بستگی
+بستنی
+بسکٹی
+بسنتی
+بکبکی
+بکینی
+بگینی
+بگیلی
+بلبلی
+بلٹتی
+بلٹنی
+بلغی
+بلکتی
+بلکنی
+بللی
+بلیسی
+بمبئی
+بنٹتی
+بنٹنی
+بنجتی
+بنجنی
+بنسنی
+بنفشی
+بنیٹی
+بنینی
+بتیتی
+بتینی
+بیٹھی
+بیجتی
+بیجنی
+بیچتی
+بیچنی
+بیسنی
+بیکسی
+بیگمی
+بیگنی
+بیلتی
+بیلتی
+بیلنی
+بینتی
+بینکی
+بیننی
+بیہقی
+بھجتی
+بھجنی
+بہشتی
+بہکتی
+بہکنی
+بہلتی
+بہلنی
+بہنگی
+بھبکی
+بھپکی
+بھتنی
+بھٹکی
+بھٹنی
+بھٹئ
+بھجتی
+بھجنی
+بھچتی
+بھچنی
+بھسکی
+بھشتی
+بھکتی
+بھکنی
+بھگتی
+بھلتی
+بھلسی
+بھلنی
+بھنتی
+بھنچی
+بھنکی
+بھنگی
+بھننی
+بھیجی
+بھیکی
+بھیگی
+بھیلی
+بھینی
+پتیلی
+پتھتی
+پتھنی
+پٹختی
+پٹچنی
+پٹکنی
+پٹکتی
+پٹیتی
+پچکتی
+پچکنی
+پچپسی
+پچھتی
+پچھلی
+پچھمی
+پچھنی
+پچتگی
+پستئ
+پسیجی
+پگلتی
+پگلنی
+پگھلی
+پلپلی
+پلتھی
+پلٹتی
+پلٹنی
+پنبئ
+پنپنی
+پنتھی
+پنچھی
+پنکھی
+پنگتی
+پنیلی
+پیپسی
+پیپلی
+پیتلی
+پیتھی
+پیٹتی
+پیٹنی
+پیٹھی
+پیستی
+پیسنی
+پیشگی
+پیکسی
+پیلتی
+پیلنی
+پینٹی
+پھسکی
+پہنتی
+پہنچی
+پہنی
+پہیلی
+پھبتی
+پھبکی
+پھبنی
+پھپی
+پھپکی
+پھپھی
+پھٹتی
+پھٹکی
+پھٹنی
+پھسکی
+پھسلی
+پھکتی
+پھکنی
+پھلتی
+پھلٹی
+پھلسی
+پھلکی
+پھلنی
+پھنتی
+پھنسی
+پھنکی
+پھنگی
+پھننی
+پھیکی
+پھیلی
+پھینی
+تبتی
+تیبچی
+تپکتی
+تپکنی
+تحفگی
+تشنجی
+تشنگی
+تعصبی
+تعصبی
+تعلقی
+تعلی
+تغلقی
+تکبکی
+تکتکی
+تکلفی
+تکینی
+تلتلی
+تللی
+تلملی
+تلیٹی
+تمیمی
+تنتنی
+تنفسی
+تنکتی
+تنکنی
+تیبچی
+تیپچی
+تیجتی
+تیجنی
+تیکھی
+تھپتی
+تھپکی
+تھپنی
+تھتھی
+تھجتی
+تھجنی
+تھکتی
+تھکلی
+تھکنی
+تھگلی
+تھلتی
+تھلنی
+تھمتی
+تھمنی
+تھنچی
+تھیلی
+ٹپکتی
+ٹکٹکی
+ٹکھلی
+ٹلٹلی
+ٹنگتی
+ٹنگنی
+ٹیپتی
+ٹیپنی
+ٹیکتی
+ٹیکسی
+ٹیکنی
+ٹینکی
+ٹہلتی
+ٹہلنی
+ٹھٹکی
+ٹھٹھی
+ٹھستی
+ٹھسکی
+ٹھسنی
+ٹھکتی
+ٹھکنی
+ٹھگتی
+ٹھگنی
+ٹھلتی
+ٹھلنی
+ٹھمکی
+ٹھنتی
+ٹھنکی
+ٹھنگی
+ٹھننی
+ٹھیکی
+ٹھیگی
+ٹھینی
+ثعلبی
+جستگی
+جلیبی
+جلیسی
+جلیلی
+جملگی
+جمنئ
+جمیلی
+جنگلی
+جیتتی
+جیتنی
+جیٹھی
+جہنمی
+جھپٹی
+جھپکی
+جھجکی
+جھکتی
+جھکنی
+جھلتی
+جھلسی
+جھلکی
+جھلنی
+جھمکی
+جھنجی
+جھیلی
+چبکتی
+چبکنی
+چبینی
+چبھتی
+چبھنی
+چپٹتی
+چپٹنی
+چپکتی
+چپکنی
+چپنٹی
+چپیٹی
+چتھلی
+چٹختی
+چٹخنی
+چٹکتی
+چٹکنی
+ہچکنی
+چسکتی
+چسکنی
+چکٹتی
+چکٹنی
+چکلتی
+چکلنی
+چکھتی
+چکھنی
+چلبلی
+چلچلی
+چلملچی
+چمپئ
+چمٹتی
+چمٹنی
+چمکتی
+چمکنی
+چنبلی
+چنچنی
+چپیتی
+چپینی
+چیختی
+چیخنی
+چپنٹی
+چینگی
+چہکتی
+چہکنی
+چہیتی
+چھپتی
+چھپٹی
+چھپنی
+چھٹتی
+چھٹکی
+چھچھو
+چھلتی
+چھلتی
+چھلکی
+چھلنی
+چھنتی
+چھنٹی
+چھنکی
+چھننی
+چھیپی
+چھیلی
+چھینی
+حبیبی
+حسنی
+حسینی
+حقیقی
+حکمتی
+حکیمی
+حلیلی
+حلیمی
+حنبلی
+خستگی
+خصلتی
+خفتگی
+خلتسی
+خلخلی
+خلیجی
+خمینی
+خنثی
+سپینی
+ستخطی
+ستھنی
+سٹکتی
+سٹکنی
+سجیلی
+سچیتی
+سسکتی
+سسکنی
+سلپـی
+سلجھی
+سلسلی
+سلفچی
+سلگتی
+سلگنی
+سلمی
+سلیٹی
+سلگنی
+سمبلی
+سمبھی
+سمپلی
+سمٹتی
+سمٹنی
+سمجھی
+سمیٹی
+سنسنی
+سنکتی
+سنکلی
+سنکنی
+سککتی
+سیفٹی
+سیکھی
+سیلتی
+سیلنی
+سیمگی
+سینتی
+سینٹی
+سینچی
+سینکی
+سینگی
+سہلتی
+سہلنی
+سہمتی
+سہمنی
+سہیلی
+شبنمی
+شستگی
+شفتگی
+شفتلی
+شکیبی
+شلجمی
+شلغمی
+شمنگی
+صحبتی
+صخحچی
+صلیبی
+صنعتی
+ضعیفی
+طبلچی
+طبیعی
+طفیلی
+طلسمی
+عظمی
+عظیمی
+عقبی
+عقیلی
+علیگی
+غصیلی
+غفلتی
+غلئ
+غنچگی
+غنغنی
+غیبتی
+فلسفی
+فلیٹی
+فیمچی
+فیملی
+فینسی
+قسمتی
+قلعئ
+قلیبی
+قلیتی
+قلیمی
+قیمتی
+قینـی
+کپکپی
+کتھئ
+کٹکٹی
+کٹکنی
+کچکچی
+کچلتی
+کچلنی
+کچھنی
+کسلتی
+کسلنی
+کشتنی
+کشمشی
+کلبلی
+کلتھی
+کلیتی
+کلیٹی
+کلیجی
+کلیمی
+کمپلی
+کمسنی
+کملتی
+کملنی
+کمیتی
+کمیٹی
+کمینی
+کنپٹی
+کنجنی
+کنچنی
+کنکتی
+کنکٹی
+کنکنی
+کنکلی
+کنگھی
+کیتلی
+کیتھی
+کیچلی
+کیکتی
+ککیلنی
+کھبی
+کھپتی
+کھپچی
+کھپنی
+کھتی
+کھتلی
+کھٹتی
+کھٹی
+کھٹکی
+کھٹل
+کھجی
+کھجلی
+کھسکی
+کھسلی
+کھلتی
+کھلنی
+کھمبی
+کھنچی
+کھنسی
+کھنکی
+کھنی
+کھیتی
+کھیلی
+کھینی
+کھیئی
+گپکتی
+گپکنی
+گتھتی
+گتھنی
+گٹکتی
+گٹکنی
+گٹھتی
+گٹھلی
+گٹھنی
+گجگجی
+گشتگی
+گفتنی
+گلتھی
+گلکلی
+گنٹھی
+گنگنی
+گینتی
+گہکتی
+گہکنی
+گھپتی
+گھپنی
+گھٹتی
+گھٹکی
+گھٹنی
+گھچلی
+گھستی
+گھسٹی
+گھسنی
+گھلتی
+گھلنی
+گھنٹی
+گھنگی
+گھنی
+لبلبی
+لبنی
+لنیلی
+لپٹتی
+لپٹنی
+لپکتی
+لپکنی
+لپیٹی
+لٹکتی
+لٹکنی
+لجمعی
+لجھتی
+لجھنی
+لچسپی
+نچکتی
+لچکنی
+لچھتی
+لچھمی
+لچھنی
+لیسنی
+لضحی
+لعنتی
+لفنگی
+لکشمی
+لکعبی
+لکھتی
+لکھنی
+لمحصی
+لمحیی
+لمعطی
+لمغنی
+لمکتی
+لکتی
+لمکنی
+لنسکی
+لنگتی
+کینڑ
+لنگھی
+لیپتی
+لیپنی
+لیٹتی
+لیٹنی
+لیجھی
+لیچتی
+لیچنی
+لیستی
+لیسنی
+لیلی
+لہکتی
+لہکنی
+مبنی
+مثیلی
+مجسٹی
+مجلسی
+مجلی
+مجملی
+مچکتی
+مچکنی
+مچلنی
+مچھلی
+محبتی
+محسنی
+محشی
+محلی
+محنتی
+مخلصی
+مخلی
+مخملی
+مسکتی
+مسکنی
+مسنتی
+مسلنی
+مسمسی
+مسمی
+مسیحی
+مشفقی
+مشقتی
+مثنی
+مشینی
+مصحفی
+مفطکی
+مصطگی
+مصلی
+مطلبی
+معطلی
+معلمی
+معلی
+معینی
+مغلئٖ
+مفلسی
+مقتضی
+مقضی
+مقفی
+مکتبی
+ملتجی
+ملگجی
+ملنکی
+ملہٹی
+منتہی
+منجلی
+منجھی
+منچلی
+منحنی
+منصبی
+منصفی
+منطقی
+منقی
+منکتی
+منکتی
+منگتی
+منگنی
+منمنی
+منہنی
+میتھی
+میٹتی
+میٹنی
+میٹھی
+میجتی
+میجنی
+میچتی
+میچنی
+میکسی
+میگنی
+میلسی
+میمنی
+مہکتی
+مہکنی
+مہنگی
+نبٹتی
+نبٹنی
+نبختی
+نبھتی
+نپٹتی
+نپٹنی
+پنجتی
+پنجنی
+نتھنی
+نٹیلی
+نٹھتی
+نٹھنی
+نجیلی
+نجھتی
+نجھنی
+نچھتی
+نچھنی
+نسبتی
+نسیسی
+نسینی
+نشیبی
+نشیلی
+نشینی
+نعیمی
+نکلتی
+نکلنی
+نکمی
+نکیلی
+نکھتی
+نکھنی
+نگلتی
+نگلنی
+نگیلی
+نگینی
+نگھتی
+نگھنی
+نمٹتی
+نمٹنی
+نطینی
+نیستی
+نیکسی
+نینسی
+ئستگی
+ئینٹی
+ٹینکی
+ئینگی
+یتیلی
+یتیمی
+یجنسی
+یحیی
+یخھنی
+یحیی
+یفتگی
+یقینی
+یکنسی
+یکھتی
+یکھنی
+یلمعی
+یمیمی
+یمینی
+ینٹھی
+ینکتی
+ینکنی
+ینگتی
+ینگنی
+ہتھنی
+نٹیلی
+ہچکتی
+ہچکنی
+ہستگی
+ہستنی
+ہلبلی
+ہلگتی
+ہلگنی
+ہمکنی
+ہنستی
+ہنسلی
+ہنسنی
+ہشیمی
+ھکیلی
+ھلکتی
+ھلکنی
+ھمکتی
+ھمکنی
+ھنستی
+ھسنی
+ھنکتی
+ھنکنی
+بپتنے
+بپتئے
+بتکتے
+بتکنے
+بتکئے
+بجھتے
+بجھنے
+بجھئے
+بچپنے
+بچکتے
+بچکنے
+بچکئے
+بچلتے
+بچلنے
+بچلئے
+بچھتے
+بچھنے
+بچھئے
+بخشتے
+بخشئے
+بکسلے
+بکسنے
+بگیلے
+بگینے
+بلبلے
+بلٹتے
+بلٹئے
+بلکتے
+بلکئے
+بللے
+بنٹتے
+بنٹئے
+بنجتے
+بنجئے
+بنگلے
+بیتتے
+بیتئے
+بیٹھے
+بیجتے
+بیچتے
+بیچئے
+بیلتے
+بیلچے
+بیلنے
+بیلئے
+بینتے
+بینئے
+بہکتے
+بہکئے
+بہلتے
+بہلئے
+بھپکے
+بھتنے
+بھٹکے
+بھجتے
+بھجئے
+بھچتے
+بھچئے
+بھسکے
+بھکتے
+بھکئے
+بھگتے
+بھلتے
+بھلسے
+بھلنے
+بھلئے
+بھنتے
+بھنچے
+بھنگے
+بھننے
+بھنئے
+بھیجے
+بھیگے
+بھیلے
+بھینے
+پپیتے
+پپیہے
+پتنگے
+پتیلے
+پتھتے
+پتھئے
+پٹختے
+پٹخئے
+پٹکتے
+پچکتے
+پچکئے
+پچھتے
+پچھلے
+پچھنے
+پچھئے
+پسیجے
+پسینے
+پگلتے
+پگلئے
+پگھلے
+پلپلے
+پلٹتے
+پلٹئے
+پنپتے
+پنپئے
+پنکھے
+پنیلے
+پیٹتے
+پیٹئے
+پیٹھے
+پیجئے
+پیچھے
+پیستے
+پیسئے
+پیلنے
+پیلئے
+پہنتے
+پہنچے
+پہننے
+پہنئے
+پھبتے
+پھبکے
+پھبنے
+پھبئے
+پھپکے
+پھٹتے
+پھٹکے
+پھٹنے
+پھٹئے
+پھسکے
+پھسلے
+پھکتے
+پھکئے
+پھلتے
+پھلسے
+پھلکے
+پھلنے
+پھلئے
+پھنسے
+پھنکے
+پھننے
+پھیکے
+پھیلے
+تپکتے
+تپکئے
+تصیفے
+تعلقے
+تکملے
+تلتلے
+تلملے
+تنتنے
+تنتئے
+تنکتے
+تنکئے
+تیجتے
+تیجئے
+تیکھے
+تھپتے
+تھپکے
+تھپنے
+تھپئے
+تھجتے
+تھجئے
+تھکتے
+تھکئے
+تھلتے
+تھلئے
+تھمتے
+تھمئے
+تھنچے
+تھیلے
+ٹپکتے
+ٹپکئے
+ٹگھلے
+ٹلٹلے
+ٹنگتے
+ٹنگئے
+ٹیپتے
+ٹیپئے
+ٹیکتے
+ٹیکئے
+ٹہلتے
+ٹہلئے
+ٹھٹکے
+ٹھٹھے
+ٹھستے
+ٹھسکے
+ٹھسئے
+ٹھگتے
+ٹھگئے
+ٹھلتے
+ٹھلئے
+ٹھمکے
+ٹھنتے
+ٹھننے
+ٹھنئے
+ٹھیکے
+ٹھیلے
+جنگلے
+جیتتے
+جیتئے
+جیٹھے
+جھپٹتے
+جھپکے
+جھٹکی
+جھجکے
+جھکتے
+جھکئے
+جھلتے
+جھلسے
+جھلکے
+جھلنے
+جھلئے
+جھمکے
+جھیلے
+چبکتے
+چبکئے
+چبینے
+چبھتے
+چبھئے
+چپٹتے
+چپٹئے
+چپچے
+چپکتے
+چپکئے
+چپیٹے
+چٹختے
+چٹخئے
+چٹکتے
+چٹکلے
+چٹکنے
+چٹکئے
+چسکتے
+چکٹتے
+چکٹئے
+چکلتے
+چکلئے
+چکھتے
+چکھئے
+چلبلے
+چمٹتے
+چمٹئے
+چمکتے
+چمکئے
+چنبھے
+چنچنے
+چیپتے
+چیپئے
+چیختے
+چیخئے
+چینٹے
+چینگے
+چہچہے
+چہکتے
+چہکئے
+چہیتے
+چھپتے
+چھپکے
+چھپنے
+چھپئے
+چھٹتے
+چھٹکے
+چھٹنے
+چھٹئے
+چھلتے
+چھلکے
+چھلنے
+چھلئے
+چھنتے
+چھنکے
+چھننے
+چھننے
+چھنئے
+چھیپے
+چھیلے
+چھینے
+ستعفے
+ستنجے
+سٹکتے
+سٹکئے
+سجیلے
+سسکتے
+سسکئے
+سفینے
+سلجھے
+سلسلے
+سلگتے
+سلگئے
+سلمے
+سلیقے
+سمٹتے
+سمٹئے
+سمجھے
+سمیٹے
+سنکتے
+سنکئے
+سیٹھے
+سیجئے
+سیچتے
+سیچئے
+سیکھے
+سیلتے
+سیلئے
+سینتے
+سینچے
+سینگے
+سہلتے
+سہلئے
+سہمتے
+سہمئے
+شکنجے
+صحیفے
+ضمیمے
+عطیئے
+عقبے
+عقیقے
+غصیلے
+غلبلے
+غلیلے
+فتیلے
+فلسفے
+فلیتے
+فیصلے
+قبیلے
+قضیئے
+قلئیے
+قمقمے
+قہقہے
+کپکپے
+کٹکتے
+کٹکٹے
+کٹکئے
+کٹیلے
+کچکچے
+کچلتے
+کچلئے
+کسلتے
+کسلئے
+کسیلے
+کلبلے
+کلیجے
+کملتے
+کملئے
+کمیلے
+کمینے
+کنٹھے
+کنکتے
+کنکٹے
+کنکنے
+کنکئے
+کنگلے
+کنگنے
+کنگھے
+کیجئے
+کیکتے
+کیکئے
+کیلتے
+کیلئے
+کھپتے
+کھپئے
+کھٹتے
+کھٹکے
+کھٹلے
+کھٹنے
+کھٹئے
+کھجلے
+کھسکے
+کھسلے
+کھلتے
+کھلئے
+کھمبے
+کھنچے
+کھنکے
+کھتے
+کھیلے
+کھنے
+کھیئے
+گپکتے
+گپکئے
+گتھتے
+گتھئے
+گٹھے
+گٹکتے
+گٹکئے
+گٹھتے
+گٹھئے
+گجگجے
+گلگلے
+گنٹھے
+گنگنے
+گہکتے
+گہکئے
+گھپتے
+گھپلے
+گھپنے
+گھپئے
+گھٹتے
+گھٹکے
+گھٹنے
+گھٹئے
+گھچلے
+گھستے
+گھٹے
+گھسئے
+گھلتے
+گھلئے
+گھنٹے
+گھنئے
+لبلبے
+لبیلے
+لپٹتے
+لپٹئے
+لپکتے
+لپکئے
+لپیٹتے
+لٹکتے
+لٹکئے
+لجھتے
+لجھئے
+لچکتے
+لچکئے
+لچھتے
+لچھئے
+لشتیے
+لطیفے
+لفنگے
+لکھتے
+لکھئے
+لمکتے
+لمکئے
+لنگتے
+لنگئے
+لنگھے
+لیپتے
+لیپئے
+لیٹتے
+لیٹئے
+لیجئے
+لیچتے
+لیچئے
+لیستے
+لیسئے
+لیکھے
+لیلے
+لینگے
+لہکتے
+لہکئے
+متھتے
+متھئے
+مٹکتے
+مٹکئے
+مثنے
+مجسمے
+مجلے
+مچکتے
+مچکئے
+مچلتے
+مچلئے
+محکمے
+مخلے
+مخمصے
+مسکتے
+مسکئے
+مسلتے
+مسلئے
+مسئلے
+مشغلے
+مشکلے
+مصلے
+مطلعے
+معلے
+ملگجے
+منجھے
+منچلے
+منکتے
+منکئے
+منگتے
+منگئے
+میٹتے
+میٹئے
+میٹھے
+میجتے
+میجئے
+میچتے
+میچئے
+مہکتے
+مہکئے
+مہنگے
+مہینے
+نبٹتے
+نبٹئے
+نبھتے
+نبھئے
+نپٹتے
+نپٹئے
+نپجتے
+نپجئے
+نتیجے
+نتھنے
+نتھئے
+نٹھئے
+نجھتے
+نجھئے
+نچنئے
+نچھتے
+نچھئے
+نشیلے
+نصیبے
+نکلتے
+نکلئے
+نکمے
+نکیلے
+نکھتے
+نکھئے
+نگلتے
+نگلئے
+نگیلے
+نگینے
+نگھتے
+نگھئے
+نمٹتے
+نمٹئے
+نمستے
+نیٹھے
+نیمچے
+ئینچے
+ئینگے
+یتیلے
+یکھتے
+یکھئے
+ینٹھے
+ینکتے
+ینکئے
+ینگتے
+ینگئے
+ہٹیلے
+ہچکتے
+ہچکئے
+ہلگتے
+ہلگئے
+ہمکتے
+ہمکئے
+ہنستے
+ہنسئے
+ھکیلتے
+ھکیلئے
+ھکیلے
+ھلکتے
+ھلکئے
+ھمکتے
+ھمکئے
+ھنستے
+ھنسئے
+ھنکتے
+ھنکئے
+بصیغہ
+بقیتہ
+بگینہ
+بلیلبہ
+بنفشہ
+بنگلہ
+بیلچہ
+تپنچہ
+تثنیہ
+تخلیہ
+تسمیہ
+تشبیہ
+تصفیہ
+تعلقہ
+تعمیہ
+تکمیلہ
+تمنچہ
+تنبیہ
+تہلکہ
+ٹھٹھہ
+ٹھیکہ
+ٹھیلہ
+ثعلبہ
+ثمینہ
+جلیلہ
+جمعتہ
+جمیلہ
+چشتیہ
+حبیبہ
+حسینہ
+حشتیہ
+حلفیہ
+حلیلہ
+حلیمہ
+حنیفہ
+خبیثہ
+خجستہ
+خفیفہ
+خلیلہ
+سفینہ
+سقیفہ
+شکستہ
+سکینہ
+سلسلہ
+سنبلہ
+سہیلہ
+شبیلہ
+شبینہ
+شعشعہ
+شفیعہ
+شفیقہ
+شقیقہ
+شکبیہ
+شکستہ
+شکنجہ
+شکیبہ
+شکیلہ
+شگفتہ
+شمیمہ
+شنیعہ
+شیفتہ
+شہنشہ
+صبعتہ
+صبغتہ
+صبیحہ
+صحیفہ
+ضحیفہ
+ضمیمہ
+طبیبہ
+طپنچہ
+طلیعہ
+طمنچہ
+طنطنہ
+عجیبہ
+عشقیہ
+عصبیہ
+عطیۂ
+عظیمہعفیفہ
+عقیقہ
+عقیلہ
+عقیمہ
+علقمہ
+علمیہ
+عیلیہ
+غلغلہ
+غلیطہ
+غلیظہ
+غلیلہ
+غنچۂ
+فتیلہ
+فصیحہ
+فلبتہ
+فلسفہ
+فلیتہ
+فیصلہ
+قبیحہ
+قبیلہ
+قتیکہ
+قسمیہ
+قمقمہ
+قہقہہ
+کبیسہ
+کٹکنہ
+کلبلہ
+کلکتہ
+کلمتہ
+کلنکہ
+کلیجہ
+کلیلہ
+کمینہ
+کنینہ
+کہھجلہ
+گنجفہ
+گھنٹہ
+لجمعہ
+لجملہ
+لجنتہ
+لخلخہ
+لشتیہ
+لشعبہ
+لطیفہ
+لعنتہ
+لقلقہ
+لکعبہ
+للغتہ
+للہ
+لمنتہ
+لیلتہ
+مبینہ
+متصلہ
+متفقہ
+متنبہ
+مثبتہ
+مجسمہ
+مجلہ
+مچلکہ
+محسنہ
+محصنہ
+محکمہ
+محلہ
+مخمصہ
+مسلمہ
+مسئلہ
+مسینہ
+مشتبہ
+مشعلہ
+مشغلہ
+مصنفہ
+مضحکہ
+مطلقہ
+مظلمہ
+مظنہ
+معلقہ
+معلمہ
+معینہ
+مغلیہ
+مغنیہ
+مقنہ
+مکتبہ
+منحقہ
+ملیحہ
+ممکنہ
+منصۂ
+منطقہ
+میختہ
+میمنہ
+مہملہ
+مہینہ
+نپیلہ
+نتیجہ
+نسیمہ
+نشستہ
+نصیبہ
+نطینہ
+نظمیہ
+نعتیہ
+نعیمہ
+نگینہ
+نیمچہ
+ئنچہ
+ہلیلہ
+ہمیشہ
+ہمہمہ
+پینٹہ
+ٹھیٹھ
+جھنجھ
+کھنکھ
+لینتھ
+ملیچھ
+ہیلتھ
+لبینتہ
+لعظمتہ
+مشخیل
+حسنی
+خنثی
+عقبی
+عیسی
+لبنی
+لصلو
+مثنی
+مجلی
+مجملا
+محشی
+جلگ
+معلی
+مقفی
+یحیی
+تعلقا
+قیمتا
+مجملا
+مطلقا
+بنجتی
+بنجنی
+بنسنی
+بنفشی
+بنیٹی
+بنینی
+بتیتی
+بتینی
+بیٹھی
+بیجتی
+بیجنی
+بیچتی
+بیچنی
+بیسنی
+بیکسی
+بیگمی
+بیگنی
+بیلتی
+بیلتی
+بیلنی
+بینتی
+بینکی
+بیننی
+بیہقی
+بھجتی
+بھجنی
+بہشتی
+بہکتی
+بہکنی
+بہلتی
+بہلنی
+بہنگی
+بھبکی
+بھپکی
+بھتنی
+بھٹکی
+بھٹنی
+بھٹئ
+بھجتی
+بھجنی
+بھچتی
+بھچنی
+بھسکی
+بھشتی
+بھکتی
+بھکنی
+بھگتی
+بھلتی
+بھلسی
+بھلنی
+بھنتی
+بھنچی
+بھنکی
+بھنگی
+بھننی
+بھیجی
+بھیکی
+بھیگی
+بھیلی
+بھینی
+پتیلی
+پتھتی
+پتھنی
+پٹختی
+پٹچنی
+پٹکنی
+پٹکتی
+پٹیتی
+پچکتی
+پچکنی
+پچپسی
+پچھتی
+پچھلی
+پچھمی
+پچھنی
+پچتگی
+پستئ
+پسیجی
+پگلتی
+پگلنی
+پگھلی
+پلپلی
+پلتھی
+پلٹتی
+پلٹنی
+پنبئ
+پنپنی
+پنتھی
+پنچھی
+پنکھی
+پنگتی
+پنیلی
+پیپسی
+پیپلی
+پیتلی
+پیتھی
+پیٹتی
+پیٹنی
+پیٹھی
+پیستی
+پیسنی
+پیشگی
+پیکسی
+پیلتی
+پیلنی
+پینٹی
+پھسکی
+پہنتی
+پہنچی
+پہنی
+پہیلی
+پھبتی
+پھبکی
+پھبنی
+پھپی
+پھپکی
+پھپھی
+پھٹتی
+پھٹکی
+پھٹنی
+پھسکی
+پھسلی
+پھکتی
+پھکنی
+پھلتی
+پھلٹی
+پھلسی
+پھلکی
+پھلنی
+پھنتی
+پھنسی
+پھنکی
+پھنگی
+پھننی
+پھیکی
+پھیلی
+پھینی
+تبتی
+تیبچی
+تپکتی
+تپکنی
+تحفگی
+تشنجی
+تشنگی
+تعصبی
+تعصبی
+تعلقی
+تعلی
+تغلقی
+تکبکی
+تکتکی
+تکلفی
+تکینی
+تلتلی
+تللی
+تلملی
+تلیٹی
+تمیمی
+تنتنی
+تنفسی
+تنکتی
+تنکنی
+تیبچی
+تیپچی
+تیجتی
+تیجنی
+تیکھی
+تھپتی
+تھپکی
+تھپنی
+تھتھی
+تھجتی
+تھجنی
+تھکتی
+تھکلی
+تھکنی
+تھگلی
+تھلتی
+تھلنی
+تھمتی
+تھمنی
+تھنچی
+تھیلی
+ٹپکتی
+ٹکٹکی
+ٹکھلی
+ٹلٹلی
+ٹنگتی
+ٹنگنی
+ٹیپتی
+ٹیپنی
+ٹیکتی
+ٹیکسی
+ٹیکنی
+ٹینکی
+ٹہلتی
+ٹہلنی
+ٹھٹکی
+ٹھٹھی
+ٹھستی
+ٹھسکی
+ٹھسنی
+ٹھکتی
+ٹھکنی
+ٹھگتی
+ٹھگنی
+ٹھلتی
+ٹھلنی
+ٹھمکی
+ٹھنتی
+ٹھنکی
+ٹھنگی
+ٹھننی
+ٹھیکی
+ٹھیگی
+ٹھینی
+ثعلبی
+جستگی
+جلیبی
+جلیسی
+جلیلی
+جملگی
+جمنئ
+جمیلی
+جنگلی
+جیتتی
+جیتنی
+جیٹھی
+جہنمی
+جھپٹی
+جھپکی
+جھجکی
+جھکتی
+جھکنی
+جھلتی
+جھلسی
+جھلکی
+جھلنی
+جھمکی
+جھنجی
+جھیلی
+چبکتی
+چبکنی
+چبینی
+چبھتی
+چبھنی
+چپٹتی
+چپٹنی
+چپکتی
+چپکنی
+چپنٹی
+چپیٹی
+چتھلی
+چٹختی
+چٹخنی
+چٹکتی
+چٹکنی
+ہچکنی
+چسکتی
+چسکنی
+چکٹتی
+چکٹنی
+چکلتی
+چکلنی
+چکھتی
+چکھنی
+چلبلی
+چلچلی
+چلملچی
+چمپئ
+چمٹتی
+چمٹنی
+چمکتی
+چمکنی
+چنبلی
+چنچنی
+چپیتی
+چپینی
+چیختی
+چیخنی
+چپنٹی
+چینگی
+چہکتی
+چہکنی
+چہیتی
+چھپتی
+چھپٹی
+چھپنی
+چھٹتی
+چھٹکی
+چھچھو
+چھلتی
+چھلتی
+چھلکی
+چھلنی
+چھنتی
+چھنٹی
+چھنکی
+چھننی
+چھیپی
+چھیلی
+چھینی
+حبیبی
+حسنی
+حسینی
+حقیقی
+حکمتی
+حکیمی
+حلیلی
+حلیمی
+حنبلی
+خستگی
+خصلتی
+خفتگی
+خلتسی
+خلخلی
+خلیجی
+خمینی
+خنثی
+سپینی
+ستخطی
+ستھنی
+سٹکتی
+سٹکنی
+سجیلی
+سچیتی
+سسکتی
+سسکنی
+سلپـی
+سلجھی
+سلسلی
+سلفچی
+سلگتی
+سلگنی
+سلمی
+سلیٹی
+سلگنی
+سمبلی
+سمبھی
+سمپلی
+سمٹتی
+سمٹنی
+سمجھی
+سمیٹی
+سنسنی
+سنکتی
+سنکلی
+سنکنی
+سککتی
+سیفٹی
+سیکھی
+سیلتی
+سیلنی
+سیمگی
+سینتی
+سینٹی
+سینچی
+سینکی
+سینگی
+سہلتی
+سہلنی
+سہمتی
+سہمنی
+سہیلی
+شبنمی
+شستگی
+شفتگی
+شفتلی
+شکیبی
+شلجمی
+شلغمی
+شمنگی
+صحبتی
+صخحچی
+صلیبی
+صنعتی
+ضعیفی
+طبلچی
+طبیعی
+طفیلی
+طلسمی
+عظمی
+عظیمی
+عقبی
+عقیلی
+علیگی
+غصیلی
+غفلتی
+غلئ
+غنچگی
+غنغنی
+غیبتی
+فلسفی
+فلیٹی
+فیمچی
+فیملی
+فینسی
+قسمتی
+قلعئ
+قلیبی
+قلیتی
+قلیمی
+قیمتی
+قینـی
+کپکپی
+کتھئ
+کٹکٹی
+کٹکنی
+کچکچی
+کچلتی
+کچلنی
+کچھنی
+کسلتی
+کسلنی
+کشتنی
+کشمشی
+کلبلی
+کلتھی
+کلیتی
+کلیٹی
+کلیجی
+کلیمی
+کمپلی
+کمسنی
+کملتی
+کملنی
+کمیتی
+کمیٹی
+کمینی
+کنپٹی
+کنجنی
+کنچنی
+کنکتی
+کنکٹی
+کنکنی
+کنکلی
+کنگھی
+کیتلی
+کیتھی
+کیچلی
+کیکتی
+ککیلنی
+کھبی
+کھپتی
+کھپچی
+کھپنی
+کھتی
+کھتلی
+کھٹتی
+کھٹی
+کھٹکی
+کھٹل
+کھجی
+کھجلی
+کھسکی
+کھسلی
+کھلتی
+کھلنی
+کھمبی
+کھنچی
+کھنسی
+کھنکی
+کھنی
+کھیتی
+کھیلی
+کھینی
+کھیئی
+گپکتی
+گپکنی
+گتھتی
+گتھنی
+گٹکتی
+گٹکنی
+گٹھتی
+گٹھلی
+گٹھنی
+گجگجی
+گشتگی
+گفتنی
+گلتھی
+گلکلی
+گنٹھی
+گنگنی
+گینتی
+گہکتی
+گہکنی
+گھپتی
+گھپنی
+گھٹتی
+گھٹکی
+گھٹنی
+گھچلی
+گھستی
+گھسٹی
+گھسنی
+گھلتی
+گھلنی
+گھنٹی
+گھنگی
+گھنی
+لبلبی
+لبنی
+لنیلی
+لپٹتی
+لپٹنی
+لپکتی
+لپکنی
+لپیٹی
+لٹکتی
+لٹکنی
+لجمعی
+لجھتی
+لجھنی
+لچسپی
+نچکتی
+لچکنی
+لچھتی
+لچھمی
+لچھنی
+لیسنی
+لضحی
+لعنتی
+لفنگی
+لکشمی
+لکعبی
+لکھتی
+لکھنی
+لمحصی
+لمحیی
+لمعطی
+لمغنی
+لمکتی
+لکتی
+لمکنی
+لنسکی
+لنگتی
+کینڑ
+لنگھی
+لیپتی
+لیپنی
+لیٹتی
+لیٹنی
+لیجھی
+لیچتی
+لیچنی
+لیستی
+لیسنی
+لیلی
+لہکتی
+لہکنی
+مبنی
+مثیلی
+مجسٹی
+مجلسی
+مجلی
+مجملی
+مچکتی
+مچکنی
+مچلنی
+مچھلی
+محبتی
+محسنی
+محشی
+محلی
+محنتی
+مخلصی
+مخلی
+مخملی
+مسکتی
+مسکنی
+مسنتی
+مسلنی
+مسمسی
+مسمی
+مسیحی
+مشفقی
+مشقتی
+مثنی
+مشینی
+مصحفی
+مفطکی
+مصطگی
+مصلی
+مطلبی
+معطلی
+معلمی
+معلی
+معینی
+مغلئٖ
+مفلسی
+مقتضی
+مقضی
+مقفی
+مکتبی
+ملتجی
+ملگجی
+ملنکی
+ملہٹی
+منتہی
+منجلی
+منجھی
+منچلی
+منحنی
+منصبی
+منصفی
+منطقی
+منقی
+منکتی
+منکتی
+منگتی
+منگنی
+منمنی
+منہنی
+میتھی
+میٹتی
+میٹنی
+میٹھی
+میجتی
+میجنی
+میچتی
+میچنی
+میکسی
+میگنی
+میلسی
+میمنی
+مہکتی
+مہکنی
+مہنگی
+نبٹتی
+نبٹنی
+نبختی
+نبھتی
+نپٹتی
+نپٹنی
+پنجتی
+پنجنی
+نتھنی
+نٹیلی
+نٹھتی
+نٹھنی
+نجیلی
+نجھتی
+نجھنی
+نچھتی
+نچھنی
+نسبتی
+نسیسی
+نسینی
+نشیبی
+نشیلی
+نشینی
+نعیمی
+نکلتی
+نکلنی
+نکمی
+نکیلی
+نکھتی
+نکھنی
+نگلتی
+نگلنی
+نگیلی
+نگینی
+نگھتی
+نگھنی
+نمٹتی
+نمٹنی
+نطینی
+نیستی
+نیکسی
+نینسی
+ئستگی
+ئینٹی
+ٹینکی
+ئینگی
+یتیلی
+یتیمی
+یجنسی
+یحیی
+یخھنی
+یحیی
+یفتگی
+یقینی
+یکنسی
+یکھتی
+یکھنی
+یلمعی
+یمیمی
+یمینی
+ینٹھی
+ینکتی
+ینکنی
+ینگتی
+ینگنی
+ہتھنی
+نٹیلی
+ہچکتی
+ہچکنی
+ہستگی
+ہستنی
+ہلبلی
+ہلگتی
+ہلگنی
+ہمکنی
+ہنستی
+ہنسلی
+ہنسنی
+ہشیمی
+ھکیلی
+ھلکتی
+ھلکنی
+ھمکتی
+ھمکنی
+ھنستی
+ھسنی
+ھنکتی
+ھنکنی
+بصیغہ
+بقیتہ
+بگینہ
+بلیلبہ
+بنفشہ
+بنگلہ
+بیلچہ
+تپنچہ
+تثنیہ
+تخلیہ
+تسمیہ
+تشبیہ
+تصفیہ
+تعلقہ
+تعمیہ
+تکمیلہ
+تمنچہ
+تنبیہ
+تہلکہ
+ٹھٹھہ
+ٹھیکہ
+ٹھیلہ
+ثعلبہ
+ثمینہ
+جلیلہ
+جمعتہ
+جمیلہ
+چشتیہ
+حبیبہ
+حسینہ
+حشتیہ
+حلفیہ
+حلیلہ
+حلیمہ
+حنیفہ
+خبیثہ
+خجستہ
+خفیفہ
+خلیلہ
+سفینہ
+سقیفہ
+شکستہ
+سکینہ
+سلسلہ
+سنبلہ
+سہیلہ
+شبیلہ
+شبینہ
+شعشعہ
+شفیعہ
+شفیقہ
+شقیقہ
+شکبیہ
+شکستہ
+شکنجہ
+شکیبہ
+شکیلہ
+شگفتہ
+شمیمہ
+شنیعہ
+شیفتہ
+شہنشہ
+صبعتہ
+صبغتہ
+صبیحہ
+صحیفہ
+ضحیفہ
+ضمیمہ
+طبیبہ
+طپنچہ
+طلیعہ
+طمنچہ
+طنطنہ
+عجیبہ
+عشقیہ
+عصبیہ
+عطیۂ
+عظیمہعفیفہ
+عقیقہ
+عقیلہ
+عقیمہ
+علقمہ
+علمیہ
+عیلیہ
+غلغلہ
+غلیطہ
+غلیظہ
+غلیلہ
+غنچۂ
+فتیلہ
+فصیحہ
+فلبتہ
+فلسفہ
+فلیتہ
+فیصلہ
+قبیحہ
+قبیلہ
+قتیکہ
+قسمیہ
+قمقمہ
+قہقہہ
+کبیسہ
+کٹکنہ
+کلبلہ
+کلکتہ
+کلمتہ
+کلنکہ
+کلیجہ
+کلیلہ
+کمینہ
+کنینہ
+کہھجلہ
+گنجفہ
+گھنٹہ
+لجمعہ
+لجملہ
+لجنتہ
+لخلخہ
+لشتیہ
+لشعبہ
+لطیفہ
+لعنتہ
+لقلقہ
+لکعبہ
+للغتہ
+للہ
+لمنتہ
+لیلتہ
+مبینہ
+متصلہ
+متفقہ
+متنبہ
+مثبتہ
+مجسمہ
+مجلہ
+مچلکہ
+محسنہ
+محصنہ
+محکمہ
+محلہ
+مخمصہ
+مسلمہ
+مسئلہ
+مسینہ
+مشتبہ
+مشعلہ
+مشغلہ
+مصنفہ
+مضحکہ
+مطلقہ
+مظلمہ
+مظنہ
+معلقہ
+معلمہ
+معینہ
+مغلیہ
+مغنیہ
+مقنہ
+مکتبہ
+منحقہ
+ملیحہ
+ممکنہ
+منصۂ
+منطقہ
+میختہ
+میمنہ
+مہملہ
+مہینہ
+نپیلہ
+نتیجہ
+نسیمہ
+نشستہ
+نصیبہ
+نطینہ
+نظمیہ
+نعتیہ
+نعیمہ
+نگینہ
+نیمچہ
+ئنچہ
+ہلیلہ
+ہمیشہ
+ہمہمہ
+پینٹہ
+ٹھیٹھ
+جھنجھ
+کھنکھ
+لینتھ
+ملیچھ
+ہیلتھ
+لبینتہ
+لعظمتہ
+مشخیل
+حسنی
+خنثی
+عقبی
+عیسی
+لبنی
+لصلو
+مثنی
+مجلی
+مجملا
+محشی
+جلگ
+معلی
+مقفی
+یحیی
+تعلقا
+قیمتا
+مجملا
+مطلقا
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/6grams.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/6grams.txt
new file mode 100644 (file)
index 0000000..d1e21f1
--- /dev/null
@@ -0,0 +1,1542 @@
+بھینگا
+ٹھینگا
+پتیلیا
+بلبلیا
+پلپلیا
+تلتلیا
+ٹلٹلیا
+پھینکا
+پگھلتا
+پگھلنا
+ٹگھلتا
+ٹگھلنا
+بنگلیا
+بیٹھتا
+بیٹھنا
+ینٹھتا
+ینٹھنا
+بھیجتا
+بھیجنا
+پہنچتا
+پہنچنا
+بھیلتا
+بھیلنا
+بھیلیا
+پھیلتا
+پھیلنا
+ٹھیلتا
+ٹھیلنا
+ٹیکسٹا
+ٹیکسیا
+پسیجتا
+پسیجنا
+بھبکتا
+بھبکنا
+بھبکیا
+بھپکتا
+بھپکنا
+بھپکیا
+بھٹکتا
+بھنکتا
+بھنکنا
+بھیگتا
+بھیگنا
+پھٹکتا
+پھنکتا
+پھنکنا
+پھنکیا
+تپھکتا
+تپھکیا
+ٹھنکتا
+ٹھنکنا
+ٹھنکیا
+بھٹکنا
+پٹھکنا
+تھپکنا
+بھتیجا
+بھینچا
+پھینچا
+تھیلیا
+ٹھمکتا
+ٹھمکنا
+ٹھمکیا
+ھکیلتا
+پہیلیا
+بھگتنا
+پھسلنا
+پھسلتا
+پھنستا
+پھنسنا
+ٹھنستا
+ٹھنسنا
+چھبیلا
+چٹخنیا
+ھکیلنا
+پھکنیا
+سلجھتا
+سلجھنا
+کھیلتا
+کھیلنا
+کھینچتا
+جھینکا
+جھینگا
+چھینکا
+کھنچنا
+کھٹکتا
+کھٹکنا
+کھٹکیا
+کھنکتا
+کھنکنا
+بھگتتا
+چینٹیا
+جھیلتا
+جھیلنا
+چھیلتا
+چھیلنا
+چینگتا
+چینگنا
+سمجھتا
+سمجھنا
+جھلنگا
+چھلنگا
+جھپٹتا
+جھپٹنا
+جھینپا
+چھنٹتا
+چھنٹنا
+چھیننا
+جھلکتا
+جھلکنا
+جھلکیا
+چھلکتا
+چھلکنا
+چھلکیا
+جھپکتا
+جھپینا
+جھپکیا
+جھٹکتا
+جھٹکنا
+جھکیا
+چھٹکتا
+چھٹکنا
+چھٹکیا
+لپیٹتا
+لپیٹنا
+بھسکنا
+بھسکتا
+ٹھسکتا
+ٹھسکنا
+جھجکنا
+جھجکتا
+چھینتا
+سمیٹنا
+سمیٹتا
+گھنٹیا
+چپیٹتا
+چپیٹنا
+چھینیا
+طبیعیا
+کھسکتا
+کھسکنا
+کھیتیا
+گھٹنیا
+میٹھتا
+میٹھنا
+جھپیٹا
+لبلبیا
+لبیلیا
+ہتھنیا
+چمکیلا
+چھلنیا
+سنکھیا
+سیکھتا
+سیکھنا
+چٹکیلیا
+جلیبیا
+جھلستا
+جھلسنا
+چھینٹا
+سینچتا
+سینچنا
+گھسٹتا
+گھسیٹا
+جھنجلا
+جھلملا
+جھمیلا
+سینکتا
+سینکنا
+فلسفیا
+لہسنیا
+لنگھتا
+لنگھنا
+بہنگیا
+بھینسا
+پتنگیا
+پھلکیا
+تخلیقا
+نتھنیا
+نخلستا
+جھنجھنا
+چھیجتا
+چھنکتا
+چھنکنا
+چبھینا
+سٹکنیا
+کیتلیا
+کنپٹیا
+گھٹلیا
+لچکیلا
+تخمینا
+سینتتا
+سینتنا
+بپتسما
+منگنیا
+مہکیلا
+سنبھلا
+مطلقا
+تحقیقا
+جھنجھیا
+جھمکتا
+جھمکنا
+جھمکیا
+چھتیسا
+سنجھلا
+فضیحتا
+فضیحتا
+متعلقا
+مچھلیا
+ملیشیا
+بھتنیا
+پھبتیا
+کھینچا
+گھیتلا
+گھیتلا
+کنکھیا
+کٹکھنا
+کنگھیا
+چھچھلا
+منجھلا
+سینگنا
+سینگیا
+طلیستا
+کنگنیا
+کھٹہنا
+کھسلتا
+گنٹھیا
+کچھنیا
+کھسلنا
+کیچلیا
+گنجھیا
+گینگٹا
+چھچھنا
+سنسنیا
+گھنگھنا
+کھکھلا
+گنٹھتا
+گنٹھنا
+بھجنگا
+بھنگیا
+ٹھنگنا
+گملیلا
+پھبکتا
+پھبکنا
+پھنگیا
+گینگلا
+پھپکنا
+تحصیلا
+ٹھٹکتا
+ٹھٹکنا
+کھلبلا
+کھنستا
+کھنسنا
+کھیکٹا
+گھٹکتا
+گھٹکنا
+گھینٹا
+گھینپا
+پٹیلتا
+پٹیلنا
+پھینٹا
+پیپلیا
+تسلیا
+تسلیما
+تعصبا
+تعطیلا
+تعلیما
+تعمیلا
+تعیشا
+تکلیفا
+تمثیلا
+تھنچتا
+تھنچنا
+ٹیکسلا
+یمیلیا
+پھسکتا
+پھسکنا
+سبھیتا
+کمپنیا
+معلما
+پھپھیا
+تنصیبا
+نگلستا
+مصطلحا
+گیمبیا
+بکسیلا
+تعظیما
+ٹکسیلا
+کنکٹیا
+تفصیلا
+گھنشیا
+تکلفا
+گھینٹا
+چھیجنا
+لکیمیا
+جھٹپٹا
+بھینٹا
+سنگیتا
+میکنما
+سٹیبلا
+نگینیا
+فلمستا
+فلمسٹا
+بھلسنا
+بھلستا
+سیمینا
+پنکھیا
+پنچھیا
+پھنسیا
+پھسکیا
+قینچیا
+لچیسپیا
+صنعتکا
+تصنیفا
+بلتستا
+تلمیحا
+ملتجیا
+تشبیحا
+بہشتیا
+مصلحتا
+منتظما
+کمیٹیا
+کنٹھیا
+کھچیا
+میکسیا
+بگھلیا
+تصحیفا
+چلمـچیا
+چہیتیا
+سلفچیا
+چمنستا
+لنہیا
+تضحیکا
+بستگیا
+فیملیو
+میگھنا
+پچکلیا
+تنعما
+تنقیحا
+پشیتبا
+ضعیفو
+سمبلیا
+نمیبیا
+منتخبا
+حسینیا
+یجنسیا
+پچیسیا
+یچھنیا
+بتیسیا
+نشینیا
+سہیلیا
+مستجیب
+متعصب
+صنعتیت
+مستغیث
+لحقیقت
+بحیثیت
+لمحصنت
+لسلطنت
+ہلسنت
+بلیسیت
+مسیحیت
+حسینیت
+جھنجھٹ
+لیمینٹ
+یتھلیٹ
+یلپمنٹ
+سٹیٹمنٹ
+لیفٹسٹ
+بینیفٹ
+لیفٹنٹ
+ٹیفیکٹ
+جسٹمنٹ
+مستغیث
+تسبیح
+عقلمند
+نقشبند
+مستفید
+کسلمند
+فلمبند
+قلمبند
+صحتمند
+ٹھیکید
+کشتمند
+تحصیلد
+کمیشنڈ
+نگلینڈ
+پلیٹڈ
+سٹلینڈ
+کھٹمنڈ
+کنسیلڈ
+ہتھکنڈ
+جھینگر
+ٹیلیگر
+نسپکڑ
+پیغمبر
+پیتمبر
+پسینجر
+مینیجر
+لمختصر
+گمبیھر
+ٹھٹھیر
+گھمبیر
+کھینچر
+کیمسٹر
+گلیشیر
+مستعمر
+منگیتر
+سپیکٹر
+مستفسر
+نجینءر
+لمتکبر
+یلفیءر
+سٹیشنر
+گھنگھر
+کھنکھر
+نیپیءر
+نفینٹر
+منٹگر
+ستکھیر
+مستظہر
+لکسمبر
+لگسمبر
+پچھتّر
+لمشتہر
+جھنجھر
+مستنصر
+کمپلسر
+سپینسر
+ٹھیھیر
+مستحصر
+بینظیر
+کینٹیز
+کمیشنر
+لمینڑ
+کمپیءر
+بغلگیر
+بیکٹیر
+لنجھیڑ
+پھلجھڑ
+کھکھپڑ
+بھلکّڑ
+پیکیجز
+کمپنیز
+متمیّز
+منگنیز
+کمیٹیز
+یجنسیز
+فنکشنز
+یلیشنز
+کمیشنر
+جیلنجز
+میٹنگز
+پنیتیس
+کمپلکس
+تینتیس
+ٹیلیکس
+سینتیس
+کلینکس
+لتشخیص
+لمتخلص
+لتخصیص
+مستفیض
+لتصنیف
+منجنیق
+لتحقیق
+ٹیکنیک
+میکینک
+ینگلیک
+تعلّقہ
+میجسٹک
+تھلیٹک
+پینٹنگ
+منیجنگ
+سمگلنگ
+میفکنگ
+کیمپنگ
+ٹیسٹنگ
+بینکنگ
+بلیجنگ
+ٹیکنکل
+نسٹیبل
+یکٹیکل
+لتفصیل
+چھنٹیل
+سٹینسل
+لتحصیل
+سلسبیل
+لتعمیل
+مستعمل
+مستقبل
+مستطیل
+کیمیکل
+بتفصیل
+سمعیل
+مستعجل
+تھلتھل
+کیلسیم
+کیلشیم
+متعلّم
+لتعظیم
+مستقیم
+بکنگھم
+لمنتکم
+مستحکم
+لتعلیم
+مستعصم
+چلبلین
+چمپیءن
+لحسنین
+فلسطین
+سلیکشن
+سلیکشن
+کینٹین
+لیٹیشن
+فسنطین
+کعبتین
+کھنکھن
+لمہیمن
+گبھیلن
+کنسیشن
+مجیشین
+کیپسٹن
+کیسپین
+محققین
+مستحسن
+کنگسٹن
+تھمپٹن
+چھچھلن
+مسلمین
+لثقلین
+متخصصین
+مصنفین
+معلمین
+فٹسمین
+محسنین
+مبلغین
+منصفین
+مصلحین
+بینجمن
+یسیپشن
+بیجتیں
+پٹختیں
+بیچتیں
+تکتیں
+پلٹتیں
+پچکتیں
+جھیلیں
+چھیلیں
+غفلتیں
+بھسکیں
+ٹھسکیں
+بھنتیں
+پھٹتیں
+ٹگھلیں
+پگھلیں
+ٹھنتیں
+نمٹتیں
+پتنگیں
+پینگیں
+پینگیں
+نٹھتیں
+بھیلیں
+پھیلیں
+ٹھیلیں
+پگلتیں
+نکلتیں
+نگلتیں
+نکھتیں
+نگھتیں
+نگھتیں
+بہلتیں
+ٹہلتیں
+بھکتیں
+بھگتیں
+پھکتیں
+ٹھکتیں
+ٹھگتیں
+بھپکیں
+بھٹکیں
+بھٹکیں
+بھیگیں
+پھٹکیں
+پھنکیں
+تھپکیں
+چٹختیں
+بچکتیں
+نکیلیں
+نگیلیں
+بیلتیں
+چبھتیں
+چپکتیں
+چٹکتیں
+کھٹکیں
+کھنکیں
+کھلتیں
+گھلتیں
+سمٹتیں
+سمیٹیں
+نجھتیں
+پچھتیں
+پٹکتیں
+ٹپکتیں
+ٹنگتیں
+ٹیکتیں
+ینکتیں
+ینگتیں
+نچھتیں
+بچھتیں
+کھیتیں
+گھٹتیں
+ھینگیں
+بجھتیں
+بھبکیں
+ٹھنکیں
+بچھئیں
+چپٹتیں
+مٹکتیں
+منگتیں
+محبتیں
+محنتیں
+جھپکیں
+جھٹکیں
+جھیکیں
+جھیکیں
+جیتتیں
+لپٹتیں
+لیپتیں
+لیٹتیں
+کھپتیں
+لپٹیں
+بتکتیں
+چکٹتیں
+لپکتیں
+لٹکتیں
+لنگتیں
+لنگتیں
+ہنستیں
+ھکیلیں
+چلبلیں
+چھپتیں
+چھٹتیں
+چسکتیں
+لہکتیں
+جھپٹیں
+چھنٹیں
+جھلسیں
+لیستیں
+ہچکتیں
+پھسلیں
+پھسلیں
+لجھتیں
+لچھتیں
+پھلتیں
+کیلتیں
+ملتیں
+بچلتیں
+پسیجیں
+بلکتیں
+پہنتیں
+پہنچیں
+بہکتیں
+ٹھستیں
+پھنسیں
+چبکتیں
+چبکتیں
+جھجکیں
+قیمتیں
+کٹکتیں
+گٹکتیں
+گھستیں
+گھسٹیں
+لکھتیں
+مجلسیں
+مچلتیں
+مچکتیں
+مسلیں
+مشکلیں
+میٹتیں
+مہکتیں
+ہمکتیں
+ٹھمکیں
+چمکتیں
+چھلکیں
+سبیلیں
+سنکتیں
+سہلتیں
+کلیلیں
+مشیتیں
+بنفشیں
+چہکتیں
+چھنکیں
+میچتین
+نسبتیں
+گھپتیں
+کھٹتیں
+سینکیں
+سینگیں
+چینگیں
+لچکتیں
+لیکھیں
+فسنطیں
+سیلتیں
+کچلتیں
+کسلتیں
+کلفتیں
+کھسکیں
+کھنچیں
+کھیلیں
+گٹھتیں
+گنٹھیں
+مخملیں
+مکھئں
+جھلکیں
+میجتیں
+بخشتیں
+بھچتیں
+بھیجیں
+سلگتیں
+سہمتیں
+سہمگیں
+سینچیں
+سیکھیں
+فضلتیں
+مسلتیں
+میٹھیں
+پیستیں
+مسکتیں
+لیچتیں
+کملتیں
+گلگلیں
+کھسلیں
+سلجھیں
+سمجھیں
+گتھتیں
+کلبلیں
+نشستیں
+گھٹکیں
+ھمکتیں
+بھلتیں
+پتھتیں
+تپکتیں
+تنکتیں
+تھلتیں
+تھمتیں
+تہمتیں
+ٹھٹکیں
+ٹھٹکیں
+سسکتیں
+سسکتیں
+سینتیں
+گپکتیں
+گپکتیں
+کیکتیں
+لعنتیں
+مشینیں
+ٹھنسیں
+بلنگیں
+پلنگیں
+پھسکیں
+بھنگیں
+پھبکیں
+ٹھلتیں
+گہکتیں
+مثلثیں
+منکتیں
+منکتیں
+تھپتیں
+نخستیں
+صحبتیں
+بگیلیں
+بھجتیں
+تھجتیں
+چپیٹیں
+تیجتیں
+ہلگتیں
+بنجتیں
+بنٹتیں
+بتیتیں
+بیٹھیں
+بینتیں
+پنپتیں
+پیٹتیں
+ٹیپتیں
+نبٹتیں
+نپٹتیں
+چیپتیں
+ینٹھیں
+جھکتیں
+بخششیں
+قسمتیں
+عصمتیں
+صنعتیں
+صنعتیں
+خشمگیں
+خصلتیں
+خصلتیں
+شکستیں
+قمیصیں
+ئجسٹیں
+غیبتیں
+قلیتیں
+خلیجیں
+شفقتیں
+محفلیں
+صلیتیں
+صلیبیں
+حبشنیں
+لجھنیں
+ستینیں
+غلیلیں
+بیلٹیں
+جبینیں
+کیسٹیں
+قفیتیں
+کمیتیں
+منطقیں
+عظمتیں
+جنبشیں
+چپٹتیں
+نجمجنیں
+پلٹنیں
+سکیمیں
+قلیمیں
+مشعلیں
+ہمیتیں
+مشقتیں
+بلبلیں
+سنگتیں
+حشمتیں
+حکمتیں
+سلیٹیں
+بیگمیں
+بھنگنو
+بھنگیو
+بھیلیو
+تھیلیو
+بھینگو
+پھینکو
+ٹھینگو
+پھکینو
+پہیلیو
+بھبکیو
+بھپکیو
+پھنکیو
+ٹھنکیو
+تھپکیو
+بھتیجو
+بھینچو
+پھینچو
+جھینکو
+چھینکو
+جھپیٹو
+جھینپو
+چھینیو
+چھینٹو
+گھٹنیو
+طبلچیو
+ہتھنیو
+طفیلیو
+حقیقتو
+چھلنیو
+لچسپیو
+پھلکیو
+ٹھمکیو
+کیتلیو
+گٹھلیو
+مچھلیو
+ٹیکسیو
+ہتھنیو
+جنگلیو
+فیمچیو
+کیپسیو
+کنپٹیو
+لبلیو
+کھینچو
+کھٹملو
+سٹکنیو
+گھینپو
+تحصیلو
+سنبھلو
+فضیلتو
+فضیحتو
+مسکینو
+گھنگھو
+گھسیٹو
+کنکھیو
+کنگھیو
+کمپنیو
+کمینیو
+کنٹھیو
+کیچلیو
+گنٹھیو
+کنگیو
+منطقیو
+لعنبکو
+بلینکو
+تعطیلو
+تکنیکو
+تنظیمو
+شخصیتو
+متھیلو
+مجسمو
+معلمو
+مملکتو
+ٹیلیفو
+مصلحتو
+سسکچیو
+کیلیفو
+بطلیمو
+بھینسو
+بھمبھو
+بیٹھکو
+مستحقو
+مغنیو
+پتیلیو
+پیپلیو
+ٹمبکٹو
+منگنیو
+بگھیلو
+ٹکھیلو
+کیلیکو
+چمیسفو
+پھنگیو
+چینٹیو
+بمبینو
+بھینٹو
+پھبتیو
+جھلکیو
+جھلکیو
+چھلکیو
+لکھنؤ
+سلطنتو
+کیسینو
+جھنجھو
+سنگینو
+جھمیلو
+پنکھیو
+پنچھیو
+قینچیو
+طبیعتو
+تکلیفو
+پھنسیو
+تصنیفو
+فیسٹیو
+عصبتیو
+مصیبتو
+بہشتیو
+لمسلمو
+بھتنیو
+جھینگو
+کھیتیو
+کیبنٹو
+لچھیو
+فیمیلیا
+کلینکو
+کمیشنو
+کیمسٹو
+میٹنگو
+مطلبیو
+کمیسٹو
+کنکشنو
+نصیحتو
+ٹیکنکو
+تمثیلو
+پیشکشو
+کیفیتو
+کھچیو
+کمیٹیو
+میکسیو
+تفصیلو
+تشبیہو
+تیئسو
+تخمینو
+تخمینو
+نیستیو
+نشیشیو
+چھبیسو
+چھتیسو
+حسینیو
+سنگھیو
+سمبلیو
+سٹیشنو
+ضعیفیا
+سہیلیو
+معیشتو
+نسیسیو
+چیلنجو
+جھمکیو
+لبعلمو
+بستگیو
+جنکشنو
+تبلیغو
+بتیسیو
+سیکشنو
+نگینیو
+لبیلیو
+یجنسیو
+پچیسو
+نطینیو
+تفتیشو
+فنکشکنو
+پیشگیو
+پینسلو
+جمعیتو
+چھبیلو
+جہنمیو
+یچھنیو
+بھشتیو
+فلسفیو
+منتظمو
+پمفلٹو
+تسبیحو
+پیچکشو
+چٹخنیو
+بصیغۂ
+بصیغۂ
+سقیفۂ
+سفینۂ
+منطقۂ
+پگھلتی
+پگھلنی
+ٹگھلتی
+ٹگھلنی
+پسیجتی
+پسیجنی
+بھتیجی
+بھینچی
+پھینچی
+بھگتتی
+بھگتنی
+پہنچتی
+پہنچنی
+پھنستی
+پھنسنی
+ٹھنستی
+ٹھنسنی
+بھینگی
+پھینکی
+ٹھینگی
+بھیلتی
+بھیلنی
+پھیلتی
+پھیلنی
+ٹھیلتی
+ٹھیلنی
+بھپکنی
+بھٹکتی
+بھٹکنی
+پھٹکتی
+پھٹکنی
+ٹھٹکنی
+بھیگتی
+بھیگنی
+بھپکتی
+ٹھمکتی
+ٹھمکنی
+چھپکی
+ستثنی
+بھنکتی
+بھنکنی
+پھنکتی
+پھنکنی
+تھپکتی
+تھپکنی
+ٹھنکتی
+ٹھنکنی
+بیٹھتی
+بیٹھنی
+ینٹھتی
+کھنچتی
+کھنچنی
+تمکینی
+جھلستی
+جھلستی
+جھلسنی
+پھسلتی
+پھسلنی
+جھلکتی
+جھلکنی
+چھلکتی
+چھلکنی
+کھٹکتی
+کھنکتی
+کھنکنی
+نمکینی
+سلجھتی
+سلجھنی
+جھجکتی
+جھجکنی
+چینگتی
+چینگنی
+سمیٹتی
+سمیٹنی
+کھیلتی
+کھیلنی
+لپیٹتی
+لپیٹنی
+بھسکتی
+بھسکنی
+ٹھسکتی
+ٹھسکنی
+چھبیسی
+چھتیسی
+ھکیلتی
+ھکیلنی
+چھنگلی
+چھپیٹی
+چھینتی
+جھپٹتی
+جھپٹنی
+چھنٹتی
+چھنٹنی
+چھیننی
+میٹھتی
+میٹھنی
+جھپکتی
+جھپکنی
+جھٹکتی
+جھٹکنی
+چھٹکتی
+چھٹکنی
+ہتھیلی
+چپیٹتی
+چپیٹنی
+بھبکتی
+بھبکنی
+ٹھٹکتی
+چنبیلی
+جھیلتی
+جھیلنی
+چھیلتی
+چھیلنی
+جھینپی
+جھینکی
+چھٹنکی
+چھینکی
+ہمیشگی
+کھسکتی
+کھسکنی
+گھسٹتی
+گھسٹنی
+گھسیٹی
+چبھینی
+سینکتی
+سینکنی
+سٹیپنی
+سینتتی
+سینتنی
+سینچتی
+سینچنی
+پھینٹی
+لحسنین
+بھیجتی
+بھیجنی
+مقفی
+چھبیلی
+چھیبلی
+مجتبی
+سیکھتی
+سیکھنی
+مسکینی
+تحقیقی
+تخفیفی
+تخلیقی
+نخستگی
+نخستگی
+چھنکتی
+چھنکنی
+سنجھلی
+مینگنی
+نہفتگی
+خجستگی
+لچکیلی
+لمنتہی
+لنگھتی
+لنگھنی
+منجھلی
+معطلی
+کھٹکنی
+کھلبلی
+متمنی
+متنبی
+متبنی
+جھلملی
+جٹکیلی
+چھیجتی
+چھیجنی
+کھپچی
+کہینگی
+کھٹیکی
+کینچلی
+گٹھیلی
+گھنگچی
+معلمی
+مصطفی
+کھسلتی
+کھسلنی
+کھسکنی
+کھٹکٹی
+فضیحتی
+مشعلچی
+مستعفی
+مستقلی
+چمکیلی
+بینجنی
+سنبھلی
+شیفتگی
+گھینٹی
+پھبکتی
+پھبکنی
+پھپکتی
+پھپکنی
+سمجھتی
+سمجھنی
+مستسقی
+بھینٹی
+پبلسٹی
+تخمینی
+تعمیلی
+تفصیلی
+تفضیلی
+سنگینی
+گنٹھنی
+گنٹھتی
+لعظمی
+مسمی
+میجیسٹی
+بلجیمی
+بھلستی
+بھلسنی
+پھلستی
+پھلسنی
+پیگشتی
+شکستگی
+شگفتگی
+گھٹکتی
+گھٹکنی
+لحسنی
+پشیتنی
+پھنگنی
+ٹھنگنی
+یکجہتی
+ستعفی
+تکمیلی
+نگلیسی
+سیلسٹی
+تحلیلی
+ٹکھیلی
+سنکھنی
+مستغنی
+گھینپی
+متحلی
+تعلی
+پیتھنی
+لیکھتی
+پھلیلی
+تمثیلی
+منتقلی
+گلیکسی
+سینکنے
+نسپلٹی
+کھینچی
+لمجستی
+تفہیمی
+تنظیمی
+تبلیغی
+تشکیلی
+فکلٹی
+غمگینی
+پینجنی
+حیثیتی
+کیفیتی
+معیشتی
+تلمیحی
+تشخیصی
+تعظیمی
+بھیکنی
+تھنکنی
+تھنکتی
+بینگنی
+پینلٹی
+سلطنتی
+عقلیتی
+کمینگی
+تہنیتی
+نصیحتی
+لبعلمی
+تفتیشی
+مکینکی
+نگیٹھی
+سلیقگی
+بھیجتے
+بھیجنے
+بھیجئے
+بھتیجے
+بھینچے
+پگھلتے
+پگھلنے
+پگھلنے
+پگھلئے
+ٹگھلتے
+ٹگھلنے
+ٹگھلئے
+پہنچتے
+پہنچنے
+ٹھٹکتے
+ٹھٹکنے
+ھکیلتے
+ھکیلنے
+ھکیلنے
+ھکیلئے
+پسیجتے
+پسیجنے
+پہنچئے
+بھگتئے
+بھپکتے
+بھپکنے
+بھنکتے
+بھنکنے
+بھیگتے
+بھیگنے
+پھنکنے
+تھپکتے
+تھپکنے
+ٹھنکتے
+ٹھنکنے
+بھینگے
+پھینکے
+پسیجئے
+بھبکتے
+بھبکنے
+بھبکئے
+بھپکئے
+بھٹکتے
+بھٹکنے
+بھٹکئے
+بھنکئے
+پھٹکتے
+پھٹکنے
+پھٹکئے
+پھنکئے
+تھپکئے
+ٹھٹکئے
+ٹھینگے
+ٹھینگے
+بھگتنے
+بھگتتے
+بھگتتے
+بھیگئے
+ٹھنکئے
+پھیلتے
+پھیلنے
+بھیلتے
+بھیلنے
+ٹھیلتے
+ٹھیلنے
+ٹھیلئے
+ٹھمکنے
+ٹھمکئے
+ٹھمکتے
+پھسلتے
+پھسلنے
+پھسلئے
+بیٹھنے
+بیٹھتے
+بیٹھئے
+ینٹھئے
+بھیلئے
+پھنستے
+پھنسنے
+پھنسئے
+ٹھنسئے
+چینگتے
+چینگنے
+چینگئے
+جھلستے
+جھلسنے
+جھلسئے
+چھیلئے
+جھلکتے
+جھلکنے
+جھلکئے
+چھلکتے
+چھلکنے
+چھلکئے
+سلجھتے
+سلجھنے
+کھٹکتے
+کھٹکنے
+کھٹکئے
+کھنکتے
+کھنکنے
+کھنکئے
+پھیلئے
+بھسکتے
+بھسکنے
+بھسکئے
+ٹھسکتے
+ٹھسکنے
+ٹھسکئے
+جھپٹتے
+جھپٹنے
+جھپٹئے
+جھینپے
+جھپیٹے
+چھنٹتے
+چھنٹنے
+چھینتے
+چھیننے
+چھینئے
+چھینٹے
+چھنٹئے
+جھپکتے
+جھپکنے
+جھپکئے
+جھٹکتے
+جھٹکنے
+جھٹکئے
+چھٹکتے
+چھٹکنے
+چھٹکئے
+چھنکتے
+چھنکنے
+چھنکئے
+سلجھئے
+سمیٹتے
+سمیٹنے
+کھنچتے
+کھنچنے
+کھنچئے
+جھجکتے
+جھجکنے
+جھجکئے
+سمیٹئے
+سمجھتے
+کھسکتے
+کھسکنے
+کھسکئے
+لپیٹتے
+لپیٹنے
+لپیٹئے
+میٹھتے
+میٹھنے
+میٹھئے
+جھیلئے
+جھینکے
+جھینگے
+چھینکے
+جھیلتے
+جھیلنے
+چھیلتے
+چھیلنے
+چپیٹتے
+چپیٹنے
+سمجھنے
+گھسٹتے
+گھسٹنے
+گھسٹئے
+گھسیٹے
+چپیٹئے
+سیکھتے
+سیکھنے
+سیکھئے
+ینٹھتے
+ینٹھنے
+چٹکیلے
+سمجھئے
+سینکتے
+سینکنے
+سینکئے
+سینتئے
+سینچتے
+سینچنے
+بھلستے
+بھلسنے
+بھلسئے
+پھلستے
+پھلسنے
+پھلسئے
+سٹینلے
+مصطفے
+بھجنگے
+پھسکتے
+پھسکنے
+پھسکئے
+تھنچتے
+تھنچنے
+تھنچئے
+تھنچئے
+جھمیلے
+کھیلتے
+کھیلنے
+چمکیلے
+کھیلئے
+تخمینے
+بھنچتے
+چھٹپٹے
+گنجینے
+لچکیلے
+چھبیلے
+تخمینہ
+متعلقہ
+مفصلہ
+متعینہ
+گنجینہ
+معلمہ
+مقننہ
+معظمہ
+لعظمتہ
+لبینتہ
+بسلسلہ
+تعلقہ
+منسلکہ
+متخیلہ
+پشمینہ
+تشمینہ
+تہمینہ
+لسبیلہ
+مختلفہ
+طلیلیہ
+طلیلیہ
+حسینیہ
+لمحکمہ
+تعلیقہ
+شبیلیہ
+مسیلمہ
+منتخبہ
+منتظمہ
+حنفیہ
+پینسٹھ
+مجتبے
+طبیعتا
+طخمینا
+مصلحتا
+مجتمعا
+تعمیلا
+مستقلا
+تعظیما
+تفصیلا
+تکلفا
+تمثیلا
+تحقیقا
+نتیجتا
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/7grams.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/7grams.txt
new file mode 100644 (file)
index 0000000..5adff9f
--- /dev/null
@@ -0,0 +1,354 @@
+پھینکتا
+پھینکنا
+بھینچتا
+بھینچنا
+بھینچنا
+پھینچتا
+پھینچنا
+پھینٹتا
+پھینٹتا
+پھنیٹنا
+بھنبھنا
+پھٹپھٹا
+نمکینیا
+جھپیٹتا
+جھپیٹنا
+جھینپتا
+جھینپنا
+چھنگلیا
+چنبیلیا
+چھٹنکیا
+چھینکنا
+چھپکلیا
+کھینچتا
+کھینچنا
+جھینکتا
+جھینکنا
+چھینکتا
+گھسیٹتا
+گھسیٹنا
+سنبھلتا
+سنبھلنا
+جھپیٹیا
+کینچلیا
+چھمچھما
+کھلبلیا
+چھلچھلا
+جھمجھما
+کھٹکھٹا
+گھنگھنا
+مستثنیا
+جھمیلیا
+مینگنیا
+بھینٹتا
+بھینٹنا
+پھنپھنا
+چھچھلتا
+چھچھلیا
+چھچھلنا
+کھکھنا
+گھینپتا
+گھینپنا
+کھسکھسا
+ٹکھیلیا
+تعظیما
+بھلبھلا
+پھلپھلا
+تھلتھلا
+جھنجھنا
+چھنچھنا
+تعلیمیا
+کھپکھپا
+بھتیجیا
+ہتھیلیا
+فیکلٹیا
+تھکتھکا
+کمینگیا
+سنگینیا
+چھتیسیا
+نگیٹھیا
+لمحصنت
+لمحصنت
+تشبیہیت
+نیشنلسٹ
+سپلیمنٹ
+سپیشلسٹ
+سٹیٹمنٹ
+یسپشنسٹ
+مینجمنٹ
+کنسلٹنٹ
+یکسچینج
+سلیکٹیڑ
+بھنبھیر
+کمنٹیٹر
+مسکیٹئر
+یکٹیشنر
+جیسلمیر
+سپلیمنٹر
+سیلیبیز
+کیمیکلز
+نٹلیجنس
+میکینکس
+ٹیفکیٹس
+نستعلیق
+سینتھٹک
+مینیجنگ
+میکینکل
+ٹیکنیکل
+پلیٹینم
+تھیلیئم
+تھینیئم
+لمستقیم
+جنٹلمین
+کمپیٹیشن
+متعلقین
+متکلمین
+مستحقیین
+منتظمین
+لمسلمین
+لمطففین
+بیٹسمین
+ٹیفیکیشن
+سبکتگین
+لیٹیشین
+متخصصین
+لنبیین
+منجمین
+ٹیکسیشن
+پنیسلین
+بھسکتیں
+ٹھسکتیں
+ٹھمکتیں
+ٹھٹکتیں
+بھیلتیں
+پھیتلتیں
+ٹھیلتیں
+چینگتیں
+چپٹیتیں
+چھلتیں
+چھنٹتیں
+بیھٹتں
+ینٹھتیں
+بھینچیں
+پھینچیں
+پگھلتیں
+ٹگھلتیں
+بھبکتیں
+بھپکتیں
+بھٹکتیں
+بھنگتیں
+بھنگنیں
+بھیگتیں
+پھٹکتیں
+تھپکتیں
+ٹھنکتین
+جھلکتین
+چھلکتین
+جھینکین
+جھینکین
+جھلستین
+جھپکتین
+جھٹکتین
+چھٹکتین
+جھیلتین
+جھینپین
+جھپٹتین
+چھینتین
+گھسٹتین
+گھسیٹین
+حقیقتین
+لپٹیتین
+پھسلتین
+تحصیلین
+بھیجتین
+پھنستین
+پھنستین
+فضیلتین
+فضیلتین
+کھینچین
+مشیتین
+ھکیلتین
+لنگھتین
+بھگتتین
+پسیجتین
+پھینکین
+سلجھتین
+کھٹکتین
+کھسکتین
+کھیلتین
+چھچھیلین
+پہنچتیں
+چھیجتیں
+سمجھتیں
+سمیٹتیں
+سیکھتیں
+سیکھتیں
+کھینچتیں
+کھینچتیں
+فضیحتیں
+میٹھتیں
+گٹھیلیں
+گنٹھتیں
+تعلیلیں
+تمثیلیں
+سنبھلیں
+سینتتین
+کھسلتیں
+بھینٹیں
+پھبکتیں
+پھپکتیں
+پھسکتیں
+تھنچتیں
+مصلحتیں
+مملکتین
+تنظیمیں
+بھنکتیں
+بھنکتیں
+شخصیتیں
+شخصیتیں
+کھنکتیں
+گھٹکتیں
+جھپیٹیں
+سلطنتیں
+بیٹھکیں
+سنگینیں
+بھینسیں
+تکلیفیں
+طبیعتیں
+ئسکلیں
+مصیبتیں
+کیفیتیں
+کلینکیں
+تفصیلیں
+میٹنگیں
+حیثیتیں
+معیشتیں
+تشبیہیں
+تشبیہیں
+جمعیتیں
+پیشکشیں
+تعطیلیں
+تنبیہیں
+تحقیقیں
+پینسلیں
+تسبیحیں
+نمکینکو
+چھٹنکیو
+چھنگلیو
+چھپکلیو
+چھینکیو
+بھنبھو
+پھٹپٹھو
+مینگنیو
+کھلبلیو
+بھتیجیو
+کیمبلپو
+کیمبلپو
+لجسلیٹیو
+میکسیکو
+نسٹیٹیو
+کینچلیو
+نسٹیبلو
+ہتھیلیو
+منجنیقیو
+گیلیلیو
+ٹیفکیٹو
+کینٹیٹو
+کمینگیو
+لیفٹسٹو
+چنبیلیو
+پینتیسو
+تینتیسو
+سینتیسو
+چھبیلیو
+کمینی
+چھتیسیو
+پینسٹھو
+پیشینگو
+نگیٹھیو
+فٹسمینو
+گنجینہ
+بھینچتی
+بھینچنی
+پھینچتی
+پھینچنی
+پھینٹتی
+پھینٹنی
+جھینپتی
+جھینپنی
+جھینکتی
+جھینکنی
+چھینکتی
+چھینکنی
+پھینکتی
+پھینکنی
+جھپیٹتی
+سنبھلتی
+متبنی
+پھٹپھٹی
+سنبھلنی
+کھٹیکنی
+کھینچتی
+کھینچنی
+گھسیٹتی
+گھسیٹنی
+گتھنیلی
+گھینپتی
+گھینپنی
+بھینٹتی
+بھینٹنی
+مستثنی
+مستغنی
+ہیلسنکی
+فلسطینی
+ٹیکنیکی
+لمنتہی
+پھسپھسی
+بھینچتے
+بھینچنے
+بھینچئے
+پھینچتے
+پھینچنے
+پھینچئے
+پسیجتے
+پھینٹتے
+پھینٹنے
+پھینٹئے
+پھینکئے
+جھینپتے
+جھینپنے
+جھینپئے
+جھینکتے
+جھینکنے
+جھینکئے
+چھینکتے
+چھینکنے
+چھینکئے
+کھینچتے
+کھینچنے
+کھینچئے
+گھسیٹتے
+گھسیٹنے
+گھسیٹئے
+جھپیٹتے
+جھپیٹنے
+جھپیٹئے
+سنبھلتے
+سنبھلنے
+سنبھلئے
+پھٹپھٹے
+چھچھلئے
+گھینپئے
+گھینپتے
+گھینپنے
+چھچھلتے
+چھچھلنے
+بھینٹتے
+بھینٹنے
+بھینٹئے
+پھینکتے
+پھینکنے
+لبینتہ
+لممتحنہ
+متخیلہ
+تفضیلیہ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/8grams.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/8grams.txt
new file mode 100644 (file)
index 0000000..d067491
--- /dev/null
@@ -0,0 +1,26 @@
+چھنچھنیا
+جھنجھٹیا
+جھنجھنیا
+گھنگھنیا
+سپلیمینٹر
+شیکسپئر
+لمطففین
+جھینکتیں
+چھینکتین
+بھینچتین
+پھینچتین
+جھینپتین
+کھینچتین
+گھسیٹتین
+پھینکتین
+گھینپتین
+چھچھلتین
+سنبھلتین
+پھینٹتین
+بھینٹتین
+جھپیٹتین
+فلسطینو
+بیٹسمینو
+نسپیلیٹی
+نیشنیلٹی
+قسطنطیہ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/LICENSE b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/LICENSE
new file mode 100644 (file)
index 0000000..85f2b63
--- /dev/null
@@ -0,0 +1,3 @@
+CC BY-NC-SA 3.0
+http://www.crulp.org/software/license/CreativeCommons.html
+https://creativecommons.org/licenses/by-nc-sa/3.0/
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/MANIFEST
new file mode 100644 (file)
index 0000000..c945d0e
--- /dev/null
@@ -0,0 +1,7 @@
+2grams.txt
+3grams.txt
+4grams.txt
+5grams.txt
+6grams.txt
+7grams.txt
+8grams.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/README b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/README
new file mode 100644 (file)
index 0000000..33202c4
--- /dev/null
@@ -0,0 +1,16 @@
+ORIGINAL README:
+
+Valid Ligatures of Urdu.
+
+In 1980 Mr. Ahmad Mirza Jamil has invented a ligature based Nastaleeq writing
+system. He has written about 18,000 valid ligatures of Urdu and developed a
+Noori Nastaliq font. Center for Research in Urdu Language Processing (CRULP) is
+releasing a soft copy of these ligatures in Unicode format. CRULP has
+extensively used these ligatures for testing the fonts developed at the center
+and realised that it will be a valuable resource for other font developers.
+These ligatures are grouped in 2 to 8 characters and are sorted in the end
+character order.
+
+These ligatures have been copied from a "Noori Nastaliq computerised Urdu
+calligraphy (list of ligatures)" calligraphically designed and compiled by
+Ahmad Mirza Jamil, Elite Publishers Limited, Karachi.
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/SOURCES b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/language-urdu/crulp/ligatures/SOURCES
new file mode 100644 (file)
index 0000000..5e67ed4
--- /dev/null
@@ -0,0 +1,4 @@
+Adapted from:
+
+http://www.crulp.org/software/ling_resources/UrduLigatures.htm
+http://www.crulp.org/Downloads/ling_resources/ligatures/Valid_Urdu_Ligatures_v1.1.zip
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/MANIFEST
new file mode 100644 (file)
index 0000000..0ac75c3
--- /dev/null
@@ -0,0 +1 @@
+diacritics
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/MANIFEST
new file mode 100644 (file)
index 0000000..c71d035
--- /dev/null
@@ -0,0 +1,7 @@
+lam-alef.txt
+language-arabic.txt
+language-persian.txt
+language-urdu.txt
+ligature-components.txt
+ligature-diacritics.txt
+mark-skipping.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/lam-alef.txt
new file mode 100644 (file)
index 0000000..26f6f7b
--- /dev/null
@@ -0,0 +1,28 @@
+لًا
+ـلًا
+لاً
+ـلاً
+لّا
+ـلّا
+لاّ
+ـلاّ
+لًّا
+ـلًّا
+لاًّ
+ـلاًّ
+لَّا
+ـلَّا
+لاَّ
+ـلاَّ
+لَا
+ـلَا
+لاَ
+ـلاَ
+لُا
+ـلُا
+لاُ
+ـلاُ
+لِا
+ـلِا
+لاِ
+ـلاِ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-arabic.txt
new file mode 100644 (file)
index 0000000..24eb0c9
--- /dev/null
@@ -0,0 +1,695 @@
+ـيًـ
+ـاً
+يُـ
+ـرً
+ـقًـ
+ـدً
+رً
+رٍ
+ـبًـ
+ـرّ
+مًـ
+ـضًـ
+مُـ
+ـدّ
+ـوّ
+ـمًـ
+ـتًـ
+ـيّـ
+يًـ
+تُـ
+ءً
+دً
+نًـ
+ـمُـ
+ـمّـ
+ةً
+حًـ
+ـوً
+ـحًـ
+ـرِّ
+ـةً
+نٍ
+ـمّ
+فًـ
+ـكّـ
+ـعًـ
+ـصًـ
+اً
+سِـ
+ـيُـ
+قِـ
+ـفًـ
+ـذّ
+ـجّـ
+بًـ
+غًـ
+ـلّـ
+ـصّـ
+ـلّ
+ـدَّ
+ـسِّـ
+ـزً
+وّ
+ـثًـ
+بُـ
+ـغّـ
+خِـ
+ـدِّ
+فٍ
+ـسّـ
+ـنًـ
+عًـ
+ـفّـ
+ـيَّـ
+ـلٍ
+ـطًـ
+ـبّـ
+ـطّـ
+ـجِّـ
+عُـ
+ـيّ
+ـنّـ
+كًـ
+ـلِـ
+ـئًـ
+جًـ
+ـذَّ
+قًـ
+ـنُـ
+ـخّـ
+ـتُـ
+رَ
+كّـ
+طًـ
+نُـ
+رّ
+لٍ
+ـضّـ
+بّـ
+عِـ
+زً
+مِـ
+ـكَّـ
+ـدَ
+ـدٍ
+أُ
+ـمَّـ
+ـأً
+ـرَ
+ـزّ
+حِـ
+مَـ
+ـيِّـ
+ـوَّ
+ـمَـ
+صًـ
+ضًـ
+ـرِ
+
+وُ
+يّ
+ـمِّـ
+ـيًّـ
+ـرَّ
+ـوِّ
+ـكًـ
+رِ
+ـلَّـ
+ـجِـ
+يَـ
+ـجَّـ
+ـاّ
+ـذً
+ـقّـ
+ـغِّـ
+ـخًـ
+ـسَّـ
+ـلٍّ
+ـهًـ
+قّـ
+حَـ
+ـجًـ
+ـفَّـ
+شُـ
+جّـ
+ـهّـ
+سَـ
+ـعّـ
+ـدِ
+دٍ
+رِّ
+ـذٍ
+ـبُّـ
+ـتَـ
+دُ
+ـتُ
+لّ
+سِّـ
+لّـ
+دّ
+دِ
+يٍّ
+جَـ
+نّ
+هَّـ
+ـكِّـ
+ـقِّـ
+ـعُـ
+بَـ
+تَـ
+ـنِّـ
+ـلُّـ
+ـسُـ
+مّـ
+قَّـ
+لَـ
+يّـ
+فُـ
+قٍ
+ـتٍ
+سّـ
+وَ
+ـسِـ
+ـتَ
+شِـ
+فَـ
+صُـ
+ـضَّـ
+تَ
+ـقَّـ
+ـطَّـ
+ـفِـ
+سًـ
+فّـ
+وَّ
+كُـ
+ـصَّـ
+عَـ
+لِـ
+ـقِ
+ـقٍ
+ـتّـ
+ـمْـ
+نّـ
+ـقَ
+وٍ
+ـطٍ
+ـةٍ
+هّـ
+هُـ
+ـوٍ
+ـبِـ
+رُ
+حّـ
+تّـ
+وِّ
+زُ
+ـلًـ
+ـفُّـ
+تٍ
+سُـ
+ضٍ
+بِـ
+خَـ
+ىً
+ضّـ
+ـبِّـ
+خّـ
+لًـ
+كَّـ
+ـظًـ
+ظًـ
+ةٍ
+ـغًـ
+ـكِـ
+طُـ
+ـنٍ
+ـقُـ
+ـبُـ
+دَ
+ثًـ
+فِـ
+يٍ
+نْـ
+ضِـ
+جُـ
+هٍ
+ـشِـ
+ـنَّـ
+يًّـ
+فِّـ
+ـفّ
+ـظّـ
+ـسَـ
+ـظِّـ
+ـبَّـ
+رْ
+تَّـ
+بٍ
+ـبَـ
+ـزُّ
+ـدُ
+ـكُـ
+طّـ
+صِـ
+تِـ
+ـغَّـ
+ـعَـ
+ـهِّـ
+ـرُ
+ـثّـ
+سَّـ
+ذً
+ـمَ
+ـلِّـ
+ـزِّ
+يٌّ
+قِّـ
+ـشِّـ
+ـسًـ
+شٍ
+سٍ
+تًـ
+ـلَـ
+ـحُـ
+ـصّ
+ـحِـ
+ـجُـ
+يَّـ
+لَّـ
+قَـ
+ـبْـ
+اِ
+وُّ
+ـشّـ
+خًـ
+ـسَ
+حُـ
+يْ
+نِـ
+كُّـ
+ـطُّـ
+سْـ
+زِ
+يَّ
+هِـ
+نَـ
+مَّـ
+مٍ
+كِـ
+ـيُّـ
+ـمِـ
+ـدٍّ
+ـحّـ
+ـتَّـ
+رِّ
+ـطّ
+ـرُّ
+عٍ
+زّ
+خَّـ
+قُـ
+ـشَـ
+ـحَـ
+ـجِّـ
+مَ
+ـيَّ
+ـقّ
+ـغِ
+ـطِ
+ـشُـ
+صّـ
+شّـ
+جِّـ
+جِـ
+وِ
+ـهِ
+ـهِـ
+ــّـ
+ـرٍ
+ـاًّ
+طَّـ
+ثُـ
+تُ
+بَّـ
+هَـ
+لْـ
+صَـ
+دْ
+يِـ
+كِّـ
+ـعِـ
+ـذَ
+ـةَ
+دَّ
+يِّ
+هًـ
+كْـ
+ـوَ
+ـقَّ
+ـؤّ
+زَ
+حٍ
+يْـ
+كَـ
+فِ
+ـهٍ
+ـنّ
+ـكِ
+ـضَـ
+ـصِـ
+صِّـ
+شِّـ
+رَّ
+يِّـ
+ـاَ
+عُ
+شَـ
+ئًـ
+مٌـ
+لُـ
+ـوِ
+ـقِـ
+ـقَـ
+ـخَـ
+ـةِ
+دِّ
+جْـ
+ةِ
+نْ
+لِّـ
+ـيَـ
+ـنَـ
+ـلٌ
+ـفِ
+ـزَّ
+ـزِ
+ـاِ
+عّـ
+حَّـ
+ثَـ
+أَ
+ـمٍ
+ـكُّـ
+عْـ
+صَّـ
+يٌـ
+مْـ
+مّ
+فُّـ
+ـنْـ
+ـمَّ
+ـكَـ
+ـصِّـ
+ـصَـ
+ـاَّ
+حْـ
+ثّـ
+اُ
+نِ
+كَ
+ـمِ
+ـلٌّ
+ـلِ
+ـلَ
+ـفَـ
+ـفٍ
+ـظَّـ
+ـزَ
+ـةُ
+ـأُ
+عَّـ
+شَّـ
+ـنِـ
+ـلُ
+ـطِّـ
+ـطَـ
+ـضِّـ
+ـصُـ
+ـسُّـ
+ـحُ
+ـثّ
+ـأَ
+ضَـ
+تْ
+اَ
+مًّـ
+ـيِـ
+ـهُـ
+ـمًّـ
+ـكْـ
+ـعْـ
+ـرِّ
+ـتِـ
+ـتً
+ـاُ
+غَـ
+عِ
+طً
+شًـ
+زٍ
+تِ
+بْـ
+بِ
+لِ
+قْـ
+قٌـ
+فّ
+ـىً
+ـلُّ
+ـلُـ
+ـفُـ
+ــُـ
+ـعَّـ
+ـشَّـ
+ـشًـ
+ـذِ
+ـدٌ
+طِـ
+طَـ
+ضَّـ
+صْـ
+رُّ
+ذُ
+جَّـ
+بِّـ
+ئِـ
+ءُ
+هُّـ
+مِّـ
+مُ
+كِ
+قُ
+فْـ
+ـيٍّ
+ـىَّ
+ـوِّ
+ـكَ
+ـعَ
+ـطَ
+ـسْـ
+ـرٌ
+ـذِّ
+ـدُّ
+ـخَّـ
+ـحْ
+ـجَـ
+ـثَّـ
+ـثُـ
+ـتّ
+ـبِ
+ـاْ
+ـإِ
+عَ
+طِّـ
+صُّـ
+زْ
+خِّـ
+خَ
+ثِـ
+تْـ
+تّ
+بٌـ
+ءَ
+ءٍ
+وْ
+نُ
+مِ
+كُ
+فْ
+ـوُّ
+ـلٍـ
+ـقٍّ
+ـفِّـ
+ـفًّـ
+ـعُ
+ـعٍ
+ـطْـ
+ـطِـ
+ـطُـ
+ـصٍ
+ـرْ
+ـرٍّ
+ـذُّ
+ـدْ
+ـدِّ
+ـخِـ
+ـجَّـ
+ـثْ
+ـتَّ
+ـةٌ
+سِ
+خْـ
+ثَ
+تُّـ
+تَّ
+إِ
+أّ
+أً
+ءِ
+ءٌ
+يُّـ
+يُّ
+نٌـ
+لْ
+لُ
+لَ
+قِ
+ـيًّ
+ـيَ
+ـهَّـ
+ـهِّـ
+ـنُّـ
+ـمٍّ
+ـلْـ
+ـلْ
+ـلٍّ
+ـكِّـ
+ـعّ
+ـطَّ
+ـضُـ
+ـضٍ
+ـضٌـ
+ـصْـ
+
+ـصُّـ
+ـصًّـ
+ـسًّـ
+ـدَّ
+ـثِّـ
+ـثِـ
+ـتِّـ
+ـبّ
+ـبَ
+ـأٌ
+غُـ
+ظَـ
+طْـ
+ضْـ
+ضِ
+صّ
+صِ
+شْـ
+سٌـ
+ذْ
+ذَ
+خِ
+خُـ
+خٌـ
+حِّـ
+حٌـ
+بِّ
+بُّ
+بَ
+يٍّ
+ىّ
+نِّـ
+نَّـ
+نٍـ
+نٌ
+مْ
+مٌ
+لُّـ
+قُّـ
+قّ
+فَّـ
+فُ
+فٍـ
+ـيْـ
+ـيَّـ
+ـيً
+ـىّ
+ـوُ
+ـهّ
+ـهَـ
+ـنُ
+ـنَ
+ـمَّـ
+ـلَّ
+ـقٌ
+ـفِّ
+ـفٍّ
+ـفًّ
+ــِّـ
+ــِ
+ــَـ
+ـغِـ
+ـغُـ
+ـغَـ
+ـعٌـ
+ـظّ
+ـظِـ
+ـظَ
+ـطٍّ
+ـطِّـ
+ـطُ
+ـضً
+ـصِ
+ـصَ
+ـصٌ
+ـشّ
+ـسّ
+ـسَّـ
+ـزْ
+ـزُ
+ـرًّ
+ـدًّ
+ـخُـ
+ـخُ
+ـحَّـ
+ـجْـ
+ـثِ
+ـثُ
+ـتْـ
+ـتْ
+ـتِ
+ـبْ
+ـبِّ
+ـبُّـ
+ـبُ
+ـبَّـ
+ـأٰ
+ـأِ
+ـأٍ
+غْـ
+غِّـ
+عْ
+ظِـ
+ضُ
+شّ
+سٍـ
+زِّ
+دُّ
+حْ
+حِ
+جُ
+ثُ
+تٌـ
+تٌ
+ةُ
+ةَ
+ةٌ
+أْ
+أِ
+أٌ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-persian.txt
new file mode 100644 (file)
index 0000000..00d9840
--- /dev/null
@@ -0,0 +1,48 @@
+ـاً
+اً
+ـهٔ
+هٔ
+وِ
+پُـ
+ـلِ
+سِـ
+اِ
+اُ
+ـهُ
+ـرّ
+گِـ
+کِـ
+کُـ
+ژِ
+ـیِ
+ـنِـ
+ـمُ
+ـصّـ
+ـسّـ
+رِ
+دّ
+دِ
+یِ
+هّ
+لِـ
+لِ
+ـیٰ
+ـیّ
+ـیَـ
+ـنِ
+ـمّـ
+ـعّـ
+ـشِ
+ـسِ
+ـزّ
+ـرِ
+ـذّ
+ـخّـ
+ـحِ
+ـثْ
+ـبّـ
+ـبّ
+ـأُ
+تّـ
+تِ
+بُـ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/language-urdu.txt
new file mode 100644 (file)
index 0000000..fddb6e5
--- /dev/null
@@ -0,0 +1,188 @@
+ـیّـ
+ـمّـ
+ـلّـ
+ـرّ
+ـاً
+ـلِـ
+ـرِ
+بُـ
+ـوّ
+ؤ
+اً
+اِ
+ـنّـ
+ثّـ
+ـجّـ
+پُـ
+ـصّـ
+ـہٰـ
+ـعّـ
+ـخّـ
+یَـ
+کُـ
+جّـ
+ـنٰـ
+ـظّـ
+دّ
+ـھّـ
+اُ
+کِـ
+لِـ
+بِـ
+نِـ
+لُـ
+ـلٰـ
+ـدّ
+مّـ
+گُـ
+ـوِ
+ـسّـ
+سُـ
+رِ
+ـھُـ
+مِـ
+يُـ
+ـطّـ
+شِـ
+سَـ
+ـگَـ
+زُ
+ـگُـ
+ئِـ
+قّـ
+قِـ
+ـفّـ
+خّـ
+نّـ
+ـبّـ
+ہِ
+تّـ
+بَـ
+فِـ
+بّـ
+ـیٰ
+ـٹّـ
+وَ
+چّـ
+پِـ
+لّـ
+دُ
+ـلِ
+ـبٰـ
+ـچّـ
+سِـ
+کّـ
+ٹِـ
+وِ
+ـی٘ـ
+ـۂ
+ـوٰ
+وّ
+ـۓ
+ـکّـ
+نِ
+مُـ
+ـتّـ
+دِ
+یِـ
+ہِـ
+گَـ
+پَـ
+ٹّ
+یٔ
+یّـ
+ہُـ
+چُـ
+مِ
+ـوُ
+ـاَ
+اَ
+گِـ
+فِ
+ـےٍ
+ـڈّ
+ـؤ
+ـقّـ
+ـجِ
+اٰ
+ـڈِ
+ـپّـ
+ـٹِـ
+ـمِـ
+ـلٔـ
+ـخِ
+رُ
+تِ
+بِ
+ۓ
+کَـ
+ٹُـ
+ـی٘
+ـںَ
+ـو٘
+ـنُـ
+ـعّ
+ـشّـ
+ـرُ
+ـحّـ
+ـجِـ
+ـبَـ
+طّـ
+شِ
+شُـ
+رّ
+جِـ
+ئٰـ
+ہٰـ
+ۂ
+ڈِ
+ڈُ
+چِـ
+نِّـ
+نُـ
+نَـ
+مٰـ
+مّ
+مَـ
+لِّـ
+لِ
+فّـ
+ـیّ
+ـیِـ
+ـہ٘ـ
+ـہّ
+ـہِـ
+ـں٘
+ـگِـ
+ـکٰـ
+ـکِـ
+ـٹَـ
+ـيّـ
+ـوَ
+ـنِـ
+ـفِـ
+ـصِ
+ـسِـ
+ـزّ
+ـرً
+ـدَ
+ـحِـ
+ـحِ
+ـتّٰـ
+ـتِ
+ـبُـ
+ـأ
+عُـ
+ظِ
+صّـ
+صُـ
+زِ
+رَ
+دِّ
+خُـ
+حِ
+حَـ
+جّ
+جُـ
+جَـ
+تَـ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/ligature-components.txt
new file mode 100644 (file)
index 0000000..0d4d47f
--- /dev/null
@@ -0,0 +1,18 @@
+لّله
+لَّله
+لَّله
+للّه
+للَّه
+للَّه
+للهّ
+للهَّ
+للهَّ
+لّلَه
+لَلّه
+لّلهَ
+لَلهّ
+للّهَ
+للَهّ
+لّلّهَ
+لّلَّه
+لَّلّه
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/ligature-diacritics.txt
new file mode 100644 (file)
index 0000000..80ba2f7
--- /dev/null
@@ -0,0 +1 @@
+لَا لا لِله للَه لله
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt b/test/shaping/texts/in-tree/shaper-arabic/script-arabic/misc/diacritics/mark-skipping.txt
new file mode 100644 (file)
index 0000000..038c921
--- /dev/null
@@ -0,0 +1,10 @@
+تختة
+تخنة
+تخئة
+تخثة
+تخٹة
+تختّة
+تخنّة
+تخئّة
+تخثّة
+تخٹّة
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mandaic/misc/MANIFEST
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/MANIFEST
new file mode 100644 (file)
index 0000000..3c76c94
--- /dev/null
@@ -0,0 +1,4 @@
+misc.txt
+non-joining.txt
+poem.txt
+variation-selectors.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/misc.txt b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/misc.txt
new file mode 100644 (file)
index 0000000..57317de
--- /dev/null
@@ -0,0 +1,6 @@
+ᠬᠦᠮᠦᠨ ᠮᠤᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌
+ᠪᠢᠴᠢᠭ᠌ ᠬᠦᠮᠦᠨ ᠮᠤᠩᠭᠣᠯ
+ᠮᠤᠩᠭᠣᠯ ᠪᠢᠴᠢᠭ᠌ ᠬᠦᠮᠦᠨ
+ᠡ᠆ᠡ
+ᠡ᠇ᠡ
+ᠡ᠊ᠡ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/non-joining.txt b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/non-joining.txt
new file mode 100644 (file)
index 0000000..93e9dd6
--- /dev/null
@@ -0,0 +1,8 @@
+ᠡᢀᠡ
+ᠡᢁᠡ
+ᠡᢂᠡ
+ᠡᢃᠡ
+ᠡᢄᠡ
+ᠡᢅᠡ
+ᠡᢆᠡ
+ᠡᢇᠡ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/poem.txt b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/poem.txt
new file mode 100644 (file)
index 0000000..14ce2d4
--- /dev/null
@@ -0,0 +1,4 @@
+ᠥᠰᠬᠦ ᠡᠴᠡ ᠰᠤᠷᠤᠭᠰᠠᠨ ᠦᠨᠳᠦᠰᠦᠨ ᠬᠡᠯᠡ
+ᠮᠠᠷᠲᠠᠵᠤ ᠪᠣᠯᠣᠰᠢ ᠦᠭᠡᠢ ᠰᠣᠶᠣᠯ
+ᠦᠬᠦᠲᠡᠯ᠎ᠡ ᠣᠷᠣᠰᠢᠬᠤ ᠲᠦᠷᠦᠯᠬᠢ ᠨᠤᠲᠤᠭ
+ᠰᠠᠯᠵᠤ ᠪᠣᠯᠣᠰᠢ ᠦᠭᠡᠢ ᠣᠷᠣᠨ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/variation-selectors.txt b/test/shaping/texts/in-tree/shaper-arabic/script-mongolian/misc/variation-selectors.txt
new file mode 100644 (file)
index 0000000..0ffb498
--- /dev/null
@@ -0,0 +1,8 @@
+ᠺᠣᠮᠫᠢᠦ᠋ᠲ᠋ᠧᠷ
+ᠭ ᠭ᠋ ᠭ᠌ ᠭ᠍‍     isol(,FVS1,FVS2,FVS3)
+ᠭ‍ ᠭ᠋‍ ᠭ᠌‍ ᠭ᠍‍     init(,FVS1,FVS2,FVS3)
+‍ᠭ‍ ‍ᠭ᠋‍ ‍ᠭ᠌‍ ‍ᠭ᠍‍      medi(,FVS1,FVS2,FVS3)
+‍ᠭ ‍ᠭ᠋ ‍ᠭ᠌      fina(,FVS1,FVS2)
+ᠠ‌ᠭᠠᠷ        ZWNJ
+ᠰᠤᠷ‍ ‍ᠭᠠ‍ ‍ᠭᠤᠯᠢ  ZWJ
+ᠪᠠᠢᠭ᠎ᠠ ᠶᠢᠨ   MVS,NNBSP
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-nko/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-nko/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/misc.txt b/test/shaping/texts/in-tree/shaper-arabic/script-nko/misc/misc.txt
new file mode 100644 (file)
index 0000000..a86af91
--- /dev/null
@@ -0,0 +1,5 @@
+ߊߊ
+ߊ߳ߊ
+ߊ߳ߺߊ
+ߊߺߊ
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/misc.txt b/test/shaping/texts/in-tree/shaper-arabic/script-phags-pa/misc/misc.txt
new file mode 100644 (file)
index 0000000..d535b67
--- /dev/null
@@ -0,0 +1,14 @@
+ꡳꡡ
+ꡡꡳꡡ
+ꡞꡞꡞ ꡞ
+ꡟꡟꡟ ꡟ
+ꡠꡠꡠ ꡠ
+ꡡꡡꡡ ꡡ
+‍ꡡ‍
+‍ꡡ
+ꡡ‍
+ꡞ‌ꡟ‌ꡠ‌ꡡ
+ꡉꡞ
+ꡉꡞ︀
+ꡪꡞ
+ꡪꡞ︀
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-syriac/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/MANIFEST
new file mode 100644 (file)
index 0000000..ae45bdf
--- /dev/null
@@ -0,0 +1 @@
+alaph.txt
diff --git a/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/alaph.txt b/test/shaping/texts/in-tree/shaper-arabic/script-syriac/misc/alaph.txt
new file mode 100644 (file)
index 0000000..27b035f
--- /dev/null
@@ -0,0 +1,98 @@
+ ܐ
+ ܐܘ
+ ܐܪ
+ ܐܖ
+ ܐܕ
+ ܐܯ
+ ܐܒ
+ܘܐ
+ܘܐܘ
+ܘܐܪ
+ܘܐܖ
+ܘܐܕ
+ܘܐܯ
+ܘܐܒ
+ܪܐ
+ܪܐܘ
+ܪܐܪ
+ܪܐܖ
+ܪܐܕ
+ܪܐܯ
+ܪܐܒ
+ܖܐ
+ܖܐܘ
+ܖܐܪ
+ܖܐܖ
+ܖܐܕ
+ܖܐܯ
+ܖܐܒ
+ܕܐ
+ܕܐܘ
+ܕܐܪ
+ܕܐܖ
+ܕܐܕ
+ܕܐܯ
+ܕܐܒ
+ܯܐ
+ܯܐܘ
+ܯܐܪ
+ܯܐܖ
+ܯܐܕ
+ܯܐܯ
+ܯܐܒ
+ܒܐ
+ܒܐܘ
+ܒܐܪ
+ܒܐܖ
+ܒܐܕ
+ܒܐܯ
+ܒܐܒ
+ ܐܐ
+ ܐܐܘ
+ ܐܐܪ
+ ܐܐܖ
+ ܐܐܕ
+ ܐܐܯ
+ ܐܐܒ
+ܘܐܐ
+ܘܐܐܘ
+ܘܐܐܪ
+ܘܐܐܖ
+ܘܐܐܕ
+ܘܐܐܯ
+ܘܐܐܒ
+ܪܐܐ
+ܪܐܐܘ
+ܪܐܐܪ
+ܪܐܐܖ
+ܪܐܐܕ
+ܪܐܐܯ
+ܪܐܐܒ
+ܖܐܐ
+ܖܐܐܘ
+ܖܐܐܪ
+ܖܐܐܖ
+ܖܐܐܕ
+ܖܐܐܯ
+ܖܐܐܒ
+ܕܐܐ
+ܕܐܐܘ
+ܕܐܐܪ
+ܕܐܐܖ
+ܕܐܐܕ
+ܕܐܐܯ
+ܕܐܐܒ
+ܯܐܐ
+ܯܐܐܘ
+ܯܐܐܪ
+ܯܐܐܖ
+ܯܐܐܕ
+ܯܐܐܯ
+ܯܐܐܒ
+ܒܐܐ
+ܒܐܐܘ
+ܒܐܐܪ
+ܒܐܐܖ
+ܒܐܐܕ
+ܒܐܐܯ
+ܒܐܐܒ
diff --git a/test/shaping/texts/in-tree/shaper-default/MANIFEST b/test/shaping/texts/in-tree/shaper-default/MANIFEST
new file mode 100644 (file)
index 0000000..d08deb7
--- /dev/null
@@ -0,0 +1,5 @@
+script-ethiopic
+script-han
+script-hiragana
+script-linear-b
+script-tifinagh
diff --git a/test/shaping/texts/in-tree/shaper-default/script-ethiopic/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-ethiopic/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/misc.txt b/test/shaping/texts/in-tree/shaper-default/script-ethiopic/misc/misc.txt
new file mode 100644 (file)
index 0000000..60dd8cc
--- /dev/null
@@ -0,0 +1 @@
+ላ፟ህ
diff --git a/test/shaping/texts/in-tree/shaper-default/script-han/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-han/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-han/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-han/misc/MANIFEST
new file mode 100644 (file)
index 0000000..003c956
--- /dev/null
@@ -0,0 +1 @@
+cjk-compat.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-han/misc/cjk-compat.txt b/test/shaping/texts/in-tree/shaper-default/script-han/misc/cjk-compat.txt
new file mode 100644 (file)
index 0000000..b3ab645
--- /dev/null
@@ -0,0 +1,3 @@
+艹
+艹
+艹
diff --git a/test/shaping/texts/in-tree/shaper-default/script-hiragana/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-hiragana/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/MANIFEST
new file mode 100644 (file)
index 0000000..4d2d52c
--- /dev/null
@@ -0,0 +1,2 @@
+kazuraki-liga-lines.txt
+kazuraki-liga.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt b/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/kazuraki-liga-lines.txt
new file mode 100644 (file)
index 0000000..5bc2d00
--- /dev/null
@@ -0,0 +1,8 @@
+ありあるあれいているべきいろうれし
+うれしくかしこかとがとうくもこと
+こともことをこのこれこれもされ
+しかししてするせんたしたのちる
+とけとしとしてとのともかくとを
+なくなどなどのなるひさひとふるほど
+ますむとめてもしろものをやるゆる
+られるとるものれる〳〵〴〵
diff --git a/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/kazuraki-liga.txt b/test/shaping/texts/in-tree/shaper-default/script-hiragana/misc/kazuraki-liga.txt
new file mode 100644 (file)
index 0000000..e043e17
--- /dev/null
@@ -0,0 +1,53 @@
+あり
+ある
+あれ
+いて
+いるべき
+いろ
+うれし
+うれしく
+かしこ
+かと
+がとう
+くも
+こと
+ことも
+ことを
+この
+これ
+これも
+され
+しかし
+して
+する
+せん
+たし
+たの
+ちる
+とけ
+とし
+として
+との
+ともかく
+とを
+なく
+など
+などの
+なる
+ひさ
+ひと
+ふる
+ほど
+ます
+むと
+めて
+もしろ
+ものを
+やる
+ゆる
+られ
+ると
+るもの
+れる
+〳〵
+〴〵
diff --git a/test/shaping/texts/in-tree/shaper-default/script-linear-b/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-linear-b/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/misc.txt b/test/shaping/texts/in-tree/shaper-default/script-linear-b/misc/misc.txt
new file mode 100644 (file)
index 0000000..b085605
--- /dev/null
@@ -0,0 +1 @@
+𐀁𐀂𐀃
diff --git a/test/shaping/texts/in-tree/shaper-default/script-tifinagh/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-tifinagh/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/misc.txt b/test/shaping/texts/in-tree/shaper-default/script-tifinagh/misc/misc.txt
new file mode 100644 (file)
index 0000000..0c307eb
--- /dev/null
@@ -0,0 +1,11 @@
+ⵎⵜ
+ⵎ⵿ⵜ
+ⵏⴾ
+ⵏ⵿ⴾ
+ⵏⵜ
+ⵏ⵿ⵜ
+ⵔⵜ
+ⵔ⵿ⵜ
+ⵙⵜ
+ⵙ⵿ⵜ
+
diff --git a/test/shaping/texts/in-tree/shaper-hangul/script-hangul/MANIFEST b/test/shaping/texts/in-tree/shaper-hangul/script-hangul/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/misc.txt b/test/shaping/texts/in-tree/shaper-hangul/script-hangul/misc/misc.txt
new file mode 100644 (file)
index 0000000..797b1c6
--- /dev/null
@@ -0,0 +1,4 @@
+휴가 가-- (오--)
+휴가 가-- (오--)
+ᄒᆞᆫ
+ᅟᅡᄫᅠ
diff --git a/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/MANIFEST b/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/MANIFEST
new file mode 100644 (file)
index 0000000..06ca481
--- /dev/null
@@ -0,0 +1 @@
+diacritics.txt
diff --git a/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/diacritics.txt b/test/shaping/texts/in-tree/shaper-hebrew/script-hebrew/misc/diacritics.txt
new file mode 100644 (file)
index 0000000..f3cf91f
--- /dev/null
@@ -0,0 +1,16 @@
+קול דודי הנה־זה בא מדלג על־ההרים מקפץ על־הגבעות
+הֲבֵל הֲבָלִים אָמַר קֹהֶלֶת
+לְהַגִּיד בַּבֹּקֶר חַסְדֶּךָ וֶאֱמוּנָתְךָ בַּלֵּילוֹת
+יְרוּשָׁלִַם
+יְרוּשָׁלִָם
+יְרוּשָׁלְַמָה
+יְרוּשָׁלְָמָה
+נְבֻֽכַדְנֶאצַּ֣ר
+מִתָּ֑͏ַ֜חַת
+אֲ‍ֽ֭דַבְּרָה
+וֽ͏ַיְהִי־֯כֵֽן
+לׅׄוּלֵׅ֗ׄאׅׄ
+אָנָּֽה אָנָּֽה
+תַעֲשֶׂ֦ה
+שֹֽׁטְרֵי֙
+אֲ‍ֽ֭
diff --git a/test/shaping/texts/in-tree/shaper-indic/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/MANIFEST
new file mode 100644 (file)
index 0000000..3f2011f
--- /dev/null
@@ -0,0 +1,2 @@
+indic
+south-east-asian
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/MANIFEST
new file mode 100644 (file)
index 0000000..5e62ebf
--- /dev/null
@@ -0,0 +1,11 @@
+script-assamese
+script-bengali
+script-devanagari
+script-gujarati
+script-gurmukhi
+script-kannada
+script-malayalam
+script-oriya
+script-sinhala
+script-tamil
+script-telugu
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/misc/MANIFEST
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..2bc4fff
--- /dev/null
@@ -0,0 +1,4 @@
+ৠ
+ৡ
+ৢ
+ৣ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..0f8fa91
--- /dev/null
@@ -0,0 +1,40 @@
+ক
+খ
+গ
+ঘ
+ঙ
+চ
+ছ
+জ
+ঝ
+ঞ
+ট
+ঠ
+ড
+ঢ
+ণ
+ত
+থ
+দ
+ধ
+ন
+প
+ফ
+ব
+ভ
+ম
+য
+ৰ
+ৱ
+ল
+ড়
+ঢ়
+য়
+শ
+ষ
+স
+হ
+ৎ
+ং
+ঃ
+ঁ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..ddf03c0
--- /dev/null
@@ -0,0 +1,10 @@
+া
+ি
+ী
+ু
+ূ
+ৃ
+ে
+ৈ
+ো
+ৌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..870ce26
--- /dev/null
@@ -0,0 +1,10 @@
+০
+১
+২
+৩
+৪
+৫
+৬
+৭
+৮
+৯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..821c261
--- /dev/null
@@ -0,0 +1,11 @@
+অ
+আ
+ই
+ঈ
+উ
+ঊ
+ঋ
+এ
+ঐ
+ও
+ঔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..0afc191
--- /dev/null
@@ -0,0 +1,6 @@
+্
+়
+ং
+ঃ
+ঁ
+৺
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..1490dfe
--- /dev/null
@@ -0,0 +1,7 @@
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..ebbc87d
--- /dev/null
@@ -0,0 +1,59 @@
+কঁ
+খঁ
+গঁ
+ঘঁ
+চঁ
+ছঁ
+জঁ
+ঝঁ
+টঁ
+ঠঁ
+ডঁ
+ঢঁ
+তঁ
+থঁ
+দঁ
+ধঁ
+পঁ
+ফঁ
+বঁ
+ভঁ
+মঁ
+যঁ
+ৰঁ
+লঁ
+শঁ
+ষঁ
+সঁ
+হঁ
+ৰ্ক
+ৰ্খ
+ৰ্গ
+ৰ্ঘ
+ৰ্চ
+ৰ্ছ
+ৰ্জ
+ৰ্ঝ
+ৰ্ঞ
+ৰ্ট
+ৰ্ঠ
+ৰ্ড
+ৰ্ঢ
+ৰ্ণ
+ৰ্ত
+ৰ্থ
+ৰ্দ
+ৰ্ধ
+ৰ্ন
+ৰ্প
+ৰ্ফ
+ৰ্ব
+ৰ্ভ
+ৰ্ম
+ৰ্য
+ৰ্ৰ
+ৰ্ল
+ৰ্শ
+ৰ্ষ
+ৰ্স
+ৰ্হ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
new file mode 100644 (file)
index 0000000..accebeb
--- /dev/null
@@ -0,0 +1,131 @@
+কু
+কূ
+কৃ
+খু
+খূ
+খৃ
+গু
+গূ
+গৃ
+ঘু
+ঘূ
+ঘৃ
+ঙু
+ঙূ
+ঙৃ
+চু
+চূ
+চৃ
+ছু
+ছূ
+ছৃ
+জু
+জূ
+জৃ
+ঝু
+ঝূ
+ঝৃ
+ঞু
+ঞূ
+টু
+টূ
+টৃ
+ঠু
+ঠূ
+ঠৃ
+ডু
+ডূ
+ডৃ
+ঢু
+ঢূ
+ঢৃ
+ণু
+ণূ
+ণৃ
+তু
+তূ
+তৃ
+থু
+থূ
+থৃ
+দু
+দূ
+দৃ
+ধু
+ধূ
+ধৃ
+নু
+নূ
+নৃ
+পু
+পূ
+পৃ
+ফু
+ফূ
+ফৃ
+বু
+বূ
+বৃ
+ভু
+ভূ
+ভৃ
+মু
+মূ
+মৃ
+যু
+যূ
+যৃ
+ৰু
+ৰূ
+ৰৃ
+লু
+লূ
+লৃ
+শু
+শূ
+শৃ
+ষু
+ষূ
+ষৃ
+সু
+সূ
+সৃ
+হু
+হূ
+হৃ
+ক্
+খ্
+গ্
+ঘ্
+ঙ্
+চ্
+ছ্
+জ্
+ঝ্
+ঞ্
+ট্
+ঠ্
+ড্
+ঢ্
+ণ্
+ত্
+থ্
+দ্
+ধ্
+ন্
+প্
+ফ্
+ব্
+ভ্
+ম্
+য্
+ৰ্
+ল্
+শ্
+ষ্
+স্
+হ্
+জ়
+ড়
+ঢ়
+য়
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..d7ae70e
--- /dev/null
@@ -0,0 +1,2 @@
+IndicFontFeatureGPOS-AboveBase.txt
+IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..87e5ea8
--- /dev/null
@@ -0,0 +1,139 @@
+ক্ৰ
+খ্ৰ
+গ্ৰ
+ঘ্ৰ
+জ্ৰ
+ত্ৰ
+দ্ৰ
+ধ্ৰ
+প্ৰ
+ম্ৰ
+শ্ৰ
+স্ৰ
+হ্ৰ
+ক্ল
+গ্ল
+প্ল
+ম্ল
+ল্ল
+শ্ল
+স্ল
+হ্ল
+ক্ক
+ক্ব
+জ্ব
+ট্ব
+ত্ব
+দ্ব
+ধ্ব
+ন্ব
+ব্ব
+ম্ব
+ল্ব
+শ্ব
+ষ্ব
+স্ব
+হ্ব
+ণ্ণ
+ষ্ণ
+ষ্ণু
+হ্ণ
+হ্ণি
+জ্জ
+ট্ট
+ত্ত
+দ্দ
+ন্ন
+প্প
+ব্ব
+ম্ম
+ত্ন
+ম্ন
+স্ন
+হ্ন
+ক্ন
+গ্ন
+ত্ম
+গ্ম
+ঙ্ম
+ট্ম
+ণ্ম
+ত্ম
+দ্ম
+ধ্ম
+ন্ম
+ম্ম
+ল্ম
+শ্ম
+ষ্ম
+হ্ম
+ক্ষ
+ক্ত
+গ্ধ
+ঙ্ক
+ঙ্খ
+ঙ্গ
+ঙ্ঘ
+চ্চ
+চ্ছ
+চ্ঞ
+জ্ঝ
+জ্ঞ
+ঞ্চ
+ঞ্ছ
+ঞ্জ
+ণ্ট
+ক্ট
+ণ্ড
+ন্ড
+দ্গ
+দ্ঘ
+দ্ধ
+দ্ভ
+ন্ত
+ন্থ
+ন্দ
+ন্ধ
+প্ত
+ব্জ
+ব্দ
+ম্প
+ম্ফ
+ম্ব
+ম্ভ
+ল্ক
+ল্গ
+ল্প
+ল্ফ
+ল্ম
+শ্চ
+ষ্ক
+ষ্ট
+ষ্ঠ
+ষ্প
+ষ্ফ
+স্ক
+স্খ
+স্ত
+স্থ
+স্প
+স্ফ
+ক্ষ্ণ
+ক্ষ্ম
+জ্জ্ব
+ত্ত্ব
+ত্ম্য
+ন্ত্ৰ
+ন্ত্ব
+ন্দ্ৰ
+ন্ধ্য
+ন্ন্য
+ম্প্ৰ
+ম্ভ্ৰ
+ৰ্ধ্ব
+ৰ্শ্ব
+ষ্ট্ৰ
+ষ্প্ৰ
+স্ত্ৰ
+চ্ছ্ব
+প্স
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-assamese/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/MANIFEST
new file mode 100644 (file)
index 0000000..3c2a4fb
--- /dev/null
@@ -0,0 +1,2 @@
+misc.txt
+reph.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/misc.txt
new file mode 100644 (file)
index 0000000..aa43590
--- /dev/null
@@ -0,0 +1,53 @@
+অ্য
+ক
+ক়
+কি
+ক্
+ক্ক
+ক্র
+ক্র্ক
+ক্‌ক
+ক্‍ক
+দ্য
+ন্ক
+ন্ধ
+ন্ব
+ন্য
+ন্র
+ন্‌ক
+ন্‌ধ
+ন্‌ব
+ন্‌র
+ন্‍ক
+ন্‍ধ
+ন্‍ব
+ন্‍র
+য্
+র্ক
+র্কি
+র্কৌ
+র্ন্‍
+র্ব্ব
+শ্য
+ষ্য
+স্য
+ি
+কো
+কৌ
+ক্র্ক
+ন্‌ক
+ন্‌ব
+ন্‍ক
+ন্‍ব
+ন্‍র
+র্কাং
+র্কাঃ
+র্কৌ
+র্ভ
+ৰ্ভ
+ৱ্ভ
+অৗ
+ন্ত্র
+ত্যু
+চ্য্র
+ক্‍ষ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/reph.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/misc/reph.txt
new file mode 100644 (file)
index 0000000..9739eaa
--- /dev/null
@@ -0,0 +1,14 @@
+র্ক
+র্কা
+র্কি
+র্কী
+র্কু
+র্কূ
+র্কে
+র্কৈ
+র্কো
+র্কৌ
+র্য
+র্‍য
+র‍্য
+র্র‍্য
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..fd5e6e6
--- /dev/null
@@ -0,0 +1 @@
+codepoint, imagepath, rawcode, desc
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..7554b36
--- /dev/null
@@ -0,0 +1,36 @@
+ক
+খ
+গ
+ঘ
+ঙ
+চ
+ছ
+জ
+ঝ
+ঞ
+ট
+ঠ
+ড
+ঢ
+ণ
+ত
+থ
+দ
+ধ
+ন
+প
+ফ
+ব
+ভ
+ম
+য
+র
+ল
+ড়
+ঢ়
+য়
+শ
+ষ
+স
+হ
+ৎ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..ddf03c0
--- /dev/null
@@ -0,0 +1,10 @@
+া
+ি
+ী
+ু
+ূ
+ৃ
+ে
+ৈ
+ো
+ৌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..870ce26
--- /dev/null
@@ -0,0 +1,10 @@
+০
+১
+২
+৩
+৪
+৫
+৬
+৭
+৮
+৯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..169ba5d
--- /dev/null
@@ -0,0 +1,12 @@
+অ
+আ
+ই
+ঈ
+উ
+ঊ
+ঋ
+ঌ
+এ
+ঐ
+ও
+ঔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..0afc191
--- /dev/null
@@ -0,0 +1,6 @@
+্
+়
+ং
+ঃ
+ঁ
+৺
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..1490dfe
--- /dev/null
@@ -0,0 +1,7 @@
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..7c652be
--- /dev/null
@@ -0,0 +1,58 @@
+কঁ
+খঁ
+গঁ
+ঘঁ
+চঁ
+ছঁ
+জঁ
+ঝঁ
+টঁ
+ঠঁ
+ডঁ
+ঢঁ
+তঁ
+থঁ
+দঁ
+ধঁ
+পঁ
+ফঁ
+বঁ
+ভঁ
+মঁ
+যঁ
+রঁ
+লঁ
+শঁ
+ষঁ
+সঁ
+হঁ
+র্ক
+র্খ
+র্গ
+র্ঘ
+র্চ
+র্ছ
+র্জ
+র্ঝ
+র্ট
+র্ঠ
+র্ড
+র্ঢ
+র্ণ
+র্ত
+র্থ
+র্দ
+র্ধ
+র্ন
+র্প
+র্ফ
+র্ব
+র্ভ
+র্ম
+র্য
+র্র
+র্ল
+র্শ
+র্ষ
+র্স
+র্হ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
new file mode 100644 (file)
index 0000000..2fd42e0
--- /dev/null
@@ -0,0 +1,119 @@
+কু
+কূ
+কৃ
+খু
+খূ
+খৃ
+গু
+গূ
+গৃ
+ঘু
+ঘূ
+ঘৃ
+চু
+চূ
+চৃ
+ছু
+ছূ
+ছৃ
+জু
+জূ
+জৃ
+ঝু
+ঝূ
+ঝৃ
+টু
+টূ
+টৃ
+ঠু
+ঠূ
+ঠৃ
+ডু
+ডূ
+ডৃ
+ঢু
+ঢূ
+ণু
+ণূ
+তু
+তূ
+তৃ
+থু
+থূ
+দু
+দূ
+দৃ
+ধু
+ধূ
+ধৃ
+নু
+নূ
+নৃ
+পু
+পূ
+পৃ
+ফু
+ফূ
+ফৃ
+বু
+বূ
+বৃ
+ভু
+ভূ
+ভৃ
+মু
+মূ
+মৃ
+যু
+যূ
+যৃ
+রু
+রূ
+রৃ
+লু
+লূ
+শু
+শূ
+শৃ
+ষু
+ষূ
+ষৃ
+সু
+সূ
+সৃ
+হু
+হূ
+হৃ
+ক্
+খ্
+গ্
+ঘ্
+ঙ্
+চ্
+ছ্
+জ্
+ঝ্
+ঞ্
+ট্
+ঠ্
+ড্
+ঢ্
+ণ্
+ত্
+থ্
+দ্
+ধ্
+ন্
+প্
+ফ্
+ব্
+ভ্
+ম্
+য্
+র্
+ল্
+শ্
+ষ্
+স্
+হ্
+জ়
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..d7ae70e
--- /dev/null
@@ -0,0 +1,2 @@
+IndicFontFeatureGPOS-AboveBase.txt
+IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..b45b778
--- /dev/null
@@ -0,0 +1,215 @@
+ক্র
+খ্র
+গ্র
+ঘ্র
+জ্র
+ত্র
+দ্র
+ধ্র
+প্র
+ম্র
+শ্র
+স্র
+হ্র
+ছ্র
+ট্র
+ঠ্র
+ড্র
+থ্র
+ফ্র
+ব্র
+ভ্র
+ক্য
+খ্য
+গ্য
+ঘ্য
+চ্য
+জ্য
+ট্য
+ঠ্য
+ড্য
+ড়্য
+ঢ্য
+ত্য
+থ্য
+দ্য
+ধ্য
+ন্য
+প্য
+ফ্য
+ব্য
+ভ্য
+ম্য
+য্য
+র‍্য
+ল্য
+শ্য
+ষ্য
+স্য
+হ্য
+ক্ল
+গ্ল
+প্ল
+ম্ল
+ল্ল
+শ্ল
+স্ল
+হ্ল
+ক্ক
+ক্ব
+জ্ব
+ট্ব
+ত্ব
+দ্ব
+ধ্ব
+ন্ব
+ব্ব
+ম্ব
+ল্ব
+শ্ব
+ষ্ব
+স্ব
+হ্ব
+ণ্ণ
+ষ্ণ
+ষ্ণু
+হ্ণ
+হ্ণি
+জ্জ
+ট্ট
+ত্ত
+দ্দ
+ন্ন
+প্প
+ত্ন
+ম্ন
+স্ন
+হ্ন
+ক্ন
+গ্ন
+গ্ম
+ঙ্ম
+ট্ম
+ণ্ম
+ত্ম
+দ্ম
+ধ্ম
+ন্ম
+ম্ম
+ল্ম
+শ্ম
+ষ্ম
+হ্ম
+ক্ষ
+ক্ত
+গ্ধ
+ঙ্ক
+ঙ্খ
+ঙ্গ
+ঙ্ঘ
+চ্চ
+চ্ছ
+চ্ঞ
+জ্ঝ
+জ্ঞ
+ঞ্চ
+ঞ্ছ
+ঞ্জ
+ণ্ট
+ক্ট
+ণ্ড
+ন্ড
+দ্গ
+দ্ঘ
+দ্ধ
+দ্ভ
+ন্ত
+ন্থ
+ন্দ
+ন্ধ
+প্ত
+ব্জ
+ব্দ
+ম্প
+ম্ফ
+ম্ভ
+ল্ক
+ল্গ
+ল্প
+ল্ফ
+শ্চ
+ষ্ক
+ষ্ট
+ষ্ঠ
+ষ্প
+ষ্ফ
+স্ক
+স্খ
+স্ত
+স্থ
+স্প
+স্ফ
+ম্থ
+ল্ত
+ল্ধ
+ক্ম
+ক্স
+গ্গ
+ঘ্ন
+চ্ন
+ছ্ব
+ঞ্ঝ
+ড্ড
+ড্ম
+ড়্গ
+ণ্ঠ
+ণ্ঢ
+ণ্ব
+ত্থ
+থ্ব
+ধ্ন
+ন্ট
+ন্ঠ
+ন্স
+প্ট
+প্ন
+ফ্ল
+ব্ধ
+ব্ল
+ভ্ল
+ম্ত
+ম্দ
+ল্ট
+ল্ড
+শ্ছ
+শ্ন
+শ্ত
+স্ট
+স্ম
+চ্ছ্র
+চ্ছ্ব
+দ্দ্ব
+দ্ধ্ব
+ন্ধ্র
+ব্দ্র
+ক্ষ্ণ
+ক্ষ্ম
+জ্জ্ব
+ত্ত্ব
+ত্ম্য
+ন্ত্র
+ন্ত্ব
+ন্দ্র
+ন্ধ্য
+ন্ন্য
+ম্প্র
+ম্ভ্র
+র্ধ্ব
+র্শ্ব
+ষ্ট্র
+ষ্প্র
+স্ত্র
+স্ট্র
+স্ক্র
+ক্ট্র
+প্স
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-bengali/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/MANIFEST
new file mode 100644 (file)
index 0000000..c384b38
--- /dev/null
@@ -0,0 +1,6 @@
+dottedcircle.txt
+eyelash.txt
+joiners.txt
+misc.txt
+spec-deviations.txt
+tricky-reordering.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/dottedcircle.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/dottedcircle.txt
new file mode 100644 (file)
index 0000000..fd0ebdb
--- /dev/null
@@ -0,0 +1,8 @@
+र्◌
+र्◌्च
+र्◌्च्छे
+र्◌ि
+र्◌्
+र्◌़
+◌्च्छे
+र् 
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/eyelash.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/eyelash.txt
new file mode 100644 (file)
index 0000000..8e11955
--- /dev/null
@@ -0,0 +1,3 @@
+त्र्क
+त्र्‍क
+त्र्‌क
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/joiners.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/joiners.txt
new file mode 100644 (file)
index 0000000..75f85cc
--- /dev/null
@@ -0,0 +1,19 @@
+र्ह
+र्‌ह
+र्‍ह
+ऱ्ह
+ऱ्‌ह
+ऱ्‍ह
+क्क
+क्‍
+क्‌क
+क्‍क
+क्कि
+क्‌कि
+क्‍कि
+क्ष
+क्‌ष
+क्‍ष
+द्सि
+द्‌सि
+द्‍सि
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/misc.txt
new file mode 100644 (file)
index 0000000..4a8326c
--- /dev/null
@@ -0,0 +1,36 @@
+क
+क़
+कि
+क्
+क्क
+क्र
+क्र्क
+क्र्‍
+क्ष
+क्ष्
+क्‌ष
+क्‍
+क्‍ष
+छ्र्क
+ज्ञ्
+ट्रु
+र्क
+र्कि
+र्क्रि
+र्‍
+ि
+फ़्र
+फ्र
+द्दि
+क्ष
+क्‌ष
+क्‍ष
+र्अ्
+र्अ्‌
+र्अ्‍
+र्आ्र्
+क‌ि
+ऽं
+रुँः
+1ि
+१॑
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/spec-deviations.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/spec-deviations.txt
new file mode 100644 (file)
index 0000000..4814019
--- /dev/null
@@ -0,0 +1 @@
+सा़े
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/tricky-reordering.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/misc/tricky-reordering.txt
new file mode 100644 (file)
index 0000000..1723ced
--- /dev/null
@@ -0,0 +1,5 @@
+Usage:
+  ./hb-unicode-encode UNICODE_STRING...
+or:
+  ./hb-unicode-encode --stdin
+फि्
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
new file mode 100644 (file)
index 0000000..89cefb6
--- /dev/null
@@ -0,0 +1,8 @@
+क़
+ख़
+ग़
+ज़
+ड़
+ढ़
+फ़
+य
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..9f7cda9
--- /dev/null
@@ -0,0 +1,4 @@
+ॠ
+ॡ
+ॢ
+ॣ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..3aa66ce
--- /dev/null
@@ -0,0 +1,45 @@
+क
+ख
+ग
+घ
+ङ
+च
+छ
+ज
+झ
+ञ
+ट
+ठ
+ड
+ढ
+ण
+त
+थ
+द
+ध
+न
+ऩ
+प
+फ
+ब
+भ
+म
+य
+र
+ऱ
+ल
+ळ
+ऴ
+व
+श
+ष
+स
+ह
+क़
+ख़
+ग़
+ज़
+ड़
+ढ़
+फ़
+य़
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..04cf0a7
--- /dev/null
@@ -0,0 +1,14 @@
+ा
+ि
+ी
+ु
+ू
+ृ
+ॄ
+ॅ
+ॆ
+े
+ै
+ॉ
+ो
+ौ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
new file mode 100644 (file)
index 0000000..7b0b32c
--- /dev/null
@@ -0,0 +1 @@
+॰
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..1427002
--- /dev/null
@@ -0,0 +1,10 @@
+०
+१
+२
+३
+४
+५
+६
+७
+८
+९
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-GenericPunctuation.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..b336c35
--- /dev/null
@@ -0,0 +1,16 @@
+अ
+आ
+इ
+ई
+उ
+ऊ
+ऋ
+ऌ
+ऍ
+ऎ
+ए
+ऐ
+ऑ
+ऒ
+ओ
+औ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..2ff3e87
--- /dev/null
@@ -0,0 +1,10 @@
+ँ
+ं
+ः
+़
+ऽ
+्
+ॐ
+॒
+॓
+॔
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..21eb56c
--- /dev/null
@@ -0,0 +1,9 @@
+IndicFontFeatureCodepoint-AdditionalConsonants.txt
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-DevnagariSpecificAddition.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-GenericPunctuation.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..6d57308
--- /dev/null
@@ -0,0 +1,185 @@
+कॅ
+खॅ
+गॅ
+घॅ
+ङॅ
+चॅ
+छॅ
+जॅ
+झॅ
+ञॅ
+टॅ
+ठॅ
+डॅ
+ढॅ
+णॅ
+तॅ
+थॅ
+दॅ
+धॅ
+नॅ
+ऩॅ
+पॅ
+फॅ
+बॅ
+भॅ
+मॅ
+यॅ
+रॅ
+ऱॅ
+लॅ
+ळॅ
+ऴॅ
+वॅ
+शॅ
+षॅ
+सॅ
+हॅ
+कॆ
+खॆ
+गॆ
+घॆ
+ङॆ
+चॆ
+छॆ
+जॆ
+झॆ
+ञॆ
+टॆ
+ठॆ
+डॆ
+ढॆ
+णॆ
+तॆ
+थॆ
+दॆ
+धॆ
+नॆ
+ऩॆ
+पॆ
+फॆ
+बॆ
+भॆ
+मॆ
+यॆ
+रॆ
+ऱॆ
+लॆ
+ळॆ
+ऴॆ
+वॆ
+शॆ
+षॆ
+सॆ
+हॆ
+के
+खे
+गे
+घे
+ङे
+चे
+छे
+जे
+झे
+ञे
+टे
+ठे
+डे
+ढे
+णे
+ते
+थे
+दे
+धे
+ने
+ऩे
+पे
+फे
+बे
+भे
+मे
+ये
+रे
+ऱे
+ले
+ळे
+ऴे
+वे
+शे
+षे
+से
+हे
+कै
+खै
+गै
+घै
+ङै
+चै
+छै
+जै
+झै
+ञै
+टै
+ठै
+डै
+ढै
+णै
+तै
+थै
+दै
+धै
+नै
+ऩै
+पै
+फै
+बै
+भै
+मै
+यै
+रै
+ऱै
+लै
+ळै
+ऴै
+वै
+शै
+षै
+सै
+है
+कँ
+खँ
+गँ
+घँ
+ङँ
+चँ
+छँ
+जँ
+झँ
+ञँ
+टँ
+ठँ
+डँ
+ढँ
+णँ
+तँ
+थँ
+दँ
+धँ
+नँ
+ऩँ
+पँ
+फँ
+बँ
+भँ
+मँ
+यँ
+रँ
+ऱँ
+लँ
+ळँ
+ऴँ
+वँ
+शँ
+षँ
+सँ
+हँ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
new file mode 100644 (file)
index 0000000..bff1a7b
--- /dev/null
@@ -0,0 +1,185 @@
+कु
+खु
+गु
+घु
+ङु
+चु
+छु
+जु
+झु
+ञु
+टु
+ठु
+डु
+ढु
+णु
+तु
+थु
+दु
+धु
+नु
+ऩु
+पु
+फु
+बु
+भु
+मु
+यु
+रु
+ऱु
+लु
+ळु
+ऴु
+वु
+शु
+षु
+सु
+हु
+कू
+खू
+गू
+घू
+ङू
+चू
+छू
+जू
+झू
+ञू
+टू
+ठू
+डू
+ढू
+णू
+तू
+थू
+दू
+धू
+नू
+ऩू
+पू
+फू
+बू
+भू
+मू
+यू
+रू
+ऱू
+लू
+ळू
+ऴू
+वू
+शू
+षू
+सू
+हू
+कृ
+खृ
+गृ
+घृ
+ङृ
+चृ
+छृ
+जृ
+झृ
+ञृ
+टृ
+ठृ
+डृ
+ढृ
+णृ
+तृ
+थृ
+दृ
+धृ
+नृ
+ऩृ
+पृ
+फृ
+बृ
+भृ
+मृ
+यृ
+रृ
+ऱृ
+लृ
+ळृ
+ऴृ
+वृ
+शृ
+षृ
+सृ
+हृ
+कॄ
+खॄ
+गॄ
+घॄ
+ङॄ
+चॄ
+छॄ
+जॄ
+झॄ
+ञॄ
+टॄ
+ठॄ
+डॄ
+ढॄ
+णॄ
+तॄ
+थॄ
+दॄ
+धॄ
+नॄ
+ऩॄ
+पॄ
+फॄ
+बॄ
+भॄ
+मॄ
+यॄ
+रॄ
+ऱॄ
+लॄ
+ळॄ
+ऴॄ
+वॄ
+शॄ
+षॄ
+सॄ
+हॄ
+क्
+ख्
+ग्
+घ्
+ङ्
+च्
+छ्
+ज्
+झ्
+ञ्
+ट्
+ठ्
+ड्
+ढ्
+ण्
+त्
+थ्
+द्
+ध्
+न्
+ऩ्
+प्
+फ्
+ब्
+भ्
+म्
+य्
+र्
+ऱ्
+ल्
+ळ्
+ऴ्
+व्
+श्
+ष्
+स्
+ह्
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..d7ae70e
--- /dev/null
@@ -0,0 +1,2 @@
+IndicFontFeatureGPOS-AboveBase.txt
+IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..3b5e620
--- /dev/null
@@ -0,0 +1,1367 @@
+क्क
+क्ख
+क्ग
+क्घ
+क्ङ
+क्च
+क्छ
+क्ज
+क्झ
+क्ञ
+क्ट
+क्ठ
+क्ड
+क्ढ
+क्ण
+क्त
+क्थ
+क्द
+क्ध
+क्न
+क्ऩ
+क्प
+क्फ
+क्ब
+क्भ
+क्म
+क्य
+क्र
+क्ऱ
+क्ल
+क्ळ
+क्ऴ
+क्व
+क्श
+क्ष
+क्स
+क्ह
+ख्क
+ख्ख
+ख्ग
+ख्घ
+ख्ङ
+ख्च
+ख्छ
+ख्ज
+ख्झ
+ख्ञ
+ख्ट
+ख्ठ
+ख्ड
+ख्ढ
+ख्ण
+ख्त
+ख्थ
+ख्द
+ख्ध
+ख्न
+ख्ऩ
+ख्प
+ख्फ
+ख्ब
+ख्भ
+ख्म
+ख्य
+ख्र
+ख्ऱ
+ख्ल
+ख्ळ
+ख्ऴ
+ख्व
+ख्श
+ख्ष
+ख्स
+ख्ह
+ग्क
+ग्ख
+ग्ग
+ग्घ
+ग्ङ
+ग्च
+ग्छ
+ग्ज
+ग्झ
+ग्ञ
+ग्ट
+ग्ठ
+ग्ड
+ग्ढ
+ग्ण
+ग्त
+ग्थ
+ग्द
+ग्ध
+ग्न
+ग्ऩ
+ग्प
+ग्फ
+ग्ब
+ग्भ
+ग्म
+ग्य
+ग्र
+ग्ऱ
+ग्ल
+ग्ळ
+ग्ऴ
+ग्व
+ग्श
+ग्ष
+ग्स
+ग्ह
+घ्क
+घ्ख
+घ्ग
+घ्घ
+घ्ङ
+घ्च
+घ्छ
+घ्ज
+घ्झ
+घ्ञ
+घ्ट
+घ्ठ
+घ्ड
+घ्ढ
+घ्ण
+घ्त
+घ्थ
+घ्द
+घ्ध
+घ्न
+घ्ऩ
+घ्प
+घ्फ
+घ्ब
+घ्भ
+घ्म
+घ्य
+घ्र
+घ्ऱ
+घ्ल
+घ्ळ
+घ्ऴ
+घ्व
+घ्श
+घ्ष
+घ्स
+घ्ह
+ङ्क
+ङ्ख
+ङ्ग
+ङ्घ
+ङ्ङ
+ङ्च
+ङ्छ
+ङ्ज
+ङ्झ
+ङ्ञ
+ङ्ट
+ङ्ठ
+ङ्ड
+ङ्ढ
+ङ्ण
+ङ्त
+ङ्थ
+ङ्द
+ङ्ध
+ङ्न
+ङ्ऩ
+ङ्प
+ङ्फ
+ङ्ब
+ङ्भ
+ङ्म
+ङ्य
+ङ्र
+ङ्ऱ
+ङ्ल
+ङ्ळ
+ङ्ऴ
+ङ्व
+ङ्श
+ङ्ष
+ङ्स
+ङ्ह
+च्क
+च्ख
+च्ग
+च्घ
+च्ङ
+च्च
+च्छ
+च्ज
+च्झ
+च्ञ
+च्ट
+च्ठ
+च्ड
+च्ढ
+च्ण
+च्त
+च्थ
+च्द
+च्ध
+च्न
+च्ऩ
+च्प
+च्फ
+च्ब
+च्भ
+च्म
+च्य
+च्र
+च्ऱ
+च्ल
+च्ळ
+च्ऴ
+च्व
+च्श
+च्ष
+च्स
+च्ह
+छ्क
+छ्ख
+छ्ग
+छ्घ
+छ्ङ
+छ्च
+छ्छ
+छ्ज
+छ्झ
+छ्ञ
+छ्ट
+छ्ठ
+छ्ड
+छ्ढ
+छ्ण
+छ्त
+छ्थ
+छ्द
+छ्ध
+छ्न
+छ्ऩ
+छ्प
+छ्फ
+छ्ब
+छ्भ
+छ्म
+छ्य
+छ्र
+छ्ऱ
+छ्ल
+छ्ळ
+छ्ऴ
+छ्व
+छ्श
+छ्ष
+छ्स
+छ्ह
+ज्क
+ज्ख
+ज्ग
+ज्घ
+ज्ङ
+ज्च
+ज्छ
+ज्ज
+ज्झ
+ज्ञ
+ज्ट
+ज्ठ
+ज्ड
+ज्ढ
+ज्ण
+ज्त
+ज्थ
+ज्द
+ज्ध
+ज्न
+ज्ऩ
+ज्प
+ज्फ
+ज्ब
+ज्भ
+ज्म
+ज्य
+ज्र
+ज्ऱ
+ज्ल
+ज्ळ
+ज्ऴ
+ज्व
+ज्श
+ज्ष
+ज्स
+ज्ह
+झ्क
+झ्ख
+झ्ग
+झ्घ
+झ्ङ
+झ्च
+झ्छ
+झ्ज
+झ्झ
+झ्ञ
+झ्ट
+झ्ठ
+झ्ड
+झ्ढ
+झ्ण
+झ्त
+झ्थ
+झ्द
+झ्ध
+झ्न
+झ्ऩ
+झ्प
+झ्फ
+झ्ब
+झ्भ
+झ्म
+झ्य
+झ्र
+झ्ऱ
+झ्ल
+झ्ळ
+झ्ऴ
+झ्व
+झ्श
+झ्ष
+झ्स
+झ्ह
+ञ्क
+ञ्ख
+ञ्ग
+ञ्घ
+ञ्ङ
+ञ्च
+ञ्छ
+ञ्ज
+ञ्झ
+ञ्ञ
+ञ्ट
+ञ्ठ
+ञ्ड
+ञ्ढ
+ञ्ण
+ञ्त
+ञ्थ
+ञ्द
+ञ्ध
+ञ्न
+ञ्ऩ
+ञ्प
+ञ्फ
+ञ्ब
+ञ्भ
+ञ्म
+ञ्य
+ञ्र
+ञ्ऱ
+ञ्ल
+ञ्ळ
+ञ्ऴ
+ञ्व
+ञ्श
+ञ्ष
+ञ्स
+ञ्ह
+ट्क
+ट्ख
+ट्ग
+ट्घ
+ट्ङ
+ट्च
+ट्छ
+ट्ज
+ट्झ
+ट्ञ
+ट्ट
+ट्ठ
+ट्ड
+ट्ढ
+ट्ण
+ट्त
+ट्थ
+ट्द
+ट्ध
+ट्न
+ट्ऩ
+ट्प
+ट्फ
+ट्ब
+ट्भ
+ट्म
+ट्य
+ट्र
+ट्ऱ
+ट्ल
+ट्ळ
+ट्ऴ
+ट्व
+ट्श
+ट्ष
+ट्स
+ट्ह
+ठ्क
+ठ्ख
+ठ्ग
+ठ्घ
+ठ्ङ
+ठ्च
+ठ्छ
+ठ्ज
+ठ्झ
+ठ्ञ
+ठ्ट
+ठ्ठ
+ठ्ड
+ठ्ढ
+ठ्ण
+ठ्त
+ठ्थ
+ठ्द
+ठ्ध
+ठ्न
+ठ्ऩ
+ठ्प
+ठ्फ
+ठ्ब
+ठ्भ
+ठ्म
+ठ्य
+ठ्र
+ठ्ऱ
+ठ्ल
+ठ्ळ
+ठ्ऴ
+ठ्व
+ठ्श
+ठ्ष
+ठ्स
+ठ्ह
+ड्क
+ड्ख
+ड्ग
+ड्घ
+ड्ङ
+ड्च
+ड्छ
+ड्ज
+ड्झ
+ड्ञ
+ड्ट
+ड्ठ
+ड्ड
+ड्ढ
+ड्ण
+ड्त
+ड्थ
+ड्द
+ड्ध
+ड्न
+ड्ऩ
+ड्प
+ड्फ
+ड्ब
+ड्भ
+ड्म
+ड्य
+ड्र
+ड्ऱ
+ड्ल
+ड्ळ
+ड्ऴ
+ड्व
+ड्श
+ड्ष
+ड्स
+ड्ह
+ढ्क
+ढ्ख
+ढ्ग
+ढ्घ
+ढ्ङ
+ढ्च
+ढ्छ
+ढ्ज
+ढ्झ
+ढ्ञ
+ढ्ट
+ढ्ठ
+ढ्ड
+ढ्ढ
+ढ्ण
+ढ्त
+ढ्थ
+ढ्द
+ढ्ध
+ढ्न
+ढ्ऩ
+ढ्प
+ढ्फ
+ढ्ब
+ढ्भ
+ढ्म
+ढ्य
+ढ्र
+ढ्ऱ
+ढ्ल
+ढ्ळ
+ढ्ऴ
+ढ्व
+ढ्श
+ढ्ष
+ढ्स
+ढ्ह
+ण्क
+ण्ख
+ण्ग
+ण्घ
+ण्ङ
+ण्च
+ण्छ
+ण्ज
+ण्झ
+ण्ञ
+ण्ट
+ण्ठ
+ण्ड
+ण्ढ
+ण्ण
+ण्त
+ण्थ
+ण्द
+ण्ध
+ण्न
+ण्ऩ
+ण्प
+ण्फ
+ण्ब
+ण्भ
+ण्म
+ण्य
+ण्र
+ण्ऱ
+ण्ल
+ण्ळ
+ण्ऴ
+ण्व
+ण्श
+ण्ष
+ण्स
+ण्ह
+त्क
+त्ख
+त्ग
+त्घ
+त्ङ
+त्च
+त्छ
+त्ज
+त्झ
+त्ञ
+त्ट
+त्ठ
+त्ड
+त्ढ
+त्ण
+त्त
+त्थ
+त्द
+त्ध
+त्न
+त्ऩ
+त्प
+त्फ
+त्ब
+त्भ
+त्म
+त्य
+त्र
+त्ऱ
+त्ल
+त्ळ
+त्ऴ
+त्व
+त्श
+त्ष
+त्स
+त्ह
+थ्क
+थ्ख
+थ्ग
+थ्घ
+थ्ङ
+थ्च
+थ्छ
+थ्ज
+थ्झ
+थ्ञ
+थ्ट
+थ्ठ
+थ्ड
+थ्ढ
+थ्ण
+थ्त
+थ्थ
+थ्द
+थ्ध
+थ्न
+थ्ऩ
+थ्प
+थ्फ
+थ्ब
+थ्भ
+थ्म
+थ्य
+थ्र
+थ्ऱ
+थ्ल
+थ्ळ
+थ्ऴ
+थ्व
+थ्श
+थ्ष
+थ्स
+थ्ह
+द्क
+द्ख
+द्ग
+द्घ
+द्ङ
+द्च
+द्छ
+द्ज
+द्झ
+द्ञ
+द्ट
+द्ठ
+द्ड
+द्ढ
+द्ण
+द्त
+द्थ
+द्द
+द्ध
+द्न
+द्ऩ
+द्प
+द्फ
+द्ब
+द्भ
+द्म
+द्य
+द्र
+द्ऱ
+द्ल
+द्ळ
+द्ऴ
+द्व
+द्श
+द्ष
+द्स
+द्ह
+ध्क
+ध्ख
+ध्ग
+ध्घ
+ध्ङ
+ध्च
+ध्छ
+ध्ज
+ध्झ
+ध्ञ
+ध्ट
+ध्ठ
+ध्ड
+ध्ढ
+ध्ण
+ध्त
+ध्थ
+ध्द
+ध्ध
+ध्न
+ध्ऩ
+ध्प
+ध्फ
+ध्ब
+ध्भ
+ध्म
+ध्य
+ध्र
+ध्ऱ
+ध्ल
+ध्ळ
+ध्ऴ
+ध्व
+ध्श
+ध्ष
+ध्स
+ध्ह
+न्क
+न्ख
+न्ग
+न्घ
+न्ङ
+न्च
+न्छ
+न्ज
+न्झ
+न्ञ
+न्ट
+न्ठ
+न्ड
+न्ढ
+न्ण
+न्त
+न्थ
+न्द
+न्ध
+न्न
+न्ऩ
+न्प
+न्फ
+न्ब
+न्भ
+न्म
+न्य
+न्र
+न्ऱ
+न्ल
+न्ळ
+न्ऴ
+न्व
+न्श
+न्ष
+न्स
+न्ह
+ऩ्क
+ऩ्ख
+ऩ्ग
+ऩ्घ
+ऩ्ङ
+ऩ्च
+ऩ्छ
+ऩ्ज
+ऩ्झ
+ऩ्ञ
+ऩ्ट
+ऩ्ठ
+ऩ्ड
+ऩ्ढ
+ऩ्ण
+ऩ्त
+ऩ्थ
+ऩ्द
+ऩ्ध
+ऩ्न
+ऩ्ऩ
+ऩ्प
+ऩ्फ
+ऩ्ब
+ऩ्भ
+ऩ्म
+ऩ्य
+ऩ्र
+ऩ्ऱ
+ऩ्ल
+ऩ्ळ
+ऩ्ऴ
+ऩ्व
+ऩ्श
+ऩ्ष
+ऩ्स
+ऩ्ह
+प्क
+प्ख
+प्ग
+प्घ
+प्ङ
+प्च
+प्छ
+प्ज
+प्झ
+प्ञ
+प्ट
+प्ठ
+प्ड
+प्ढ
+प्ण
+प्त
+प्थ
+प्द
+प्ध
+प्न
+प्ऩ
+प्प
+प्फ
+प्ब
+प्भ
+प्म
+प्य
+प्र
+प्ऱ
+प्ल
+प्ळ
+प्ऴ
+प्व
+प्श
+प्ष
+प्स
+प्ह
+फ्क
+फ्ख
+फ्ग
+फ्घ
+फ्ङ
+फ्च
+फ्छ
+फ्ज
+फ्झ
+फ्ञ
+फ्ट
+फ्ठ
+फ्ड
+फ्ढ
+फ्ण
+फ्त
+फ्थ
+फ्द
+फ्ध
+फ्न
+फ्ऩ
+फ्प
+फ्फ
+फ्ब
+फ्भ
+फ्म
+फ्य
+फ्र
+फ्ऱ
+फ्ल
+फ्ळ
+फ्ऴ
+फ्व
+फ्श
+फ्ष
+फ्स
+फ्ह
+ब्क
+ब्ख
+ब्ग
+ब्घ
+ब्ङ
+ब्च
+ब्छ
+ब्ज
+ब्झ
+ब्ञ
+ब्ट
+ब्ठ
+ब्ड
+ब्ढ
+ब्ण
+ब्त
+ब्थ
+ब्द
+ब्ध
+ब्न
+ब्ऩ
+ब्प
+ब्फ
+ब्ब
+ब्भ
+ब्म
+ब्य
+ब्र
+ब्ऱ
+ब्ल
+ब्ळ
+ब्ऴ
+ब्व
+ब्श
+ब्ष
+ब्स
+ब्ह
+भ्क
+भ्ख
+भ्ग
+भ्घ
+भ्ङ
+भ्च
+भ्छ
+भ्ज
+भ्झ
+भ्ञ
+भ्ट
+भ्ठ
+भ्ड
+भ्ढ
+भ्ण
+भ्त
+भ्थ
+भ्द
+भ्ध
+भ्न
+भ्ऩ
+भ्प
+भ्फ
+भ्ब
+भ्भ
+भ्म
+भ्य
+भ्र
+भ्ऱ
+भ्ल
+भ्ळ
+भ्ऴ
+भ्व
+भ्श
+भ्ष
+भ्स
+भ्ह
+म्क
+म्ख
+म्ग
+म्घ
+म्ङ
+म्च
+म्छ
+म्ज
+म्झ
+म्ञ
+म्ट
+म्ठ
+म्ड
+म्ढ
+म्ण
+म्त
+म्थ
+म्द
+म्ध
+म्न
+म्ऩ
+म्प
+म्फ
+म्ब
+म्भ
+म्म
+म्य
+म्र
+म्ऱ
+म्ल
+म्ळ
+म्ऴ
+म्व
+म्श
+म्ष
+म्स
+म्ह
+य्क
+य्ख
+य्ग
+य्घ
+य्ङ
+य्च
+य्छ
+य्ज
+य्झ
+य्ञ
+य्ट
+य्ठ
+य्ड
+य्ढ
+य्ण
+य्त
+य्थ
+य्द
+य्ध
+य्न
+य्ऩ
+य्प
+य्फ
+य्ब
+य्भ
+य्म
+य्य
+य्र
+य्ऱ
+य्ल
+य्ळ
+य्ऴ
+य्व
+य्श
+य्ष
+य्स
+य्ह
+र्क
+र्ख
+र्ग
+र्घ
+र्ङ
+र्च
+र्छ
+र्ज
+र्झ
+र्ञ
+र्ट
+र्ठ
+र्ड
+र्ढ
+र्ण
+र्त
+र्थ
+र्द
+र्ध
+र्न
+र्ऩ
+र्प
+र्फ
+र्ब
+र्भ
+र्म
+र्य
+र्र
+र्ऱ
+र्ल
+र्ळ
+र्ऴ
+र्व
+र्श
+र्ष
+र्स
+र्ह
+ऱ्क
+ऱ्ख
+ऱ्ग
+ऱ्घ
+ऱ्ङ
+ऱ्च
+ऱ्छ
+ऱ्ज
+ऱ्झ
+ऱ्ञ
+ऱ्ट
+ऱ्ठ
+ऱ्ड
+ऱ्ढ
+ऱ्ण
+ऱ्त
+ऱ्थ
+ऱ्द
+ऱ्ध
+ऱ्न
+ऱ्ऩ
+ऱ्प
+ऱ्फ
+ऱ्ब
+ऱ्भ
+ऱ्म
+ऱ्य
+ऱ्र
+ऱ्ऱ
+ऱ्ल
+ऱ्ळ
+ऱ्ऴ
+ऱ्व
+ऱ्श
+ऱ्ष
+ऱ्स
+ऱ्ह
+ल्क
+ल्ख
+ल्ग
+ल्घ
+ल्ङ
+ल्च
+ल्छ
+ल्ज
+ल्झ
+ल्ञ
+ल्ट
+ल्ठ
+ल्ड
+ल्ढ
+ल्ण
+ल्त
+ल्थ
+ल्द
+ल्ध
+ल्न
+ल्ऩ
+ल्प
+ल्फ
+ल्ब
+ल्भ
+ल्म
+ल्य
+ल्र
+ल्ऱ
+ल्ल
+ल्ळ
+ल्ऴ
+ल्व
+ल्श
+ल्ष
+ल्स
+ल्ह
+ळ्क
+ळ्ख
+ळ्ग
+ळ्घ
+ळ्ङ
+ळ्च
+ळ्छ
+ळ्ज
+ळ्झ
+ळ्ञ
+ळ्ट
+ळ्ठ
+ळ्ड
+ळ्ढ
+ळ्ण
+ळ्त
+ळ्थ
+ळ्द
+ळ्ध
+ळ्न
+ळ्ऩ
+ळ्प
+ळ्फ
+ळ्ब
+ळ्भ
+ळ्म
+ळ्य
+ळ्र
+ळ्ऱ
+ळ्ल
+ळ्ळ
+ळ्ऴ
+ळ्व
+ळ्श
+ळ्ष
+ळ्स
+ळ्ह
+ऴ्क
+ऴ्ख
+ऴ्ग
+ऴ्घ
+ऴ्ङ
+ऴ्च
+ऴ्छ
+ऴ्ज
+ऴ्झ
+ऴ्ञ
+ऴ्ट
+ऴ्ठ
+ऴ्ड
+ऴ्ढ
+ऴ्ण
+ऴ्त
+ऴ्थ
+ऴ्द
+ऴ्ध
+ऴ्न
+ऴ्ऩ
+ऴ्प
+ऴ्फ
+ऴ्ब
+ऴ्भ
+ऴ्म
+ऴ्य
+ऴ्र
+ऴ्ऱ
+ऴ्ल
+ऴ्ळ
+ऴ्ऴ
+ऴ्व
+ऴ्श
+ऴ्ष
+ऴ्स
+ऴ्ह
+व्क
+व्ख
+व्ग
+व्घ
+व्ङ
+व्च
+व्छ
+व्ज
+व्झ
+व्ञ
+व्ट
+व्ठ
+व्ड
+व्ढ
+व्ण
+व्त
+व्थ
+व्द
+व्ध
+व्न
+व्ऩ
+व्प
+व्फ
+व्ब
+व्भ
+व्म
+व्य
+व्र
+व्ऱ
+व्ल
+व्ळ
+व्ऴ
+व्व
+व्श
+व्ष
+व्स
+व्ह
+श्क
+श्ख
+श्ग
+श्घ
+श्ङ
+श्च
+श्छ
+श्ज
+श्झ
+श्ञ
+श्ट
+श्ठ
+श्ड
+श्ढ
+श्ण
+श्त
+श्थ
+श्द
+श्ध
+श्न
+श्ऩ
+श्प
+श्फ
+श्ब
+श्भ
+श्म
+श्य
+श्र
+श्ऱ
+श्ल
+श्ळ
+श्ऴ
+श्व
+श्श
+श्ष
+श्स
+श्ह
+ष्क
+ष्ख
+ष्ग
+ष्घ
+ष्ङ
+ष्च
+ष्छ
+ष्ज
+ष्झ
+ष्ञ
+ष्ट
+ष्ठ
+ष्ड
+ष्ढ
+ष्ण
+ष्त
+ष्थ
+ष्द
+ष्ध
+ष्न
+ष्ऩ
+ष्प
+ष्फ
+ष्ब
+ष्भ
+ष्म
+ष्य
+ष्र
+ष्ऱ
+ष्ल
+ष्ळ
+ष्ऴ
+ष्व
+ष्श
+ष्ष
+ष्स
+ष्ह
+स्क
+स्ख
+स्ग
+स्घ
+स्ङ
+स्च
+स्छ
+स्ज
+स्झ
+स्ञ
+स्ट
+स्ठ
+स्ड
+स्ढ
+स्ण
+स्त
+स्थ
+स्द
+स्ध
+स्न
+स्ऩ
+स्प
+स्फ
+स्ब
+स्भ
+स्म
+स्य
+स्र
+स्ऱ
+स्ल
+स्ळ
+स्ऴ
+स्व
+स्श
+स्ष
+स्स
+स्ह
+ह्क
+ह्ख
+ह्ग
+ह्घ
+ह्ङ
+ह्च
+ह्छ
+ह्ज
+ह्झ
+ह्ञ
+ह्ट
+ह्ठ
+ह्ड
+ह्ढ
+ह्ण
+ह्त
+ह्थ
+ह्द
+ह्ध
+ह्न
+ह्ऩ
+ह्प
+ह्फ
+ह्ब
+ह्भ
+ह्म
+ह्य
+ह्र
+ह्ऱ
+ह्ल
+ह्ळ
+ह्ऴ
+ह्व
+ह्श
+ह्ष
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-devanagari/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/misc/MANIFEST
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..fd5e6e6
--- /dev/null
@@ -0,0 +1 @@
+codepoint, imagepath, rawcode, desc
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..e91003a
--- /dev/null
@@ -0,0 +1,34 @@
+ક
+ખ
+ગ
+ઘ
+ઙ
+ચ
+છ
+જ
+ઝ
+ઞ
+ટ
+ઠ
+ડ
+ઢ
+ણ
+ત
+થ
+દ
+ધ
+ન
+પ
+ફ
+બ
+ભ
+મ
+ય
+ર
+લ
+ળ
+વ
+શ
+ષ
+સ
+હ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..3650298
--- /dev/null
@@ -0,0 +1,12 @@
+ા
+િ
+ી
+ુ
+ૂ
+ૃ
+ૅ
+ે
+ૈ
+ૉ
+ો
+ૌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..eabae39
--- /dev/null
@@ -0,0 +1,10 @@
+૦
+૧
+૨
+૩
+૪
+૫
+૬
+૭
+૮
+૯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..116eb60
--- /dev/null
@@ -0,0 +1,13 @@
+અ
+આ
+ઇ
+ઈ
+ઉ
+ઊ
+ઋ
+ઍ
+એ
+ઐ
+ઑ
+ઓ
+ઔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..218e507
--- /dev/null
@@ -0,0 +1,7 @@
+ઁ
+ં
+ઃ
+઼
+ઽ
+્
+ૐ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..1490dfe
--- /dev/null
@@ -0,0 +1,7 @@
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..f7ff3af
--- /dev/null
@@ -0,0 +1,170 @@
+કૅ
+ખૅ
+ગૅ
+ઘૅ
+ઙૅ
+ચૅ
+છૅ
+જૅ
+ઝૅ
+ઞૅ
+ટૅ
+ઠૅ
+ડૅ
+ઢૅ
+ણૅ
+તૅ
+થૅ
+દૅ
+ધૅ
+નૅ
+પૅ
+ફૅ
+બૅ
+ભૅ
+મૅ
+યૅ
+રૅ
+લૅ
+ળૅ
+વૅ
+શૅ
+ષૅ
+સૅ
+હૅ
+કે
+ખે
+ગે
+ઘે
+ઙે
+ચે
+છે
+જે
+ઝે
+ઞે
+ટે
+ઠે
+ડે
+ઢે
+ણે
+તે
+થે
+દે
+ધે
+ને
+પે
+ફે
+બે
+ભે
+મે
+યે
+રે
+લે
+ળે
+વે
+શે
+ષે
+સે
+હે
+કૈ
+ખૈ
+ગૈ
+ઘૈ
+ઙૈ
+ચૈ
+છૈ
+જૈ
+ઝૈ
+ઞૈ
+ટૈ
+ઠૈ
+ડૈ
+ઢૈ
+ણૈ
+તૈ
+થૈ
+દૈ
+ધૈ
+નૈ
+પૈ
+ફૈ
+બૈ
+ભૈ
+મૈ
+યૈ
+રૈ
+લૈ
+ળૈ
+વૈ
+શૈ
+ષૈ
+સૈ
+હૈ
+કઁ
+ખઁ
+ગઁ
+ઘઁ
+ઙઁ
+ચઁ
+છઁ
+જઁ
+ઝઁ
+ઞઁ
+ટઁ
+ઠઁ
+ડઁ
+ઢઁ
+ણઁ
+તઁ
+થઁ
+દઁ
+ધઁ
+નઁ
+પઁ
+ફઁ
+બઁ
+ભઁ
+મઁ
+યઁ
+રઁ
+લઁ
+ળઁ
+વઁ
+શઁ
+ષઁ
+સઁ
+હઁ
+કં
+ખં
+ગં
+ઘં
+ઙં
+ચં
+છં
+જં
+ઝં
+ઞં
+ટં
+ઠં
+ડં
+ઢં
+ણં
+તં
+થં
+દં
+ધં
+નં
+પં
+ફં
+બં
+ભં
+મં
+યં
+રં
+લં
+ળં
+વં
+શં
+ષં
+સં
+હં
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
new file mode 100644 (file)
index 0000000..fa658cf
--- /dev/null
@@ -0,0 +1,170 @@
+કુ
+ખુ
+ગુ
+ઘુ
+ઙુ
+ચુ
+છુ
+જુ
+ઝુ
+ઞુ
+ટુ
+ઠુ
+ડુ
+ઢુ
+ણુ
+તુ
+થુ
+દુ
+ધુ
+નુ
+પુ
+ફુ
+બુ
+ભુ
+મુ
+યુ
+રુ
+લુ
+ળુ
+વુ
+શુ
+ષુ
+સુ
+હુ
+કૂ
+ખૂ
+ગૂ
+ઘૂ
+ઙૂ
+ચૂ
+છૂ
+જૂ
+ઝૂ
+ઞૂ
+ટૂ
+ઠૂ
+ડૂ
+ઢૂ
+ણૂ
+તૂ
+થૂ
+દૂ
+ધૂ
+નૂ
+પૂ
+ફૂ
+બૂ
+ભૂ
+મૂ
+યૂ
+રૂ
+લૂ
+ળૂ
+વૂ
+શૂ
+ષૂ
+સૂ
+હૂ
+કૃ
+ખૃ
+ગૃ
+ઘૃ
+ઙૃ
+ચૃ
+છૃ
+જૃ
+ઝૃ
+ઞૃ
+ટૃ
+ઠૃ
+ડૃ
+ઢૃ
+ણૃ
+તૃ
+થૃ
+દૃ
+ધૃ
+નૃ
+પૃ
+ફૃ
+બૃ
+ભૃ
+મૃ
+યૃ
+રૃ
+લૃ
+ળૃ
+વૃ
+શૃ
+ષૃ
+સૃ
+હૃ
+કૄ
+ખૄ
+ગૄ
+ઘૄ
+ઙૄ
+ચૄ
+છૄ
+જૄ
+ઝૄ
+ઞૄ
+ટૄ
+ઠૄ
+ડૄ
+ઢૄ
+ણૄ
+તૄ
+થૄ
+દૄ
+ધૄ
+નૄ
+પૄ
+ફૄ
+બૄ
+ભૄ
+મૄ
+યૄ
+રૄ
+લૄ
+ળૄ
+વૄ
+શૄ
+ષૄ
+સૄ
+હૄ
+ક્
+ખ્
+ગ્
+ઘ્
+ઙ્
+ચ્
+છ્
+જ્
+ઝ્
+ઞ્
+ટ્
+ઠ્
+ડ્
+ઢ્
+ણ્
+ત્
+થ્
+દ્
+ધ્
+ન્
+પ્
+ફ્
+બ્
+ભ્
+મ્
+ય્
+ર્
+લ્
+ળ્
+વ્
+શ્
+ષ્
+સ્
+હ્
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..d7ae70e
--- /dev/null
@@ -0,0 +1,2 @@
+IndicFontFeatureGPOS-AboveBase.txt
+IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..6211c9b
--- /dev/null
@@ -0,0 +1,1156 @@
+ક્ક
+ક્ખ
+ક્ગ
+ક્ઘ
+ક્ઙ
+ક્ચ
+ક્છ
+ક્જ
+ક્ઝ
+ક્ઞ
+ક્ટ
+ક્ઠ
+ક્ડ
+ક્ઢ
+ક્ણ
+ક્ત
+ક્થ
+ક્દ
+ક્ધ
+ક્ન
+ક્પ
+ક્ફ
+ક્બ
+ક્ભ
+ક્મ
+ક્ય
+ક્ર
+ક્લ
+ક્ળ
+ક્વ
+ક્શ
+ક્ષ
+ક્સ
+ક્હ
+ખ્ક
+ખ્ખ
+ખ્ગ
+ખ્ઘ
+ખ્ઙ
+ખ્ચ
+ખ્છ
+ખ્જ
+ખ્ઝ
+ખ્ઞ
+ખ્ટ
+ખ્ઠ
+ખ્ડ
+ખ્ઢ
+ખ્ણ
+ખ્ત
+ખ્થ
+ખ્દ
+ખ્ધ
+ખ્ન
+ખ્પ
+ખ્ફ
+ખ્બ
+ખ્ભ
+ખ્મ
+ખ્ય
+ખ્ર
+ખ્લ
+ખ્ળ
+ખ્વ
+ખ્શ
+ખ્ષ
+ખ્સ
+ખ્હ
+ગ્ક
+ગ્ખ
+ગ્ગ
+ગ્ઘ
+ગ્ઙ
+ગ્ચ
+ગ્છ
+ગ્જ
+ગ્ઝ
+ગ્ઞ
+ગ્ટ
+ગ્ઠ
+ગ્ડ
+ગ્ઢ
+ગ્ણ
+ગ્ત
+ગ્થ
+ગ્દ
+ગ્ધ
+ગ્ન
+ગ્પ
+ગ્ફ
+ગ્બ
+ગ્ભ
+ગ્મ
+ગ્ય
+ગ્ર
+ગ્લ
+ગ્ળ
+ગ્વ
+ગ્શ
+ગ્ષ
+ગ્સ
+ગ્હ
+ઘ્ક
+ઘ્ખ
+ઘ્ગ
+ઘ્ઘ
+ઘ્ઙ
+ઘ્ચ
+ઘ્છ
+ઘ્જ
+ઘ્ઝ
+ઘ્ઞ
+ઘ્ટ
+ઘ્ઠ
+ઘ્ડ
+ઘ્ઢ
+ઘ્ણ
+ઘ્ત
+ઘ્થ
+ઘ્દ
+ઘ્ધ
+ઘ્ન
+ઘ્પ
+ઘ્ફ
+ઘ્બ
+ઘ્ભ
+ઘ્મ
+ઘ્ય
+ઘ્ર
+ઘ્લ
+ઘ્ળ
+ઘ્વ
+ઘ્શ
+ઘ્ષ
+ઘ્સ
+ઘ્હ
+ઙ્ક
+ઙ્ખ
+ઙ્ગ
+ઙ્ઘ
+ઙ્ઙ
+ઙ્ચ
+ઙ્છ
+ઙ્જ
+ઙ્ઝ
+ઙ્ઞ
+ઙ્ટ
+ઙ્ઠ
+ઙ્ડ
+ઙ્ઢ
+ઙ્ણ
+ઙ્ત
+ઙ્થ
+ઙ્દ
+ઙ્ધ
+ઙ્ન
+ઙ્પ
+ઙ્ફ
+ઙ્બ
+ઙ્ભ
+ઙ્મ
+ઙ્ય
+ઙ્ર
+ઙ્લ
+ઙ્ળ
+ઙ્વ
+ઙ્શ
+ઙ્ષ
+ઙ્સ
+ઙ્હ
+ચ્ક
+ચ્ખ
+ચ્ગ
+ચ્ઘ
+ચ્ઙ
+ચ્ચ
+ચ્છ
+ચ્જ
+ચ્ઝ
+ચ્ઞ
+ચ્ટ
+ચ્ઠ
+ચ્ડ
+ચ્ઢ
+ચ્ણ
+ચ્ત
+ચ્થ
+ચ્દ
+ચ્ધ
+ચ્ન
+ચ્પ
+ચ્ફ
+ચ્બ
+ચ્ભ
+ચ્મ
+ચ્ય
+ચ્ર
+ચ્લ
+ચ્ળ
+ચ્વ
+ચ્શ
+ચ્ષ
+ચ્સ
+ચ્હ
+છ્ક
+છ્ખ
+છ્ગ
+છ્ઘ
+છ્ઙ
+છ્ચ
+છ્છ
+છ્જ
+છ્ઝ
+છ્ઞ
+છ્ટ
+છ્ઠ
+છ્ડ
+છ્ઢ
+છ્ણ
+છ્ત
+છ્થ
+છ્દ
+છ્ધ
+છ્ન
+છ્પ
+છ્ફ
+છ્બ
+છ્ભ
+છ્મ
+છ્ય
+છ્ર
+છ્લ
+છ્ળ
+છ્વ
+છ્શ
+છ્ષ
+છ્સ
+છ્હ
+જ્ક
+જ્ખ
+જ્ગ
+જ્ઘ
+જ્ઙ
+જ્ચ
+જ્છ
+જ્જ
+જ્ઝ
+જ્ઞ
+જ્ટ
+જ્ઠ
+જ્ડ
+જ્ઢ
+જ્ણ
+જ્ત
+જ્થ
+જ્દ
+જ્ધ
+જ્ન
+જ્પ
+જ્ફ
+જ્બ
+જ્ભ
+જ્મ
+જ્ય
+જ્ર
+જ્લ
+જ્ળ
+જ્વ
+જ્શ
+જ્ષ
+જ્સ
+જ્હ
+ઝ્ક
+ઝ્ખ
+ઝ્ગ
+ઝ્ઘ
+ઝ્ઙ
+ઝ્ચ
+ઝ્છ
+ઝ્જ
+ઝ્ઝ
+ઝ્ઞ
+ઝ્ટ
+ઝ્ઠ
+ઝ્ડ
+ઝ્ઢ
+ઝ્ણ
+ઝ્ત
+ઝ્થ
+ઝ્દ
+ઝ્ધ
+ઝ્ન
+ઝ્પ
+ઝ્ફ
+ઝ્બ
+ઝ્ભ
+ઝ્મ
+ઝ્ય
+ઝ્ર
+ઝ્લ
+ઝ્ળ
+ઝ્વ
+ઝ્શ
+ઝ્ષ
+ઝ્સ
+ઝ્હ
+ઞ્ક
+ઞ્ખ
+ઞ્ગ
+ઞ્ઘ
+ઞ્ઙ
+ઞ્ચ
+ઞ્છ
+ઞ્જ
+ઞ્ઝ
+ઞ્ઞ
+ઞ્ટ
+ઞ્ઠ
+ઞ્ડ
+ઞ્ઢ
+ઞ્ણ
+ઞ્ત
+ઞ્થ
+ઞ્દ
+ઞ્ધ
+ઞ્ન
+ઞ્પ
+ઞ્ફ
+ઞ્બ
+ઞ્ભ
+ઞ્મ
+ઞ્ય
+ઞ્ર
+ઞ્લ
+ઞ્ળ
+ઞ્વ
+ઞ્શ
+ઞ્ષ
+ઞ્સ
+ઞ્હ
+ટ્ક
+ટ્ખ
+ટ્ગ
+ટ્ઘ
+ટ્ઙ
+ટ્ચ
+ટ્છ
+ટ્જ
+ટ્ઝ
+ટ્ઞ
+ટ્ટ
+ટ્ઠ
+ટ્ડ
+ટ્ઢ
+ટ્ણ
+ટ્ત
+ટ્થ
+ટ્દ
+ટ્ધ
+ટ્ન
+ટ્પ
+ટ્ફ
+ટ્બ
+ટ્ભ
+ટ્મ
+ટ્ય
+ટ્ર
+ટ્લ
+ટ્ળ
+ટ્વ
+ટ્શ
+ટ્ષ
+ટ્સ
+ટ્હ
+ઠ્ક
+ઠ્ખ
+ઠ્ગ
+ઠ્ઘ
+ઠ્ઙ
+ઠ્ચ
+ઠ્છ
+ઠ્જ
+ઠ્ઝ
+ઠ્ઞ
+ઠ્ટ
+ઠ્ઠ
+ઠ્ડ
+ઠ્ઢ
+ઠ્ણ
+ઠ્ત
+ઠ્થ
+ઠ્દ
+ઠ્ધ
+ઠ્ન
+ઠ્પ
+ઠ્ફ
+ઠ્બ
+ઠ્ભ
+ઠ્મ
+ઠ્ય
+ઠ્ર
+ઠ્લ
+ઠ્ળ
+ઠ્વ
+ઠ્શ
+ઠ્ષ
+ઠ્સ
+ઠ્હ
+ડ્ક
+ડ્ખ
+ડ્ગ
+ડ્ઘ
+ડ્ઙ
+ડ્ચ
+ડ્છ
+ડ્જ
+ડ્ઝ
+ડ્ઞ
+ડ્ટ
+ડ્ઠ
+ડ્ડ
+ડ્ઢ
+ડ્ણ
+ડ્ત
+ડ્થ
+ડ્દ
+ડ્ધ
+ડ્ન
+ડ્પ
+ડ્ફ
+ડ્બ
+ડ્ભ
+ડ્મ
+ડ્ય
+ડ્ર
+ડ્લ
+ડ્ળ
+ડ્વ
+ડ્શ
+ડ્ષ
+ડ્સ
+ડ્હ
+ઢ્ક
+ઢ્ખ
+ઢ્ગ
+ઢ્ઘ
+ઢ્ઙ
+ઢ્ચ
+ઢ્છ
+ઢ્જ
+ઢ્ઝ
+ઢ્ઞ
+ઢ્ટ
+ઢ્ઠ
+ઢ્ડ
+ઢ્ઢ
+ઢ્ણ
+ઢ્ત
+ઢ્થ
+ઢ્દ
+ઢ્ધ
+ઢ્ન
+ઢ્પ
+ઢ્ફ
+ઢ્બ
+ઢ્ભ
+ઢ્મ
+ઢ્ય
+ઢ્ર
+ઢ્લ
+ઢ્ળ
+ઢ્વ
+ઢ્શ
+ઢ્ષ
+ઢ્સ
+ઢ્હ
+ણ્ક
+ણ્ખ
+ણ્ગ
+ણ્ઘ
+ણ્ઙ
+ણ્ચ
+ણ્છ
+ણ્જ
+ણ્ઝ
+ણ્ઞ
+ણ્ટ
+ણ્ઠ
+ણ્ડ
+ણ્ઢ
+ણ્ણ
+ણ્ત
+ણ્થ
+ણ્દ
+ણ્ધ
+ણ્ન
+ણ્પ
+ણ્ફ
+ણ્બ
+ણ્ભ
+ણ્મ
+ણ્ય
+ણ્ર
+ણ્લ
+ણ્ળ
+ણ્વ
+ણ્શ
+ણ્ષ
+ણ્સ
+ણ્હ
+ત્ક
+ત્ખ
+ત્ગ
+ત્ઘ
+ત્ઙ
+ત્ચ
+ત્છ
+ત્જ
+ત્ઝ
+ત્ઞ
+ત્ટ
+ત્ઠ
+ત્ડ
+ત્ઢ
+ત્ણ
+ત્ત
+ત્થ
+ત્દ
+ત્ધ
+ત્ન
+ત્પ
+ત્ફ
+ત્બ
+ત્ભ
+ત્મ
+ત્ય
+ત્ર
+ત્લ
+ત્ળ
+ત્વ
+ત્શ
+ત્ષ
+ત્સ
+ત્હ
+થ્ક
+થ્ખ
+થ્ગ
+થ્ઘ
+થ્ઙ
+થ્ચ
+થ્છ
+થ્જ
+થ્ઝ
+થ્ઞ
+થ્ટ
+થ્ઠ
+થ્ડ
+થ્ઢ
+થ્ણ
+થ્ત
+થ્થ
+થ્દ
+થ્ધ
+થ્ન
+થ્પ
+થ્ફ
+થ્બ
+થ્ભ
+થ્મ
+થ્ય
+થ્ર
+થ્લ
+થ્ળ
+થ્વ
+થ્શ
+થ્ષ
+થ્સ
+થ્હ
+દ્ક
+દ્ખ
+દ્ગ
+દ્ઘ
+દ્ઙ
+દ્ચ
+દ્છ
+દ્જ
+દ્ઝ
+દ્ઞ
+દ્ટ
+દ્ઠ
+દ્ડ
+દ્ઢ
+દ્ણ
+દ્ત
+દ્થ
+દ્દ
+દ્ધ
+દ્ન
+દ્પ
+દ્ફ
+દ્બ
+દ્ભ
+દ્મ
+દ્ય
+દ્ર
+દ્લ
+દ્ળ
+દ્વ
+દ્શ
+દ્ષ
+દ્સ
+દ્હ
+ધ્ક
+ધ્ખ
+ધ્ગ
+ધ્ઘ
+ધ્ઙ
+ધ્ચ
+ધ્છ
+ધ્જ
+ધ્ઝ
+ધ્ઞ
+ધ્ટ
+ધ્ઠ
+ધ્ડ
+ધ્ઢ
+ધ્ણ
+ધ્ત
+ધ્થ
+ધ્દ
+ધ્ધ
+ધ્ન
+ધ્પ
+ધ્ફ
+ધ્બ
+ધ્ભ
+ધ્મ
+ધ્ય
+ધ્ર
+ધ્લ
+ધ્ળ
+ધ્વ
+ધ્શ
+ધ્ષ
+ધ્સ
+ધ્હ
+ન્ક
+ન્ખ
+ન્ગ
+ન્ઘ
+ન્ઙ
+ન્ચ
+ન્છ
+ન્જ
+ન્ઝ
+ન્ઞ
+ન્ટ
+ન્ઠ
+ન્ડ
+ન્ઢ
+ન્ણ
+ન્ત
+ન્થ
+ન્દ
+ન્ધ
+ન્ન
+ન્પ
+ન્ફ
+ન્બ
+ન્ભ
+ન્મ
+ન્ય
+ન્ર
+ન્લ
+ન્ળ
+ન્વ
+ન્શ
+ન્ષ
+ન્સ
+ન્હ
+પ્ક
+પ્ખ
+પ્ગ
+પ્ઘ
+પ્ઙ
+પ્ચ
+પ્છ
+પ્જ
+પ્ઝ
+પ્ઞ
+પ્ટ
+પ્ઠ
+પ્ડ
+પ્ઢ
+પ્ણ
+પ્ત
+પ્થ
+પ્દ
+પ્ધ
+પ્ન
+પ્પ
+પ્ફ
+પ્બ
+પ્ભ
+પ્મ
+પ્ય
+પ્ર
+પ્લ
+પ્ળ
+પ્વ
+પ્શ
+પ્ષ
+પ્સ
+પ્હ
+ફ્ક
+ફ્ખ
+ફ્ગ
+ફ્ઘ
+ફ્ઙ
+ફ્ચ
+ફ્છ
+ફ્જ
+ફ્ઝ
+ફ્ઞ
+ફ્ટ
+ફ્ઠ
+ફ્ડ
+ફ્ઢ
+ફ્ણ
+ફ્ત
+ફ્થ
+ફ્દ
+ફ્ધ
+ફ્ન
+ફ્પ
+ફ્ફ
+ફ્બ
+ફ્ભ
+ફ્મ
+ફ્ય
+ફ્ર
+ફ્લ
+ફ્ળ
+ફ્વ
+ફ્શ
+ફ્ષ
+ફ્સ
+ફ્હ
+બ્ક
+બ્ખ
+બ્ગ
+બ્ઘ
+બ્ઙ
+બ્ચ
+બ્છ
+બ્જ
+બ્ઝ
+બ્ઞ
+બ્ટ
+બ્ઠ
+બ્ડ
+બ્ઢ
+બ્ણ
+બ્ત
+બ્થ
+બ્દ
+બ્ધ
+બ્ન
+બ્પ
+બ્ફ
+બ્બ
+બ્ભ
+બ્મ
+બ્ય
+બ્ર
+બ્લ
+બ્ળ
+બ્વ
+બ્શ
+બ્ષ
+બ્સ
+બ્હ
+ભ્ક
+ભ્ખ
+ભ્ગ
+ભ્ઘ
+ભ્ઙ
+ભ્ચ
+ભ્છ
+ભ્જ
+ભ્ઝ
+ભ્ઞ
+ભ્ટ
+ભ્ઠ
+ભ્ડ
+ભ્ઢ
+ભ્ણ
+ભ્ત
+ભ્થ
+ભ્દ
+ભ્ધ
+ભ્ન
+ભ્પ
+ભ્ફ
+ભ્બ
+ભ્ભ
+ભ્મ
+ભ્ય
+ભ્ર
+ભ્લ
+ભ્ળ
+ભ્વ
+ભ્શ
+ભ્ષ
+ભ્સ
+ભ્હ
+મ્ક
+મ્ખ
+મ્ગ
+મ્ઘ
+મ્ઙ
+મ્ચ
+મ્છ
+મ્જ
+મ્ઝ
+મ્ઞ
+મ્ટ
+મ્ઠ
+મ્ડ
+મ્ઢ
+મ્ણ
+મ્ત
+મ્થ
+મ્દ
+મ્ધ
+મ્ન
+મ્પ
+મ્ફ
+મ્બ
+મ્ભ
+મ્મ
+મ્ય
+મ્ર
+મ્લ
+મ્ળ
+મ્વ
+મ્શ
+મ્ષ
+મ્સ
+મ્હ
+ય્ક
+ય્ખ
+ય્ગ
+ય્ઘ
+ય્ઙ
+ય્ચ
+ય્છ
+ય્જ
+ય્ઝ
+ય્ઞ
+ય્ટ
+ય્ઠ
+ય્ડ
+ય્ઢ
+ય્ણ
+ય્ત
+ય્થ
+ય્દ
+ય્ધ
+ય્ન
+ય્પ
+ય્ફ
+ય્બ
+ય્ભ
+ય્મ
+ય્ય
+ય્ર
+ય્લ
+ય્ળ
+ય્વ
+ય્શ
+ય્ષ
+ય્સ
+ય્હ
+ર્ક
+ર્ખ
+ર્ગ
+ર્ઘ
+ર્ઙ
+ર્ચ
+ર્છ
+ર્જ
+ર્ઝ
+ર્ઞ
+ર્ટ
+ર્ઠ
+ર્ડ
+ર્ઢ
+ર્ણ
+ર્ત
+ર્થ
+ર્દ
+ર્ધ
+ર્ન
+ર્પ
+ર્ફ
+ર્બ
+ર્ભ
+ર્મ
+ર્ય
+ર્ર
+ર્લ
+ર્ળ
+ર્વ
+ર્શ
+ર્ષ
+ર્સ
+ર્હ
+લ્ક
+લ્ખ
+લ્ગ
+લ્ઘ
+લ્ઙ
+લ્ચ
+લ્છ
+લ્જ
+લ્ઝ
+લ્ઞ
+લ્ટ
+લ્ઠ
+લ્ડ
+લ્ઢ
+લ્ણ
+લ્ત
+લ્થ
+લ્દ
+લ્ધ
+લ્ન
+લ્પ
+લ્ફ
+લ્બ
+લ્ભ
+લ્મ
+લ્ય
+લ્ર
+લ્લ
+લ્ળ
+લ્વ
+લ્શ
+લ્ષ
+લ્સ
+લ્હ
+ળ્ક
+ળ્ખ
+ળ્ગ
+ળ્ઘ
+ળ્ઙ
+ળ્ચ
+ળ્છ
+ળ્જ
+ળ્ઝ
+ળ્ઞ
+ળ્ટ
+ળ્ઠ
+ળ્ડ
+ળ્ઢ
+ળ્ણ
+ળ્ત
+ળ્થ
+ળ્દ
+ળ્ધ
+ળ્ન
+ળ્પ
+ળ્ફ
+ળ્બ
+ળ્ભ
+ળ્મ
+ળ્ય
+ળ્ર
+ળ્લ
+ળ્ળ
+ળ્વ
+ળ્શ
+ળ્ષ
+ળ્સ
+ળ્હ
+વ્ક
+વ્ખ
+વ્ગ
+વ્ઘ
+વ્ઙ
+વ્ચ
+વ્છ
+વ્જ
+વ્ઝ
+વ્ઞ
+વ્ટ
+વ્ઠ
+વ્ડ
+વ્ઢ
+વ્ણ
+વ્ત
+વ્થ
+વ્દ
+વ્ધ
+વ્ન
+વ્પ
+વ્ફ
+વ્બ
+વ્ભ
+વ્મ
+વ્ય
+વ્ર
+વ્લ
+વ્ળ
+વ્વ
+વ્શ
+વ્ષ
+વ્સ
+વ્હ
+શ્ક
+શ્ખ
+શ્ગ
+શ્ઘ
+શ્ઙ
+શ્ચ
+શ્છ
+શ્જ
+શ્ઝ
+શ્ઞ
+શ્ટ
+શ્ઠ
+શ્ડ
+શ્ઢ
+શ્ણ
+શ્ત
+શ્થ
+શ્દ
+શ્ધ
+શ્ન
+શ્પ
+શ્ફ
+શ્બ
+શ્ભ
+શ્મ
+શ્ય
+શ્ર
+શ્લ
+શ્ળ
+શ્વ
+શ્શ
+શ્ષ
+શ્સ
+શ્હ
+ષ્ક
+ષ્ખ
+ષ્ગ
+ષ્ઘ
+ષ્ઙ
+ષ્ચ
+ષ્છ
+ષ્જ
+ષ્ઝ
+ષ્ઞ
+ષ્ટ
+ષ્ઠ
+ષ્ડ
+ષ્ઢ
+ષ્ણ
+ષ્ત
+ષ્થ
+ષ્દ
+ષ્ધ
+ષ્ન
+ષ્પ
+ષ્ફ
+ષ્બ
+ષ્ભ
+ષ્મ
+ષ્ય
+ષ્ર
+ષ્લ
+ષ્ળ
+ષ્વ
+ષ્શ
+ષ્ષ
+ષ્સ
+ષ્હ
+સ્ક
+સ્ખ
+સ્ગ
+સ્ઘ
+સ્ઙ
+સ્ચ
+સ્છ
+સ્જ
+સ્ઝ
+સ્ઞ
+સ્ટ
+સ્ઠ
+સ્ડ
+સ્ઢ
+સ્ણ
+સ્ત
+સ્થ
+સ્દ
+સ્ધ
+સ્ન
+સ્પ
+સ્ફ
+સ્બ
+સ્ભ
+સ્મ
+સ્ય
+સ્ર
+સ્લ
+સ્ળ
+સ્વ
+સ્શ
+સ્ષ
+સ્સ
+સ્હ
+હ્ક
+હ્ખ
+હ્ગ
+હ્ઘ
+હ્ઙ
+હ્ચ
+હ્છ
+હ્જ
+હ્ઝ
+હ્ઞ
+હ્ટ
+હ્ઠ
+હ્ડ
+હ્ઢ
+હ્ણ
+હ્ત
+હ્થ
+હ્દ
+હ્ધ
+હ્ન
+હ્પ
+હ્ફ
+હ્બ
+હ્ભ
+હ્મ
+હ્ય
+હ્ર
+હ્લ
+હ્ળ
+હ્વ
+હ્શ
+હ્ષ
+હ્સ
+હ્હ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gujarati/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/misc/misc.txt
new file mode 100644 (file)
index 0000000..27a39f6
--- /dev/null
@@ -0,0 +1,2 @@
+ਕ੍ਹ
+ਤ੍ਯੋ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..ee8b3be
--- /dev/null
@@ -0,0 +1,38 @@
+ਕ
+ਖ
+ਗ
+ਘ
+ਙ
+ਚ
+ਛ
+ਜ
+ਝ
+ਞ
+ਟ
+ਠ
+ਡ
+ਢ
+ਣ
+ਤ
+ਥ
+ਦ
+ਧ
+ਨ
+ਪ
+ਫ
+ਬ
+ਭ
+ਮ
+ਯ
+ਰ
+ਲ
+ਲ਼
+ਵ
+ਸ਼
+ਸ
+ਹ
+ਖ਼
+ਗ਼
+ਜ਼
+ੜ
+ਫ਼
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..a934caa
--- /dev/null
@@ -0,0 +1,9 @@
+ਾ
+ਿ
+ੀ
+ੁ
+ੂ
+ੇ
+ੈ
+ੋ
+ੌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..d08b7a8
--- /dev/null
@@ -0,0 +1,10 @@
+੦
+੧
+੨
+੩
+੪
+੫
+੬
+੭
+੮
+੯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-GurmukhiSpecific.txt
new file mode 100644 (file)
index 0000000..8565c88
--- /dev/null
@@ -0,0 +1,6 @@
+ੰ
+ੱ
+ੲ
+ੳ
+ੴ
+ੵ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..05827ca
--- /dev/null
@@ -0,0 +1,10 @@
+ਅ
+ਆ
+ਇ
+ਈ
+ਉ
+ਊ
+ਏ
+ਐ
+ਓ
+ਔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..adb725e
--- /dev/null
@@ -0,0 +1,6 @@
+ਁ
+ਂ
+ਃ
+਼
+੍
+ੑ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..c213616
--- /dev/null
@@ -0,0 +1,7 @@
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-GurmukhiSpecific.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..7fdf6e4
--- /dev/null
@@ -0,0 +1,22 @@
+ਉਂ
+ਊਂ
+ਏਂ
+ਐਂ
+ਓਂ
+ਔਂ
+ਠਂ
+ਠੇ
+ਠੈ
+ਠੋ
+ਠੌ
+ਠੰ
+ਨਂ
+ਨੇ
+ਨੈ
+ਨੋ
+ਨੌ
+ਨੰ
+ਠੱ
+ਨੱ
+ਲੱ
+ਲ਼ੱ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
new file mode 100644 (file)
index 0000000..63d54a5
--- /dev/null
@@ -0,0 +1,2 @@
+ੳ
+ੲ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..d7ae70e
--- /dev/null
@@ -0,0 +1,2 @@
+IndicFontFeatureGPOS-AboveBase.txt
+IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..eb2e8ee
--- /dev/null
@@ -0,0 +1,152 @@
+ਕ੍ਯ
+ਖ੍ਯ
+ਗ੍ਯ
+ਘ੍ਯ
+ਙ੍ਯ
+ਚ੍ਯ
+ਛ੍ਯ
+ਜ੍ਯ
+ਝ੍ਯ
+ਞ੍ਯ
+ਟ੍ਯ
+ਠ੍ਯ
+ਡ੍ਯ
+ਢ੍ਯ
+ਣ੍ਯ
+ਤ੍ਯ
+ਥ੍ਯ
+ਦ੍ਯ
+ਧ੍ਯ
+ਨ੍ਯ
+ਪ੍ਯ
+ਫ੍ਯ
+ਬ੍ਯ
+ਭ੍ਯ
+ਮ੍ਯ
+ਯ੍ਯ
+ਰ੍ਯ
+ਲ੍ਯ
+ਲ਼੍ਯ
+ਵ੍ਯ
+ਸ਼੍ਯ
+ਸ੍ਯ
+ਹ੍ਯ
+ਖ਼੍ਯ
+ਗ਼੍ਯ
+ਜ਼੍ਯ
+ੜ੍ਯ
+ਫ਼੍ਯ
+ਕ੍ਰ
+ਖ੍ਰ
+ਗ੍ਰ
+ਘ੍ਰ
+ਙ੍ਰ
+ਚ੍ਰ
+ਛ੍ਰ
+ਜ੍ਰ
+ਝ੍ਰ
+ਞ੍ਰ
+ਟ੍ਰ
+ਠ੍ਰ
+ਡ੍ਰ
+ਢ੍ਰ
+ਣ੍ਰ
+ਤ੍ਰ
+ਥ੍ਰ
+ਦ੍ਰ
+ਧ੍ਰ
+ਨ੍ਰ
+ਪ੍ਰ
+ਫ੍ਰ
+ਬ੍ਰ
+ਭ੍ਰ
+ਮ੍ਰ
+ਯ੍ਰ
+ਰ੍ਰ
+ਲ੍ਰ
+ਲ਼੍ਰ
+ਵ੍ਰ
+ਸ਼੍ਰ
+ਸ੍ਰ
+ਹ੍ਰ
+ਖ਼੍ਰ
+ਗ਼੍ਰ
+ਜ਼੍ਰ
+ੜ੍ਰ
+ਫ਼੍ਰ
+ਕ੍ਵ
+ਖ੍ਵ
+ਗ੍ਵ
+ਘ੍ਵ
+ਙ੍ਵ
+ਚ੍ਵ
+ਛ੍ਵ
+ਜ੍ਵ
+ਝ੍ਵ
+ਞ੍ਵ
+ਟ੍ਵ
+ਠ੍ਵ
+ਡ੍ਵ
+ਢ੍ਵ
+ਣ੍ਵ
+ਤ੍ਵ
+ਥ੍ਵ
+ਦ੍ਵ
+ਧ੍ਵ
+ਨ੍ਵ
+ਪ੍ਵ
+ਫ੍ਵ
+ਬ੍ਵ
+ਭ੍ਵ
+ਮ੍ਵ
+ਯ੍ਵ
+ਰ੍ਵ
+ਲ੍ਵ
+ਲ਼੍ਵ
+ਵ੍ਵ
+ਸ਼੍ਵ
+ਸ੍ਵ
+ਹ੍ਵ
+ਖ਼੍ਵ
+ਗ਼੍ਵ
+ਜ਼੍ਵ
+ੜ੍ਵ
+ਫ਼੍ਵ
+ਕ੍ਹ
+ਖ੍ਹ
+ਗ੍ਹ
+ਘ੍ਹ
+ਙ੍ਹ
+ਚ੍ਹ
+ਛ੍ਹ
+ਜ੍ਹ
+ਝ੍ਹ
+ਞ੍ਹ
+ਟ੍ਹ
+ਠ੍ਹ
+ਡ੍ਹ
+ਢ੍ਹ
+ਣ੍ਹ
+ਤ੍ਹ
+ਥ੍ਹ
+ਦ੍ਹ
+ਧ੍ਹ
+ਨ੍ਹ
+ਪ੍ਹ
+ਫ੍ਹ
+ਬ੍ਹ
+ਭ੍ਹ
+ਮ੍ਹ
+ਯ੍ਹ
+ਰ੍ਹ
+ਲ੍ਹ
+ਲ਼੍ਹ
+ਵ੍ਹ
+ਸ਼੍ਹ
+ਸ੍ਹ
+ਹ੍ਹ
+ਖ਼੍ਹ
+ਗ਼੍ਹ
+ਜ਼੍ਹ
+ੜ੍ਹ
+ਫ਼੍ਹ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-gurmukhi/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/MANIFEST
new file mode 100644 (file)
index 0000000..f53f999
--- /dev/null
@@ -0,0 +1,2 @@
+misc.txt
+right-matras.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/misc.txt
new file mode 100644 (file)
index 0000000..a8a6325
--- /dev/null
@@ -0,0 +1,20 @@
+ಕ್ರ
+ನ್ಡ
+ನ್ನ
+ಯೂ
+ರ್ಕ
+ರ್ಮ
+ರ್‍ಕ
+ವೋ
+ಷೆ
+ಷ್
+ೠ
+೦೧೨
+ಕೀ
+ಕೊ
+ಕೇ
+ಕೈ
+ಕೋ
+ಕ್ಷ
+ಕ್ಷಿ
+ಚ್ಚ್
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/right-matras.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/misc/right-matras.txt
new file mode 100644 (file)
index 0000000..3130f35
--- /dev/null
@@ -0,0 +1,7 @@
+ಸ್ಕು
+ಸ್ಕೂ
+ಸ್ಕೃ
+ಸ್ಕೄ
+ಸ್ಕಾ
+ಸ್ಕೕ
+ಸ್ಕೕ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
new file mode 100644 (file)
index 0000000..fff748a
--- /dev/null
@@ -0,0 +1 @@
+ೞ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..f641547
--- /dev/null
@@ -0,0 +1,4 @@
+ೠ
+ೡ
+ೢ
+ೣ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..650cbf7
--- /dev/null
@@ -0,0 +1,40 @@
+ಕ
+ಖ
+ಗ
+ಘ
+ಙ
+ಚ
+ಛ
+ಜ
+ಝ
+ಞ
+ಟ
+ಠ
+ಡ
+ಢ
+ಣ
+ತ
+ಥ
+ದ
+ಧ
+ನ
+ಪ
+ಫ
+ಬ
+ಭ
+ಮ
+ಯ
+ರ
+ಱ
+ಲ
+ಳ
+ವ
+ಶ
+ಷ
+ಸ
+ಹ
+ಂ
+ಃ
+಼
+ಽ
+್
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..476f39f
--- /dev/null
@@ -0,0 +1,13 @@
+ಾ
+ಿ
+ೀ
+ು
+ೂ
+ೃ
+ೄ
+ೆ
+ೇ
+ೈ
+ೊ
+ೋ
+ೌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..57ac088
--- /dev/null
@@ -0,0 +1,10 @@
+೦
+೧
+೨
+೩
+೪
+೫
+೬
+೭
+೮
+೯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..38f1719
--- /dev/null
@@ -0,0 +1,14 @@
+ಅ
+ಆ
+ಇ
+ಈ
+ಉ
+ಊ
+ಋ
+ಌ
+ಎ
+ಏ
+ಐ
+ಒ
+ಓ
+ಔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..6bbf23e
--- /dev/null
@@ -0,0 +1,9 @@
+ಂ
+ಃ
+಼
+ಽ
+್
+ೕ
+ೖ
+ೱ
+ೲ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..8fac7bc
--- /dev/null
@@ -0,0 +1,8 @@
+IndicFontFeatureCodepoint-AdditionalConsonants.txt
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..4cc0f56
--- /dev/null
@@ -0,0 +1,188 @@
+ಕಾ
+ಖಾ
+ಗಾ
+ಠಾ
+ಡಾ
+ಛಾ
+ಕಿ
+ಖಿ
+ಗಿ
+ಘಿ
+ಙಿ
+ಚಿ
+ಛಿ
+ಜಿ
+ಝಿ
+ಞಿ
+ಟಿ
+ಠಿ
+ಡಿ
+ಢಿ
+ಣಿ
+ತಿ
+ಥಿ
+ದಿ
+ಧಿ
+ನಿ
+ಪಿ
+ಫಿ
+ಬಿ
+ಭಿ
+ಮಿ
+ಯಿ
+ರಿ
+ಱಿ
+ಲಿ
+ಳಿ
+ವಿ
+ಶಿ
+ಷಿ
+ಸಿ
+ಹಿ
+ಕು
+ಗು
+ಜು
+ಟು
+ತು
+ಖು
+ಕೂ
+ಖೂ
+ಗೂ
+ಟೂ
+ಚೂ
+ಛೂ
+ಕೄ
+ಗೄ
+ಜೄ
+ಟೄ
+ತೄ
+ಖೄ
+ಕೇ
+ಗೇ
+ಜೇ
+ಟೇ
+ತೇ
+ಖೇ
+ಕೈ
+ಗೈ
+ಜೈ
+ಟೈ
+ತೈ
+ಖೈ
+ಕೊ
+ಗೊ
+ಜೊ
+ಟೊ
+ತೊ
+ಖೊ
+ಕೋ
+ಗೋ
+ಜೋ
+ಟೋ
+ತೋ
+ಖೋ
+ಕೆ
+ಖೆ
+ಗೆ
+ಘೆ
+ಙೆ
+ಚೆ
+ಛೆ
+ಜೆ
+ಝೆ
+ಞೆ
+ಟೆ
+ಠೆ
+ಡೆ
+ಢೆ
+ಣೆ
+ತೆ
+ಥೆ
+ದೆ
+ಧೆ
+ನೆ
+ಪೆ
+ಫೆ
+ಬೆ
+ಭೆ
+ಮೆ
+ಯೆ
+ರೆ
+ಱೆ
+ಲೆ
+ಳೆ
+ವೆ
+ಶೆ
+ಷೆ
+ಸೆ
+ಹೆ
+ಕೌ
+ಖೌ
+ಗೌ
+ಘೌ
+ಙೌ
+ಚೌ
+ಛೌ
+ಜೌ
+ಝೌ
+ಞೌ
+ಟೌ
+ಠೌ
+ಡೌ
+ಢೌ
+ಣೌ
+ತೌ
+ಥೌ
+ದೌ
+ಧೌ
+ನೌ
+ಪೌ
+ಫೌ
+ಬೌ
+ಭೌ
+ಮೌ
+ಯೌ
+ರೌ
+ಱೌ
+ಲೌ
+ಳೌ
+ವೌ
+ಶೌ
+ಷೌ
+ಸೌ
+ಹೌ
+ಕ್
+ಖ್
+ಗ್
+ಘ್
+ಙ್
+ಚ್
+ಛ್
+ಜ್
+ಝ್
+ಞ್
+ಟ್
+ಠ್
+ಡ್
+ಢ್
+ಣ್
+ತ್
+ಥ್
+ದ್
+ಧ್
+ನ್
+ಪ್
+ಫ್
+ಬ್
+ಭ್
+ಮ್
+ಯ್
+ರ್
+ಱ್
+ಲ್
+ಳ್
+ವ್
+ಶ್
+ಷ್
+ಸ್
+ಹ್
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..49d0284
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..583072d
--- /dev/null
@@ -0,0 +1,306 @@
+ಕ್ಕ
+ಕ್ಖ
+ಕ್ಗ
+ಕ್ಘ
+ಕ್ಙ
+ಕ್ಚ
+ಕ್ಛ
+ಕ್ಜ
+ಕ್ಝ
+ಕ್ಞ
+ಕ್ಟ
+ಕ್ಠ
+ಕ್ಡ
+ಕ್ಢ
+ಕ್ಣ
+ಕ್ತ
+ಕ್ಥ
+ಕ್ದ
+ಕ್ಧ
+ಕ್ನ
+ಕ್ಪ
+ಕ್ಫ
+ಕ್ಬ
+ಕ್ಭ
+ಕ್ಮ
+ಕ್ಯ
+ಕ್ರ
+ಕ್ಲ
+ಕ್ಳ
+ಕ್ವ
+ಕ್ಶ
+ಕ್ಷ
+ಕ್ಸ
+ಕ್ಹ
+ತ್ಕ
+ತ್ಖ
+ತ್ಗ
+ತ್ಘ
+ತ್ಙ
+ತ್ಚ
+ತ್ಛ
+ತ್ಜ
+ತ್ಝ
+ತ್ಞ
+ತ್ಟ
+ತ್ಠ
+ತ್ಡ
+ತ್ಢ
+ತ್ಣ
+ತ್ತ
+ತ್ಥ
+ತ್ದ
+ತ್ಧ
+ತ್ನ
+ತ್ಪ
+ತ್ಫ
+ತ್ಬ
+ತ್ಭ
+ತ್ಮ
+ತ್ಯ
+ತ್ರ
+ತ್ಲ
+ತ್ಳ
+ತ್ವ
+ತ್ಶ
+ತ್ಷ
+ತ್ಸ
+ತ್ಹ
+ನ್ಕ
+ನ್ಖ
+ನ್ಗ
+ನ್ಘ
+ನ್ಙ
+ನ್ಚ
+ನ್ಛ
+ನ್ಜ
+ನ್ಝ
+ನ್ಞ
+ನ್ಟ
+ನ್ಠ
+ನ್ಡ
+ನ್ಢ
+ನ್ಣ
+ನ್ತ
+ನ್ಥ
+ನ್ದ
+ನ್ಧ
+ನ್ನ
+ನ್ಪ
+ನ್ಫ
+ನ್ಬ
+ನ್ಭ
+ನ್ಮ
+ನ್ಯ
+ನ್ರ
+ನ್ಲ
+ನ್ಳ
+ನ್ವ
+ನ್ಶ
+ನ್ಷ
+ನ್ಸ
+ನ್ಹ
+ಮ್ಕ
+ಮ್ಖ
+ಮ್ಗ
+ಮ್ಘ
+ಮ್ಙ
+ಮ್ಚ
+ಮ್ಛ
+ಮ್ಜ
+ಮ್ಝ
+ಮ್ಞ
+ಮ್ಟ
+ಮ್ಠ
+ಮ್ಡ
+ಮ್ಢ
+ಮ್ಣ
+ಮ್ತ
+ಮ್ಥ
+ಮ್ದ
+ಮ್ಧ
+ಮ್ನ
+ಮ್ಪ
+ಮ್ಫ
+ಮ್ಬ
+ಮ್ಭ
+ಮ್ಮ
+ಮ್ಯ
+ಮ್ರ
+ಮ್ಲ
+ಮ್ಳ
+ಮ್ವ
+ಮ್ಶ
+ಮ್ಷ
+ಮ್ಸ
+ಮ್ಹ
+ಯ್ಕ
+ಯ್ಖ
+ಯ್ಗ
+ಯ್ಘ
+ಯ್ಙ
+ಯ್ಚ
+ಯ್ಛ
+ಯ್ಜ
+ಯ್ಝ
+ಯ್ಞ
+ಯ್ಟ
+ಯ್ಠ
+ಯ್ಡ
+ಯ್ಢ
+ಯ್ಣ
+ಯ್ತ
+ಯ್ಥ
+ಯ್ದ
+ಯ್ಧ
+ಯ್ನ
+ಯ್ಪ
+ಯ್ಫ
+ಯ್ಬ
+ಯ್ಭ
+ಯ್ಮ
+ಯ್ಯ
+ಯ್ರ
+ಯ್ಲ
+ಯ್ಳ
+ಯ್ವ
+ಯ್ಶ
+ಯ್ಷ
+ಯ್ಸ
+ಯ್ಹ
+ರ್ಕ
+ರ್ಖ
+ರ್ಗ
+ರ್ಘ
+ರ್ಙ
+ರ್ಚ
+ರ್ಛ
+ರ್ಜ
+ರ್ಝ
+ರ್ಞ
+ರ್ಟ
+ರ್ಠ
+ರ್ಡ
+ರ್ಢ
+ರ್ಣ
+ರ್ತ
+ರ್ಥ
+ರ್ದ
+ರ್ಧ
+ರ್ನ
+ರ್ಪ
+ರ್ಫ
+ರ್ಬ
+ರ್ಭ
+ರ್ಮ
+ರ್ಯ
+ರ್ರ
+ರ್ಲ
+ರ್ಳ
+ರ್ವ
+ರ್ಶ
+ರ್ಷ
+ರ್ಸ
+ರ್ಹ
+ರ್ಕ
+ರ್ಖ
+ರ್ಗ
+ರ್ಘ
+ರ್ಙ
+ರ್ಚ
+ರ್ಛ
+ರ್ಜ
+ರ್ಝ
+ರ್ಞ
+ರ್ಟ
+ರ್ಠ
+ರ್ಡ
+ರ್ಢ
+ರ್ಣ
+ರ್ತ
+ರ್ಥ
+ರ್ದ
+ರ್ಧ
+ರ್ನ
+ರ್ಪ
+ರ್ಫ
+ರ್ಬ
+ರ್ಭ
+ರ್ಮ
+ರ್ಯ
+ರ್ರ
+ರ್ಲ
+ರ್ಳ
+ರ್ವ
+ರ್ಶ
+ರ್ಷ
+ರ್ಸ
+ರ್ಹ
+ಲ್ಕ
+ಲ್ಖ
+ಲ್ಗ
+ಲ್ಘ
+ಲ್ಙ
+ಲ್ಚ
+ಲ್ಛ
+ಲ್ಜ
+ಲ್ಝ
+ಲ್ಞ
+ಲ್ಟ
+ಲ್ಠ
+ಲ್ಡ
+ಲ್ಢ
+ಲ್ಣ
+ಲ್ತ
+ಲ್ಥ
+ಲ್ದ
+ಲ್ಧ
+ಲ್ನ
+ಲ್ಪ
+ಲ್ಫ
+ಲ್ಬ
+ಲ್ಭ
+ಲ್ಮ
+ಲ್ಯ
+ಲ್ರ
+ಲ್ಲ
+ಲ್ಳ
+ಲ್ವ
+ಲ್ಶ
+ಲ್ಷ
+ಲ್ಸ
+ಲ್ಹ
+ವ್ಕ
+ವ್ಖ
+ವ್ಗ
+ವ್ಘ
+ವ್ಙ
+ವ್ಚ
+ವ್ಛ
+ವ್ಜ
+ವ್ಝ
+ವ್ಞ
+ವ್ಟ
+ವ್ಠ
+ವ್ಡ
+ವ್ಢ
+ವ್ಣ
+ವ್ತ
+ವ್ಥ
+ವ್ದ
+ವ್ಧ
+ವ್ನ
+ವ್ಪ
+ವ್ಫ
+ವ್ಬ
+ವ್ಭ
+ವ್ಮ
+ವ್ಯ
+ವ್ರ
+ವ್ಲ
+ವ್ಳ
+ವ್ವ
+ವ್ಶ
+ವ್ಷ
+ವ್ಸ
+ವ್ಹ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-kannada/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/MANIFEST
new file mode 100644 (file)
index 0000000..48800d4
--- /dev/null
@@ -0,0 +1,3 @@
+cibu.txt
+dot-reph.txt
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/cibu.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/cibu.txt
new file mode 100644 (file)
index 0000000..3d53867
--- /dev/null
@@ -0,0 +1,188 @@
+2ാം
+2-ാം
+ല്ം
+എ്ന
+9-൹
+₹100
+൦
+൧
+൨
+൩
+൪
+൫
+൬
+൭
+൮
+൯
+൰
+൱
+൲
+൳
+൴
+൵
+അങ്ങ്
+അത്
+അർത്ഥം
+അന്ധൻ
+അന്യം
+അന്വയം
+അൽപ്പം
+അമ്മ
+അമ്ലം
+അല്പം
+അല
+അവൻ
+അവന്
+അവനു്
+അസോഽസൗ
+അഹല്യ
+അഺ്
+ആമ്പിൿ
+ആല
+ആാ
+ആാാാ
+ഇൻക
+ഇല്ല
+ഇല
+ഇള
+ഇഴ
+ഈറ
+ഈൗ
+ഉമ
+ഉള്ള
+ഊമ
+ഊൗ
+ഋതു
+ൠന്ന്
+ഌകാരം
+ൡതം
+എന്ന
+എന്റെ
+എലി
+എൻറോൾ
+ഏലം
+ഐക്യം
+ഒരു
+ഓരം
+ഓാാാ
+ഔഷധം
+ഔൗ
+കണ്ഢം
+കണ്ണ്
+കണ്വൻ
+കഥ
+കമ്പം
+കമ്രം
+കല്മഷം
+കല
+കാാ
+കീീ
+കുണ്ഠിതം
+കൂൂ
+കൄന്ന്
+കൢപ്തം
+കൣതം
+കൌതുകം
+ക്രൌഞ്ചം
+ഗങ്ഗ
+ഗരം
+ങഞ
+അച്ഛൻ
+ങ്യാവൂ
+ചരം
+ഛായ
+ജലം
+ജാള്യം
+ഝാൻസി
+ഞാൻ
+ടിപ്പു
+ഡപ്പി
+തത്ത
+തെരഞ്ഞെടുപ്പിന്‍െറ
+ദയ
+ദുഃഖം
+ദൃഢം
+ധനം
+നഖം
+നന്ദി
+നന്ന്
+നന്മ
+നാണ്യം
+തന്ത
+ന്രസ്ഥി
+പച്ച
+പട്ട
+പണ്ടു്
+പല
+പറ
+പാഠം
+പാണ്ഡു
+പാണ്ഡ്യൻ
+പാന്ഥൻ
+പാറ്റ
+പിന്നെ
+പുച്ഛം
+പുഞ്ച
+പൊൻനാണ്യം
+ഫലം
+ബലം
+ഭയം
+ഭാൎയ്യ
+ഭാര്യ
+മങ്ക
+മണം
+മണ്ട
+മ്അദനി
+മയം
+മേഘം
+മോഹന്‍ലാല്‍
+യതി
+രണ്ട്
+രമ്യം
+ലത
+അറബ്‌ബസ്സാർ
+ലോക്‌സഭ
+വഅള്
+വരം
+വാഞ്ഛ
+വില്വാദ്രി
+വെണ്മ
+ഷാരം
+ശ്രുതി
+ശരം
+ശാർങ്ഗപക്ഷി
+സമ്യക്
+സംയോഗം
+സംരംഭം
+സമ്രാട്ട്
+സസ്യം
+സാരം
+സ്രാവം
+സ്ലാവിക്
+സ്വരം
+സ്വാതന്ത്ര്യം
+സ്ട്രാപ്പ്
+സ്റ്റിംഗ്
+സ്റ്റ്രീം
+ഹാരം
+റിപ്പോര്‍ട്ട്
+  ന്‍റെ
+ന്റെ
+ൻ്റെ
+ച്ച്യൂ
+യ്ക്ക്യൂ
+ട്ട്യൂ
+യ‍്യ
+വ‍്വ
+ഹൈലൈറ്റ്സ്
+ ച്ല്‍സി
+മലയാളത്തില്‍
+ഡിപ്പാർട്ട്മെന്റിന്റെ
+യ്യ്ര
+ യ്യ്ര
+ ്യ്ര
+ ്യ്യ്ര
+വ്വ്ര
+ വ്വ്ര
+ ്വ്ര
+ ്വ്വ്ര
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/dot-reph.txt
new file mode 100644 (file)
index 0000000..fc74da9
--- /dev/null
@@ -0,0 +1,15 @@
+ൎക
+ൎക്ക്ര
+ൎന്ന
+ൎഗ്ഗ്രോ
+ൎഗ്രോ
+ൎഗോ
+ൎഗ
+ഗ്ഗ്രോ
+ഗ്ഗ്ര
+ഗ്ഗോ
+ഗ്ഗ
+ഗ്രോ
+ൎകു
+ൎക്കു
+ൎച്ച്
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/misc/misc.txt
new file mode 100644 (file)
index 0000000..2e732ae
--- /dev/null
@@ -0,0 +1,65 @@
+അൎത്ഥം
+അഥൎവ്വം
+ക്‍
+കായ്‌കറി
+കാര്‍ക്കോടകന്‍
+കുറ്റ്യാടി
+കെ
+കേ
+കൈ
+കൊ
+കോ
+കൌ
+ക്കെ
+ക്കൊ
+ക്ത്ര
+ക്യ
+ക്വ
+ഖ്യ
+ഖ്ര
+ഗ്ദ്ധ്രോ
+ട്ട
+ട്ടു്
+ണ്‍
+ണ്ട
+ത്ത
+ത്തെ
+ത്തൊ
+ദ്ദ
+ന്‍
+ന്ത
+ന്ത്യ
+ന്ത്ര്യ
+പ്ര
+പ്ലോ
+മുഖ്യമന്ത്രി
+മ്പ
+യാത്രാകൂലി
+യും
+യ്ക്കു
+യ്യ
+ര്
+ര്‍
+ര്ക
+ര്യ
+ര്‍വ്വ
+ല്‍
+ല്യ
+ല്ല
+ല്ലാം
+വ്വ
+ഷ്ട്രീ
+സോഫ്റ്റ്‌വെയര്‍
+സ്പ്രി
+സ്പ്രേ
+സ്പ്ലേ
+സ്വാതന്ത്ര്യം
+ഹാര്‍ഡ്‌വെയര്‍
+ള്‍
+ള്യം
+ള്ള
+ല്‍പ്പേ
+ശിം‌
+കോം‌
+യ‍്യ
+സ്റ്റ്
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..b389359
--- /dev/null
@@ -0,0 +1,2 @@
+codepoint
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..0d1a19b
--- /dev/null
@@ -0,0 +1,2 @@
+ൠ
+ൡ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..4924e56
--- /dev/null
@@ -0,0 +1,36 @@
+ക
+ഖ
+ഗ
+ഘ
+ങ
+ച
+ഛ
+ജ
+ഝ
+ഞ
+ട
+ഠ
+ഡ
+ഢ
+ണ
+ത
+ഥ
+ദ
+ധ
+ന
+പ
+ഫ
+ബ
+ഭ
+മ
+യ
+ര
+റ
+ല
+ള
+ഴ
+വ
+ശ
+ഷ
+സ
+ഹ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..dc49691
--- /dev/null
@@ -0,0 +1,12 @@
+ാ
+ി
+ീ
+ു
+ൂ
+ൃ
+െ
+േ
+ൈ
+ൊ
+ോ
+ൌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..c2a9f06
--- /dev/null
@@ -0,0 +1,10 @@
+൦
+൧
+൨
+൩
+൪
+൫
+൬
+൭
+൮
+൯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..d879c3b
--- /dev/null
@@ -0,0 +1,14 @@
+അ
+ആ
+ഇ
+ഈ
+ഉ
+ഊ
+ഋ
+ഌ
+എ
+ഏ
+ഐ
+ഒ
+ഓ
+ഔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..2c976a4
--- /dev/null
@@ -0,0 +1,4 @@
+ം
+ഃ
+്
+ൗ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..1490dfe
--- /dev/null
@@ -0,0 +1,7 @@
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..1053215
--- /dev/null
@@ -0,0 +1,254 @@
+ക്ക
+ച്ച
+ട്ട
+ത്ത
+പ്പ
+ഗ്ഗ
+ജ്ജ
+ഡ്ഡ
+ദ്ദ
+ബ്ബ
+ങ്ങ
+ഞ്ഞ
+ണ്ണ
+ന്ന
+മ്മ
+യ്യ
+ല്ല
+വ്വ
+ശ്ശ
+സ്സ
+ള്ള
+റ്റ
+ക്ത
+ക്ഷ
+ഗ്ന
+ഗ്മ
+ങ്ക
+ച്ഛ
+ജ്ഞ
+ഞ്ച
+ണ്ട
+ണ്മ
+ത്ഥ
+ത്മ
+ത്ഭ
+ത്സ
+ദ്ധ
+ന്ത
+ന്ഥ
+ന്ദ
+ന്ധ
+ന്മ
+ന്റ
+മ്പ
+ബ്ദ
+ബ്ധ
+ശ്ച
+ഷ്ട
+സ്ഥ
+ഹ്ന
+ഹ്മ
+ക്യ
+ഖ്യ
+ഗ്യ
+ഘ്യ
+ങ്യ
+ച്യ
+ഛ്യ
+ജ്യ
+ഝ്യ
+ഞ്യ
+ട്യ
+ഠ്യ
+ഡ്യ
+ഢ്യ
+ണ്യ
+ത്യ
+ഥ്യ
+ദ്യ
+ധ്യ
+ന്യ
+പ്യ
+ഫ്യ
+ബ്യ
+ഭ്യ
+മ്യ
+ര്യ
+റ്യ
+ല്യ
+ള്യ
+ഴ്യ
+വ്യ
+ശ്യ
+ഷ്യ
+സ്യ
+ഹ്യ
+ക്ര
+ഖ്ര
+ഗ്ര
+ഘ്ര
+ച്ര
+ഛ്ര
+ജ്ര
+ട്ര
+ഠ്ര
+ഡ്ര
+ഢ്ര
+ത്ര
+ഥ്ര
+ദ്ര
+ധ്ര
+ന്ര
+പ്ര
+ഫ്ര
+ബ്ര
+ഭ്ര
+മ്ര
+ല്ര
+വ്ര
+ശ്ര
+ഷ്ര
+സ്ര
+ഹ്ര
+ക്ല
+ഖ്ല
+ഗ്ല
+ഘ്ല
+ങ്ല
+ച്ല
+ഛ്ല
+ജ്ല
+ഝ്ല
+ഞ്ല
+ട്ല
+ഠ്ല
+ഡ്ല
+ഢ്ല
+ണ്ല
+ത്ല
+ഥ്ല
+ദ്ല
+ധ്ല
+ന്ല
+പ്ല
+ഫ്ല
+ബ്ല
+ഭ്ല
+മ്ല
+യ്ല
+ര്ല
+റ്ല
+വ്ല
+ശ്ല
+ഷ്ല
+സ്ല
+ഹ്ല
+ക്ള
+ഖ്ള
+ഗ്ള
+ഘ്ള
+ങ്ള
+ച്ള
+ഛ്ള
+ജ്ള
+ഝ്ള
+ഞ്ള
+ട്ള
+ഠ്ള
+ഡ്ള
+ഢ്ള
+ണ്ള
+ത്ള
+ഥ്ള
+ദ്ള
+ധ്ള
+ന്ള
+പ്ള
+ഫ്ള
+ബ്ള
+ഭ്ള
+മ്ള
+യ്ള
+ര്ള
+റ്ള
+വ്ള
+ശ്ള
+ഷ്ള
+സ്ള
+ഹ്ള
+ക്വ
+ഖ്വ
+ഗ്വ
+ഘ്വ
+ങ്വ
+ച്വ
+ഛ്വ
+ജ്വ
+ഝ്വ
+ഞ്വ
+ട്വ
+ഠ്വ
+ഡ്വ
+ഢ്വ
+ണ്വ
+ത്വ
+ഥ്വ
+ദ്വ
+ധ്വ
+ന്വ
+പ്വ
+ഫ്വ
+ബ്വ
+ഭ്വ
+മ്വ
+ര്വ
+റ്വ
+ല്വ
+ള്വ
+ഴ്വ
+ശ്വ
+ഷ്വ
+സ്വ
+ഹ്വ
+ക്
+ഖ്
+ഗ്
+ഘ്
+ങ്
+ച്
+ഛ്
+ജ്
+ഝ്
+ഞ്
+ട്
+ഠ്
+ഡ്
+ഢ്
+ണ്
+ത്
+ഥ്
+ദ്
+ധ്
+ന്
+പ്
+ഫ്
+ബ്
+ഭ്
+മ്
+യ്
+ര്
+റ്
+ല്
+ള്
+ഴ്
+വ്
+ശ്
+ഷ്
+സ്
+ഹ്
+ഡ്രൈവ്
+അപ്ഡേറ്റ്
+അപ്ഗ്രേഡ്
+വ്യക്തം
+ഇന്‍സ്റ്റോള്‍
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-malayalam/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/MANIFEST
new file mode 100644 (file)
index 0000000..66a2468
--- /dev/null
@@ -0,0 +1,2 @@
+bindu.txt
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/bindu.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/bindu.txt
new file mode 100644 (file)
index 0000000..13de6ee
--- /dev/null
@@ -0,0 +1,2 @@
+ମୁଁ
+ମୁଂ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/misc/misc.txt
new file mode 100644 (file)
index 0000000..44a53df
--- /dev/null
@@ -0,0 +1,28 @@
+ஃ
+ஃக
+கூ
+கெ
+கொ
+கொ
+க்ஷ
+க்ஷொ
+க்ஷொ
+ஙூ
+சூ
+டி
+டீ
+டூ
+தூ
+மூ
+ரி
+ரீ
+ரூ
+ர்
+லி
+லீ
+କ୍ତ୍ର
+ତ୍ତ୍ବ
+ନ୍ତ୍ବ
+ନ୍ତ୍ର
+ନ୍ତ୍ର୍ଯ
+ସ୍ତ୍ର
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..b389359
--- /dev/null
@@ -0,0 +1,2 @@
+codepoint
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalConsonants.txt
new file mode 100644 (file)
index 0000000..c311f42
--- /dev/null
@@ -0,0 +1,3 @@
+ଡ଼
+ଢ଼
+ୟ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..c15795c
--- /dev/null
@@ -0,0 +1,2 @@
+ୠ
+ୡ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..5692fa1
--- /dev/null
@@ -0,0 +1,34 @@
+କ
+ଖ
+ଗ
+ଘ
+ଙ
+ଚ
+ଛ
+ଜ
+ଝ
+ଞ
+ଟ
+ଠ
+ଡ
+ଢ
+ଣ
+ତ
+ଥ
+ଦ
+ଧ
+ନ
+ପ
+ଫ
+ବ
+ଭ
+ମ
+ଯ
+ର
+ଲ
+ଳ
+ଵ
+ଶ
+ଷ
+ସ
+ହ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..d95d909
--- /dev/null
@@ -0,0 +1,12 @@
+ା
+ି
+ୀ
+ୁ
+ୂ
+ୃ
+େ
+ୈ
+ୋ
+ୌ
+ୖ
+ୗ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..ce7af5e
--- /dev/null
@@ -0,0 +1,10 @@
+୦
+୧
+୨
+୩
+୪
+୫
+୬
+୭
+୮
+୯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..9d21b9d
--- /dev/null
@@ -0,0 +1,12 @@
+ଅ
+ଆ
+ଇ
+ଈ
+ଉ
+ଊ
+ଋ
+ଌ
+ଏ
+ଐ
+ଓ
+ଔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-OriyaSpecific.txt
new file mode 100644 (file)
index 0000000..6571b52
--- /dev/null
@@ -0,0 +1,2 @@
+୰
+ୱ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..ce411d2
--- /dev/null
@@ -0,0 +1,8 @@
+ଁ
+ଂ
+ଃ
+଼
+ଽ
+୍
+ୖ
+ୗ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..17fe498
--- /dev/null
@@ -0,0 +1,9 @@
+IndicFontFeatureCodepoint-AdditionalConsonants.txt
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-OriyaSpecific.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..fe11060
--- /dev/null
@@ -0,0 +1,170 @@
+କ୍ଷ
+ଙ୍କ
+ଙ୍ଖ
+ଙ୍ଗ
+ଙ୍ଘ
+ଙ୍ଳ
+ଙ୍କ୍ତ
+ଚ୍ଚ
+ଚ୍ଛ
+ଜ୍ଜ
+ଜ୍ଝ
+ଜ୍ଞ
+ଞ୍ଚ
+ଞ୍ଛ
+ଞ୍ଜ
+ଟ୍ଟ
+ଣ୍ଟ
+ଣ୍ଠ
+ଣ୍ଡ
+ଣ୍ଢ
+ଣ୍ଣ
+ତ୍କ
+ତ୍ତ
+ତ୍ଥ
+ତ୍ନ
+ତ୍ସ
+ତ୍ପ
+ଦ୍ଦ
+ଦ୍ଧ
+ଦ୍ଭ
+ଦ୍ଯ
+ବ୍ଡ
+ବ୍ଦ
+ବ୍ଧ
+ନ୍ତ
+ନ୍ତ୍ର
+ନ୍ଥ
+ନ୍ଦ
+ନ୍ଧ
+ନ୍ନ
+ଯ୍ତ
+ମ୍ପ
+ମ୍ଫ
+ମ୍ବ
+ମ୍ମ
+ମ୍ଭ
+ଶ୍ଚ
+ଶ୍ପ
+ଶ୍ଫ
+ଶ୍କ
+ଶ୍ଟ
+ଷ୍ଟ
+ଷ୍ଟ୍ବ
+ଷ୍ଠ
+ଷ୍ଣ
+ସ୍କ
+ସ୍ଖ
+ସ୍ଘ
+ସ୍ପ
+ସ୍ଫ
+ସ୍ତ
+ସ୍ତ୍ର
+ସ୍ଥ
+ସ୍ବ
+ସ୍ମୃ
+ହ୍ନ
+ହ୍ଳ
+ହ୍ଵ
+ପ୍ଟ
+କ୍କ
+କ୍ଖ
+କ୍ଗ
+କ୍ଘ
+କ୍ଚ
+କ୍ଛ
+କ୍ଜ
+କ୍ଝ
+କ୍ଟ
+କ୍ଠ
+କ୍ଡ
+କ୍ଢ
+କ୍ଣ
+କ୍ତ
+କ୍ଥ
+କ୍ଦ
+କ୍ଧ
+କ୍ନ
+କ୍ପ
+କ୍ଫ
+କ୍ବ
+କ୍ଭ
+କ୍ମ
+କ୍ଯ
+କ୍ର
+କ୍ଳ
+କ୍ଲ
+କ୍ହ
+ର୍କ
+ର୍ଖ
+ର୍ଗ
+ର୍ଘ
+ର୍ଚ
+ର୍ଚ୍ଚ
+ର୍ଚ୍ଛ
+ର୍ଛ
+ର୍ଜ
+ର୍ଝ
+ର୍ଟ
+ର୍ଠ
+ର୍ଡ
+ର୍ଢ
+ର୍ଣ
+ର୍ତ
+ର୍ତ୍ତ
+ର୍ଥ
+ର୍ଦ
+ର୍ଦ୍ଦ
+ର୍ଦ୍ଧ
+ର୍ଧ
+ର୍ନ
+ର୍ପ
+ର୍ଫ
+ର୍ବ
+ର୍ଭ
+ର୍ମ
+ର୍ଯ
+ର୍ଯ୍ଯ
+ର୍ଶ
+ର୍ଷ
+ର୍ସ
+ର୍ହ
+ର୍ଡ଼
+ର୍ଢ଼
+ଖ୍ର
+ଗ୍ର
+ଘ୍ର
+ଚ୍ଚ୍ର
+ଚ୍ଛ୍ର
+ଚ୍ର
+ଛ୍ର
+ଜ୍ର
+ଝ୍ର
+ଟ୍ର
+ଠ୍ର
+ଡ୍ର
+ଢ୍ର
+ଣ୍ର
+ତ୍ର
+ତ୍ତ୍ର
+ତ୍ଥ୍ର
+ଥ୍ର
+ଦ୍ର
+ଦ୍ଦ୍ର
+ଦ୍ଧ୍ର
+ଧ୍ର
+ନ୍ର
+ପ୍ର
+ଫ୍ର
+ବ୍ର
+ଭ୍ର
+ମ୍ର
+ଯ୍ର
+ଶ୍ର
+ଷ୍ର
+ସ୍ର
+ହ୍ର
+ଡ଼୍ର
+ଢ଼୍ର
+ଦ୍ଗ
+ତ୍ମ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-oriya/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/MANIFEST
new file mode 100644 (file)
index 0000000..a00d7ae
--- /dev/null
@@ -0,0 +1,4 @@
+extensive.txt
+misc.txt
+reph.txt
+split-matras.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/extensive.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/extensive.txt
new file mode 100644 (file)
index 0000000..231a1f7
--- /dev/null
@@ -0,0 +1,4390 @@
+අ
+ආ
+ඇ
+ඈ
+ඉ
+ඊ
+උ
+ඌ
+ඍ
+ඎ
+ඏ
+ඐ
+එ
+ඒ
+ඓ
+ඔ
+ඕ
+ඖ
+ක
+කා
+කැ
+කෑ
+කි
+කී
+කු
+කූ
+කෘ
+කෲ
+කෟ
+කෳ
+කෙ
+කේ
+කෛ
+කො
+කෝ
+කෞ
+ක්
+කං
+කඃ
+ක්‍ර
+ක්‍රා
+ක්‍රැ
+ක්‍රෑ
+ක්‍රි
+ක්‍රී
+ක්‍රු
+ක්‍රූ
+ක්‍රෘ
+ක්‍රෲ
+ක්‍රෟ
+ක්‍රෳ
+ක්‍රෙ
+ක්‍රේ
+ක්‍රෛ
+ක්‍රො
+ක්‍රෝ
+ක්‍රෞ
+ක්‍ර්
+ක්‍රං
+ක්‍රඃ
+ක්‍ය
+ක්‍යා
+ක්‍යැ
+ක්‍යෑ
+ක්‍යි
+ක්‍යී
+ක්‍යු
+ක්‍යූ
+ක්‍යෘ
+ක්‍යෲ
+ක්‍යෟ
+ක්‍යෳ
+ක්‍යෙ
+ක්‍යේ
+ක්‍යෛ
+ක්‍යො
+ක්‍යෝ
+ක්‍යෞ
+ක්‍ය්
+ක්‍යං
+ක්‍යඃ
+ර්‍ක
+ර්‍කා
+ර්‍කැ
+ර්‍කෑ
+ර්‍කි
+ර්‍කී
+ර්‍කු
+ර්‍කූ
+ර්‍කෘ
+ර්‍කෲ
+ර්‍කෟ
+ර්‍කෳ
+ර්‍කෙ
+ර්‍කේ
+ර්‍කෛ
+ර්‍කො
+ර්‍කෝ
+ර්‍කෞ
+ර්‍ක්
+ර්‍කං
+ර්‍කඃ
+ඛ
+ඛා
+ඛැ
+ඛෑ
+ඛි
+ඛී
+ඛු
+ඛූ
+ඛෘ
+ඛෲ
+ඛෟ
+ඛෳ
+ඛෙ
+ඛේ
+ඛෛ
+ඛො
+ඛෝ
+ඛෞ
+ඛ්
+ඛං
+ඛඃ
+ඛ්‍ර
+ඛ්‍රා
+ඛ්‍රැ
+ඛ්‍රෑ
+ඛ්‍රි
+ඛ්‍රී
+ඛ්‍රු
+ඛ්‍රූ
+ඛ්‍රෘ
+ඛ්‍රෲ
+ඛ්‍රෟ
+ඛ්‍රෳ
+ඛ්‍රෙ
+ඛ්‍රේ
+ඛ්‍රෛ
+ඛ්‍රො
+ඛ්‍රෝ
+ඛ්‍රෞ
+ඛ්‍ර්
+ඛ්‍රං
+ඛ්‍රඃ
+ඛ්‍ය
+ඛ්‍යා
+ඛ්‍යැ
+ඛ්‍යෑ
+ඛ්‍යි
+ඛ්‍යී
+ඛ්‍යු
+ඛ්‍යූ
+ඛ්‍යෘ
+ඛ්‍යෲ
+ඛ්‍යෟ
+ඛ්‍යෳ
+ඛ්‍යෙ
+ඛ්‍යේ
+ඛ්‍යෛ
+ඛ්‍යො
+ඛ්‍යෝ
+ඛ්‍යෞ
+ඛ්‍ය්
+ඛ්‍යං
+ඛ්‍යඃ
+ර්‍ඛ
+ර්‍ඛා
+ර්‍ඛැ
+ර්‍ඛෑ
+ර්‍ඛි
+ර්‍ඛී
+ර්‍ඛු
+ර්‍ඛූ
+ර්‍ඛෘ
+ර්‍ඛෲ
+ර්‍ඛෟ
+ර්‍ඛෳ
+ර්‍ඛෙ
+ර්‍ඛේ
+ර්‍ඛෛ
+ර්‍ඛො
+ර්‍ඛෝ
+ර්‍ඛෞ
+ර්‍ඛ්
+ර්‍ඛං
+ර්‍ඛඃ
+ග
+ගා
+ගැ
+ගෑ
+ගි
+ගී
+ගු
+ගූ
+ගෘ
+ගෲ
+ගෟ
+ගෳ
+ගෙ
+ගේ
+ගෛ
+ගො
+ගෝ
+ගෞ
+ග්
+ගං
+ගඃ
+ග්‍ර
+ග්‍රා
+ග්‍රැ
+ග්‍රෑ
+ග්‍රි
+ග්‍රී
+ග්‍රු
+ග්‍රූ
+ග්‍රෘ
+ග්‍රෲ
+ග්‍රෟ
+ග්‍රෳ
+ග්‍රෙ
+ග්‍රේ
+ග්‍රෛ
+ග්‍රො
+ග්‍රෝ
+ග්‍රෞ
+ග්‍ර්
+ග්‍රං
+ග්‍රඃ
+ග්‍ය
+ග්‍යා
+ග්‍යැ
+ග්‍යෑ
+ග්‍යි
+ග්‍යී
+ග්‍යු
+ග්‍යූ
+ග්‍යෘ
+ග්‍යෲ
+ග්‍යෟ
+ග්‍යෳ
+ග්‍යෙ
+ග්‍යේ
+ග්‍යෛ
+ග්‍යො
+ග්‍යෝ
+ග්‍යෞ
+ග්‍ය්
+ග්‍යං
+ග්‍යඃ
+ර්‍ග
+ර්‍ගා
+ර්‍ගැ
+ර්‍ගෑ
+ර්‍ගි
+ර්‍ගී
+ර්‍ගු
+ර්‍ගූ
+ර්‍ගෘ
+ර්‍ගෲ
+ර්‍ගෟ
+ර්‍ගෳ
+ර්‍ගෙ
+ර්‍ගේ
+ර්‍ගෛ
+ර්‍ගො
+ර්‍ගෝ
+ර්‍ගෞ
+ර්‍ග්
+ර්‍ගං
+ර්‍ගඃ
+ඝ
+ඝා
+ඝැ
+ඝෑ
+ඝි
+ඝී
+ඝු
+ඝූ
+ඝෘ
+ඝෲ
+ඝෟ
+ඝෳ
+ඝෙ
+ඝේ
+ඝෛ
+ඝො
+ඝෝ
+ඝෞ
+ඝ්
+ඝං
+ඝඃ
+ඝ්‍ර
+ඝ්‍රා
+ඝ්‍රැ
+ඝ්‍රෑ
+ඝ්‍රි
+ඝ්‍රී
+ඝ්‍රු
+ඝ්‍රූ
+ඝ්‍රෘ
+ඝ්‍රෲ
+ඝ්‍රෟ
+ඝ්‍රෳ
+ඝ්‍රෙ
+ඝ්‍රේ
+ඝ්‍රෛ
+ඝ්‍රො
+ඝ්‍රෝ
+ඝ්‍රෞ
+ඝ්‍ර්
+ඝ්‍රං
+ඝ්‍රඃ
+ඝ්‍ය
+ඝ්‍යා
+ඝ්‍යැ
+ඝ්‍යෑ
+ඝ්‍යි
+ඝ්‍යී
+ඝ්‍යු
+ඝ්‍යූ
+ඝ්‍යෘ
+ඝ්‍යෲ
+ඝ්‍යෟ
+ඝ්‍යෳ
+ඝ්‍යෙ
+ඝ්‍යේ
+ඝ්‍යෛ
+ඝ්‍යො
+ඝ්‍යෝ
+ඝ්‍යෞ
+ඝ්‍ය්
+ඝ්‍යං
+ඝ්‍යඃ
+ර්‍ඝ
+ර්‍ඝා
+ර්‍ඝැ
+ර්‍ඝෑ
+ර්‍ඝි
+ර්‍ඝී
+ර්‍ඝු
+ර්‍ඝූ
+ර්‍ඝෘ
+ර්‍ඝෲ
+ර්‍ඝෟ
+ර්‍ඝෳ
+ර්‍ඝෙ
+ර්‍ඝේ
+ර්‍ඝෛ
+ර්‍ඝො
+ර්‍ඝෝ
+ර්‍ඝෞ
+ර්‍ඝ්
+ර්‍ඝං
+ර්‍ඝඃ
+ඞ
+ඞා
+ඞැ
+ඞෑ
+ඞි
+ඞී
+ඞු
+ඞූ
+ඞෘ
+ඞෲ
+ඞෟ
+ඞෳ
+ඞෙ
+ඞේ
+ඞෛ
+ඞො
+ඞෝ
+ඞෞ
+ඞ්
+ඞං
+ඞඃ
+ඞ්‍ර
+ඞ්‍රා
+ඞ්‍රැ
+ඞ්‍රෑ
+ඞ්‍රි
+ඞ්‍රී
+ඞ්‍රු
+ඞ්‍රූ
+ඞ්‍රෘ
+ඞ්‍රෲ
+ඞ්‍රෟ
+ඞ්‍රෳ
+ඞ්‍රෙ
+ඞ්‍රේ
+ඞ්‍රෛ
+ඞ්‍රො
+ඞ්‍රෝ
+ඞ්‍රෞ
+ඞ්‍ර්
+ඞ්‍රං
+ඞ්‍රඃ
+ඞ්‍ය
+ඞ්‍යා
+ඞ්‍යැ
+ඞ්‍යෑ
+ඞ්‍යි
+ඞ්‍යී
+ඞ්‍යු
+ඞ්‍යූ
+ඞ්‍යෘ
+ඞ්‍යෲ
+ඞ්‍යෟ
+ඞ්‍යෳ
+ඞ්‍යෙ
+ඞ්‍යේ
+ඞ්‍යෛ
+ඞ්‍යො
+ඞ්‍යෝ
+ඞ්‍යෞ
+ඞ්‍ය්
+ඞ්‍යං
+ඞ්‍යඃ
+ර්‍ඞ
+ර්‍ඞා
+ර්‍ඞැ
+ර්‍ඞෑ
+ර්‍ඞි
+ර්‍ඞී
+ර්‍ඞු
+ර්‍ඞූ
+ර්‍ඞෘ
+ර්‍ඞෲ
+ර්‍ඞෟ
+ර්‍ඞෳ
+ර්‍ඞෙ
+ර්‍ඞේ
+ර්‍ඞෛ
+ර්‍ඞො
+ර්‍ඞෝ
+ර්‍ඞෞ
+ර්‍ඞ්
+ර්‍ඞං
+ර්‍ඞඃ
+ඟ
+ඟා
+ඟැ
+ඟෑ
+ඟි
+ඟී
+ඟු
+ඟූ
+ඟෘ
+ඟෲ
+ඟෟ
+ඟෳ
+ඟෙ
+ඟේ
+ඟෛ
+ඟො
+ඟෝ
+ඟෞ
+ඟ්
+ඟං
+ඟඃ
+ඟ්‍ර
+ඟ්‍රා
+ඟ්‍රැ
+ඟ්‍රෑ
+ඟ්‍රි
+ඟ්‍රී
+ඟ්‍රු
+ඟ්‍රූ
+ඟ්‍රෘ
+ඟ්‍රෲ
+ඟ්‍රෟ
+ඟ්‍රෳ
+ඟ්‍රෙ
+ඟ්‍රේ
+ඟ්‍රෛ
+ඟ්‍රො
+ඟ්‍රෝ
+ඟ්‍රෞ
+ඟ්‍ර්
+ඟ්‍රං
+ඟ්‍රඃ
+ඟ්‍ය
+ඟ්‍යා
+ඟ්‍යැ
+ඟ්‍යෑ
+ඟ්‍යි
+ඟ්‍යී
+ඟ්‍යු
+ඟ්‍යූ
+ඟ්‍යෘ
+ඟ්‍යෲ
+ඟ්‍යෟ
+ඟ්‍යෳ
+ඟ්‍යෙ
+ඟ්‍යේ
+ඟ්‍යෛ
+ඟ්‍යො
+ඟ්‍යෝ
+ඟ්‍යෞ
+ඟ්‍ය්
+ඟ්‍යං
+ඟ්‍යඃ
+ර්‍ඟ
+ර්‍ඟා
+ර්‍ඟැ
+ර්‍ඟෑ
+ර්‍ඟි
+ර්‍ඟී
+ර්‍ඟු
+ර්‍ඟූ
+ර්‍ඟෘ
+ර්‍ඟෲ
+ර්‍ඟෟ
+ර්‍ඟෳ
+ර්‍ඟෙ
+ර්‍ඟේ
+ර්‍ඟෛ
+ර්‍ඟො
+ර්‍ඟෝ
+ර්‍ඟෞ
+ර්‍ඟ්
+ර්‍ඟං
+ර්‍ඟඃ
+ච
+චා
+චැ
+චෑ
+චි
+චී
+චු
+චූ
+චෘ
+චෲ
+චෟ
+චෳ
+චෙ
+චේ
+චෛ
+චො
+චෝ
+චෞ
+ච්
+චං
+චඃ
+ච්‍ර
+ච්‍රා
+ච්‍රැ
+ච්‍රෑ
+ච්‍රි
+ච්‍රී
+ච්‍රු
+ච්‍රූ
+ච්‍රෘ
+ච්‍රෲ
+ච්‍රෟ
+ච්‍රෳ
+ච්‍රෙ
+ච්‍රේ
+ච්‍රෛ
+ච්‍රො
+ච්‍රෝ
+ච්‍රෞ
+ච්‍ර්
+ච්‍රං
+ච්‍රඃ
+ච්‍ය
+ච්‍යා
+ච්‍යැ
+ච්‍යෑ
+ච්‍යි
+ච්‍යී
+ච්‍යු
+ච්‍යූ
+ච්‍යෘ
+ච්‍යෲ
+ච්‍යෟ
+ච්‍යෳ
+ච්‍යෙ
+ච්‍යේ
+ච්‍යෛ
+ච්‍යො
+ච්‍යෝ
+ච්‍යෞ
+ච්‍ය්
+ච්‍යං
+ච්‍යඃ
+ර්‍ච
+ර්‍චා
+ර්‍චැ
+ර්‍චෑ
+ර්‍චි
+ර්‍චී
+ර්‍චු
+ර්‍චූ
+ර්‍චෘ
+ර්‍චෲ
+ර්‍චෟ
+ර්‍චෳ
+ර්‍චෙ
+ර්‍චේ
+ර්‍චෛ
+ර්‍චො
+ර්‍චෝ
+ර්‍චෞ
+ර්‍ච්
+ර්‍චං
+ර්‍චඃ
+ඡ
+ඡා
+ඡැ
+ඡෑ
+ඡි
+ඡී
+ඡු
+ඡූ
+ඡෘ
+ඡෲ
+ඡෟ
+ඡෳ
+ඡෙ
+ඡේ
+ඡෛ
+ඡො
+ඡෝ
+ඡෞ
+ඡ්
+ඡං
+ඡඃ
+ඡ්‍ර
+ඡ්‍රා
+ඡ්‍රැ
+ඡ්‍රෑ
+ඡ්‍රි
+ඡ්‍රී
+ඡ්‍රු
+ඡ්‍රූ
+ඡ්‍රෘ
+ඡ්‍රෲ
+ඡ්‍රෟ
+ඡ්‍රෳ
+ඡ්‍රෙ
+ඡ්‍රේ
+ඡ්‍රෛ
+ඡ්‍රො
+ඡ්‍රෝ
+ඡ්‍රෞ
+ඡ්‍ර්
+ඡ්‍රං
+ඡ්‍රඃ
+ඡ්‍ය
+ඡ්‍යා
+ඡ්‍යැ
+ඡ්‍යෑ
+ඡ්‍යි
+ඡ්‍යී
+ඡ්‍යු
+ඡ්‍යූ
+ඡ්‍යෘ
+ඡ්‍යෲ
+ඡ්‍යෟ
+ඡ්‍යෳ
+ඡ්‍යෙ
+ඡ්‍යේ
+ඡ්‍යෛ
+ඡ්‍යො
+ඡ්‍යෝ
+ඡ්‍යෞ
+ඡ්‍ය්
+ඡ්‍යං
+ඡ්‍යඃ
+ර්‍ඡ
+ර්‍ඡා
+ර්‍ඡැ
+ර්‍ඡෑ
+ර්‍ඡි
+ර්‍ඡී
+ර්‍ඡු
+ර්‍ඡූ
+ර්‍ඡෘ
+ර්‍ඡෲ
+ර්‍ඡෟ
+ර්‍ඡෳ
+ර්‍ඡෙ
+ර්‍ඡේ
+ර්‍ඡෛ
+ර්‍ඡො
+ර්‍ඡෝ
+ර්‍ඡෞ
+ර්‍ඡ්
+ර්‍ඡං
+ර්‍ඡඃ
+ජ
+ජා
+ජැ
+ජෑ
+ජි
+ජී
+ජු
+ජූ
+ජෘ
+ජෲ
+ජෟ
+ජෳ
+ජෙ
+ජේ
+ජෛ
+ජො
+ජෝ
+ජෞ
+ජ්
+ජං
+ජඃ
+ජ්‍ර
+ජ්‍රා
+ජ්‍රැ
+ජ්‍රෑ
+ජ්‍රි
+ජ්‍රී
+ජ්‍රු
+ජ්‍රූ
+ජ්‍රෘ
+ජ්‍රෲ
+ජ්‍රෟ
+ජ්‍රෳ
+ජ්‍රෙ
+ජ්‍රේ
+ජ්‍රෛ
+ජ්‍රො
+ජ්‍රෝ
+ජ්‍රෞ
+ජ්‍ර්
+ජ්‍රං
+ජ්‍රඃ
+ජ්‍ය
+ජ්‍යා
+ජ්‍යැ
+ජ්‍යෑ
+ජ්‍යි
+ජ්‍යී
+ජ්‍යු
+ජ්‍යූ
+ජ්‍යෘ
+ජ්‍යෲ
+ජ්‍යෟ
+ජ්‍යෳ
+ජ්‍යෙ
+ජ්‍යේ
+ජ්‍යෛ
+ජ්‍යො
+ජ්‍යෝ
+ජ්‍යෞ
+ජ්‍ය්
+ජ්‍යං
+ජ්‍යඃ
+ර්‍ජ
+ර්‍ජා
+ර්‍ජැ
+ර්‍ජෑ
+ර්‍ජි
+ර්‍ජී
+ර්‍ජු
+ර්‍ජූ
+ර්‍ජෘ
+ර්‍ජෲ
+ර්‍ජෟ
+ර්‍ජෳ
+ර්‍ජෙ
+ර්‍ජේ
+ර්‍ජෛ
+ර්‍ජො
+ර්‍ජෝ
+ර්‍ජෞ
+ර්‍ජ්
+ර්‍ජං
+ර්‍ජඃ
+ඣ
+ඣා
+ඣැ
+ඣෑ
+ඣි
+ඣී
+ඣු
+ඣූ
+ඣෘ
+ඣෲ
+ඣෟ
+ඣෳ
+ඣෙ
+ඣේ
+ඣෛ
+ඣො
+ඣෝ
+ඣෞ
+ඣ්
+ඣං
+ඣඃ
+ඣ්‍ර
+ඣ්‍රා
+ඣ්‍රැ
+ඣ්‍රෑ
+ඣ්‍රි
+ඣ්‍රී
+ඣ්‍රු
+ඣ්‍රූ
+ඣ්‍රෘ
+ඣ්‍රෲ
+ඣ්‍රෟ
+ඣ්‍රෳ
+ඣ්‍රෙ
+ඣ්‍රේ
+ඣ්‍රෛ
+ඣ්‍රො
+ඣ්‍රෝ
+ඣ්‍රෞ
+ඣ්‍ර්
+ඣ්‍රං
+ඣ්‍රඃ
+ඣ්‍ය
+ඣ්‍යා
+ඣ්‍යැ
+ඣ්‍යෑ
+ඣ්‍යි
+ඣ්‍යී
+ඣ්‍යු
+ඣ්‍යූ
+ඣ්‍යෘ
+ඣ්‍යෲ
+ඣ්‍යෟ
+ඣ්‍යෳ
+ඣ්‍යෙ
+ඣ්‍යේ
+ඣ්‍යෛ
+ඣ්‍යො
+ඣ්‍යෝ
+ඣ්‍යෞ
+ඣ්‍ය්
+ඣ්‍යං
+ඣ්‍යඃ
+ර්‍ඣ
+ර්‍ඣා
+ර්‍ඣැ
+ර්‍ඣෑ
+ර්‍ඣි
+ර්‍ඣී
+ර්‍ඣු
+ර්‍ඣූ
+ර්‍ඣෘ
+ර්‍ඣෲ
+ර්‍ඣෟ
+ර්‍ඣෳ
+ර්‍ඣෙ
+ර්‍ඣේ
+ර්‍ඣෛ
+ර්‍ඣො
+ර්‍ඣෝ
+ර්‍ඣෞ
+ර්‍ඣ්
+ර්‍ඣං
+ර්‍ඣඃ
+ඥ
+ඥා
+ඥැ
+ඥෑ
+ඥි
+ඥී
+ඥු
+ඥූ
+ඥෘ
+ඥෲ
+ඥෟ
+ඥෳ
+ඥෙ
+ඥේ
+ඥෛ
+ඥො
+ඥෝ
+ඥෞ
+ඥ්
+ඥං
+ඥඃ
+ඥ්‍ර
+ඥ්‍රා
+ඥ්‍රැ
+ඥ්‍රෑ
+ඥ්‍රි
+ඥ්‍රී
+ඥ්‍රු
+ඥ්‍රූ
+ඥ්‍රෘ
+ඥ්‍රෲ
+ඥ්‍රෟ
+ඥ්‍රෳ
+ඥ්‍රෙ
+ඥ්‍රේ
+ඥ්‍රෛ
+ඥ්‍රො
+ඥ්‍රෝ
+ඥ්‍රෞ
+ඥ්‍ර්
+ඥ්‍රං
+ඥ්‍රඃ
+ඥ්‍ය
+ඥ්‍යා
+ඥ්‍යැ
+ඥ්‍යෑ
+ඥ්‍යි
+ඥ්‍යී
+ඥ්‍යු
+ඥ්‍යූ
+ඥ්‍යෘ
+ඥ්‍යෲ
+ඥ්‍යෟ
+ඥ්‍යෳ
+ඥ්‍යෙ
+ඥ්‍යේ
+ඥ්‍යෛ
+ඥ්‍යො
+ඥ්‍යෝ
+ඥ්‍යෞ
+ඥ්‍ය්
+ඥ්‍යං
+ඥ්‍යඃ
+ර්‍ඥ
+ර්‍ඥා
+ර්‍ඥැ
+ර්‍ඥෑ
+ර්‍ඥි
+ර්‍ඥී
+ර්‍ඥු
+ර්‍ඥූ
+ර්‍ඥෘ
+ර්‍ඥෲ
+ර්‍ඥෟ
+ර්‍ඥෳ
+ර්‍ඥෙ
+ර්‍ඥේ
+ර්‍ඥෛ
+ර්‍ඥො
+ර්‍ඥෝ
+ර්‍ඥෞ
+ර්‍ඥ්
+ර්‍ඥං
+ර්‍ඥඃ
+ඤ
+ඤා
+ඤැ
+ඤෑ
+ඤි
+ඤී
+ඤු
+ඤූ
+ඤෘ
+ඤෲ
+ඤෟ
+ඤෳ
+ඤෙ
+ඤේ
+ඤෛ
+ඤො
+ඤෝ
+ඤෞ
+ඤ්
+ඤං
+ඤඃ
+ඤ්‍ර
+ඤ්‍රා
+ඤ්‍රැ
+ඤ්‍රෑ
+ඤ්‍රි
+ඤ්‍රී
+ඤ්‍රු
+ඤ්‍රූ
+ඤ්‍රෘ
+ඤ්‍රෲ
+ඤ්‍රෟ
+ඤ්‍රෳ
+ඤ්‍රෙ
+ඤ්‍රේ
+ඤ්‍රෛ
+ඤ්‍රො
+ඤ්‍රෝ
+ඤ්‍රෞ
+ඤ්‍ර්
+ඤ්‍රං
+ඤ්‍රඃ
+ඤ්‍ය
+ඤ්‍යා
+ඤ්‍යැ
+ඤ්‍යෑ
+ඤ්‍යි
+ඤ්‍යී
+ඤ්‍යු
+ඤ්‍යූ
+ඤ්‍යෘ
+ඤ්‍යෲ
+ඤ්‍යෟ
+ඤ්‍යෳ
+ඤ්‍යෙ
+ඤ්‍යේ
+ඤ්‍යෛ
+ඤ්‍යො
+ඤ්‍යෝ
+ඤ්‍යෞ
+ඤ්‍ය්
+ඤ්‍යං
+ඤ්‍යඃ
+ර්‍ඤ
+ර්‍ඤා
+ර්‍ඤැ
+ර්‍ඤෑ
+ර්‍ඤි
+ර්‍ඤී
+ර්‍ඤු
+ර්‍ඤූ
+ර්‍ඤෘ
+ර්‍ඤෲ
+ර්‍ඤෟ
+ර්‍ඤෳ
+ර්‍ඤෙ
+ර්‍ඤේ
+ර්‍ඤෛ
+ර්‍ඤො
+ර්‍ඤෝ
+ර්‍ඤෞ
+ර්‍ඤ්
+ර්‍ඤං
+ර්‍ඤඃ
+ඦ
+ඦා
+ඦැ
+ඦෑ
+ඦි
+ඦී
+ඦු
+ඦූ
+ඦෘ
+ඦෲ
+ඦෟ
+ඦෳ
+ඦෙ
+ඦේ
+ඦෛ
+ඦො
+ඦෝ
+ඦෞ
+ඦ්
+ඦං
+ඦඃ
+ඦ්‍ර
+ඦ්‍රා
+ඦ්‍රැ
+ඦ්‍රෑ
+ඦ්‍රි
+ඦ්‍රී
+ඦ්‍රු
+ඦ්‍රූ
+ඦ්‍රෘ
+ඦ්‍රෲ
+ඦ්‍රෟ
+ඦ්‍රෳ
+ඦ්‍රෙ
+ඦ්‍රේ
+ඦ්‍රෛ
+ඦ්‍රො
+ඦ්‍රෝ
+ඦ්‍රෞ
+ඦ්‍ර්
+ඦ්‍රං
+ඦ්‍රඃ
+ඦ්‍ය
+ඦ්‍යා
+ඦ්‍යැ
+ඦ්‍යෑ
+ඦ්‍යි
+ඦ්‍යී
+ඦ්‍යු
+ඦ්‍යූ
+ඦ්‍යෘ
+ඦ්‍යෲ
+ඦ්‍යෟ
+ඦ්‍යෳ
+ඦ්‍යෙ
+ඦ්‍යේ
+ඦ්‍යෛ
+ඦ්‍යො
+ඦ්‍යෝ
+ඦ්‍යෞ
+ඦ්‍ය්
+ඦ්‍යං
+ඦ්‍යඃ
+ර්‍ඦ
+ර්‍ඦා
+ර්‍ඦැ
+ර්‍ඦෑ
+ර්‍ඦි
+ර්‍ඦී
+ර්‍ඦු
+ර්‍ඦූ
+ර්‍ඦෘ
+ර්‍ඦෲ
+ර්‍ඦෟ
+ර්‍ඦෳ
+ර්‍ඦෙ
+ර්‍ඦේ
+ර්‍ඦෛ
+ර්‍ඦො
+ර්‍ඦෝ
+ර්‍ඦෞ
+ර්‍ඦ්
+ර්‍ඦං
+ර්‍ඦඃ
+ට
+ටා
+ටැ
+ටෑ
+ටි
+ටී
+ටු
+ටූ
+ටෘ
+ටෲ
+ටෟ
+ටෳ
+ටෙ
+ටේ
+ටෛ
+ටො
+ටෝ
+ටෞ
+ට්
+ටං
+ටඃ
+ට්‍ර
+ට්‍රා
+ට්‍රැ
+ට්‍රෑ
+ට්‍රි
+ට්‍රී
+ට්‍රු
+ට්‍රූ
+ට්‍රෘ
+ට්‍රෲ
+ට්‍රෟ
+ට්‍රෳ
+ට්‍රෙ
+ට්‍රේ
+ට්‍රෛ
+ට්‍රො
+ට්‍රෝ
+ට්‍රෞ
+ට්‍ර්
+ට්‍රං
+ට්‍රඃ
+ට්‍ය
+ට්‍යා
+ට්‍යැ
+ට්‍යෑ
+ට්‍යි
+ට්‍යී
+ට්‍යු
+ට්‍යූ
+ට්‍යෘ
+ට්‍යෲ
+ට්‍යෟ
+ට්‍යෳ
+ට්‍යෙ
+ට්‍යේ
+ට්‍යෛ
+ට්‍යො
+ට්‍යෝ
+ට්‍යෞ
+ට්‍ය්
+ට්‍යං
+ට්‍යඃ
+ර්‍ට
+ර්‍ටා
+ර්‍ටැ
+ර්‍ටෑ
+ර්‍ටි
+ර්‍ටී
+ර්‍ටු
+ර්‍ටූ
+ර්‍ටෘ
+ර්‍ටෲ
+ර්‍ටෟ
+ර්‍ටෳ
+ර්‍ටෙ
+ර්‍ටේ
+ර්‍ටෛ
+ර්‍ටො
+ර්‍ටෝ
+ර්‍ටෞ
+ර්‍ට්
+ර්‍ටං
+ර්‍ටඃ
+ඨ
+ඨා
+ඨැ
+ඨෑ
+ඨි
+ඨී
+ඨු
+ඨූ
+ඨෘ
+ඨෲ
+ඨෟ
+ඨෳ
+ඨෙ
+ඨේ
+ඨෛ
+ඨො
+ඨෝ
+ඨෞ
+ඨ්
+ඨං
+ඨඃ
+ඨ්‍ර
+ඨ්‍රා
+ඨ්‍රැ
+ඨ්‍රෑ
+ඨ්‍රි
+ඨ්‍රී
+ඨ්‍රු
+ඨ්‍රූ
+ඨ්‍රෘ
+ඨ්‍රෲ
+ඨ්‍රෟ
+ඨ්‍රෳ
+ඨ්‍රෙ
+ඨ්‍රේ
+ඨ්‍රෛ
+ඨ්‍රො
+ඨ්‍රෝ
+ඨ්‍රෞ
+ඨ්‍ර්
+ඨ්‍රං
+ඨ්‍රඃ
+ඨ්‍ය
+ඨ්‍යා
+ඨ්‍යැ
+ඨ්‍යෑ
+ඨ්‍යි
+ඨ්‍යී
+ඨ්‍යු
+ඨ්‍යූ
+ඨ්‍යෘ
+ඨ්‍යෲ
+ඨ්‍යෟ
+ඨ්‍යෳ
+ඨ්‍යෙ
+ඨ්‍යේ
+ඨ්‍යෛ
+ඨ්‍යො
+ඨ්‍යෝ
+ඨ්‍යෞ
+ඨ්‍ය්
+ඨ්‍යං
+ඨ්‍යඃ
+ර්‍ඨ
+ර්‍ඨා
+ර්‍ඨැ
+ර්‍ඨෑ
+ර්‍ඨි
+ර්‍ඨී
+ර්‍ඨු
+ර්‍ඨූ
+ර්‍ඨෘ
+ර්‍ඨෲ
+ර්‍ඨෟ
+ර්‍ඨෳ
+ර්‍ඨෙ
+ර්‍ඨේ
+ර්‍ඨෛ
+ර්‍ඨො
+ර්‍ඨෝ
+ර්‍ඨෞ
+ර්‍ඨ්
+ර්‍ඨං
+ර්‍ඨඃ
+ඩ
+ඩා
+ඩැ
+ඩෑ
+ඩි
+ඩී
+ඩු
+ඩූ
+ඩෘ
+ඩෲ
+ඩෟ
+ඩෳ
+ඩෙ
+ඩේ
+ඩෛ
+ඩො
+ඩෝ
+ඩෞ
+ඩ්
+ඩං
+ඩඃ
+ඩ්‍ර
+ඩ්‍රා
+ඩ්‍රැ
+ඩ්‍රෑ
+ඩ්‍රි
+ඩ්‍රී
+ඩ්‍රු
+ඩ්‍රූ
+ඩ්‍රෘ
+ඩ්‍රෲ
+ඩ්‍රෟ
+ඩ්‍රෳ
+ඩ්‍රෙ
+ඩ්‍රේ
+ඩ්‍රෛ
+ඩ්‍රො
+ඩ්‍රෝ
+ඩ්‍රෞ
+ඩ්‍ර්
+ඩ්‍රං
+ඩ්‍රඃ
+ඩ්‍ය
+ඩ්‍යා
+ඩ්‍යැ
+ඩ්‍යෑ
+ඩ්‍යි
+ඩ්‍යී
+ඩ්‍යු
+ඩ්‍යූ
+ඩ්‍යෘ
+ඩ්‍යෲ
+ඩ්‍යෟ
+ඩ්‍යෳ
+ඩ්‍යෙ
+ඩ්‍යේ
+ඩ්‍යෛ
+ඩ්‍යො
+ඩ්‍යෝ
+ඩ්‍යෞ
+ඩ්‍ය්
+ඩ්‍යං
+ඩ්‍යඃ
+ර්‍ඩ
+ර්‍ඩා
+ර්‍ඩැ
+ර්‍ඩෑ
+ර්‍ඩි
+ර්‍ඩී
+ර්‍ඩු
+ර්‍ඩූ
+ර්‍ඩෘ
+ර්‍ඩෲ
+ර්‍ඩෟ
+ර්‍ඩෳ
+ර්‍ඩෙ
+ර්‍ඩේ
+ර්‍ඩෛ
+ර්‍ඩො
+ර්‍ඩෝ
+ර්‍ඩෞ
+ර්‍ඩ්
+ර්‍ඩං
+ර්‍ඩඃ
+ඪ
+ඪා
+ඪැ
+ඪෑ
+ඪි
+ඪී
+ඪු
+ඪූ
+ඪෘ
+ඪෲ
+ඪෟ
+ඪෳ
+ඪෙ
+ඪේ
+ඪෛ
+ඪො
+ඪෝ
+ඪෞ
+ඪ්
+ඪං
+ඪඃ
+ඪ්‍ර
+ඪ්‍රා
+ඪ්‍රැ
+ඪ්‍රෑ
+ඪ්‍රි
+ඪ්‍රී
+ඪ්‍රු
+ඪ්‍රූ
+ඪ්‍රෘ
+ඪ්‍රෲ
+ඪ්‍රෟ
+ඪ්‍රෳ
+ඪ්‍රෙ
+ඪ්‍රේ
+ඪ්‍රෛ
+ඪ්‍රො
+ඪ්‍රෝ
+ඪ්‍රෞ
+ඪ්‍ර්
+ඪ්‍රං
+ඪ්‍රඃ
+ඪ්‍ය
+ඪ්‍යා
+ඪ්‍යැ
+ඪ්‍යෑ
+ඪ්‍යි
+ඪ්‍යී
+ඪ්‍යු
+ඪ්‍යූ
+ඪ්‍යෘ
+ඪ්‍යෲ
+ඪ්‍යෟ
+ඪ්‍යෳ
+ඪ්‍යෙ
+ඪ්‍යේ
+ඪ්‍යෛ
+ඪ්‍යො
+ඪ්‍යෝ
+ඪ්‍යෞ
+ඪ්‍ය්
+ඪ්‍යං
+ඪ්‍යඃ
+ර්‍ඪ
+ර්‍ඪා
+ර්‍ඪැ
+ර්‍ඪෑ
+ර්‍ඪි
+ර්‍ඪී
+ර්‍ඪු
+ර්‍ඪූ
+ර්‍ඪෘ
+ර්‍ඪෲ
+ර්‍ඪෟ
+ර්‍ඪෳ
+ර්‍ඪෙ
+ර්‍ඪේ
+ර්‍ඪෛ
+ර්‍ඪො
+ර්‍ඪෝ
+ර්‍ඪෞ
+ර්‍ඪ්
+ර්‍ඪං
+ර්‍ඪඃ
+ණ
+ණා
+ණැ
+ණෑ
+ණි
+ණී
+ණු
+ණූ
+ණෘ
+ණෲ
+ණෟ
+ණෳ
+ණෙ
+ණේ
+ණෛ
+ණො
+ණෝ
+ණෞ
+ණ්
+ණං
+ණඃ
+ණ්‍ර
+ණ්‍රා
+ණ්‍රැ
+ණ්‍රෑ
+ණ්‍රි
+ණ්‍රී
+ණ්‍රු
+ණ්‍රූ
+ණ්‍රෘ
+ණ්‍රෲ
+ණ්‍රෟ
+ණ්‍රෳ
+ණ්‍රෙ
+ණ්‍රේ
+ණ්‍රෛ
+ණ්‍රො
+ණ්‍රෝ
+ණ්‍රෞ
+ණ්‍ර්
+ණ්‍රං
+ණ්‍රඃ
+ණ්‍ය
+ණ්‍යා
+ණ්‍යැ
+ණ්‍යෑ
+ණ්‍යි
+ණ්‍යී
+ණ්‍යු
+ණ්‍යූ
+ණ්‍යෘ
+ණ්‍යෲ
+ණ්‍යෟ
+ණ්‍යෳ
+ණ්‍යෙ
+ණ්‍යේ
+ණ්‍යෛ
+ණ්‍යො
+ණ්‍යෝ
+ණ්‍යෞ
+ණ්‍ය්
+ණ්‍යං
+ණ්‍යඃ
+ර්‍ණ
+ර්‍ණා
+ර්‍ණැ
+ර්‍ණෑ
+ර්‍ණි
+ර්‍ණී
+ර්‍ණු
+ර්‍ණූ
+ර්‍ණෘ
+ර්‍ණෲ
+ර්‍ණෟ
+ර්‍ණෳ
+ර්‍ණෙ
+ර්‍ණේ
+ර්‍ණෛ
+ර්‍ණො
+ර්‍ණෝ
+ර්‍ණෞ
+ර්‍ණ්
+ර්‍ණං
+ර්‍ණඃ
+ඬ
+ඬා
+ඬැ
+ඬෑ
+ඬි
+ඬී
+ඬු
+ඬූ
+ඬෘ
+ඬෲ
+ඬෟ
+ඬෳ
+ඬෙ
+ඬේ
+ඬෛ
+ඬො
+ඬෝ
+ඬෞ
+ඬ්
+ඬං
+ඬඃ
+ඬ්‍ර
+ඬ්‍රා
+ඬ්‍රැ
+ඬ්‍රෑ
+ඬ්‍රි
+ඬ්‍රී
+ඬ්‍රු
+ඬ්‍රූ
+ඬ්‍රෘ
+ඬ්‍රෲ
+ඬ්‍රෟ
+ඬ්‍රෳ
+ඬ්‍රෙ
+ඬ්‍රේ
+ඬ්‍රෛ
+ඬ්‍රො
+ඬ්‍රෝ
+ඬ්‍රෞ
+ඬ්‍ර්
+ඬ්‍රං
+ඬ්‍රඃ
+ඬ්‍ය
+ඬ්‍යා
+ඬ්‍යැ
+ඬ්‍යෑ
+ඬ්‍යි
+ඬ්‍යී
+ඬ්‍යු
+ඬ්‍යූ
+ඬ්‍යෘ
+ඬ්‍යෲ
+ඬ්‍යෟ
+ඬ්‍යෳ
+ඬ්‍යෙ
+ඬ්‍යේ
+ඬ්‍යෛ
+ඬ්‍යො
+ඬ්‍යෝ
+ඬ්‍යෞ
+ඬ්‍ය්
+ඬ්‍යං
+ඬ්‍යඃ
+ර්‍ඬ
+ර්‍ඬා
+ර්‍ඬැ
+ර්‍ඬෑ
+ර්‍ඬි
+ර්‍ඬී
+ර්‍ඬු
+ර්‍ඬූ
+ර්‍ඬෘ
+ර්‍ඬෲ
+ර්‍ඬෟ
+ර්‍ඬෳ
+ර්‍ඬෙ
+ර්‍ඬේ
+ර්‍ඬෛ
+ර්‍ඬො
+ර්‍ඬෝ
+ර්‍ඬෞ
+ර්‍ඬ්
+ර්‍ඬං
+ර්‍ඬඃ
+ත
+තා
+තැ
+තෑ
+ති
+තී
+තු
+තූ
+තෘ
+තෲ
+තෟ
+තෳ
+තෙ
+තේ
+තෛ
+තො
+තෝ
+තෞ
+ත්
+තං
+තඃ
+ත්‍ර
+ත්‍රා
+ත්‍රැ
+ත්‍රෑ
+ත්‍රි
+ත්‍රී
+ත්‍රු
+ත්‍රූ
+ත්‍රෘ
+ත්‍රෲ
+ත්‍රෟ
+ත්‍රෳ
+ත්‍රෙ
+ත්‍රේ
+ත්‍රෛ
+ත්‍රො
+ත්‍රෝ
+ත්‍රෞ
+ත්‍ර්
+ත්‍රං
+ත්‍රඃ
+ත්‍ය
+ත්‍යා
+ත්‍යැ
+ත්‍යෑ
+ත්‍යි
+ත්‍යී
+ත්‍යු
+ත්‍යූ
+ත්‍යෘ
+ත්‍යෲ
+ත්‍යෟ
+ත්‍යෳ
+ත්‍යෙ
+ත්‍යේ
+ත්‍යෛ
+ත්‍යො
+ත්‍යෝ
+ත්‍යෞ
+ත්‍ය්
+ත්‍යං
+ත්‍යඃ
+ර්‍ත
+ර්‍තා
+ර්‍තැ
+ර්‍තෑ
+ර්‍ති
+ර්‍තී
+ර්‍තු
+ර්‍තූ
+ර්‍තෘ
+ර්‍තෲ
+ර්‍තෟ
+ර්‍තෳ
+ර්‍තෙ
+ර්‍තේ
+ර්‍තෛ
+ර්‍තො
+ර්‍තෝ
+ර්‍තෞ
+ර්‍ත්
+ර්‍තං
+ර්‍තඃ
+ථ
+ථා
+ථැ
+ථෑ
+ථි
+ථී
+ථු
+ථූ
+ථෘ
+ථෲ
+ථෟ
+ථෳ
+ථෙ
+ථේ
+ථෛ
+ථො
+ථෝ
+ථෞ
+ථ්
+ථං
+ථඃ
+ථ්‍ර
+ථ්‍රා
+ථ්‍රැ
+ථ්‍රෑ
+ථ්‍රි
+ථ්‍රී
+ථ්‍රු
+ථ්‍රූ
+ථ්‍රෘ
+ථ්‍රෲ
+ථ්‍රෟ
+ථ්‍රෳ
+ථ්‍රෙ
+ථ්‍රේ
+ථ්‍රෛ
+ථ්‍රො
+ථ්‍රෝ
+ථ්‍රෞ
+ථ්‍ර්
+ථ්‍රං
+ථ්‍රඃ
+ථ්‍ය
+ථ්‍යා
+ථ්‍යැ
+ථ්‍යෑ
+ථ්‍යි
+ථ්‍යී
+ථ්‍යු
+ථ්‍යූ
+ථ්‍යෘ
+ථ්‍යෲ
+ථ්‍යෟ
+ථ්‍යෳ
+ථ්‍යෙ
+ථ්‍යේ
+ථ්‍යෛ
+ථ්‍යො
+ථ්‍යෝ
+ථ්‍යෞ
+ථ්‍ය්
+ථ්‍යං
+ථ්‍යඃ
+ර්‍ථ
+ර්‍ථා
+ර්‍ථැ
+ර්‍ථෑ
+ර්‍ථි
+ර්‍ථී
+ර්‍ථු
+ර්‍ථූ
+ර්‍ථෘ
+ර්‍ථෲ
+ර්‍ථෟ
+ර්‍ථෳ
+ර්‍ථෙ
+ර්‍ථේ
+ර්‍ථෛ
+ර්‍ථො
+ර්‍ථෝ
+ර්‍ථෞ
+ර්‍ථ්
+ර්‍ථං
+ර්‍ථඃ
+ද
+දා
+දැ
+දෑ
+දි
+දී
+දු
+දූ
+දෘ
+දෲ
+දෟ
+දෳ
+දෙ
+දේ
+දෛ
+දො
+දෝ
+දෞ
+ද්
+දං
+දඃ
+ද්‍ර
+ද්‍රා
+ද්‍රැ
+ද්‍රෑ
+ද්‍රි
+ද්‍රී
+ද්‍රු
+ද්‍රූ
+ද්‍රෘ
+ද්‍රෲ
+ද්‍රෟ
+ද්‍රෳ
+ද්‍රෙ
+ද්‍රේ
+ද්‍රෛ
+ද්‍රො
+ද්‍රෝ
+ද්‍රෞ
+ද්‍ර්
+ද්‍රං
+ද්‍රඃ
+ද්‍ය
+ද්‍යා
+ද්‍යැ
+ද්‍යෑ
+ද්‍යි
+ද්‍යී
+ද්‍යු
+ද්‍යූ
+ද්‍යෘ
+ද්‍යෲ
+ද්‍යෟ
+ද්‍යෳ
+ද්‍යෙ
+ද්‍යේ
+ද්‍යෛ
+ද්‍යො
+ද්‍යෝ
+ද්‍යෞ
+ද්‍ය්
+ද්‍යං
+ද්‍යඃ
+ර්‍ද
+ර්‍දා
+ර්‍දැ
+ර්‍දෑ
+ර්‍දි
+ර්‍දී
+ර්‍දු
+ර්‍දූ
+ර්‍දෘ
+ර්‍දෲ
+ර්‍දෟ
+ර්‍දෳ
+ර්‍දෙ
+ර්‍දේ
+ර්‍දෛ
+ර්‍දො
+ර්‍දෝ
+ර්‍දෞ
+ර්‍ද්
+ර්‍දං
+ර්‍දඃ
+ධ
+ධා
+ධැ
+ධෑ
+ධි
+ධී
+ධු
+ධූ
+ධෘ
+ධෲ
+ධෟ
+ධෳ
+ධෙ
+ධේ
+ධෛ
+ධො
+ධෝ
+ධෞ
+ධ්
+ධං
+ධඃ
+ධ්‍ර
+ධ්‍රා
+ධ්‍රැ
+ධ්‍රෑ
+ධ්‍රි
+ධ්‍රී
+ධ්‍රු
+ධ්‍රූ
+ධ්‍රෘ
+ධ්‍රෲ
+ධ්‍රෟ
+ධ්‍රෳ
+ධ්‍රෙ
+ධ්‍රේ
+ධ්‍රෛ
+ධ්‍රො
+ධ්‍රෝ
+ධ්‍රෞ
+ධ්‍ර්
+ධ්‍රං
+ධ්‍රඃ
+ධ්‍ය
+ධ්‍යා
+ධ්‍යැ
+ධ්‍යෑ
+ධ්‍යි
+ධ්‍යී
+ධ්‍යු
+ධ්‍යූ
+ධ්‍යෘ
+ධ්‍යෲ
+ධ්‍යෟ
+ධ්‍යෳ
+ධ්‍යෙ
+ධ්‍යේ
+ධ්‍යෛ
+ධ්‍යො
+ධ්‍යෝ
+ධ්‍යෞ
+ධ්‍ය්
+ධ්‍යං
+ධ්‍යඃ
+ර්‍ධ
+ර්‍ධා
+ර්‍ධැ
+ර්‍ධෑ
+ර්‍ධි
+ර්‍ධී
+ර්‍ධු
+ර්‍ධූ
+ර්‍ධෘ
+ර්‍ධෲ
+ර්‍ධෟ
+ර්‍ධෳ
+ර්‍ධෙ
+ර්‍ධේ
+ර්‍ධෛ
+ර්‍ධො
+ර්‍ධෝ
+ර්‍ධෞ
+ර්‍ධ්
+ර්‍ධං
+ර්‍ධඃ
+න
+නා
+නැ
+නෑ
+නි
+නී
+නු
+නූ
+නෘ
+නෲ
+නෟ
+නෳ
+නෙ
+නේ
+නෛ
+නො
+නෝ
+නෞ
+න්
+නං
+නඃ
+න්‍ර
+න්‍රා
+න්‍රැ
+න්‍රෑ
+න්‍රි
+න්‍රී
+න්‍රු
+න්‍රූ
+න්‍රෘ
+න්‍රෲ
+න්‍රෟ
+න්‍රෳ
+න්‍රෙ
+න්‍රේ
+න්‍රෛ
+න්‍රො
+න්‍රෝ
+න්‍රෞ
+න්‍ර්
+න්‍රං
+න්‍රඃ
+න්‍ය
+න්‍යා
+න්‍යැ
+න්‍යෑ
+න්‍යි
+න්‍යී
+න්‍යු
+න්‍යූ
+න්‍යෘ
+න්‍යෲ
+න්‍යෟ
+න්‍යෳ
+න්‍යෙ
+න්‍යේ
+න්‍යෛ
+න්‍යො
+න්‍යෝ
+න්‍යෞ
+න්‍ය්
+න්‍යං
+න්‍යඃ
+ර්‍න
+ර්‍නා
+ර්‍නැ
+ර්‍නෑ
+ර්‍නි
+ර්‍නී
+ර්‍නු
+ර්‍නූ
+ර්‍නෘ
+ර්‍නෲ
+ර්‍නෟ
+ර්‍නෳ
+ර්‍නෙ
+ර්‍නේ
+ර්‍නෛ
+ර්‍නො
+ර්‍නෝ
+ර්‍නෞ
+ර්‍න්
+ර්‍නං
+ර්‍නඃ
+ඳ
+ඳා
+ඳැ
+ඳෑ
+ඳි
+ඳී
+ඳු
+ඳූ
+ඳෘ
+ඳෲ
+ඳෟ
+ඳෳ
+ඳෙ
+ඳේ
+ඳෛ
+ඳො
+ඳෝ
+ඳෞ
+ඳ්
+ඳං
+ඳඃ
+ඳ්‍ර
+ඳ්‍රා
+ඳ්‍රැ
+ඳ්‍රෑ
+ඳ්‍රි
+ඳ්‍රී
+ඳ්‍රු
+ඳ්‍රූ
+ඳ්‍රෘ
+ඳ්‍රෲ
+ඳ්‍රෟ
+ඳ්‍රෳ
+ඳ්‍රෙ
+ඳ්‍රේ
+ඳ්‍රෛ
+ඳ්‍රො
+ඳ්‍රෝ
+ඳ්‍රෞ
+ඳ්‍ර්
+ඳ්‍රං
+ඳ්‍රඃ
+ඳ්‍ය
+ඳ්‍යා
+ඳ්‍යැ
+ඳ්‍යෑ
+ඳ්‍යි
+ඳ්‍යී
+ඳ්‍යු
+ඳ්‍යූ
+ඳ්‍යෘ
+ඳ්‍යෲ
+ඳ්‍යෟ
+ඳ්‍යෳ
+ඳ්‍යෙ
+ඳ්‍යේ
+ඳ්‍යෛ
+ඳ්‍යො
+ඳ්‍යෝ
+ඳ්‍යෞ
+ඳ්‍ය්
+ඳ්‍යං
+ඳ්‍යඃ
+ර්‍ඳ
+ර්‍ඳා
+ර්‍ඳැ
+ර්‍ඳෑ
+ර්‍ඳි
+ර්‍ඳී
+ර්‍ඳු
+ර්‍ඳූ
+ර්‍ඳෘ
+ර්‍ඳෲ
+ර්‍ඳෟ
+ර්‍ඳෳ
+ර්‍ඳෙ
+ර්‍ඳේ
+ර්‍ඳෛ
+ර්‍ඳො
+ර්‍ඳෝ
+ර්‍ඳෞ
+ර්‍ඳ්
+ර්‍ඳං
+ර්‍ඳඃ
+ප
+පා
+පැ
+පෑ
+පි
+පී
+පු
+පූ
+පෘ
+පෲ
+පෟ
+පෳ
+පෙ
+පේ
+පෛ
+පො
+පෝ
+පෞ
+ප්
+පං
+පඃ
+ප්‍ර
+ප්‍රා
+ප්‍රැ
+ප්‍රෑ
+ප්‍රි
+ප්‍රී
+ප්‍රු
+ප්‍රූ
+ප්‍රෘ
+ප්‍රෲ
+ප්‍රෟ
+ප්‍රෳ
+ප්‍රෙ
+ප්‍රේ
+ප්‍රෛ
+ප්‍රො
+ප්‍රෝ
+ප්‍රෞ
+ප්‍ර්
+ප්‍රං
+ප්‍රඃ
+ප්‍ය
+ප්‍යා
+ප්‍යැ
+ප්‍යෑ
+ප්‍යි
+ප්‍යී
+ප්‍යු
+ප්‍යූ
+ප්‍යෘ
+ප්‍යෲ
+ප්‍යෟ
+ප්‍යෳ
+ප්‍යෙ
+ප්‍යේ
+ප්‍යෛ
+ප්‍යො
+ප්‍යෝ
+ප්‍යෞ
+ප්‍ය්
+ප්‍යං
+ප්‍යඃ
+ර්‍ප
+ර්‍පා
+ර්‍පැ
+ර්‍පෑ
+ර්‍පි
+ර්‍පී
+ර්‍පු
+ර්‍පූ
+ර්‍පෘ
+ර්‍පෲ
+ර්‍පෟ
+ර්‍පෳ
+ර්‍පෙ
+ර්‍පේ
+ර්‍පෛ
+ර්‍පො
+ර්‍පෝ
+ර්‍පෞ
+ර්‍ප්
+ර්‍පං
+ර්‍පඃ
+ඵ
+ඵා
+ඵැ
+ඵෑ
+ඵි
+ඵී
+ඵු
+ඵූ
+ඵෘ
+ඵෲ
+ඵෟ
+ඵෳ
+ඵෙ
+ඵේ
+ඵෛ
+ඵො
+ඵෝ
+ඵෞ
+ඵ්
+ඵං
+ඵඃ
+ඵ්‍ර
+ඵ්‍රා
+ඵ්‍රැ
+ඵ්‍රෑ
+ඵ්‍රි
+ඵ්‍රී
+ඵ්‍රු
+ඵ්‍රූ
+ඵ්‍රෘ
+ඵ්‍රෲ
+ඵ්‍රෟ
+ඵ්‍රෳ
+ඵ්‍රෙ
+ඵ්‍රේ
+ඵ්‍රෛ
+ඵ්‍රො
+ඵ්‍රෝ
+ඵ්‍රෞ
+ඵ්‍ර්
+ඵ්‍රං
+ඵ්‍රඃ
+ඵ්‍ය
+ඵ්‍යා
+ඵ්‍යැ
+ඵ්‍යෑ
+ඵ්‍යි
+ඵ්‍යී
+ඵ්‍යු
+ඵ්‍යූ
+ඵ්‍යෘ
+ඵ්‍යෲ
+ඵ්‍යෟ
+ඵ්‍යෳ
+ඵ්‍යෙ
+ඵ්‍යේ
+ඵ්‍යෛ
+ඵ්‍යො
+ඵ්‍යෝ
+ඵ්‍යෞ
+ඵ්‍ය්
+ඵ්‍යං
+ඵ්‍යඃ
+ර්‍ඵ
+ර්‍ඵා
+ර්‍ඵැ
+ර්‍ඵෑ
+ර්‍ඵි
+ර්‍ඵී
+ර්‍ඵු
+ර්‍ඵූ
+ර්‍ඵෘ
+ර්‍ඵෲ
+ර්‍ඵෟ
+ර්‍ඵෳ
+ර්‍ඵෙ
+ර්‍ඵේ
+ර්‍ඵෛ
+ර්‍ඵො
+ර්‍ඵෝ
+ර්‍ඵෞ
+ර්‍ඵ්
+ර්‍ඵං
+ර්‍ඵඃ
+බ
+බා
+බැ
+බෑ
+බි
+බී
+බු
+බූ
+බෘ
+බෲ
+බෟ
+බෳ
+බෙ
+බේ
+බෛ
+බො
+බෝ
+බෞ
+බ්
+බං
+බඃ
+බ්‍ර
+බ්‍රා
+බ්‍රැ
+බ්‍රෑ
+බ්‍රි
+බ්‍රී
+බ්‍රු
+බ්‍රූ
+බ්‍රෘ
+බ්‍රෲ
+බ්‍රෟ
+බ්‍රෳ
+බ්‍රෙ
+බ්‍රේ
+බ්‍රෛ
+බ්‍රො
+බ්‍රෝ
+බ්‍රෞ
+බ්‍ර්
+බ්‍රං
+බ්‍රඃ
+බ්‍ය
+බ්‍යා
+බ්‍යැ
+බ්‍යෑ
+බ්‍යි
+බ්‍යී
+බ්‍යු
+බ්‍යූ
+බ්‍යෘ
+බ්‍යෲ
+බ්‍යෟ
+බ්‍යෳ
+බ්‍යෙ
+බ්‍යේ
+බ්‍යෛ
+බ්‍යො
+බ්‍යෝ
+බ්‍යෞ
+බ්‍ය්
+බ්‍යං
+බ්‍යඃ
+ර්‍බ
+ර්‍බා
+ර්‍බැ
+ර්‍බෑ
+ර්‍බි
+ර්‍බී
+ර්‍බු
+ර්‍බූ
+ර්‍බෘ
+ර්‍බෲ
+ර්‍බෟ
+ර්‍බෳ
+ර්‍බෙ
+ර්‍බේ
+ර්‍බෛ
+ර්‍බො
+ර්‍බෝ
+ර්‍බෞ
+ර්‍බ්
+ර්‍බං
+ර්‍බඃ
+භ
+භා
+භැ
+භෑ
+භි
+භී
+භු
+භූ
+භෘ
+භෲ
+භෟ
+භෳ
+භෙ
+භේ
+භෛ
+භො
+භෝ
+භෞ
+භ්
+භං
+භඃ
+භ්‍ර
+භ්‍රා
+භ්‍රැ
+භ්‍රෑ
+භ්‍රි
+භ්‍රී
+භ්‍රු
+භ්‍රූ
+භ්‍රෘ
+භ්‍රෲ
+භ්‍රෟ
+භ්‍රෳ
+භ්‍රෙ
+භ්‍රේ
+භ්‍රෛ
+භ්‍රො
+භ්‍රෝ
+භ්‍රෞ
+භ්‍ර්
+භ්‍රං
+භ්‍රඃ
+භ්‍ය
+භ්‍යා
+භ්‍යැ
+භ්‍යෑ
+භ්‍යි
+භ්‍යී
+භ්‍යු
+භ්‍යූ
+භ්‍යෘ
+භ්‍යෲ
+භ්‍යෟ
+භ්‍යෳ
+භ්‍යෙ
+භ්‍යේ
+භ්‍යෛ
+භ්‍යො
+භ්‍යෝ
+භ්‍යෞ
+භ්‍ය්
+භ්‍යං
+භ්‍යඃ
+ර්‍භ
+ර්‍භා
+ර්‍භැ
+ර්‍භෑ
+ර්‍භි
+ර්‍භී
+ර්‍භු
+ර්‍භූ
+ර්‍භෘ
+ර්‍භෲ
+ර්‍භෟ
+ර්‍භෳ
+ර්‍භෙ
+ර්‍භේ
+ර්‍භෛ
+ර්‍භො
+ර්‍භෝ
+ර්‍භෞ
+ර්‍භ්
+ර්‍භං
+ර්‍භඃ
+ම
+මා
+මැ
+මෑ
+මි
+මී
+මු
+මූ
+මෘ
+මෲ
+මෟ
+මෳ
+මෙ
+මේ
+මෛ
+මො
+මෝ
+මෞ
+ම්
+මං
+මඃ
+ම්‍ර
+ම්‍රා
+ම්‍රැ
+ම්‍රෑ
+ම්‍රි
+ම්‍රී
+ම්‍රු
+ම්‍රූ
+ම්‍රෘ
+ම්‍රෲ
+ම්‍රෟ
+ම්‍රෳ
+ම්‍රෙ
+ම්‍රේ
+ම්‍රෛ
+ම්‍රො
+ම්‍රෝ
+ම්‍රෞ
+ම්‍ර්
+ම්‍රං
+ම්‍රඃ
+ම්‍ය
+ම්‍යා
+ම්‍යැ
+ම්‍යෑ
+ම්‍යි
+ම්‍යී
+ම්‍යු
+ම්‍යූ
+ම්‍යෘ
+ම්‍යෲ
+ම්‍යෟ
+ම්‍යෳ
+ම්‍යෙ
+ම්‍යේ
+ම්‍යෛ
+ම්‍යො
+ම්‍යෝ
+ම්‍යෞ
+ම්‍ය්
+ම්‍යං
+ම්‍යඃ
+ර්‍ම
+ර්‍මා
+ර්‍මැ
+ර්‍මෑ
+ර්‍මි
+ර්‍මී
+ර්‍මු
+ර්‍මූ
+ර්‍මෘ
+ර්‍මෲ
+ර්‍මෟ
+ර්‍මෳ
+ර්‍මෙ
+ර්‍මේ
+ර්‍මෛ
+ර්‍මො
+ර්‍මෝ
+ර්‍මෞ
+ර්‍ම්
+ර්‍මං
+ර්‍මඃ
+ඹ
+ඹා
+ඹැ
+ඹෑ
+ඹි
+ඹී
+ඹු
+ඹූ
+ඹෘ
+ඹෲ
+ඹෟ
+ඹෳ
+ඹෙ
+ඹේ
+ඹෛ
+ඹො
+ඹෝ
+ඹෞ
+ඹ්
+ඹං
+ඹඃ
+ඹ්‍ර
+ඹ්‍රා
+ඹ්‍රැ
+ඹ්‍රෑ
+ඹ්‍රි
+ඹ්‍රී
+ඹ්‍රු
+ඹ්‍රූ
+ඹ්‍රෘ
+ඹ්‍රෲ
+ඹ්‍රෟ
+ඹ්‍රෳ
+ඹ්‍රෙ
+ඹ්‍රේ
+ඹ්‍රෛ
+ඹ්‍රො
+ඹ්‍රෝ
+ඹ්‍රෞ
+ඹ්‍ර්
+ඹ්‍රං
+ඹ්‍රඃ
+ඹ්‍ය
+ඹ්‍යා
+ඹ්‍යැ
+ඹ්‍යෑ
+ඹ්‍යි
+ඹ්‍යී
+ඹ්‍යු
+ඹ්‍යූ
+ඹ්‍යෘ
+ඹ්‍යෲ
+ඹ්‍යෟ
+ඹ්‍යෳ
+ඹ්‍යෙ
+ඹ්‍යේ
+ඹ්‍යෛ
+ඹ්‍යො
+ඹ්‍යෝ
+ඹ්‍යෞ
+ඹ්‍ය්
+ඹ්‍යං
+ඹ්‍යඃ
+ර්‍ඹ
+ර්‍ඹා
+ර්‍ඹැ
+ර්‍ඹෑ
+ර්‍ඹි
+ර්‍ඹී
+ර්‍ඹු
+ර්‍ඹූ
+ර්‍ඹෘ
+ර්‍ඹෲ
+ර්‍ඹෟ
+ර්‍ඹෳ
+ර්‍ඹෙ
+ර්‍ඹේ
+ර්‍ඹෛ
+ර්‍ඹො
+ර්‍ඹෝ
+ර්‍ඹෞ
+ර්‍ඹ්
+ර්‍ඹං
+ර්‍ඹඃ
+ය
+යා
+යැ
+යෑ
+යි
+යී
+යු
+යූ
+යෘ
+යෲ
+යෟ
+යෳ
+යෙ
+යේ
+යෛ
+යො
+යෝ
+යෞ
+ය්
+යං
+යඃ
+ය්‍ර
+ය්‍රා
+ය්‍රැ
+ය්‍රෑ
+ය්‍රි
+ය්‍රී
+ය්‍රු
+ය්‍රූ
+ය්‍රෘ
+ය්‍රෲ
+ය්‍රෟ
+ය්‍රෳ
+ය්‍රෙ
+ය්‍රේ
+ය්‍රෛ
+ය්‍රො
+ය්‍රෝ
+ය්‍රෞ
+ය්‍ර්
+ය්‍රං
+ය්‍රඃ
+ය්‍ය
+ය්‍යා
+ය්‍යැ
+ය්‍යෑ
+ය්‍යි
+ය්‍යී
+ය්‍යු
+ය්‍යූ
+ය්‍යෘ
+ය්‍යෲ
+ය්‍යෟ
+ය්‍යෳ
+ය්‍යෙ
+ය්‍යේ
+ය්‍යෛ
+ය්‍යො
+ය්‍යෝ
+ය්‍යෞ
+ය්‍ය්
+ය්‍යං
+ය්‍යඃ
+ර්‍ය
+ර්‍යා
+ර්‍යැ
+ර්‍යෑ
+ර්‍යි
+ර්‍යී
+ර්‍යු
+ර්‍යූ
+ර්‍යෘ
+ර්‍යෲ
+ර්‍යෟ
+ර්‍යෳ
+ර්‍යෙ
+ර්‍යේ
+ර්‍යෛ
+ර්‍යො
+ර්‍යෝ
+ර්‍යෞ
+ර්‍ය්
+ර්‍යං
+ර්‍යඃ
+ර
+රා
+රැ
+රෑ
+රි
+රී
+රු
+රූ
+රෘ
+රෲ
+රෟ
+රෳ
+රෙ
+රේ
+රෛ
+රො
+රෝ
+රෞ
+ර්
+රං
+රඃ
+ර්‍ර
+ර්‍රා
+ර්‍රැ
+ර්‍රෑ
+ර්‍රි
+ර්‍රී
+ර්‍රු
+ර්‍රූ
+ර්‍රෘ
+ර්‍රෲ
+ර්‍රෟ
+ර්‍රෳ
+ර්‍රෙ
+ර්‍රේ
+ර්‍රෛ
+ර්‍රො
+ර්‍රෝ
+ර්‍රෞ
+ර්‍ර්
+ර්‍රං
+ර්‍රඃ
+ර්‍ය
+ර්‍යා
+ර්‍යැ
+ර්‍යෑ
+ර්‍යි
+ර්‍යී
+ර්‍යු
+ර්‍යූ
+ර්‍යෘ
+ර්‍යෲ
+ර්‍යෟ
+ර්‍යෳ
+ර්‍යෙ
+ර්‍යේ
+ර්‍යෛ
+ර්‍යො
+ර්‍යෝ
+ර්‍යෞ
+ර්‍ය්
+ර්‍යං
+ර්‍යඃ
+ර්‍ර
+ර්‍රා
+ර්‍රැ
+ර්‍රෑ
+ර්‍රි
+ර්‍රී
+ර්‍රු
+ර්‍රූ
+ර්‍රෘ
+ර්‍රෲ
+ර්‍රෟ
+ර්‍රෳ
+ර්‍රෙ
+ර්‍රේ
+ර්‍රෛ
+ර්‍රො
+ර්‍රෝ
+ර්‍රෞ
+ර්‍ර්
+ර්‍රං
+ර්‍රඃ
+ල
+ලා
+ලැ
+ලෑ
+ලි
+ලී
+ලු
+ලූ
+ලෘ
+ලෲ
+ලෟ
+ලෳ
+ලෙ
+ලේ
+ලෛ
+ලො
+ලෝ
+ලෞ
+ල්
+ලං
+ලඃ
+ල්‍ර
+ල්‍රා
+ල්‍රැ
+ල්‍රෑ
+ල්‍රි
+ල්‍රී
+ල්‍රු
+ල්‍රූ
+ල්‍රෘ
+ල්‍රෲ
+ල්‍රෟ
+ල්‍රෳ
+ල්‍රෙ
+ල්‍රේ
+ල්‍රෛ
+ල්‍රො
+ල්‍රෝ
+ල්‍රෞ
+ල්‍ර්
+ල්‍රං
+ල්‍රඃ
+ල්‍ය
+ල්‍යා
+ල්‍යැ
+ල්‍යෑ
+ල්‍යි
+ල්‍යී
+ල්‍යු
+ල්‍යූ
+ල්‍යෘ
+ල්‍යෲ
+ල්‍යෟ
+ල්‍යෳ
+ල්‍යෙ
+ල්‍යේ
+ල්‍යෛ
+ල්‍යො
+ල්‍යෝ
+ල්‍යෞ
+ල්‍ය්
+ල්‍යං
+ල්‍යඃ
+ර්‍ල
+ර්‍ලා
+ර්‍ලැ
+ර්‍ලෑ
+ර්‍ලි
+ර්‍ලී
+ර්‍ලු
+ර්‍ලූ
+ර්‍ලෘ
+ර්‍ලෲ
+ර්‍ලෟ
+ර්‍ලෳ
+ර්‍ලෙ
+ර්‍ලේ
+ර්‍ලෛ
+ර්‍ලො
+ර්‍ලෝ
+ර්‍ලෞ
+ර්‍ල්
+ර්‍ලං
+ර්‍ලඃ
+ව
+වා
+වැ
+වෑ
+වි
+වී
+වු
+වූ
+වෘ
+වෲ
+වෟ
+වෳ
+වෙ
+වේ
+වෛ
+වො
+වෝ
+වෞ
+ව්
+වං
+වඃ
+ව්‍ර
+ව්‍රා
+ව්‍රැ
+ව්‍රෑ
+ව්‍රි
+ව්‍රී
+ව්‍රු
+ව්‍රූ
+ව්‍රෘ
+ව්‍රෲ
+ව්‍රෟ
+ව්‍රෳ
+ව්‍රෙ
+ව්‍රේ
+ව්‍රෛ
+ව්‍රො
+ව්‍රෝ
+ව්‍රෞ
+ව්‍ර්
+ව්‍රං
+ව්‍රඃ
+ව්‍ය
+ව්‍යා
+ව්‍යැ
+ව්‍යෑ
+ව්‍යි
+ව්‍යී
+ව්‍යු
+ව්‍යූ
+ව්‍යෘ
+ව්‍යෲ
+ව්‍යෟ
+ව්‍යෳ
+ව්‍යෙ
+ව්‍යේ
+ව්‍යෛ
+ව්‍යො
+ව්‍යෝ
+ව්‍යෞ
+ව්‍ය්
+ව්‍යං
+ව්‍යඃ
+ර්‍ව
+ර්‍වා
+ර්‍වැ
+ර්‍වෑ
+ර්‍වි
+ර්‍වී
+ර්‍වු
+ර්‍වූ
+ර්‍වෘ
+ර්‍වෲ
+ර්‍වෟ
+ර්‍වෳ
+ර්‍වෙ
+ර්‍වේ
+ර්‍වෛ
+ර්‍වො
+ර්‍වෝ
+ර්‍වෞ
+ර්‍ව්
+ර්‍වං
+ර්‍වඃ
+ශ
+ශා
+ශැ
+ශෑ
+ශි
+ශී
+ශු
+ශූ
+ශෘ
+ශෲ
+ශෟ
+ශෳ
+ශෙ
+ශේ
+ශෛ
+ශො
+ශෝ
+ශෞ
+ශ්
+ශං
+ශඃ
+ශ්‍ර
+ශ්‍රා
+ශ්‍රැ
+ශ්‍රෑ
+ශ්‍රි
+ශ්‍රී
+ශ්‍රු
+ශ්‍රූ
+ශ්‍රෘ
+ශ්‍රෲ
+ශ්‍රෟ
+ශ්‍රෳ
+ශ්‍රෙ
+ශ්‍රේ
+ශ්‍රෛ
+ශ්‍රො
+ශ්‍රෝ
+ශ්‍රෞ
+ශ්‍ර්
+ශ්‍රං
+ශ්‍රඃ
+ශ්‍ය
+ශ්‍යා
+ශ්‍යැ
+ශ්‍යෑ
+ශ්‍යි
+ශ්‍යී
+ශ්‍යු
+ශ්‍යූ
+ශ්‍යෘ
+ශ්‍යෲ
+ශ්‍යෟ
+ශ්‍යෳ
+ශ්‍යෙ
+ශ්‍යේ
+ශ්‍යෛ
+ශ්‍යො
+ශ්‍යෝ
+ශ්‍යෞ
+ශ්‍ය්
+ශ්‍යං
+ශ්‍යඃ
+ර්‍ශ
+ර්‍ශා
+ර්‍ශැ
+ර්‍ශෑ
+ර්‍ශි
+ර්‍ශී
+ර්‍ශු
+ර්‍ශූ
+ර්‍ශෘ
+ර්‍ශෲ
+ර්‍ශෟ
+ර්‍ශෳ
+ර්‍ශෙ
+ර්‍ශේ
+ර්‍ශෛ
+ර්‍ශො
+ර්‍ශෝ
+ර්‍ශෞ
+ර්‍ශ්
+ර්‍ශං
+ර්‍ශඃ
+ෂ
+ෂා
+ෂැ
+ෂෑ
+ෂි
+ෂී
+ෂු
+ෂූ
+ෂෘ
+ෂෲ
+ෂෟ
+ෂෳ
+ෂෙ
+ෂේ
+ෂෛ
+ෂො
+ෂෝ
+ෂෞ
+ෂ්
+ෂං
+ෂඃ
+ෂ්‍ර
+ෂ්‍රා
+ෂ්‍රැ
+ෂ්‍රෑ
+ෂ්‍රි
+ෂ්‍රී
+ෂ්‍රු
+ෂ්‍රූ
+ෂ්‍රෘ
+ෂ්‍රෲ
+ෂ්‍රෟ
+ෂ්‍රෳ
+ෂ්‍රෙ
+ෂ්‍රේ
+ෂ්‍රෛ
+ෂ්‍රො
+ෂ්‍රෝ
+ෂ්‍රෞ
+ෂ්‍ර්
+ෂ්‍රං
+ෂ්‍රඃ
+ෂ්‍ය
+ෂ්‍යා
+ෂ්‍යැ
+ෂ්‍යෑ
+ෂ්‍යි
+ෂ්‍යී
+ෂ්‍යු
+ෂ්‍යූ
+ෂ්‍යෘ
+ෂ්‍යෲ
+ෂ්‍යෟ
+ෂ්‍යෳ
+ෂ්‍යෙ
+ෂ්‍යේ
+ෂ්‍යෛ
+ෂ්‍යො
+ෂ්‍යෝ
+ෂ්‍යෞ
+ෂ්‍ය්
+ෂ්‍යං
+ෂ්‍යඃ
+ර්‍ෂ
+ර්‍ෂා
+ර්‍ෂැ
+ර්‍ෂෑ
+ර්‍ෂි
+ර්‍ෂී
+ර්‍ෂු
+ර්‍ෂූ
+ර්‍ෂෘ
+ර්‍ෂෲ
+ර්‍ෂෟ
+ර්‍ෂෳ
+ර්‍ෂෙ
+ර්‍ෂේ
+ර්‍ෂෛ
+ර්‍ෂො
+ර්‍ෂෝ
+ර්‍ෂෞ
+ර්‍ෂ්
+ර්‍ෂං
+ර්‍ෂඃ
+ස
+සා
+සැ
+සෑ
+සි
+සී
+සු
+සූ
+සෘ
+සෲ
+සෟ
+සෳ
+සෙ
+සේ
+සෛ
+සො
+සෝ
+සෞ
+ස්
+සං
+සඃ
+ස්‍ර
+ස්‍රා
+ස්‍රැ
+ස්‍රෑ
+ස්‍රි
+ස්‍රී
+ස්‍රු
+ස්‍රූ
+ස්‍රෘ
+ස්‍රෲ
+ස්‍රෟ
+ස්‍රෳ
+ස්‍රෙ
+ස්‍රේ
+ස්‍රෛ
+ස්‍රො
+ස්‍රෝ
+ස්‍රෞ
+ස්‍ර්
+ස්‍රං
+ස්‍රඃ
+ස්‍ය
+ස්‍යා
+ස්‍යැ
+ස්‍යෑ
+ස්‍යි
+ස්‍යී
+ස්‍යු
+ස්‍යූ
+ස්‍යෘ
+ස්‍යෲ
+ස්‍යෟ
+ස්‍යෳ
+ස්‍යෙ
+ස්‍යේ
+ස්‍යෛ
+ස්‍යො
+ස්‍යෝ
+ස්‍යෞ
+ස්‍ය්
+ස්‍යං
+ස්‍යඃ
+ර්‍ස
+ර්‍සා
+ර්‍සැ
+ර්‍සෑ
+ර්‍සි
+ර්‍සී
+ර්‍සු
+ර්‍සූ
+ර්‍සෘ
+ර්‍සෲ
+ර්‍සෟ
+ර්‍සෳ
+ර්‍සෙ
+ර්‍සේ
+ර්‍සෛ
+ර්‍සො
+ර්‍සෝ
+ර්‍සෞ
+ර්‍ස්
+ර්‍සං
+ර්‍සඃ
+හ
+හා
+හැ
+හෑ
+හි
+හී
+හු
+හූ
+හෘ
+හෲ
+හෟ
+හෳ
+හෙ
+හේ
+හෛ
+හො
+හෝ
+හෞ
+හ්
+හං
+හඃ
+හ්‍ර
+හ්‍රා
+හ්‍රැ
+හ්‍රෑ
+හ්‍රි
+හ්‍රී
+හ්‍රු
+හ්‍රූ
+හ්‍රෘ
+හ්‍රෲ
+හ්‍රෟ
+හ්‍රෳ
+හ්‍රෙ
+හ්‍රේ
+හ්‍රෛ
+හ්‍රො
+හ්‍රෝ
+හ්‍රෞ
+හ්‍ර්
+හ්‍රං
+හ්‍රඃ
+හ්‍ය
+හ්‍යා
+හ්‍යැ
+හ්‍යෑ
+හ්‍යි
+හ්‍යී
+හ්‍යු
+හ්‍යූ
+හ්‍යෘ
+හ්‍යෲ
+හ්‍යෟ
+හ්‍යෳ
+හ්‍යෙ
+හ්‍යේ
+හ්‍යෛ
+හ්‍යො
+හ්‍යෝ
+හ්‍යෞ
+හ්‍ය්
+හ්‍යං
+හ්‍යඃ
+ර්‍හ
+ර්‍හා
+ර්‍හැ
+ර්‍හෑ
+ර්‍හි
+ර්‍හී
+ර්‍හු
+ර්‍හූ
+ර්‍හෘ
+ර්‍හෲ
+ර්‍හෟ
+ර්‍හෳ
+ර්‍හෙ
+ර්‍හේ
+ර්‍හෛ
+ර්‍හො
+ර්‍හෝ
+ර්‍හෞ
+ර්‍හ්
+ර්‍හං
+ර්‍හඃ
+ළ
+ළා
+ළැ
+ළෑ
+ළි
+ළී
+ළු
+ළූ
+ළෘ
+ළෲ
+ළෟ
+ළෳ
+ළෙ
+ළේ
+ළෛ
+ළො
+ළෝ
+ළෞ
+ළ්
+ළං
+ළඃ
+ළ්‍ර
+ළ්‍රා
+ළ්‍රැ
+ළ්‍රෑ
+ළ්‍රි
+ළ්‍රී
+ළ්‍රු
+ළ්‍රූ
+ළ්‍රෘ
+ළ්‍රෲ
+ළ්‍රෟ
+ළ්‍රෳ
+ළ්‍රෙ
+ළ්‍රේ
+ළ්‍රෛ
+ළ්‍රො
+ළ්‍රෝ
+ළ්‍රෞ
+ළ්‍ර්
+ළ්‍රං
+ළ්‍රඃ
+ළ්‍ය
+ළ්‍යා
+ළ්‍යැ
+ළ්‍යෑ
+ළ්‍යි
+ළ්‍යී
+ළ්‍යු
+ළ්‍යූ
+ළ්‍යෘ
+ළ්‍යෲ
+ළ්‍යෟ
+ළ්‍යෳ
+ළ්‍යෙ
+ළ්‍යේ
+ළ්‍යෛ
+ළ්‍යො
+ළ්‍යෝ
+ළ්‍යෞ
+ළ්‍ය්
+ළ්‍යං
+ළ්‍යඃ
+ර්‍ළ
+ර්‍ළා
+ර්‍ළැ
+ර්‍ළෑ
+ර්‍ළි
+ර්‍ළී
+ර්‍ළු
+ර්‍ළූ
+ර්‍ළෘ
+ර්‍ළෲ
+ර්‍ළෟ
+ර්‍ළෳ
+ර්‍ළෙ
+ර්‍ළේ
+ර්‍ළෛ
+ර්‍ළො
+ර්‍ළෝ
+ර්‍ළෞ
+ර්‍ළ්
+ර්‍ළං
+ර්‍ළඃ
+ෆ
+ෆා
+ෆැ
+ෆෑ
+ෆි
+ෆී
+ෆු
+ෆූ
+ෆෘ
+ෆෲ
+ෆෟ
+ෆෳ
+ෆෙ
+ෆේ
+ෆෛ
+ෆො
+ෆෝ
+ෆෞ
+ෆ්
+ෆං
+ෆඃ
+ෆ්‍ර
+ෆ්‍රා
+ෆ්‍රැ
+ෆ්‍රෑ
+ෆ්‍රි
+ෆ්‍රී
+ෆ්‍රු
+ෆ්‍රූ
+ෆ්‍රෘ
+ෆ්‍රෲ
+ෆ්‍රෟ
+ෆ්‍රෳ
+ෆ්‍රෙ
+ෆ්‍රේ
+ෆ්‍රෛ
+ෆ්‍රො
+ෆ්‍රෝ
+ෆ්‍රෞ
+ෆ්‍ර්
+ෆ්‍රං
+ෆ්‍රඃ
+ෆ්‍ය
+ෆ්‍යා
+ෆ්‍යැ
+ෆ්‍යෑ
+ෆ්‍යි
+ෆ්‍යී
+ෆ්‍යු
+ෆ්‍යූ
+ෆ්‍යෘ
+ෆ්‍යෲ
+ෆ්‍යෟ
+ෆ්‍යෳ
+ෆ්‍යෙ
+ෆ්‍යේ
+ෆ්‍යෛ
+ෆ්‍යො
+ෆ්‍යෝ
+ෆ්‍යෞ
+ෆ්‍ය්
+ෆ්‍යං
+ෆ්‍යඃ
+ර්‍ෆ
+ර්‍ෆා
+ර්‍ෆැ
+ර්‍ෆෑ
+ර්‍ෆි
+ර්‍ෆී
+ර්‍ෆු
+ර්‍ෆූ
+ර්‍ෆෘ
+ර්‍ෆෲ
+ර්‍ෆෟ
+ර්‍ෆෳ
+ර්‍ෆෙ
+ර්‍ෆේ
+ර්‍ෆෛ
+ර්‍ෆො
+ර්‍ෆෝ
+ර්‍ෆෞ
+ර්‍ෆ්
+ර්‍ෆං
+ර්‍ෆඃ
+ක්‍ෂ
+ක්‍ෂා
+ක්‍ෂැ
+ක්‍ෂෑ
+ක්‍ෂි
+ක්‍ෂී
+ක්‍ෂු
+ක්‍ෂූ
+ක්‍ෂෘ
+ක්‍ෂෲ
+ක්‍ෂෟ
+ක්‍ෂෳ
+ක්‍ෂෙ
+ක්‍ෂේ
+ක්‍ෂෛ
+ක්‍ෂො
+ක්‍ෂෝ
+ක්‍ෂෞ
+ක්‍ෂ්
+ක්‍ෂං
+ක්‍ෂඃ
+ක්‍ෂ්‍ර
+ක්‍ෂ්‍රා
+ක්‍ෂ්‍රැ
+ක්‍ෂ්‍රෑ
+ක්‍ෂ්‍රි
+ක්‍ෂ්‍රී
+ක්‍ෂ්‍රු
+ක්‍ෂ්‍රූ
+ක්‍ෂ්‍රෘ
+ක්‍ෂ්‍රෲ
+ක්‍ෂ්‍රෟ
+ක්‍ෂ්‍රෳ
+ක්‍ෂ්‍රෙ
+ක්‍ෂ්‍රේ
+ක්‍ෂ්‍රෛ
+ක්‍ෂ්‍රො
+ක්‍ෂ්‍රෝ
+ක්‍ෂ්‍රෞ
+ක්‍ෂ්‍ර්
+ක්‍ෂ්‍රං
+ක්‍ෂ්‍රඃ
+ක්‍ෂ්‍ය
+ක්‍ෂ්‍යා
+ක්‍ෂ්‍යැ
+ක්‍ෂ්‍යෑ
+ක්‍ෂ්‍යි
+ක්‍ෂ්‍යී
+ක්‍ෂ්‍යු
+ක්‍ෂ්‍යූ
+ක්‍ෂ්‍යෘ
+ක්‍ෂ්‍යෲ
+ක්‍ෂ්‍යෟ
+ක්‍ෂ්‍යෳ
+ක්‍ෂ්‍යෙ
+ක්‍ෂ්‍යේ
+ක්‍ෂ්‍යෛ
+ක්‍ෂ්‍යො
+ක්‍ෂ්‍යෝ
+ක්‍ෂ්‍යෞ
+ක්‍ෂ්‍ය්
+ක්‍ෂ්‍යං
+ක්‍ෂ්‍යඃ
+ර්‍ක්‍ෂ
+ර්‍ක්‍ෂා
+ර්‍ක්‍ෂැ
+ර්‍ක්‍ෂෑ
+ර්‍ක්‍ෂි
+ර්‍ක්‍ෂී
+ර්‍ක්‍ෂු
+ර්‍ක්‍ෂූ
+ර්‍ක්‍ෂෘ
+ර්‍ක්‍ෂෲ
+ර්‍ක්‍ෂෟ
+ර්‍ක්‍ෂෳ
+ර්‍ක්‍ෂෙ
+ර්‍ක්‍ෂේ
+ර්‍ක්‍ෂෛ
+ර්‍ක්‍ෂො
+ර්‍ක්‍ෂෝ
+ර්‍ක්‍ෂෞ
+ර්‍ක්‍ෂ්
+ර්‍ක්‍ෂං
+ර්‍ක්‍ෂඃ
+ක්‍ව
+ක්‍වා
+ක්‍වැ
+ක්‍වෑ
+ක්‍වි
+ක්‍වී
+ක්‍වු
+ක්‍වූ
+ක්‍වෘ
+ක්‍වෲ
+ක්‍වෟ
+ක්‍වෳ
+ක්‍වෙ
+ක්‍වේ
+ක්‍වෛ
+ක්‍වො
+ක්‍වෝ
+ක්‍වෞ
+ක්‍ව්
+ක්‍වං
+ක්‍වඃ
+ක්‍ව්‍ර
+ක්‍ව්‍රා
+ක්‍ව්‍රැ
+ක්‍ව්‍රෑ
+ක්‍ව්‍රි
+ක්‍ව්‍රී
+ක්‍ව්‍රු
+ක්‍ව්‍රූ
+ක්‍ව්‍රෘ
+ක්‍ව්‍රෲ
+ක්‍ව්‍රෟ
+ක්‍ව්‍රෳ
+ක්‍ව්‍රෙ
+ක්‍ව්‍රේ
+ක්‍ව්‍රෛ
+ක්‍ව්‍රො
+ක්‍ව්‍රෝ
+ක්‍ව්‍රෞ
+ක්‍ව්‍ර්
+ක්‍ව්‍රං
+ක්‍ව්‍රඃ
+ක්‍ව්‍ය
+ක්‍ව්‍යා
+ක්‍ව්‍යැ
+ක්‍ව්‍යෑ
+ක්‍ව්‍යි
+ක්‍ව්‍යී
+ක්‍ව්‍යු
+ක්‍ව්‍යූ
+ක්‍ව්‍යෘ
+ක්‍ව්‍යෲ
+ක්‍ව්‍යෟ
+ක්‍ව්‍යෳ
+ක්‍ව්‍යෙ
+ක්‍ව්‍යේ
+ක්‍ව්‍යෛ
+ක්‍ව්‍යො
+ක්‍ව්‍යෝ
+ක්‍ව්‍යෞ
+ක්‍ව්‍ය්
+ක්‍ව්‍යං
+ක්‍ව්‍යඃ
+ර්‍ක්‍ව
+ර්‍ක්‍වා
+ර්‍ක්‍වැ
+ර්‍ක්‍වෑ
+ර්‍ක්‍වි
+ර්‍ක්‍වී
+ර්‍ක්‍වු
+ර්‍ක්‍වූ
+ර්‍ක්‍වෘ
+ර්‍ක්‍වෲ
+ර්‍ක්‍වෟ
+ර්‍ක්‍වෳ
+ර්‍ක්‍වෙ
+ර්‍ක්‍වේ
+ර්‍ක්‍වෛ
+ර්‍ක්‍වො
+ර්‍ක්‍වෝ
+ර්‍ක්‍වෞ
+ර්‍ක්‍ව්
+ර්‍ක්‍වං
+ර්‍ක්‍වඃ
+ත්‍ථ
+ත්‍ථා
+ත්‍ථැ
+ත්‍ථෑ
+ත්‍ථි
+ත්‍ථී
+ත්‍ථු
+ත්‍ථූ
+ත්‍ථෘ
+ත්‍ථෲ
+ත්‍ථෟ
+ත්‍ථෳ
+ත්‍ථෙ
+ත්‍ථේ
+ත්‍ථෛ
+ත්‍ථො
+ත්‍ථෝ
+ත්‍ථෞ
+ත්‍ථ්
+ත්‍ථං
+ත්‍ථඃ
+ත්‍ථ්‍ර
+ත්‍ථ්‍රා
+ත්‍ථ්‍රැ
+ත්‍ථ්‍රෑ
+ත්‍ථ්‍රි
+ත්‍ථ්‍රී
+ත්‍ථ්‍රු
+ත්‍ථ්‍රූ
+ත්‍ථ්‍රෘ
+ත්‍ථ්‍රෲ
+ත්‍ථ්‍රෟ
+ත්‍ථ්‍රෳ
+ත්‍ථ්‍රෙ
+ත්‍ථ්‍රේ
+ත්‍ථ්‍රෛ
+ත්‍ථ්‍රො
+ත්‍ථ්‍රෝ
+ත්‍ථ්‍රෞ
+ත්‍ථ්‍ර්
+ත්‍ථ්‍රං
+ත්‍ථ්‍රඃ
+ත්‍ථ්‍ය
+ත්‍ථ්‍යා
+ත්‍ථ්‍යැ
+ත්‍ථ්‍යෑ
+ත්‍ථ්‍යි
+ත්‍ථ්‍යී
+ත්‍ථ්‍යු
+ත්‍ථ්‍යූ
+ත්‍ථ්‍යෘ
+ත්‍ථ්‍යෲ
+ත්‍ථ්‍යෟ
+ත්‍ථ්‍යෳ
+ත්‍ථ්‍යෙ
+ත්‍ථ්‍යේ
+ත්‍ථ්‍යෛ
+ත්‍ථ්‍යො
+ත්‍ථ්‍යෝ
+ත්‍ථ්‍යෞ
+ත්‍ථ්‍ය්
+ත්‍ථ්‍යං
+ත්‍ථ්‍යඃ
+ර්‍ත්‍ථ
+ර්‍ත්‍ථා
+ර්‍ත්‍ථැ
+ර්‍ත්‍ථෑ
+ර්‍ත්‍ථි
+ර්‍ත්‍ථී
+ර්‍ත්‍ථු
+ර්‍ත්‍ථූ
+ර්‍ත්‍ථෘ
+ර්‍ත්‍ථෲ
+ර්‍ත්‍ථෟ
+ර්‍ත්‍ථෳ
+ර්‍ත්‍ථෙ
+ර්‍ත්‍ථේ
+ර්‍ත්‍ථෛ
+ර්‍ත්‍ථො
+ර්‍ත්‍ථෝ
+ර්‍ත්‍ථෞ
+ර්‍ත්‍ථ්
+ර්‍ත්‍ථං
+ර්‍ත්‍ථඃ
+ත්‍ව
+ත්‍වා
+ත්‍වැ
+ත්‍වෑ
+ත්‍වි
+ත්‍වී
+ත්‍වු
+ත්‍වූ
+ත්‍වෘ
+ත්‍වෲ
+ත්‍වෟ
+ත්‍වෳ
+ත්‍වෙ
+ත්‍වේ
+ත්‍වෛ
+ත්‍වො
+ත්‍වෝ
+ත්‍වෞ
+ත්‍ව්
+ත්‍වං
+ත්‍වඃ
+ත්‍ව්‍ර
+ත්‍ව්‍රා
+ත්‍ව්‍රැ
+ත්‍ව්‍රෑ
+ත්‍ව්‍රි
+ත්‍ව්‍රී
+ත්‍ව්‍රු
+ත්‍ව්‍රූ
+ත්‍ව්‍රෘ
+ත්‍ව්‍රෲ
+ත්‍ව්‍රෟ
+ත්‍ව්‍රෳ
+ත්‍ව්‍රෙ
+ත්‍ව්‍රේ
+ත්‍ව්‍රෛ
+ත්‍ව්‍රො
+ත්‍ව්‍රෝ
+ත්‍ව්‍රෞ
+ත්‍ව්‍ර්
+ත්‍ව්‍රං
+ත්‍ව්‍රඃ
+ත්‍ව්‍ය
+ත්‍ව්‍යා
+ත්‍ව්‍යැ
+ත්‍ව්‍යෑ
+ත්‍ව්‍යි
+ත්‍ව්‍යී
+ත්‍ව්‍යු
+ත්‍ව්‍යූ
+ත්‍ව්‍යෘ
+ත්‍ව්‍යෲ
+ත්‍ව්‍යෟ
+ත්‍ව්‍යෳ
+ත්‍ව්‍යෙ
+ත්‍ව්‍යේ
+ත්‍ව්‍යෛ
+ත්‍ව්‍යො
+ත්‍ව්‍යෝ
+ත්‍ව්‍යෞ
+ත්‍ව්‍ය්
+ත්‍ව්‍යං
+ත්‍ව්‍යඃ
+ර්‍ත්‍ව
+ර්‍ත්‍වා
+ර්‍ත්‍වැ
+ර්‍ත්‍වෑ
+ර්‍ත්‍වි
+ර්‍ත්‍වී
+ර්‍ත්‍වු
+ර්‍ත්‍වූ
+ර්‍ත්‍වෘ
+ර්‍ත්‍වෲ
+ර්‍ත්‍වෟ
+ර්‍ත්‍වෳ
+ර්‍ත්‍වෙ
+ර්‍ත්‍වේ
+ර්‍ත්‍වෛ
+ර්‍ත්‍වො
+ර්‍ත්‍වෝ
+ර්‍ත්‍වෞ
+ර්‍ත්‍ව්
+ර්‍ත්‍වං
+ර්‍ත්‍වඃ
+න්‍ථ
+න්‍ථා
+න්‍ථැ
+න්‍ථෑ
+න්‍ථි
+න්‍ථී
+න්‍ථු
+න්‍ථූ
+න්‍ථෘ
+න්‍ථෲ
+න්‍ථෟ
+න්‍ථෳ
+න්‍ථෙ
+න්‍ථේ
+න්‍ථෛ
+න්‍ථො
+න්‍ථෝ
+න්‍ථෞ
+න්‍ථ්
+න්‍ථං
+න්‍ථඃ
+න්‍ථ්‍ර
+න්‍ථ්‍රා
+න්‍ථ්‍රැ
+න්‍ථ්‍රෑ
+න්‍ථ්‍රි
+න්‍ථ්‍රී
+න්‍ථ්‍රු
+න්‍ථ්‍රූ
+න්‍ථ්‍රෘ
+න්‍ථ්‍රෲ
+න්‍ථ්‍රෟ
+න්‍ථ්‍රෳ
+න්‍ථ්‍රෙ
+න්‍ථ්‍රේ
+න්‍ථ්‍රෛ
+න්‍ථ්‍රො
+න්‍ථ්‍රෝ
+න්‍ථ්‍රෞ
+න්‍ථ්‍ර්
+න්‍ථ්‍රං
+න්‍ථ්‍රඃ
+න්‍ථ්‍ය
+න්‍ථ්‍යා
+න්‍ථ්‍යැ
+න්‍ථ්‍යෑ
+න්‍ථ්‍යි
+න්‍ථ්‍යී
+න්‍ථ්‍යු
+න්‍ථ්‍යූ
+න්‍ථ්‍යෘ
+න්‍ථ්‍යෲ
+න්‍ථ්‍යෟ
+න්‍ථ්‍යෳ
+න්‍ථ්‍යෙ
+න්‍ථ්‍යේ
+න්‍ථ්‍යෛ
+න්‍ථ්‍යො
+න්‍ථ්‍යෝ
+න්‍ථ්‍යෞ
+න්‍ථ්‍ය්
+න්‍ථ්‍යං
+න්‍ථ්‍යඃ
+ර්‍න්‍ථ
+ර්‍න්‍ථා
+ර්‍න්‍ථැ
+ර්‍න්‍ථෑ
+ර්‍න්‍ථි
+ර්‍න්‍ථී
+ර්‍න්‍ථු
+ර්‍න්‍ථූ
+ර්‍න්‍ථෘ
+ර්‍න්‍ථෲ
+ර්‍න්‍ථෟ
+ර්‍න්‍ථෳ
+ර්‍න්‍ථෙ
+ර්‍න්‍ථේ
+ර්‍න්‍ථෛ
+ර්‍න්‍ථො
+ර්‍න්‍ථෝ
+ර්‍න්‍ථෞ
+ර්‍න්‍ථ්
+ර්‍න්‍ථං
+ර්‍න්‍ථඃ
+න්‍ද
+න්‍දා
+න්‍දැ
+න්‍දෑ
+න්‍දි
+න්‍දී
+න්‍දු
+න්‍දූ
+න්‍දෘ
+න්‍දෲ
+න්‍දෟ
+න්‍දෳ
+න්‍දෙ
+න්‍දේ
+න්‍දෛ
+න්‍දො
+න්‍දෝ
+න්‍දෞ
+න්‍ද්
+න්‍දං
+න්‍දඃ
+න්‍ද්‍ර
+න්‍ද්‍රා
+න්‍ද්‍රැ
+න්‍ද්‍රෑ
+න්‍ද්‍රි
+න්‍ද්‍රී
+න්‍ද්‍රු
+න්‍ද්‍රූ
+න්‍ද්‍රෘ
+න්‍ද්‍රෲ
+න්‍ද්‍රෟ
+න්‍ද්‍රෳ
+න්‍ද්‍රෙ
+න්‍ද්‍රේ
+න්‍ද්‍රෛ
+න්‍ද්‍රො
+න්‍ද්‍රෝ
+න්‍ද්‍රෞ
+න්‍ද්‍ර්
+න්‍ද්‍රං
+න්‍ද්‍රඃ
+න්‍ද්‍ය
+න්‍ද්‍යා
+න්‍ද්‍යැ
+න්‍ද්‍යෑ
+න්‍ද්‍යි
+න්‍ද්‍යී
+න්‍ද්‍යු
+න්‍ද්‍යූ
+න්‍ද්‍යෘ
+න්‍ද්‍යෲ
+න්‍ද්‍යෟ
+න්‍ද්‍යෳ
+න්‍ද්‍යෙ
+න්‍ද්‍යේ
+න්‍ද්‍යෛ
+න්‍ද්‍යො
+න්‍ද්‍යෝ
+න්‍ද්‍යෞ
+න්‍ද්‍ය්
+න්‍ද්‍යං
+න්‍ද්‍යඃ
+ර්‍න්‍ද
+ර්‍න්‍දා
+ර්‍න්‍දැ
+ර්‍න්‍දෑ
+ර්‍න්‍දි
+ර්‍න්‍දී
+ර්‍න්‍දු
+ර්‍න්‍දූ
+ර්‍න්‍දෘ
+ර්‍න්‍දෲ
+ර්‍න්‍දෟ
+ර්‍න්‍දෳ
+ර්‍න්‍දෙ
+ර්‍න්‍දේ
+ර්‍න්‍දෛ
+ර්‍න්‍දො
+ර්‍න්‍දෝ
+ර්‍න්‍දෞ
+ර්‍න්‍ද්
+ර්‍න්‍දං
+ර්‍න්‍දඃ
+න්‍ධ
+න්‍ධා
+න්‍ධැ
+න්‍ධෑ
+න්‍ධි
+න්‍ධී
+න්‍ධු
+න්‍ධූ
+න්‍ධෘ
+න්‍ධෲ
+න්‍ධෟ
+න්‍ධෳ
+න්‍ධෙ
+න්‍ධේ
+න්‍ධෛ
+න්‍ධො
+න්‍ධෝ
+න්‍ධෞ
+න්‍ධ්
+න්‍ධං
+න්‍ධඃ
+න්‍ධ්‍ර
+න්‍ධ්‍රා
+න්‍ධ්‍රැ
+න්‍ධ්‍රෑ
+න්‍ධ්‍රි
+න්‍ධ්‍රී
+න්‍ධ්‍රු
+න්‍ධ්‍රූ
+න්‍ධ්‍රෘ
+න්‍ධ්‍රෲ
+න්‍ධ්‍රෟ
+න්‍ධ්‍රෳ
+න්‍ධ්‍රෙ
+න්‍ධ්‍රේ
+න්‍ධ්‍රෛ
+න්‍ධ්‍රො
+න්‍ධ්‍රෝ
+න්‍ධ්‍රෞ
+න්‍ධ්‍ර්
+න්‍ධ්‍රං
+න්‍ධ්‍රඃ
+න්‍ධ්‍ය
+න්‍ධ්‍යා
+න්‍ධ්‍යැ
+න්‍ධ්‍යෑ
+න්‍ධ්‍යි
+න්‍ධ්‍යී
+න්‍ධ්‍යු
+න්‍ධ්‍යූ
+න්‍ධ්‍යෘ
+න්‍ධ්‍යෲ
+න්‍ධ්‍යෟ
+න්‍ධ්‍යෳ
+න්‍ධ්‍යෙ
+න්‍ධ්‍යේ
+න්‍ධ්‍යෛ
+න්‍ධ්‍යො
+න්‍ධ්‍යෝ
+න්‍ධ්‍යෞ
+න්‍ධ්‍ය්
+න්‍ධ්‍යං
+න්‍ධ්‍යඃ
+ර්‍න්‍ධ
+ර්‍න්‍ධා
+ර්‍න්‍ධැ
+ර්‍න්‍ධෑ
+ර්‍න්‍ධි
+ර්‍න්‍ධී
+ර්‍න්‍ධු
+ර්‍න්‍ධූ
+ර්‍න්‍ධෘ
+ර්‍න්‍ධෲ
+ර්‍න්‍ධෟ
+ර්‍න්‍ධෳ
+ර්‍න්‍ධෙ
+ර්‍න්‍ධේ
+ර්‍න්‍ධෛ
+ර්‍න්‍ධො
+ර්‍න්‍ධෝ
+ර්‍න්‍ධෞ
+ර්‍න්‍ධ්
+ර්‍න්‍ධං
+ර්‍න්‍ධඃ
+න්‍ව
+න්‍වා
+න්‍වැ
+න්‍වෑ
+න්‍වි
+න්‍වී
+න්‍වු
+න්‍වූ
+න්‍වෘ
+න්‍වෲ
+න්‍වෟ
+න්‍වෳ
+න්‍වෙ
+න්‍වේ
+න්‍වෛ
+න්‍වො
+න්‍වෝ
+න්‍වෞ
+න්‍ව්
+න්‍වං
+න්‍වඃ
+න්‍ව්‍ර
+න්‍ව්‍රා
+න්‍ව්‍රැ
+න්‍ව්‍රෑ
+න්‍ව්‍රි
+න්‍ව්‍රී
+න්‍ව්‍රු
+න්‍ව්‍රූ
+න්‍ව්‍රෘ
+න්‍ව්‍රෲ
+න්‍ව්‍රෟ
+න්‍ව්‍රෳ
+න්‍ව්‍රෙ
+න්‍ව්‍රේ
+න්‍ව්‍රෛ
+න්‍ව්‍රො
+න්‍ව්‍රෝ
+න්‍ව්‍රෞ
+න්‍ව්‍ර්
+න්‍ව්‍රං
+න්‍ව්‍රඃ
+න්‍ව්‍ය
+න්‍ව්‍යා
+න්‍ව්‍යැ
+න්‍ව්‍යෑ
+න්‍ව්‍යි
+න්‍ව්‍යී
+න්‍ව්‍යු
+න්‍ව්‍යූ
+න්‍ව්‍යෘ
+න්‍ව්‍යෲ
+න්‍ව්‍යෟ
+න්‍ව්‍යෳ
+න්‍ව්‍යෙ
+න්‍ව්‍යේ
+න්‍ව්‍යෛ
+න්‍ව්‍යො
+න්‍ව්‍යෝ
+න්‍ව්‍යෞ
+න්‍ව්‍ය්
+න්‍ව්‍යං
+න්‍ව්‍යඃ
+ර්‍න්‍ව
+ර්‍න්‍වා
+ර්‍න්‍වැ
+ර්‍න්‍වෑ
+ර්‍න්‍වි
+ර්‍න්‍වී
+ර්‍න්‍වු
+ර්‍න්‍වූ
+ර්‍න්‍වෘ
+ර්‍න්‍වෲ
+ර්‍න්‍වෟ
+ර්‍න්‍වෳ
+ර්‍න්‍වෙ
+ර්‍න්‍වේ
+ර්‍න්‍වෛ
+ර්‍න්‍වො
+ර්‍න්‍වෝ
+ර්‍න්‍වෞ
+ර්‍න්‍ව්
+ර්‍න්‍වං
+ර්‍න්‍වඃ
+ද්‍ව
+ද්‍වා
+ද්‍වැ
+ද්‍වෑ
+ද්‍වි
+ද්‍වී
+ද්‍වු
+ද්‍වූ
+ද්‍වෘ
+ද්‍වෲ
+ද්‍වෟ
+ද්‍වෳ
+ද්‍වෙ
+ද්‍වේ
+ද්‍වෛ
+ද්‍වො
+ද්‍වෝ
+ද්‍වෞ
+ද්‍ව්
+ද්‍වං
+ද්‍වඃ
+ද්‍ව්‍ර
+ද්‍ව්‍රා
+ද්‍ව්‍රැ
+ද්‍ව්‍රෑ
+ද්‍ව්‍රි
+ද්‍ව්‍රී
+ද්‍ව්‍රු
+ද්‍ව්‍රූ
+ද්‍ව්‍රෘ
+ද්‍ව්‍රෲ
+ද්‍ව්‍රෟ
+ද්‍ව්‍රෳ
+ද්‍ව්‍රෙ
+ද්‍ව්‍රේ
+ද්‍ව්‍රෛ
+ද්‍ව්‍රො
+ද්‍ව්‍රෝ
+ද්‍ව්‍රෞ
+ද්‍ව්‍ර්
+ද්‍ව්‍රං
+ද්‍ව්‍රඃ
+ද්‍ව්‍ය
+ද්‍ව්‍යා
+ද්‍ව්‍යැ
+ද්‍ව්‍යෑ
+ද්‍ව්‍යි
+ද්‍ව්‍යී
+ද්‍ව්‍යු
+ද්‍ව්‍යූ
+ද්‍ව්‍යෘ
+ද්‍ව්‍යෲ
+ද්‍ව්‍යෟ
+ද්‍ව්‍යෳ
+ද්‍ව්‍යෙ
+ද්‍ව්‍යේ
+ද්‍ව්‍යෛ
+ද්‍ව්‍යො
+ද්‍ව්‍යෝ
+ද්‍ව්‍යෞ
+ද්‍ව්‍ය්
+ද්‍ව්‍යං
+ද්‍ව්‍යඃ
+ර්‍ද්‍ව
+ර්‍ද්‍වා
+ර්‍ද්‍වැ
+ර්‍ද්‍වෑ
+ර්‍ද්‍වි
+ර්‍ද්‍වී
+ර්‍ද්‍වු
+ර්‍ද්‍වූ
+ර්‍ද්‍වෘ
+ර්‍ද්‍වෲ
+ර්‍ද්‍වෟ
+ර්‍ද්‍වෳ
+ර්‍ද්‍වෙ
+ර්‍ද්‍වේ
+ර්‍ද්‍වෛ
+ර්‍ද්‍වො
+ර්‍ද්‍වෝ
+ර්‍ද්‍වෞ
+ර්‍ද්‍ව්
+ර්‍ද්‍වං
+ර්‍ද්‍වඃ
+ද්‍ධ
+ද්‍ධා
+ද්‍ධැ
+ද්‍ධෑ
+ද්‍ධි
+ද්‍ධී
+ද්‍ධු
+ද්‍ධූ
+ද්‍ධෘ
+ද්‍ධෲ
+ද්‍ධෟ
+ද්‍ධෳ
+ද්‍ධෙ
+ද්‍ධේ
+ද්‍ධෛ
+ද්‍ධො
+ද්‍ධෝ
+ද්‍ධෞ
+ද්‍ධ්
+ද්‍ධං
+ද්‍ධඃ
+ද්‍ධ්‍ර
+ද්‍ධ්‍රා
+ද්‍ධ්‍රැ
+ද්‍ධ්‍රෑ
+ද්‍ධ්‍රි
+ද්‍ධ්‍රී
+ද්‍ධ්‍රු
+ද්‍ධ්‍රූ
+ද්‍ධ්‍රෘ
+ද්‍ධ්‍රෲ
+ද්‍ධ්‍රෟ
+ද්‍ධ්‍රෳ
+ද්‍ධ්‍රෙ
+ද්‍ධ්‍රේ
+ද්‍ධ්‍රෛ
+ද්‍ධ්‍රො
+ද්‍ධ්‍රෝ
+ද්‍ධ්‍රෞ
+ද්‍ධ්‍ර්
+ද්‍ධ්‍රං
+ද්‍ධ්‍රඃ
+ද්‍ධ්‍ය
+ද්‍ධ්‍යා
+ද්‍ධ්‍යැ
+ද්‍ධ්‍යෑ
+ද්‍ධ්‍යි
+ද්‍ධ්‍යී
+ද්‍ධ්‍යු
+ද්‍ධ්‍යූ
+ද්‍ධ්‍යෘ
+ද්‍ධ්‍යෲ
+ද්‍ධ්‍යෟ
+ද්‍ධ්‍යෳ
+ද්‍ධ්‍යෙ
+ද්‍ධ්‍යේ
+ද්‍ධ්‍යෛ
+ද්‍ධ්‍යො
+ද්‍ධ්‍යෝ
+ද්‍ධ්‍යෞ
+ද්‍ධ්‍ය්
+ද්‍ධ්‍යං
+ද්‍ධ්‍යඃ
+ර්‍ද්‍ධ
+ර්‍ද්‍ධා
+ර්‍ද්‍ධැ
+ර්‍ද්‍ධෑ
+ර්‍ද්‍ධි
+ර්‍ද්‍ධී
+ර්‍ද්‍ධු
+ර්‍ද්‍ධූ
+ර්‍ද්‍ධෘ
+ර්‍ද්‍ධෲ
+ර්‍ද්‍ධෟ
+ර්‍ද්‍ධෳ
+ර්‍ද්‍ධෙ
+ර්‍ද්‍ධේ
+ර්‍ද්‍ධෛ
+ර්‍ද්‍ධො
+ර්‍ද්‍ධෝ
+ර්‍ද්‍ධෞ
+ර්‍ද්‍ධ්
+ර්‍ද්‍ධං
+ර්‍ද්‍ධඃ
+ට්‍ඨ
+ට්‍ඨා
+ට්‍ඨැ
+ට්‍ඨෑ
+ට්‍ඨි
+ට්‍ඨී
+ට්‍ඨු
+ට්‍ඨූ
+ට්‍ඨෘ
+ට්‍ඨෲ
+ට්‍ඨෟ
+ට්‍ඨෳ
+ට්‍ඨෙ
+ට්‍ඨේ
+ට්‍ඨෛ
+ට්‍ඨො
+ට්‍ඨෝ
+ට්‍ඨෞ
+ට්‍ඨ්
+ට්‍ඨං
+ට්‍ඨඃ
+ට්‍ඨ්‍ර
+ට්‍ඨ්‍රා
+ට්‍ඨ්‍රැ
+ට්‍ඨ්‍රෑ
+ට්‍ඨ්‍රි
+ට්‍ඨ්‍රී
+ට්‍ඨ්‍රු
+ට්‍ඨ්‍රූ
+ට්‍ඨ්‍රෘ
+ට්‍ඨ්‍රෲ
+ට්‍ඨ්‍රෟ
+ට්‍ඨ්‍රෳ
+ට්‍ඨ්‍රෙ
+ට්‍ඨ්‍රේ
+ට්‍ඨ්‍රෛ
+ට්‍ඨ්‍රො
+ට්‍ඨ්‍රෝ
+ට්‍ඨ්‍රෞ
+ට්‍ඨ්‍ර්
+ට්‍ඨ්‍රං
+ට්‍ඨ්‍රඃ
+ට්‍ඨ්‍ය
+ට්‍ඨ්‍යා
+ට්‍ඨ්‍යැ
+ට්‍ඨ්‍යෑ
+ට්‍ඨ්‍යි
+ට්‍ඨ්‍යී
+ට්‍ඨ්‍යු
+ට්‍ඨ්‍යූ
+ට්‍ඨ්‍යෘ
+ට්‍ඨ්‍යෲ
+ට්‍ඨ්‍යෟ
+ට්‍ඨ්‍යෳ
+ට්‍ඨ්‍යෙ
+ට්‍ඨ්‍යේ
+ට්‍ඨ්‍යෛ
+ට්‍ඨ්‍යො
+ට්‍ඨ්‍යෝ
+ට්‍ඨ්‍යෞ
+ට්‍ඨ්‍ය්
+ට්‍ඨ්‍යං
+ට්‍ඨ්‍යඃ
+ර්‍ට්‍ඨ
+ර්‍ට්‍ඨා
+ර්‍ට්‍ඨැ
+ර්‍ට්‍ඨෑ
+ර්‍ට්‍ඨි
+ර්‍ට්‍ඨී
+ර්‍ට්‍ඨු
+ර්‍ට්‍ඨූ
+ර්‍ට්‍ඨෘ
+ර්‍ට්‍ඨෲ
+ර්‍ට්‍ඨෟ
+ර්‍ට්‍ඨෳ
+ර්‍ට්‍ඨෙ
+ර්‍ට්‍ඨේ
+ර්‍ට්‍ඨෛ
+ර්‍ට්‍ඨො
+ර්‍ට්‍ඨෝ
+ර්‍ට්‍ඨෞ
+ර්‍ට්‍ඨ්
+ර්‍ට්‍ඨං
+ර්‍ට්‍ඨඃ
+්‍ර
+්‍ය
+ර්‍
+෴
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/misc.txt
new file mode 100644 (file)
index 0000000..c43cb95
--- /dev/null
@@ -0,0 +1,41 @@
+ක
+කං
+කඃ
+කා
+කැ
+කෑ
+කි
+කී
+කු
+කූ
+කෘ
+කෲ
+කෟ
+කෳ
+කෙ
+කො
+කෞ
+කේ
+කේ
+කෛ
+කො
+කෝ
+කෝ
+කෞ
+ක්
+ක්‍ය
+ක්‍ර
+ක‍්‍රම
+ර්‍ම
+ශී‍්‍ර
+ස්ට්‍රේ
+ග්‍යෙ
+ර්‍ය්‍ය
+එ‍ඬේ
+න්ගේ
+න්‍ගේ
+න‍්ගේ
+ර්‍
+ක්‍රා
+කේ
+ගර්‍
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/reph.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/reph.txt
new file mode 100644 (file)
index 0000000..f5f2f53
--- /dev/null
@@ -0,0 +1,3 @@
+ර්ධ
+ර්‍ධ
+ර්‌ධ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/split-matras.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/misc/split-matras.txt
new file mode 100644 (file)
index 0000000..2a73a40
--- /dev/null
@@ -0,0 +1,4 @@
+කේ
+කො
+කෝ
+කෞ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..0e8810a
--- /dev/null
@@ -0,0 +1,41 @@
+ක
+ඛ
+ග
+ඝ
+ඞ
+ඟ
+ච
+ඡ
+ජ
+ඣ
+ඤ
+ඥ
+ඦ
+ට
+ඨ
+ඩ
+ඪ
+ණ
+ඬ
+ත
+ථ
+ද
+ධ
+න
+ඳ
+ප
+ඵ
+බ
+භ
+ම
+ඹ
+ය
+ර
+ල
+ව
+ශ
+ෂ
+ස
+හ
+ළ
+ෆ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..27911e4
--- /dev/null
@@ -0,0 +1,17 @@
+ා
+ැ
+ෑ
+ි
+ී
+ු
+ූ
+ෘ
+ෙ
+ේ
+ෛ
+ො
+ෝ
+ෞ
+ෟ
+ෲ
+ෳ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..939be04
--- /dev/null
@@ -0,0 +1,18 @@
+අ
+ආ
+ඇ
+ඈ
+ඉ
+ඊ
+උ
+ඌ
+ඍ
+ඎ
+ඏ
+ඐ
+එ
+ඒ
+ඓ
+ඔ
+ඕ
+ඖ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-Punctuation.txt
new file mode 100644 (file)
index 0000000..d6c6809
--- /dev/null
@@ -0,0 +1 @@
+෴
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..a65a9ba
--- /dev/null
@@ -0,0 +1,3 @@
+ං
+ඃ
+්
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..48e393c
--- /dev/null
@@ -0,0 +1,5 @@
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Punctuation.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/IndicFontFeatureGPOS.txt
new file mode 100644 (file)
index 0000000..7cd1eac
--- /dev/null
@@ -0,0 +1,162 @@
+කේ
+කෛ
+කී
+කෑ
+කූ
+කෲ
+ගේ
+ගෛ
+ගී
+ගෑ
+ගූ
+ගෲ
+තේ
+තෛ
+තී
+තෑ
+තූ
+තෲ
+ටේ
+ටෛ
+ටී
+ටෑ
+ටූ
+ටෲ
+ඩේ
+ඩෛ
+ඩී
+ඩෑ
+ඩූ
+ඩෲ
+චේ
+චෛ
+චී
+චෑ
+චූ
+චෲ
+ඡේ
+ඡෛ
+ඡී
+ඡෑ
+ඡූ
+ඡෲ
+ණේ
+ණෛ
+ණී
+ණෑ
+ණූ
+ණෲ
+පේ
+පෛ
+පී
+පෑ
+පූ
+පෲ
+දේ
+දෛ
+දී
+දෑ
+දූ
+දෲ
+ඳේ
+ඳෛ
+ඳී
+ඳෑ
+ඳූ
+ඳෲ
+ධේ
+ධෛ
+ධී
+ධෑ
+ධූ
+ධෲ
+බේ
+බෛ
+බී
+බෑ
+බූ
+බෲ
+මේ
+මෛ
+මී
+මෑ
+මූ
+මෲ
+වේ
+වෛ
+වී
+වෑ
+වූ
+වෲ
+හේ
+හෛ
+හී
+හෑ
+හූ
+හෲ
+රේ
+රෛ
+රී
+රෑ
+රූ
+රෲ
+ෆේ
+ෆෛ
+ෆී
+ෆෑ
+ෆූ
+ෆෲ
+ළේ
+ළෛ
+ළී
+ළෑ
+ළූ
+ළෲ
+ලේ
+ලෛ
+ලී
+ලෑ
+ලූ
+ලෲ
+යේ
+යෛ
+යී
+යෑ
+යූ
+යෲ
+සේ
+සෛ
+සී
+සෑ
+සූ
+සෲ
+ශේ
+ශෛ
+ශී
+ශෑ
+ශූ
+ශෲ
+ෂේ
+ෂෛ
+ෂී
+ෂෑ
+ෂූ
+ෂෲ
+ඹේ
+ඹෛ
+ඹී
+ඹෑ
+ඹූ
+ඹෲ
+ඵේ
+ඵෛ
+ඵී
+ඵෑ
+ඵූ
+ඵෲ
+ථේ
+ථෛ
+ථී
+ථෑ
+ථූ
+ථෲ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..f4d0fc3
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGPOS.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Conjunct.txt
new file mode 100644 (file)
index 0000000..a100c69
--- /dev/null
@@ -0,0 +1 @@
+්‍
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Rakaaraansaya.txt
new file mode 100644 (file)
index 0000000..bf89a71
--- /dev/null
@@ -0,0 +1,41 @@
+ක්‍ර
+ඛ්‍ර
+ග්‍ර
+ඝ්‍ර
+ඞ්‍ර
+ඟ්‍ර
+ච්‍ර
+ඡ්‍ර
+ජ්‍ර
+ඣ්‍ර
+ඤ්‍ර
+ඥ්‍ර
+ඦ්‍ර
+ට්‍ර
+ඨ්‍ර
+ඩ්‍ර
+ඪ්‍ර
+ණ්‍ර
+ඬ්‍ර
+ත්‍ර
+ථ්‍ර
+ද්‍ර
+ධ්‍ර
+න්‍ර
+ඳ්‍ර
+ප්‍ර
+ඵ්‍ර
+බ්‍ර
+භ්‍ර
+ම්‍ර
+ඹ්‍ර
+ය්‍ර
+ර්‍ර
+ල්‍ර
+ව්‍ර
+ශ්‍ර
+ෂ්‍ර
+ස්‍ර
+හ්‍ර
+ළ්‍ර
+ෆ්‍ර
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Repaya.txt
new file mode 100644 (file)
index 0000000..6f0293d
--- /dev/null
@@ -0,0 +1,42 @@
+කර්‍ක
+ඛර්‍ක
+ගර්‍ක
+ඝර්‍ක
+ඞර්‍ක
+ඟර්‍ක
+චර්‍ක
+ඡර්‍ක
+ජර්‍ක
+ඣර්‍ක
+ඤර්‍ක
+ඥර්‍ක
+ඦර්‍ක
+ටර්‍ක
+ඨර්‍ක
+ඩර්‍ක
+ඪර්‍ක
+ණර්‍ක
+ඬර්‍ක
+තර්‍ක
+ථර්‍ක
+දර්‍ක
+ධර්‍ක
+නර්‍ක
+ඳර්‍ක
+පර්‍ක
+ඵර්‍ක
+බර්‍ක
+භර්‍ක
+මර්‍ක
+ඹර්‍ක
+යර්‍ක
+රර්‍ක
+ලර්‍ක
+වර්‍ක
+ශර්‍ක
+ෂර්‍ක
+සර්‍ක
+හර්‍ක
+ළර්‍ක
+ෆර්‍ක
+කර්‍ය්‍ය
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Special-Cases.txt
new file mode 100644 (file)
index 0000000..109c873
--- /dev/null
@@ -0,0 +1,2 @@
+ක්‍ෂ
+න්‍ද
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-TouchingLetters.txt
new file mode 100644 (file)
index 0000000..105b295
--- /dev/null
@@ -0,0 +1 @@
+‍්
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB-Yansaya.txt
new file mode 100644 (file)
index 0000000..299ca9d
--- /dev/null
@@ -0,0 +1,41 @@
+ක්‍ය
+ඛ්‍ය
+ග්‍ය
+ඝ්‍ය
+ඞ්‍ය
+ඟ්‍ය
+ච්‍ය
+ඡ්‍ය
+ජ්‍ය
+ඣ්‍ය
+ඤ්‍ය
+ඥ්‍ය
+ඦ්‍ය
+ට්‍ය
+ඨ්‍ය
+ඩ්‍ය
+ඪ්‍ය
+ණ්‍ය
+ඬ්‍ය
+ත්‍ය
+ථ්‍ය
+ද්‍ය
+ධ්‍ය
+න්‍ය
+ඳ්‍ය
+ප්‍ය
+ඵ්‍ය
+බ්‍ය
+භ්‍ය
+ම්‍ය
+ඹ්‍ය
+ය්‍ය
+ර්‍ය
+ල්‍ය
+ව්‍ය
+ශ්‍ය
+ෂ්‍ය
+ස්‍ය
+හ්‍ය
+ළ්‍ය
+ෆ්‍ය
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..fd5e6e6
--- /dev/null
@@ -0,0 +1 @@
+codepoint, imagepath, rawcode, desc
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-sinhala/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..6aa964b
--- /dev/null
@@ -0,0 +1,7 @@
+IndicFontFeatureGSUB-Conjunct.txt
+IndicFontFeatureGSUB-Rakaaraansaya.txt
+IndicFontFeatureGSUB-Repaya.txt
+IndicFontFeatureGSUB-Special-Cases.txt
+IndicFontFeatureGSUB-TouchingLetters.txt
+IndicFontFeatureGSUB-Yansaya.txt
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/misc/misc.txt
new file mode 100644 (file)
index 0000000..c72be69
--- /dev/null
@@ -0,0 +1,43 @@
+தமிழ்நாடு
+ஓர்
+இந்திய
+மாநிலமாகும்.
+தமிழ்நாடு,
+தமிழகம்
+என்றும்
+பரவலாக
+அழைக்கப்படுகிறது.
+ஆங்கிலத்தில்
+மெட்ராஸ்
+ஸ்டேட்
+என்றும்
+தமிழில்
+சென்னை
+ராஜ்ஜியம்
+என்றும்
+அழைக்கப்பெற்றது.
+இதனை
+தமிழ்நாடு
+என்று
+மாற்றக்கோரி
+போராட்டங்கள்
+நடைபெற்றன.
+சங்கரலிங்கனார்
+என்பவர்
+நாட்கள்
+உண்ணாவிரதம்
+இருந்து
+உயிர்துறந்தார்.
+பின்னர்
+மதராசு
+ஸ்டேட்
+என்று
+இருந்த
+பெயர்
+ஆம்
+ஆண்டு
+தமிழ்நாடு
+என்று
+மாற்றப்பட்டது.
+ஸ்ரீ
+க்ஷ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..7a26510
--- /dev/null
@@ -0,0 +1,23 @@
+க
+ங
+ச
+ஜ
+ஞ
+ட
+ண
+த
+ந
+ன
+ப
+ம
+ய
+ர
+ற
+ல
+ள
+ழ
+வ
+ஶ
+ஷ
+ஸ
+ஹ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-CurrencySymbols.txt
new file mode 100644 (file)
index 0000000..f70ba6a
--- /dev/null
@@ -0,0 +1 @@
+௹
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..f22470c
--- /dev/null
@@ -0,0 +1,11 @@
+ா
+ி
+ீ
+ு
+ூ
+ெ
+ே
+ை
+ொ
+ோ
+ௌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..47b1d62
--- /dev/null
@@ -0,0 +1,10 @@
+௦
+௧
+௨
+௩
+௪
+௫
+௬
+௭
+௮
+௯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..3940ad3
--- /dev/null
@@ -0,0 +1,12 @@
+அ
+ஆ
+இ
+ஈ
+உ
+ஊ
+எ
+ஏ
+ஐ
+ஒ
+ஓ
+ஔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Numerics.txt
new file mode 100644 (file)
index 0000000..33f6850
--- /dev/null
@@ -0,0 +1,3 @@
+௰
+௱
+௲
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-Symbols.txt
new file mode 100644 (file)
index 0000000..a7d89e8
--- /dev/null
@@ -0,0 +1,6 @@
+௳
+௴
+௵
+௶
+௷
+௸
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-TamilSymbol.txt
new file mode 100644 (file)
index 0000000..2d4bdc1
--- /dev/null
@@ -0,0 +1 @@
+௺
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..49c469c
--- /dev/null
@@ -0,0 +1,4 @@
+ஂ
+ஃ
+்
+ௗ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..3e28731
--- /dev/null
@@ -0,0 +1,10 @@
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-CurrencySymbols.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Numerics.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-Symbols.txt
+IndicFontFeatureCodepoint-TamilSymbol.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..40b2b21
--- /dev/null
@@ -0,0 +1,64 @@
+கி
+ஙி
+சி
+ஜி
+ஞி
+டி
+ணி
+தி
+நி
+னி
+பி
+மி
+யி
+ரி
+றி
+லி
+ளி
+ழி
+வி
+ஷி
+ஸி
+ஹி
+கீ
+ஙீ
+சீ
+ஜீ
+ஞீ
+டீ
+ணீ
+தீ
+நீ
+னீ
+பீ
+மீ
+யீ
+ரீ
+றீ
+லீ
+ளீ
+ழீ
+வீ
+ஷீ
+ஸீ
+க்
+ங்
+ச்
+ஜ்
+ஞ்
+ட்
+ண்
+த்
+ந்
+ன்
+ப்
+ம்
+ய்
+ர்
+ற்
+ல்
+ழ்
+வ்
+ஷ்
+ஸ்
+ஹ்
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/IndicFontFeatureGPOS-BelowBase.txt
new file mode 100644 (file)
index 0000000..847495a
--- /dev/null
@@ -0,0 +1,44 @@
+கு
+ஙு
+சு
+ஜு
+ஞு
+டு
+ணு
+து
+நு
+னு
+பு
+மு
+யு
+ரு
+று
+லு
+ளு
+ழு
+வு
+ஷு
+ஸு
+ஹு
+கூ
+ஙூ
+சூ
+ஜூ
+ஞூ
+டூ
+ணூ
+தூ
+நூ
+னூ
+பூ
+மூ
+யூ
+ரூ
+றூ
+லூ
+ளூ
+ழூ
+வூ
+ஷூ
+ஸூ
+ஹூ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..d7ae70e
--- /dev/null
@@ -0,0 +1,2 @@
+IndicFontFeatureGPOS-AboveBase.txt
+IndicFontFeatureGPOS-BelowBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..2ca1df3
--- /dev/null
@@ -0,0 +1,4 @@
+க்ஷ
+க்ஷி
+க்ஷீ
+ஷ்ரீ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-tamil/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/MANIFEST
new file mode 100644 (file)
index 0000000..ecb8d96
--- /dev/null
@@ -0,0 +1,2 @@
+misc
+utrrs
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/misc/misc.txt
new file mode 100644 (file)
index 0000000..ff522d2
--- /dev/null
@@ -0,0 +1,12 @@
+కై
+క్
+క్కై
+క్ర
+క్రి
+క్రై
+క్ర్
+క్ర్క
+క్ష
+క్ష్
+క్ష్ణ
+ఽం
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/LICENSE b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/LICENSE
new file mode 100644 (file)
index 0000000..2cf8228
--- /dev/null
@@ -0,0 +1,19 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/MANIFEST
new file mode 100644 (file)
index 0000000..0658824
--- /dev/null
@@ -0,0 +1,3 @@
+codepoint
+gpos
+gsub
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/README b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/README
new file mode 100644 (file)
index 0000000..8bad337
--- /dev/null
@@ -0,0 +1,13 @@
+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/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/SOURCES b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/SOURCES
new file mode 100644 (file)
index 0000000..0ed1a89
--- /dev/null
@@ -0,0 +1,2 @@
+https://fedorahosted.org/utrrs/
+Fetched in late 2011
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-AdditionalVowels.txt
new file mode 100644 (file)
index 0000000..a92b179
--- /dev/null
@@ -0,0 +1,2 @@
+ౠ
+ౡ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Consonants.txt
new file mode 100644 (file)
index 0000000..9b8ff69
--- /dev/null
@@ -0,0 +1,38 @@
+క
+ఖ
+గ
+ఘ
+ఙ
+చ
+ఛ
+జ
+ఝ
+ఞ
+ట
+ఠ
+డ
+ఢ
+ణ
+త
+థ
+ద
+ధ
+న
+ప
+ఫ
+బ
+భ
+మ
+య
+ర
+ఱ
+ల
+ళ
+వ
+శ
+ష
+స
+హ
+ఁ
+ం
+ః
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-DependentVowels.txt
new file mode 100644 (file)
index 0000000..b48ed5d
--- /dev/null
@@ -0,0 +1,13 @@
+ా
+ి
+ీ
+ు
+ూ
+ృ
+ౄ
+ె
+ే
+ై
+ొ
+ో
+ౌ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Digits.txt
new file mode 100644 (file)
index 0000000..8751b40
--- /dev/null
@@ -0,0 +1,10 @@
+౦
+౧
+౨
+౩
+౪
+౫
+౬
+౭
+౮
+౯
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-IndependentVowels.txt
new file mode 100644 (file)
index 0000000..53c6daf
--- /dev/null
@@ -0,0 +1,14 @@
+అ
+ఆ
+ఇ
+ఈ
+ఉ
+ఊ
+ఋ
+ఌ
+ఎ
+ఏ
+ఐ
+ఒ
+ఓ
+ఔ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-Reserved.txt
new file mode 100644 (file)
index 0000000..66a7ca4
--- /dev/null
@@ -0,0 +1,2 @@
+।
+॥
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/IndicFontFeatureCodepoint-VariousSigns.txt
new file mode 100644 (file)
index 0000000..ebefb52
--- /dev/null
@@ -0,0 +1,6 @@
+ఁ
+ం
+ః
+్
+ౕ
+ౖ
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/codepoint/MANIFEST
new file mode 100644 (file)
index 0000000..1490dfe
--- /dev/null
@@ -0,0 +1,7 @@
+IndicFontFeatureCodepoint-AdditionalVowels.txt
+IndicFontFeatureCodepoint-Consonants.txt
+IndicFontFeatureCodepoint-DependentVowels.txt
+IndicFontFeatureCodepoint-Digits.txt
+IndicFontFeatureCodepoint-IndependentVowels.txt
+IndicFontFeatureCodepoint-Reserved.txt
+IndicFontFeatureCodepoint-VariousSigns.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/IndicFontFeatureGPOS-AboveBase.txt
new file mode 100644 (file)
index 0000000..939e44a
--- /dev/null
@@ -0,0 +1,385 @@
+కా
+ఖా
+గా
+ఘా
+ఙా
+చా
+ఛా
+జా
+ఝా
+ఞా
+టా
+ఠా
+డా
+ఢా
+ణా
+తా
+థా
+దా
+ధా
+నా
+పా
+ఫా
+బా
+భా
+మా
+యా
+రా
+ఱా
+లా
+ళా
+వా
+శా
+షా
+సా
+హా
+కి
+ఖి
+గి
+ఘి
+ఙి
+చి
+ఛి
+జి
+ఝి
+ఞి
+టి
+ఠి
+డి
+ఢి
+ణి
+తి
+థి
+ది
+ధి
+ని
+పి
+ఫి
+బి
+భి
+మి
+యి
+రి
+ఱి
+లి
+ళి
+వి
+శి
+షి
+సి
+హి
+కీ
+ఖీ
+గీ
+ఘీ
+ఙీ
+చీ
+ఛీ
+జీ
+ఝీ
+ఞీ
+టీ
+ఠీ
+డీ
+ఢీ
+ణీ
+తీ
+థీ
+దీ
+ధీ
+నీ
+పీ
+ఫీ
+బీ
+భీ
+మీ
+యీ
+రీ
+ఱీ
+లీ
+ళీ
+వీ
+శీ
+షీ
+సీ
+హీ
+కె
+ఖె
+గె
+ఘె
+ఙె
+చె
+ఛె
+జె
+ఝె
+ఞె
+టె
+ఠె
+డె
+ఢె
+ణె
+తె
+థె
+దె
+ధె
+నె
+పె
+ఫె
+బె
+భె
+మె
+యె
+రె
+ఱె
+లె
+ళె
+వె
+శె
+షె
+సె
+హె
+కే
+ఖే
+గే
+ఘే
+ఙే
+చే
+ఛే
+జే
+ఝే
+ఞే
+టే
+ఠే
+డే
+ఢే
+ణే
+తే
+థే
+దే
+ధే
+నే
+పే
+ఫే
+బే
+భే
+మే
+యే
+రే
+ఱే
+లే
+ళే
+వే
+శే
+షే
+సే
+హే
+కై
+ఖై
+గై
+ఘై
+ఙై
+చై
+ఛై
+జై
+ఝై
+ఞై
+టై
+ఠై
+డై
+ఢై
+ణై
+తై
+థై
+దై
+ధై
+నై
+పై
+ఫై
+బై
+భై
+మై
+యై
+రై
+ఱై
+లై
+ళై
+వై
+శై
+షై
+సై
+హై
+కొ
+ఖొ
+గొ
+ఘొ
+ఙొ
+చొ
+ఛొ
+జొ
+ఝొ
+ఞొ
+టొ
+ఠొ
+డొ
+ఢొ
+ణొ
+తొ
+థొ
+దొ
+ధొ
+నొ
+పొ
+ఫొ
+బొ
+భొ
+మొ
+యొ
+రొ
+ఱొ
+లొ
+ళొ
+వొ
+శొ
+షొ
+సొ
+హొ
+కో
+ఖో
+గో
+ఘో
+ఙో
+చో
+ఛో
+జో
+ఝో
+ఞో
+టో
+ఠో
+డో
+ఢో
+ణో
+తో
+థో
+దో
+ధో
+నో
+పో
+ఫో
+బో
+భో
+మో
+యో
+రో
+ఱో
+లో
+ళో
+వో
+శో
+షో
+సో
+హో
+కౌ
+ఖౌ
+గౌ
+ఘౌ
+ఙౌ
+చౌ
+ఛౌ
+జౌ
+ఝౌ
+ఞౌ
+టౌ
+ఠౌ
+డౌ
+ఢౌ
+ణౌ
+తౌ
+థౌ
+దౌ
+ధౌ
+నౌ
+పౌ
+ఫౌ
+బౌ
+భౌ
+మౌ
+యౌ
+రౌ
+ఱౌ
+లౌ
+ళౌ
+వౌ
+శౌ
+షౌ
+సౌ
+హౌ
+కఁ
+ఖఁ
+గఁ
+ఘఁ
+ఙఁ
+చఁ
+ఛఁ
+జఁ
+ఝఁ
+ఞఁ
+టఁ
+ఠఁ
+డఁ
+ఢఁ
+ణఁ
+తఁ
+థఁ
+దఁ
+ధఁ
+నఁ
+పఁ
+ఫఁ
+బఁ
+భఁ
+మఁ
+యఁ
+రఁ
+ఱఁ
+లఁ
+ళఁ
+వఁ
+శఁ
+షఁ
+సఁ
+హఁ
+క్
+ఖ్
+గ్
+ఘ్
+ఙ్
+చ్
+ఛ్
+జ్
+ఝ్
+ఞ్
+ట్
+ఠ్
+డ్
+ఢ్
+ణ్
+త్
+థ్
+ద్
+ధ్
+న్
+ప్
+ఫ్
+బ్
+భ్
+మ్
+య్
+ర్
+ఱ్
+ల్
+ళ్
+వ్
+శ్
+ష్
+స్
+హ్
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gpos/MANIFEST
new file mode 100644 (file)
index 0000000..49d0284
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGPOS-AboveBase.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/IndicFontFeatureGSUB.txt
new file mode 100644 (file)
index 0000000..50b630b
--- /dev/null
@@ -0,0 +1,287 @@
+క్క
+క్ఖ
+క్గ
+క్ఘ
+క్ఙ
+క్చ
+క్ఛ
+క్జ
+క్ఝ
+క్ఞ
+క్ట
+క్ఠ
+క్డ
+క్ఢ
+క్ణ
+క్త
+క్థ
+క్ద
+క్ధ
+క్న
+క్ప
+క్ఫ
+క్బ
+క్భ
+క్మ
+క్య
+క్ర
+క్ఱ
+క్ల
+క్ళ
+క్వ
+క్శ
+క్ష
+క్స
+క్హ
+త్క
+త్ఖ
+త్గ
+త్ఘ
+త్ఙ
+త్చ
+త్ఛ
+త్జ
+త్ఝ
+త్ఞ
+త్ట
+త్ఠ
+త్డ
+త్ఢ
+త్ణ
+త్త
+త్థ
+త్ద
+త్ధ
+త్న
+త్ప
+త్ఫ
+త్బ
+త్భ
+త్మ
+త్య
+త్ర
+త్ఱ
+త్ల
+త్ళ
+త్వ
+త్శ
+త్ష
+త్స
+త్హ
+న్క
+న్ఖ
+న్గ
+న్ఘ
+న్ఙ
+న్చ
+న్ఛ
+న్జ
+న్ఝ
+న్ఞ
+న్ట
+న్ఠ
+న్డ
+న్ఢ
+న్ణ
+న్త
+న్థ
+న్ద
+న్ధ
+న్న
+న్ప
+న్ఫ
+న్బ
+న్భ
+న్మ
+న్య
+న్ర
+న్ఱ
+న్ల
+న్ళ
+న్వ
+న్శ
+న్ష
+న్స
+న్హ
+మ్క
+మ్ఖ
+మ్గ
+మ్ఘ
+మ్ఙ
+మ్చ
+మ్ఛ
+మ్జ
+మ్ఝ
+మ్ఞ
+మ్ట
+మ్ఠ
+మ్డ
+మ్ఢ
+మ్ణ
+మ్త
+మ్థ
+మ్ద
+మ్ధ
+మ్న
+మ్ప
+మ్ఫ
+మ్బ
+మ్భ
+మ్మ
+మ్య
+మ్ర
+మ్ఱ
+మ్ల
+మ్ళ
+మ్వ
+మ్శ
+మ్ష
+మ్స
+మ్హ
+య్క
+య్ఖ
+య్గ
+య్ఘ
+య్ఙ
+య్చ
+య్ఛ
+య్జ
+య్ఝ
+య్ఞ
+య్ట
+య్ఠ
+య్డ
+య్ఢ
+య్ణ
+య్త
+య్థ
+య్ద
+య్ధ
+య్న
+య్ప
+య్ఫ
+య్బ
+య్భ
+య్మ
+య్య
+య్ర
+య్ఱ
+య్ల
+య్ళ
+య్వ
+య్శ
+య్ష
+య్స
+య్హ
+ర్క
+ర్ఖ
+ర్గ
+ర్ఘ
+ర్ఙ
+ర్చ
+ర్ఛ
+ర్జ
+ర్ఝ
+ర్ఞ
+ర్ట
+ర్ఠ
+ర్డ
+ర్ఢ
+ర్ణ
+ర్త
+ర్థ
+ర్ద
+ర్ధ
+ర్న
+ర్ప
+ర్ఫ
+ర్బ
+ర్భ
+ర్మ
+ర్య
+ర్ర
+ర్ఱ
+ర్ల
+ర్ళ
+ర్వ
+ర్శ
+ర్ష
+ర్స
+ర్హ
+ల్క
+ల్ఖ
+ల్గ
+ల్ఘ
+ల్ఙ
+ల్చ
+ల్ఛ
+ల్జ
+ల్ఝ
+ల్ఞ
+ల్ట
+ల్ఠ
+ల్డ
+ల్ఢ
+ల్ణ
+ల్త
+ల్థ
+ల్ద
+ల్ధ
+ల్న
+ల్ప
+ల్ఫ
+ల్బ
+ల్భ
+ల్మ
+ల్య
+ల్ర
+ల్ఱ
+ల్ల
+ల్ళ
+ల్వ
+ల్శ
+ల్ష
+ల్స
+ల్హ
+వ్క
+వ్ఖ
+వ్గ
+వ్ఘ
+వ్ఙ
+వ్చ
+వ్ఛ
+వ్జ
+వ్ఝ
+వ్ఞ
+వ్ట
+వ్ఠ
+వ్డ
+వ్ఢ
+వ్ణ
+వ్త
+వ్థ
+వ్ద
+వ్ధ
+వ్న
+వ్ప
+వ్ఫ
+వ్బ
+వ్భ
+వ్మ
+వ్య
+వ్ర
+వ్ఱ
+వ్ల
+వ్ళ
+వ్వ
+వ్శ
+వ్ష
+వ్స
+వ్హ
+స్త్ర
+స్త్రి
+స్త్రీ
+ష్ట్ర
+షటరీ
+క్ష్మ
+క్ష్మి
diff --git a/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/indic/script-telugu/utrrs/gsub/MANIFEST
new file mode 100644 (file)
index 0000000..4b47068
--- /dev/null
@@ -0,0 +1 @@
+IndicFontFeatureGSUB.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/MANIFEST
new file mode 100644 (file)
index 0000000..9627b9e
--- /dev/null
@@ -0,0 +1 @@
+script-khmer
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/MANIFEST
new file mode 100644 (file)
index 0000000..fde3fa1
--- /dev/null
@@ -0,0 +1,3 @@
+misc.txt
+other-marks-invalid.txt
+other-marks.txt
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/misc.txt b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/misc.txt
new file mode 100644 (file)
index 0000000..945dd1d
--- /dev/null
@@ -0,0 +1,23 @@
+ខ្មែ
+ជា
+ថ្ងៃ
+មា
+ម្ពុ
+រ
+រី
+រ៍
+សៅ
+រ្ឥ
+ងឹ្ឈ
+ង្ឈឹ
+ង្គ្រ
+ង្រ្គ
+ម៉្លេះ
+ម‌៉្លេះ
+ប៊័
+នែ៎
+កេ្រ
+កៀ្រ
+កោ្រ
+កៅ្រ
+ព៑ា
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/other-marks-invalid.txt b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/other-marks-invalid.txt
new file mode 100644 (file)
index 0000000..213cfc2
--- /dev/null
@@ -0,0 +1,4 @@
+ព់្ឈា
+ព្ឈា៉
+ព្ឈា៌
+ព្ឈ៌ា
diff --git a/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/other-marks.txt b/test/shaping/texts/in-tree/shaper-indic/south-east-asian/script-khmer/misc/other-marks.txt
new file mode 100644 (file)
index 0000000..1fd350c
--- /dev/null
@@ -0,0 +1,7 @@
+ព្ឈា
+ព្ឈា់
+ព្ឈ់ា
+ព្ឈ៉ា
+ព៉្ឈា
+ព៌្ឈា
+ក៝ៈនូយ្សក៝ៈនហ៝ម់
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/MANIFEST b/test/shaping/texts/in-tree/shaper-myanmar/MANIFEST
new file mode 100644 (file)
index 0000000..895bcea
--- /dev/null
@@ -0,0 +1 @@
+script-myanmar
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/MANIFEST b/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/MANIFEST
new file mode 100644 (file)
index 0000000..b5a09c0
--- /dev/null
@@ -0,0 +1,3 @@
+misc.txt
+otspec.txt
+utn11.txt
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/misc.txt b/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/misc.txt
new file mode 100644 (file)
index 0000000..9dc6332
--- /dev/null
@@ -0,0 +1,7 @@
+သီဟိုဠ်မှ ဉာဏ်ကြီးရှင်သည် အာယုဝဍ္ဎနဆေးညွှန်းစာကို ဇလွန်ဈေးဘေးဗာဒံပင်ထက် အဓိဋ္ဌာန်လျက် ဂဃနဏဖတ်ခဲ့သည်။
+။း
+င်္၎
+နၣ်
+နၢၣ်
+ဂ်ျ
+ဂျ်
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/otspec.txt b/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/otspec.txt
new file mode 100644 (file)
index 0000000..66779cb
--- /dev/null
@@ -0,0 +1,2 @@
+င်္က္ကျြွှေို့်ာှီ့ၤဲံ့းႍ
+
diff --git a/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/utn11.txt b/test/shaping/texts/in-tree/shaper-myanmar/script-myanmar/misc/utn11.txt
new file mode 100644 (file)
index 0000000..d5cea7c
--- /dev/null
@@ -0,0 +1,34 @@
+စာ
+ခါ
+သိက္ခာ
+သဒ္ဓါ
+ညို
+ထုံး
+နေ
+ပေါ
+ဖျား
+ကြေး
+မွေး
+မှု
+ပတ္တာ
+ထင်
+ကြဉ်
+ကော်
+စင်္ကြံ
+သင်္ဘော
+ပသျှူး
+မြွှာ
+သျှောင်
+ကောင်လေးတွေကျောင်းကိုသွားကြတယ်။
+အိပ်ခန်းတံခါးကို
+အိပ်ခန်းတံ⁠ခါးကို
+အင်္ဝေ
+အငွေ
+ယောက်ျား
+ကျွန်ုပ်
+ဝါကျ
+ဂိမှာန်
+ဥယ‌ျာန
+က္လ
+ကျ္လပ်
+နိယ္အ်
diff --git a/test/shaping/texts/in-tree/shaper-sea/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/MANIFEST
new file mode 100644 (file)
index 0000000..ba95488
--- /dev/null
@@ -0,0 +1,3 @@
+script-cham
+script-new-tai-lue
+script-tai-tham
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-cham/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-cham/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/misc.txt b/test/shaping/texts/in-tree/shaper-sea/script-cham/misc/misc.txt
new file mode 100644 (file)
index 0000000..32b793a
--- /dev/null
@@ -0,0 +1,3 @@
+ꩀꨴ
+ꨗꨪꨇꨮꩃꨯꨗꨱꨧꨩꩂꨯꨨꨱꩃꨨꨮ
+ꨆꨴꨯ
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/misc.txt b/test/shaping/texts/in-tree/shaper-sea/script-new-tai-lue/misc/misc.txt
new file mode 100644 (file)
index 0000000..11224a1
--- /dev/null
@@ -0,0 +1 @@
+ᦀᦷᧃᧈ
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/MANIFEST
new file mode 100644 (file)
index 0000000..cfc4f65
--- /dev/null
@@ -0,0 +1,2 @@
+misc.txt
+torture.txt
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/misc.txt b/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/misc.txt
new file mode 100644 (file)
index 0000000..62e9317
--- /dev/null
@@ -0,0 +1,2 @@
+ᨠ᩠ᨠᩮᩕ
+ᩋᩫᨶ᩠ᨲᩕᩣ᩠ᨿ
diff --git a/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/torture.txt b/test/shaping/texts/in-tree/shaper-sea/script-tai-tham/misc/torture.txt
new file mode 100644 (file)
index 0000000..faee302
--- /dev/null
@@ -0,0 +1,23 @@
+ᨣᩕ᩵ᩣᩴᨣᩕ᩠ᩅᩁ
+ᨣᩕ᩵ᩮ᩠ᨦᨣᩕᩢ᩠ᨯ
+ᩅᩥᨣᩅᩰᩬᩡ
+ᩋᩫᨶ᩠ᨲᩕᩣ᩠ᨿ
+ᨶᩫᨶ᩠ᨲᩕᩧ
+ᩈ᩠ᨾ᩵ᩣᩴᩈ᩠ᨾᩮᩬᩥ
+ᩀᩢ᩠᩵ᨦᨶ᩶ᩣᩴ
+ᩉᩫ᩠ᨯᩉ᩠ᨿᩬᩴ᩶
+ᩅᩥᨱ᩠ᨬᩣ᩠ᨱ
+ᨠᩕᩫ᩠ᨮᩉᩫ᩠ᩅᨷᩫ᩠ᩅ
+ᨷᩴ᩠᩵ᨯᩲ᩶
+ᨷᩴ᩠᩶ᨯᩲ᩵
+ᨺᩮᩥᩢ᩠ᨠ
+ᨡᩧ᩠᩶ᨦ᩻
+ᨸᩢ᩠᩶ᨶ
+ᨵᩥᩢ᩠᩶ᨶ
+ᨷᩣ᩠ᨦ
+ᨷᩤ᩠ᨦ
+ᨻᩮᩬᩧ᩵ᩋᩉᩲ᩶
+ᨾᩨᨤᩕᩢ᩠᩵ᨦ
+ᨴᩣᩴᩋᩁᩲ
+ᩈᩢᨬ᩠ᨬᩣ
+◌ᩲ
diff --git a/test/shaping/texts/in-tree/shaper-thai/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/MANIFEST
new file mode 100644 (file)
index 0000000..32b5476
--- /dev/null
@@ -0,0 +1,2 @@
+script-lao
+script-thai
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-lao/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-lao/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-lao/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-lao/misc/MANIFEST
new file mode 100644 (file)
index 0000000..ffd16f1
--- /dev/null
@@ -0,0 +1 @@
+sara-am.txt
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-lao/misc/sara-am.txt b/test/shaping/texts/in-tree/shaper-thai/script-lao/misc/sara-am.txt
new file mode 100644 (file)
index 0000000..234d8c0
--- /dev/null
@@ -0,0 +1,20 @@
+ດຳ
+ດ໋ຳ
+ດໍ໋າ
+ດ໋ໍາ
+ມັຳ
+ມິຳ
+ມີຳ
+ມຶຳ
+ມືຳ
+ມຸຳ
+ມູຳ
+ມ຺ຳ
+ມ໇ຳ
+ມ່ຳ
+ມ້ຳ
+ມ໊ຳ
+ມ໋ຳ
+ມ໌ຳ
+ມໍຳ
+ມ໎ຳ
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-thai/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/MANIFEST
new file mode 100644 (file)
index 0000000..6b5ca6f
--- /dev/null
@@ -0,0 +1,4 @@
+misc.txt
+phinthu.txt
+pua-shaping.txt
+sara-am.txt
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/misc.txt b/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/misc.txt
new file mode 100644 (file)
index 0000000..b4f164b
--- /dev/null
@@ -0,0 +1,11 @@
+ป่ำ
+ป่ำซ้ำพ่อปู่พี่ปี่ฎุฐุญุ
+ก่ํา
+กํ่า
+กุเ
+กะ
+ก่ื
+กื
+กำ
+ก่ำ
+ก่
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/phinthu.txt b/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/phinthu.txt
new file mode 100644 (file)
index 0000000..e304777
--- /dev/null
@@ -0,0 +1,16 @@
+ป
+ปฺ
+ปุ
+ปู
+ปุู
+ปูุ
+ปฺุ
+ปฺุ
+ปฺู
+ปฺู
+ปฺุู
+ปฺุู
+ปฺุู
+ปฺูุ
+ปฺูุ
+ปฺูุ
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/pua-shaping.txt b/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/pua-shaping.txt
new file mode 100644 (file)
index 0000000..c17834b
--- /dev/null
@@ -0,0 +1,11 @@
+นี
+น่
+นี่
+น่ี
+ป็
+ญ
+ญุ
+ฝิ
+ฝิ่
+ฝ่
+ฎู
diff --git a/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/sara-am.txt b/test/shaping/texts/in-tree/shaper-thai/script-thai/misc/sara-am.txt
new file mode 100644 (file)
index 0000000..9f044ce
--- /dev/null
@@ -0,0 +1,20 @@
+ดำ
+ด๋ำ
+ดํ๋า
+ด๋ํา
+มัำ
+มิำ
+มีำ
+มึำ
+มืำ
+มุำ
+มูำ
+มฺำ
+ม็ำ
+ม่ำ
+ม้ำ
+ม๊ำ
+ม๋ำ
+ม์ำ
+มํำ
+ม๎ำ
diff --git a/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/MANIFEST b/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/MANIFEST
new file mode 100644 (file)
index 0000000..b8752e7
--- /dev/null
@@ -0,0 +1 @@
+misc
diff --git a/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/MANIFEST b/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/MANIFEST
new file mode 100644 (file)
index 0000000..29cfb2f
--- /dev/null
@@ -0,0 +1 @@
+misc.txt
diff --git a/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/misc.txt b/test/shaping/texts/in-tree/shaper-tibetan/script-tibetan/misc/misc.txt
new file mode 100644 (file)
index 0000000..a5d4082
--- /dev/null
@@ -0,0 +1,2 @@
+སྟྲཱ
+ཀ࿆ྃ
index 944b1aa..3f23bab 100644 (file)
@@ -6,9 +6,14 @@ CLEANFILES =
 DISTCLEANFILES =
 MAINTAINERCLEANFILES =
 
+# Convenience targets:
+lib:
+       @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+
 bin_PROGRAMS =
 
 AM_CPPFLAGS = \
+       -DHB_DISABLE_DEPRECATED \
        -I$(top_srcdir)/src/ \
        -I$(top_builddir)/src/ \
        $(GLIB_CFLAGS) \
@@ -23,8 +28,8 @@ LDADD = \
        $(NULL)
 
 if HAVE_GLIB
-if HAVE_FREETYPE
 
+if HAVE_FREETYPE
 if HAVE_CAIRO_FT
 hb_view_SOURCES = \
        hb-view.cc \
@@ -48,6 +53,7 @@ hb_view_LDADD = \
        $(NULL)
 bin_PROGRAMS += hb-view
 endif # HAVE_CAIRO_FT
+endif # HAVE_FREETYPE
 
 hb_shape_SOURCES = \
        hb-shape.cc \
@@ -68,7 +74,6 @@ hb_ot_shape_closure_SOURCES = \
 bin_PROGRAMS += hb-ot-shape-closure
 endif # HAVE_OT
 
-endif # HAVE_FREETYPE
 endif # HAVE_GLIB
 
 -include $(top_srcdir)/git.mk
index 873bee8..0fc3719 100644 (file)
 #include <unistd.h> /* for isatty() */
 #endif
 
+#ifdef _MSC_VER
+static inline long int
+lround (double x)
+{
+  if (x >= 0)
+    return floor (x + 0.5);
+  else
+    return ceil (x - 0.5);
+}
+#endif
+
 #define MIN(a,b) ((a) < (b) ? (a) : (b))
 
 #define CELL_W 8
@@ -146,6 +157,7 @@ struct biimage_t
   biimage_t (unsigned int width, unsigned int height) :
                width (width),
                height (height),
+               bg (0), fg (0), unicolor (true),
                data ((uint8_t *) malloc (sizeof (data[0]) * width * height)) {}
   ~biimage_t (void)
   { free (data); }
index 6dce7a1..859f9a6 100644 (file)
@@ -61,29 +61,32 @@ struct shape_closure_consumer_t : option_group_t
   }
   void consume_line (hb_buffer_t  *buffer,
                     const char   *text,
-                    unsigned int  text_len)
+                    unsigned int  text_len,
+                    const char   *text_before,
+                    const char   *text_after)
   {
     hb_set_clear (glyphs);
     shaper.shape_closure (text, text_len, font, buffer, glyphs);
 
-    if (hb_set_empty (glyphs))
+    if (hb_set_is_empty (glyphs))
       return;
 
     /* Print it out! */
     bool first = true;
     for (hb_codepoint_t i = -1; hb_set_next (glyphs, &i);)
-      if (hb_set_has (glyphs, i)) {
-        if (first)
-         first = false;
-       else
-         printf (" ");
-       char glyph_name[32];
-       if (show_glyph_names) {
-         hb_font_get_glyph_name (font, i, glyph_name, sizeof (glyph_name));
-         printf ("%s", glyph_name);
-       } else
-         printf ("%u", i);
-      }
+    {
+      if (first)
+       first = false;
+      else
+       printf (" ");
+      if (show_glyph_names)
+      {
+       char glyph_name[64];
+       hb_font_glyph_to_string (font, i, glyph_name, sizeof (glyph_name));
+       printf ("%s", glyph_name);
+      } else
+       printf ("%u", i);
+    }
   }
   void finish (const font_options_t *font_opts)
   {
@@ -107,6 +110,6 @@ struct shape_closure_consumer_t : option_group_t
 int
 main (int argc, char **argv)
 {
-  main_font_text_t<shape_closure_consumer_t> driver;
+  main_font_text_t<shape_closure_consumer_t, FONT_SIZE_NONE, 0> driver;
   return driver.main (argc, argv);
 }
index b23519b..f38f387 100644 (file)
 struct output_buffer_t
 {
   output_buffer_t (option_parser_t *parser)
-                 : options (parser),
-                   format (parser) {}
+                 : options (parser, hb_buffer_serialize_list_formats ()),
+                   format (parser),
+                   gs (NULL),
+                   line_no (0),
+                   font (NULL) {}
 
   void init (const font_options_t *font_opts)
   {
@@ -40,6 +43,34 @@ struct output_buffer_t
     gs = g_string_new (NULL);
     line_no = 0;
     font = hb_font_reference (font_opts->get_font ());
+
+    if (!options.output_format)
+      output_format = HB_BUFFER_SERIALIZE_FORMAT_TEXT;
+    else
+      output_format = hb_buffer_serialize_format_from_string (options.output_format, -1);
+    /* An empty "output_format" parameter basically skips output generating.
+     * Useful for benchmarking. */
+    if ((!options.output_format || *options.output_format) &&
+       !hb_buffer_serialize_format_to_string (output_format))
+    {
+      if (options.explicit_output_format)
+       fail (false, "Unknown output format `%s'; supported formats are: %s",
+             options.output_format,
+             g_strjoinv ("/", const_cast<char**> (options.supported_formats)));
+      else
+       /* Just default to TEXT if not explicitly requested and the
+        * file extension is not recognized. */
+       output_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;
+    format_flags = (hb_buffer_serialize_flags_t) flags;
   }
   void new_line (void)
   {
@@ -51,7 +82,7 @@ struct output_buffer_t
                     hb_bool_t     utf8_clusters)
   {
     g_string_set_size (gs, 0);
-    format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, utf8_clusters, gs);
+    format.serialize_buffer_of_text (buffer, line_no, text, text_len, font, gs);
     fprintf (options.fp, "%s", gs->str);
   }
   void shape_failed (hb_buffer_t  *buffer,
@@ -69,7 +100,8 @@ struct output_buffer_t
                       hb_bool_t     utf8_clusters)
   {
     g_string_set_size (gs, 0);
-    format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font, utf8_clusters, gs);
+    format.serialize_buffer_of_glyphs (buffer, line_no, text, text_len, font,
+                                      output_format, format_flags, gs);
     fprintf (options.fp, "%s", gs->str);
   }
   void finish (const font_options_t *font_opts)
@@ -87,11 +119,13 @@ struct output_buffer_t
   GString *gs;
   unsigned int line_no;
   hb_font_t *font;
+  hb_buffer_serialize_format_t output_format;
+  hb_buffer_serialize_flags_t format_flags;
 };
 
 int
 main (int argc, char **argv)
 {
-  main_font_text_t<shape_consumer_t<output_buffer_t> > driver;
+  main_font_text_t<shape_consumer_t<output_buffer_t>, FONT_SIZE_UPEM, 0> driver;
   return driver.main (argc, argv);
 }
index 26fad66..ef75e6d 100644 (file)
 #include "shape-consumer.hh"
 #include "view-cairo.hh"
 
+#define DEFAULT_FONT_SIZE 256
+#define SUBPIXEL_BITS 8
+
 int
 main (int argc, char **argv)
 {
-  main_font_text_t<shape_consumer_t<view_cairo_t> > driver;
+  main_font_text_t<shape_consumer_t<view_cairo_t>, DEFAULT_FONT_SIZE, SUBPIXEL_BITS> driver;
   return driver.main (argc, argv);
 }
index f7c0660..50f9eb4 100644 (file)
@@ -57,16 +57,16 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t  *surface,
     cairo_surface_reference (surface);
 
   unsigned int stride = cairo_image_surface_get_stride (surface);
-  const uint32_t *data = (uint32_t *) cairo_image_surface_get_data (surface);
+  const uint32_t *data = (uint32_t *) (void *) cairo_image_surface_get_data (surface);
 
   /* We don't have rows to spare on the terminal window...
    * Find the tight image top/bottom and only print in between. */
 
   /* Use corner color as background color. */
-  uint32_t bg_color = * (uint32_t *) data;
+  uint32_t bg_color = data ? * (uint32_t *) data : 0;
 
   /* Drop first row while empty */
-  while (height) 
+  while (height)
   {
     unsigned int i;
     for (i = 0; i < width; i++)
index 0cdfd63..d576c3f 100644 (file)
@@ -60,19 +60,43 @@ _cairo_eps_surface_create_for_stream (cairo_write_func_t  write_func,
 #  endif
 #endif
 
+
+static FT_Library ft_library;
+
+static inline
+void free_ft_library (void)
+{
+  FT_Done_FreeType (ft_library);
+}
+
 cairo_scaled_font_t *
-helper_cairo_create_scaled_font (const font_options_t *font_opts,
-                                double font_size)
+helper_cairo_create_scaled_font (const font_options_t *font_opts)
 {
   hb_font_t *font = hb_font_reference (font_opts->get_font ());
 
   cairo_font_face_t *cairo_face;
   FT_Face ft_face = 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
+    }
+    FT_New_Face (ft_library,
+                font_opts->font_file,
+                font_opts->face_index,
+                &ft_face);
+  }
+  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
     cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
   cairo_matrix_t ctm, font_matrix;
@@ -80,7 +104,8 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts,
 
   cairo_matrix_init_identity (&ctm);
   cairo_matrix_init_scale (&font_matrix,
-                          font_size, font_size);
+                          font_opts->font_size_x,
+                          font_opts->font_size_y);
   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);
@@ -246,6 +271,27 @@ stdio_write_func (void                *closure,
   return CAIRO_STATUS_SUCCESS;
 }
 
+const char *helper_cairo_supported_formats[] =
+{
+  "ansi",
+  #ifdef CAIRO_HAS_PNG_FUNCTIONS
+  "png",
+  #endif
+  #ifdef CAIRO_HAS_SVG_SURFACE
+  "svg",
+  #endif
+  #ifdef CAIRO_HAS_PDF_SURFACE
+  "pdf",
+  #endif
+  #ifdef CAIRO_HAS_PS_SURFACE
+  "ps",
+   #ifdef HAS_EPS
+    "eps",
+   #endif
+  #endif
+  NULL
+};
+
 cairo_t *
 helper_cairo_create_context (double w, double h,
                             view_options_t *view_opts,
@@ -268,7 +314,13 @@ helper_cairo_create_context (double w, double h,
       extension = "ansi";
     else
 #endif
+    {
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
       extension = "png";
+#else
+      extension = "ansi";
+#endif
+    }
   }
   if (0)
     ;
@@ -317,7 +369,11 @@ helper_cairo_create_context (double w, double h,
   else if (constructor2)
     surface = constructor2 (stdio_write_func, f, w, h, content);
   else
-    fail (false, "Unknown output format `%s'", extension);
+    fail (false, "Unknown output format `%s'; supported formats are: %s%s",
+         extension,
+         g_strjoinv ("/", const_cast<char**> (helper_cairo_supported_formats)),
+         out_opts->explicit_output_format ? "" :
+         "\nTry setting format using --output-format");
 
   cairo_t *cr = cairo_create (surface);
   content = cairo_surface_get_content (surface);
@@ -367,7 +423,7 @@ helper_cairo_line_from_buffer (helper_cairo_line_t *l,
                               hb_buffer_t         *buffer,
                               const char          *text,
                               unsigned int         text_len,
-                              double               scale,
+                              int                  scale_bits,
                               hb_bool_t            utf8_clusters)
 {
   memset (l, 0, sizeof (*l));
@@ -400,23 +456,23 @@ helper_cairo_line_from_buffer (helper_cairo_line_t *l,
   for (i = 0; i < (int) l->num_glyphs; i++)
   {
     l->glyphs[i].index = hb_glyph[i].codepoint;
-    l->glyphs[i].x = ( hb_position->x_offset + x) * scale;
-    l->glyphs[i].y = (-hb_position->y_offset + y) * scale;
+    l->glyphs[i].x = scalbn ( hb_position->x_offset + x, scale_bits);
+    l->glyphs[i].y = scalbn (-hb_position->y_offset + y, scale_bits);
     x +=  hb_position->x_advance;
     y += -hb_position->y_advance;
 
     hb_position++;
   }
   l->glyphs[i].index = -1;
-  l->glyphs[i].x = x * scale;
-  l->glyphs[i].y = y * scale;
+  l->glyphs[i].x = scalbn (x, scale_bits);
+  l->glyphs[i].y = scalbn (y, scale_bits);
 
   if (l->num_clusters) {
     memset ((void *) l->clusters, 0, l->num_clusters * sizeof (l->clusters[0]));
     hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
     l->cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
     unsigned int cluster = 0;
-    const char *start = l->utf8, *end = start;
+    const char *start = l->utf8, *end;
     l->clusters[cluster].num_glyphs++;
     if (backward) {
       for (i = l->num_glyphs - 2; i >= 0; i--) {
index 2f2c9d4..ed55a45 100644 (file)
@@ -33,9 +33,9 @@
 
 
 cairo_scaled_font_t *
-helper_cairo_create_scaled_font (const font_options_t *font_opts,
-                                double font_size);
+helper_cairo_create_scaled_font (const font_options_t *font_opts);
 
+extern const char *helper_cairo_supported_formats[];
 
 cairo_t *
 helper_cairo_create_context (double w, double h,
@@ -75,7 +75,7 @@ helper_cairo_line_from_buffer (helper_cairo_line_t *l,
                               hb_buffer_t         *buffer,
                               const char          *text,
                               unsigned int         text_len,
-                              double               scale,
+                              int                  scale_bits,
                               hb_bool_t            utf8_clusters);
 
 #endif
index 44e3bfb..628cdf9 100644 (file)
 
 /* main() body for utilities taking font and processing text.*/
 
-template <typename consumer_t>
+template <typename consumer_t, int default_font_size, int subpixel_bits>
 struct main_font_text_t
 {
   main_font_text_t (void)
                  : options ("[FONT-FILE] [TEXT]"),
-                   font_opts (&options),
+                   font_opts (&options, default_font_size, subpixel_bits),
                    input (&options),
                    consumer (&options) {}
 
@@ -61,7 +61,7 @@ struct main_font_text_t
     unsigned int text_len;
     const char *text;
     while ((text = input.get_line (&text_len)))
-      consumer.consume_line (buffer, text, text_len);
+      consumer.consume_line (buffer, text, text_len, input.text_before, input.text_after);
     hb_buffer_destroy (buffer);
 
     consumer.finish (&font_opts);
index db1b244..7387a56 100644 (file)
 #ifdef HAVE_FREETYPE
 #include <hb-ft.h>
 #endif
+#ifdef HAVE_OT
+#include <hb-ot-font.h>
+#endif
+
+struct supported_font_funcs_t {
+       char name[4];
+       void (*func) (hb_font_t *);
+} supported_font_funcs[] =
+{
+#ifdef HAVE_FREETYPE
+  {"ft",       hb_ft_font_set_funcs},
+#endif
+#ifdef HAVE_OT
+  {"ot",       hb_ot_font_set_funcs},
+#endif
+};
 
 
 void
@@ -39,6 +55,7 @@ fail (hb_bool_t suggest_help, const char *format, ...)
   va_list vap;
   va_start (vap, format);
   msg = g_strdup_vprintf (format, vap);
+  va_end (vap);
   const char *prgname = g_get_prgname ();
   g_printerr ("%s: %s\n", prgname, msg);
   if (suggest_help)
@@ -178,7 +195,7 @@ parse_shapers (const char *name G_GNUC_UNUSED,
               GError    **error G_GNUC_UNUSED)
 {
   shape_options_t *shape_opts = (shape_options_t *) data;
-  g_free (shape_opts->shapers);
+  g_strfreev (shape_opts->shapers);
   shape_opts->shapers = g_strsplit (arg, ",", 0);
   return true;
 }
@@ -196,130 +213,6 @@ list_shapers (const char *name G_GNUC_UNUSED,
 }
 
 
-
-static void
-parse_space (char **pp)
-{
-  char c;
-#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v')
-  while (c = **pp, ISSPACE (c))
-    (*pp)++;
-#undef ISSPACE
-}
-
-static hb_bool_t
-parse_char (char **pp, char c)
-{
-  parse_space (pp);
-
-  if (**pp != c)
-    return false;
-
-  (*pp)++;
-  return true;
-}
-
-static hb_bool_t
-parse_uint (char **pp, unsigned int *pv)
-{
-  char *p = *pp;
-  unsigned int v;
-
-  v = strtol (p, pp, 0);
-
-  if (p == *pp)
-    return false;
-
-  *pv = v;
-  return true;
-}
-
-
-static hb_bool_t
-parse_feature_value_prefix (char **pp, hb_feature_t *feature)
-{
-  if (parse_char (pp, '-'))
-    feature->value = 0;
-  else {
-    parse_char (pp, '+');
-    feature->value = 1;
-  }
-
-  return true;
-}
-
-static hb_bool_t
-parse_feature_tag (char **pp, hb_feature_t *feature)
-{
-  char *p = *pp, c;
-
-  parse_space (pp);
-
-#define ISALNUM(c) (('a' <= (c) && (c) <= 'z') || ('A' <= (c) && (c) <= 'Z') || ('0' <= (c) && (c) <= '9'))
-  while (c = **pp, ISALNUM(c))
-    (*pp)++;
-#undef ISALNUM
-
-  if (p == *pp)
-    return false;
-
-  feature->tag = hb_tag_from_string (p, *pp - p);
-  return true;
-}
-
-static hb_bool_t
-parse_feature_indices (char **pp, hb_feature_t *feature)
-{
-  parse_space (pp);
-
-  hb_bool_t has_start;
-
-  feature->start = 0;
-  feature->end = (unsigned int) -1;
-
-  if (!parse_char (pp, '['))
-    return true;
-
-  has_start = parse_uint (pp, &feature->start);
-
-  if (parse_char (pp, ':')) {
-    parse_uint (pp, &feature->end);
-  } else {
-    if (has_start)
-      feature->end = feature->start + 1;
-  }
-
-  return parse_char (pp, ']');
-}
-
-static hb_bool_t
-parse_feature_value_postfix (char **pp, hb_feature_t *feature)
-{
-  return !parse_char (pp, '=') || parse_uint (pp, &feature->value);
-}
-
-
-static hb_bool_t
-parse_one_feature (char **pp, hb_feature_t *feature)
-{
-  return parse_feature_value_prefix (pp, feature) &&
-        parse_feature_tag (pp, feature) &&
-        parse_feature_indices (pp, feature) &&
-        parse_feature_value_postfix (pp, feature) &&
-        (parse_char (pp, ',') || **pp == '\0');
-}
-
-static void
-skip_one_feature (char **pp)
-{
-  char *e;
-  e = strchr (*pp, ',');
-  if (e)
-    *pp = e + 1;
-  else
-    *pp = *pp + strlen (*pp);
-}
-
 static gboolean
 parse_features (const char *name G_GNUC_UNUSED,
                const char *arg,
@@ -351,11 +244,11 @@ parse_features (const char *name G_GNUC_UNUSED,
   /* now do the actual parsing */
   p = s;
   shape_opts->num_features = 0;
-  while (*p) {
-    if (parse_one_feature (&p, &shape_opts->features[shape_opts->num_features]))
+  while (p && *p) {
+    char *end = strchr (p, ',');
+    if (hb_feature_from_string (p, end ? end - p : -1, &shape_opts->features[shape_opts->num_features]))
       shape_opts->num_features++;
-    else
-      skip_one_feature (&p);
+    p = end ? end + 1 : NULL;
   }
 
   return true;
@@ -368,11 +261,10 @@ view_options_t::add_options (option_parser_t *parser)
   GOptionEntry entries[] =
   {
     {"annotate",       0, 0, G_OPTION_ARG_NONE,        &this->annotate,                "Annotate output rendering",                            NULL},
-    {"background",     0, 0, G_OPTION_ARG_STRING,      &this->back,                    "Set background color (default: "DEFAULT_BACK")",       "red/#rrggbb/#rrggbbaa"},
-    {"foreground",     0, 0, G_OPTION_ARG_STRING,      &this->fore,                    "Set foreground color (default: "DEFAULT_FORE")",       "red/#rrggbb/#rrggbbaa"},
+    {"background",     0, 0, G_OPTION_ARG_STRING,      &this->back,                    "Set background color (default: " DEFAULT_BACK ")",     "rrggbb/rrggbbaa"},
+    {"foreground",     0, 0, G_OPTION_ARG_STRING,      &this->fore,                    "Set foreground color (default: " DEFAULT_FORE ")",     "rrggbb/rrggbbaa"},
     {"line-space",     0, 0, G_OPTION_ARG_DOUBLE,      &this->line_space,              "Set space between lines (default: 0)",                 "units"},
-    {"margin",         0, 0, G_OPTION_ARG_CALLBACK,    (gpointer) &parse_margin,       "Margin around output (default: "G_STRINGIFY(DEFAULT_MARGIN)")","one to four numbers"},
-    {"font-size",      0, 0, G_OPTION_ARG_DOUBLE,      &this->font_size,               "Font size (default: "G_STRINGIFY(DEFAULT_FONT_SIZE)")","size"},
+    {"margin",         0, 0, G_OPTION_ARG_CALLBACK,    (gpointer) &parse_margin,       "Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"},
     {NULL}
   };
   parser->add_group (entries,
@@ -391,11 +283,16 @@ shape_options_t::add_options (option_parser_t *parser)
                              G_OPTION_ARG_CALLBACK,    (gpointer) &list_shapers,       "List available shapers and quit",      NULL},
     {"shaper",         0, G_OPTION_FLAG_HIDDEN,
                              G_OPTION_ARG_CALLBACK,    (gpointer) &parse_shapers,      "Hidden duplicate of --shapers",        NULL},
-    {"shapers",                0, 0, G_OPTION_ARG_CALLBACK,    (gpointer) &parse_shapers,      "Comma-separated list of shapers to try","list"},
+    {"shapers",                0, 0, G_OPTION_ARG_CALLBACK,    (gpointer) &parse_shapers,      "Set comma-separated list of shapers to try","list"},
     {"direction",      0, 0, G_OPTION_ARG_STRING,      &this->direction,               "Set text direction (default: auto)",   "ltr/rtl/ttb/btt"},
     {"language",       0, 0, G_OPTION_ARG_STRING,      &this->language,                "Set text language (default: $LANG)",   "langstr"},
     {"script",         0, 0, G_OPTION_ARG_STRING,      &this->script,                  "Set text script (default: auto)",      "ISO-15924 tag"},
+    {"bot",            0, 0, G_OPTION_ARG_NONE,        &this->bot,                     "Treat text as beginning-of-paragraph", NULL},
+    {"eot",            0, 0, G_OPTION_ARG_NONE,        &this->eot,                     "Treat text as end-of-paragraph",       NULL},
+    {"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE,    &this->preserve_default_ignorables,     "Preserve Default-Ignorable characters",        NULL},
     {"utf8-clusters",  0, 0, G_OPTION_ARG_NONE,        &this->utf8_clusters,           "Use UTF8 byte indices, not char indices",      NULL},
+    {"normalize-glyphs",0, 0, G_OPTION_ARG_NONE,       &this->normalize_glyphs,        "Rearrange glyph clusters in nominal order",    NULL},
+    {"num-iterations", 0, 0, G_OPTION_ARG_INT,         &this->num_iterations,          "Run shaper N times (default: 1)",      "N"},
     {NULL}
   };
   parser->add_group (entries,
@@ -407,7 +304,9 @@ shape_options_t::add_options (option_parser_t *parser)
   const gchar *features_help = "Comma-separated list of font features\n"
     "\n"
     "    Features can be enabled or disabled, either globally or limited to\n"
-    "    specific character ranges.\n"
+    "    specific character ranges.  The format for specifying feature settings\n"
+    "    follows.  All valid CSS font-feature-settings values other than 'normal'\n"
+    "    and 'inherited' are also accepted, though, not documented below.\n"
     "\n"
     "    The range indices refer to the positions between Unicode characters,\n"
     "    unless the --utf8-clusters is provided, in which case range indices\n"
@@ -436,7 +335,7 @@ shape_options_t::add_options (option_parser_t *parser)
     "\n"
     "    Mixing it all:\n"
     "\n"
-    "      \"kern[3:5]=0\" 1         3         5         # Turn feature off for range";
+    "      \"aalt[3:5]=2\" 2         3         5         # Turn 2nd alternate on for range";
 
   GOptionEntry entries2[] =
   {
@@ -450,13 +349,64 @@ shape_options_t::add_options (option_parser_t *parser)
                     this);
 }
 
+static gboolean
+parse_font_size (const char *name G_GNUC_UNUSED,
+                const char *arg,
+                gpointer    data,
+                GError    **error G_GNUC_UNUSED)
+{
+  font_options_t *font_opts = (font_options_t *) data;
+  if (0 == strcmp (arg, "upem"))
+  {
+    font_opts->font_size_y = font_opts->font_size_x = FONT_SIZE_UPEM;
+    return true;
+  }
+  switch (sscanf (arg, "%lf %lf", &font_opts->font_size_x, &font_opts->font_size_y)) {
+    case 1: font_opts->font_size_y = font_opts->font_size_x;
+    case 2: return true;
+    default:
+      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
+                  "%s argument should be one to four space-separated numbers",
+                  name);
+      return false;
+  }
+}
 void
 font_options_t::add_options (option_parser_t *parser)
 {
+  char *text = NULL;
+
+  {
+    ASSERT_STATIC (ARRAY_LENGTH_CONST (supported_font_funcs) > 0);
+    GString *s = g_string_new (NULL);
+    g_string_printf (s, "Set font functions implementation to use (default: %s)\n\n    Supported font function implementations are: %s",
+                    supported_font_funcs[0].name,
+                    supported_font_funcs[0].name);
+    for (unsigned int i = 1; i < ARRAY_LENGTH (supported_font_funcs); i++)
+    {
+      g_string_append_c (s, '/');
+      g_string_append (s, supported_font_funcs[i].name);
+    }
+    text = g_string_free (s, FALSE);
+    parser->free_later (text);
+  }
+
+  char *font_size_text;
+  if (default_font_size == FONT_SIZE_UPEM)
+    font_size_text = (char *) "Font size (default: upem)";
+  else
+  {
+    font_size_text = g_strdup_printf ("Font size (default: %d)", default_font_size);
+    parser->free_later (font_size_text);
+  }
+
   GOptionEntry entries[] =
   {
-    {"font-file",      0, 0, G_OPTION_ARG_STRING,      &this->font_file,               "Font file-name",                                       "filename"},
-    {"face-index",     0, 0, G_OPTION_ARG_INT,         &this->face_index,              "Face index (default: 0)",                              "index"},
+    {"font-file",      0, 0, G_OPTION_ARG_STRING,      &this->font_file,               "Set font file-name",                   "filename"},
+    {"face-index",     0, 0, G_OPTION_ARG_INT,         &this->face_index,              "Set face index (default: 0)",          "index"},
+    {"font-size",      0, default_font_size ? 0 : G_OPTION_FLAG_HIDDEN,
+                             G_OPTION_ARG_CALLBACK,    (gpointer) &parse_font_size,    font_size_text,                         "1/2 numbers or 'upem'"},
+    {"font-funcs",     0, 0, G_OPTION_ARG_STRING,      &this->font_funcs,              text,                                   "impl"},
     {NULL}
   };
   parser->add_group (entries,
@@ -472,7 +422,9 @@ text_options_t::add_options (option_parser_t *parser)
   GOptionEntry entries[] =
   {
     {"text",           0, 0, G_OPTION_ARG_STRING,      &this->text,                    "Set input text",                       "string"},
-    {"text-file",      0, 0, G_OPTION_ARG_STRING,      &this->text_file,               "Set input text file-name\n\n    If no text is provided, standard input is used for input.",            "filename"},
+    {"text-file",      0, 0, G_OPTION_ARG_STRING,      &this->text_file,               "Set input text file-name\n\n    If no text is provided, standard input is used for input.\n",          "filename"},
+    {"text-before",    0, 0, G_OPTION_ARG_STRING,      &this->text_before,             "Set text context before each line",    "string"},
+    {"text-after",     0, 0, G_OPTION_ARG_STRING,      &this->text_after,              "Set text context after each line",     "string"},
     {NULL}
   };
   parser->add_group (entries,
@@ -485,10 +437,22 @@ text_options_t::add_options (option_parser_t *parser)
 void
 output_options_t::add_options (option_parser_t *parser)
 {
+  const char *text;
+
+  if (NULL == supported_formats)
+    text = "Set output format";
+  else
+  {
+    char *items = g_strjoinv ("/", const_cast<char **> (supported_formats));
+    text = g_strdup_printf ("Set output format\n\n    Supported output formats are: %s", items);
+    g_free (items);
+    parser->free_later ((char *) text);
+  }
+
   GOptionEntry entries[] =
   {
     {"output-file",    0, 0, G_OPTION_ARG_STRING,      &this->output_file,             "Set output file-name (default: stdout)","filename"},
-    {"output-format",  0, 0, G_OPTION_ARG_STRING,      &this->output_format,           "Set output format",                    "format"},
+    {"output-format",  0, 0, G_OPTION_ARG_STRING,      &this->output_format,           text,                                   "format"},
     {NULL}
   };
   parser->add_group (entries,
@@ -524,8 +488,8 @@ font_options_t::get_font (void) const
       /* read it */
       GString *gs = g_string_new (NULL);
       char buf[BUFSIZ];
-#ifdef HAVE__SETMODE
-      _setmode (fileno (stdin), _O_BINARY);
+#if defined(_WIN32) || defined(__CYGWIN__)
+      setmode (fileno (stdin), _O_BINARY);
 #endif
       while (!feof (stdin)) {
        size_t ret = fread (buf, 1, sizeof (buf), stdin);
@@ -583,13 +547,47 @@ font_options_t::get_font (void) const
 
   font = hb_font_create (face);
 
-  unsigned int upem = hb_face_get_upem (face);
-  hb_font_set_scale (font, upem, upem);
+  if (font_size_x == FONT_SIZE_UPEM)
+    font_size_x = hb_face_get_upem (face);
+  if (font_size_y == FONT_SIZE_UPEM)
+    font_size_y = hb_face_get_upem (face);
+
+  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);
   hb_face_destroy (face);
 
-#ifdef HAVE_FREETYPE
-  hb_ft_font_set_funcs (font);
-#endif
+  void (*set_font_funcs) (hb_font_t *) = NULL;
+  if (!font_funcs)
+  {
+    set_font_funcs = supported_font_funcs[0].func;
+  }
+  else
+  {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+      if (0 == strcasecmp (font_funcs, supported_font_funcs[i].name))
+      {
+       set_font_funcs = supported_font_funcs[i].func;
+       break;
+      }
+    if (!set_font_funcs)
+    {
+      GString *s = g_string_new (NULL);
+      for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++)
+      {
+        if (i)
+         g_string_append_c (s, '/');
+       g_string_append (s, supported_font_funcs[i].name);
+      }
+      char *p = g_string_free (s, FALSE);
+      fail (false, "Unknown font function implementation `%s'; supported values are: %s; default is %s",
+           font_funcs,
+           p,
+           supported_font_funcs[0].name);
+      //free (p);
+    }
+  }
+  set_font_funcs (font);
 
   return font;
 }
@@ -668,8 +666,8 @@ output_options_t::get_file_handle (void)
   if (output_file)
     fp = fopen (output_file, "wb");
   else {
-#ifdef HAVE__SETMODE
-    _setmode (fileno (stdout), _O_BINARY);
+#if defined(_WIN32) || defined(__CYGWIN__)
+    setmode (fileno (stdout), _O_BINARY);
 #endif
     fp = stdout;
   }
@@ -733,45 +731,23 @@ format_options_t::serialize_unicode (hb_buffer_t *buffer,
 void
 format_options_t::serialize_glyphs (hb_buffer_t *buffer,
                                    hb_font_t   *font,
-                                   hb_bool_t    utf8_clusters,
+                                   hb_buffer_serialize_format_t output_format,
+                                   hb_buffer_serialize_flags_t flags,
                                    GString     *gs)
 {
-  unsigned int num_glyphs = hb_buffer_get_length (buffer);
-  hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
-  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
-
   g_string_append_c (gs, '[');
-  for (unsigned int i = 0; i < num_glyphs; i++)
-  {
-    if (i)
-      g_string_append_c (gs, '|');
-
-    char glyph_name[32];
-    if (show_glyph_names) {
-      hb_font_get_glyph_name (font, info->codepoint, glyph_name, sizeof (glyph_name));
-      g_string_append_printf (gs, "%s", glyph_name);
-    } else
-      g_string_append_printf (gs, "%u", info->codepoint);
-
-    if (show_clusters) {
-      g_string_append_printf (gs, "=%u", info->cluster);
-      if (utf8_clusters)
-       g_string_append (gs, "u8");
-    }
-
-    if (show_positions && (pos->x_offset || pos->y_offset)) {
-      g_string_append_c (gs, '@');
-      if (pos->x_offset) g_string_append_printf (gs, "%d", pos->x_offset);
-      if (pos->y_offset) g_string_append_printf (gs, ",%d", pos->y_offset);
-    }
-    if (show_positions && (pos->x_advance || pos->y_advance)) {
-      g_string_append_c (gs, '+');
-      if (pos->x_advance) g_string_append_printf (gs, "%d", pos->x_advance);
-      if (pos->y_advance) g_string_append_printf (gs, ",%d", pos->y_advance);
-    }
-
-    info++;
-    pos++;
+  unsigned int num_glyphs = hb_buffer_get_length (buffer);
+  unsigned int start = 0;
+
+  while (start < num_glyphs) {
+    char buf[1024];
+    unsigned int consumed;
+    start += hb_buffer_serialize_glyphs (buffer, start, num_glyphs,
+                                        buf, sizeof (buf), &consumed,
+                                        font, output_format, flags);
+    if (!consumed)
+      break;
+    g_string_append (gs, buf);
   }
   g_string_append_c (gs, ']');
 }
@@ -788,7 +764,6 @@ format_options_t::serialize_buffer_of_text (hb_buffer_t  *buffer,
                                            const char   *text,
                                            unsigned int  text_len,
                                            hb_font_t    *font,
-                                           hb_bool_t     utf8_clusters,
                                            GString      *gs)
 {
   if (show_text) {
@@ -820,10 +795,11 @@ format_options_t::serialize_buffer_of_glyphs (hb_buffer_t  *buffer,
                                              const char   *text,
                                              unsigned int  text_len,
                                              hb_font_t    *font,
-                                             hb_bool_t     utf8_clusters,
+                                             hb_buffer_serialize_format_t output_format,
+                                             hb_buffer_serialize_flags_t format_flags,
                                              GString      *gs)
 {
   serialize_line_no (line_no, gs);
-  serialize_glyphs (buffer, font, utf8_clusters, gs);
+  serialize_glyphs (buffer, font, output_format, format_flags, gs);
   g_string_append_c (gs, '\n');
 }
index 9b7baa7..8b9b10e 100644 (file)
@@ -43,8 +43,8 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h> /* for isatty() */
 #endif
-#ifdef HAVE_IO_H
-#include <io.h> /* for _setmode() under Windows */
+#if defined(_WIN32) || defined(__CYGWIN__)
+#include <io.h> /* for setmode() under Windows */
 #endif
 
 #include <hb.h>
 #include <glib.h>
 #include <glib/gprintf.h>
 
+#if !GLIB_CHECK_VERSION (2, 22, 0)
+# define g_mapped_file_unref g_mapped_file_free
+#endif
+
+
+/* A few macros copied from hb-private.hh. */
+
+#if __GNUC__ >= 4
+#define HB_UNUSED      __attribute__((unused))
+#else
+#define HB_UNUSED
+#endif
+
 #undef MIN
 template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
 
 #undef MAX
 template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
 
+#undef  ARRAY_LENGTH
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
+/* A const version, but does not detect erratically being called on pointers. */
+#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+
+#define _ASSERT_STATIC1(_line, _cond)  HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC0(_line, _cond)  _ASSERT_STATIC1 (_line, (_cond))
+#define ASSERT_STATIC(_cond)           _ASSERT_STATIC0 (__LINE__, (_cond))
+
 
-void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN;
+void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GNUC_PRINTF (2, 3);
 
 
 extern hb_bool_t debug;
@@ -81,11 +104,14 @@ struct option_parser_t
     memset (this, 0, sizeof (*this));
     usage_str = usage;
     context = g_option_context_new (usage);
+    to_free = g_ptr_array_new ();
 
     add_main_options ();
   }
   ~option_parser_t (void) {
     g_option_context_free (context);
+    g_ptr_array_foreach (to_free, (GFunc) g_free, NULL);
+    g_ptr_array_free (to_free, TRUE);
   }
 
   void add_main_options (void);
@@ -96,6 +122,10 @@ struct option_parser_t
                  const gchar    *help_description,
                  option_group_t *option_group);
 
+  void free_later (char *p) {
+    g_ptr_array_add (to_free, p);
+  }
+
   void parse (int *argc, char ***argv);
 
   G_GNUC_NORETURN void usage (void) {
@@ -103,15 +133,18 @@ struct option_parser_t
     exit (1);
   }
 
+  private:
   const char *usage_str;
   GOptionContext *context;
+  GPtrArray *to_free;
 };
 
 
 #define DEFAULT_MARGIN 16
 #define DEFAULT_FORE "#000000"
 #define DEFAULT_BACK "#FFFFFF"
-#define DEFAULT_FONT_SIZE 256
+#define FONT_SIZE_UPEM 0x7FFFFFFF
+#define FONT_SIZE_NONE 0
 
 struct view_options_t : option_group_t
 {
@@ -121,7 +154,6 @@ struct view_options_t : option_group_t
     back = DEFAULT_BACK;
     line_space = 0;
     margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN;
-    font_size = DEFAULT_FONT_SIZE;
 
     add_options (parser);
   }
@@ -135,7 +167,6 @@ struct view_options_t : option_group_t
   struct margin_t {
     double t, r, b, l;
   } margin;
-  double font_size;
 };
 
 
@@ -144,17 +175,20 @@ struct shape_options_t : option_group_t
   shape_options_t (option_parser_t *parser)
   {
     direction = language = script = NULL;
+    bot = eot = preserve_default_ignorables = false;
     features = NULL;
     num_features = 0;
     shapers = NULL;
     utf8_clusters = false;
+    normalize_glyphs = false;
+    num_iterations = 1;
 
     add_options (parser);
   }
   ~shape_options_t (void)
   {
     free (features);
-    g_free (shapers);
+    g_strfreev (shapers);
   }
 
   void add_options (option_parser_t *parser);
@@ -164,12 +198,25 @@ struct shape_options_t : option_group_t
     hb_buffer_set_direction (buffer, hb_direction_from_string (direction, -1));
     hb_buffer_set_script (buffer, hb_script_from_string (script, -1));
     hb_buffer_set_language (buffer, hb_language_from_string (language, -1));
+    hb_buffer_set_flags (buffer, (hb_buffer_flags_t) (HB_BUFFER_FLAG_DEFAULT |
+                        (bot ? HB_BUFFER_FLAG_BOT : 0) |
+                        (eot ? HB_BUFFER_FLAG_EOT : 0) |
+                        (preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0)));
+    hb_buffer_guess_segment_properties (buffer);
   }
 
-  void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len)
+  void populate_buffer (hb_buffer_t *buffer, const char *text, int text_len,
+                       const char *text_before, const char *text_after)
   {
-    hb_buffer_reset (buffer);
+    hb_buffer_clear_contents (buffer);
+    if (text_before) {
+      unsigned int len = strlen (text_before);
+      hb_buffer_add_utf8 (buffer, text_before, len, len, 0);
+    }
     hb_buffer_add_utf8 (buffer, text, text_len, 0, text_len);
+    if (text_after) {
+      hb_buffer_add_utf8 (buffer, text_after, -1, 0, 0);
+    }
 
     if (!utf8_clusters) {
       /* Reset cluster values to refer to Unicode character index
@@ -188,7 +235,10 @@ struct shape_options_t : option_group_t
 
   hb_bool_t shape (hb_font_t *font, hb_buffer_t *buffer)
   {
-    return hb_shape_full (font, buffer, features, num_features, shapers);
+    hb_bool_t res = hb_shape_full (font, buffer, features, num_features, shapers);
+    if (normalize_glyphs)
+      hb_buffer_normalize_glyphs (buffer);
+    return res;
   }
 
   void shape_closure (const char *text, int text_len,
@@ -201,21 +251,36 @@ struct shape_options_t : option_group_t
     hb_ot_shape_glyphs_closure (font, buffer, features, num_features, glyphs);
   }
 
+  /* Buffer properties */
   const char *direction;
   const char *language;
   const char *script;
+
+  /* Buffer flags */
+  hb_bool_t bot;
+  hb_bool_t eot;
+  hb_bool_t preserve_default_ignorables;
+
   hb_feature_t *features;
   unsigned int num_features;
   char **shapers;
   hb_bool_t utf8_clusters;
+  hb_bool_t normalize_glyphs;
+  unsigned int num_iterations;
 };
 
 
 struct font_options_t : option_group_t
 {
-  font_options_t (option_parser_t *parser) {
+  font_options_t (option_parser_t *parser,
+                 int default_font_size_,
+                 unsigned int subpixel_bits_) {
+    default_font_size = default_font_size_;
+    subpixel_bits = subpixel_bits_;
     font_file = NULL;
     face_index = 0;
+    font_size_x = font_size_y = default_font_size;
+    font_funcs = NULL;
 
     font = NULL;
 
@@ -231,6 +296,11 @@ struct font_options_t : option_group_t
 
   const char *font_file;
   int face_index;
+  int default_font_size;
+  unsigned int subpixel_bits;
+  mutable double font_size_x;
+  mutable double font_size_y;
+  const char *font_funcs;
 
   private:
   mutable hb_font_t *font;
@@ -240,6 +310,9 @@ struct font_options_t : option_group_t
 struct text_options_t : option_group_t
 {
   text_options_t (option_parser_t *parser) {
+    text_before = NULL;
+    text_after = NULL;
+
     text = NULL;
     text_file = NULL;
 
@@ -268,6 +341,9 @@ struct text_options_t : option_group_t
 
   const char *get_line (unsigned int *len);
 
+  const char *text_before;
+  const char *text_after;
+
   const char *text;
   const char *text_file;
 
@@ -279,9 +355,12 @@ struct text_options_t : option_group_t
 
 struct output_options_t : option_group_t
 {
-  output_options_t (option_parser_t *parser) {
+  output_options_t (option_parser_t *parser,
+                   const char **supported_formats_ = NULL) {
     output_file = NULL;
     output_format = NULL;
+    supported_formats = supported_formats_;
+    explicit_output_format = false;
 
     fp = NULL;
 
@@ -296,6 +375,9 @@ struct output_options_t : option_group_t
 
   void post_parse (GError **error G_GNUC_UNUSED)
   {
+    if (output_format)
+      explicit_output_format = true;
+
     if (output_file && !output_format) {
       output_format = strrchr (output_file, '.');
       if (output_format)
@@ -310,6 +392,8 @@ struct output_options_t : option_group_t
 
   const char *output_file;
   const char *output_format;
+  const char **supported_formats;
+  bool explicit_output_format;
 
   mutable FILE *fp;
 };
@@ -333,7 +417,8 @@ struct format_options_t : option_group_t
                          GString      *gs);
   void serialize_glyphs (hb_buffer_t  *buffer,
                         hb_font_t    *font,
-                        hb_bool_t    utf8_clusters,
+                        hb_buffer_serialize_format_t format,
+                        hb_buffer_serialize_flags_t flags,
                         GString      *gs);
   void serialize_line_no (unsigned int  line_no,
                          GString      *gs);
@@ -342,7 +427,6 @@ struct format_options_t : option_group_t
                                 const char   *text,
                                 unsigned int  text_len,
                                 hb_font_t    *font,
-                                hb_bool_t     utf8_clusters,
                                 GString      *gs);
   void serialize_message (unsigned int  line_no,
                          const char   *msg,
@@ -352,7 +436,8 @@ struct format_options_t : option_group_t
                                   const char   *text,
                                   unsigned int  text_len,
                                   hb_font_t    *font,
-                                  hb_bool_t     utf8_clusters,
+                                  hb_buffer_serialize_format_t output_format,
+                                  hb_buffer_serialize_flags_t format_flags,
                                   GString      *gs);
 
 
index 220daa4..422c8cd 100644 (file)
@@ -34,8 +34,10 @@ template <typename output_t>
 struct shape_consumer_t
 {
   shape_consumer_t (option_parser_t *parser)
-                 : shaper (parser),
-                   output (parser) {}
+                 : failed (false),
+                   shaper (parser),
+                   output (parser),
+                   font (NULL) {}
 
   void init (const font_options_t *font_opts)
   {
@@ -45,18 +47,23 @@ struct shape_consumer_t
   }
   void consume_line (hb_buffer_t  *buffer,
                     const char   *text,
-                    unsigned int  text_len)
+                    unsigned int  text_len,
+                    const char   *text_before,
+                    const char   *text_after)
   {
     output.new_line ();
 
-    shaper.populate_buffer (buffer, text, text_len);
-    output.consume_text (buffer, text, text_len, shaper.utf8_clusters);
-
-    if (!shaper.shape (font, buffer)) {
-      failed = true;
-      hb_buffer_set_length (buffer, 0);
-      output.shape_failed (buffer, text, text_len, shaper.utf8_clusters);
-      return;
+    for (unsigned int n = shaper.num_iterations; n; n--)
+    {
+      shaper.populate_buffer (buffer, text, text_len, text_before, text_after);
+      if (n == 1)
+       output.consume_text (buffer, text, text_len, shaper.utf8_clusters);
+      if (!shaper.shape (font, buffer)) {
+       failed = true;
+       hb_buffer_set_length (buffer, 0);
+       output.shape_failed (buffer, text, text_len, shaper.utf8_clusters);
+       return;
+      }
     }
 
     output.consume_glyphs (buffer, text, text_len, shaper.utf8_clusters);
index 666013e..160250e 100644 (file)
@@ -54,7 +54,7 @@ view_cairo_t::get_surface_size (cairo_scaled_font_t *scaled_font,
 void
 view_cairo_t::render (const font_options_t *font_opts)
 {
-  cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts, view_options.font_size);
+  cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts);
   double w, h;
   get_surface_size (scaled_font, &w, &h);
   cairo_t *cr = helper_cairo_create_context (w, h, &view_options, &output_options);
index c621984..cb52373 100644 (file)
 #define VIEW_CAIRO_HH
 
 
-struct view_cairo_t {
+struct view_cairo_t
+{
   view_cairo_t (option_parser_t *parser)
-              : output_options (parser),
-                view_options (parser) {}
+              : output_options (parser, helper_cairo_supported_formats),
+                view_options (parser),
+                direction (HB_DIRECTION_INVALID),
+                lines (0), scale_bits (0) {}
   ~view_cairo_t (void) {
     if (debug)
       cairo_debug_reset_static_data ();
@@ -43,7 +46,7 @@ struct view_cairo_t {
   void init (const font_options_t *font_opts)
   {
     lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
-    scale = double (view_options.font_size) / hb_face_get_upem (hb_font_get_face (font_opts->get_font ()));
+    scale_bits = -font_opts->subpixel_bits;
   }
   void new_line (void)
   {
@@ -68,7 +71,7 @@ struct view_cairo_t {
   {
     direction = hb_buffer_get_direction (buffer);
     helper_cairo_line_t l;
-    helper_cairo_line_from_buffer (&l, buffer, text, text_len, scale, utf8_clusters);
+    helper_cairo_line_from_buffer (&l, buffer, text, text_len, scale_bits, utf8_clusters);
     g_array_append_val (lines, l);
   }
   void finish (const font_options_t *font_opts)
@@ -79,7 +82,11 @@ struct view_cairo_t {
       helper_cairo_line_t &line = g_array_index (lines, helper_cairo_line_t, i);
       line.finish ();
     }
+#if GLIB_CHECK_VERSION (2, 22, 0)
     g_array_unref (lines);
+#else
+    g_array_free (lines, TRUE);
+#endif
   }
 
   protected:
@@ -93,7 +100,7 @@ struct view_cairo_t {
 
   hb_direction_t direction; // Remove this, make segment_properties accessible
   GArray *lines;
-  double scale;
+  int scale_bits;
 };
 
 #endif