aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSeigo Nonaka <nona@google.com>2018-10-22 16:00:50 -0700
committerSeigo Nonaka <nona@google.com>2018-10-22 23:06:18 +0000
commit60868b2fef0c932f27d877d9a13b312e8565f44c (patch)
treee378d24436936e1cb001fdd0910c99e05d7d802f
parent710596947a8c534b1ddaa86419367ada5071fc21 (diff)
parent0a3b7a0fb0734a66926dfda5d95d3cacea8890ce (diff)
downloadharfbuzz_ng-60868b2fef0c932f27d877d9a13b312e8565f44c.tar.gz
Update HarfBuzz to 2.0.2
Merge commit '0a3b7a0fb0734a66926dfda5d95d3cacea8890ce' Bug: 117953171 Change-Id: I3d3eb44406f826abde601f1aad7ed15c82930ca1
-rw-r--r--.circleci/config.yml144
-rw-r--r--.travis.yml2
-rw-r--r--AUTHORS12
-rw-r--r--Android.bp3
-rw-r--r--BUILD.md2
-rw-r--r--CMakeLists.txt161
-rw-r--r--NEWS106
-rw-r--r--README.python.md2
-rw-r--r--README.version4
-rw-r--r--README.wine.md6
-rw-r--r--RELEASING.md5
-rw-r--r--TODO12
-rw-r--r--appveyor.yml21
-rw-r--r--configure.ac12
-rw-r--r--docs/harfbuzz-sections.txt60
-rw-r--r--m4/pkg.m4157
-rw-r--r--src/Makefile.am25
-rw-r--r--src/Makefile.sources86
-rwxr-xr-xsrc/check-includes.sh8
-rwxr-xr-xsrc/check-static-inits.sh4
-rwxr-xr-xsrc/check-symbols.sh2
-rw-r--r--src/dump-emoji.cc42
-rw-r--r--src/dump-indic-data.cc2
-rw-r--r--src/dump-khmer-data.cc10
-rw-r--r--src/dump-myanmar-data.cc2
-rw-r--r--src/dump-use-data.cc2
-rwxr-xr-xsrc/gen-emoji-table.py64
-rwxr-xr-xsrc/gen-indic-table.py2
-rw-r--r--src/gen-os2-unicode-ranges.py (renamed from src/gen-unicode-ranges.py)2
-rwxr-xr-xsrc/gen-tag-table.py1126
-rwxr-xr-xsrc/gen-use-table.py43
-rw-r--r--src/harfbuzz-config.cmake.in4
-rw-r--r--src/hb-aat-layout-ankr-table.hh29
-rw-r--r--src/hb-aat-layout-bsln-table.hh2
-rw-r--r--src/hb-aat-layout-common.hh (renamed from src/hb-aat-layout-common-private.hh)296
-rw-r--r--src/hb-aat-layout-feat-table.hh4
-rw-r--r--src/hb-aat-layout-kerx-table.hh733
-rw-r--r--src/hb-aat-layout-morx-table.hh397
-rw-r--r--src/hb-aat-layout-trak-table.hh150
-rw-r--r--src/hb-aat-layout.cc202
-rw-r--r--src/hb-aat-layout.hh80
-rw-r--r--src/hb-aat-ltag-table.hh4
-rw-r--r--src/hb-atomic.hh (renamed from src/hb-atomic-private.hh)55
-rw-r--r--src/hb-blob.cc47
-rw-r--r--src/hb-blob.hh (renamed from src/hb-blob-private.hh)12
-rw-r--r--src/hb-buffer-deserialize-json.hh2
-rw-r--r--src/hb-buffer-deserialize-json.rl2
-rw-r--r--src/hb-buffer-deserialize-text.hh2
-rw-r--r--src/hb-buffer-deserialize-text.rl2
-rw-r--r--src/hb-buffer-serialize.cc6
-rw-r--r--src/hb-buffer.cc116
-rw-r--r--src/hb-buffer.h28
-rw-r--r--src/hb-buffer.hh (renamed from src/hb-buffer-private.hh)86
-rw-r--r--src/hb-cache.hh80
-rw-r--r--src/hb-common.cc53
-rw-r--r--src/hb-common.h42
-rw-r--r--src/hb-coretext.cc200
-rw-r--r--src/hb-debug.hh14
-rw-r--r--src/hb-deprecated.h181
-rw-r--r--src/hb-directwrite.cc4
-rw-r--r--src/hb-dsalgs.hh44
-rw-r--r--src/hb-face.cc233
-rw-r--r--src/hb-face.h33
-rw-r--r--src/hb-face.hh (renamed from src/hb-face-private.hh)12
-rw-r--r--src/hb-fallback-shape.cc2
-rw-r--r--src/hb-font.cc143
-rw-r--r--src/hb-font.h91
-rw-r--r--src/hb-font.hh (renamed from src/hb-font-private.hh)43
-rw-r--r--src/hb-ft.cc136
-rw-r--r--src/hb-glib.cc57
-rw-r--r--src/hb-gobject-enums.cc.tmpl2
-rw-r--r--src/hb-gobject-structs.cc2
-rw-r--r--src/hb-graphite2.cc43
-rw-r--r--src/hb-graphite2.h2
-rw-r--r--src/hb-icu.cc70
-rw-r--r--src/hb-iter.hh (renamed from src/hb-iter-private.hh)8
-rw-r--r--src/hb-machinery.hh (renamed from src/hb-machinery-private.hh)213
-rw-r--r--src/hb-map.cc2
-rw-r--r--src/hb-map.hh (renamed from src/hb-map-private.hh)10
-rw-r--r--src/hb-mutex.hh (renamed from src/hb-mutex-private.hh)16
-rw-r--r--src/hb-null.hh38
-rw-r--r--src/hb-object.hh (renamed from src/hb-object-private.hh)14
-rw-r--r--src/hb-open-file.hh (renamed from src/hb-open-file-private.hh)236
-rw-r--r--src/hb-open-type.hh (renamed from src/hb-open-type-private.hh)335
-rw-r--r--src/hb-ot-cmap-table.hh298
-rw-r--r--src/hb-ot-color-cbdt-table.hh66
-rw-r--r--src/hb-ot-color-colr-table.hh6
-rw-r--r--src/hb-ot-color-cpal-table.hh10
-rw-r--r--src/hb-ot-color-sbix-table.hh2
-rw-r--r--src/hb-ot-color-svg-table.hh4
-rw-r--r--src/hb-ot-color.cc12
-rw-r--r--src/hb-ot-face.cc76
-rw-r--r--src/hb-ot-face.hh116
-rw-r--r--src/hb-ot-font.cc241
-rw-r--r--src/hb-ot-glyf-table.hh16
-rw-r--r--src/hb-ot-hdmx-table.hh50
-rw-r--r--src/hb-ot-head-table.hh2
-rw-r--r--src/hb-ot-hhea-table.hh2
-rw-r--r--src/hb-ot-hmtx-table.hh59
-rw-r--r--src/hb-ot-kern-table.hh204
-rw-r--r--src/hb-ot-layout-base-table.hh4
-rw-r--r--src/hb-ot-layout-common.hh (renamed from src/hb-ot-layout-common-private.hh)360
-rw-r--r--src/hb-ot-layout-gdef-table.hh53
-rw-r--r--src/hb-ot-layout-gpos-table.hh269
-rw-r--r--src/hb-ot-layout-gsub-table.hh434
-rw-r--r--src/hb-ot-layout-gsubgpos.hh (renamed from src/hb-ot-layout-gsubgpos-private.hh)690
-rw-r--r--src/hb-ot-layout-jstf-table.hh6
-rw-r--r--src/hb-ot-layout.cc574
-rw-r--r--src/hb-ot-layout.h49
-rw-r--r--src/hb-ot-layout.hh (renamed from src/hb-ot-layout-private.hh)255
-rw-r--r--src/hb-ot-map.cc34
-rw-r--r--src/hb-ot-map.hh (renamed from src/hb-ot-map-private.hh)51
-rw-r--r--src/hb-ot-math-table.hh52
-rw-r--r--src/hb-ot-math.cc8
-rw-r--r--src/hb-ot-maxp-table.hh5
-rw-r--r--src/hb-ot-name-table.hh15
-rw-r--r--src/hb-ot-name.h (renamed from src/hb-aat-layout-private.hh)38
-rw-r--r--src/hb-ot-os2-table.hh5
-rw-r--r--src/hb-ot-os2-unicode-ranges.hh51
-rw-r--r--src/hb-ot-post-macroman.hh2
-rw-r--r--src/hb-ot-post-table.hh15
-rw-r--r--src/hb-ot-shape-complex-arabic-fallback.hh7
-rw-r--r--src/hb-ot-shape-complex-arabic-win1256.hh2
-rw-r--r--src/hb-ot-shape-complex-arabic.cc59
-rw-r--r--src/hb-ot-shape-complex-arabic.hh (renamed from src/hb-ot-shape-complex-arabic-private.hh)10
-rw-r--r--src/hb-ot-shape-complex-default.cc4
-rw-r--r--src/hb-ot-shape-complex-hangul.cc24
-rw-r--r--src/hb-ot-shape-complex-hebrew.cc18
-rw-r--r--src/hb-ot-shape-complex-indic-machine.hh1638
-rw-r--r--src/hb-ot-shape-complex-indic-machine.rl24
-rw-r--r--src/hb-ot-shape-complex-indic-table.cc2
-rw-r--r--src/hb-ot-shape-complex-indic.cc361
-rw-r--r--src/hb-ot-shape-complex-indic.hh (renamed from src/hb-ot-shape-complex-indic-private.hh)20
-rw-r--r--src/hb-ot-shape-complex-khmer-machine.hh310
-rw-r--r--src/hb-ot-shape-complex-khmer-machine.rl52
-rw-r--r--src/hb-ot-shape-complex-khmer-private.hh124
-rw-r--r--src/hb-ot-shape-complex-khmer.cc65
-rw-r--r--src/hb-ot-shape-complex-khmer.hh114
-rw-r--r--src/hb-ot-shape-complex-myanmar-machine.hh24
-rw-r--r--src/hb-ot-shape-complex-myanmar-machine.rl10
-rw-r--r--src/hb-ot-shape-complex-myanmar.cc66
-rw-r--r--src/hb-ot-shape-complex-myanmar.hh (renamed from src/hb-ot-shape-complex-myanmar-private.hh)58
-rw-r--r--src/hb-ot-shape-complex-thai.cc13
-rw-r--r--src/hb-ot-shape-complex-tibetan.cc63
-rw-r--r--src/hb-ot-shape-complex-use-machine.hh526
-rw-r--r--src/hb-ot-shape-complex-use-machine.rl40
-rw-r--r--src/hb-ot-shape-complex-use-table.cc100
-rw-r--r--src/hb-ot-shape-complex-use.cc39
-rw-r--r--src/hb-ot-shape-complex-use.hh (renamed from src/hb-ot-shape-complex-use-private.hh)15
-rw-r--r--src/hb-ot-shape-complex.hh (renamed from src/hb-ot-shape-complex-private.hh)73
-rw-r--r--src/hb-ot-shape-fallback.cc92
-rw-r--r--src/hb-ot-shape-fallback.hh (renamed from src/hb-ot-shape-fallback-private.hh)22
-rw-r--r--src/hb-ot-shape-normalize.cc218
-rw-r--r--src/hb-ot-shape-normalize.hh (renamed from src/hb-ot-shape-normalize-private.hh)15
-rw-r--r--src/hb-ot-shape.cc404
-rw-r--r--src/hb-ot-shape.hh (renamed from src/hb-ot-shape-private.hh)52
-rw-r--r--src/hb-ot-tag-table.hh2064
-rw-r--r--src/hb-ot-tag.cc1121
-rw-r--r--src/hb-ot-tag.h31
-rw-r--r--src/hb-ot-var-avar-table.hh10
-rw-r--r--src/hb-ot-var-fvar-table.hh11
-rw-r--r--src/hb-ot-var-hvar-table.hh13
-rw-r--r--src/hb-ot-var-mvar-table.hh13
-rw-r--r--src/hb-ot-var.cc12
-rw-r--r--src/hb-ot.h1
-rw-r--r--src/hb-set-digest.hh (renamed from src/hb-set-digest-private.hh)12
-rw-r--r--src/hb-set.cc2
-rw-r--r--src/hb-set.hh (renamed from src/hb-set-private.hh)24
-rw-r--r--src/hb-shape-plan.cc18
-rw-r--r--src/hb-shape-plan.hh (renamed from src/hb-shape-plan-private.hh)10
-rw-r--r--src/hb-shape.cc16
-rw-r--r--src/hb-shaper-impl.hh (renamed from src/hb-shaper-impl-private.hh)16
-rw-r--r--src/hb-shaper-list.hh2
-rw-r--r--src/hb-shaper.cc9
-rw-r--r--src/hb-shaper.hh (renamed from src/hb-shaper-private.hh)8
-rw-r--r--src/hb-static.cc12
-rw-r--r--src/hb-string-array.hh2
-rw-r--r--src/hb-subset-glyf.cc3
-rw-r--r--src/hb-subset-glyf.hh4
-rw-r--r--src/hb-subset-input.cc48
-rw-r--r--src/hb-subset-input.hh (renamed from src/hb-subset-private.hh)24
-rw-r--r--src/hb-subset-plan.cc33
-rw-r--r--src/hb-subset-plan.hh22
-rw-r--r--src/hb-subset.cc259
-rw-r--r--src/hb-subset.h33
-rw-r--r--src/hb-subset.hh60
-rw-r--r--src/hb-ucdn.cc37
-rw-r--r--src/hb-unicode-emoji-table.hh269
-rw-r--r--src/hb-unicode.cc24
-rw-r--r--src/hb-unicode.h83
-rw-r--r--src/hb-unicode.hh (renamed from src/hb-unicode-private.hh)62
-rw-r--r--src/hb-uniscribe.cc20
-rw-r--r--src/hb-utf.hh (renamed from src/hb-utf-private.hh)8
-rw-r--r--src/hb-vector.hh (renamed from src/hb-vector-private.hh)110
-rw-r--r--src/hb-version.h8
-rw-r--r--src/hb-warning.cc6
-rw-r--r--src/hb.hh (renamed from src/hb-private.hh)49
-rw-r--r--src/main.cc4
-rwxr-xr-xsrc/sample.py6
-rw-r--r--src/test-buffer-serialize.cc2
-rw-r--r--src/test-size-params.cc2
-rw-r--r--src/test-unicode-ranges.cc10
-rw-r--r--src/test-would-substitute.cc2
-rw-r--r--src/test.cc2
-rw-r--r--test/api/CMakeLists.txt2
-rw-r--r--test/api/Makefile.am30
-rw-r--r--test/api/fonts/Roboto-Regular.multihdmx.a.ttfbin0 -> 2052 bytes
-rw-r--r--test/api/fonts/Roboto-Regular.multihdmx.abc.ttfbin0 -> 2468 bytes
-rw-r--r--test/api/fonts/cv01.otfbin0 -> 1956 bytes
-rw-r--r--test/api/hb-subset-test.h19
-rw-r--r--test/api/hb-test.h1
-rw-r--r--test/api/test-blob.c2
-rw-r--r--test/api/test-buffer.c8
-rw-r--r--test/api/test-c.c7
-rw-r--r--test/api/test-collect-unicodes.c (renamed from test/api/test-subset-codepoints.c)27
-rw-r--r--test/api/test-common.c1
-rw-r--r--test/api/test-font.c83
-rw-r--r--test/api/test-map.c114
-rw-r--r--test/api/test-multithread.c178
-rw-r--r--test/api/test-ot-color.c2
-rw-r--r--test/api/test-ot-math.c4
-rw-r--r--test/api/test-ot-name.c102
-rw-r--r--test/api/test-ot-tag.c295
-rw-r--r--test/api/test-set.c8
-rw-r--r--test/api/test-shape.c16
-rw-r--r--test/api/test-subset-glyf.c31
-rw-r--r--test/api/test-subset-hdmx.c36
-rw-r--r--test/api/test-subset-hmtx.c7
-rw-r--r--test/api/test-subset-post.c3
-rw-r--r--test/api/test-subset-vmtx.c6
-rw-r--r--test/api/test-subset.c24
-rw-r--r--test/api/test-unicode.c125
-rw-r--r--test/fuzzing/CMakeLists.txt7
-rw-r--r--test/fuzzing/Makefile.am17
-rw-r--r--test/fuzzing/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6 (renamed from test/shaping/data/in-house/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf)bin61 -> 61 bytes
-rw-r--r--test/fuzzing/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf (renamed from test/shaping/data/in-house/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf)bin64 -> 64 bytes
-rw-r--r--test/fuzzing/fonts/205edd09bd3d141cc9580f650109556cc28b22cb (renamed from test/shaping/data/in-house/fonts/205edd09bd3d141cc9580f650109556cc28b22cb.ttf)bin1966 -> 1966 bytes
-rw-r--r--test/fuzzing/fonts/217a934cfe15c548b572c203dceb2befdf026462 (renamed from test/shaping/data/in-house/fonts/217a934cfe15c548b572c203dceb2befdf026462.ttf)bin1384 -> 1384 bytes
-rw-r--r--test/fuzzing/fonts/3511ff5c1647150595846ac414c595cccac34f18 (renamed from test/shaping/data/in-house/fonts/3511ff5c1647150595846ac414c595cccac34f18.ttf)bin1483 -> 1483 bytes
-rw-r--r--test/fuzzing/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3 (renamed from test/shaping/data/in-house/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf)bin1024 -> 1024 bytes
-rw-r--r--test/fuzzing/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b (renamed from test/shaping/data/in-house/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf)bin1804 -> 1804 bytes
-rw-r--r--test/fuzzing/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0 (renamed from test/shaping/data/in-house/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf)bin1358 -> 1358 bytes
-rw-r--r--test/fuzzing/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8 (renamed from test/shaping/data/in-house/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf)bin61 -> 61 bytes
-rw-r--r--test/fuzzing/fonts/641bd9db850193064d17575053ae2bf8ec149ddc (renamed from test/shaping/data/in-house/fonts/641bd9db850193064d17575053ae2bf8ec149ddc.ttf)bin305 -> 305 bytes
-rw-r--r--test/fuzzing/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f (renamed from test/shaping/data/in-house/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf)bin633 -> 633 bytes
-rw-r--r--test/fuzzing/fonts/a34a9191d9376bda419836effeef7e75c1386016 (renamed from test/shaping/data/in-house/fonts/a34a9191d9376bda419836effeef7e75c1386016.ttf)bin1010 -> 1010 bytes
-rw-r--r--test/fuzzing/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e (renamed from test/shaping/data/in-house/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf)bin820 -> 820 bytes
-rw-r--r--test/fuzzing/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2 (renamed from test/shaping/data/in-house/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf)bin1804 -> 1804 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-5517117891805184bin0 -> 178 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-6107935408390144bin0 -> 16800 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-4666056377368576 (renamed from test/shaping/data/in-house/fonts/ef2511f215aa3ca847cbfffbf861793b42170875.ttf)bin1152 -> 1152 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528bin0 -> 242272 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6243458541944832bin0 -> 370187 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6303297511096320 (renamed from test/shaping/data/in-house/fonts/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf)bin4545 -> 4545 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6696647723581440bin0 -> 3266 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5634395566768128bin0 -> 106 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5688420752424960bin0 -> 163 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5728971283496960bin0 -> 101 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5746142327865344bin0 -> 219 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5750379279548416bin0 -> 317 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-4884742786777088bin0 -> 393 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-5255344882188288bin0 -> 65 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-5720051798769664 (renamed from test/shaping/data/in-house/fonts/233c1e252e737ca79e03a9fd56b71aaa4a230f2b.ttf)bin1048576 -> 1048576 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-5924299061854208bin0 -> 2786 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-6460279560863744bin0 -> 589 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5973566991106048bin0 -> 4047 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4523479581851648bin0 -> 322 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4535496598355968 (renamed from test/shaping/data/in-house/fonts/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf)bin2786 -> 2786 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4548492505645056bin0 -> 122 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4595692015190016 (renamed from test/shaping/data/in-house/fonts/243798dd281c1c77c065958e1ff467420faa9bde.ttf)bin225 -> 225 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4687441845813248bin0 -> 162 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4706238090706944bin0 -> 350 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4769173588672512bin0 -> 37 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4827735151083520bin0 -> 1384 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4841745322868736bin0 -> 660 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4884742786777088bin0 -> 393 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5216838347653120bin0 -> 157600 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5255344882188288bin0 -> 65 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5294584596791296bin0 -> 1602 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5303930168803328bin0 -> 7321 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5331901587914752 (renamed from test/shaping/data/in-house/fonts/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf)bin3301 -> 3301 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5388906574905344bin0 -> 9937 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5517117891805184bin0 -> 178 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5617496443846656bin0 -> 195 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5672141338968064bin0 -> 176 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5700697074958336bin0 -> 878 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5713868010553344bin0 -> 370 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5720051798769664bin0 -> 1048576 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5924299061854208bin0 -> 2786 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6023178755244032bin0 -> 2261 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6111685556305920bin0 -> 586 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6160439919509504 (renamed from test/shaping/data/in-house/fonts/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf)bin204 -> 204 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6210176798425088bin0 -> 1420 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6260579246276608bin0 -> 700 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6264625609834496bin0 -> 1731 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6278851874258944bin0 -> 598 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6424351550210048bin0 -> 73 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6460279560863744bin0 -> 589 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6576177596596224bin0 -> 385 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6595199411159040bin0 -> 1862 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6624904746106880bin0 -> 42 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6723367514144768bin0 -> 1074 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5630246225707008bin0 -> 109 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5633985665826816bin0 -> 73 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5635082459545600bin0 -> 52 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5649959857160192bin0 -> 3608 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5650286710882304bin0 -> 76 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652019562414080bin0 -> 49 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5656511058018304bin0 -> 28 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5659641787187200bin0 -> 3498 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5664873493561344bin0 -> 400 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5668791174823936bin0 -> 3608 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5672261407735808bin0 -> 192 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5674361600606208bin0 -> 518 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5677421274071040bin0 -> 3608 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5679244475105280bin0 -> 256 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5685596677210112bin0 -> 58 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5688420752424960bin0 -> 69 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5695615258853376bin0 -> 194 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5696686572175360bin0 -> 256 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718464350650368bin0 -> 41 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718889451749376bin0 -> 1680 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5719982789361664bin0 -> 3608 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5725129603022848bin0 -> 3608 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5726089628876800bin0 -> 76 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5729361857085440bin0 -> 2250 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5733166795456512bin0 -> 78 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5734736291430400bin0 -> 66 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5738888765636608bin0 -> 267731 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5740171484463104bin0 -> 186 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5750379279548416bin0 -> 219 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762490181353472bin0 -> 101 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762953198960640bin0 -> 62 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5764636557705216bin0 -> 2184 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5359635656605696bin0 -> 393270 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016)bin1228 -> 1228 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872)bin160249 -> 160249 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016)bin313 -> 313 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5629878397829120bin0 -> 3746 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5651059347816448bin0 -> 2648 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5669437462544384bin0 -> 284427 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480)bin1298 -> 1298 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5690658895953920bin0 -> 2735 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695279609675776bin0 -> 135 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696607199166464bin0 -> 28 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711951464759296bin0 -> 284521 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5718215406125056bin0 -> 107 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5743250149736448bin0 -> 103 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747265633779712bin0 -> 177090 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560)bin72435 -> 72435 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758598970343424bin0 -> 64 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5765071062958080bin0 -> 329 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6543700493598720bin0 -> 138425 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016)bin15229 -> 15229 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5203067375976448bin0 -> 16310 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5630904853069824bin0 -> 580 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5687638085337088bin0 -> 1206 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920bin0 -> 512 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5930139383758848bin0 -> 9410 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648)bin109 -> 109 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912 (renamed from test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912)bin65816 -> 65816 bytes
-rw-r--r--test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6394290358976512bin0 -> 1868 bytes
-rw-r--r--test/fuzzing/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249 (renamed from test/api/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249)bin3140 -> 3140 bytes
-rw-r--r--test/fuzzing/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54 (renamed from test/api/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54)bin22473 -> 22473 bytes
-rw-r--r--test/fuzzing/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a (renamed from test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a)bin63302 -> 63302 bytes
-rw-r--r--test/fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480 (renamed from test/api/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480)bin63302 -> 63302 bytes
-rw-r--r--test/fuzzing/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467 (renamed from test/shaping/data/in-house/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf)bin515 -> 515 bytes
-rw-r--r--test/fuzzing/fonts/fab39d60d758cb586db5a504f218442cd1395725 (renamed from test/shaping/data/in-house/fonts/fab39d60d758cb586db5a504f218442cd1395725.ttf)bin1894 -> 1894 bytes
-rw-r--r--test/fuzzing/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653 (renamed from test/api/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653)bin24233 -> 24233 bytes
-rw-r--r--test/fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a (renamed from test/api/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a)bin63302 -> 63302 bytes
-rw-r--r--test/fuzzing/hb-shape-fuzzer.cc42
-rw-r--r--test/fuzzing/hb-subset-fuzzer.cc48
-rw-r--r--test/fuzzing/hb-subset-get-codepoints-fuzzer.cc23
-rw-r--r--test/fuzzing/main.cc28
-rwxr-xr-xtest/fuzzing/run-shape-fuzzer-tests.py77
-rwxr-xr-xtest/fuzzing/run-subset-fuzzer-tests.py39
-rw-r--r--test/shaping/Makefile.am2
-rw-r--r--test/shaping/data/in-house/Makefile.sources12
-rw-r--r--test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttfbin0 -> 2904 bytes
-rw-r--r--test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttfbin0 -> 8188 bytes
-rw-r--r--test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttfbin0 -> 1496 bytes
-rw-r--r--test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttfbin0 -> 2460 bytes
-rw-r--r--test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttfbin0 -> 3364 bytes
-rw-r--r--test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttfbin0 -> 16596 bytes
-rw-r--r--test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttfbin0 -> 51924 bytes
-rw-r--r--test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttfbin0 -> 1352 bytes
-rw-r--r--test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttfbin0 -> 4120 bytes
-rw-r--r--test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttfbin0 -> 11492 bytes
-rw-r--r--test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttfbin0 -> 2336 bytes
-rw-r--r--test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttfbin0 -> 3452 bytes
-rw-r--r--test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttfbin0 -> 2760 bytes
-rw-r--r--test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttfbin0 -> 2380 bytes
-rw-r--r--test/shaping/data/in-house/fonts/TestDFONT.dfontbin0 -> 3505 bytes
-rw-r--r--test/shaping/data/in-house/fonts/TestTRAK.ttfbin0 -> 2456 bytes
-rw-r--r--test/shaping/data/in-house/fonts/TestTTC.ttcbin0 -> 2608 bytes
-rw-r--r--test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttfbin0 -> 1792 bytes
-rw-r--r--test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttfbin0 -> 2656 bytes
-rw-r--r--test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttfbin0 -> 2564 bytes
-rw-r--r--test/shaping/data/in-house/fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttfbin74856 -> 0 bytes
-rw-r--r--test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttfbin0 -> 956 bytes
-rw-r--r--test/shaping/data/in-house/tests/aat-trak.tests8
-rw-r--r--test/shaping/data/in-house/tests/arabic-mark-attach.tests1
-rw-r--r--test/shaping/data/in-house/tests/collections.tests6
-rw-r--r--test/shaping/data/in-house/tests/cursive-positioning.tests1
-rw-r--r--test/shaping/data/in-house/tests/emoji-flag-tags.tests2
-rw-r--r--test/shaping/data/in-house/tests/emoji.tests4
-rw-r--r--test/shaping/data/in-house/tests/fuzzed.tests23
-rw-r--r--test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests2
-rw-r--r--test/shaping/data/in-house/tests/indic-joiners.tests6
-rw-r--r--test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests53
-rw-r--r--test/shaping/data/in-house/tests/khmer-mark-order.tests25
-rw-r--r--test/shaping/data/in-house/tests/language-tags.tests1
-rw-r--r--test/shaping/data/in-house/tests/mongolian-variation-selector.tests17
-rw-r--r--test/shaping/data/in-house/tests/myanmar-zawgyi.tests1
-rw-r--r--test/shaping/data/in-house/tests/rand.tests3
-rw-r--r--test/shaping/data/in-house/tests/use-indic3.tests1
-rw-r--r--test/shaping/data/in-house/tests/use-syllable.tests3
-rw-r--r--test/shaping/data/in-house/tests/vertical.tests2
-rw-r--r--test/shaping/data/text-rendering-tests/DISABLED30
-rw-r--r--test/shaping/data/text-rendering-tests/Makefile.sources27
-rwxr-xr-xtest/shaping/data/text-rendering-tests/extract-tests.py18
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttfbin0 -> 1504 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttfbin0 -> 2408 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttfbin0 -> 2248 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttfbin0 -> 2444 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttfbin0 -> 1968 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttfbin0 -> 3608 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttfbin0 -> 2436 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttfbin0 -> 2964 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttfbin0 -> 2444 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttfbin0 -> 1836 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttfbin0 -> 1520 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttfbin0 -> 2948 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttfbin0 -> 1828 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttfbin0 -> 3012 bytes
-rw-r--r--test/shaping/data/text-rendering-tests/tests/GSUB-3.tests1
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-24.tests1
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-29.tests4
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-30.tests4
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-31.tests8
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-32.tests4
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-33.tests3
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-34.tests1
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-35.tests2
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-36.tests1
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-37.tests4
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-38.tests4
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-39.tests4
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-40.tests4
-rw-r--r--test/shaping/data/text-rendering-tests/tests/MORX-41.tests4
-rw-r--r--test/shaping/hb_test_tools.py4
-rwxr-xr-xtest/shaping/record-test.sh5
-rwxr-xr-xtest/shaping/run-tests.py33
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt3
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt33
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt17
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt8
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt9
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt3
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt5
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt3
-rw-r--r--test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt5
-rw-r--r--test/subset/Makefile.am2
-rw-r--r--util/Makefile.am8
-rw-r--r--util/ansi-print.cc4
-rw-r--r--util/ansi-print.hh3
-rw-r--r--util/hb-subset.cc7
-rw-r--r--util/hb-view.cc2
-rw-r--r--util/helper-cairo-ansi.hh2
-rw-r--r--util/helper-cairo.cc4
-rw-r--r--util/helper-cairo.hh2
-rw-r--r--util/main-font-text.hh2
-rw-r--r--util/options.cc25
-rw-r--r--util/options.hh45
-rw-r--r--util/shape-consumer.hh2
-rw-r--r--util/view-cairo.hh4
476 files changed, 14784 insertions, 7307 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 5ad1ae135..e73f53cac 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -27,15 +27,26 @@ jobs:
# Ignoring assembler complains, https://stackoverflow.com/a/39867021
- run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*'
+ macos-notest-ios:
+ macos:
+ xcode: "10.0.0"
+ steps:
+ - checkout
+ - run: brew update-reset
+ - run: brew install cmake
+ # not needed to be a framework but we like to test that also
+ - run: cmake -DBUILD_FRAMEWORK=ON -H. -Bbuild -GXcode -DHB_IOS=ON
+ - run: cd build && xcodebuild -sdk iphoneos12.0 -configuration Release build -arch arm64
+
distcheck:
docker:
- image: ubuntu:17.10
steps:
- checkout
- - run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
+ - run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: ./autogen.sh
- - run: make
+ - run: make -j32
- run: make distcheck || .ci/fail.sh
- run: rm -rf harfbuzz-*
- run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
@@ -48,7 +59,7 @@ jobs:
- run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
- - run: make
+ - run: make -j32
- run: make check || .ci/fail.sh
archlinux-debug-O0-py3:
@@ -60,7 +71,7 @@ jobs:
- run: pip install fonttools
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- - run: make
+ - run: make -j32
- run: make check || .ci/fail.sh
clang-O3-O0:
@@ -69,16 +80,114 @@ jobs:
steps:
- checkout
- run: apt update || true
- - run: apt install -y ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
+ - run: apt install -y ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- - run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- - run: make
+ - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j32 && cd ..
+ - run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
+ - run: make -j32
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
- - run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- - run: make
+ - run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
+ - run: make -j32
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
+ gcc-valgrind:
+ docker:
+ - image: ubuntu:18.10
+ steps:
+ - checkout
+ - run: apt update || true
+ - run: apt install -y gcc binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip valgrind
+ - run: pip install fonttools
+ - run: ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
+ - run: make -j32
+ # run-shape-fuzzer-tests.py automatically runs valgrind if see available
+ # but test/api runs it by request, we probably should normalize the approaches
+ - run: RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh
+ # informational for now
+ - run: make -Ctest/api check-symbols || true
+
+ clang-everything:
+ docker:
+ - image: ubuntu:18.10
+ steps:
+ - checkout
+ - run: apt update || true; apt install -y wget gnupg
+ - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+ - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
+ - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
+ - run: apt update || true
+ - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
+ - run: pip install fonttools
+ - run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-extra-semi -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
+ - run: make -j32 CPPFLAGS="-Werror"
+ - run: make check CPPFLAGS="-Werror" || .ci/fail.sh
+
+ clang-asan:
+ docker:
+ - image: ubuntu:18.10
+ steps:
+ - checkout
+ - run: apt update || true; apt install -y wget gnupg
+ - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+ - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
+ - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
+ - run: apt update || true
+ - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
+ - run: pip install fonttools
+ - run: CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
+ - run: make -j32
+ - run: make check || .ci/fail.sh | asan_symbolize | c++filt
+
+ clang-msan:
+ docker:
+ - image: ubuntu:18.10
+ steps:
+ - checkout
+ - run: apt update || true; apt install -y wget gnupg
+ - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+ - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
+ - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
+ - run: apt update || true
+ - run: apt install -y clang lld binutils libtool autoconf automake gtk-doc-tools gettext make pkg-config ragel libcairo2-dev libicu-dev libmount-dev libgraphite2-dev python python-pip
+ - run: pip install fonttools
+ - run: update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld" 10
+ - run: wget https://ftp.gnome.org/pub/gnome/sources/glib/2.58/glib-2.58.1.tar.xz && tar xf glib-2.58.1.tar.xz && cd glib-2.58.1 && ./autogen.sh --with-pcre CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CFLAGS="-fsanitize=memory" CXXFLAGS="-fsanitize=memory" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
+ - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
+ - run: CPPFLAGS="-fsanitize=memory -fsanitize-memory-track-origins" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --without-icu
+ - run: make -j32 && MSAN_OPTIONS=exitcode=42 make check || .ci/fail.sh | asan_symbolize | c++filt
+
+ clang-tsan:
+ docker:
+ - image: ubuntu:18.10
+ steps:
+ - checkout
+ - run: apt update || true; apt install -y wget gnupg
+ - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+ - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
+ - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
+ - run: apt update || true
+ - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
+ - run: pip install fonttools
+ - run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
+ - run: make -j32
+ - run: make check || .ci/fail.sh | asan_symbolize | c++filt
+
+ clang-ubsan:
+ docker:
+ - image: ubuntu:18.10
+ steps:
+ - checkout
+ - run: apt update || true; apt install -y wget gnupg
+ - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
+ - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
+ - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
+ - run: apt update || true
+ - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
+ - run: pip install fonttools
+ - run: CPPFLAGS="-fsanitize=undefined" LDFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
+ - run: make -j32
+ - run: make check || .ci/fail.sh | asan_symbolize | c++filt
+
fedora-outoftreebuild:
docker:
- image: fedora
@@ -108,7 +217,7 @@ jobs:
- run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
- run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
- run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
- - run: make -Cbuild
+ - run: make -Cbuild -j32
- run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
- run: make -Cbuild install
@@ -119,7 +228,7 @@ jobs:
- checkout
- run: apt update && apt install -y ragel pkg-config libtool autoconf
- run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp
- - run: make
+ - run: make -j32
crosscompile-notest-freebsd9:
docker:
@@ -128,7 +237,7 @@ jobs:
- checkout
- run: apt update && apt install -y pkg-config ragel
- run: ./autogen.sh --prefix=/freebsd --host=x86_64-pc-freebsd9
- - run: make
+ - run: make -j32
crosscompile-notest-psvita:
docker:
@@ -138,7 +247,7 @@ jobs:
- run: apt update && apt install ragel
- run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh
- run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
- - run: make
+ - run: make -j32
crosscompile-cmake-notest-android-arm:
docker:
@@ -192,6 +301,7 @@ workflows:
# macOS
- macos-llvm-gcc-4.2
- macos-notest-apple-gcc-i686-4.2
+ - macos-notest-ios
# both autotools and cmake
- distcheck
@@ -199,7 +309,13 @@ workflows:
# autotools based builds
- alpine-O3-NOMMAP
- archlinux-debug-O0-py3
+ - gcc-valgrind
- clang-O3-O0
+ - clang-everything
+ - clang-asan
+ - clang-msan
+ - clang-tsan
+ - clang-ubsan
- fedora-outoftreebuild
# cmake based builds
diff --git a/.travis.yml b/.travis.yml
index 83b479ee7..eadfa7679 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -47,8 +47,6 @@ matrix:
- os: osx
compiler: clang
install:
- # https://github.com/harfbuzz/harfbuzz/issues/345
- - export CXXFLAGS="$CXXFLAGS -Wno-deprecated-declarations"
- brew update;
# Workaround Travis/brew bug
- brew uninstall libtool && brew install libtool
diff --git a/AUTHORS b/AUTHORS
index 81cdc4cf3..0763761bb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,9 +1,11 @@
Behdad Esfahbod
-Simon Hausmann
-Martin Hosken
+David Turner
+Ebrahim Byagowi
Jonathan Kew
+Khaled Hosny
Lars Knoll
-Werner Lemberg
-Roozbeh Pournader
+Martin Hosken
Owen Taylor
-David Turner
+Roozbeh Pournader
+Simon Hausmann
+Werner Lemberg
diff --git a/Android.bp b/Android.bp
index a205af817..14cecf8fa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -60,6 +60,7 @@ cc_library_shared {
},
},
srcs: [
+ "src/hb-aat-layout.cc",
"src/hb-blob.cc",
"src/hb-buffer-serialize.cc",
"src/hb-buffer.cc",
@@ -74,6 +75,7 @@ cc_library_shared {
"src/hb-static.cc",
"src/hb-unicode.cc",
"src/hb-warning.cc",
+ "src/hb-ot-face.cc",
"src/hb-ot-font.cc",
"src/hb-ot-layout.cc",
"src/hb-ot-map.cc",
@@ -88,7 +90,6 @@ cc_library_shared {
"src/hb-ot-shape-complex-khmer.cc",
"src/hb-ot-shape-complex-myanmar.cc",
"src/hb-ot-shape-complex-thai.cc",
- "src/hb-ot-shape-complex-tibetan.cc",
"src/hb-ot-shape-complex-use.cc",
"src/hb-ot-shape-complex-use-table.cc",
"src/hb-ot-shape-normalize.cc",
diff --git a/BUILD.md b/BUILD.md
index 8a6b5695a..4c1c30645 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -26,7 +26,7 @@ as with any other standard package. That should leave you with a shared
library in `src/`, and a few utility programs including `hb-view` and `hb-shape`
under `util/`.
-If you are bootstraping from git, you need a few more tools before you can
+If you are bootstrapping from git, you need a few more tools before you can
run `autogen.sh` for the first time. Namely, `pkg-config` and `ragel`.
Again, on Ubuntu / Debian:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e881dbd1a..4eb23af4d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,12 +82,21 @@ if (HB_CHECK)
endif ()
endif ()
+set (HB_DISABLE_SUBSET OFF)
+set (HB_DISABLE_TESTS OFF)
+option(HB_IOS "Apply iOS specific build flags" OFF)
+if (HB_IOS)
+ # We should fix their issue and enable them
+ set (HB_DISABLE_SUBSET ON)
+ set (HB_DISABLE_TESTS ON)
+ set (HB_HAVE_CORETEXT OFF)
+endif ()
+
include_directories(AFTER
${PROJECT_SOURCE_DIR}/src
${PROJECT_BINARY_DIR}/src
)
-add_definitions(-DHAVE_OT)
add_definitions(-DHAVE_FALLBACK)
# We need PYTHON_EXECUTABLE to be set for running the tests...
@@ -98,10 +107,10 @@ include (CheckFunctionExists)
include (CheckIncludeFile)
macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
foreach (func_name ${ARGN})
- string(TOUPPER ${func_name} definiton_to_add)
- check_function_exists(${func_name} HAVE_${definiton_to_add})
- if (${HAVE_${definiton_to_add}})
- add_definitions(-DHAVE_${definiton_to_add})
+ string(TOUPPER ${func_name} definition_to_add)
+ check_function_exists(${func_name} HAVE_${definition_to_add})
+ if (${HAVE_${definition_to_add}})
+ add_definitions(-DHAVE_${definition_to_add})
endif ()
endforeach ()
endmacro ()
@@ -359,12 +368,32 @@ if (APPLE AND HB_HAVE_CORETEXT)
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
- find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
- if (APPLICATION_SERVICES_FRAMEWORK)
- list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
- endif (APPLICATION_SERVICES_FRAMEWORK)
+ if (HB_IOS)
+ find_library(COREFOUNDATION CoreFoundation)
+ if (COREFOUNDATION)
+ list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION})
+ endif ()
+ mark_as_advanced(COREFOUNDATION)
- mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
+ find_library(CORETEXT CoreText)
+ if (CORETEXT)
+ list(APPEND THIRD_PARTY_LIBS ${CORETEXT})
+ endif ()
+ mark_as_advanced(CORETEXT)
+
+ find_library(COREGRAPHICS CoreGraphics)
+ if (COREGRAPHICS)
+ list(APPEND THIRD_PARTY_LIBS ${COREGRAPHICS})
+ endif ()
+ mark_as_advanced(COREGRAPHICS)
+ else ()
+ find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
+ if (APPLICATION_SERVICES_FRAMEWORK)
+ list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
+ endif ()
+
+ mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
+ endif ()
endif ()
if (WIN32 AND HB_HAVE_UNISCRIBE)
@@ -527,12 +556,14 @@ add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_heade
target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
## Define harfbuzz-subset library
-add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
-add_dependencies(harfbuzz-subset harfbuzz)
-target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
+if (NOT HB_DISABLE_SUBSET)
+ add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
+ add_dependencies(harfbuzz-subset harfbuzz)
+ target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
-if (BUILD_SHARED_LIBS)
- set_target_properties(harfbuzz harfbuzz-subset PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
+ if (BUILD_SHARED_LIBS)
+ set_target_properties(harfbuzz harfbuzz-subset PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
+ endif ()
endif ()
if (UNIX OR MINGW)
@@ -549,7 +580,9 @@ if (UNIX OR MINGW)
set (CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "m") # libm
set (CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set_target_properties(harfbuzz PROPERTIES LINKER_LANGUAGE C)
- set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C)
+ if (NOT HB_DISABLE_SUBSET)
+ set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C)
+ endif ()
# No threadsafe statics as we do it ourselves
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics")
@@ -574,7 +607,7 @@ if (HB_HAVE_GOBJECT)
endif ()
if (BUILD_SHARED_LIBS AND WIN32 AND NOT MINGW)
- add_definitions("-DHB_EXTERN=__declspec(dllexport) extern")
+ add_definitions("-DHB_DLL_EXPORT")
endif ()
# On Windows, g-ir-scanner requires a DLL build in order for it to work
@@ -761,12 +794,22 @@ endif ()
if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS harfbuzz
+ EXPORT harfbuzzConfig
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
+ install(EXPORT harfbuzzConfig
+ NAMESPACE harfbuzz::
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
+ )
if (HB_BUILD_UTILS)
+ if (WIN32 AND BUILD_SHARED_LIBS)
+ install(TARGETS harfbuzz-subset
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ )
+ endif ()
install(TARGETS hb-view
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
@@ -818,51 +861,53 @@ if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
endif ()
-## src/ executables
-foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
- set (prog_name ${prog})
- if (${prog_name} STREQUAL "test")
- # test can not be used as a valid executable name on cmake, lets special case it
- set (prog_name test-test)
- endif ()
- add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
- target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
-endforeach ()
-set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
-
-## Tests
-if (UNIX OR MINGW)
- if (BUILD_SHARED_LIBS)
- # generate harfbuzz.def after build completion
- add_custom_command(TARGET harfbuzz POST_BUILD
- COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers}
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
-
- add_test(NAME check-static-inits.sh
- COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
- WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack
- )
- add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
- add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
+if (NOT HB_DISABLE_TESTS)
+ ## src/ executables
+ foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
+ set (prog_name ${prog})
+ if (${prog_name} STREQUAL "test")
+ # test can not be used as a valid executable name on cmake, lets special case it
+ set (prog_name test-test)
+ endif ()
+ add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
+ target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
+ endforeach ()
+ set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
+
+ ## Tests
+ if (UNIX OR MINGW)
+ if (BUILD_SHARED_LIBS)
+ # generate harfbuzz.def after build completion
+ add_custom_command(TARGET harfbuzz POST_BUILD
+ COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers}
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
+
+ add_test(NAME check-static-inits.sh
+ COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack
+ )
+ add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
+ add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
+
+ set_tests_properties(
+ check-static-inits.sh check-libstdc++.sh check-symbols.sh
+ PROPERTIES
+ ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src"
+ SKIP_RETURN_CODE 77)
+ endif ()
+ add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh)
+ add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh)
+ add_test(NAME check-externs.sh COMMAND ./check-externs.sh)
+ add_test(NAME check-includes.sh COMMAND ./check-includes.sh)
set_tests_properties(
- check-static-inits.sh check-libstdc++.sh check-symbols.sh
+ check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh
PROPERTIES
- ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src"
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
SKIP_RETURN_CODE 77)
endif ()
- add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh)
- add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh)
- add_test(NAME check-externs.sh COMMAND ./check-externs.sh)
- add_test(NAME check-includes.sh COMMAND ./check-includes.sh)
- set_tests_properties(
- check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh
- PROPERTIES
- WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
- SKIP_RETURN_CODE 77)
+ # Needs to come last so that variables defined above are passed to
+ # subdirectories.
+ add_subdirectory(test)
endif ()
-
-# Needs to come last so that variables defined above are passed to
-# subdirectories.
-add_subdirectory(test)
diff --git a/NEWS b/NEWS
index 3ae857ef3..b8d364081 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,109 @@
+Overview of changes leading to 2.0.2
+Saturday, October 20, 2018
+====================================
+- Fix two minor memory access issues in AAT tables.
+
+
+Overview of changes leading to 2.0.1
+Friday, October 19, 2018
+====================================
+- Fix hb-version.h reported release version that went wrong (1.8.0)
+ with previous release.
+- Fix extrapolation in 'trak' table.
+- Fix hb-font infinite-recursion issue with some font funcs and
+ subclassed fonts.
+- Implement variation-kerning format in kerx table, although without
+ variation.
+- Fix return value of hb_map_is_empty().
+
+
+Overview of changes leading to 2.0.0
+Thursday, October 18, 2018
+====================================
+- Added AAT shaping support (morx/kerx/trak).
+ Automatically used if GSUB/GPOS are not available respectively.
+ Set HB_OPTIONS=aat env var to have morx/kerx preferred over
+ GSUB/GPOS.
+- Apply TrueType kern table internally, instead of relying on
+ hb_font_t callbacks.
+- Khmer shaper significantly rewritten to better match Uniscribe.
+- Indic3 tags ('dev3', etc) are passed to USE shaper.
+- .dfont Mac font containers implemented.
+- Script- and language-mapping revamped to better use BCP 47.
+- Misc USE and Indic fixes.
+- Misc everything fixes.
+- Too many things to list. Biggest release since 0.9.1, with
+ over 500 commits in just over 5 weeks! Didn't intend it to
+ be a big release. Just happened to become.
+- hb-ft now locks underlying FT_Face during use.
+
+API changes:
+
+- Newly-created hb_font_t's now have our internal "hb-ot-font"
+ callbacks set on them, so they should work out of the box
+ without any callbacks set. If callbacks are set, everything
+ is back to what it was before, the fallback callbacks are
+ null. If you to get the internal implementation modified,
+ sub_font it.
+
+- New hb_font_funcs_set_nominal_glyphs_func() allows speeding
+ up character to glyph mapping.
+
+New API:
++HB_FEATURE_GLOBAL_START
++HB_FEATURE_GLOBAL_END
++hb_buffer_set_invisible_glyph()
++hb_buffer_get_invisible_glyph()
++hb_font_funcs_set_nominal_glyphs_func()
++hb_ot_layout_table_select_script()
++hb_ot_layout_script_select_language()
++hb_ot_layout_feature_get_name_ids()
++hb_ot_layout_feature_get_characters()
++hb_name_id_t
++HB_NAME_ID_INVALID
++HB_OT_MAX_TAGS_PER_SCRIPT
++hb_ot_tags_from_script_and_language()
++hb_ot_tags_to_script_and_language()
+
+Deprecated API:
+-hb_font_funcs_set_glyph_func()
+-hb_unicode_eastasian_width_func_t
+-hb_unicode_funcs_set_eastasian_width_func()
+-hb_unicode_eastasian_width()
+-hb_unicode_decompose_compatibility_func_t
+-HB_UNICODE_MAX_DECOMPOSITION_LEN
+-hb_unicode_funcs_set_decompose_compatibility_func()
+-hb_unicode_decompose_compatibility()
+-hb_font_funcs_set_glyph_h_kerning_func()
+-hb_font_funcs_set_glyph_v_kerning_func()
+-hb_font_get_glyph_h_kerning()
+-hb_font_get_glyph_v_kerning()
+-hb_font_get_glyph_kerning_for_direction()
+-hb_ot_layout_table_choose_script()
+-hb_ot_layout_script_find_language()
+-hb_ot_tags_from_script()
+-hb_ot_tag_from_language()
+
+
+Overview of changes leading to 1.9.0
+Monday, September 10, 2018
+====================================
+- Added 'cmap' API to hb_face_t.
+- Face-builder API.
+- hb-ot-font re-creation should be much leaner now, as the
+ font tables it uses are cached on hb_face_t now.
+- Internal source header file name changes:
+ hb-*-private.hh is renamed to hb-*.hh.
+
+New API:
++HB_UNICODE_MAX
++hb_face_collect_unicodes()
++hb_face_collect_variation_selectors()
++hb_face_collect_variation_unicodes()
++hb_face_builder_create()
++hb_face_builder_add_table()
+
+
Overview of changes leading to 1.8.8
Tuesday, August 14, 2018
====================================
diff --git a/README.python.md b/README.python.md
index 4c0ba9b27..7cf091a09 100644
--- a/README.python.md
+++ b/README.python.md
@@ -23,7 +23,7 @@ Then make sure you also have GI_TYPELIB_PATH pointing to the resulting
$prefix/lib/girepository-* directory.
Make sure you have pygobject installed. Then check that the following
-import works in your Python interpretter:
+import works in your Python interpreter:
```python
from gi.repository import HarfBuzz
diff --git a/README.version b/README.version
index 457bf26d1..1781d2587 100644
--- a/README.version
+++ b/README.version
@@ -1,3 +1,3 @@
-URL: https://github.com/harfbuzz/harfbuzz/commit/63be5dcdde61275822d931b2924425478bc1dac1
-Version: 1.8.8
+URL: https://github.com/harfbuzz/harfbuzz/commit/0a3b7a0fb0734a66926dfda5d95d3cacea8890ce
+Version: 2.0.2
BugComponent: 25699
diff --git a/README.wine.md b/README.wine.md
index 851d2bf3d..799eb631f 100644
--- a/README.wine.md
+++ b/README.wine.md
@@ -1,6 +1,6 @@
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
as a widely used and tested shaper is used as more-or-less OpenType reference
-implemenetation and that specially is important where OpenType specification
+implementation and that specially is important where OpenType specification
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
steps are recommended:
@@ -27,8 +27,8 @@ steps are recommended:
Now you can use hb-shape using `wine winbuild/util/hb-shape.exe` but if you like to
to use the original Uniscribe,
-8. Bring a 32bit version of `usp10.dll` for youself from `C:\Windows\SysWOW64\usp10.dll` of your
- Windows installation (asuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`)
+8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
+ Windows installation (assuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`)
that it is not a DirectWrite proxy ([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
it is designed to work with DirectWrite which Wine can't work with its original one.
diff --git a/RELEASING.md b/RELEASING.md
index d431871c0..4f5705e53 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -27,7 +27,10 @@ HarfBuzz release walk-through checklist:
Otherwise, fix things and commit them separately before making release,
Note: Check src/hb-version.h and make sure the new version number is
there. Sometimes, it does not get updated. If that's the case,
- "touch configure.ac" and rebuild. TODO: debug.
+ "touch configure.ac" and rebuild. Also check that there is no hb-version.h
+ in your build/src file. Typically it will fail the distcheck if there is.
+ That's what happened to 2.0.0 going out with 1.8.0 hb-version.h... So, that's
+ a clue.
7. "make release-files". Enter your GPG password. This creates a sha256 hash
and signs it.
diff --git a/TODO b/TODO
index 6dac0be52..d8e41050e 100644
--- a/TODO
+++ b/TODO
@@ -1,9 +1,3 @@
-General fixes:
-=============
-
-- Implement 'rand' feature.
-
-
API issues:
===========
@@ -19,11 +13,7 @@ API additions
- Add hb-cairo glue
-- Add sanitize API (and a cached version, that saves result on blob user-data)
-
-- BCP 47 language handling / API (language_matches?)
-
-- Add hb_font_create_unscaled()?
+- Add sanitize API.
- Add query / enumeration API for aalt-like features?
diff --git a/appveyor.yml b/appveyor.yml
index cc4acec1c..bf982199b 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -28,9 +28,19 @@ environment:
MINGW_CHOST: i686-w64-mingw32
MSYS2_ARCH: i686
+ - compiler: cygwin
+ CYGWIN_PREFIX: C:\Cygwin64
+ CYGWIN_ARCH: x86_64
+ # Lots of test failures here!
+ #- compiler: cygwin
+ # CYGWIN_PREFIX: C:\Cygwin
+ # CYGWIN_ARCH: x86
+
+
install:
- - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman -Syu --noconfirm"'
+ - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --force --noconfirm -Sy && pacman --noconfirm --force -S pacman-mirrors && pacman --force -Syu --noconfirm"'
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
+ - 'if "%compiler%"=="cygwin" %CYGWIN_PREFIX%\setup-%CYGWIN_ARCH%.exe -g -q -P cygwin-devel,libfreetype-devel,libcairo-devel,libicu-devel,gcc,gcc-g++,gobject-introspection,libglib2.0-devel,libgraphite2-devel,pkg-config,python2'
build_script:
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
@@ -44,13 +54,18 @@ build_script:
- 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
- - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syyu mingw-w64-$MSYS2_ARCH-gcc"'
- - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S --needed mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
+ - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -Syyu mingw-w64-$MSYS2_ARCH-gcc"'
+ - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make; make check || .ci/fail.sh"'
+ - 'if "%compiler%"=="cygwin" set PATH=%PATH%;c:\msys64\mingw64\bin' # msys2 is added just for having "ragel" on PATH
+ - 'if "%compiler%"=="cygwin" curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h -o %CYGWIN_PREFIX%\usr\include\dwrite_1.h'
+ - 'if "%compiler%"=="cygwin" %CYGWIN_PREFIX%\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite; make; make check || .ci/fail.sh"'
+
cache:
- c:\tools\vcpkg\installed\
+ - '%CYGWIN_PREFIX%\var\cache\setup'
notifications:
- provider: Email
diff --git a/configure.ac b/configure.ac
index 55cc12b3f..a2d0992a7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
- [1.8.8],
+ [2.0.2],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@@ -12,6 +12,7 @@ AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
AM_SILENT_RULES([yes])
AX_CODE_COVERAGE
+AC_USE_SYSTEM_EXTENSIONS
# Initialize libtool
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
@@ -19,7 +20,6 @@ LT_PREREQ([2.2])
LT_INIT([disable-static])
# Check for programs
-AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CC_C99
AM_PROG_CC_C_O
@@ -148,12 +148,6 @@ AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread)
dnl ==========================================================================
-have_ot=true
-if $have_ot; then
- AC_DEFINE(HAVE_OT, 1, [Have native OpenType Layout backend])
-fi
-AM_CONDITIONAL(HAVE_OT, $have_ot)
-
have_fallback=true
if $have_fallback; then
AC_DEFINE(HAVE_FALLBACK, 1, [Have simple TrueType Layout backend])
@@ -330,7 +324,7 @@ AC_ARG_WITH(graphite2,
[Use the graphite2 library @<:@default=no@:>@])],,
[with_graphite2=no])
have_graphite2=false
-GRAPHITE2_DEPS="graphite2"
+GRAPHITE2_DEPS="graphite2 >= 1.2.0"
AC_SUBST(GRAPHITE2_DEPS)
if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then
PKG_CHECK_MODULES(GRAPHITE2, $GRAPHITE2_DEPS, have_graphite2=true, :)
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt
index 16b662777..fccfcb0ed 100644
--- a/docs/harfbuzz-sections.txt
+++ b/docs/harfbuzz-sections.txt
@@ -67,6 +67,8 @@ hb_buffer_set_user_data
hb_buffer_get_user_data
hb_buffer_get_glyph_infos
hb_buffer_get_glyph_positions
+hb_buffer_get_invisible_glyph
+hb_buffer_set_invisible_glyph
hb_buffer_set_replacement_codepoint
hb_buffer_get_replacement_codepoint
hb_buffer_normalize_glyphs
@@ -153,7 +155,26 @@ HB_BUFFER_SERIALIZE_FLAGS_DEFAULT
HB_SCRIPT_CANADIAN_ABORIGINAL
hb_font_funcs_set_glyph_func
hb_font_get_glyph_func_t
+hb_ot_layout_table_choose_script
+hb_ot_layout_table_find_script
+hb_ot_tag_from_language
+hb_ot_tags_from_script
hb_set_invert
+hb_unicode_eastasian_width_func_t
+hb_unicode_eastasian_width
+hb_unicode_funcs_set_eastasian_width_func
+HB_UNICODE_MAX_DECOMPOSITION_LEN
+hb_unicode_decompose_compatibility_func_t
+hb_unicode_decompose_compatibility
+hb_unicode_funcs_set_decompose_compatibility_func
+hb_font_funcs_set_glyph_h_kerning_func
+hb_font_funcs_set_glyph_v_kerning_func
+hb_font_get_glyph_h_kerning
+hb_font_get_glyph_h_kerning_func_t
+hb_font_get_glyph_kerning_for_direction
+hb_font_get_glyph_kerning_func_t
+hb_font_get_glyph_v_kerning
+hb_font_get_glyph_v_kerning_func_t
</SECTION>
<SECTION>
@@ -170,6 +191,7 @@ hb_coretext_font_get_ct_font
<SECTION>
<FILE>hb-face</FILE>
hb_face_count
+hb_face_t
hb_face_create
hb_face_create_for_tables
hb_face_destroy
@@ -188,7 +210,11 @@ hb_face_set_glyph_count
hb_face_set_index
hb_face_set_upem
hb_face_set_user_data
-hb_face_t
+hb_face_collect_unicodes
+hb_face_collect_variation_selectors
+hb_face_collect_variation_unicodes
+hb_face_builder_create
+hb_face_builder_add_table
</SECTION>
<SECTION>
@@ -209,14 +235,13 @@ hb_font_funcs_set_glyph_extents_func
hb_font_funcs_set_glyph_from_name_func
hb_font_funcs_set_glyph_h_advance_func
hb_font_funcs_set_glyph_h_advances_func
-hb_font_funcs_set_glyph_h_kerning_func
hb_font_funcs_set_glyph_h_origin_func
hb_font_funcs_set_glyph_name_func
hb_font_funcs_set_glyph_v_advance_func
hb_font_funcs_set_glyph_v_advances_func
-hb_font_funcs_set_glyph_v_kerning_func
hb_font_funcs_set_glyph_v_origin_func
hb_font_funcs_set_nominal_glyph_func
+hb_font_funcs_set_nominal_glyphs_func
hb_font_funcs_set_user_data
hb_font_funcs_set_variation_glyph_func
hb_font_funcs_t
@@ -226,6 +251,7 @@ hb_font_get_glyph
hb_font_get_glyph_advance_for_direction
hb_font_get_glyph_advance_func_t
hb_font_get_glyph_advances_for_direction
+hb_font_get_glyph_advances_func_t
hb_font_get_glyph_contour_point
hb_font_get_glyph_contour_point_for_origin
hb_font_get_glyph_contour_point_func_t
@@ -238,12 +264,8 @@ hb_font_get_glyph_h_advance
hb_font_get_glyph_h_advance_func_t
hb_font_get_glyph_h_advances
hb_font_get_glyph_h_advances_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
@@ -252,12 +274,12 @@ hb_font_get_glyph_v_advance
hb_font_get_glyph_v_advance_func_t
hb_font_get_glyph_v_advances
hb_font_get_glyph_v_advances_func_t
-hb_font_get_glyph_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_nominal_glyph
hb_font_get_nominal_glyph_func_t
+hb_font_get_nominal_glyphs
+hb_font_get_nominal_glyphs_func_t
hb_font_get_parent
hb_font_get_ppem
hb_font_get_ptem
@@ -457,7 +479,9 @@ HB_OT_TAG_GSUB
HB_OT_TAG_JSTF
hb_ot_layout_collect_lookups
hb_ot_layout_collect_features
+hb_ot_layout_feature_get_characters
hb_ot_layout_feature_get_lookups
+hb_ot_layout_feature_get_name_ids
hb_ot_layout_feature_with_variations_get_lookups
hb_ot_layout_get_attach_points
hb_ot_layout_get_glyph_class
@@ -479,12 +503,12 @@ hb_ot_layout_lookups_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_script_select_language
hb_ot_layout_table_find_feature_variations
-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_layout_table_select_script
hb_ot_shape_plan_collect_lookups
hb_ot_layout_language_get_required_feature_index
<SUBSECTION Private>
@@ -532,12 +556,14 @@ hb_ot_math_get_glyph_assembly
<SECTION>
<FILE>hb-ot-tag</FILE>
+HB_OT_MAX_TAGS_PER_LANGUAGE
+HB_OT_MAX_TAGS_PER_SCRIPT
HB_OT_TAG_DEFAULT_LANGUAGE
HB_OT_TAG_DEFAULT_SCRIPT
-hb_ot_tag_from_language
hb_ot_tag_to_language
hb_ot_tag_to_script
-hb_ot_tags_from_script
+hb_ot_tags_from_script_and_language
+hb_ot_tags_to_script_and_language
</SECTION>
<SECTION>
@@ -576,6 +602,8 @@ hb_set_union
<SECTION>
<FILE>hb-shape</FILE>
+HB_FEATURE_GLOBAL_END
+HB_FEATURE_GLOBAL_START
hb_feature_t
hb_feature_from_string
hb_feature_to_string
@@ -602,16 +630,14 @@ hb_shape_plan_t
<SECTION>
<FILE>hb-unicode</FILE>
-HB_UNICODE_MAX_DECOMPOSITION_LEN
+HB_UNICODE_MAX
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
@@ -623,9 +649,7 @@ 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
diff --git a/m4/pkg.m4 b/m4/pkg.m4
deleted file mode 100644
index 0048a3fa0..000000000
--- a/m4/pkg.m4
+++ /dev/null
@@ -1,157 +0,0 @@
-# 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
diff --git a/src/Makefile.am b/src/Makefile.am
index 9e7fd2995..e0ea1c5de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,7 +13,7 @@ TESTS =
check_PROGRAMS =
# Convenience targets:
-lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la
+lib: $(BUILT_SOURCES) libharfbuzz.la
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
@@ -29,11 +29,9 @@ HBSOURCES = $(HB_BASE_sources)
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
HBHEADERS = $(HB_BASE_headers)
-if HAVE_OT
HBSOURCES += $(HB_OT_sources)
HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources)
HBHEADERS += $(HB_OT_headers)
-endif
if HAVE_FALLBACK
HBSOURCES += $(HB_FALLBACK_sources)
@@ -271,7 +269,7 @@ EXTRA_DIST += \
CLEANFILES += $(pkgconfig_DATA)
-DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def
+DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated.def
if HAVE_GOBJECT
DEF_FILES += harfbuzz-gobject.def
endif
@@ -285,17 +283,22 @@ harfbuzz-icu.def: $(HB_ICU_headers)
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-gobject.def: $(HB_GOBJECT_headers)
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
+harfbuzz-deprecated.def: $(srcdir)/hb-deprecated.h
+ $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
GENERATORS = \
gen-arabic-table.py \
+ gen-def.py \
+ gen-emoji-table.py \
gen-indic-table.py \
+ gen-os2-unicode-ranges.py \
+ gen-tag-table.py \
gen-use-table.py \
- gen-def.py \
$(NULL)
EXTRA_DIST += $(GENERATORS)
-unicode-tables: arabic-table indic-table use-table
+unicode-tables: arabic-table indic-table tag-table use-table emoji-table
arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \
@@ -305,13 +308,21 @@ indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategor
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
+tag-table: gen-tag-table.py languagetags language-subtag-registry
+ $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \
+ || ($(RM) $(srcdir)/hb-ot-tag-table.hh; false)
+
use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
+emoji-table: gen-emoji-table.py emoji-data.txt
+ $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
+ || ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
+
built-sources: $(BUILT_SOURCES)
-.PHONY: unicode-tables arabic-table indic-table use-table built-sources
+.PHONY: unicode-tables arabic-table indic-table tag-table use-table emoji-table built-sources
RAGEL_GENERATED = \
$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
diff --git a/src/Makefile.sources b/src/Makefile.sources
index b981b0e26..59cde6bd1 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -1,28 +1,29 @@
# Base and default-included sources and headers
HB_BASE_sources = \
- hb-atomic-private.hh \
- hb-blob-private.hh \
+ hb-atomic.hh \
+ hb-blob.hh \
hb-blob.cc \
- hb-buffer-private.hh \
+ hb-buffer.hh \
hb-buffer-serialize.cc \
hb-buffer.cc \
+ hb-cache.hh \
hb-common.cc \
hb-debug.hh \
hb-dsalgs.hh \
- hb-face-private.hh \
+ hb-face.hh \
hb-face.cc \
- hb-font-private.hh \
+ hb-font.hh \
hb-font.cc \
- hb-iter-private.hh \
- hb-map-private.hh \
+ hb-iter.hh \
+ hb-map.hh \
hb-map.cc \
- hb-machinery-private.hh \
- hb-mutex-private.hh \
+ hb-machinery.hh \
+ hb-mutex.hh \
hb-null.hh \
- hb-object-private.hh \
- hb-open-file-private.hh \
- hb-open-type-private.hh \
+ hb-object.hh \
+ hb-open-file.hh \
+ hb-open-type.hh \
hb-ot-color-cbdt-table.hh \
hb-ot-cmap-table.hh \
hb-ot-glyf-table.hh \
@@ -37,24 +38,26 @@ HB_BASE_sources = \
hb-ot-os2-unicode-ranges.hh \
hb-ot-post-macroman.hh \
hb-ot-post-table.hh \
+ hb-ot-tag-table.hh \
hb-ot-tag.cc \
- hb-private.hh \
- hb-set-digest-private.hh \
- hb-set-private.hh \
+ hb.hh \
+ hb-set-digest.hh \
+ hb-set.hh \
hb-set.cc \
hb-shape.cc \
- hb-shape-plan-private.hh \
+ hb-shape-plan.hh \
hb-shape-plan.cc \
hb-shaper-list.hh \
- hb-shaper-impl-private.hh \
- hb-shaper-private.hh \
+ hb-shaper-impl.hh \
+ hb-shaper.hh \
hb-shaper.cc \
hb-static.cc \
hb-string-array.hh \
- hb-unicode-private.hh \
+ hb-unicode.hh \
+ hb-unicode-emoji-table.hh \
hb-unicode.cc \
- hb-vector-private.hh \
- hb-utf-private.hh \
+ hb-vector.hh \
+ hb-utf.hh \
hb-warning.cc \
$(NULL)
@@ -89,61 +92,62 @@ HB_FALLBACK_sources = \
HB_OT_sources = \
hb-aat-layout.cc \
- hb-aat-layout-common-private.hh \
+ hb-aat-layout-common.hh \
hb-aat-layout-ankr-table.hh \
hb-aat-layout-bsln-table.hh \
hb-aat-layout-feat-table.hh \
hb-aat-layout-kerx-table.hh \
hb-aat-layout-morx-table.hh \
hb-aat-layout-trak-table.hh \
- hb-aat-layout-private.hh \
+ hb-aat-layout.hh \
hb-aat-ltag-table.hh \
+ hb-ot-face.hh \
+ hb-ot-face.cc \
hb-ot-font.cc \
hb-ot-layout.cc \
hb-ot-layout-base-table.hh \
- hb-ot-layout-common-private.hh \
+ hb-ot-layout-common.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
- hb-ot-layout-gsubgpos-private.hh \
+ hb-ot-layout-gsubgpos.hh \
hb-ot-layout-gsub-table.hh \
hb-ot-layout-jstf-table.hh \
- hb-ot-layout-private.hh \
+ hb-ot-layout.hh \
hb-ot-color.cc \
hb-ot-color-colr-table.hh \
hb-ot-color-cpal-table.hh \
hb-ot-color-sbix-table.hh \
hb-ot-color-svg-table.hh \
hb-ot-map.cc \
- hb-ot-map-private.hh \
+ hb-ot-map.hh \
hb-ot-math.cc \
hb-ot-math-table.hh \
hb-ot-shape.cc \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic-fallback.hh \
- hb-ot-shape-complex-arabic-private.hh \
+ hb-ot-shape-complex-arabic.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-private.hh \
+ hb-ot-shape-complex-indic.hh \
hb-ot-shape-complex-indic-table.cc \
- hb-ot-shape-complex-khmer-private.hh \
+ hb-ot-shape-complex-khmer.hh \
hb-ot-shape-complex-khmer.cc \
- hb-ot-shape-complex-myanmar-private.hh \
+ hb-ot-shape-complex-myanmar.hh \
hb-ot-shape-complex-myanmar.cc \
hb-ot-shape-complex-thai.cc \
- hb-ot-shape-complex-tibetan.cc \
hb-ot-shape-complex-use.cc \
- hb-ot-shape-complex-use-private.hh \
+ hb-ot-shape-complex-use.hh \
hb-ot-shape-complex-use-table.cc \
- hb-ot-shape-complex-private.hh \
- hb-ot-shape-normalize-private.hh \
+ hb-ot-shape-complex.hh \
+ hb-ot-shape-normalize.hh \
hb-ot-shape-normalize.cc \
- hb-ot-shape-fallback-private.hh \
+ hb-ot-shape-fallback.hh \
hb-ot-shape-fallback.cc \
- hb-ot-shape-private.hh \
+ hb-ot-shape.hh \
hb-ot-var.cc \
hb-ot-var-avar-table.hh \
hb-ot-var-fvar-table.hh \
@@ -169,6 +173,7 @@ HB_OT_headers = \
hb-ot-font.h \
hb-ot-layout.h \
hb-ot-math.h \
+ hb-ot-name.h \
hb-ot-shape.h \
hb-ot-tag.h \
hb-ot-var.h \
@@ -207,16 +212,17 @@ HB_ICU_headers = hb-icu.h
HB_SUBSET_sources = \
hb-static.cc \
hb-subset.cc \
+ hb-subset.hh \
hb-subset-glyf.cc \
+ hb-subset-glyf.hh \
hb-subset-input.cc \
+ hb-subset-input.hh \
hb-subset-plan.cc \
+ hb-subset-plan.hh \
$(NULL)
HB_SUBSET_headers = \
hb-subset.h \
- hb-subset-glyf.hh \
- hb-subset-plan.hh \
- hb-subset-private.hh \
$(NULL)
HB_GOBJECT_DIST_sources = hb-gobject-structs.cc
diff --git a/src/check-includes.sh b/src/check-includes.sh
index fd565da53..f938f706c 100755
--- a/src/check-includes.sh
+++ b/src/check-includes.sh
@@ -23,14 +23,14 @@ grep -v 'hb[.]h:' |
grep . >&2 && stat=1
-echo 'Checking that source files #include "hb-*private.hh" first (or none)'
+echo 'Checking that source files #include a private header first (or none)'
for x in $HBSOURCES; do
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
- grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
+ grep '#.*\<include\>' "$x" /dev/null | head -n 1
done |
-grep -v '"hb-.*private[.]hh"' |
-grep -v 'hb-private[.]hh:' |
+grep -v '"hb-.*[.]hh"' |
+grep -v 'hb[.]hh' |
grep . >&2 && stat=1
diff --git a/src/check-static-inits.sh b/src/check-static-inits.sh
index 71551cbd4..def25c701 100755
--- a/src/check-static-inits.sh
+++ b/src/check-static-inits.sh
@@ -7,7 +7,6 @@ test -z "$srcdir" && srcdir=.
test -z "$libs" && libs=.libs
stat=0
-
if which objdump 2>/dev/null >/dev/null; then
:
else
@@ -31,7 +30,8 @@ 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
+ if objdump -t "$obj" | grep -q '__cxa_' && ! objdump -t "$obj" | grep -q __ubsan_handle; then
+ objdump -t "$obj" | grep '__cxa_'
echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff"
stat=1
fi
diff --git a/src/check-symbols.sh b/src/check-symbols.sh
index d4eca5079..cea868488 100755
--- a/src/check-symbols.sh
+++ b/src/check-symbols.sh
@@ -26,7 +26,7 @@ for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do
symprefix=
if test $suffix = dylib; then symprefix=_; fi
- EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
+ EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
diff --git a/src/dump-emoji.cc b/src/dump-emoji.cc
index 65214692f..f45bc3106 100644
--- a/src/dump-emoji.cc
+++ b/src/dump-emoji.cc
@@ -45,8 +45,8 @@
#include <stdlib.h>
#include <stdio.h>
-void cbdt_callback (const uint8_t* data, unsigned int length,
- unsigned int group, unsigned int gid)
+static void cbdt_callback (const uint8_t* data, unsigned int length,
+ unsigned int group, unsigned int gid)
{
char output_path[255];
sprintf (output_path, "out/cbdt-%d-%d.png", group, gid);
@@ -55,8 +55,8 @@ void cbdt_callback (const uint8_t* data, unsigned int length,
fclose (f);
}
-void sbix_callback (const uint8_t* data, unsigned int length,
- unsigned int group, unsigned int gid)
+static void sbix_callback (const uint8_t* data, unsigned int length,
+ unsigned int group, unsigned int gid)
{
char output_path[255];
sprintf (output_path, "out/sbix-%d-%d.png", group, gid);
@@ -65,8 +65,8 @@ void sbix_callback (const uint8_t* data, unsigned int length,
fclose (f);
}
-void svg_callback (const uint8_t* data, unsigned int length,
- unsigned int start_glyph, unsigned int end_glyph)
+static void svg_callback (const uint8_t* data, unsigned int length,
+ unsigned int start_glyph, unsigned int end_glyph)
{
char output_path[255];
if (start_glyph == end_glyph)
@@ -83,8 +83,8 @@ void svg_callback (const uint8_t* data, unsigned int length,
fclose (f);
}
-void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs,
- const OT::COLR *colr, const OT::CPAL *cpal)
+static void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs,
+ const OT::COLR *colr, const OT::CPAL *cpal)
{
for (unsigned int i = 0; i < num_glyphs; ++i)
{
@@ -146,7 +146,7 @@ void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsi
int r = (color >> 8) & 0xFF;
int g = (color >> 16) & 0xFF;
int b = (color >> 24) & 0xFF;
- cairo_set_source_rgba (cr, r / 255.f, g / 255.f, b / 255.f, alpha);
+ cairo_set_source_rgba (cr, r / 255., g / 255., b / 255., alpha);
cairo_glyph_t glyph;
glyph.index = glyph_id;
@@ -162,7 +162,8 @@ void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsi
}
}
-void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs)
+static void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem,
+ unsigned int num_glyphs)
{
// Dump every glyph available on the font
return; // disabled for now
@@ -210,10 +211,29 @@ void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int
int main (int argc, char **argv)
{
if (argc != 2) {
- fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+ fprintf (stderr, "usage: %s font-file.ttf\n"
+ "run it like `rm -rf out && mkdir out && %s font-file.ttf`\n",
+ argv[0], argv[0]);
exit (1);
}
+
+ FILE *font_name_file = fopen ("out/_font_name_file.txt", "r");
+ if (font_name_file != nullptr)
+ {
+ fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n");
+ exit (1);
+ }
+
+ font_name_file = fopen ("out/_font_name_file.txt", "w");
+ if (font_name_file == nullptr)
+ {
+ fprintf (stderr, "./out is not accessible, create it please\n");
+ exit (1);
+ }
+ fwrite (argv[1], 1, strlen (argv[1]), font_name_file);
+ fclose (font_name_file);
+
hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
hb_face_t *face = hb_face_create (blob, 0);
hb_font_t *font = hb_font_create (face);
diff --git a/src/dump-indic-data.cc b/src/dump-indic-data.cc
index d57413884..a50688981 100644
--- a/src/dump-indic-data.cc
+++ b/src/dump-indic-data.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-indic-private.hh"
+#include "hb-ot-shape-complex-indic.hh"
int
main (void)
diff --git a/src/dump-khmer-data.cc b/src/dump-khmer-data.cc
index 7dd09b2b5..1e79a9767 100644
--- a/src/dump-khmer-data.cc
+++ b/src/dump-khmer-data.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-khmer-private.hh"
+#include "hb-ot-shape-complex-khmer.hh"
int
main (void)
@@ -34,10 +34,8 @@ main (void)
hb_glyph_info_t info;
info.codepoint = u;
set_khmer_properties (info);
- if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
- info.khmer_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
- printf("U+%04X %u %u\n", u,
- info.khmer_category(),
- info.khmer_position());
+ if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER)
+ printf("U+%04X %u\n", u,
+ info.khmer_category());
}
}
diff --git a/src/dump-myanmar-data.cc b/src/dump-myanmar-data.cc
index 2df9cd987..9f8b12ed2 100644
--- a/src/dump-myanmar-data.cc
+++ b/src/dump-myanmar-data.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-myanmar-private.hh"
+#include "hb-ot-shape-complex-myanmar.hh"
int
main (void)
diff --git a/src/dump-use-data.cc b/src/dump-use-data.cc
index 0e64688f1..4a8b25842 100644
--- a/src/dump-use-data.cc
+++ b/src/dump-use-data.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-use-private.hh"
+#include "hb-ot-shape-complex-use.hh"
int
main (void)
diff --git a/src/gen-emoji-table.py b/src/gen-emoji-table.py
new file mode 100755
index 000000000..278e0b2d4
--- /dev/null
+++ b/src/gen-emoji-table.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+
+from __future__ import print_function, division, absolute_import
+import sys
+import os.path
+from collections import OrderedDict
+
+if len (sys.argv) != 2:
+ print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr)
+ sys.exit (1)
+
+f = open(sys.argv[1])
+header = [f.readline () for _ in range(10)]
+
+sets = OrderedDict()
+for line in f.readlines():
+ line = line.strip()
+ if not line or line[0] == '#':
+ continue
+ rang, typ = [s.strip() for s in line.split('#')[0].split(';')[:2]]
+
+ rang = [int(s, 16) for s in rang.split('..')]
+ if len(rang) > 1:
+ start, end = rang
+ else:
+ start = end = rang[0]
+
+ if typ not in sets:
+ sets[typ] = set()
+ sets[typ].add((start, end))
+
+
+
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following tables are generated by running:")
+print (" *")
+print (" * ./gen-emoji-table.py emoji-data.txt")
+print (" *")
+print (" * on file with this header:")
+print (" *")
+for l in header:
+ print (" * %s" % (l.strip()))
+print (" */")
+print ()
+print ("#ifndef HB_UNICODE_EMOJI_TABLE_HH")
+print ("#define HB_UNICODE_EMOJI_TABLE_HH")
+print ()
+print ('#include "hb-unicode.hh"')
+print ()
+
+for typ,s in sets.items():
+ if typ != "Extended_Pictographic": continue
+ print()
+ print("static const struct hb_unicode_range_t _hb_unicode_emoji_%s_table[] =" % typ)
+ print("{")
+ for pair in sorted(s):
+ print(" {0x%04X, 0x%04X}," % pair)
+ print("};")
+
+print ()
+print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
+print ()
+print ("/* == End of generated table == */")
diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py
index 6252664ca..e65b9814a 100755
--- a/src/gen-indic-table.py
+++ b/src/gen-indic-table.py
@@ -102,7 +102,7 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
-print ('#include "hb-ot-shape-complex-indic-private.hh"')
+print ('#include "hb-ot-shape-complex-indic.hh"')
print ()
# Shorten values
diff --git a/src/gen-unicode-ranges.py b/src/gen-os2-unicode-ranges.py
index 30249a8f8..d768313dd 100644
--- a/src/gen-unicode-ranges.py
+++ b/src/gen-os2-unicode-ranges.py
@@ -13,7 +13,7 @@ import sys
reload(sys)
sys.setdefaultencoding('utf-8')
-print ("""static Range os2UnicodeRangesSorted[] =
+print ("""static OS2Range _hb_os2_unicode_ranges[] =
{""")
args = sys.argv[1:]
diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py
new file mode 100755
index 000000000..13004629d
--- /dev/null
+++ b/src/gen-tag-table.py
@@ -0,0 +1,1126 @@
+#!/usr/bin/python
+
+"""Generator of the mapping from OpenType tags to BCP 47 tags and vice
+versa.
+
+It creates a ``const LangTag[]``, matching the tags from the OpenType
+languages system tag list to the language subtags of the BCP 47 language
+subtag registry, with some manual adjustments. The mappings are
+supplemented with macrolanguages' sublanguages and retired codes'
+replacements, according to BCP 47 and some manual additions where BCP 47
+omits a retired code entirely.
+
+Also generated is a function, ``hb_ot_ambiguous_tag_to_language``,
+intended for use by ``hb_ot_tag_to_language``. It maps OpenType tags
+back to BCP 47 tags. Ambiguous OpenType tags (those that correspond to
+multiple BCP 47 tags) are listed here, except when the alphabetically
+first BCP 47 tag happens to be the chosen disambiguated tag. In that
+case, the fallback behavior will choose the right tag anyway.
+"""
+
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import collections
+try:
+ from HTMLParser import HTMLParser
+ def write (s):
+ print (s.encode ('utf-8'), end='')
+except ImportError:
+ from html.parser import HTMLParser
+ def write (s):
+ sys.stdout.flush ()
+ sys.stdout.buffer.write (s.encode ('utf-8'))
+import io
+import itertools
+import re
+import sys
+import unicodedata
+
+if len (sys.argv) != 3:
+ print ('usage: ./gen-tag-table.py languagetags language-subtag-registry', file=sys.stderr)
+ sys.exit (1)
+
+try:
+ from html import unescape
+ def html_unescape (parser, entity):
+ return unescape (entity)
+except ImportError:
+ def html_unescape (parser, entity):
+ return parser.unescape (entity)
+
+def expect (condition, message=None):
+ if not condition:
+ if message is None:
+ raise AssertionError
+ raise AssertionError (message)
+
+# from http://www-01.sil.org/iso639-3/iso-639-3.tab
+ISO_639_3_TO_1 = {
+ 'aar': 'aa',
+ 'abk': 'ab',
+ 'afr': 'af',
+ 'aka': 'ak',
+ 'amh': 'am',
+ 'ara': 'ar',
+ 'arg': 'an',
+ 'asm': 'as',
+ 'ava': 'av',
+ 'ave': 'ae',
+ 'aym': 'ay',
+ 'aze': 'az',
+ 'bak': 'ba',
+ 'bam': 'bm',
+ 'bel': 'be',
+ 'ben': 'bn',
+ 'bis': 'bi',
+ 'bod': 'bo',
+ 'bos': 'bs',
+ 'bre': 'br',
+ 'bul': 'bg',
+ 'cat': 'ca',
+ 'ces': 'cs',
+ 'cha': 'ch',
+ 'che': 'ce',
+ 'chu': 'cu',
+ 'chv': 'cv',
+ 'cor': 'kw',
+ 'cos': 'co',
+ 'cre': 'cr',
+ 'cym': 'cy',
+ 'dan': 'da',
+ 'deu': 'de',
+ 'div': 'dv',
+ 'dzo': 'dz',
+ 'ell': 'el',
+ 'eng': 'en',
+ 'epo': 'eo',
+ 'est': 'et',
+ 'eus': 'eu',
+ 'ewe': 'ee',
+ 'fao': 'fo',
+ 'fas': 'fa',
+ 'fij': 'fj',
+ 'fin': 'fi',
+ 'fra': 'fr',
+ 'fry': 'fy',
+ 'ful': 'ff',
+ 'gla': 'gd',
+ 'gle': 'ga',
+ 'glg': 'gl',
+ 'glv': 'gv',
+ 'grn': 'gn',
+ 'guj': 'gu',
+ 'hat': 'ht',
+ 'hau': 'ha',
+ 'hbs': 'sh',
+ 'heb': 'he',
+ 'her': 'hz',
+ 'hin': 'hi',
+ 'hmo': 'ho',
+ 'hrv': 'hr',
+ 'hun': 'hu',
+ 'hye': 'hy',
+ 'ibo': 'ig',
+ 'ido': 'io',
+ 'iii': 'ii',
+ 'iku': 'iu',
+ 'ile': 'ie',
+ 'ina': 'ia',
+ 'ind': 'id',
+ 'ipk': 'ik',
+ 'isl': 'is',
+ 'ita': 'it',
+ 'jav': 'jv',
+ 'jpn': 'ja',
+ 'kal': 'kl',
+ 'kan': 'kn',
+ 'kas': 'ks',
+ 'kat': 'ka',
+ 'kau': 'kr',
+ 'kaz': 'kk',
+ 'khm': 'km',
+ 'kik': 'ki',
+ 'kin': 'rw',
+ 'kir': 'ky',
+ 'kom': 'kv',
+ 'kon': 'kg',
+ 'kor': 'ko',
+ 'kua': 'kj',
+ 'kur': 'ku',
+ 'lao': 'lo',
+ 'lat': 'la',
+ 'lav': 'lv',
+ 'lim': 'li',
+ 'lin': 'ln',
+ 'lit': 'lt',
+ 'ltz': 'lb',
+ 'lub': 'lu',
+ 'lug': 'lg',
+ 'mah': 'mh',
+ 'mal': 'ml',
+ 'mar': 'mr',
+ 'mkd': 'mk',
+ 'mlg': 'mg',
+ 'mlt': 'mt',
+ 'mol': 'mo',
+ 'mon': 'mn',
+ 'mri': 'mi',
+ 'msa': 'ms',
+ 'mya': 'my',
+ 'nau': 'na',
+ 'nav': 'nv',
+ 'nbl': 'nr',
+ 'nde': 'nd',
+ 'ndo': 'ng',
+ 'nep': 'ne',
+ 'nld': 'nl',
+ 'nno': 'nn',
+ 'nob': 'nb',
+ 'nor': 'no',
+ 'nya': 'ny',
+ 'oci': 'oc',
+ 'oji': 'oj',
+ 'ori': 'or',
+ 'orm': 'om',
+ 'oss': 'os',
+ 'pan': 'pa',
+ 'pli': 'pi',
+ 'pol': 'pl',
+ 'por': 'pt',
+ 'pus': 'ps',
+ 'que': 'qu',
+ 'roh': 'rm',
+ 'ron': 'ro',
+ 'run': 'rn',
+ 'rus': 'ru',
+ 'sag': 'sg',
+ 'san': 'sa',
+ 'sin': 'si',
+ 'slk': 'sk',
+ 'slv': 'sl',
+ 'sme': 'se',
+ 'smo': 'sm',
+ 'sna': 'sn',
+ 'snd': 'sd',
+ 'som': 'so',
+ 'sot': 'st',
+ 'spa': 'es',
+ 'sqi': 'sq',
+ 'srd': 'sc',
+ 'srp': 'sr',
+ 'ssw': 'ss',
+ 'sun': 'su',
+ 'swa': 'sw',
+ 'swe': 'sv',
+ 'tah': 'ty',
+ 'tam': 'ta',
+ 'tat': 'tt',
+ 'tel': 'te',
+ 'tgk': 'tg',
+ 'tgl': 'tl',
+ 'tha': 'th',
+ 'tir': 'ti',
+ 'ton': 'to',
+ 'tsn': 'tn',
+ 'tso': 'ts',
+ 'tuk': 'tk',
+ 'tur': 'tr',
+ 'twi': 'tw',
+ 'uig': 'ug',
+ 'ukr': 'uk',
+ 'urd': 'ur',
+ 'uzb': 'uz',
+ 'ven': 've',
+ 'vie': 'vi',
+ 'vol': 'vo',
+ 'wln': 'wa',
+ 'wol': 'wo',
+ 'xho': 'xh',
+ 'yid': 'yi',
+ 'yor': 'yo',
+ 'zha': 'za',
+ 'zho': 'zh',
+ 'zul': 'zu',
+}
+
+class LanguageTag (object):
+ """A BCP 47 language tag.
+
+ Attributes:
+ subtags (List[str]): The list of subtags in this tag.
+ grandfathered (bool): Whether this tag is grandfathered. If
+ ``true``, the entire lowercased tag is the ``language``
+ and the other subtag fields are empty.
+ language (str): The language subtag.
+ script (str): The script subtag.
+ region (str): The region subtag.
+ variant (str): The variant subtag.
+
+ Args:
+ tag (str): A BCP 47 language tag.
+
+ """
+ def __init__ (self, tag):
+ global bcp_47
+ self.subtags = tag.lower ().split ('-')
+ self.grandfathered = tag.lower () in bcp_47.grandfathered
+ if self.grandfathered:
+ self.language = tag.lower ()
+ self.script = ''
+ self.region = ''
+ self.variant = ''
+ else:
+ self.language = self.subtags[0]
+ self.script = self._find_first (lambda s: len (s) == 4 and s[0] > '9', self.subtags)
+ self.region = self._find_first (lambda s: len (s) == 2 and s[0] > '9' or len (s) == 3 and s[0] <= '9', self.subtags[1:])
+ self.variant = self._find_first (lambda s: len (s) > 4 or len (s) == 4 and s[0] <= '9', self.subtags)
+
+ def __str__(self):
+ return '-'.join(self.subtags)
+
+ def __repr__ (self):
+ return 'LanguageTag(%r)' % str(self)
+
+ @staticmethod
+ def _find_first (function, sequence):
+ try:
+ return next (iter (filter (function, sequence)))
+ except StopIteration:
+ return None
+
+ def is_complex (self):
+ """Return whether this tag is too complex to represent as a
+ ``LangTag`` in the generated code.
+
+ Complex tags need to be handled in
+ ``hb_ot_tags_from_complex_language``.
+
+ Returns:
+ Whether this tag is complex.
+ """
+ return not (len (self.subtags) == 1
+ or self.grandfathered
+ and len (self.subtags[1]) != 3
+ and ot.from_bcp_47[self.subtags[0]] == ot.from_bcp_47[self.language])
+
+ def get_group (self):
+ """Return the group into which this tag should be categorized in
+ ``hb_ot_tags_from_complex_language``.
+
+ The group is the first letter of the tag, or ``'und'`` if this tag
+ should not be matched in a ``switch`` statement in the generated
+ code.
+
+ Returns:
+ This tag's group.
+ """
+ return ('und'
+ if (self.language == 'und'
+ or self.variant in bcp_47.prefixes and len (bcp_47.prefixes[self.variant]) == 1)
+ else self.language[0])
+
+class OpenTypeRegistryParser (HTMLParser):
+ """A parser for the OpenType language system tag registry.
+
+ Attributes:
+ header (str): The "last updated" line of the registry.
+ names (Mapping[str, str]): A map of language system tags to the
+ names they are given in the registry.
+ ranks (DefaultDict[str, int]): A map of language system tags to
+ numbers. If a single BCP 47 tag corresponds to multiple
+ OpenType tags, the tags are ordered in increasing order by
+ rank. The rank is based on the number of BCP 47 tags
+ associated with a tag, though it may be manually modified.
+ to_bcp_47 (DefaultDict[str, AbstractSet[str]]): A map of
+ OpenType language system tags to sets of BCP 47 tags.
+ from_bcp_47 (DefaultDict[str, AbstractSet[str]]): ``to_bcp_47``
+ inverted. Its values start as unsorted sets;
+ ``sort_languages`` converts them to sorted lists.
+
+ """
+ def __init__ (self):
+ HTMLParser.__init__ (self)
+ self.header = ''
+ self.names = {}
+ self.ranks = collections.defaultdict (int)
+ self.to_bcp_47 = collections.defaultdict (set)
+ self.from_bcp_47 = collections.defaultdict (set)
+ # Whether the parser is in a <td> element
+ self._td = False
+ # The text of the <td> elements of the current <tr> element.
+ self._current_tr = []
+
+ def handle_starttag (self, tag, attrs):
+ if tag == 'meta':
+ for attr, value in attrs:
+ if attr == 'name' and value == 'updated_at':
+ self.header = self.get_starttag_text ()
+ break
+ elif tag == 'td':
+ self._td = True
+ self._current_tr.append ('')
+ elif tag == 'tr':
+ self._current_tr = []
+
+ def handle_endtag (self, tag):
+ if tag == 'td':
+ self._td = False
+ elif tag == 'tr' and self._current_tr:
+ expect (2 <= len (self._current_tr) <= 3)
+ name = self._current_tr[0].strip ()
+ tag = self._current_tr[1].strip ("\t\n\v\f\r '")
+ rank = 0
+ if len (tag) > 4:
+ expect (tag.endswith (' (deprecated)'), 'ill-formed OpenType tag: %s' % tag)
+ name += ' (deprecated)'
+ tag = tag.split (' ')[0]
+ rank = 1
+ self.names[tag] = re.sub (' languages$', '', name)
+ if not self._current_tr[2]:
+ return
+ iso_codes = self._current_tr[2].strip ()
+ self.to_bcp_47[tag].update (ISO_639_3_TO_1.get (code, code) for code in iso_codes.replace (' ', '').split (','))
+ rank += 2 * len (self.to_bcp_47[tag])
+ self.ranks[tag] = rank
+
+ def handle_data (self, data):
+ if self._td:
+ self._current_tr[-1] += data
+
+ def handle_charref (self, name):
+ self.handle_data (html_unescape (self, '&#%s;' % name))
+
+ def handle_entityref (self, name):
+ self.handle_data (html_unescape (self, '&%s;' % name))
+
+ def parse (self, filename):
+ """Parse the OpenType language system tag registry.
+
+ Args:
+ filename (str): The file name of the registry.
+ """
+ with io.open (filename, encoding='utf-8') as f:
+ self.feed (f.read ())
+ expect (self.header)
+ for tag, iso_codes in self.to_bcp_47.items ():
+ for iso_code in iso_codes:
+ self.from_bcp_47[iso_code].add (tag)
+
+ def add_language (self, bcp_47_tag, ot_tag):
+ """Add a language as if it were in the registry.
+
+ Args:
+ bcp_47_tag (str): A BCP 47 tag. If the tag is more than just
+ a language subtag, and if the language subtag is a
+ macrolanguage, then new languages are added corresponding
+ to the macrolanguages' individual languages with the
+ remainder of the tag appended.
+ ot_tag (str): An OpenType language system tag.
+ """
+ global bcp_47
+ self.to_bcp_47[ot_tag].add (bcp_47_tag)
+ self.from_bcp_47[bcp_47_tag].add (ot_tag)
+ if bcp_47_tag.lower () not in bcp_47.grandfathered:
+ try:
+ [macrolanguage, suffix] = bcp_47_tag.split ('-', 1)
+ if macrolanguage in bcp_47.macrolanguages:
+ s = set ()
+ for language in bcp_47.macrolanguages[macrolanguage]:
+ if language.lower () not in bcp_47.grandfathered:
+ s.add ('%s-%s' % (language, suffix))
+ bcp_47.macrolanguages['%s-%s' % (macrolanguage, suffix)] = s
+ except ValueError:
+ pass
+
+ @staticmethod
+ def _remove_language (tag_1, dict_1, dict_2):
+ for tag_2 in dict_1.pop (tag_1):
+ dict_2[tag_2].remove (tag_1)
+ if not dict_2[tag_2]:
+ del dict_2[tag_2]
+
+ def remove_language_ot (self, ot_tag):
+ """Remove an OpenType tag from the registry.
+
+ Args:
+ ot_tag (str): An OpenType tag.
+ """
+ self._remove_language (ot_tag, self.to_bcp_47, self.from_bcp_47)
+
+ def remove_language_bcp_47 (self, bcp_47_tag):
+ """Remove a BCP 47 tag from the registry.
+
+ Args:
+ bcp_47_tag (str): A BCP 47 tag.
+ """
+ self._remove_language (bcp_47_tag, self.from_bcp_47, self.to_bcp_47)
+
+ def inherit_from_macrolanguages (self):
+ """Copy mappings from macrolanguages to individual languages.
+
+ If a BCP 47 tag for an individual mapping has no OpenType
+ mapping but its macrolanguage does, the mapping is copied to
+ the individual language. For example, als (Tosk Albanian) has no
+ explicit mapping, so it inherits from sq (Albanian) the mapping
+ to SQI.
+
+ If a BCP 47 tag for a macrolanguage has no OpenType mapping but
+ all of its individual languages do and they all map to the same
+ tags, the mapping is copied to the macrolanguage.
+ """
+ global bcp_47
+ original_ot_from_bcp_47 = dict (self.from_bcp_47)
+ for macrolanguage, languages in dict (bcp_47.macrolanguages).items ():
+ ot_macrolanguages = set (original_ot_from_bcp_47.get (macrolanguage, set ()))
+ if ot_macrolanguages:
+ for ot_macrolanguage in ot_macrolanguages:
+ for language in languages:
+ # Remove the following condition if e.g. nn should map to NYN,NOR
+ # instead of just NYN.
+ if language not in original_ot_from_bcp_47:
+ self.add_language (language, ot_macrolanguage)
+ self.ranks[ot_macrolanguage] += 1
+ else:
+ for language in languages:
+ if language in original_ot_from_bcp_47:
+ if ot_macrolanguages:
+ ml = original_ot_from_bcp_47[language]
+ if ml:
+ ot_macrolanguages &= ml
+ else:
+ pass
+ else:
+ ot_macrolanguages |= original_ot_from_bcp_47[language]
+ else:
+ ot_macrolanguages.clear ()
+ if not ot_macrolanguages:
+ break
+ for ot_macrolanguage in ot_macrolanguages:
+ self.add_language (macrolanguage, ot_macrolanguage)
+
+ def sort_languages (self):
+ """Sort the values of ``from_bcp_47`` in ascending rank order."""
+ for language, tags in self.from_bcp_47.items ():
+ self.from_bcp_47[language] = sorted (tags,
+ key=lambda t: (self.ranks[t] + rank_delta (language, t), t))
+
+ot = OpenTypeRegistryParser ()
+
+class BCP47Parser (object):
+ """A parser for the BCP 47 subtag registry.
+
+ Attributes:
+ header (str): The "File-Date" line of the registry.
+ names (Mapping[str, str]): A map of subtags to the names they
+ are given in the registry. Each value is a
+ ``'\\n'``-separated list of names.
+ scopes (Mapping[str, str]): A map of language subtags to strings
+ suffixed to language names, including suffixes to explain
+ language scopes.
+ macrolanguages (DefaultDict[str, AbstractSet[str]]): A map of
+ language subtags to the sets of language subtags which
+ inherit from them. See
+ ``OpenTypeRegistryParser.inherit_from_macrolanguages``.
+ prefixes (DefaultDict[str, AbstractSet[str]]): A map of variant
+ subtags to their prefixes.
+ grandfathered (AbstractSet[str]): The set of grandfathered tags,
+ normalized to lowercase.
+
+ """
+ def __init__ (self):
+ self.header = ''
+ self.names = {}
+ self.scopes = {}
+ self.macrolanguages = collections.defaultdict (set)
+ self.prefixes = collections.defaultdict (set)
+ self.grandfathered = set ()
+
+ def parse (self, filename):
+ """Parse the BCP 47 subtag registry.
+
+ Args:
+ filename (str): The file name of the registry.
+ """
+ with io.open (filename, encoding='utf-8') as f:
+ subtag_type = None
+ subtag = None
+ deprecated = False
+ has_preferred_value = False
+ line_buffer = ''
+ for line in itertools.chain (f, ['']):
+ line = line.rstrip ()
+ if line.startswith (' '):
+ line_buffer += line[1:]
+ continue
+ line, line_buffer = line_buffer, line
+ if line.startswith ('Type: '):
+ subtag_type = line.split (' ')[1]
+ deprecated = False
+ has_preferred_value = False
+ elif line.startswith ('Subtag: ') or line.startswith ('Tag: '):
+ subtag = line.split (' ')[1]
+ if subtag_type == 'grandfathered':
+ self.grandfathered.add (subtag.lower ())
+ elif line.startswith ('Description: '):
+ description = line.split (' ', 1)[1].replace (' (individual language)', '')
+ description = re.sub (' (\((individual |macro)language\)|languages)$', '',
+ description)
+ if subtag in self.names:
+ self.names[subtag] += '\n' + description
+ else:
+ self.names[subtag] = description
+ elif subtag_type == 'language' or subtag_type == 'grandfathered':
+ if line.startswith ('Scope: '):
+ scope = line.split (' ')[1]
+ if scope == 'macrolanguage':
+ scope = ' [macrolanguage]'
+ elif scope == 'collection':
+ scope = ' [family]'
+ else:
+ continue
+ self.scopes[subtag] = scope
+ elif line.startswith ('Deprecated: '):
+ self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '')
+ deprecated = True
+ elif deprecated and line.startswith ('Comments: see '):
+ # If a subtag is split into multiple replacement subtags,
+ # it essentially represents a macrolanguage.
+ for language in line.replace (',', '').split (' ')[2:]:
+ self._add_macrolanguage (subtag, language)
+ elif line.startswith ('Preferred-Value: '):
+ # If a subtag is deprecated in favor of a single replacement subtag,
+ # it is either a dialect or synonym of the preferred subtag. Either
+ # way, it is close enough to the truth to consider the replacement
+ # the macrolanguage of the deprecated language.
+ has_preferred_value = True
+ macrolanguage = line.split (' ')[1]
+ self._add_macrolanguage (macrolanguage, subtag)
+ elif not has_preferred_value and line.startswith ('Macrolanguage: '):
+ self._add_macrolanguage (line.split (' ')[1], subtag)
+ elif subtag_type == 'variant':
+ if line.startswith ('Prefix: '):
+ self.prefixes[subtag].add (line.split (' ')[1])
+ elif line.startswith ('File-Date: '):
+ self.header = line
+ expect (self.header)
+
+ def _add_macrolanguage (self, macrolanguage, language):
+ global ot
+ if language not in ot.from_bcp_47:
+ for l in self.macrolanguages.get (language, set ()):
+ self._add_macrolanguage (macrolanguage, l)
+ if macrolanguage not in ot.from_bcp_47:
+ for ls in list (self.macrolanguages.values ()):
+ if macrolanguage in ls:
+ ls.add (language)
+ return
+ self.macrolanguages[macrolanguage].add (language)
+
+ def remove_extra_macrolanguages (self):
+ """Make every language have at most one macrolanguage."""
+ inverted = collections.defaultdict (list)
+ for macrolanguage, languages in self.macrolanguages.items ():
+ for language in languages:
+ inverted[language].append (macrolanguage)
+ for language, macrolanguages in inverted.items ():
+ if len (macrolanguages) > 1:
+ macrolanguages.sort (key=lambda ml: len (self.macrolanguages[ml]))
+ biggest_macrolanguage = macrolanguages.pop ()
+ for macrolanguage in macrolanguages:
+ self._add_macrolanguage (biggest_macrolanguage, macrolanguage)
+
+ def get_name (self, lt):
+ """Return the names of the subtags in a language tag.
+
+ Args:
+ lt (LanguageTag): A BCP 47 language tag.
+
+ Returns:
+ The name form of ``lt``.
+ """
+ name = self.names[lt.language].split ('\n')[0]
+ if lt.script:
+ name += '; ' + self.names[lt.script.title ()].split ('\n')[0]
+ if lt.region:
+ name += '; ' + self.names[lt.region.upper ()].split ('\n')[0]
+ if lt.variant:
+ name += '; ' + self.names[lt.variant].split ('\n')[0]
+ return name
+
+bcp_47 = BCP47Parser ()
+
+ot.parse (sys.argv[1])
+bcp_47.parse (sys.argv[2])
+
+ot.add_language ('ary', 'MOR')
+
+ot.add_language ('ath', 'ATH')
+
+ot.add_language ('bai', 'BML')
+
+ot.ranks['BAL'] = ot.ranks['KAR'] + 1
+
+ot.add_language ('ber', 'BBR')
+
+ot.remove_language_ot ('PGR')
+ot.add_language ('el-polyton', 'PGR')
+
+bcp_47.macrolanguages['et'] = {'ekk'}
+
+bcp_47.names['flm'] = 'Falam Chin'
+bcp_47.scopes['flm'] = ' (retired code)'
+bcp_47.macrolanguages['flm'] = {'cfm'}
+
+ot.ranks['FNE'] = ot.ranks['TNE'] + 1
+
+ot.add_language ('und-fonipa', 'IPPH')
+
+ot.add_language ('und-fonnapa', 'APPH')
+
+ot.remove_language_ot ('IRT')
+ot.add_language ('ga-Latg', 'IRT')
+
+ot.remove_language_ot ('KGE')
+ot.add_language ('und-Geok', 'KGE')
+
+ot.add_language ('guk', 'GUK')
+ot.names['GUK'] = 'Gumuz (SIL fonts)'
+ot.ranks['GUK'] = ot.ranks['GMZ'] + 1
+
+bcp_47.macrolanguages['id'] = {'in'}
+
+bcp_47.macrolanguages['ijo'] = {'ijc'}
+
+ot.add_language ('kht', 'KHN')
+ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)'
+ot.names['KHT'] = ot.names['KHT'] + ' (OpenType spec and SIL fonts)'
+ot.ranks['KHN'] = ot.ranks['KHT']
+ot.ranks['KHT'] += 1
+
+ot.ranks['LCR'] = ot.ranks['MCR'] + 1
+
+ot.names['MAL'] = 'Malayalam Traditional'
+ot.ranks['MLR'] += 1
+
+bcp_47.names['mhv'] = 'Arakanese'
+bcp_47.scopes['mhv'] = ' (retired code)'
+
+ot.add_language ('no', 'NOR')
+
+ot.add_language ('oc-provenc', 'PRO')
+
+ot.add_language ('qu', 'QUZ')
+ot.add_language ('qub', 'QWH')
+ot.add_language ('qud', 'QVI')
+ot.add_language ('qug', 'QVI')
+ot.add_language ('qup', 'QVI')
+ot.add_language ('qur', 'QWH')
+ot.add_language ('qus', 'QUH')
+ot.add_language ('quw', 'QVI')
+ot.add_language ('qux', 'QWH')
+ot.add_language ('qva', 'QWH')
+ot.add_language ('qvh', 'QWH')
+ot.add_language ('qvj', 'QVI')
+ot.add_language ('qvl', 'QWH')
+ot.add_language ('qvm', 'QWH')
+ot.add_language ('qvn', 'QWH')
+ot.add_language ('qvo', 'QVI')
+ot.add_language ('qvp', 'QWH')
+ot.add_language ('qvw', 'QWH')
+ot.add_language ('qvz', 'QVI')
+ot.add_language ('qwa', 'QWH')
+ot.add_language ('qws', 'QWH')
+ot.add_language ('qxa', 'QWH')
+ot.add_language ('qxc', 'QWH')
+ot.add_language ('qxh', 'QWH')
+ot.add_language ('qxl', 'QVI')
+ot.add_language ('qxn', 'QWH')
+ot.add_language ('qxo', 'QWH')
+ot.add_language ('qxr', 'QVI')
+ot.add_language ('qxt', 'QWH')
+ot.add_language ('qxw', 'QWH')
+
+bcp_47.macrolanguages['ro'].remove ('mo')
+bcp_47.macrolanguages['ro-MD'].add ('mo')
+
+ot.add_language ('sgw', 'SGW')
+ot.names['SGW'] = ot.names['CHG'] + ' (SIL fonts)'
+ot.ranks['SGW'] = ot.ranks['CHG'] + 1
+
+ot.remove_language_ot ('SYRE')
+ot.remove_language_ot ('SYRJ')
+ot.remove_language_ot ('SYRN')
+ot.add_language ('und-Syre', 'SYRE')
+ot.add_language ('und-Syrj', 'SYRJ')
+ot.add_language ('und-Syrn', 'SYRN')
+
+bcp_47.names['xst'] = u"Silt'e"
+bcp_47.scopes['xst'] = ' (retired code)'
+bcp_47.macrolanguages['xst'] = {'stv', 'wle'}
+
+ot.add_language ('xwo', 'TOD')
+
+ot.remove_language_ot ('ZHH')
+ot.remove_language_ot ('ZHP')
+ot.remove_language_ot ('ZHT')
+bcp_47.macrolanguages['zh'].remove ('lzh')
+bcp_47.macrolanguages['zh'].remove ('yue')
+ot.add_language ('zh-Hant-MO', 'ZHH')
+ot.add_language ('zh-Hant-HK', 'ZHH')
+ot.add_language ('zh-Hans', 'ZHS')
+ot.add_language ('zh-Hant', 'ZHT')
+ot.add_language ('zh-HK', 'ZHH')
+ot.add_language ('zh-MO', 'ZHH')
+ot.add_language ('zh-TW', 'ZHT')
+ot.add_language ('lzh', 'ZHT')
+ot.add_language ('lzh-Hans', 'ZHS')
+ot.add_language ('yue', 'ZHH')
+ot.add_language ('yue-Hans', 'ZHS')
+
+bcp_47.macrolanguages['zom'] = {'yos'}
+
+def rank_delta (bcp_47, ot):
+ """Return a delta to apply to a BCP 47 tag's rank.
+
+ Most OpenType tags have a constant rank, but a few have ranks that
+ depend on the BCP 47 tag.
+
+ Args:
+ bcp_47 (str): A BCP 47 tag.
+ ot (str): An OpenType tag to.
+
+ Returns:
+ A number to add to ``ot``'s rank when sorting ``bcp_47``'s
+ OpenType equivalents.
+ """
+ if bcp_47 == 'ak' and ot == 'AKA':
+ return -1
+ if bcp_47 == 'tw' and ot == 'TWI':
+ return -1
+ return 0
+
+disambiguation = {
+ 'ALT': 'alt',
+ 'ARK': 'rki',
+ 'BHI': 'bhb',
+ 'BLN': 'bjt',
+ 'BTI': 'beb',
+ 'CCHN': 'cco',
+ 'CMR': 'swb',
+ 'CPP': 'crp',
+ 'CRR': 'crx',
+ 'DUJ': 'dwu',
+ 'ECR': 'crj',
+ 'HAL': 'cfm',
+ 'HND': 'hnd',
+ 'KIS': 'kqs',
+ 'LRC': 'bqi',
+ 'NDB': 'nd',
+ 'NIS': 'njz',
+ 'PLG': 'pce',
+ 'PRO': 'pro',
+ 'QIN': 'bgr',
+ 'QUH': 'quh',
+ 'QVI': 'qvi',
+ 'QWH': 'qwh',
+ 'SIG': 'stv',
+ 'TNE': 'yrk',
+ 'ZHH': 'zh-HK',
+ 'ZHS': 'zh-Hans',
+ 'ZHT': 'zh-Hant',
+}
+
+ot.inherit_from_macrolanguages ()
+bcp_47.remove_extra_macrolanguages ()
+ot.inherit_from_macrolanguages ()
+ot.sort_languages ()
+
+print ('/* == Start of generated table == */')
+print ('/*')
+print (' * The following table is generated by running:')
+print (' *')
+print (' * %s languagetags language-subtag-registry' % sys.argv[0])
+print (' *')
+print (' * on files with these headers:')
+print (' *')
+print (' * %s' % ot.header.strip ())
+print (' * %s' % bcp_47.header)
+print (' */')
+print ()
+print ('#ifndef HB_OT_TAG_TABLE_HH')
+print ('#define HB_OT_TAG_TABLE_HH')
+print ()
+print ('static const LangTag ot_languages[] = {')
+
+def hb_tag (tag):
+ """Convert a tag to ``HB_TAG`` form.
+
+ Args:
+ tag (str): An OpenType tag.
+
+ Returns:
+ A snippet of C++ representing ``tag``.
+ """
+ return u"HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4])
+
+def get_variant_set (name):
+ """Return a set of variant language names from a name.
+
+ Args:
+ name (str): A list of language names from the BCP 47 registry,
+ joined on ``'\\n'``.
+
+ Returns:
+ A set of normalized language names.
+ """
+ return set (unicodedata.normalize ('NFD', n.replace ('\u2019', u"'"))
+ .encode ('ASCII', 'ignore')
+ .strip ()
+ for n in re.split ('[\n(),]', name) if n)
+
+def language_name_intersection (a, b):
+ """Return the names in common between two language names.
+
+ Args:
+ a (str): A list of language names from the BCP 47 registry,
+ joined on ``'\\n'``.
+ b (str): A list of language names from the BCP 47 registry,
+ joined on ``'\\n'``.
+
+ Returns:
+ The normalized language names shared by ``a`` and ``b``.
+ """
+ return get_variant_set (a).intersection (get_variant_set (b))
+
+def get_matching_language_name (intersection, candidates):
+ return next (iter (c for c in candidates if not intersection.isdisjoint (get_variant_set (c))))
+
+maximum_tags = 0
+for language, tags in sorted (ot.from_bcp_47.items ()):
+ if language == '' or '-' in language:
+ continue
+ print (' {\"%s\",\t{' % language, end='')
+ maximum_tags = max (maximum_tags, len (tags))
+ tag_count = len (tags)
+ for i, tag in enumerate (tags, start=1):
+ if i > 1:
+ print ('\t\t ', end='')
+ print (hb_tag (tag), end='')
+ if i == tag_count:
+ print ('}}', end='')
+ print (',\t/* ', end='')
+ bcp_47_name = bcp_47.names.get (language, '')
+ bcp_47_name_candidates = bcp_47_name.split ('\n')
+ intersection = language_name_intersection (bcp_47_name, ot.names[tag])
+ scope = bcp_47.scopes.get (language, '')
+ if not intersection:
+ write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot.names[tag]))
+ else:
+ name = get_matching_language_name (intersection, bcp_47_name_candidates)
+ bcp_47.names[language] = name
+ write ('%s%s' % (name if len (name) > len (ot.names[tag]) else ot.names[tag], scope))
+ print (' */')
+
+print ('};')
+print ()
+print ('static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == %iu, "");' % maximum_tags)
+print ()
+
+print ('/**')
+print (' * hb_ot_tags_from_complex_language:')
+print (' * @lang_str: a BCP 47 language tag to convert.')
+print (' * @limit: a pointer to the end of the substring of @lang_str to consider for')
+print (' * conversion.')
+print (' * @count: maximum number of language tags to retrieve (IN) and actual number of')
+print (' * language tags retrieved (OUT). If no tags are retrieved, it is not modified.')
+print (' * @tags: array of size at least @language_count to store the language tag')
+print (' * results')
+print (' *')
+print (' * Converts a multi-subtag BCP 47 language tag to language tags.')
+print (' *')
+print (' * Return value: Whether any language systems were retrieved.')
+print (' **/')
+print ('static bool')
+print ('hb_ot_tags_from_complex_language (const char *lang_str,')
+print ('\t\t\t\t const char *limit,')
+print ('\t\t\t\t unsigned int *count /* IN/OUT */,')
+print ('\t\t\t\t hb_tag_t *tags /* OUT */)')
+print ('{')
+
+def print_subtag_matches (subtag, new_line):
+ if subtag:
+ if new_line:
+ print ()
+ print ('\t&& ', end='')
+ print ('subtag_matches (lang_str, limit, "-%s")' % subtag, end='')
+
+complex_tags = collections.defaultdict (list)
+for initial, group in itertools.groupby ((lt_tags for lt_tags in [
+ (LanguageTag (language), tags)
+ for language, tags in sorted (ot.from_bcp_47.items (),
+ key=lambda i: (-len (i[0]), i[0]))
+ ] if lt_tags[0].is_complex ()),
+ key=lambda lt_tags: lt_tags[0].get_group ()):
+ complex_tags[initial] += group
+
+for initial, items in sorted (complex_tags.items ()):
+ if initial != 'und':
+ continue
+ for lt, tags in items:
+ if lt.variant in bcp_47.prefixes:
+ expect (next (iter (bcp_47.prefixes[lt.variant])) == lt.language,
+ '%s is not a valid prefix of %s' % (lt.language, lt.variant))
+ print (' if (', end='')
+ print_subtag_matches (lt.script, False)
+ print_subtag_matches (lt.region, False)
+ print_subtag_matches (lt.variant, False)
+ print (')')
+ print (' {')
+ write (' /* %s */' % bcp_47.get_name (lt))
+ print ()
+ if len (tags) == 1:
+ write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
+ print ()
+ print (' *count = 1;')
+ else:
+ print (' hb_tag_t possible_tags[] = {')
+ for tag in tags:
+ write (' %s, /* %s */' % (hb_tag (tag), ot.names[tag]))
+ print ()
+ print (' };')
+ print (' for (i = 0; i < %s && i < *count; i++)' % len (tags))
+ print (' tags[i] = possible_tags[i];')
+ print (' *count = i;')
+ print (' return true;')
+ print (' }')
+
+print (' switch (lang_str[0])')
+print (' {')
+for initial, items in sorted (complex_tags.items ()):
+ if initial == 'und':
+ continue
+ print (" case '%s':" % initial)
+ for lt, tags in items:
+ print (' if (', end='')
+ if lt.grandfathered:
+ print ('0 == strcmp (&lang_str[1], "%s")' % lt.language[1:], end='')
+ else:
+ string_literal = lt.language[1:] + '-'
+ if lt.script:
+ string_literal += lt.script
+ lt.script = None
+ if lt.region:
+ string_literal += '-' + lt.region
+ lt.region = None
+ if string_literal[-1] == '-':
+ print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='')
+ else:
+ print ('lang_matches (&lang_str[1], "%s")' % string_literal, end='')
+ print_subtag_matches (lt.script, True)
+ print_subtag_matches (lt.region, True)
+ print_subtag_matches (lt.variant, True)
+ print (')')
+ print (' {')
+ write (' /* %s */' % bcp_47.get_name (lt))
+ print ()
+ if len (tags) == 1:
+ write (' tags[0] = %s; /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
+ print ()
+ print (' *count = 1;')
+ else:
+ print (' unsigned int i;')
+ print (' hb_tag_t possible_tags[] = {')
+ for tag in tags:
+ write ('\t%s, /* %s */' % (hb_tag (tag), ot.names[tag]))
+ print ()
+ print (' };')
+ print (' for (i = 0; i < %s && i < *count; i++)' % len (tags))
+ print ('\ttags[i] = possible_tags[i];')
+ print (' *count = i;')
+ print (' return true;')
+ print (' }')
+ print (' break;')
+
+print (' }')
+print (' return false;')
+print ('}')
+print ()
+print ('/**')
+print (' * hb_ot_ambiguous_tag_to_language')
+print (' * @tag: A language tag.')
+print (' *')
+print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to')
+print (' * many language tags) and the best tag is not the alphabetically first, or if')
+print (' * the best tag consists of multiple subtags.')
+print (' *')
+print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,')
+print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.')
+print (' **/')
+print ('static hb_language_t')
+print ('hb_ot_ambiguous_tag_to_language (hb_tag_t tag)')
+print ('{')
+print (' switch (tag)')
+print (' {')
+
+def verify_disambiguation_dict ():
+ """Verify and normalize ``disambiguation``.
+
+ ``disambiguation`` is a map of ambiguous OpenType language system
+ tags to the particular BCP 47 tags they correspond to. This function
+ checks that all its keys really are ambiguous and that each key's
+ value is valid for that key. It checks that no ambiguous tag is
+ missing, except when it can figure out which BCP 47 tag is the best
+ by itself.
+
+ It modifies ``disambiguation`` to remove keys whose values are the
+ same as those that the fallback would return anyway, and to add
+ ambiguous keys whose disambiguations it determined automatically.
+
+ Raises:
+ AssertionError: Verification failed.
+ """
+ global bcp_47
+ global disambiguation
+ global ot
+ for ot_tag, bcp_47_tags in ot.to_bcp_47.items ():
+ primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag)
+ if len (primary_tags) == 1:
+ expect (ot_tag not in disambiguation, 'unnecessary disambiguation for OT tag: %s' % ot_tag)
+ if '-' in primary_tags[0]:
+ disambiguation[ot_tag] = primary_tags[0]
+ elif len (primary_tags) == 0:
+ expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag)
+ else:
+ macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [macrolanguage]')
+ if len (macrolanguages) != 1:
+ macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [family]')
+ if len (macrolanguages) != 1:
+ macrolanguages = list (t for t in primary_tags if 'retired code' not in bcp_47.scopes.get (t, ''))
+ if len (macrolanguages) != 1:
+ expect (ot_tag in disambiguation, 'ambiguous OT tag: %s %s' % (ot_tag, str (macrolanguages)))
+ expect (disambiguation[ot_tag] in bcp_47_tags,
+ '%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag))
+ elif ot_tag not in disambiguation:
+ disambiguation[ot_tag] = macrolanguages[0]
+ if disambiguation[ot_tag] == sorted (primary_tags)[0] and '-' not in disambiguation[ot_tag]:
+ del disambiguation[ot_tag]
+ for ot_tag in disambiguation.keys ():
+ expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag)
+
+verify_disambiguation_dict ()
+for ot_tag, bcp_47_tag in sorted (disambiguation.items ()):
+ write (' case %s: /* %s */' % (hb_tag (ot_tag), ot.names[ot_tag]))
+ print ()
+ write (' return hb_language_from_string (\"%s\", -1); /* %s */' % (bcp_47_tag, bcp_47.get_name (LanguageTag (bcp_47_tag))))
+ print ()
+
+print (' default:')
+print (' return HB_LANGUAGE_INVALID;')
+print (' }')
+print ('}')
+
+print ()
+print ('#endif /* HB_OT_TAG_TABLE_HH */')
+print ()
+print ('/* == End of generated table == */')
+
diff --git a/src/gen-use-table.py b/src/gen-use-table.py
index c742ebaca..ebfae6fab 100755
--- a/src/gen-use-table.py
+++ b/src/gen-use-table.py
@@ -8,7 +8,7 @@ if len (sys.argv) != 5:
print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
sys.exit (1)
-BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
+BLACKLISTED_BLOCKS = ["Thai", "Lao"]
files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
@@ -197,7 +197,10 @@ def is_CONS_SUB(U, UISC, UGC):
def is_CONS_WITH_STACKER(U, UISC, UGC):
return UISC == Consonant_With_Stacker
def is_HALANT(U, UISC, UGC):
- return UISC in [Virama, Invisible_Stacker]
+ return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
+def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
+ # https://github.com/harfbuzz/harfbuzz/issues/1102
+ return U == 0x11046
def is_HALANT_NUM(U, UISC, UGC):
return UISC == Number_Joiner
def is_ZWNJ(U, UISC, UGC):
@@ -248,6 +251,7 @@ use_mapping = {
'SUB': is_CONS_SUB,
'CS': is_CONS_WITH_STACKER,
'H': is_HALANT,
+ 'HVM': is_HALANT_OR_VOWEL_MODIFIER,
'HN': is_HALANT_NUM,
'ZWNJ': is_ZWNJ,
'ZWJ': is_ZWJ,
@@ -281,8 +285,8 @@ use_positions = {
'V': {
'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right],
'Blw': [Bottom, Overstruck, Bottom_And_Right],
- 'Pst': [Right],
- 'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
+ 'Pst': [Right, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
+ 'Pre': [Left],
},
'VM': {
'Abv': [Top],
@@ -295,6 +299,7 @@ use_positions = {
'Blw': [Bottom],
},
'H': None,
+ 'HVM': None,
'B': None,
'FM': None,
'SUB': None,
@@ -307,11 +312,28 @@ def map_to_use(data):
# Resolve Indic_Syllabic_Category
- # TODO: These don't have UISC assigned in Unicode 8.0, but
- # have UIPC
+ # TODO: These don't have UISC assigned in Unicode 8.0, but have UIPC
if U == 0x17DD: UISC = Vowel_Dependent
if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
+ # Tibetan:
+ # TODO: These don't have UISC assigned in Unicode 11.0, but have UIPC
+ if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
+ if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark
+ # Overrides to allow NFC order matching syllable
+ # https://github.com/harfbuzz/harfbuzz/issues/1012
+ if UBlock == 'Tibetan' and is_VOWEL (U, UISC, UGC):
+ if UIPC == Top:
+ UIPC = Bottom
+
+ # TODO: https://github.com/harfbuzz/harfbuzz/pull/982
+ # also https://github.com/harfbuzz/harfbuzz/issues/1012
+ if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC):
+ if UIPC == Top:
+ UIPC = Bottom
+ elif UIPC == Bottom:
+ UIPC = Top
+
# TODO: https://github.com/harfbuzz/harfbuzz/pull/627
if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
@@ -359,13 +381,6 @@ def map_to_use(data):
# https://github.com/roozbehp/unicode-data/issues/8
if U == 0x0A51: UIPC = Bottom
- # TODO: https://github.com/harfbuzz/harfbuzz/pull/982
- if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC):
- if UIPC == Top:
- UIPC = Bottom
- elif UIPC == Bottom:
- UIPC = Top
-
assert (UIPC in [Not_Applicable, Visual_Order_Left] or
USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
@@ -394,7 +409,7 @@ for h in headers:
print (" * %s" % (l.strip()))
print (" */")
print ()
-print ('#include "hb-ot-shape-complex-use-private.hh"')
+print ('#include "hb-ot-shape-complex-use.hh"')
print ()
total = 0
diff --git a/src/harfbuzz-config.cmake.in b/src/harfbuzz-config.cmake.in
index 87b15721a..304410d9b 100644
--- a/src/harfbuzz-config.cmake.in
+++ b/src/harfbuzz-config.cmake.in
@@ -12,7 +12,11 @@ set(_harfbuzz_libdir "@libdir@")
string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}")
set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}")
while (_harfbuzz_libdir_iter)
+ set(_harfbuzz_libdir_prev_iter "${_harfbuzz_libdir_iter}")
get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY)
+ if (_harfbuzz_libdir_prev_iter STREQUAL _harfbuzz_libdir_iter)
+ break()
+ endif ()
get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
endwhile ()
unset(_harfbuzz_libdir_iter)
diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh
index 3b7912b9d..5f7656d2a 100644
--- a/src/hb-aat-layout-ankr-table.hh
+++ b/src/hb-aat-layout-ankr-table.hh
@@ -25,7 +25,7 @@
#ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH
#define HB_AAT_LAYOUT_ANKR_TABLE_HH
-#include "hb-aat-layout-common-private.hh"
+#include "hb-aat-layout-common.hh"
/*
* ankr -- Anchor Point
@@ -45,32 +45,49 @@ struct Anchor
return_trace (c->check_struct (this));
}
+ public:
FWORD xCoordinate;
FWORD yCoordinate;
public:
DEFINE_SIZE_STATIC (4);
};
+typedef LArrayOf<Anchor> GlyphAnchors;
+
struct ankr
{
static const hb_tag_t tableTag = HB_AAT_TAG_ankr;
+ inline const Anchor &get_anchor (hb_codepoint_t glyph_id,
+ unsigned int i,
+ unsigned int num_glyphs,
+ const char *end) const
+ {
+ const Offset<HBUINT16, false> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
+ if (!offset)
+ return Null(Anchor);
+ const GlyphAnchors &anchors = StructAtOffset<GlyphAnchors> (&(this+anchorData), *offset);
+ /* TODO Use sanitizer; to avoid overflows and more. */
+ if (unlikely ((const char *) &anchors + anchors.get_size () > end))
+ return Null(Anchor);
+ return anchors[i];
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version == 0 &&
- lookupTable.sanitize (c, this) &&
- anchors.sanitize (c, this)));
+ lookupTable.sanitize (c, this)));
}
protected:
HBUINT16 version; /* Version number (set to zero) */
HBUINT16 flags; /* Flags (currently unused; set to zero) */
- LOffsetTo<Lookup<HBUINT16> >
+ LOffsetTo<Lookup<Offset<HBUINT16, false> >, false>
lookupTable; /* Offset to the table's lookup table */
- LOffsetTo<LArrayOf<Anchor> >
- anchors; /* Offset to the glyph data table */
+ LOffsetTo<HBUINT8, false>
+ anchorData; /* Offset to the glyph data table */
public:
DEFINE_SIZE_STATIC (12);
diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh
index df2bf5b43..b86408626 100644
--- a/src/hb-aat-layout-bsln-table.hh
+++ b/src/hb-aat-layout-bsln-table.hh
@@ -25,7 +25,7 @@
#ifndef HB_AAT_LAYOUT_BSLN_TABLE_HH
#define HB_AAT_LAYOUT_BSLN_TABLE_HH
-#include "hb-aat-layout-common-private.hh"
+#include "hb-aat-layout-common.hh"
/*
* bsln -- Baseline
diff --git a/src/hb-aat-layout-common-private.hh b/src/hb-aat-layout-common.hh
index d7f35052d..a99ccaf9f 100644
--- a/src/hb-aat-layout-common-private.hh
+++ b/src/hb-aat-layout-common.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_AAT_LAYOUT_COMMON_PRIVATE_HH
-#define HB_AAT_LAYOUT_COMMON_PRIVATE_HH
+#ifndef HB_AAT_LAYOUT_COMMON_HH
+#define HB_AAT_LAYOUT_COMMON_HH
-#include "hb-aat-layout-private.hh"
+#include "hb-aat-layout.hh"
namespace AAT {
@@ -36,111 +36,6 @@ using namespace OT;
/*
- * Binary Searching Tables
- */
-
-struct BinSearchHeader
-{
-
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this));
- }
-
- HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
- HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
- HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
- * that is less than or equal to the value of nUnits. */
- HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
- * or equal to the value of nUnits. */
- HBUINT16 rangeShift; /* The value of unitSize times the difference of the
- * value of nUnits minus the largest power of 2 less
- * than or equal to the value of nUnits. */
- public:
- DEFINE_SIZE_STATIC (10);
-};
-
-template <typename Type>
-struct BinSearchArrayOf
-{
- inline const Type& operator [] (unsigned int i) const
- {
- if (unlikely (i >= header.nUnits)) return Null(Type);
- return StructAtOffset<Type> (bytesZ, i * header.unitSize);
- }
- inline Type& operator [] (unsigned int i)
- {
- return StructAtOffset<Type> (bytesZ, i * header.unitSize);
- }
- inline unsigned int get_size (void) const
- { return header.static_size + header.nUnits * header.unitSize; }
-
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (unlikely (!sanitize_shallow (c))) return_trace (false);
-
- /* Note: for structs that do not reference other structs,
- * we do not need to call their sanitize() as we already did
- * a bound check on the aggregate array size. We just include
- * a small unreachable expression to make sure the structs
- * pointed to do have a simple sanitize(), ie. they do not
- * reference other structs via offsets.
- */
- (void) (false && StructAtOffset<Type> (bytesZ, 0).sanitize (c));
-
- return_trace (true);
- }
- inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
- {
- TRACE_SANITIZE (this);
- if (unlikely (!sanitize_shallow (c))) return_trace (false);
- unsigned int count = header.nUnits;
- for (unsigned int i = 0; i < count; i++)
- if (unlikely (!(*this)[i].sanitize (c, base)))
- return_trace (false);
- return_trace (true);
- }
-
- template <typename T>
- inline const Type *bsearch (const T &key) const
- {
- unsigned int size = header.unitSize;
- int min = 0, max = (int) header.nUnits - 1;
- while (min <= max)
- {
- int mid = (min + max) / 2;
- const Type *p = (const Type *) (((const char *) bytesZ) + (mid * size));
- int c = p->cmp (key);
- if (c < 0)
- max = mid - 1;
- else if (c > 0)
- min = mid + 1;
- else
- return p;
- }
- return nullptr;
- }
-
- private:
- inline bool sanitize_shallow (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (header.sanitize (c) &&
- Type::static_size >= header.unitSize &&
- c->check_array (bytesZ, header.unitSize, header.nUnits));
- }
-
- protected:
- BinSearchHeader header;
- HBUINT8 bytesZ[VAR];
- public:
- DEFINE_SIZE_ARRAY (10, bytesZ);
-};
-
-
-/*
* Lookup Table
*/
@@ -213,7 +108,7 @@ struct LookupFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
- BinSearchArrayOf<LookupSegmentSingle<T> >
+ VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
@@ -243,7 +138,7 @@ struct LookupSegmentArray
GlyphID last; /* Last GlyphID in this segment */
GlyphID first; /* First GlyphID in this segment */
- OffsetTo<UnsizedArrayOf<T> >
+ OffsetTo<UnsizedArrayOf<T>, HBUINT16, false>
valuesZ; /* A 16-bit offset from the start of
* the table to the data. */
public:
@@ -269,8 +164,8 @@ struct LookupFormat4
}
protected:
- HBUINT16 format; /* Format identifier--format = 2 */
- BinSearchArrayOf<LookupSegmentArray<T> >
+ HBUINT16 format; /* Format identifier--format = 4 */
+ VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
@@ -292,7 +187,7 @@ struct LookupSingle
GlyphID glyph; /* Last GlyphID */
T value; /* The lookup value (only one) */
public:
- DEFINE_SIZE_STATIC (4 + T::static_size);
+ DEFINE_SIZE_STATIC (2 + T::static_size);
};
template <typename T>
@@ -315,7 +210,7 @@ struct LookupFormat6
protected:
HBUINT16 format; /* Format identifier--format = 6 */
- BinSearchArrayOf<LookupSingle<T> >
+ VarSizedBinSearchArrayOf<LookupSingle<T> >
entries; /* The actual entries, sorted by glyph index. */
public:
DEFINE_SIZE_ARRAY (8, entries);
@@ -329,7 +224,8 @@ struct LookupFormat8
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
{
- return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
+ return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
+ &valueArrayZ[glyph_id - firstGlyph] : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -339,7 +235,7 @@ struct LookupFormat8
}
protected:
- HBUINT16 format; /* Format identifier--format = 6 */
+ HBUINT16 format; /* Format identifier--format = 8 */
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
@@ -351,6 +247,48 @@ struct LookupFormat8
};
template <typename T>
+struct LookupFormat10
+{
+ friend struct Lookup<T>;
+
+ private:
+ inline const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
+ {
+ if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
+ return Null(T);
+
+ const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
+
+ unsigned int v = 0;
+ unsigned int count = valueSize;
+ for (unsigned int i = 0; i < count; i++)
+ v = (v << 8) | *p++;
+
+ return v;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ valueSize <= 4 &&
+ valueArrayZ.sanitize (c, glyphCount * valueSize));
+ }
+
+ protected:
+ HBUINT16 format; /* Format identifier--format = 8 */
+ HBUINT16 valueSize; /* Byte size of each value. */
+ GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
+ HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
+ * glyph minus the value of firstGlyph plus 1). */
+ UnsizedArrayOf<HBUINT8>
+ valueArrayZ; /* The lookup values (indexed by the glyph index
+ * minus the value of firstGlyph). */
+ public:
+ DEFINE_SIZE_ARRAY (8, valueArrayZ);
+};
+
+template <typename T>
struct Lookup
{
inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
@@ -365,6 +303,17 @@ struct Lookup
}
}
+ inline const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
+ {
+ switch (u.format) {
+ /* Format 10 cannot return a pointer. */
+ case 10: return u.format10.get_value_or_null (glyph_id);
+ default:
+ const T *v = get_value (glyph_id, num_glyphs);
+ return v ? *v : Null(T);
+ }
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -375,6 +324,7 @@ struct Lookup
case 4: return_trace (u.format4.sanitize (c));
case 6: return_trace (u.format6.sanitize (c));
case 8: return_trace (u.format8.sanitize (c));
+ case 10: return_trace (u.format10.sanitize (c));
default:return_trace (true);
}
}
@@ -387,10 +337,30 @@ struct Lookup
LookupFormat4<T> format4;
LookupFormat6<T> format6;
LookupFormat8<T> format8;
+ LookupFormat10<T> format10;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
+/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined
+ * special NULL objects for Lookup<> objects, but since it's template our macros
+ * don't work. So we have to hand-code them here. UGLY. */
+} /* Close namespace. */
+/* Ugly hand-coded null objects for template Lookup<> :(. */
+extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
+template <>
+/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > (void) {
+ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup);
+}
+template <>
+/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > (void) {
+ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup);
+}
+template <>
+/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > (void) {
+ return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup);
+}
+namespace AAT {
/*
@@ -439,10 +409,23 @@ struct Entry<void>
template <typename Extra>
struct StateTable
{
+ enum State
+ {
+ STATE_START_OF_TEXT = 0,
+ STATE_START_OF_LINE = 1,
+ };
+ enum Class
+ {
+ CLASS_END_OF_TEXT = 0,
+ CLASS_OUT_OF_BOUNDS = 1,
+ CLASS_DELETED_GLYPH = 2,
+ CLASS_END_OF_LINE = 3,
+ };
+
inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
- return v ? *v : 1;
+ return v ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS;
}
inline const Entry<Extra> *get_entries () const
@@ -472,6 +455,8 @@ struct StateTable
const HBUINT16 *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
+ unsigned int num_classes = nClasses;
+
unsigned int num_states = 1;
unsigned int num_entries = 0;
@@ -479,20 +464,25 @@ struct StateTable
unsigned int entry = 0;
while (state < num_states)
{
+ if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
+ return_trace (false);
+
if (unlikely (!c->check_array (states,
- states[0].static_size * nClasses,
- num_states)))
+ num_states,
+ num_classes * states[0].static_size)))
+ return_trace (false);
+ if ((c->max_ops -= num_states - state) < 0)
return_trace (false);
{ /* Sweep new states. */
- const HBUINT16 *stop = &states[num_states * nClasses];
- for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++)
+ const HBUINT16 *stop = &states[num_states * num_classes];
+ for (const HBUINT16 *p = &states[state * num_classes]; p < stop; p++)
num_entries = MAX<unsigned int> (num_entries, *p + 1);
state = num_states;
}
- if (unlikely (!c->check_array (entries,
- entries[0].static_size,
- num_entries)))
+ if (unlikely (!c->check_array (entries, num_entries)))
+ return_trace (false);
+ if ((c->max_ops -= num_entries - entry) < 0)
return_trace (false);
{ /* Sweep new entries. */
const Entry<Extra> *stop = &entries[num_entries];
@@ -511,11 +501,11 @@ struct StateTable
protected:
HBUINT32 nClasses; /* Number of classes, which is the number of indices
* in a single line in the state array. */
- LOffsetTo<Lookup<HBUINT16> >
+ LOffsetTo<Lookup<HBUINT16>, false>
classTable; /* Offset to the class table. */
- LOffsetTo<UnsizedArrayOf<HBUINT16> >
+ LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
stateArrayTable;/* Offset to the state array. */
- LOffsetTo<UnsizedArrayOf<Entry<Extra> > >
+ LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
entryTable; /* Offset to the entry array. */
public:
@@ -535,31 +525,32 @@ struct StateTableDriver
template <typename context_t>
inline void drive (context_t *c)
{
- hb_glyph_info_t *info = buffer->info;
-
if (!c->in_place)
buffer->clear_output ();
- unsigned int state = 0;
+ unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
bool last_was_dont_advance = false;
for (buffer->idx = 0;;)
{
unsigned int klass = buffer->idx < buffer->len ?
- machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
- 0 /* End of text */;
+ machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
+ (unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
if (unlikely (!entry))
break;
/* Unsafe-to-break before this if not in state 0, as things might
- * go differently if we start from state 0 here. */
- if (state && buffer->idx)
+ * go differently if we start from state 0 here.
+ *
+ * Ugh. The indexing here is ugly... */
+ if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
{
/* If there's no action and we're just epsilon-transitioning to state 0,
* safe to break. */
if (c->is_actionable (this, entry) ||
- !(entry->newState == 0 && entry->flags == context_t::DontAdvance))
- buffer->unsafe_to_break (buffer->idx - 1, buffer->idx + 1);
+ !(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
+ entry->flags == context_t::DontAdvance))
+ buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
}
/* Unsafe-to-break if end-of-text would kick in here. */
@@ -573,6 +564,8 @@ struct StateTableDriver
if (unlikely (!c->transition (this, entry)))
break;
+ if (unlikely (!buffer->successful)) return;
+
last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
state = entry->newState;
@@ -586,9 +579,10 @@ struct StateTableDriver
if (!c->in_place)
{
- for (; buffer->idx < buffer->len;)
- buffer->next_glyph ();
- buffer->swap_buffers ();
+ for (; buffer->successful && buffer->idx < buffer->len;)
+ buffer->next_glyph ();
+ if (likely (buffer->successful))
+ buffer->swap_buffers ();
}
}
@@ -599,6 +593,7 @@ struct StateTableDriver
};
+struct ankr;
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
@@ -609,24 +604,33 @@ struct hb_aat_apply_context_t :
static return_t default_return_value (void) { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
+ hb_ot_shape_plan_t *plan;
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
+ const ankr &ankr_table;
+ const char *ankr_end;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
unsigned int debug_depth;
- inline hb_aat_apply_context_t (hb_font_t *font_,
+ inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_,
+ hb_font_t *font_,
hb_buffer_t *buffer_,
- hb_blob_t *table) :
- font (font_), face (font->face), buffer (buffer_),
- sanitizer (), lookup_index (0), debug_depth (0)
- {
- sanitizer.init (table);
+ hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)),
+ const ankr &ankr_table_ = Null(ankr),
+ const char *ankr_end_ = nullptr) :
+ plan (plan_), font (font_), face (font->face), buffer (buffer_),
+ sanitizer (),
+ ankr_table (ankr_table_), ankr_end (ankr_end_),
+ lookup_index (0), debug_depth (0)
+ {
+ sanitizer.init (blob);
sanitizer.set_num_glyphs (face->get_num_glyphs ());
sanitizer.start_processing ();
+ sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
}
inline void set_lookup_index (unsigned int i) { lookup_index = i; }
@@ -641,4 +645,4 @@ struct hb_aat_apply_context_t :
} /* namespace AAT */
-#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */
+#endif /* HB_AAT_LAYOUT_COMMON_HH */
diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh
index 3e070d795..b670caab8 100644
--- a/src/hb-aat-layout-feat-table.hh
+++ b/src/hb-aat-layout-feat-table.hh
@@ -25,7 +25,7 @@
#ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH
#define HB_AAT_LAYOUT_FEAT_TABLE_HH
-#include "hb-aat-layout-common-private.hh"
+#include "hb-aat-layout-common.hh"
/*
* feat -- Feature Name
@@ -78,7 +78,7 @@ struct FeatureName
protected:
HBUINT16 feature; /* Feature type. */
HBUINT16 nSettings; /* The number of records in the setting name array. */
- LOffsetTo<UnsizedArrayOf<SettingName> >
+ LOffsetTo<UnsizedArrayOf<SettingName>, false>
settingTable; /* Offset in bytes from the beginning of this table to
* this feature's setting name array. The actual type of
* record this offset refers to will depend on the
diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh
index cc03d6278..e8eb43b87 100644
--- a/src/hb-aat-layout-kerx-table.hh
+++ b/src/hb-aat-layout-kerx-table.hh
@@ -28,9 +28,10 @@
#ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
#define HB_AAT_LAYOUT_KERX_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-aat-layout-common-private.hh"
-#include "hb-aat-layout-ankr-table.hh"
+#include "hb-open-type.hh"
+#include "hb-aat-layout-common.hh"
+#include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-kern-table.hh"
/*
* kerx -- Extended Kerning
@@ -44,7 +45,22 @@ namespace AAT {
using namespace OT;
-struct KerxFormat0Records
+static inline int
+kerxTupleKern (int value,
+ unsigned int tupleCount,
+ const void *base,
+ hb_aat_apply_context_t *c)
+{
+ if (likely (!tupleCount)) return value;
+
+ unsigned int offset = value;
+ const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
+ if (unlikely (!pv->sanitize (&c->sanitizer))) return 0;
+ return *pv;
+}
+
+
+struct KerxSubTableHeader
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -52,217 +68,573 @@ struct KerxFormat0Records
return_trace (likely (c->check_struct (this)));
}
- protected:
- GlyphID left;
- GlyphID right;
- FWORD value;
public:
- DEFINE_SIZE_STATIC (6);
+ HBUINT32 length;
+ HBUINT32 coverage;
+ HBUINT32 tupleCount;
+ public:
+ DEFINE_SIZE_STATIC (12);
};
struct KerxSubTableFormat0
{
- // TODO(ebraminio) Enable when we got suitable BinSearchArrayOf
- // inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
- // {
- // hb_glyph_pair_t pair = {left, right};
- // int i = pairs.bsearch (pair);
- // if (i == -1)
- // return 0;
- // return pairs[i].get_kerning ();
- // }
+ inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
+ {
+ if (header.tupleCount) return 0; /* TODO kerxTupleKern */
+ hb_glyph_pair_t pair = {left, right};
+ int i = pairs.bsearch (pair);
+ return i == -1 ? 0 : pairs[i].get_kerning ();
+ }
+
+ inline bool apply (hb_aat_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ if (!c->plan->requested_kerning)
+ return false;
+
+ hb_kern_machine_t<KerxSubTableFormat0> machine (*this);
+
+ machine.kern (c->font, c->buffer, c->plan->kern_mask);
+
+ return_trace (true);
+ }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- recordsZ.sanitize (c, nPairs)));
+ pairs.sanitize (c)));
}
protected:
- // TODO(ebraminio): A custom version of "BinSearchArrayOf<KerxPair> pairs;" is
- // needed here to use HBUINT32 instead
- HBUINT32 nPairs; /* The number of kerning pairs in this subtable */
- HBUINT32 searchRange; /* The largest power of two less than or equal to the value of nPairs,
- * multiplied by the size in bytes of an entry in the subtable. */
- HBUINT32 entrySelector; /* This is calculated as log2 of the largest power of two less
- * than or equal to the value of nPairs. */
- HBUINT32 rangeShift; /* The value of nPairs minus the largest power of two less than or equal to nPairs. */
- UnsizedArrayOf<KerxFormat0Records>
- recordsZ; /* VAR=nPairs */
+ KerxSubTableHeader header;
+ BinSearchArrayOf<KernPair, HBUINT32>
+ pairs; /* Sorted kern records. */
public:
- DEFINE_SIZE_ARRAY (16, recordsZ);
+ DEFINE_SIZE_ARRAY (28, pairs);
};
struct KerxSubTableFormat1
{
- inline bool sanitize (hb_sanitize_context_t *c) const
+ struct EntryData
{
- TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this) &&
- stateHeader.sanitize (c)));
- }
+ HBUINT16 kernActionIndex;/* Index into the kerning value array. If
+ * this index is 0xFFFF, then no kerning
+ * is to be performed. */
+ public:
+ DEFINE_SIZE_STATIC (2);
+ };
+
+ struct driver_context_t
+ {
+ static const bool in_place = true;
+ enum Flags
+ {
+ Push = 0x8000, /* If set, push this glyph on the kerning stack. */
+ DontAdvance = 0x4000, /* If set, don't advance to the next glyph
+ * before going to the new state. */
+ Reset = 0x2000, /* If set, reset the kerning data (clear the stack) */
+ Reserved = 0x1FFF, /* Not used; set to 0. */
+ };
+
+ inline driver_context_t (const KerxSubTableFormat1 *table,
+ hb_aat_apply_context_t *c_) :
+ c (c_),
+ /* Apparently the offset kernAction is from the beginning of the state-machine,
+ * similar to offsets in morx table, NOT from beginning of this table, like
+ * other subtables in kerx. Discovered via testing. */
+ kernAction (&table->machine + table->kernAction),
+ depth (0) {}
+
+ inline bool is_actionable (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ return entry->data.kernActionIndex != 0xFFFF;
+ }
+ inline bool transition (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ hb_buffer_t *buffer = driver->buffer;
+ unsigned int flags = entry->flags;
+
+ if (flags & Reset)
+ {
+ depth = 0;
+ }
+
+ if (flags & Push)
+ {
+ if (likely (depth < ARRAY_LENGTH (stack)))
+ stack[depth++] = buffer->idx;
+ else
+ depth = 0; /* Probably not what CoreText does, but better? */
+ }
+
+ if (entry->data.kernActionIndex != 0xFFFF)
+ {
+ const FWORD *actions = &kernAction[entry->data.kernActionIndex];
+ if (!c->sanitizer.check_array (actions, depth))
+ {
+ depth = 0;
+ return false;
+ }
+
+ hb_mask_t kern_mask = c->plan->kern_mask;
+ for (unsigned int i = 0; i < depth; i++)
+ {
+ /* Apparently, when spec says "Each pops one glyph from the kerning stack
+ * and applies the kerning value to it.", it doesn't mean it in that order.
+ * The deepest item in the stack corresponds to the first item in the action
+ * list. Discovered by testing. */
+ unsigned int idx = stack[i];
+ int v = *actions++;
+ if (idx < buffer->len && buffer->info[idx].mask & kern_mask)
+ {
+ /* XXX Non-forward direction... */
+ if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+ buffer->pos[idx].x_advance += c->font->em_scale_x (v);
+ else
+ buffer->pos[idx].y_advance += c->font->em_scale_y (v);
+ }
+ }
+ depth = 0;
+ }
+
+ return true;
+ }
- protected:
- StateTable<HBUINT16> stateHeader;
- LOffsetTo<ArrayOf<HBUINT16> > valueTable;
- public:
- DEFINE_SIZE_STATIC (20);
-};
+ private:
+ hb_aat_apply_context_t *c;
+ const UnsizedArrayOf<FWORD> &kernAction;
+ unsigned int stack[8];
+ unsigned int depth;
+ };
-// TODO(ebraminio): Maybe this can be replaced with Lookup<HBUINT16>?
-struct KerxClassTable
-{
- inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
+ inline bool apply (hb_aat_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ if (!c->plan->requested_kerning)
+ return false;
+
+ if (header.tupleCount)
+ return_trace (false); /* TODO kerxTupleKern */
+
+ driver_context_t dc (this, c);
+
+ StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
+ driver.drive (&dc);
+
+ return_trace (true);
+ }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (firstGlyph.sanitize (c) &&
- classes.sanitize (c)));
+ /* The rest of array sanitizations are done at run-time. */
+ return_trace (likely (c->check_struct (this) &&
+ machine.sanitize (c)));
}
protected:
- HBUINT16 firstGlyph; /* First glyph in class range. */
- ArrayOf<HBUINT16> classes; /* Glyph classes. */
+ KerxSubTableHeader header;
+ StateTable<EntryData> machine;
+ LOffsetTo<UnsizedArrayOf<FWORD>, false> kernAction;
public:
- DEFINE_SIZE_ARRAY (4, classes);
+ DEFINE_SIZE_STATIC (32);
};
struct KerxSubTableFormat2
{
- inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
+ inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
+ hb_aat_apply_context_t *c) const
{
- unsigned int l = (this+leftClassTable).get_class (left);
- unsigned int r = (this+leftClassTable).get_class (left);
- unsigned int offset = l * rowWidth + r * sizeof (FWORD);
- const FWORD *arr = &(this+array);
- if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
- return 0;
- const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
- if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
- return 0;
- return *v;
+ unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
+ unsigned int l = (this+leftClassTable).get_value_or_null (left, num_glyphs);
+ unsigned int r = (this+rightClassTable).get_value_or_null (right, num_glyphs);
+ unsigned int offset = l + r;
+ const FWORD *v = &StructAtOffset<FWORD> (&(this+array), offset);
+ if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
+ return kerxTupleKern (*v, header.tupleCount, this, c);
+ }
+
+ inline bool apply (hb_aat_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ if (!c->plan->requested_kerning)
+ return false;
+
+ accelerator_t accel (*this, c);
+ hb_kern_machine_t<accelerator_t> machine (accel);
+ machine.kern (c->font, c->buffer, c->plan->kern_mask);
+
+ return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- rowWidth.sanitize (c) &&
leftClassTable.sanitize (c, this) &&
rightClassTable.sanitize (c, this) &&
- array.sanitize (c, this)));
+ c->check_range (this, array)));
}
+ struct accelerator_t
+ {
+ const KerxSubTableFormat2 &table;
+ hb_aat_apply_context_t *c;
+
+ inline accelerator_t (const KerxSubTableFormat2 &table_,
+ hb_aat_apply_context_t *c_) :
+ table (table_), c (c_) {}
+
+ inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
+ { return table.get_kerning (left, right, c); }
+ };
+
protected:
- HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */
- LOffsetTo<KerxClassTable>
- leftClassTable; /* Offset from beginning of this subtable to
- * left-hand class table. */
- LOffsetTo<KerxClassTable>
- rightClassTable;/* Offset from beginning of this subtable to
- * right-hand class table. */
- LOffsetTo<FWORD>
- array; /* Offset from beginning of this subtable to
- * the start of the kerning array. */
+ KerxSubTableHeader header;
+ HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */
+ LOffsetTo<Lookup<HBUINT16>, false>
+ leftClassTable; /* Offset from beginning of this subtable to
+ * left-hand class table. */
+ LOffsetTo<Lookup<HBUINT16>, false>
+ rightClassTable;/* Offset from beginning of this subtable to
+ * right-hand class table. */
+ LOffsetTo<UnsizedArrayOf<FWORD>, false>
+ array; /* Offset from beginning of this subtable to
+ * the start of the kerning array. */
public:
- DEFINE_SIZE_STATIC (16);
+ DEFINE_SIZE_STATIC (28);
};
struct KerxSubTableFormat4
{
+ struct EntryData
+ {
+ HBUINT16 ankrActionIndex;/* Either 0xFFFF (for no action) or the index of
+ * the action to perform. */
+ public:
+ DEFINE_SIZE_STATIC (2);
+ };
+
+ struct driver_context_t
+ {
+ static const bool in_place = true;
+ enum Flags
+ {
+ Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
+ DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
+ * going to the new state. */
+ Reserved = 0x3FFF, /* Not used; set to 0. */
+ };
+
+ enum SubTableFlags
+ {
+ ActionType = 0xC0000000, /* A two-bit field containing the action type. */
+ Unused = 0x3F000000, /* Unused - must be zero. */
+ Offset = 0x00FFFFFF, /* Masks the offset in bytes from the beginning
+ * of the subtable to the beginning of the control
+ * point table. */
+ };
+
+ inline driver_context_t (const KerxSubTableFormat4 *table,
+ hb_aat_apply_context_t *c_) :
+ c (c_),
+ action_type ((table->flags & ActionType) >> 30),
+ ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
+ mark_set (false),
+ mark (0) {}
+
+ inline bool is_actionable (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ return entry->data.ankrActionIndex != 0xFFFF;
+ }
+ inline bool transition (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ hb_buffer_t *buffer = driver->buffer;
+ unsigned int flags = entry->flags;
+
+ if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
+ {
+ hb_glyph_position_t &o = buffer->cur_pos();
+ switch (action_type)
+ {
+ case 0: /* Control Point Actions.*/
+ {
+ /* indexed into glyph outline. */
+ const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
+ if (!c->sanitizer.check_array (data, 2))
+ return false;
+ HB_UNUSED unsigned int markControlPoint = *data++;
+ HB_UNUSED unsigned int currControlPoint = *data++;
+ hb_position_t markX = 0;
+ hb_position_t markY = 0;
+ hb_position_t currX = 0;
+ hb_position_t currY = 0;
+ if (!c->font->get_glyph_contour_point_for_origin (c->buffer->info[mark].codepoint,
+ markControlPoint,
+ HB_DIRECTION_LTR /*XXX*/,
+ &markX, &markY) ||
+ !c->font->get_glyph_contour_point_for_origin (c->buffer->cur ().codepoint,
+ currControlPoint,
+ HB_DIRECTION_LTR /*XXX*/,
+ &currX, &currY))
+ return true; /* True, such that the machine continues. */
+
+ o.x_offset = markX - currX;
+ o.y_offset = markY - currY;
+ }
+ break;
+
+ case 1: /* Anchor Point Actions. */
+ {
+ /* Indexed into 'ankr' table. */
+ const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
+ if (!c->sanitizer.check_array (data, 2))
+ return false;
+ unsigned int markAnchorPoint = *data++;
+ unsigned int currAnchorPoint = *data++;
+ const Anchor markAnchor = c->ankr_table.get_anchor (c->buffer->info[mark].codepoint,
+ markAnchorPoint,
+ c->sanitizer.get_num_glyphs (),
+ c->ankr_end);
+ const Anchor currAnchor = c->ankr_table.get_anchor (c->buffer->cur ().codepoint,
+ currAnchorPoint,
+ c->sanitizer.get_num_glyphs (),
+ c->ankr_end);
+
+ o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate);
+ o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate);
+ }
+ break;
+
+ case 2: /* Control Point Coordinate Actions. */
+ {
+ const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex];
+ if (!c->sanitizer.check_array (data, 4))
+ return false;
+ int markX = *data++;
+ int markY = *data++;
+ int currX = *data++;
+ int currY = *data++;
+
+ o.x_offset = c->font->em_scale_x (markX) - c->font->em_scale_x (currX);
+ o.y_offset = c->font->em_scale_y (markY) - c->font->em_scale_y (currY);
+ }
+ break;
+ }
+ o.attach_type() = ATTACH_TYPE_MARK;
+ o.attach_chain() = (int) mark - (int) buffer->idx;
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+ }
+
+ if (flags & Mark)
+ {
+ mark_set = true;
+ mark = buffer->idx;
+ }
+
+ return true;
+ }
+
+ private:
+ hb_aat_apply_context_t *c;
+ unsigned int action_type;
+ const HBUINT16 *ankrData;
+ bool mark_set;
+ unsigned int mark;
+ };
+
+ inline bool apply (hb_aat_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ driver_context_t dc (this, c);
+
+ StateTableDriver<EntryData> driver (machine, c->buffer, c->font->face);
+ driver.drive (&dc);
+
+ return_trace (true);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
+ /* The rest of array sanitizations are done at run-time. */
return_trace (likely (c->check_struct (this) &&
- rowWidth.sanitize (c) &&
- leftClassTable.sanitize (c, this) &&
- rightClassTable.sanitize (c, this) &&
- array.sanitize (c, this)));
+ machine.sanitize (c)));
}
protected:
- HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */
- LOffsetTo<KerxClassTable>
- leftClassTable; /* Offset from beginning of this subtable to
- * left-hand class table. */
- LOffsetTo<KerxClassTable>
- rightClassTable;/* Offset from beginning of this subtable to
- * right-hand class table. */
- LOffsetTo<FWORD>
- array; /* Offset from beginning of this subtable to
- * the start of the kerning array. */
+ KerxSubTableHeader header;
+ StateTable<EntryData> machine;
+ HBUINT32 flags;
public:
- DEFINE_SIZE_STATIC (16);
+ DEFINE_SIZE_STATIC (32);
};
struct KerxSubTableFormat6
{
+ enum Flags
+ {
+ ValuesAreLong = 0x00000001,
+ };
+
+ inline bool is_long (void) const { return flags & ValuesAreLong; }
+
+ inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
+ hb_aat_apply_context_t *c) const
+ {
+ unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
+ if (is_long ())
+ {
+ const U::Long &t = u.l;
+ unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
+ unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
+ unsigned int offset = l + r;
+ if (unlikely (offset < l)) return 0; /* Addition overflow. */
+ if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
+ const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
+ if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
+ return kerxTupleKern (*v, header.tupleCount, &(this+vector), c);
+ }
+ else
+ {
+ const U::Short &t = u.s;
+ unsigned int l = (this+t.rowIndexTable).get_value_or_null (left, num_glyphs);
+ unsigned int r = (this+t.columnIndexTable).get_value_or_null (right, num_glyphs);
+ unsigned int offset = l + r;
+ const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
+ if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
+ return kerxTupleKern (*v, header.tupleCount, &(this+vector), c);
+ }
+ }
+
+ inline bool apply (hb_aat_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+
+ if (!c->plan->requested_kerning)
+ return false;
+
+ accelerator_t accel (*this, c);
+ hb_kern_machine_t<accelerator_t> machine (accel);
+ machine.kern (c->font, c->buffer, c->plan->kern_mask);
+
+ return_trace (true);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- rowIndexTable.sanitize (c, this) &&
- columnIndexTable.sanitize (c, this) &&
- kerningArray.sanitize (c, this) &&
- kerningVector.sanitize (c, this)));
+ (is_long () ?
+ (
+ u.l.rowIndexTable.sanitize (c, this) &&
+ u.l.columnIndexTable.sanitize (c, this) &&
+ c->check_range (this, u.l.array)
+ ) : (
+ u.s.rowIndexTable.sanitize (c, this) &&
+ u.s.columnIndexTable.sanitize (c, this) &&
+ c->check_range (this, u.s.array)
+ )) &&
+ (header.tupleCount == 0 ||
+ c->check_range (this, vector))));
}
+ struct accelerator_t
+ {
+ const KerxSubTableFormat6 &table;
+ hb_aat_apply_context_t *c;
+
+ inline accelerator_t (const KerxSubTableFormat6 &table_,
+ hb_aat_apply_context_t *c_) :
+ table (table_), c (c_) {}
+
+ inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
+ { return table.get_kerning (left, right, c); }
+ };
+
protected:
- HBUINT32 flags;
- HBUINT16 rowCount;
- HBUINT16 columnCount;
- LOffsetTo<Lookup<HBUINT16> > rowIndexTable;
- LOffsetTo<Lookup<HBUINT16> > columnIndexTable;
- LOffsetTo<Lookup<HBUINT16> > kerningArray;
- LOffsetTo<Lookup<HBUINT16> > kerningVector;
+ KerxSubTableHeader header;
+ HBUINT32 flags;
+ HBUINT16 rowCount;
+ HBUINT16 columnCount;
+ union U
+ {
+ struct Long
+ {
+ LOffsetTo<Lookup<HBUINT32>, false> rowIndexTable;
+ LOffsetTo<Lookup<HBUINT32>, false> columnIndexTable;
+ LOffsetTo<UnsizedArrayOf<FWORD32>, false> array;
+ } l;
+ struct Short
+ {
+ LOffsetTo<Lookup<HBUINT16>, false> rowIndexTable;
+ LOffsetTo<Lookup<HBUINT16>, false> columnIndexTable;
+ LOffsetTo<UnsizedArrayOf<FWORD>, false> array;
+ } s;
+ } u;
+ LOffsetTo<UnsizedArrayOf<FWORD>, false> vector;
public:
- DEFINE_SIZE_STATIC (24);
-};
-
-enum coverage_flags_t
-{
- COVERAGE_VERTICAL_FLAG = 0x80u,
- COVERAGE_CROSSSTREAM_FLAG = 0x40u,
- COVERAGE_VARIATION_FLAG = 0x20u,
- COVERAGE_PROCESS_DIRECTION = 0x10u,
+ DEFINE_SIZE_STATIC (36);
};
struct KerxTable
{
- inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const
+ friend struct kerx;
+
+ inline unsigned int get_size (void) const { return u.header.length; }
+ inline unsigned int get_type (void) const { return u.header.coverage & SubtableType; }
+
+ enum Coverage
{
- TRACE_APPLY (this);
- /* TODO */
- return_trace (false);
+ Vertical = 0x80000000, /* Set if table has vertical kerning values. */
+ CrossStream = 0x40000000, /* Set if table has cross-stream kerning values. */
+ Variation = 0x20000000, /* Set if table has variation kerning values. */
+ Backwards = 0x10000000, /* If clear, process the glyphs forwards, that
+ * is, from first to last in the glyph stream.
+ * If we, process them from last to first.
+ * This flag only applies to state-table based
+ * 'kerx' subtables (types 1 and 4). */
+ Reserved = 0x0FFFFF00, /* Reserved, set to zero. */
+ SubtableType = 0x000000FF, /* Subtable type. */
+ };
+
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ unsigned int subtable_type = get_type ();
+ TRACE_DISPATCH (this, subtable_type);
+ switch (subtable_type) {
+ case 0 : return_trace (c->dispatch (u.format0));
+ case 1 : return_trace (c->dispatch (u.format1));
+ case 2 : return_trace (c->dispatch (u.format2));
+ case 4 : return_trace (c->dispatch (u.format4));
+ case 6 : return_trace (c->dispatch (u.format6));
+ default: return_trace (c->default_return_value ());
+ }
}
- inline unsigned int get_size (void) const { return length; }
-
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (unlikely (!c->check_struct (this)))
+ if (!u.header.sanitize (c) ||
+ !c->check_range (this, u.header.length))
return_trace (false);
- switch (format) {
- case 0: return u.format0.sanitize (c);
- case 1: return u.format1.sanitize (c);
- case 2: return u.format2.sanitize (c);
- case 4: return u.format4.sanitize (c);
- case 6: return u.format6.sanitize (c);
- default:return_trace (false);
- }
+ return_trace (dispatch (c));
}
protected:
- HBUINT32 length;
- HBUINT8 coverage;
- HBUINT16 unused;
- HBUINT8 format;
- HBUINT32 tupleIndex;
union {
+ KerxSubTableHeader header;
KerxSubTableFormat0 format0;
KerxSubTableFormat1 format1;
KerxSubTableFormat2 format2;
@@ -273,71 +645,90 @@ public:
DEFINE_SIZE_MIN (12);
};
-struct SubtableGlyphCoverageArray
-{
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)));
- }
- protected:
- HBUINT32 length;
- HBUINT32 coverage;
- HBUINT32 tupleCount;
- public:
- DEFINE_SIZE_STATIC (12);
-};
+/*
+ * The 'kerx' Table
+ */
struct kerx
{
static const hb_tag_t tableTag = HB_AAT_TAG_kerx;
- inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const
+ inline bool has_data (void) const { return version != 0; }
+
+ inline void apply (hb_aat_apply_context_t *c) const
{
- TRACE_APPLY (this);
- const KerxTable &table = StructAfter<KerxTable> (*this);
- return_trace (table.apply (c, ankr));
+ c->set_lookup_index (0);
+ const KerxTable *table = &firstTable;
+ unsigned int count = tableCount;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ bool reverse;
+
+ if (table->u.header.coverage & (KerxTable::CrossStream))
+ goto skip; /* We do NOT handle cross-stream. */
+
+ if (HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
+ bool (table->u.header.coverage & KerxTable::Vertical))
+ goto skip;
+
+ reverse = bool (table->u.header.coverage & KerxTable::Backwards) !=
+ HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
+
+ if (!c->buffer->message (c->font, "start kerx subtable %d", c->lookup_index))
+ goto skip;
+
+ if (reverse)
+ c->buffer->reverse ();
+
+ c->sanitizer.set_object (*table);
+
+ /* XXX Reverse-kern is not working yet...
+ * hb_kern_machine_t would need to know that it's reverse-kerning.
+ * Or better yet, make it work in reverse as well, so we don't have
+ * to reverse and reverse back? */
+ table->dispatch (c);
+
+ if (reverse)
+ c->buffer->reverse ();
+
+ (void) c->buffer->message (c->font, "end kerx subtable %d", c->lookup_index);
+
+ skip:
+ table = &StructAfter<KerxTable> (*table);
+ }
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (unlikely (!(c->check_struct (this))))
- return_trace (false);
-
- /* TODO: Something like `morx`s ChainSubtable should be done here instead */
- const KerxTable *table = &StructAfter<KerxTable> (*this);
- if (unlikely (!(table->sanitize (c))))
+ if (!version.sanitize (c) || version < 2 ||
+ !tableCount.sanitize (c))
return_trace (false);
- for (unsigned int i = 0; i < nTables - 1; ++i)
+ const KerxTable *table = &firstTable;
+ unsigned int count = tableCount;
+ for (unsigned int i = 0; i < count; i++)
{
+ if (!table->sanitize (c))
+ return_trace (false);
table = &StructAfter<KerxTable> (*table);
- if (unlikely (!(table->sanitize (c))))
- return_trace (false);
}
- // If version is less than 3, we are done here; otherwise better to check footer also
- if (version < 3)
- return_trace (true);
-
- // TODO: Investigate why this just work on some fonts no matter of version
- // const SubtableGlyphCoverageArray &footer =
- // StructAfter<SubtableGlyphCoverageArray> (*table);
- // return_trace (footer.sanitize (c));
-
return_trace (true);
}
protected:
- HBUINT16 version;
- HBUINT16 padding;
- HBUINT32 nTables;
-/*KerxTable tablesZ[VAR]; XXX ArrayOf??? */
-/*SubtableGlyphCoverageArray coverage_array;*/
+ HBUINT16 version; /* The version number of the extended kerning table
+ * (currently 2, 3, or 4). */
+ HBUINT16 unused; /* Set to 0. */
+ HBUINT32 tableCount; /* The number of subtables included in the extended kerning
+ * table. */
+ KerxTable firstTable; /* Subtables. */
+/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
+
public:
- DEFINE_SIZE_STATIC (8);
+ DEFINE_SIZE_MIN (8);
};
} /* namespace AAT */
diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh
index f25842457..651af2188 100644
--- a/src/hb-aat-layout-morx-table.hh
+++ b/src/hb-aat-layout-morx-table.hh
@@ -27,9 +27,9 @@
#ifndef HB_AAT_LAYOUT_MORX_TABLE_HH
#define HB_AAT_LAYOUT_MORX_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-aat-layout-common-private.hh"
-#include "hb-ot-layout-common-private.hh"
+#include "hb-open-type.hh"
+#include "hb-aat-layout-common.hh"
+#include "hb-ot-layout-common.hh"
/*
* morx -- Extended Glyph Metamorphosis
@@ -50,7 +50,8 @@ struct RearrangementSubtable
struct driver_context_t
{
static const bool in_place = true;
- enum Flags {
+ enum Flags
+ {
MarkFirst = 0x8000, /* If set, make the current glyph the first
* glyph to be rearranged. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
@@ -163,7 +164,7 @@ struct RearrangementSubtable
driver_context_t dc (this);
- StateTableDriver<void> driver (machine, c->buffer, c->face);
+ StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
@@ -196,7 +197,8 @@ struct ContextualSubtable
struct driver_context_t
{
static const bool in_place = true;
- enum Flags {
+ enum Flags
+ {
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
@@ -268,7 +270,7 @@ struct ContextualSubtable
private:
bool mark_set;
unsigned int mark;
- const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> &subs;
+ const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false> &subs;
};
inline bool apply (hb_aat_apply_context_t *c) const
@@ -309,7 +311,7 @@ struct ContextualSubtable
protected:
StateTable<EntryData>
machine;
- LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> >
+ LOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32, false>, false>
substitutionTables;
public:
DEFINE_SIZE_STATIC (20);
@@ -329,7 +331,8 @@ struct LigatureSubtable
struct driver_context_t
{
static const bool in_place = false;
- enum Flags {
+ enum Flags
+ {
SetComponent = 0x8000, /* Push this glyph onto the component stack for
* eventual processing. */
DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the
@@ -338,7 +341,8 @@ struct LigatureSubtable
* group. */
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
};
- enum LigActionFlags {
+ enum LigActionFlags
+ {
LigActionLast = 0x80000000, /* This is the last action in the list. This also
* implies storage. */
LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index
@@ -361,7 +365,7 @@ struct LigatureSubtable
inline bool is_actionable (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
{
- return !!(entry->flags & PerformAction);
+ return entry->flags & PerformAction;
}
inline bool transition (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
@@ -387,12 +391,20 @@ struct LigatureSubtable
unsigned int action_idx = entry->data.ligActionIndex;
unsigned int action;
unsigned int ligature_idx = 0;
+
+ if (unlikely (!match_length))
+ return true;
+
+ /* TODO Only when ligation happens? */
+ buffer->merge_out_clusters (match_positions[0], buffer->out_len);
+
+ unsigned int cursor = match_length;
do
{
- if (unlikely (!match_length))
- return false;
+ if (unlikely (!cursor))
+ break;
- buffer->move_to (match_positions[--match_length]);
+ buffer->move_to (match_positions[--cursor]);
const HBUINT32 &actionData = ligAction[action_idx];
if (unlikely (!actionData.sanitize (&c->sanitizer))) return false;
@@ -400,8 +412,10 @@ struct LigatureSubtable
uint32_t uoffset = action & LigActionOffset;
if (uoffset & 0x20000000)
- uoffset += 0xC0000000;
+ uoffset |= 0xC0000000; /* Sign-extend. */
int32_t offset = (int32_t) uoffset;
+ if (buffer->idx >= buffer->len)
+ return false; // TODO Work on previous instead?
unsigned int component_idx = buffer->cur().codepoint + offset;
const HBUINT16 &componentData = component[component_idx];
@@ -414,21 +428,21 @@ struct LigatureSubtable
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
hb_codepoint_t lig = ligatureData;
- match_positions[match_length++] = buffer->out_len;
buffer->replace_glyph (lig);
- //ligature_idx = 0; // XXX Yes or no?
- }
- else
- {
- buffer->skip_glyph ();
- end--;
+ /* Now go and delete all subsequent components. */
+ while (match_length - 1 > cursor)
+ {
+ buffer->move_to (match_positions[--match_length]);
+ buffer->skip_glyph ();
+ end--;
+ }
}
- /* TODO merge_clusters / unsafe_to_break */
action_idx++;
}
while (!(action & LigActionLast));
+ match_length = 0;
buffer->move_to (end);
}
@@ -469,11 +483,11 @@ struct LigatureSubtable
protected:
StateTable<EntryData>
machine;
- LOffsetTo<UnsizedArrayOf<HBUINT32> >
+ LOffsetTo<UnsizedArrayOf<HBUINT32>, false>
ligAction; /* Offset to the ligature action table. */
- LOffsetTo<UnsizedArrayOf<HBUINT16> >
+ LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
component; /* Offset to the component table. */
- LOffsetTo<UnsizedArrayOf<GlyphID> >
+ LOffsetTo<UnsizedArrayOf<GlyphID>, false>
ligature; /* Offset to the actual ligature lists. */
public:
DEFINE_SIZE_STATIC (28);
@@ -517,19 +531,201 @@ struct NoncontextualSubtable
struct InsertionSubtable
{
+ struct EntryData
+ {
+ HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table.
+ * The number of glyphs to be inserted is contained
+ * in the currentInsertCount field in the flags.
+ * A value of 0xFFFF indicates no insertion is to
+ * be done. */
+ HBUINT16 markedInsertIndex; /* Zero-based index into the insertion glyph table.
+ * The number of glyphs to be inserted is contained
+ * in the markedInsertCount field in the flags.
+ * A value of 0xFFFF indicates no insertion is to
+ * be done. */
+ public:
+ DEFINE_SIZE_STATIC (4);
+ };
+
+ struct driver_context_t
+ {
+ static const bool in_place = false;
+ enum Flags
+ {
+ SetMark = 0x8000, /* If set, mark the current glyph. */
+ DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
+ * going to the new state. This does not mean
+ * that the glyph pointed to is the same one as
+ * before. If you've made insertions immediately
+ * downstream of the current glyph, the next glyph
+ * processed would in fact be the first one
+ * inserted. */
+ CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero,
+ * then the specified glyph list will be inserted
+ * as a kashida-like insertion, either before or
+ * after the current glyph (depending on the state
+ * of the currentInsertBefore flag). If clear, and
+ * the currentInsertList is nonzero, then the
+ * specified glyph list will be inserted as a
+ * split-vowel-like insertion, either before or
+ * after the current glyph (depending on the state
+ * of the currentInsertBefore flag). */
+ MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero,
+ * then the specified glyph list will be inserted
+ * as a kashida-like insertion, either before or
+ * after the marked glyph (depending on the state
+ * of the markedInsertBefore flag). If clear, and
+ * the markedInsertList is nonzero, then the
+ * specified glyph list will be inserted as a
+ * split-vowel-like insertion, either before or
+ * after the marked glyph (depending on the state
+ * of the markedInsertBefore flag). */
+ CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made
+ * to the left of the current glyph. If clear,
+ * they're made to the right of the current glyph. */
+ MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be
+ * made to the left of the marked glyph. If clear,
+ * they're made to the right of the marked glyph. */
+ CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the
+ * number of glyphs to insert at the current
+ * position. Since zero means no insertions, the
+ * largest number of insertions at any given
+ * current location is 31 glyphs. */
+ MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the
+ * number of glyphs to insert at the marked
+ * position. Since zero means no insertions, the
+ * largest number of insertions at any given
+ * marked location is 31 glyphs. */
+ };
+
+ inline driver_context_t (const InsertionSubtable *table,
+ hb_aat_apply_context_t *c_) :
+ ret (false),
+ c (c_),
+ mark_set (false),
+ mark (0),
+ insertionAction (table+table->insertionAction) {}
+
+ inline bool is_actionable (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
+ (entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
+ }
+ inline bool transition (StateTableDriver<EntryData> *driver,
+ const Entry<EntryData> *entry)
+ {
+ hb_buffer_t *buffer = driver->buffer;
+ unsigned int flags = entry->flags;
+
+ if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
+ {
+ unsigned int count = (flags & MarkedInsertCount);
+ unsigned int start = entry->data.markedInsertIndex;
+ const GlyphID *glyphs = &insertionAction[start];
+ if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+
+ bool before = flags & MarkedInsertBefore;
+
+ unsigned int end = buffer->out_len;
+ buffer->move_to (mark);
+
+ if (buffer->idx < buffer->len && !before)
+ buffer->copy_glyph ();
+ /* TODO We ignore KashidaLike setting. */
+ for (unsigned int i = 0; i < count; i++)
+ buffer->output_glyph (glyphs[i]);
+ if (buffer->idx < buffer->len && !before)
+ buffer->skip_glyph ();
+
+ buffer->move_to (end + count);
+
+ buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
+ }
+
+ if (entry->data.currentInsertIndex != 0xFFFF)
+ {
+ unsigned int count = (flags & CurrentInsertCount) >> 5;
+ unsigned int start = entry->data.currentInsertIndex;
+ const GlyphID *glyphs = &insertionAction[start];
+ if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
+
+ bool before = flags & CurrentInsertBefore;
+
+ unsigned int end = buffer->out_len;
+
+ if (buffer->idx < buffer->len && !before)
+ buffer->copy_glyph ();
+ /* TODO We ignore KashidaLike setting. */
+ for (unsigned int i = 0; i < count; i++)
+ buffer->output_glyph (glyphs[i]);
+ if (buffer->idx < buffer->len && !before)
+ buffer->skip_glyph ();
+
+ /* Humm. Not sure where to move to. There's this wording under
+ * DontAdvance flag:
+ *
+ * "If set, don't update the glyph index before going to the new state.
+ * This does not mean that the glyph pointed to is the same one as
+ * before. If you've made insertions immediately downstream of the
+ * current glyph, the next glyph processed would in fact be the first
+ * one inserted."
+ *
+ * This suggests that if DontAdvance is NOT set, we should move to
+ * end+count. If it *was*, then move to end, such that newly inserted
+ * glyphs are now visible.
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417
+ */
+ buffer->move_to ((flags & DontAdvance) ? end : end + count);
+ }
+
+ if (flags & SetMark)
+ {
+ mark_set = true;
+ mark = buffer->out_len;
+ }
+
+ return true;
+ }
+
+ public:
+ bool ret;
+ private:
+ hb_aat_apply_context_t *c;
+ bool mark_set;
+ unsigned int mark;
+ const UnsizedArrayOf<GlyphID> &insertionAction;
+ };
+
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
- /* TODO */
- return_trace (false);
+
+ driver_context_t dc (this, c);
+
+ StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
+ driver.drive (&dc);
+
+ return_trace (dc.ret);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- /* TODO */
- return_trace (true);
+ /* The rest of array sanitizations are done at run-time. */
+ return_trace (c->check_struct (this) && machine.sanitize (c) &&
+ insertionAction);
}
+
+ protected:
+ StateTable<EntryData>
+ machine;
+ LOffsetTo<UnsizedArrayOf<GlyphID>, false>
+ insertionAction; /* Byte offset from stateHeader to the start of
+ * the insertion glyph table. */
+ public:
+ DEFINE_SIZE_STATIC (20);
};
@@ -559,9 +755,27 @@ struct ChainSubtable
friend struct Chain;
inline unsigned int get_size (void) const { return length; }
- inline unsigned int get_type (void) const { return coverage & 0xFF; }
+ inline unsigned int get_type (void) const { return coverage & SubtableType; }
- enum Type {
+ enum Coverage
+ {
+ Vertical = 0x80000000, /* If set, this subtable will only be applied
+ * to vertical text. If clear, this subtable
+ * will only be applied to horizontal text. */
+ Backwards = 0x40000000, /* If set, this subtable will process glyphs
+ * in descending order. If clear, it will
+ * process the glyphs in ascending order. */
+ AllDirections = 0x20000000, /* If set, this subtable will be applied to
+ * both horizontal and vertical text (i.e.
+ * the state of bit 0x80000000 is ignored). */
+ Logical = 0x10000000, /* If set, this subtable will process glyphs
+ * in logical order (or reverse logical order,
+ * depending on the value of bit 0x80000000). */
+ Reserved = 0x0FFFFF00, /* Reserved, set to zero. */
+ SubtableType = 0x000000FF, /* Subtable type; see following table. */
+ };
+ enum Type
+ {
Rearrangement = 0,
Contextual = 1,
Ligature = 2,
@@ -569,11 +783,6 @@ struct ChainSubtable
Insertion = 5
};
- inline void apply (hb_aat_apply_context_t *c) const
- {
- dispatch (c);
- }
-
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
{
@@ -619,28 +828,94 @@ struct Chain
{
inline void apply (hb_aat_apply_context_t *c) const
{
- const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
+ uint32_t flags = defaultFlags;
+ {
+ /* Compute applicable flags. TODO Should move this to planning
+ * stage and take user-requested features into account. */
+ unsigned int count = featureCount;
+ for (unsigned i = 0; i < count; i++)
+ {
+ const Feature &feature = featureZ[i];
+ if (false) /* XXX Check if feature enabled... */
+ {
+ flags &= feature.disableFlags;
+ flags |= feature.enableFlags;
+ }
+ }
+ }
+
+ const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
+ bool reverse;
+
+ if (!(subtable->subFeatureFlags & flags))
+ goto skip;
+
+ if (!(subtable->coverage & ChainSubtable::AllDirections) &&
+ HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
+ bool (subtable->coverage & ChainSubtable::Vertical))
+ goto skip;
+
+ /* Buffer contents is always in logical direction. Determine if
+ * we need to reverse before applying this subtable. We reverse
+ * back after if we did reverse indeed.
+ *
+ * Quoting the spac:
+ * """
+ * Bits 28 and 30 of the coverage field control the order in which
+ * glyphs are processed when the subtable is run by the layout engine.
+ * Bit 28 is used to indicate if the glyph processing direction is
+ * the same as logical order or layout order. Bit 30 is used to
+ * indicate whether glyphs are processed forwards or backwards within
+ * that order.
+
+ Bit 30 Bit 28 Interpretation for Horizontal Text
+ 0 0 The subtable is processed in layout order
+ (the same order as the glyphs, which is
+ always left-to-right).
+ 1 0 The subtable is processed in reverse layout order
+ (the order opposite that of the glyphs, which is
+ always right-to-left).
+ 0 1 The subtable is processed in logical order
+ (the same order as the characters, which may be
+ left-to-right or right-to-left).
+ 1 1 The subtable is processed in reverse logical order
+ (the order opposite that of the characters, which
+ may be right-to-left or left-to-right).
+ */
+ reverse = subtable->coverage & ChainSubtable::Logical ?
+ bool (subtable->coverage & ChainSubtable::Backwards) :
+ bool (subtable->coverage & ChainSubtable::Backwards) !=
+ HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
+
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
- {
- c->set_lookup_index (c->lookup_index + 1);
- continue;
- }
+ goto skip;
- subtable->apply (c);
- subtable = &StructAfter<ChainSubtable> (*subtable);
+ if (reverse)
+ c->buffer->reverse ();
+
+ c->sanitizer.set_object (*subtable);
+
+ subtable->dispatch (c);
+
+ if (reverse)
+ c->buffer->reverse ();
(void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
+ if (unlikely (!c->buffer->successful)) return;
+
+ skip:
+ subtable = &StructAfter<ChainSubtable> (*subtable);
c->set_lookup_index (c->lookup_index + 1);
}
}
inline unsigned int get_size (void) const { return length; }
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int major) const
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int version) const
{
TRACE_SANITIZE (this);
if (!length.sanitize (c) ||
@@ -648,10 +923,10 @@ struct Chain
!c->check_range (this, length))
return_trace (false);
- if (!c->check_array (featureZ, featureZ[0].static_size, featureCount))
+ if (!c->check_array (featureZ.arrayZ, featureCount))
return_trace (false);
- const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
+ const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (&featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
@@ -669,9 +944,9 @@ struct Chain
HBUINT32 featureCount; /* Number of feature subtable entries. */
HBUINT32 subtableCount; /* The number of subtables in the chain. */
- Feature featureZ[VAR]; /* Features. */
-/*ChainSubtable subtableX[VAR];*//* Subtables. */
-/*subtableGlyphCoverageArray*/ /* Only if major == 3. */
+ UnsizedArrayOf<Feature> featureZ; /* Features. */
+/*ChainSubtable firstSubtable;*//* Subtables. */
+/*subtableGlyphCoverageArray*/ /* Only if version >= 3. We don't use. */
public:
DEFINE_SIZE_MIN (16);
@@ -679,21 +954,25 @@ struct Chain
/*
- * The 'mort'/'morx' Tables
+ * The 'morx' Table
*/
struct morx
{
static const hb_tag_t tableTag = HB_AAT_TAG_morx;
+ inline bool has_data (void) const { return version != 0; }
+
inline void apply (hb_aat_apply_context_t *c) const
{
+ if (unlikely (!c->buffer->successful)) return;
c->set_lookup_index (0);
- const Chain *chain = chainsZ;
+ const Chain *chain = &firstChain;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
chain->apply (c);
+ if (unlikely (!c->buffer->successful)) return;
chain = &StructAfter<Chain> (*chain);
}
}
@@ -701,16 +980,15 @@ struct morx
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!version.sanitize (c) ||
- (version.major >> (sizeof (HBUINT32) == 4 ? 1 : 0)) != 1 ||
+ if (!version.sanitize (c) || version < 2 ||
!chainCount.sanitize (c))
return_trace (false);
- const Chain *chain = chainsZ;
+ const Chain *chain = &firstChain;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
- if (!chain->sanitize (c, version.major))
+ if (!chain->sanitize (c, version))
return_trace (false);
chain = &StructAfter<Chain> (*chain);
}
@@ -719,11 +997,12 @@ struct morx
}
protected:
- FixedVersion<>version; /* Version number of the glyph metamorphosis table.
- * 1 for mort, 2 or 3 for morx. */
+ HBUINT16 version; /* Version number of the glyph metamorphosis table.
+ * 2 or 3. */
+ HBUINT16 unused; /* Set to 0. */
HBUINT32 chainCount; /* Number of metamorphosis chains contained in this
* table. */
- Chain chainsZ[VAR]; /* Chains. */
+ Chain firstChain; /* Chains. */
public:
DEFINE_SIZE_MIN (8);
diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh
index f5dc558c3..16729d16f 100644
--- a/src/hb-aat-layout-trak-table.hh
+++ b/src/hb-aat-layout-trak-table.hh
@@ -28,9 +28,9 @@
#ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
#define HB_AAT_LAYOUT_TRAK_TABLE_HH
-#include "hb-aat-layout-common-private.hh"
-#include "hb-ot-layout-private.hh"
-#include "hb-open-type-private.hh"
+#include "hb-aat-layout-common.hh"
+#include "hb-ot-layout.hh"
+#include "hb-open-type.hh"
/*
* trak -- Tracking
@@ -46,29 +46,33 @@ struct TrackTableEntry
{
friend struct TrackData;
- inline bool sanitize (hb_sanitize_context_t *c, const void *base,
- unsigned int size) const
+ inline float get_track_value () const
{
- TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this) &&
- (valuesZ.sanitize (c, base, size))));
+ return track.to_float ();
}
- private:
- inline float get_track_value () const
+ inline int get_value (const void *base,
+ unsigned int index,
+ unsigned int nSizes) const
{
- return track.to_float ();
+ return hb_array_t<FWORD> ((base+valuesZ).arrayZ, nSizes)[index];
}
- inline int get_value (const void *base, unsigned int index) const
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base,
+ unsigned int nSizes) const
{
- return (base+valuesZ)[index];
+ TRACE_SANITIZE (this);
+ return_trace (likely (c->check_struct (this) &&
+ (valuesZ.sanitize (c, base, nSizes))));
}
protected:
Fixed track; /* Track value for this record. */
- NameID trackNameID; /* The 'name' table index for this track */
- OffsetTo<UnsizedArrayOf<FWORD> >
+ NameID trackNameID; /* The 'name' table index for this track.
+ * (a short word or phrase like "loose"
+ * or "very tight") */
+ OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>
valuesZ; /* Offset from start of tracking table to
* per-size tracking values for this track. */
@@ -78,15 +82,22 @@ struct TrackTableEntry
struct TrackData
{
- inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ inline float interpolate_at (unsigned int idx,
+ float target_size,
+ const TrackTableEntry &trackTableEntry,
+ const void *base) const
{
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) &&
- sizeTable.sanitize (c, base, nSizes) &&
- trackTable.sanitize (c, nTracks, base, nSizes));
+ unsigned int sizes = nSizes;
+ hb_array_t<Fixed> size_table ((base+sizeTable).arrayZ, sizes);
+
+ float s0 = size_table[idx].to_float ();
+ float s1 = size_table[idx + 1].to_float ();
+ float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
+ return t * trackTableEntry.get_value (base, idx + 1, sizes) +
+ (1.f - t) * trackTableEntry.get_value (base, idx, sizes);
}
- inline float get_tracking (const void *base, float ptem) const
+ inline int get_tracking (const void *base, float ptem) const
{
/* CoreText points are CSS pixels (96 per inch),
* NOT typographic points (72 per inch).
@@ -94,48 +105,59 @@ struct TrackData
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
*/
float csspx = ptem * 96.f / 72.f;
- Fixed fixed_size;
- fixed_size.set_float (csspx);
- /* XXX Clean this up. Make it work with nSizes==1 and 0. */
+ /*
+ * Choose track.
+ */
+ const TrackTableEntry *trackTableEntry = nullptr;
+ unsigned int count = nTracks;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ /* Note: Seems like the track entries are sorted by values. But the
+ * spec doesn't explicitly say that. It just mentions it in the example. */
- unsigned int sizes = nSizes;
+ /* For now we only seek for track entries with zero tracking value */
- const TrackTableEntry *trackTableEntry = nullptr;
- for (unsigned int i = 0; i < sizes; ++i)
- // For now we only seek for track entries with zero tracking value
if (trackTable[i].get_track_value () == 0.f)
- trackTableEntry = &trackTable[0];
-
- // We couldn't match any, exit
+ {
+ trackTableEntry = &trackTable[i];
+ break;
+ }
+ }
if (!trackTableEntry) return 0.;
+ /*
+ * Choose size.
+ */
+ unsigned int sizes = nSizes;
+ if (!sizes) return 0.;
+ if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
+
/* TODO bfind() */
+ hb_array_t<Fixed> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index;
- UnsizedArrayOf<Fixed> size_table = base+sizeTable;
- for (size_index = 0; size_index < sizes; ++size_index)
- if (size_table[size_index] >= fixed_size)
+ for (size_index = 0; size_index < sizes - 1; size_index++)
+ if (size_table[size_index].to_float () >= csspx)
break;
- // TODO(ebraminio): We don't attempt to extrapolate to larger or
- // smaller values for now but we should do, per spec
- if (size_index == sizes)
- return trackTableEntry->get_value (base, sizes - 1);
- if (size_index == 0 || size_table[size_index] == fixed_size)
- return trackTableEntry->get_value (base, size_index);
-
- float s0 = size_table[size_index - 1].to_float ();
- float s1 = size_table[size_index].to_float ();
- float t = (csspx - s0) / (s1 - s0);
- return (float) t * trackTableEntry->get_value (base, size_index) +
- ((float) 1.0 - t) * trackTableEntry->get_value (base, size_index - 1);
+ return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
+ *trackTableEntry, base));
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ sizeTable.sanitize (c, base, nSizes) &&
+ trackTable.sanitize (c, nTracks, base, nSizes));
}
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
- LOffsetTo<UnsizedArrayOf<Fixed> >
- sizeTable; /* Offset to array[nSizes] of size values. */
+ LOffsetTo<UnsizedArrayOf<Fixed>, false>
+ sizeTable; /* Offset from start of the tracking table to
+ * Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry>
trackTable; /* Array[nTracks] of TrackTableEntry records. */
@@ -147,6 +169,8 @@ struct trak
{
static const hb_tag_t tableTag = HB_AAT_TAG_trak;
+ inline bool has_data (void) const { return version.to_int () != 0; }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -168,25 +192,25 @@ struct trak
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
const TrackData &trackData = this+horizData;
- float tracking = trackData.get_tracking (this, ptem);
- hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2);
+ int tracking = trackData.get_tracking (this, ptem);
+ hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
+ hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
foreach_grapheme (buffer, start, end)
{
- buffer->pos[start].x_offset += advance_to_add;
buffer->pos[start].x_advance += advance_to_add;
- buffer->pos[end].x_advance += advance_to_add;
+ buffer->pos[start].x_offset += offset_to_add;
}
}
else
{
const TrackData &trackData = this+vertData;
- float tracking = trackData.get_tracking (this, ptem);
- hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2);
+ int tracking = trackData.get_tracking (this, ptem);
+ hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
+ hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
foreach_grapheme (buffer, start, end)
{
- buffer->pos[start].y_offset += advance_to_add;
buffer->pos[start].y_advance += advance_to_add;
- buffer->pos[end].y_advance += advance_to_add;
+ buffer->pos[start].y_offset += offset_to_add;
}
}
@@ -194,15 +218,17 @@ struct trak
}
protected:
- FixedVersion<> version; /* Version of the tracking table--currently
- * 0x00010000u for version 1.0. */
- HBUINT16 format; /* Format of the tracking table */
- OffsetTo<TrackData> horizData; /* TrackData for horizontal text */
- OffsetTo<TrackData> vertData; /* TrackData for vertical text */
+ FixedVersion<> version; /* Version of the tracking table
+ * (0x00010000u for version 1.0). */
+ HBUINT16 format; /* Format of the tracking table (set to 0). */
+ OffsetTo<TrackData> horizData; /* Offset from start of tracking table to TrackData
+ * for horizontal text (or 0 if none). */
+ OffsetTo<TrackData> vertData; /* Offset from start of tracking table to TrackData
+ * for vertical text (or 0 if none). */
HBUINT16 reserved; /* Reserved. Set to 0. */
public:
- DEFINE_SIZE_MIN (12);
+ DEFINE_SIZE_STATIC (12);
};
} /* namespace AAT */
diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc
index 36d4037ad..e9da850b3 100644
--- a/src/hb-aat-layout.cc
+++ b/src/hb-aat-layout.cc
@@ -24,12 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
-#include "hb-ot-layout-private.hh"
-#include "hb-ot-layout-gsubgpos-private.hh"
-
-#include "hb-aat-layout-private.hh"
+#include "hb-ot-face.hh"
+#include "hb-aat-layout.hh"
#include "hb-aat-layout-ankr-table.hh"
#include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-feat-table.hh" // Just so we compile it; unused otherwise.
@@ -38,8 +36,101 @@
#include "hb-aat-layout-trak-table.hh"
#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
+
+/* Table data courtesy of Apple. Converted from mnemonics to integers
+ * when moving to this file. */
+static const hb_aat_feature_mapping_t feature_mappings[] =
+{
+ {HB_TAG ('c','2','p','c'), 38/*kUpperCaseType*/, 2/*kUpperCasePetiteCapsSelector*/, 0/*kDefaultUpperCaseSelector*/},
+ {HB_TAG ('c','2','s','c'), 38/*kUpperCaseType*/, 1/*kUpperCaseSmallCapsSelector*/, 0/*kDefaultUpperCaseSelector*/},
+ {HB_TAG ('c','a','l','t'), 36/*kContextualAlternatesType*/, 0/*kContextualAlternatesOnSelector*/, 1/*kContextualAlternatesOffSelector*/},
+ {HB_TAG ('c','a','s','e'), 33/*kCaseSensitiveLayoutType*/, 0/*kCaseSensitiveLayoutOnSelector*/, 1/*kCaseSensitiveLayoutOffSelector*/},
+ {HB_TAG ('c','l','i','g'), 1/*kLigaturesType*/, 18/*kContextualLigaturesOnSelector*/, 19/*kContextualLigaturesOffSelector*/},
+ {HB_TAG ('c','p','s','p'), 33/*kCaseSensitiveLayoutType*/, 2/*kCaseSensitiveSpacingOnSelector*/, 3/*kCaseSensitiveSpacingOffSelector*/},
+ {HB_TAG ('c','s','w','h'), 36/*kContextualAlternatesType*/, 4/*kContextualSwashAlternatesOnSelector*/, 5/*kContextualSwashAlternatesOffSelector*/},
+ {HB_TAG ('d','l','i','g'), 1/*kLigaturesType*/, 4/*kRareLigaturesOnSelector*/, 5/*kRareLigaturesOffSelector*/},
+ {HB_TAG ('e','x','p','t'), 20/*kCharacterShapeType*/, 10/*kExpertCharactersSelector*/, 16},
+ {HB_TAG ('f','r','a','c'), 11/*kFractionsType*/, 2/*kDiagonalFractionsSelector*/, 0/*kNoFractionsSelector*/},
+ {HB_TAG ('f','w','i','d'), 22/*kTextSpacingType*/, 1/*kMonospacedTextSelector*/, 7},
+ {HB_TAG ('h','a','l','t'), 22/*kTextSpacingType*/, 6/*kAltHalfWidthTextSelector*/, 7},
+ {HB_TAG ('h','i','s','t'), 1/*kLigaturesType*/, 20/*kHistoricalLigaturesOnSelector*/, 21/*kHistoricalLigaturesOffSelector*/},
+ {HB_TAG ('h','k','n','a'), 34/*kAlternateKanaType*/, 0/*kAlternateHorizKanaOnSelector*/, 1/*kAlternateHorizKanaOffSelector*/, },
+ {HB_TAG ('h','l','i','g'), 1/*kLigaturesType*/, 20/*kHistoricalLigaturesOnSelector*/, 21/*kHistoricalLigaturesOffSelector*/},
+ {HB_TAG ('h','n','g','l'), 23/*kTransliterationType*/, 1/*kHanjaToHangulSelector*/, 0/*kNoTransliterationSelector*/},
+ {HB_TAG ('h','o','j','o'), 20/*kCharacterShapeType*/, 12/*kHojoCharactersSelector*/, 16},
+ {HB_TAG ('h','w','i','d'), 22/*kTextSpacingType*/, 2/*kHalfWidthTextSelector*/, 7},
+ {HB_TAG ('i','t','a','l'), 32/*kItalicCJKRomanType*/, 2/*kCJKItalicRomanOnSelector*/, 3/*kCJKItalicRomanOffSelector*/},
+ {HB_TAG ('j','p','0','4'), 20/*kCharacterShapeType*/, 11/*kJIS2004CharactersSelector*/, 16},
+ {HB_TAG ('j','p','7','8'), 20/*kCharacterShapeType*/, 2/*kJIS1978CharactersSelector*/, 16},
+ {HB_TAG ('j','p','8','3'), 20/*kCharacterShapeType*/, 3/*kJIS1983CharactersSelector*/, 16},
+ {HB_TAG ('j','p','9','0'), 20/*kCharacterShapeType*/, 4/*kJIS1990CharactersSelector*/, 16},
+ {HB_TAG ('l','i','g','a'), 1/*kLigaturesType*/, 2/*kCommonLigaturesOnSelector*/, 3/*kCommonLigaturesOffSelector*/},
+ {HB_TAG ('l','n','u','m'), 21/*kNumberCaseType*/, 1/*kUpperCaseNumbersSelector*/, 2},
+ {HB_TAG ('m','g','r','k'), 15/*kMathematicalExtrasType*/, 10/*kMathematicalGreekOnSelector*/, 11/*kMathematicalGreekOffSelector*/},
+ {HB_TAG ('n','l','c','k'), 20/*kCharacterShapeType*/, 13/*kNLCCharactersSelector*/, 16},
+ {HB_TAG ('o','n','u','m'), 21/*kNumberCaseType*/, 0/*kLowerCaseNumbersSelector*/, 2},
+ {HB_TAG ('o','r','d','n'), 10/*kVerticalPositionType*/, 3/*kOrdinalsSelector*/, 0/*kNormalPositionSelector*/},
+ {HB_TAG ('p','a','l','t'), 22/*kTextSpacingType*/, 5/*kAltProportionalTextSelector*/, 7},
+ {HB_TAG ('p','c','a','p'), 37/*kLowerCaseType*/, 2/*kLowerCasePetiteCapsSelector*/, 0/*kDefaultLowerCaseSelector*/},
+ {HB_TAG ('p','k','n','a'), 22/*kTextSpacingType*/, 0/*kProportionalTextSelector*/, 7},
+ {HB_TAG ('p','n','u','m'), 6/*kNumberSpacingType*/, 1/*kProportionalNumbersSelector*/, 4},
+ {HB_TAG ('p','w','i','d'), 22/*kTextSpacingType*/, 0/*kProportionalTextSelector*/, 7},
+ {HB_TAG ('q','w','i','d'), 22/*kTextSpacingType*/, 4/*kQuarterWidthTextSelector*/, 7},
+ {HB_TAG ('r','u','b','y'), 28/*kRubyKanaType*/, 2/*kRubyKanaOnSelector*/, 3/*kRubyKanaOffSelector*/},
+ {HB_TAG ('s','i','n','f'), 10/*kVerticalPositionType*/, 4/*kScientificInferiorsSelector*/, 0/*kNormalPositionSelector*/},
+ {HB_TAG ('s','m','c','p'), 37/*kLowerCaseType*/, 1/*kLowerCaseSmallCapsSelector*/, 0/*kDefaultLowerCaseSelector*/},
+ {HB_TAG ('s','m','p','l'), 20/*kCharacterShapeType*/, 1/*kSimplifiedCharactersSelector*/, 16},
+ {HB_TAG ('s','s','0','1'), 35/*kStylisticAlternativesType*/, 2/*kStylisticAltOneOnSelector*/, 3/*kStylisticAltOneOffSelector*/},
+ {HB_TAG ('s','s','0','2'), 35/*kStylisticAlternativesType*/, 4/*kStylisticAltTwoOnSelector*/, 5/*kStylisticAltTwoOffSelector*/},
+ {HB_TAG ('s','s','0','3'), 35/*kStylisticAlternativesType*/, 6/*kStylisticAltThreeOnSelector*/, 7/*kStylisticAltThreeOffSelector*/},
+ {HB_TAG ('s','s','0','4'), 35/*kStylisticAlternativesType*/, 8/*kStylisticAltFourOnSelector*/, 9/*kStylisticAltFourOffSelector*/},
+ {HB_TAG ('s','s','0','5'), 35/*kStylisticAlternativesType*/, 10/*kStylisticAltFiveOnSelector*/, 11/*kStylisticAltFiveOffSelector*/},
+ {HB_TAG ('s','s','0','6'), 35/*kStylisticAlternativesType*/, 12/*kStylisticAltSixOnSelector*/, 13/*kStylisticAltSixOffSelector*/},
+ {HB_TAG ('s','s','0','7'), 35/*kStylisticAlternativesType*/, 14/*kStylisticAltSevenOnSelector*/, 15/*kStylisticAltSevenOffSelector*/},
+ {HB_TAG ('s','s','0','8'), 35/*kStylisticAlternativesType*/, 16/*kStylisticAltEightOnSelector*/, 17/*kStylisticAltEightOffSelector*/},
+ {HB_TAG ('s','s','0','9'), 35/*kStylisticAlternativesType*/, 18/*kStylisticAltNineOnSelector*/, 19/*kStylisticAltNineOffSelector*/},
+ {HB_TAG ('s','s','1','0'), 35/*kStylisticAlternativesType*/, 20/*kStylisticAltTenOnSelector*/, 21/*kStylisticAltTenOffSelector*/},
+ {HB_TAG ('s','s','1','1'), 35/*kStylisticAlternativesType*/, 22/*kStylisticAltElevenOnSelector*/, 23/*kStylisticAltElevenOffSelector*/},
+ {HB_TAG ('s','s','1','2'), 35/*kStylisticAlternativesType*/, 24/*kStylisticAltTwelveOnSelector*/, 25/*kStylisticAltTwelveOffSelector*/},
+ {HB_TAG ('s','s','1','3'), 35/*kStylisticAlternativesType*/, 26/*kStylisticAltThirteenOnSelector*/, 27/*kStylisticAltThirteenOffSelector*/},
+ {HB_TAG ('s','s','1','4'), 35/*kStylisticAlternativesType*/, 28/*kStylisticAltFourteenOnSelector*/, 29/*kStylisticAltFourteenOffSelector*/},
+ {HB_TAG ('s','s','1','5'), 35/*kStylisticAlternativesType*/, 30/*kStylisticAltFifteenOnSelector*/, 31/*kStylisticAltFifteenOffSelector*/},
+ {HB_TAG ('s','s','1','6'), 35/*kStylisticAlternativesType*/, 32/*kStylisticAltSixteenOnSelector*/, 33/*kStylisticAltSixteenOffSelector*/},
+ {HB_TAG ('s','s','1','7'), 35/*kStylisticAlternativesType*/, 34/*kStylisticAltSeventeenOnSelector*/, 35/*kStylisticAltSeventeenOffSelector*/},
+ {HB_TAG ('s','s','1','8'), 35/*kStylisticAlternativesType*/, 36/*kStylisticAltEighteenOnSelector*/, 37/*kStylisticAltEighteenOffSelector*/},
+ {HB_TAG ('s','s','1','9'), 35/*kStylisticAlternativesType*/, 38/*kStylisticAltNineteenOnSelector*/, 39/*kStylisticAltNineteenOffSelector*/},
+ {HB_TAG ('s','s','2','0'), 35/*kStylisticAlternativesType*/, 40/*kStylisticAltTwentyOnSelector*/, 41/*kStylisticAltTwentyOffSelector*/},
+ {HB_TAG ('s','u','b','s'), 10/*kVerticalPositionType*/, 2/*kInferiorsSelector*/, 0/*kNormalPositionSelector*/},
+ {HB_TAG ('s','u','p','s'), 10/*kVerticalPositionType*/, 1/*kSuperiorsSelector*/, 0/*kNormalPositionSelector*/},
+ {HB_TAG ('s','w','s','h'), 36/*kContextualAlternatesType*/, 2/*kSwashAlternatesOnSelector*/, 3/*kSwashAlternatesOffSelector*/},
+ {HB_TAG ('t','i','t','l'), 19/*kStyleOptionsType*/, 4/*kTitlingCapsSelector*/, 0/*kNoStyleOptionsSelector*/},
+ {HB_TAG ('t','n','a','m'), 20/*kCharacterShapeType*/, 14/*kTraditionalNamesCharactersSelector*/, 16},
+ {HB_TAG ('t','n','u','m'), 6/*kNumberSpacingType*/, 0/*kMonospacedNumbersSelector*/, 4},
+ {HB_TAG ('t','r','a','d'), 20/*kCharacterShapeType*/, 0/*kTraditionalCharactersSelector*/, 16},
+ {HB_TAG ('t','w','i','d'), 22/*kTextSpacingType*/, 3/*kThirdWidthTextSelector*/, 7},
+ {HB_TAG ('u','n','i','c'), 3/*kLetterCaseType*/, 14, 15},
+ {HB_TAG ('v','a','l','t'), 22/*kTextSpacingType*/, 5/*kAltProportionalTextSelector*/, 7},
+ {HB_TAG ('v','e','r','t'), 4/*kVerticalSubstitutionType*/, 0/*kSubstituteVerticalFormsOnSelector*/, 1/*kSubstituteVerticalFormsOffSelector*/},
+ {HB_TAG ('v','h','a','l'), 22/*kTextSpacingType*/, 6/*kAltHalfWidthTextSelector*/, 7},
+ {HB_TAG ('v','k','n','a'), 34/*kAlternateKanaType*/, 2/*kAlternateVertKanaOnSelector*/, 3/*kAlternateVertKanaOffSelector*/},
+ {HB_TAG ('v','p','a','l'), 22/*kTextSpacingType*/, 5/*kAltProportionalTextSelector*/, 7},
+ {HB_TAG ('v','r','t','2'), 4/*kVerticalSubstitutionType*/, 0/*kSubstituteVerticalFormsOnSelector*/, 1/*kSubstituteVerticalFormsOffSelector*/},
+ {HB_TAG ('z','e','r','o'), 14/*kTypographicExtrasType*/, 4/*kSlashedZeroOnSelector*/, 5/*kSlashedZeroOffSelector*/},
+};
+
+const hb_aat_feature_mapping_t *
+hb_aat_layout_find_feature_mapping (hb_tag_t tag)
+{
+ return (const hb_aat_feature_mapping_t *) bsearch (&tag,
+ feature_mappings,
+ ARRAY_LENGTH (feature_mappings),
+ sizeof (feature_mappings[0]),
+ hb_aat_feature_mapping_t::cmp);
+}
+
+
/*
- * morx/kerx/trak/ankr
+ * morx/kerx/trak
*/
static inline const AAT::morx&
@@ -51,46 +142,101 @@ _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
*blob = hb_blob_get_empty ();
return Null(AAT::morx);
}
- hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
- const AAT::morx& morx = *(layout->table.morx.get ());
+ const AAT::morx& morx = *(hb_ot_face_data (face)->morx.get ());
if (blob)
- *blob = layout->table.morx.get_blob ();
+ *blob = hb_ot_face_data (face)->morx.get_blob ();
return morx;
}
+static inline const AAT::kerx&
+_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
+ {
+ if (blob)
+ *blob = hb_blob_get_empty ();
+ return Null(AAT::kerx);
+ }
+ const AAT::kerx& kerx = *(hb_ot_face_data (face)->kerx.get ());
+ if (blob)
+ *blob = hb_ot_face_data (face)->kerx.get_blob ();
+ return kerx;
+}
+static inline const AAT::ankr&
+_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
+ {
+ if (blob)
+ *blob = hb_blob_get_empty ();
+ return Null(AAT::ankr);
+ }
+ const AAT::ankr& ankr = *(hb_ot_face_data (face)->ankr.get ());
+ if (blob)
+ *blob = hb_ot_face_data (face)->ankr.get_blob ();
+ return ankr;
+}
+static inline const AAT::trak&
+_get_trak (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(AAT::trak);
+ return *(hb_ot_face_data (face)->trak.get ());
+}
-// static inline void
-// _hb_aat_layout_create (hb_face_t *face)
-// {
-// hb_blob_t *morx_blob = hb_sanitize_context_t ().reference_table<AAT::morx> (face);
-// morx_blob->as<AAT::morx> ();
-// if (0)
-// {
-// morx_blob->as<AAT::Lookup<OT::GlyphID> > ()->get_value (1, face->get_num_glyphs ());
-// }
-// }
+hb_bool_t
+hb_aat_layout_has_substitution (hb_face_t *face)
+{
+ return _get_morx (face).has_data ();
+}
void
-hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
+hb_aat_layout_substitute (hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
{
hb_blob_t *blob;
const AAT::morx& morx = _get_morx (font->face, &blob);
- AAT::hb_aat_apply_context_t c (font, buffer, blob);
+ AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
morx.apply (&c);
}
+
+hb_bool_t
+hb_aat_layout_has_positioning (hb_face_t *face)
+{
+ return _get_kerx (face).has_data ();
+}
+
void
-hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer)
+hb_aat_layout_position (hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
{
-#if 0
hb_blob_t *blob;
- const AAT::ankr& ankr = _get_ankr (font->face, &blob);
const AAT::kerx& kerx = _get_kerx (font->face, &blob);
- const AAT::trak& trak = _get_trak (font->face, &blob);
- AAT::hb_aat_apply_context_t c (font, buffer, blob);
- kerx.apply (&c, &ankr);
+ hb_blob_t *ankr_blob;
+ const AAT::ankr& ankr = _get_ankr (font->face, &ankr_blob);
+
+ AAT::hb_aat_apply_context_t c (plan, font, buffer, blob,
+ ankr, ankr_blob->data + ankr_blob->length);
+ kerx.apply (&c);
+}
+
+hb_bool_t
+hb_aat_layout_has_tracking (hb_face_t *face)
+{
+ return _get_trak (face).has_data ();
+}
+
+void
+hb_aat_layout_track (hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ const AAT::trak& trak = _get_trak (font->face);
+
+ AAT::hb_aat_apply_context_t c (plan, font, buffer);
trak.apply (&c);
-#endif
}
diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh
new file mode 100644
index 000000000..d0eb0190d
--- /dev/null
+++ b/src/hb-aat-layout.hh
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2017 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_AAT_LAYOUT_HH
+#define HB_AAT_LAYOUT_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shape.hh"
+
+
+struct hb_aat_feature_mapping_t
+{
+ hb_tag_t otFeatureTag;
+ uint16_t aatFeatureType;
+ uint16_t selectorToEnable;
+ uint16_t selectorToDisable;
+
+ static inline int cmp (const void *key_, const void *entry_)
+ {
+ hb_tag_t key = * (unsigned int *) key_;
+ const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
+ return key < entry->otFeatureTag ? -1 :
+ key > entry->otFeatureTag ? 1 :
+ 0;
+ }
+};
+
+HB_INTERNAL const hb_aat_feature_mapping_t *
+hb_aat_layout_find_feature_mapping (hb_tag_t tag);
+
+
+HB_INTERNAL hb_bool_t
+hb_aat_layout_has_substitution (hb_face_t *face);
+
+HB_INTERNAL void
+hb_aat_layout_substitute (hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+HB_INTERNAL hb_bool_t
+hb_aat_layout_has_positioning (hb_face_t *face);
+
+HB_INTERNAL void
+hb_aat_layout_position (hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+HB_INTERNAL hb_bool_t
+hb_aat_layout_has_tracking (hb_face_t *face);
+
+HB_INTERNAL void
+hb_aat_layout_track (hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+#endif /* HB_AAT_LAYOUT_HH */
diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh
index 15c4e89cb..08a1b51a9 100644
--- a/src/hb-aat-ltag-table.hh
+++ b/src/hb-aat-ltag-table.hh
@@ -25,7 +25,7 @@
#ifndef HB_AAT_LTAG_TABLE_HH
#define HB_AAT_LTAG_TABLE_HH
-#include "hb-aat-layout-common-private.hh"
+#include "hb-aat-layout-common.hh"
/*
* ltag -- Language Tag
@@ -46,7 +46,7 @@ struct FTStringRange
}
protected:
- OffsetTo<UnsizedArrayOf<HBUINT8> >
+ OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false>
tag; /* Offset from the start of the table to
* the beginning of the string */
HBUINT16 length; /* String length (in bytes) */
diff --git a/src/hb-atomic-private.hh b/src/hb-atomic.hh
index 297c64698..5cb7ca5d5 100644
--- a/src/hb-atomic-private.hh
+++ b/src/hb-atomic.hh
@@ -29,10 +29,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_ATOMIC_PRIVATE_HH
-#define HB_ATOMIC_PRIVATE_HH
+#ifndef HB_ATOMIC_HH
+#define HB_ATOMIC_HH
-#include "hb-private.hh"
+#include "hb.hh"
/*
@@ -49,17 +49,21 @@
/* Defined externally, i.e. in config.h. */
-#elif !defined(HB_NO_MT) && defined(__ATOMIC_CONSUME)
+#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
/* C++11-style GCC primitives. */
+#define _hb_memory_barrier() __sync_synchronize ()
+
#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL)
#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED)
+#define hb_atomic_int_impl_set(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELEASE)
#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED)
+#define hb_atomic_int_impl_get(AI) __atomic_load_n ((AI), __ATOMIC_ACQUIRE)
#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED)
#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED)
-#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_CONSUME)
+#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_ACQUIRE)
static inline bool
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
{
@@ -74,13 +78,19 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#include <atomic>
+#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel)
+#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
+#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
+
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
+#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
+#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed))
-#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_consume))
+#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
static inline bool
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
{
@@ -98,7 +108,7 @@ static inline void _hb_memory_barrier (void)
{
#if !defined(MemoryBarrier)
/* MinGW has a convoluted history of supporting MemoryBarrier. */
- long dummy = 0;
+ LONG dummy = 0;
InterlockedExchange (&dummy, 1);
#else
MemoryBarrier ();
@@ -106,9 +116,10 @@ static inline void _hb_memory_barrier (void)
}
#define _hb_memory_barrier() _hb_memory_barrier ()
-#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((unsigned *) (AI), (V))
+#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V))
+static_assert ((sizeof (LONG) == sizeof (int)), "");
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O))
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
@@ -136,17 +147,17 @@ static inline int _hb_fetch_and_add (int *AI, int V)
_hb_memory_r_barrier ();
return result;
}
-static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, const void *N)
+static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
{
_hb_memory_w_barrier ();
- int result = atomic_cas_ptr ((void **) P, (void *) O, (void *) N) == (void *) O;
+ bool result = atomic_cas_ptr (P, O, N) == O;
_hb_memory_r_barrier ();
return result;
}
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((const void **) (P), (O), (N))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(__APPLE__)
@@ -163,12 +174,12 @@ static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, cons
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V))
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P))
#else
#if __ppc64__ || __x86_64__ || __aarch64__
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else
-#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P))
+#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
#endif
#endif
@@ -242,6 +253,12 @@ static_assert ((sizeof (long) == sizeof (void *)), "");
#ifndef hb_atomic_ptr_impl_get_relaxed
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
#endif
+#ifndef hb_atomic_int_impl_set
+inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
+#endif
+#ifndef hb_atomic_int_impl_get
+inline int hb_atomic_int_impl_get (int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
+#endif
#ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif
@@ -251,7 +268,9 @@ inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barr
struct hb_atomic_int_t
{
inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); }
+ inline void set (int v_) const { hb_atomic_int_impl_set (&v, v_); }
inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); }
+ inline int get (void) const { return hb_atomic_int_impl_get (&v); }
inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); }
inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); }
@@ -270,12 +289,12 @@ struct hb_atomic_ptr_t
inline void init (T* v_ = nullptr) { set_relaxed (v_); }
inline void set_relaxed (T* v_) const { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
- inline T *get_relaxed (void) const { return hb_atomic_ptr_impl_get_relaxed (&v); }
+ inline T *get_relaxed (void) const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
- inline bool cmpexch (const T *old, T *new_) const{ return hb_atomic_ptr_impl_cmpexch (&v, old, new_); }
+ inline bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
mutable T *v;
};
-#endif /* HB_ATOMIC_PRIVATE_HH */
+#endif /* HB_ATOMIC_HH */
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index 25c3e05aa..368491c05 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -25,13 +25,8 @@
* 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 200809L
-#endif
-
-#include "hb-private.hh"
-#include "hb-blob-private.hh"
+#include "hb.hh"
+#include "hb-blob.hh"
#ifdef HAVE_SYS_MMAN_H
#ifdef HAVE_UNISTD_H
@@ -293,6 +288,8 @@ hb_blob_make_immutable (hb_blob_t *blob)
{
if (hb_object_is_inert (blob))
return;
+ if (blob->immutable)
+ return;
blob->immutable = true;
}
@@ -490,8 +487,8 @@ hb_blob_t::try_make_writable (void)
#if defined(_WIN32) || defined(__CYGWIN__)
# include <windows.h>
#else
-# ifndef _O_BINARY
-# define _O_BINARY 0
+# ifndef O_BINARY
+# define O_BINARY 0
# endif
#endif
@@ -510,8 +507,9 @@ struct hb_mapped_file_t
#if (defined(HAVE_MMAP) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
static void
-_hb_mapped_file_destroy (hb_mapped_file_t *file)
+_hb_mapped_file_destroy (void *file_)
{
+ hb_mapped_file_t *file = (hb_mapped_file_t *) file_;
#ifdef HAVE_MMAP
munmap (file->contents, file->length);
#elif defined(_WIN32) || defined(__CYGWIN__)
@@ -542,7 +540,7 @@ hb_blob_create_from_file (const char *file_name)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty ();
- int fd = open (file_name, O_RDONLY | _O_BINARY, 0);
+ int fd = open (file_name, O_RDONLY | O_BINARY, 0);
if (unlikely (fd == -1)) goto fail_without_close;
struct stat st;
@@ -574,18 +572,45 @@ fail_without_close:
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
mbstowcs (wchar_file_name, file_name, size);
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+ {
+ CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
+ ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
+ ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF;
+ ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000;
+ ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000;
+ ceparams.lpSecurityAttributes = nullptr;
+ ceparams.hTemplateFile = nullptr;
+ fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ,
+ OPEN_EXISTING, &ceparams);
+ }
+#else
fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
nullptr);
+#endif
free (wchar_file_name);
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+ {
+ LARGE_INTEGER length;
+ GetFileSizeEx (fd, &length);
+ file->length = length.LowPart;
+ file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr);
+ }
+#else
file->length = (unsigned long) GetFileSize (fd, nullptr);
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
+#endif
if (unlikely (file->mapping == nullptr)) goto fail;
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+ file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
+#else
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
+#endif
if (unlikely (file->contents == nullptr)) goto fail;
CloseHandle (fd);
diff --git a/src/hb-blob-private.hh b/src/hb-blob.hh
index 49ad68ece..bee8c9794 100644
--- a/src/hb-blob-private.hh
+++ b/src/hb-blob.hh
@@ -26,10 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_BLOB_PRIVATE_HH
-#define HB_BLOB_PRIVATE_HH
+#ifndef HB_BLOB_HH
+#define HB_BLOB_HH
-#include "hb-private.hh"
+#include "hb.hh"
/*
@@ -62,6 +62,10 @@ struct hb_blob_t
{
return unlikely (!data) ? &Null(Type) : reinterpret_cast<const Type *> (data);
}
+ inline hb_bytes_t as_bytes (void) const
+ {
+ return hb_bytes_t (data, length);
+ }
public:
hb_object_header_t header;
@@ -79,4 +83,4 @@ struct hb_blob_t
DECLARE_NULL_INSTANCE (hb_blob_t);
-#endif /* HB_BLOB_PRIVATE_HH */
+#endif /* HB_BLOB_HH */
diff --git a/src/hb-buffer-deserialize-json.hh b/src/hb-buffer-deserialize-json.hh
index 380f3c5fc..1f9e2e91d 100644
--- a/src/hb-buffer-deserialize-json.hh
+++ b/src/hb-buffer-deserialize-json.hh
@@ -29,7 +29,7 @@
#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
#define HB_BUFFER_DESERIALIZE_JSON_HH
-#include "hb-private.hh"
+#include "hb.hh"
#line 36 "hb-buffer-deserialize-json.hh"
diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl
index ec9bc7c9a..f3abb027b 100644
--- a/src/hb-buffer-deserialize-json.rl
+++ b/src/hb-buffer-deserialize-json.rl
@@ -27,7 +27,7 @@
#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
#define HB_BUFFER_DESERIALIZE_JSON_HH
-#include "hb-private.hh"
+#include "hb.hh"
%%{
diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh
index 5bca369f8..67f0a1252 100644
--- a/src/hb-buffer-deserialize-text.hh
+++ b/src/hb-buffer-deserialize-text.hh
@@ -29,7 +29,7 @@
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
#define HB_BUFFER_DESERIALIZE_TEXT_HH
-#include "hb-private.hh"
+#include "hb.hh"
#line 36 "hb-buffer-deserialize-text.hh"
diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl
index 1d90979a9..6268a6c50 100644
--- a/src/hb-buffer-deserialize-text.rl
+++ b/src/hb-buffer-deserialize-text.rl
@@ -27,7 +27,7 @@
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
#define HB_BUFFER_DESERIALIZE_TEXT_HH
-#include "hb-private.hh"
+#include "hb.hh"
%%{
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
index 11471941d..c1d82ab8d 100644
--- a/src/hb-buffer-serialize.cc
+++ b/src/hb-buffer-serialize.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-buffer-private.hh"
+#include "hb-buffer.hh"
static const char *serialize_formats[] = {
@@ -440,8 +440,8 @@ 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 nullptr */
- hb_font_t *font, /* May be nullptr */
+ const char **end_ptr, /* May be NULL */
+ hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format)
{
const char *end;
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index eb7b01caa..ce9b0530c 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -27,8 +27,8 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-buffer-private.hh"
-#include "hb-utf-private.hh"
+#include "hb-buffer.hh"
+#include "hb-utf.hh"
/**
@@ -182,7 +182,11 @@ hb_buffer_t::shift_forward (unsigned int count)
if (idx + count > len)
{
/* Under memory failure we might expose this area. At least
- * clean it up. Oh well... */
+ * clean it up. Oh well...
+ *
+ * Ideally, we should at least set Default_Ignorable bits on
+ * these, as well as consistent cluster values. But the former
+ * is layering violation... */
memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
}
len += count;
@@ -219,6 +223,7 @@ hb_buffer_t::reset (void)
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
flags = HB_BUFFER_FLAG_DEFAULT;
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+ invisible = 0;
clear ();
}
@@ -354,6 +359,8 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
{
if (unlikely (!make_room_for (num_in, num_out))) return;
+ assert (idx + num_in <= len);
+
merge_clusters (idx, idx + num_in);
hb_glyph_info_t orig_info = info[idx];
@@ -369,37 +376,6 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
out_len += num_out;
}
-void
-hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
-{
- if (unlikely (!make_room_for (0, 1))) return;
-
- out_info[out_len] = info[idx];
- out_info[out_len].codepoint = glyph_index;
-
- out_len++;
-}
-
-void
-hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
-{
- if (unlikely (!make_room_for (0, 1))) return;
-
- out_info[out_len] = glyph_info;
-
- out_len++;
-}
-
-void
-hb_buffer_t::copy_glyph (void)
-{
- if (unlikely (!make_room_for (0, 1))) return;
-
- out_info[out_len] = info[idx];
-
- out_len++;
-}
-
bool
hb_buffer_t::move_to (unsigned int i)
{
@@ -429,8 +405,14 @@ hb_buffer_t::move_to (unsigned int i)
unsigned int count = out_len - i;
/* This will blow in our face if memory allocation fails later
- * in this same lookup... */
- if (unlikely (idx < count && !shift_forward (count + 32))) return false;
+ * in this same lookup...
+ *
+ * We used to shift with extra 32 items, instead of the 0 below.
+ * But that would leave empty slots in the buffer in case of allocation
+ * failures. Setting to zero for now to avoid other problems (see
+ * comments in shift_forward(). This can cause O(N^2) behavior more
+ * severely than adding 32 empty slots can... */
+ if (unlikely (idx < count && !shift_forward (count + 0))) return false;
assert (idx >= count);
@@ -442,19 +424,6 @@ hb_buffer_t::move_to (unsigned int i)
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,
@@ -709,6 +678,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_BUFFER_FLAG_DEFAULT,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
+ 0, /* invisible */
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_MAX_OPS_DEFAULT,
@@ -1028,7 +998,7 @@ hb_buffer_get_script (hb_buffer_t *buffer)
* are orthogonal to the scripts, and though they are related, they are
* different concepts and should not be confused with each other.
*
- * Use hb_language_from_string() to convert from ISO 639 language codes to
+ * Use hb_language_from_string() to convert from BCP 47 language tags to
* #hb_language_t.
*
* Since: 0.9.2
@@ -1211,6 +1181,46 @@ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
/**
+ * hb_buffer_set_invisible_glyph:
+ * @buffer: an #hb_buffer_t.
+ * @invisible: the invisible #hb_codepoint_t
+ *
+ * Sets the #hb_codepoint_t that replaces invisible characters in
+ * the shaping result. If set to zero (default), the glyph for the
+ * U+0020 SPACE character is used. Otherwise, this value is used
+ * verbatim.
+ *
+ * Since: 2.0.0
+ **/
+void
+hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t invisible)
+{
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->invisible = invisible;
+}
+
+/**
+ * hb_buffer_get_invisible_glyph:
+ * @buffer: an #hb_buffer_t.
+ *
+ * See hb_buffer_set_invisible_glyph().
+ *
+ * Return value:
+ * The @buffer invisible #hb_codepoint_t.
+ *
+ * Since: 2.0.0
+ **/
+hb_codepoint_t
+hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)
+{
+ return buffer->invisible;
+}
+
+
+/**
* hb_buffer_reset:
* @buffer: an #hb_buffer_t.
*
@@ -1499,6 +1509,8 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
* 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.
+ * Note that hb_language_get_default() is NOT threadsafe the first time
+ * it is called. See documentation for that function for details.
*
* Since: 0.9.7
**/
@@ -1887,6 +1899,10 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
/**
* hb_buffer_diff:
+ * @buffer: a buffer.
+ * @reference: other buffer to compare to.
+ * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
+ * @position_fuzz: allowed absolute difference in position values.
*
* If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
* and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index 8a2d3e869..d0aed02d5 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -44,7 +44,6 @@ HB_BEGIN_DECLS
* hb_glyph_info_t:
* @codepoint: either a Unicode code point (before shaping) or a glyph index
* (after shaping).
- * @mask:
* @cluster: the index of the character in the original text that corresponds
* to this #hb_glyph_info_t, or whatever the client passes to
* hb_buffer_add(). More than one #hb_glyph_info_t can have the same
@@ -59,11 +58,13 @@ HB_BEGIN_DECLS
*
* The #hb_glyph_info_t is the structure that holds information about the
* glyphs and their relation to input text.
- *
*/
-typedef struct hb_glyph_info_t {
+typedef struct hb_glyph_info_t
+{
hb_codepoint_t codepoint;
- hb_mask_t mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */
+ /*< private >*/
+ hb_mask_t mask;
+ /*< public >*/
uint32_t cluster;
/*< private >*/
@@ -92,7 +93,7 @@ typedef struct hb_glyph_info_t {
typedef enum { /*< flags >*/
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
- HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */
+ HB_GLYPH_FLAG_DEFINED = 0x00000001 /*< skip >*/ /* OR of all defined flags */
} hb_glyph_flags_t;
HB_EXTERN hb_glyph_flags_t
@@ -298,7 +299,15 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
HB_EXTERN hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer);
-/*
+/**
+ * hb_buffer_cluster_level_t:
+ * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: Return cluster values grouped by graphemes into
+ * monotone order.
+ * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: Return cluster values grouped into monotone order.
+ * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
+ * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
+ * equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
+ *
* Since: 0.9.42
*/
typedef enum {
@@ -332,6 +341,13 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
HB_EXTERN hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
+HB_EXTERN void
+hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t invisible);
+
+HB_EXTERN hb_codepoint_t
+hb_buffer_get_invisible_glyph (hb_buffer_t *buffer);
+
HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer.hh
index a6c4b6963..0d888e1e0 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer.hh
@@ -27,11 +27,11 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_BUFFER_PRIVATE_HH
-#define HB_BUFFER_PRIVATE_HH
+#ifndef HB_BUFFER_HH
+#define HB_BUFFER_HH
-#include "hb-private.hh"
-#include "hb-unicode-private.hh"
+#include "hb.hh"
+#include "hb-unicode.hh"
#ifndef HB_BUFFER_MAX_LEN_FACTOR
@@ -93,6 +93,7 @@ struct hb_buffer_t
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
+ hb_codepoint_t invisible; /* 0 or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
@@ -119,7 +120,7 @@ struct hb_buffer_t
/* 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;
+ enum { CONTEXT_LENGTH = 5 };
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
@@ -212,13 +213,49 @@ struct hb_buffer_t
unsigned int num_out,
const hb_codepoint_t *glyph_data);
- HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
+ inline void 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++;
+ }
/* 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);
+ inline hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
+ {
+ if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
+
+ if (unlikely (idx == len && !out_len))
+ return Crap(hb_glyph_info_t);
+
+ out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
+ out_info[out_len].codepoint = glyph_index;
+
+ out_len++;
+
+ return out_info[out_len - 1];
+ }
+ inline void output_info (const hb_glyph_info_t &glyph_info)
+ {
+ if (unlikely (!make_room_for (0, 1))) return;
+
+ out_info[out_len] = glyph_info;
+
+ out_len++;
+ }
/* 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. */
+ inline void copy_glyph (void)
+ {
+ if (unlikely (!make_room_for (0, 1))) return;
+
+ out_info[out_len] = info[idx];
+
+ out_len++;
+ }
/* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */
inline void
@@ -226,7 +263,8 @@ struct hb_buffer_t
{
if (have_output)
{
- if (unlikely (out_info != info || out_len != idx)) {
+ if (out_info != info || out_len != idx)
+ {
if (unlikely (!make_room_for (1, 1))) return;
out_info[out_len] = info[idx];
}
@@ -235,10 +273,28 @@ struct hb_buffer_t
idx++;
}
+ /* Copies n glyphs at idx to output and advance idx.
+ * If there's no output, just advance idx. */
+ inline void
+ next_glyphs (unsigned int n)
+ {
+ if (have_output)
+ {
+ if (out_info != info || out_len != idx)
+ {
+ if (unlikely (!make_room_for (n, n))) return;
+ memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
+ }
+ out_len += n;
+ }
+ idx += n;
+ }
/* Advance idx without copying to output. */
- inline void skip_glyph (void) { idx++; }
-
+ inline void skip_glyph (void)
+ {
+ idx++;
+ }
inline void reset_masks (hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
@@ -275,6 +331,8 @@ struct hb_buffer_t
/* Internal methods */
+ HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
+
HB_INTERNAL bool enlarge (unsigned int size);
inline bool ensure (unsigned int size)
@@ -386,4 +444,4 @@ _next_cluster (hb_buffer_t *buffer, unsigned int start)
#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
-#endif /* HB_BUFFER_PRIVATE_HH */
+#endif /* HB_BUFFER_HH */
diff --git a/src/hb-cache.hh b/src/hb-cache.hh
new file mode 100644
index 000000000..eb48f18cf
--- /dev/null
+++ b/src/hb-cache.hh
@@ -0,0 +1,80 @@
+/*
+ * 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_CACHE_HH
+#define HB_CACHE_HH
+
+#include "hb.hh"
+
+
+/* Implements a lock-free cache for int->int functions. */
+
+template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
+struct hb_cache_t
+{
+ static_assert ((key_bits >= cache_bits), "");
+ static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), "");
+ static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), "");
+
+ inline void init (void) { clear (); }
+ inline void fini (void) {}
+
+ inline void clear (void)
+ {
+ for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
+ values[i].set_relaxed (-1);
+ }
+
+ inline bool get (unsigned int key, unsigned int *value) const
+ {
+ unsigned int k = key & ((1u<<cache_bits)-1);
+ unsigned int v = values[k].get_relaxed ();
+ if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) ||
+ (v >> value_bits) != (key >> cache_bits))
+ return false;
+ *value = v & ((1u<<value_bits)-1);
+ return true;
+ }
+
+ inline bool set (unsigned int key, unsigned int value)
+ {
+ if (unlikely ((key >> key_bits) || (value >> value_bits)))
+ return false; /* Overflows */
+ unsigned int k = key & ((1u<<cache_bits)-1);
+ unsigned int v = ((key>>cache_bits)<<value_bits) | value;
+ values[k].set_relaxed (v);
+ return true;
+ }
+
+ private:
+ hb_atomic_int_t values[1u<<cache_bits];
+};
+
+typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
+typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
+
+
+#endif /* HB_CACHE_HH */
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 22dd52f49..ba48dd561 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -26,9 +26,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-machinery-private.hh"
+#include "hb-machinery.hh"
#include <locale.h>
#ifdef HAVE_XLOCALE_H
@@ -45,10 +45,29 @@ _hb_options_init (void)
{
hb_options_union_t u;
u.i = 0;
- u.opts.initialized = 1;
+ u.opts.initialized = true;
- char *c = getenv ("HB_OPTIONS");
- u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
+ const char *c = getenv ("HB_OPTIONS");
+ if (c)
+ {
+ while (*c)
+ {
+ const char *p = strchr (c, ':');
+ if (!p)
+ p = c + strlen (c);
+
+#define OPTION(name, symbol) \
+ if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
+
+ OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
+ OPTION ("aat", aat);
+
+#undef OPTION
+
+ c = *p ? p + 1 : p;
+ }
+
+ }
/* This is idempotent and threadsafe. */
_hb_options.set_relaxed (u.i);
@@ -306,14 +325,14 @@ retry:
/**
* hb_language_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing
- * ISO 639 language code
+ * a BCP 47 language tag
* @len: length of the @str, or -1 if it is %NULL-terminated.
*
- * Converts @str representing an ISO 639 language code to the corresponding
+ * Converts @str representing a BCP 47 language tag to the corresponding
* #hb_language_t.
*
* Return value: (transfer none):
- * The #hb_language_t corresponding to the ISO 639 language code.
+ * The #hb_language_t corresponding to the BCP 47 language tag.
*
* Since: 0.9.2
**/
@@ -361,7 +380,14 @@ hb_language_to_string (hb_language_t language)
/**
* hb_language_get_default:
*
+ * Get default language from current locale.
*
+ * Note that the first time this function is called, it calls
+ * "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
+ * setlocale function is, in many implementations, NOT threadsafe. To avoid
+ * problems, call this function once before multiple threads can call it.
+ * This function is only used from hb_buffer_guess_segment_properties() by
+ * HarfBuzz itself.
*
* Return value: (transfer none):
*
@@ -531,7 +557,6 @@ hb_script_get_horizontal_direction (hb_script_t script)
/* Unicode-8.0 additions */
case HB_SCRIPT_HATRAN:
- case HB_SCRIPT_OLD_HUNGARIAN:
/* Unicode-9.0 additions */
case HB_SCRIPT_ADLAM:
@@ -545,6 +570,7 @@ hb_script_get_horizontal_direction (hb_script_t script)
/* https://github.com/harfbuzz/harfbuzz/issues/1000 */
+ case HB_SCRIPT_OLD_HUNGARIAN:
case HB_SCRIPT_OLD_ITALIC:
case HB_SCRIPT_RUNIC:
@@ -731,8 +757,9 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
#ifdef USE_XLOCALE
-
+#ifdef HB_USE_ATEXIT
static void free_static_C_locale (void);
+#endif
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<HB_LOCALE_T>::value,
hb_C_locale_lazy_loader_t>
@@ -876,8 +903,8 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
bool has_start;
- feature->start = 0;
- feature->end = (unsigned int) -1;
+ feature->start = HB_FEATURE_GLOBAL_START;
+ feature->end = HB_FEATURE_GLOBAL_END;
if (!parse_char (pp, end, '['))
return true;
@@ -1064,7 +1091,7 @@ hb_variation_to_string (hb_variation_t *variation,
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
- len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value));
+ len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
diff --git a/src/hb-common.h b/src/hb-common.h
index 5dc1ebcd2..2f09f4318 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -63,6 +63,23 @@ typedef unsigned __int64 uint64_t;
# include <stdint.h>
#endif
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#define HB_DEPRECATED __attribute__((__deprecated__))
+#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+#define HB_DEPRECATED __declspec(deprecated)
+#else
+#define HB_DEPRECATED
+#endif
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
+#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead")))
+#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
+#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead"))
+#else
+#define HB_DEPRECATED_FOR(f) HB_DEPRECATED
+#endif
+
+
HB_BEGIN_DECLS
@@ -86,8 +103,8 @@ typedef union _hb_var_int_t {
typedef uint32_t hb_tag_t;
-#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(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
+#define HB_UNTAG(tag) (((tag)>>24)&0xFF), (((tag)>>16)&0xFF), (((tag)>>8)&0xFF), ((tag)&0xFF)
#define HB_TAG_NONE HB_TAG(0,0,0,0)
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
@@ -340,13 +357,15 @@ typedef enum
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.
+ * without risking undefined behavior. We have two, for historical reasons.
+ * HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
+ * to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
+ *
* See this thread for technicalities:
*
* https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
*/
- _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/
+ _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_script_t;
@@ -379,6 +398,19 @@ typedef void (*hb_destroy_func_t) (void *user_data);
/* Font features and variations. */
+/**
+ * HB_FEATURE_GLOBAL_START
+ *
+ * Since: 2.0.0
+ */
+#define HB_FEATURE_GLOBAL_START 0
+/**
+ * HB_FEATURE_GLOBAL_END
+ *
+ * Since: 2.0.0
+ */
+#define HB_FEATURE_GLOBAL_END ((unsigned int) -1)
+
typedef struct hb_feature_t {
hb_tag_t tag;
uint32_t value;
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
index 1b916a53d..9f7745dbf 100644
--- a/src/hb-coretext.cc
+++ b/src/hb-coretext.cc
@@ -28,10 +28,11 @@
#define HB_SHAPER coretext
-#include "hb-private.hh"
-#include "hb-shaper-impl-private.hh"
+#include "hb.hh"
+#include "hb-shaper-impl.hh"
#include "hb-coretext.h"
+#include "hb-aat-layout.hh"
#include <math.h>
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
@@ -210,7 +211,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
}
CFURLRef original_url = nullptr;
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ATSFontRef atsFont;
FSRef fsref;
OSStatus status;
@@ -240,7 +241,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = nullptr;
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
+#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
@@ -431,183 +432,6 @@ struct range_record_t {
};
-/* 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,
@@ -624,7 +448,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
/* Attach marks to their bases, to match the 'ot' shaper.
- * Adapted from hb-ot-shape:hb_form_clusters().
+ * Adapted from a very old version of 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
@@ -653,11 +477,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
hb_auto_t<hb_vector_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);
+ const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
if (!mapping)
continue;
@@ -766,7 +586,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
} else {
active_feature_t *feature = active_features.find (&event->feature);
if (feature)
- active_features.remove (feature - active_features.arrayZ);
+ active_features.remove (feature - active_features.arrayZ());
}
}
}
@@ -823,7 +643,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CFStringRef string_ref = nullptr;
CTLineRef line = nullptr;
- if (0)
+ if (false)
{
resize_and_retry:
DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
@@ -1234,7 +1054,7 @@ resize_and_retry:
*
* https://crbug.com/419769
*/
- if (0)
+ if (false)
{
/* Make sure all runs had the expected direction. */
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
diff --git a/src/hb-debug.hh b/src/hb-debug.hh
index 9056ffca2..58c190d27 100644
--- a/src/hb-debug.hh
+++ b/src/hb-debug.hh
@@ -27,8 +27,8 @@
#ifndef HB_DEBUG_HH
#define HB_DEBUG_HH
-#include "hb-private.hh"
-#include "hb-atomic-private.hh"
+#include "hb.hh"
+#include "hb-atomic.hh"
#include "hb-dsalgs.hh"
@@ -43,9 +43,10 @@
struct hb_options_t
{
- unsigned int unused : 1; /* In-case sign bit is here. */
- unsigned int initialized : 1;
- unsigned int uniscribe_bug_compatible : 1;
+ bool unused : 1; /* In-case sign bit is here. */
+ bool initialized : 1;
+ bool uniscribe_bug_compatible : 1;
+ bool aat : 1;
};
union hb_options_union_t {
@@ -67,7 +68,10 @@ hb_options (void)
u.i = _hb_options.get_relaxed ();
if (unlikely (!u.i))
+ {
_hb_options_init ();
+ u.i = _hb_options.get_relaxed ();
+ }
return u.opts;
}
diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h
index eac7efb42..5af9bdbd8 100644
--- a/src/hb-deprecated.h
+++ b/src/hb-deprecated.h
@@ -50,14 +50,191 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t *glyph,
void *user_data);
-HB_EXTERN void
+HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
-HB_EXTERN void
+HB_EXTERN HB_DEPRECATED void
hb_set_invert (hb_set_t *set);
+/**
+ * hb_unicode_eastasian_width_func_t:
+ *
+ * Deprecated: 2.0.0
+ */
+typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode,
+ void *user_data);
+
+/**
+ * hb_unicode_funcs_set_eastasian_width_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ * Deprecated: 2.0.0
+ **/
+HB_EXTERN HB_DEPRECATED void
+hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_eastasian_width_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_unicode_eastasian_width:
+ *
+ * Since: 0.9.2
+ * Deprecated: 2.0.0
+ **/
+HB_EXTERN HB_DEPRECATED unsigned int
+hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t unicode);
+
+
+/**
+ * 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.
+ *
+ * Deprecated: 2.0.0
+ */
+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);
+
+/**
+ * HB_UNICODE_MAX_DECOMPOSITION_LEN:
+ *
+ * See Unicode 6.1 for details on the maximum decomposition length.
+ *
+ * Deprecated: 2.0.0
+ */
+#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */
+
+/**
+ * hb_unicode_funcs_set_decompose_compatibility_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ * Deprecated: 2.0.0
+ **/
+HB_EXTERN HB_DEPRECATED 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);
+
+/**
+ * hb_unicode_decompose_compatibility:
+ *
+ *
+ * Deprecated: 2.0.0
+ **/
+HB_EXTERN HB_DEPRECATED unsigned int
+hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed);
+
+
+typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+ void *user_data);
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
+typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
+
+/**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 0.9.2
+ * Deprecated: 2.0.0
+ **/
+HB_EXTERN 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: 0.9.2
+ * Deprecated: 2.0.0
+ **/
+HB_EXTERN 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_EXTERN hb_position_t
+hb_font_get_glyph_h_kerning (hb_font_t *font,
+ hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
+HB_EXTERN hb_position_t
+hb_font_get_glyph_v_kerning (hb_font_t *font,
+ hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
+
+HB_EXTERN 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);
+
+/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
+HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t
+hb_ot_layout_table_choose_script (hb_face_t *face,
+ hb_tag_t table_tag,
+ const hb_tag_t *script_tags,
+ unsigned int *script_index,
+ hb_tag_t *chosen_script);
+
+HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) hb_bool_t
+hb_ot_layout_script_find_language (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ hb_tag_t language_tag,
+ unsigned int *language_index);
+
+HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void
+hb_ot_tags_from_script (hb_script_t script,
+ hb_tag_t *script_tag_1,
+ hb_tag_t *script_tag_2);
+
+HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t
+hb_ot_tag_from_language (hb_language_t language);
+
+
#endif
HB_END_DECLS
diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc
index baad81884..35197c238 100644
--- a/src/hb-directwrite.cc
+++ b/src/hb-directwrite.cc
@@ -22,9 +22,9 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#include "hb-private.hh"
+#include "hb.hh"
#define HB_SHAPER directwrite
-#include "hb-shaper-impl-private.hh"
+#include "hb-shaper-impl.hh"
#include <DWrite_1.h>
diff --git a/src/hb-dsalgs.hh b/src/hb-dsalgs.hh
index 8cbe6584b..eb15c089e 100644
--- a/src/hb-dsalgs.hh
+++ b/src/hb-dsalgs.hh
@@ -27,7 +27,9 @@
#ifndef HB_DSALGS_HH
#define HB_DSALGS_HH
-#include "hb-private.hh"
+#include "hb.hh"
+
+#include "hb-null.hh"
/* Void! For when we need a expression-type of void. */
@@ -492,23 +494,55 @@ template <typename Type>
struct hb_auto_t : Type
{
hb_auto_t (void) { Type::init (); }
+ /* Explicitly allow the following only for pointer and references,
+ * to avoid any accidental copies.
+ *
+ * Apparently if we template for all types, then gcc seems to
+ * capture a reference argument in the type, but clang doesn't,
+ * causing unwanted copies and bugs that come with it. Ideally
+ * we should use C++11-style rvalue reference &&t1. */
+ template <typename T1> explicit hb_auto_t (T1 *t1) { Type::init (t1); }
+ template <typename T1> explicit hb_auto_t (T1 &t1) { Type::init (t1); }
~hb_auto_t (void) { Type::fini (); }
private: /* Hide */
void init (void) {}
void fini (void) {}
};
+template <typename T>
+struct hb_array_t
+{
+ inline hb_array_t (void) : arrayZ (nullptr), len (0) {}
+ inline hb_array_t (const T *array_, unsigned int len_) : arrayZ (array_), len (len_) {}
+
+ inline const T& operator [] (unsigned int i) const
+ {
+ if (unlikely (i >= len)) return Null(T);
+ return arrayZ[i];
+ }
+
+ inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
+
+ const T *arrayZ;
+ unsigned int len;
+};
+
struct hb_bytes_t
{
- inline hb_bytes_t (void) : bytes (nullptr), len (0) {}
- inline hb_bytes_t (const char *bytes_, unsigned int len_) : bytes (bytes_), len (len_) {}
+ inline hb_bytes_t (void) : arrayZ (nullptr), len (0) {}
+ inline hb_bytes_t (const char *bytes_, unsigned int len_) : arrayZ (bytes_), len (len_) {}
+ inline hb_bytes_t (const void *bytes_, unsigned int len_) : arrayZ ((const char *) bytes_), len (len_) {}
+ template <typename T>
+ inline hb_bytes_t (const T& array) : arrayZ ((const char *) array.arrayZ), len (array.len) {}
+
+ inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
inline int cmp (const hb_bytes_t &a) const
{
if (len != a.len)
return (int) a.len - (int) len;
- return memcmp (a.bytes, bytes, len);
+ return memcmp (a.arrayZ, arrayZ, len);
}
static inline int cmp (const void *pa, const void *pb)
{
@@ -517,7 +551,7 @@ struct hb_bytes_t
return b->cmp (*a);
}
- const char *bytes;
+ const char *arrayZ;
unsigned int len;
};
diff --git a/src/hb-face.cc b/src/hb-face.cc
index 49f29d3fa..bba1ee3fa 100644
--- a/src/hb-face.cc
+++ b/src/hb-face.cc
@@ -26,20 +26,22 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-face-private.hh"
-#include "hb-blob-private.hh"
-#include "hb-open-file-private.hh"
+#include "hb-face.hh"
+#include "hb-blob.hh"
+#include "hb-open-file.hh"
+#include "hb-ot-face.hh"
+#include "hb-ot-cmap-table.hh"
/**
- * hb_face_count: Get number of faces on the blob
- * @blob:
- *
+ * hb_face_count:
+ * @blob: a blob.
*
+ * Get number of faces in a blob.
*
- * Return value: Number of faces on the blob
+ * Return value: Number of faces in @blob
*
* Since: 1.7.7
**/
@@ -161,11 +163,12 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
return hb_blob_reference (data->blob);
const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
- const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+ unsigned int base_offset;
+ const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);
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);
+ hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);
return blob;
}
@@ -322,6 +325,8 @@ hb_face_make_immutable (hb_face_t *face)
{
if (unlikely (hb_object_is_inert (face)))
return;
+ if (face->immutable)
+ return;
face->immutable = true;
}
@@ -485,6 +490,9 @@ hb_face_get_glyph_count (const hb_face_t *face)
/**
* hb_face_get_table_tags:
* @face: a face.
+ * @start_offset: index of first tag to return.
+ * @table_count: input length of @table_tags array, output number of items written.
+ * @table_tags: array to write tags into.
*
* Retrieves table tags for a face, if possible.
*
@@ -512,3 +520,208 @@ hb_face_get_table_tags (const hb_face_t *face,
return ot_face.get_table_tags (start_offset, table_count, table_tags);
}
+
+
+/*
+ * Character set.
+ */
+
+
+/**
+ * hb_face_collect_unicodes:
+ * @face: font face.
+ * @out: set to add Unicode characters covered by @face to.
+ *
+ * Since: 1.9.0
+ */
+void
+hb_face_collect_unicodes (hb_face_t *face,
+ hb_set_t *out)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
+ hb_ot_face_data (face)->cmap->collect_unicodes (out);
+}
+
+/**
+ * hb_face_collect_variation_selectors:
+ * @face: font face.
+ * @out: set to add Variation Selector characters covered by @face to.
+ *
+ *
+ *
+ * Since: 1.9.0
+ */
+void
+hb_face_collect_variation_selectors (hb_face_t *face,
+ hb_set_t *out)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
+ hb_ot_face_data (face)->cmap->collect_variation_selectors (out);
+}
+
+/**
+ * hb_face_collect_variation_unicodes:
+ * @face: font face.
+ * @out: set to add Unicode characters for @variation_selector covered by @face to.
+ *
+ *
+ *
+ * Since: 1.9.0
+ */
+void
+hb_face_collect_variation_unicodes (hb_face_t *face,
+ hb_codepoint_t variation_selector,
+ hb_set_t *out)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
+ hb_ot_face_data (face)->cmap->collect_variation_unicodes (variation_selector, out);
+}
+
+
+
+/*
+ * face-builder: A face that has add_table().
+ */
+
+struct hb_face_builder_data_t
+{
+ struct table_entry_t
+ {
+ inline int cmp (const hb_tag_t *t) const
+ {
+ if (*t < tag) return -1;
+ if (*t > tag) return -1;
+ return 0;
+ }
+
+ hb_tag_t tag;
+ hb_blob_t *blob;
+ };
+
+ hb_vector_t<table_entry_t, 32> tables;
+};
+
+static hb_face_builder_data_t *
+_hb_face_builder_data_create (void)
+{
+ hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
+ if (unlikely (!data))
+ return nullptr;
+
+ data->tables.init ();
+
+ return data;
+}
+
+static void
+_hb_face_builder_data_destroy (void *user_data)
+{
+ hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
+
+ for (unsigned int i = 0; i < data->tables.len; i++)
+ hb_blob_destroy (data->tables[i].blob);
+
+ data->tables.fini ();
+
+ free (data);
+}
+
+static hb_blob_t *
+_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
+{
+
+ unsigned int table_count = data->tables.len;
+ unsigned int face_length = table_count * 16 + 12;
+
+ for (unsigned int i = 0; i < table_count; i++)
+ face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
+
+ char *buf = (char *) malloc (face_length);
+ if (unlikely (!buf))
+ return nullptr;
+
+ hb_serialize_context_t c (buf, face_length);
+ OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
+
+ bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
+ hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
+
+ Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
+ Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
+ bool ret = f->serialize_single (&c,
+ sfnt_tag,
+ tags_supplier,
+ blobs_supplier,
+ table_count);
+
+ c.end_serialize ();
+
+ if (unlikely (!ret))
+ {
+ free (buf);
+ return nullptr;
+ }
+
+ return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
+}
+
+static hb_blob_t *
+_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
+{
+ hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
+
+ if (!tag)
+ return _hb_face_builder_data_reference_blob (data);
+
+ hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
+ if (entry)
+ return hb_blob_reference (entry->blob);
+
+ return nullptr;
+}
+
+
+/**
+ * hb_face_builder_create:
+ *
+ * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
+ * After tables are added to the face, it can be compiled to a binary
+ * font file by calling hb_face_reference_blob().
+ *
+ * Return value: (transfer full): New face.
+ *
+ * Since: 1.9.0
+ **/
+hb_face_t *
+hb_face_builder_create (void)
+{
+ hb_face_builder_data_t *data = _hb_face_builder_data_create ();
+ if (unlikely (!data)) return hb_face_get_empty ();
+
+ return hb_face_create_for_tables (_hb_face_builder_reference_table,
+ data,
+ _hb_face_builder_data_destroy);
+}
+
+/**
+ * hb_face_builder_add_table:
+ *
+ * Add table for @tag with data provided by @blob to the face. @face must
+ * be created using hb_face_builder_create().
+ *
+ * Since: 1.9.0
+ **/
+hb_bool_t
+hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
+{
+ if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+ return false;
+
+ hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+ hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
+
+ entry->tag = tag;
+ entry->blob = hb_blob_reference (blob);
+
+ return true;
+}
diff --git a/src/hb-face.h b/src/hb-face.h
index 208092efc..e8ff090d5 100644
--- a/src/hb-face.h
+++ b/src/hb-face.h
@@ -33,6 +33,7 @@
#include "hb-common.h"
#include "hb-blob.h"
+#include "hb-set.h"
HB_BEGIN_DECLS
@@ -120,6 +121,38 @@ hb_face_get_table_tags (const hb_face_t *face,
unsigned int *table_count, /* IN/OUT */
hb_tag_t *table_tags /* OUT */);
+
+/*
+ * Character set.
+ */
+
+HB_EXTERN void
+hb_face_collect_unicodes (hb_face_t *face,
+ hb_set_t *out);
+
+HB_EXTERN void
+hb_face_collect_variation_selectors (hb_face_t *face,
+ hb_set_t *out);
+
+HB_EXTERN void
+hb_face_collect_variation_unicodes (hb_face_t *face,
+ hb_codepoint_t variation_selector,
+ hb_set_t *out);
+
+
+/*
+ * Builder face.
+ */
+
+HB_EXTERN hb_face_t *
+hb_face_builder_create (void);
+
+HB_EXTERN hb_bool_t
+hb_face_builder_add_table (hb_face_t *face,
+ hb_tag_t tag,
+ hb_blob_t *blob);
+
+
HB_END_DECLS
#endif /* HB_FACE_H */
diff --git a/src/hb-face-private.hh b/src/hb-face.hh
index 086ce6e96..f90453dbd 100644
--- a/src/hb-face-private.hh
+++ b/src/hb-face.hh
@@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_FACE_PRIVATE_HH
-#define HB_FACE_PRIVATE_HH
+#ifndef HB_FACE_HH
+#define HB_FACE_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-shaper-private.hh"
-#include "hb-shape-plan-private.hh"
+#include "hb-shaper.hh"
+#include "hb-shape-plan.hh"
/*
@@ -105,4 +105,4 @@ DECLARE_NULL_INSTANCE (hb_face_t);
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
-#endif /* HB_FACE_PRIVATE_HH */
+#endif /* HB_FACE_HH */
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index eff20f70c..dc8536c82 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -25,7 +25,7 @@
*/
#define HB_SHAPER fallback
-#include "hb-shaper-impl-private.hh"
+#include "hb-shaper-impl.hh"
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face)
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 857b8f577..b6b668dd8 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -26,10 +26,12 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-font-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb-font.hh"
+#include "hb-machinery.hh"
+
+#include "hb-ot.h"
/*
@@ -101,9 +103,42 @@ hb_font_get_nominal_glyph_default (hb_font_t *font,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
+ if (font->has_nominal_glyphs_func_set ())
+ {
+ return font->get_nominal_glyphs (1, &unicode, 0, glyph, 0);
+ }
return font->parent->get_nominal_glyph (unicode, glyph);
}
+#define hb_font_get_nominal_glyphs_nil hb_font_get_nominal_glyphs_default
+static unsigned int
+hb_font_get_nominal_glyphs_default (hb_font_t *font,
+ void *font_data HB_UNUSED,
+ unsigned int count,
+ const hb_codepoint_t *first_unicode,
+ unsigned int unicode_stride,
+ hb_codepoint_t *first_glyph,
+ unsigned int glyph_stride,
+ void *user_data HB_UNUSED)
+{
+ if (font->has_nominal_glyph_func_set ())
+ {
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (!font->get_nominal_glyph (*first_unicode, first_glyph))
+ return i;
+
+ first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
+ first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+ }
+ return count;
+ }
+
+ return font->parent->get_nominal_glyphs (count,
+ first_unicode, unicode_stride,
+ first_glyph, glyph_stride);
+}
+
static hb_bool_t
hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
@@ -141,6 +176,12 @@ hb_font_get_glyph_h_advance_default (hb_font_t *font,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
+ if (font->has_glyph_h_advances_func_set ())
+ {
+ hb_position_t ret;
+ font->get_glyph_h_advances (1, &glyph, 0, &ret, 0);
+ return ret;
+ }
return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
}
@@ -159,6 +200,12 @@ hb_font_get_glyph_v_advance_default (hb_font_t *font,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
+ if (font->has_glyph_v_advances_func_set ())
+ {
+ hb_position_t ret;
+ font->get_glyph_v_advances (1, &glyph, 0, &ret, 0);
+ return ret;
+ }
return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
}
@@ -167,13 +214,13 @@ static void
hb_font_get_glyph_h_advances_default (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned int count,
- hb_codepoint_t *first_glyph,
+ const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride,
void *user_data HB_UNUSED)
{
- if (font->has_glyph_h_advance_func ())
+ if (font->has_glyph_h_advance_func_set ())
{
for (unsigned int i = 0; i < count; i++)
{
@@ -199,13 +246,13 @@ static void
hb_font_get_glyph_v_advances_default (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned int count,
- hb_codepoint_t *first_glyph,
+ const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride,
void *user_data HB_UNUSED)
{
- if (font->has_glyph_v_advance_func ())
+ if (font->has_glyph_v_advance_func_set ())
{
for (unsigned int i = 0; i < count; i++)
{
@@ -586,6 +633,8 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
{
if (unlikely (hb_object_is_inert (ffuncs)))
return;
+ if (ffuncs->immutable)
+ return;
ffuncs->immutable = true;
}
@@ -639,9 +688,15 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
bool
+hb_font_t::has_func_set (unsigned int i)
+{
+ return this->klass->get.array[i] != _hb_font_funcs_default.get.array[i];
+}
+
+bool
hb_font_t::has_func (unsigned int i)
{
- return (this->klass->get.array[i] != _hb_font_funcs_default.get.array[i]) ||
+ return has_func_set (i) ||
(parent && parent != &_hb_Null_hb_font_t && parent->has_func (i));
}
@@ -793,8 +848,8 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
**/
void
hb_font_get_glyph_h_advances (hb_font_t* font,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
@@ -811,8 +866,8 @@ hb_font_get_glyph_h_advances (hb_font_t* font,
**/
void
hb_font_get_glyph_v_advances (hb_font_t* font,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
@@ -873,6 +928,7 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
* Return value:
*
* Since: 0.9.2
+ * Deprecated: 2.0.0
**/
hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
@@ -892,6 +948,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
* Return value:
*
* Since: 0.9.2
+ * Deprecated: 2.0.0
**/
hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
@@ -991,7 +1048,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
* hb_font_get_extents_for_direction:
* @font: a font.
* @direction:
- * @extents:
+ * @extents: (out):
*
*
*
@@ -1036,8 +1093,8 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
HB_EXTERN void
hb_font_get_glyph_advances_for_direction (hb_font_t* font,
hb_direction_t direction,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
@@ -1120,6 +1177,7 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
*
*
* Since: 0.9.2
+ * Deprecated: 2.0.0
**/
void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
@@ -1254,18 +1312,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
};
-/**
- * hb_font_create: (Xconstructor)
- * @face: a face.
- *
- *
- *
- * Return value: (transfer full):
- *
- * Since: 0.9.2
- **/
-hb_font_t *
-hb_font_create (hb_face_t *face)
+static hb_font_t *
+_hb_font_create (hb_face_t *face)
{
hb_font_t *font;
@@ -1285,6 +1333,27 @@ hb_font_create (hb_face_t *face)
}
/**
+ * hb_font_create: (Xconstructor)
+ * @face: a face.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 0.9.2
+ **/
+hb_font_t *
+hb_font_create (hb_face_t *face)
+{
+ hb_font_t *font = _hb_font_create (face);
+
+ /* Install our in-house, very lightweight, funcs. */
+ hb_ot_font_set_funcs (font);
+
+ return font;
+}
+
+/**
* hb_font_create_sub_font:
* @parent: parent font.
*
@@ -1300,7 +1369,7 @@ hb_font_create_sub_font (hb_font_t *parent)
if (unlikely (!parent))
parent = hb_font_get_empty ();
- hb_font_t *font = hb_font_create (parent->face);
+ hb_font_t *font = _hb_font_create (parent->face);
if (unlikely (hb_object_is_inert (font)))
return font;
@@ -1444,6 +1513,8 @@ hb_font_make_immutable (hb_font_t *font)
{
if (unlikely (hb_object_is_inert (font)))
return;
+ if (font->immutable)
+ return;
if (font->parent)
hb_font_make_immutable (font->parent);
@@ -1703,9 +1774,11 @@ hb_font_get_ppem (hb_font_t *font,
/**
* hb_font_set_ptem:
* @font: a font.
- * @ptem:
+ * @ptem: font size in points.
*
- * Sets "point size" of the font.
+ * Sets "point size" of the font. Set to 0 to unset.
+ *
+ * There are 72 points in an inch.
*
* Since: 1.6.0
**/
@@ -1843,8 +1916,6 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
}
-#ifndef HB_DISABLE_DEPRECATED
-
/*
* Deprecated get_glyph_func():
*/
@@ -1931,9 +2002,9 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font,
/**
* hb_font_funcs_set_glyph_func:
* @ffuncs: font functions.
- * @func: (closure user_data) (destroy destroy) (scope notified):
- * @user_data:
- * @destroy:
+ * @func: (closure user_data) (destroy destroy) (scope notified): callback function.
+ * @user_data: data to pass to @func.
+ * @destroy: function to call when @user_data is not needed anymore.
*
* Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and
* hb_font_funcs_set_variation_glyph_func() instead.
@@ -1967,5 +2038,3 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
trampoline,
trampoline_destroy);
}
-
-#endif /* HB_DISABLE_DEPRECATED */
diff --git a/src/hb-font.h b/src/hb-font.h
index 6cd486979..74c61aba4 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -125,6 +125,14 @@ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *
hb_codepoint_t *glyph,
void *user_data);
+typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data,
+ unsigned int count,
+ const hb_codepoint_t *first_unicode,
+ unsigned int unicode_stride,
+ hb_codepoint_t *first_glyph,
+ unsigned int glyph_stride,
+ void *user_data);
+
typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@@ -133,8 +141,8 @@ typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
@@ -149,12 +157,6 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
-typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
- hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
- void *user_data);
-typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
-typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
-
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@@ -227,6 +229,22 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
void *user_data, hb_destroy_func_t destroy);
/**
+ * hb_font_funcs_set_nominal_glyphs_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 2.0.0
+ **/
+HB_EXTERN void
+hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_nominal_glyphs_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+/**
* hb_font_funcs_set_variation_glyph_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
@@ -339,38 +357,6 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
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: 0.9.2
- **/
-HB_EXTERN 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: 0.9.2
- **/
-HB_EXTERN 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):
@@ -461,15 +447,15 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
HB_EXTERN void
hb_font_get_glyph_h_advances (hb_font_t* font,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
HB_EXTERN void
hb_font_get_glyph_v_advances (hb_font_t* font,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
@@ -483,13 +469,6 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y);
-HB_EXTERN hb_position_t
-hb_font_get_glyph_h_kerning (hb_font_t *font,
- hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
-HB_EXTERN hb_position_t
-hb_font_get_glyph_v_kerning (hb_font_t *font,
- hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
-
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph,
@@ -531,8 +510,8 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
HB_EXTERN void
hb_font_get_glyph_advances_for_direction (hb_font_t* font,
hb_direction_t direction,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
@@ -552,12 +531,6 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
-HB_EXTERN 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);
-
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph,
diff --git a/src/hb-font-private.hh b/src/hb-font.hh
index d3a413802..2df5e42ee 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font.hh
@@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_FONT_PRIVATE_HH
-#define HB_FONT_PRIVATE_HH
+#ifndef HB_FONT_HH
+#define HB_FONT_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-face-private.hh"
-#include "hb-shaper-private.hh"
+#include "hb-face.hh"
+#include "hb-shaper.hh"
/*
@@ -43,6 +43,7 @@
HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
+ HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \
HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
@@ -170,6 +171,7 @@ struct hb_font_t
/* Public getters */
HB_INTERNAL bool has_func (unsigned int i);
+ HB_INTERNAL bool has_func_set (unsigned int i);
/* has_* ... */
#define HB_FONT_FUNC_IMPLEMENT(name) \
@@ -179,6 +181,13 @@ struct hb_font_t
hb_font_funcs_t *funcs = this->klass; \
unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
return has_func (i); \
+ } \
+ bool \
+ has_##name##_func_set (void) \
+ { \
+ hb_font_funcs_t *funcs = this->klass; \
+ unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
+ return has_func_set (i); \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
@@ -212,6 +221,18 @@ struct hb_font_t
unicode, glyph,
klass->user_data.nominal_glyph);
}
+ inline unsigned int get_nominal_glyphs (unsigned int count,
+ const hb_codepoint_t *first_unicode,
+ unsigned int unicode_stride,
+ hb_codepoint_t *first_glyph,
+ unsigned int glyph_stride)
+ {
+ return klass->get.f.nominal_glyphs (this, user_data,
+ count,
+ first_unicode, unicode_stride,
+ first_glyph, glyph_stride,
+ klass->user_data.nominal_glyphs);
+ }
inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
@@ -237,7 +258,7 @@ struct hb_font_t
}
inline void get_glyph_h_advances (unsigned int count,
- hb_codepoint_t *first_glyph,
+ const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
@@ -250,7 +271,7 @@ struct hb_font_t
}
inline void get_glyph_v_advances (unsigned int count,
- hb_codepoint_t *first_glyph,
+ const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
@@ -377,8 +398,8 @@ struct hb_font_t
*y = get_glyph_v_advance (glyph);
}
inline void get_glyph_advances_for_direction (hb_direction_t direction,
- unsigned count,
- hb_codepoint_t *first_glyph,
+ unsigned int count,
+ const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
@@ -502,8 +523,8 @@ struct hb_font_t
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;
+ *x = get_glyph_h_kerning (first_glyph, second_glyph);
} else {
*x = 0;
*y = get_glyph_v_kerning (first_glyph, second_glyph);
@@ -601,4 +622,4 @@ DECLARE_NULL_INSTANCE (hb_font_t);
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
-#endif /* HB_FONT_PRIVATE_HH */
+#endif /* HB_FONT_HH */
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 01341b604..18fb72a73 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -27,12 +27,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb-ft.h"
-#include "hb-font-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb-font.hh"
+#include "hb-machinery.hh"
+#include "hb-cache.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
@@ -44,30 +45,29 @@
* In general, this file does a fine job of what it's supposed to do.
* There are, however, things that need more work:
*
- * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
- * Have not investigated.
- *
* - 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 as load_flags. Would be much better to use NO_SCALE, and scale
- * ourselves, like we do in uniscribe, etc.
+ * ourselves.
*
* - We don't handle / allow for emboldening / obliqueing.
*
* - In the future, we should add constructors to create fonts in font space?
- *
- * - FT_Load_Glyph() is extremely costly. Do something about it?
*/
struct hb_ft_font_t
{
+ mutable hb_mutex_t lock;
FT_Face ft_face;
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
+
+ mutable hb_atomic_int_t cached_x_scale;
+ mutable hb_advance_cache_t advance_cache;
};
static hb_ft_font_t *
@@ -78,12 +78,16 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
if (unlikely (!ft_font))
return nullptr;
+ ft_font->lock.init ();
ft_font->ft_face = ft_face;
ft_font->symbol = symbol;
ft_font->unref = unref;
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+ ft_font->cached_x_scale.set (0);
+ ft_font->advance_cache.init ();
+
return ft_font;
}
@@ -98,9 +102,13 @@ _hb_ft_font_destroy (void *data)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
+ ft_font->advance_cache.fini ();
+
if (ft_font->unref)
_hb_ft_face_destroy (ft_font->ft_face);
+ ft_font->lock.fini ();
+
free (ft_font);
}
@@ -168,6 +176,7 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
if (unlikely (!g))
@@ -191,6 +200,32 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
return true;
}
+static unsigned int
+hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ unsigned int count,
+ const hb_codepoint_t *first_unicode,
+ unsigned int unicode_stride,
+ hb_codepoint_t *first_glyph,
+ unsigned int glyph_stride,
+ void *user_data HB_UNUSED)
+{
+ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ unsigned int done;
+ for (done = 0;
+ done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
+ done++)
+ {
+ first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
+ first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+ }
+ /* We don't need to do ft_font->symbol dance here, since HB calls the singular
+ * nominal_glyph() for what we don't handle here. */
+ return done;
+}
+
+
static hb_bool_t
hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
@@ -200,6 +235,7 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
if (unlikely (!g))
@@ -209,22 +245,45 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
return true;
}
-static hb_position_t
-hb_ft_get_glyph_h_advance (hb_font_t *font,
- void *font_data,
- hb_codepoint_t glyph,
- void *user_data HB_UNUSED)
+static void
+hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
+ unsigned count,
+ const hb_codepoint_t *first_glyph,
+ unsigned glyph_stride,
+ hb_position_t *first_advance,
+ unsigned advance_stride,
+ void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
- FT_Fixed v;
+ hb_lock_t lock (ft_font->lock);
+ FT_Face ft_face = ft_font->ft_face;
+ int load_flags = ft_font->load_flags;
+ int mult = font->x_scale < 0 ? -1 : +1;
- if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
- return 0;
+ if (font->x_scale != ft_font->cached_x_scale.get ())
+ {
+ ft_font->advance_cache.clear ();
+ ft_font->cached_x_scale.set (font->x_scale);
+ }
- if (font->x_scale < 0)
- v = -v;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ FT_Fixed v = 0;
+ hb_codepoint_t glyph = *first_glyph;
+
+ unsigned int cv;
+ if (ft_font->advance_cache.get (glyph, &cv))
+ v = cv;
+ else
+ {
+ FT_Get_Advance (ft_face, glyph, load_flags, &v);
+ ft_font->advance_cache.set (glyph, v);
+ }
- return (v + (1<<9)) >> 10;
+ *first_advance = (v * mult + (1<<9)) >> 10;
+ first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+ first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+ }
}
static hb_position_t
@@ -234,6 +293,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
@@ -256,6 +316,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
@@ -274,23 +335,6 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
return true;
}
-static hb_position_t
-hb_ft_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)
-{
- const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
- FT_Vector kerningv;
-
- FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
- if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
- return 0;
-
- return kerningv.x;
-}
-
static hb_bool_t
hb_ft_get_glyph_extents (hb_font_t *font,
void *font_data,
@@ -299,6 +343,7 @@ hb_ft_get_glyph_extents (hb_font_t *font,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
@@ -331,6 +376,7 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
@@ -356,8 +402,10 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ FT_Face ft_face = ft_font->ft_face;
- hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
+ hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
if (ret && (size && !*name))
ret = false;
@@ -372,6 +420,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (len < 0)
@@ -404,6 +453,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
metrics->ascender = ft_face->size->metrics.ascender;
metrics->descender = ft_face->size->metrics.descender;
@@ -417,7 +467,9 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
return true;
}
+#ifdef HB_USE_ATEXIT
static void free_static_ft_funcs (void);
+#endif
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
{
@@ -428,13 +480,12 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
- //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
@@ -682,8 +733,9 @@ hb_ft_font_create_referenced (FT_Face ft_face)
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
-
+#ifdef HB_USE_ATEXIT
static void free_static_ft_library (void);
+#endif
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<FT_Library>::value,
hb_ft_library_lazy_loader_t>
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 809b22f6b..a34acbba1 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -26,12 +26,11 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb-glib.h"
-#include "hb-unicode-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb-machinery.hh"
#if !GLIB_CHECK_VERSION(2,29,14)
@@ -202,14 +201,6 @@ hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode);
}
-static unsigned int
-hb_glib_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
- hb_codepoint_t unicode,
- void *user_data HB_UNUSED)
-{
- return g_unichar_iswide (unicode) ? 2 : 1;
-}
-
static hb_unicode_general_category_t
hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
@@ -334,40 +325,10 @@ 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
-
- /* 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;
-
- /* 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;
-}
-
-
+#ifdef HB_USE_ATEXIT
static void free_static_glib_funcs (void);
+#endif
static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
{
@@ -375,10 +336,12 @@ static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
{
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
-#define HB_UNICODE_FUNC_IMPLEMENT(name) \
- hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr);
- HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
+ hb_unicode_funcs_set_combining_class_func (funcs, hb_glib_unicode_combining_class, nullptr, nullptr);
+ hb_unicode_funcs_set_general_category_func (funcs, hb_glib_unicode_general_category, nullptr, nullptr);
+ hb_unicode_funcs_set_mirroring_func (funcs, hb_glib_unicode_mirroring, nullptr, nullptr);
+ hb_unicode_funcs_set_script_func (funcs, hb_glib_unicode_script, nullptr, nullptr);
+ hb_unicode_funcs_set_compose_func (funcs, hb_glib_unicode_compose, nullptr, nullptr);
+ hb_unicode_funcs_set_decompose_func (funcs, hb_glib_unicode_decompose, nullptr, nullptr);
hb_unicode_funcs_make_immutable (funcs);
diff --git a/src/hb-gobject-enums.cc.tmpl b/src/hb-gobject-enums.cc.tmpl
index ca458a384..e056df478 100644
--- a/src/hb-gobject-enums.cc.tmpl
+++ b/src/hb-gobject-enums.cc.tmpl
@@ -25,7 +25,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index 0c8e55733..1b8758583 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 1f42a36f3..6b2b6f19d 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -27,12 +27,14 @@
*/
#define HB_SHAPER graphite2
-#include "hb-shaper-impl-private.hh"
+#include "hb-shaper-impl.hh"
#include "hb-graphite2.h"
#include <graphite2/Segment.h>
+#include "hb-ot-tag.h"
+
HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font)
@@ -95,6 +97,32 @@ retry:
return d;
}
+static void hb_graphite2_release_table(const void *data, const void *table_buffer)
+{
+ hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
+ hb_graphite2_tablelist_t *tlist = face_data->tlist.get();
+
+ hb_graphite2_tablelist_t *prev = nullptr;
+ hb_graphite2_tablelist_t *curr = tlist;
+ while (curr)
+ {
+ if (hb_blob_get_data(curr->blob, nullptr) == table_buffer)
+ {
+ if (prev == nullptr)
+ face_data->tlist.cmpexch(tlist, curr->next);
+ else
+ prev->next = curr->next;
+ hb_blob_destroy(curr->blob);
+ free(curr);
+ break;
+ }
+ prev = curr;
+ curr = curr->next;
+ }
+}
+
+static gr_face_ops hb_graphite2_face_ops = { sizeof(gr_face_ops), hb_graphite2_get_table, hb_graphite2_release_table };
+
hb_graphite2_face_data_t *
_hb_graphite2_shaper_face_data_create (hb_face_t *face)
{
@@ -113,7 +141,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
return nullptr;
data->face = face;
- data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
+ data->grface = gr_make_face_with_ops (data, &hb_graphite2_face_ops, gr_face_preloadAll);
if (unlikely (!data->grface)) {
free (data);
@@ -251,11 +279,16 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
/* TODO ensure_native_direction. */
- hb_tag_t script_tag[2];
- hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
+ hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT];
+ unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT;
+ hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer),
+ HB_LANGUAGE_INVALID,
+ &count,
+ script_tag,
+ nullptr, nullptr);
seg = gr_make_seg (nullptr, grface,
- script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
+ count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
feats,
gr_utf32, chars, buffer->len,
2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h
index 05c55debe..1720191b4 100644
--- a/src/hb-graphite2.h
+++ b/src/hb-graphite2.h
@@ -41,7 +41,7 @@ hb_graphite2_face_get_gr_face (hb_face_t *face);
#ifndef HB_DISABLE_DEPRECATED
-HB_EXTERN gr_font *
+HB_EXTERN HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) gr_font *
hb_graphite2_font_get_gr_font (hb_font_t *font);
#endif
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 2e3ad3675..e012314b5 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -27,12 +27,11 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb-icu.h"
-#include "hb-unicode-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb-machinery.hh"
#include <unicode/uchar.h>
#include <unicode/unorm2.h>
@@ -73,25 +72,6 @@ hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return (hb_unicode_combining_class_t) u_getCombiningClass (unicode);
}
-static unsigned int
-hb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
- hb_codepoint_t unicode,
- void *user_data HB_UNUSED)
-{
- switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
- {
- case U_EA_WIDE:
- case U_EA_FULLWIDTH:
- return 2;
- case U_EA_NEUTRAL:
- case U_EA_AMBIGUOUS:
- case U_EA_HALFWIDTH:
- case U_EA_NARROW:
- return 1;
- }
- return 1;
-}
-
static hb_unicode_general_category_t
hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
@@ -309,42 +289,10 @@ 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;
-
- /* Normalise the codepoint using NFKD mode. */
- icu_err = U_ZERO_ERROR;
- len = unorm2_normalize (unorm2_getNFKDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
- if (U_FAILURE (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 (U_FAILURE (icu_err))
- return 0;
-
- return utf32_len;
-}
-
+#ifdef HB_USE_ATEXIT
static void free_static_icu_funcs (void);
+#endif
static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
{
@@ -359,10 +307,12 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
-#define HB_UNICODE_FUNC_IMPLEMENT(name) \
- hb_unicode_funcs_set_##name##_func (funcs, hb_icu_unicode_##name, user_data, nullptr);
- HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
+ hb_unicode_funcs_set_combining_class_func (funcs, hb_icu_unicode_combining_class, nullptr, nullptr);
+ hb_unicode_funcs_set_general_category_func (funcs, hb_icu_unicode_general_category, nullptr, nullptr);
+ hb_unicode_funcs_set_mirroring_func (funcs, hb_icu_unicode_mirroring, nullptr, nullptr);
+ hb_unicode_funcs_set_script_func (funcs, hb_icu_unicode_script, nullptr, nullptr);
+ hb_unicode_funcs_set_compose_func (funcs, hb_icu_unicode_compose, user_data, nullptr);
+ hb_unicode_funcs_set_decompose_func (funcs, hb_icu_unicode_decompose, user_data, nullptr);
hb_unicode_funcs_make_immutable (funcs);
diff --git a/src/hb-iter-private.hh b/src/hb-iter.hh
index 314133ade..6fd6aed79 100644
--- a/src/hb-iter-private.hh
+++ b/src/hb-iter.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_ITER_PRIVATE_HH
-#define HB_ITER_PRIVATE_HH
+#ifndef HB_ITER_HH
+#define HB_ITER_HH
-#include "hb-private.hh"
+#include "hb.hh"
/* Unified iterator object.
@@ -146,4 +146,4 @@ m (void)
}
}
-#endif /* HB_ITER_PRIVATE_HH */
+#endif /* HB_ITER_HH */
diff --git a/src/hb-machinery-private.hh b/src/hb-machinery.hh
index 99ef485a3..ae34c92f4 100644
--- a/src/hb-machinery-private.hh
+++ b/src/hb-machinery.hh
@@ -26,13 +26,14 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_MACHINERY_PRIVATE_HH
-#define HB_MACHINERY_PRIVATE_HH
+#ifndef HB_MACHINERY_HH
+#define HB_MACHINERY_HH
-#include "hb-private.hh"
-#include "hb-blob-private.hh"
+#include "hb.hh"
+#include "hb-blob.hh"
-#include "hb-iter-private.hh"
+#include "hb-iter.hh"
+#include "hb-vector.hh"
/*
@@ -98,8 +99,8 @@ static inline Type& StructAfter(TObject &X)
#define DEFINE_SIZE_STATIC(size) \
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
- static const unsigned int static_size = (size); \
- static const unsigned int min_size = (size); \
+ enum { static_size = (size) }; \
+ enum { min_size = (size) }; \
inline unsigned int get_size (void) const { return (size); }
#define DEFINE_SIZE_UNION(size, _member) \
@@ -111,9 +112,13 @@ static inline Type& StructAfter(TObject &X)
static const unsigned int min_size = (size)
#define DEFINE_SIZE_ARRAY(size, array) \
- DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
+ DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof (array[0])); \
DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
- static const unsigned int min_size = (size)
+ enum { min_size = (size) }; \
+
+#define DEFINE_SIZE_ARRAY_SIZED(size, array) \
+ DEFINE_SIZE_ARRAY(size, array); \
+ inline unsigned int get_size (void) const { return (size - array[0].min_size + array.get_size ()); }
#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
@@ -128,7 +133,7 @@ static inline Type& StructAfter(TObject &X)
template <typename Context, typename Return, unsigned int MaxDebugDepth>
struct hb_dispatch_context_t
{
- static const unsigned int max_debug_depth = MaxDebugDepth;
+ enum { max_debug_depth = MaxDebugDepth };
typedef Return return_t;
template <typename T, typename F>
inline bool may_dispatch (const T *obj, const F *format) { return true; }
@@ -138,6 +143,68 @@ struct hb_dispatch_context_t
/*
* Sanitize
+ *
+ *
+ * === Introduction ===
+ *
+ * The sanitize machinery is at the core of our zero-cost font loading. We
+ * mmap() font file into memory and create a blob out of it. Font subtables
+ * are returned as a readonly sub-blob of the main font blob. These table
+ * blobs are then sanitized before use, to ensure invalid memory access does
+ * not happen. The toplevel sanitize API use is like, eg. to load the 'head'
+ * table:
+ *
+ * hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face);
+ *
+ * The blob then can be converted to a head table struct with:
+ *
+ * const head *head_table = head_blob->as<head> ();
+ *
+ * What the reference_table does is, to call hb_face_reference_table() to load
+ * the table blob, sanitize it and return either the sanitized blob, or empty
+ * blob if sanitization failed. The blob->as() function returns the null
+ * object of its template type argument if the blob is empty. Otherwise, it
+ * just casts the blob contents to the desired type.
+ *
+ * Sanitizing a blob of data with a type T works as follows (with minor
+ * simplification):
+ *
+ * - Cast blob content to T*, call sanitize() method of it,
+ * - If sanitize succeeded, return blob.
+ * - Otherwise, if blob is not writable, try making it writable,
+ * or copy if cannot be made writable in-place,
+ * - Call sanitize() again. Return blob if sanitize succeeded.
+ * - Return empty blob otherwise.
+ *
+ *
+ * === The sanitize() contract ===
+ *
+ * The sanitize() method of each object type shall return true if it's safe to
+ * call other methods of the object, and false otherwise.
+ *
+ * Note that what sanitize() checks for might align with what the specification
+ * describes as valid table data, but does not have to be. In particular, we
+ * do NOT want to be pedantic and concern ourselves with validity checks that
+ * are irrelevant to our use of the table. On the contrary, we want to be
+ * lenient with error handling and accept invalid data to the extent that it
+ * does not impose extra burden on us.
+ *
+ * Based on the sanitize contract, one can see that what we check for depends
+ * on how we use the data in other table methods. Ie. if other table methods
+ * assume that offsets do NOT point out of the table data block, then that's
+ * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On
+ * the other hand, if other methods do such checks themselves, then sanitize()
+ * does not have to bother with them (glyf/local work this way). The choice
+ * depends on the table structure and sanitize() performance. For example, to
+ * check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard
+ * to avoid such costs during font loading. By postponing such checks to the
+ * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime
+ * cost to O(used-glyphs). As such, this is preferred.
+ *
+ * The same argument can be made re GSUB/GPOS/GDEF, but there, the table
+ * structure is so complicated that by checking all offsets at sanitize() time,
+ * we make the code much simpler in other methods, as offsets and referenced
+ * objects do not need to be validated at each use site.
*/
/* This limits sanitizing time on really broken fonts. */
@@ -150,6 +217,9 @@ struct hb_dispatch_context_t
#ifndef HB_SANITIZE_MAX_OPS_MIN
#define HB_SANITIZE_MAX_OPS_MIN 16384
#endif
+#ifndef HB_SANITIZE_MAX_OPS_MAX
+#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
+#endif
struct hb_sanitize_context_t :
hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
@@ -157,7 +227,8 @@ struct hb_sanitize_context_t :
inline hb_sanitize_context_t (void) :
debug_depth (0),
start (nullptr), end (nullptr),
- writable (false), edit_count (0), max_ops (0),
+ max_ops (0),
+ writable (false), edit_count (0),
blob (nullptr),
num_glyphs (65536),
num_glyphs_set (false) {}
@@ -185,6 +256,23 @@ struct hb_sanitize_context_t :
}
inline unsigned int get_num_glyphs (void) { return num_glyphs; }
+ inline void set_max_ops (int max_ops_) { max_ops = max_ops_; }
+
+ /* TODO
+ * This set_object() thing is to use sanitize at runtime lookup
+ * application time. This is very distinct from the regular
+ * sanitizer operation, so, eventually, separate into another
+ * type and make hb_aat_apply_context_t use that one instead
+ * of abusing this one.
+ */
+ template <typename T>
+ inline void set_object (const T& obj)
+ {
+ this->start = (const char *) &obj;
+ this->end = (const char *) &obj + obj.get_size ();
+ assert (this->start <= this->end); /* Must not overflow. */
+ }
+
inline void start_processing (void)
{
this->start = this->blob->data;
@@ -215,10 +303,10 @@ 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->max_ops-- > 0 &&
- this->start <= p &&
+ bool ok = this->start <= p &&
p <= this->end &&
- (unsigned int) (this->end - p) >= len;
+ (unsigned int) (this->end - p) >= len &&
+ this->max_ops-- > 0;
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
"check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
@@ -229,7 +317,8 @@ struct hb_sanitize_context_t :
return likely (ok);
}
- inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
+ template <typename T>
+ inline bool check_array (const T *base, unsigned int len, unsigned int record_size = T::static_size) const
{
const char *p = (const char *) base;
bool overflows = hb_unsigned_mul_overflows (len, record_size);
@@ -355,10 +444,10 @@ struct hb_sanitize_context_t :
mutable unsigned int debug_depth;
const char *start, *end;
+ mutable int max_ops;
private:
bool writable;
unsigned int edit_count;
- mutable int max_ops;
hb_blob_t *blob;
unsigned int num_glyphs;
bool num_glyphs_set;
@@ -375,12 +464,19 @@ struct hb_serialize_context_t
{
this->start = (char *) start_;
this->end = this->start + size;
+ reset ();
+ }
+ inline void reset (void)
+ {
this->ran_out_of_room = false;
this->head = this->start;
this->debug_depth = 0;
}
+ inline bool err (bool e) { return this->ran_out_of_room = this->ran_out_of_room || e; }
+
+ /* To be called around main operation. */
template <typename Type>
inline Type *start_serialize (void)
{
@@ -391,7 +487,6 @@ struct hb_serialize_context_t
return start_embed<Type> ();
}
-
inline void end_serialize (void)
{
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
@@ -401,15 +496,20 @@ struct hb_serialize_context_t
this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
}
+ inline unsigned int length (void) const { return this->head - this->start; }
+
+ inline void align (unsigned int alignment)
+ {
+ unsigned int l = length () % alignment;
+ if (l)
+ allocate_size<void> (alignment - l);
+ }
+
template <typename Type>
- inline Type *copy (void)
+ inline Type *start_embed (void) const
{
- 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);
+ Type *ret = reinterpret_cast<Type *> (this->head);
+ return ret;
}
template <typename Type>
@@ -432,19 +532,12 @@ struct hb_serialize_context_t
}
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 nullptr;
- memcpy (ret, obj, size);
+ memcpy (ret, &obj, size);
return ret;
}
@@ -466,6 +559,38 @@ struct hb_serialize_context_t
return reinterpret_cast<Type *> (&obj);
}
+ /* Output routines. */
+ template <typename Type>
+ inline Type *copy (void) const
+ {
+ 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);
+ }
+ inline hb_bytes_t copy_bytes (void) const
+ {
+ assert (!this->ran_out_of_room);
+ unsigned int len = this->head - this->start;
+ void *p = malloc (len);
+ if (p)
+ memcpy (p, this->start, len);
+ else
+ return hb_bytes_t ();
+ return hb_bytes_t (p, len);
+ }
+ inline hb_blob_t *copy_blob (void) const
+ {
+ assert (!this->ran_out_of_room);
+ return hb_blob_create (this->start,
+ this->head - this->start,
+ HB_MEMORY_MODE_DUPLICATE,
+ nullptr, nullptr);
+ }
+
+ public:
unsigned int debug_depth;
char *start, *end, *head;
bool ran_out_of_room;
@@ -479,12 +604,19 @@ struct hb_serialize_context_t
template <typename Type>
struct Supplier
{
- inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
+ inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof (Type))
{
head = array;
len = len_;
stride = stride_;
}
+ inline Supplier (const hb_vector_t<Type> *v)
+ {
+ head = v->arrayZ();
+ len = v->len;
+ stride = sizeof (Type);
+ }
+
inline const Type operator [] (unsigned int i) const
{
if (unlikely (i >= len)) return Type ();
@@ -520,6 +652,7 @@ template <typename Type>
struct BEInt<Type, 1>
{
public:
+ typedef Type type;
inline void set (Type V)
{
v = V;
@@ -534,6 +667,7 @@ template <typename Type>
struct BEInt<Type, 2>
{
public:
+ typedef Type type;
inline void set (Type V)
{
v[0] = (V >> 8) & 0xFF;
@@ -550,6 +684,7 @@ template <typename Type>
struct BEInt<Type, 3>
{
public:
+ typedef Type type;
inline void set (Type V)
{
v[0] = (V >> 16) & 0xFF;
@@ -568,6 +703,7 @@ template <typename Type>
struct BEInt<Type, 4>
{
public:
+ typedef Type type;
inline void set (Type V)
{
v[0] = (V >> 24) & 0xFF;
@@ -682,6 +818,10 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
}
return p;
}
+ inline Stored * get_stored_relaxed (void) const
+ {
+ return this->instance.get_relaxed ();
+ }
inline void set_stored (Stored *instance_)
{
@@ -695,6 +835,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
}
inline const Returned * get (void) const { return Funcs::convert (get_stored ()); }
+ inline const Returned * get_relaxed (void) const { return Funcs::convert (get_stored_relaxed ()); }
inline Returned * get_unconst (void) const { return const_cast<Returned *> (Funcs::convert (get_stored ())); }
/* To be possibly overloaded by subclasses. */
@@ -729,9 +870,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
/* Specializations. */
-template <unsigned int WheresFace, typename T>
+template <typename T, unsigned int WheresFace>
struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
- hb_face_lazy_loader_t<WheresFace, T>,
+ hb_face_lazy_loader_t<T, WheresFace>,
hb_face_t, WheresFace> {};
template <typename T, unsigned int WheresFace>
@@ -789,4 +930,4 @@ struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Sub
};
-#endif /* HB_MACHINERY_PRIVATE_HH */
+#endif /* HB_MACHINERY_HH */
diff --git a/src/hb-map.cc b/src/hb-map.cc
index 138a85612..225f37bc6 100644
--- a/src/hb-map.cc
+++ b/src/hb-map.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-map-private.hh"
+#include "hb-map.hh"
/* Public API */
diff --git a/src/hb-map-private.hh b/src/hb-map.hh
index 00f089e81..b55e3a954 100644
--- a/src/hb-map-private.hh
+++ b/src/hb-map.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_MAP_PRIVATE_HH
-#define HB_MAP_PRIVATE_HH
+#ifndef HB_MAP_HH
+#define HB_MAP_HH
-#include "hb-private.hh"
+#include "hb.hh"
template <typename T>
@@ -172,7 +172,7 @@ struct hb_map_t
inline bool is_empty (void) const
{
- return population != 0;
+ return population == 0;
}
inline unsigned int get_population () const
@@ -251,4 +251,4 @@ struct hb_map_t
};
-#endif /* HB_MAP_PRIVATE_HH */
+#endif /* HB_MAP_HH */
diff --git a/src/hb-mutex-private.hh b/src/hb-mutex.hh
index 14bde3103..75b89addb 100644
--- a/src/hb-mutex-private.hh
+++ b/src/hb-mutex.hh
@@ -29,10 +29,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_MUTEX_PRIVATE_HH
-#define HB_MUTEX_PRIVATE_HH
+#ifndef HB_MUTEX_HH
+#define HB_MUTEX_HH
-#include "hb-private.hh"
+#include "hb.hh"
/* mutex */
@@ -137,5 +137,13 @@ struct hb_mutex_t
inline void fini (void) { hb_mutex_impl_finish (&m); }
};
+struct hb_lock_t
+{
+ inline hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); }
+ inline ~hb_lock_t (void) { mutex.unlock (); }
+ private:
+ hb_mutex_t &mutex;
+};
+
-#endif /* HB_MUTEX_PRIVATE_HH */
+#endif /* HB_MUTEX_HH */
diff --git a/src/hb-null.hh b/src/hb-null.hh
index 91efee644..87662265c 100644
--- a/src/hb-null.hh
+++ b/src/hb-null.hh
@@ -27,7 +27,7 @@
#ifndef HB_NULL_HH
#define HB_NULL_HH
-#include "hb-private.hh"
+#include "hb.hh"
/*
@@ -36,7 +36,7 @@
/* Global nul-content Null pool. Enlarge as necessary. */
-#define HB_NULL_POOL_SIZE 264
+#define HB_NULL_POOL_SIZE 1024
extern HB_INTERNAL
hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
@@ -49,29 +49,29 @@ static inline Type const & Null (void) {
}
#define Null(Type) Null<Type>()
-/* Specializaitons for arbitrary-content Null objects expressed in bytes. */
+/* Specializations for arbitrary-content Null objects expressed in bytes. */
#define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \
-} /* Close namespace. */ \
-extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \
-template <> \
-/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
- return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
-} \
-namespace Namespace { \
-static_assert (true, "Just so we take semicolon after.")
+ } /* Close namespace. */ \
+ extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \
+ template <> \
+ /*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
+ return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
+ } \
+ namespace Namespace { \
+ static_assert (true, "Just so we take semicolon after.")
#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
-const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]
+ const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]
-/* Specializaitons for arbitrary-content Null objects expressed as struct initializer. */
+/* Specializations for arbitrary-content Null objects expressed as struct initializer. */
#define DECLARE_NULL_INSTANCE(Type) \
-extern HB_INTERNAL const Type _hb_Null_##Type; \
-template <> \
-/*static*/ inline const Type& Null<Type> (void) { \
- return _hb_Null_##Type; \
-} \
+ extern HB_INTERNAL const Type _hb_Null_##Type; \
+ template <> \
+ /*static*/ inline const Type& Null<Type> (void) { \
+ return _hb_Null_##Type; \
+ } \
static_assert (true, "Just so we take semicolon after.")
#define DEFINE_NULL_INSTANCE(Type) \
-const Type _hb_Null_##Type
+ const Type _hb_Null_##Type
/* Global writable pool. Enlarge as necessary. */
diff --git a/src/hb-object-private.hh b/src/hb-object.hh
index 4955a68dc..ca85af691 100644
--- a/src/hb-object-private.hh
+++ b/src/hb-object.hh
@@ -29,13 +29,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OBJECT_PRIVATE_HH
-#define HB_OBJECT_PRIVATE_HH
+#ifndef HB_OBJECT_HH
+#define HB_OBJECT_HH
-#include "hb-private.hh"
-#include "hb-atomic-private.hh"
-#include "hb-mutex-private.hh"
-#include "hb-vector-private.hh"
+#include "hb.hh"
+#include "hb-atomic.hh"
+#include "hb-mutex.hh"
+#include "hb-vector.hh"
/*
@@ -322,4 +322,4 @@ static inline void *hb_object_get_user_data (Type *obj,
}
-#endif /* HB_OBJECT_PRIVATE_HH */
+#endif /* HB_OBJECT_HH */
diff --git a/src/hb-open-file-private.hh b/src/hb-open-file.hh
index d47bff66e..817791ab0 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file.hh
@@ -26,10 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OPEN_FILE_PRIVATE_HH
-#define HB_OPEN_FILE_PRIVATE_HH
+#ifndef HB_OPEN_FILE_HH
+#define HB_OPEN_FILE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
#include "hb-ot-head-table.hh"
@@ -115,7 +115,7 @@ typedef struct OffsetTable
* table list. */
int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t);
if (table_index)
- *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i;
+ *table_index = i == -1 ? (unsigned) Index::NOT_FOUND_INDEX : (unsigned) i;
return i != -1;
}
inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
@@ -160,9 +160,8 @@ typedef struct OffsetTable
memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
- /* 4-byte allignment. */
- if (rec.length % 4)
- c->allocate_size<void> (4 - rec.length % 4);
+ /* 4-byte alignment. */
+ c->align (4);
const char *end = (const char *) c->head;
if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size)
@@ -288,188 +287,159 @@ struct TTCHeader
/*
* Mac Resource Fork
+ *
+ * http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html
*/
-struct ResourceRefItem
+struct ResourceRecord
{
- inline bool sanitize (hb_sanitize_context_t *c) const
+ inline const OpenTypeFontFace & get_face (const void *data_base) const
+ { return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); }
+
+ inline bool sanitize (hb_sanitize_context_t *c,
+ const void *data_base) const
{
TRACE_SANITIZE (this);
- // actual data sanitization is done on ResourceForkHeader sanitizer
- return_trace (likely (c->check_struct (this)));
+ return_trace (c->check_struct (this) &&
+ offset.sanitize (c, data_base) &&
+ get_face (data_base).sanitize (c));
}
- HBINT16 id; /* Resource ID, is really should be signed? */
+ protected:
+ HBUINT16 id; /* Resource ID. */
HBINT16 nameOffset; /* Offset from beginning of resource name list
- * to resource name, minus means there is no */
- HBUINT8 attr; /* Resource attributes */
- HBUINT24 dataOffset; /* Offset from beginning of resource data to
+ * to resource name, -1 means there is none. */
+ HBUINT8 attrs; /* Resource attributes */
+ OffsetTo<LArrayOf<HBUINT8>, HBUINT24, false>
+ offset; /* Offset from beginning of data block to
* data for this resource */
HBUINT32 reserved; /* Reserved for handle to resource */
public:
DEFINE_SIZE_STATIC (12);
};
-struct ResourceTypeItem
+#define HB_TAG_sfnt HB_TAG ('s','f','n','t')
+
+struct ResourceTypeRecord
{
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- // RefList sanitization is done on ResourceMap sanitizer
- return_trace (likely (c->check_struct (this)));
- }
+ inline unsigned int get_resource_count (void) const
+ { return tag == HB_TAG_sfnt ? resCountM1 + 1 : 0; }
- inline unsigned int get_resource_count () const
- {
- return numRes + 1;
- }
+ inline bool is_sfnt (void) const { return tag == HB_TAG_sfnt; }
- inline bool is_sfnt () const
+ inline const ResourceRecord& get_resource_record (unsigned int i,
+ const void *type_base) const
{
- return type == HB_TAG ('s','f','n','t');
+ return hb_array_t<ResourceRecord> ((type_base+resourcesZ).arrayZ,
+ get_resource_count ()) [i];
}
- inline const ResourceRefItem& get_ref_item (const void *base,
- unsigned int i) const
+ inline bool sanitize (hb_sanitize_context_t *c,
+ const void *type_base,
+ const void *data_base) const
{
- return (base+refList)[i];
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ resourcesZ.sanitize (c, type_base,
+ get_resource_count (),
+ data_base));
}
protected:
- Tag type; /* Resource type */
- HBUINT16 numRes; /* Number of resource this type in map minus 1 */
- OffsetTo<UnsizedArrayOf<ResourceRefItem> >
- refList; /* Offset from beginning of resource type list
- * to reference list for this type */
+ Tag tag; /* Resource type. */
+ HBUINT16 resCountM1; /* Number of resources minus 1. */
+ OffsetTo<UnsizedArrayOf<ResourceRecord>, HBUINT16, false>
+ resourcesZ; /* Offset from beginning of resource type list
+ * to reference item list for this type. */
public:
DEFINE_SIZE_STATIC (8);
};
struct ResourceMap
{
- inline bool sanitize (hb_sanitize_context_t *c) const
+ inline unsigned int get_face_count (void) const
{
- TRACE_SANITIZE (this);
- if (unlikely (!c->check_struct (this)))
- return_trace (false);
- for (unsigned int i = 0; i < get_types_count (); ++i)
+ unsigned int count = get_type_count ();
+ for (unsigned int i = 0; i < count; i++)
{
- const ResourceTypeItem& type = get_type (i);
- if (unlikely (!type.sanitize (c)))
- return_trace (false);
- for (unsigned int j = 0; j < type.get_resource_count (); ++j)
- if (unlikely (!get_ref_item (type, j).sanitize (c)))
- return_trace (false);
+ const ResourceTypeRecord& type = get_type_record (i);
+ if (type.is_sfnt ())
+ return type.get_resource_count ();
}
- return_trace (true);
- }
-
- inline const ResourceTypeItem& get_type (unsigned int i) const
- {
- // Why offset from the second byte of the object? I'm not sure
- return ((&reserved[2])+typeList)[i];
+ return 0;
}
- inline unsigned int get_types_count () const
+ inline const OpenTypeFontFace& get_face (unsigned int idx,
+ const void *data_base) const
{
- return nTypes + 1;
+ unsigned int count = get_type_count ();
+ for (unsigned int i = 0; i < count; i++)
+ {
+ const ResourceTypeRecord& type = get_type_record (i);
+ /* The check for idx < count is here because ResourceRecord is NOT null-safe.
+ * Because an offset of 0 there does NOT mean null. */
+ if (type.is_sfnt () && idx < type.get_resource_count ())
+ return type.get_resource_record (idx, &(this+typeList)).get_face (data_base);
+ }
+ return Null (OpenTypeFontFace);
}
- inline const ResourceRefItem &get_ref_item (const ResourceTypeItem &type,
- unsigned int i) const
+ inline bool sanitize (hb_sanitize_context_t *c, const void *data_base) const
{
- return type.get_ref_item (&(this+typeList), i);
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ typeList.sanitize (c, this,
+ &(this+typeList),
+ data_base));
}
- inline const PString& get_name (const ResourceRefItem &item,
- unsigned int i) const
- {
- if (item.nameOffset == -1)
- return Null (PString);
+ private:
+ inline unsigned int get_type_count (void) const { return (this+typeList).lenM1 + 1; }
- return StructAtOffset<PString> (this, nameList + item.nameOffset);
- }
+ inline const ResourceTypeRecord& get_type_record (unsigned int i) const
+ { return (this+typeList)[i]; }
protected:
- HBUINT8 reserved[16]; /* Reserved for copy of resource header */
- LOffsetTo<ResourceMap>
- reserved1; /* Reserved for handle to next resource map */
- HBUINT16 reserved2; /* Reserved for file reference number */
- HBUINT16 attr; /* Resource fork attribute */
- OffsetTo<UnsizedArrayOf<ResourceTypeItem> >
+ HBUINT8 reserved0[16]; /* Reserved for copy of resource header */
+ HBUINT32 reserved1; /* Reserved for handle to next resource map */
+ HBUINT16 resreved2; /* Reserved for file reference number */
+ HBUINT16 attrs; /* Resource fork attribute */
+ OffsetTo<ArrayOfM1<ResourceTypeRecord>, HBUINT16, false>
typeList; /* Offset from beginning of map to
* resource type list */
- HBUINT16 nameList; /* Offset from beginning of map to
+ Offset16 nameList; /* Offset from beginning of map to
* resource name list */
- HBUINT16 nTypes; /* Number of types in the map minus 1 */
public:
- DEFINE_SIZE_STATIC (30);
+ DEFINE_SIZE_STATIC (28);
};
struct ResourceForkHeader
{
- inline unsigned int get_face_count () const
- {
- const ResourceMap &resource_map = this+map;
- for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
- {
- const ResourceTypeItem& type = resource_map.get_type (i);
- if (type.is_sfnt ())
- return type.get_resource_count ();
- }
- return 0;
- }
+ inline unsigned int get_face_count (void) const
+ { return (this+map).get_face_count (); }
- inline const LArrayOf<HBUINT8>& get_data (const ResourceTypeItem& type,
- unsigned int idx) const
+ inline const OpenTypeFontFace& get_face (unsigned int idx,
+ unsigned int *base_offset = nullptr) const
{
- const ResourceMap &resource_map = this+map;
- unsigned int offset = dataOffset;
- offset += resource_map.get_ref_item (type, idx).dataOffset;
- return StructAtOffset<LArrayOf<HBUINT8> > (this, offset);
- }
-
- inline const OpenTypeFontFace& get_face (unsigned int idx) const
- {
- const ResourceMap &resource_map = this+map;
- for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
- {
- const ResourceTypeItem& type = resource_map.get_type (i);
- if (type.is_sfnt () && idx < type.get_resource_count ())
- return (OpenTypeFontFace&) get_data (type, idx).arrayZ;
- }
- return Null (OpenTypeFontFace);
+ const OpenTypeFontFace &face = (this+map).get_face (idx, &(this+data));
+ if (base_offset)
+ *base_offset = (const char *) &face - (const char *) this;
+ return face;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (unlikely (!c->check_struct (this)))
- return_trace (false);
-
- const ResourceMap &resource_map = this+map;
- if (unlikely (!resource_map.sanitize (c)))
- return_trace (false);
-
- for (unsigned int i = 0; i < resource_map.get_types_count (); ++i)
- {
- const ResourceTypeItem& type = resource_map.get_type (i);
- for (unsigned int j = 0; j < type.get_resource_count (); ++j)
- {
- const LArrayOf<HBUINT8>& data = get_data (type, j);
- if (unlikely (!(data.sanitize (c) &&
- ((OpenTypeFontFace&) data.arrayZ).sanitize (c))))
- return_trace (false);
- }
- }
-
- return_trace (true);
+ return_trace (c->check_struct (this) &&
+ data.sanitize (c, this, dataLen) &&
+ map.sanitize (c, this, &(this+data)));
}
protected:
- HBUINT32 dataOffset; /* Offset from beginning of resource fork
+ LOffsetTo<UnsizedArrayOf<HBUINT8>, false>
+ data; /* Offset from beginning of resource fork
* to resource data */
- LOffsetTo<ResourceMap>
+ LOffsetTo<ResourceMap, false>
map; /* Offset from beginning of resource fork
* to resource map */
HBUINT32 dataLen; /* Length of resource data */
@@ -486,7 +456,7 @@ struct OpenTypeFontFile
{
enum {
CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */
- TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */
+ TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */
TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */
DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */
TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */
@@ -503,12 +473,14 @@ struct OpenTypeFontFile
case Typ1Tag:
case TrueTypeTag: return 1;
case TTCTag: return u.ttcHeader.get_face_count ();
-// case DFontTag: return u.rfHeader.get_face_count ();
+ case DFontTag: return u.rfHeader.get_face_count ();
default: return 0;
}
}
- inline const OpenTypeFontFace& get_face (unsigned int i) const
+ inline const OpenTypeFontFace& get_face (unsigned int i, unsigned int *base_offset = nullptr) const
{
+ if (base_offset)
+ *base_offset = 0;
switch (u.tag) {
/* Note: for non-collection SFNT data we ignore index. This is because
* Apple dfont container is a container of SFNT's. So each SFNT is a
@@ -518,7 +490,7 @@ struct OpenTypeFontFile
case Typ1Tag:
case TrueTypeTag: return u.fontFace;
case TTCTag: return u.ttcHeader.get_face (i);
-// case DFontTag: return u.rfHeader.get_face (i);
+ case DFontTag: return u.rfHeader.get_face (i, base_offset);
default: return Null(OpenTypeFontFace);
}
}
@@ -545,7 +517,7 @@ struct OpenTypeFontFile
case Typ1Tag:
case TrueTypeTag: return_trace (u.fontFace.sanitize (c));
case TTCTag: return_trace (u.ttcHeader.sanitize (c));
-// case DFontTag: return_trace (u.rfHeader.sanitize (c));
+ case DFontTag: return_trace (u.rfHeader.sanitize (c));
default: return_trace (true);
}
}
@@ -565,4 +537,4 @@ struct OpenTypeFontFile
} /* namespace OT */
-#endif /* HB_OPEN_FILE_PRIVATE_HH */
+#endif /* HB_OPEN_FILE_HH */
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type.hh
index 5580565f1..08e72064a 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type.hh
@@ -26,13 +26,14 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OPEN_TYPE_PRIVATE_HH
-#define HB_OPEN_TYPE_PRIVATE_HH
+#ifndef HB_OPEN_TYPE_HH
+#define HB_OPEN_TYPE_HH
-#include "hb-private.hh"
-#include "hb-blob-private.hh"
-#include "hb-face-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb.hh"
+#include "hb-blob.hh"
+#include "hb-face.hh"
+#include "hb-machinery.hh"
+#include "hb-subset.hh"
namespace OT {
@@ -55,6 +56,7 @@ namespace OT {
template <typename Type, unsigned int Size>
struct IntType
{
+ typedef Type type;
inline void set (Type i) { v.set (i); }
inline operator Type(void) const { return v; }
inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
@@ -91,6 +93,9 @@ typedef IntType<uint32_t, 3> HBUINT24; /* 24-bit unsigned integer. */
/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
typedef HBINT16 FWORD;
+/* 32-bit signed integer (HBINT32) that describes a quantity in FUnits. */
+typedef HBINT32 FWORD32;
+
/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
typedef HBUINT16 UFWORD;
@@ -149,15 +154,17 @@ typedef HBUINT16 NameID;
/* Script/language-system/feature index */
struct Index : HBUINT16 {
- static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
+ enum { NOT_FOUND_INDEX = 0xFFFFu };
};
DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
/* Offset, Null offset = 0 */
-template <typename Type>
+template <typename Type, bool has_null=true>
struct Offset : Type
{
- inline bool is_null (void) const { return 0 == *this; }
+ typedef Type type;
+
+ inline bool is_null (void) const { return has_null && 0 == *this; }
inline void *serialize (hb_serialize_context_t *c, const void *base)
{
@@ -225,20 +232,23 @@ struct FixedVersion
* Use: (base+offset)
*/
-template <typename Type, typename OffsetType=HBUINT16>
-struct OffsetTo : Offset<OffsetType>
+template <typename Type, bool has_null_> struct assert_has_min_size { static_assert (Type::min_size > 0, ""); };
+template <typename Type> struct assert_has_min_size<Type, false> {};
+
+template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
+struct OffsetTo : Offset<OffsetType, has_null>
{
+ static_assert (sizeof (assert_has_min_size<Type, has_null>) || true, "");
+
inline const Type& operator () (const void *base) const
{
- unsigned int offset = *this;
- if (unlikely (!offset)) return Null(Type);
- return StructAtOffset<const Type> (base, offset);
+ if (unlikely (this->is_null ())) return Null(Type);
+ return StructAtOffset<const Type> (base, *this);
}
inline Type& operator () (void *base) const
{
- unsigned int offset = *this;
- if (unlikely (!offset)) return Crap(Type);
- return StructAtOffset<Type> (base, offset);
+ if (unlikely (this->is_null ())) return Crap(Type);
+ return StructAtOffset<Type> (base, *this);
}
inline Type& serialize (hb_serialize_context_t *c, const void *base)
@@ -246,46 +256,83 @@ struct OffsetTo : Offset<OffsetType>
return * (Type *) Offset<OffsetType>::serialize (c, base);
}
- inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ template <typename T>
+ inline void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
+ {
+ if (&src == &Null(T))
+ {
+ this->set (0);
+ return;
+ }
+ serialize (c->serializer, base);
+ if (!src.subset (c))
+ this->set (0);
+ }
+
+ inline bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false);
- unsigned int offset = *this;
- if (unlikely (!offset)) return_trace (true);
- if (unlikely (!c->check_range (base, offset))) return_trace (false);
- const Type &obj = StructAtOffset<Type> (base, offset);
- return_trace (likely (obj.sanitize (c)) || neuter (c));
+ if (unlikely (this->is_null ())) return_trace (true);
+ if (unlikely (!c->check_range (base, *this))) return_trace (false);
+ return_trace (true);
}
- template <typename T>
- inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
- if (unlikely (!c->check_struct (this))) return_trace (false);
- unsigned int offset = *this;
- if (unlikely (!offset)) return_trace (true);
- if (unlikely (!c->check_range (base, offset))) return_trace (false);
- const Type &obj = StructAtOffset<Type> (base, offset);
- return_trace (likely (obj.sanitize (c, user_data)) || neuter (c));
+ return_trace (sanitize_shallow (c, base) &&
+ (this->is_null () ||
+ StructAtOffset<Type> (base, *this).sanitize (c) ||
+ neuter (c)));
+ }
+ template <typename T1>
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (sanitize_shallow (c, base) &&
+ (this->is_null () ||
+ StructAtOffset<Type> (base, *this).sanitize (c, d1) ||
+ neuter (c)));
+ }
+ template <typename T1, typename T2>
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (sanitize_shallow (c, base) &&
+ (this->is_null () ||
+ StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) ||
+ neuter (c)));
+ }
+ template <typename T1, typename T2, typename T3>
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (sanitize_shallow (c, base) &&
+ (this->is_null () ||
+ StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) ||
+ neuter (c)));
}
/* Set the offset to Null */
- inline bool neuter (hb_sanitize_context_t *c) const {
+ inline bool neuter (hb_sanitize_context_t *c) const
+ {
+ if (!has_null) return false;
return c->try_set (this, 0);
}
DEFINE_SIZE_STATIC (sizeof(OffsetType));
};
-template <typename Type> struct LOffsetTo : OffsetTo<Type, HBUINT32> {};
-template <typename Base, typename OffsetType, typename 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); }
+template <typename Type, bool has_null=true> struct LOffsetTo : OffsetTo<Type, HBUINT32, has_null> {};
+template <typename Base, typename OffsetType, bool has_null, typename Type>
+static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
+template <typename Base, typename OffsetType, bool has_null, typename Type>
+static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
/*
* Array Types
*/
-/* TODO Use it in ArrayOf, HeadlessArrayOf, and other places around the code base?? */
template <typename Type>
struct UnsizedArrayOf
{
@@ -331,22 +378,22 @@ struct UnsizedArrayOf
inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
+ return_trace (c->check_array (arrayZ, count));
}
public:
- Type arrayZ[VAR];
+ Type arrayZ[VAR];
public:
DEFINE_SIZE_ARRAY (0, arrayZ);
};
/* Unsized array of offset's */
-template <typename Type, typename OffsetType>
-struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
+template <typename Type, typename OffsetType, bool has_null=true>
+struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {};
/* Unsized array of offsets relative to the beginning of the array itself. */
-template <typename Type, typename OffsetType>
-struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
+template <typename Type, typename OffsetType, bool has_null=true>
+struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
{
inline const Type& operator [] (unsigned int i) const
{
@@ -356,13 +403,13 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
- return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this)));
+ return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this)));
}
template <typename T>
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
{
TRACE_SANITIZE (this);
- return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data)));
+ return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data)));
}
};
@@ -404,7 +451,6 @@ struct ArrayOf
if (unlikely (!c->extend (*this))) return_trace (false);
return_trace (true);
}
-
inline bool serialize (hb_serialize_context_t *c,
Supplier<Type> &items,
unsigned int items_len)
@@ -474,12 +520,12 @@ struct ArrayOf
inline bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (len.sanitize (c) && c->check_array (arrayZ, Type::static_size, len));
+ return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
}
public:
- LenType len;
- Type arrayZ[VAR];
+ LenType len;
+ Type arrayZ[VAR];
public:
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
};
@@ -505,6 +551,17 @@ struct OffsetListOf : OffsetArrayOf<Type>
return this+this->arrayZ[i];
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ struct OffsetListOf<Type> *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ unsigned int count = this->len;
+ for (unsigned int i = 0; i < count; i++)
+ out->arrayZ[i].serialize_subset (c, (*this)[i], out);
+ return_trace (true);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -524,16 +581,16 @@ struct HeadlessArrayOf
{
inline const Type& operator [] (unsigned int i) const
{
- if (unlikely (i >= len || !i)) return Null(Type);
+ if (unlikely (i >= lenP1 || !i)) return Null(Type);
return arrayZ[i-1];
}
inline Type& operator [] (unsigned int i)
{
- if (unlikely (i >= len || !i)) return Crap(Type);
+ if (unlikely (i >= lenP1 || !i)) return Crap(Type);
return arrayZ[i-1];
}
inline unsigned int get_size (void) const
- { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
+ { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; }
inline bool serialize (hb_serialize_context_t *c,
Supplier<Type> &items,
@@ -541,7 +598,7 @@ struct HeadlessArrayOf
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- len.set (items_len); /* TODO(serialize) Overflow? */
+ lenP1.set (items_len); /* TODO(serialize) Overflow? */
if (unlikely (!items_len)) return_trace (true);
if (unlikely (!c->extend (*this))) return_trace (false);
for (unsigned int i = 0; i < items_len - 1; i++)
@@ -571,13 +628,57 @@ struct HeadlessArrayOf
inline bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (len.sanitize (c) &&
- (!len || c->check_array (arrayZ, Type::static_size, len - 1)));
+ return_trace (lenP1.sanitize (c) &&
+ (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
+ }
+
+ public:
+ LenType lenP1;
+ Type arrayZ[VAR];
+ public:
+ DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
+};
+
+/* An array storing length-1. */
+template <typename Type, typename LenType=HBUINT16>
+struct ArrayOfM1
+{
+ inline const Type& operator [] (unsigned int i) const
+ {
+ if (unlikely (i > lenM1)) return Null(Type);
+ return arrayZ[i];
+ }
+ inline Type& operator [] (unsigned int i)
+ {
+ if (unlikely (i > lenM1)) return Crap(Type);
+ return arrayZ[i];
+ }
+ inline unsigned int get_size (void) const
+ { return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
+
+ template <typename T>
+ 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 (false);
+ unsigned int count = lenM1 + 1;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
+ return_trace (false);
+ return_trace (true);
+ }
+
+ private:
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (lenM1.sanitize (c) &&
+ (c->check_array (arrayZ, lenM1 + 1)));
}
public:
- LenType len;
- Type arrayZ[VAR];
+ LenType lenM1;
+ Type arrayZ[VAR];
public:
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
};
@@ -607,7 +708,11 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
}
};
-/* Binary-search arrays */
+/*
+ * Binary-search arrays
+ */
+
+template <typename LenType=HBUINT16>
struct BinSearchHeader
{
inline operator uint32_t (void) const { return len; }
@@ -630,20 +735,120 @@ struct BinSearchHeader
}
protected:
- HBUINT16 len;
- HBUINT16 searchRange;
- HBUINT16 entrySelector;
- HBUINT16 rangeShift;
+ LenType len;
+ LenType searchRange;
+ LenType entrySelector;
+ LenType rangeShift;
public:
DEFINE_SIZE_STATIC (8);
};
+template <typename Type, typename LenType=HBUINT16>
+struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {};
+
+struct VarSizedBinSearchHeader
+{
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this));
+ }
+
+ HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
+ HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
+ HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
+ * that is less than or equal to the value of nUnits. */
+ HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
+ * or equal to the value of nUnits. */
+ HBUINT16 rangeShift; /* The value of unitSize times the difference of the
+ * value of nUnits minus the largest power of 2 less
+ * than or equal to the value of nUnits. */
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
template <typename Type>
-struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
+struct VarSizedBinSearchArrayOf
+{
+ inline const Type& operator [] (unsigned int i) const
+ {
+ if (unlikely (i >= header.nUnits)) return Null(Type);
+ return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
+ }
+ inline Type& operator [] (unsigned int i)
+ {
+ return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
+ }
+ inline unsigned int get_size (void) const
+ { return header.static_size + header.nUnits * header.unitSize; }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!sanitize_shallow (c))) return_trace (false);
+
+ /* Note: for structs that do not reference other structs,
+ * we do not need to call their sanitize() as we already did
+ * a bound check on the aggregate array size. We just include
+ * a small unreachable expression to make sure the structs
+ * pointed to do have a simple sanitize(), ie. they do not
+ * reference other structs via offsets.
+ */
+ (void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c));
+
+ return_trace (true);
+ }
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!sanitize_shallow (c))) return_trace (false);
+ unsigned int count = header.nUnits;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!(*this)[i].sanitize (c, base)))
+ return_trace (false);
+ return_trace (true);
+ }
+
+ template <typename T>
+ inline const Type *bsearch (const T &key) const
+ {
+ unsigned int size = header.unitSize;
+ int min = 0, max = (int) header.nUnits - 1;
+ while (min <= max)
+ {
+ int mid = (min + max) / 2;
+ const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
+ int c = p->cmp (key);
+ if (c < 0)
+ max = mid - 1;
+ else if (c > 0)
+ min = mid + 1;
+ else
+ return p;
+ }
+ return nullptr;
+ }
+
+ private:
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (header.sanitize (c) &&
+ Type::static_size <= header.unitSize &&
+ c->check_array (bytesZ.arrayZ, header.nUnits, header.unitSize));
+ }
+
+ protected:
+ VarSizedBinSearchHeader header;
+ UnsizedArrayOf<HBUINT8> bytesZ;
+ public:
+ DEFINE_SIZE_ARRAY (10, bytesZ);
+};
} /* namespace OT */
-#endif /* HB_OPEN_TYPE_PRIVATE_HH */
+#endif /* HB_OPEN_TYPE_HH */
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
index 67a9c7dd9..e5793c387 100644
--- a/src/hb-ot-cmap-table.hh
+++ b/src/hb-ot-cmap-table.hh
@@ -27,9 +27,8 @@
#ifndef HB_OT_CMAP_TABLE_HH
#define HB_OT_CMAP_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-set-private.hh"
-#include "hb-subset-plan.hh"
+#include "hb-open-type.hh"
+#include "hb-set.hh"
/*
* cmap -- Character to Glyph Index Mapping
@@ -37,10 +36,6 @@
*/
#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
-#ifndef HB_MAX_UNICODE_CODEPOINT_VALUE
-#define HB_MAX_UNICODE_CODEPOINT_VALUE 0x10FFFF
-#endif
-
namespace OT {
@@ -54,6 +49,12 @@ struct CmapSubtableFormat0
*glyph = gid;
return true;
}
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ for (unsigned int i = 0; i < 256; i++)
+ if (glyphIdArray[i])
+ out->add (i);
+ }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -230,22 +231,21 @@ struct CmapSubtableFormat4
inline void init (const CmapSubtableFormat4 *subtable)
{
segCount = subtable->segCountX2 / 2;
- endCount = subtable->values;
+ endCount = subtable->values.arrayZ;
startCount = endCount + segCount + 1;
idDelta = startCount + segCount;
idRangeOffset = idDelta + segCount;
glyphIdArray = idRangeOffset + segCount;
glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
}
+ inline void fini (void) {}
- static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
- const accelerator_t *thiz = (const accelerator_t *) obj;
-
/* Custom two-array bsearch. */
- int min = 0, max = (int) thiz->segCount - 1;
- const HBUINT16 *startCount = thiz->startCount;
- const HBUINT16 *endCount = thiz->endCount;
+ int min = 0, max = (int) this->segCount - 1;
+ const HBUINT16 *startCount = this->startCount;
+ const HBUINT16 *endCount = this->endCount;
unsigned int i;
while (min <= max)
{
@@ -264,33 +264,55 @@ struct CmapSubtableFormat4
found:
hb_codepoint_t gid;
- unsigned int rangeOffset = thiz->idRangeOffset[i];
+ unsigned int rangeOffset = this->idRangeOffset[i];
if (rangeOffset == 0)
- gid = codepoint + thiz->idDelta[i];
+ gid = codepoint + this->idDelta[i];
else
{
/* Somebody has been smoking... */
- unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
- if (unlikely (index >= thiz->glyphIdArrayLength))
+ unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
+ if (unlikely (index >= this->glyphIdArrayLength))
return false;
- gid = thiz->glyphIdArray[index];
+ gid = this->glyphIdArray[index];
if (unlikely (!gid))
return false;
- gid += thiz->idDelta[i];
+ gid += this->idDelta[i];
}
-
- *glyph = gid & 0xFFFFu;
+ gid &= 0xFFFFu;
+ if (!gid)
+ return false;
+ *glyph = gid;
return true;
}
-
- static inline void get_all_codepoints_func (const void *obj, hb_set_t *out)
+ static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
{
- const accelerator_t *thiz = (const accelerator_t *) obj;
- for (unsigned int i = 0; i < thiz->segCount; i++)
+ return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph);
+ }
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ unsigned int count = this->segCount;
+ if (count && this->startCount[count - 1] == 0xFFFFu)
+ count--; /* Skip sentinel segment. */
+ for (unsigned int i = 0; i < count; i++)
{
- if (thiz->startCount[i] != 0xFFFFu
- || thiz->endCount[i] != 0xFFFFu) // Skip the last segment (0xFFFF)
- hb_set_add_range (out, thiz->startCount[i], thiz->endCount[i]);
+ unsigned int rangeOffset = this->idRangeOffset[i];
+ if (rangeOffset == 0)
+ out->add_range (this->startCount[i], this->endCount[i]);
+ else
+ {
+ for (hb_codepoint_t codepoint = this->startCount[i];
+ codepoint <= this->endCount[i];
+ codepoint++)
+ {
+ unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount;
+ if (unlikely (index >= this->glyphIdArrayLength))
+ break;
+ hb_codepoint_t gid = this->glyphIdArray[index];
+ if (unlikely (!gid))
+ continue;
+ out->add (codepoint);
+ }
+ }
}
}
@@ -305,10 +327,14 @@ struct CmapSubtableFormat4
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
- accelerator_t accel;
- accel.init (this);
+ hb_auto_t<accelerator_t> accel (this);
return accel.get_glyph_func (&accel, codepoint, glyph);
}
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ hb_auto_t<accelerator_t> accel (this);
+ accel.collect_unicodes (out);
+ }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -343,7 +369,8 @@ struct CmapSubtableFormat4
HBUINT16 entrySelector; /* log2(searchRange/2) */
HBUINT16 rangeShift; /* 2 x segCount - searchRange */
- HBUINT16 values[VAR];
+ UnsizedArrayOf<HBUINT16>
+ values;
#if 0
HBUINT16 endCount[segCount]; /* End characterCode for each segment,
* last=0xFFFFu. */
@@ -351,7 +378,8 @@ struct CmapSubtableFormat4
HBUINT16 startCount[segCount]; /* Start character code for each segment. */
HBINT16 idDelta[segCount]; /* Delta for all character codes in segment. */
HBUINT16 idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
- HBUINT16 glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */
+ UnsizedArrayOf<HBUINT16>
+ glyphIdArray; /* Glyph index array (arbitrary length) */
#endif
public:
@@ -383,7 +411,7 @@ struct CmapSubtableLongGroup
HBUINT32 startCharCode; /* First character code in this group. */
HBUINT32 endCharCode; /* Last character code in this group. */
HBUINT32 glyphID; /* Glyph index; interpretation depends on
- * subtable format. */
+ * subtable format. */
public:
DEFINE_SIZE_STATIC (12);
};
@@ -400,6 +428,14 @@ struct CmapSubtableTrimmed
*glyph = gid;
return true;
}
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ hb_codepoint_t start = startCharCode;
+ unsigned int count = glyphIdArray.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (glyphIdArray[i])
+ out->add (start + i);
+ }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -432,18 +468,19 @@ struct CmapSubtableLongSegmented
int i = groups.bsearch (codepoint);
if (i == -1)
return false;
- *glyph = T::group_get_glyph (groups[i], codepoint);
+ hb_codepoint_t gid = T::group_get_glyph (groups[i], codepoint);
+ if (!gid)
+ return false;
+ *glyph = gid;
return true;
}
- inline void get_all_codepoints (hb_set_t *out) const
+ inline void collect_unicodes (hb_set_t *out) const
{
for (unsigned int i = 0; i < this->groups.len; i++) {
- hb_set_add_range (out,
- MIN ((unsigned int) this->groups[i].startCharCode,
- (unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE),
- MIN ((unsigned int) this->groups[i].endCharCode,
- (unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE));
+ out->add_range (this->groups[i].startCharCode,
+ MIN ((hb_codepoint_t) this->groups[i].endCharCode,
+ (hb_codepoint_t) HB_UNICODE_MAX));
}
}
@@ -458,7 +495,7 @@ struct CmapSubtableLongSegmented
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
- Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ, group_data.len);
+ Supplier<CmapSubtableLongGroup> supplier (group_data.arrayZ(), group_data.len);
if (unlikely (!groups.serialize (c, supplier, group_data.len))) return_trace (false);
return true;
}
@@ -574,13 +611,29 @@ struct UnicodeValueRange
}
HBUINT24 startUnicodeValue; /* First value in this range. */
- HBUINT8 additionalCount; /* Number of additional values in this
+ HBUINT8 additionalCount; /* Number of additional values in this
* range. */
public:
DEFINE_SIZE_STATIC (4);
};
-typedef SortedArrayOf<UnicodeValueRange, HBUINT32> DefaultUVS;
+struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
+{
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ hb_codepoint_t first = arrayZ[i].startUnicodeValue;
+ hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount),
+ (hb_codepoint_t) HB_UNICODE_MAX);
+ out->add_range (first, last);
+ }
+ }
+
+ public:
+ DEFINE_SIZE_ARRAY (4, arrayZ);
+};
struct UVSMapping
{
@@ -601,7 +654,18 @@ struct UVSMapping
DEFINE_SIZE_STATIC (5);
};
-typedef SortedArrayOf<UVSMapping, HBUINT32> NonDefaultUVS;
+struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
+{
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ out->add (arrayZ[i].glyphID);
+ }
+
+ public:
+ DEFINE_SIZE_ARRAY (4, arrayZ);
+};
struct VariationSelectorRecord
{
@@ -616,7 +680,7 @@ struct VariationSelectorRecord
return GLYPH_VARIANT_USE_DEFAULT;
const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
i = nonDefaults.bsearch (codepoint);
- if (i != -1)
+ if (i != -1 && nonDefaults[i].glyphID)
{
*glyph = nonDefaults[i].glyphID;
return GLYPH_VARIANT_FOUND;
@@ -624,6 +688,12 @@ struct VariationSelectorRecord
return GLYPH_VARIANT_NOT_FOUND;
}
+ inline void collect_unicodes (hb_set_t *out, const void *base) const
+ {
+ (base+defaultUVS).collect_unicodes (out);
+ (base+nonDefaultUVS).collect_unicodes (out);
+ }
+
inline int cmp (const hb_codepoint_t &variation_selector) const
{
return varSelector.cmp (variation_selector);
@@ -639,9 +709,9 @@ struct VariationSelectorRecord
HBUINT24 varSelector; /* Variation selector. */
LOffsetTo<DefaultUVS>
- defaultUVS; /* Offset to Default UVS Table. May be 0. */
+ defaultUVS; /* Offset to Default UVS Table. May be 0. */
LOffsetTo<NonDefaultUVS>
- nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
+ nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
public:
DEFINE_SIZE_STATIC (11);
};
@@ -652,7 +722,19 @@ struct CmapSubtableFormat14
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
- return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
+ return record[record.bsearch (variation_selector)].get_glyph (codepoint, glyph, this);
+ }
+
+ inline void collect_variation_selectors (hb_set_t *out) const
+ {
+ unsigned int count = record.len;
+ for (unsigned int i = 0; i < count; i++)
+ out->add (record.arrayZ[i].varSelector);
+ }
+ inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
+ hb_set_t *out) const
+ {
+ record[record.bsearch (variation_selector)].collect_unicodes (out, this);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -690,6 +772,19 @@ struct CmapSubtable
default: return false;
}
}
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ switch (u.format) {
+ case 0: u.format0 .collect_unicodes (out); return;
+ case 4: u.format4 .collect_unicodes (out); return;
+ case 6: u.format6 .collect_unicodes (out); return;
+ case 10: u.format10.collect_unicodes (out); return;
+ case 12: u.format12.collect_unicodes (out); return;
+ case 13: u.format13.collect_unicodes (out); return;
+ case 14:
+ default: return;
+ }
+ }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -754,7 +849,8 @@ struct cmap
{
static const hb_tag_t tableTag = HB_OT_TAG_cmap;
- struct subset_plan {
+ struct subset_plan
+ {
subset_plan(void)
{
format4_segments.init();
@@ -895,33 +991,44 @@ struct cmap
return result;
}
+ const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
+ {
+ if (symbol) *symbol = false;
+
+ const CmapSubtable *subtable;
+
+ /* 32-bit subtables. */
+ if ((subtable = this->find_subtable (3, 10))) return subtable;
+ if ((subtable = this->find_subtable (0, 6))) return subtable;
+ if ((subtable = this->find_subtable (0, 4))) return subtable;
+
+ /* 16-bit subtables. */
+ if ((subtable = this->find_subtable (3, 1))) return subtable;
+ if ((subtable = this->find_subtable (0, 3))) return subtable;
+ if ((subtable = this->find_subtable (0, 2))) return subtable;
+ if ((subtable = this->find_subtable (0, 1))) return subtable;
+ if ((subtable = this->find_subtable (0, 0))) return subtable;
+
+ /* Symbol subtable. */
+ if ((subtable = this->find_subtable (3, 0)))
+ {
+ if (symbol) *symbol = true;
+ return subtable;
+ }
+
+ /* Meh. */
+ return &Null(CmapSubtable);
+ }
+
struct accelerator_t
{
inline void init (hb_face_t *face)
{
this->blob = hb_sanitize_context_t().reference_table<cmap> (face);
const cmap *table = this->blob->as<cmap> ();
- const CmapSubtable *subtable = nullptr;
const CmapSubtableFormat14 *subtable_uvs = nullptr;
-
- bool symbol = false;
- /* 32-bit subtables. */
- if (!subtable) subtable = table->find_subtable (3, 10);
- if (!subtable) subtable = table->find_subtable (0, 6);
- if (!subtable) subtable = table->find_subtable (0, 4);
- /* 16-bit subtables. */
- if (!subtable) subtable = table->find_subtable (3, 1);
- if (!subtable) subtable = table->find_subtable (0, 3);
- if (!subtable) subtable = table->find_subtable (0, 2);
- if (!subtable) subtable = table->find_subtable (0, 1);
- if (!subtable) subtable = table->find_subtable (0, 0);
- if (!subtable)
- {
- subtable = table->find_subtable (3, 0);
- if (subtable) symbol = true;
- }
- /* Meh. */
- if (!subtable) subtable = &Null(CmapSubtable);
+ bool symbol;
+ subtable = table->find_best_subtable (&symbol);
/* UVS subtable. */
if (!subtable_uvs)
@@ -933,30 +1040,26 @@ struct cmap
/* Meh. */
if (!subtable_uvs) subtable_uvs = &Null(CmapSubtableFormat14);
- this->uvs_table = subtable_uvs;
+ this->subtable_uvs = subtable_uvs;
this->get_glyph_data = subtable;
if (unlikely (symbol))
{
this->get_glyph_func = get_glyph_from_symbol<CmapSubtable>;
- this->get_all_codepoints_func = null_get_all_codepoints_func;
} else {
switch (subtable->u.format) {
/* Accelerate format 4 and format 12. */
default:
this->get_glyph_func = get_glyph_from<CmapSubtable>;
- this->get_all_codepoints_func = null_get_all_codepoints_func;
break;
case 12:
this->get_glyph_func = get_glyph_from<CmapSubtableFormat12>;
- this->get_all_codepoints_func = get_all_codepoints_from<CmapSubtableFormat12>;
break;
case 4:
{
this->format4_accel.init (&subtable->u.format4);
this->get_glyph_data = &this->format4_accel;
this->get_glyph_func = this->format4_accel.get_glyph_func;
- this->get_all_codepoints_func = this->format4_accel.get_all_codepoints_func;
}
break;
}
@@ -978,9 +1081,9 @@ struct cmap
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
- switch (this->uvs_table->get_glyph_variant (unicode,
- variation_selector,
- glyph))
+ switch (this->subtable_uvs->get_glyph_variant (unicode,
+ variation_selector,
+ glyph))
{
case GLYPH_VARIANT_NOT_FOUND: return false;
case GLYPH_VARIANT_FOUND: return true;
@@ -990,22 +1093,24 @@ struct cmap
return get_nominal_glyph (unicode, glyph);
}
- inline void get_all_codepoints (hb_set_t *out) const
+ inline void collect_unicodes (hb_set_t *out) const
+ {
+ subtable->collect_unicodes (out);
+ }
+ inline void collect_variation_selectors (hb_set_t *out) const
+ {
+ subtable_uvs->collect_variation_selectors (out);
+ }
+ inline void collect_variation_unicodes (hb_codepoint_t variation_selector,
+ hb_set_t *out) const
{
- this->get_all_codepoints_func (get_glyph_data, out);
+ subtable_uvs->collect_variation_unicodes (variation_selector, out);
}
protected:
typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph);
- typedef void (*hb_cmap_get_all_codepoints_func_t) (const void *obj,
- hb_set_t *out);
-
- static inline void null_get_all_codepoints_func (const void *obj, hb_set_t *out)
- {
- // NOOP
- }
template <typename Type>
static inline bool get_glyph_from (const void *obj,
@@ -1017,14 +1122,6 @@ struct cmap
}
template <typename Type>
- static inline void get_all_codepoints_from (const void *obj,
- hb_set_t *out)
- {
- const Type *typed_obj = (const Type *) obj;
- typed_obj->get_all_codepoints (out);
- }
-
- template <typename Type>
static inline bool get_glyph_from_symbol (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph)
@@ -1047,13 +1144,14 @@ struct cmap
}
private:
+ const CmapSubtable *subtable;
+ const CmapSubtableFormat14 *subtable_uvs;
+
hb_cmap_get_glyph_func_t get_glyph_func;
const void *get_glyph_data;
- hb_cmap_get_all_codepoints_func_t get_all_codepoints_func;
CmapSubtableFormat4::accelerator_t format4_accel;
- const CmapSubtableFormat14 *uvs_table;
hb_blob_t *blob;
};
@@ -1066,10 +1164,7 @@ struct cmap
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);
+ int result = encodingRecord.bsearch (key);
if (result == -1 || !encodingRecord[result].subtable)
return nullptr;
@@ -1084,6 +1179,7 @@ struct cmap
DEFINE_SIZE_ARRAY (4, encodingRecord);
};
+struct cmap_accelerator_t : cmap::accelerator_t {};
} /* namespace OT */
diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh
index 21c2f4773..1e1fe0956 100644
--- a/src/hb-ot-color-cbdt-table.hh
+++ b/src/hb-ot-color-cbdt-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_COLOR_CBDT_TABLE_HH
#define HB_OT_COLOR_CBDT_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* CBLC -- Color Bitmap Location
@@ -128,7 +128,7 @@ struct IndexSubtableFormat1Or3
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
- c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1));
+ offsetArrayZ.sanitize (c, glyph_count + 1));
}
bool get_image_data (unsigned int idx,
@@ -144,7 +144,8 @@ struct IndexSubtableFormat1Or3
}
IndexSubtableHeader header;
- Offset<OffsetType> offsetArrayZ[VAR];
+ UnsizedArrayOf<Offset<OffsetType> >
+ offsetArrayZ;
public:
DEFINE_SIZE_ARRAY(8, offsetArrayZ);
};
@@ -205,24 +206,23 @@ struct IndexSubtableRecord
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
firstGlyphIndex <= lastGlyphIndex &&
- offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1));
+ offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
}
- inline bool get_extents (hb_glyph_extents_t *extents) const
+ inline bool get_extents (hb_glyph_extents_t *extents,
+ const void *base) const
{
- return (this+offsetToSubtable).get_extents (extents);
+ return (base+offsetToSubtable).get_extents (extents);
}
- bool get_image_data (unsigned int gid,
+ bool get_image_data (unsigned int gid,
+ const void *base,
unsigned int *offset,
unsigned int *length,
unsigned int *format) const
{
- if (gid < firstGlyphIndex || gid > lastGlyphIndex)
- {
- return false;
- }
- return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
+ if (gid < firstGlyphIndex || gid > lastGlyphIndex) return false;
+ return (base+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
offset, length, format);
}
@@ -240,12 +240,7 @@ struct IndexSubtableArray
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
- if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count)))
- return_trace (false);
- for (unsigned int i = 0; i < count; i++)
- if (unlikely (!indexSubtablesZ[i].sanitize (c, this)))
- return_trace (false);
- return_trace (true);
+ return_trace (indexSubtablesZ.sanitize (c, count, this));
}
public:
@@ -255,17 +250,14 @@ struct IndexSubtableArray
{
unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
- if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
+ if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex)
return &indexSubtablesZ[i];
- }
}
return nullptr;
}
protected:
- IndexSubtableRecord indexSubtablesZ[VAR];
- public:
- DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
+ UnsizedArrayOf<IndexSubtableRecord> indexSubtablesZ;
};
struct BitmapSizeTable
@@ -278,18 +270,20 @@ struct BitmapSizeTable
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
- c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) &&
horizontal.sanitize (c) &&
vertical.sanitize (c));
}
- const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
+ const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
+ const void *base,
+ const void **out_base) const
{
+ *out_base = &(base+indexSubtableArrayOffset);
return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
}
protected:
- LOffsetTo<IndexSubtableArray>
+ LOffsetTo<IndexSubtableArray, false>
indexSubtableArrayOffset;
HBUINT32 indexTablesSize;
HBUINT32 numberOfIndexSubtables;
@@ -350,7 +344,8 @@ struct CBLC
protected:
const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
- unsigned int *x_ppem, unsigned int *y_ppem) const
+ unsigned int *x_ppem, unsigned int *y_ppem,
+ const void **base) const
{
/* TODO: Make it possible to select strike. */
@@ -363,7 +358,7 @@ struct CBLC
{
*x_ppem = sizeTables[i].ppemX;
*y_ppem = sizeTables[i].ppemY;
- return sizeTables[i].find_table (glyph, this);
+ return sizeTables[i].find_table (glyph, this, base);
}
}
@@ -421,15 +416,16 @@ struct CBDT
if (!cblc)
return false; // Not a color bitmap font.
- const IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
+ const void *base;
+ const IndexSubtableRecord *subtable_record = this->cblc->find_table (glyph, &x_ppem, &y_ppem, &base);
if (!subtable_record || !x_ppem || !y_ppem)
return false;
- if (subtable_record->get_extents (extents))
+ if (subtable_record->get_extents (extents, base))
return true;
unsigned int image_offset = 0, image_length = 0, image_format = 0;
- if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
+ if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
return false;
{
@@ -480,7 +476,7 @@ struct CBDT
{
unsigned int image_offset = 0, image_length = 0, image_format = 0;
- if (!subtable_record.get_image_data (gid,
+ if (!subtable_record.get_image_data (gid, &subtable_array,
&image_offset, &image_length, &image_format))
continue;
@@ -527,12 +523,14 @@ struct CBDT
protected:
- FixedVersion<> version;
- HBUINT8 dataZ[VAR];
+ FixedVersion<> version;
+ UnsizedArrayOf<HBUINT8> dataZ;
public:
DEFINE_SIZE_ARRAY(4, dataZ);
};
+struct CBDT_accelerator_t : CBDT::accelerator_t {};
+
} /* namespace OT */
#endif /* HB_OT_COLOR_CBDT_TABLE_HH */
diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh
index ce6702d2a..a59d2bfa9 100644
--- a/src/hb-ot-color-colr-table.hh
+++ b/src/hb-ot-color-colr-table.hh
@@ -25,7 +25,7 @@
#ifndef HB_OT_COLOR_COLR_TABLE_HH
#define HB_OT_COLOR_COLR_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* COLR -- Color
@@ -129,9 +129,9 @@ struct COLR
protected:
HBUINT16 version; /* Table version number */
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records */
- LOffsetTo<UnsizedArrayOf<BaseGlyphRecord> >
+ LOffsetTo<UnsizedArrayOf<BaseGlyphRecord>, false>
baseGlyphsZ; /* Offset to Base Glyph records. */
- LOffsetTo<UnsizedArrayOf<LayerRecord> >
+ LOffsetTo<UnsizedArrayOf<LayerRecord>, false>
layersZ; /* Offset to Layer Records */
HBUINT16 numLayers; /* Number of Layer Records */
public:
diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh
index 2c312748d..e354ced5c 100644
--- a/src/hb-ot-color-cpal-table.hh
+++ b/src/hb-ot-color-cpal-table.hh
@@ -28,7 +28,7 @@
#ifndef HB_OT_COLOR_CPAL_TABLE_HH
#define HB_OT_COLOR_CPAL_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
@@ -118,15 +118,15 @@ struct CPALV1Tail
}
protected:
- LOffsetTo<UnsizedArrayOf<HBUINT32> >
+ LOffsetTo<UnsizedArrayOf<HBUINT32>, false>
paletteFlagsZ; /* Offset from the beginning of CPAL table to
* the Palette Type Array. Set to 0 if no array
* is provided. */
- LOffsetTo<UnsizedArrayOf<HBUINT16> >
+ LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
paletteLabelZ; /* Offset from the beginning of CPAL table to
* the Palette Labels Array. Set to 0 if no
* array is provided. */
- LOffsetTo<UnsizedArrayOf<HBUINT16> >
+ LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
paletteEntryLabelZ; /* Offset from the beginning of CPAL table to
* the Palette Entry Label Array. Set to 0
* if no array is provided. */
@@ -207,7 +207,7 @@ struct CPAL
HBUINT16 numPalettes; /* Number of palettes in the table. */
HBUINT16 numColorRecords; /* Total number of color records, combined for
* all palettes. */
- LOffsetTo<UnsizedArrayOf<BGRAColor> >
+ LOffsetTo<UnsizedArrayOf<BGRAColor>, false>
colorRecordsZ; /* Offset from the beginning of CPAL table to
* the first ColorRecord. */
UnsizedArrayOf<HBUINT16>
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
index 0461afa32..1b643c77a 100644
--- a/src/hb-ot-color-sbix-table.hh
+++ b/src/hb-ot-color-sbix-table.hh
@@ -25,7 +25,7 @@
#ifndef HB_OT_COLOR_SBIX_TABLE_HH
#define HB_OT_COLOR_SBIX_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* sbix -- Standard Bitmap Graphics
diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh
index 3976694f8..53d466846 100644
--- a/src/hb-ot-color-svg-table.hh
+++ b/src/hb-ot-color-svg-table.hh
@@ -25,7 +25,7 @@
#ifndef HB_OT_COLOR_SVG_TABLE_HH
#define HB_OT_COLOR_SVG_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* SVG -- SVG (Scalable Vector Graphics)
@@ -54,7 +54,7 @@ struct SVGDocumentIndexEntry
* this index entry. */
HBUINT16 endGlyphID; /* The last glyph ID in the range described by
* this index entry. Must be >= startGlyphID. */
- LOffsetTo<UnsizedArrayOf<HBUINT8> >
+ LOffsetTo<UnsizedArrayOf<HBUINT8>, false>
svgDoc; /* Offset from the beginning of the SVG Document Index
* to an SVG document. Must be non-zero. */
HBUINT32 svgDocLength; /* Length of the SVG document.
diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc
index 86171c633..7cdff380e 100644
--- a/src/hb-ot-color.cc
+++ b/src/hb-ot-color.cc
@@ -25,7 +25,7 @@
* Google Author(s): Sascha Brawer
*/
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-cpal-table.hh"
#include "hb-ot.h"
@@ -33,8 +33,8 @@
#include <stdlib.h>
#include <string.h>
-#include "hb-ot-layout-private.hh"
-#include "hb-shaper-private.hh"
+#include "hb-ot-layout.hh"
+#include "hb-shaper.hh"
#if 0
HB_MARK_AS_FLAG_T (hb_ot_color_palette_flags_t)
@@ -45,16 +45,14 @@ static inline const OT::COLR&
_get_colr (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::COLR);
- hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
- return *(layout->colr.get ());
+ return *(hb_ot_face_data (face)->colr.get ());
}
static inline const OT::CPAL&
_get_cpal (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::CPAL);
- hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
- return *(layout->cpal.get ());
+ return *(hb_ot_face_data (face)->cpal.get ());
}
diff --git a/src/hb-ot-face.cc b/src/hb-ot-face.cc
new file mode 100644
index 000000000..1bc68d366
--- /dev/null
+++ b/src/hb-ot-face.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2018 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-face.hh"
+
+#include "hb-ot-cmap-table.hh"
+#include "hb-ot-glyf-table.hh"
+#include "hb-ot-hmtx-table.hh"
+#include "hb-ot-kern-table.hh"
+#include "hb-ot-post-table.hh"
+#include "hb-ot-color-cbdt-table.hh"
+#include "hb-ot-layout-gdef-table.hh"
+#include "hb-ot-layout-gsub-table.hh"
+#include "hb-ot-layout-gpos-table.hh"
+
+
+void hb_ot_face_data_t::init0 (hb_face_t *face)
+{
+ this->face = face;
+#define HB_OT_TABLE(Namespace, Type) Type.init0 ();
+#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+ HB_OT_TABLES
+#undef HB_OT_ACCELERATOR
+#undef HB_OT_TABLE
+}
+void hb_ot_face_data_t::fini (void)
+{
+#define HB_OT_TABLE(Namespace, Type) Type.fini ();
+#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+ HB_OT_TABLES
+#undef HB_OT_ACCELERATOR
+#undef HB_OT_TABLE
+}
+
+hb_ot_face_data_t *
+_hb_ot_face_data_create (hb_face_t *face)
+{
+ hb_ot_face_data_t *data = (hb_ot_face_data_t *) calloc (1, sizeof (hb_ot_face_data_t));
+ if (unlikely (!data))
+ return nullptr;
+
+ data->init0 (face);
+
+ return data;
+}
+
+void
+_hb_ot_face_data_destroy (hb_ot_face_data_t *data)
+{
+ data->fini ();
+ free (data);
+}
+
diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh
new file mode 100644
index 000000000..e30592218
--- /dev/null
+++ b/src/hb-ot-face.hh
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2012,2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_FACE_HH
+#define HB_OT_FACE_HH
+
+#include "hb.hh"
+
+#include "hb-machinery.hh"
+
+
+#define hb_ot_face_data(face) ((hb_ot_face_data_t *) face->shaper_data.ot.get_relaxed ())
+
+
+/*
+ * hb_ot_face_data_t
+ */
+
+/* Most of these tables are NOT needed for shaping. But we need to hook them *somewhere*.
+ * This is as good as any place. */
+#define HB_OT_TABLES \
+ /* OpenType shaping. */ \
+ HB_OT_TABLE(OT, JSTF) \
+ HB_OT_TABLE(OT, BASE) \
+ /* AAT shaping. */ \
+ HB_OT_TABLE(AAT, morx) \
+ HB_OT_TABLE(AAT, kerx) \
+ HB_OT_TABLE(AAT, ankr) \
+ HB_OT_TABLE(AAT, trak) \
+ /* OpenType variations. */ \
+ HB_OT_TABLE(OT, fvar) \
+ HB_OT_TABLE(OT, avar) \
+ HB_OT_TABLE(OT, MVAR) \
+ /* OpenType math. */ \
+ HB_OT_TABLE(OT, MATH) \
+ /* OpenType fundamentals. */ \
+ HB_OT_ACCELERATOR(OT, GDEF) \
+ HB_OT_ACCELERATOR(OT, GSUB) \
+ HB_OT_ACCELERATOR(OT, GPOS) \
+ HB_OT_ACCELERATOR(OT, cmap) \
+ HB_OT_ACCELERATOR(OT, hmtx) \
+ HB_OT_ACCELERATOR(OT, vmtx) \
+ HB_OT_ACCELERATOR(OT, post) \
+ HB_OT_ACCELERATOR(OT, kern) \
+ HB_OT_ACCELERATOR(OT, glyf) \
+ HB_OT_ACCELERATOR(OT, CBDT) \
+ /* */
+
+/* Declare tables. */
+#define HB_OT_TABLE(Namespace, Type) namespace Namespace { struct Type; }
+#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type##_accelerator_t)
+HB_OT_TABLES
+#undef HB_OT_ACCELERATOR
+#undef HB_OT_TABLE
+
+struct hb_ot_face_data_t
+{
+ HB_INTERNAL void init0 (hb_face_t *face);
+ HB_INTERNAL void fini (void);
+
+#define HB_OT_TABLE_ORDER(Namespace, Type) \
+ HB_PASTE (ORDER_, HB_PASTE (Namespace, HB_PASTE (_, Type)))
+ enum order_t
+ {
+ ORDER_ZERO,
+#define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER (Namespace, Type),
+#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
+ HB_OT_TABLES
+#undef HB_OT_ACCELERATOR
+#undef HB_OT_TABLE
+ };
+
+ hb_face_t *face; /* MUST be JUST before the lazy loaders. */
+#define HB_OT_TABLE(Namespace, Type) \
+ hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
+#define HB_OT_ACCELERATOR(Namespace, Type) \
+ hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
+ HB_OT_TABLES
+#undef HB_OT_ACCELERATOR
+#undef HB_OT_TABLE
+};
+
+
+HB_INTERNAL hb_ot_face_data_t *
+_hb_ot_face_data_create (hb_face_t *face);
+
+HB_INTERNAL void
+_hb_ot_face_data_destroy (hb_ot_face_data_t *data);
+
+
+#endif /* HB_OT_FACE_HH */
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 9da8fc7d4..e6df038d3 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -24,94 +24,54 @@
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb-ot.h"
-#include "hb-font-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb-font.hh"
+#include "hb-machinery.hh"
+#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
-#include "hb-ot-glyf-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-kern-table.hh"
#include "hb-ot-post-table.hh"
-
+#include "hb-ot-glyf-table.hh"
#include "hb-ot-color-cbdt-table.hh"
-struct hb_ot_font_t
-{
- inline void init (hb_face_t *face)
- {
- cmap.init (face);
- h_metrics.init (face);
- v_metrics.init (face, h_metrics.ascender - h_metrics.descender); /* TODO Can we do this lazily? */
-
- this->face = face;
- glyf.init ();
- cbdt.init ();
- post.init ();
- kern.init ();
- }
- inline void fini (void)
- {
- cmap.fini ();
- h_metrics.fini ();
- v_metrics.fini ();
-
- glyf.fini ();
- cbdt.fini ();
- post.fini ();
- kern.fini ();
- }
-
- OT::cmap::accelerator_t cmap;
- OT::hmtx::accelerator_t h_metrics;
- OT::vmtx::accelerator_t v_metrics;
-
- hb_face_t *face; /* MUST be JUST before the lazy loaders. */
- hb_face_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
- hb_face_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
- hb_face_lazy_loader_t<3, OT::post::accelerator_t> post;
- hb_face_lazy_loader_t<4, OT::kern::accelerator_t> kern;
-};
-
-
-static hb_ot_font_t *
-_hb_ot_font_create (hb_face_t *face)
-{
- hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
-
- if (unlikely (!ot_font))
- return nullptr;
-
- ot_font->init (face);
-
- return ot_font;
-}
-
-static void
-_hb_ot_font_destroy (void *data)
-{
- hb_ot_font_t *ot_font = (hb_ot_font_t *) data;
-
- ot_font->fini ();
-
- free (ot_font);
-}
-
-
static hb_bool_t
hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
+{
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ return ot_face->cmap.get ()->get_nominal_glyph (unicode, glyph);
+}
+static unsigned int
+hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ unsigned int count,
+ const hb_codepoint_t *first_unicode,
+ unsigned int unicode_stride,
+ hb_codepoint_t *first_glyph,
+ unsigned int glyph_stride,
+ void *user_data HB_UNUSED)
{
- const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return ot_font->cmap.get_nominal_glyph (unicode, glyph);
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ const OT::cmap_accelerator_t &cmap = *ot_face->cmap.get ();
+ unsigned int done;
+ for (done = 0;
+ done < count && cmap.get_nominal_glyph (*first_unicode, first_glyph);
+ done++)
+ {
+ first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
+ first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+ }
+ return done;
}
static hb_bool_t
@@ -122,39 +82,77 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
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_variation_glyph (unicode, variation_selector, glyph);
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ return ot_face->cmap.get ()->get_variation_glyph (unicode, variation_selector, glyph);
}
-static hb_position_t
-hb_ot_get_glyph_h_advance (hb_font_t *font,
- void *font_data,
- hb_codepoint_t glyph,
- void *user_data HB_UNUSED)
+static void
+hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
+ unsigned count,
+ const hb_codepoint_t *first_glyph,
+ unsigned glyph_stride,
+ hb_position_t *first_advance,
+ unsigned advance_stride,
+ 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, font));
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx.get ();
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font));
+ first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+ first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+ }
}
-static hb_position_t
-hb_ot_get_glyph_v_advance (hb_font_t *font,
- void *font_data,
- hb_codepoint_t glyph,
- void *user_data HB_UNUSED)
+static void
+hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
+ unsigned count,
+ const hb_codepoint_t *first_glyph,
+ unsigned glyph_stride,
+ hb_position_t *first_advance,
+ unsigned advance_stride,
+ void *user_data HB_UNUSED)
{
- const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get ();
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font));
+ first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
+ first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
+ }
}
-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)
+static hb_bool_t
+hb_ot_get_glyph_v_origin (hb_font_t *font,
+ void *font_data,
+ hb_codepoint_t glyph,
+ hb_position_t *x,
+ hb_position_t *y,
+ 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->kern->get_h_kerning (left_glyph, right_glyph));
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+
+ *x = font->get_glyph_h_advance (glyph) / 2;
+
+ hb_glyph_extents_t extents = {0};
+ bool ret = ot_face->glyf->get_extents (glyph, &extents);
+ if (ret)
+ {
+ const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get ();
+ hb_position_t tsb = vmtx.get_side_bearing (glyph);
+ *y = font->em_scale_y (extents.y_bearing + tsb);
+ return true;
+ }
+
+ hb_font_extents_t font_extents;
+ font->get_h_extents_with_fallback (&font_extents);
+ *y = font_extents.ascender;
+
+ return true;
}
static hb_bool_t
@@ -164,10 +162,10 @@ hb_ot_get_glyph_extents (hb_font_t *font,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
- const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- bool ret = ot_font->glyf->get_extents (glyph, extents);
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ bool ret = ot_face->glyf->get_extents (glyph, extents);
if (!ret)
- ret = ot_font->cbdt->get_extents (glyph, extents);
+ ret = ot_face->CBDT->get_extents (glyph, extents);
// TODO Hook up side-bearings variations.
extents->x_bearing = font->em_scale_x (extents->x_bearing);
extents->y_bearing = font->em_scale_y (extents->y_bearing);
@@ -183,8 +181,8 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
- const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- return ot_font->post->get_glyph_name (glyph, name, size);
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ return ot_face->post->get_glyph_name (glyph, name, size);
}
static hb_bool_t
@@ -194,8 +192,8 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
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->post->get_glyph_from_name (name, len, glyph);
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ return ot_face->post->get_glyph_from_name (name, len, glyph);
}
static hb_bool_t
@@ -204,12 +202,13 @@ hb_ot_get_font_h_extents (hb_font_t *font,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
- const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
- metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
- metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx.get ();
+ metrics->ascender = font->em_scale_y (hmtx.ascender);
+ metrics->descender = font->em_scale_y (hmtx.descender);
+ metrics->line_gap = font->em_scale_y (hmtx.line_gap);
// TODO Hook up variations.
- return ot_font->h_metrics.has_font_extents;
+ return hmtx.has_font_extents;
}
static hb_bool_t
@@ -218,16 +217,18 @@ hb_ot_get_font_v_extents (hb_font_t *font,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
- const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
- metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
- metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
- metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
+ const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
+ const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx.get ();
+ metrics->ascender = font->em_scale_x (vmtx.ascender);
+ metrics->descender = font->em_scale_x (vmtx.descender);
+ metrics->line_gap = font->em_scale_x (vmtx.line_gap);
// TODO Hook up variations.
- return ot_font->v_metrics.has_font_extents;
+ return vmtx.has_font_extents;
}
-
+#ifdef HB_USE_ATEXIT
static void free_static_ot_funcs (void);
+#endif
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
{
@@ -238,13 +239,12 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
- //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr);
- //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
//hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
@@ -283,12 +283,11 @@ _hb_ot_get_font_funcs (void)
void
hb_ot_font_set_funcs (hb_font_t *font)
{
- hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
- if (unlikely (!ot_font))
- return;
+ if (unlikely (!hb_ot_shaper_face_data_ensure (font->face))) return;
+ hb_ot_face_data_t *ot_face = hb_ot_face_data (font->face);
hb_font_set_funcs (font,
_hb_ot_get_font_funcs (),
- ot_font,
- _hb_ot_font_destroy);
+ ot_face,
+ nullptr);
}
diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh
index bcf89e462..2145ac02b 100644
--- a/src/hb-ot-glyf-table.hh
+++ b/src/hb-ot-glyf-table.hh
@@ -27,11 +27,9 @@
#ifndef HB_OT_GLYF_TABLE_HH
#define HB_OT_GLYF_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
#include "hb-ot-head-table.hh"
#include "hb-subset-glyf.hh"
-#include "hb-subset-plan.hh"
-#include "hb-subset-private.hh"
namespace OT {
@@ -56,7 +54,7 @@ struct loca
}
protected:
- HBUINT8 dataZ[VAR]; /* Location data. */
+ UnsizedArrayOf<HBUINT8> dataZ; /* Location data. */
DEFINE_SIZE_ARRAY (0, dataZ);
};
@@ -377,13 +375,13 @@ struct glyf
if (short_offset)
{
- const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ;
+ const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ;
*start_offset = 2 * offsets[glyph];
*end_offset = 2 * offsets[glyph + 1];
}
else
{
- const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ;
+ const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ;
*start_offset = offsets[glyph];
*end_offset = offsets[glyph + 1];
@@ -420,7 +418,7 @@ struct glyf
} while (composite_it.move_to_next());
if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS)
- *instruction_start = ((char *) last - (char *) glyf_table->dataZ) + last->get_size();
+ *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size();
else
*instruction_start = end_offset;
*instruction_end = end_offset;
@@ -485,11 +483,13 @@ struct glyf
};
protected:
- HBUINT8 dataZ[VAR]; /* Glyphs data. */
+ UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */
DEFINE_SIZE_ARRAY (0, dataZ);
};
+struct glyf_accelerator_t : glyf::accelerator_t {};
+
} /* namespace OT */
diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh
index 0951871ce..04511b5d0 100644
--- a/src/hb-ot-hdmx-table.hh
+++ b/src/hb-ot-hdmx-table.hh
@@ -27,8 +27,7 @@
#ifndef HB_OT_HDMX_TABLE_HH
#define HB_OT_HDMX_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-subset-plan.hh"
+#include "hb-open-type.hh"
/*
* hdmx -- Horizontal Device Metrics
@@ -67,7 +66,7 @@ struct DeviceRecord
if (unlikely (i >= len())) return nullptr;
hb_codepoint_t gid = this->subset_plan->glyphs [i];
- const HBUINT8* width = &(this->source_device_record->widths[gid]);
+ const HBUINT8* width = &(this->source_device_record->widthsZ[gid]);
if (width < ((const HBUINT8 *) this->source_device_record) + size_device_record)
return width;
@@ -78,19 +77,20 @@ struct DeviceRecord
static inline unsigned int get_size (unsigned int count)
{
- unsigned int raw_size = min_size + count * HBUINT8::static_size;
- if (raw_size % 4)
- /* Align to 32 bits */
- return raw_size + (4 - (raw_size % 4));
- return raw_size;
+ return hb_ceil_to_4 (min_size + count * HBUINT8::static_size);
}
inline bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
{
TRACE_SERIALIZE (this);
- if (unlikely (!c->allocate_size<DeviceRecord> (get_size (subset_view.len()))))
+ unsigned int size = get_size (subset_view.len());
+ if (unlikely (!c->allocate_size<DeviceRecord> (size)))
+ {
+ DEBUG_MSG (SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
+ size);
return_trace (false);
+ }
this->pixel_size.set (subset_view.source_device_record->pixel_size);
this->max_width.set (subset_view.source_device_record->max_width);
@@ -103,7 +103,7 @@ struct DeviceRecord
DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
return_trace (false);
}
- widths[i].set (*width);
+ widthsZ[i].set (*width);
}
return_trace (true);
@@ -116,11 +116,11 @@ struct DeviceRecord
c->check_range (this, size_device_record)));
}
- HBUINT8 pixel_size; /* Pixel size for following widths (as ppem). */
- HBUINT8 max_width; /* Maximum width. */
- HBUINT8 widths[VAR]; /* Array of widths (numGlyphs is from the 'maxp' table). */
+ HBUINT8 pixel_size; /* Pixel size for following widths (as ppem). */
+ HBUINT8 max_width; /* Maximum width. */
+ UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
public:
- DEFINE_SIZE_ARRAY (2, widths);
+ DEFINE_SIZE_ARRAY (2, widthsZ);
};
@@ -136,7 +136,7 @@ struct hdmx
inline const DeviceRecord& operator [] (unsigned int i) const
{
if (unlikely (i >= num_records)) return Null(DeviceRecord);
- return StructAtOffset<DeviceRecord> (this->data, i * size_device_record);
+ return StructAtOffset<DeviceRecord> (&this->dataZ, i * size_device_record);
}
inline bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
@@ -161,14 +161,14 @@ struct hdmx
return_trace (true);
}
- static inline size_t get_subsetted_size (hb_subset_plan_t *plan)
+ static inline size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
{
- return min_size + DeviceRecord::get_size (plan->glyphs.len);
+ return min_size + source_hdmx->num_records * DeviceRecord::get_size (plan->glyphs.len);
}
inline bool subset (hb_subset_plan_t *plan) const
{
- size_t dest_size = get_subsetted_size (plan);
+ size_t dest_size = get_subsetted_size (this, plan);
hdmx *dest = (hdmx *) malloc (dest_size);
if (unlikely (!dest))
{
@@ -178,8 +178,10 @@ struct hdmx
hb_serialize_context_t c (dest, dest_size);
hdmx *hdmx_prime = c.start_serialize<hdmx> ();
- if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) {
+ if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
+ {
free (dest);
+ DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
return false;
}
c.end_serialize ();
@@ -205,12 +207,12 @@ struct hdmx
}
protected:
- HBUINT16 version; /* Table version number (0) */
- HBUINT16 num_records; /* Number of device records. */
- HBUINT32 size_device_record; /* Size of a device record, 32-bit aligned. */
- HBUINT8 data[VAR]; /* Array of device records. */
+ HBUINT16 version; /* Table version number (0) */
+ HBUINT16 num_records; /* Number of device records. */
+ HBUINT32 size_device_record; /* Size of a device record, 32-bit aligned. */
+ UnsizedArrayOf<HBUINT8> dataZ; /* Array of device records. */
public:
- DEFINE_SIZE_ARRAY (8, data);
+ DEFINE_SIZE_ARRAY (8, dataZ);
};
} /* namespace OT */
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index fded120be..602e365ce 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -29,7 +29,7 @@
#ifndef HB_OT_HEAD_TABLE_HH
#define HB_OT_HEAD_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* head -- Font Header
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index efb42b616..3336cadd4 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_HHEA_TABLE_HH
#define HB_OT_HHEA_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* hhea -- Horizontal Header
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 13fa9d6e0..5293fdada 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -27,11 +27,10 @@
#ifndef HB_OT_HMTX_TABLE_HH
#define HB_OT_HMTX_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-var-hvar-table.hh"
-#include "hb-subset-plan.hh"
/*
* hmtx -- Horizontal Metrics
@@ -49,7 +48,7 @@ namespace OT {
struct LongMetric
{
UFWORD advance; /* Advance width/height. */
- FWORD lsb; /* Leading (left/top) side bearing. */
+ FWORD sb; /* Leading (left/top) side bearing. */
public:
DEFINE_SIZE_STATIC (4);
};
@@ -135,8 +134,8 @@ struct hmtxvmtx
}
else
{
- /* dest just lsb */
- *((FWORD *) dest_pos) = src_metric->lsb;
+ /* dest just sb */
+ *((FWORD *) dest_pos) = src_metric->sb;
}
}
else
@@ -148,18 +147,18 @@ struct hmtxvmtx
failed = true;
break;
}
- FWORD src_lsb = *(lsbs + gids[i] - _mtx.num_advances);
+ FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances);
if (i < num_advances)
{
/* dest needs a full LongMetric */
LongMetric *metric = (LongMetric *)dest_pos;
metric->advance = src_metric->advance;
- metric->lsb = src_lsb;
+ metric->sb = src_sb;
}
else
{
- /* dest just needs an lsb */
- *((FWORD *) dest_pos) = src_lsb;
+ /* dest just needs an sb */
+ *((FWORD *) dest_pos) = src_sb;
}
}
dest_pos += (i < num_advances ? 4 : 2);
@@ -250,20 +249,33 @@ struct hmtxvmtx
hb_blob_destroy (var_blob);
}
- inline unsigned int get_advance (hb_codepoint_t glyph) const
+ /* TODO Add variations version. */
+ inline unsigned int get_side_bearing (hb_codepoint_t glyph) const
+ {
+ if (glyph < num_advances)
+ return table->longMetricZ[glyph].sb;
+
+ if (unlikely (glyph > num_metrics))
+ return 0;
+
+ const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances];
+ return bearings[glyph - num_advances];
+ }
+
+ inline unsigned int get_advance (hb_codepoint_t glyph) const
{
if (unlikely (glyph >= num_metrics))
{
- /* If num_metrics is zero, it means we don't have the metrics table
- * for this direction: return default advance. Otherwise, it means that the
- * glyph index is out of bound: return zero. */
- if (num_metrics)
- return 0;
- else
- return default_advance;
+ /* If num_metrics is zero, it means we don't have the metrics table
+ * for this direction: return default advance. Otherwise, it means that the
+ * glyph index is out of bound: return zero. */
+ if (num_metrics)
+ return 0;
+ else
+ return default_advance;
}
- return table->longMetric[MIN (glyph, (uint32_t) num_advances - 1)].advance;
+ return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance;
}
inline unsigned int get_advance (hb_codepoint_t glyph,
@@ -272,7 +284,7 @@ struct hmtxvmtx
unsigned int advance = get_advance (glyph);
if (likely(glyph < num_metrics))
{
- advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?!
+ advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?!
}
return advance;
}
@@ -296,7 +308,7 @@ struct hmtxvmtx
};
protected:
- LongMetric longMetric[VAR]; /* Paired advance width and leading
+ UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading
* bearing values for each glyph. The
* value numOfHMetrics comes from
* the 'hhea' table. If the font is
@@ -304,7 +316,7 @@ struct hmtxvmtx
* be in the array, but that entry is
* required. The last entry applies to
* all subsequent glyphs. */
-/*FWORD leadingBearingX[VAR];*/ /* Here the advance is assumed
+/*UnsizedArrayOf<FWORD> leadingBearingX;*//* 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
@@ -318,7 +330,7 @@ struct hmtxvmtx
* font to vary the side bearing
* values for each glyph. */
public:
- DEFINE_SIZE_ARRAY (0, longMetric);
+ DEFINE_SIZE_ARRAY (0, longMetricZ);
};
struct hmtx : hmtxvmtx<hmtx, hhea> {
@@ -332,6 +344,9 @@ struct vmtx : hmtxvmtx<vmtx, vhea> {
static const hb_tag_t os2Tag = HB_TAG_NONE;
};
+struct hmtx_accelerator_t : hmtx::accelerator_t {};
+struct vmtx_accelerator_t : vmtx::accelerator_t {};
+
} /* namespace OT */
diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh
index b4d810952..63551d313 100644
--- a/src/hb-ot-kern-table.hh
+++ b/src/hb-ot-kern-table.hh
@@ -27,7 +27,89 @@
#ifndef HB_OT_KERN_TABLE_HH
#define HB_OT_KERN_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
+#include "hb-ot-shape.hh"
+#include "hb-ot-layout-gsubgpos.hh"
+
+
+template <typename Driver>
+struct hb_kern_machine_t
+{
+ hb_kern_machine_t (const Driver &driver_) : driver (driver_) {}
+
+ HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW
+ inline void kern (hb_font_t *font,
+ hb_buffer_t *buffer,
+ hb_mask_t kern_mask,
+ bool scale = true) const
+ {
+ OT::hb_ot_apply_context_t c (1, font, buffer);
+ c.set_lookup_mask (kern_mask);
+ c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
+ OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
+ skippy_iter.init (&c);
+
+ bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
+ 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;)
+ {
+ if (!(info[idx].mask & kern_mask))
+ {
+ idx++;
+ continue;
+ }
+
+ skippy_iter.reset (idx, 1);
+ if (!skippy_iter.next ())
+ {
+ idx++;
+ continue;
+ }
+
+ unsigned int i = idx;
+ unsigned int j = skippy_iter.idx;
+
+ hb_position_t kern = driver.get_kerning (info[i].codepoint,
+ info[j].codepoint);
+
+
+ if (likely (!kern))
+ goto skip;
+
+
+ if (horizontal)
+ {
+ if (scale)
+ kern = font->em_scale_x (kern);
+ hb_position_t kern1 = kern >> 1;
+ hb_position_t kern2 = kern - kern1;
+ pos[i].x_advance += kern1;
+ pos[j].x_advance += kern2;
+ pos[j].x_offset += kern2;
+ }
+ else
+ {
+ if (scale)
+ kern = font->em_scale_y (kern);
+ hb_position_t kern1 = kern >> 1;
+ hb_position_t kern2 = kern - kern1;
+ pos[i].y_advance += kern1;
+ pos[j].y_advance += kern2;
+ pos[j].y_offset += kern2;
+ }
+
+ buffer->unsafe_to_break (i, j + 1);
+
+ skip:
+ idx = skippy_iter.idx;
+ }
+ }
+
+ const Driver &driver;
+};
+
/*
* kern -- Kerning
@@ -116,14 +198,18 @@ struct KernSubTableFormat2
{
inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
{
+ /* This subtable is disabled. It's not cleaer to me *exactly* where the offests are
+ * based from. I *think* they should be based from beginning of kern subtable wrapper,
+ * *NOT* "this". Since we know of no fonts that use this subtable, we are disabling
+ * it. Someday fix it and re-enable. Better yet, find fonts that use it... Meh,
+ * Windows doesn't implement it. Maybe just remove... */
+ return 0;
unsigned int l = (this+leftClassTable).get_class (left);
unsigned int r = (this+rightClassTable).get_class (right);
- unsigned int offset = l * rowWidth + r * sizeof (FWORD);
- const FWORD *arr = &(this+array);
- if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
- return 0;
- const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
- if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
+ unsigned int offset = l + r;
+ const FWORD *v = &StructAtOffset<FWORD> (&(this+array), offset);
+ if (unlikely ((const char *) v < (const char *) &array ||
+ (const char *) v > (const char *) end - 2))
return 0;
return *v;
}
@@ -131,6 +217,7 @@ struct KernSubTableFormat2
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
+ return_trace (true); /* Disabled. See above. */
return_trace (rowWidth.sanitize (c) &&
leftClassTable.sanitize (c, this) &&
rightClassTable.sanitize (c, this) &&
@@ -190,10 +277,10 @@ struct KernSubTableWrapper
inline const T* thiz (void) const { return static_cast<const T *> (this); }
inline bool is_horizontal (void) const
- { return (thiz()->coverage & T::COVERAGE_CHECK_FLAGS) == T::COVERAGE_CHECK_HORIZONTAL; }
+ { return (thiz()->coverage & T::CheckFlags) == T::CheckHorizontal; }
inline bool is_override (void) const
- { return bool (thiz()->coverage & T::COVERAGE_OVERRIDE_FLAG); }
+ { return bool (thiz()->coverage & T::Override); }
inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
{ return thiz()->subtable.get_kerning (left, right, end, thiz()->format); }
@@ -208,7 +295,7 @@ struct KernSubTableWrapper
TRACE_SANITIZE (this);
return_trace (c->check_struct (thiz()) &&
thiz()->length >= T::min_size &&
- c->check_array (thiz(), 1, thiz()->length) &&
+ c->check_range (thiz(), thiz()->length) &&
thiz()->subtable.sanitize (c, thiz()->format));
}
};
@@ -219,16 +306,16 @@ struct KernTable
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
inline const T* thiz (void) const { return static_cast<const T *> (this); }
- inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
+ inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
int v = 0;
- const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
+ const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
unsigned int count = thiz()->nTables;
for (unsigned int i = 0; i < count; i++)
{
if (st->is_override ())
v = 0;
- v += st->get_h_kerning (left, right, table_length + (const char *) this);
+ v += st->get_h_kerning (left, right, st->length + (const char *) st);
st = &StructAfter<typename T::SubTableWrapper> (*st);
}
return v;
@@ -241,7 +328,7 @@ struct KernTable
thiz()->version != T::VERSION))
return_trace (false);
- const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (thiz()->data);
+ const typename T::SubTableWrapper *st = CastP<typename T::SubTableWrapper> (&thiz()->dataZ);
unsigned int count = thiz()->nTables;
for (unsigned int i = 0; i < count; i++)
{
@@ -262,18 +349,20 @@ struct KernOT : KernTable<KernOT>
struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
{
+ friend struct KernTable<KernOT>;
friend struct KernSubTableWrapper<SubTableWrapper>;
- enum coverage_flags_t {
- COVERAGE_DIRECTION_FLAG = 0x01u,
- COVERAGE_MINIMUM_FLAG = 0x02u,
- COVERAGE_CROSSSTREAM_FLAG = 0x04u,
- COVERAGE_OVERRIDE_FLAG = 0x08u,
+ enum Coverage
+ {
+ Direction = 0x01u,
+ Minimum = 0x02u,
+ CrossStream = 0x04u,
+ Override = 0x08u,
- COVERAGE_VARIATION_FLAG = 0x00u, /* Not supported. */
+ Variation = 0x00u, /* Not supported. */
- COVERAGE_CHECK_FLAGS = 0x07u,
- COVERAGE_CHECK_HORIZONTAL = 0x01u
+ CheckFlags = 0x07u,
+ CheckHorizontal = 0x01u
};
protected:
@@ -287,11 +376,11 @@ struct KernOT : KernTable<KernOT>
};
protected:
- HBUINT16 version; /* Version--0x0000u */
- HBUINT16 nTables; /* Number of subtables in the kerning table. */
- HBUINT8 data[VAR];
+ HBUINT16 version; /* Version--0x0000u */
+ HBUINT16 nTables; /* Number of subtables in the kerning table. */
+ UnsizedArrayOf<HBUINT8> dataZ;
public:
- DEFINE_SIZE_ARRAY (4, data);
+ DEFINE_SIZE_ARRAY (4, dataZ);
};
struct KernAAT : KernTable<KernAAT>
@@ -302,17 +391,19 @@ struct KernAAT : KernTable<KernAAT>
struct SubTableWrapper : KernSubTableWrapper<SubTableWrapper>
{
+ friend struct KernTable<KernAAT>;
friend struct KernSubTableWrapper<SubTableWrapper>;
- enum coverage_flags_t {
- COVERAGE_DIRECTION_FLAG = 0x80u,
- COVERAGE_CROSSSTREAM_FLAG = 0x40u,
- COVERAGE_VARIATION_FLAG = 0x20u,
+ enum Coverage
+ {
+ Direction = 0x80u,
+ CrossStream = 0x40u,
+ Variation = 0x20u,
- COVERAGE_OVERRIDE_FLAG = 0x00u, /* Not supported. */
+ Override = 0x00u, /* Not supported. */
- COVERAGE_CHECK_FLAGS = 0xE0u,
- COVERAGE_CHECK_HORIZONTAL = 0x00u
+ CheckFlags = 0xE0u,
+ CheckHorizontal = 0x00u
};
protected:
@@ -327,22 +418,25 @@ struct KernAAT : KernTable<KernAAT>
};
protected:
- HBUINT32 version; /* Version--0x00010000u */
- HBUINT32 nTables; /* Number of subtables in the kerning table. */
- HBUINT8 data[VAR];
+ HBUINT32 version; /* Version--0x00010000u */
+ HBUINT32 nTables; /* Number of subtables in the kerning table. */
+ UnsizedArrayOf<HBUINT8> dataZ;
public:
- DEFINE_SIZE_ARRAY (8, data);
+ DEFINE_SIZE_ARRAY (8, dataZ);
};
struct kern
{
static const hb_tag_t tableTag = HB_OT_TAG_kern;
- inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
+ inline bool has_data (void) const
+ { return u.version32 != 0; }
+
+ inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
switch (u.major) {
- case 0: return u.ot.get_h_kerning (left, right, table_length);
- case 1: return u.aat.get_h_kerning (left, right, table_length);
+ case 0: return u.ot.get_h_kerning (left, right);
+ case 1: return u.aat.get_h_kerning (left, right);
default:return 0;
}
}
@@ -350,7 +444,7 @@ struct kern
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!u.major.sanitize (c)) return_trace (false);
+ if (!u.version32.sanitize (c)) return_trace (false);
switch (u.major) {
case 0: return_trace (u.ot.sanitize (c));
case 1: return_trace (u.aat.sanitize (c));
@@ -364,32 +458,52 @@ struct kern
{
blob = hb_sanitize_context_t().reference_table<kern> (face);
table = blob->as<kern> ();
- table_length = blob->length;
}
inline void fini (void)
{
hb_blob_destroy (blob);
}
+ inline bool has_data (void) const
+ { return table->has_data (); }
+
inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
- { return table->get_h_kerning (left, right, table_length); }
+ { return table->get_h_kerning (left, right); }
+
+ inline int get_kerning (hb_codepoint_t first, hb_codepoint_t second) const
+ { return get_h_kerning (first, second); }
+
+ inline void apply (hb_font_t *font,
+ hb_buffer_t *buffer,
+ hb_mask_t kern_mask) const
+ {
+ /* We only apply horizontal kerning in this table. */
+ if (!HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+ return;
+
+ hb_kern_machine_t<accelerator_t> machine (*this);
+
+ machine.kern (font, buffer, kern_mask);
+ }
private:
hb_blob_t *blob;
const kern *table;
- unsigned int table_length;
};
protected:
union {
+ HBUINT32 version32;
HBUINT16 major;
KernOT ot;
KernAAT aat;
} u;
public:
- DEFINE_SIZE_UNION (2, major);
+ DEFINE_SIZE_UNION (4, version32);
};
+struct kern_accelerator_t : kern::accelerator_t {};
+
} /* namespace OT */
diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh
index 96da07fb5..449e74550 100644
--- a/src/hb-ot-layout-base-table.hh
+++ b/src/hb-ot-layout-base-table.hh
@@ -28,8 +28,8 @@
#ifndef HB_OT_LAYOUT_BASE_TABLE_HH
#define HB_OT_LAYOUT_BASE_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-ot-layout-common-private.hh"
+#include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
namespace OT {
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common.hh
index 89d5eae49..98f6a079f 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common.hh
@@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_LAYOUT_COMMON_PRIVATE_HH
-#define HB_OT_LAYOUT_COMMON_PRIVATE_HH
+#ifndef HB_OT_LAYOUT_COMMON_HH
+#define HB_OT_LAYOUT_COMMON_HH
-#include "hb-private.hh"
-#include "hb-ot-layout-private.hh"
-#include "hb-open-type-private.hh"
-#include "hb-set-private.hh"
+#include "hb.hh"
+#include "hb-ot-layout.hh"
+#include "hb-open-type.hh"
+#include "hb-set.hh"
#ifndef HB_MAX_NESTING_LEVEL
@@ -70,6 +70,11 @@ namespace OT {
* Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
*/
+struct Record_sanitize_closure_t {
+ hb_tag_t tag;
+ const void *list_base;
+};
+
template <typename Type>
struct Record
{
@@ -77,14 +82,10 @@ struct Record
return tag.cmp (a);
}
- 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};
+ const Record_sanitize_closure_t closure = {tag, base};
return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
}
@@ -97,15 +98,14 @@ struct Record
};
template <typename Type>
-struct RecordArrayOf : SortedArrayOf<Record<Type> > {
+struct RecordArrayOf : SortedArrayOf<Record<Type> >
+{
+ inline const OffsetTo<Type>& get_offset (unsigned int i) const
+ { return (*this)[i].offset; }
+ inline OffsetTo<Type>& get_offset (unsigned int i)
+ { return (*this)[i].offset; }
inline const Tag& get_tag (unsigned int i) const
- {
- /* We cheat slightly and don't define separate Null objects
- * for Record types. Instead, we return the correct Null(Tag)
- * here. */
- if (unlikely (i >= this->len)) return Null(Tag);
- return (*this)[i].tag;
- }
+ { return (*this)[i].tag; }
inline unsigned int get_tags (unsigned int start_offset,
unsigned int *record_count /* IN/OUT */,
hb_tag_t *record_tags /* OUT */) const
@@ -136,7 +136,18 @@ template <typename Type>
struct RecordListOf : RecordArrayOf<Type>
{
inline const Type& operator [] (unsigned int i) const
- { return this+RecordArrayOf<Type>::operator [](i).offset; }
+ { return this+this->get_offset (i); }
+
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ struct RecordListOf<Type> *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ unsigned int count = this->len;
+ for (unsigned int i = 0; i < count; i++)
+ out->get_offset (i).serialize_subset (c, (*this)[i], out);
+ return_trace (true);
+ }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -158,9 +169,8 @@ struct RangeRecord
return_trace (c->check_struct (this));
}
- inline bool intersects (const hb_set_t *glyphs) const {
- return glyphs->intersects (start, end);
- }
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return glyphs->intersects (start, end); }
template <typename set_t>
inline bool add_coverage (set_t *glyphs) const {
@@ -224,8 +234,14 @@ struct LangSys
return reqFeatureIndex;;
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ return_trace (c->serializer->embed (*this));
+ }
+
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<LangSys>::sanitize_closure_t * = nullptr) const
+ const Record_sanitize_closure_t * = nullptr) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && featureIndex.sanitize (c));
@@ -238,7 +254,7 @@ struct LangSys
* = 0xFFFFu */
IndexArray featureIndex; /* Array of indices into the FeatureList */
public:
- DEFINE_SIZE_ARRAY (6, featureIndex);
+ DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
};
DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
@@ -263,8 +279,20 @@ 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 subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ struct Script *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out);
+ unsigned int count = langSys.len;
+ for (unsigned int i = 0; i < count; i++)
+ out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out);
+ return_trace (true);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<Script>::sanitize_closure_t * = nullptr) const
+ const Record_sanitize_closure_t * = nullptr) const
{
TRACE_SANITIZE (this);
return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
@@ -278,7 +306,7 @@ struct Script
langSys; /* Array of LangSysRecords--listed
* alphabetically by LangSysTag */
public:
- DEFINE_SIZE_ARRAY (4, langSys);
+ DEFINE_SIZE_ARRAY_SIZED (4, langSys);
};
typedef RecordListOf<Script> ScriptList;
@@ -372,7 +400,7 @@ struct FeatureParamsSize
* same subfamily value. If this value is
* zero, the remaining fields in the array
* will be ignored. */
- HBUINT16 subfamilyNameID;/* If the preceding value is non-zero, this
+ NameID subfamilyNameID;/* If the preceding value is non-zero, this
* value must be set in the range 256 - 32767
* (inclusive). It records the value of a
* field in the name table, which must
@@ -445,7 +473,7 @@ struct FeatureParamsCharacterVariants
* specifies a string (or strings,
* for multiple languages) for a
* user-interface label for this
- * feature. (May be nullptr.) */
+ * feature. (May be NULL.) */
NameID featUITooltipTextNameID;/* The ‘name’ table name ID that
* specifies a string (or strings,
* for multiple languages) that an
@@ -455,7 +483,7 @@ struct FeatureParamsCharacterVariants
NameID sampleTextNameID; /* The ‘name’ table name ID that
* specifies sample text that
* illustrates the effect of this
- * feature. (May be nullptr.) */
+ * feature. (May be NULL.) */
HBUINT16 numNamedParameters; /* Number of named parameters. (May
* be zero.) */
NameID firstParamUILabelNameID;/* The first ‘name’ table name ID
@@ -493,12 +521,27 @@ struct FeatureParams
return Null(FeatureParamsSize);
}
+ inline const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const
+ {
+ if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+ return u.stylisticSet;
+ return Null(FeatureParamsStylisticSet);
+ }
+
+ inline const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const
+ {
+ if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+ return u.characterVariants;
+ return Null(FeatureParamsCharacterVariants);
+ }
+
private:
union {
FeatureParamsSize size;
FeatureParamsStylisticSet stylisticSet;
FeatureParamsCharacterVariants characterVariants;
} u;
+ public:
DEFINE_SIZE_STATIC (17);
};
@@ -516,8 +559,17 @@ struct Feature
inline const FeatureParams &get_feature_params (void) const
{ return this+featureParams; }
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ struct Feature *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ out->featureParams.set (0); /* TODO(subset) FeatureParams. */
+ return_trace (true);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<Feature>::sanitize_closure_t *closure = nullptr) const
+ const Record_sanitize_closure_t *closure = nullptr) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
@@ -567,7 +619,7 @@ struct Feature
* if not required */
IndexArray lookupIndex; /* Array of LookupList indices */
public:
- DEFINE_SIZE_ARRAY (4, lookupIndex);
+ DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
};
typedef RecordListOf<Feature> FeatureList;
@@ -598,16 +650,16 @@ 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 TSubTable>
+ inline const TSubTable& get_subtable (unsigned int i) const
+ { return this+CastR<OffsetArrayOf<TSubTable> > (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); }
+ template <typename TSubTable>
+ inline const OffsetArrayOf<TSubTable>& get_subtables (void) const
+ { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
+ template <typename TSubTable>
+ inline OffsetArrayOf<TSubTable>& get_subtables (void)
+ { return CastR<OffsetArrayOf<TSubTable> > (subTable); }
inline unsigned int get_size (void) const
{
@@ -633,14 +685,14 @@ struct Lookup
return flag;
}
- template <typename SubTableType, typename context_t>
+ template <typename TSubTable, 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);
+ typename context_t::return_t r = get_subtable<TSubTable> (i).dispatch (c, lookup_type);
if (c->stop_sublookup_iteration (r))
return_trace (r);
}
@@ -666,16 +718,72 @@ struct Lookup
return_trace (true);
}
+ /* Older compilers need this to NOT be locally defined in a function. */
+ template <typename TSubTable>
+ struct SubTableSubsetWrapper
+ {
+ inline SubTableSubsetWrapper (const TSubTable &subtable_,
+ unsigned int lookup_type_) :
+ subtable (subtable_),
+ lookup_type (lookup_type_) {}
+
+ inline bool subset (hb_subset_context_t *c) const
+ { return subtable.dispatch (c, lookup_type); }
+
+ private:
+ const TSubTable &subtable;
+ unsigned int lookup_type;
+ };
+
+ template <typename TSubTable>
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ struct Lookup *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ /* Subset the actual subtables. */
+ /* TODO Drop empty ones, either by calling intersects() beforehand,
+ * or just dropping null offsets after. */
+ const OffsetArrayOf<TSubTable>& subtables = get_subtables<TSubTable> ();
+ OffsetArrayOf<TSubTable>& out_subtables = out->get_subtables<TSubTable> ();
+ unsigned int count = subTable.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ SubTableSubsetWrapper<TSubTable> wrapper (this+subtables[i], get_type ());
+
+ out_subtables[i].serialize_subset (c, wrapper, out);
+ }
+
+ return_trace (true);
+ }
+
+ template <typename TSubTable>
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 (false);
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
if (!markFilteringSet.sanitize (c)) return_trace (false);
}
+
+ if (unlikely (!dispatch<TSubTable> (c))) return_trace (false);
+
+ if (unlikely (get_type () == TSubTable::Extension))
+ {
+ /* The spec says all subtables of an Extension lookup should
+ * have the same type, which shall not be the Extension type
+ * itself (but we already checked for that).
+ * This is specially important if one has a reverse type! */
+ unsigned int type = get_subtable<TSubTable> (0).u.extension.get_type ();
+ unsigned int count = get_subtable_count ();
+ for (unsigned int i = 1; i < count; i++)
+ if (get_subtable<TSubTable> (i).u.extension.get_type () != type)
+ return_trace (false);
+ }
+ return_trace (true);
return_trace (true);
}
@@ -730,9 +838,17 @@ struct CoverageFormat1
return_trace (glyphArray.sanitize (c));
}
- inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
- return glyphs->has (glyphArray[index]);
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ /* TODO Speed up, using hb_set_next() and bsearch()? */
+ unsigned int count = glyphArray.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (glyphs->has (glyphArray[i]))
+ return true;
+ return false;
}
+ inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+ { return glyphs->has (glyphArray[index]); }
template <typename set_t>
inline bool add_coverage (set_t *glyphs) const {
@@ -743,6 +859,7 @@ struct CoverageFormat1
/* Older compilers need this to be public. */
struct Iter {
inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
+ inline void fini (void) {};
inline bool more (void) { return i < c->glyphArray.len; }
inline void next (void) { i++; }
inline hb_codepoint_t get_glyph (void) { return c->glyphArray[i]; }
@@ -819,7 +936,17 @@ struct CoverageFormat2
return_trace (rangeRecord.sanitize (c));
}
- inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ /* TODO Speed up, using hb_set_next() and bsearch()? */
+ unsigned int count = rangeRecord.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (rangeRecord[i].intersects (glyphs))
+ return true;
+ return false;
+ }
+ inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+ {
unsigned int i;
unsigned int count = rangeRecord.len;
for (i = 0; i < count; i++) {
@@ -859,6 +986,7 @@ struct CoverageFormat2
i = c->rangeRecord.len;
}
}
+ inline void fini (void) {};
inline bool more (void) { return i < c->rangeRecord.len; }
inline void next (void)
{
@@ -924,7 +1052,8 @@ struct Coverage
if (glyphs[i - 1] + 1 != glyphs[i])
num_ranges++;
u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
- switch (u.format) {
+ switch (u.format)
+ {
case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs));
case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs));
default:return_trace (false);
@@ -935,25 +1064,27 @@ struct Coverage
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
- switch (u.format) {
+ switch (u.format)
+ {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
default:return_trace (true);
}
}
- inline bool intersects (const hb_set_t *glyphs) const {
- /* TODO speed this up */
- Coverage::Iter iter;
- for (iter.init (*this); iter.more (); iter.next ()) {
- if (glyphs->has (iter.get_glyph ()))
- return true;
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ switch (u.format)
+ {
+ case 1: return u.format1.intersects (glyphs);
+ case 2: return u.format2.intersects (glyphs);
+ default:return false;
}
- return false;
}
-
- inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
- switch (u.format) {
+ inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+ {
+ switch (u.format)
+ {
case 1: return u.format1.intersects_coverage (glyphs, index);
case 2: return u.format2.intersects_coverage (glyphs, index);
default:return false;
@@ -963,47 +1094,61 @@ struct Coverage
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>
- inline bool add_coverage (set_t *glyphs) const {
- switch (u.format) {
+ inline bool add_coverage (set_t *glyphs) const
+ {
+ switch (u.format)
+ {
case 1: return u.format1.add_coverage (glyphs);
case 2: return u.format2.add_coverage (glyphs);
default:return false;
}
}
- struct Iter {
+ struct Iter
+ {
Iter (void) : format (0), u () {};
- inline void init (const Coverage &c_) {
+ inline void init (const Coverage &c_)
+ {
format = c_.u.format;
- switch (format) {
+ switch (format)
+ {
case 1: u.format1.init (c_.u.format1); return;
case 2: u.format2.init (c_.u.format2); return;
- default: return;
+ default: return;
}
}
- inline bool more (void) {
- switch (format) {
+ inline void fini (void) {}
+ inline bool more (void)
+ {
+ switch (format)
+ {
case 1: return u.format1.more ();
case 2: return u.format2.more ();
default:return false;
}
}
- inline void next (void) {
- switch (format) {
+ inline void next (void)
+ {
+ switch (format)
+ {
case 1: u.format1.next (); break;
case 2: u.format2.next (); break;
- default: break;
+ default: break;
}
}
- inline hb_codepoint_t get_glyph (void) {
- switch (format) {
+ inline hb_codepoint_t get_glyph (void)
+ {
+ switch (format)
+ {
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
default:return 0;
}
}
- inline unsigned int get_coverage (void) {
- switch (format) {
+ inline unsigned int get_coverage (void)
+ {
+ switch (format)
+ {
case 1: return u.format1.get_coverage ();
case 2: return u.format2.get_coverage ();
default:return -1;
@@ -1085,6 +1230,17 @@ struct ClassDefFormat1
return true;
}
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ /* TODO Speed up, using hb_set_next()? */
+ hb_codepoint_t start = startGlyph;
+ hb_codepoint_t end = startGlyph + classValue.len;
+ for (hb_codepoint_t iter = startGlyph - 1;
+ hb_set_next (glyphs, &iter) && iter < end;)
+ if (classValue[iter - start])
+ return true;
+ return false;
+ }
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
unsigned int count = classValue.len;
if (klass == 0)
@@ -1135,7 +1291,8 @@ struct ClassDefFormat2
}
template <typename set_t>
- inline bool add_coverage (set_t *glyphs) const {
+ inline bool add_coverage (set_t *glyphs) const
+ {
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
if (rangeRecord[i].value)
@@ -1145,7 +1302,8 @@ struct ClassDefFormat2
}
template <typename set_t>
- inline bool add_class (set_t *glyphs, unsigned int klass) const {
+ inline bool add_class (set_t *glyphs, unsigned int klass) const
+ {
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
{
@@ -1156,7 +1314,17 @@ struct ClassDefFormat2
return true;
}
- inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ /* TODO Speed up, using hb_set_next() and bsearch()? */
+ unsigned int count = rangeRecord.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (rangeRecord[i].intersects (glyphs))
+ return true;
+ return false;
+ }
+ inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+ {
unsigned int count = rangeRecord.len;
if (klass == 0)
{
@@ -1233,6 +1401,13 @@ struct ClassDef
}
}
+ inline bool intersects (const hb_set_t *glyphs) const {
+ switch (u.format) {
+ case 1: return u.format1.intersects (glyphs);
+ case 2: return u.format2.intersects (glyphs);
+ default:return false;
+ }
+ }
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);
@@ -1300,7 +1475,7 @@ struct VarRegionAxis
struct VarRegionList
{
inline float evaluate (unsigned int region_index,
- int *coords, unsigned int coord_len) const
+ const int *coords, unsigned int coord_len) const
{
if (unlikely (region_index >= regionCount))
return 0.;
@@ -1345,7 +1520,7 @@ struct VarData
{ return itemCount * get_row_size (); }
inline float get_delta (unsigned int inner,
- int *coords, unsigned int coord_count,
+ const int *coords, unsigned int coord_count,
const VarRegionList &regions) const
{
if (unlikely (inner >= itemCount))
@@ -1383,14 +1558,14 @@ struct VarData
regionIndices.sanitize(c) &&
shortCount <= regionIndices.len &&
c->check_array (&StructAfter<HBUINT8> (regionIndices),
- get_row_size (), itemCount));
+ itemCount, get_row_size ()));
}
protected:
HBUINT16 itemCount;
HBUINT16 shortCount;
ArrayOf<HBUINT16> regionIndices;
- HBUINT8 bytesX[VAR];
+ UnsizedArrayOf<HBUINT8>bytesX;
public:
DEFINE_SIZE_ARRAY2 (6, regionIndices, bytesX);
};
@@ -1398,7 +1573,7 @@ struct VarData
struct VariationStore
{
inline float get_delta (unsigned int outer, unsigned int inner,
- int *coords, unsigned int coord_count) const
+ const int *coords, unsigned int coord_count) const
{
if (unlikely (outer >= dataSets.len))
return 0.;
@@ -1409,7 +1584,7 @@ struct VariationStore
}
inline float get_delta (unsigned int index,
- int *coords, unsigned int coord_count) const
+ const int *coords, unsigned int coord_count) const
{
unsigned int outer = index >> 16;
unsigned int inner = index & 0xFFFF;
@@ -1584,7 +1759,7 @@ struct FeatureVariationRecord
struct FeatureVariations
{
- static const unsigned int NOT_FOUND_INDEX = 0xFFFFFFFFu;
+ enum { NOT_FOUND_INDEX = 0xFFFFFFFFu };
inline bool find_index (const int *coords, unsigned int coord_len,
unsigned int *index) const
@@ -1610,6 +1785,12 @@ struct FeatureVariations
return (this+record.substitutions).find_substitute (feature_index);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ return_trace (c->serializer->embed (*this));
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1623,7 +1804,7 @@ struct FeatureVariations
LArrayOf<FeatureVariationRecord>
varRecords;
public:
- DEFINE_SIZE_ARRAY (8, varRecords);
+ DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
};
@@ -1679,7 +1860,7 @@ struct HintingDevice
unsigned int s = ppem_size - startSize;
- unsigned int byte = deltaValue[s >> (4 - f)];
+ unsigned int byte = deltaValueZ[s >> (4 - f)];
unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
@@ -1699,9 +1880,10 @@ struct HintingDevice
* 2 Signed 4-bit value, 4 values per uint16
* 3 Signed 8-bit value, 2 values per uint16
*/
- HBUINT16 deltaValue[VAR]; /* Array of compressed data */
+ UnsizedArrayOf<HBUINT16>
+ deltaValueZ; /* Array of compressed data */
public:
- DEFINE_SIZE_ARRAY (6, deltaValue);
+ DEFINE_SIZE_ARRAY (6, deltaValueZ);
};
struct VariationDevice
@@ -1803,4 +1985,4 @@ struct Device
} /* namespace OT */
-#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
+#endif /* HB_OT_LAYOUT_COMMON_HH */
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index d2b41a8ef..757090861 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -29,9 +29,9 @@
#ifndef HB_OT_LAYOUT_GDEF_TABLE_HH
#define HB_OT_LAYOUT_GDEF_TABLE_HH
-#include "hb-ot-layout-common-private.hh"
+#include "hb-ot-layout-common.hh"
-#include "hb-font-private.hh"
+#include "hb-font.hh"
namespace OT {
@@ -337,6 +337,7 @@ struct MarkGlyphSets
* https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
*/
+
struct GDEF
{
static const hb_tag_t tableTag = HB_OT_TAG_GDEF;
@@ -386,21 +387,8 @@ struct GDEF
inline const VariationStore &get_var_store (void) const
{ return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (version.sanitize (c) &&
- likely (version.major == 1) &&
- glyphClassDef.sanitize (c, this) &&
- attachList.sanitize (c, this) &&
- ligCaretList.sanitize (c, this) &&
- markAttachClassDef.sanitize (c, this) &&
- (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
- (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
- }
-
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
- * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
+ * glyph class and other bits, and high 8-bit the mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
inline unsigned int get_glyph_props (hb_codepoint_t glyph) const
{
@@ -420,6 +408,38 @@ struct GDEF
}
}
+ struct accelerator_t
+ {
+ HB_INTERNAL inline void init (hb_face_t *face);
+
+ inline void fini (void)
+ {
+ hb_blob_destroy (this->blob);
+ }
+
+ hb_blob_t *blob;
+ const GDEF *table;
+ };
+
+ inline unsigned int get_size (void) const
+ {
+ return min_size +
+ (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
+ (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (version.sanitize (c) &&
+ likely (version.major == 1) &&
+ glyphClassDef.sanitize (c, this) &&
+ attachList.sanitize (c, this) &&
+ ligCaretList.sanitize (c, this) &&
+ markAttachClassDef.sanitize (c, this) &&
+ (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+ (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+ }
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
@@ -454,6 +474,7 @@ struct GDEF
DEFINE_SIZE_MIN (12);
};
+struct GDEF_accelerator_t : GDEF::accelerator_t {};
} /* namespace OT */
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index fe34a328b..dad6c4ea9 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -29,7 +29,7 @@
#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
#define HB_OT_LAYOUT_GPOS_TABLE_HH
-#include "hb-ot-layout-gsubgpos-private.hh"
+#include "hb-ot-layout-gsubgpos.hh"
namespace OT {
@@ -199,7 +199,7 @@ struct ValueFormat : HBUINT16
TRACE_SANITIZE (this);
unsigned int len = get_len ();
- if (!c->check_array (values, get_size (), count)) return_trace (false);
+ if (!c->check_array (values, count, get_size ())) return_trace (false);
if (!has_device ()) return_trace (true);
@@ -376,7 +376,7 @@ struct AnchorMatrix
if (!c->check_struct (this)) return_trace (false);
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
- if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
+ if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
for (unsigned int i = 0; i < count; i++)
if (!matrixZ[i].sanitize (c, this)) return_trace (false);
return_trace (true);
@@ -384,8 +384,8 @@ struct AnchorMatrix
HBUINT16 rows; /* Number of rows */
protected:
- OffsetTo<Anchor>
- matrixZ[VAR]; /* Matrix of offsets to Anchor tables--
+ UnsizedArrayOf<OffsetTo<Anchor> >
+ matrixZ; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */
public:
DEFINE_SIZE_ARRAY (2, matrixZ);
@@ -459,6 +459,9 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
struct SinglePosFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -466,9 +469,7 @@ struct SinglePosFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -483,6 +484,13 @@ struct SinglePosFormat1
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -507,6 +515,9 @@ struct SinglePosFormat1
struct SinglePosFormat2
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -514,9 +525,7 @@ struct SinglePosFormat2
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -535,6 +544,13 @@ struct SinglePosFormat2
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -598,6 +614,24 @@ struct PairSet
{
friend struct PairPosFormat1;
+ inline bool intersects (const hb_set_t *glyphs,
+ const ValueFormat *valueFormats) const
+ {
+ unsigned int len1 = valueFormats[0].get_len ();
+ unsigned int len2 = valueFormats[1].get_len ();
+ unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+ const PairValueRecord *record = &firstPairValueRecord;
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (glyphs->has (record->secondGlyph))
+ return true;
+ record = &StructAtOffset<const PairValueRecord> (record, record_size);
+ }
+ return false;
+ }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c,
const ValueFormat *valueFormats) const
{
@@ -606,7 +640,7 @@ struct PairSet
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
- const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+ const PairValueRecord *record = &firstPairValueRecord;
c->input->add_array (&record->secondGlyph, len, record_size);
}
@@ -620,7 +654,6 @@ struct PairSet
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
- const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
unsigned int count = len;
/* Hand-coded bsearch. */
@@ -631,7 +664,7 @@ struct PairSet
while (min <= max)
{
int mid = (min + max) / 2;
- const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
+ const PairValueRecord *record = &StructAtOffset<PairValueRecord> (&firstPairValueRecord, record_size * mid);
hb_codepoint_t mid_x = record->secondGlyph;
if (x < mid_x)
max = mid - 1;
@@ -652,7 +685,8 @@ struct PairSet
return_trace (false);
}
- struct sanitize_closure_t {
+ struct sanitize_closure_t
+ {
const void *base;
const ValueFormat *valueFormats;
unsigned int len1; /* valueFormats[0].get_len() */
@@ -663,24 +697,39 @@ struct PairSet
{
TRACE_SANITIZE (this);
if (!(c->check_struct (this)
- && c->check_array (arrayZ, HBUINT16::static_size * closure->stride, len))) return_trace (false);
+ && c->check_array (&firstPairValueRecord, len, HBUINT16::static_size * closure->stride))) return_trace (false);
unsigned int count = len;
- const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+ const PairValueRecord *record = &firstPairValueRecord;
return_trace (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));
}
protected:
- HBUINT16 len; /* Number of PairValueRecords */
- HBUINT16 arrayZ[VAR]; /* Array of PairValueRecords--ordered
- * by GlyphID of the second glyph */
+ HBUINT16 len; /* Number of PairValueRecords */
+ PairValueRecord firstPairValueRecord;
+ /* Array of PairValueRecords--ordered
+ * by GlyphID of the second glyph */
public:
- DEFINE_SIZE_ARRAY (2, arrayZ);
+ DEFINE_SIZE_MIN (2);
};
struct PairPosFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ unsigned int count = pairSet.len;
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+ if (glyphs->has (iter.get_glyph ()) &&
+ (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
+ return true;
+ }
+ return false;
+ }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -691,9 +740,7 @@ struct PairPosFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -709,6 +756,13 @@ struct PairPosFormat1
return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -717,7 +771,8 @@ struct PairPosFormat1
unsigned int len1 = valueFormat[0].get_len ();
unsigned int len2 = valueFormat[1].get_len ();
- PairSet::sanitize_closure_t closure = {
+ PairSet::sanitize_closure_t closure =
+ {
this,
valueFormat,
len1,
@@ -747,6 +802,12 @@ struct PairPosFormat1
struct PairPosFormat2
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ return (this+coverage).intersects (glyphs) &&
+ (this+classDef2).intersects (glyphs);
+ }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -755,9 +816,7 @@ struct PairPosFormat2
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -790,6 +849,13 @@ struct PairPosFormat2
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -803,7 +869,7 @@ struct PairPosFormat2
unsigned int stride = len1 + len2;
unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
- return_trace (c->check_array (values, record_size, count) &&
+ return_trace (c->check_array (values, count, record_size) &&
valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
}
@@ -889,6 +955,9 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc
struct CursivePosFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -896,9 +965,7 @@ struct CursivePosFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -906,22 +973,22 @@ struct CursivePosFormat1
hb_buffer_t *buffer = c->buffer;
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
- if (!this_record.exitAnchor) return_trace (false);
+ if (!this_record.entryAnchor) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
- if (!skippy_iter.next ()) return_trace (false);
+ if (!skippy_iter.prev ()) return_trace (false);
- const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
- if (!next_record.entryAnchor) return_trace (false);
+ const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
+ if (!prev_record.exitAnchor) return_trace (false);
- unsigned int i = buffer->idx;
- unsigned int j = skippy_iter.idx;
+ unsigned int i = skippy_iter.idx;
+ unsigned int j = buffer->idx;
buffer->unsafe_to_break (i, j);
float entry_x, entry_y, exit_x, exit_y;
- (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
- (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
+ (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
+ (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
hb_glyph_position_t *pos = buffer->pos;
@@ -968,7 +1035,7 @@ struct CursivePosFormat1
* parent.
*
* Optimize things for the case of RightToLeft, as that's most common in
- * Arabinc. */
+ * Arabic. */
unsigned int child = i;
unsigned int parent = j;
hb_position_t x_offset = entry_x - exit_x;
@@ -997,10 +1064,17 @@ struct CursivePosFormat1
else
pos[child].x_offset = x_offset;
- buffer->idx = j;
+ buffer->idx++;
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1047,6 +1121,10 @@ typedef AnchorMatrix BaseArray; /* base-major--
struct MarkBasePosFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+markCoverage).intersects (glyphs) &&
+ (this+baseCoverage).intersects (glyphs); }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -1055,9 +1133,7 @@ struct MarkBasePosFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+markCoverage;
- }
+ { return this+markCoverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -1088,7 +1164,7 @@ struct MarkBasePosFormat1
))
break;
skippy_iter.reject ();
- } while (1);
+ } while (true);
/* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
//if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
@@ -1099,6 +1175,13 @@ struct MarkBasePosFormat1
return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1161,6 +1244,10 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
struct MarkLigPosFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+markCoverage).intersects (glyphs) &&
+ (this+ligatureCoverage).intersects (glyphs); }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -1169,9 +1256,7 @@ struct MarkLigPosFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+markCoverage;
- }
+ { return this+markCoverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -1216,6 +1301,13 @@ struct MarkLigPosFormat1
return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1274,6 +1366,10 @@ typedef AnchorMatrix Mark2Array; /* mark2-major--
struct MarkMarkPosFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+mark1Coverage).intersects (glyphs) &&
+ (this+mark2Coverage).intersects (glyphs); }
+
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -1282,9 +1378,7 @@ struct MarkMarkPosFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+mark1Coverage;
- }
+ { return this+mark1Coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -1330,6 +1424,13 @@ struct MarkMarkPosFormat1
return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1388,7 +1489,7 @@ struct ChainContextPos : ChainContext {};
struct ExtensionPos : Extension<ExtensionPos>
{
- typedef struct PosLookupSubTable LookupSubTable;
+ typedef struct PosLookupSubTable SubTable;
};
@@ -1400,6 +1501,7 @@ struct ExtensionPos : Extension<ExtensionPos>
struct PosLookupSubTable
{
+ friend struct Lookup;
friend struct PosLookup;
enum Type {
@@ -1453,8 +1555,10 @@ struct PosLookupSubTable
struct PosLookup : Lookup
{
- inline const PosLookupSubTable& get_subtable (unsigned int i) const
- { return Lookup::get_subtable<PosLookupSubTable> (i); }
+ typedef struct PosLookupSubTable SubTable;
+
+ inline const SubTable& get_subtable (unsigned int i) const
+ { return Lookup::get_subtable<SubTable> (i); }
inline bool is_reverse (void) const
{
@@ -1467,6 +1571,12 @@ struct PosLookup : Lookup
return_trace (dispatch (c));
}
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ hb_intersects_context_t c (glyphs);
+ return dispatch (&c);
+ }
+
inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
@@ -1487,18 +1597,15 @@ struct PosLookup : Lookup
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
- { return Lookup::dispatch<PosLookupSubTable> (c); }
+ { return Lookup::dispatch<SubTable> (c); }
+
+ inline bool subset (hb_subset_context_t *c) const
+ { return Lookup::subset<SubTable> (c); }
inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (unlikely (!Lookup::sanitize (c))) return_trace (false);
- return_trace (dispatch (c));
- }
+ { return Lookup::sanitize<SubTable> (c); }
};
-typedef OffsetListOf<PosLookup> PosLookupList;
-
/*
* GPOS -- Glyph Positioning
* https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
@@ -1515,13 +1622,13 @@ struct GPOS : GSUBGPOS
static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
+ inline bool subset (hb_subset_context_t *c) const
+ { return GSUBGPOS::subset<PosLookup> (c); }
+
inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
- const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
- return_trace (list.sanitize (c, this));
- }
+ { return GSUBGPOS::sanitize<PosLookup> (c); }
+
+ typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
};
@@ -1551,7 +1658,10 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc
pos[j].attach_type() = type;
}
static void
-propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+propagate_attachment_offsets (hb_glyph_position_t *pos,
+ unsigned int len,
+ unsigned int i,
+ hb_direction_t direction)
{
/* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
* offset of glyph they are attached to. */
@@ -1559,11 +1669,14 @@ propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direc
if (likely (!chain))
return;
+ pos[i].attach_chain() = 0;
+
unsigned int j = (int) i + chain;
- pos[i].attach_chain() = 0;
+ if (unlikely (j >= len))
+ return;
- propagate_attachment_offsets (pos, j, direction);
+ propagate_attachment_offsets (pos, len, j, direction);
assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
@@ -1619,7 +1732,7 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
/* Handle attachments */
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
for (unsigned int i = 0; i < len; i++)
- propagate_attachment_offsets (pos, i, direction);
+ propagate_attachment_offsets (pos, len, i, direction);
}
@@ -1628,15 +1741,13 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
template <typename context_t>
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
{
- const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->table.GPOS);
- const PosLookup &l = gpos.get_lookup (lookup_index);
+ const PosLookup &l = _get_gpos_relaxed (c->face)->get_lookup (lookup_index);
return l.dispatch (c);
}
/*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
{
- const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->table.GPOS);
- const PosLookup &l = gpos.get_lookup (lookup_index);
+ const PosLookup &l = _get_gpos_relaxed (c->face).get_lookup (lookup_index);
unsigned int saved_lookup_props = c->lookup_props;
unsigned int saved_lookup_index = c->lookup_index;
c->set_lookup_index (lookup_index);
@@ -1647,9 +1758,7 @@ template <typename context_t>
return ret;
}
-
-#undef attach_chain
-#undef attach_type
+struct GPOS_accelerator_t : GPOS::accelerator_t {};
} /* namespace OT */
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index 1d5a02a02..2ce52a1b4 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -29,19 +29,26 @@
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
#define HB_OT_LAYOUT_GSUB_TABLE_HH
-#include "hb-ot-layout-gsubgpos-private.hh"
+#include "hb-ot-layout-gsubgpos.hh"
namespace OT {
+static inline void SingleSubst_serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<GlyphID> &substitutes,
+ unsigned int num_glyphs);
+
struct SingleSubstFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
/* TODO Switch to range-based API to work around malicious fonts.
* https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -55,8 +62,7 @@ struct SingleSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- Coverage::Iter iter;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
/* TODO Switch to range-based API to work around malicious fonts.
* https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -66,9 +72,7 @@ struct SingleSubstFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool would_apply (hb_would_apply_context_t *c) const
{
@@ -99,10 +103,34 @@ struct SingleSubstFormat1
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
- deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
+ deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ hb_auto_t<hb_vector_t<GlyphID> > from;
+ hb_auto_t<hb_vector_t<GlyphID> > to;
+ hb_codepoint_t delta = deltaGlyphID;
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (!c->plan->glyphset->has (iter.get_glyph ()))
+ continue;
+ from.push ()->set (iter.get_glyph ());
+ to.push ()->set ((iter.get_glyph () + delta) & 0xFFFF);
+ }
+ c->serializer->err (from.in_error () || to.in_error ());
+
+ Supplier<GlyphID> from_supplier (&from);
+ Supplier<GlyphID> to_supplier (&to);
+ SingleSubst_serialize (c->serializer,
+ from_supplier,
+ to_supplier,
+ from.len);
+ return_trace (from.len);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -122,12 +150,14 @@ struct SingleSubstFormat1
struct SingleSubstFormat2
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- Coverage::Iter iter;
unsigned int count = substitute.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -140,9 +170,8 @@ struct SingleSubstFormat2
{
TRACE_COLLECT_GLYPHS (this);
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- Coverage::Iter iter;
unsigned int count = substitute.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -151,9 +180,7 @@ struct SingleSubstFormat2
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool would_apply (hb_would_apply_context_t *c) const
{
@@ -164,14 +191,12 @@ struct SingleSubstFormat2
inline bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage).get_coverage (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (index >= substitute.len)) return_trace (false);
- glyph_id = substitute[index];
- c->replace_glyph (glyph_id);
+ c->replace_glyph (substitute[index]);
return_trace (true);
}
@@ -188,6 +213,29 @@ struct SingleSubstFormat2
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ hb_auto_t<hb_vector_t<GlyphID> > from;
+ hb_auto_t<hb_vector_t<GlyphID> > to;
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (!c->plan->glyphset->has (iter.get_glyph ()))
+ continue;
+ from.push ()->set (iter.get_glyph ());
+ to.push ()->set (substitute[iter.get_coverage ()]);
+ }
+ c->serializer->err (from.in_error () || to.in_error ());
+
+ Supplier<GlyphID> from_supplier (&from);
+ Supplier<GlyphID> to_supplier (&to);
+ SingleSubst_serialize (c->serializer,
+ from_supplier,
+ to_supplier,
+ from.len);
+ return_trace (from.len);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -255,6 +303,17 @@ struct SingleSubst
} u;
};
+static inline void
+SingleSubst_serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<GlyphID> &substitutes,
+ unsigned int num_glyphs)
+{
+ c->start_embed<SingleSubst> ()->serialize (c,
+ glyphs,
+ substitutes,
+ num_glyphs);
+}
struct Sequence
{
@@ -329,12 +388,14 @@ struct Sequence
struct MultipleSubstFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- Coverage::Iter iter;
unsigned int count = sequence.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -349,13 +410,11 @@ struct MultipleSubstFormat1
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
unsigned int count = sequence.len;
for (unsigned int i = 0; i < count; i++)
- (this+sequence[i]).collect_glyphs (c);
+ (this+sequence[i]).collect_glyphs (c);
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool would_apply (hb_would_apply_context_t *c) const
{
@@ -391,6 +450,13 @@ struct MultipleSubstFormat1
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -445,27 +511,86 @@ struct MultipleSubst
} u;
};
+struct AlternateSet
+{
+ inline void closure (hb_closure_context_t *c) const
+ {
+ TRACE_CLOSURE (this);
+ unsigned int count = alternates.len;
+ for (unsigned int i = 0; i < count; i++)
+ c->out->add (alternates[i]);
+ }
+
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ c->output->add_array (alternates.arrayZ, alternates.len);
+ }
+
+ inline bool apply (hb_ot_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int count = alternates.len;
+
+ if (unlikely (!count)) return_trace (false);
+
+ hb_mask_t glyph_mask = c->buffer->cur().mask;
+ hb_mask_t lookup_mask = c->lookup_mask;
+
+ /* Note: This breaks badly if two features enabled this lookup together. */
+ unsigned int shift = hb_ctz (lookup_mask);
+ unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+ /* If alt_index is MAX, randomize feature if it is the rand feature. */
+ if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
+ alt_index = c->random_number () % count + 1;
+
+ if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+
+ c->replace_glyph (alternates[alt_index - 1]);
+
+ return_trace (true);
+ }
+
+ 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 (false);
+ if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false);
+ return_trace (true);
+ }
-typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (alternates.sanitize (c));
+ }
+
+ protected:
+ ArrayOf<GlyphID>
+ alternates; /* Array of alternate GlyphIDs--in
* arbitrary order */
+ public:
+ DEFINE_SIZE_ARRAY (2, alternates);
+};
struct AlternateSubstFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ { return (this+coverage).intersects (glyphs); }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- Coverage::Iter iter;
unsigned int count = alternateSet.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- if (c->glyphs->has (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->out->add (alt_set[i]);
- }
+ if (c->glyphs->has (iter.get_glyph ()))
+ (this+alternateSet[iter.get_coverage ()]).closure (c);
}
}
@@ -473,21 +598,17 @@ struct AlternateSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- Coverage::Iter iter;
unsigned int count = alternateSet.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
- const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
- c->output->add_array (alt_set.arrayZ, alt_set.len);
+ (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
}
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool would_apply (hb_would_apply_context_t *c) const
{
@@ -498,29 +619,11 @@ struct AlternateSubstFormat1
inline bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage).get_coverage (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
- const AlternateSet &alt_set = this+alternateSet[index];
-
- if (unlikely (!alt_set.len)) return_trace (false);
-
- hb_mask_t glyph_mask = c->buffer->cur().mask;
- hb_mask_t lookup_mask = c->lookup_mask;
-
- /* Note: This breaks badly if two features enabled this lookup together. */
- unsigned int shift = hb_ctz (lookup_mask);
- unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
-
- if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
-
- glyph_id = alt_set[alt_index - 1];
-
- c->replace_glyph (glyph_id);
-
- return_trace (true);
+ return_trace ((this+alternateSet[index]).apply (c));
}
inline bool serialize (hb_serialize_context_t *c,
@@ -541,6 +644,13 @@ struct AlternateSubstFormat1
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -598,10 +708,19 @@ struct AlternateSubst
struct Ligature
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ unsigned int count = component.lenP1;
+ for (unsigned int i = 1; i < count; i++)
+ if (!glyphs->has (component[i]))
+ return false;
+ return true;
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- unsigned int count = component.len;
+ unsigned int count = component.lenP1;
for (unsigned int i = 1; i < count; i++)
if (!c->glyphs->has (component[i]))
return;
@@ -611,14 +730,14 @@ struct Ligature
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
- c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0);
+ c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
c->output->add (ligGlyph);
}
inline bool would_apply (hb_would_apply_context_t *c) const
{
TRACE_WOULD_APPLY (this);
- if (c->len != component.len)
+ if (c->len != component.lenP1)
return_trace (false);
for (unsigned int i = 1; i < c->len; i++)
@@ -631,7 +750,7 @@ struct Ligature
inline bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- unsigned int count = component.len;
+ unsigned int count = component.lenP1;
if (unlikely (!count)) return_trace (false);
@@ -643,7 +762,6 @@ struct Ligature
return_trace (true);
}
- bool is_mark_ligature = false;
unsigned int total_component_count = 0;
unsigned int match_length = 0;
@@ -655,7 +773,6 @@ struct Ligature
nullptr,
&match_length,
match_positions,
- &is_mark_ligature,
&total_component_count)))
return_trace (false);
@@ -664,7 +781,6 @@ struct Ligature
match_positions,
match_length,
ligGlyph,
- is_mark_ligature,
total_component_count);
return_trace (true);
@@ -701,6 +817,15 @@ struct Ligature
struct LigatureSet
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ unsigned int num_ligs = ligature.len;
+ for (unsigned int i = 0; i < num_ligs; i++)
+ if ((this+ligature[i]).intersects (glyphs))
+ return true;
+ return false;
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
@@ -778,12 +903,25 @@ struct LigatureSet
struct LigatureSubstFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ unsigned int count = ligatureSet.len;
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+ if (glyphs->has (iter.get_glyph ()) &&
+ (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
+ return true;
+ }
+ return false;
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- Coverage::Iter iter;
unsigned int count = ligatureSet.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -796,9 +934,8 @@ struct LigatureSubstFormat1
{
TRACE_COLLECT_GLYPHS (this);
if (unlikely (!(this+coverage).add_coverage (c->input))) return;
- Coverage::Iter iter;
unsigned int count = ligatureSet.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -807,9 +944,7 @@ struct LigatureSubstFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool would_apply (hb_would_apply_context_t *c) const
{
@@ -824,9 +959,8 @@ struct LigatureSubstFormat1
inline bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage).get_coverage (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
const LigatureSet &lig_set = this+ligatureSet[index];
@@ -855,6 +989,13 @@ struct LigatureSubstFormat1
return_trace (true);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -924,7 +1065,7 @@ struct ChainContextSubst : ChainContext {};
struct ExtensionSubst : Extension<ExtensionSubst>
{
- typedef struct SubstLookupSubTable LookupSubTable;
+ typedef struct SubstLookupSubTable SubTable;
inline bool is_reverse (void) const;
};
@@ -932,6 +1073,28 @@ struct ExtensionSubst : Extension<ExtensionSubst>
struct ReverseChainSingleSubstFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ if (!(this+coverage).intersects (glyphs))
+ return false;
+
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+ unsigned int count;
+
+ count = backtrack.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (!(this+backtrack[i]).intersects (glyphs))
+ return false;
+
+ count = lookahead.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (!(this+lookahead[i]).intersects (glyphs))
+ return false;
+
+ return true;
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
@@ -950,9 +1113,8 @@ struct ReverseChainSingleSubstFormat1
return;
const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
- Coverage::Iter iter;
count = substitute.len;
- for (iter.init (this+coverage); iter.more (); iter.next ())
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
{
if (unlikely (iter.get_coverage () >= count))
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
@@ -983,9 +1145,7 @@ struct ReverseChainSingleSubstFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool would_apply (hb_would_apply_context_t *c) const
{
@@ -1026,6 +1186,13 @@ struct ReverseChainSingleSubstFormat1
return_trace (false);
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1045,7 +1212,7 @@ struct ReverseChainSingleSubstFormat1
* beginning of table */
OffsetArrayOf<Coverage>
backtrack; /* Array of coverage tables
- * in backtracking sequence, in glyph
+ * in backtracking sequence, in glyph
* sequence order */
OffsetArrayOf<Coverage>
lookaheadX; /* Array of coverage tables
@@ -1086,6 +1253,7 @@ struct ReverseChainSingleSubst
struct SubstLookupSubTable
{
+ friend struct Lookup;
friend struct SubstLookup;
enum Type {
@@ -1136,16 +1304,18 @@ struct SubstLookupSubTable
struct SubstLookup : Lookup
{
- inline const SubstLookupSubTable& get_subtable (unsigned int i) const
- { return Lookup::get_subtable<SubstLookupSubTable> (i); }
+ typedef SubstLookupSubTable SubTable;
+
+ inline const SubTable& get_subtable (unsigned int i) const
+ { return Lookup::get_subtable<SubTable> (i); }
inline static bool lookup_type_is_reverse (unsigned int lookup_type)
- { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
+ { return lookup_type == SubTable::ReverseChainSingle; }
inline bool is_reverse (void) const
{
unsigned int type = get_type ();
- if (unlikely (type == SubstLookupSubTable::Extension))
+ if (unlikely (type == SubTable::Extension))
return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
return lookup_type_is_reverse (type);
}
@@ -1156,6 +1326,12 @@ struct SubstLookup : Lookup
return_trace (dispatch (c));
}
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ hb_intersects_context_t c (glyphs);
+ return dispatch (&c);
+ }
+
inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
{
TRACE_CLOSURE (this);
@@ -1196,9 +1372,9 @@ struct SubstLookup : Lookup
static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
- inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
- unsigned int i)
- { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
+ inline SubTable& serialize_subtable (hb_serialize_context_t *c,
+ unsigned int i)
+ { return get_subtables<SubTable> ()[i].serialize (c, this); }
inline bool serialize_single (hb_serialize_context_t *c,
uint32_t lookup_props,
@@ -1207,7 +1383,7 @@ struct SubstLookup : Lookup
unsigned int num_glyphs)
{
TRACE_SERIALIZE (this);
- if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
+ if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
}
@@ -1219,7 +1395,7 @@ struct SubstLookup : Lookup
Supplier<GlyphID> &substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
- if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
+ if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
glyphs,
substitute_len_list,
@@ -1235,7 +1411,7 @@ struct SubstLookup : Lookup
Supplier<GlyphID> &alternate_glyphs_list)
{
TRACE_SERIALIZE (this);
- if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
+ if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
glyphs,
alternate_len_list,
@@ -1253,7 +1429,7 @@ struct SubstLookup : Lookup
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 (false);
+ if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
first_glyphs,
ligature_per_first_glyph_count_list,
@@ -1280,32 +1456,15 @@ struct SubstLookup : Lookup
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
- { return Lookup::dispatch<SubstLookupSubTable> (c); }
+ { return Lookup::dispatch<SubTable> (c); }
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (unlikely (!Lookup::sanitize (c))) return_trace (false);
- if (unlikely (!dispatch (c))) return_trace (false);
+ inline bool subset (hb_subset_context_t *c) const
+ { return Lookup::subset<SubTable> (c); }
- if (unlikely (get_type () == SubstLookupSubTable::Extension))
- {
- /* The spec says all subtables of an Extension lookup should
- * have the same type, which shall not be the Extension type
- * itself (but we already checked for that).
- * This is specially important if one has a reverse type! */
- 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 (false);
- }
- return_trace (true);
- }
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ { return Lookup::sanitize<SubTable> (c); }
};
-typedef OffsetListOf<SubstLookup> SubstLookupList;
-
/*
* GSUB -- Glyph Substitution
* https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
@@ -1318,32 +1477,14 @@ struct GSUB : GSUBGPOS
inline const SubstLookup& get_lookup (unsigned int i) const
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
- static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
+ inline bool subset (hb_subset_context_t *c) const
+ { return GSUBGPOS::subset<SubstLookup> (c); }
inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
- const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
- return_trace (list.sanitize (c, this));
- }
-};
-
-
-void
-GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
-{
- _hb_buffer_assert_gsubgpos_vars (buffer);
+ { return GSUBGPOS::sanitize<SubstLookup> (c); }
- const GDEF &gdef = *hb_ot_layout_from_face (font->face)->table.GDEF;
- unsigned int count = buffer->len;
- for (unsigned int i = 0; i < count; i++)
- {
- _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;
- }
-}
+ typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
+};
/* Out-of-class implementation for methods recursing */
@@ -1351,23 +1492,21 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
{
unsigned int type = get_type ();
- if (unlikely (type == SubstLookupSubTable::Extension))
- return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
+ if (unlikely (type == SubTable::Extension))
+ return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
return SubstLookup::lookup_type_is_reverse (type);
}
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 = *(hb_ot_layout_from_face (c->face)->table.GSUB);
- const SubstLookup &l = gsub.get_lookup (lookup_index);
+ const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
return l.dispatch (c);
}
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
{
- const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->table.GSUB);
- const SubstLookup &l = gsub.get_lookup (lookup_index);
+ const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
unsigned int saved_lookup_props = c->lookup_props;
unsigned int saved_lookup_index = c->lookup_index;
c->set_lookup_index (lookup_index);
@@ -1378,6 +1517,7 @@ template <typename context_t>
return ret;
}
+struct GSUB_accelerator_t : GSUB::accelerator_t {};
} /* namespace OT */
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos.hh
index 40a2fc4cc..a4066265c 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos.hh
@@ -26,19 +26,38 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
-#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
-
-#include "hb-private.hh"
-#include "hb-buffer-private.hh"
-#include "hb-map-private.hh"
+#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
+#define HB_OT_LAYOUT_GSUBGPOS_HH
+
+#include "hb.hh"
+#include "hb-buffer.hh"
+#include "hb-map.hh"
+#include "hb-set.hh"
+#include "hb-ot-map.hh"
+#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
-#include "hb-set-private.hh"
namespace OT {
+struct hb_intersects_context_t :
+ hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
+{
+ inline const char *get_name (void) { return "INTERSECTS"; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
+ static return_t default_return_value (void) { return false; }
+ bool stop_sublookup_iteration (return_t r) const { return r; }
+
+ const hb_set_t *glyphs;
+ unsigned int debug_depth;
+
+ hb_intersects_context_t (const hb_set_t *glyphs_) :
+ glyphs (glyphs_),
+ debug_depth (0) {}
+};
+
struct hb_closure_context_t :
hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
{
@@ -48,15 +67,14 @@ struct hb_closure_context_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)
+ void recurse (unsigned int lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func))
- return default_return_value ();
+ return;
nesting_level_left--;
recurse_func (this, lookup_index);
nesting_level_left++;
- return HB_VOID;
}
bool should_visit_lookup (unsigned int lookup_index)
@@ -145,10 +163,10 @@ struct hb_collect_glyphs_context_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)
+ void recurse (unsigned int lookup_index)
{
if (unlikely (nesting_level_left == 0 || !recurse_func))
- return default_return_value ();
+ return;
/* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
* past the previous check. For GSUB, we only want to collect the output
@@ -161,11 +179,11 @@ struct hb_collect_glyphs_context_t :
*/
if (output == hb_set_get_empty ())
- return HB_VOID;
+ return;
/* Return if new lookup was recursed to before. */
if (recursed_lookups->has (lookup_index))
- return HB_VOID;
+ return;
hb_set_t *old_before = before;
hb_set_t *old_input = input;
@@ -181,8 +199,6 @@ struct hb_collect_glyphs_context_t :
after = old_after;
recursed_lookups->add (lookup_index);
-
- return HB_VOID;
}
hb_face_t *face;
@@ -196,10 +212,10 @@ struct hb_collect_glyphs_context_t :
unsigned int debug_depth;
hb_collect_glyphs_context_t (hb_face_t *face_,
- hb_set_t *glyphs_before, /* OUT. May be nullptr */
- hb_set_t *glyphs_input, /* OUT. May be nullptr */
- hb_set_t *glyphs_after, /* OUT. May be nullptr */
- hb_set_t *glyphs_output, /* OUT. May be nullptr */
+ 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_ = HB_MAX_NESTING_LEVEL) :
face (face_),
before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
@@ -207,24 +223,16 @@ struct hb_collect_glyphs_context_t :
after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
recurse_func (nullptr),
- recursed_lookups (nullptr),
+ recursed_lookups (hb_set_create ()),
nesting_level_left (nesting_level_left_),
- debug_depth (0)
- {
- recursed_lookups = hb_set_create ();
- }
- ~hb_collect_glyphs_context_t (void)
- {
- hb_set_destroy (recursed_lookups);
- }
+ debug_depth (0) {}
+ ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
};
-/* XXX Can we remove this? */
-
template <typename set_t>
struct hb_add_coverage_context_t :
hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
@@ -334,10 +342,10 @@ struct hb_ot_apply_context_t :
match_glyph_data = nullptr;
matcher.set_match_func (nullptr, nullptr);
matcher.set_lookup_props (c->lookup_props);
- /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+ /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
- /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
- matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
+ /* Ignore ZWJ if we are matching context, or asked to. */
+ matcher.set_ignore_zwj (context_match || c->auto_zwj);
matcher.set_mask (context_match ? -1 : c->lookup_mask);
}
inline void set_lookup_props (unsigned int lookup_props)
@@ -469,9 +477,12 @@ struct hb_ot_apply_context_t :
unsigned int nesting_level_left;
unsigned int debug_depth;
+ bool has_glyph_classes;
bool auto_zwnj;
bool auto_zwj;
- bool has_glyph_classes;
+ bool random;
+
+ uint32_t random_state;
hb_ot_apply_context_t (unsigned int table_index_,
@@ -480,7 +491,7 @@ struct hb_ot_apply_context_t :
iter_input (), iter_context (),
font (font_), face (font->face), buffer (buffer_),
recurse_func (nullptr),
- gdef (*hb_ot_layout_from_face (face)->table.GDEF),
+ gdef (_get_gdef (face)),
var_store (gdef.get_var_store ()),
direction (buffer_->props.direction),
lookup_mask (1),
@@ -489,22 +500,33 @@ struct hb_ot_apply_context_t :
lookup_props (0),
nesting_level_left (HB_MAX_NESTING_LEVEL),
debug_depth (0),
+ has_glyph_classes (gdef.has_glyph_classes ()),
auto_zwnj (true),
auto_zwj (true),
- has_glyph_classes (gdef.has_glyph_classes ()) {}
+ random (false),
+ random_state (1) { init_iters (); }
- 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_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
- inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
- inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
- inline void set_lookup_props (unsigned int lookup_props_)
+ inline void init_iters (void)
{
- lookup_props = lookup_props_;
iter_input.init (this, false);
iter_context.init (this, true);
}
+ inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
+ inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
+ inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
+ inline void set_random (bool random_) { random = random_; }
+ inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+ inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
+ inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
+
+ inline uint32_t random_number (void)
+ {
+ /* http://www.cplusplus.com/reference/random/minstd_rand/ */
+ random_state = random_state * 48271 % 2147483647;
+ return random_state;
+ }
+
inline bool
match_properties_mark (hb_codepoint_t glyph,
unsigned int glyph_props,
@@ -558,7 +580,7 @@ struct hb_ot_apply_context_t :
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,
+ * Ligature and Multiple substitutions. Ie. if you ligate, expand,
* and ligate again, it forgives the multiplication and acts as
* if only ligation happened. As such, clear MULTIPLIED bit.
*/
@@ -597,8 +619,66 @@ struct hb_ot_apply_context_t :
};
+struct hb_get_subtables_context_t :
+ hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
+{
+ template <typename Type>
+ static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return typed_obj->apply (c);
+ }
+
+ typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
+
+ struct hb_applicable_t
+ {
+ template <typename T>
+ inline void init (const T &obj_, hb_apply_func_t apply_func_)
+ {
+ obj = &obj_;
+ apply_func = apply_func_;
+ digest.init ();
+ obj_.get_coverage ().add_coverage (&digest);
+ }
+
+ inline bool apply (OT::hb_ot_apply_context_t *c) const
+ {
+ return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
+ }
+
+ private:
+ const void *obj;
+ hb_apply_func_t apply_func;
+ hb_set_digest_t digest;
+ };
+
+ typedef hb_vector_t<hb_applicable_t, 2> array_t;
+
+ /* Dispatch interface. */
+ inline const char *get_name (void) { return "GET_SUBTABLES"; }
+ template <typename T>
+ inline return_t dispatch (const T &obj)
+ {
+ hb_applicable_t *entry = array.push();
+ entry->init (obj, apply_to<T>);
+ 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; }
+
+ hb_get_subtables_context_t (array_t &array_) :
+ array (array_),
+ debug_depth (0) {}
+
+ array_t &array;
+ unsigned int debug_depth;
+};
+
+
-typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+
+typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
@@ -616,29 +696,29 @@ struct ContextApplyFuncs
};
-static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
{
return glyphs->has (value);
}
-static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return class_def.intersects_class (glyphs, value);
}
-static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
{
const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
return (data+coverage).intersects (glyphs);
}
-static inline bool intersects_array (hb_closure_context_t *c,
+static inline bool intersects_array (const hb_set_t *glyphs,
unsigned int count,
const HBUINT16 values[],
intersects_func_t intersects_func,
const void *intersects_data)
{
for (unsigned int i = 0; i < count; i++)
- if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
+ if (likely (!intersects_func (glyphs, values[i], intersects_data)))
return false;
return true;
}
@@ -707,7 +787,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
const void *match_data,
unsigned int *end_offset,
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
- bool *p_is_mark_ligature = nullptr,
unsigned int *p_total_component_count = nullptr)
{
TRACE_APPLY (nullptr);
@@ -744,8 +823,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
* https://github.com/harfbuzz/harfbuzz/issues/545
*/
- 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());
@@ -812,15 +889,11 @@ static inline bool match_input (hb_ot_apply_context_t *c,
return_trace (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]);
}
*end_offset = skippy_iter.idx - buffer->idx + 1;
- if (p_is_mark_ligature)
- *p_is_mark_ligature = is_mark_ligature;
-
if (p_total_component_count)
*p_total_component_count = total_component_count;
@@ -828,10 +901,9 @@ static inline bool match_input (hb_ot_apply_context_t *c,
}
static inline bool ligate_input (hb_ot_apply_context_t *c,
unsigned int count, /* Including the first glyph */
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ const unsigned int match_positions[HB_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 (nullptr);
@@ -840,11 +912,15 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
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
+ /* - If a base and one or more marks ligate, consider that as a base, NOT
+ * ligature, such that all following marks can still attach to it.
+ * https://github.com/harfbuzz/harfbuzz/issues/1109
+ *
+ * - If all components of the ligature were marks, we call this a mark ligature.
+ * 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
+ * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with 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
@@ -868,13 +944,24 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
* 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);
+ bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
+ bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
+ for (unsigned int i = 1; i < count; i++)
+ if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
+ {
+ is_base_ligature = false;
+ is_mark_ligature = false;
+ break;
+ }
+ bool is_ligature = !is_base_ligature && !is_mark_ligature;
+
+ unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
+ unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
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)
+ if (is_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)
@@ -888,7 +975,8 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
{
while (buffer->idx < match_positions[i] && buffer->successful)
{
- if (!is_mark_ligature) {
+ if (is_ligature)
+ {
unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
if (this_comp == 0)
this_comp = last_num_components;
@@ -987,7 +1075,6 @@ struct LookupRecord
DEFINE_SIZE_STATIC (4);
};
-
template <typename context_t>
static inline void recurse_lookups (context_t *c,
unsigned int lookupCount,
@@ -1140,6 +1227,16 @@ struct ContextApplyLookupContext
const void *match_data;
};
+static inline bool context_intersects (const hb_set_t *glyphs,
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const HBUINT16 input[], /* Array of input values--start with second glyph */
+ ContextClosureLookupContext &lookup_context)
+{
+ return intersects_array (glyphs,
+ inputCount ? inputCount - 1 : 0, input,
+ lookup_context.funcs.intersects, lookup_context.intersects_data);
+}
+
static inline void context_closure_lookup (hb_closure_context_t *c,
unsigned int inputCount, /* Including the first glyph (not matched) */
const HBUINT16 input[], /* Array of input values--start with second glyph */
@@ -1147,9 +1244,9 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
const LookupRecord lookupRecord[],
ContextClosureLookupContext &lookup_context)
{
- if (intersects_array (c,
- inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data))
+ if (context_intersects (c->glyphs,
+ inputCount, input,
+ lookup_context))
recurse_lookups (c,
lookupCount, lookupRecord);
}
@@ -1201,38 +1298,45 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
struct Rule
{
+ inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
+ {
+ return context_intersects (glyphs,
+ inputCount, inputZ.arrayZ,
+ lookup_context);
+ }
+
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{
TRACE_CLOSURE (this);
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+ const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
context_closure_lookup (c,
- inputCount, inputZ,
- lookupCount, lookupRecord,
+ inputCount, inputZ.arrayZ,
+ lookupCount, lookupRecord.arrayZ,
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));
+ const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
context_collect_glyphs_lookup (c,
- inputCount, inputZ,
- lookupCount, lookupRecord,
+ inputCount, inputZ.arrayZ,
+ lookupCount, lookupRecord.arrayZ,
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 (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+ const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+ return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
}
inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
- return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+ const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+ return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
}
public:
@@ -1241,8 +1345,8 @@ struct Rule
TRACE_SANITIZE (this);
return_trace (inputCount.sanitize (c) &&
lookupCount.sanitize (c) &&
- c->check_range (inputZ,
- inputZ[0].static_size * inputCount +
+ c->check_range (inputZ.arrayZ,
+ inputZ[0].static_size * (inputCount ? inputCount - 1 : 0) +
LookupRecord::static_size * lookupCount));
}
@@ -1251,9 +1355,11 @@ struct Rule
* glyph sequence--includes the first
* glyph */
HBUINT16 lookupCount; /* Number of LookupRecords */
- HBUINT16 inputZ[VAR]; /* Array of match inputs--start with
+ UnsizedArrayOf<HBUINT16>
+ inputZ; /* Array of match inputs--start with
* second glyph */
-/*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in
+/*UnsizedArrayOf<LookupRecord>
+ lookupRecordX;*/ /* Array of LookupRecords--in
* design order */
public:
DEFINE_SIZE_ARRAY (4, inputZ);
@@ -1261,6 +1367,15 @@ struct Rule
struct RuleSet
{
+ inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
+ {
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ if ((this+rule[i]).intersects (glyphs, lookup_context))
+ return true;
+ return false;
+ }
+
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{
TRACE_CLOSURE (this);
@@ -1318,23 +1433,42 @@ struct RuleSet
struct ContextFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ struct ContextClosureLookupContext lookup_context = {
+ {intersects_glyph},
+ nullptr
+ };
+
+ unsigned int count = ruleSet.len;
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+ if (glyphs->has (iter.get_glyph ()) &&
+ (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+ return true;
+ }
+ return false;
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- const Coverage &cov = (this+coverage);
-
struct ContextClosureLookupContext lookup_context = {
{intersects_glyph},
nullptr
};
unsigned int count = ruleSet.len;
- for (unsigned int i = 0; i < count; i++)
- if (cov.intersects_coverage (c->glyphs, i)) {
- const RuleSet &rule_set = this+ruleSet[i];
- rule_set.closure (c, lookup_context);
- }
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+ if (c->glyphs->has (iter.get_glyph ()))
+ (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
+ }
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1365,9 +1499,7 @@ struct ContextFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -1384,6 +1516,13 @@ struct ContextFormat1
return_trace (rule_set.apply (c, lookup_context));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1405,6 +1544,27 @@ struct ContextFormat1
struct ContextFormat2
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ if (!(this+coverage).intersects (glyphs))
+ return false;
+
+ const ClassDef &class_def = this+classDef;
+
+ struct ContextClosureLookupContext lookup_context = {
+ {intersects_class},
+ &class_def
+ };
+
+ unsigned int count = ruleSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (class_def.intersects_class (glyphs, i) &&
+ (this+ruleSet[i]).intersects (glyphs, lookup_context))
+ return true;
+
+ return false;
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
@@ -1457,9 +1617,7 @@ struct ContextFormat2
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -1477,6 +1635,13 @@ struct ContextFormat2
return_trace (rule_set.apply (c, lookup_context));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1501,19 +1666,33 @@ struct ContextFormat2
struct ContextFormat3
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ if (!(this+coverageZ[0]).intersects (glyphs))
+ return false;
+
+ struct ContextClosureLookupContext lookup_context = {
+ {intersects_coverage},
+ this
+ };
+ return context_intersects (glyphs,
+ glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
+ lookup_context);
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
if (!(this+coverageZ[0]).intersects (c->glyphs))
return;
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
struct ContextClosureLookupContext lookup_context = {
{intersects_coverage},
this
};
context_closure_lookup (c,
- glyphCount, (const HBUINT16 *) (coverageZ + 1),
+ glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
lookupCount, lookupRecord,
lookup_context);
}
@@ -1523,14 +1702,14 @@ struct ContextFormat3
TRACE_COLLECT_GLYPHS (this);
(this+coverageZ[0]).add_coverage (c->input);
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
struct ContextCollectGlyphsLookupContext lookup_context = {
{collect_coverage},
this
};
context_collect_glyphs_lookup (c,
- glyphCount, (const HBUINT16 *) (coverageZ + 1),
+ glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
lookupCount, lookupRecord,
lookup_context);
}
@@ -1539,18 +1718,16 @@ struct ContextFormat3
{
TRACE_WOULD_APPLY (this);
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
struct ContextApplyLookupContext lookup_context = {
{match_coverage},
this
};
- return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+ return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverageZ[0];
- }
+ { return this+coverageZ[0]; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -1558,12 +1735,19 @@ struct ContextFormat3
unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
struct ContextApplyLookupContext lookup_context = {
{match_coverage},
this
};
- return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+ return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
+ }
+
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
}
inline bool sanitize (hb_sanitize_context_t *c) const
@@ -1572,11 +1756,11 @@ struct ContextFormat3
if (!c->check_struct (this)) return_trace (false);
unsigned int count = glyphCount;
if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
- if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
+ if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
for (unsigned int i = 0; i < count; i++)
if (!coverageZ[i].sanitize (c, this)) return_trace (false);
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
- return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * count);
+ return_trace (c->check_array (lookupRecord, lookupCount));
}
protected:
@@ -1584,10 +1768,11 @@ struct ContextFormat3
HBUINT16 glyphCount; /* Number of glyphs in the input glyph
* sequence */
HBUINT16 lookupCount; /* Number of LookupRecords */
- OffsetTo<Coverage>
- coverageZ[VAR]; /* Array of offsets to Coverage
+ UnsizedArrayOf<OffsetTo<Coverage> >
+ coverageZ; /* Array of offsets to Coverage
* table in glyph sequence order */
-/*LookupRecord lookupRecordX[VAR];*/ /* Array of LookupRecords--in
+/*UnsizedArrayOf<LookupRecord>
+ lookupRecordX;*/ /* Array of LookupRecords--in
* design order */
public:
DEFINE_SIZE_ARRAY (6, coverageZ);
@@ -1638,6 +1823,26 @@ struct ChainContextApplyLookupContext
const void *match_data[3];
};
+static inline bool chain_context_intersects (const hb_set_t *glyphs,
+ unsigned int backtrackCount,
+ const HBUINT16 backtrack[],
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const HBUINT16 input[], /* Array of input values--start with second glyph */
+ unsigned int lookaheadCount,
+ const HBUINT16 lookahead[],
+ ChainContextClosureLookupContext &lookup_context)
+{
+ return intersects_array (glyphs,
+ backtrackCount, backtrack,
+ lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+ && intersects_array (glyphs,
+ inputCount ? inputCount - 1 : 0, input,
+ lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+ && intersects_array (glyphs,
+ lookaheadCount, lookahead,
+ lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+}
+
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
unsigned int backtrackCount,
const HBUINT16 backtrack[],
@@ -1649,15 +1854,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
const LookupRecord lookupRecord[],
ChainContextClosureLookupContext &lookup_context)
{
- if (intersects_array (c,
- backtrackCount, backtrack,
- lookup_context.funcs.intersects, lookup_context.intersects_data[0])
- && intersects_array (c,
- inputCount ? inputCount - 1 : 0, input,
- lookup_context.funcs.intersects, lookup_context.intersects_data[1])
- && intersects_array (c,
- lookaheadCount, lookahead,
- lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
+ if (chain_context_intersects (c->glyphs,
+ backtrackCount, backtrack,
+ inputCount, input,
+ lookaheadCount, lookahead,
+ lookup_context))
recurse_lookups (c,
lookupCount, lookupRecord);
}
@@ -1737,6 +1938,17 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
struct ChainRule
{
+ inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
+ {
+ const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+ const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
+ return chain_context_intersects (glyphs,
+ backtrack.len, backtrack.arrayZ,
+ input.lenP1, input.arrayZ,
+ lookahead.len, lookahead.arrayZ,
+ lookup_context);
+ }
+
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{
TRACE_CLOSURE (this);
@@ -1745,7 +1957,7 @@ struct ChainRule
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
chain_context_closure_lookup (c,
backtrack.len, backtrack.arrayZ,
- input.len, input.arrayZ,
+ input.lenP1, input.arrayZ,
lookahead.len, lookahead.arrayZ,
lookup.len, lookup.arrayZ,
lookup_context);
@@ -1759,7 +1971,7 @@ struct ChainRule
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
chain_context_collect_glyphs_lookup (c,
backtrack.len, backtrack.arrayZ,
- input.len, input.arrayZ,
+ input.lenP1, input.arrayZ,
lookahead.len, lookahead.arrayZ,
lookup.len, lookup.arrayZ,
lookup_context);
@@ -1773,7 +1985,7 @@ struct ChainRule
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
return_trace (chain_context_would_apply_lookup (c,
backtrack.len, backtrack.arrayZ,
- input.len, input.arrayZ,
+ input.lenP1, input.arrayZ,
lookahead.len, lookahead.arrayZ, lookup.len,
lookup.arrayZ, lookup_context));
}
@@ -1786,7 +1998,7 @@ struct ChainRule
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
return_trace (chain_context_apply_lookup (c,
backtrack.len, backtrack.arrayZ,
- input.len, input.arrayZ,
+ input.lenP1, input.arrayZ,
lookahead.len, lookahead.arrayZ, lookup.len,
lookup.arrayZ, lookup_context));
}
@@ -1823,6 +2035,14 @@ struct ChainRule
struct ChainRuleSet
{
+ inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
+ {
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ if ((this+rule[i]).intersects (glyphs, lookup_context))
+ return true;
+ return false;
+ }
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{
TRACE_CLOSURE (this);
@@ -1877,10 +2097,28 @@ struct ChainRuleSet
struct ChainContextFormat1
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ struct ChainContextClosureLookupContext lookup_context = {
+ {intersects_glyph},
+ {nullptr, nullptr, nullptr}
+ };
+
+ unsigned int count = ruleSet.len;
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+ if (glyphs->has (iter.get_glyph ()) &&
+ (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+ return true;
+ }
+ return false;
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
- const Coverage &cov = (this+coverage);
struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph},
@@ -1888,11 +2126,13 @@ struct ChainContextFormat1
};
unsigned int count = ruleSet.len;
- for (unsigned int i = 0; i < count; i++)
- if (cov.intersects_coverage (c->glyphs, i)) {
- const ChainRuleSet &rule_set = this+ruleSet[i];
- rule_set.closure (c, lookup_context);
- }
+ for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+ {
+ if (unlikely (iter.get_coverage () >= count))
+ break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+ if (c->glyphs->has (iter.get_glyph ()))
+ (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
+ }
}
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1923,9 +2163,7 @@ struct ChainContextFormat1
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -1941,6 +2179,13 @@ struct ChainContextFormat1
return_trace (rule_set.apply (c, lookup_context));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -1961,6 +2206,30 @@ struct ChainContextFormat1
struct ChainContextFormat2
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ if (!(this+coverage).intersects (glyphs))
+ return false;
+
+ const ClassDef &backtrack_class_def = this+backtrackClassDef;
+ const ClassDef &input_class_def = this+inputClassDef;
+ const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+ struct ChainContextClosureLookupContext lookup_context = {
+ {intersects_class},
+ {&backtrack_class_def,
+ &input_class_def,
+ &lookahead_class_def}
+ };
+
+ unsigned int count = ruleSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (input_class_def.intersects_class (glyphs, i) &&
+ (this+ruleSet[i]).intersects (glyphs, lookup_context))
+ return true;
+
+ return false;
+ }
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
@@ -2027,9 +2296,7 @@ struct ChainContextFormat2
}
inline const Coverage &get_coverage (void) const
- {
- return this+coverage;
- }
+ { return this+coverage; }
inline bool apply (hb_ot_apply_context_t *c) const
{
@@ -2052,6 +2319,13 @@ struct ChainContextFormat2
return_trace (rule_set.apply (c, lookup_context));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -2088,6 +2362,25 @@ struct ChainContextFormat2
struct ChainContextFormat3
{
+ inline bool intersects (const hb_set_t *glyphs) const
+ {
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+ if (!(this+input[0]).intersects (glyphs))
+ return false;
+
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+ struct ChainContextClosureLookupContext lookup_context = {
+ {intersects_coverage},
+ {this, this, this}
+ };
+ return chain_context_intersects (glyphs,
+ backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
+ input.len, (const HBUINT16 *) input.arrayZ + 1,
+ lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
+ lookup_context);
+ }
+
inline void closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
@@ -2176,6 +2469,13 @@ struct ChainContextFormat3
lookup.len, lookup.arrayZ, lookup_context));
}
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ // TODO(subset)
+ return_trace (false);
+ }
+
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -2244,8 +2544,8 @@ struct ExtensionFormat1
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);
+ if (unlikely (!offset)) return Null(typename T::SubTable);
+ return StructAtOffset<typename T::SubTable> (this, offset);
}
template <typename context_t>
@@ -2253,7 +2553,7 @@ struct ExtensionFormat1
{
TRACE_DISPATCH (this, format);
if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
- return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
+ return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
}
/* This is called from may_dispatch() above with hb_sanitize_context_t. */
@@ -2262,7 +2562,7 @@ struct ExtensionFormat1
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
extensionOffset != 0 &&
- extensionLookupType != T::LookupSubTable::Extension);
+ extensionLookupType != T::SubTable::Extension);
}
protected:
@@ -2290,8 +2590,8 @@ struct Extension
inline const X& get_subtable (void) const
{
switch (u.format) {
- case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
- default:return Null(typename T::LookupSubTable);
+ case 1: return u.format1.template get_subtable<typename T::SubTable> ();
+ default:return Null(typename T::SubTable);
}
}
@@ -2318,6 +2618,39 @@ struct Extension
* GSUB/GPOS Common
*/
+struct hb_ot_layout_lookup_accelerator_t
+{
+ template <typename TLookup>
+ inline void init (const TLookup &lookup)
+ {
+ digest.init ();
+ lookup.add_coverage (&digest);
+
+ subtables.init ();
+ OT::hb_get_subtables_context_t c_get_subtables (subtables);
+ lookup.dispatch (&c_get_subtables);
+ }
+ inline void fini (void)
+ {
+ subtables.fini ();
+ }
+
+ inline bool may_have (hb_codepoint_t g) const
+ { return digest.may_have (g); }
+
+ inline bool apply (hb_ot_apply_context_t *c) const
+ {
+ for (unsigned int i = 0; i < subtables.len; i++)
+ if (subtables[i].apply (c))
+ return true;
+ return false;
+ }
+
+ private:
+ hb_set_digest_t digest;
+ hb_get_subtables_context_t::array_t subtables;
+};
+
struct GSUBGPOS
{
inline bool has_data (void) const { return version.to_int () != 0; }
@@ -2370,17 +2703,78 @@ struct GSUBGPOS
return get_feature (feature_index);
}
+ template <typename TLookup>
+ inline bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ struct GSUBGPOS *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ out->scriptList.serialize_subset (c, this+scriptList, out);
+ out->featureList.serialize_subset (c, this+featureList, out);
+
+ typedef OffsetListOf<TLookup> TLookupList;
+ /* TODO Use intersects() to count how many subtables survive? */
+ CastR<OffsetTo<TLookupList> > (out->lookupList)
+ .serialize_subset (c,
+ this+CastR<const OffsetTo<TLookupList> > (lookupList),
+ out);
+
+ if (version.to_int () >= 0x00010001u)
+ out->featureVars.serialize_subset (c, this+featureVars, out);
+ return_trace (true);
+ }
+
+ inline unsigned int get_size (void) const
+ {
+ return min_size +
+ (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
+ }
+
+ template <typename TLookup>
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
+ typedef OffsetListOf<TLookup> TLookupList;
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
featureList.sanitize (c, this) &&
- lookupList.sanitize (c, this) &&
+ CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
(version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
}
+ template <typename T>
+ struct accelerator_t
+ {
+ inline void init (hb_face_t *face)
+ {
+ this->blob = hb_sanitize_context_t().reference_table<T> (face);
+ table = this->blob->template as<T> ();
+
+ this->lookup_count = table->get_lookup_count ();
+
+ this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
+ if (unlikely (!this->accels))
+ this->lookup_count = 0;
+
+ for (unsigned int i = 0; i < this->lookup_count; i++)
+ this->accels[i].init (table->get_lookup (i));
+ }
+
+ inline void fini (void)
+ {
+ for (unsigned int i = 0; i < this->lookup_count; i++)
+ this->accels[i].fini ();
+ free (this->accels);
+ hb_blob_destroy (this->blob);
+ }
+
+ hb_blob_t *blob;
+ const T *table;
+ unsigned int lookup_count;
+ hb_ot_layout_lookup_accelerator_t *accels;
+ };
+
protected:
FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
* to 0x00010000u */
@@ -2403,4 +2797,4 @@ struct GSUBGPOS
} /* namespace OT */
-#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
+#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
index 7fabdebb2..2fb23cbc3 100644
--- a/src/hb-ot-layout-jstf-table.hh
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_LAYOUT_JSTF_TABLE_HH
#define HB_OT_LAYOUT_JSTF_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
#include "hb-ot-layout-gpos-table.hh"
@@ -124,7 +124,7 @@ struct JstfPriority
struct JstfLangSys : OffsetListOf<JstfPriority>
{
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<JstfLangSys>::sanitize_closure_t * = nullptr) const
+ const Record_sanitize_closure_t * = nullptr) const
{
TRACE_SANITIZE (this);
return_trace (OffsetListOf<JstfPriority>::sanitize (c));
@@ -165,7 +165,7 @@ struct JstfScript
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 * = nullptr) const
+ const Record_sanitize_closure_t * = nullptr) const
{
TRACE_SANITIZE (this);
return_trace (extenderGlyphs.sanitize (c, this) &&
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 09ff0e6c0..fb1d9b11f 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -28,10 +28,11 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-open-type-private.hh"
-#include "hb-ot-layout-private.hh"
-#include "hb-ot-map-private.hh"
-#include "hb-map-private.hh"
+#include "hb-open-type.hh"
+#include "hb-ot-layout.hh"
+#include "hb-ot-face.hh"
+#include "hb-ot-map.hh"
+#include "hb-map.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
@@ -44,9 +45,73 @@
#include "hb-ot-color-cpal-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
+#include "hb-ot-kern-table.hh"
#include "hb-ot-name-table.hh"
+static const OT::kern::accelerator_t& _get_kern (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::kern::accelerator_t);
+ return *hb_ot_face_data (face)->kern;
+}
+const OT::GDEF& _get_gdef (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF);
+ return *hb_ot_face_data (face)->GDEF->table;
+}
+static hb_blob_t * _get_gsub_blob (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return hb_blob_get_empty ();
+ return hb_ot_face_data (face)->GSUB->blob;
+}
+static inline const OT::GSUB& _get_gsub (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GSUB);
+ return *hb_ot_face_data (face)->GSUB->table;
+}
+const OT::GSUB& _get_gsub_relaxed (hb_face_t *face)
+{
+ return *hb_ot_face_data (face)->GSUB.get_relaxed ()->table;
+}
+static hb_blob_t * _get_gpos_blob (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return hb_blob_get_empty ();
+ return hb_ot_face_data (face)->GPOS->blob;
+}
+static inline const OT::GPOS& _get_gpos (hb_face_t *face)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GPOS);
+ return *hb_ot_face_data (face)->GPOS->table;
+}
+const OT::GPOS& _get_gpos_relaxed (hb_face_t *face)
+{
+ return *hb_ot_face_data (face)->GPOS.get_relaxed ()->table;
+}
+
+
+/*
+ * kern
+ */
+
+hb_bool_t
+hb_ot_layout_has_kerning (hb_face_t *face)
+{
+ return _get_kern (face).has_data ();
+}
+
+void
+hb_ot_layout_kern (hb_font_t *font,
+ hb_buffer_t *buffer,
+ hb_mask_t kern_mask)
+{
+ _get_kern (font->face).apply (font, buffer, kern_mask);
+}
+
+
+/*
+ * GDEF
+ */
+
static bool
_hb_ot_blacklist_gdef (unsigned int gdef_len,
unsigned int gsub_len,
@@ -149,106 +214,39 @@ _hb_ot_blacklist_gdef (unsigned int gdef_len,
return false;
}
-void hb_ot_layout_t::tables_t::init0 (hb_face_t *face)
+inline void
+OT::GDEF::accelerator_t::init (hb_face_t *face)
{
- this->face = face;
-#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.init0 ();
- HB_OT_LAYOUT_TABLES
-#undef HB_OT_LAYOUT_TABLE
-}
-void hb_ot_layout_t::tables_t::fini (void)
-{
-#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.fini ();
- HB_OT_LAYOUT_TABLES
-#undef HB_OT_LAYOUT_TABLE
-}
+ this->blob = hb_sanitize_context_t().reference_table<GDEF> (face);
-hb_ot_layout_t *
-_hb_ot_layout_create (hb_face_t *face)
-{
- hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
- if (unlikely (!layout))
- return nullptr;
-
- layout->table.init0 (face);
-
- const OT::GSUB &gsub = *layout->table.GSUB;
- const OT::GPOS &gpos = *layout->table.GPOS;
-
- if (unlikely (_hb_ot_blacklist_gdef (layout->table.GDEF.get_blob ()->length,
- layout->table.GSUB.get_blob ()->length,
- layout->table.GPOS.get_blob ()->length)))
- layout->table.GDEF.set_stored (hb_blob_get_empty ());
-
- unsigned int gsub_lookup_count = layout->gsub_lookup_count = gsub.get_lookup_count ();
- unsigned int gpos_lookup_count = layout->gpos_lookup_count = gpos.get_lookup_count ();
-
- layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (gsub_lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
- layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (gpos_lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
-
- if (unlikely ((gsub_lookup_count && !layout->gsub_accels) ||
- (gpos_lookup_count && !layout->gpos_accels)))
+ if (unlikely (_hb_ot_blacklist_gdef (this->blob->length,
+ _get_gsub_blob (face)->length,
+ _get_gpos_blob (face)->length)))
{
- _hb_ot_layout_destroy (layout);
- return nullptr;
+ hb_blob_destroy (this->blob);
+ this->blob = hb_blob_get_empty ();
}
- for (unsigned int i = 0; i < gsub_lookup_count; i++)
- layout->gsub_accels[i].init (gsub.get_lookup (i));
- for (unsigned int i = 0; i < gpos_lookup_count; i++)
- layout->gpos_accels[i].init (gpos.get_lookup (i));
-
- return layout;
+ table = this->blob->as<GDEF> ();
}
-void
-_hb_ot_layout_destroy (hb_ot_layout_t *layout)
+static void
+_hb_ot_layout_set_glyph_props (hb_font_t *font,
+ hb_buffer_t *buffer)
{
- if (layout->gsub_accels)
- for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
- layout->gsub_accels[i].fini ();
- if (layout->gpos_accels)
- for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
- layout->gpos_accels[i].fini ();
+ _hb_buffer_assert_gsubgpos_vars (buffer);
- free (layout->gsub_accels);
- free (layout->gpos_accels);
-
- layout->table.fini ();
-
- free (layout);
-}
-
-// static inline const OT::BASE&
-// _get_base (hb_face_t *face)
-// {
-// if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::BASE);
-// hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
-// return *(layout->base.get ());
-// }
-
-static inline const OT::GDEF&
-_get_gdef (hb_face_t *face)
-{
- if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF);
- return *hb_ot_layout_from_face (face)->table.GDEF;
-}
-static inline const OT::GSUB&
-_get_gsub (hb_face_t *face)
-{
- if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GSUB);
- return *hb_ot_layout_from_face (face)->table.GSUB;
-}
-static inline const OT::GPOS&
-_get_gpos (hb_face_t *face)
-{
- if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GPOS);
- return *hb_ot_layout_from_face (face)->table.GPOS;
+ const OT::GDEF &gdef = _get_gdef (font->face);
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ _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;
+ }
}
-/*
- * GDEF
- */
+/* Public API */
hb_bool_t
hb_ot_layout_has_glyph_classes (hb_face_t *face)
@@ -324,7 +322,7 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *script_count /* IN/OUT */,
- hb_tag_t *script_tags /* OUT */)
+ hb_tag_t *script_tags /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -370,17 +368,36 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
unsigned int *script_index,
hb_tag_t *chosen_script)
{
+ const hb_tag_t *t;
+ for (t = script_tags; *t; t++);
+ return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script);
+}
+
+/**
+ * hb_ot_layout_table_select_script:
+ *
+ * Since: 2.0.0
+ **/
+hb_bool_t
+hb_ot_layout_table_select_script (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_count,
+ const hb_tag_t *script_tags,
+ unsigned int *script_index /* OUT */,
+ hb_tag_t *chosen_script /* OUT */)
+{
static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), "");
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ unsigned int i;
- while (*script_tags)
+ for (i = 0; i < script_count; i++)
{
- if (g.find_script_index (*script_tags, script_index)) {
+ if (g.find_script_index (script_tags[i], script_index))
+ {
if (chosen_script)
- *chosen_script = *script_tags;
+ *chosen_script = script_tags[i];
return true;
}
- script_tags++;
}
/* try finding 'DFLT' */
@@ -416,7 +433,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
- hb_tag_t *feature_tags /* OUT */)
+ hb_tag_t *feature_tags /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -452,7 +469,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
unsigned int script_index,
unsigned int start_offset,
unsigned int *language_count /* IN/OUT */,
- hb_tag_t *language_tags /* OUT */)
+ hb_tag_t *language_tags /* OUT */)
{
const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
@@ -466,13 +483,33 @@ hb_ot_layout_script_find_language (hb_face_t *face,
hb_tag_t language_tag,
unsigned int *language_index)
{
+ return hb_ot_layout_script_select_language (face, table_tag, script_index, 1, &language_tag, language_index);
+}
+
+/**
+ * hb_ot_layout_script_select_language:
+ *
+ * Since: 2.0.0
+ **/
+hb_bool_t
+hb_ot_layout_script_select_language (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_count,
+ const hb_tag_t *language_tags,
+ unsigned int *language_index /* OUT */)
+{
static_assert ((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);
+ unsigned int i;
- if (s.find_lang_sys_index (language_tag, language_index))
- return true;
+ for (i = 0; i < language_count; i++)
+ {
+ if (s.find_lang_sys_index (language_tags[i], language_index))
+ return true;
+ }
- /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
+ /* try finding 'dflt' */
if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
return false;
@@ -537,7 +574,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
unsigned int script_index,
unsigned int language_index,
unsigned int start_offset,
- unsigned int *feature_count /* IN/OUT */,
+ unsigned int *feature_count /* IN/OUT */,
unsigned int *feature_indexes /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
@@ -553,7 +590,7 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
unsigned int language_index,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
- hb_tag_t *feature_tags /* OUT */)
+ hb_tag_t *feature_tags /* OUT */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
@@ -607,7 +644,7 @@ 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_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */)
{
return hb_ot_layout_feature_with_variations_get_lookups (face,
@@ -633,11 +670,11 @@ hb_ot_layout_table_get_lookup_count (hb_face_t *face,
{
case HB_OT_TAG_GSUB:
{
- return hb_ot_layout_from_face (face)->gsub_lookup_count;
+ return hb_ot_face_data (face)->GSUB->lookup_count;
}
case HB_OT_TAG_GPOS:
{
- return hb_ot_layout_from_face (face)->gpos_lookup_count;
+ return hb_ot_face_data (face)->GPOS->lookup_count;
}
}
return 0;
@@ -745,11 +782,12 @@ _hb_ot_layout_collect_features_languages (hb_face_t *face,
for (; *languages; languages++)
{
unsigned int language_index;
- if (hb_ot_layout_script_find_language (face,
- table_tag,
- script_index,
- *languages,
- &language_index))
+ if (hb_ot_layout_script_select_language (face,
+ table_tag,
+ script_index,
+ 1,
+ languages,
+ &language_index))
_hb_ot_layout_collect_features_features (face,
table_tag,
script_index,
@@ -834,10 +872,10 @@ 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 nullptr */
- hb_set_t *glyphs_input, /* OUT. May be nullptr */
- hb_set_t *glyphs_after, /* OUT. May be nullptr */
- hb_set_t *glyphs_output /* OUT. May be nullptr */)
+ 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;
@@ -851,13 +889,13 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
{
case HB_OT_TAG_GSUB:
{
- const OT::SubstLookup& l = hb_ot_layout_from_face (face)->table.GSUB->get_lookup (lookup_index);
+ const OT::SubstLookup& l = hb_ot_face_data (face)->GSUB->table->get_lookup (lookup_index);
l.collect_glyphs (&c);
return;
}
case HB_OT_TAG_GPOS:
{
- const OT::PosLookup& l = hb_ot_layout_from_face (face)->table.GPOS->get_lookup (lookup_index);
+ const OT::PosLookup& l = hb_ot_face_data (face)->GPOS->table->get_lookup (lookup_index);
l.collect_glyphs (&c);
return;
}
@@ -930,18 +968,19 @@ hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
unsigned int glyphs_length,
hb_bool_t zero_context)
{
- if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
+ if (unlikely (lookup_index >= hb_ot_face_data (face)->GSUB->lookup_count)) return false;
OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
- const OT::SubstLookup& l = hb_ot_layout_from_face (face)->table.GSUB->get_lookup (lookup_index);
+ const OT::SubstLookup& l = hb_ot_face_data (face)->GSUB->table->get_lookup (lookup_index);
- return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
+ return l.would_apply (&c, &hb_ot_face_data (face)->GSUB->accels[lookup_index]);
}
void
-hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
+hb_ot_layout_substitute_start (hb_font_t *font,
+ hb_buffer_t *buffer)
{
- OT::GSUB::substitute_start (font, buffer);
+_hb_ot_layout_set_glyph_props (font, buffer);
}
/**
@@ -1034,11 +1073,11 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
**/
hb_bool_t
hb_ot_layout_get_size_params (hb_face_t *face,
- unsigned int *design_size, /* OUT. May be nullptr */
- unsigned int *subfamily_id, /* OUT. May be nullptr */
- unsigned int *subfamily_name_id, /* OUT. May be nullptr */
- unsigned int *range_start, /* OUT. May be nullptr */
- unsigned int *range_end /* OUT. May be nullptr */)
+ 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');
@@ -1053,30 +1092,152 @@ hb_ot_layout_get_size_params (hb_face_t *face,
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
+ if (design_size) *design_size = params.designSize;
+ if (subfamily_id) *subfamily_id = params.subfamilyID;
+ if (subfamily_name_id) *subfamily_name_id = params.subfamilyNameID;
+ if (range_start) *range_start = params.rangeStart;
+ if (range_end) *range_end = params.rangeEnd;
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
+ if (design_size) *design_size = 0;
+ if (subfamily_id) *subfamily_id = 0;
+ if (subfamily_name_id) *subfamily_name_id = 0;
+ if (range_start) *range_start = 0;
+ if (range_end) *range_end = 0;
return false;
}
+/**
+ * hb_ot_layout_feature_get_name_ids:
+ * @face: #hb_face_t to work upon
+ * @table_tag:
+ * @feature_index:
+ * @label_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * for a user-interface label for this feature. (May be NULL.)
+ * @tooltip_id: (out) (allow-none): The ‘name’ table name ID that specifies a string
+ * that an application can use for tooltip text for this
+ * feature. (May be NULL.)
+ * @sample_id: (out) (allow-none): The ‘name’ table name ID that specifies sample text
+ * that illustrates the effect of this feature. (May be NULL.)
+ * @num_named_parameters: (out) (allow-none): Number of named parameters. (May be zero.)
+ * @first_param_id: (out) (allow-none): 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.)
+ *
+ * Fetches name indices from feature parameters for "Stylistic Set" ('ssXX') or
+ * "Character Variant" ('cvXX') features.
+ *
+ * Return value: true if data found, false otherwise
+ *
+ * Since: 2.0.0
+ **/
+hb_bool_t
+hb_ot_layout_feature_get_name_ids (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ hb_name_id_t *label_id, /* OUT. May be NULL */
+ hb_name_id_t *tooltip_id, /* OUT. May be NULL */
+ hb_name_id_t *sample_id, /* OUT. May be NULL */
+ unsigned int *num_named_parameters, /* OUT. May be NULL */
+ hb_name_id_t *first_param_id /* OUT. May be NULL */)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ hb_tag_t feature_tag = g.get_feature_tag (feature_index);
+ const OT::Feature &f = g.get_feature (feature_index);
+
+ const OT::FeatureParams &feature_params = f.get_feature_params ();
+ if (&feature_params != &Null (OT::FeatureParams))
+ {
+ const OT::FeatureParamsStylisticSet& ss_params =
+ feature_params.get_stylistic_set_params (feature_tag);
+ if (&ss_params != &Null (OT::FeatureParamsStylisticSet)) /* ssXX */
+ {
+ if (label_id) *label_id = ss_params.uiNameID;
+ // ssXX features don't have the rest
+ if (tooltip_id) *tooltip_id = HB_NAME_ID_INVALID;
+ if (sample_id) *sample_id = HB_NAME_ID_INVALID;
+ if (num_named_parameters) *num_named_parameters = 0;
+ if (first_param_id) *first_param_id = HB_NAME_ID_INVALID;
+ return true;
+ }
+ const OT::FeatureParamsCharacterVariants& cv_params =
+ feature_params.get_character_variants_params (feature_tag);
+ if (&cv_params != &Null (OT::FeatureParamsCharacterVariants)) /* cvXX */
+ {
+ if (label_id) *label_id = cv_params.featUILableNameID;
+ if (tooltip_id) *tooltip_id = cv_params.featUITooltipTextNameID;
+ if (sample_id) *sample_id = cv_params.sampleTextNameID;
+ if (num_named_parameters) *num_named_parameters = cv_params.numNamedParameters;
+ if (first_param_id) *first_param_id = cv_params.firstParamUILabelNameID;
+ return true;
+ }
+ }
+
+ if (label_id) *label_id = HB_NAME_ID_INVALID;
+ if (tooltip_id) *tooltip_id = HB_NAME_ID_INVALID;
+ if (sample_id) *sample_id = HB_NAME_ID_INVALID;
+ if (num_named_parameters) *num_named_parameters = 0;
+ if (first_param_id) *first_param_id = HB_NAME_ID_INVALID;
+ return false;
+}
+
+/**
+ * hb_ot_layout_feature_get_characters::
+ * @face: #hb_face_t to work upon
+ * @table_tag:
+ * @feature_index:
+ * @start_offset: In case the resulting char_count was equal to its input value, there
+ * is a chance there were more characters on the tag so this API can be
+ * called with an offset till resulting char_count gets to a number
+ * lower than input buffer (or consider using just a bigger buffer for
+ * one shot copying).
+ * @char_count: (inout) (allow-none): The count of characters for which this feature
+ * provides glyph variants. (May be zero.)
+ * @characters: (out) (allow-none): A buffer pointer. The Unicode Scalar Value
+ * of the characters for which this feature provides glyph variants.
+ *
+ * Fetches characters listed by designer under feature parameters for "Character
+ * Variant" ("cvXX") features.
+ *
+ * Return value: Number of total sample characters in the cvXX feature.
+ *
+ * Since: 2.0.0
+ **/
+unsigned int
+hb_ot_layout_feature_get_characters (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int start_offset,
+ unsigned int *char_count, /* IN/OUT. May be NULL */
+ hb_codepoint_t *characters /* OUT. May be NULL */)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+
+ hb_tag_t feature_tag = g.get_feature_tag (feature_index);
+ const OT::Feature &f = g.get_feature (feature_index);
+
+ const OT::FeatureParams &feature_params = f.get_feature_params ();
+
+ const OT::FeatureParamsCharacterVariants& cv_params =
+ feature_params.get_character_variants_params(feature_tag);
+
+ unsigned int len = 0;
+ if (char_count && characters && start_offset < cv_params.characters.len)
+ {
+ len = MIN (cv_params.characters.len - start_offset, *char_count);
+ for (unsigned int i = 0; i < len; ++i)
+ characters[i] = cv_params.characters[start_offset + i];
+ }
+ if (char_count) *char_count = len;
+ return cv_params.characters.len;
+}
+
/*
* Parts of different types are implemented here such that they have direct
@@ -1086,86 +1247,36 @@ hb_ot_layout_get_size_params (hb_face_t *face,
struct GSUBProxy
{
- static const unsigned int table_index = 0;
+ enum { table_index = 0 };
static const bool inplace = false;
typedef OT::SubstLookup Lookup;
GSUBProxy (hb_face_t *face) :
- table (*hb_ot_layout_from_face (face)->table.GSUB),
- accels (hb_ot_layout_from_face (face)->gsub_accels) {}
+ table (*hb_ot_face_data (face)->GSUB->table),
+ accels (hb_ot_face_data (face)->GSUB->accels) {}
const OT::GSUB &table;
- const hb_ot_layout_lookup_accelerator_t *accels;
+ const OT::hb_ot_layout_lookup_accelerator_t *accels;
};
struct GPOSProxy
{
- static const unsigned int table_index = 1;
+ enum { table_index = 1 };
static const bool inplace = true;
typedef OT::PosLookup Lookup;
GPOSProxy (hb_face_t *face) :
- table (*hb_ot_layout_from_face (face)->table.GPOS),
- accels (hb_ot_layout_from_face (face)->gpos_accels) {}
+ table (*hb_ot_face_data (face)->GPOS->table),
+ accels (hb_ot_face_data (face)->GPOS->accels) {}
const OT::GPOS &table;
- const hb_ot_layout_lookup_accelerator_t *accels;
+ const OT::hb_ot_layout_lookup_accelerator_t *accels;
};
-struct hb_get_subtables_context_t :
- hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
-{
- template <typename Type>
- static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
- {
- const Type *typed_obj = (const Type *) obj;
- return typed_obj->apply (c);
- }
-
- typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
-
- struct hb_applicable_t
- {
- inline void init (const void *obj_, hb_apply_func_t apply_func_)
- {
- obj = obj_;
- apply_func = apply_func_;
- }
-
- inline bool apply (OT::hb_ot_apply_context_t *c) const { return apply_func (obj, c); }
-
- private:
- const void *obj;
- hb_apply_func_t apply_func;
- };
-
- typedef hb_auto_t<hb_vector_t<hb_applicable_t> > array_t;
-
- /* Dispatch interface. */
- inline const char *get_name (void) { return "GET_SUBTABLES"; }
- template <typename T>
- inline return_t dispatch (const T &obj)
- {
- hb_applicable_t *entry = array.push();
- entry->init (&obj, apply_to<T>);
- 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; }
-
- hb_get_subtables_context_t (array_t &array_) :
- array (array_),
- debug_depth (0) {}
-
- array_t &array;
- unsigned int debug_depth;
-};
-
static inline bool
apply_forward (OT::hb_ot_apply_context_t *c,
- const hb_ot_layout_lookup_accelerator_t &accel,
- const hb_get_subtables_context_t::array_t &subtables)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
@@ -1176,12 +1287,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
{
- for (unsigned int i = 0; i < subtables.len; i++)
- if (subtables[i].apply (c))
- {
- applied = true;
- break;
- }
+ applied = accel.apply (c);
}
if (applied)
@@ -1194,8 +1300,7 @@ apply_forward (OT::hb_ot_apply_context_t *c,
static inline bool
apply_backward (OT::hb_ot_apply_context_t *c,
- const hb_ot_layout_lookup_accelerator_t &accel,
- const hb_get_subtables_context_t::array_t &subtables)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
@@ -1205,12 +1310,8 @@ apply_backward (OT::hb_ot_apply_context_t *c,
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
{
- for (unsigned int i = 0; i < subtables.len; i++)
- if (subtables[i].apply (c))
- {
- ret = true;
- break;
- }
+ if (accel.apply (c))
+ ret = true;
}
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
@@ -1224,7 +1325,7 @@ template <typename Proxy>
static inline void
apply_string (OT::hb_ot_apply_context_t *c,
const typename Proxy::Lookup &lookup,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
hb_buffer_t *buffer = c->buffer;
@@ -1233,10 +1334,6 @@ apply_string (OT::hb_ot_apply_context_t *c,
c->set_lookup_props (lookup.get_props ());
- hb_get_subtables_context_t::array_t subtables;
- hb_get_subtables_context_t c_get_subtables (subtables);
- lookup.dispatch (&c_get_subtables);
-
if (likely (!lookup.is_reverse ()))
{
/* in/out forward substitution/positioning */
@@ -1245,7 +1342,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
buffer->idx = 0;
bool ret;
- ret = apply_forward (c, accel, subtables);
+ ret = apply_forward (c, accel);
if (ret)
{
if (!Proxy::inplace)
@@ -1261,7 +1358,7 @@ apply_string (OT::hb_ot_apply_context_t *c,
buffer->remove_output ();
buffer->idx = buffer->len - 1;
- apply_backward (c, accel, subtables);
+ apply_backward (c, accel);
}
}
@@ -1286,6 +1383,11 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
c.set_lookup_mask (lookups[table_index][i].mask);
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
+ if (lookups[table_index][i].random)
+ {
+ c.set_random (true);
+ buffer->unsafe_to_break_all ();
+ }
apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index),
proxy.accels[lookup_index]);
@@ -1315,31 +1417,7 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_
void
hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
const OT::SubstLookup &lookup,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const OT::hb_ot_layout_lookup_accelerator_t &accel)
{
apply_string<GSUBProxy> (c, lookup, accel);
}
-
-
-
-
-/*
- * OT::BASE
- */
-
-// /**
-// * hb_ot_base_has_data:
-// * @face: #hb_face_t to test
-// *
-// * This function allows to verify the presence of an OpenType BASE table on the
-// * face.
-// *
-// * Return value: true if face has a BASE table, false otherwise
-// *
-// * Since: XXX
-// **/
-// hb_bool_t
-// hb_ot_base_has_data (hb_face_t *face)
-// {
-// return _get_base (face).has_data ();
-// }
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index 586fb1517..9bd18c8af 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -34,6 +34,7 @@
#include "hb.h"
#include "hb-ot-tag.h"
+#include "hb-ot-name.h"
HB_BEGIN_DECLS
@@ -111,13 +112,13 @@ hb_ot_layout_table_find_script (hb_face_t *face,
hb_tag_t script_tag,
unsigned int *script_index);
-/* Like find_script, but takes zero-terminated array of scripts to test */
HB_EXTERN hb_bool_t
-hb_ot_layout_table_choose_script (hb_face_t *face,
+hb_ot_layout_table_select_script (hb_face_t *face,
hb_tag_t table_tag,
+ unsigned int script_count,
const hb_tag_t *script_tags,
- unsigned int *script_index,
- hb_tag_t *chosen_script);
+ unsigned int *script_index /* OUT */,
+ hb_tag_t *chosen_script /* OUT */);
HB_EXTERN unsigned int
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
@@ -135,11 +136,12 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
hb_tag_t *language_tags /* OUT */);
HB_EXTERN hb_bool_t
-hb_ot_layout_script_find_language (hb_face_t *face,
- hb_tag_t table_tag,
- unsigned int script_index,
- hb_tag_t language_tag,
- unsigned int *language_index);
+hb_ot_layout_script_select_language (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_count,
+ const hb_tag_t *language_tags,
+ unsigned int *language_index /* OUT */);
HB_EXTERN hb_bool_t
hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
@@ -214,10 +216,10 @@ HB_EXTERN 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 */);
+ 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
@@ -325,11 +327,30 @@ HB_EXTERN 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 */
+ hb_name_id_t *subfamily_name_id, /* OUT. May be NULL */
unsigned int *range_start, /* OUT. May be NULL */
unsigned int *range_end /* OUT. May be NULL */);
+HB_EXTERN hb_bool_t
+hb_ot_layout_feature_get_name_ids (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ hb_name_id_t *label_id /* OUT. May be NULL */,
+ hb_name_id_t *tooltip_id /* OUT. May be NULL */,
+ hb_name_id_t *sample_id /* OUT. May be NULL */,
+ unsigned int *num_named_parameters /* OUT. May be NULL */,
+ hb_name_id_t *first_param_id /* OUT. May be NULL */);
+
+
+HB_EXTERN unsigned int
+hb_ot_layout_feature_get_characters (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int start_offset,
+ unsigned int *char_count /* IN/OUT. May be NULL */,
+ hb_codepoint_t *characters /* OUT. May be NULL */);
+
/*
* BASE
*/
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout.hh
index 612bc7fce..64b3d7480 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout.hh
@@ -26,15 +26,40 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_LAYOUT_PRIVATE_HH
-#define HB_OT_LAYOUT_PRIVATE_HH
+#ifndef HB_OT_LAYOUT_HH
+#define HB_OT_LAYOUT_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
-#include "hb-set-digest-private.hh"
-#include "hb-open-type-private.hh"
+#include "hb-font.hh"
+#include "hb-buffer.hh"
+#include "hb-open-type.hh"
+#include "hb-set-digest.hh"
+
+
+namespace OT
+{
+ struct GDEF;
+ struct GSUB;
+ struct GPOS;
+}
+
+HB_INTERNAL const OT::GDEF& _get_gdef (hb_face_t *face);
+HB_INTERNAL const OT::GSUB& _get_gsub_relaxed (hb_face_t *face);
+HB_INTERNAL const OT::GPOS& _get_gpos_relaxed (hb_face_t *face);
+
+
+/*
+ * kern
+ */
+
+HB_INTERNAL hb_bool_t
+hb_ot_layout_has_kerning (hb_face_t *face);
+
+HB_INTERNAL void
+hb_ot_layout_kern (hb_font_t *font,
+ hb_buffer_t *buffer,
+ hb_mask_t kern_mask);
/* Private API corresponding to hb-ot-layout.h: */
@@ -87,17 +112,16 @@ hb_ot_layout_substitute_start (hb_font_t *font,
hb_buffer_t *buffer);
-struct hb_ot_layout_lookup_accelerator_t;
-
namespace OT {
struct hb_ot_apply_context_t;
struct SubstLookup;
+ struct hb_ot_layout_lookup_accelerator_t;
}
HB_INTERNAL void
hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
const OT::SubstLookup &lookup,
- const hb_ot_layout_lookup_accelerator_t &accel);
+ const OT::hb_ot_layout_lookup_accelerator_t &accel);
/* Should be called before all the position_lookup's are done. */
@@ -116,112 +140,6 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font,
hb_buffer_t *buffer);
-
-/*
- * hb_ot_layout_t
- */
-
-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;
-};
-
-/* Most of these tables are NOT needed for shaping. But we need to hook them *somewhere*.
- * This is as good as any place. */
-#define HB_OT_LAYOUT_TABLES \
- /* OpenType shaping. */ \
- HB_OT_LAYOUT_TABLE(OT, GDEF) \
- HB_OT_LAYOUT_TABLE(OT, GSUB) \
- HB_OT_LAYOUT_TABLE(OT, GPOS) \
- HB_OT_LAYOUT_TABLE(OT, JSTF) \
- HB_OT_LAYOUT_TABLE(OT, BASE) \
- /* AAT shaping. */ \
- HB_OT_LAYOUT_TABLE(AAT, morx) \
- HB_OT_LAYOUT_TABLE(AAT, kerx) \
- HB_OT_LAYOUT_TABLE(AAT, ankr) \
- HB_OT_LAYOUT_TABLE(AAT, trak) \
- /* OpenType variations. */ \
- HB_OT_LAYOUT_TABLE(OT, fvar) \
- HB_OT_LAYOUT_TABLE(OT, avar) \
- HB_OT_LAYOUT_TABLE(OT, MVAR) \
- /* OpenType color. */ \
- HB_OT_LAYOUT_TABLE(OT, COLR) \
- HB_OT_LAYOUT_TABLE(OT, CPAL) \
- HB_OT_LAYOUT_TABLE(OT, CBDT) \
- HB_OT_LAYOUT_TABLE(OT, CBLC) \
- HB_OT_LAYOUT_TABLE(OT, sbix) \
- HB_OT_LAYOUT_TABLE(OT, svg) \
- /* OpenType math. */ \
- HB_OT_LAYOUT_TABLE(OT, MATH) \
- /* OpenType fundamentals. */ \
- HB_OT_LAYOUT_TABLE(OT, post) \
- /* */
-
-/* Declare tables. */
-#define HB_OT_LAYOUT_TABLE(Namespace, Type) namespace Namespace { struct Type; }
-HB_OT_LAYOUT_TABLES
-#undef HB_OT_LAYOUT_TABLE
-
-struct hb_ot_layout_t
-{
- 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;
-
- /* Various non-shaping tables. */
- struct tables_t
- {
- HB_INTERNAL void init0 (hb_face_t *face);
- HB_INTERNAL void fini (void);
-
-#define HB_OT_LAYOUT_TABLE_ORDER(Namespace, Type) \
- HB_PASTE (ORDER_, HB_PASTE (Namespace, HB_PASTE (_, Type)))
- enum order_t
- {
- ORDER_ZERO,
-#define HB_OT_LAYOUT_TABLE(Namespace, Type) \
- HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type),
- HB_OT_LAYOUT_TABLES
-#undef HB_OT_LAYOUT_TABLE
- };
-
- hb_face_t *face; /* MUST be JUST before the lazy loaders. */
-#define HB_OT_LAYOUT_TABLE(Namespace, Type) \
- hb_table_lazy_loader_t<struct Namespace::Type, HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type)> Type;
- HB_OT_LAYOUT_TABLES
-#undef HB_OT_LAYOUT_TABLE
- } table;
-};
-
-
-HB_INTERNAL hb_ot_layout_t *
-_hb_ot_layout_create (hb_face_t *face);
-
-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.get_relaxed ())
-
-
/*
* Buffer var routines.
*/
@@ -239,12 +157,12 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout);
#define foreach_syllable(buffer, start, end) \
for (unsigned int \
_count = buffer->len, \
- start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
+ start = 0, end = _count ? _hb_next_syllable (buffer, 0) : 0; \
start < _count; \
- start = end, end = _next_syllable (buffer, start))
+ start = end, end = _hb_next_syllable (buffer, start))
static inline unsigned int
-_next_syllable (hb_buffer_t *buffer, unsigned int start)
+_hb_next_syllable (hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
@@ -267,7 +185,7 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start)
* * Whether it's one of the three Mongolian Free Variation Selectors,
* CGJ, or other characters that are hidden but should not be ignored
* like most other Default_Ignorable()s do during matching.
- * * One free bit right now.
+ * * Whether it's a grapheme continuation.
*
* The high-byte has different meanings, switched by the Gen-Cat:
* - For Mn,Mc,Me: the modified Combining_Class.
@@ -279,8 +197,8 @@ _next_syllable (hb_buffer_t *buffer, unsigned int start)
enum hb_unicode_props_flags_t {
UPROPS_MASK_GEN_CAT = 0x001Fu,
UPROPS_MASK_IGNORABLE = 0x0020u,
- UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3,
- * or TAG characters */
+ UPROPS_MASK_HIDDEN = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3, or TAG characters */
+ UPROPS_MASK_CONTINUATION=0x0080u,
/* If GEN_CAT=FORMAT, top byte masks: */
UPROPS_MASK_Cf_ZWJ = 0x0100u,
@@ -299,6 +217,7 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
if (u >= 0x80)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
+
if (unlikely (unicode->is_default_ignorable (u)))
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
@@ -324,35 +243,11 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
props |= UPROPS_MASK_HIDDEN;
}
}
- else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
+
+ if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (gen_cat)))
{
- /* The above check is just an optimization to let in only things we need further
- * processing on. */
-
- /* Only Mn and Mc can have non-zero ccc:
- * https://unicode.org/policies/stability_policy.html#Property_Value
- * """
- * Canonical_Combining_Class, General_Category
- * All characters other than those with General_Category property values
- * Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
- * property value 0.
- * 1.1.5+
- * """
- *
- * Also, all Mn's that are Default_Ignorable, have ccc=0, hence
- * the "else if".
- */
- props |= unicode->modified_combining_class (info->codepoint)<<8;
-
- /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
- * behave correctly in non-native directionality. They originally
- * are MODIFIER_SYMBOL. Fixes:
- * https://github.com/harfbuzz/harfbuzz/issues/169
- */
- if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
- {
- props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
- }
+ props |= UPROPS_MASK_CONTINUATION;
+ props |= unicode->modified_combining_class (u)<<8;
}
}
@@ -391,29 +286,6 @@ _hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
}
-
-
-/* Loop over grapheme. Based on foreach_cluster(). */
-#define foreach_grapheme(buffer, start, end) \
- for (unsigned int \
- _count = buffer->len, \
- start = 0, end = _count ? _next_grapheme (buffer, 0) : 0; \
- start < _count; \
- start = end, end = _next_grapheme (buffer, start))
-
-static inline unsigned int
-_next_grapheme (hb_buffer_t *buffer, unsigned int start)
-{
- hb_glyph_info_t *info = buffer->info;
- unsigned int count = buffer->len;
-
- while (++start < count && _hb_glyph_info_is_unicode_mark (&info[start]))
- ;
-
- return start;
-}
-
-
#define info_cc(info) (_hb_glyph_info_get_modified_combining_class (&(info)))
static inline bool
@@ -458,6 +330,41 @@ _hb_glyph_info_unhide (hb_glyph_info_t *info)
info->unicode_props() &= ~ UPROPS_MASK_HIDDEN;
}
+static inline void
+_hb_glyph_info_set_continuation (hb_glyph_info_t *info)
+{
+ info->unicode_props() |= UPROPS_MASK_CONTINUATION;
+}
+static inline void
+_hb_glyph_info_reset_continuation (hb_glyph_info_t *info)
+{
+ info->unicode_props() &= ~ UPROPS_MASK_CONTINUATION;
+}
+static inline bool
+_hb_glyph_info_is_continuation (const hb_glyph_info_t *info)
+{
+ return info->unicode_props() & UPROPS_MASK_CONTINUATION;
+}
+/* Loop over grapheme. Based on foreach_cluster(). */
+#define foreach_grapheme(buffer, start, end) \
+ for (unsigned int \
+ _count = buffer->len, \
+ start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \
+ start < _count; \
+ start = end, end = _hb_next_grapheme (buffer, start))
+
+static inline unsigned int
+_hb_next_grapheme (hb_buffer_t *buffer, unsigned int start)
+{
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+
+ while (++start < count && _hb_glyph_info_is_continuation (&info[start]))
+ ;
+
+ return start;
+}
+
static inline bool
_hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
{
@@ -701,4 +608,4 @@ _hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
#undef lig_props
#undef glyph_props
-#endif /* HB_OT_LAYOUT_PRIVATE_HH */
+#endif /* HB_OT_LAYOUT_HH */
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index f26cac9b1..45d7dbdcf 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -26,9 +26,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-map-private.hh"
+#include "hb-ot-map.hh"
-#include "hb-ot-layout-private.hh"
+#include "hb-ot-layout.hh"
void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
@@ -54,16 +54,17 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
/* 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;
+ unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
+ unsigned int language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
+ hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+ hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
- hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
- language_tag = hb_ot_tag_from_language (props.language);
+ hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags);
for (unsigned int table_index = 0; table_index < 2; table_index++) {
hb_tag_t table_tag = table_tags[table_index];
- found_script[table_index] = (bool) 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]);
+ found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]);
+ hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]);
}
}
@@ -74,8 +75,9 @@ hb_ot_map_builder_t::~hb_ot_map_builder_t (void)
stages[table_index].fini ();
}
-void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
- hb_ot_map_feature_flags_t flags)
+void hb_ot_map_builder_t::add_feature (hb_tag_t tag,
+ hb_ot_map_feature_flags_t flags,
+ unsigned int value)
{
feature_info_t *info = feature_infos.push();
if (unlikely (!tag)) return;
@@ -95,7 +97,8 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
unsigned int variations_index,
hb_mask_t mask,
bool auto_zwnj,
- bool auto_zwj)
+ bool auto_zwj,
+ bool random)
{
unsigned int lookup_indices[32];
unsigned int offset, len;
@@ -122,6 +125,7 @@ hb_ot_map_builder_t::add_lookups (hb_ot_map_t &m,
lookup->index = lookup_indices[i];
lookup->auto_zwnj = auto_zwnj;
lookup->auto_zwj = auto_zwj;
+ lookup->random = random;
}
offset += len;
@@ -208,8 +212,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
/* Uses the global bit */
bits_needed = 0;
else
- /* Limit to 8 bits per feature. */
- bits_needed = MIN(8u, hb_bit_storage (info->max_value));
+ /* Limit bits per feature. */
+ bits_needed = MIN(HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
continue; /* Feature disabled, or not enough bits. */
@@ -252,6 +256,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->stage[1] = info->stage[1];
map->auto_zwnj = !(info->flags & F_MANUAL_ZWNJ);
map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
+ map->random = !!(info->flags & F_RANDOM);
if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */
map->shift = global_bit_shift;
@@ -301,7 +306,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
variations_index,
m.features[i].mask,
m.features[i].auto_zwnj,
- m.features[i].auto_zwj);
+ m.features[i].auto_zwj,
+ m.features[i].random);
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].len)
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map.hh
index 4aaf32831..40b9921fd 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map.hh
@@ -26,12 +26,15 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_MAP_PRIVATE_HH
-#define HB_OT_MAP_PRIVATE_HH
+#ifndef HB_OT_MAP_HH
+#define HB_OT_MAP_HH
-#include "hb-buffer-private.hh"
+#include "hb-buffer.hh"
+#define HB_OT_MAP_MAX_BITS 8u
+#define HB_OT_MAP_MAX_VALUE ((1u << HB_OT_MAP_MAX_BITS) - 1u)
+
struct hb_ot_shape_plan_t;
static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
@@ -52,6 +55,7 @@ struct hb_ot_map_t
unsigned int needs_fallback : 1;
unsigned int auto_zwnj : 1;
unsigned int auto_zwj : 1;
+ unsigned int random : 1;
inline int cmp (const hb_tag_t *tag_) const
{ return *tag_ < tag ? -1 : *tag_ > tag ? 1 : 0; }
@@ -61,6 +65,7 @@ struct hb_ot_map_t
unsigned short index;
unsigned short auto_zwnj : 1;
unsigned short auto_zwj : 1;
+ unsigned short random : 1;
hb_mask_t mask;
static int cmp (const void *pa, const void *pb)
@@ -161,17 +166,27 @@ struct hb_ot_map_t
hb_vector_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
};
-enum hb_ot_map_feature_flags_t {
+enum hb_ot_map_feature_flags_t
+{
F_NONE = 0x0000u,
F_GLOBAL = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
F_HAS_FALLBACK = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
F_MANUAL_ZWNJ = 0x0004u, /* Don't skip over ZWNJ when matching **context**. */
F_MANUAL_ZWJ = 0x0008u, /* Don't skip over ZWJ when matching **input**. */
- F_GLOBAL_SEARCH = 0x0010u /* If feature not found in LangSys, look for it in global feature list and pick one. */
+ F_MANUAL_JOINERS = F_MANUAL_ZWNJ | F_MANUAL_ZWJ,
+ F_GLOBAL_MANUAL_JOINERS= F_GLOBAL | F_MANUAL_JOINERS,
+ F_GLOBAL_HAS_FALLBACK = F_GLOBAL | F_HAS_FALLBACK,
+ F_GLOBAL_SEARCH = 0x0010u, /* If feature not found in LangSys, look for it in global feature list and pick one. */
+ F_RANDOM = 0x0020u /* Randomly select a glyph from an AlternateSubstFormat1 subtable. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
-/* Macro version for where const is desired. */
-#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
+
+
+struct hb_ot_map_feature_t
+{
+ hb_tag_t tag;
+ hb_ot_map_feature_flags_t flags;
+};
struct hb_ot_map_builder_t
@@ -183,11 +198,20 @@ struct hb_ot_map_builder_t
HB_INTERNAL ~hb_ot_map_builder_t (void);
- HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value,
- hb_ot_map_feature_flags_t flags);
+ HB_INTERNAL void add_feature (hb_tag_t tag,
+ hb_ot_map_feature_flags_t flags=F_NONE,
+ unsigned int value=1);
+
+ inline void add_feature (const hb_ot_map_feature_t &feat)
+ { add_feature (feat.tag, feat.flags); }
+
+ inline void enable_feature (hb_tag_t tag,
+ hb_ot_map_feature_flags_t flags=F_NONE,
+ unsigned int value=1)
+ { add_feature (tag, F_GLOBAL | flags, value); }
- inline void add_global_bool_feature (hb_tag_t tag)
- { add_feature (tag, 1, F_GLOBAL); }
+ inline void disable_feature (hb_tag_t tag)
+ { add_feature (tag, F_GLOBAL, 0); }
inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
{ add_pause (0, pause_func); }
@@ -206,7 +230,8 @@ struct hb_ot_map_builder_t
unsigned int variations_index,
hb_mask_t mask,
bool auto_zwnj = true,
- bool auto_zwj = true);
+ bool auto_zwj = true,
+ bool random = false);
struct feature_info_t {
hb_tag_t tag;
@@ -250,4 +275,4 @@ struct hb_ot_map_builder_t
-#endif /* HB_OT_MAP_PRIVATE_HH */
+#endif /* HB_OT_MAP_HH */
diff --git a/src/hb-ot-math-table.hh b/src/hb-ot-math-table.hh
index 2dd714580..2f871124c 100644
--- a/src/hb-ot-math-table.hh
+++ b/src/hb-ot-math-table.hh
@@ -27,8 +27,8 @@
#ifndef HB_OT_MATH_TABLE_HH
#define HB_OT_MATH_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-ot-layout-common-private.hh"
+#include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
#include "hb-ot-math.h"
namespace OT {
@@ -50,7 +50,7 @@ struct MathValueRecord
protected:
HBINT16 value; /* The X or Y value in design units */
OffsetTo<Device> deviceTable; /* Offset to the device table - from the
- * beginning of parent table. May be nullptr.
+ * beginning of parent table. May be NULL.
* Suggested format for device table is 1. */
public:
@@ -234,7 +234,7 @@ struct MathKern
TRACE_SANITIZE (this);
unsigned int count = 2 * heightCount + 1;
for (unsigned int i = 0; i < count; i++)
- if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
+ if (!mathValueRecordsZ.arrayZ[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
@@ -242,16 +242,14 @@ struct MathKern
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
- c->check_array (mathValueRecords,
- mathValueRecords[0].static_size,
- 2 * heightCount + 1) &&
+ c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
sanitize_math_value_records (c));
}
inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
{
- const MathValueRecord* correctionHeight = mathValueRecords;
- const MathValueRecord* kernValue = mathValueRecords + heightCount;
+ const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ;
+ const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount;
int sign = font->y_scale < 0 ? -1 : +1;
/* The description of the MathKern table is a ambiguous, but interpreting
@@ -279,18 +277,19 @@ struct MathKern
}
protected:
- HBUINT16 heightCount;
- MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
- * which the kern value changes.
- * Sorted by the height value in
- * design units (heightCount entries),
- * Followed by:
- * Array of kern values corresponding
- * to heights. (heightCount+1 entries).
- */
+ HBUINT16 heightCount;
+ UnsizedArrayOf<MathValueRecord>
+ mathValueRecordsZ; /* Array of correction heights at
+ * which the kern value changes.
+ * Sorted by the height value in
+ * design units (heightCount entries),
+ * Followed by:
+ * Array of kern values corresponding
+ * to heights. (heightCount+1 entries).
+ */
public:
- DEFINE_SIZE_ARRAY (2, mathValueRecords);
+ DEFINE_SIZE_ARRAY (2, mathValueRecordsZ);
};
struct MathKernInfoRecord
@@ -319,7 +318,7 @@ struct MathKernInfoRecord
protected:
/* Offset to MathKern table for each corner -
- * from the beginning of MathKernInfo table. May be nullptr. */
+ * from the beginning of MathKernInfo table. May be NULL. */
OffsetTo<MathKern> mathKern[4];
public:
@@ -402,7 +401,7 @@ struct MathGlyphInfo
* from the beginning of MathGlyphInfo table. When the left or right glyph of
* a box is an extended shape variant, the (ink) box (and not the default
* position defined by values in MathConstants table) should be used for
- * vertical positioning purposes. May be nullptr.. */
+ * vertical positioning purposes. May be NULL.. */
OffsetTo<Coverage> extendedShapeCoverage;
/* Offset to MathKernInfo table -
@@ -571,7 +570,7 @@ struct MathGlyphConstruction
protected:
/* Offset to MathGlyphAssembly table for this shape - from the beginning of
- MathGlyphConstruction table. May be nullptr. */
+ MathGlyphConstruction table. May be NULL. */
OffsetTo<MathGlyphAssembly> glyphAssembly;
/* MathGlyphVariantRecords for alternative variants of the glyphs. */
@@ -588,7 +587,7 @@ struct MathVariants
TRACE_SANITIZE (this);
unsigned int count = vertGlyphCount + horizGlyphCount;
for (unsigned int i = 0; i < count; i++)
- if (!glyphConstruction[i].sanitize (c, this)) return_trace (false);
+ if (!glyphConstruction.arrayZ[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
@@ -598,9 +597,7 @@ struct MathVariants
return_trace (c->check_struct (this) &&
vertGlyphCoverage.sanitize (c, this) &&
horizGlyphCoverage.sanitize (c, this) &&
- c->check_array (glyphConstruction,
- glyphConstruction[0].static_size,
- vertGlyphCount + horizGlyphCount) &&
+ c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
sanitize_offsets (c));
}
@@ -670,7 +667,8 @@ struct MathVariants
/* Array of offsets to MathGlyphConstruction tables - from the beginning of
the MathVariants table, for shapes growing in vertical/horizontal
direction. */
- OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
+ UnsizedArrayOf<OffsetTo<MathGlyphConstruction> >
+ glyphConstruction;
public:
DEFINE_SIZE_ARRAY (10, glyphConstruction);
diff --git a/src/hb-ot-math.cc b/src/hb-ot-math.cc
index 66ce207a7..c693f4807 100644
--- a/src/hb-ot-math.cc
+++ b/src/hb-ot-math.cc
@@ -24,17 +24,17 @@
* Igalia Author(s): Frédéric Wang
*/
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
-#include "hb-ot-layout-private.hh"
+#include "hb-ot-face.hh"
#include "hb-ot-math-table.hh"
static inline const OT::MATH&
_get_math (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::MATH);
- hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
- return *(layout->table.MATH.get ());
+ hb_ot_face_data_t * data = hb_ot_face_data (face);
+ return *(data->MATH.get ());
}
/*
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index 75aac4f44..2572ad288 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -27,8 +27,7 @@
#ifndef HB_OT_MAXP_TABLE_HH
#define HB_OT_MAXP_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-subset-plan.hh"
+#include "hb-open-type.hh"
namespace OT {
@@ -137,7 +136,7 @@ struct maxp
FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0),
* 0x00005000u or 0x00010000u. */
HBUINT16 numGlyphs; /* The number of glyphs in the font. */
-/*maxpV1Tail v1Tail[VAR]; */
+/*maxpV1Tail v1Tail[VAR]; */
public:
DEFINE_SIZE_STATIC (6);
};
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index bff85df27..bb49c2cb0 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_NAME_TABLE_HH
#define HB_OT_NAME_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
namespace OT {
@@ -91,7 +91,7 @@ struct name
key.encodingID.set (encoding_id);
key.languageID.set (language_id);
key.nameID.set (name_id);
- NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), NameRecord::cmp);
+ NameRecord *match = (NameRecord *) bsearch (&key, nameRecordZ.arrayZ, count, sizeof (nameRecordZ[0]), NameRecord::cmp);
if (!match)
return 0;
@@ -102,14 +102,14 @@ struct name
}
inline unsigned int get_size (void) const
- { return min_size + count * nameRecord[0].min_size; }
+ { return min_size + count * nameRecordZ[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++)
- if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false);
+ if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false);
return_trace (true);
}
@@ -118,7 +118,7 @@ struct name
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
likely (format == 0 || format == 1) &&
- c->check_array (nameRecord, nameRecord[0].static_size, count) &&
+ c->check_array (nameRecordZ.arrayZ, count) &&
sanitize_records (c));
}
@@ -126,9 +126,10 @@ struct name
HBUINT16 format; /* Format selector (=0/1). */
HBUINT16 count; /* Number of name records. */
Offset16 stringOffset; /* Offset to start of string storage (from start of table). */
- NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */
+ UnsizedArrayOf<NameRecord>
+ nameRecordZ; /* The name records where count is the number of records. */
public:
- DEFINE_SIZE_ARRAY (6, nameRecord);
+ DEFINE_SIZE_ARRAY (6, nameRecordZ);
};
diff --git a/src/hb-aat-layout-private.hh b/src/hb-ot-name.h
index ce75c8e71..49423e87c 100644
--- a/src/hb-aat-layout-private.hh
+++ b/src/hb-ot-name.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2017 Google, Inc.
+ * Copyright © 2018 Ebrahim Byagowi.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -20,24 +20,34 @@
* 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_AAT_LAYOUT_PRIVATE_HH
-#define HB_AAT_LAYOUT_PRIVATE_HH
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_NAME_H
+#define HB_OT_NAME_H
+
+#include "hb.h"
-#include "hb-private.hh"
+HB_BEGIN_DECLS
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
-#include "hb-open-type-private.hh"
+/**
+ * hb_name_id_t:
+ *
+ * Since: 2.0.0
+ */
+typedef unsigned int hb_name_id_t;
-HB_INTERNAL void
-hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer);
+/**
+ * HB_NAME_ID_INVALID
+ *
+ * Since: 2.0.0
+ **/
+#define HB_NAME_ID_INVALID 0xFFFF
-HB_INTERNAL void
-hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer);
+HB_END_DECLS
-#endif /* HB_AAT_LAYOUT_PRIVATE_HH */
+#endif /* HB_OT_NAME_H */
diff --git a/src/hb-ot-os2-table.hh b/src/hb-ot-os2-table.hh
index 56bbab741..71d2bf59d 100644
--- a/src/hb-ot-os2-table.hh
+++ b/src/hb-ot-os2-table.hh
@@ -27,9 +27,8 @@
#ifndef HB_OT_OS2_TABLE_HH
#define HB_OT_OS2_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
#include "hb-ot-os2-unicode-ranges.hh"
-#include "hb-subset-plan.hh"
namespace OT {
@@ -82,7 +81,7 @@ struct os2
hb_codepoint_t cp = HB_SET_VALUE_INVALID;
while (codepoints->next (&cp)) {
- unsigned int bit = hb_get_unicode_range_bit (cp);
+ unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp);
if (bit < 128)
{
unsigned int block = bit / 32;
diff --git a/src/hb-ot-os2-unicode-ranges.hh b/src/hb-ot-os2-unicode-ranges.hh
index cb1260784..19780088a 100644
--- a/src/hb-ot-os2-unicode-ranges.hh
+++ b/src/hb-ot-os2-unicode-ranges.hh
@@ -27,18 +27,33 @@
#ifndef HB_OT_OS2_UNICODE_RANGES_HH
#define HB_OT_OS2_UNICODE_RANGES_HH
-#include "hb-private.hh"
+#include "hb.hh"
namespace OT {
-struct Range {
+struct OS2Range
+{
+ static int
+ cmp (const void *_key, const void *_item, void *_arg)
+ {
+ hb_codepoint_t cp = *((hb_codepoint_t *) _key);
+ const OS2Range *range = (OS2Range *) _item;
+
+ if (cp < range->start)
+ return -1;
+ else if (cp <= range->end)
+ return 0;
+ else
+ return +1;
+ }
+
hb_codepoint_t start;
hb_codepoint_t end;
unsigned int bit;
};
-/* Note: The contents of this array was generated using src/gen-unicode-ranges.py. */
-static Range os2UnicodeRangesSorted[] =
+/* Note: The contents of this array was generated using gen-os2-unicode-ranges.py. */
+static const OS2Range _hb_os2_unicode_ranges[] =
{
{ 0x0, 0x7F, 0}, // Basic Latin
{ 0x80, 0xFF, 1}, // Latin-1 Supplement
@@ -211,31 +226,17 @@ static Range os2UnicodeRangesSorted[] =
{0x100000, 0x10FFFD, 90}, // Private Use (plane 16)
};
-static int
-_compare_range (const void *_key, const void *_item, void *_arg)
-{
- hb_codepoint_t cp = *((hb_codepoint_t *) _key);
- const Range *range = (Range *) _item;
-
- if (cp < range->start)
- return -1;
- else if (cp <= range->end)
- return 0;
- else
- return 1;
-}
-
/**
- * hb_get_unicode_range_bit:
- * Returns the bit to be set in os/2 ulUnicodeRange for a given codepoint.
+ * _hb_ot_os2_get_unicode_range_bit:
+ * Returns the bit to be set in os/2 ulUnicodeOS2Range for a given codepoint.
**/
static unsigned int
-hb_get_unicode_range_bit (hb_codepoint_t cp)
+_hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp)
{
- Range *range = (Range*) hb_bsearch_r (&cp, os2UnicodeRangesSorted,
- sizeof (os2UnicodeRangesSorted) / sizeof(Range),
- sizeof(Range),
- _compare_range, nullptr);
+ OS2Range *range = (OS2Range*) hb_bsearch_r (&cp, _hb_os2_unicode_ranges,
+ ARRAY_LENGTH (_hb_os2_unicode_ranges),
+ sizeof (OS2Range),
+ OS2Range::cmp, nullptr);
if (range != nullptr)
return range->bit;
return -1;
diff --git a/src/hb-ot-post-macroman.hh b/src/hb-ot-post-macroman.hh
index dbbb97e5a..b4df8aaee 100644
--- a/src/hb-ot-post-macroman.hh
+++ b/src/hb-ot-post-macroman.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_POST_MACROMAN_HH
#if 0 /* Make checks happy. */
#define HB_OT_POST_MACROMAN_HH
-#include "hb-private.hh"
+#include "hb.hh"
#endif
diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh
index 4f08a51a2..bd049f9ab 100644
--- a/src/hb-ot-post-table.hh
+++ b/src/hb-ot-post-table.hh
@@ -27,8 +27,7 @@
#ifndef HB_OT_POST_TABLE_HH
#define HB_OT_POST_TABLE_HH
-#include "hb-open-type-private.hh"
-#include "hb-subset-plan.hh"
+#include "hb-open-type.hh"
#define HB_STRING_ARRAY_NAME format1_names
#define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh"
@@ -56,10 +55,11 @@ struct postV2Tail
return_trace (glyphNameIndex.sanitize (c));
}
- ArrayOf<HBUINT16>glyphNameIndex; /* This is not an offset, but is the
+ ArrayOf<HBUINT16> glyphNameIndex; /* This is not an offset, but is the
* ordinal number of the glyph in 'post'
* string tables. */
- HBUINT8 namesX[VAR]; /* Glyph names with length bytes [variable]
+ UnsizedArrayOf<HBUINT8>
+ namesX; /* Glyph names with length bytes [variable]
* (a Pascal string). */
DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX);
@@ -131,6 +131,7 @@ struct post
{
index_to_offset.fini ();
free (gids_sorted_by_name.get ());
+ hb_blob_destroy (blob);
}
inline bool get_glyph_name (hb_codepoint_t glyph,
@@ -143,7 +144,7 @@ struct post
return true;
if (buf_len <= s.len) /* What to do with truncation? Returning false for now. */
return false;
- strncpy (buf, s.bytes, s.len);
+ strncpy (buf, s.arrayZ, s.len);
buf[s.len] = '\0';
return true;
}
@@ -241,7 +242,7 @@ struct post
if (index >= index_to_offset.len)
return hb_bytes_t ();
- unsigned int offset = index_to_offset.arrayZ[index];
+ unsigned int offset = index_to_offset[index];
const uint8_t *data = pool + offset;
unsigned int name_length = *data;
@@ -295,6 +296,8 @@ struct post
DEFINE_SIZE_STATIC (32);
};
+struct post_accelerator_t : post::accelerator_t {};
+
} /* namespace OT */
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
index a55511aa0..2aa036728 100644
--- a/src/hb-ot-shape-complex-arabic-fallback.hh
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -27,9 +27,9 @@
#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape.hh"
#include "hb-ot-layout-gsub-table.hh"
@@ -173,7 +173,6 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
ligatures_supplier,
component_count_supplier,
component_supplier);
-
c.end_serialize ();
/* TODO sanitize the results? */
@@ -202,7 +201,7 @@ struct arabic_fallback_plan_t
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];
+ OT::hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
};
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh
index 54c6cdc24..b15e145f2 100644
--- a/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -313,7 +313,7 @@ OT_TABLE_END
* Include a second time to get the table data...
*/
#if 0
-#include "hb-private.hh" /* Make check-includes.sh happy. */
+#include "hb.hh" /* Make check-includes.sh happy. */
#endif
#ifdef OT_MEASURE
#include "hb-ot-shape-complex-arabic-win1256.hh"
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index f4b397b93..b56443910 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -24,9 +24,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
-#include "hb-ot-shape-complex-arabic-private.hh"
-#include "hb-ot-shape-private.hh"
+#include "hb.hh"
+#include "hb-ot-shape-complex-arabic.hh"
+#include "hb-ot-shape.hh"
/* buffer var allocations */
@@ -159,11 +159,6 @@ static const struct arabic_state_table_entry {
static void
-nuke_joiners (const hb_ot_shape_plan_t *plan,
- hb_font_t *font,
- hb_buffer_t *buffer);
-
-static void
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
@@ -200,32 +195,38 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* work correctly. See https://github.com/harfbuzz/harfbuzz/issues/505
*/
- map->add_gsub_pause (nuke_joiners);
- map->add_global_bool_feature (HB_TAG('s','t','c','h'));
+ map->enable_feature (HB_TAG('s','t','c','h'));
map->add_gsub_pause (record_stch);
- map->add_global_bool_feature (HB_TAG('c','c','m','p'));
- map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+ map->enable_feature (HB_TAG('c','c','m','p'));
+ map->enable_feature (HB_TAG('l','o','c','l'));
map->add_gsub_pause (nullptr);
for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
{
bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
- map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
+ map->add_feature (arabic_features[i], has_fallback ? F_HAS_FALLBACK : F_NONE);
map->add_gsub_pause (nullptr);
}
- map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
+ /* Normally, Unicode says a ZWNJ means "don't ligate". In Arabic script
+ * however, it says a ZWJ should also mean "don't ligate". So we run
+ * the main ligating features as MANUAL_ZWJ. */
+
+ map->enable_feature (HB_TAG('r','l','i','g'), F_MANUAL_ZWJ | F_HAS_FALLBACK);
+
if (plan->props.script == HB_SCRIPT_ARABIC)
map->add_gsub_pause (arabic_fallback_shape);
/* No pause after rclt. See 98460779bae19e4d64d29461ff154b3527bf8420. */
- map->add_global_bool_feature (HB_TAG('r','c','l','t'));
- map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+ map->enable_feature (HB_TAG('r','c','l','t'), F_MANUAL_ZWJ);
+ map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ);
map->add_gsub_pause (nullptr);
+ /* And undo here. */
+
/* 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,
@@ -234,8 +235,8 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
* Note that IranNastaliq uses this feature extensively
* to fixup broken glyph sequences. Oh well...
* Test case: U+0643,U+0640,U+0631. */
- //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
- map->add_global_bool_feature (HB_TAG('m','s','e','t'));
+ //map->enable_feature (HB_TAG('c','s','w','h'));
+ map->enable_feature (HB_TAG('m','s','e','t'));
}
#include "hb-ot-shape-complex-arabic-fallback.hh"
@@ -379,19 +380,6 @@ setup_masks_arabic (const hb_ot_shape_plan_t *plan,
setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
}
-
-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,
@@ -470,9 +458,9 @@ apply_stch (const hb_ot_shape_plan_t *plan,
int sign = font->x_scale < 0 ? -1 : +1;
unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
- typedef enum { MEASURE, CUT } step_t;
+ enum { MEASURE, CUT } /* step_t */;
- for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
+ for (unsigned int step = MEASURE; step <= CUT; step = step + 1)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
@@ -611,7 +599,7 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
-/* https://unicode.org/reports/tr53/tr53-1.pdf */
+/* http://www.unicode.org/reports/tr53/ */
static hb_codepoint_t
modifier_combining_marks[] =
@@ -623,6 +611,7 @@ modifier_combining_marks[] =
0x06E3u, /* ARABIC SMALL LOW SEEN */
0x06E7u, /* ARABIC SMALL HIGH YEH */
0x06E8u, /* ARABIC SMALL HIGH NOON */
+ 0x08D3u, /* ARABIC SMALL LOW WAW */
0x08F3u, /* ARABIC SMALL HIGH WAW */
};
@@ -714,7 +703,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
nullptr, /* decompose */
nullptr, /* compose */
setup_masks_arabic,
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
reorder_marks_arabic,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
diff --git a/src/hb-ot-shape-complex-arabic-private.hh b/src/hb-ot-shape-complex-arabic.hh
index fcedc7d74..5bf6ff633 100644
--- a/src/hb-ot-shape-complex-arabic-private.hh
+++ b/src/hb-ot-shape-complex-arabic.hh
@@ -26,12 +26,12 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
-#define HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-complex.hh"
struct arabic_shape_plan_t;
@@ -47,4 +47,4 @@ setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
hb_buffer_t *buffer,
hb_script_t script);
-#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_HH */
diff --git a/src/hb-ot-shape-complex-default.cc b/src/hb-ot-shape-complex-default.cc
index 68a62a10d..97923ecf6 100644
--- a/src/hb-ot-shape-complex-default.cc
+++ b/src/hb-ot-shape-complex-default.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-complex.hh"
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
@@ -39,7 +39,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
nullptr, /* decompose */
nullptr, /* compose */
nullptr, /* setup_masks */
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
index 7420c5d18..959540258 100644
--- a/src/hb-ot-shape-complex-hangul.cc
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-complex.hh"
/* Hangul shaper */
@@ -56,7 +56,7 @@ 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);
+ map->add_feature (hangul_features[i]);
}
static void
@@ -65,7 +65,7 @@ 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);
+ plan->map.disable_feature (HB_TAG('c','a','l','t'));
}
struct hangul_shape_plan_t
@@ -345,13 +345,6 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
{
unsigned int s_len = tindex ? 3 : 2;
buffer->replace_glyphs (1, s_len, decomposed);
- if (unlikely (!buffer->successful))
- 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.
@@ -361,6 +354,14 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
buffer->next_glyph ();
s_len++;
}
+
+ if (unlikely (!buffer->successful))
+ 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;
end = start + s_len;
unsigned int i = start;
@@ -368,6 +369,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
info[i++].hangul_shaping_feature() = VJMO;
if (i < end)
info[i++].hangul_shaping_feature() = TJMO;
+
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
buffer->merge_out_clusters (start, end);
continue;
@@ -424,7 +426,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
nullptr, /* decompose */
nullptr, /* compose */
setup_masks_hangul,
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
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
index 34cf28b8e..90c36c023 100644
--- a/src/hb-ot-shape-complex-hebrew.cc
+++ b/src/hb-ot-shape-complex-hebrew.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-complex.hh"
static bool
@@ -70,7 +70,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
bool found = (bool) c->unicode->compose (a, b, ab);
- if (!found && !c->plan->has_mark)
+ if (!found && !c->plan->has_gpos_mark)
{
/* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */
@@ -154,18 +154,6 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
return found;
}
-static bool
-disable_otl_hebrew (const hb_ot_shape_plan_t *plan)
-{
- /* For Hebrew shaper, use fallback if GPOS does not have 'hebr'
- * script. This matches Uniscribe better, and makes fonts like
- * Arial that have GSUB/GPOS/GDEF but no data for Hebrew work.
- * See:
- * https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368
- */
- return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r');
-}
-
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
{
@@ -179,7 +167,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
nullptr, /* decompose */
compose_hebrew,
nullptr, /* setup_masks */
- disable_otl_hebrew,
+ HB_TAG ('h','e','b','r'), /* gpos_tag. https://github.com/harfbuzz/harfbuzz/issues/347#issuecomment-267838368 */
nullptr, /* reorder_marks */
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
index 73f9d5871..e2ecfb89c 100644
--- a/src/hb-ot-shape-complex-indic-machine.hh
+++ b/src/hb-ot-shape-complex-indic-machine.hh
@@ -29,892 +29,714 @@
#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
#line 36 "hb-ot-shape-complex-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
- 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
+ 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u,
4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
- 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u,
- 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
- 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u,
- 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
- 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u,
- 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 8u,
- 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u,
- 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
- 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
- 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u,
- 8u, 8u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
- 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u,
- 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u,
- 16u, 16u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u,
- 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u, 5u, 8u, 5u, 8u, 5u, 7u, 5u, 8u,
- 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u,
- 8u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
- 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 8u, 8u, 1u, 19u, 3u, 17u,
- 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
- 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u,
- 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u,
- 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u,
- 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u,
- 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u,
- 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u,
- 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u,
- 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u,
- 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u,
- 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u,
- 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u,
- 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u,
- 5u, 10u, 3u, 10u, 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u,
- 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
- 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
- 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u,
- 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u,
+ 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u,
+ 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
+ 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u,
+ 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
+ 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u,
+ 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u,
+ 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u,
+ 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u,
+ 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u,
+ 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 8u, 8u, 4u, 8u, 5u, 7u,
+ 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u,
+ 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u,
+ 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u,
+ 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u,
+ 5u, 8u, 8u, 8u, 1u, 19u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u,
+ 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u,
+ 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u,
+ 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u,
4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u,
- 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u,
- 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u, 3u, 17u, 4u, 8u,
- 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
- 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u,
- 3u, 17u, 3u, 17u, 4u, 17u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u,
- 10u, 10u, 5u, 10u, 3u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u,
+ 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u,
+ 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u,
+ 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u,
+ 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u,
+ 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u,
+ 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u,
+ 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u,
+ 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u,
+ 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 10u, 3u, 10u, 4u, 10u, 1u, 16u,
+ 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u,
+ 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u,
+ 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u,
+ 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u,
+ 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u,
+ 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u,
+ 3u, 10u, 4u, 8u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u,
+ 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u,
+ 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u,
+ 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u,
5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u,
- 4u, 10u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u,
- 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u,
- 1u, 16u, 1u, 16u, 1u, 16u, 3u, 17u, 3u, 17u, 1u, 16u, 1u, 16u, 1u, 16u,
- 1u, 16u, 3u, 17u, 1u, 17u, 3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u,
- 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u,
- 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u,
+ 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u,
+ 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u,
+ 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 1u, 16u, 3u, 13u,
+ 1u, 16u, 4u, 13u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u,
3u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u,
0
};
static const char _indic_syllable_machine_key_spans[] = {
- 1, 4, 3, 1, 4, 3, 1, 4,
+ 1, 5, 3, 1, 4, 3, 1, 4,
3, 1, 4, 3, 1, 5, 1, 1,
5, 1, 1, 5, 1, 1, 5, 1,
- 1, 5, 10, 5, 10, 5, 10, 5,
- 10, 5, 10, 1, 4, 3, 1, 4,
- 3, 1, 4, 3, 1, 4, 3, 1,
- 5, 1, 1, 5, 1, 1, 5, 1,
- 1, 5, 1, 1, 5, 10, 5, 10,
- 5, 10, 5, 10, 5, 10, 1, 4,
- 3, 1, 4, 3, 1, 4, 3, 1,
- 4, 3, 1, 5, 1, 1, 5, 1,
+ 1, 10, 5, 10, 5, 10, 5, 10,
+ 5, 10, 1, 5, 3, 1, 4, 3,
+ 1, 4, 3, 1, 4, 3, 1, 5,
+ 1, 1, 5, 1, 1, 5, 1, 1,
+ 5, 1, 1, 10, 5, 10, 5, 10,
+ 5, 10, 5, 10, 1, 5, 3, 1,
+ 4, 3, 1, 4, 3, 1, 4, 3,
1, 5, 1, 1, 5, 1, 1, 5,
- 10, 5, 10, 5, 10, 5, 10, 5,
+ 1, 1, 5, 1, 1, 10, 5, 10,
+ 5, 10, 5, 10, 5, 1, 5, 3,
1, 4, 3, 1, 4, 3, 1, 4,
- 3, 1, 4, 3, 1, 5, 1, 1,
- 5, 1, 1, 5, 1, 1, 5, 1,
- 1, 5, 10, 5, 10, 5, 10, 5,
- 10, 5, 10, 10, 4, 4, 3, 4,
- 3, 1, 4, 3, 1, 4, 3, 1,
- 1, 5, 1, 1, 5, 1, 1, 5,
- 1, 1, 5, 1, 1, 1, 19, 15,
- 15, 14, 16, 15, 15, 14, 16, 15,
- 15, 14, 16, 15, 15, 14, 16, 15,
- 15, 14, 6, 6, 6, 1, 1, 1,
- 6, 8, 8, 7, 6, 8, 7, 6,
- 8, 7, 6, 8, 7, 6, 8, 7,
- 15, 15, 16, 16, 16, 16, 15, 15,
- 16, 16, 16, 16, 15, 15, 16, 16,
- 16, 16, 15, 15, 16, 16, 16, 16,
- 15, 15, 15, 15, 14, 16, 15, 15,
- 14, 16, 15, 15, 14, 16, 15, 15,
- 14, 16, 15, 15, 14, 6, 6, 6,
- 1, 1, 1, 6, 8, 8, 7, 6,
- 8, 7, 6, 8, 7, 6, 8, 7,
- 6, 8, 7, 15, 15, 16, 16, 16,
- 16, 15, 15, 16, 16, 16, 16, 15,
- 15, 16, 16, 16, 16, 15, 15, 16,
- 16, 16, 16, 5, 15, 15, 14, 16,
- 15, 15, 14, 16, 15, 15, 14, 16,
- 15, 15, 14, 16, 15, 15, 14, 6,
- 6, 6, 1, 1, 1, 6, 8, 8,
+ 3, 1, 5, 1, 1, 5, 1, 1,
+ 5, 1, 1, 5, 1, 1, 10, 5,
+ 10, 5, 10, 5, 10, 5, 10, 10,
+ 4, 1, 19, 11, 8, 7, 16, 11,
+ 8, 7, 16, 11, 8, 7, 16, 11,
+ 8, 7, 16, 11, 8, 7, 6, 6,
+ 6, 1, 1, 1, 6, 8, 6, 8,
7, 6, 8, 7, 6, 8, 7, 6,
- 8, 7, 6, 8, 7, 15, 15, 16,
- 16, 16, 16, 15, 15, 16, 16, 16,
- 16, 15, 15, 16, 16, 16, 16, 15,
- 15, 16, 16, 16, 16, 10, 15, 5,
- 15, 15, 14, 16, 15, 15, 14, 16,
- 15, 15, 14, 16, 15, 15, 14, 16,
- 15, 15, 14, 6, 6, 6, 1, 1,
- 1, 6, 8, 8, 7, 6, 8, 7,
+ 8, 7, 8, 11, 16, 16, 16, 8,
+ 11, 16, 16, 16, 8, 11, 16, 16,
+ 16, 8, 11, 16, 16, 16, 8, 11,
+ 11, 8, 7, 16, 11, 8, 7, 16,
+ 11, 8, 7, 16, 11, 8, 7, 16,
+ 11, 8, 7, 6, 6, 6, 1, 1,
+ 1, 6, 8, 6, 8, 7, 6, 8,
+ 7, 6, 8, 7, 6, 8, 7, 8,
+ 11, 16, 16, 16, 8, 11, 16, 16,
+ 16, 8, 11, 16, 16, 16, 8, 11,
+ 16, 16, 16, 5, 8, 8, 7, 16,
+ 11, 8, 7, 16, 11, 8, 7, 16,
+ 11, 8, 7, 16, 11, 8, 7, 6,
+ 6, 6, 1, 1, 1, 6, 8, 6,
+ 8, 7, 6, 8, 7, 6, 8, 7,
+ 6, 8, 7, 8, 11, 16, 16, 16,
+ 8, 11, 16, 16, 16, 8, 11, 16,
+ 16, 16, 8, 11, 16, 16, 16, 10,
+ 8, 5, 11, 8, 7, 16, 11, 8,
+ 7, 16, 11, 8, 7, 16, 11, 8,
+ 7, 16, 11, 8, 7, 6, 6, 6,
+ 1, 1, 1, 6, 8, 6, 8, 7,
6, 8, 7, 6, 8, 7, 6, 8,
- 7, 15, 15, 16, 16, 16, 16, 15,
- 15, 16, 16, 16, 16, 15, 15, 16,
- 16, 16, 16, 15, 15, 16, 16, 16,
- 16, 15, 17, 15, 17, 10, 6, 1,
- 1, 1, 6, 16, 8, 7, 6, 8,
- 7, 6, 8, 7, 6, 8, 7, 6,
+ 7, 8, 11, 16, 16, 16, 8, 11,
+ 16, 16, 16, 8, 11, 16, 16, 16,
+ 8, 11, 16, 16, 16, 8, 16, 11,
+ 16, 10, 6, 1, 1, 1, 6, 16,
8, 6, 6, 1, 1, 1, 6, 16
};
static const short _indic_syllable_machine_index_offsets[] = {
- 0, 2, 7, 11, 13, 18, 22, 24,
- 29, 33, 35, 40, 44, 46, 52, 54,
- 56, 62, 64, 66, 72, 74, 76, 82,
- 84, 86, 92, 103, 109, 120, 126, 137,
- 143, 154, 160, 171, 173, 178, 182, 184,
- 189, 193, 195, 200, 204, 206, 211, 215,
- 217, 223, 225, 227, 233, 235, 237, 243,
- 245, 247, 253, 255, 257, 263, 274, 280,
- 291, 297, 308, 314, 325, 331, 342, 344,
- 349, 353, 355, 360, 364, 366, 371, 375,
- 377, 382, 386, 388, 394, 396, 398, 404,
- 406, 408, 414, 416, 418, 424, 426, 428,
- 434, 445, 451, 462, 468, 479, 485, 496,
- 502, 504, 509, 513, 515, 520, 524, 526,
- 531, 535, 537, 542, 546, 548, 554, 556,
- 558, 564, 566, 568, 574, 576, 578, 584,
- 586, 588, 594, 605, 611, 622, 628, 639,
- 645, 656, 662, 673, 684, 689, 694, 698,
- 703, 707, 709, 714, 718, 720, 725, 729,
- 731, 733, 739, 741, 743, 749, 751, 753,
- 759, 761, 763, 769, 771, 773, 775, 795,
- 811, 827, 842, 859, 875, 891, 906, 923,
- 939, 955, 970, 987, 1003, 1019, 1034, 1051,
- 1067, 1083, 1098, 1105, 1112, 1119, 1121, 1123,
- 1125, 1132, 1141, 1150, 1158, 1165, 1174, 1182,
- 1189, 1198, 1206, 1213, 1222, 1230, 1237, 1246,
- 1254, 1270, 1286, 1303, 1320, 1337, 1354, 1370,
- 1386, 1403, 1420, 1437, 1454, 1470, 1486, 1503,
- 1520, 1537, 1554, 1570, 1586, 1603, 1620, 1637,
- 1654, 1670, 1686, 1702, 1718, 1733, 1750, 1766,
- 1782, 1797, 1814, 1830, 1846, 1861, 1878, 1894,
- 1910, 1925, 1942, 1958, 1974, 1989, 1996, 2003,
- 2010, 2012, 2014, 2016, 2023, 2032, 2041, 2049,
- 2056, 2065, 2073, 2080, 2089, 2097, 2104, 2113,
- 2121, 2128, 2137, 2145, 2161, 2177, 2194, 2211,
- 2228, 2245, 2261, 2277, 2294, 2311, 2328, 2345,
- 2361, 2377, 2394, 2411, 2428, 2445, 2461, 2477,
- 2494, 2511, 2528, 2545, 2551, 2567, 2583, 2598,
- 2615, 2631, 2647, 2662, 2679, 2695, 2711, 2726,
- 2743, 2759, 2775, 2790, 2807, 2823, 2839, 2854,
- 2861, 2868, 2875, 2877, 2879, 2881, 2888, 2897,
- 2906, 2914, 2921, 2930, 2938, 2945, 2954, 2962,
- 2969, 2978, 2986, 2993, 3002, 3010, 3026, 3042,
- 3059, 3076, 3093, 3110, 3126, 3142, 3159, 3176,
- 3193, 3210, 3226, 3242, 3259, 3276, 3293, 3310,
- 3326, 3342, 3359, 3376, 3393, 3410, 3421, 3437,
- 3443, 3459, 3475, 3490, 3507, 3523, 3539, 3554,
- 3571, 3587, 3603, 3618, 3635, 3651, 3667, 3682,
- 3699, 3715, 3731, 3746, 3753, 3760, 3767, 3769,
- 3771, 3773, 3780, 3789, 3798, 3806, 3813, 3822,
- 3830, 3837, 3846, 3854, 3861, 3870, 3878, 3885,
- 3894, 3902, 3918, 3934, 3951, 3968, 3985, 4002,
- 4018, 4034, 4051, 4068, 4085, 4102, 4118, 4134,
- 4151, 4168, 4185, 4202, 4218, 4234, 4251, 4268,
- 4285, 4302, 4318, 4336, 4352, 4370, 4381, 4388,
- 4390, 4392, 4394, 4401, 4418, 4427, 4435, 4442,
- 4451, 4459, 4466, 4475, 4483, 4490, 4499, 4507,
- 4514, 4523, 4530, 4537, 4539, 4541, 4543, 4550
+ 0, 2, 8, 12, 14, 19, 23, 25,
+ 30, 34, 36, 41, 45, 47, 53, 55,
+ 57, 63, 65, 67, 73, 75, 77, 83,
+ 85, 87, 98, 104, 115, 121, 132, 138,
+ 149, 155, 166, 168, 174, 178, 180, 185,
+ 189, 191, 196, 200, 202, 207, 211, 213,
+ 219, 221, 223, 229, 231, 233, 239, 241,
+ 243, 249, 251, 253, 264, 270, 281, 287,
+ 298, 304, 315, 321, 332, 334, 340, 344,
+ 346, 351, 355, 357, 362, 366, 368, 373,
+ 377, 379, 385, 387, 389, 395, 397, 399,
+ 405, 407, 409, 415, 417, 419, 430, 436,
+ 447, 453, 464, 470, 481, 487, 489, 495,
+ 499, 501, 506, 510, 512, 517, 521, 523,
+ 528, 532, 534, 540, 542, 544, 550, 552,
+ 554, 560, 562, 564, 570, 572, 574, 585,
+ 591, 602, 608, 619, 625, 636, 642, 653,
+ 664, 669, 671, 691, 703, 712, 720, 737,
+ 749, 758, 766, 783, 795, 804, 812, 829,
+ 841, 850, 858, 875, 887, 896, 904, 911,
+ 918, 925, 927, 929, 931, 938, 947, 954,
+ 963, 971, 978, 987, 995, 1002, 1011, 1019,
+ 1026, 1035, 1043, 1052, 1064, 1081, 1098, 1115,
+ 1124, 1136, 1153, 1170, 1187, 1196, 1208, 1225,
+ 1242, 1259, 1268, 1280, 1297, 1314, 1331, 1340,
+ 1352, 1364, 1373, 1381, 1398, 1410, 1419, 1427,
+ 1444, 1456, 1465, 1473, 1490, 1502, 1511, 1519,
+ 1536, 1548, 1557, 1565, 1572, 1579, 1586, 1588,
+ 1590, 1592, 1599, 1608, 1615, 1624, 1632, 1639,
+ 1648, 1656, 1663, 1672, 1680, 1687, 1696, 1704,
+ 1713, 1725, 1742, 1759, 1776, 1785, 1797, 1814,
+ 1831, 1848, 1857, 1869, 1886, 1903, 1920, 1929,
+ 1941, 1958, 1975, 1992, 1998, 2007, 2016, 2024,
+ 2041, 2053, 2062, 2070, 2087, 2099, 2108, 2116,
+ 2133, 2145, 2154, 2162, 2179, 2191, 2200, 2208,
+ 2215, 2222, 2229, 2231, 2233, 2235, 2242, 2251,
+ 2258, 2267, 2275, 2282, 2291, 2299, 2306, 2315,
+ 2323, 2330, 2339, 2347, 2356, 2368, 2385, 2402,
+ 2419, 2428, 2440, 2457, 2474, 2491, 2500, 2512,
+ 2529, 2546, 2563, 2572, 2584, 2601, 2618, 2635,
+ 2646, 2655, 2661, 2673, 2682, 2690, 2707, 2719,
+ 2728, 2736, 2753, 2765, 2774, 2782, 2799, 2811,
+ 2820, 2828, 2845, 2857, 2866, 2874, 2881, 2888,
+ 2895, 2897, 2899, 2901, 2908, 2917, 2924, 2933,
+ 2941, 2948, 2957, 2965, 2972, 2981, 2989, 2996,
+ 3005, 3013, 3022, 3034, 3051, 3068, 3085, 3094,
+ 3106, 3123, 3140, 3157, 3166, 3178, 3195, 3212,
+ 3229, 3238, 3250, 3267, 3284, 3301, 3310, 3327,
+ 3339, 3356, 3367, 3374, 3376, 3378, 3380, 3387,
+ 3404, 3413, 3420, 3427, 3429, 3431, 3433, 3440
};
static const short _indic_syllable_machine_indicies[] = {
- 1, 0, 2, 2, 3, 1, 0, 4,
- 4, 3, 0, 3, 0, 5, 5, 6,
- 1, 0, 7, 7, 6, 0, 6, 0,
- 8, 8, 9, 1, 0, 10, 10, 9,
- 0, 9, 0, 11, 11, 12, 1, 0,
- 13, 13, 12, 0, 12, 0, 14, 0,
- 0, 0, 1, 0, 15, 0, 16, 0,
- 17, 11, 11, 12, 1, 0, 18, 0,
- 19, 0, 20, 8, 8, 9, 1, 0,
- 21, 0, 22, 0, 23, 5, 5, 6,
- 1, 0, 24, 0, 25, 0, 26, 2,
- 2, 3, 1, 0, 26, 2, 2, 3,
- 1, 0, 0, 0, 0, 27, 0, 28,
- 2, 2, 3, 1, 0, 28, 2, 2,
- 3, 1, 0, 0, 0, 0, 29, 0,
- 30, 2, 2, 3, 1, 0, 30, 2,
- 2, 3, 1, 0, 0, 0, 0, 31,
- 0, 32, 2, 2, 3, 1, 0, 32,
- 2, 2, 3, 1, 0, 0, 0, 0,
- 33, 0, 34, 2, 2, 3, 1, 0,
- 34, 2, 2, 3, 1, 0, 0, 0,
- 0, 35, 0, 37, 36, 38, 38, 39,
- 37, 36, 40, 40, 39, 36, 39, 36,
- 41, 41, 42, 37, 36, 43, 43, 42,
- 36, 42, 36, 44, 44, 45, 37, 36,
- 46, 46, 45, 36, 45, 36, 47, 47,
- 48, 37, 36, 49, 49, 48, 36, 48,
- 36, 50, 36, 36, 36, 37, 36, 51,
- 36, 52, 36, 53, 47, 47, 48, 37,
- 36, 54, 36, 55, 36, 56, 44, 44,
- 45, 37, 36, 57, 36, 58, 36, 59,
- 41, 41, 42, 37, 36, 60, 36, 61,
- 36, 62, 38, 38, 39, 37, 36, 62,
- 38, 38, 39, 37, 36, 36, 36, 36,
- 63, 36, 64, 38, 38, 39, 37, 36,
- 64, 38, 38, 39, 37, 36, 36, 36,
- 36, 65, 36, 66, 38, 38, 39, 37,
- 36, 66, 38, 38, 39, 37, 36, 36,
- 36, 36, 67, 36, 68, 38, 38, 39,
- 37, 36, 68, 38, 38, 39, 37, 36,
- 36, 36, 36, 69, 36, 70, 38, 38,
- 39, 37, 36, 70, 38, 38, 39, 37,
- 36, 36, 36, 36, 71, 36, 73, 72,
- 74, 74, 75, 73, 72, 77, 77, 75,
- 76, 75, 76, 78, 78, 79, 73, 72,
- 80, 80, 79, 72, 79, 72, 81, 81,
- 82, 73, 72, 83, 83, 82, 72, 82,
- 72, 84, 84, 85, 73, 72, 86, 86,
- 85, 72, 85, 72, 87, 72, 72, 72,
- 73, 72, 88, 72, 89, 72, 90, 84,
- 84, 85, 73, 72, 91, 72, 92, 72,
- 93, 81, 81, 82, 73, 72, 94, 72,
- 95, 72, 96, 78, 78, 79, 73, 72,
- 97, 72, 98, 72, 99, 74, 74, 75,
- 73, 72, 99, 74, 74, 75, 73, 72,
- 72, 72, 72, 100, 72, 101, 74, 74,
- 75, 73, 72, 101, 74, 74, 75, 73,
- 72, 72, 72, 72, 102, 72, 103, 74,
- 74, 75, 73, 72, 103, 74, 74, 75,
- 73, 72, 72, 72, 72, 104, 72, 105,
- 74, 74, 75, 73, 72, 105, 74, 74,
- 75, 73, 72, 72, 72, 72, 106, 72,
- 107, 74, 74, 75, 73, 72, 109, 108,
- 110, 110, 111, 109, 108, 112, 112, 111,
- 108, 111, 108, 113, 113, 114, 109, 108,
- 115, 115, 114, 108, 114, 108, 116, 116,
- 117, 109, 108, 118, 118, 117, 108, 117,
- 108, 119, 119, 120, 109, 108, 121, 121,
- 120, 108, 120, 108, 122, 108, 108, 108,
- 109, 108, 123, 108, 124, 108, 125, 119,
- 119, 120, 109, 108, 126, 108, 127, 108,
- 128, 116, 116, 117, 109, 108, 129, 108,
- 130, 108, 131, 113, 113, 114, 109, 108,
- 132, 108, 133, 108, 134, 110, 110, 111,
- 109, 108, 134, 110, 110, 111, 109, 108,
- 108, 108, 108, 135, 108, 136, 110, 110,
- 111, 109, 108, 136, 110, 110, 111, 109,
- 108, 108, 108, 108, 137, 108, 138, 110,
- 110, 111, 109, 108, 138, 110, 110, 111,
- 109, 108, 108, 108, 108, 139, 108, 140,
- 110, 110, 111, 109, 108, 140, 110, 110,
- 111, 109, 108, 108, 108, 108, 141, 108,
- 142, 110, 110, 111, 109, 108, 142, 110,
- 110, 111, 109, 108, 108, 108, 108, 143,
- 108, 107, 74, 74, 75, 73, 72, 72,
- 72, 72, 144, 72, 77, 77, 75, 1,
- 0, 145, 145, 146, 1, 0, 4, 4,
- 146, 0, 147, 147, 148, 149, 0, 150,
- 150, 148, 0, 148, 0, 151, 151, 152,
- 149, 0, 153, 153, 152, 0, 152, 0,
- 154, 154, 155, 149, 0, 156, 156, 155,
- 0, 155, 0, 149, 0, 157, 0, 0,
- 0, 149, 0, 158, 0, 159, 0, 160,
- 154, 154, 155, 149, 0, 161, 0, 162,
- 0, 163, 151, 151, 152, 149, 0, 164,
- 0, 165, 0, 166, 147, 147, 148, 149,
- 0, 167, 0, 168, 0, 170, 169, 172,
- 173, 174, 175, 176, 177, 75, 73, 171,
- 178, 179, 179, 144, 171, 180, 181, 182,
- 183, 184, 171, 186, 187, 188, 189, 3,
- 1, 185, 190, 185, 185, 35, 185, 185,
- 185, 191, 185, 192, 187, 193, 193, 3,
- 1, 185, 190, 185, 185, 185, 185, 185,
- 185, 191, 185, 187, 193, 193, 3, 1,
- 185, 190, 185, 185, 185, 185, 185, 185,
- 191, 185, 194, 185, 185, 185, 16, 195,
- 185, 1, 185, 190, 185, 185, 185, 185,
- 185, 194, 185, 196, 197, 198, 199, 3,
- 1, 185, 190, 185, 185, 33, 185, 185,
- 185, 191, 185, 200, 197, 201, 201, 3,
- 1, 185, 190, 185, 185, 185, 185, 185,
- 185, 191, 185, 197, 201, 201, 3, 1,
- 185, 190, 185, 185, 185, 185, 185, 185,
- 191, 185, 202, 185, 185, 185, 16, 203,
- 185, 1, 185, 190, 185, 185, 185, 185,
- 185, 202, 185, 204, 205, 206, 207, 3,
- 1, 185, 190, 185, 185, 31, 185, 185,
- 185, 191, 185, 208, 205, 209, 209, 3,
- 1, 185, 190, 185, 185, 185, 185, 185,
- 185, 191, 185, 205, 209, 209, 3, 1,
- 185, 190, 185, 185, 185, 185, 185, 185,
- 191, 185, 210, 185, 185, 185, 16, 211,
- 185, 1, 185, 190, 185, 185, 185, 185,
- 185, 210, 185, 212, 213, 214, 215, 3,
- 1, 185, 190, 185, 185, 29, 185, 185,
- 185, 191, 185, 216, 213, 217, 217, 3,
- 1, 185, 190, 185, 185, 185, 185, 185,
- 185, 191, 185, 213, 217, 217, 3, 1,
- 185, 190, 185, 185, 185, 185, 185, 185,
- 191, 185, 218, 185, 185, 185, 16, 219,
- 185, 1, 185, 190, 185, 185, 185, 185,
- 185, 218, 185, 220, 221, 222, 223, 3,
- 1, 185, 190, 185, 185, 27, 185, 185,
- 185, 191, 185, 224, 221, 225, 225, 3,
- 1, 185, 190, 185, 185, 185, 185, 185,
- 185, 191, 185, 221, 225, 225, 3, 1,
- 185, 190, 185, 185, 185, 185, 185, 185,
- 191, 185, 16, 226, 185, 1, 185, 190,
- 185, 227, 227, 185, 1, 185, 190, 185,
- 228, 185, 185, 229, 185, 190, 185, 190,
- 185, 230, 185, 231, 185, 228, 185, 185,
- 185, 185, 190, 185, 16, 185, 232, 232,
- 3, 1, 185, 190, 185, 233, 25, 234,
- 235, 6, 1, 185, 190, 185, 25, 234,
- 235, 6, 1, 185, 190, 185, 234, 234,
- 6, 1, 185, 190, 185, 236, 22, 237,
- 238, 9, 1, 185, 190, 185, 22, 237,
- 238, 9, 1, 185, 190, 185, 237, 237,
- 9, 1, 185, 190, 185, 239, 19, 240,
- 241, 12, 1, 185, 190, 185, 19, 240,
- 241, 12, 1, 185, 190, 185, 240, 240,
- 12, 1, 185, 190, 185, 242, 16, 227,
- 243, 185, 1, 185, 190, 185, 16, 227,
- 243, 185, 1, 185, 190, 185, 227, 244,
- 185, 1, 185, 190, 185, 16, 185, 227,
- 227, 185, 1, 185, 190, 185, 221, 225,
- 225, 3, 1, 185, 190, 185, 220, 221,
- 225, 225, 3, 1, 185, 190, 185, 185,
- 185, 185, 185, 185, 191, 185, 220, 221,
- 222, 225, 3, 1, 185, 190, 185, 185,
- 27, 185, 185, 185, 191, 185, 218, 185,
- 245, 185, 232, 232, 3, 1, 185, 190,
- 185, 185, 185, 185, 185, 218, 185, 218,
- 185, 185, 185, 227, 227, 185, 1, 185,
- 190, 185, 185, 185, 185, 185, 218, 185,
- 218, 185, 185, 185, 227, 246, 185, 1,
- 185, 190, 185, 185, 185, 185, 185, 218,
- 185, 218, 185, 245, 185, 227, 227, 185,
- 1, 185, 190, 185, 185, 185, 185, 185,
- 218, 185, 212, 213, 217, 217, 3, 1,
- 185, 190, 185, 185, 185, 185, 185, 185,
- 191, 185, 212, 213, 214, 217, 3, 1,
- 185, 190, 185, 185, 29, 185, 185, 185,
- 191, 185, 210, 185, 247, 185, 232, 232,
- 3, 1, 185, 190, 185, 185, 185, 185,
- 185, 210, 185, 210, 185, 185, 185, 227,
- 227, 185, 1, 185, 190, 185, 185, 185,
- 185, 185, 210, 185, 210, 185, 185, 185,
- 227, 248, 185, 1, 185, 190, 185, 185,
- 185, 185, 185, 210, 185, 210, 185, 247,
- 185, 227, 227, 185, 1, 185, 190, 185,
- 185, 185, 185, 185, 210, 185, 204, 205,
- 209, 209, 3, 1, 185, 190, 185, 185,
- 185, 185, 185, 185, 191, 185, 204, 205,
- 206, 209, 3, 1, 185, 190, 185, 185,
- 31, 185, 185, 185, 191, 185, 202, 185,
- 249, 185, 232, 232, 3, 1, 185, 190,
- 185, 185, 185, 185, 185, 202, 185, 202,
- 185, 185, 185, 227, 227, 185, 1, 185,
- 190, 185, 185, 185, 185, 185, 202, 185,
- 202, 185, 185, 185, 227, 250, 185, 1,
- 185, 190, 185, 185, 185, 185, 185, 202,
- 185, 202, 185, 249, 185, 227, 227, 185,
- 1, 185, 190, 185, 185, 185, 185, 185,
- 202, 185, 196, 197, 201, 201, 3, 1,
- 185, 190, 185, 185, 185, 185, 185, 185,
- 191, 185, 196, 197, 198, 201, 3, 1,
- 185, 190, 185, 185, 33, 185, 185, 185,
- 191, 185, 194, 185, 251, 185, 232, 232,
- 3, 1, 185, 190, 185, 185, 185, 185,
- 185, 194, 185, 194, 185, 185, 185, 227,
- 227, 185, 1, 185, 190, 185, 185, 185,
- 185, 185, 194, 185, 194, 185, 185, 185,
- 227, 252, 185, 1, 185, 190, 185, 185,
- 185, 185, 185, 194, 185, 194, 185, 251,
- 185, 227, 227, 185, 1, 185, 190, 185,
- 185, 185, 185, 185, 194, 185, 186, 187,
- 193, 193, 3, 1, 185, 190, 185, 185,
- 185, 185, 185, 185, 191, 185, 186, 187,
- 188, 193, 3, 1, 185, 190, 185, 185,
- 35, 185, 185, 185, 191, 185, 254, 255,
- 256, 257, 39, 37, 253, 258, 253, 253,
- 71, 253, 253, 253, 259, 253, 260, 255,
- 261, 257, 39, 37, 253, 258, 253, 253,
- 253, 253, 253, 253, 259, 253, 255, 261,
- 257, 39, 37, 253, 258, 253, 253, 253,
- 253, 253, 253, 259, 253, 262, 253, 253,
- 253, 52, 263, 253, 37, 253, 258, 253,
- 253, 253, 253, 253, 262, 253, 264, 265,
- 266, 267, 39, 37, 253, 258, 253, 253,
- 69, 253, 253, 253, 259, 253, 268, 265,
- 269, 269, 39, 37, 253, 258, 253, 253,
- 253, 253, 253, 253, 259, 253, 265, 269,
- 269, 39, 37, 253, 258, 253, 253, 253,
- 253, 253, 253, 259, 253, 270, 253, 253,
- 253, 52, 271, 253, 37, 253, 258, 253,
- 253, 253, 253, 253, 270, 253, 272, 273,
- 274, 275, 39, 37, 253, 258, 253, 253,
- 67, 253, 253, 253, 259, 253, 276, 273,
- 277, 277, 39, 37, 253, 258, 253, 253,
- 253, 253, 253, 253, 259, 253, 273, 277,
- 277, 39, 37, 253, 258, 253, 253, 253,
- 253, 253, 253, 259, 253, 278, 253, 253,
- 253, 52, 279, 253, 37, 253, 258, 253,
- 253, 253, 253, 253, 278, 253, 280, 281,
- 282, 283, 39, 37, 253, 258, 253, 253,
- 65, 253, 253, 253, 259, 253, 284, 281,
- 285, 285, 39, 37, 253, 258, 253, 253,
- 253, 253, 253, 253, 259, 253, 281, 285,
- 285, 39, 37, 253, 258, 253, 253, 253,
- 253, 253, 253, 259, 253, 286, 253, 253,
- 253, 52, 287, 253, 37, 253, 258, 253,
- 253, 253, 253, 253, 286, 253, 288, 289,
- 290, 291, 39, 37, 253, 258, 253, 253,
- 63, 253, 253, 253, 259, 253, 292, 289,
- 293, 293, 39, 37, 253, 258, 253, 253,
- 253, 253, 253, 253, 259, 253, 289, 293,
- 293, 39, 37, 253, 258, 253, 253, 253,
- 253, 253, 253, 259, 253, 52, 294, 253,
- 37, 253, 258, 253, 295, 295, 253, 37,
- 253, 258, 253, 296, 253, 253, 297, 253,
- 258, 253, 258, 253, 298, 253, 299, 253,
- 296, 253, 253, 253, 253, 258, 253, 52,
- 253, 300, 300, 39, 37, 253, 258, 253,
- 301, 61, 302, 303, 42, 37, 253, 258,
- 253, 61, 302, 303, 42, 37, 253, 258,
- 253, 302, 302, 42, 37, 253, 258, 253,
- 304, 58, 305, 306, 45, 37, 253, 258,
- 253, 58, 305, 306, 45, 37, 253, 258,
- 253, 305, 305, 45, 37, 253, 258, 253,
- 307, 55, 308, 309, 48, 37, 253, 258,
- 253, 55, 308, 309, 48, 37, 253, 258,
- 253, 308, 308, 48, 37, 253, 258, 253,
- 310, 52, 295, 311, 253, 37, 253, 258,
- 253, 52, 295, 311, 253, 37, 253, 258,
- 253, 295, 312, 253, 37, 253, 258, 253,
- 52, 253, 295, 295, 253, 37, 253, 258,
- 253, 289, 293, 293, 39, 37, 253, 258,
- 253, 288, 289, 293, 293, 39, 37, 253,
- 258, 253, 253, 253, 253, 253, 253, 259,
- 253, 288, 289, 290, 293, 39, 37, 253,
- 258, 253, 253, 63, 253, 253, 253, 259,
- 253, 286, 253, 313, 253, 300, 300, 39,
- 37, 253, 258, 253, 253, 253, 253, 253,
- 286, 253, 286, 253, 253, 253, 295, 295,
- 253, 37, 253, 258, 253, 253, 253, 253,
- 253, 286, 253, 286, 253, 253, 253, 295,
- 314, 253, 37, 253, 258, 253, 253, 253,
- 253, 253, 286, 253, 286, 253, 313, 253,
- 295, 295, 253, 37, 253, 258, 253, 253,
- 253, 253, 253, 286, 253, 280, 281, 285,
- 285, 39, 37, 253, 258, 253, 253, 253,
- 253, 253, 253, 259, 253, 280, 281, 282,
- 285, 39, 37, 253, 258, 253, 253, 65,
- 253, 253, 253, 259, 253, 278, 253, 315,
- 253, 300, 300, 39, 37, 253, 258, 253,
- 253, 253, 253, 253, 278, 253, 278, 253,
- 253, 253, 295, 295, 253, 37, 253, 258,
- 253, 253, 253, 253, 253, 278, 253, 278,
- 253, 253, 253, 295, 316, 253, 37, 253,
- 258, 253, 253, 253, 253, 253, 278, 253,
- 278, 253, 315, 253, 295, 295, 253, 37,
- 253, 258, 253, 253, 253, 253, 253, 278,
- 253, 272, 273, 277, 277, 39, 37, 253,
- 258, 253, 253, 253, 253, 253, 253, 259,
- 253, 272, 273, 274, 277, 39, 37, 253,
- 258, 253, 253, 67, 253, 253, 253, 259,
- 253, 270, 253, 317, 253, 300, 300, 39,
- 37, 253, 258, 253, 253, 253, 253, 253,
- 270, 253, 270, 253, 253, 253, 295, 295,
- 253, 37, 253, 258, 253, 253, 253, 253,
- 253, 270, 253, 270, 253, 253, 253, 295,
- 318, 253, 37, 253, 258, 253, 253, 253,
- 253, 253, 270, 253, 270, 253, 317, 253,
- 295, 295, 253, 37, 253, 258, 253, 253,
- 253, 253, 253, 270, 253, 264, 265, 269,
- 269, 39, 37, 253, 258, 253, 253, 253,
- 253, 253, 253, 259, 253, 264, 265, 266,
- 269, 39, 37, 253, 258, 253, 253, 69,
- 253, 253, 253, 259, 253, 262, 253, 319,
- 253, 300, 300, 39, 37, 253, 258, 253,
- 253, 253, 253, 253, 262, 253, 262, 253,
- 253, 253, 295, 295, 253, 37, 253, 258,
- 253, 253, 253, 253, 253, 262, 253, 262,
- 253, 253, 253, 295, 320, 253, 37, 253,
- 258, 253, 253, 253, 253, 253, 262, 253,
- 262, 253, 319, 253, 295, 295, 253, 37,
- 253, 258, 253, 253, 253, 253, 253, 262,
- 253, 70, 38, 38, 39, 37, 253, 254,
- 255, 261, 257, 39, 37, 253, 258, 253,
- 253, 253, 253, 253, 253, 259, 253, 322,
- 175, 323, 323, 75, 73, 321, 178, 321,
- 321, 321, 321, 321, 321, 182, 321, 175,
- 323, 323, 75, 73, 321, 178, 321, 321,
- 321, 321, 321, 321, 182, 321, 324, 321,
- 321, 321, 89, 325, 321, 73, 321, 178,
- 321, 321, 321, 321, 321, 324, 321, 326,
- 327, 328, 329, 75, 73, 321, 178, 321,
- 321, 106, 321, 321, 321, 182, 321, 330,
- 327, 331, 331, 75, 73, 321, 178, 321,
- 321, 321, 321, 321, 321, 182, 321, 327,
- 331, 331, 75, 73, 321, 178, 321, 321,
- 321, 321, 321, 321, 182, 321, 332, 321,
- 321, 321, 89, 333, 321, 73, 321, 178,
- 321, 321, 321, 321, 321, 332, 321, 334,
- 335, 336, 337, 75, 73, 321, 178, 321,
- 321, 104, 321, 321, 321, 182, 321, 338,
- 335, 339, 339, 75, 73, 321, 178, 321,
- 321, 321, 321, 321, 321, 182, 321, 335,
- 339, 339, 75, 73, 321, 178, 321, 321,
- 321, 321, 321, 321, 182, 321, 340, 321,
- 321, 321, 89, 341, 321, 73, 321, 178,
- 321, 321, 321, 321, 321, 340, 321, 342,
- 343, 344, 345, 75, 73, 321, 178, 321,
- 321, 102, 321, 321, 321, 182, 321, 346,
- 343, 347, 347, 75, 73, 321, 178, 321,
- 321, 321, 321, 321, 321, 182, 321, 343,
- 347, 347, 75, 73, 321, 178, 321, 321,
- 321, 321, 321, 321, 182, 321, 348, 321,
- 321, 321, 89, 349, 321, 73, 321, 178,
- 321, 321, 321, 321, 321, 348, 321, 350,
- 351, 352, 353, 75, 73, 321, 178, 321,
- 321, 100, 321, 321, 321, 182, 321, 354,
- 351, 355, 355, 75, 73, 321, 178, 321,
- 321, 321, 321, 321, 321, 182, 321, 351,
- 355, 355, 75, 73, 321, 178, 321, 321,
- 321, 321, 321, 321, 182, 321, 89, 356,
- 321, 73, 321, 178, 321, 357, 357, 321,
- 73, 321, 178, 321, 358, 321, 321, 359,
- 321, 178, 321, 178, 321, 360, 321, 361,
- 321, 358, 321, 321, 321, 321, 178, 321,
- 89, 321, 362, 362, 75, 73, 321, 178,
- 321, 363, 98, 364, 365, 79, 73, 321,
- 178, 321, 98, 364, 365, 79, 73, 321,
- 178, 321, 364, 364, 79, 73, 321, 178,
- 321, 366, 95, 367, 368, 82, 73, 321,
- 178, 321, 95, 367, 368, 82, 73, 321,
- 178, 321, 367, 367, 82, 73, 321, 178,
- 321, 369, 92, 370, 371, 85, 73, 321,
- 178, 321, 92, 370, 371, 85, 73, 321,
- 178, 321, 370, 370, 85, 73, 321, 178,
- 321, 372, 89, 357, 373, 321, 73, 321,
- 178, 321, 89, 357, 373, 321, 73, 321,
- 178, 321, 357, 374, 321, 73, 321, 178,
- 321, 89, 321, 357, 357, 321, 73, 321,
- 178, 321, 351, 355, 355, 75, 73, 321,
- 178, 321, 350, 351, 355, 355, 75, 73,
- 321, 178, 321, 321, 321, 321, 321, 321,
- 182, 321, 350, 351, 352, 355, 75, 73,
- 321, 178, 321, 321, 100, 321, 321, 321,
- 182, 321, 348, 321, 375, 321, 362, 362,
- 75, 73, 321, 178, 321, 321, 321, 321,
- 321, 348, 321, 348, 321, 321, 321, 357,
- 357, 321, 73, 321, 178, 321, 321, 321,
- 321, 321, 348, 321, 348, 321, 321, 321,
- 357, 376, 321, 73, 321, 178, 321, 321,
- 321, 321, 321, 348, 321, 348, 321, 375,
- 321, 357, 357, 321, 73, 321, 178, 321,
- 321, 321, 321, 321, 348, 321, 342, 343,
- 347, 347, 75, 73, 321, 178, 321, 321,
- 321, 321, 321, 321, 182, 321, 342, 343,
- 344, 347, 75, 73, 321, 178, 321, 321,
- 102, 321, 321, 321, 182, 321, 340, 321,
- 377, 321, 362, 362, 75, 73, 321, 178,
- 321, 321, 321, 321, 321, 340, 321, 340,
- 321, 321, 321, 357, 357, 321, 73, 321,
- 178, 321, 321, 321, 321, 321, 340, 321,
- 340, 321, 321, 321, 357, 378, 321, 73,
- 321, 178, 321, 321, 321, 321, 321, 340,
- 321, 340, 321, 377, 321, 357, 357, 321,
- 73, 321, 178, 321, 321, 321, 321, 321,
- 340, 321, 334, 335, 339, 339, 75, 73,
- 321, 178, 321, 321, 321, 321, 321, 321,
- 182, 321, 334, 335, 336, 339, 75, 73,
- 321, 178, 321, 321, 104, 321, 321, 321,
- 182, 321, 332, 321, 379, 321, 362, 362,
- 75, 73, 321, 178, 321, 321, 321, 321,
- 321, 332, 321, 332, 321, 321, 321, 357,
- 357, 321, 73, 321, 178, 321, 321, 321,
- 321, 321, 332, 321, 332, 321, 321, 321,
- 357, 380, 321, 73, 321, 178, 321, 321,
- 321, 321, 321, 332, 321, 332, 321, 379,
- 321, 357, 357, 321, 73, 321, 178, 321,
- 321, 321, 321, 321, 332, 321, 326, 327,
- 331, 331, 75, 73, 321, 178, 321, 321,
- 321, 321, 321, 321, 182, 321, 326, 327,
- 328, 331, 75, 73, 321, 178, 321, 321,
- 106, 321, 321, 321, 182, 321, 324, 321,
- 381, 321, 362, 362, 75, 73, 321, 178,
- 321, 321, 321, 321, 321, 324, 321, 324,
- 321, 321, 321, 357, 357, 321, 73, 321,
- 178, 321, 321, 321, 321, 321, 324, 321,
- 324, 321, 321, 321, 357, 382, 321, 73,
- 321, 178, 321, 321, 321, 321, 321, 324,
- 321, 324, 321, 381, 321, 357, 357, 321,
- 73, 321, 178, 321, 321, 321, 321, 321,
- 324, 321, 107, 74, 74, 75, 73, 383,
- 383, 383, 383, 144, 383, 174, 175, 323,
- 323, 75, 73, 321, 178, 321, 321, 321,
- 321, 321, 321, 182, 321, 107, 74, 74,
- 75, 73, 383, 385, 386, 387, 388, 111,
- 109, 384, 389, 384, 384, 143, 384, 384,
- 384, 390, 384, 391, 386, 388, 388, 111,
- 109, 384, 389, 384, 384, 384, 384, 384,
- 384, 390, 384, 386, 388, 388, 111, 109,
- 384, 389, 384, 384, 384, 384, 384, 384,
- 390, 384, 392, 384, 384, 384, 124, 393,
- 384, 109, 384, 389, 384, 384, 384, 384,
- 384, 392, 384, 394, 395, 396, 397, 111,
- 109, 384, 389, 384, 384, 141, 384, 384,
- 384, 390, 384, 398, 395, 399, 399, 111,
- 109, 384, 389, 384, 384, 384, 384, 384,
- 384, 390, 384, 395, 399, 399, 111, 109,
- 384, 389, 384, 384, 384, 384, 384, 384,
- 390, 384, 400, 384, 384, 384, 124, 401,
- 384, 109, 384, 389, 384, 384, 384, 384,
- 384, 400, 384, 402, 403, 404, 405, 111,
- 109, 384, 389, 384, 384, 139, 384, 384,
- 384, 390, 384, 406, 403, 407, 407, 111,
- 109, 384, 389, 384, 384, 384, 384, 384,
- 384, 390, 384, 403, 407, 407, 111, 109,
- 384, 389, 384, 384, 384, 384, 384, 384,
- 390, 384, 408, 384, 384, 384, 124, 409,
- 384, 109, 384, 389, 384, 384, 384, 384,
- 384, 408, 384, 410, 411, 412, 413, 111,
- 109, 384, 389, 384, 384, 137, 384, 384,
- 384, 390, 384, 414, 411, 415, 415, 111,
- 109, 384, 389, 384, 384, 384, 384, 384,
- 384, 390, 384, 411, 415, 415, 111, 109,
- 384, 389, 384, 384, 384, 384, 384, 384,
- 390, 384, 416, 384, 384, 384, 124, 417,
- 384, 109, 384, 389, 384, 384, 384, 384,
- 384, 416, 384, 418, 419, 420, 421, 111,
- 109, 384, 389, 384, 384, 135, 384, 384,
- 384, 390, 384, 422, 419, 423, 423, 111,
- 109, 384, 389, 384, 384, 384, 384, 384,
- 384, 390, 384, 419, 423, 423, 111, 109,
- 384, 389, 384, 384, 384, 384, 384, 384,
- 390, 384, 124, 424, 384, 109, 384, 389,
- 384, 425, 425, 384, 109, 384, 389, 384,
- 426, 384, 384, 427, 384, 389, 384, 389,
- 384, 428, 384, 429, 384, 426, 384, 384,
- 384, 384, 389, 384, 124, 384, 430, 430,
- 111, 109, 384, 389, 384, 431, 133, 432,
- 433, 114, 109, 384, 389, 384, 133, 432,
- 433, 114, 109, 384, 389, 384, 432, 432,
- 114, 109, 384, 389, 384, 434, 130, 435,
- 436, 117, 109, 384, 389, 384, 130, 435,
- 436, 117, 109, 384, 389, 384, 435, 435,
- 117, 109, 384, 389, 384, 437, 127, 438,
- 439, 120, 109, 384, 389, 384, 127, 438,
- 439, 120, 109, 384, 389, 384, 438, 438,
- 120, 109, 384, 389, 384, 440, 124, 425,
- 441, 384, 109, 384, 389, 384, 124, 425,
- 441, 384, 109, 384, 389, 384, 425, 442,
- 384, 109, 384, 389, 384, 124, 384, 425,
- 425, 384, 109, 384, 389, 384, 419, 423,
- 423, 111, 109, 384, 389, 384, 418, 419,
- 423, 423, 111, 109, 384, 389, 384, 384,
- 384, 384, 384, 384, 390, 384, 418, 419,
- 420, 423, 111, 109, 384, 389, 384, 384,
- 135, 384, 384, 384, 390, 384, 416, 384,
- 443, 384, 430, 430, 111, 109, 384, 389,
- 384, 384, 384, 384, 384, 416, 384, 416,
- 384, 384, 384, 425, 425, 384, 109, 384,
- 389, 384, 384, 384, 384, 384, 416, 384,
- 416, 384, 384, 384, 425, 444, 384, 109,
- 384, 389, 384, 384, 384, 384, 384, 416,
- 384, 416, 384, 443, 384, 425, 425, 384,
- 109, 384, 389, 384, 384, 384, 384, 384,
- 416, 384, 410, 411, 415, 415, 111, 109,
- 384, 389, 384, 384, 384, 384, 384, 384,
- 390, 384, 410, 411, 412, 415, 111, 109,
- 384, 389, 384, 384, 137, 384, 384, 384,
- 390, 384, 408, 384, 445, 384, 430, 430,
- 111, 109, 384, 389, 384, 384, 384, 384,
- 384, 408, 384, 408, 384, 384, 384, 425,
- 425, 384, 109, 384, 389, 384, 384, 384,
- 384, 384, 408, 384, 408, 384, 384, 384,
- 425, 446, 384, 109, 384, 389, 384, 384,
- 384, 384, 384, 408, 384, 408, 384, 445,
- 384, 425, 425, 384, 109, 384, 389, 384,
- 384, 384, 384, 384, 408, 384, 402, 403,
- 407, 407, 111, 109, 384, 389, 384, 384,
- 384, 384, 384, 384, 390, 384, 402, 403,
- 404, 407, 111, 109, 384, 389, 384, 384,
- 139, 384, 384, 384, 390, 384, 400, 384,
- 447, 384, 430, 430, 111, 109, 384, 389,
- 384, 384, 384, 384, 384, 400, 384, 400,
- 384, 384, 384, 425, 425, 384, 109, 384,
- 389, 384, 384, 384, 384, 384, 400, 384,
- 400, 384, 384, 384, 425, 448, 384, 109,
- 384, 389, 384, 384, 384, 384, 384, 400,
- 384, 400, 384, 447, 384, 425, 425, 384,
- 109, 384, 389, 384, 384, 384, 384, 384,
- 400, 384, 394, 395, 399, 399, 111, 109,
- 384, 389, 384, 384, 384, 384, 384, 384,
- 390, 384, 394, 395, 396, 399, 111, 109,
- 384, 389, 384, 384, 141, 384, 384, 384,
- 390, 384, 392, 384, 449, 384, 430, 430,
- 111, 109, 384, 389, 384, 384, 384, 384,
- 384, 392, 384, 392, 384, 384, 384, 425,
- 425, 384, 109, 384, 389, 384, 384, 384,
- 384, 384, 392, 384, 392, 384, 384, 384,
- 425, 450, 384, 109, 384, 389, 384, 384,
- 384, 384, 384, 392, 384, 392, 384, 449,
- 384, 425, 425, 384, 109, 384, 389, 384,
- 384, 384, 384, 384, 392, 384, 385, 386,
- 388, 388, 111, 109, 384, 389, 384, 384,
- 384, 384, 384, 384, 390, 384, 172, 173,
- 174, 175, 451, 323, 75, 73, 321, 178,
- 179, 179, 144, 321, 321, 172, 182, 321,
- 186, 452, 188, 189, 3, 1, 185, 190,
- 185, 185, 35, 185, 185, 185, 191, 185,
- 194, 173, 174, 175, 453, 454, 75, 149,
- 185, 455, 185, 179, 144, 185, 185, 194,
- 182, 185, 107, 456, 456, 75, 149, 185,
- 190, 185, 185, 144, 185, 457, 185, 185,
- 458, 185, 455, 185, 455, 185, 459, 185,
- 231, 185, 457, 185, 185, 185, 185, 455,
- 185, 194, 185, 251, 107, 460, 460, 146,
- 149, 185, 190, 185, 185, 185, 185, 185,
- 194, 185, 461, 168, 462, 463, 148, 149,
- 185, 455, 185, 168, 462, 463, 148, 149,
- 185, 455, 185, 462, 462, 148, 149, 185,
- 455, 185, 464, 165, 465, 466, 152, 149,
- 185, 455, 185, 165, 465, 466, 152, 149,
- 185, 455, 185, 465, 465, 152, 149, 185,
- 455, 185, 467, 162, 468, 469, 155, 149,
- 185, 455, 185, 162, 468, 469, 155, 149,
- 185, 455, 185, 468, 468, 155, 149, 185,
- 455, 185, 470, 159, 471, 472, 185, 149,
- 185, 455, 185, 159, 471, 472, 185, 149,
- 185, 455, 185, 471, 471, 185, 149, 185,
- 455, 185, 474, 473, 475, 475, 473, 170,
- 473, 476, 473, 475, 475, 473, 170, 473,
- 476, 473, 477, 473, 473, 478, 473, 476,
- 473, 476, 473, 479, 473, 480, 473, 477,
- 473, 473, 473, 473, 476, 473, 172, 383,
- 383, 383, 383, 383, 383, 383, 383, 383,
- 179, 383, 383, 383, 383, 172, 383, 0
+ 1, 0, 2, 3, 3, 4, 1, 0,
+ 5, 5, 4, 0, 4, 0, 6, 6,
+ 7, 1, 0, 8, 8, 7, 0, 7,
+ 0, 9, 9, 10, 1, 0, 11, 11,
+ 10, 0, 10, 0, 12, 12, 13, 1,
+ 0, 14, 14, 13, 0, 13, 0, 15,
+ 0, 0, 0, 1, 0, 16, 0, 17,
+ 0, 18, 12, 12, 13, 1, 0, 19,
+ 0, 20, 0, 21, 9, 9, 10, 1,
+ 0, 22, 0, 23, 0, 24, 6, 6,
+ 7, 1, 0, 25, 0, 26, 0, 2,
+ 3, 3, 4, 1, 0, 0, 0, 0,
+ 27, 0, 28, 3, 3, 4, 1, 0,
+ 28, 3, 3, 4, 1, 0, 0, 0,
+ 0, 29, 0, 30, 3, 3, 4, 1,
+ 0, 30, 3, 3, 4, 1, 0, 0,
+ 0, 0, 31, 0, 32, 3, 3, 4,
+ 1, 0, 32, 3, 3, 4, 1, 0,
+ 0, 0, 0, 33, 0, 34, 3, 3,
+ 4, 1, 0, 34, 3, 3, 4, 1,
+ 0, 0, 0, 0, 35, 0, 37, 36,
+ 38, 39, 39, 40, 37, 36, 41, 41,
+ 40, 36, 40, 36, 42, 42, 43, 37,
+ 36, 44, 44, 43, 36, 43, 36, 45,
+ 45, 46, 37, 36, 47, 47, 46, 36,
+ 46, 36, 48, 48, 49, 37, 36, 50,
+ 50, 49, 36, 49, 36, 51, 36, 36,
+ 36, 37, 36, 52, 36, 53, 36, 54,
+ 48, 48, 49, 37, 36, 55, 36, 56,
+ 36, 57, 45, 45, 46, 37, 36, 58,
+ 36, 59, 36, 60, 42, 42, 43, 37,
+ 36, 61, 36, 62, 36, 38, 39, 39,
+ 40, 37, 36, 36, 36, 36, 63, 36,
+ 64, 39, 39, 40, 37, 36, 64, 39,
+ 39, 40, 37, 36, 36, 36, 36, 65,
+ 36, 66, 39, 39, 40, 37, 36, 66,
+ 39, 39, 40, 37, 36, 36, 36, 36,
+ 67, 36, 68, 39, 39, 40, 37, 36,
+ 68, 39, 39, 40, 37, 36, 36, 36,
+ 36, 69, 36, 70, 39, 39, 40, 37,
+ 36, 70, 39, 39, 40, 37, 36, 36,
+ 36, 36, 71, 36, 73, 72, 74, 75,
+ 75, 76, 73, 72, 78, 78, 76, 77,
+ 76, 77, 79, 79, 80, 73, 72, 81,
+ 81, 80, 72, 80, 72, 82, 82, 83,
+ 73, 72, 84, 84, 83, 72, 83, 72,
+ 85, 85, 86, 73, 72, 87, 87, 86,
+ 72, 86, 72, 88, 72, 72, 72, 73,
+ 72, 89, 72, 90, 72, 91, 85, 85,
+ 86, 73, 72, 92, 72, 93, 72, 94,
+ 82, 82, 83, 73, 72, 95, 72, 96,
+ 72, 97, 79, 79, 80, 73, 72, 98,
+ 72, 99, 72, 74, 75, 75, 76, 73,
+ 72, 72, 72, 72, 100, 72, 101, 75,
+ 75, 76, 73, 72, 101, 75, 75, 76,
+ 73, 72, 72, 72, 72, 102, 72, 103,
+ 75, 75, 76, 73, 72, 103, 75, 75,
+ 76, 73, 72, 72, 72, 72, 104, 72,
+ 105, 75, 75, 76, 73, 72, 105, 75,
+ 75, 76, 73, 72, 72, 72, 72, 106,
+ 72, 107, 75, 75, 76, 73, 72, 109,
+ 108, 110, 111, 111, 112, 109, 108, 113,
+ 113, 112, 108, 112, 108, 114, 114, 115,
+ 109, 108, 116, 116, 115, 108, 115, 108,
+ 117, 117, 118, 109, 108, 119, 119, 118,
+ 108, 118, 108, 120, 120, 121, 109, 108,
+ 122, 122, 121, 108, 121, 108, 123, 108,
+ 108, 108, 109, 108, 124, 108, 125, 108,
+ 126, 120, 120, 121, 109, 108, 127, 108,
+ 128, 108, 129, 117, 117, 118, 109, 108,
+ 130, 108, 131, 108, 132, 114, 114, 115,
+ 109, 108, 133, 108, 134, 108, 110, 111,
+ 111, 112, 109, 108, 108, 108, 108, 135,
+ 108, 136, 111, 111, 112, 109, 108, 136,
+ 111, 111, 112, 109, 108, 108, 108, 108,
+ 137, 108, 138, 111, 111, 112, 109, 108,
+ 138, 111, 111, 112, 109, 108, 108, 108,
+ 108, 139, 108, 140, 111, 111, 112, 109,
+ 108, 140, 111, 111, 112, 109, 108, 108,
+ 108, 108, 141, 108, 142, 111, 111, 112,
+ 109, 108, 142, 111, 111, 112, 109, 108,
+ 108, 108, 108, 143, 108, 107, 75, 75,
+ 76, 73, 72, 72, 72, 72, 144, 72,
+ 78, 78, 76, 1, 0, 146, 145, 148,
+ 149, 150, 151, 152, 153, 76, 73, 147,
+ 154, 155, 155, 144, 147, 156, 157, 147,
+ 158, 159, 147, 161, 162, 163, 164, 4,
+ 1, 160, 165, 160, 160, 35, 160, 166,
+ 162, 167, 167, 4, 1, 160, 165, 160,
+ 162, 167, 167, 4, 1, 160, 165, 160,
+ 168, 160, 160, 160, 17, 169, 160, 1,
+ 160, 165, 160, 160, 160, 160, 160, 168,
+ 160, 170, 171, 172, 173, 4, 1, 160,
+ 165, 160, 160, 33, 160, 174, 171, 175,
+ 175, 4, 1, 160, 165, 160, 171, 175,
+ 175, 4, 1, 160, 165, 160, 176, 160,
+ 160, 160, 17, 177, 160, 1, 160, 165,
+ 160, 160, 160, 160, 160, 176, 160, 178,
+ 179, 180, 181, 4, 1, 160, 165, 160,
+ 160, 31, 160, 182, 179, 183, 183, 4,
+ 1, 160, 165, 160, 179, 183, 183, 4,
+ 1, 160, 165, 160, 184, 160, 160, 160,
+ 17, 185, 160, 1, 160, 165, 160, 160,
+ 160, 160, 160, 184, 160, 186, 187, 188,
+ 189, 4, 1, 160, 165, 160, 160, 29,
+ 160, 190, 187, 191, 191, 4, 1, 160,
+ 165, 160, 187, 191, 191, 4, 1, 160,
+ 165, 160, 192, 160, 160, 160, 17, 193,
+ 160, 1, 160, 165, 160, 160, 160, 160,
+ 160, 192, 160, 194, 195, 196, 197, 4,
+ 1, 160, 165, 160, 160, 27, 160, 198,
+ 195, 199, 199, 4, 1, 160, 165, 160,
+ 195, 199, 199, 4, 1, 160, 165, 160,
+ 17, 200, 160, 1, 160, 165, 160, 201,
+ 201, 160, 1, 160, 165, 160, 202, 160,
+ 160, 203, 160, 165, 160, 165, 160, 204,
+ 160, 205, 160, 202, 160, 160, 160, 160,
+ 165, 160, 17, 160, 201, 201, 160, 1,
+ 160, 165, 160, 201, 200, 160, 1, 160,
+ 165, 160, 206, 26, 207, 208, 7, 1,
+ 160, 165, 160, 26, 207, 208, 7, 1,
+ 160, 165, 160, 207, 207, 7, 1, 160,
+ 165, 160, 209, 23, 210, 211, 10, 1,
+ 160, 165, 160, 23, 210, 211, 10, 1,
+ 160, 165, 160, 210, 210, 10, 1, 160,
+ 165, 160, 212, 20, 213, 214, 13, 1,
+ 160, 165, 160, 20, 213, 214, 13, 1,
+ 160, 165, 160, 213, 213, 13, 1, 160,
+ 165, 160, 215, 17, 201, 216, 160, 1,
+ 160, 165, 160, 17, 201, 216, 160, 1,
+ 160, 165, 160, 194, 195, 199, 199, 4,
+ 1, 160, 165, 160, 194, 195, 196, 199,
+ 4, 1, 160, 165, 160, 160, 27, 160,
+ 192, 160, 217, 160, 201, 201, 160, 1,
+ 160, 165, 160, 160, 160, 160, 160, 192,
+ 160, 192, 160, 160, 160, 201, 201, 160,
+ 1, 160, 165, 160, 160, 160, 160, 160,
+ 192, 160, 192, 160, 160, 160, 201, 193,
+ 160, 1, 160, 165, 160, 160, 160, 160,
+ 160, 192, 160, 186, 187, 191, 191, 4,
+ 1, 160, 165, 160, 186, 187, 188, 191,
+ 4, 1, 160, 165, 160, 160, 29, 160,
+ 184, 160, 218, 160, 201, 201, 160, 1,
+ 160, 165, 160, 160, 160, 160, 160, 184,
+ 160, 184, 160, 160, 160, 201, 201, 160,
+ 1, 160, 165, 160, 160, 160, 160, 160,
+ 184, 160, 184, 160, 160, 160, 201, 185,
+ 160, 1, 160, 165, 160, 160, 160, 160,
+ 160, 184, 160, 178, 179, 183, 183, 4,
+ 1, 160, 165, 160, 178, 179, 180, 183,
+ 4, 1, 160, 165, 160, 160, 31, 160,
+ 176, 160, 219, 160, 201, 201, 160, 1,
+ 160, 165, 160, 160, 160, 160, 160, 176,
+ 160, 176, 160, 160, 160, 201, 201, 160,
+ 1, 160, 165, 160, 160, 160, 160, 160,
+ 176, 160, 176, 160, 160, 160, 201, 177,
+ 160, 1, 160, 165, 160, 160, 160, 160,
+ 160, 176, 160, 170, 171, 175, 175, 4,
+ 1, 160, 165, 160, 170, 171, 172, 175,
+ 4, 1, 160, 165, 160, 160, 33, 160,
+ 168, 160, 220, 160, 201, 201, 160, 1,
+ 160, 165, 160, 160, 160, 160, 160, 168,
+ 160, 168, 160, 160, 160, 201, 201, 160,
+ 1, 160, 165, 160, 160, 160, 160, 160,
+ 168, 160, 168, 160, 160, 160, 201, 169,
+ 160, 1, 160, 165, 160, 160, 160, 160,
+ 160, 168, 160, 161, 162, 167, 167, 4,
+ 1, 160, 165, 160, 161, 162, 163, 167,
+ 4, 1, 160, 165, 160, 160, 35, 160,
+ 222, 223, 224, 225, 40, 37, 221, 226,
+ 221, 221, 71, 221, 227, 223, 228, 225,
+ 40, 37, 221, 226, 221, 223, 228, 225,
+ 40, 37, 221, 226, 221, 229, 221, 221,
+ 221, 53, 230, 221, 37, 221, 226, 221,
+ 221, 221, 221, 221, 229, 221, 231, 232,
+ 233, 234, 40, 37, 221, 226, 221, 221,
+ 69, 221, 235, 232, 236, 236, 40, 37,
+ 221, 226, 221, 232, 236, 236, 40, 37,
+ 221, 226, 221, 237, 221, 221, 221, 53,
+ 238, 221, 37, 221, 226, 221, 221, 221,
+ 221, 221, 237, 221, 239, 240, 241, 242,
+ 40, 37, 221, 226, 221, 221, 67, 221,
+ 243, 240, 244, 244, 40, 37, 221, 226,
+ 221, 240, 244, 244, 40, 37, 221, 226,
+ 221, 245, 221, 221, 221, 53, 246, 221,
+ 37, 221, 226, 221, 221, 221, 221, 221,
+ 245, 221, 247, 248, 249, 250, 40, 37,
+ 221, 226, 221, 221, 65, 221, 251, 248,
+ 252, 252, 40, 37, 221, 226, 221, 248,
+ 252, 252, 40, 37, 221, 226, 221, 253,
+ 221, 221, 221, 53, 254, 221, 37, 221,
+ 226, 221, 221, 221, 221, 221, 253, 221,
+ 255, 256, 257, 258, 40, 37, 221, 226,
+ 221, 221, 63, 221, 259, 256, 260, 260,
+ 40, 37, 221, 226, 221, 256, 260, 260,
+ 40, 37, 221, 226, 221, 53, 261, 221,
+ 37, 221, 226, 221, 262, 262, 221, 37,
+ 221, 226, 221, 263, 221, 221, 264, 221,
+ 226, 221, 226, 221, 265, 221, 266, 221,
+ 263, 221, 221, 221, 221, 226, 221, 53,
+ 221, 262, 262, 221, 37, 221, 226, 221,
+ 262, 261, 221, 37, 221, 226, 221, 267,
+ 62, 268, 269, 43, 37, 221, 226, 221,
+ 62, 268, 269, 43, 37, 221, 226, 221,
+ 268, 268, 43, 37, 221, 226, 221, 270,
+ 59, 271, 272, 46, 37, 221, 226, 221,
+ 59, 271, 272, 46, 37, 221, 226, 221,
+ 271, 271, 46, 37, 221, 226, 221, 273,
+ 56, 274, 275, 49, 37, 221, 226, 221,
+ 56, 274, 275, 49, 37, 221, 226, 221,
+ 274, 274, 49, 37, 221, 226, 221, 276,
+ 53, 262, 277, 221, 37, 221, 226, 221,
+ 53, 262, 277, 221, 37, 221, 226, 221,
+ 255, 256, 260, 260, 40, 37, 221, 226,
+ 221, 255, 256, 257, 260, 40, 37, 221,
+ 226, 221, 221, 63, 221, 253, 221, 278,
+ 221, 262, 262, 221, 37, 221, 226, 221,
+ 221, 221, 221, 221, 253, 221, 253, 221,
+ 221, 221, 262, 262, 221, 37, 221, 226,
+ 221, 221, 221, 221, 221, 253, 221, 253,
+ 221, 221, 221, 262, 254, 221, 37, 221,
+ 226, 221, 221, 221, 221, 221, 253, 221,
+ 247, 248, 252, 252, 40, 37, 221, 226,
+ 221, 247, 248, 249, 252, 40, 37, 221,
+ 226, 221, 221, 65, 221, 245, 221, 279,
+ 221, 262, 262, 221, 37, 221, 226, 221,
+ 221, 221, 221, 221, 245, 221, 245, 221,
+ 221, 221, 262, 262, 221, 37, 221, 226,
+ 221, 221, 221, 221, 221, 245, 221, 245,
+ 221, 221, 221, 262, 246, 221, 37, 221,
+ 226, 221, 221, 221, 221, 221, 245, 221,
+ 239, 240, 244, 244, 40, 37, 221, 226,
+ 221, 239, 240, 241, 244, 40, 37, 221,
+ 226, 221, 221, 67, 221, 237, 221, 280,
+ 221, 262, 262, 221, 37, 221, 226, 221,
+ 221, 221, 221, 221, 237, 221, 237, 221,
+ 221, 221, 262, 262, 221, 37, 221, 226,
+ 221, 221, 221, 221, 221, 237, 221, 237,
+ 221, 221, 221, 262, 238, 221, 37, 221,
+ 226, 221, 221, 221, 221, 221, 237, 221,
+ 231, 232, 236, 236, 40, 37, 221, 226,
+ 221, 231, 232, 233, 236, 40, 37, 221,
+ 226, 221, 221, 69, 221, 229, 221, 281,
+ 221, 262, 262, 221, 37, 221, 226, 221,
+ 221, 221, 221, 221, 229, 221, 229, 221,
+ 221, 221, 262, 262, 221, 37, 221, 226,
+ 221, 221, 221, 221, 221, 229, 221, 229,
+ 221, 221, 221, 262, 230, 221, 37, 221,
+ 226, 221, 221, 221, 221, 221, 229, 221,
+ 70, 39, 39, 40, 37, 221, 222, 223,
+ 228, 225, 40, 37, 221, 226, 221, 283,
+ 151, 284, 284, 76, 73, 282, 154, 282,
+ 151, 284, 284, 76, 73, 282, 154, 282,
+ 285, 282, 282, 282, 90, 286, 282, 73,
+ 282, 154, 282, 282, 282, 282, 282, 285,
+ 282, 287, 288, 289, 290, 76, 73, 282,
+ 154, 282, 282, 106, 282, 291, 288, 292,
+ 292, 76, 73, 282, 154, 282, 288, 292,
+ 292, 76, 73, 282, 154, 282, 293, 282,
+ 282, 282, 90, 294, 282, 73, 282, 154,
+ 282, 282, 282, 282, 282, 293, 282, 295,
+ 296, 297, 298, 76, 73, 282, 154, 282,
+ 282, 104, 282, 299, 296, 300, 300, 76,
+ 73, 282, 154, 282, 296, 300, 300, 76,
+ 73, 282, 154, 282, 301, 282, 282, 282,
+ 90, 302, 282, 73, 282, 154, 282, 282,
+ 282, 282, 282, 301, 282, 303, 304, 305,
+ 306, 76, 73, 282, 154, 282, 282, 102,
+ 282, 307, 304, 308, 308, 76, 73, 282,
+ 154, 282, 304, 308, 308, 76, 73, 282,
+ 154, 282, 309, 282, 282, 282, 90, 310,
+ 282, 73, 282, 154, 282, 282, 282, 282,
+ 282, 309, 282, 311, 312, 313, 314, 76,
+ 73, 282, 154, 282, 282, 100, 282, 315,
+ 312, 316, 316, 76, 73, 282, 154, 282,
+ 312, 316, 316, 76, 73, 282, 154, 282,
+ 90, 317, 282, 73, 282, 154, 282, 318,
+ 318, 282, 73, 282, 154, 282, 319, 282,
+ 282, 320, 282, 154, 282, 154, 282, 321,
+ 282, 322, 282, 319, 282, 282, 282, 282,
+ 154, 282, 90, 282, 318, 318, 282, 73,
+ 282, 154, 282, 318, 317, 282, 73, 282,
+ 154, 282, 323, 99, 324, 325, 80, 73,
+ 282, 154, 282, 99, 324, 325, 80, 73,
+ 282, 154, 282, 324, 324, 80, 73, 282,
+ 154, 282, 326, 96, 327, 328, 83, 73,
+ 282, 154, 282, 96, 327, 328, 83, 73,
+ 282, 154, 282, 327, 327, 83, 73, 282,
+ 154, 282, 329, 93, 330, 331, 86, 73,
+ 282, 154, 282, 93, 330, 331, 86, 73,
+ 282, 154, 282, 330, 330, 86, 73, 282,
+ 154, 282, 332, 90, 318, 333, 282, 73,
+ 282, 154, 282, 90, 318, 333, 282, 73,
+ 282, 154, 282, 311, 312, 316, 316, 76,
+ 73, 282, 154, 282, 311, 312, 313, 316,
+ 76, 73, 282, 154, 282, 282, 100, 282,
+ 309, 282, 334, 282, 318, 318, 282, 73,
+ 282, 154, 282, 282, 282, 282, 282, 309,
+ 282, 309, 282, 282, 282, 318, 318, 282,
+ 73, 282, 154, 282, 282, 282, 282, 282,
+ 309, 282, 309, 282, 282, 282, 318, 310,
+ 282, 73, 282, 154, 282, 282, 282, 282,
+ 282, 309, 282, 303, 304, 308, 308, 76,
+ 73, 282, 154, 282, 303, 304, 305, 308,
+ 76, 73, 282, 154, 282, 282, 102, 282,
+ 301, 282, 335, 282, 318, 318, 282, 73,
+ 282, 154, 282, 282, 282, 282, 282, 301,
+ 282, 301, 282, 282, 282, 318, 318, 282,
+ 73, 282, 154, 282, 282, 282, 282, 282,
+ 301, 282, 301, 282, 282, 282, 318, 302,
+ 282, 73, 282, 154, 282, 282, 282, 282,
+ 282, 301, 282, 295, 296, 300, 300, 76,
+ 73, 282, 154, 282, 295, 296, 297, 300,
+ 76, 73, 282, 154, 282, 282, 104, 282,
+ 293, 282, 336, 282, 318, 318, 282, 73,
+ 282, 154, 282, 282, 282, 282, 282, 293,
+ 282, 293, 282, 282, 282, 318, 318, 282,
+ 73, 282, 154, 282, 282, 282, 282, 282,
+ 293, 282, 293, 282, 282, 282, 318, 294,
+ 282, 73, 282, 154, 282, 282, 282, 282,
+ 282, 293, 282, 287, 288, 292, 292, 76,
+ 73, 282, 154, 282, 287, 288, 289, 292,
+ 76, 73, 282, 154, 282, 282, 106, 282,
+ 285, 282, 337, 282, 318, 318, 282, 73,
+ 282, 154, 282, 282, 282, 282, 282, 285,
+ 282, 285, 282, 282, 282, 318, 318, 282,
+ 73, 282, 154, 282, 282, 282, 282, 282,
+ 285, 282, 285, 282, 282, 282, 318, 286,
+ 282, 73, 282, 154, 282, 282, 282, 282,
+ 282, 285, 282, 107, 75, 75, 76, 73,
+ 338, 338, 338, 338, 144, 338, 150, 151,
+ 284, 284, 76, 73, 282, 154, 282, 107,
+ 75, 75, 76, 73, 338, 340, 341, 342,
+ 343, 112, 109, 339, 344, 339, 339, 143,
+ 339, 345, 341, 343, 343, 112, 109, 339,
+ 344, 339, 341, 343, 343, 112, 109, 339,
+ 344, 339, 346, 339, 339, 339, 125, 347,
+ 339, 109, 339, 344, 339, 339, 339, 339,
+ 339, 346, 339, 348, 349, 350, 351, 112,
+ 109, 339, 344, 339, 339, 141, 339, 352,
+ 349, 353, 353, 112, 109, 339, 344, 339,
+ 349, 353, 353, 112, 109, 339, 344, 339,
+ 354, 339, 339, 339, 125, 355, 339, 109,
+ 339, 344, 339, 339, 339, 339, 339, 354,
+ 339, 356, 357, 358, 359, 112, 109, 339,
+ 344, 339, 339, 139, 339, 360, 357, 361,
+ 361, 112, 109, 339, 344, 339, 357, 361,
+ 361, 112, 109, 339, 344, 339, 362, 339,
+ 339, 339, 125, 363, 339, 109, 339, 344,
+ 339, 339, 339, 339, 339, 362, 339, 364,
+ 365, 366, 367, 112, 109, 339, 344, 339,
+ 339, 137, 339, 368, 365, 369, 369, 112,
+ 109, 339, 344, 339, 365, 369, 369, 112,
+ 109, 339, 344, 339, 370, 339, 339, 339,
+ 125, 371, 339, 109, 339, 344, 339, 339,
+ 339, 339, 339, 370, 339, 372, 373, 374,
+ 375, 112, 109, 339, 344, 339, 339, 135,
+ 339, 376, 373, 377, 377, 112, 109, 339,
+ 344, 339, 373, 377, 377, 112, 109, 339,
+ 344, 339, 125, 378, 339, 109, 339, 344,
+ 339, 379, 379, 339, 109, 339, 344, 339,
+ 380, 339, 339, 381, 339, 344, 339, 344,
+ 339, 382, 339, 383, 339, 380, 339, 339,
+ 339, 339, 344, 339, 125, 339, 379, 379,
+ 339, 109, 339, 344, 339, 379, 378, 339,
+ 109, 339, 344, 339, 384, 134, 385, 386,
+ 115, 109, 339, 344, 339, 134, 385, 386,
+ 115, 109, 339, 344, 339, 385, 385, 115,
+ 109, 339, 344, 339, 387, 131, 388, 389,
+ 118, 109, 339, 344, 339, 131, 388, 389,
+ 118, 109, 339, 344, 339, 388, 388, 118,
+ 109, 339, 344, 339, 390, 128, 391, 392,
+ 121, 109, 339, 344, 339, 128, 391, 392,
+ 121, 109, 339, 344, 339, 391, 391, 121,
+ 109, 339, 344, 339, 393, 125, 379, 394,
+ 339, 109, 339, 344, 339, 125, 379, 394,
+ 339, 109, 339, 344, 339, 372, 373, 377,
+ 377, 112, 109, 339, 344, 339, 372, 373,
+ 374, 377, 112, 109, 339, 344, 339, 339,
+ 135, 339, 370, 339, 395, 339, 379, 379,
+ 339, 109, 339, 344, 339, 339, 339, 339,
+ 339, 370, 339, 370, 339, 339, 339, 379,
+ 379, 339, 109, 339, 344, 339, 339, 339,
+ 339, 339, 370, 339, 370, 339, 339, 339,
+ 379, 371, 339, 109, 339, 344, 339, 339,
+ 339, 339, 339, 370, 339, 364, 365, 369,
+ 369, 112, 109, 339, 344, 339, 364, 365,
+ 366, 369, 112, 109, 339, 344, 339, 339,
+ 137, 339, 362, 339, 396, 339, 379, 379,
+ 339, 109, 339, 344, 339, 339, 339, 339,
+ 339, 362, 339, 362, 339, 339, 339, 379,
+ 379, 339, 109, 339, 344, 339, 339, 339,
+ 339, 339, 362, 339, 362, 339, 339, 339,
+ 379, 363, 339, 109, 339, 344, 339, 339,
+ 339, 339, 339, 362, 339, 356, 357, 361,
+ 361, 112, 109, 339, 344, 339, 356, 357,
+ 358, 361, 112, 109, 339, 344, 339, 339,
+ 139, 339, 354, 339, 397, 339, 379, 379,
+ 339, 109, 339, 344, 339, 339, 339, 339,
+ 339, 354, 339, 354, 339, 339, 339, 379,
+ 379, 339, 109, 339, 344, 339, 339, 339,
+ 339, 339, 354, 339, 354, 339, 339, 339,
+ 379, 355, 339, 109, 339, 344, 339, 339,
+ 339, 339, 339, 354, 339, 348, 349, 353,
+ 353, 112, 109, 339, 344, 339, 348, 349,
+ 350, 353, 112, 109, 339, 344, 339, 339,
+ 141, 339, 346, 339, 398, 339, 379, 379,
+ 339, 109, 339, 344, 339, 339, 339, 339,
+ 339, 346, 339, 346, 339, 339, 339, 379,
+ 379, 339, 109, 339, 344, 339, 339, 339,
+ 339, 339, 346, 339, 346, 339, 339, 339,
+ 379, 347, 339, 109, 339, 344, 339, 339,
+ 339, 339, 339, 346, 339, 340, 341, 343,
+ 343, 112, 109, 339, 344, 339, 148, 149,
+ 150, 151, 399, 284, 76, 73, 282, 154,
+ 155, 155, 144, 282, 282, 148, 282, 161,
+ 400, 163, 164, 4, 1, 160, 165, 160,
+ 160, 35, 160, 168, 149, 150, 151, 401,
+ 402, 76, 403, 160, 404, 160, 155, 144,
+ 160, 160, 168, 160, 107, 405, 405, 76,
+ 403, 160, 165, 160, 160, 144, 160, 406,
+ 160, 160, 407, 160, 404, 160, 404, 160,
+ 408, 160, 205, 160, 406, 160, 160, 160,
+ 160, 404, 160, 168, 160, 220, 107, 405,
+ 405, 76, 403, 160, 165, 160, 160, 160,
+ 160, 160, 168, 160, 410, 409, 411, 411,
+ 409, 146, 409, 412, 409, 411, 411, 409,
+ 146, 409, 412, 409, 413, 409, 409, 414,
+ 409, 412, 409, 412, 409, 415, 409, 416,
+ 409, 413, 409, 409, 409, 409, 412, 409,
+ 148, 338, 338, 338, 338, 338, 338, 338,
+ 338, 338, 155, 338, 338, 338, 338, 148,
+ 338, 0
};
static const short _indic_syllable_machine_trans_targs[] = {
- 166, 188, 2, 194, 3, 5, 197, 6,
- 8, 200, 9, 11, 203, 12, 14, 15,
- 187, 17, 18, 202, 20, 21, 199, 23,
- 24, 196, 205, 208, 212, 214, 218, 220,
- 224, 226, 230, 232, 166, 255, 37, 261,
- 38, 40, 264, 41, 43, 267, 44, 46,
- 270, 47, 49, 50, 254, 52, 53, 269,
- 55, 56, 266, 58, 59, 263, 272, 275,
- 279, 281, 285, 287, 291, 293, 297, 300,
- 166, 321, 72, 327, 166, 73, 75, 330,
- 76, 78, 333, 79, 81, 336, 82, 84,
- 85, 320, 87, 88, 335, 90, 91, 332,
- 93, 94, 329, 338, 341, 345, 347, 351,
- 353, 357, 359, 363, 166, 389, 106, 395,
- 107, 109, 398, 110, 112, 401, 113, 115,
- 404, 116, 118, 119, 388, 121, 122, 403,
- 124, 125, 400, 127, 128, 397, 406, 409,
- 413, 415, 419, 421, 425, 427, 431, 433,
- 366, 142, 444, 144, 447, 438, 145, 147,
- 450, 148, 150, 453, 151, 154, 155, 455,
- 157, 158, 452, 160, 161, 449, 163, 164,
- 446, 166, 458, 166, 167, 234, 301, 303,
- 365, 367, 323, 368, 434, 435, 340, 456,
- 463, 166, 168, 170, 34, 233, 190, 207,
- 169, 33, 171, 228, 172, 174, 32, 227,
- 173, 31, 175, 222, 176, 178, 30, 221,
- 177, 29, 179, 216, 180, 182, 28, 215,
- 181, 27, 183, 210, 184, 186, 26, 209,
- 185, 25, 193, 0, 189, 192, 191, 166,
- 1, 195, 4, 22, 198, 7, 19, 201,
- 10, 16, 204, 13, 206, 211, 213, 217,
- 219, 223, 225, 229, 231, 166, 235, 237,
- 69, 299, 257, 274, 236, 68, 238, 295,
- 239, 241, 67, 294, 240, 66, 242, 289,
- 243, 245, 65, 288, 244, 64, 246, 283,
- 247, 249, 63, 282, 248, 62, 250, 277,
- 251, 253, 61, 276, 252, 60, 260, 35,
- 256, 259, 258, 166, 36, 262, 39, 57,
- 265, 42, 54, 268, 45, 51, 271, 48,
- 273, 278, 280, 284, 286, 290, 292, 296,
- 298, 166, 302, 103, 304, 361, 305, 307,
- 102, 360, 306, 101, 308, 355, 309, 311,
- 100, 354, 310, 99, 312, 349, 313, 315,
- 98, 348, 314, 97, 316, 343, 317, 319,
- 96, 342, 318, 95, 326, 70, 322, 325,
- 324, 166, 71, 328, 74, 92, 331, 77,
- 89, 334, 80, 86, 337, 83, 339, 344,
- 346, 350, 352, 356, 358, 362, 364, 166,
- 166, 369, 371, 138, 137, 391, 408, 370,
- 372, 429, 373, 375, 136, 428, 374, 135,
- 376, 423, 377, 379, 134, 422, 378, 133,
- 380, 417, 381, 383, 132, 416, 382, 131,
- 384, 411, 385, 387, 130, 410, 386, 129,
- 394, 104, 390, 393, 392, 166, 105, 396,
- 108, 126, 399, 111, 123, 402, 114, 120,
- 405, 117, 407, 412, 414, 418, 420, 424,
- 426, 430, 432, 139, 436, 437, 443, 440,
- 140, 439, 442, 441, 141, 445, 143, 162,
- 448, 146, 159, 451, 149, 156, 454, 152,
- 153, 166, 457, 165, 460, 459, 462, 461,
- 166
+ 138, 160, 166, 2, 167, 3, 5, 170,
+ 6, 8, 173, 9, 11, 176, 12, 14,
+ 15, 159, 17, 18, 175, 20, 21, 172,
+ 23, 24, 169, 178, 182, 183, 187, 188,
+ 192, 193, 197, 198, 138, 221, 227, 36,
+ 228, 37, 39, 231, 40, 42, 234, 43,
+ 45, 237, 46, 48, 49, 220, 51, 52,
+ 236, 54, 55, 233, 57, 58, 230, 239,
+ 243, 244, 248, 249, 253, 254, 258, 260,
+ 138, 281, 287, 70, 288, 138, 71, 73,
+ 291, 74, 76, 294, 77, 79, 297, 80,
+ 82, 83, 280, 85, 86, 296, 88, 89,
+ 293, 91, 92, 290, 299, 303, 304, 308,
+ 309, 313, 314, 318, 138, 343, 349, 103,
+ 350, 104, 106, 353, 107, 109, 356, 110,
+ 112, 359, 113, 115, 116, 342, 118, 119,
+ 358, 121, 122, 355, 124, 125, 352, 361,
+ 365, 366, 370, 371, 375, 376, 380, 381,
+ 320, 138, 394, 138, 139, 200, 261, 263,
+ 319, 321, 283, 322, 382, 383, 392, 399,
+ 138, 140, 142, 33, 199, 162, 141, 32,
+ 143, 195, 144, 146, 31, 194, 145, 30,
+ 147, 190, 148, 150, 29, 189, 149, 28,
+ 151, 185, 152, 154, 27, 184, 153, 26,
+ 155, 180, 156, 158, 25, 179, 157, 1,
+ 165, 0, 161, 164, 163, 138, 168, 4,
+ 22, 171, 7, 19, 174, 10, 16, 177,
+ 13, 181, 186, 191, 196, 138, 201, 203,
+ 67, 259, 223, 202, 66, 204, 256, 205,
+ 207, 65, 255, 206, 64, 208, 251, 209,
+ 211, 63, 250, 210, 62, 212, 246, 213,
+ 215, 61, 245, 214, 60, 216, 241, 217,
+ 219, 59, 240, 218, 35, 226, 34, 222,
+ 225, 224, 138, 229, 38, 56, 232, 41,
+ 53, 235, 44, 50, 238, 47, 242, 247,
+ 252, 257, 138, 262, 100, 264, 316, 265,
+ 267, 99, 315, 266, 98, 268, 311, 269,
+ 271, 97, 310, 270, 96, 272, 306, 273,
+ 275, 95, 305, 274, 94, 276, 301, 277,
+ 279, 93, 300, 278, 69, 286, 68, 282,
+ 285, 284, 138, 289, 72, 90, 292, 75,
+ 87, 295, 78, 84, 298, 81, 302, 307,
+ 312, 317, 138, 138, 323, 325, 134, 133,
+ 345, 324, 326, 378, 327, 329, 132, 377,
+ 328, 131, 330, 373, 331, 333, 130, 372,
+ 332, 129, 334, 368, 335, 337, 128, 367,
+ 336, 127, 338, 363, 339, 341, 126, 362,
+ 340, 102, 348, 101, 344, 347, 346, 138,
+ 351, 105, 123, 354, 108, 120, 357, 111,
+ 117, 360, 114, 364, 369, 374, 379, 135,
+ 384, 385, 391, 386, 388, 136, 387, 390,
+ 389, 138, 393, 137, 396, 395, 398, 397,
+ 138
};
static const char _indic_syllable_machine_trans_actions[] = {
- 1, 0, 0, 2, 0, 0, 2, 0,
- 0, 2, 0, 0, 2, 0, 0, 0,
- 2, 0, 0, 2, 0, 0, 2, 0,
- 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 3, 0, 0, 2,
- 0, 0, 2, 0, 0, 2, 0, 0,
- 2, 0, 0, 0, 2, 0, 0, 2,
- 0, 0, 2, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 4, 0, 0, 2, 5, 0, 0, 2,
+ 1, 0, 2, 0, 2, 0, 0, 2,
0, 0, 2, 0, 0, 2, 0, 0,
0, 2, 0, 0, 2, 0, 0, 2,
- 0, 0, 2, 2, 6, 2, 6, 2,
- 6, 2, 6, 2, 7, 0, 0, 2,
- 0, 0, 2, 0, 0, 2, 0, 0,
- 2, 0, 0, 0, 2, 0, 0, 2,
- 0, 0, 2, 0, 0, 2, 2, 2,
+ 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 3, 0, 2, 0,
+ 2, 0, 0, 2, 0, 0, 2, 0,
+ 0, 2, 0, 0, 0, 2, 0, 0,
+ 2, 0, 0, 2, 0, 0, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
- 6, 0, 2, 0, 2, 0, 0, 0,
- 2, 0, 0, 2, 0, 0, 0, 2,
+ 4, 0, 2, 0, 2, 5, 0, 0,
+ 2, 0, 0, 2, 0, 0, 2, 0,
0, 0, 2, 0, 0, 2, 0, 0,
- 2, 8, 0, 11, 2, 2, 6, 0,
- 12, 12, 0, 2, 6, 2, 6, 2,
- 0, 13, 2, 0, 0, 2, 0, 2,
- 2, 0, 2, 2, 2, 0, 0, 2,
- 2, 0, 2, 2, 2, 0, 0, 2,
- 2, 0, 2, 2, 2, 0, 0, 2,
- 2, 0, 2, 2, 2, 0, 0, 2,
- 2, 0, 2, 0, 0, 0, 0, 14,
- 0, 2, 0, 0, 2, 0, 0, 2,
- 0, 0, 2, 0, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 15, 2, 0,
- 0, 2, 0, 2, 2, 0, 2, 2,
- 2, 0, 0, 2, 2, 0, 2, 2,
- 2, 0, 0, 2, 2, 0, 2, 2,
- 2, 0, 0, 2, 2, 0, 2, 2,
- 2, 0, 0, 2, 2, 0, 2, 0,
- 0, 0, 0, 16, 0, 2, 0, 0,
+ 2, 0, 0, 2, 6, 2, 6, 2,
+ 6, 2, 6, 2, 7, 0, 2, 0,
2, 0, 0, 2, 0, 0, 2, 0,
+ 0, 2, 0, 0, 0, 2, 0, 0,
+ 2, 0, 0, 2, 0, 0, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
- 2, 17, 6, 0, 6, 6, 6, 0,
- 0, 6, 6, 0, 6, 6, 6, 0,
- 0, 6, 6, 0, 6, 6, 6, 0,
- 0, 6, 6, 0, 6, 6, 6, 0,
- 0, 6, 6, 0, 6, 0, 0, 0,
- 0, 18, 0, 2, 0, 0, 2, 0,
- 0, 2, 0, 0, 2, 0, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 19,
- 20, 2, 0, 0, 0, 0, 2, 2,
+ 6, 8, 0, 11, 2, 2, 6, 0,
+ 12, 12, 0, 2, 6, 2, 2, 0,
+ 13, 2, 0, 0, 2, 0, 2, 0,
2, 2, 2, 0, 0, 2, 2, 0,
2, 2, 2, 0, 0, 2, 2, 0,
2, 2, 2, 0, 0, 2, 2, 0,
2, 2, 2, 0, 0, 2, 2, 0,
- 2, 0, 0, 0, 0, 21, 0, 2,
- 0, 0, 2, 0, 0, 2, 0, 0,
- 2, 0, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 0, 0, 22, 2, 0,
- 0, 0, 0, 0, 0, 2, 0, 0,
+ 2, 0, 0, 0, 0, 14, 2, 0,
+ 0, 2, 0, 0, 2, 0, 0, 2,
+ 0, 2, 2, 2, 2, 15, 2, 0,
+ 0, 2, 0, 2, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0, 2, 2, 2,
+ 0, 0, 2, 2, 0, 2, 0, 0,
+ 0, 0, 16, 2, 0, 0, 2, 0,
+ 0, 2, 0, 0, 2, 0, 2, 2,
+ 2, 2, 17, 6, 0, 6, 2, 6,
+ 0, 0, 6, 6, 0, 6, 2, 6,
+ 0, 0, 6, 6, 0, 6, 2, 6,
+ 0, 0, 6, 6, 0, 6, 2, 6,
+ 0, 0, 6, 6, 0, 2, 0, 0,
+ 0, 0, 18, 2, 0, 0, 2, 0,
+ 0, 2, 0, 0, 2, 0, 2, 2,
+ 2, 2, 19, 20, 2, 0, 0, 0,
+ 0, 2, 2, 2, 2, 0, 0, 2,
+ 2, 0, 2, 2, 2, 0, 0, 2,
+ 2, 0, 2, 2, 2, 0, 0, 2,
+ 2, 0, 2, 2, 2, 0, 0, 2,
+ 2, 0, 2, 0, 0, 0, 0, 21,
2, 0, 0, 2, 0, 0, 2, 0,
+ 0, 2, 0, 2, 2, 2, 2, 0,
+ 0, 22, 22, 0, 0, 0, 0, 0,
0, 23, 2, 0, 0, 0, 0, 0,
24
};
@@ -937,15 +759,7 @@ static const char _indic_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 9, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 9, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -998,15 +812,7 @@ static const char _indic_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -1046,67 +852,59 @@ static const short _indic_syllable_machine_eof_trans[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 37, 37, 37, 37, 37,
+ 1, 1, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 73, 73,
- 77, 77, 73, 73, 73, 73, 73, 73,
+ 37, 37, 37, 37, 73, 73, 78, 78,
73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73,
73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 109, 109, 109,
109, 109, 109, 109, 109, 109, 109, 109,
109, 109, 109, 109, 109, 109, 109, 109,
109, 109, 109, 109, 109, 109, 109, 109,
- 109, 109, 109, 109, 109, 109, 109, 109,
- 109, 109, 109, 73, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 170, 0, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 322, 322, 322,
- 322, 322, 322, 322, 322, 322, 322, 322,
- 322, 322, 322, 322, 322, 322, 322, 322,
- 322, 322, 322, 322, 322, 322, 322, 322,
- 322, 322, 322, 322, 322, 322, 322, 322,
- 322, 322, 322, 322, 322, 322, 322, 322,
- 322, 322, 322, 322, 322, 322, 322, 322,
- 322, 322, 322, 322, 322, 322, 322, 322,
- 322, 322, 322, 322, 322, 384, 322, 384,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 322, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 186, 186, 186, 186, 186, 186, 186, 186,
- 474, 474, 474, 474, 474, 474, 474, 384
+ 109, 109, 109, 109, 109, 109, 109, 73,
+ 1, 146, 0, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 339,
+ 283, 339, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 283, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161,
+ 410, 410, 410, 410, 410, 410, 410, 339
};
-static const int indic_syllable_machine_start = 166;
-static const int indic_syllable_machine_first_final = 166;
+static const int indic_syllable_machine_start = 138;
+static const int indic_syllable_machine_first_final = 138;
static const int indic_syllable_machine_error = -1;
-static const int indic_syllable_machine_en_main = 166;
+static const int indic_syllable_machine_en_main = 138;
#line 36 "hb-ot-shape-complex-indic-machine.rl"
@@ -1118,10 +916,9 @@ static const int indic_syllable_machine_en_main = 166;
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -1129,11 +926,11 @@ static const int indic_syllable_machine_en_main = 166;
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te, act;
+ unsigned int p, pe, eof, ts, te, act;
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 1137 "hb-ot-shape-complex-indic-machine.hh"
+#line 934 "hb-ot-shape-complex-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -1141,16 +938,15 @@ find_syllables (hb_buffer_t *buffer)
act = 0;
}
-#line 113 "hb-ot-shape-complex-indic-machine.rl"
+#line 112 "hb-ot-shape-complex-indic-machine.rl"
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 1154 "hb-ot-shape-complex-indic-machine.hh"
+#line 950 "hb-ot-shape-complex-indic-machine.hh"
{
int _slen;
int _trans;
@@ -1164,7 +960,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 1168 "hb-ot-shape-complex-indic-machine.hh"
+#line 964 "hb-ot-shape-complex-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -1287,7 +1083,7 @@ _eof_trans:
#line 88 "hb-ot-shape-complex-indic-machine.rl"
{act = 6;}
break;
-#line 1291 "hb-ot-shape-complex-indic-machine.hh"
+#line 1087 "hb-ot-shape-complex-indic-machine.hh"
}
_again:
@@ -1296,7 +1092,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 1300 "hb-ot-shape-complex-indic-machine.hh"
+#line 1096 "hb-ot-shape-complex-indic-machine.hh"
}
if ( ++p != pe )
@@ -1312,7 +1108,7 @@ _again:
}
-#line 122 "hb-ot-shape-complex-indic-machine.rl"
+#line 120 "hb-ot-shape-complex-indic-machine.rl"
}
diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index 35e7ce906..c5d945d4e 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -27,7 +27,7 @@
#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
%%{
machine indic_syllable_machine;
@@ -52,7 +52,6 @@ DOTTEDCIRCLE = 12;
RS = 13;
Repha = 15;
Ra = 16;
-CM = 17;
Symbol= 18;
CS = 19;
@@ -68,15 +67,16 @@ matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
syllable_tail = (z?.SM.SM?.ZWNJ?)? A{0,3}?;
halant_group = (z?.H.(ZWJ.N?)?);
final_halant_group = halant_group | H.ZWNJ;
-medial_group = CM?;
-halant_or_matra_group = (final_halant_group | (H.ZWJ)? matra_group{0,4});
+halant_or_matra_group = (final_halant_group | matra_group{0,4});
+complex_syllable_tail = (halant_group.cn){0,4} halant_or_matra_group syllable_tail;
-consonant_syllable = (Repha|CS)? (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|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
+
+consonant_syllable = (Repha|CS)? cn complex_syllable_tail;
+vowel_syllable = reph? V.n? (ZWJ | complex_syllable_tail);
+standalone_cluster = ((Repha|CS)? PLACEHOLDER | reph? DOTTEDCIRCLE).n? complex_syllable_tail;
symbol_cluster = symbol syllable_tail;
-broken_cluster = reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
+broken_cluster = reph? n? complex_syllable_tail;
other = any;
main := |*
@@ -93,10 +93,9 @@ main := |*
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -104,7 +103,7 @@ main := |*
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te, act;
+ unsigned int p, pe, eof, ts, te, act;
int cs;
hb_glyph_info_t *info = buffer->info;
%%{
@@ -115,7 +114,6 @@ find_syllables (hb_buffer_t *buffer)
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
%%{
write exec;
diff --git a/src/hb-ot-shape-complex-indic-table.cc b/src/hb-ot-shape-complex-indic-table.cc
index 54291bc22..b7e4e7c7c 100644
--- a/src/hb-ot-shape-complex-indic-table.cc
+++ b/src/hb-ot-shape-complex-indic-table.cc
@@ -14,7 +14,7 @@
* # Date: 2017-10-16, 24:39:00 GMT [KW]
*/
-#include "hb-ot-shape-complex-indic-private.hh"
+#include "hb-ot-shape-complex-indic.hh"
#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 16 chars; Avagraha */
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index b52656f44..f1ae303ad 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -24,8 +24,8 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-indic-private.hh"
-#include "hb-ot-layout-private.hh"
+#include "hb-ot-shape-complex-indic.hh"
+#include "hb-ot-layout.hh"
/*
@@ -95,42 +95,40 @@ static const indic_config_t indic_configs[] =
* Indic shaper.
*/
-struct feature_list_t {
- hb_tag_t tag;
- hb_ot_map_feature_flags_t flags;
-};
-
-static const feature_list_t
+static const hb_ot_map_feature_t
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('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('r','p','h','f'), F_MANUAL_JOINERS},
+ {HB_TAG('r','k','r','f'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
+ {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
+ {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
+ {HB_TAG('h','a','l','f'), F_MANUAL_JOINERS},
+ {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
+ {HB_TAG('v','a','t','u'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
/*
* 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('i','n','i','t'), F_MANUAL_JOINERS},
+ {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS},
+ /*
+ * Positioning features.
+ * 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},
@@ -158,12 +156,13 @@ enum {
_BLWS,
_PSTS,
_HALN,
+
_DIST,
_ABVM,
_BLWM,
INDIC_NUM_FEATURES,
- INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
+ INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */
};
static void
@@ -191,25 +190,27 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
/* 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'));
+ map->enable_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->enable_feature (HB_TAG('c','c','m','p'));
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 | F_MANUAL_ZWNJ);
+ map->add_feature (indic_features[i]);
map->add_gsub_pause (nullptr);
}
+
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 | F_MANUAL_ZWNJ);
- }
- map->add_global_bool_feature (HB_TAG('c','a','l','t'));
- map->add_global_bool_feature (HB_TAG('c','l','i','g'));
+ for (; i < INDIC_NUM_FEATURES; i++)
+ map->add_feature (indic_features[i]);
+
+ map->enable_feature (HB_TAG('c','a','l','t'));
+ map->enable_feature (HB_TAG('c','l','i','g'));
map->add_gsub_pause (clear_syllables);
}
@@ -217,7 +218,7 @@ collect_features_indic (hb_ot_shape_planner_t *plan)
static void
override_features_indic (hb_ot_shape_planner_t *plan)
{
- plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+ plan->map.disable_feature (HB_TAG('l','i','g','a'));
}
@@ -273,6 +274,7 @@ struct indic_shape_plan_t
const indic_config_t *config;
bool is_old_spec;
+ bool uniscribe_bug_compatible;
mutable hb_atomic_int_t virama_glyph;
would_substitute_feature_t rphf;
@@ -298,6 +300,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
}
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
+ indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible;
indic_plan->virama_glyph.set_relaxed (-1);
/* Use zero-context would_substitute() matching for new-spec of the main
@@ -328,6 +331,275 @@ data_destroy_indic (void *data)
free (data);
}
+static void
+_output_with_dotted_circle (hb_buffer_t *buffer)
+{
+ hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);
+ _hb_glyph_info_reset_continuation (&dottedcircle);
+
+ buffer->next_glyph ();
+}
+
+static void
+preprocess_text_indic (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font)
+{
+ /* UGLY UGLY UGLY business of adding dotted-circle in the middle of
+ * vowel-sequences that look like another vowel. Data for each script
+ * collected from Unicode 11 book, tables named "Vowel Letters" with
+ * "Use" and "Do Not Use" columns.
+ *
+ * https://github.com/harfbuzz/harfbuzz/issues/1019
+ */
+ bool processed = false;
+ buffer->clear_output ();
+ unsigned int count = buffer->len;
+ switch ((unsigned) buffer->props.script)
+ {
+ case HB_SCRIPT_DEVANAGARI:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0905u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x093Au: case 0x093Bu: case 0x093Eu: case 0x0945u:
+ case 0x0946u: case 0x0949u: case 0x094Au: case 0x094Bu:
+ case 0x094Cu: case 0x094Fu: case 0x0956u: case 0x0957u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x0906u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x093Au: case 0x0945u: case 0x0946u: case 0x0947u:
+ case 0x0948u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x0909u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0941u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x090Fu:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0945u: case 0x0946u: case 0x0947u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x0930u:
+ if (0x094Du == buffer->cur(1).codepoint &&
+ buffer->idx + 2 < count &&
+ 0x0907u == buffer->cur(2).codepoint)
+ {
+ buffer->next_glyph ();
+ buffer->next_glyph ();
+ buffer->output_glyph (0x25CCu);
+ }
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ case HB_SCRIPT_BENGALI:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0985u:
+ matched = 0x09BE == buffer->cur(1).codepoint;
+ break;
+ case 0x098Bu:
+ matched = 0x09C3 == buffer->cur(1).codepoint;
+ break;
+ case 0x098Cu:
+ matched = 0x09E2 == buffer->cur(1).codepoint;
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ case HB_SCRIPT_GURMUKHI:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0A05u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0A3Eu: case 0x0A48u: case 0x0A4Cu:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x0A72u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0A3Fu: case 0x0A40u: case 0x0A47u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x0A73u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0A41u: case 0x0A42u: case 0x0A4Bu:
+ matched = true;
+ break;
+ }
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ case HB_SCRIPT_GUJARATI:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0A85u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0ABEu: case 0x0AC5u: case 0x0AC7u: case 0x0AC8u:
+ case 0x0AC9u: case 0x0ACBu: case 0x0ACCu:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x0AC5u:
+ matched = 0x0ABE == buffer->cur(1).codepoint;
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ case HB_SCRIPT_ORIYA:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0B05u:
+ matched = 0x0B3E == buffer->cur(1).codepoint;
+ break;
+ case 0x0B0Fu: case 0x0B13u:
+ matched = 0x0B57 == buffer->cur(1).codepoint;
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ case HB_SCRIPT_TELUGU:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0C12u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0C4Cu: case 0x0C55u:
+ matched = true;
+ break;
+ }
+ break;
+ case 0x0C3Fu: case 0x0C46u: case 0xC4Au:
+ matched = 0x0C55 == buffer->cur(1).codepoint;
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ case HB_SCRIPT_KANNADA:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0C89u: case 0x0C8Bu:
+ matched = 0x0CBE == buffer->cur(1).codepoint;
+ break;
+ case 0x0C92u:
+ matched = 0x0CCC == buffer->cur(1).codepoint;
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ case HB_SCRIPT_MALAYALAM:
+ for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
+ {
+ bool matched = false;
+ switch (buffer->cur().codepoint)
+ {
+ case 0x0D07u: case 0x0D09u:
+ matched = 0x0D57 == buffer->cur(1).codepoint;
+ break;
+ case 0x0D0Eu:
+ matched = 0x0D46 == buffer->cur(1).codepoint;
+ break;
+ case 0x0D12u:
+ switch (buffer->cur(1).codepoint)
+ {
+ case 0x0D3Eu: case 0x0D57u:
+ matched = true;
+ break;
+ }
+ break;
+ }
+ buffer->next_glyph ();
+ if (matched) _output_with_dotted_circle (buffer);
+ }
+ processed = true;
+ break;
+
+ default:
+ break;
+ }
+ if (processed)
+ {
+ if (buffer->idx < count)
+ buffer->next_glyph ();
+ if (likely (buffer->successful))
+ buffer->swap_buffers ();
+ }
+}
+
static indic_position_t
consonant_position_from_face (const indic_shape_plan_t *indic_plan,
const hb_codepoint_t consonant,
@@ -717,7 +989,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
indic_position_t last_pos = POS_START;
for (unsigned int i = start; i < end; i++)
{
- if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H))))
+ if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | FLAG (OT_H))))
{
info[i].indic_position() = last_pos;
if (unlikely (info[i].indic_category() == OT_H &&
@@ -913,10 +1185,12 @@ initial_reordering_standalone_cluster (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;
+
/* We treat placeholder/dotted-circle as if they are consonants, so we
* should just chain. Only if not in compatibility mode that is... */
- if (hb_options ().uniscribe_bug_compatible)
+ if (indic_plan->uniscribe_bug_compatible)
{
/* For dotted-circle, this is what Uniscribe does:
* If dotted-circle is the last glyph, it just does nothing.
@@ -958,7 +1232,8 @@ 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. */
+ /* Note: This loop is extra overhead, but should not be measurable.
+ * TODO Use a buffer scratch flag to remove the loop. */
bool has_broken_syllables = false;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
@@ -1356,7 +1631,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
* Uniscribe doesn't do this.
* TEST: U+0930,U+094D,U+0915,U+094B,U+094D
*/
- if (!hb_options ().uniscribe_bug_compatible &&
+ if (!indic_plan->uniscribe_bug_compatible &&
unlikely (is_halant (info[new_reph_pos]))) {
for (unsigned int i = base + 1; i < new_reph_pos; i++)
if (info[i].indic_category() == OT_M) {
@@ -1462,7 +1737,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
/*
* Finish off the clusters and go home!
*/
- if (hb_options ().uniscribe_bug_compatible)
+ if (indic_plan->uniscribe_bug_compatible)
{
switch ((hb_tag_t) plan->props.script)
{
@@ -1609,13 +1884,13 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
override_features_indic,
data_create_indic,
data_destroy_indic,
- nullptr, /* preprocess_text */
+ preprocess_text_indic,
nullptr, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_indic,
compose_indic,
setup_masks_indic,
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
diff --git a/src/hb-ot-shape-complex-indic-private.hh b/src/hb-ot-shape-complex-indic.hh
index bb7fff384..dcc2a7a6c 100644
--- a/src/hb-ot-shape-complex-indic-private.hh
+++ b/src/hb-ot-shape-complex-indic.hh
@@ -24,14 +24,12 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH
+#ifndef HB_OT_SHAPE_COMPLEX_INDIC_HH
+#define HB_OT_SHAPE_COMPLEX_INDIC_HH
-#include "hb-private.hh"
+#include "hb.hh"
-
-#include "hb-ot-shape-complex-private.hh"
-#include "hb-ot-shape-private.hh" /* XXX Remove */
+#include "hb-ot-shape-complex.hh"
/* buffer var allocations */
@@ -64,19 +62,17 @@ enum indic_category_t {
OT_Coeng = 14, /* Khmer-style Virama. */
OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
OT_Ra = 16,
- OT_CM = 17, /* Consonant-Medial. */
+ OT_CM = 17, /* Consonant-Medial; Unused by Indic shaper. */
OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
OT_CS = 19
};
-#define MEDIAL_FLAGS (FLAG (OT_CM))
-
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
-#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
+#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
@@ -125,7 +121,7 @@ enum indic_syllabic_category_t {
INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_CS,
INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM, /* https://github.com/harfbuzz/harfbuzz/issues/552 */
INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng,
@@ -400,4 +396,4 @@ set_indic_properties (hb_glyph_info_t &info)
}
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */
diff --git a/src/hb-ot-shape-complex-khmer-machine.hh b/src/hb-ot-shape-complex-khmer-machine.hh
index d00102156..2bc8ca650 100644
--- a/src/hb-ot-shape-complex-khmer-machine.hh
+++ b/src/hb-ot-shape-complex-khmer-machine.hh
@@ -29,143 +29,212 @@
#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
#line 36 "hb-ot-shape-complex-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
- 7u, 7u, 1u, 16u, 13u, 13u, 1u, 16u, 7u, 13u, 7u, 7u, 1u, 16u, 13u, 13u,
- 1u, 16u, 7u, 13u, 1u, 16u, 3u, 14u, 3u, 14u, 5u, 14u, 3u, 14u, 5u, 14u,
- 8u, 8u, 3u, 13u, 3u, 8u, 8u, 8u, 3u, 8u, 3u, 14u, 3u, 14u, 5u, 14u,
- 3u, 14u, 5u, 14u, 8u, 8u, 3u, 13u, 3u, 8u, 8u, 8u, 3u, 8u, 3u, 14u,
- 3u, 14u, 7u, 13u, 7u, 7u, 1u, 16u, 0
+ 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u,
+ 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u,
+ 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 16u, 1u, 29u, 5u, 29u,
+ 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 5u, 26u,
+ 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u,
+ 5u, 29u, 0
};
static const char _khmer_syllable_machine_key_spans[] = {
- 1, 16, 1, 16, 7, 1, 16, 1,
- 16, 7, 16, 12, 12, 10, 12, 10,
- 1, 11, 6, 1, 6, 12, 12, 10,
- 12, 10, 1, 11, 6, 1, 6, 12,
- 12, 7, 1, 16
+ 22, 17, 22, 17, 16, 17, 22, 17,
+ 22, 17, 16, 17, 22, 17, 16, 17,
+ 22, 17, 22, 17, 22, 16, 29, 25,
+ 25, 25, 1, 18, 25, 25, 25, 22,
+ 25, 25, 1, 18, 25, 25, 16, 25,
+ 25
};
static const short _khmer_syllable_machine_index_offsets[] = {
- 0, 2, 19, 21, 38, 46, 48, 65,
- 67, 84, 92, 109, 122, 135, 146, 159,
- 170, 172, 184, 191, 193, 200, 213, 226,
- 237, 250, 261, 263, 275, 282, 284, 291,
- 304, 317, 325, 327
+ 0, 23, 41, 64, 82, 99, 117, 140,
+ 158, 181, 199, 216, 234, 257, 275, 292,
+ 310, 333, 351, 374, 392, 415, 432, 462,
+ 488, 514, 540, 542, 561, 587, 613, 639,
+ 662, 688, 714, 716, 735, 761, 787, 804,
+ 830
};
static const char _khmer_syllable_machine_indicies[] = {
- 1, 0, 2, 2, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2,
+ 3, 0, 0, 0, 0, 4, 0, 1,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 2, 0, 3, 0, 4, 4, 0,
+ 0, 3, 0, 0, 0, 0, 4, 0,
+ 5, 5, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 4, 0, 1, 0,
- 0, 0, 0, 0, 5, 0, 7, 6,
- 8, 8, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 8,
- 6, 9, 6, 10, 10, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 10, 6, 7, 6, 6, 6,
- 6, 6, 11, 6, 4, 4, 13, 12,
- 14, 15, 7, 16, 12, 12, 4, 4,
- 11, 17, 12, 4, 12, 19, 18, 20,
- 21, 1, 22, 18, 18, 18, 18, 5,
- 23, 18, 24, 18, 21, 21, 1, 22,
- 18, 18, 18, 18, 18, 23, 18, 21,
- 21, 1, 22, 18, 18, 18, 18, 18,
- 23, 18, 25, 18, 21, 21, 1, 22,
- 18, 18, 18, 18, 18, 26, 18, 21,
- 21, 1, 22, 18, 18, 18, 18, 18,
- 26, 18, 27, 18, 28, 18, 29, 18,
- 18, 22, 18, 18, 18, 18, 3, 18,
- 30, 18, 18, 18, 18, 22, 18, 22,
- 18, 28, 18, 18, 18, 18, 22, 18,
- 19, 18, 21, 21, 1, 22, 18, 18,
- 18, 18, 18, 23, 18, 32, 31, 33,
- 33, 7, 16, 31, 31, 31, 31, 31,
- 34, 31, 33, 33, 7, 16, 31, 31,
- 31, 31, 31, 34, 31, 35, 31, 33,
- 33, 7, 16, 31, 31, 31, 31, 31,
- 36, 31, 33, 33, 7, 16, 31, 31,
- 31, 31, 31, 36, 31, 37, 31, 38,
- 31, 39, 31, 31, 16, 31, 31, 31,
- 31, 9, 31, 40, 31, 31, 31, 31,
- 16, 31, 16, 31, 38, 31, 31, 31,
- 31, 16, 31, 13, 31, 41, 33, 7,
- 16, 31, 31, 31, 31, 11, 34, 31,
- 13, 31, 33, 33, 7, 16, 31, 31,
- 31, 31, 31, 34, 31, 7, 42, 42,
- 42, 42, 42, 11, 42, 7, 42, 10,
- 10, 42, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 10, 42,
+ 4, 0, 6, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 6, 0, 7, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 8, 0, 9, 9, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 10, 0, 0,
+ 0, 0, 4, 0, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 10, 0, 11, 11,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 12, 0,
+ 0, 0, 0, 4, 0, 11, 11, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 12, 0, 13,
+ 13, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 13, 0,
+ 15, 15, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 16, 14, 15, 15, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 16, 17, 17, 17, 17, 18,
+ 17, 19, 19, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 18, 17, 20, 20, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 20, 17, 21, 21, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 22, 17, 23, 23,
+ 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 24, 17,
+ 17, 17, 17, 18, 17, 23, 23, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 24, 17, 25,
+ 25, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 26,
+ 17, 17, 17, 17, 18, 17, 25, 25,
+ 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 26, 17,
+ 15, 15, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 27,
+ 16, 17, 17, 17, 17, 18, 17, 28,
+ 28, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 28, 17,
+ 13, 13, 29, 29, 30, 30, 29, 29,
+ 29, 29, 2, 2, 29, 31, 29, 13,
+ 29, 29, 29, 29, 16, 20, 29, 29,
+ 29, 18, 24, 26, 22, 29, 33, 33,
+ 32, 32, 32, 32, 32, 32, 32, 34,
+ 32, 32, 32, 32, 32, 2, 3, 6,
+ 32, 32, 32, 4, 10, 12, 8, 32,
+ 35, 35, 32, 32, 32, 32, 32, 32,
+ 32, 36, 32, 32, 32, 32, 32, 32,
+ 3, 6, 32, 32, 32, 4, 10, 12,
+ 8, 32, 5, 5, 32, 32, 32, 32,
+ 32, 32, 32, 36, 32, 32, 32, 32,
+ 32, 32, 4, 6, 32, 32, 32, 32,
+ 32, 32, 8, 32, 6, 32, 7, 7,
+ 32, 32, 32, 32, 32, 32, 32, 36,
+ 32, 32, 32, 32, 32, 32, 8, 6,
+ 32, 37, 37, 32, 32, 32, 32, 32,
+ 32, 32, 36, 32, 32, 32, 32, 32,
+ 32, 10, 6, 32, 32, 32, 4, 32,
+ 32, 8, 32, 38, 38, 32, 32, 32,
+ 32, 32, 32, 32, 36, 32, 32, 32,
+ 32, 32, 32, 12, 6, 32, 32, 32,
+ 4, 10, 32, 8, 32, 35, 35, 32,
+ 32, 32, 32, 32, 32, 32, 34, 32,
+ 32, 32, 32, 32, 32, 3, 6, 32,
+ 32, 32, 4, 10, 12, 8, 32, 15,
+ 15, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 16,
+ 39, 39, 39, 39, 18, 39, 41, 41,
+ 40, 40, 40, 40, 40, 40, 40, 42,
+ 40, 40, 40, 40, 40, 40, 16, 20,
+ 40, 40, 40, 18, 24, 26, 22, 40,
+ 19, 19, 40, 40, 40, 40, 40, 40,
+ 40, 42, 40, 40, 40, 40, 40, 40,
+ 18, 20, 40, 40, 40, 40, 40, 40,
+ 22, 40, 20, 40, 21, 21, 40, 40,
+ 40, 40, 40, 40, 40, 42, 40, 40,
+ 40, 40, 40, 40, 22, 20, 40, 43,
+ 43, 40, 40, 40, 40, 40, 40, 40,
+ 42, 40, 40, 40, 40, 40, 40, 24,
+ 20, 40, 40, 40, 18, 40, 40, 22,
+ 40, 44, 44, 40, 40, 40, 40, 40,
+ 40, 40, 42, 40, 40, 40, 40, 40,
+ 40, 26, 20, 40, 40, 40, 18, 24,
+ 40, 22, 40, 28, 28, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 28, 39, 45, 45, 40, 40,
+ 40, 40, 40, 40, 40, 46, 40, 40,
+ 40, 40, 40, 27, 16, 20, 40, 40,
+ 40, 18, 24, 26, 22, 40, 41, 41,
+ 40, 40, 40, 40, 40, 40, 40, 46,
+ 40, 40, 40, 40, 40, 40, 16, 20,
+ 40, 40, 40, 18, 24, 26, 22, 40,
0
};
static const char _khmer_syllable_machine_trans_targs[] = {
- 10, 14, 17, 20, 11, 21, 10, 24,
- 27, 30, 31, 32, 10, 22, 33, 34,
- 26, 35, 10, 12, 4, 0, 16, 3,
- 13, 15, 1, 10, 18, 2, 19, 10,
- 23, 5, 8, 25, 6, 10, 28, 7,
- 29, 9, 10
+ 22, 1, 30, 24, 25, 3, 26, 5,
+ 27, 7, 28, 9, 29, 23, 22, 11,
+ 32, 22, 33, 13, 34, 15, 35, 17,
+ 36, 19, 37, 40, 39, 22, 31, 38,
+ 22, 0, 10, 2, 4, 6, 8, 22,
+ 22, 12, 14, 16, 18, 20, 21
};
static const char _khmer_syllable_machine_trans_actions[] = {
- 1, 2, 2, 0, 2, 2, 3, 2,
- 2, 0, 2, 2, 6, 2, 0, 0,
- 0, 0, 7, 2, 0, 0, 0, 0,
- 2, 2, 0, 8, 0, 0, 0, 9,
- 2, 0, 0, 2, 0, 10, 0, 0,
- 0, 0, 11
+ 1, 0, 2, 2, 2, 0, 0, 0,
+ 2, 0, 2, 0, 2, 2, 3, 0,
+ 4, 5, 2, 0, 0, 0, 2, 0,
+ 2, 0, 2, 4, 4, 8, 9, 0,
+ 10, 0, 0, 0, 0, 0, 0, 11,
+ 12, 0, 0, 0, 0, 0, 0
};
static const char _khmer_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 6, 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 _khmer_syllable_machine_from_state_actions[] = {
0, 0, 0, 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, 7, 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 _khmer_syllable_machine_eof_trans[] = {
- 1, 1, 1, 1, 1, 7, 7, 7,
- 7, 7, 0, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 43, 43, 43
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 15, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 0, 33,
+ 33, 33, 33, 33, 33, 33, 33, 40,
+ 41, 41, 41, 41, 41, 41, 40, 41,
+ 41
};
-static const int khmer_syllable_machine_start = 10;
-static const int khmer_syllable_machine_first_final = 10;
+static const int khmer_syllable_machine_start = 22;
+static const int khmer_syllable_machine_first_final = 22;
static const int khmer_syllable_machine_error = -1;
-static const int khmer_syllable_machine_en_main = 10;
+static const int khmer_syllable_machine_en_main = 22;
#line 36 "hb-ot-shape-complex-khmer-machine.rl"
-#line 74 "hb-ot-shape-complex-khmer-machine.rl"
+#line 80 "hb-ot-shape-complex-khmer-machine.rl"
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -173,11 +242,11 @@ static const int khmer_syllable_machine_en_main = 10;
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te, act HB_UNUSED;
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 181 "hb-ot-shape-complex-khmer-machine.hh"
+#line 250 "hb-ot-shape-complex-khmer-machine.hh"
{
cs = khmer_syllable_machine_start;
ts = 0;
@@ -185,16 +254,15 @@ find_syllables (hb_buffer_t *buffer)
act = 0;
}
-#line 95 "hb-ot-shape-complex-khmer-machine.rl"
+#line 100 "hb-ot-shape-complex-khmer-machine.rl"
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 198 "hb-ot-shape-complex-khmer-machine.hh"
+#line 266 "hb-ot-shape-complex-khmer-machine.hh"
{
int _slen;
int _trans;
@@ -204,11 +272,11 @@ find_syllables (hb_buffer_t *buffer)
goto _test_eof;
_resume:
switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
- case 5:
+ case 7:
#line 1 "NONE"
{ts = p;}
break;
-#line 212 "hb-ot-shape-complex-khmer-machine.hh"
+#line 280 "hb-ot-shape-complex-khmer-machine.hh"
}
_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -231,47 +299,63 @@ _eof_trans:
{te = p+1;}
break;
case 8:
-#line 68 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p+1;{ found_syllable (consonant_syllable); }}
- break;
- case 10:
-#line 69 "hb-ot-shape-complex-khmer-machine.rl"
- {te = p+1;{ found_syllable (broken_cluster); }}
- break;
- case 6:
-#line 70 "hb-ot-shape-complex-khmer-machine.rl"
+#line 76 "hb-ot-shape-complex-khmer-machine.rl"
{te = p+1;{ found_syllable (non_khmer_cluster); }}
break;
- case 7:
-#line 68 "hb-ot-shape-complex-khmer-machine.rl"
+ case 10:
+#line 74 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p--;{ found_syllable (consonant_syllable); }}
break;
- case 9:
-#line 69 "hb-ot-shape-complex-khmer-machine.rl"
+ case 12:
+#line 75 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
case 11:
-#line 70 "hb-ot-shape-complex-khmer-machine.rl"
+#line 76 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p--;{ found_syllable (non_khmer_cluster); }}
break;
case 1:
-#line 68 "hb-ot-shape-complex-khmer-machine.rl"
+#line 74 "hb-ot-shape-complex-khmer-machine.rl"
{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
break;
- case 3:
-#line 69 "hb-ot-shape-complex-khmer-machine.rl"
+ case 5:
+#line 75 "hb-ot-shape-complex-khmer-machine.rl"
{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
break;
-#line 266 "hb-ot-shape-complex-khmer-machine.hh"
+ case 3:
+#line 1 "NONE"
+ { switch( act ) {
+ case 2:
+ {{p = ((te))-1;} found_syllable (broken_cluster); }
+ break;
+ case 3:
+ {{p = ((te))-1;} found_syllable (non_khmer_cluster); }
+ break;
+ }
+ }
+ break;
+ case 4:
+#line 1 "NONE"
+ {te = p+1;}
+#line 75 "hb-ot-shape-complex-khmer-machine.rl"
+ {act = 2;}
+ break;
+ case 9:
+#line 1 "NONE"
+ {te = p+1;}
+#line 76 "hb-ot-shape-complex-khmer-machine.rl"
+ {act = 3;}
+ break;
+#line 350 "hb-ot-shape-complex-khmer-machine.hh"
}
_again:
switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
- case 4:
+ case 6:
#line 1 "NONE"
{ts = 0;}
break;
-#line 275 "hb-ot-shape-complex-khmer-machine.hh"
+#line 359 "hb-ot-shape-complex-khmer-machine.hh"
}
if ( ++p != pe )
@@ -287,7 +371,7 @@ _again:
}
-#line 104 "hb-ot-shape-complex-khmer-machine.rl"
+#line 108 "hb-ot-shape-complex-khmer-machine.rl"
}
diff --git a/src/hb-ot-shape-complex-khmer-machine.rl b/src/hb-ot-shape-complex-khmer-machine.rl
index 54644d8aa..4c596ab64 100644
--- a/src/hb-ot-shape-complex-khmer-machine.rl
+++ b/src/hb-ot-shape-complex-khmer-machine.rl
@@ -27,7 +27,7 @@
#ifndef HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
%%{
machine khmer_syllable_machine;
@@ -40,28 +40,34 @@
# Same order as enum khmer_category_t. Not sure how to avoid duplication.
C = 1;
V = 2;
-N = 3;
ZWNJ = 5;
ZWJ = 6;
-M = 7;
-SM = 8;
PLACEHOLDER = 11;
DOTTEDCIRCLE = 12;
-RS = 13;
-Coeng = 14;
-Ra = 16;
-
-c = (C | Ra | V); # is_consonant
-n = ((ZWNJ?.RS)? (N.N?)?); # is_consonant_modifier
-z = ZWJ|ZWNJ; # is_joiner
-
-cn = c.n?;
-matra_group = z?.M.N?;
-syllable_tail = (SM.SM?)?;
-
-
-broken_cluster = n? (Coeng.cn)* matra_group* (Coeng.cn)? syllable_tail;
-consonant_syllable = (c|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster;
+Coeng= 14;
+Ra = 16;
+Robatic = 20;
+Xgroup = 21;
+Ygroup = 22;
+VAbv = 26;
+VBlw = 27;
+VPre = 28;
+VPst = 29;
+
+c = (C | Ra | V);
+cn = c.((ZWJ|ZWNJ)?.Robatic)?;
+joiner = (ZWJ | ZWNJ);
+xgroup = (joiner*.Xgroup)*;
+ygroup = Ygroup*;
+
+# This grammar was experimentally extracted from what Uniscribe allows.
+
+matra_group = VPre? xgroup VBlw? xgroup (joiner?.VAbv)? xgroup VPst?;
+syllable_tail = xgroup matra_group xgroup (Coeng.c)? ygroup;
+
+
+broken_cluster = (Coeng.cn)* syllable_tail;
+consonant_syllable = (cn|PLACEHOLDER|DOTTEDCIRCLE) broken_cluster;
other = any;
main := |*
@@ -75,10 +81,9 @@ main := |*
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -86,7 +91,7 @@ main := |*
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te, act HB_UNUSED;
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
int cs;
hb_glyph_info_t *info = buffer->info;
%%{
@@ -97,7 +102,6 @@ find_syllables (hb_buffer_t *buffer)
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
%%{
write exec;
diff --git a/src/hb-ot-shape-complex-khmer-private.hh b/src/hb-ot-shape-complex-khmer-private.hh
deleted file mode 100644
index f90ef9674..000000000
--- a/src/hb-ot-shape-complex-khmer-private.hh
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright © 2018 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH
-#define HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH
-
-#include "hb-private.hh"
-
-#include "hb-ot-shape-complex-indic-private.hh"
-
-
-/* buffer var allocations */
-#define khmer_category() indic_category() /* khmer_category_t */
-#define khmer_position() indic_position() /* khmer_position_t */
-
-
-typedef indic_category_t khmer_category_t;
-typedef indic_position_t khmer_position_t;
-
-
-static inline khmer_position_t
-matra_position_khmer (khmer_position_t side)
-{
- switch ((int) side)
- {
- case POS_PRE_C:
- return POS_PRE_M;
-
- case POS_POST_C:
- case POS_ABOVE_C:
- case POS_BELOW_C:
- return POS_AFTER_POST;
-
- default:
- return side;
- };
-}
-
-static inline bool
-is_consonant_or_vowel (const hb_glyph_info_t &info)
-{
- return is_one_of (info, CONSONANT_FLAGS | FLAG (OT_V));
-}
-
-static inline bool
-is_coeng (const hb_glyph_info_t &info)
-{
- return is_one_of (info, FLAG (OT_Coeng));
-}
-
-static inline void
-set_khmer_properties (hb_glyph_info_t &info)
-{
- hb_codepoint_t u = info.codepoint;
- unsigned int type = hb_indic_get_categories (u);
- khmer_category_t cat = (khmer_category_t) (type & 0x7Fu);
- khmer_position_t pos = (khmer_position_t) (type >> 8);
-
-
- /*
- * Re-assign category
- */
-
- if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
- else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x17CDu, 0x17D1u) ||
- u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
- {
- /* These can occur mid-syllable (eg. before matras), even though Unicode marks them as Syllable_Modifier.
- * https://github.com/roozbehp/unicode-data/issues/5 */
- cat = OT_M;
- pos = POS_ABOVE_C;
- }
- else if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x2010u, 0x2011u))) cat = OT_PLACEHOLDER;
- else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
-
-
- /*
- * Re-assign position.
- */
-
- if ((FLAG_UNSAFE (cat) & CONSONANT_FLAGS))
- {
- pos = POS_BASE_C;
- if (u == 0x179Au)
- cat = OT_Ra;
- }
- else if (cat == OT_M)
- {
- pos = matra_position_khmer (pos);
- }
- else if ((FLAG_UNSAFE (cat) & (FLAG (OT_SM) | FLAG (OT_A) | FLAG (OT_Symbol))))
- {
- pos = POS_SMVD;
- }
-
- info.khmer_category() = cat;
- info.khmer_position() = pos;
-}
-
-
-#endif /* HB_OT_SHAPE_COMPLEX_KHMER_PRIVATE_HH */
diff --git a/src/hb-ot-shape-complex-khmer.cc b/src/hb-ot-shape-complex-khmer.cc
index 264515e86..88d16267b 100644
--- a/src/hb-ot-shape-complex-khmer.cc
+++ b/src/hb-ot-shape-complex-khmer.cc
@@ -24,40 +24,38 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-khmer-private.hh"
-#include "hb-ot-layout-private.hh"
+#include "hb-ot-shape-complex-khmer.hh"
+#include "hb-ot-layout.hh"
/*
* Khmer shaper.
*/
-struct feature_list_t {
- hb_tag_t tag;
- hb_ot_map_feature_flags_t flags;
-};
-
-static const feature_list_t
+static const hb_ot_map_feature_t
khmer_features[] =
{
/*
* Basic features.
* These features are applied in order, one at a time, after reordering.
*/
- {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('p','s','t','f'), F_NONE},
- {HB_TAG('c','f','a','r'), F_NONE},
+ {HB_TAG('p','r','e','f'), F_MANUAL_JOINERS},
+ {HB_TAG('b','l','w','f'), F_MANUAL_JOINERS},
+ {HB_TAG('a','b','v','f'), F_MANUAL_JOINERS},
+ {HB_TAG('p','s','t','f'), F_MANUAL_JOINERS},
+ {HB_TAG('c','f','a','r'), F_MANUAL_JOINERS},
/*
* Other features.
* These features are applied all at once.
*/
- {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},
- /* Positioning features, though we don't care about the types. */
+ {HB_TAG('p','r','e','s'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS},
+ /*
+ * Positioning features.
+ * 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},
@@ -77,12 +75,13 @@ enum {
_ABVS,
_BLWS,
_PSTS,
+
_DIST,
_ABVM,
_BLWM,
KHMER_NUM_FEATURES,
- KHMER_BASIC_FEATURES = _PRES /* Don't forget to update this! */
+ KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */
};
static void
@@ -117,22 +116,20 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
*
* https://github.com/harfbuzz/harfbuzz/issues/974
*/
- map->add_global_bool_feature (HB_TAG('l','o','c','l'));
- map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+ map->enable_feature (HB_TAG('l','o','c','l'));
+ map->enable_feature (HB_TAG('c','c','m','p'));
unsigned int i = 0;
- for (; i < KHMER_BASIC_FEATURES; i++) {
- map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
- }
+ for (; i < KHMER_BASIC_FEATURES; i++)
+ map->add_feature (khmer_features[i]);
map->add_gsub_pause (clear_syllables);
- for (; i < KHMER_NUM_FEATURES; i++) {
- map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
- }
+ for (; i < KHMER_NUM_FEATURES; i++)
+ map->add_feature (khmer_features[i]);
- map->add_global_bool_feature (HB_TAG('c','a','l','t'));
- map->add_global_bool_feature (HB_TAG('c','l','i','g'));
+ map->enable_feature (HB_TAG('c','a','l','t'));
+ map->enable_feature (HB_TAG('c','l','i','g'));
}
@@ -142,10 +139,10 @@ override_features_khmer (hb_ot_shape_planner_t *plan)
/* Uniscribe does not apply 'kern' in Khmer. */
if (hb_options ().uniscribe_bug_compatible)
{
- plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
+ plan->map.disable_feature (HB_TAG('k','e','r','n'));
}
- plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+ plan->map.disable_feature (HB_TAG('l','i','g','a'));
}
@@ -244,7 +241,6 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED)
{
HB_BUFFER_ALLOCATE_VAR (buffer, khmer_category);
- HB_BUFFER_ALLOCATE_VAR (buffer, khmer_position);
/* We cannot setup masks here. We save information about characters
* and setup masks later on in a pause-callback. */
@@ -333,7 +329,7 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
}
/* Reorder left matra piece. */
- else if (info[i].khmer_position() == POS_PRE_M)
+ else if (info[i].khmer_category() == OT_VPre)
{
/* Move to the start. */
buffer->merge_clusters (start, i + 1);
@@ -435,7 +431,6 @@ reorder (const hb_ot_shape_plan_t *plan,
initial_reordering_syllable (plan, font->face, buffer, start, end);
HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category);
- HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_position);
}
static void
@@ -501,7 +496,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer =
decompose_khmer,
compose_khmer,
setup_masks_khmer,
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
diff --git a/src/hb-ot-shape-complex-khmer.hh b/src/hb-ot-shape-complex-khmer.hh
new file mode 100644
index 000000000..622294588
--- /dev/null
+++ b/src/hb-ot-shape-complex-khmer.hh
@@ -0,0 +1,114 @@
+/*
+ * Copyright © 2018 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_KHMER_HH
+#define HB_OT_SHAPE_COMPLEX_KHMER_HH
+
+#include "hb.hh"
+
+#include "hb-ot-shape-complex-indic.hh"
+
+
+/* buffer var allocations */
+#define khmer_category() indic_category() /* khmer_category_t */
+
+
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum khmer_category_t
+{
+ OT_Robatic = 20,
+ OT_Xgroup = 21,
+ OT_Ygroup = 22,
+
+ OT_VAbv = 26,
+ OT_VBlw = 27,
+ OT_VPre = 28,
+ OT_VPst = 29,
+};
+
+static inline void
+set_khmer_properties (hb_glyph_info_t &info)
+{
+ hb_codepoint_t u = info.codepoint;
+ unsigned int type = hb_indic_get_categories (u);
+ khmer_category_t cat = (khmer_category_t) (type & 0x7Fu);
+ indic_position_t pos = (indic_position_t) (type >> 8);
+
+
+ /*
+ * Re-assign category
+ *
+ * These categories are experimentally extracted from what Uniscribe allows.
+ */
+ switch (u)
+ {
+ case 0x179Au:
+ cat = (khmer_category_t) OT_Ra;
+ break;
+
+ case 0x17CCu:
+ case 0x17C9u:
+ case 0x17CAu:
+ cat = OT_Robatic;
+ break;
+
+ case 0x17C6u:
+ case 0x17CBu:
+ case 0x17CDu:
+ case 0x17CEu:
+ case 0x17CFu:
+ case 0x17D0u:
+ case 0x17D1u:
+ cat = OT_Xgroup;
+ break;
+
+ case 0x17C7u:
+ case 0x17C8u:
+ case 0x17DDu:
+ case 0x17D3u: /* Just guessing. Uniscribe doesn't categorize it. */
+ cat = OT_Ygroup;
+ break;
+ }
+
+ /*
+ * Re-assign position.
+ */
+ if (cat == (khmer_category_t) OT_M)
+ switch ((int) pos)
+ {
+ case POS_PRE_C: cat = OT_VPre; break;
+ case POS_BELOW_C: cat = OT_VBlw; break;
+ case POS_ABOVE_C: cat = OT_VAbv; break;
+ case POS_POST_C: cat = OT_VPst; break;
+ default: assert (0);
+ };
+
+ info.khmer_category() = cat;
+}
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_KHMER_HH */
diff --git a/src/hb-ot-shape-complex-myanmar-machine.hh b/src/hb-ot-shape-complex-myanmar-machine.hh
index fb67dd42e..0c19e4f68 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -29,7 +29,7 @@
#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
@@ -283,10 +283,9 @@ static const int myanmar_syllable_machine_en_main = 0;
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -294,11 +293,11 @@ static const int myanmar_syllable_machine_en_main = 0;
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 302 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 301 "hb-ot-shape-complex-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@@ -306,16 +305,15 @@ find_syllables (hb_buffer_t *buffer)
act = 0;
}
-#line 115 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 319 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 317 "hb-ot-shape-complex-myanmar-machine.hh"
{
int _slen;
int _trans;
@@ -329,7 +327,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 333 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 331 "hb-ot-shape-complex-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -379,7 +377,7 @@ _eof_trans:
#line 90 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
break;
-#line 383 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 381 "hb-ot-shape-complex-myanmar-machine.hh"
}
_again:
@@ -388,7 +386,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 392 "hb-ot-shape-complex-myanmar-machine.hh"
+#line 390 "hb-ot-shape-complex-myanmar-machine.hh"
}
if ( ++p != pe )
@@ -404,7 +402,7 @@ _again:
}
-#line 124 "hb-ot-shape-complex-myanmar-machine.rl"
+#line 122 "hb-ot-shape-complex-myanmar-machine.rl"
}
diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl
index 0cd84fa1b..7845a86d4 100644
--- a/src/hb-ot-shape-complex-myanmar-machine.rl
+++ b/src/hb-ot-shape-complex-myanmar-machine.rl
@@ -27,7 +27,7 @@
#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
%%{
machine myanmar_syllable_machine;
@@ -95,10 +95,9 @@ main := |*
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -106,7 +105,7 @@ main := |*
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+ unsigned int p, pe, eof, ts, te, act HB_UNUSED;
int cs;
hb_glyph_info_t *info = buffer->info;
%%{
@@ -117,7 +116,6 @@ find_syllables (hb_buffer_t *buffer)
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
%%{
write exec;
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
index e4214b87e..e201a2309 100644
--- a/src/hb-ot-shape-complex-myanmar.cc
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-myanmar-private.hh"
+#include "hb-ot-shape-complex-myanmar.hh"
/*
@@ -54,7 +54,14 @@ other_features[] =
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. */
+};
+static const hb_tag_t
+positioning_features[] =
+{
+ /*
+ * Positioning features.
+ * 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
@@ -89,27 +96,33 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan)
/* 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'));
+ map->enable_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->enable_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->enable_feature (basic_features[i], F_MANUAL_ZWJ);
map->add_gsub_pause (nullptr);
}
+
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);
+ map->enable_feature (other_features[i], F_MANUAL_ZWJ);
+
+ for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
+ map->enable_feature (positioning_features[i]);
}
static void
override_features_myanmar (hb_ot_shape_planner_t *plan)
{
- plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+ plan->map.disable_feature (HB_TAG('l','i','g','a'));
}
@@ -362,6 +375,25 @@ final_reordering (const hb_ot_shape_plan_t *plan,
}
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
+{
+ collect_features_myanmar,
+ override_features_myanmar,
+ nullptr, /* data_create */
+ nullptr, /* data_destroy */
+ nullptr, /* preprocess_text */
+ nullptr, /* postprocess_glyphs */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+ nullptr, /* decompose */
+ nullptr, /* compose */
+ setup_masks_myanmar,
+ HB_TAG_NONE, /* gpos_tag */
+ nullptr, /* reorder_marks */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+ false, /* fallback_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 =
@@ -376,26 +408,30 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
nullptr, /* decompose */
nullptr, /* compose */
nullptr, /* setup_masks */
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
-const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
+
+/* Ugly Zawgyi encoding.
+ * Disable all auto processing.
+ * https://github.com/harfbuzz/harfbuzz/issues/1162 */
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi =
{
- collect_features_myanmar,
- override_features_myanmar,
+ nullptr, /* collect_features */
+ nullptr, /* override_features */
nullptr, /* data_create */
nullptr, /* data_destroy */
nullptr, /* preprocess_text */
nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+ HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
nullptr, /* decompose */
nullptr, /* compose */
- setup_masks_myanmar,
- nullptr, /* disable_otl */
+ nullptr, /* setup_masks */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};
diff --git a/src/hb-ot-shape-complex-myanmar-private.hh b/src/hb-ot-shape-complex-myanmar.hh
index 14d011d67..3e9537a64 100644
--- a/src/hb-ot-shape-complex-myanmar-private.hh
+++ b/src/hb-ot-shape-complex-myanmar.hh
@@ -24,12 +24,12 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH
-#define HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH
+#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_HH
+#define HB_OT_SHAPE_COMPLEX_MYANMAR_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-ot-shape-complex-indic-private.hh"
+#include "hb-ot-shape-complex-indic.hh"
/* buffer var allocations */
@@ -64,42 +64,42 @@ 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);
+ unsigned int cat = type & 0x7Fu;
indic_position_t pos = (indic_position_t) (type >> 8);
/* Myanmar
* https://docs.microsoft.com/en-us/typography/script-development/myanmar#analyze
*/
if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xFE00u, 0xFE0Fu)))
- cat = (indic_category_t) OT_VS;
+ cat = OT_VS;
switch (u)
{
case 0x104Eu:
- cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
+ cat = OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
break;
case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u:
case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u:
case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu:
case 0x25FEu:
- cat = (indic_category_t) OT_GB;
+ cat = OT_GB;
break;
case 0x1004u: case 0x101Bu: case 0x105Au:
- cat = (indic_category_t) OT_Ra;
+ cat = OT_Ra;
break;
case 0x1032u: case 0x1036u:
- cat = (indic_category_t) OT_A;
+ cat = OT_A;
break;
case 0x1039u:
- cat = (indic_category_t) OT_H;
+ cat = OT_H;
break;
case 0x103Au:
- cat = (indic_category_t) OT_As;
+ cat = OT_As;
break;
case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
@@ -107,47 +107,47 @@ set_myanmar_properties (hb_glyph_info_t &info)
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;
+ cat = OT_D;
break;
case 0x1040u:
- cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
+ cat = 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;
+ cat = OT_MH;
break;
case 0x103Cu:
- cat = (indic_category_t) OT_MR;
+ cat = OT_MR;
break;
case 0x103Du: case 0x1082u:
- cat = (indic_category_t) OT_MW;
+ cat = OT_MW;
break;
case 0x103Bu: case 0x105Eu: case 0x105Fu:
- cat = (indic_category_t) OT_MY;
+ cat = 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;
+ cat = OT_PT;
break;
case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u:
case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du:
case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu:
- cat = (indic_category_t) OT_SM;
+ cat = OT_SM;
break;
case 0x104Au: case 0x104Bu:
- cat = (indic_category_t) OT_P;
+ cat = OT_P;
break;
case 0xAA74u: case 0xAA75u: case 0xAA76u:
/* https://github.com/roozbehp/unicode-data/issues/3 */
- cat = (indic_category_t) OT_C;
+ cat = OT_C;
break;
}
@@ -155,17 +155,17 @@ set_myanmar_properties (hb_glyph_info_t &info)
{
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;
+ case POS_PRE_C: cat = OT_VPre;
+ pos = POS_PRE_M; break;
+ case POS_ABOVE_C: cat = OT_VAbv; break;
+ case POS_BELOW_C: cat = OT_VBlw; break;
+ case POS_POST_C: cat = OT_VPst; break;
}
}
- info.myanmar_category() = (myanmar_category_t) cat;
+ info.myanmar_category() = cat;
info.myanmar_position() = pos;
}
-#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_HH */
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
index 02d78ac04..b687fe61e 100644
--- a/src/hb-ot-shape-complex-thai.cc
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-complex.hh"
/* Thai / Lao shaper */
@@ -324,9 +324,9 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
}
/* 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);
+ hb_glyph_info_t &nikhahit = buffer->output_glyph (NIKHAHIT_FROM_SARA_AM (u));
+ _hb_glyph_info_set_continuation (&nikhahit);
+ buffer->replace_glyph (SARA_AA_FROM_SARA_AM (u));
if (unlikely (!buffer->successful))
return;
@@ -357,7 +357,8 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
buffer->merge_out_clusters (start - 1, end);
}
}
- buffer->swap_buffers ();
+ if (likely (buffer->successful))
+ buffer->swap_buffers ();
/* If font has Thai GSUB, we are done. */
if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0])
@@ -376,7 +377,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
nullptr, /* decompose */
nullptr, /* compose */
nullptr, /* setup_masks */
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
false,/* fallback_position */
diff --git a/src/hb-ot-shape-complex-tibetan.cc b/src/hb-ot-shape-complex-tibetan.cc
deleted file mode 100644
index eaac0bf68..000000000
--- a/src/hb-ot-shape-complex-tibetan.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 =
-{
- collect_features_tibetan,
- nullptr, /* override_features */
- nullptr, /* data_create */
- nullptr, /* data_destroy */
- nullptr, /* preprocess_text */
- nullptr, /* postprocess_glyphs */
- HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
- nullptr, /* decompose */
- nullptr, /* compose */
- nullptr, /* setup_masks */
- nullptr, /* disable_otl */
- nullptr, /* reorder_marks */
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
- true, /* fallback_position */
-};
diff --git a/src/hb-ot-shape-complex-use-machine.hh b/src/hb-ot-shape-complex-use-machine.hh
index 0ec805afc..c9410e4e5 100644
--- a/src/hb-ot-shape-complex-use-machine.hh
+++ b/src/hb-ot-shape-complex-use-machine.hh
@@ -31,232 +31,271 @@
#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
#line 38 "hb-ot-shape-complex-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
- 12u, 12u, 1u, 15u, 1u, 1u, 12u, 12u, 0u, 43u, 21u, 21u, 8u, 39u, 8u, 39u,
- 1u, 15u, 1u, 1u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u,
- 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
- 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 13u, 21u, 4u, 4u, 13u, 13u, 8u, 39u,
- 8u, 39u, 8u, 39u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, 8u, 39u,
- 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u, 8u, 39u,
- 8u, 39u, 1u, 15u, 12u, 12u, 1u, 39u, 8u, 39u, 21u, 42u, 41u, 42u, 42u, 42u,
- 1u, 5u, 0
+ 12u, 44u, 1u, 15u, 1u, 1u, 12u, 44u, 0u, 44u, 21u, 21u, 8u, 44u, 8u, 44u,
+ 1u, 15u, 1u, 1u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u,
+ 8u, 39u, 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u,
+ 8u, 44u, 8u, 44u, 8u, 44u, 1u, 39u, 8u, 44u, 13u, 21u, 4u, 4u, 13u, 13u,
+ 8u, 44u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u,
+ 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u,
+ 8u, 44u, 8u, 44u, 1u, 39u, 1u, 15u, 12u, 44u, 1u, 44u, 8u, 44u, 21u, 42u,
+ 41u, 42u, 42u, 42u, 1u, 5u, 0
};
static const char _use_syllable_machine_key_spans[] = {
- 1, 15, 1, 1, 44, 1, 32, 32,
- 15, 1, 32, 32, 32, 19, 19, 19,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 9, 1, 1, 32,
- 32, 32, 32, 19, 19, 19, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 15, 1, 39, 32, 22, 2, 1,
- 5
+ 33, 15, 1, 33, 45, 1, 37, 37,
+ 15, 1, 37, 37, 32, 19, 19, 19,
+ 32, 32, 32, 37, 37, 37, 37, 37,
+ 37, 37, 37, 39, 37, 9, 1, 1,
+ 37, 37, 37, 32, 19, 19, 19, 32,
+ 32, 32, 37, 37, 37, 37, 37, 37,
+ 37, 37, 39, 15, 33, 44, 37, 22,
+ 2, 1, 5
};
static const short _use_syllable_machine_index_offsets[] = {
- 0, 2, 18, 20, 22, 67, 69, 102,
- 135, 151, 153, 186, 219, 252, 272, 292,
- 312, 345, 378, 411, 444, 477, 510, 543,
- 576, 609, 642, 675, 708, 718, 720, 722,
- 755, 788, 821, 854, 874, 894, 914, 947,
- 980, 1013, 1046, 1079, 1112, 1145, 1178, 1211,
- 1244, 1277, 1293, 1295, 1335, 1368, 1391, 1394,
- 1396
+ 0, 34, 50, 52, 86, 132, 134, 172,
+ 210, 226, 228, 266, 304, 337, 357, 377,
+ 397, 430, 463, 496, 534, 572, 610, 648,
+ 686, 724, 762, 800, 840, 878, 888, 890,
+ 892, 930, 968, 1006, 1039, 1059, 1079, 1099,
+ 1132, 1165, 1198, 1236, 1274, 1312, 1350, 1388,
+ 1426, 1464, 1502, 1542, 1558, 1592, 1637, 1675,
+ 1698, 1701, 1703
};
static const char _use_syllable_machine_indicies[] = {
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 3, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2,
- 4, 2, 3, 2, 6, 5, 7, 8,
+ 4, 2, 3, 2, 6, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 6, 5, 7, 8,
9, 7, 10, 8, 9, 9, 11, 9,
9, 3, 12, 9, 9, 13, 7, 7,
14, 15, 9, 9, 16, 17, 18, 19,
20, 21, 22, 16, 23, 24, 25, 26,
27, 28, 9, 29, 30, 31, 9, 9,
- 9, 32, 9, 34, 33, 36, 35, 35,
- 37, 1, 35, 35, 38, 35, 35, 35,
- 35, 35, 39, 40, 41, 42, 43, 44,
- 45, 46, 40, 47, 39, 48, 49, 50,
- 51, 35, 52, 53, 54, 35, 36, 35,
- 35, 37, 1, 35, 35, 38, 35, 35,
- 35, 35, 35, 55, 40, 41, 42, 43,
- 44, 45, 46, 40, 47, 48, 48, 49,
- 50, 51, 35, 52, 53, 54, 35, 37,
- 56, 56, 56, 56, 56, 56, 56, 56,
- 56, 56, 56, 56, 56, 57, 56, 37,
- 56, 36, 35, 35, 37, 1, 35, 35,
- 38, 35, 35, 35, 35, 35, 35, 40,
- 41, 42, 43, 44, 45, 46, 40, 47,
- 48, 48, 49, 50, 51, 35, 52, 53,
- 54, 35, 36, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 40, 41, 42, 43, 44, 35, 35, 35,
- 35, 35, 35, 49, 50, 51, 35, 52,
- 53, 54, 35, 36, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 41, 42, 43, 44, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 52, 53, 54, 35, 36, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 42, 43, 44, 35,
- 36, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 43, 44, 35, 36, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 44, 35,
- 36, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 42, 43, 44, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 52, 53, 54,
- 35, 36, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 42, 43, 44, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 53,
- 54, 35, 36, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 42, 43, 44, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 54, 35, 36, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 41, 42, 43, 44, 35, 35,
- 35, 35, 35, 35, 49, 50, 51, 35,
- 52, 53, 54, 35, 36, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 41, 42, 43, 44, 35,
- 35, 35, 35, 35, 35, 35, 50, 51,
- 35, 52, 53, 54, 35, 36, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 41, 42, 43, 44,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 51, 35, 52, 53, 54, 35, 36, 35,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 40, 41, 42, 43,
- 44, 35, 46, 40, 35, 35, 35, 49,
- 50, 51, 35, 52, 53, 54, 35, 36,
- 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 40, 41, 42,
- 43, 44, 35, 58, 40, 35, 35, 35,
- 49, 50, 51, 35, 52, 53, 54, 35,
- 36, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 40, 41,
- 42, 43, 44, 35, 35, 40, 35, 35,
- 35, 49, 50, 51, 35, 52, 53, 54,
- 35, 36, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 40,
- 41, 42, 43, 44, 45, 46, 40, 35,
- 35, 35, 49, 50, 51, 35, 52, 53,
- 54, 35, 36, 35, 35, 37, 1, 35,
- 35, 38, 35, 35, 35, 35, 35, 35,
- 40, 41, 42, 43, 44, 45, 46, 40,
- 47, 35, 48, 49, 50, 51, 35, 52,
- 53, 54, 35, 36, 35, 35, 37, 1,
- 35, 35, 38, 35, 35, 35, 35, 35,
- 35, 40, 41, 42, 43, 44, 45, 46,
- 40, 47, 39, 48, 49, 50, 51, 35,
- 52, 53, 54, 35, 60, 59, 59, 59,
- 59, 59, 59, 59, 61, 59, 10, 62,
- 60, 59, 11, 63, 63, 3, 6, 63,
- 63, 64, 63, 63, 63, 63, 63, 65,
+ 9, 32, 33, 9, 35, 34, 37, 36,
+ 36, 38, 1, 36, 36, 39, 36, 36,
+ 36, 36, 36, 40, 41, 42, 43, 44,
+ 45, 46, 47, 41, 48, 40, 49, 50,
+ 51, 52, 36, 53, 54, 55, 36, 36,
+ 36, 36, 56, 36, 37, 36, 36, 38,
+ 1, 36, 36, 39, 36, 36, 36, 36,
+ 36, 57, 41, 42, 43, 44, 45, 46,
+ 47, 41, 48, 49, 49, 50, 51, 52,
+ 36, 53, 54, 55, 36, 36, 36, 36,
+ 56, 36, 38, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58,
+ 59, 58, 38, 58, 37, 36, 36, 38,
+ 1, 36, 36, 39, 36, 36, 36, 36,
+ 36, 36, 41, 42, 43, 44, 45, 46,
+ 47, 41, 48, 49, 49, 50, 51, 52,
+ 36, 53, 54, 55, 36, 36, 36, 36,
+ 56, 36, 37, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 41, 42, 43, 44, 45, 36, 36, 36,
+ 36, 36, 36, 50, 51, 52, 36, 53,
+ 54, 55, 36, 36, 36, 36, 42, 36,
+ 37, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 42,
+ 43, 44, 45, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 53, 54, 55,
+ 36, 37, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 43, 44, 45, 36, 37, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 44, 45,
+ 36, 37, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 45, 36, 37, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 43, 44, 45,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 53, 54, 55, 36, 37, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 43, 44,
+ 45, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 54, 55, 36, 37,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 43,
+ 44, 45, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 55, 36,
+ 37, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 42,
+ 43, 44, 45, 36, 36, 36, 36, 36,
+ 36, 50, 51, 52, 36, 53, 54, 55,
+ 36, 36, 36, 36, 42, 36, 37, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 42, 43, 44,
+ 45, 36, 36, 36, 36, 36, 36, 36,
+ 51, 52, 36, 53, 54, 55, 36, 36,
+ 36, 36, 42, 36, 37, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 42, 43, 44, 45, 36,
+ 36, 36, 36, 36, 36, 36, 36, 52,
+ 36, 53, 54, 55, 36, 36, 36, 36,
+ 42, 36, 37, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 41, 42, 43, 44, 45, 36, 47, 41,
+ 36, 36, 36, 50, 51, 52, 36, 53,
+ 54, 55, 36, 36, 36, 36, 42, 36,
+ 37, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 41, 42,
+ 43, 44, 45, 36, 60, 41, 36, 36,
+ 36, 50, 51, 52, 36, 53, 54, 55,
+ 36, 36, 36, 36, 42, 36, 37, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 41, 42, 43, 44,
+ 45, 36, 36, 41, 36, 36, 36, 50,
+ 51, 52, 36, 53, 54, 55, 36, 36,
+ 36, 36, 42, 36, 37, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 41, 42, 43, 44, 45, 46,
+ 47, 41, 36, 36, 36, 50, 51, 52,
+ 36, 53, 54, 55, 36, 36, 36, 36,
+ 42, 36, 37, 36, 36, 38, 1, 36,
+ 36, 39, 36, 36, 36, 36, 36, 36,
+ 41, 42, 43, 44, 45, 46, 47, 41,
+ 48, 36, 49, 50, 51, 52, 36, 53,
+ 54, 55, 36, 36, 36, 36, 56, 36,
+ 38, 58, 58, 58, 58, 58, 58, 37,
+ 58, 58, 58, 58, 58, 58, 59, 58,
+ 58, 58, 58, 58, 58, 58, 42, 43,
+ 44, 45, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 53, 54, 55, 58,
+ 37, 36, 36, 38, 1, 36, 36, 39,
+ 36, 36, 36, 36, 36, 36, 41, 42,
+ 43, 44, 45, 46, 47, 41, 48, 40,
+ 49, 50, 51, 52, 36, 53, 54, 55,
+ 36, 36, 36, 36, 56, 36, 62, 61,
+ 61, 61, 61, 61, 61, 61, 63, 61,
+ 10, 64, 62, 61, 11, 65, 65, 3,
+ 6, 65, 65, 66, 65, 65, 65, 65,
+ 65, 67, 16, 17, 18, 19, 20, 21,
+ 22, 16, 23, 25, 25, 26, 27, 28,
+ 65, 29, 30, 31, 65, 65, 65, 65,
+ 33, 65, 11, 65, 65, 3, 6, 65,
+ 65, 66, 65, 65, 65, 65, 65, 65,
16, 17, 18, 19, 20, 21, 22, 16,
- 23, 25, 25, 26, 27, 28, 63, 29,
- 30, 31, 63, 11, 63, 63, 3, 6,
- 63, 63, 64, 63, 63, 63, 63, 63,
- 63, 16, 17, 18, 19, 20, 21, 22,
- 16, 23, 25, 25, 26, 27, 28, 63,
- 29, 30, 31, 63, 11, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 16, 17, 18, 19, 20, 63,
- 63, 63, 63, 63, 63, 26, 27, 28,
- 63, 29, 30, 31, 63, 11, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 17, 18, 19, 20,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 29, 30, 31, 63, 11, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 18, 19,
- 20, 63, 11, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 19, 20, 63, 11, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 20, 63, 11, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 18, 19, 20, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 29,
- 30, 31, 63, 11, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 18, 19, 20, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 30, 31, 63, 11, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 18, 19, 20, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 31, 63, 11, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 17, 18, 19, 20,
- 63, 63, 63, 63, 63, 63, 26, 27,
- 28, 63, 29, 30, 31, 63, 11, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 17, 18, 19,
- 20, 63, 63, 63, 63, 63, 63, 63,
- 27, 28, 63, 29, 30, 31, 63, 11,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 17, 18,
- 19, 20, 63, 63, 63, 63, 63, 63,
- 63, 63, 28, 63, 29, 30, 31, 63,
- 11, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 16, 17,
- 18, 19, 20, 63, 22, 16, 63, 63,
- 63, 26, 27, 28, 63, 29, 30, 31,
- 63, 11, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 16,
- 17, 18, 19, 20, 63, 66, 16, 63,
- 63, 63, 26, 27, 28, 63, 29, 30,
- 31, 63, 11, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 16, 17, 18, 19, 20, 63, 63, 16,
- 63, 63, 63, 26, 27, 28, 63, 29,
- 30, 31, 63, 11, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 16, 17, 18, 19, 20, 21, 22,
- 16, 63, 63, 63, 26, 27, 28, 63,
- 29, 30, 31, 63, 11, 63, 63, 3,
- 6, 63, 63, 64, 63, 63, 63, 63,
- 63, 63, 16, 17, 18, 19, 20, 21,
- 22, 16, 23, 63, 25, 26, 27, 28,
- 63, 29, 30, 31, 63, 3, 67, 67,
- 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 4, 67, 6, 67, 8,
- 63, 63, 63, 8, 63, 63, 11, 63,
- 63, 3, 6, 63, 63, 64, 63, 63,
- 63, 63, 63, 63, 16, 17, 18, 19,
- 20, 21, 22, 16, 23, 24, 25, 26,
- 27, 28, 63, 29, 30, 31, 63, 11,
- 63, 63, 3, 6, 63, 63, 64, 63,
- 63, 63, 63, 63, 63, 16, 17, 18,
+ 23, 25, 25, 26, 27, 28, 65, 29,
+ 30, 31, 65, 65, 65, 65, 33, 65,
+ 11, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 16, 17,
+ 18, 19, 20, 65, 65, 65, 65, 65,
+ 65, 26, 27, 28, 65, 29, 30, 31,
+ 65, 65, 65, 65, 17, 65, 11, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 17, 18, 19,
+ 20, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 29, 30, 31, 65, 11,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 18,
+ 19, 20, 65, 11, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 19, 20, 65, 11,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 20, 65, 11, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 18, 19, 20, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 29, 30, 31, 65, 11, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 18, 19, 20, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 30, 31, 65, 11, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 18, 19, 20,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 31, 65, 11, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 17, 18, 19,
+ 20, 65, 65, 65, 65, 65, 65, 26,
+ 27, 28, 65, 29, 30, 31, 65, 65,
+ 65, 65, 17, 65, 11, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 17, 18, 19, 20, 65,
+ 65, 65, 65, 65, 65, 65, 27, 28,
+ 65, 29, 30, 31, 65, 65, 65, 65,
+ 17, 65, 11, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 17, 18, 19, 20, 65, 65, 65,
+ 65, 65, 65, 65, 65, 28, 65, 29,
+ 30, 31, 65, 65, 65, 65, 17, 65,
+ 11, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 16, 17,
+ 18, 19, 20, 65, 22, 16, 65, 65,
+ 65, 26, 27, 28, 65, 29, 30, 31,
+ 65, 65, 65, 65, 17, 65, 11, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 16, 17, 18, 19,
+ 20, 65, 68, 16, 65, 65, 65, 26,
+ 27, 28, 65, 29, 30, 31, 65, 65,
+ 65, 65, 17, 65, 11, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 16, 17, 18, 19, 20, 65,
+ 65, 16, 65, 65, 65, 26, 27, 28,
+ 65, 29, 30, 31, 65, 65, 65, 65,
+ 17, 65, 11, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 16, 17, 18, 19, 20, 21, 22, 16,
+ 65, 65, 65, 26, 27, 28, 65, 29,
+ 30, 31, 65, 65, 65, 65, 17, 65,
+ 11, 65, 65, 3, 6, 65, 65, 66,
+ 65, 65, 65, 65, 65, 65, 16, 17,
+ 18, 19, 20, 21, 22, 16, 23, 65,
+ 25, 26, 27, 28, 65, 29, 30, 31,
+ 65, 65, 65, 65, 33, 65, 3, 65,
+ 65, 65, 65, 65, 65, 11, 65, 65,
+ 65, 65, 65, 65, 4, 65, 65, 65,
+ 65, 65, 65, 65, 17, 18, 19, 20,
+ 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 29, 30, 31, 65, 3, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 4, 69, 6, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 6, 69,
+ 8, 65, 65, 65, 8, 65, 65, 11,
+ 65, 65, 3, 6, 65, 65, 66, 65,
+ 65, 65, 65, 65, 65, 16, 17, 18,
19, 20, 21, 22, 16, 23, 24, 25,
- 26, 27, 28, 63, 29, 30, 31, 63,
- 69, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 69, 70, 68, 69,
- 70, 68, 70, 68, 8, 67, 67, 67,
- 8, 67, 0
+ 26, 27, 28, 65, 29, 30, 31, 65,
+ 65, 65, 65, 33, 65, 11, 65, 65,
+ 3, 6, 65, 65, 66, 65, 65, 65,
+ 65, 65, 65, 16, 17, 18, 19, 20,
+ 21, 22, 16, 23, 24, 25, 26, 27,
+ 28, 65, 29, 30, 31, 65, 65, 65,
+ 65, 33, 65, 71, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 71,
+ 72, 70, 71, 72, 70, 72, 70, 8,
+ 69, 69, 69, 8, 69, 0
};
static const char _use_syllable_machine_trans_targs[] = {
- 4, 8, 4, 31, 2, 4, 1, 5,
- 6, 4, 28, 4, 49, 50, 51, 53,
- 33, 34, 35, 36, 37, 44, 45, 47,
- 52, 48, 41, 42, 43, 38, 39, 40,
- 56, 4, 4, 4, 4, 7, 0, 27,
- 11, 12, 13, 14, 15, 22, 23, 25,
- 26, 19, 20, 21, 16, 17, 18, 10,
- 4, 9, 24, 4, 29, 30, 4, 4,
- 3, 32, 46, 4, 4, 54, 55
+ 4, 8, 4, 32, 2, 4, 1, 5,
+ 6, 4, 29, 4, 51, 52, 53, 55,
+ 34, 35, 36, 37, 38, 45, 46, 48,
+ 54, 49, 42, 43, 44, 39, 40, 41,
+ 58, 50, 4, 4, 4, 4, 7, 0,
+ 28, 11, 12, 13, 14, 15, 22, 23,
+ 25, 26, 19, 20, 21, 16, 17, 18,
+ 27, 10, 4, 9, 24, 4, 30, 31,
+ 4, 4, 3, 33, 47, 4, 4, 56,
+ 57
};
static const char _use_syllable_machine_trans_actions[] = {
@@ -264,11 +303,12 @@ static const char _use_syllable_machine_trans_actions[] = {
7, 8, 0, 9, 10, 10, 3, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 3, 0, 0, 0, 0, 0, 0,
- 0, 11, 12, 13, 14, 7, 0, 7,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 7, 0, 0, 0, 0, 0, 0, 7,
- 15, 0, 0, 16, 0, 0, 17, 18,
- 0, 3, 0, 19, 20, 0, 0
+ 0, 3, 11, 12, 13, 14, 7, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 7, 0, 0, 0, 0, 0, 0,
+ 0, 7, 15, 0, 0, 16, 0, 0,
+ 17, 18, 0, 3, 0, 19, 20, 0,
+ 0
};
static const char _use_syllable_machine_to_state_actions[] = {
@@ -279,7 +319,7 @@ static const char _use_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0
+ 0, 0, 0
};
static const char _use_syllable_machine_from_state_actions[] = {
@@ -290,18 +330,18 @@ static const char _use_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0
+ 0, 0, 0
};
static const short _use_syllable_machine_eof_trans[] = {
- 1, 3, 3, 6, 0, 34, 36, 36,
- 57, 57, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 60, 63, 60, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 68, 68, 64, 64, 69, 69, 69,
- 68
+ 1, 3, 3, 6, 0, 35, 37, 37,
+ 59, 59, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 59, 37, 62, 65, 62,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 70, 70, 66, 66, 71,
+ 71, 71, 70
};
static const int use_syllable_machine_start = 4;
@@ -315,15 +355,14 @@ static const int use_syllable_machine_en_main = 4;
-#line 141 "hb-ot-shape-complex-use-machine.rl"
+#line 143 "hb-ot-shape-complex-use-machine.rl"
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -331,11 +370,11 @@ static const int use_syllable_machine_en_main = 4;
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te, act;
+ unsigned int p, pe, eof, ts, te, act;
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 339 "hb-ot-shape-complex-use-machine.hh"
+#line 378 "hb-ot-shape-complex-use-machine.hh"
{
cs = use_syllable_machine_start;
ts = 0;
@@ -343,16 +382,15 @@ find_syllables (hb_buffer_t *buffer)
act = 0;
}
-#line 162 "hb-ot-shape-complex-use-machine.rl"
+#line 163 "hb-ot-shape-complex-use-machine.rl"
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 356 "hb-ot-shape-complex-use-machine.hh"
+#line 394 "hb-ot-shape-complex-use-machine.hh"
{
int _slen;
int _trans;
@@ -366,7 +404,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 370 "hb-ot-shape-complex-use-machine.hh"
+#line 408 "hb-ot-shape-complex-use-machine.hh"
}
_keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -389,59 +427,59 @@ _eof_trans:
{te = p+1;}
break;
case 12:
-#line 130 "hb-ot-shape-complex-use-machine.rl"
+#line 132 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (independent_cluster); }}
break;
case 14:
-#line 132 "hb-ot-shape-complex-use-machine.rl"
+#line 134 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (standard_cluster); }}
break;
case 9:
-#line 136 "hb-ot-shape-complex-use-machine.rl"
+#line 138 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (broken_cluster); }}
break;
case 8:
-#line 137 "hb-ot-shape-complex-use-machine.rl"
+#line 139 "hb-ot-shape-complex-use-machine.rl"
{te = p+1;{ found_syllable (non_cluster); }}
break;
case 11:
-#line 130 "hb-ot-shape-complex-use-machine.rl"
+#line 132 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (independent_cluster); }}
break;
case 15:
-#line 131 "hb-ot-shape-complex-use-machine.rl"
+#line 133 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (virama_terminated_cluster); }}
break;
case 13:
-#line 132 "hb-ot-shape-complex-use-machine.rl"
+#line 134 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (standard_cluster); }}
break;
case 17:
-#line 133 "hb-ot-shape-complex-use-machine.rl"
+#line 135 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }}
break;
case 16:
-#line 134 "hb-ot-shape-complex-use-machine.rl"
+#line 136 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (numeral_cluster); }}
break;
case 20:
-#line 135 "hb-ot-shape-complex-use-machine.rl"
+#line 137 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (symbol_cluster); }}
break;
case 18:
-#line 136 "hb-ot-shape-complex-use-machine.rl"
+#line 138 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
case 19:
-#line 137 "hb-ot-shape-complex-use-machine.rl"
+#line 139 "hb-ot-shape-complex-use-machine.rl"
{te = p;p--;{ found_syllable (non_cluster); }}
break;
case 1:
-#line 132 "hb-ot-shape-complex-use-machine.rl"
+#line 134 "hb-ot-shape-complex-use-machine.rl"
{{p = ((te))-1;}{ found_syllable (standard_cluster); }}
break;
case 4:
-#line 136 "hb-ot-shape-complex-use-machine.rl"
+#line 138 "hb-ot-shape-complex-use-machine.rl"
{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
break;
case 2:
@@ -459,16 +497,16 @@ _eof_trans:
case 3:
#line 1 "NONE"
{te = p+1;}
-#line 136 "hb-ot-shape-complex-use-machine.rl"
+#line 138 "hb-ot-shape-complex-use-machine.rl"
{act = 7;}
break;
case 10:
#line 1 "NONE"
{te = p+1;}
-#line 137 "hb-ot-shape-complex-use-machine.rl"
+#line 139 "hb-ot-shape-complex-use-machine.rl"
{act = 8;}
break;
-#line 472 "hb-ot-shape-complex-use-machine.hh"
+#line 510 "hb-ot-shape-complex-use-machine.hh"
}
_again:
@@ -477,7 +515,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 481 "hb-ot-shape-complex-use-machine.hh"
+#line 519 "hb-ot-shape-complex-use-machine.hh"
}
if ( ++p != pe )
diff --git a/src/hb-ot-shape-complex-use-machine.rl b/src/hb-ot-shape-complex-use-machine.rl
index 7ec8a7fd1..7702cd94d 100644
--- a/src/hb-ot-shape-complex-use-machine.rl
+++ b/src/hb-ot-shape-complex-use-machine.rl
@@ -29,7 +29,7 @@
#ifndef HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_USE_MACHINE_HH
-#include "hb-private.hh"
+#include "hb.hh"
%%{
machine use_syllable_machine;
@@ -88,22 +88,19 @@ SMAbv = 41; # SYM_MOD_ABOVE
SMBlw = 42; # SYM_MOD_BELOW
CS = 43; # CONS_WITH_STACKER
+HVM = 44; # HALANT_OR_VOWEL_MODIFIER
+
+h = H | HVM; # https://github.com/harfbuzz/harfbuzz/issues/1102
# Override: Adhoc ZWJ placement. https://github.com/harfbuzz/harfbuzz/issues/542#issuecomment-353169729
-consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.H.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*;
+consonant_modifiers = CMAbv* CMBlw* ((ZWJ?.h.ZWJ? B | SUB) VS? CMAbv? CMBlw*)*;
# Override: Allow two MBlw. https://github.com/harfbuzz/harfbuzz/issues/376
medial_consonants = MPre? MAbv? MBlw?.MBlw? MPst?;
dependent_vowels = VPre* VAbv* VBlw* VPst*;
-vowel_modifiers = VMPre* VMAbv* VMBlw* VMPst*;
+vowel_modifiers = HVM? VMPre* VMAbv* VMBlw* VMPst*;
final_consonants = FAbv* FBlw* FPst* FM?;
-virama_terminated_cluster =
- (R|CS)? (B | GB) VS?
- consonant_modifiers
- ZWJ?.H.ZWJ?
-;
-standard_cluster =
- (R|CS)? (B | GB) VS?
+complex_syllable_tail =
consonant_modifiers
medial_consonants
dependent_vowels
@@ -111,13 +108,18 @@ standard_cluster =
final_consonants
;
+virama_terminated_cluster =
+ (R|CS)? (B | GB) VS?
+ consonant_modifiers
+ ZWJ?.h.ZWJ?
+;
+standard_cluster =
+ (R|CS)? (B | GB) VS?
+ complex_syllable_tail
+;
broken_cluster =
R?
- consonant_modifiers
- medial_consonants
- dependent_vowels
- vowel_modifiers
- final_consonants
+ complex_syllable_tail
;
number_joiner_terminated_cluster = N VS? (HN N VS?)* HN;
@@ -142,10 +144,9 @@ main := |*
#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++) \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+ for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
- last = p+1; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
@@ -153,7 +154,7 @@ main := |*
static void
find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts HB_UNUSED, te, act;
+ unsigned int p, pe, eof, ts, te, act;
int cs;
hb_glyph_info_t *info = buffer->info;
%%{
@@ -164,7 +165,6 @@ find_syllables (hb_buffer_t *buffer)
p = 0;
pe = eof = buffer->len;
- unsigned int last = 0;
unsigned int syllable_serial = 1;
%%{
write exec;
diff --git a/src/hb-ot-shape-complex-use-table.cc b/src/hb-ot-shape-complex-use-table.cc
index 9c796f051..e9c88aec4 100644
--- a/src/hb-ot-shape-complex-use-table.cc
+++ b/src/hb-ot-shape-complex-use-table.cc
@@ -15,7 +15,7 @@
* UnicodeData.txt does not have a header.
*/
-#include "hb-ot-shape-complex-use-private.hh"
+#include "hb-ot-shape-complex-use.hh"
#define B USE_B /* BASE */
#define CGJ USE_CGJ /* CGJ */
@@ -24,6 +24,7 @@
#define GB USE_GB /* BASE_OTHER */
#define H USE_H /* HALANT */
#define HN USE_HN /* HALANT_NUM */
+#define HVM USE_HVM /* HALANT_OR_VOWEL_MODIFIER */
#define IND USE_IND /* BASE_IND */
#define N USE_N /* BASE_NUM */
#define O USE_O /* OTHER */
@@ -101,7 +102,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 0990 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 09A0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 09B0 */ B, O, B, O, O, O, B, B, B, B, O, O, CMBlw, B, VPst, VPre,
- /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, IND, O,
+ /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPst, VPst, H, IND, O,
/* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B,
/* 09E0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FM, O,
@@ -134,7 +135,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 0B10 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv,
- /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
+ /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPst, O, O, VPst, VPst, H, O, O,
/* 0B50 */ O, O, O, O, O, O, VAbv, VAbv, O, O, O, O, B, B, O, B,
/* 0B60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
@@ -145,7 +146,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 0B90 */ B, O, B, B, B, B, O, O, O, B, B, O, B, O, B, B,
/* 0BA0 */ O, O, O, B, B, O, O, O, B, B, B, O, O, O, B, B,
/* 0BB0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, VPst, VPst,
- /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, O, O,
+ /* 0BC0 */ VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPst, VPst, VPst, H, O, O,
/* 0BD0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, O, O,
/* 0BE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0BF0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
@@ -178,7 +179,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 0D10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, VAbv, VAbv, B, VPst, VPst,
- /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPre, VPre, VPre, H, R, O,
+ /* 0D40 */ VPst, VPst, VPst, VBlw, VBlw, O, VPre, VPre, VPre, O, VPst, VPst, VPst, H, R, O,
/* 0D50 */ O, O, O, O, IND, IND, IND, VPst, O, O, O, O, O, O, O, B,
/* 0D60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0D70 */ O, O, O, O, O, O, O, O, O, O, IND, IND, IND, IND, IND, IND,
@@ -190,11 +191,28 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O,
/* 0DC0 */ B, B, B, B, B, B, B, O, O, O, H, O, O, O, O, VPst,
- /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst,
+ /* 0DD0 */ VPst, VPst, VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPst, VPre, VPst, VPst, VPst, VPst,
/* 0DE0 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B,
/* 0DF0 */ O, O, VPst, VPst, O, O, O, O,
-#define use_offset_0x1000u 1360
+#define use_offset_0x0f18u 1360
+
+
+ /* Tibetan */
+ VBlw, VBlw, O, O, O, O, O, O,
+ /* 0F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0F30 */ B, B, B, B, O, FM, O, FM, O, CMAbv, O, O, O, O, VPst, VPre,
+ /* 0F40 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B,
+ /* 0F50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
+ /* 0F60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O,
+ /* 0F70 */ O, VBlw, VBlw, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VMAbv, VMPst,
+ /* 0F80 */ VBlw, VAbv, VMAbv, VMAbv, VBlw, IND, VMAbv, VMAbv, B, B, B, B, B, SUB, SUB, SUB,
+ /* 0F90 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
+ /* 0FA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
+ /* 0FB0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, O, O,
+ /* 0FC0 */ O, O, O, O, O, O, FM, O,
+
+#define use_offset_0x1000u 1536
/* Myanmar */
@@ -210,7 +228,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1080 */ B, B, MBlw, VPst, VPre, VAbv, VAbv, VMPst, VMPst, VMPst, VMPst, VMPst, VMPst, VMBlw, B, VMPst,
/* 1090 */ B, B, B, B, B, B, B, B, B, B, VMPst, VMPst, VPst, VAbv, O, O,
-#define use_offset_0x1700u 1520
+#define use_offset_0x1700u 1696
/* Tagalog */
@@ -238,12 +256,12 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1780 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1790 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPre, VPre,
- /* 17C0 */ VPre, VPre, VPre, VPre, VPre, VPre, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM,
+ /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPst, VPst,
+ /* 17C0 */ VPst, VPre, VPre, VPre, VPst, VPst, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM,
/* 17D0 */ FM, VAbv, H, FM, O, O, O, O, O, O, O, O, B, VAbv, O, O,
/* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-#define use_offset_0x1900u 1760
+#define use_offset_0x1900u 1936
/* Limbu */
@@ -287,7 +305,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
/* 1A90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-#define use_offset_0x1b00u 2176
+#define use_offset_0x1b00u 2352
/* Balinese */
@@ -296,7 +314,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1B10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre,
- /* 1B40 */ VPre, VPre, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O,
+ /* 1B40 */ VPst, VPst, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O,
/* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
/* 1B60 */ O, O, O, O, O, O, O, O, O, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv,
/* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O,
@@ -319,11 +337,11 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv,
+ /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPst, VPst, VPst, VBlw, FAbv, FAbv, FAbv,
/* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FM, CMBlw, O, O, O, O, O, O, O, O,
/* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B,
-#define use_offset_0x1cd0u 2512
+#define use_offset_0x1cd0u 2688
/* Vedic Extensions */
@@ -332,20 +350,20 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O,
/* 1CF0 */ O, O, VMPst, VMPst, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, O, O, O, O, O, O,
-#define use_offset_0x1df8u 2560
+#define use_offset_0x1df8u 2736
/* Combining Diacritical Marks Supplement */
O, O, O, FM, O, O, O, O,
-#define use_offset_0x2008u 2568
+#define use_offset_0x2008u 2744
/* General Punctuation */
O, O, O, O, ZWNJ, ZWJ, O, O,
/* 2010 */ GB, GB, GB, GB, GB, O, O, O,
-#define use_offset_0x2060u 2584
+#define use_offset_0x2060u 2760
/* 2060 */ WJ, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
@@ -354,20 +372,20 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 2070 */ O, O, O, O, FM, O, O, O, O, O, O, O, O, O, O, O,
/* 2080 */ O, O, FM, FM, FM, O, O, O,
-#define use_offset_0x20f0u 2624
+#define use_offset_0x20f0u 2800
/* Combining Diacritical Marks for Symbols */
/* 20F0 */ VMAbv, O, O, O, O, O, O, O,
-#define use_offset_0x25c8u 2632
+#define use_offset_0x25c8u 2808
/* Geometric Shapes */
O, O, O, O, GB, O, O, O,
-#define use_offset_0xa800u 2640
+#define use_offset_0xa800u 2816
/* Syloti Nagri */
@@ -454,7 +472,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* AAE0 */ B, B, B, B, B, B, B, B, B, B, B, VPre, VBlw, VAbv, VPre, VPst,
/* AAF0 */ O, O, O, O, O, VMPst, H, O,
-#define use_offset_0xabc0u 3400
+#define use_offset_0xabc0u 3576
/* Meetei Mayek */
@@ -464,14 +482,14 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* ABE0 */ B, B, B, VPst, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O, VMPst, VBlw, O, O,
/* ABF0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-#define use_offset_0xfe00u 3464
+#define use_offset_0xfe00u 3640
/* Variation Selectors */
/* FE00 */ VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS, VS,
-#define use_offset_0x10a00u 3480
+#define use_offset_0x10a00u 3656
/* Kharoshthi */
@@ -482,7 +500,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 10A30 */ B, B, B, B, B, B, O, O, CMAbv, CMBlw, CMBlw, O, O, O, O, H,
/* 10A40 */ B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, O,
-#define use_offset_0x11000u 3560
+#define use_offset_0x11000u 3736
/* Brahmi */
@@ -491,7 +509,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11010 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11020 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11030 */ B, B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,
- /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O, O, O, O, O, O, O,
+ /* 11040 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, HVM, O, O, O, O, O, O, O, O, O,
/* 11050 */ O, O, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
/* 11060 */ N, N, N, N, N, N, B, B, B, B, B, B, B, B, B, B,
/* 11070 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, HN,
@@ -503,7 +521,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 110A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 110B0 */ VPst, VPre, VPst, VBlw, VBlw, VAbv, VAbv, VPst, VPst, H, CMBlw, O, O, O, O, O,
-#define use_offset_0x11100u 3752
+#define use_offset_0x11100u 3928
/* Chakma */
@@ -511,7 +529,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv,
- /* 11130 */ VBlw, VAbv, VAbv, H, CMAbv, O, B, B, B, B, B, B, B, B, B, B,
+ /* 11130 */ VBlw, VAbv, VAbv, H, CMBlw, O, B, B, B, B, B, B, B, B, B, B,
/* 11140 */ O, O, O, O, B, VPst, VPst, O, O, O, O, O, O, O, O, O,
/* Mahajani */
@@ -541,7 +559,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11220 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPst, VPst, VBlw,
/* 11230 */ VAbv, VAbv, VAbv, VAbv, VMAbv, H, CMAbv, CMAbv, O, O, O, O, O, O, VMAbv, O,
-#define use_offset_0x11280u 4072
+#define use_offset_0x11280u 4248
/* Multani */
@@ -564,12 +582,12 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B,
/* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst,
- /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPre, VPre, H, O, O,
+ /* 11340 */ VAbv, VPst, VPst, VPst, VPst, O, O, VPre, VPre, O, O, VPst, VPst, H, O, O,
/* 11350 */ O, O, O, O, O, O, O, VPst, O, O, O, O, O, O, B, B,
/* 11360 */ B, B, VPst, VPst, O, O, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
/* 11370 */ VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, O, O, O,
-#define use_offset_0x11400u 4320
+#define use_offset_0x11400u 4496
/* Newa */
@@ -588,11 +606,11 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11480 */ O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
- /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPre, VPre, VPst, VPre, VMAbv,
+ /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPst, VPst, VPst, VPst, VMAbv,
/* 114C0 */ VMAbv, VMPst, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O,
/* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-#define use_offset_0x11580u 4544
+#define use_offset_0x11580u 4720
/* Siddham */
@@ -600,7 +618,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11580 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11590 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 115A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, VPst,
- /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, VPre, VPre, VMAbv, VMAbv, VMPst, H,
+ /* 115B0 */ VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPst, VPst, VPst, VMAbv, VMAbv, VMPst, H,
/* 115C0 */ CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
/* 115D0 */ O, O, O, O, O, O, O, O, B, B, B, B, VBlw, VBlw, O, O,
/* 115E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O,
@@ -635,7 +653,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11720 */ VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VBlw, VAbv, VAbv, VAbv, O, O, O, O,
/* 11730 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O,
-#define use_offset_0x11800u 4992
+#define use_offset_0x11800u 5168
/* Dogra */
@@ -645,7 +663,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11820 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPre, VPst, VBlw,
/* 11830 */ VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VMAbv, VMPst, H, CMBlw, O, O, O, O, O,
-#define use_offset_0x11a00u 5056
+#define use_offset_0x11a00u 5232
/* Zanabazar Square */
@@ -664,7 +682,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11A80 */ B, B, B, B, O, O, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw,
/* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, H, O, O, O, B, O, O,
-#define use_offset_0x11c00u 5216
+#define use_offset_0x11c00u 5392
/* Bhaiksuki */
@@ -685,7 +703,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB,
/* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, O,
-#define use_offset_0x11d00u 5400
+#define use_offset_0x11d00u 5576
/* Masaram Gondi */
@@ -705,7 +723,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11D90 */ VAbv, VAbv, O, VPst, VPst, VMAbv, VMPst, H, O, O, O, O, O, O, O, O,
/* 11DA0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O,
-#define use_offset_0x11ee0u 5576
+#define use_offset_0x11ee0u 5752
/* Makasar */
@@ -713,7 +731,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
/* 11EE0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
/* 11EF0 */ B, B, GB, VAbv, VBlw, VPre, VPst, O,
-}; /* Table items: 5600; occupancy: 73% */
+}; /* Table items: 5776; occupancy: 74% */
USE_TABLE_ELEMENT_TYPE
hb_use_get_category (hb_codepoint_t u)
@@ -725,6 +743,7 @@ hb_use_get_category (hb_codepoint_t u)
if (hb_in_range<hb_codepoint_t> (u, 0x00A0u, 0x00D7u)) return use_table[u - 0x00A0u + use_offset_0x00a0u];
if (hb_in_range<hb_codepoint_t> (u, 0x0348u, 0x034Fu)) return use_table[u - 0x0348u + use_offset_0x0348u];
if (hb_in_range<hb_codepoint_t> (u, 0x0900u, 0x0DF7u)) return use_table[u - 0x0900u + use_offset_0x0900u];
+ if (hb_in_range<hb_codepoint_t> (u, 0x0F18u, 0x0FC7u)) return use_table[u - 0x0F18u + use_offset_0x0f18u];
break;
case 0x1u:
@@ -782,6 +801,7 @@ hb_use_get_category (hb_codepoint_t u)
#undef GB
#undef H
#undef HN
+#undef HVM
#undef IND
#undef N
#undef O
diff --git a/src/hb-ot-shape-complex-use.cc b/src/hb-ot-shape-complex-use.cc
index f8e86c9d6..f9a580ca2 100644
--- a/src/hb-ot-shape-complex-use.cc
+++ b/src/hb-ot-shape-complex-use.cc
@@ -26,8 +26,8 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-use-private.hh"
-#include "hb-ot-shape-complex-arabic-private.hh"
+#include "hb-ot-shape-complex-use.hh"
+#include "hb-ot-shape-complex-arabic.hh"
/* buffer var allocations */
#define use_category() complex_var_u8_0()
@@ -86,7 +86,14 @@ other_features[] =
HB_TAG('h','a','l','n'),
HB_TAG('p','r','e','s'),
HB_TAG('p','s','t','s'),
- /* Positioning features, though we don't care about the types. */
+};
+static const hb_tag_t
+positioning_features[] =
+{
+ /*
+ * Positioning features.
+ * We don't care about the types.
+ */
HB_TAG('d','i','s','t'),
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
@@ -122,33 +129,37 @@ collect_features_use (hb_ot_shape_planner_t *plan)
map->add_gsub_pause (setup_syllables);
/* "Default glyph pre-processing group" */
- map->add_global_bool_feature (HB_TAG('l','o','c','l'));
- map->add_global_bool_feature (HB_TAG('c','c','m','p'));
- map->add_global_bool_feature (HB_TAG('n','u','k','t'));
- map->add_global_bool_feature (HB_TAG('a','k','h','n'));
+ map->enable_feature (HB_TAG('l','o','c','l'));
+ map->enable_feature (HB_TAG('c','c','m','p'));
+ map->enable_feature (HB_TAG('n','u','k','t'));
+ map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ);
/* "Reordering group" */
map->add_gsub_pause (clear_substitution_flags);
- map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ);
+ map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ);
map->add_gsub_pause (record_rphf);
map->add_gsub_pause (clear_substitution_flags);
- map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ);
+ map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ);
map->add_gsub_pause (record_pref);
/* "Orthographic unit shaping group" */
for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
- map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+ map->enable_feature (basic_features[i], F_MANUAL_ZWJ);
map->add_gsub_pause (reorder);
/* "Topographical features" */
for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++)
- map->add_feature (arabic_features[i], 1, F_NONE);
+ map->add_feature (arabic_features[i]);
map->add_gsub_pause (nullptr);
- /* "Standard typographic presentation" and "Positional feature application" */
+ /* "Standard typographic presentation" */
for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
- map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+ map->enable_feature (other_features[i], F_MANUAL_ZWJ);
+
+ /* "Positional feature application" */
+ for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++)
+ map->enable_feature (positioning_features[i]);
}
struct use_shape_plan_t
@@ -586,7 +597,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
nullptr, /* decompose */
compose_use,
setup_masks_use,
- nullptr, /* disable_otl */
+ HB_TAG_NONE, /* gpos_tag */
nullptr, /* reorder_marks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
diff --git a/src/hb-ot-shape-complex-use-private.hh b/src/hb-ot-shape-complex-use.hh
index b4bda8bb7..ab56e1b8f 100644
--- a/src/hb-ot-shape-complex-use-private.hh
+++ b/src/hb-ot-shape-complex-use.hh
@@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
-#define HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH
+#ifndef HB_OT_SHAPE_COMPLEX_USE_HH
+#define HB_OT_SHAPE_COMPLEX_USE_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-complex.hh"
#define USE_TABLE_ELEMENT_TYPE uint8_t
@@ -88,10 +88,13 @@ enum use_category_t {
USE_VMPre = 23, /* VOWEL_MOD_PRE */
USE_SMAbv = 41, /* SYM_MOD_ABOVE */
USE_SMBlw = 42, /* SYM_MOD_BELOW */
- USE_CS = 43 /* CONS_WITH_STACKER */
+ USE_CS = 43, /* CONS_WITH_STACKER */
+
+ /* https://github.com/harfbuzz/harfbuzz/issues/1102 */
+ USE_HVM = 44, /* HALANT_OR_VOWEL_MODIFIER */
};
HB_INTERNAL USE_TABLE_ELEMENT_TYPE
hb_use_get_category (hb_codepoint_t u);
-#endif /* HB_OT_SHAPE_COMPLEX_USE_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_COMPLEX_USE_HH */
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex.hh
index 37a4d918b..2944d745c 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex.hh
@@ -24,14 +24,14 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH
-#define HB_OT_SHAPE_COMPLEX_PRIVATE_HH
+#ifndef HB_OT_SHAPE_COMPLEX_HH
+#define HB_OT_SHAPE_COMPLEX_HH
-#include "hb-private.hh"
-
-#include "hb-ot-shape-private.hh"
-#include "hb-ot-shape-normalize-private.hh"
+#include "hb.hh"
+#include "hb-ot-layout.hh"
+#include "hb-ot-shape.hh"
+#include "hb-ot-shape-normalize.hh"
/* buffer var allocations, used by complex shapers */
@@ -58,8 +58,8 @@ enum hb_ot_shape_zero_width_marks_type_t {
HB_COMPLEX_SHAPER_IMPLEMENT (khmer) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \
HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
- HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
HB_COMPLEX_SHAPER_IMPLEMENT (use) \
/* ^--- Add new shapers here */
@@ -69,7 +69,7 @@ struct hb_ot_complex_shaper_t
/* collect_features()
* Called during shape_plan().
* Shapers should use plan->map to add their features and callbacks.
- * May be nullptr.
+ * May be NULL.
*/
void (*collect_features) (hb_ot_shape_planner_t *plan);
@@ -77,7 +77,7 @@ struct hb_ot_complex_shaper_t
* Called during shape_plan().
* Shapers should use plan->map to override features and add callbacks after
* common features are added.
- * May be nullptr.
+ * May be NULL.
*/
void (*override_features) (hb_ot_shape_planner_t *plan);
@@ -93,7 +93,7 @@ struct hb_ot_complex_shaper_t
* Called when the shape_plan is being destroyed.
* plan->data is passed here for destruction.
* If nullptr is returned, means a plan failure.
- * May be nullptr.
+ * May be NULL.
*/
void (*data_destroy) (void *data);
@@ -101,7 +101,7 @@ struct hb_ot_complex_shaper_t
/* preprocess_text()
* Called during shape().
* Shapers can use to modify text before shaping starts.
- * May be nullptr.
+ * May be NULL.
*/
void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
@@ -110,7 +110,7 @@ struct hb_ot_complex_shaper_t
/* postprocess_glyphs()
* Called during shape().
* Shapers can use to modify glyphs after shaping ends.
- * May be nullptr.
+ * May be NULL.
*/
void (*postprocess_glyphs) (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
@@ -121,7 +121,7 @@ struct hb_ot_complex_shaper_t
/* decompose()
* Called during shape()'s normalization.
- * May be nullptr.
+ * May be NULL.
*/
bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
@@ -130,7 +130,7 @@ struct hb_ot_complex_shaper_t
/* compose()
* Called during shape()'s normalization.
- * May be nullptr.
+ * May be NULL.
*/
bool (*compose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
@@ -141,24 +141,22 @@ struct hb_ot_complex_shaper_t
* Called during shape().
* Shapers should use map to get feature masks and set on buffer.
* Shapers may NOT modify characters.
- * May be nullptr.
+ * May be NULL.
*/
void (*setup_masks) (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font);
- /* disable_otl()
- * Called during shape().
- * If set and returns true, GDEF/GSUB/GPOS of the font are ignored
- * and fallback operations used.
- * May be nullptr.
+ /* gpos_tag()
+ * If not HB_TAG_NONE, then must match found GPOS script tag for
+ * GPOS to be applied. Otherwise, fallback positioning will be used.
*/
- bool (*disable_otl) (const hb_ot_shape_plan_t *plan);
+ hb_tag_t gpos_tag;
/* reorder_marks()
* Called during shape().
* Shapers can use to modify ordering of combining marks.
- * May be nullptr.
+ * May be NULL.
*/
void (*reorder_marks) (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
@@ -234,25 +232,12 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
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 */
-
-#if 0
- /* Unicode-4.1 additions */
- case HB_SCRIPT_NEW_TAI_LUE:
-#endif
-
/* Unicode-1.1 additions */
case HB_SCRIPT_BENGALI:
case HB_SCRIPT_DEVANAGARI:
@@ -270,11 +255,13 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* If the designer designed the font for the 'DFLT' script,
* (or we ended up arbitrarily pick 'latn'), use the default shaper.
* Otherwise, use the specific shaper.
- * Note that for some simple scripts, there may not be *any*
- * GSUB/GPOS needed, so there may be no scripts found! */
+ *
+ * If it's indy3 tag, send to USE. */
if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
return &_hb_ot_complex_shaper_default;
+ else if ((planner->map.chosen_script[0] & 0x000000FF) == '3')
+ return &_hb_ot_complex_shaper_use;
else
return &_hb_ot_complex_shaper_indic;
@@ -291,7 +278,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-2.0 additions */
- //case HB_SCRIPT_TIBETAN:
+ case HB_SCRIPT_TIBETAN:
/* Unicode-3.0 additions */
//case HB_SCRIPT_MONGOLIAN:
@@ -359,9 +346,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-8.0 additions */
case HB_SCRIPT_AHOM:
- //case HB_SCRIPT_MULTANI:
/* Unicode-9.0 additions */
+ //case HB_SCRIPT_ADLAM:
case HB_SCRIPT_BHAIKSUKI:
case HB_SCRIPT_MARCHEN:
case HB_SCRIPT_NEWA:
@@ -374,7 +361,9 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
/* Unicode-11.0 additions */
case HB_SCRIPT_DOGRA:
case HB_SCRIPT_GUNJALA_GONDI:
+ //case HB_SCRIPT_HANIFI_ROHINGYA:
case HB_SCRIPT_MAKASAR:
+ //case HB_SCRIPT_SOGDIAN:
/* If the designer designed the font for the 'DFLT' script,
* (or we ended up arbitrarily pick 'latn'), use the default shaper.
@@ -386,8 +375,12 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_default;
else
return &_hb_ot_complex_shaper_use;
+
+ /* https://github.com/harfbuzz/harfbuzz/issues/1162 */
+ case HB_SCRIPT_MYANMAR_ZAWGYI:
+ return &_hb_ot_complex_shaper_myanmar_zawgyi;
}
}
-#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_COMPLEX_HH */
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
index fbf31ab24..4c5ccc974 100644
--- a/src/hb-ot-shape-fallback.cc
+++ b/src/hb-ot-shape-fallback.cc
@@ -24,8 +24,8 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-fallback-private.hh"
-#include "hb-ot-layout-gsubgpos-private.hh"
+#include "hb-ot-shape-fallback.hh"
+#include "hb-ot-kern-table.hh"
static unsigned int
recategorize_combining_class (hb_codepoint_t u,
@@ -162,9 +162,9 @@ recategorize_combining_class (hb_codepoint_t u,
}
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)
+_hb_ot_shape_fallback_mark_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;
@@ -417,9 +417,9 @@ position_cluster (const hb_ot_shape_plan_t *plan,
}
void
-_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
- hb_font_t *font,
- hb_buffer_t *buffer)
+_hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
{
_hb_buffer_assert_gsubgpos_vars (buffer);
@@ -435,60 +435,38 @@ _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
}
-/* 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)
+struct hb_ot_shape_fallback_kern_driver_t
{
- if (!plan->has_kern) return;
+ hb_ot_shape_fallback_kern_driver_t (hb_font_t *font_,
+ hb_buffer_t *buffer) :
+ font (font_), direction (buffer->props.direction) {}
- OT::hb_ot_apply_context_t c (1, font, buffer);
- c.set_lookup_mask (plan->kern_mask);
- c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
- OT::hb_ot_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;)
+ hb_position_t get_kerning (hb_codepoint_t first, hb_codepoint_t second) const
{
- 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;
- buffer->unsafe_to_break (idx, skippy_iter.idx + 1);
- }
+ hb_position_t kern = 0;
+ font->get_glyph_kerning_for_direction (first, second,
+ direction,
+ &kern, &kern);
+ return kern;
+ }
- 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;
- buffer->unsafe_to_break (idx, skippy_iter.idx + 1);
- }
+ hb_font_t *font;
+ hb_direction_t direction;
+};
- idx = skippy_iter.idx;
- }
+/* Performs font-assisted kerning. */
+void
+_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
+ !font->has_glyph_h_kerning_func () :
+ !font->has_glyph_v_kerning_func ())
+ return;
+ hb_ot_shape_fallback_kern_driver_t driver (font, buffer);
+ hb_kern_machine_t<hb_ot_shape_fallback_kern_driver_t> machine (driver);
+ machine.kern (font, buffer, plan->kern_mask, false);
}
diff --git a/src/hb-ot-shape-fallback-private.hh b/src/hb-ot-shape-fallback.hh
index e134224df..12f18ed12 100644
--- a/src/hb-ot-shape-fallback-private.hh
+++ b/src/hb-ot-shape-fallback.hh
@@ -24,21 +24,21 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_FALLBACK_PRIVATE_HH
-#define HB_OT_SHAPE_FALLBACK_PRIVATE_HH
+#ifndef HB_OT_SHAPE_FALLBACK_HH
+#define HB_OT_SHAPE_FALLBACK_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape.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_mark_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_mark_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,
@@ -50,4 +50,4 @@ HB_INTERNAL void _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer);
-#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_FALLBACK_HH */
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 358450ee7..a8229a98d 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -24,9 +24,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-normalize-private.hh"
-#include "hb-ot-shape-complex-private.hh"
-#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-normalize.hh"
+#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shape.hh"
/*
@@ -264,15 +264,6 @@ decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned
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)
@@ -294,6 +285,16 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
_hb_buffer_assert_unicode_vars (buffer);
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
+ if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_AUTO)
+ {
+ if (plan->has_gpos_mark)
+ // https://github.com/harfbuzz/harfbuzz/issues/653#issuecomment-423905920
+ //mode = HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
+ mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
+ else
+ mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
+ }
+
const hb_ot_shape_normalize_context_t c = {
plan,
buffer,
@@ -318,105 +319,81 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
/* First round, decompose */
- buffer->clear_output ();
- count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count && buffer->successful;)
+ bool all_simple = true;
{
- unsigned int end;
- for (end = buffer->idx + 1; end < count; end++)
- if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
- break;
+ buffer->clear_output ();
+ count = buffer->len;
+ buffer->idx = 0;
+ do
+ {
+ unsigned int end;
+ for (end = buffer->idx + 1; end < count; end++)
+ if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))))
+ break;
- decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
- }
- buffer->swap_buffers ();
+ if (end < count)
+ end--; /* Leave one base for the marks to cluster with. */
+ /* From idx to end are simple clusters. */
+ if (might_short_circuit)
+ {
+ unsigned int done = font->get_nominal_glyphs (end - buffer->idx,
+ &buffer->cur().codepoint,
+ sizeof (buffer->info[0]),
+ &buffer->cur().glyph_index(),
+ sizeof (buffer->info[0]));
+ buffer->next_glyphs (done);
+ }
+ while (buffer->idx < end && buffer->successful)
+ decompose_current_character (&c, might_short_circuit);
- /* Second round, reorder (inplace) */
+ if (buffer->idx == count || !buffer->successful)
+ break;
- count = buffer->len;
- for (unsigned int i = 0; i < count; i++)
- {
- if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
- continue;
+ all_simple = false;
- unsigned int end;
- for (end = i + 1; end < count; end++)
- if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
- break;
+ /* Find all the marks now. */
+ for (end = buffer->idx + 1; end < count; end++)
+ if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))
+ break;
- /* We are going to do a O(n^2). Only do this if the sequence is short. */
- if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) {
- i = end;
- continue;
+ /* idx to end is one non-simple cluster. */
+ decompose_multi_char_cluster (&c, end, always_short_circuit);
}
-
- buffer->sort (i, end, compare_combining_class);
-
- if (plan->shaper->reorder_marks)
- plan->shaper->reorder_marks (plan, buffer, i, end);
-
- i = end;
+ while (buffer->idx < count && buffer->successful);
+ buffer->swap_buffers ();
}
- if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
- mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
- return;
-
- /* Third round, recompose */
-
- /* As noted in the comment earlier, we don't try to combine
- * ccc=0 chars with their previous Starter. */
+ /* Second round, reorder (inplace) */
- buffer->clear_output ();
- count = buffer->len;
- unsigned int starter = 0;
- buffer->next_glyph ();
- while (buffer->idx < count && buffer->successful)
+ if (!all_simple)
{
- hb_codepoint_t composed, glyph;
- 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())))
+ count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
{
- if (/* If there's anything between the starter and this char, they should have CCC
- * smaller than this character's. */
- (starter == buffer->out_len - 1 ||
- info_cc (buffer->prev()) < info_cc (buffer->cur())) &&
- /* And compose. */
- c.compose (&c,
- buffer->out_info[starter].codepoint,
- buffer->cur().codepoint,
- &composed) &&
- /* And the font has glyph for the composite. */
- font->get_nominal_glyph (composed, &glyph))
- {
- /* Composes. */
- buffer->next_glyph (); /* Copy to out-buffer. */
- if (unlikely (!buffer->successful))
- 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;
- buffer->out_info[starter].glyph_index() = glyph;
- _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
+ if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
+ continue;
+
+ unsigned int end;
+ for (end = i + 1; end < count; end++)
+ if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
+ break;
+ /* We are going to do a O(n^2). Only do this if the sequence is short. */
+ if (end - i > HB_OT_SHAPE_COMPLEX_MAX_COMBINING_MARKS) {
+ i = end;
continue;
}
- }
- /* Blocked, or doesn't compose. */
- buffer->next_glyph ();
+ buffer->sort (i, end, compare_combining_class);
- if (info_cc (buffer->prev()) == 0)
- starter = buffer->out_len - 1;
- }
- buffer->swap_buffers ();
+ if (plan->shaper->reorder_marks)
+ plan->shaper->reorder_marks (plan, buffer, i, end);
+ i = end;
+ }
+ }
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_CGJ)
{
/* For all CGJ, check if it prevented any reordering at all.
@@ -430,4 +407,63 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
_hb_glyph_info_unhide (&buffer->info[i]);
}
}
+
+
+ /* Third round, recompose */
+
+ if (!all_simple &&
+ (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS ||
+ mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT))
+ {
+ /* As noted in the comment earlier, we don't try to combine
+ * ccc=0 chars with their previous Starter. */
+
+ buffer->clear_output ();
+ count = buffer->len;
+ unsigned int starter = 0;
+ buffer->next_glyph ();
+ while (buffer->idx < count && buffer->successful)
+ {
+ hb_codepoint_t composed, glyph;
+ 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 (/* If there's anything between the starter and this char, they should have CCC
+ * smaller than this character's. */
+ (starter == buffer->out_len - 1 ||
+ info_cc (buffer->prev()) < info_cc (buffer->cur())) &&
+ /* And compose. */
+ c.compose (&c,
+ buffer->out_info[starter].codepoint,
+ buffer->cur().codepoint,
+ &composed) &&
+ /* And the font has glyph for the composite. */
+ font->get_nominal_glyph (composed, &glyph))
+ {
+ /* Composes. */
+ buffer->next_glyph (); /* Copy to out-buffer. */
+ if (unlikely (!buffer->successful))
+ 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;
+ buffer->out_info[starter].glyph_index() = glyph;
+ _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer);
+
+ continue;
+ }
+ }
+
+ /* Blocked, or doesn't compose. */
+ buffer->next_glyph ();
+
+ if (info_cc (buffer->prev()) == 0)
+ starter = buffer->out_len - 1;
+ }
+ buffer->swap_buffers ();
+ }
}
diff --git a/src/hb-ot-shape-normalize-private.hh b/src/hb-ot-shape-normalize.hh
index c744e2645..04f1a8009 100644
--- a/src/hb-ot-shape-normalize-private.hh
+++ b/src/hb-ot-shape-normalize.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_NORMALIZE_PRIVATE_HH
-#define HB_OT_SHAPE_NORMALIZE_PRIVATE_HH
+#ifndef HB_OT_SHAPE_NORMALIZE_HH
+#define HB_OT_SHAPE_NORMALIZE_HH
-#include "hb-private.hh"
+#include "hb.hh"
/* buffer var allocations, used during the normalization process */
@@ -38,10 +38,11 @@ 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_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* Never composes base-to-base */
+ 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_OT_SHAPE_NORMALIZATION_MODE_AUTO, /* See hb-ot-shape-normalize.cc for logic. */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_AUTO
};
HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
@@ -66,4 +67,4 @@ struct hb_ot_shape_normalize_context_t
};
-#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_NORMALIZE_HH */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 71632b563..a5538871b 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -27,41 +27,120 @@
*/
#define HB_SHAPER ot
-#define hb_ot_face_data_t hb_ot_layout_t
#define hb_ot_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-ot-layout-private.hh"
-#include "hb-unicode-private.hh"
-#include "hb-set-private.hh"
-
-#include "hb-ot-layout-gsubgpos-private.hh"
-#include "hb-aat-layout-private.hh"
-
-static hb_tag_t common_features[] = {
- HB_TAG('c','c','m','p'),
- HB_TAG('l','o','c','l'),
- HB_TAG('m','a','r','k'),
- HB_TAG('m','k','m','k'),
- HB_TAG('r','l','i','g'),
-};
+#include "hb-shaper-impl.hh"
+
+#include "hb-ot-shape.hh"
+#include "hb-ot-shape-complex.hh"
+#include "hb-ot-shape-fallback.hh"
+#include "hb-ot-shape-normalize.hh"
+
+#include "hb-ot-face.hh"
+
+#include "hb-set.hh"
+
+#include "hb-aat-layout.hh"
+
+static bool
+_hb_apply_morx (hb_face_t *face)
+{
+ if (hb_options ().aat &&
+ hb_aat_layout_has_substitution (face))
+ return true;
+
+ return !hb_ot_layout_has_substitution (face) &&
+ hb_aat_layout_has_substitution (face);
+}
-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'),
+void
+hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
+ const int *coords,
+ unsigned int num_coords)
+{
+ plan.props = props;
+ plan.shaper = shaper;
+ map.compile (plan.map, coords, num_coords);
+
+ 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.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
+ hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
+ HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n');
+ plan.kern_mask = plan.map.get_mask (kern_tag);
+
+ plan.requested_kerning = !!plan.kern_mask;
+ bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX;
+ bool disable_gpos = plan.shaper->gpos_tag &&
+ plan.shaper->gpos_tag != plan.map.chosen_script[1];
+
+ /*
+ * Decide who provides glyph classes. GDEF or Unicode.
+ */
+
+ if (!hb_ot_layout_has_glyph_classes (face))
+ plan.fallback_glyph_classes = true;
+
+ /*
+ * Decide who does substitutions. GSUB, morx, or fallback.
+ */
+
+ plan.apply_morx = _hb_apply_morx (face);
+
+ /*
+ * Decide who does positioning. GPOS, kerx, kern, or fallback.
+ */
+
+ if (hb_options ().aat && hb_aat_layout_has_positioning (face))
+ plan.apply_kerx = true;
+ else if (!disable_gpos && hb_ot_layout_has_positioning (face))
+ plan.apply_gpos = true;
+ else if (hb_aat_layout_has_positioning (face))
+ plan.apply_kerx = true;
+
+ if (plan.requested_kerning && !plan.apply_kerx && !has_gpos_kern)
+ {
+ /* Apparently Apple applies kerx if GPOS kern was not applied. */
+ if (hb_aat_layout_has_positioning (face))
+ plan.apply_kerx = true;
+ if (hb_ot_layout_has_kerning (face))
+ plan.apply_kern = true;
+ else
+ plan.fallback_kerning = true;
+ }
+
+ plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
+ if (!plan.apply_gpos && !plan.apply_kerx)
+ plan.fallback_mark_positioning = true;
+
+ /* Currently we always apply trak. */
+ plan.apply_trak = hb_aat_layout_has_tracking (face);
+}
+
+
+static const hb_ot_map_feature_t
+common_features[] =
+{
+ {HB_TAG('c','c','m','p'), F_GLOBAL},
+ {HB_TAG('l','o','c','l'), F_GLOBAL},
+ {HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('m','k','m','k'), F_GLOBAL_MANUAL_JOINERS},
+ {HB_TAG('r','l','i','g'), F_GLOBAL},
};
+static const hb_ot_map_feature_t
+horizontal_features[] =
+{
+ {HB_TAG('c','a','l','t'), F_GLOBAL},
+ {HB_TAG('c','l','i','g'), F_GLOBAL},
+ {HB_TAG('c','u','r','s'), F_GLOBAL},
+ {HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK},
+ {HB_TAG('l','i','g','a'), F_GLOBAL},
+ {HB_TAG('r','c','l','t'), F_GLOBAL},
+};
static void
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
@@ -71,17 +150,17 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
{
hb_ot_map_builder_t *map = &planner->map;
- map->add_global_bool_feature (HB_TAG('r','v','r','n'));
+ map->enable_feature (HB_TAG('r','v','r','n'));
map->add_gsub_pause (nullptr);
switch (props->direction) {
case HB_DIRECTION_LTR:
- map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
- map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
+ map->enable_feature (HB_TAG ('l','t','r','a'));
+ map->enable_feature (HB_TAG ('l','t','r','m'));
break;
case HB_DIRECTION_RTL:
- map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
- map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
+ map->enable_feature (HB_TAG ('r','t','l','a'));
+ map->add_feature (HB_TAG ('r','t','l','m'));
break;
case HB_DIRECTION_TTB:
case HB_DIRECTION_BTT:
@@ -90,38 +169,46 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
break;
}
- 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);
+ /* Automatic fractions. */
+ map->add_feature (HB_TAG ('f','r','a','c'));
+ map->add_feature (HB_TAG ('n','u','m','r'));
+ map->add_feature (HB_TAG ('d','n','o','m'));
+
+ /* Random! */
+ map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE);
+
+ map->enable_feature (HB_TAG('H','A','R','F'));
if (planner->shaper->collect_features)
planner->shaper->collect_features (planner);
+ map->enable_feature (HB_TAG('B','U','Z','Z'));
+
for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
- map->add_global_bool_feature (common_features[i]);
+ map->add_feature (common_features[i]);
if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
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));
+ map->add_feature (horizontal_features[i]);
else
{
/* We really want to find a 'vert' feature if there's any in the font, no
* matter which script/langsys it is listed (or not) under.
* See various bugs referenced from:
* https://github.com/harfbuzz/harfbuzz/issues/63 */
- map->add_feature (HB_TAG ('v','e','r','t'), 1, F_GLOBAL | F_GLOBAL_SEARCH);
+ map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH);
}
if (planner->shaper->override_features)
planner->shaper->override_features (planner);
- for (unsigned int i = 0; i < num_user_features; i++) {
+ for (unsigned int i = 0; i < num_user_features; i++)
+ {
const hb_feature_t *feature = &user_features[i];
- map->add_feature (feature->tag, feature->value,
- (feature->start == 0 && feature->end == (unsigned int) -1) ?
- F_GLOBAL : F_NONE);
+ map->add_feature (feature->tag,
+ (feature->start == HB_FEATURE_GLOBAL_START &&
+ feature->end == HB_FEATURE_GLOBAL_END) ? F_GLOBAL : F_NONE,
+ feature->value);
}
}
@@ -135,13 +222,13 @@ HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
hb_ot_face_data_t *
_hb_ot_shaper_face_data_create (hb_face_t *face)
{
- return _hb_ot_layout_create (face);
+ return _hb_ot_face_data_create (face);
}
void
_hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data)
{
- _hb_ot_layout_destroy (data);
+ _hb_ot_face_data_destroy (data);
}
@@ -184,7 +271,12 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
hb_ot_shape_planner_t planner (shape_plan);
- planner.shaper = hb_ot_shape_complex_categorize (&planner);
+ /* Ugly that we have to do this here...
+ * If we are going to apply morx, choose default shaper. */
+ if (_hb_apply_morx (planner.face))
+ planner.shaper = &_hb_ot_complex_shaper_default;
+ else
+ planner.shaper = hb_ot_shape_complex_categorize (&planner);
hb_ot_shape_collect_features (&planner, &shape_plan->props,
user_features, num_user_features);
@@ -229,8 +321,6 @@ struct hb_ot_shape_context_t
unsigned int num_user_features;
/* Transient stuff */
- bool fallback_positioning;
- bool fallback_glyph_classes;
hb_direction_t target_direction;
};
@@ -244,10 +334,39 @@ struct hb_ot_shape_context_t
static void
hb_set_unicode_props (hb_buffer_t *buffer)
{
+ /* Implement enough of Unicode Graphemes here that shaping
+ * in reverse-direction wouldn't break graphemes. Namely,
+ * we mark all marks and ZWJ and ZWJ,Extended_Pictographic
+ * sequences as continuations. The foreach_grapheme()
+ * macro uses this bit.
+ *
+ * https://www.unicode.org/reports/tr29/#Regex_Definitions
+ */
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 (&info[i], buffer);
+
+ /* Marks are already set as continuation by the above line.
+ * Handle Emoji_Modifier and ZWJ-continuation. */
+ if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
+ hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
+ {
+ _hb_glyph_info_set_continuation (&info[i]);
+ }
+ else if (unlikely (_hb_glyph_info_is_zwj (&info[i])))
+ {
+ _hb_glyph_info_set_continuation (&info[i]);
+ if (i + 1 < count &&
+ _hb_unicode_is_emoji_Extended_Pictographic (info[i + 1].codepoint))
+ {
+ i++;
+ _hb_glyph_info_set_unicode_props (&info[i], buffer);
+ _hb_glyph_info_set_continuation (&info[i]);
+ }
+ }
+ }
}
static void
@@ -255,8 +374,7 @@ 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)
+ !_hb_glyph_info_is_unicode_mark (&buffer->info[0]))
return;
if (!font->has_glyph (0x25CCu))
@@ -285,26 +403,12 @@ hb_form_clusters (hb_buffer_t *buffer)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
return;
- /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
- unsigned int base = 0;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 1; i < count; i++)
- {
- if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
- !_hb_glyph_info_is_joiner (&info[i])))
- {
- if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
- buffer->merge_clusters (base, i);
- else
- buffer->unsafe_to_break (base, i);
- base = i;
- }
- }
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
- buffer->merge_clusters (base, count);
+ foreach_grapheme (buffer, start, end)
+ buffer->merge_clusters (start, end);
else
- buffer->unsafe_to_break (base, count);
+ foreach_grapheme (buffer, start, end)
+ buffer->unsafe_to_break (start, end);
}
static void
@@ -322,25 +426,17 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
(HB_DIRECTION_IS_VERTICAL (direction) &&
direction != HB_DIRECTION_TTB))
{
- /* Same loop as hb_form_clusters().
- * Since form_clusters() merged clusters already, we don't merge. */
- unsigned int base = 0;
- unsigned int count = buffer->len;
- hb_glyph_info_t *info = buffer->info;
- for (unsigned int i = 1; i < count; i++)
- {
- if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
- {
- if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
- buffer->merge_clusters (base, i);
- buffer->reverse_range (base, i);
- base = i;
- }
- }
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS)
- buffer->merge_clusters (base, count);
- buffer->reverse_range (base, count);
+ foreach_grapheme (buffer, start, end)
+ {
+ buffer->merge_clusters (start, end);
+ buffer->reverse_range (start, end);
+ }
+ else
+ foreach_grapheme (buffer, start, end)
+ /* form_clusters() merged clusters already, we don't merge. */
+ buffer->reverse_range (start, end);
buffer->reverse ();
@@ -352,7 +448,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
/* Substitute */
static inline void
-hb_ot_mirror_chars (hb_ot_shape_context_t *c)
+hb_ot_mirror_chars (const hb_ot_shape_context_t *c)
{
if (HB_DIRECTION_IS_FORWARD (c->target_direction))
return;
@@ -373,7 +469,7 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
+hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
{
if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) ||
!c->plan->has_frac)
@@ -423,7 +519,7 @@ hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
+hb_ot_shape_initialize_masks (const hb_ot_shape_context_t *c)
{
hb_ot_map_t *map = &c->plan->map;
hb_buffer_t *buffer = c->buffer;
@@ -433,7 +529,7 @@ hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
+hb_ot_shape_setup_masks (const hb_ot_shape_context_t *c)
{
hb_ot_map_t *map = &c->plan->map;
hb_buffer_t *buffer = c->buffer;
@@ -455,7 +551,7 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
}
static void
-hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
+hb_ot_zero_width_default_ignorables (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
@@ -474,7 +570,7 @@ hb_ot_zero_width_default_ignorables (hb_ot_shape_context_t *c)
}
static void
-hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
+hb_ot_hide_default_ignorables (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
@@ -485,34 +581,24 @@ hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
- unsigned int i = 0;
- for (i = 0; i < count; i++)
- {
- if (unlikely (_hb_glyph_info_is_default_ignorable (&info[i])))
- break;
- }
-
- /* No default-ignorables found; return. */
- if (i == count)
- return;
- hb_codepoint_t space;
+ hb_codepoint_t invisible = c->buffer->invisible;
if (!(buffer->flags & HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) &&
- c->font->get_nominal_glyph (' ', &space))
+ (invisible || c->font->get_nominal_glyph (' ', &invisible)))
{
- /* Replace default-ignorables with a zero-advance space glyph. */
- for (/*continue*/; i < count; i++)
+ /* Replace default-ignorables with a zero-advance invisible glyph. */
+ for (unsigned int i = 0; i < count; i++)
{
if (_hb_glyph_info_is_default_ignorable (&info[i]))
- info[i].codepoint = space;
+ info[i].codepoint = invisible;
}
}
else
{
/* Merge clusters and delete default-ignorables.
* NOTE! We can't use out-buffer as we have positioning data. */
- unsigned int j = i;
- for (; i < count; i++)
+ unsigned int j = 0;
+ for (unsigned int i = 0; i < count; i++)
{
if (_hb_glyph_info_is_default_ignorable (&info[i]))
{
@@ -567,7 +653,7 @@ hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
}
static inline void
-hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
+hb_synthesize_glyph_classes (const hb_ot_shape_context_t *c)
{
unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
@@ -593,7 +679,7 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_substitute_default (hb_ot_shape_context_t *c)
+hb_ot_substitute_default (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
@@ -606,8 +692,8 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
hb_ot_shape_setup_masks (c);
/* This is unfortunate to go here, but necessary... */
- if (c->fallback_positioning)
- _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
+ if (c->plan->fallback_mark_positioning)
+ _hb_ot_shape_fallback_mark_position_recategorize_marks (c->plan, c->font, buffer);
hb_ot_map_glyphs_fast (buffer);
@@ -615,23 +701,23 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_substitute_complex (hb_ot_shape_context_t *c)
+hb_ot_substitute_complex (const hb_ot_shape_context_t *c)
{
hb_buffer_t *buffer = c->buffer;
hb_ot_layout_substitute_start (c->font, buffer);
- if (!hb_ot_layout_has_glyph_classes (c->face))
+ if (c->plan->fallback_glyph_classes)
hb_synthesize_glyph_classes (c);
- c->plan->substitute (c->font, buffer);
-
- if (0) /* XXX Call morx instead. */
- hb_aat_layout_substitute (c->font, c->buffer);
+ if (unlikely (c->plan->apply_morx))
+ hb_aat_layout_substitute (c->plan, c->font, c->buffer);
+ else
+ c->plan->substitute (c->font, buffer);
}
static inline void
-hb_ot_substitute (hb_ot_shape_context_t *c)
+hb_ot_substitute (const hb_ot_shape_context_t *c)
{
hb_ot_substitute_default (c);
@@ -671,7 +757,7 @@ zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
}
static inline void
-hb_ot_position_default (hb_ot_shape_context_t *c)
+hb_ot_position_default (const hb_ot_shape_context_t *c)
{
hb_direction_t direction = c->buffer->props.direction;
unsigned int count = c->buffer->len;
@@ -705,7 +791,7 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_position_complex (hb_ot_shape_context_t *c)
+hb_ot_position_complex (const hb_ot_shape_context_t *c)
{
unsigned int count = c->buffer->len;
hb_glyph_info_t *info = c->buffer->info;
@@ -720,7 +806,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
* If fallback positinoing happens or GPOS is present, we don't
* care.
*/
- bool adjust_offsets_when_zeroing = c->fallback_positioning &&
+ bool adjust_offsets_when_zeroing = c->plan->fallback_mark_positioning &&
!c->plan->shaper->fallback_position &&
HB_DIRECTION_IS_FORWARD (c->buffer->props.direction);
@@ -735,32 +821,39 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
hb_ot_layout_position_start (c->font, c->buffer);
- 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;
-
- default:
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
- break;
- }
+ if (!c->plan->apply_kerx)
+ 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;
+
+ default:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+ break;
+ }
- if (likely (!c->fallback_positioning))
+ if (c->plan->apply_gpos)
c->plan->position (c->font, c->buffer);
+ else if (c->plan->apply_kerx)
+ hb_aat_layout_position (c->plan, c->font, c->buffer);
- switch (c->plan->shaper->zero_width_marks)
- {
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
- zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
- break;
+ if (c->plan->apply_trak)
+ hb_aat_layout_track (c->plan, c->font, c->buffer);
- default:
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
- case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
- break;
- }
+ if (!c->plan->apply_kerx)
+ switch (c->plan->shaper->zero_width_marks)
+ {
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+ zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
+ break;
+
+ default:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
+ break;
+ }
/* Finishing off GPOS has to follow a certain order. */
hb_ot_layout_position_finish_advances (c->font, c->buffer);
@@ -776,7 +869,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
}
static inline void
-hb_ot_position (hb_ot_shape_context_t *c)
+hb_ot_position (const hb_ot_shape_context_t *c)
{
c->buffer->clear_positions ();
@@ -784,20 +877,20 @@ hb_ot_position (hb_ot_shape_context_t *c)
hb_ot_position_complex (c);
- if (c->fallback_positioning && c->plan->shaper->fallback_position)
- _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
+ if (c->plan->fallback_mark_positioning && c->plan->shaper->fallback_position)
+ _hb_ot_shape_fallback_mark_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 (c->fallback_positioning)
+ if (c->plan->apply_kern)
+ hb_ot_layout_kern (c->font, c->buffer, c->plan->kern_mask);
+ else if (c->plan->fallback_kerning)
_hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
_hb_buffer_deallocate_gsubgpos_vars (c->buffer);
-
- //hb_aat_layout_position (c->font, c->buffer);
}
static inline void
@@ -844,11 +937,6 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c)
(unsigned) HB_BUFFER_MAX_OPS_MIN);
}
- bool disable_otl = c->plan->shaper->disable_otl && c->plan->shaper->disable_otl (c->plan);
- //c->fallback_substitute = disable_otl || !hb_ot_layout_has_substitution (c->face);
- c->fallback_positioning = disable_otl || !hb_ot_layout_has_positioning (c->face);
- c->fallback_glyph_classes = disable_otl || !hb_ot_layout_has_glyph_classes (c->face);
-
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape.hh
index d6898263f..c9c0d3e09 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape.hh
@@ -24,13 +24,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_OT_SHAPE_PRIVATE_HH
-#define HB_OT_SHAPE_PRIVATE_HH
+#ifndef HB_OT_SHAPE_HH
+#define HB_OT_SHAPE_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-ot-map-private.hh"
-#include "hb-ot-layout-private.hh"
+#include "hb-ot-map.hh"
+#include "hb-shape-plan.hh"
@@ -42,9 +42,20 @@ struct 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;
+
+ bool requested_kerning : 1;
+ bool has_frac : 1;
+ bool has_gpos_mark : 1;
+ bool fallback_glyph_classes : 1;
+ bool fallback_kerning : 1;
+ bool fallback_mark_positioning : 1;
+
+ bool apply_gpos : 1;
+ bool apply_kerx : 1;
+ bool apply_kern : 1;
+ bool apply_morx : 1;
+ bool apply_trak : 1;
+
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
{
@@ -83,30 +94,13 @@ struct hb_ot_shape_planner_t
shaper (nullptr),
map (face, &props) {}
- inline void compile (hb_ot_shape_plan_t &plan,
- const int *coords,
- unsigned int num_coords)
- {
- plan.props = props;
- plan.shaper = shaper;
- map.compile (plan.map, coords, num_coords);
-
- 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'));
- }
+ HB_INTERNAL void compile (hb_ot_shape_plan_t &plan,
+ const int *coords,
+ unsigned int num_coords);
private:
HB_DISALLOW_COPY_AND_ASSIGN (hb_ot_shape_planner_t);
};
-#endif /* HB_OT_SHAPE_PRIVATE_HH */
+#endif /* HB_OT_SHAPE_HH */
diff --git a/src/hb-ot-tag-table.hh b/src/hb-ot-tag-table.hh
new file mode 100644
index 000000000..b7090a0a7
--- /dev/null
+++ b/src/hb-ot-tag-table.hh
@@ -0,0 +1,2064 @@
+/* == Start of generated table == */
+/*
+ * The following table is generated by running:
+ *
+ * ./gen-tag-table.py languagetags language-subtag-registry
+ *
+ * on files with these headers:
+ *
+ * <meta name="updated_at" content="2018-09-07 07:45 PM" />
+ * File-Date: 2018-08-08
+ */
+
+#ifndef HB_OT_TAG_TABLE_HH
+#define HB_OT_TAG_TABLE_HH
+
+static const LangTag ot_languages[] = {
+ {"aa", {HB_TAG('A','F','R',' ')}}, /* Afar */
+ {"aae", {HB_TAG('S','Q','I',' ')}}, /* Arbëreshë Albanian -> Albanian */
+ {"aao", {HB_TAG('A','R','A',' ')}}, /* Algerian Saharan Arabic -> Arabic */
+ {"aat", {HB_TAG('S','Q','I',' ')}}, /* Arvanitika Albanian -> Albanian */
+ {"ab", {HB_TAG('A','B','K',' ')}}, /* Abkhazian */
+ {"abh", {HB_TAG('A','R','A',' ')}}, /* Tajiki Arabic -> Arabic */
+ {"abq", {HB_TAG('A','B','A',' ')}}, /* Abaza */
+ {"abv", {HB_TAG('A','R','A',' ')}}, /* Baharna Arabic -> Arabic */
+ {"acf", {HB_TAG('F','A','N',' ')}}, /* Saint Lucian Creole French -> French Antillean */
+ {"ach", {HB_TAG('A','C','H',' ')}}, /* Acoli -> Acholi */
+ {"acm", {HB_TAG('A','R','A',' ')}}, /* Mesopotamian Arabic -> Arabic */
+ {"acq", {HB_TAG('A','R','A',' ')}}, /* Ta'izzi-Adeni Arabic -> Arabic */
+ {"acr", {HB_TAG('A','C','R',' ')}}, /* Achi */
+ {"acw", {HB_TAG('A','R','A',' ')}}, /* Hijazi Arabic -> Arabic */
+ {"acx", {HB_TAG('A','R','A',' ')}}, /* Omani Arabic -> Arabic */
+ {"acy", {HB_TAG('A','R','A',' ')}}, /* Cypriot Arabic -> Arabic */
+ {"ada", {HB_TAG('D','N','G',' ')}}, /* Adangme -> Dangme */
+ {"adf", {HB_TAG('A','R','A',' ')}}, /* Dhofari Arabic -> Arabic */
+ {"adp", {HB_TAG('D','Z','N',' ')}}, /* Adap (retired code) -> Dzongkha */
+ {"ady", {HB_TAG('A','D','Y',' ')}}, /* Adyghe */
+ {"aeb", {HB_TAG('A','R','A',' ')}}, /* Tunisian Arabic -> Arabic */
+ {"aec", {HB_TAG('A','R','A',' ')}}, /* Saidi Arabic -> Arabic */
+ {"af", {HB_TAG('A','F','K',' ')}}, /* Afrikaans */
+ {"afb", {HB_TAG('A','R','A',' ')}}, /* Gulf Arabic -> Arabic */
+ {"ahg", {HB_TAG('A','G','W',' ')}}, /* Qimant -> Agaw */
+ {"aht", {HB_TAG('A','T','H',' ')}}, /* Ahtena -> Athapaskan */
+ {"aii", {HB_TAG('S','W','A',' '), /* Assyrian Neo-Aramaic -> Swadaya Aramaic */
+ HB_TAG('S','Y','R',' ')}}, /* Assyrian Neo-Aramaic -> Syriac */
+ {"aio", {HB_TAG('A','I','O',' ')}}, /* Aiton */
+ {"aiw", {HB_TAG('A','R','I',' ')}}, /* Aari */
+ {"ajp", {HB_TAG('A','R','A',' ')}}, /* South Levantine Arabic -> Arabic */
+ {"ak", {HB_TAG('A','K','A',' '), /* Akan [macrolanguage] */
+ HB_TAG('T','W','I',' ')}}, /* Akan [macrolanguage] -> Twi */
+ {"aln", {HB_TAG('S','Q','I',' ')}}, /* Gheg Albanian -> Albanian */
+ {"als", {HB_TAG('S','Q','I',' ')}}, /* Tosk Albanian -> Albanian */
+ {"alt", {HB_TAG('A','L','T',' ')}}, /* Southern Altai -> Altai */
+ {"am", {HB_TAG('A','M','H',' ')}}, /* Amharic */
+ {"amf", {HB_TAG('H','B','N',' ')}}, /* Hamer-Banna -> Hammer-Banna */
+ {"amw", {HB_TAG('S','Y','R',' ')}}, /* Western Neo-Aramaic -> Syriac */
+ {"an", {HB_TAG('A','R','G',' ')}}, /* Aragonese */
+ {"ang", {HB_TAG('A','N','G',' ')}}, /* Old English (ca. 450-1100) -> Anglo-Saxon */
+ {"apc", {HB_TAG('A','R','A',' ')}}, /* North Levantine Arabic -> Arabic */
+ {"apd", {HB_TAG('A','R','A',' ')}}, /* Sudanese Arabic -> Arabic */
+ {"apj", {HB_TAG('A','T','H',' ')}}, /* Jicarilla Apache -> Athapaskan */
+ {"apk", {HB_TAG('A','T','H',' ')}}, /* Kiowa Apache -> Athapaskan */
+ {"apl", {HB_TAG('A','T','H',' ')}}, /* Lipan Apache -> Athapaskan */
+ {"apm", {HB_TAG('A','T','H',' ')}}, /* Mescalero-Chiricahua Apache -> Athapaskan */
+ {"apw", {HB_TAG('A','T','H',' ')}}, /* Western Apache -> Athapaskan */
+ {"ar", {HB_TAG('A','R','A',' ')}}, /* Arabic [macrolanguage] */
+ {"arb", {HB_TAG('A','R','A',' ')}}, /* Standard Arabic -> Arabic */
+ {"arn", {HB_TAG('M','A','P',' ')}}, /* Mapudungun */
+ {"arq", {HB_TAG('A','R','A',' ')}}, /* Algerian Arabic -> Arabic */
+ {"ars", {HB_TAG('A','R','A',' ')}}, /* Najdi Arabic -> Arabic */
+ {"ary", {HB_TAG('M','O','R',' ')}}, /* Moroccan Arabic -> Moroccan */
+ {"arz", {HB_TAG('A','R','A',' ')}}, /* Egyptian Arabic -> Arabic */
+ {"as", {HB_TAG('A','S','M',' ')}}, /* Assamese */
+ {"ast", {HB_TAG('A','S','T',' ')}}, /* Asturian */
+ {"ath", {HB_TAG('A','T','H',' ')}}, /* Athapascan [family] -> Athapaskan */
+ {"atj", {HB_TAG('R','C','R',' ')}}, /* Atikamekw -> R-Cree */
+ {"atv", {HB_TAG('A','L','T',' ')}}, /* Northern Altai -> Altai */
+ {"auz", {HB_TAG('A','R','A',' ')}}, /* Uzbeki Arabic -> Arabic */
+ {"av", {HB_TAG('A','V','R',' ')}}, /* Avaric -> Avar */
+ {"avl", {HB_TAG('A','R','A',' ')}}, /* Eastern Egyptian Bedawi Arabic -> Arabic */
+ {"awa", {HB_TAG('A','W','A',' ')}}, /* Awadhi */
+ {"ay", {HB_TAG('A','Y','M',' ')}}, /* Aymara [macrolanguage] */
+ {"ayc", {HB_TAG('A','Y','M',' ')}}, /* Southern Aymara -> Aymara */
+ {"ayh", {HB_TAG('A','R','A',' ')}}, /* Hadrami Arabic -> Arabic */
+ {"ayl", {HB_TAG('A','R','A',' ')}}, /* Libyan Arabic -> Arabic */
+ {"ayn", {HB_TAG('A','R','A',' ')}}, /* Sanaani Arabic -> Arabic */
+ {"ayp", {HB_TAG('A','R','A',' ')}}, /* North Mesopotamian Arabic -> Arabic */
+ {"ayr", {HB_TAG('A','Y','M',' ')}}, /* Central Aymara -> Aymara */
+ {"az", {HB_TAG('A','Z','E',' ')}}, /* Azerbaijani [macrolanguage] */
+ {"azb", {HB_TAG('A','Z','B',' ')}}, /* South Azerbaijani -> Torki */
+ {"azj", {HB_TAG('A','Z','E',' ')}}, /* North Azerbaijani -> Azerbaijani */
+ {"ba", {HB_TAG('B','S','H',' ')}}, /* Bashkir */
+ {"bad", {HB_TAG('B','A','D','0')}}, /* Banda [family] */
+ {"bai", {HB_TAG('B','M','L',' ')}}, /* Bamileke [family] */
+ {"bal", {HB_TAG('B','L','I',' ')}}, /* Baluchi [macrolanguage] */
+ {"ban", {HB_TAG('B','A','N',' ')}}, /* Balinese */
+ {"bar", {HB_TAG('B','A','R',' ')}}, /* Bavarian */
+ {"bbc", {HB_TAG('B','B','C',' ')}}, /* Batak Toba */
+ {"bbz", {HB_TAG('A','R','A',' ')}}, /* Babalia Creole Arabic -> Arabic */
+ {"bcc", {HB_TAG('B','L','I',' ')}}, /* Southern Balochi -> Baluchi */
+ {"bci", {HB_TAG('B','A','U',' ')}}, /* Baoulé -> Baulé */
+ {"bcl", {HB_TAG('B','I','K',' ')}}, /* Central Bikol -> Bikol */
+ {"bcq", {HB_TAG('B','C','H',' ')}}, /* Bench */
+ {"bcr", {HB_TAG('A','T','H',' ')}}, /* Babine -> Athapaskan */
+ {"bdy", {HB_TAG('B','D','Y',' ')}}, /* Bandjalang */
+ {"be", {HB_TAG('B','E','L',' ')}}, /* Belarusian -> Belarussian */
+ {"bea", {HB_TAG('A','T','H',' ')}}, /* Beaver -> Athapaskan */
+ {"beb", {HB_TAG('B','T','I',' ')}}, /* Bebele -> Beti */
+ {"bem", {HB_TAG('B','E','M',' ')}}, /* Bemba (Zambia) */
+ {"ber", {HB_TAG('B','B','R',' ')}}, /* Berber [family] */
+ {"bfq", {HB_TAG('B','A','D',' ')}}, /* Badaga */
+ {"bft", {HB_TAG('B','L','T',' ')}}, /* Balti */
+ {"bfu", {HB_TAG('L','A','H',' ')}}, /* Gahri -> Lahuli */
+ {"bfy", {HB_TAG('B','A','G',' ')}}, /* Bagheli -> Baghelkhandi */
+ {"bg", {HB_TAG('B','G','R',' ')}}, /* Bulgarian */
+ {"bgc", {HB_TAG('B','G','C',' ')}}, /* Haryanvi */
+ {"bgn", {HB_TAG('B','L','I',' ')}}, /* Western Balochi -> Baluchi */
+ {"bgp", {HB_TAG('B','L','I',' ')}}, /* Eastern Balochi -> Baluchi */
+ {"bgq", {HB_TAG('B','G','Q',' ')}}, /* Bagri */
+ {"bgr", {HB_TAG('Q','I','N',' ')}}, /* Bawm Chin -> Chin */
+ {"bhb", {HB_TAG('B','H','I',' ')}}, /* Bhili */
+ {"bhi", {HB_TAG('B','H','I',' ')}}, /* Bhilali -> Bhili */
+ {"bhk", {HB_TAG('B','I','K',' ')}}, /* Albay Bicolano (retired code) -> Bikol */
+ {"bho", {HB_TAG('B','H','O',' ')}}, /* Bhojpuri */
+ {"bhr", {HB_TAG('M','L','G',' ')}}, /* Bara Malagasy -> Malagasy */
+ {"bi", {HB_TAG('B','I','S',' ')}}, /* Bislama */
+ {"bik", {HB_TAG('B','I','K',' ')}}, /* Bikol [macrolanguage] */
+ {"bin", {HB_TAG('E','D','O',' ')}}, /* Edo */
+ {"bjj", {HB_TAG('B','J','J',' ')}}, /* Kanauji */
+ {"bjn", {HB_TAG('M','L','Y',' ')}}, /* Banjar -> Malay */
+ {"bjq", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */
+ {"bjt", {HB_TAG('B','L','N',' ')}}, /* Balanta-Ganja -> Balante */
+ {"bla", {HB_TAG('B','K','F',' ')}}, /* Siksika -> Blackfoot */
+ {"ble", {HB_TAG('B','L','N',' ')}}, /* Balanta-Kentohe -> Balante */
+ {"blk", {HB_TAG('B','L','K',' ')}}, /* Pa'o Karen */
+ {"bln", {HB_TAG('B','I','K',' ')}}, /* Southern Catanduanes Bikol -> Bikol */
+ {"bm", {HB_TAG('B','M','B',' ')}}, /* Bambara (Bamanankan) */
+ {"bmm", {HB_TAG('M','L','G',' ')}}, /* Northern Betsimisaraka Malagasy -> Malagasy */
+ {"bn", {HB_TAG('B','E','N',' ')}}, /* Bengali */
+ {"bo", {HB_TAG('T','I','B',' ')}}, /* Tibetan */
+ {"bpy", {HB_TAG('B','P','Y',' ')}}, /* Bishnupriya -> Bishnupriya Manipuri */
+ {"bqi", {HB_TAG('L','R','C',' ')}}, /* Bakhtiari -> Luri */
+ {"br", {HB_TAG('B','R','E',' ')}}, /* Breton */
+ {"bra", {HB_TAG('B','R','I',' ')}}, /* Braj -> Braj Bhasha */
+ {"brh", {HB_TAG('B','R','H',' ')}}, /* Brahui */
+ {"brx", {HB_TAG('B','R','X',' ')}}, /* Bodo (India) */
+ {"bs", {HB_TAG('B','O','S',' ')}}, /* Bosnian */
+ {"bsk", {HB_TAG('B','S','K',' ')}}, /* Burushaski */
+ {"btb", {HB_TAG('B','T','I',' ')}}, /* Beti (Cameroon) (retired code) */
+ {"btj", {HB_TAG('M','L','Y',' ')}}, /* Bacanese Malay -> Malay */
+ {"bto", {HB_TAG('B','I','K',' ')}}, /* Rinconada Bikol -> Bikol */
+ {"bts", {HB_TAG('B','T','S',' ')}}, /* Batak Simalungun */
+ {"bug", {HB_TAG('B','U','G',' ')}}, /* Buginese -> Bugis */
+ {"bum", {HB_TAG('B','T','I',' ')}}, /* Bulu (Cameroon) -> Beti */
+ {"bve", {HB_TAG('M','L','Y',' ')}}, /* Berau Malay -> Malay */
+ {"bvu", {HB_TAG('M','L','Y',' ')}}, /* Bukit Malay -> Malay */
+ {"bxk", {HB_TAG('L','U','H',' ')}}, /* Bukusu -> Luyia */
+ {"bxp", {HB_TAG('B','T','I',' ')}}, /* Bebil -> Beti */
+ {"bxr", {HB_TAG('R','B','U',' ')}}, /* Russia Buriat -> Russian Buriat */
+ {"byn", {HB_TAG('B','I','L',' ')}}, /* Bilin -> Bilen */
+ {"byv", {HB_TAG('B','Y','V',' ')}}, /* Medumba */
+ {"bzc", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy -> Malagasy */
+ {"ca", {HB_TAG('C','A','T',' ')}}, /* Catalan */
+ {"caf", {HB_TAG('C','R','R',' '), /* Southern Carrier -> Carrier */
+ HB_TAG('A','T','H',' ')}}, /* Southern Carrier -> Athapaskan */
+ {"cak", {HB_TAG('C','A','K',' ')}}, /* Kaqchikel */
+ {"cbk", {HB_TAG('C','B','K',' ')}}, /* Chavacano -> Zamboanga Chavacano */
+ {"cbl", {HB_TAG('Q','I','N',' ')}}, /* Bualkhaw Chin -> Chin */
+ {"cco", {HB_TAG('C','C','H','N')}}, /* Comaltepec Chinantec -> Chinantec */
+ {"ccq", {HB_TAG('A','R','K',' ')}}, /* Chaungtha (retired code) -> Rakhine */
+ {"cdo", {HB_TAG('Z','H','S',' ')}}, /* Min Dong Chinese -> Chinese Simplified */
+ {"ce", {HB_TAG('C','H','E',' ')}}, /* Chechen */
+ {"ceb", {HB_TAG('C','E','B',' ')}}, /* Cebuano */
+ {"cfm", {HB_TAG('H','A','L',' ')}}, /* Halam (Falam Chin) */
+ {"cgg", {HB_TAG('C','G','G',' ')}}, /* Chiga */
+ {"ch", {HB_TAG('C','H','A',' ')}}, /* Chamorro */
+ {"chj", {HB_TAG('C','C','H','N')}}, /* Ojitlán Chinantec -> Chinantec */
+ {"chk", {HB_TAG('C','H','K','0')}}, /* Chuukese */
+ {"cho", {HB_TAG('C','H','O',' ')}}, /* Choctaw */
+ {"chp", {HB_TAG('C','H','P',' '), /* Chipewyan */
+ HB_TAG('S','A','Y',' '), /* Chipewyan -> Sayisi */
+ HB_TAG('A','T','H',' ')}}, /* Chipewyan -> Athapaskan */
+ {"chq", {HB_TAG('C','C','H','N')}}, /* Quiotepec Chinantec -> Chinantec */
+ {"chr", {HB_TAG('C','H','R',' ')}}, /* Cherokee */
+ {"chy", {HB_TAG('C','H','Y',' ')}}, /* Cheyenne */
+ {"chz", {HB_TAG('C','C','H','N')}}, /* Ozumacín Chinantec -> Chinantec */
+ {"ciw", {HB_TAG('O','J','B',' ')}}, /* Chippewa -> Ojibway */
+ {"cja", {HB_TAG('C','J','A',' ')}}, /* Western Cham */
+ {"cjm", {HB_TAG('C','J','M',' ')}}, /* Eastern Cham */
+ {"cjy", {HB_TAG('Z','H','S',' ')}}, /* Jinyu Chinese -> Chinese Simplified */
+ {"cka", {HB_TAG('Q','I','N',' ')}}, /* Khumi Awa Chin (retired code) -> Chin */
+ {"ckb", {HB_TAG('K','U','R',' ')}}, /* Central Kurdish -> Kurdish */
+ {"ckt", {HB_TAG('C','H','K',' ')}}, /* Chukot -> Chukchi */
+ {"clc", {HB_TAG('A','T','H',' ')}}, /* Chilcotin -> Athapaskan */
+ {"cld", {HB_TAG('S','Y','R',' ')}}, /* Chaldean Neo-Aramaic -> Syriac */
+ {"cle", {HB_TAG('C','C','H','N')}}, /* Lealao Chinantec -> Chinantec */
+ {"cmn", {HB_TAG('Z','H','S',' ')}}, /* Mandarin Chinese -> Chinese Simplified */
+ {"cmr", {HB_TAG('Q','I','N',' ')}}, /* Mro-Khimi Chin -> Chin */
+ {"cnb", {HB_TAG('Q','I','N',' ')}}, /* Chinbon Chin -> Chin */
+ {"cnh", {HB_TAG('Q','I','N',' ')}}, /* Hakha Chin -> Chin */
+ {"cnk", {HB_TAG('Q','I','N',' ')}}, /* Khumi Chin -> Chin */
+ {"cnl", {HB_TAG('C','C','H','N')}}, /* Lalana Chinantec -> Chinantec */
+ {"cnt", {HB_TAG('C','C','H','N')}}, /* Tepetotutla Chinantec -> Chinantec */
+ {"cnw", {HB_TAG('Q','I','N',' ')}}, /* Ngawn Chin -> Chin */
+ {"co", {HB_TAG('C','O','S',' ')}}, /* Corsican */
+ {"coa", {HB_TAG('M','L','Y',' ')}}, /* Cocos Islands Malay -> Malay */
+ {"cop", {HB_TAG('C','O','P',' ')}}, /* Coptic */
+ {"coq", {HB_TAG('A','T','H',' ')}}, /* Coquille -> Athapaskan */
+ {"cpa", {HB_TAG('C','C','H','N')}}, /* Palantla Chinantec -> Chinantec */
+ {"cpe", {HB_TAG('C','P','P',' ')}}, /* English-based creoles and pidgins [family] -> Creoles */
+ {"cpf", {HB_TAG('C','P','P',' ')}}, /* French-based creoles and pidgins [family] -> Creoles */
+ {"cpp", {HB_TAG('C','P','P',' ')}}, /* Portuguese-based creoles and pidgins [family] -> Creoles */
+ {"cpx", {HB_TAG('Z','H','S',' ')}}, /* Pu-Xian Chinese -> Chinese Simplified */
+ {"cqd", {HB_TAG('H','M','N',' ')}}, /* Chuanqiandian Cluster Miao -> Hmong */
+ {"cqu", {HB_TAG('Q','U','H',' ')}}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */
+ {"cr", {HB_TAG('C','R','E',' '), /* Cree [macrolanguage] */
+ HB_TAG('Y','C','R',' ')}}, /* Cree [macrolanguage] -> Y-Cree */
+ {"crh", {HB_TAG('C','R','T',' ')}}, /* Crimean Tatar */
+ {"crj", {HB_TAG('E','C','R',' ')}}, /* Southern East Cree -> Eastern Cree */
+ {"crk", {HB_TAG('W','C','R',' ')}}, /* Plains Cree -> West-Cree */
+ {"crl", {HB_TAG('E','C','R',' ')}}, /* Northern East Cree -> Eastern Cree */
+ {"crm", {HB_TAG('M','C','R',' '), /* Moose Cree */
+ HB_TAG('L','C','R',' ')}}, /* Moose Cree -> L-Cree */
+ {"crp", {HB_TAG('C','P','P',' ')}}, /* Creoles and pidgins [family] -> Creoles */
+ {"crx", {HB_TAG('C','R','R',' '), /* Carrier */
+ HB_TAG('A','T','H',' ')}}, /* Carrier -> Athapaskan */
+ {"cs", {HB_TAG('C','S','Y',' ')}}, /* Czech */
+ {"csa", {HB_TAG('C','C','H','N')}}, /* Chiltepec Chinantec -> Chinantec */
+ {"csb", {HB_TAG('C','S','B',' ')}}, /* Kashubian */
+ {"csh", {HB_TAG('Q','I','N',' ')}}, /* Asho Chin -> Chin */
+ {"cso", {HB_TAG('C','C','H','N')}}, /* Sochiapam Chinantec -> Chinantec */
+ {"csw", {HB_TAG('N','C','R',' '), /* Swampy Cree -> N-Cree */
+ HB_TAG('N','H','C',' ')}}, /* Swampy Cree -> Norway House Cree */
+ {"csy", {HB_TAG('Q','I','N',' ')}}, /* Siyin Chin -> Chin */
+ {"ctc", {HB_TAG('A','T','H',' ')}}, /* Chetco -> Athapaskan */
+ {"ctd", {HB_TAG('Q','I','N',' ')}}, /* Tedim Chin -> Chin */
+ {"cte", {HB_TAG('C','C','H','N')}}, /* Tepinapa Chinantec -> Chinantec */
+ {"ctg", {HB_TAG('C','T','G',' ')}}, /* Chittagonian */
+ {"ctl", {HB_TAG('C','C','H','N')}}, /* Tlacoatzintepec Chinantec -> Chinantec */
+ {"cts", {HB_TAG('B','I','K',' ')}}, /* Northern Catanduanes Bikol -> Bikol */
+ {"cu", {HB_TAG('C','S','L',' ')}}, /* Church Slavonic */
+ {"cuc", {HB_TAG('C','C','H','N')}}, /* Usila Chinantec -> Chinantec */
+ {"cuk", {HB_TAG('C','U','K',' ')}}, /* San Blas Kuna */
+ {"cv", {HB_TAG('C','H','U',' ')}}, /* Chuvash */
+ {"cvn", {HB_TAG('C','C','H','N')}}, /* Valle Nacional Chinantec -> Chinantec */
+ {"cwd", {HB_TAG('D','C','R',' '), /* Woods Cree */
+ HB_TAG('T','C','R',' ')}}, /* Woods Cree -> TH-Cree */
+ {"cy", {HB_TAG('W','E','L',' ')}}, /* Welsh */
+ {"czh", {HB_TAG('Z','H','S',' ')}}, /* Huizhou Chinese -> Chinese Simplified */
+ {"czo", {HB_TAG('Z','H','S',' ')}}, /* Min Zhong Chinese -> Chinese Simplified */
+ {"czt", {HB_TAG('Q','I','N',' ')}}, /* Zotung Chin -> Chin */
+ {"da", {HB_TAG('D','A','N',' ')}}, /* Danish */
+ {"dao", {HB_TAG('Q','I','N',' ')}}, /* Daai Chin -> Chin */
+ {"dap", {HB_TAG('N','I','S',' ')}}, /* Nisi (India) (retired code) */
+ {"dar", {HB_TAG('D','A','R',' ')}}, /* Dargwa */
+ {"dax", {HB_TAG('D','A','X',' ')}}, /* Dayi */
+ {"de", {HB_TAG('D','E','U',' ')}}, /* German */
+ {"den", {HB_TAG('S','L','A',' '), /* Slave (Athapascan) [macrolanguage] -> Slavey */
+ HB_TAG('A','T','H',' ')}}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */
+ {"dgo", {HB_TAG('D','G','O',' ')}}, /* Dogri */
+ {"dgr", {HB_TAG('A','T','H',' ')}}, /* Dogrib -> Athapaskan */
+ {"dhd", {HB_TAG('M','A','W',' ')}}, /* Dhundari -> Marwari */
+ {"dhg", {HB_TAG('D','H','G',' ')}}, /* Dhangu */
+ {"dib", {HB_TAG('D','N','K',' ')}}, /* South Central Dinka -> Dinka */
+ {"dik", {HB_TAG('D','N','K',' ')}}, /* Southwestern Dinka -> Dinka */
+ {"din", {HB_TAG('D','N','K',' ')}}, /* Dinka [macrolanguage] */
+ {"dip", {HB_TAG('D','N','K',' ')}}, /* Northeastern Dinka -> Dinka */
+ {"diq", {HB_TAG('D','I','Q',' ')}}, /* Dimli */
+ {"diw", {HB_TAG('D','N','K',' ')}}, /* Northwestern Dinka -> Dinka */
+ {"dje", {HB_TAG('D','J','R',' ')}}, /* Zarma */
+ {"djr", {HB_TAG('D','J','R','0')}}, /* Djambarrpuyngu */
+ {"dks", {HB_TAG('D','N','K',' ')}}, /* Southeastern Dinka -> Dinka */
+ {"dng", {HB_TAG('D','U','N',' ')}}, /* Dungan */
+ {"dnj", {HB_TAG('D','N','J',' ')}}, /* Dan */
+ {"doi", {HB_TAG('D','G','R',' ')}}, /* Dogri [macrolanguage] */
+ {"drh", {HB_TAG('M','N','G',' ')}}, /* Darkhat (retired code) -> Mongolian */
+ {"drw", {HB_TAG('D','R','I',' ')}}, /* Darwazi (retired code) -> Dari */
+ {"dsb", {HB_TAG('L','S','B',' ')}}, /* Lower Sorbian */
+ {"dty", {HB_TAG('N','E','P',' ')}}, /* Dotyali -> Nepali */
+ {"duj", {HB_TAG('D','U','J',' ')}}, /* Dhuwal (retired code) */
+ {"dup", {HB_TAG('M','L','Y',' ')}}, /* Duano -> Malay */
+ {"dv", {HB_TAG('D','I','V',' '), /* Divehi (Dhivehi, Maldivian) */
+ HB_TAG('D','H','V',' ')}}, /* Divehi (Dhivehi, Maldivian) (deprecated) */
+ {"dwu", {HB_TAG('D','U','J',' ')}}, /* Dhuwal */
+ {"dwy", {HB_TAG('D','U','J',' ')}}, /* Dhuwaya -> Dhuwal */
+ {"dyu", {HB_TAG('J','U','L',' ')}}, /* Dyula -> Jula */
+ {"dz", {HB_TAG('D','Z','N',' ')}}, /* Dzongkha */
+ {"ee", {HB_TAG('E','W','E',' ')}}, /* Ewe */
+ {"efi", {HB_TAG('E','F','I',' ')}}, /* Efik */
+ {"ekk", {HB_TAG('E','T','I',' ')}}, /* Standard Estonian -> Estonian */
+ {"el", {HB_TAG('E','L','L',' ')}}, /* Modern Greek (1453-) -> Greek */
+ {"emk", {HB_TAG('E','M','K',' '), /* Eastern Maninkakan */
+ HB_TAG('M','N','K',' ')}}, /* Eastern Maninkakan -> Maninka */
+ {"en", {HB_TAG('E','N','G',' ')}}, /* English */
+ {"enb", {HB_TAG('K','A','L',' ')}}, /* Markweeta -> Kalenjin */
+ {"enf", {HB_TAG('F','N','E',' ')}}, /* Forest Enets -> Forest Nenets */
+ {"enh", {HB_TAG('T','N','E',' ')}}, /* Tundra Enets -> Tundra Nenets */
+ {"eo", {HB_TAG('N','T','O',' ')}}, /* Esperanto */
+ {"es", {HB_TAG('E','S','P',' ')}}, /* Spanish */
+ {"esg", {HB_TAG('G','O','N',' ')}}, /* Aheri Gondi -> Gondi */
+ {"esi", {HB_TAG('I','P','K',' ')}}, /* North Alaskan Inupiatun -> Inupiat */
+ {"esk", {HB_TAG('I','P','K',' ')}}, /* Northwest Alaska Inupiatun -> Inupiat */
+ {"esu", {HB_TAG('E','S','U',' ')}}, /* Central Yupik */
+ {"et", {HB_TAG('E','T','I',' ')}}, /* Estonian [macrolanguage] */
+ {"eto", {HB_TAG('B','T','I',' ')}}, /* Eton (Cameroon) -> Beti */
+ {"eu", {HB_TAG('E','U','Q',' ')}}, /* Basque */
+ {"eve", {HB_TAG('E','V','N',' ')}}, /* Even */
+ {"evn", {HB_TAG('E','V','K',' ')}}, /* Evenki */
+ {"ewo", {HB_TAG('B','T','I',' ')}}, /* Ewondo -> Beti */
+ {"eyo", {HB_TAG('K','A','L',' ')}}, /* Keiyo -> Kalenjin */
+ {"fa", {HB_TAG('F','A','R',' ')}}, /* Persian [macrolanguage] */
+ {"fan", {HB_TAG('F','A','N','0')}}, /* Fang (Equatorial Guinea) */
+ {"fat", {HB_TAG('F','A','T',' ')}}, /* Fanti */
+ {"fbl", {HB_TAG('B','I','K',' ')}}, /* West Albay Bikol -> Bikol */
+ {"ff", {HB_TAG('F','U','L',' ')}}, /* Fulah [macrolanguage] */
+ {"ffm", {HB_TAG('F','U','L',' ')}}, /* Maasina Fulfulde -> Fulah */
+ {"fi", {HB_TAG('F','I','N',' ')}}, /* Finnish */
+ {"fil", {HB_TAG('P','I','L',' ')}}, /* Filipino */
+ {"fj", {HB_TAG('F','J','I',' ')}}, /* Fijian */
+ {"flm", {HB_TAG('H','A','L',' '), /* Halam (Falam Chin) (retired code) */
+ HB_TAG('Q','I','N',' ')}}, /* Falam Chin (retired code) -> Chin */
+ {"fmp", {HB_TAG('F','M','P',' ')}}, /* Fe'fe' */
+ {"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 */
+ {"fub", {HB_TAG('F','U','L',' ')}}, /* Adamawa Fulfulde -> Fulah */
+ {"fuc", {HB_TAG('F','U','L',' ')}}, /* Pulaar -> Fulah */
+ {"fue", {HB_TAG('F','U','L',' ')}}, /* Borgu Fulfulde -> Fulah */
+ {"fuf", {HB_TAG('F','T','A',' ')}}, /* Pular -> Futa */
+ {"fuh", {HB_TAG('F','U','L',' ')}}, /* Western Niger Fulfulde -> Fulah */
+ {"fui", {HB_TAG('F','U','L',' ')}}, /* Bagirmi Fulfulde -> Fulah */
+ {"fuq", {HB_TAG('F','U','L',' ')}}, /* Central-Eastern Niger Fulfulde -> Fulah */
+ {"fur", {HB_TAG('F','R','L',' ')}}, /* Friulian */
+ {"fuv", {HB_TAG('F','U','V',' ')}}, /* Nigerian Fulfulde */
+ {"fy", {HB_TAG('F','R','I',' ')}}, /* Western Frisian -> Frisian */
+ {"ga", {HB_TAG('I','R','I',' ')}}, /* Irish */
+ {"gaa", {HB_TAG('G','A','D',' ')}}, /* Ga */
+ {"gag", {HB_TAG('G','A','G',' ')}}, /* Gagauz */
+ {"gan", {HB_TAG('Z','H','S',' ')}}, /* Gan Chinese -> Chinese Simplified */
+ {"gax", {HB_TAG('O','R','O',' ')}}, /* Borana-Arsi-Guji Oromo -> Oromo */
+ {"gaz", {HB_TAG('O','R','O',' ')}}, /* West Central Oromo -> Oromo */
+ {"gbm", {HB_TAG('G','A','W',' ')}}, /* Garhwali */
+ {"gce", {HB_TAG('A','T','H',' ')}}, /* Galice -> Athapaskan */
+ {"gd", {HB_TAG('G','A','E',' ')}}, /* Scottish Gaelic (Gaelic) */
+ {"gda", {HB_TAG('R','A','J',' ')}}, /* Gade Lohar -> Rajasthani */
+ {"gez", {HB_TAG('G','E','Z',' ')}}, /* Geez */
+ {"ggo", {HB_TAG('G','O','N',' ')}}, /* Southern Gondi (retired code) -> Gondi */
+ {"gih", {HB_TAG('G','I','H',' ')}}, /* Githabul */
+ {"gil", {HB_TAG('G','I','L','0')}}, /* Kiribati (Gilbertese) */
+ {"gju", {HB_TAG('R','A','J',' ')}}, /* Gujari -> Rajasthani */
+ {"gkp", {HB_TAG('G','K','P',' ')}}, /* Guinea Kpelle -> Kpelle (Guinea) */
+ {"gl", {HB_TAG('G','A','L',' ')}}, /* Galician */
+ {"gld", {HB_TAG('N','A','N',' ')}}, /* Nanai */
+ {"glk", {HB_TAG('G','L','K',' ')}}, /* Gilaki */
+ {"gn", {HB_TAG('G','U','A',' ')}}, /* Guarani [macrolanguage] */
+ {"gnn", {HB_TAG('G','N','N',' ')}}, /* Gumatj */
+ {"gno", {HB_TAG('G','O','N',' ')}}, /* Northern Gondi -> Gondi */
+ {"gnw", {HB_TAG('G','U','A',' ')}}, /* Western Bolivian Guaraní -> Guarani */
+ {"gog", {HB_TAG('G','O','G',' ')}}, /* Gogo */
+ {"gom", {HB_TAG('K','O','K',' ')}}, /* Goan Konkani -> Konkani */
+ {"gon", {HB_TAG('G','O','N',' ')}}, /* Gondi [macrolanguage] */
+ {"grt", {HB_TAG('G','R','O',' ')}}, /* Garo */
+ {"gru", {HB_TAG('S','O','G',' ')}}, /* Kistane -> Sodo Gurage */
+ {"gsw", {HB_TAG('A','L','S',' ')}}, /* Alsatian */
+ {"gu", {HB_TAG('G','U','J',' ')}}, /* Gujarati */
+ {"guc", {HB_TAG('G','U','C',' ')}}, /* Wayuu */
+ {"guf", {HB_TAG('G','U','F',' ')}}, /* Gupapuyngu */
+ {"gug", {HB_TAG('G','U','A',' ')}}, /* Paraguayan Guaraní -> Guarani */
+ {"gui", {HB_TAG('G','U','A',' ')}}, /* Eastern Bolivian Guaraní -> Guarani */
+ {"guk", {HB_TAG('G','M','Z',' '), /* Gumuz */
+ HB_TAG('G','U','K',' ')}}, /* Gumuz (SIL fonts) */
+ {"gun", {HB_TAG('G','U','A',' ')}}, /* Mbyá Guaraní -> Guarani */
+ {"guz", {HB_TAG('G','U','Z',' ')}}, /* Gusii */
+ {"gv", {HB_TAG('M','N','X',' ')}}, /* Manx */
+ {"gwi", {HB_TAG('A','T','H',' ')}}, /* Gwichʼin -> Athapaskan */
+ {"ha", {HB_TAG('H','A','U',' ')}}, /* Hausa */
+ {"haa", {HB_TAG('A','T','H',' ')}}, /* Han -> Athapaskan */
+ {"hae", {HB_TAG('O','R','O',' ')}}, /* Eastern Oromo -> Oromo */
+ {"hak", {HB_TAG('Z','H','S',' ')}}, /* Hakka Chinese -> Chinese Simplified */
+ {"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 */
+ {"hea", {HB_TAG('H','M','N',' ')}}, /* Northern Qiandong Miao -> Hmong */
+ {"hi", {HB_TAG('H','I','N',' ')}}, /* Hindi */
+ {"hil", {HB_TAG('H','I','L',' ')}}, /* Hiligaynon */
+ {"hji", {HB_TAG('M','L','Y',' ')}}, /* Haji -> Malay */
+ {"hlt", {HB_TAG('Q','I','N',' ')}}, /* Matu Chin -> Chin */
+ {"hma", {HB_TAG('H','M','N',' ')}}, /* Southern Mashan Hmong -> Hmong */
+ {"hmc", {HB_TAG('H','M','N',' ')}}, /* Central Huishui Hmong -> Hmong */
+ {"hmd", {HB_TAG('H','M','N',' ')}}, /* Large Flowery Miao -> Hmong */
+ {"hme", {HB_TAG('H','M','N',' ')}}, /* Eastern Huishui Hmong -> Hmong */
+ {"hmg", {HB_TAG('H','M','N',' ')}}, /* Southwestern Guiyang Hmong -> Hmong */
+ {"hmh", {HB_TAG('H','M','N',' ')}}, /* Southwestern Huishui Hmong -> Hmong */
+ {"hmi", {HB_TAG('H','M','N',' ')}}, /* Northern Huishui Hmong -> Hmong */
+ {"hmj", {HB_TAG('H','M','N',' ')}}, /* Ge -> Hmong */
+ {"hml", {HB_TAG('H','M','N',' ')}}, /* Luopohe Hmong -> Hmong */
+ {"hmm", {HB_TAG('H','M','N',' ')}}, /* Central Mashan Hmong -> Hmong */
+ {"hmn", {HB_TAG('H','M','N',' ')}}, /* Hmong [macrolanguage] */
+ {"hmp", {HB_TAG('H','M','N',' ')}}, /* Northern Mashan Hmong -> Hmong */
+ {"hmq", {HB_TAG('H','M','N',' ')}}, /* Eastern Qiandong Miao -> Hmong */
+ {"hms", {HB_TAG('H','M','N',' ')}}, /* Southern Qiandong Miao -> Hmong */
+ {"hmw", {HB_TAG('H','M','N',' ')}}, /* Western Mashan Hmong -> Hmong */
+ {"hmy", {HB_TAG('H','M','N',' ')}}, /* Southern Guiyang Hmong -> Hmong */
+ {"hmz", {HB_TAG('H','M','N',' ')}}, /* Hmong Shua -> Hmong */
+ {"hnd", {HB_TAG('H','N','D',' ')}}, /* Southern Hindko -> Hindko */
+ {"hne", {HB_TAG('C','H','H',' ')}}, /* Chhattisgarhi -> Chattisgarhi */
+ {"hnj", {HB_TAG('H','M','N',' ')}}, /* Hmong Njua -> Hmong */
+ {"hno", {HB_TAG('H','N','D',' ')}}, /* Northern Hindko -> Hindko */
+ {"ho", {HB_TAG('H','M','O',' ')}}, /* Hiri Motu */
+ {"hoc", {HB_TAG('H','O',' ',' ')}}, /* Ho */
+ {"hoi", {HB_TAG('A','T','H',' ')}}, /* Holikachuk -> Athapaskan */
+ {"hoj", {HB_TAG('H','A','R',' ')}}, /* Hadothi -> Harauti */
+ {"hr", {HB_TAG('H','R','V',' ')}}, /* Croatian */
+ {"hrm", {HB_TAG('H','M','N',' ')}}, /* Horned Miao -> Hmong */
+ {"hsb", {HB_TAG('U','S','B',' ')}}, /* Upper Sorbian */
+ {"hsn", {HB_TAG('Z','H','S',' ')}}, /* Xiang Chinese -> Chinese Simplified */
+ {"ht", {HB_TAG('H','A','I',' ')}}, /* Haitian (Haitian Creole) */
+ {"hu", {HB_TAG('H','U','N',' ')}}, /* Hungarian */
+ {"huj", {HB_TAG('H','M','N',' ')}}, /* Northern Guiyang Hmong -> Hmong */
+ {"hup", {HB_TAG('A','T','H',' ')}}, /* Hupa -> Athapaskan */
+ {"hy", {HB_TAG('H','Y','E','0'), /* Armenian -> Armenian East */
+ HB_TAG('H','Y','E',' ')}}, /* Armenian */
+ {"hyw", {HB_TAG('H','Y','E',' ')}}, /* Western Armenian -> Armenian */
+ {"hz", {HB_TAG('H','E','R',' ')}}, /* Herero */
+ {"ia", {HB_TAG('I','N','A',' ')}}, /* Interlingua (International Auxiliary Language Association) */
+ {"iba", {HB_TAG('I','B','A',' ')}}, /* Iban */
+ {"ibb", {HB_TAG('I','B','B',' ')}}, /* Ibibio */
+ {"id", {HB_TAG('I','N','D',' ')}}, /* Indonesian */
+ {"ida", {HB_TAG('L','U','H',' ')}}, /* Idakho-Isukha-Tiriki -> Luyia */
+ {"ie", {HB_TAG('I','L','E',' ')}}, /* Interlingue */
+ {"ig", {HB_TAG('I','B','O',' ')}}, /* Igbo */
+ {"igb", {HB_TAG('E','B','I',' ')}}, /* Ebira */
+ {"ii", {HB_TAG('Y','I','M',' ')}}, /* Sichuan Yi -> Yi Modern */
+ {"ijc", {HB_TAG('I','J','O',' ')}}, /* Izon -> Ijo */
+ {"ijo", {HB_TAG('I','J','O',' ')}}, /* Ijo [family] */
+ {"ik", {HB_TAG('I','P','K',' ')}}, /* Inupiaq [macrolanguage] -> Inupiat */
+ {"ike", {HB_TAG('I','N','U',' ')}}, /* Eastern Canadian Inuktitut -> Inuktitut */
+ {"ikt", {HB_TAG('I','N','U',' ')}}, /* Inuinnaqtun -> Inuktitut */
+ {"ilo", {HB_TAG('I','L','O',' ')}}, /* Iloko -> Ilokano */
+ {"in", {HB_TAG('I','N','D',' ')}}, /* Indonesian (retired code) */
+ {"ing", {HB_TAG('A','T','H',' ')}}, /* Degexit'an -> Athapaskan */
+ {"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 [macrolanguage] */
+ {"iw", {HB_TAG('I','W','R',' ')}}, /* Hebrew (retired code) */
+ {"ja", {HB_TAG('J','A','N',' ')}}, /* Japanese */
+ {"jak", {HB_TAG('M','L','Y',' ')}}, /* Jakun -> Malay */
+ {"jam", {HB_TAG('J','A','M',' ')}}, /* Jamaican Creole English -> Jamaican Creole */
+ {"jax", {HB_TAG('M','L','Y',' ')}}, /* Jambi Malay -> Malay */
+ {"jbo", {HB_TAG('J','B','O',' ')}}, /* Lojban */
+ {"jct", {HB_TAG('J','C','T',' ')}}, /* Krymchak */
+ {"ji", {HB_TAG('J','I','I',' ')}}, /* Yiddish (retired code) */
+ {"jv", {HB_TAG('J','A','V',' ')}}, /* Javanese */
+ {"jw", {HB_TAG('J','A','V',' ')}}, /* Javanese (retired code) */
+ {"ka", {HB_TAG('K','A','T',' ')}}, /* Georgian */
+ {"kaa", {HB_TAG('K','R','K',' ')}}, /* Kara-Kalpak -> Karakalpak */
+ {"kab", {HB_TAG('K','A','B','0')}}, /* Kabyle */
+ {"kam", {HB_TAG('K','M','B',' ')}}, /* Kamba (Kenya) */
+ {"kar", {HB_TAG('K','R','N',' ')}}, /* Karen [family] */
+ {"kbd", {HB_TAG('K','A','B',' ')}}, /* Kabardian */
+ {"kby", {HB_TAG('K','N','R',' ')}}, /* Manga Kanuri -> Kanuri */
+ {"kca", {HB_TAG('K','H','K',' '), /* Khanty -> Khanty-Kazim */
+ HB_TAG('K','H','S',' '), /* Khanty -> Khanty-Shurishkar */
+ HB_TAG('K','H','V',' ')}}, /* Khanty -> Khanty-Vakhi */
+ {"kde", {HB_TAG('K','D','E',' ')}}, /* Makonde */
+ {"kdr", {HB_TAG('K','R','M',' ')}}, /* Karaim */
+ {"kdt", {HB_TAG('K','U','Y',' ')}}, /* Kuy */
+ {"kea", {HB_TAG('K','E','A',' ')}}, /* Kabuverdianu (Crioulo) */
+ {"kek", {HB_TAG('K','E','K',' ')}}, /* Kekchi */
+ {"kex", {HB_TAG('K','K','N',' ')}}, /* Kukna -> Kokni */
+ {"kfa", {HB_TAG('K','O','D',' ')}}, /* Kodava -> Kodagu */
+ {"kfr", {HB_TAG('K','A','C',' ')}}, /* Kachhi -> Kachchi */
+ {"kfx", {HB_TAG('K','U','L',' ')}}, /* Kullu Pahari -> Kulvi */
+ {"kfy", {HB_TAG('K','M','N',' ')}}, /* Kumaoni */
+ {"kg", {HB_TAG('K','O','N','0')}}, /* Kongo [macrolanguage] */
+ {"kha", {HB_TAG('K','S','I',' ')}}, /* Khasi */
+ {"khb", {HB_TAG('X','B','D',' ')}}, /* Lü */
+ {"khk", {HB_TAG('M','N','G',' ')}}, /* Halh Mongolian -> Mongolian */
+ {"kht", {HB_TAG('K','H','N',' '), /* Khamti -> Khamti Shan (Microsoft fonts) */
+ HB_TAG('K','H','T',' ')}}, /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */
+ {"khw", {HB_TAG('K','H','W',' ')}}, /* Khowar */
+ {"ki", {HB_TAG('K','I','K',' ')}}, /* Kikuyu (Gikuyu) */
+ {"kiu", {HB_TAG('K','I','U',' ')}}, /* Kirmanjki */
+ {"kj", {HB_TAG('K','U','A',' ')}}, /* Kuanyama */
+ {"kjd", {HB_TAG('K','J','D',' ')}}, /* Southern Kiwai */
+ {"kjh", {HB_TAG('K','H','A',' ')}}, /* Khakas -> Khakass */
+ {"kjp", {HB_TAG('K','J','P',' ')}}, /* Pwo Eastern Karen -> Eastern Pwo Karen */
+ {"kjz", {HB_TAG('K','J','Z',' ')}}, /* Bumthangkha */
+ {"kk", {HB_TAG('K','A','Z',' ')}}, /* Kazakh */
+ {"kkz", {HB_TAG('A','T','H',' ')}}, /* Kaska -> Athapaskan */
+ {"kl", {HB_TAG('G','R','N',' ')}}, /* Greenlandic */
+ {"kln", {HB_TAG('K','A','L',' ')}}, /* Kalenjin [macrolanguage] */
+ {"km", {HB_TAG('K','H','M',' ')}}, /* Khmer */
+ {"kmb", {HB_TAG('M','B','N',' ')}}, /* Kimbundu -> Mbundu */
+ {"kmr", {HB_TAG('K','U','R',' ')}}, /* Northern Kurdish -> Kurdish */
+ {"kmw", {HB_TAG('K','M','O',' ')}}, /* Komo (Democratic Republic of Congo) */
+ {"kmz", {HB_TAG('K','M','Z',' ')}}, /* Khorasani Turkish -> Khorasani Turkic */
+ {"kn", {HB_TAG('K','A','N',' ')}}, /* Kannada */
+ {"knc", {HB_TAG('K','N','R',' ')}}, /* Central Kanuri -> Kanuri */
+ {"kng", {HB_TAG('K','O','N','0')}}, /* Koongo -> Kongo */
+ {"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 [macrolanguage] */
+ {"kos", {HB_TAG('K','O','S',' ')}}, /* Kosraean */
+ {"koy", {HB_TAG('A','T','H',' ')}}, /* Koyukon -> Athapaskan */
+ {"kpe", {HB_TAG('K','P','L',' ')}}, /* Kpelle [macrolanguage] */
+ {"kpv", {HB_TAG('K','O','Z',' ')}}, /* Komi-Zyrian */
+ {"kpy", {HB_TAG('K','Y','K',' ')}}, /* Koryak */
+ {"kqs", {HB_TAG('K','I','S',' ')}}, /* Northern Kissi -> Kisii */
+ {"kqy", {HB_TAG('K','R','T',' ')}}, /* Koorete */
+ {"kr", {HB_TAG('K','N','R',' ')}}, /* Kanuri [macrolanguage] */
+ {"krc", {HB_TAG('K','A','R',' '), /* Karachay-Balkar -> Karachay */
+ HB_TAG('B','A','L',' ')}}, /* Karachay-Balkar -> Balkar */
+ {"kri", {HB_TAG('K','R','I',' ')}}, /* Krio */
+ {"krl", {HB_TAG('K','R','L',' ')}}, /* Karelian */
+ {"krt", {HB_TAG('K','N','R',' ')}}, /* Tumari Kanuri -> Kanuri */
+ {"kru", {HB_TAG('K','U','U',' ')}}, /* Kurukh */
+ {"ks", {HB_TAG('K','S','H',' ')}}, /* Kashmiri */
+ {"ksh", {HB_TAG('K','S','H','0')}}, /* Kölsch -> Ripuarian */
+ {"kss", {HB_TAG('K','I','S',' ')}}, /* Southern Kisi -> Kisii */
+ {"ksw", {HB_TAG('K','S','W',' ')}}, /* S’gaw Karen */
+ {"ktb", {HB_TAG('K','E','B',' ')}}, /* Kambaata -> Kebena */
+ {"ktu", {HB_TAG('K','O','N',' ')}}, /* Kituba (Democratic Republic of Congo) -> Kikongo */
+ {"ktw", {HB_TAG('A','T','H',' ')}}, /* Kato -> Athapaskan */
+ {"ku", {HB_TAG('K','U','R',' ')}}, /* Kurdish [macrolanguage] */
+ {"kum", {HB_TAG('K','U','M',' ')}}, /* Kumyk */
+ {"kuu", {HB_TAG('A','T','H',' ')}}, /* Upper Kuskokwim -> Athapaskan */
+ {"kv", {HB_TAG('K','O','M',' ')}}, /* Komi [macrolanguage] */
+ {"kvb", {HB_TAG('M','L','Y',' ')}}, /* Kubu -> Malay */
+ {"kvr", {HB_TAG('M','L','Y',' ')}}, /* Kerinci -> Malay */
+ {"kw", {HB_TAG('C','O','R',' ')}}, /* Cornish */
+ {"kwy", {HB_TAG('K','O','N','0')}}, /* San Salvador Kongo -> Kongo */
+ {"kxc", {HB_TAG('K','M','S',' ')}}, /* Konso -> Komso */
+ {"kxd", {HB_TAG('M','L','Y',' ')}}, /* Brunei -> Malay */
+ {"kxu", {HB_TAG('K','U','I',' ')}}, /* Kui (India) */
+ {"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 */
+ {"lbl", {HB_TAG('B','I','K',' ')}}, /* Libon Bikol -> Bikol */
+ {"lce", {HB_TAG('M','L','Y',' ')}}, /* Loncong -> Malay */
+ {"lcf", {HB_TAG('M','L','Y',' ')}}, /* Lubu -> Malay */
+ {"ldi", {HB_TAG('K','O','N','0')}}, /* Laari -> Kongo */
+ {"lez", {HB_TAG('L','E','Z',' ')}}, /* Lezghian -> Lezgi */
+ {"lg", {HB_TAG('L','U','G',' ')}}, /* Ganda */
+ {"li", {HB_TAG('L','I','M',' ')}}, /* Limburgish */
+ {"lif", {HB_TAG('L','M','B',' ')}}, /* Limbu */
+ {"lij", {HB_TAG('L','I','J',' ')}}, /* Ligurian */
+ {"lis", {HB_TAG('L','I','S',' ')}}, /* Lisu */
+ {"liw", {HB_TAG('M','L','Y',' ')}}, /* Col -> Malay */
+ {"ljp", {HB_TAG('L','J','P',' ')}}, /* Lampung Api -> Lampung */
+ {"lkb", {HB_TAG('L','U','H',' ')}}, /* Kabras -> Luyia */
+ {"lki", {HB_TAG('L','K','I',' ')}}, /* Laki */
+ {"lko", {HB_TAG('L','U','H',' ')}}, /* Khayo -> Luyia */
+ {"lks", {HB_TAG('L','U','H',' ')}}, /* Kisa -> Luyia */
+ {"lld", {HB_TAG('L','A','D',' ')}}, /* Ladin */
+ {"lmn", {HB_TAG('L','A','M',' ')}}, /* Lambadi -> Lambani */
+ {"lmo", {HB_TAG('L','M','O',' ')}}, /* Lombard */
+ {"ln", {HB_TAG('L','I','N',' ')}}, /* Lingala */
+ {"lo", {HB_TAG('L','A','O',' ')}}, /* Lao */
+ {"lom", {HB_TAG('L','O','M',' ')}}, /* Loma (Liberia) */
+ {"lrc", {HB_TAG('L','R','C',' ')}}, /* Northern Luri -> Luri */
+ {"lri", {HB_TAG('L','U','H',' ')}}, /* Marachi -> Luyia */
+ {"lrm", {HB_TAG('L','U','H',' ')}}, /* Marama -> Luyia */
+ {"lsm", {HB_TAG('L','U','H',' ')}}, /* Saamia -> Luyia */
+ {"lt", {HB_TAG('L','T','H',' ')}}, /* Lithuanian */
+ {"ltg", {HB_TAG('L','V','I',' ')}}, /* Latgalian -> Latvian */
+ {"lto", {HB_TAG('L','U','H',' ')}}, /* Tsotso -> Luyia */
+ {"lts", {HB_TAG('L','U','H',' ')}}, /* Tachoni -> Luyia */
+ {"lu", {HB_TAG('L','U','B',' ')}}, /* Luba-Katanga */
+ {"lua", {HB_TAG('L','U','A',' ')}}, /* Luba-Lulua */
+ {"luo", {HB_TAG('L','U','O',' ')}}, /* Luo (Kenya and Tanzania) */
+ {"lus", {HB_TAG('M','I','Z',' ')}}, /* Lushai -> Mizo */
+ {"luy", {HB_TAG('L','U','H',' ')}}, /* Luyia [macrolanguage] */
+ {"luz", {HB_TAG('L','R','C',' ')}}, /* Southern Luri -> Luri */
+ {"lv", {HB_TAG('L','V','I',' ')}}, /* Latvian [macrolanguage] */
+ {"lvs", {HB_TAG('L','V','I',' ')}}, /* Standard Latvian -> Latvian */
+ {"lwg", {HB_TAG('L','U','H',' ')}}, /* Wanga -> Luyia */
+ {"lzh", {HB_TAG('Z','H','T',' ')}}, /* Literary Chinese -> Chinese Traditional */
+ {"lzz", {HB_TAG('L','A','Z',' ')}}, /* Laz */
+ {"mad", {HB_TAG('M','A','D',' ')}}, /* Madurese -> Madura */
+ {"mag", {HB_TAG('M','A','G',' ')}}, /* Magahi */
+ {"mai", {HB_TAG('M','T','H',' ')}}, /* Maithili */
+ {"mak", {HB_TAG('M','K','R',' ')}}, /* Makasar */
+ {"mam", {HB_TAG('M','A','M',' ')}}, /* Mam */
+ {"man", {HB_TAG('M','N','K',' ')}}, /* Mandingo [macrolanguage] -> Maninka */
+ {"max", {HB_TAG('M','L','Y',' ')}}, /* North Moluccan Malay -> Malay */
+ {"mbo", {HB_TAG('M','B','O',' ')}}, /* Mbo (Cameroon) */
+ {"mct", {HB_TAG('B','T','I',' ')}}, /* Mengisa -> Beti */
+ {"mdf", {HB_TAG('M','O','K',' ')}}, /* Moksha */
+ {"mdr", {HB_TAG('M','D','R',' ')}}, /* Mandar */
+ {"mdy", {HB_TAG('M','L','E',' ')}}, /* Male (Ethiopia) */
+ {"men", {HB_TAG('M','D','E',' ')}}, /* Mende (Sierra Leone) */
+ {"meo", {HB_TAG('M','L','Y',' ')}}, /* Kedah Malay -> Malay */
+ {"mer", {HB_TAG('M','E','R',' ')}}, /* Meru */
+ {"mfa", {HB_TAG('M','F','A',' ')}}, /* Pattani Malay */
+ {"mfb", {HB_TAG('M','L','Y',' ')}}, /* Bangka -> Malay */
+ {"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',' ')}}, /* Eastern Mari -> Low Mari */
+ {"mhv", {HB_TAG('A','R','K',' ')}}, /* Arakanese (retired code) -> Rakhine */
+ {"mi", {HB_TAG('M','R','I',' ')}}, /* Maori */
+ {"min", {HB_TAG('M','I','N',' ')}}, /* Minangkabau */
+ {"mk", {HB_TAG('M','K','D',' ')}}, /* Macedonian */
+ {"mku", {HB_TAG('M','N','K',' ')}}, /* Konyanka Maninka -> Maninka */
+ {"mkw", {HB_TAG('M','K','W',' ')}}, /* Kituba (Congo) */
+ {"ml", {HB_TAG('M','A','L',' '), /* Malayalam -> Malayalam Traditional */
+ HB_TAG('M','L','R',' ')}}, /* Malayalam -> Malayalam Reformed */
+ {"mlq", {HB_TAG('M','L','N',' '), /* Western Maninkakan -> Malinke */
+ HB_TAG('M','N','K',' ')}}, /* Western Maninkakan -> Maninka */
+ {"mmr", {HB_TAG('H','M','N',' ')}}, /* Western Xiangxi Miao -> Hmong */
+ {"mn", {HB_TAG('M','N','G',' ')}}, /* Mongolian [macrolanguage] */
+ {"mnc", {HB_TAG('M','C','H',' ')}}, /* Manchu */
+ {"mni", {HB_TAG('M','N','I',' ')}}, /* Manipuri */
+ {"mnk", {HB_TAG('M','N','D',' '), /* Mandinka */
+ HB_TAG('M','N','K',' ')}}, /* Mandinka -> Maninka */
+ {"mnp", {HB_TAG('Z','H','S',' ')}}, /* Min Bei Chinese -> Chinese Simplified */
+ {"mns", {HB_TAG('M','A','N',' ')}}, /* Mansi */
+ {"mnw", {HB_TAG('M','O','N',' ')}}, /* Mon */
+ {"mo", {HB_TAG('M','O','L',' ')}}, /* Moldavian (retired code) */
+ {"moh", {HB_TAG('M','O','H',' ')}}, /* Mohawk */
+ {"mos", {HB_TAG('M','O','S',' ')}}, /* Mossi */
+ {"mpe", {HB_TAG('M','A','J',' ')}}, /* Majang */
+ {"mqg", {HB_TAG('M','L','Y',' ')}}, /* Kota Bangun Kutai Malay -> Malay */
+ {"mr", {HB_TAG('M','A','R',' ')}}, /* Marathi */
+ {"mrh", {HB_TAG('Q','I','N',' ')}}, /* Mara Chin -> Chin */
+ {"mrj", {HB_TAG('H','M','A',' ')}}, /* Western Mari -> High Mari */
+ {"ms", {HB_TAG('M','L','Y',' ')}}, /* Malay [macrolanguage] */
+ {"msc", {HB_TAG('M','N','K',' ')}}, /* Sankaran Maninka -> Maninka */
+ {"msh", {HB_TAG('M','L','G',' ')}}, /* Masikoro Malagasy -> Malagasy */
+ {"msi", {HB_TAG('M','L','Y',' ')}}, /* Sabah Malay -> Malay */
+ {"mt", {HB_TAG('M','T','S',' ')}}, /* Maltese */
+ {"mtr", {HB_TAG('M','A','W',' ')}}, /* Mewari -> Marwari */
+ {"mui", {HB_TAG('M','L','Y',' ')}}, /* Musi -> Malay */
+ {"mup", {HB_TAG('R','A','J',' ')}}, /* Malvi -> Rajasthani */
+ {"muq", {HB_TAG('H','M','N',' ')}}, /* Eastern Xiangxi Miao -> Hmong */
+ {"mus", {HB_TAG('M','U','S',' ')}}, /* Creek -> Muscogee */
+ {"mvb", {HB_TAG('A','T','H',' ')}}, /* Mattole -> Athapaskan */
+ {"mve", {HB_TAG('M','A','W',' ')}}, /* Marwari (Pakistan) */
+ {"mvf", {HB_TAG('M','N','G',' ')}}, /* Peripheral Mongolian -> Mongolian */
+ {"mwk", {HB_TAG('M','N','K',' ')}}, /* Kita Maninkakan -> Maninka */
+ {"mwl", {HB_TAG('M','W','L',' ')}}, /* Mirandese */
+ {"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 */
+ {"myn", {HB_TAG('M','Y','N',' ')}}, /* Mayan [family] */
+ {"myq", {HB_TAG('M','N','K',' ')}}, /* Forest Maninka (retired code) -> Maninka */
+ {"myv", {HB_TAG('E','R','Z',' ')}}, /* Erzya */
+ {"mzn", {HB_TAG('M','Z','N',' ')}}, /* Mazanderani */
+ {"na", {HB_TAG('N','A','U',' ')}}, /* Nauru -> Nauruan */
+ {"nag", {HB_TAG('N','A','G',' ')}}, /* Naga Pidgin -> Naga-Assamese */
+ {"nah", {HB_TAG('N','A','H',' ')}}, /* Nahuatl [family] */
+ {"nan", {HB_TAG('Z','H','S',' ')}}, /* Min Nan Chinese -> Chinese Simplified */
+ {"nap", {HB_TAG('N','A','P',' ')}}, /* Neapolitan */
+ {"nb", {HB_TAG('N','O','R',' ')}}, /* Norwegian Bokmål -> Norwegian */
+ {"nd", {HB_TAG('N','D','B',' ')}}, /* North Ndebele -> Ndebele */
+ {"ndc", {HB_TAG('N','D','C',' ')}}, /* Ndau */
+ {"nds", {HB_TAG('N','D','S',' ')}}, /* Low Saxon */
+ {"ne", {HB_TAG('N','E','P',' ')}}, /* Nepali [macrolanguage] */
+ {"new", {HB_TAG('N','E','W',' ')}}, /* Newari */
+ {"ng", {HB_TAG('N','D','G',' ')}}, /* Ndonga */
+ {"nga", {HB_TAG('N','G','A',' ')}}, /* Ngbaka */
+ {"ngl", {HB_TAG('L','M','W',' ')}}, /* Lomwe */
+ {"ngo", {HB_TAG('S','X','T',' ')}}, /* Ngoni -> Sutu */
+ {"nhd", {HB_TAG('G','U','A',' ')}}, /* Chiripá -> Guarani */
+ {"niq", {HB_TAG('K','A','L',' ')}}, /* Nandi -> Kalenjin */
+ {"niu", {HB_TAG('N','I','U',' ')}}, /* Niuean */
+ {"niv", {HB_TAG('G','I','L',' ')}}, /* Gilyak */
+ {"njz", {HB_TAG('N','I','S',' ')}}, /* Nyishi -> Nisi */
+ {"nl", {HB_TAG('N','L','D',' ')}}, /* Dutch */
+ {"nle", {HB_TAG('L','U','H',' ')}}, /* East Nyala -> Luyia */
+ {"nn", {HB_TAG('N','Y','N',' ')}}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */
+ {"no", {HB_TAG('N','O','R',' ')}}, /* Norwegian [macrolanguage] */
+ {"nod", {HB_TAG('N','T','A',' ')}}, /* Northern Thai -> Northern Tai */
+ {"noe", {HB_TAG('N','O','E',' ')}}, /* Nimadi */
+ {"nog", {HB_TAG('N','O','G',' ')}}, /* Nogai */
+ {"nov", {HB_TAG('N','O','V',' ')}}, /* Novial */
+ {"npi", {HB_TAG('N','E','P',' ')}}, /* Nepali */
+ {"nqo", {HB_TAG('N','K','O',' ')}}, /* N'Ko */
+ {"nr", {HB_TAG('N','D','B',' ')}}, /* South Ndebele -> Ndebele */
+ {"nsk", {HB_TAG('N','A','S',' ')}}, /* Naskapi */
+ {"nso", {HB_TAG('N','S','O',' ')}}, /* Pedi -> Sotho, Northern */
+ {"nv", {HB_TAG('N','A','V',' '), /* Navajo */
+ HB_TAG('A','T','H',' ')}}, /* Navajo -> Athapaskan */
+ {"ny", {HB_TAG('C','H','I',' ')}}, /* Chichewa (Chewa, Nyanja) */
+ {"nyd", {HB_TAG('L','U','H',' ')}}, /* Nyore -> Luyia */
+ {"nym", {HB_TAG('N','Y','M',' ')}}, /* Nyamwezi */
+ {"nyn", {HB_TAG('N','K','L',' ')}}, /* Nyankole */
+ {"nza", {HB_TAG('N','Z','A',' ')}}, /* Tigon Mbembe -> Mbembe Tigon */
+ {"oc", {HB_TAG('O','C','I',' ')}}, /* Occitan (post 1500) */
+ {"oj", {HB_TAG('O','J','B',' ')}}, /* Ojibwa [macrolanguage] -> Ojibway */
+ {"ojb", {HB_TAG('O','J','B',' ')}}, /* Northwestern Ojibwa -> Ojibway */
+ {"ojc", {HB_TAG('O','J','B',' ')}}, /* Central Ojibwa -> Ojibway */
+ {"ojg", {HB_TAG('O','J','B',' ')}}, /* Eastern Ojibwa -> Ojibway */
+ {"ojs", {HB_TAG('O','C','R',' ')}}, /* Severn Ojibwa -> Oji-Cree */
+ {"ojw", {HB_TAG('O','J','B',' ')}}, /* Western Ojibwa -> Ojibway */
+ {"oki", {HB_TAG('K','A','L',' ')}}, /* Okiek -> Kalenjin */
+ {"okm", {HB_TAG('K','O','H',' ')}}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
+ {"om", {HB_TAG('O','R','O',' ')}}, /* Oromo [macrolanguage] */
+ {"or", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) [macrolanguage] */
+ {"orc", {HB_TAG('O','R','O',' ')}}, /* Orma -> Oromo */
+ {"orn", {HB_TAG('M','L','Y',' ')}}, /* Orang Kanaq -> Malay */
+ {"ors", {HB_TAG('M','L','Y',' ')}}, /* Orang Seletar -> Malay */
+ {"ory", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) */
+ {"os", {HB_TAG('O','S','S',' ')}}, /* Ossetian */
+ {"otw", {HB_TAG('O','J','B',' ')}}, /* Ottawa -> Ojibway */
+ {"pa", {HB_TAG('P','A','N',' ')}}, /* Punjabi */
+ {"pag", {HB_TAG('P','A','G',' ')}}, /* Pangasinan */
+ {"pam", {HB_TAG('P','A','M',' ')}}, /* Pampanga -> Pampangan */
+ {"pap", {HB_TAG('P','A','P','0')}}, /* Papiamento -> Papiamentu */
+ {"pau", {HB_TAG('P','A','U',' ')}}, /* Palauan */
+ {"pbt", {HB_TAG('P','A','S',' ')}}, /* Southern Pashto -> Pashto */
+ {"pbu", {HB_TAG('P','A','S',' ')}}, /* Northern Pashto -> Pashto */
+ {"pcc", {HB_TAG('P','C','C',' ')}}, /* Bouyei */
+ {"pcd", {HB_TAG('P','C','D',' ')}}, /* Picard */
+ {"pce", {HB_TAG('P','L','G',' ')}}, /* Ruching Palaung -> Palaung */
+ {"pck", {HB_TAG('Q','I','N',' ')}}, /* Paite Chin -> Chin */
+ {"pdc", {HB_TAG('P','D','C',' ')}}, /* Pennsylvania German */
+ {"pel", {HB_TAG('M','L','Y',' ')}}, /* Pekal -> Malay */
+ {"pes", {HB_TAG('F','A','R',' ')}}, /* Iranian Persian -> Persian */
+ {"pga", {HB_TAG('A','R','A',' ')}}, /* Sudanese Creole Arabic -> Arabic */
+ {"phk", {HB_TAG('P','H','K',' ')}}, /* Phake */
+ {"pi", {HB_TAG('P','A','L',' ')}}, /* Pali */
+ {"pih", {HB_TAG('P','I','H',' ')}}, /* Pitcairn-Norfolk -> Norfolk */
+ {"pko", {HB_TAG('K','A','L',' ')}}, /* Pökoot -> Kalenjin */
+ {"pl", {HB_TAG('P','L','K',' ')}}, /* Polish */
+ {"pll", {HB_TAG('P','L','G',' ')}}, /* Shwe Palaung -> Palaung */
+ {"plp", {HB_TAG('P','A','P',' ')}}, /* Palpa */
+ {"plt", {HB_TAG('M','L','G',' ')}}, /* Plateau Malagasy -> Malagasy */
+ {"pms", {HB_TAG('P','M','S',' ')}}, /* Piemontese */
+ {"pnb", {HB_TAG('P','N','B',' ')}}, /* Western Panjabi */
+ {"poh", {HB_TAG('P','O','H',' ')}}, /* Poqomchi' -> Pocomchi */
+ {"pon", {HB_TAG('P','O','N',' ')}}, /* Pohnpeian */
+ {"ppa", {HB_TAG('B','A','G',' ')}}, /* Pao (retired code) -> Baghelkhandi */
+ {"pro", {HB_TAG('P','R','O',' ')}}, /* Old Provençal (to 1500) -> Provençal / Old Provençal */
+ {"prs", {HB_TAG('D','R','I',' ')}}, /* Dari */
+ {"ps", {HB_TAG('P','A','S',' ')}}, /* Pashto [macrolanguage] */
+ {"pse", {HB_TAG('M','L','Y',' ')}}, /* Central Malay -> Malay */
+ {"pst", {HB_TAG('P','A','S',' ')}}, /* Central Pashto -> Pashto */
+ {"pt", {HB_TAG('P','T','G',' ')}}, /* Portuguese */
+ {"pwo", {HB_TAG('P','W','O',' ')}}, /* Pwo Western Karen -> Western Pwo Karen */
+ {"qu", {HB_TAG('Q','U','Z',' ')}}, /* Quechua [macrolanguage] */
+ {"qub", {HB_TAG('Q','W','H',' ')}}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */
+ {"quc", {HB_TAG('Q','U','C',' ')}}, /* K’iche’ */
+ {"qud", {HB_TAG('Q','V','I',' ')}}, /* Calderón Highland Quichua -> Quechua (Ecuador) */
+ {"quf", {HB_TAG('Q','U','Z',' ')}}, /* Lambayeque Quechua -> Quechua */
+ {"qug", {HB_TAG('Q','V','I',' ')}}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */
+ {"quh", {HB_TAG('Q','U','H',' ')}}, /* South Bolivian Quechua -> Quechua (Bolivia) */
+ {"quk", {HB_TAG('Q','U','Z',' ')}}, /* Chachapoyas Quechua -> Quechua */
+ {"qul", {HB_TAG('Q','U','Z',' ')}}, /* North Bolivian Quechua -> Quechua */
+ {"qup", {HB_TAG('Q','V','I',' ')}}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */
+ {"qur", {HB_TAG('Q','W','H',' ')}}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */
+ {"qus", {HB_TAG('Q','U','H',' ')}}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */
+ {"quw", {HB_TAG('Q','V','I',' ')}}, /* Tena Lowland Quichua -> Quechua (Ecuador) */
+ {"qux", {HB_TAG('Q','W','H',' ')}}, /* Yauyos Quechua -> Quechua (Peru) */
+ {"quy", {HB_TAG('Q','U','Z',' ')}}, /* Ayacucho Quechua -> Quechua */
+ {"quz", {HB_TAG('Q','U','Z',' ')}}, /* Cusco Quechua -> Quechua */
+ {"qva", {HB_TAG('Q','W','H',' ')}}, /* Ambo-Pasco Quechua -> Quechua (Peru) */
+ {"qvc", {HB_TAG('Q','U','Z',' ')}}, /* Cajamarca Quechua -> Quechua */
+ {"qve", {HB_TAG('Q','U','Z',' ')}}, /* Eastern Apurímac Quechua -> Quechua */
+ {"qvh", {HB_TAG('Q','W','H',' ')}}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */
+ {"qvi", {HB_TAG('Q','V','I',' ')}}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */
+ {"qvj", {HB_TAG('Q','V','I',' ')}}, /* Loja Highland Quichua -> Quechua (Ecuador) */
+ {"qvl", {HB_TAG('Q','W','H',' ')}}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */
+ {"qvm", {HB_TAG('Q','W','H',' ')}}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */
+ {"qvn", {HB_TAG('Q','W','H',' ')}}, /* North Junín Quechua -> Quechua (Peru) */
+ {"qvo", {HB_TAG('Q','V','I',' ')}}, /* Napo Lowland Quechua -> Quechua (Ecuador) */
+ {"qvp", {HB_TAG('Q','W','H',' ')}}, /* Pacaraos Quechua -> Quechua (Peru) */
+ {"qvs", {HB_TAG('Q','U','Z',' ')}}, /* San Martín Quechua -> Quechua */
+ {"qvw", {HB_TAG('Q','W','H',' ')}}, /* Huaylla Wanca Quechua -> Quechua (Peru) */
+ {"qvz", {HB_TAG('Q','V','I',' ')}}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */
+ {"qwa", {HB_TAG('Q','W','H',' ')}}, /* Corongo Ancash Quechua -> Quechua (Peru) */
+ {"qwc", {HB_TAG('Q','U','Z',' ')}}, /* Classical Quechua -> Quechua */
+ {"qwh", {HB_TAG('Q','W','H',' ')}}, /* Huaylas Ancash Quechua -> Quechua (Peru) */
+ {"qws", {HB_TAG('Q','W','H',' ')}}, /* Sihuas Ancash Quechua -> Quechua (Peru) */
+ {"qxa", {HB_TAG('Q','W','H',' ')}}, /* Chiquián Ancash Quechua -> Quechua (Peru) */
+ {"qxc", {HB_TAG('Q','W','H',' ')}}, /* Chincha Quechua -> Quechua (Peru) */
+ {"qxh", {HB_TAG('Q','W','H',' ')}}, /* Panao Huánuco Quechua -> Quechua (Peru) */
+ {"qxl", {HB_TAG('Q','V','I',' ')}}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */
+ {"qxn", {HB_TAG('Q','W','H',' ')}}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */
+ {"qxo", {HB_TAG('Q','W','H',' ')}}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */
+ {"qxp", {HB_TAG('Q','U','Z',' ')}}, /* Puno Quechua -> Quechua */
+ {"qxr", {HB_TAG('Q','V','I',' ')}}, /* Cañar Highland Quichua -> Quechua (Ecuador) */
+ {"qxt", {HB_TAG('Q','W','H',' ')}}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */
+ {"qxu", {HB_TAG('Q','U','Z',' ')}}, /* Arequipa-La Unión Quechua -> Quechua */
+ {"qxw", {HB_TAG('Q','W','H',' ')}}, /* Jauja Wanca Quechua -> Quechua (Peru) */
+ {"rag", {HB_TAG('L','U','H',' ')}}, /* Logooli -> Luyia */
+ {"raj", {HB_TAG('R','A','J',' ')}}, /* Rajasthani [macrolanguage] */
+ {"rar", {HB_TAG('R','A','R',' ')}}, /* Rarotongan */
+ {"rbb", {HB_TAG('P','L','G',' ')}}, /* Rumai Palaung -> Palaung */
+ {"rbl", {HB_TAG('B','I','K',' ')}}, /* Miraya Bikol -> Bikol */
+ {"rej", {HB_TAG('R','E','J',' ')}}, /* Rejang */
+ {"ria", {HB_TAG('R','I','A',' ')}}, /* Riang (India) */
+ {"rif", {HB_TAG('R','I','F',' ')}}, /* Tarifit */
+ {"rit", {HB_TAG('R','I','T',' ')}}, /* Ritarungo */
+ {"rki", {HB_TAG('A','R','K',' ')}}, /* Rakhine */
+ {"rkw", {HB_TAG('R','K','W',' ')}}, /* Arakwal */
+ {"rm", {HB_TAG('R','M','S',' ')}}, /* Romansh */
+ {"rmc", {HB_TAG('R','O','Y',' ')}}, /* Carpathian Romani -> Romany */
+ {"rmf", {HB_TAG('R','O','Y',' ')}}, /* Kalo Finnish Romani -> Romany */
+ {"rml", {HB_TAG('R','O','Y',' ')}}, /* Baltic Romani -> Romany */
+ {"rmn", {HB_TAG('R','O','Y',' ')}}, /* Balkan Romani -> Romany */
+ {"rmo", {HB_TAG('R','O','Y',' ')}}, /* Sinte Romani -> Romany */
+ {"rmw", {HB_TAG('R','O','Y',' ')}}, /* Welsh Romani -> Romany */
+ {"rmy", {HB_TAG('R','M','Y',' ')}}, /* Vlax Romani */
+ {"rmz", {HB_TAG('A','R','K',' ')}}, /* Marma -> Rakhine */
+ {"rn", {HB_TAG('R','U','N',' ')}}, /* Rundi */
+ {"rnl", {HB_TAG('H','A','L',' ')}}, /* Ranglong -> Halam (Falam Chin) */
+ {"ro", {HB_TAG('R','O','M',' ')}}, /* Romanian */
+ {"rom", {HB_TAG('R','O','Y',' ')}}, /* Romany [macrolanguage] */
+ {"rtm", {HB_TAG('R','T','M',' ')}}, /* Rotuman */
+ {"ru", {HB_TAG('R','U','S',' ')}}, /* Russian */
+ {"rue", {HB_TAG('R','S','Y',' ')}}, /* Rusyn */
+ {"rup", {HB_TAG('R','U','P',' ')}}, /* Aromanian */
+ {"rw", {HB_TAG('R','U','A',' ')}}, /* Kinyarwanda */
+ {"rwr", {HB_TAG('M','A','W',' ')}}, /* Marwari (India) */
+ {"sa", {HB_TAG('S','A','N',' ')}}, /* Sanskrit */
+ {"sah", {HB_TAG('Y','A','K',' ')}}, /* Yakut -> Sakha */
+ {"sam", {HB_TAG('P','A','A',' ')}}, /* Samaritan Aramaic -> Palestinian Aramaic */
+ {"sas", {HB_TAG('S','A','S',' ')}}, /* Sasak */
+ {"sat", {HB_TAG('S','A','T',' ')}}, /* Santali */
+ {"sc", {HB_TAG('S','R','D',' ')}}, /* Sardinian [macrolanguage] */
+ {"sck", {HB_TAG('S','A','D',' ')}}, /* Sadri */
+ {"scn", {HB_TAG('S','C','N',' ')}}, /* Sicilian */
+ {"sco", {HB_TAG('S','C','O',' ')}}, /* Scots */
+ {"scs", {HB_TAG('S','C','S',' '), /* North Slavey */
+ HB_TAG('S','L','A',' '), /* North Slavey -> Slavey */
+ HB_TAG('A','T','H',' ')}}, /* North Slavey -> Athapaskan */
+ {"sd", {HB_TAG('S','N','D',' ')}}, /* Sindhi */
+ {"sdc", {HB_TAG('S','R','D',' ')}}, /* Sassarese Sardinian -> Sardinian */
+ {"sdh", {HB_TAG('K','U','R',' ')}}, /* Southern Kurdish -> Kurdish */
+ {"sdn", {HB_TAG('S','R','D',' ')}}, /* Gallurese Sardinian -> Sardinian */
+ {"se", {HB_TAG('N','S','M',' ')}}, /* Northern Sami */
+ {"seh", {HB_TAG('S','N','A',' ')}}, /* Sena */
+ {"sek", {HB_TAG('A','T','H',' ')}}, /* Sekani -> Athapaskan */
+ {"sel", {HB_TAG('S','E','L',' ')}}, /* Selkup */
+ {"sez", {HB_TAG('Q','I','N',' ')}}, /* Senthang Chin -> Chin */
+ {"sfm", {HB_TAG('H','M','N',' ')}}, /* Small Flowery Miao -> Hmong */
+ {"sg", {HB_TAG('S','G','O',' ')}}, /* Sango */
+ {"sga", {HB_TAG('S','G','A',' ')}}, /* Old Irish (to 900) */
+ {"sgc", {HB_TAG('K','A','L',' ')}}, /* Kipsigis -> Kalenjin */
+ {"sgs", {HB_TAG('S','G','S',' ')}}, /* Samogitian */
+ {"sgw", {HB_TAG('C','H','G',' '), /* Sebat Bet Gurage -> Chaha Gurage */
+ HB_TAG('S','G','W',' ')}}, /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */
+ {"shi", {HB_TAG('S','H','I',' ')}}, /* Tachelhit */
+ {"shn", {HB_TAG('S','H','N',' ')}}, /* Shan */
+ {"shu", {HB_TAG('A','R','A',' ')}}, /* Chadian Arabic -> Arabic */
+ {"si", {HB_TAG('S','N','H',' ')}}, /* Sinhala (Sinhalese) */
+ {"sid", {HB_TAG('S','I','D',' ')}}, /* Sidamo */
+ {"sjd", {HB_TAG('K','S','M',' ')}}, /* Kildin Sami */
+ {"sjo", {HB_TAG('S','I','B',' ')}}, /* Xibe -> Sibe */
+ {"sk", {HB_TAG('S','K','Y',' ')}}, /* Slovak */
+ {"skg", {HB_TAG('M','L','G',' ')}}, /* Sakalava Malagasy -> Malagasy */
+ {"skr", {HB_TAG('S','R','K',' ')}}, /* Saraiki */
+ {"sl", {HB_TAG('S','L','V',' ')}}, /* Slovenian */
+ {"sm", {HB_TAG('S','M','O',' ')}}, /* Samoan */
+ {"sma", {HB_TAG('S','S','M',' ')}}, /* Southern Sami */
+ {"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','0')}}, /* Shona */
+ {"snk", {HB_TAG('S','N','K',' ')}}, /* Soninke */
+ {"so", {HB_TAG('S','M','L',' ')}}, /* Somali */
+ {"sop", {HB_TAG('S','O','P',' ')}}, /* Songe */
+ {"spv", {HB_TAG('O','R','I',' ')}}, /* Sambalpuri -> Odia (formerly Oriya) */
+ {"spy", {HB_TAG('K','A','L',' ')}}, /* Sabaot -> Kalenjin */
+ {"sq", {HB_TAG('S','Q','I',' ')}}, /* Albanian [macrolanguage] */
+ {"sr", {HB_TAG('S','R','B',' ')}}, /* Serbian */
+ {"src", {HB_TAG('S','R','D',' ')}}, /* Logudorese Sardinian -> Sardinian */
+ {"sro", {HB_TAG('S','R','D',' ')}}, /* Campidanese Sardinian -> Sardinian */
+ {"srr", {HB_TAG('S','R','R',' ')}}, /* Serer */
+ {"srs", {HB_TAG('A','T','H',' ')}}, /* Sarsi -> Athapaskan */
+ {"ss", {HB_TAG('S','W','Z',' ')}}, /* Swati */
+ {"ssh", {HB_TAG('A','R','A',' ')}}, /* Shihhi Arabic -> Arabic */
+ {"st", {HB_TAG('S','O','T',' ')}}, /* Southern Sotho -> Sotho, Southern */
+ {"stq", {HB_TAG('S','T','Q',' ')}}, /* Saterfriesisch -> Saterland Frisian */
+ {"stv", {HB_TAG('S','I','G',' ')}}, /* Silt'e -> Silte Gurage */
+ {"su", {HB_TAG('S','U','N',' ')}}, /* Sundanese */
+ {"suk", {HB_TAG('S','U','K',' ')}}, /* Sukuma */
+ {"suq", {HB_TAG('S','U','R',' ')}}, /* Suri */
+ {"sv", {HB_TAG('S','V','E',' ')}}, /* Swedish */
+ {"sva", {HB_TAG('S','V','A',' ')}}, /* Svan */
+ {"sw", {HB_TAG('S','W','K',' ')}}, /* Swahili [macrolanguage] */
+ {"swb", {HB_TAG('C','M','R',' ')}}, /* Maore Comorian -> Comorian */
+ {"swc", {HB_TAG('S','W','K',' ')}}, /* Congo Swahili -> Swahili */
+ {"swh", {HB_TAG('S','W','K',' ')}}, /* Swahili */
+ {"swv", {HB_TAG('M','A','W',' ')}}, /* Shekhawati -> Marwari */
+ {"sxu", {HB_TAG('S','X','U',' ')}}, /* Upper Saxon */
+ {"syc", {HB_TAG('S','Y','R',' ')}}, /* Classical Syriac -> Syriac */
+ {"syl", {HB_TAG('S','Y','L',' ')}}, /* Sylheti */
+ {"syr", {HB_TAG('S','Y','R',' ')}}, /* Syriac [macrolanguage] */
+ {"szl", {HB_TAG('S','Z','L',' ')}}, /* Silesian */
+ {"ta", {HB_TAG('T','A','M',' ')}}, /* Tamil */
+ {"taa", {HB_TAG('A','T','H',' ')}}, /* Lower Tanana -> Athapaskan */
+ {"tab", {HB_TAG('T','A','B',' ')}}, /* Tabassaran -> Tabasaran */
+ {"taq", {HB_TAG('T','M','H',' ')}}, /* Tamasheq -> Tamashek */
+ {"tau", {HB_TAG('A','T','H',' ')}}, /* Upper Tanana -> Athapaskan */
+ {"tcb", {HB_TAG('A','T','H',' ')}}, /* Tanacross -> Athapaskan */
+ {"tce", {HB_TAG('A','T','H',' ')}}, /* Southern Tutchone -> Athapaskan */
+ {"tcp", {HB_TAG('Q','I','N',' ')}}, /* Tawr Chin -> Chin */
+ {"tcy", {HB_TAG('T','U','L',' ')}}, /* Tulu -> Tumbuka */
+ {"tcz", {HB_TAG('Q','I','N',' ')}}, /* Thado Chin -> Chin */
+ {"tdd", {HB_TAG('T','D','D',' ')}}, /* Tai Nüa -> Dehong Dai */
+ {"tdx", {HB_TAG('M','L','G',' ')}}, /* Tandroy-Mahafaly Malagasy -> Malagasy */
+ {"te", {HB_TAG('T','E','L',' ')}}, /* Telugu */
+ {"tec", {HB_TAG('K','A','L',' ')}}, /* Terik -> Kalenjin */
+ {"tem", {HB_TAG('T','M','N',' ')}}, /* Timne -> Temne */
+ {"tet", {HB_TAG('T','E','T',' ')}}, /* Tetum */
+ {"tfn", {HB_TAG('A','T','H',' ')}}, /* Tanaina -> Athapaskan */
+ {"tg", {HB_TAG('T','A','J',' ')}}, /* Tajik -> Tajiki */
+ {"tgj", {HB_TAG('N','I','S',' ')}}, /* Tagin -> Nisi */
+ {"tgx", {HB_TAG('A','T','H',' ')}}, /* Tagish -> Athapaskan */
+ {"th", {HB_TAG('T','H','A',' ')}}, /* Thai */
+ {"tht", {HB_TAG('A','T','H',' ')}}, /* Tahltan -> Athapaskan */
+ {"thv", {HB_TAG('T','M','H',' ')}}, /* Tahaggart Tamahaq -> Tamashek */
+ {"thz", {HB_TAG('T','M','H',' ')}}, /* Tayart Tamajeq -> Tamashek */
+ {"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 */
+ {"tkg", {HB_TAG('M','L','G',' ')}}, /* Tesaka Malagasy -> Malagasy */
+ {"tl", {HB_TAG('T','G','L',' ')}}, /* Tagalog */
+ {"tmh", {HB_TAG('T','M','H',' ')}}, /* Tamashek [macrolanguage] */
+ {"tmw", {HB_TAG('M','L','Y',' ')}}, /* Temuan -> Malay */
+ {"tn", {HB_TAG('T','N','A',' ')}}, /* Tswana */
+ {"tnf", {HB_TAG('D','R','I',' ')}}, /* Tangshewi (retired code) -> Dari */
+ {"to", {HB_TAG('T','G','N',' ')}}, /* Tonga (Tonga Islands) -> Tongan */
+ {"tod", {HB_TAG('T','O','D','0')}}, /* Toma */
+ {"toi", {HB_TAG('T','N','G',' ')}}, /* Tonga (Zambia) */
+ {"tol", {HB_TAG('A','T','H',' ')}}, /* Tolowa -> Athapaskan */
+ {"tpi", {HB_TAG('T','P','I',' ')}}, /* Tok Pisin */
+ {"tr", {HB_TAG('T','R','K',' ')}}, /* Turkish */
+ {"tru", {HB_TAG('T','U','A',' '), /* Turoyo -> Turoyo Aramaic */
+ HB_TAG('S','Y','R',' ')}}, /* Turoyo -> Syriac */
+ {"ts", {HB_TAG('T','S','G',' ')}}, /* Tsonga */
+ {"tsj", {HB_TAG('T','S','J',' ')}}, /* Tshangla */
+ {"tt", {HB_TAG('T','A','T',' ')}}, /* Tatar */
+ {"ttm", {HB_TAG('A','T','H',' ')}}, /* Northern Tutchone -> Athapaskan */
+ {"ttq", {HB_TAG('T','M','H',' ')}}, /* Tawallammat Tamajaq -> Tamashek */
+ {"tum", {HB_TAG('T','U','M',' ')}}, /* Tumbuka -> Tulu */
+ {"tuu", {HB_TAG('A','T','H',' ')}}, /* Tututni -> Athapaskan */
+ {"tuy", {HB_TAG('K','A','L',' ')}}, /* Tugen -> Kalenjin */
+ {"tvl", {HB_TAG('T','V','L',' ')}}, /* Tuvalu */
+ {"tw", {HB_TAG('T','W','I',' '), /* Twi */
+ HB_TAG('A','K','A',' ')}}, /* Twi -> Akan */
+ {"txc", {HB_TAG('A','T','H',' ')}}, /* Tsetsaut -> Athapaskan */
+ {"txy", {HB_TAG('M','L','G',' ')}}, /* Tanosy Malagasy -> Malagasy */
+ {"ty", {HB_TAG('T','H','T',' ')}}, /* Tahitian */
+ {"tyv", {HB_TAG('T','U','V',' ')}}, /* Tuvinian -> Tuvin */
+ {"tyz", {HB_TAG('T','Y','Z',' ')}}, /* Tày */
+ {"tzm", {HB_TAG('T','Z','M',' ')}}, /* Central Atlas Tamazight -> Tamazight */
+ {"tzo", {HB_TAG('T','Z','O',' ')}}, /* Tzotzil */
+ {"ubl", {HB_TAG('B','I','K',' ')}}, /* Buhi'non Bikol -> Bikol */
+ {"udm", {HB_TAG('U','D','M',' ')}}, /* Udmurt */
+ {"ug", {HB_TAG('U','Y','G',' ')}}, /* Uyghur */
+ {"uk", {HB_TAG('U','K','R',' ')}}, /* Ukrainian */
+ {"umb", {HB_TAG('U','M','B',' ')}}, /* Umbundu */
+ {"unr", {HB_TAG('M','U','N',' ')}}, /* Mundari */
+ {"ur", {HB_TAG('U','R','D',' ')}}, /* Urdu */
+ {"urk", {HB_TAG('M','L','Y',' ')}}, /* Urak Lawoi' -> Malay */
+ {"uz", {HB_TAG('U','Z','B',' ')}}, /* Uzbek [macrolanguage] */
+ {"uzn", {HB_TAG('U','Z','B',' ')}}, /* Northern Uzbek -> Uzbek */
+ {"uzs", {HB_TAG('U','Z','B',' ')}}, /* Southern Uzbek -> Uzbek */
+ {"ve", {HB_TAG('V','E','N',' ')}}, /* Venda */
+ {"vec", {HB_TAG('V','E','C',' ')}}, /* Venetian */
+ {"vi", {HB_TAG('V','I','T',' ')}}, /* Vietnamese */
+ {"vkk", {HB_TAG('M','L','Y',' ')}}, /* Kaur -> Malay */
+ {"vkt", {HB_TAG('M','L','Y',' ')}}, /* Tenggarong Kutai Malay -> Malay */
+ {"vls", {HB_TAG('F','L','E',' ')}}, /* Vlaams -> Dutch (Flemish) */
+ {"vmw", {HB_TAG('M','A','K',' ')}}, /* Makhuwa */
+ {"vo", {HB_TAG('V','O','L',' ')}}, /* Volapük */
+ {"vro", {HB_TAG('V','R','O',' ')}}, /* Võro */
+ {"wa", {HB_TAG('W','L','N',' ')}}, /* Walloon */
+ {"war", {HB_TAG('W','A','R',' ')}}, /* Waray (Philippines) -> Waray-Waray */
+ {"wbm", {HB_TAG('W','A',' ',' ')}}, /* Wa */
+ {"wbr", {HB_TAG('W','A','G',' ')}}, /* Wagdi */
+ {"wlc", {HB_TAG('C','M','R',' ')}}, /* Mwali Comorian -> Comorian */
+ {"wle", {HB_TAG('S','I','G',' ')}}, /* Wolane -> Silte Gurage */
+ {"wlk", {HB_TAG('A','T','H',' ')}}, /* Wailaki -> Athapaskan */
+ {"wni", {HB_TAG('C','M','R',' ')}}, /* Ndzwani Comorian -> Comorian */
+ {"wo", {HB_TAG('W','L','F',' ')}}, /* Wolof */
+ {"wry", {HB_TAG('M','A','W',' ')}}, /* Merwari -> Marwari */
+ {"wsg", {HB_TAG('G','O','N',' ')}}, /* Adilabad Gondi -> Gondi */
+ {"wtm", {HB_TAG('W','T','M',' ')}}, /* Mewati */
+ {"wuu", {HB_TAG('Z','H','S',' ')}}, /* Wu Chinese -> Chinese Simplified */
+ {"xal", {HB_TAG('K','L','M',' '), /* Kalmyk */
+ HB_TAG('T','O','D',' ')}}, /* Kalmyk -> Todo */
+ {"xan", {HB_TAG('S','E','K',' ')}}, /* Xamtanga -> Sekota */
+ {"xh", {HB_TAG('X','H','S',' ')}}, /* Xhosa */
+ {"xjb", {HB_TAG('X','J','B',' ')}}, /* Minjungbal -> Minjangbal */
+ {"xkf", {HB_TAG('X','K','F',' ')}}, /* Khengkha */
+ {"xmm", {HB_TAG('M','L','Y',' ')}}, /* Manado Malay -> Malay */
+ {"xmv", {HB_TAG('M','L','G',' ')}}, /* Antankarana Malagasy -> Malagasy */
+ {"xmw", {HB_TAG('M','L','G',' ')}}, /* Tsimihety Malagasy -> Malagasy */
+ {"xnr", {HB_TAG('D','G','R',' ')}}, /* Kangri -> Dogri */
+ {"xog", {HB_TAG('X','O','G',' ')}}, /* Soga */
+ {"xpe", {HB_TAG('X','P','E',' ')}}, /* Liberia Kpelle -> Kpelle (Liberia) */
+ {"xsl", {HB_TAG('S','S','L',' '), /* South Slavey */
+ HB_TAG('S','L','A',' '), /* South Slavey -> Slavey */
+ HB_TAG('A','T','H',' ')}}, /* South Slavey -> Athapaskan */
+ {"xst", {HB_TAG('S','I','G',' ')}}, /* Silt'e (retired code) -> Silte Gurage */
+ {"xwo", {HB_TAG('T','O','D',' ')}}, /* Written Oirat -> Todo */
+ {"yao", {HB_TAG('Y','A','O',' ')}}, /* Yao */
+ {"yap", {HB_TAG('Y','A','P',' ')}}, /* Yapese */
+ {"ybd", {HB_TAG('A','R','K',' ')}}, /* Yangbye (retired code) -> Rakhine */
+ {"ydd", {HB_TAG('J','I','I',' ')}}, /* Eastern Yiddish -> Yiddish */
+ {"yi", {HB_TAG('J','I','I',' ')}}, /* Yiddish [macrolanguage] */
+ {"yih", {HB_TAG('J','I','I',' ')}}, /* Western Yiddish -> Yiddish */
+ {"yo", {HB_TAG('Y','B','A',' ')}}, /* Yoruba */
+ {"yos", {HB_TAG('Q','I','N',' ')}}, /* Yos (retired code) -> Chin */
+ {"yrk", {HB_TAG('T','N','E',' '), /* Nenets -> Tundra Nenets */
+ HB_TAG('F','N','E',' ')}}, /* Nenets -> Forest Nenets */
+ {"yue", {HB_TAG('Z','H','H',' ')}}, /* Yue Chinese -> Chinese, Hong Kong SAR */
+ {"za", {HB_TAG('Z','H','A',' ')}}, /* Zhuang [macrolanguage] */
+ {"zch", {HB_TAG('Z','H','A',' ')}}, /* Central Hongshuihe Zhuang -> Zhuang */
+ {"zdj", {HB_TAG('C','M','R',' ')}}, /* Ngazidja Comorian -> Comorian */
+ {"zea", {HB_TAG('Z','E','A',' ')}}, /* Zeeuws -> Zealandic */
+ {"zeh", {HB_TAG('Z','H','A',' ')}}, /* Eastern Hongshuihe Zhuang -> Zhuang */
+ {"zgb", {HB_TAG('Z','H','A',' ')}}, /* Guibei Zhuang -> Zhuang */
+ {"zgh", {HB_TAG('Z','G','H',' ')}}, /* Standard Moroccan Tamazight */
+ {"zgm", {HB_TAG('Z','H','A',' ')}}, /* Minz Zhuang -> Zhuang */
+ {"zgn", {HB_TAG('Z','H','A',' ')}}, /* Guibian Zhuang -> Zhuang */
+ {"zh", {HB_TAG('Z','H','S',' ')}}, /* Chinese [macrolanguage] -> Chinese Simplified */
+ {"zhd", {HB_TAG('Z','H','A',' ')}}, /* Dai Zhuang -> Zhuang */
+ {"zhn", {HB_TAG('Z','H','A',' ')}}, /* Nong Zhuang -> Zhuang */
+ {"zlj", {HB_TAG('Z','H','A',' ')}}, /* Liujiang Zhuang -> Zhuang */
+ {"zlm", {HB_TAG('M','L','Y',' ')}}, /* Malay */
+ {"zln", {HB_TAG('Z','H','A',' ')}}, /* Lianshan Zhuang -> Zhuang */
+ {"zlq", {HB_TAG('Z','H','A',' ')}}, /* Liuqian Zhuang -> Zhuang */
+ {"zmi", {HB_TAG('M','L','Y',' ')}}, /* Negeri Sembilan Malay -> Malay */
+ {"zne", {HB_TAG('Z','N','D',' ')}}, /* Zande */
+ {"zom", {HB_TAG('Q','I','N',' ')}}, /* Zou -> Chin */
+ {"zqe", {HB_TAG('Z','H','A',' ')}}, /* Qiubei Zhuang -> Zhuang */
+ {"zsm", {HB_TAG('M','L','Y',' ')}}, /* Standard Malay -> Malay */
+ {"zu", {HB_TAG('Z','U','L',' ')}}, /* Zulu */
+ {"zum", {HB_TAG('L','R','C',' ')}}, /* Kumzari -> Luri */
+ {"zyb", {HB_TAG('Z','H','A',' ')}}, /* Yongbei Zhuang -> Zhuang */
+ {"zyg", {HB_TAG('Z','H','A',' ')}}, /* Yang Zhuang -> Zhuang */
+ {"zyj", {HB_TAG('Z','H','A',' ')}}, /* Youjiang Zhuang -> Zhuang */
+ {"zyn", {HB_TAG('Z','H','A',' ')}}, /* Yongnan Zhuang -> Zhuang */
+ {"zza", {HB_TAG('Z','Z','A',' ')}}, /* Zazaki [macrolanguage] */
+ {"zzj", {HB_TAG('Z','H','A',' ')}}, /* Zuojiang Zhuang -> Zhuang */
+};
+
+static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == 3u, "");
+
+/**
+ * hb_ot_tags_from_complex_language:
+ * @lang_str: a BCP 47 language tag to convert.
+ * @limit: a pointer to the end of the substring of @lang_str to consider for
+ * conversion.
+ * @count: maximum number of language tags to retrieve (IN) and actual number of
+ * language tags retrieved (OUT). If no tags are retrieved, it is not modified.
+ * @tags: array of size at least @language_count to store the language tag
+ * results
+ *
+ * Converts a multi-subtag BCP 47 language tag to language tags.
+ *
+ * Return value: Whether any language systems were retrieved.
+ **/
+static bool
+hb_ot_tags_from_complex_language (const char *lang_str,
+ const char *limit,
+ unsigned int *count /* IN/OUT */,
+ hb_tag_t *tags /* OUT */)
+{
+ if (subtag_matches (lang_str, limit, "-fonnapa"))
+ {
+ /* Undetermined; North American Phonetic Alphabet */
+ tags[0] = HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (lang_str, limit, "-polyton"))
+ {
+ /* Modern Greek (1453-); Polytonic Greek */
+ tags[0] = HB_TAG('P','G','R',' '); /* Polytonic Greek */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (lang_str, limit, "-provenc"))
+ {
+ /* Occitan (post 1500); Provençal */
+ tags[0] = HB_TAG('P','R','O',' '); /* Provençal / Old Provençal */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (lang_str, limit, "-fonipa"))
+ {
+ /* Undetermined; International Phonetic Alphabet */
+ tags[0] = HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (lang_str, limit, "-geok"))
+ {
+ /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
+ tags[0] = HB_TAG('K','G','E',' '); /* Khutsuri Georgian */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (lang_str, limit, "-syre"))
+ {
+ /* Undetermined; Syriac (Estrangelo variant) */
+ tags[0] = HB_TAG('S','Y','R','E'); /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (lang_str, limit, "-syrj"))
+ {
+ /* Undetermined; Syriac (Western variant) */
+ tags[0] = HB_TAG('S','Y','R','J'); /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */
+ *count = 1;
+ return true;
+ }
+ if (subtag_matches (lang_str, limit, "-syrn"))
+ {
+ /* Undetermined; Syriac (Eastern variant) */
+ tags[0] = HB_TAG('S','Y','R','N'); /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */
+ *count = 1;
+ return true;
+ }
+ switch (lang_str[0])
+ {
+ case 'a':
+ if (0 == strcmp (&lang_str[1], "rt-lojban"))
+ {
+ /* Lojban */
+ tags[0] = HB_TAG('J','B','O',' '); /* Lojban */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'c':
+ if (lang_matches (&lang_str[1], "do-hant-hk"))
+ {
+ /* Min Dong Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "do-hant-mo"))
+ {
+ /* Min Dong Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "jy-hant-hk"))
+ {
+ /* Jinyu Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "jy-hant-mo"))
+ {
+ /* Jinyu Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "mn-hant-hk"))
+ {
+ /* Mandarin Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "mn-hant-mo"))
+ {
+ /* Mandarin Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "px-hant-hk"))
+ {
+ /* Pu-Xian Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "px-hant-mo"))
+ {
+ /* Pu-Xian Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zh-hant-hk"))
+ {
+ /* Huizhou Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zh-hant-mo"))
+ {
+ /* Huizhou Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zo-hant-hk"))
+ {
+ /* Min Zhong Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zo-hant-mo"))
+ {
+ /* Min Zhong Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "do-hans"))
+ {
+ /* Min Dong Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "do-hant"))
+ {
+ /* Min Dong Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "jy-hans"))
+ {
+ /* Jinyu Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "jy-hant"))
+ {
+ /* Jinyu Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "mn-hans"))
+ {
+ /* Mandarin Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "mn-hant"))
+ {
+ /* Mandarin Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "px-hans"))
+ {
+ /* Pu-Xian Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "px-hant"))
+ {
+ /* Pu-Xian Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zh-hans"))
+ {
+ /* Huizhou Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zh-hant"))
+ {
+ /* Huizhou Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zo-hans"))
+ {
+ /* Min Zhong Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "zo-hant"))
+ {
+ /* Min Zhong Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "do-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Min Dong Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "do-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Min Dong Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "do-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Min Dong Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "jy-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Jinyu Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "jy-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Jinyu Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "jy-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Jinyu Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "mn-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Mandarin Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "mn-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Mandarin Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "mn-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Mandarin Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "px-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Pu-Xian Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "px-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Pu-Xian Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "px-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Pu-Xian Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "zh-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Huizhou Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "zh-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Huizhou Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "zh-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Huizhou Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "zo-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Min Zhong Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "zo-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Min Zhong Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "zo-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Min Zhong Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'g':
+ if (lang_matches (&lang_str[1], "an-hant-hk"))
+ {
+ /* Gan Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "an-hant-mo"))
+ {
+ /* Gan Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "an-hans"))
+ {
+ /* Gan Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "an-hant"))
+ {
+ /* Gan Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "a-latg"))
+ {
+ /* Irish */
+ tags[0] = HB_TAG('I','R','T',' '); /* Irish Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "an-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Gan Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "an-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Gan Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "an-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Gan Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'h':
+ if (lang_matches (&lang_str[1], "ak-hant-hk"))
+ {
+ /* Hakka Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "ak-hant-mo"))
+ {
+ /* Hakka Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "sn-hant-hk"))
+ {
+ /* Xiang Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "sn-hant-mo"))
+ {
+ /* Xiang Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "ak-hans"))
+ {
+ /* Hakka Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "ak-hant"))
+ {
+ /* Hakka Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "sn-hans"))
+ {
+ /* Xiang Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "sn-hant"))
+ {
+ /* Xiang Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "ak-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Hakka Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "ak-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Hakka Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "ak-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Hakka Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "sn-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Xiang Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "sn-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Xiang Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "sn-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Xiang Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'i':
+ if (0 == strcmp (&lang_str[1], "-navajo"))
+ {
+ /* Navajo */
+ unsigned int i;
+ hb_tag_t possible_tags[] = {
+ HB_TAG('N','A','V',' '), /* Navajo */
+ HB_TAG('A','T','H',' '), /* Athapaskan */
+ };
+ for (i = 0; i < 2 && i < *count; i++)
+ tags[i] = possible_tags[i];
+ *count = i;
+ return true;
+ }
+ if (0 == strcmp (&lang_str[1], "-hak"))
+ {
+ /* Hakka */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (0 == strcmp (&lang_str[1], "-lux"))
+ {
+ /* Luxembourgish */
+ tags[0] = HB_TAG('L','T','Z',' '); /* Luxembourgish */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'l':
+ if (lang_matches (&lang_str[1], "zh-hans"))
+ {
+ /* Literary Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'm':
+ if (lang_matches (&lang_str[1], "np-hant-hk"))
+ {
+ /* Min Bei Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "np-hant-mo"))
+ {
+ /* Min Bei Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "np-hans"))
+ {
+ /* Min Bei Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "np-hant"))
+ {
+ /* Min Bei Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "np-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Min Bei Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "np-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Min Bei Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "np-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Min Bei Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'n':
+ if (lang_matches (&lang_str[1], "an-hant-hk"))
+ {
+ /* Min Nan Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "an-hant-mo"))
+ {
+ /* Min Nan Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "an-hans"))
+ {
+ /* Min Nan Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "an-hant"))
+ {
+ /* Min Nan Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "an-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Min Nan Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "an-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Min Nan Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "an-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Min Nan Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strcmp (&lang_str[1], "o-bok"))
+ {
+ /* Norwegian Bokmal */
+ tags[0] = HB_TAG('N','O','R',' '); /* Norwegian */
+ *count = 1;
+ return true;
+ }
+ if (0 == strcmp (&lang_str[1], "o-nyn"))
+ {
+ /* Norwegian Nynorsk */
+ tags[0] = HB_TAG('N','Y','N',' '); /* Norwegian Nynorsk (Nynorsk, Norwegian) */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'r':
+ if (0 == strncmp (&lang_str[1], "o-", 2)
+ && subtag_matches (lang_str, limit, "-md"))
+ {
+ /* Romanian; Moldova */
+ tags[0] = HB_TAG('M','O','L',' '); /* Moldavian */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'w':
+ if (lang_matches (&lang_str[1], "uu-hant-hk"))
+ {
+ /* Wu Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "uu-hant-mo"))
+ {
+ /* Wu Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "uu-hans"))
+ {
+ /* Wu Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "uu-hant"))
+ {
+ /* Wu Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "uu-", 3)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Wu Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "uu-", 3)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Wu Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "uu-", 3)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Wu Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'y':
+ if (lang_matches (&lang_str[1], "ue-hans"))
+ {
+ /* Yue Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ break;
+ case 'z':
+ if (lang_matches (&lang_str[1], "h-hant-hk"))
+ {
+ /* Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "h-hant-mo"))
+ {
+ /* Chinese */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strcmp (&lang_str[1], "h-min-nan"))
+ {
+ /* Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "h-hans"))
+ {
+ /* Chinese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (lang_matches (&lang_str[1], "h-hant"))
+ {
+ /* Chinese */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ if (0 == strcmp (&lang_str[1], "h-min"))
+ {
+ /* Min, Fuzhou, Hokkien, Amoy, or Taiwanese */
+ tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "h-", 2)
+ && subtag_matches (lang_str, limit, "-hk"))
+ {
+ /* Chinese; Hong Kong */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "h-", 2)
+ && subtag_matches (lang_str, limit, "-mo"))
+ {
+ /* Chinese; Macao */
+ tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */
+ *count = 1;
+ return true;
+ }
+ if (0 == strncmp (&lang_str[1], "h-", 2)
+ && subtag_matches (lang_str, limit, "-tw"))
+ {
+ /* Chinese; Taiwan, Province of China */
+ tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */
+ *count = 1;
+ return true;
+ }
+ break;
+ }
+ return false;
+}
+
+/**
+ * hb_ot_ambiguous_tag_to_language
+ * @tag: A language tag.
+ *
+ * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to
+ * many language tags) and the best tag is not the alphabetically first, or if
+ * the best tag consists of multiple subtags.
+ *
+ * Return value: The #hb_language_t corresponding to the BCP 47 language tag,
+ * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.
+ **/
+static hb_language_t
+hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
+{
+ switch (tag)
+ {
+ case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
+ return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */
+ case HB_TAG('A','R','A',' '): /* Arabic */
+ return hb_language_from_string ("ar", -1); /* Arabic */
+ case HB_TAG('A','R','K',' '): /* Rakhine */
+ return hb_language_from_string ("rki", -1); /* Rakhine */
+ case HB_TAG('A','T','H',' '): /* Athapaskan */
+ return hb_language_from_string ("ath", -1); /* Athapascan */
+ case HB_TAG('B','I','K',' '): /* Bikol */
+ return hb_language_from_string ("bik", -1); /* Bikol */
+ case HB_TAG('C','P','P',' '): /* Creoles */
+ return hb_language_from_string ("crp", -1); /* Creoles and pidgins */
+ case HB_TAG('C','R','R',' '): /* Carrier */
+ return hb_language_from_string ("crx", -1); /* Carrier */
+ case HB_TAG('D','N','K',' '): /* Dinka */
+ return hb_language_from_string ("din", -1); /* Dinka */
+ case HB_TAG('D','R','I',' '): /* Dari */
+ return hb_language_from_string ("prs", -1); /* Dari */
+ case HB_TAG('D','U','J',' '): /* Dhuwal */
+ return hb_language_from_string ("dwu", -1); /* Dhuwal */
+ case HB_TAG('D','Z','N',' '): /* Dzongkha */
+ return hb_language_from_string ("dz", -1); /* Dzongkha */
+ case HB_TAG('E','T','I',' '): /* Estonian */
+ return hb_language_from_string ("et", -1); /* Estonian */
+ case HB_TAG('G','O','N',' '): /* Gondi */
+ return hb_language_from_string ("gon", -1); /* Gondi */
+ case HB_TAG('H','M','N',' '): /* Hmong */
+ return hb_language_from_string ("hmn", -1); /* Hmong */
+ case HB_TAG('I','J','O',' '): /* Ijo */
+ return hb_language_from_string ("ijo", -1); /* Ijo */
+ case HB_TAG('I','N','U',' '): /* Inuktitut */
+ return hb_language_from_string ("iu", -1); /* Inuktitut */
+ case HB_TAG('I','P','K',' '): /* Inupiat */
+ return hb_language_from_string ("ik", -1); /* Inupiaq */
+ case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
+ return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */
+ case HB_TAG('I','R','T',' '): /* Irish Traditional */
+ return hb_language_from_string ("ga-Latg", -1); /* Irish; Latin (Gaelic variant) */
+ case HB_TAG('J','I','I',' '): /* Yiddish */
+ return hb_language_from_string ("yi", -1); /* Yiddish */
+ case HB_TAG('K','A','L',' '): /* Kalenjin */
+ return hb_language_from_string ("kln", -1); /* Kalenjin */
+ case HB_TAG('K','G','E',' '): /* Khutsuri Georgian */
+ return hb_language_from_string ("und-Geok", -1); /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */
+ case HB_TAG('K','N','R',' '): /* Kanuri */
+ return hb_language_from_string ("kr", -1); /* Kanuri */
+ case HB_TAG('K','O','K',' '): /* Konkani */
+ return hb_language_from_string ("kok", -1); /* Konkani */
+ case HB_TAG('K','U','R',' '): /* Kurdish */
+ return hb_language_from_string ("ku", -1); /* Kurdish */
+ case HB_TAG('L','U','H',' '): /* Luyia */
+ return hb_language_from_string ("luy", -1); /* Luyia */
+ case HB_TAG('L','V','I',' '): /* Latvian */
+ return hb_language_from_string ("lv", -1); /* Latvian */
+ case HB_TAG('M','A','W',' '): /* Marwari */
+ return hb_language_from_string ("mwr", -1); /* Marwari */
+ case HB_TAG('M','L','G',' '): /* Malagasy */
+ return hb_language_from_string ("mg", -1); /* Malagasy */
+ case HB_TAG('M','L','Y',' '): /* Malay */
+ return hb_language_from_string ("ms", -1); /* Malay */
+ case HB_TAG('M','N','G',' '): /* Mongolian */
+ return hb_language_from_string ("mn", -1); /* Mongolian */
+ case HB_TAG('M','O','L',' '): /* Moldavian */
+ return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */
+ case HB_TAG('N','E','P',' '): /* Nepali */
+ return hb_language_from_string ("ne", -1); /* Nepali */
+ case HB_TAG('N','I','S',' '): /* Nisi */
+ return hb_language_from_string ("njz", -1); /* Nyishi */
+ case HB_TAG('N','O','R',' '): /* Norwegian */
+ return hb_language_from_string ("no", -1); /* Norwegian */
+ case HB_TAG('O','J','B',' '): /* Ojibway */
+ return hb_language_from_string ("oj", -1); /* Ojibwa */
+ case HB_TAG('O','R','O',' '): /* Oromo */
+ return hb_language_from_string ("om", -1); /* Oromo */
+ case HB_TAG('P','A','S',' '): /* Pashto */
+ return hb_language_from_string ("ps", -1); /* Pashto */
+ case HB_TAG('P','G','R',' '): /* Polytonic Greek */
+ return hb_language_from_string ("el-polyton", -1); /* Modern Greek (1453-); Polytonic Greek */
+ case HB_TAG('P','R','O',' '): /* Provençal / Old Provençal */
+ return hb_language_from_string ("pro", -1); /* Old Provençal (to 1500) */
+ case HB_TAG('Q','U','H',' '): /* Quechua (Bolivia) */
+ return hb_language_from_string ("quh", -1); /* South Bolivian Quechua */
+ case HB_TAG('Q','V','I',' '): /* Quechua (Ecuador) */
+ return hb_language_from_string ("qvi", -1); /* Imbabura Highland Quichua */
+ case HB_TAG('Q','W','H',' '): /* Quechua (Peru) */
+ return hb_language_from_string ("qwh", -1); /* Huaylas Ancash Quechua */
+ case HB_TAG('R','A','J',' '): /* Rajasthani */
+ return hb_language_from_string ("raj", -1); /* Rajasthani */
+ case HB_TAG('R','O','Y',' '): /* Romany */
+ return hb_language_from_string ("rom", -1); /* Romany */
+ case HB_TAG('S','Q','I',' '): /* Albanian */
+ return hb_language_from_string ("sq", -1); /* Albanian */
+ case HB_TAG('S','Y','R',' '): /* Syriac */
+ return hb_language_from_string ("syr", -1); /* Syriac */
+ case HB_TAG('S','Y','R','E'): /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */
+ return hb_language_from_string ("und-Syre", -1); /* Undetermined; Syriac (Estrangelo variant) */
+ case HB_TAG('S','Y','R','J'): /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */
+ return hb_language_from_string ("und-Syrj", -1); /* Undetermined; Syriac (Western variant) */
+ case HB_TAG('S','Y','R','N'): /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */
+ return hb_language_from_string ("und-Syrn", -1); /* Undetermined; Syriac (Eastern variant) */
+ case HB_TAG('T','M','H',' '): /* Tamashek */
+ return hb_language_from_string ("tmh", -1); /* Tamashek */
+ case HB_TAG('T','N','E',' '): /* Tundra Nenets */
+ return hb_language_from_string ("yrk", -1); /* Nenets */
+ case HB_TAG('Z','H','H',' '): /* Chinese, Hong Kong SAR */
+ return hb_language_from_string ("zh-HK", -1); /* Chinese; Hong Kong */
+ case HB_TAG('Z','H','S',' '): /* Chinese Simplified */
+ return hb_language_from_string ("zh-Hans", -1); /* Chinese; Han (Simplified variant) */
+ case HB_TAG('Z','H','T',' '): /* Chinese Traditional */
+ return hb_language_from_string ("zh-Hant", -1); /* Chinese; Han (Traditional variant) */
+ default:
+ return HB_LANGUAGE_INVALID;
+ }
+}
+
+#endif /* HB_OT_TAG_TABLE_HH */
+
+/* == End of generated table == */
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index 991d8e77a..4dba9c31a 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -26,7 +26,7 @@
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
-#include "hb-private.hh"
+#include "hb.hh"
/* hb_script_t */
@@ -36,7 +36,8 @@ 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) {
+ switch ((hb_tag_t) script)
+ {
case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT;
/* KATAKANA and HIRAGANA both map to 'kana' */
@@ -49,8 +50,6 @@ hb_ot_old_tag_from_script (hb_script_t script)
case HB_SCRIPT_NKO: return HB_TAG('n','k','o',' ');
/* Unicode-5.1 additions */
case HB_SCRIPT_VAI: return HB_TAG('v','a','i',' ');
- /* Unicode-5.2 additions */
- /* Unicode-6.0 additions */
}
/* Else, just change first char to lowercase and return */
@@ -114,6 +113,18 @@ hb_ot_new_tag_to_script (hb_tag_t tag)
return HB_SCRIPT_UNKNOWN;
}
+void
+hb_ot_tags_from_script (hb_script_t script,
+ hb_tag_t *script_tag_1,
+ hb_tag_t *script_tag_2)
+{
+ unsigned int count = 2;
+ hb_tag_t tags[2];
+ hb_ot_tags_from_script_and_language (script, HB_LANGUAGE_INVALID, &count, tags, nullptr, nullptr);
+ *script_tag_1 = count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_SCRIPT;
+ *script_tag_2 = count > 1 ? tags[1] : HB_OT_TAG_DEFAULT_SCRIPT;
+}
+
/*
* Complete list at:
* https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags
@@ -122,28 +133,37 @@ hb_ot_new_tag_to_script (hb_tag_t tag)
* So we just do that, and handle the exceptional cases in a switch.
*/
-void
-hb_ot_tags_from_script (hb_script_t script,
- hb_tag_t *script_tag_1,
- hb_tag_t *script_tag_2)
+static void
+hb_ot_all_tags_from_script (hb_script_t script,
+ unsigned int *count /* IN/OUT */,
+ hb_tag_t *tags /* OUT */)
{
- hb_tag_t new_tag;
+ unsigned int i = 0;
- *script_tag_2 = HB_OT_TAG_DEFAULT_SCRIPT;
- *script_tag_1 = hb_ot_old_tag_from_script (script);
+ hb_tag_t new_tag = hb_ot_new_tag_from_script (script);
+ if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT))
+ {
+ tags[i++] = new_tag | '3';
+ if (*count > i)
+ tags[i++] = new_tag;
+ }
- new_tag = hb_ot_new_tag_from_script (script);
- if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) {
- *script_tag_2 = *script_tag_1;
- *script_tag_1 = new_tag;
+ if (*count > i)
+ {
+ hb_tag_t old_tag = hb_ot_old_tag_from_script (script);
+ if (old_tag != HB_OT_TAG_DEFAULT_SCRIPT)
+ tags[i++] = old_tag;
}
+
+ *count = i;
}
hb_script_t
hb_ot_tag_to_script (hb_tag_t tag)
{
- if (unlikely ((tag & 0x000000FFu) == '2'))
- return hb_ot_new_tag_to_script (tag);
+ unsigned char digit = tag & 0x000000FFu;
+ if (unlikely (digit == '2' || digit == '3'))
+ return hb_ot_new_tag_to_script (tag & 0xFFFFFF32);
return hb_ot_old_tag_to_script (tag);
}
@@ -151,732 +171,6 @@ hb_ot_tag_to_script (hb_tag_t tag)
/* hb_language_t */
-typedef struct {
- char language[4];
- hb_tag_t tag;
-} LangTag;
-
-/*
- * Complete list at:
- * https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
- *
- * 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.
- *
- * 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.
- *
- * Some items still missing. Those are commented out at the end.
- * Keep sorted for bsearch.
- *
- * Updated as of 2015-05-06: OT1.7 on MS website has some newer
- * items that we don't have here, eg. Zazaki. This is the new
- * items in OpenType 1.7 (red items), most of which we have:
- * https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
- */
-
-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 */
- {"acf", HB_TAG('F','A','N',' ')}, /* French Antillean */
- {"ach", HB_TAG('A','C','H',' ')}, /* Acoli */
- {"acr", HB_TAG('A','C','R',' ')}, /* Achi */
- {"ada", HB_TAG('D','N','G',' ')}, /* Dangme */
- {"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */
- {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */
- {"ahg", HB_TAG('A','G','W',' ')}, /* Agaw */
- {"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] */
- {"aka", HB_TAG('A','K','A',' ')}, /* Akan */
- {"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */
- {"am", HB_TAG('A','M','H',' ')}, /* Amharic */
- {"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */
- {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic */
- {"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] */
- {"atj", HB_TAG('R','C','R',' ')}, /* R-Cree */
- {"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 [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 */
- {"bad", HB_TAG('B','A','D','0')}, /* Banda */
- {"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 */
- {"bdy", HB_TAG('B','D','Y',' ')}, /* Bandjalang */
- {"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 */
- {"bfu", HB_TAG('L','A','H',' ')}, /* Lahuli */
- {"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 */
- {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin */
- {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */
- {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) */
- {"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */
- {"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 */
- {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */
- {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */
- {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin */
- {"cco", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
- {"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */
- {"cfm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin */
- {"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */
- {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */
- {"chj", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */
- {"cho", HB_TAG('C','H','O',' ')}, /* Choctaw */
- {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
- {"chq", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */
- {"chy", HB_TAG('C','H','Y',' ')}, /* Cheyenne */
- {"chz", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cja", HB_TAG('C','J','A',' ')}, /* Western Cham */
- {"cjm", HB_TAG('C','J','M',' ')}, /* Eastern Cham */
- {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin */
- {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */
- {"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */
- {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic */
- {"cle", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin */
- {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin */
- {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin */
- {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin */
- {"cnl", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cnt", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin */
- {"cop", HB_TAG('C','O','P',' ')}, /* Coptic */
- {"cpa", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cpp", HB_TAG('C','P','P',' ')}, /* Creoles */
- {"cr", HB_TAG('C','R','E',' ')}, /* Cree */
- {"cre", HB_TAG('Y','C','R',' ')}, /* Y-Cree */
- {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */
- {"crj", HB_TAG('E','C','R',' ')}, /* [Southern] East Cree */
- {"crk", HB_TAG('W','C','R',' ')}, /* West-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 */
- {"csa", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"csb", HB_TAG('C','S','B',' ')}, /* Kashubian */
- {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin */
- {"cso", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin */
- {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin */
- {"cte", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */
- {"ctl", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */
- {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */
- {"cuc", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cuk", HB_TAG('C','U','K',' ')}, /* San Blas Kuna */
- {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
- {"cvn", HB_TAG('C','C','H','N')}, /* Chinantec */
- {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
- {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */
- {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin */
- {"da", HB_TAG('D','A','N',' ')}, /* Danish */
- {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin */
- {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */
- {"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */
- {"dax", HB_TAG('D','A','X',' ')}, /* Dayi */
- {"de", HB_TAG('D','E','U',' ')}, /* German */
- {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri */
- {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari */
- {"dhg", HB_TAG('D','H','G',' ')}, /* Dhangu */
- {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */
- {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */
- {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */
- {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */
- {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */
- {"dnj", HB_TAG('D','N','J',' ')}, /* Dan */
- {"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */
- {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */
- {"duj", HB_TAG('D','U','J',' ')}, /* Dhuwal */
- {"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 */
- {"enf", HB_TAG('F','N','E',' ')}, /* Forest Nenets */
- {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Nenets */
- {"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 */
- {"esu", HB_TAG('E','S','U',' ')}, /* Central Yupik */
- {"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 [macrolanguage] */
- {"fan", HB_TAG('F','A','N','0')}, /* Fang */
- {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */
- {"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 */
- {"flm", HB_TAG('H','A','L',' ')}, /* Halam/Falam Chin [retired ISO639 code] */
- {"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 */
- {"fuf", HB_TAG('F','T','A',' ')}, /* Futa */
- {"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 */
- {"gih", HB_TAG('G','I','H',' ')}, /* Githabul */
- {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */
- {"gkp", HB_TAG('G','K','P',' ')}, /* Kpelle (Guinea) */
- {"gl", HB_TAG('G','A','L',' ')}, /* Galician */
- {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */
- {"glk", HB_TAG('G','L','K',' ')}, /* Gilaki */
- {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
- {"gnn", HB_TAG('G','N','N',' ')}, /* Gumatj */
- {"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 */
- {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */
- {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */
- {"guc", HB_TAG('G','U','C',' ')}, /* Wayuu */
- {"guf", HB_TAG('G','U','F',' ')}, /* Gupapuyngu */
- {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */
-/*{"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 */
- {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
- {"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
- {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin */
- {"hmn", HB_TAG('H','M','N',' ')}, /* Hmong */
- {"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/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) */
- {"iba", HB_TAG('I','B','A',' ')}, /* Iban */
- {"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 */
- {"ii", HB_TAG('Y','I','M',' ')}, /* Yi Modern */
- {"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 [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','0')}, /* Kabyle */
- {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
- {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */
- {"kat", HB_TAG('K','G','E',' ')}, /* Khutsuri Georgian */
- {"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 */
- {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */
- {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */
- {"kex", HB_TAG('K','K','N',' ')}, /* Kokni */
- {"kfa", HB_TAG('K','O','D',' ')}, /* Kodagu */
- {"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */
- {"kfx", HB_TAG('K','U','L',' ')}, /* Kulvi */
- {"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',' ')}, /* Gikuyu/Kikuyu */
- {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */
- {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama/Kwanyama */
- {"kjd", HB_TAG('K','J','D',' ')}, /* Southern Kiwai */
- {"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 [macrolanguage] */
- {"kon", HB_TAG('K','O','N','0')}, /* Kongo */
- {"kos", HB_TAG('K','O','S',' ')}, /* Kosraean */
- {"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 [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 */
- {"ksh", HB_TAG('K','S','H','0')}, /* Ripuarian, 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) */
- {"ktb", HB_TAG('K','E','B',' ')}, /* Kebena */
- {"ktu", HB_TAG('K','O','N',' ')}, /* Kikongo */
- {"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/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 */
- {"lom", HB_TAG('L','O','M',' ')}, /* Loma */
- {"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) */
- {"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 */
- {"mam", HB_TAG('M','A','M',' ')}, /* Mam */
- {"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) */
- {"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 */
- {"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 */
- {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */
- {"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 */
- {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin */
- {"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 */
- {"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 */
- {"myn", HB_TAG('M','Y','N',' ')}, /* Mayan */
- {"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 */
- {"ngo", HB_TAG('S','X','T',' ')}, /* Sutu */
- {"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 [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 */
- {"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */
- {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */
- {"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 [macrolanguage] */
- {"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */
- {"okm", HB_TAG('K','O','H',' ')}, /* Korean Old Hangul */
- {"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','0')}, /* Papiamento */
- {"pau", HB_TAG('P','A','U',' ')}, /* Palauan */
- {"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */
- {"pcd", HB_TAG('P','C','D',' ')}, /* Picard */
- {"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */
- {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin */
- {"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 */
- {"pms", HB_TAG('P','M','S',' ')}, /* Piemontese */
- {"pnb", HB_TAG('P','N','B',' ')}, /* Western Panjabi */
- {"poh", HB_TAG('P','O','H',' ')}, /* Pocomchi */
- {"pon", HB_TAG('P','O','N',' ')}, /* Pohnpeian */
- {"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 */
- {"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é */
- {"quh", HB_TAG('Q','U','H',' ')}, /* Quechua (Bolivia) */
- {"quz", HB_TAG('Q','U','Z',' ')}, /* Cusco Quechua */
- {"qvi", HB_TAG('Q','V','I',' ')}, /* Quechua (Ecuador) */
- {"qwh", HB_TAG('Q','W','H',' ')}, /* Quechua (Peru) */
- {"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani [macrolanguage] */
- {"rar", HB_TAG('R','A','R',' ')}, /* Rarotongan */
- {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung */
- {"rej", HB_TAG('R','E','J',' ')}, /* Rejang */
- {"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */
- {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */
- {"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */
- {"rit", HB_TAG('R','I','T',' ')}, /* Ritarungo */
- {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */
- {"rkw", HB_TAG('R','K','W',' ')}, /* Arakwal */
- {"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 [macrolanguage] */
- {"rtm", HB_TAG('R','T','M',' ')}, /* Rotuman */
- {"ru", HB_TAG('R','U','S',' ')}, /* Russian */
- {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */
- {"rup", HB_TAG('R','U','P',' ')}, /* Aromanian/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 */
- {"sam", HB_TAG('P','A','A',' ')}, /* Palestinian Aramaic */
- {"sas", HB_TAG('S','A','S',' ')}, /* Sasak */
- {"sat", HB_TAG('S','A','T',' ')}, /* Santali */
- {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
- {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
- {"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */
- {"sco", HB_TAG('S','C','O',' ')}, /* Scots */
- {"scs", HB_TAG('S','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 */
- {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin */
- {"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) */
- {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */
- {"shn", HB_TAG('S','H','N',' ')}, /* Shan */
- {"si", HB_TAG('S','N','H',' ')}, /* Sinhala */
- {"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */
- {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */
- {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */
- {"skr", HB_TAG('S','R','K',' ')}, /* Seraiki */
- {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */
- {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */
- {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */
- {"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','0')}, /* Shona */
- {"snk", HB_TAG('S','N','K',' ')}, /* Soninke */
- {"so", HB_TAG('S','M','L',' ')}, /* Somali */
- {"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 [macrolanguage] */
- {"swb", HB_TAG('C','M','R',' ')}, /* Comorian */
- {"swh", HB_TAG('S','W','K',' ')}, /* Kiswahili/Swahili */
- {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati */
- {"sxu", HB_TAG('S','X','U',' ')}, /* Upper Saxon */
- {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac */
- {"syl", HB_TAG('S','Y','L',' ')}, /* Sylheti */
- {"syr", HB_TAG('S','Y','R',' ')}, /* Syriac [macrolanguage] */
- {"szl", HB_TAG('S','Z','L',' ')}, /* Silesian */
- {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */
- {"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */
- {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin */
- {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */
- {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin */
- {"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 */
- {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */
- {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */
- {"tod", HB_TAG('T','O','D','0')}, /* Toma */
- {"toi", HB_TAG('T','N','G',' ')}, /* Tonga */
- {"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 */
- {"tvl", HB_TAG('T','V','L',' ')}, /* Tuvalu */
- {"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 */
- {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */
- {"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 [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 */
- {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
- {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
- {"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 */
- {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
- {"wry", HB_TAG('M','A','W',' ')}, /* Merwari */
- {"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */
- {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
- {"xan", HB_TAG('S','E','K',' ')}, /* Sekota */
- {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
- {"xjb", HB_TAG('X','J','B',' ')}, /* Minjangbal */
- {"xog", HB_TAG('X','O','G',' ')}, /* Soga */
- {"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */
- {"xpe", HB_TAG('X','P','E',' ')}, /* Kpelle (Liberia) */
- {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */
- {"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 */
- {"yap", HB_TAG('Y','A','P',' ')}, /* Yapese */
- {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
- {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
- {"yos", HB_TAG('Q','I','N',' ')}, /* Yos, deprecated by IANA in favor of Zou [zom] */
- {"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */
- {"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */
- {"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */
- {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Morrocan Tamazigh */
- {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
- {"zom", HB_TAG('Q','I','N',' ')}, /* Zou */
- {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */
- {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari */
- {"zza", HB_TAG('Z','Z','A',' ')}, /* Zazaki */
-
- /* The corresponding languages IDs for the following IDs are unclear,
- * overlap, or are architecturally weird. Needs more research. */
-
-/*{"chp", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */
-/*{"cwd", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */
-/*{"emk", HB_TAG('E','M','K',' ')},*/ /* Eastern Maninkakan */
-/*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */
-/*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */
-/*{"zh?", HB_TAG('C','H','N',' ')},*/ /* Chinese (seen in Microsoft fonts) */
-/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */
-/*{"hy?", HB_TAG('H','Y','E','0')},*/ /* Armenian East (ISO 639-3 hye according to Microsoft, but that’s equivalent to ISO 639-1 hy) */
-/*{"ga-Latg?/" HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
-/*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */
-/*{"ka-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 */
-/*{"kqs, kss", HB_TAG('K','I','S',' ')},*/ /* Kisii */
-/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */
-/*{"mlq", HB_TAG('M','L','N',' ')},*/ /* Malinke */
-/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Sotho, Northern */
-/*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */
-/*{"csw", HB_TAG('N','C','R',' ')},*/ /* N-Cree */
-/*{"csw", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */
-/*{"el-polyton", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */
-/*{"bgr, cnh, cnw, czt, sez, tcp, csy, ctd, flm, pck, tcz, zom, cmr, dao, hlt, cka, cnk, mrh, mwg, cbl, cnb, csh", HB_TAG('Q','I','N',' ')},*/ /* Chin */
-/*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */
-/*{"zh-Latn-pinyin", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */
-};
-
-typedef struct {
- char language[11];
- hb_tag_t tag;
-} LangTagLong;
-static const LangTagLong ot_languages_zh[] = {
- /* Store longest-first, if one is a prefix of another. */
- {"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','H',' ')}, /* Chinese (Macao) */
- {"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */
- {"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */
- {"zh-hans", HB_TAG('Z','H','S',' ')}, /* Chinese (Simplified) */
- {"zh-hant-hk",HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */
- {"zh-hant-mo",HB_TAG('Z','H','H',' ')}, /* Chinese (Macao) */
- {"zh-hant", HB_TAG('Z','H','T',' ')}, /* Chinese (Traditional) */
-};
-
static int
lang_compare_first_component (const void *pa,
const void *pb)
@@ -895,6 +189,21 @@ lang_compare_first_component (const void *pa,
return strncmp (a, b, MAX (da, db));
}
+static bool
+subtag_matches (const char *lang_str,
+ const char *limit,
+ const char *subtag)
+{
+ do {
+ const char *s = strstr (lang_str, subtag);
+ if (!s || s >= limit)
+ return false;
+ if (!ISALNUM (s[strlen (subtag)]))
+ return true;
+ lang_str = s + strlen (subtag);
+ } while (true);
+}
+
static hb_bool_t
lang_matches (const char *lang_str, const char *spec)
{
@@ -904,106 +213,187 @@ lang_matches (const char *lang_str, const char *spec)
(lang_str[len] == '\0' || lang_str[len] == '-');
}
+typedef struct {
+ char language[4];
+ hb_tag_t tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+} LangTag;
+
+#include "hb-ot-tag-table.hh"
+
+/* The corresponding languages IDs for the following IDs are unclear,
+ * overlap, or are architecturally weird. Needs more research. */
+
+/*{"??", {HB_TAG('B','C','R',' ')}},*/ /* Bible Cree */
+/*{"zh?", {HB_TAG('C','H','N',' ')}},*/ /* Chinese (seen in Microsoft fonts) */
+/*{"ar-Syrc?", {HB_TAG('G','A','R',' ')}},*/ /* Garshuni */
+/*{"??", {HB_TAG('N','G','R',' ')}},*/ /* Nagari */
+/*{"??", {HB_TAG('Y','I','C',' ')}},*/ /* Yi Classic */
+/*{"zh?", {HB_TAG('Z','H','P',' ')}},*/ /* Chinese Phonetic */
+
hb_tag_t
hb_ot_tag_from_language (hb_language_t language)
{
- const char *lang_str, *s;
+ unsigned int count = 1;
+ hb_tag_t tags[1];
+ hb_ot_tags_from_script_and_language (HB_SCRIPT_UNKNOWN, language, nullptr, nullptr, &count, tags);
+ return count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_LANGUAGE;
+}
- if (language == HB_LANGUAGE_INVALID)
- return HB_OT_TAG_DEFAULT_LANGUAGE;
+static void
+hb_ot_tags_from_language (const char *lang_str,
+ const char *limit,
+ const char *private_use_subtag,
+ unsigned int *count,
+ hb_tag_t *tags)
+{
+ const char *s;
- lang_str = hb_language_to_string (language);
+ /* Check for matches of multiple subtags. */
+ if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags))
+ return;
- s = strstr (lang_str, "x-hbot");
- if (s) {
- char tag[4];
- int i;
- s += 6;
- for (i = 0; i < 4 && ISALNUM (s[i]); i++)
- tag[i] = TOUPPER (s[i]);
- if (i) {
- for (; i < 4; i++)
- tag[i] = ' ';
- return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
+ /* Find a language matching in the first component. */
+ s = strchr (lang_str, '-');
+ {
+ const LangTag *lang_tag;
+ if (s && limit - lang_str >= 6)
+ {
+ const char *extlang_end = strchr (s + 1, '-');
+ /* If there is an extended language tag, use it. */
+ if (3 == (extlang_end ? extlang_end - s - 1 : strlen (s + 1)) &&
+ ISALPHA (s[1]))
+ lang_str = s + 1;
+ }
+ lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
+ ARRAY_LENGTH (ot_languages), sizeof (LangTag),
+ lang_compare_first_component);
+ if (lang_tag)
+ {
+ unsigned int i;
+ for (i = 0; i < *count && lang_tag->tags[i] != HB_TAG_NONE; i++)
+ tags[i] = lang_tag->tags[i];
+ *count = i;
+ return;
}
}
- /*
- * "fonipa" is a variant tag in BCP-47, meaning the International Phonetic Alphabet.
- * It can be applied to any language.
- */
- if (strstr (lang_str, "-fonipa")) {
- return HB_TAG('I','P','P','H'); /* Phonetic transcription—IPA conventions */
- }
-
- /*
- * "fonnapa" is a variant tag in BCP-47, meaning the North American Phonetic Alphabet
- * also known as Americanist Phonetic Notation. It can be applied to any language.
- */
- if (strstr (lang_str, "-fonnapa")) {
- return HB_TAG('A','P','P','H'); /* Phonetic transcription—Americanist conventions */
+ if (!s)
+ s = lang_str + strlen (lang_str);
+ if (s - lang_str == 3) {
+ /* Assume it's ISO-639-3 and upper-case and use it. */
+ tags[0] = hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u;
+ *count = 1;
+ return;
}
- /*
- * "Syre" is a BCP-47 script tag, meaning the Estrangela variant of the Syriac script.
- * It can be applied to any language.
- */
- if (strstr (lang_str, "-syre")) {
- return HB_TAG('S','Y','R','E'); /* Estrangela Syriac */
- }
+ *count = 0;
+}
- /*
- * "Syrj" is a BCP-47 script tag, meaning the Western variant of the Syriac script.
- * It can be applied to any language.
- */
- if (strstr (lang_str, "-syrj")) {
- return HB_TAG('S','Y','R','J'); /* Western Syriac */
+static bool
+parse_private_use_subtag (const char *private_use_subtag,
+ unsigned int *count,
+ hb_tag_t *tags,
+ const char *prefix,
+ unsigned char (*normalize) (unsigned char))
+{
+ if (private_use_subtag && count && tags && *count)
+ {
+ const char *s = strstr (private_use_subtag, prefix);
+ if (s)
+ {
+ char tag[4];
+ int i;
+ s += strlen (prefix);
+ for (i = 0; i < 4 && ISALNUM (s[i]); i++)
+ tag[i] = normalize (s[i]);
+ if (i)
+ {
+ for (; i < 4; i++)
+ tag[i] = ' ';
+ tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]);
+ if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT)
+ tags[0] ^= ~0xDFDFDFDF;
+ *count = 1;
+ return false;
+ }
+ }
}
+ return true;
+}
- /*
- * "Syrn" is a BCP-47 script tag, meaning the Eastern variant of the Syriac script.
- * It can be applied to any language.
- */
- if (strstr (lang_str, "-syrn")) {
- return HB_TAG('S','Y','R','N'); /* Eastern Syriac */
- }
+/**
+ * hb_ot_tags_from_script_and_language:
+ * @script: an #hb_script_t to convert.
+ * @language: an #hb_language_t to convert.
+ * @script_count: (allow-none): maximum number of script tags to retrieve (IN)
+ * and actual number of script tags retrieved (OUT)
+ * @script_tags: (out) (allow-none): array of size at least @script_count to store the
+ * script tag results
+ * @language_count: (allow-none): maximum number of language tags to retrieve
+ * (IN) and actual number of language tags retrieved (OUT)
+ * @language_tags: (out) (allow-none): array of size at least @language_count to store
+ * the language tag results
+ *
+ * Converts an #hb_script_t and an #hb_language_t to script and language tags.
+ *
+ * Since: 2.0.0
+ **/
+void
+hb_ot_tags_from_script_and_language (hb_script_t script,
+ hb_language_t language,
+ unsigned int *script_count /* IN/OUT */,
+ hb_tag_t *script_tags /* OUT */,
+ unsigned int *language_count /* IN/OUT */,
+ hb_tag_t *language_tags /* OUT */)
+{
+ bool needs_script = true;
- /* Find a language matching in the first component */
+ if (language == HB_LANGUAGE_INVALID)
{
- const LangTag *lang_tag;
- lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
- ARRAY_LENGTH (ot_languages), sizeof (LangTag),
- lang_compare_first_component);
- if (lang_tag)
- return lang_tag->tag;
+ if (language_count && language_tags && *language_count)
+ *language_count = 0;
}
-
- /* Otherwise, check the Chinese ones */
- if (0 == lang_compare_first_component (lang_str, "zh"))
+ else
{
- unsigned int i;
+ const char *lang_str, *s, *limit, *private_use_subtag;
+ bool needs_language;
- for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
+ lang_str = hb_language_to_string (language);
+ limit = nullptr;
+ private_use_subtag = nullptr;
+ if (lang_str[0] == 'x' && lang_str[1] == '-')
{
- const LangTagLong *lang_tag;
- lang_tag = &ot_languages_zh[i];
- if (lang_matches (lang_str, lang_tag->language))
- return lang_tag->tag;
+ private_use_subtag = lang_str;
+ } else {
+ for (s = lang_str + 1; *s; s++)
+ {
+ if (s[-1] == '-' && s[1] == '-')
+ {
+ if (s[0] == 'x')
+ {
+ private_use_subtag = s;
+ if (!limit)
+ limit = s - 1;
+ break;
+ } else if (!limit)
+ {
+ limit = s - 1;
+ }
+ }
+ }
+ if (!limit)
+ limit = s;
}
- /* Otherwise just return 'ZHS ' */
- return HB_TAG('Z','H','S',' ');
- }
+ needs_script = parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER);
+ needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER);
- s = strchr (lang_str, '-');
- if (!s)
- 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) & ~0x20202000u;
+ if (needs_language && language_count && language_tags && *language_count)
+ hb_ot_tags_from_language (lang_str, limit, private_use_subtag, language_count, language_tags);
}
- return HB_OT_TAG_DEFAULT_LANGUAGE;
+ if (needs_script && script_count && script_tags && *script_count)
+ hb_ot_all_tags_from_script (script, script_count, script_tags);
}
/**
@@ -1023,36 +413,16 @@ hb_ot_tag_to_language (hb_tag_t tag)
if (tag == HB_OT_TAG_DEFAULT_LANGUAGE)
return nullptr;
- /* struct LangTag has only room for 3-letter language tags. */
- switch (tag) {
- case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */
- return hb_language_from_string ("und-fonnapa", -1);
- case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
- return hb_language_from_string ("und-fonipa", -1);
- case HB_TAG('S','Y','R',' '): /* Syriac [macrolanguage] */
- return hb_language_from_string ("syr", -1);
- case HB_TAG('S','Y','R','E'): /* Estrangela Syriac */
- return hb_language_from_string ("und-Syre", -1);
- case HB_TAG('S','Y','R','J'): /* Western Syriac */
- return hb_language_from_string ("und-Syrj", -1);
- case HB_TAG('S','Y','R','N'): /* Eastern Syriac */
- return hb_language_from_string ("und-Syrn", -1);
+ {
+ hb_language_t disambiguated_tag = hb_ot_ambiguous_tag_to_language (tag);
+ if (disambiguated_tag != HB_LANGUAGE_INVALID)
+ return disambiguated_tag;
}
for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
- if (ot_languages[i].tag == tag)
+ if (ot_languages[i].tags[0] == tag)
return hb_language_from_string (ot_languages[i].language, -1);
- /* If tag starts with ZH, it's Chinese */
- if ((tag & 0xFFFF0000u) == 0x5A480000u) {
- switch (tag) {
- case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
- 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 */
- }
- }
-
/* Else return a custom language in the form of "x-hbotABCD" */
{
unsigned char buf[11] = "x-hbot";
@@ -1067,6 +437,71 @@ hb_ot_tag_to_language (hb_tag_t tag)
}
}
+/**
+ * hb_ot_tags_to_script_and_language:
+ * @script_tag: a script tag
+ * @language_tag: a language tag
+ * @script: (allow-none): the #hb_script_t corresponding to @script_tag (OUT).
+ * @language: (allow-none): the #hb_language_t corresponding to @script_tag and
+ * @language_tag (OUT).
+ *
+ * Converts a script tag and a language tag to an #hb_script_t and an
+ * #hb_language_t.
+ *
+ * Since: 2.0.0
+ **/
+void
+hb_ot_tags_to_script_and_language (hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_script_t *script /* OUT */,
+ hb_language_t *language /* OUT */)
+{
+ hb_script_t script_out = hb_ot_tag_to_script (script_tag);
+ if (script)
+ *script = script_out;
+ if (language)
+ {
+ unsigned int script_count = 1;
+ hb_tag_t primary_script_tag[1];
+ hb_ot_tags_from_script_and_language (script_out,
+ HB_LANGUAGE_INVALID,
+ &script_count,
+ primary_script_tag,
+ nullptr, nullptr);
+ *language = hb_ot_tag_to_language (language_tag);
+ if (script_count == 0 || primary_script_tag[0] != script_tag)
+ {
+ unsigned char *buf;
+ const char *lang_str = hb_language_to_string (*language);
+ size_t len = strlen (lang_str);
+ buf = (unsigned char *) malloc (len + 11);
+ if (unlikely (!buf))
+ {
+ *language = nullptr;
+ }
+ else
+ {
+ memcpy (buf, lang_str, len);
+ if (lang_str[0] != 'x' || lang_str[1] != '-') {
+ buf[len++] = '-';
+ buf[len++] = 'x';
+ }
+ buf[len++] = '-';
+ buf[len++] = 'h';
+ buf[len++] = 'b';
+ buf[len++] = 's';
+ buf[len++] = 'c';
+ buf[len++] = script_tag >> 24;
+ buf[len++] = (script_tag >> 16) & 0xFF;
+ buf[len++] = (script_tag >> 8) & 0xFF;
+ buf[len++] = script_tag & 0xFF;
+ *language = hb_language_from_string ((char *) buf, len);
+ free (buf);
+ }
+ }
+ }
+}
+
#ifdef MAIN
static inline void
test_langs_sorted (void)
diff --git a/src/hb-ot-tag.h b/src/hb-ot-tag.h
index 54fb747f5..33a4dbdbc 100644
--- a/src/hb-ot-tag.h
+++ b/src/hb-ot-tag.h
@@ -39,20 +39,39 @@ HB_BEGIN_DECLS
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
+/**
+ * HB_OT_MAX_TAGS_PER_SCRIPT:
+ *
+ * Since: 2.0.0
+ **/
+#define HB_OT_MAX_TAGS_PER_SCRIPT 3u
+/**
+ * HB_OT_MAX_TAGS_PER_LANGUAGE:
+ *
+ * Since: 2.0.0
+ **/
+#define HB_OT_MAX_TAGS_PER_LANGUAGE 3u
+
HB_EXTERN void
-hb_ot_tags_from_script (hb_script_t script,
- hb_tag_t *script_tag_1,
- hb_tag_t *script_tag_2);
+hb_ot_tags_from_script_and_language (hb_script_t script,
+ hb_language_t language,
+ unsigned int *script_count /* IN/OUT */,
+ hb_tag_t *script_tags /* OUT */,
+ unsigned int *language_count /* IN/OUT */,
+ hb_tag_t *language_tags /* OUT */);
HB_EXTERN hb_script_t
hb_ot_tag_to_script (hb_tag_t tag);
-HB_EXTERN hb_tag_t
-hb_ot_tag_from_language (hb_language_t language);
-
HB_EXTERN hb_language_t
hb_ot_tag_to_language (hb_tag_t tag);
+HB_EXTERN void
+hb_ot_tags_to_script_and_language (hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_script_t *script /* OUT */,
+ hb_language_t *language /* OUT */);
+
HB_END_DECLS
diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh
index ad063d32d..d100ca21e 100644
--- a/src/hb-ot-var-avar-table.hh
+++ b/src/hb-ot-var-avar-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_VAR_AVAR_TABLE_HH
#define HB_OT_VAR_AVAR_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* avar -- Axis Variations
@@ -93,6 +93,7 @@ struct SegmentMaps : ArrayOf<AxisValueMap>
(value - arrayZ[i-1].fromCoord) + denom/2) / denom;
}
+ public:
DEFINE_SIZE_ARRAY (2, arrayZ);
};
@@ -108,7 +109,7 @@ struct avar
c->check_struct (this))))
return_trace (false);
- const SegmentMaps *map = axisSegmentMapsZ;
+ const SegmentMaps *map = axisSegmentMapsZ.arrayZ;
unsigned int count = axisCount;
for (unsigned int i = 0; i < count; i++)
{
@@ -124,7 +125,7 @@ struct avar
{
unsigned int count = MIN<unsigned int> (coords_length, axisCount);
- const SegmentMaps *map = axisSegmentMapsZ;
+ const SegmentMaps *map = axisSegmentMapsZ.arrayZ;
for (unsigned int i = 0; i < count; i++)
{
coords[i] = map->map (coords[i]);
@@ -139,7 +140,8 @@ struct avar
HBUINT16 axisCount; /* The number of variation axes in the font. This
* must be the same number as axisCount in the
* 'fvar' table. */
- SegmentMaps axisSegmentMapsZ[VAR];
+ UnsizedArrayOf<SegmentMaps>
+ axisSegmentMapsZ;
public:
DEFINE_SIZE_MIN (8);
diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh
index 101476ed3..96c39c109 100644
--- a/src/hb-ot-var-fvar-table.hh
+++ b/src/hb-ot-var-fvar-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_VAR_FVAR_TABLE_HH
#define HB_OT_VAR_FVAR_TABLE_HH
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
/*
* fvar -- Font Variations
@@ -46,20 +46,21 @@ struct InstanceRecord
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
- c->check_array (coordinates, coordinates[0].static_size, axis_count));
+ c->check_array (coordinatesZ.arrayZ, axis_count));
}
protected:
NameID subfamilyNameID;/* The name ID for entries in the 'name' table
* that provide subfamily names for this instance. */
HBUINT16 reserved; /* Reserved for future use — set to 0. */
- Fixed coordinates[VAR];/* The coordinates array for this instance. */
+ UnsizedArrayOf<Fixed>
+ coordinatesZ; /* The coordinates array for this instance. */
//NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
// * table that provide PostScript names for this
// * instance. */
public:
- DEFINE_SIZE_ARRAY (4, coordinates);
+ DEFINE_SIZE_ARRAY (4, coordinatesZ);
};
struct AxisRecord
@@ -176,7 +177,7 @@ struct fvar
v = (v - axis.default_value) / (axis.default_value - axis.min_value);
else
v = (v - axis.default_value) / (axis.max_value - axis.default_value);
- return (int) (v * 16384. + (v >= 0. ? .5 : -.5));
+ return (int) (v * 16384.f + (v >= 0.f ? .5f : -.5f));
}
protected:
diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh
index 2b384db71..66e086e1d 100644
--- a/src/hb-ot-var-hvar-table.hh
+++ b/src/hb-ot-var-hvar-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_VAR_HVAR_TABLE_HH
#define HB_OT_VAR_HVAR_TABLE_HH
-#include "hb-ot-layout-common-private.hh"
+#include "hb-ot-layout-common.hh"
namespace OT {
@@ -39,7 +39,7 @@ struct DeltaSetIndexMap
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
- c->check_array (mapData, get_width (), mapCount));
+ c->check_array (mapDataZ.arrayZ, mapCount, get_width ()));
}
unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */
@@ -55,7 +55,7 @@ struct DeltaSetIndexMap
unsigned int u = 0;
{ /* Fetch it. */
unsigned int w = get_width ();
- const HBUINT8 *p = mapData + w * v;
+ const HBUINT8 *p = mapDataZ.arrayZ + w * v;
for (; w; w--)
u = (u << 8) + *p++;
}
@@ -81,10 +81,11 @@ struct DeltaSetIndexMap
HBUINT16 format; /* A packed field that describes the compressed
* representation of delta-set indices. */
HBUINT16 mapCount; /* The number of mapping entries. */
- HBUINT8 mapData[VAR]; /* The delta-set index mapping data. */
+ UnsizedArrayOf<HBUINT8>
+ mapDataZ; /* The delta-set index mapping data. */
public:
- DEFINE_SIZE_ARRAY (4, mapData);
+ DEFINE_SIZE_ARRAY (4, mapDataZ);
};
@@ -114,7 +115,7 @@ struct HVARVVAR
}
inline float get_advance_var (hb_codepoint_t glyph,
- int *coords, unsigned int coord_count) const
+ const int *coords, unsigned int coord_count) const
{
unsigned int varidx = (this+advMap).map (glyph);
return (this+varStore).get_delta (varidx, coords, coord_count);
diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh
index dfde782f6..5d6b55954 100644
--- a/src/hb-ot-var-mvar-table.hh
+++ b/src/hb-ot-var-mvar-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_VAR_MVAR_TABLE_HH
#define HB_OT_VAR_MVAR_TABLE_HH
-#include "hb-ot-layout-common-private.hh"
+#include "hb-ot-layout-common.hh"
namespace OT {
@@ -68,14 +68,14 @@ struct MVAR
c->check_struct (this) &&
valueRecordSize >= VariationValueRecord::static_size &&
varStore.sanitize (c, this) &&
- c->check_array (values, valueRecordSize, valueRecordCount));
+ c->check_array (valuesZ.arrayZ, valueRecordCount, valueRecordSize));
}
inline float get_var (hb_tag_t tag,
- int *coords, unsigned int coord_count) const
+ const int *coords, unsigned int coord_count) const
{
const VariationValueRecord *record;
- record = (VariationValueRecord *) bsearch (&tag, values,
+ record = (VariationValueRecord *) bsearch (&tag, valuesZ.arrayZ,
valueRecordCount, valueRecordSize,
tag_compare);
if (!record)
@@ -101,11 +101,12 @@ protected:
HBUINT16 valueRecordCount;/* The number of value records — may be zero. */
OffsetTo<VariationStore>
varStore; /* Offset to item variation store table. */
- HBUINT8 values[VAR]; /* Array of value records. The records must be
+ UnsizedArrayOf<HBUINT8>
+ valuesZ; /* Array of value records. The records must be
* in binary order of their valueTag field. */
public:
- DEFINE_SIZE_ARRAY (12, values);
+ DEFINE_SIZE_ARRAY (12, valuesZ);
};
} /* namespace OT */
diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc
index 6081ddfc3..472ee8452 100644
--- a/src/hb-ot-var.cc
+++ b/src/hb-ot-var.cc
@@ -24,9 +24,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
-#include "hb-ot-layout-private.hh"
+#include "hb-ot-face.hh"
#include "hb-ot-var-avar-table.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-mvar-table.hh"
@@ -40,15 +40,15 @@ static inline const OT::fvar&
_get_fvar (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::fvar);
- hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
- return *(layout->table.fvar.get ());
+ hb_ot_face_data_t *layout = hb_ot_face_data (face);
+ return *(layout->fvar.get ());
}
static inline const OT::avar&
_get_avar (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::avar);
- hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
- return *(layout->table.avar.get ());
+ hb_ot_face_data_t *layout = hb_ot_face_data (face);
+ return *(layout->avar.get ());
}
/**
diff --git a/src/hb-ot.h b/src/hb-ot.h
index 2120a3efa..4b6e3cf74 100644
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@ -33,6 +33,7 @@
#include "hb-ot-font.h"
#include "hb-ot-layout.h"
#include "hb-ot-math.h"
+#include "hb-ot-name.h"
#include "hb-ot-tag.h"
#include "hb-ot-shape.h"
#include "hb-ot-var.h"
diff --git a/src/hb-set-digest-private.hh b/src/hb-set-digest.hh
index e099a8264..0f9329f62 100644
--- a/src/hb-set-digest-private.hh
+++ b/src/hb-set-digest.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_SET_DIGEST_PRIVATE_HH
-#define HB_SET_DIGEST_PRIVATE_HH
+#ifndef HB_SET_DIGEST_HH
+#define HB_SET_DIGEST_HH
-#include "hb-private.hh"
+#include "hb.hh"
/*
* The set digests here implement various "filters" that support
@@ -50,8 +50,8 @@ 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;
+ enum { mask_bytes = sizeof (mask_t) };
+ enum { mask_bits = sizeof (mask_t) * 8 };
static const unsigned int num_bits = 0
+ (mask_bytes >= 1 ? 3 : 0)
+ (mask_bytes >= 2 ? 1 : 0)
@@ -176,4 +176,4 @@ typedef hb_set_digest_combiner_t
> hb_set_digest_t;
-#endif /* HB_SET_DIGEST_PRIVATE_HH */
+#endif /* HB_SET_DIGEST_HH */
diff --git a/src/hb-set.cc b/src/hb-set.cc
index 25027e6c2..09dc4b483 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-set-private.hh"
+#include "hb-set.hh"
/* Public API */
diff --git a/src/hb-set-private.hh b/src/hb-set.hh
index 032ddb1ee..7ca329761 100644
--- a/src/hb-set-private.hh
+++ b/src/hb-set.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_SET_PRIVATE_HH
-#define HB_SET_PRIVATE_HH
+#ifndef HB_SET_HH
+#define HB_SET_HH
-#include "hb-private.hh"
+#include "hb.hh"
/*
@@ -157,7 +157,7 @@ struct hb_set_t
}
typedef unsigned long long elt_t;
- static const unsigned int PAGE_BITS = 512;
+ enum { PAGE_BITS = 512 };
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
static inline unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
@@ -165,11 +165,11 @@ struct hb_set_t
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
- static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
- static const unsigned int ELT_MASK = ELT_BITS - 1;
- static const unsigned int BITS = sizeof (vector_t) * 8;
- static const unsigned int MASK = BITS - 1;
- static_assert (PAGE_BITS == BITS, "");
+ enum { ELT_BITS = sizeof (elt_t) * 8 };
+ enum { ELT_MASK = ELT_BITS - 1 };
+ enum { BITS = sizeof (vector_t) * 8 };
+ enum { MASK = BITS - 1 };
+ static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
elt_t const &elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
@@ -368,8 +368,8 @@ struct hb_set_t
if (!resize (count))
return;
population = other->population;
- memcpy (pages.arrayZ, other->pages.arrayZ, count * sizeof (pages.arrayZ[0]));
- memcpy (page_map.arrayZ, other->page_map.arrayZ, count * sizeof (page_map.arrayZ[0]));
+ memcpy (pages.arrayZ(), other->pages.arrayZ(), count * sizeof (pages.arrayZ()[0]));
+ memcpy (page_map.arrayZ(), other->page_map.arrayZ(), count * sizeof (page_map.arrayZ()[0]));
}
inline bool is_equal (const hb_set_t *other) const
@@ -697,4 +697,4 @@ struct hb_set_t
};
-#endif /* HB_SET_PRIVATE_HH */
+#endif /* HB_SET_HH */
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
index 0d61d9e1f..b2289f869 100644
--- a/src/hb-shape-plan.cc
+++ b/src/hb-shape-plan.cc
@@ -24,11 +24,11 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
-#include "hb-shape-plan-private.hh"
-#include "hb-shaper-private.hh"
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
+#include "hb.hh"
+#include "hb-shape-plan.hh"
+#include "hb-shaper.hh"
+#include "hb-font.hh"
+#include "hb-buffer.hh"
static void
@@ -64,7 +64,7 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
if (likely (!shaper_list)) {
for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
- if (0)
+ if (false)
;
#define HB_SHAPER_IMPLEMENT(shaper) \
else if (shapers[i].func == _hb_##shaper##_shape) \
@@ -73,7 +73,7 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
#undef HB_SHAPER_IMPLEMENT
} else {
for (; *shaper_list; shaper_list++)
- if (0)
+ if (false)
;
#define HB_SHAPER_IMPLEMENT(shaper) \
else if (0 == strcmp (*shaper_list, #shaper)) \
@@ -346,7 +346,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
_hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
} HB_STMT_END
- if (0)
+ if (false)
;
#define HB_SHAPER_IMPLEMENT(shaper) \
else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
@@ -501,7 +501,7 @@ hb_shape_plan_create_cached2 (hb_face_t *face,
/* 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)
+ if (false)
;
#define HB_SHAPER_IMPLEMENT(shaper) \
else if (0 == strcmp (*shaper_item, #shaper) && \
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan.hh
index 7d020ff16..bf82b912b 100644
--- a/src/hb-shape-plan-private.hh
+++ b/src/hb-shape-plan.hh
@@ -24,11 +24,11 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_SHAPE_PLAN_PRIVATE_HH
-#define HB_SHAPE_PLAN_PRIVATE_HH
+#ifndef HB_SHAPE_PLAN_HH
+#define HB_SHAPE_PLAN_HH
-#include "hb-private.hh"
-#include "hb-shaper-private.hh"
+#include "hb.hh"
+#include "hb-shaper.hh"
struct hb_shape_plan_t
@@ -64,4 +64,4 @@ DECLARE_NULL_INSTANCE (hb_shape_plan_t);
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
-#endif /* HB_SHAPE_PLAN_PRIVATE_HH */
+#endif /* HB_SHAPE_PLAN_HH */
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 3c2e6c4a9..e8eeff5b3 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -26,13 +26,13 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-shaper-private.hh"
-#include "hb-shape-plan-private.hh"
-#include "hb-buffer-private.hh"
-#include "hb-font-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb-shaper.hh"
+#include "hb-shape-plan.hh"
+#include "hb-buffer.hh"
+#include "hb-font.hh"
+#include "hb-machinery.hh"
/**
* SECTION:hb-shape
@@ -46,8 +46,10 @@
* contains the output glyphs and their positions.
**/
-
+#ifdef HB_USE_ATEXIT
static void free_static_shaper_list (void);
+#endif
+
static const char *nil_shaper_list[] = {nullptr};
static struct hb_shaper_list_lazy_loader_t : hb_lazy_loader_t<const char *,
diff --git a/src/hb-shaper-impl-private.hh b/src/hb-shaper-impl.hh
index 4a10279c7..d40cb085a 100644
--- a/src/hb-shaper-impl-private.hh
+++ b/src/hb-shaper-impl.hh
@@ -24,15 +24,15 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_SHAPER_IMPL_PRIVATE_HH
-#define HB_SHAPER_IMPL_PRIVATE_HH
+#ifndef HB_SHAPER_IMPL_HH
+#define HB_SHAPER_IMPL_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-shaper-private.hh"
-#include "hb-shape-plan-private.hh"
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
+#include "hb-shaper.hh"
+#include "hb-shape-plan.hh"
+#include "hb-font.hh"
+#include "hb-buffer.hh"
#ifdef HB_SHAPER
@@ -40,4 +40,4 @@
#endif
-#endif /* HB_SHAPER_IMPL_PRIVATE_HH */
+#endif /* HB_SHAPER_IMPL_HH */
diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh
index b0835d31a..1fdb64810 100644
--- a/src/hb-shaper-list.hh
+++ b/src/hb-shaper-list.hh
@@ -39,9 +39,7 @@ HB_SHAPER_IMPLEMENT (graphite2)
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)
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index e423f2557..52418c082 100644
--- a/src/hb-shaper.cc
+++ b/src/hb-shaper.cc
@@ -24,9 +24,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
-#include "hb-shaper-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb.hh"
+#include "hb-shaper.hh"
+#include "hb-machinery.hh"
static const hb_shaper_pair_t all_shapers[] = {
@@ -35,8 +35,9 @@ static const hb_shaper_pair_t all_shapers[] = {
#undef HB_SHAPER_IMPLEMENT
};
-
+#ifdef HB_USE_ATEXIT
static void free_static_shapers (void);
+#endif
static struct hb_shapers_lazy_loader_t : hb_lazy_loader_t<const hb_shaper_pair_t,
hb_shapers_lazy_loader_t>
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper.hh
index fb04bbc3c..361165e4f 100644
--- a/src/hb-shaper-private.hh
+++ b/src/hb-shaper.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_SHAPER_PRIVATE_HH
-#define HB_SHAPER_PRIVATE_HH
+#ifndef HB_SHAPER_HH
+#define HB_SHAPER_HH
-#include "hb-private.hh"
+#include "hb.hh"
typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan,
hb_font_t *font,
@@ -131,4 +131,4 @@ struct hb_shaper_data_t {
#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
-#endif /* HB_SHAPER_PRIVATE_HH */
+#endif /* HB_SHAPER_HH */
diff --git a/src/hb-static.cc b/src/hb-static.cc
index ddecbba11..e5507960d 100644
--- a/src/hb-static.cc
+++ b/src/hb-static.cc
@@ -24,12 +24,14 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-open-type-private.hh"
-#include "hb-ot-layout-common-private.hh"
+#include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
+#include "hb-aat-layout-ankr-table.hh" /* I don't even want to know why... */
+#include "hb-aat-layout-common.hh"
-#include "hb-face-private.hh"
+#include "hb-face.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
@@ -41,6 +43,8 @@ hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_
DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF};
DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00};
+/* Hand-coded because Lookup is a template. Sad. */
+const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF};
void
diff --git a/src/hb-string-array.hh b/src/hb-string-array.hh
index 679841c87..c4cf666d7 100644
--- a/src/hb-string-array.hh
+++ b/src/hb-string-array.hh
@@ -29,7 +29,7 @@
#define HB_STRING_ARRAY_HH
#endif
-#include "hb-private.hh"
+#include "hb.hh"
/* Based on Bruno Haible's code in Appendix B of Ulrich Drepper's dsohowto.pdf:
* https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf */
diff --git a/src/hb-subset-glyf.cc b/src/hb-subset-glyf.cc
index 36af3beae..499380a97 100644
--- a/src/hb-subset-glyf.cc
+++ b/src/hb-subset-glyf.cc
@@ -24,11 +24,10 @@
* Google Author(s): Garret Rieger, Roderick Sheeter
*/
-#include "hb-open-type-private.hh"
+#include "hb-open-type.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-set.h"
#include "hb-subset-glyf.hh"
-#include "hb-subset-plan.hh"
static bool
_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf,
diff --git a/src/hb-subset-glyf.hh b/src/hb-subset-glyf.hh
index 99b76db9b..3109ecb64 100644
--- a/src/hb-subset-glyf.hh
+++ b/src/hb-subset-glyf.hh
@@ -27,9 +27,9 @@
#ifndef HB_SUBSET_GLYF_HH
#define HB_SUBSET_GLYF_HH
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-subset-plan.hh"
+#include "hb-subset.hh"
HB_INTERNAL bool
hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc
index 74470fd1f..d59b5bae0 100644
--- a/src/hb-subset-input.cc
+++ b/src/hb-subset-input.cc
@@ -24,8 +24,8 @@
* Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
*/
-#include "hb-subset-private.hh"
-#include "hb-set-private.hh"
+#include "hb-subset.hh"
+#include "hb-set.hh"
/**
* hb_subset_input_create_or_fail:
@@ -44,7 +44,7 @@ hb_subset_input_create_or_fail (void)
input->unicodes = hb_set_create ();
input->glyphs = hb_set_create ();
- input->drop_ot_layout = true;
+ input->drop_layout = true;
return input;
}
@@ -106,30 +106,28 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input)
return subset_input->glyphs;
}
-/**
- * hb_subset_input_drop_hints:
- * @subset_input: a subset_input.
- *
- * Since: 1.8.0
- **/
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_hints (hb_subset_input_t *subset_input)
+HB_EXTERN void
+hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
+ hb_bool_t drop_hints)
{
- return &subset_input->drop_hints;
+ subset_input->drop_hints = drop_hints;
}
-/**
- * hb_subset_input_drop_ot_layout:
- * @subset_input: a subset_input.
- *
- * If enabled ot layout tables will be dropped as part of
- * the subsetting operation. Currently this defaults to
- * true.
- *
- * Since: REPLACEME
- **/
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input)
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input)
+{
+ return subset_input->drop_hints;
+}
+
+HB_EXTERN void
+hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
+ hb_bool_t drop_layout)
+{
+ subset_input->drop_layout = drop_layout;
+}
+
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input)
{
- return &subset_input->drop_ot_layout;
+ return subset_input->drop_layout;
}
diff --git a/src/hb-subset-private.hh b/src/hb-subset-input.hh
index 6b2b207ff..9fc86154e 100644
--- a/src/hb-subset-private.hh
+++ b/src/hb-subset-input.hh
@@ -24,27 +24,26 @@
* Google Author(s): Garret Rieger, Roderick Sheeter
*/
-#ifndef HB_SUBSET_PRIVATE_HH
-#define HB_SUBSET_PRIVATE_HH
+#ifndef HB_SUBSET_INPUT_HH
+#define HB_SUBSET_INPUT_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb-subset.h"
-#include "hb-font-private.hh"
+#include "hb-font.hh"
-typedef struct hb_subset_face_data_t hb_subset_face_data_t;
-
-struct hb_subset_input_t {
+struct hb_subset_input_t
+{
hb_object_header_t header;
ASSERT_POD ();
hb_set_t *unicodes;
hb_set_t *glyphs;
- hb_bool_t drop_hints;
- hb_bool_t drop_ot_layout;
+ bool drop_hints : 1;
+ bool drop_layout : 1;
/* TODO
*
* features
@@ -54,10 +53,5 @@ struct hb_subset_input_t {
*/
};
-HB_INTERNAL hb_face_t *
-hb_subset_face_create (void);
-
-HB_INTERNAL hb_bool_t
-hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob);
-#endif /* HB_SUBSET_PRIVATE_HH */
+#endif /* HB_SUBSET_INPUT_HH */
diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc
index 125668272..057006039 100644
--- a/src/hb-subset-plan.cc
+++ b/src/hb-subset-plan.cc
@@ -24,11 +24,10 @@
* Google Author(s): Garret Rieger, Roderick Sheeter
*/
-#include "hb-map-private.hh"
-#include "hb-subset-private.hh"
-#include "hb-set-private.hh"
-
#include "hb-subset-plan.hh"
+#include "hb-map.hh"
+#include "hb-set.hh"
+
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
@@ -69,7 +68,7 @@ _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
}
-static void
+static hb_set_t *
_populate_gids_to_retain (hb_face_t *face,
const hb_set_t *unicodes,
bool close_over_gsub,
@@ -118,9 +117,10 @@ _populate_gids_to_retain (hb_face_t *face,
while (all_gids_to_retain->next (&gid))
glyphs->push (gid);
- hb_set_destroy (all_gids_to_retain);
glyf.fini ();
cmap.fini ();
+
+ return all_gids_to_retain;
}
static void
@@ -135,7 +135,7 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
/**
* hb_subset_plan_create:
* Computes a plan for subsetting the supplied face according
- * to a provide profile and input. The plan describes
+ * to a provided input. The plan describes
* which tables and glyphs should be retained.
*
* Return value: New subset plan.
@@ -144,26 +144,24 @@ _create_old_gid_to_new_gid_map (const hb_vector_t<hb_codepoint_t> &glyphs,
**/
hb_subset_plan_t *
hb_subset_plan_create (hb_face_t *face,
- hb_subset_profile_t *profile,
hb_subset_input_t *input)
{
hb_subset_plan_t *plan = hb_object_create<hb_subset_plan_t> ();
plan->drop_hints = input->drop_hints;
- plan->drop_ot_layout = input->drop_ot_layout;
+ plan->drop_layout = input->drop_layout;
plan->unicodes = hb_set_create();
plan->glyphs.init();
plan->source = hb_face_reference (face);
- plan->dest = hb_subset_face_create ();
+ plan->dest = hb_face_builder_create ();
plan->codepoint_to_glyph = hb_map_create();
plan->glyph_map = hb_map_create();
-
- _populate_gids_to_retain (face,
- input->unicodes,
- !plan->drop_ot_layout,
- plan->unicodes,
- plan->codepoint_to_glyph,
- &plan->glyphs);
+ plan->glyphset = _populate_gids_to_retain (face,
+ input->unicodes,
+ !plan->drop_layout,
+ plan->unicodes,
+ plan->codepoint_to_glyph,
+ &plan->glyphs);
_create_old_gid_to_new_gid_map (plan->glyphs,
plan->glyph_map);
@@ -186,6 +184,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan)
hb_face_destroy (plan->dest);
hb_map_destroy (plan->codepoint_to_glyph);
hb_map_destroy (plan->glyph_map);
+ hb_set_destroy (plan->glyphset);
free (plan);
}
diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh
index 7501294d7..c2c484a5b 100644
--- a/src/hb-subset-plan.hh
+++ b/src/hb-subset-plan.hh
@@ -27,27 +27,26 @@
#ifndef HB_SUBSET_PLAN_HH
#define HB_SUBSET_PLAN_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb-subset.h"
-#include "hb-subset-private.hh"
+#include "hb-subset-input.hh"
-#include "hb-map-private.hh"
+#include "hb-map.hh"
struct hb_subset_plan_t
{
hb_object_header_t header;
ASSERT_POD ();
- hb_bool_t drop_hints;
- hb_bool_t drop_ot_layout;
+ bool drop_hints : 1;
+ bool drop_layout : 1;
// For each cp that we'd like to retain maps to the corresponding gid.
hb_set_t *unicodes;
- // This list contains the complete set of glyphs to retain and may contain
- // more glyphs then the lists above.
hb_vector_t<hb_codepoint_t> glyphs;
+ hb_set_t *glyphset;
hb_map_t *codepoint_to_glyph;
hb_map_t *glyph_map;
@@ -56,7 +55,7 @@ struct hb_subset_plan_t
hb_face_t *source;
hb_face_t *dest;
- inline hb_bool_t
+ inline bool
new_gid_for_codepoint (hb_codepoint_t codepoint,
hb_codepoint_t *new_gid) const
{
@@ -67,7 +66,7 @@ struct hb_subset_plan_t
return new_gid_for_old_gid (old_gid, new_gid);
}
- inline hb_bool_t
+ inline bool
new_gid_for_old_gid (hb_codepoint_t old_gid,
hb_codepoint_t *new_gid) const
{
@@ -79,7 +78,7 @@ struct hb_subset_plan_t
return true;
}
- inline hb_bool_t
+ inline bool
add_table (hb_tag_t tag,
hb_blob_t *contents)
{
@@ -89,7 +88,7 @@ struct hb_subset_plan_t
hb_blob_get_length (contents),
hb_blob_get_length (source_blob));
hb_blob_destroy (source_blob);
- return hb_subset_face_add_table(dest, tag, contents);
+ return hb_face_builder_add_table (dest, tag, contents);
}
};
@@ -97,7 +96,6 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
HB_INTERNAL hb_subset_plan_t *
hb_subset_plan_create (hb_face_t *face,
- hb_subset_profile_t *profile,
hb_subset_input_t *input);
HB_INTERNAL void
diff --git a/src/hb-subset.cc b/src/hb-subset.cc
index 411c6b861..9f14b89ba 100644
--- a/src/hb-subset.cc
+++ b/src/hb-subset.cc
@@ -24,14 +24,13 @@
* Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
*/
-#include "hb-private.hh"
-#include "hb-open-type-private.hh"
+#include "hb.hh"
+#include "hb-open-type.hh"
+#include "hb-subset.hh"
#include "hb-subset-glyf.hh"
-#include "hb-subset-private.hh"
-#include "hb-subset-plan.hh"
-#include "hb-open-file-private.hh"
+#include "hb-open-file.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-hdmx-table.hh"
@@ -41,42 +40,26 @@
#include "hb-ot-maxp-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-post-table.hh"
+#include "hb-ot-layout-gsub-table.hh"
+#include "hb-ot-layout-gpos-table.hh"
-struct hb_subset_profile_t {
- hb_object_header_t header;
- ASSERT_POD ();
-};
-
-/**
- * hb_subset_profile_create:
- *
- * Return value: New profile with default settings.
- *
- * Since: 1.8.0
- **/
-hb_subset_profile_t *
-hb_subset_profile_create ()
+static unsigned int
+_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
+ unsigned int table_len)
{
- return hb_object_create<hb_subset_profile_t>();
-}
+ unsigned int src_glyphs = plan->source->get_num_glyphs ();
+ unsigned int dst_glyphs = plan->glyphset->get_population ();
-/**
- * hb_subset_profile_destroy:
- *
- * Since: 1.8.0
- **/
-void
-hb_subset_profile_destroy (hb_subset_profile_t *profile)
-{
- if (!hb_object_destroy (profile)) return;
+ if (unlikely (!src_glyphs))
+ return 512 + table_len;
- free (profile);
+ return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
}
template<typename TableType>
static bool
-_subset (hb_subset_plan_t *plan)
+_subset2 (hb_subset_plan_t *plan)
{
hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
const TableType *table = source_blob->as<TableType> ();
@@ -85,145 +68,69 @@ _subset (hb_subset_plan_t *plan)
hb_bool_t result = false;
if (source_blob->data)
{
- result = table->subset(plan);
- } else {
- DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag));
+ hb_auto_t<hb_vector_t<char> > buf;
+ unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length);
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG(tag), buf_size);
+ if (unlikely (!buf.alloc (buf_size)))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG(tag), buf_size);
+ return false;
+ }
+ retry:
+ hb_serialize_context_t serializer (buf.arrayZ(), buf_size);
+ hb_subset_context_t c (plan, &serializer);
+ result = table->subset (&c);
+ if (serializer.ran_out_of_room)
+ {
+ buf_size += (buf_size >> 1) + 32;
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG(tag), buf_size);
+ if (unlikely (!buf.alloc (buf_size)))
+ {
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG(tag), buf_size);
+ return false;
+ }
+ goto retry;
+ }
+ if (result)
+ {
+ hb_blob_t *dest_blob = serializer.copy_blob ();
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG(tag), dest_blob->length);
+ result = c.plan->add_table (tag, dest_blob);
+ hb_blob_destroy (dest_blob);
+ }
+ else
+ {
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG(tag));
+ result = true;
+ }
}
+ else
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag));
hb_blob_destroy (source_blob);
DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
return result;
}
-
-/*
- * A face that has add_table().
- */
-
-struct hb_subset_face_data_t
-{
- struct table_entry_t
- {
- inline int cmp (const hb_tag_t *t) const
- {
- if (*t < tag) return -1;
- if (*t > tag) return -1;
- return 0;
- }
-
- hb_tag_t tag;
- hb_blob_t *blob;
- };
-
- hb_vector_t<table_entry_t, 32> tables;
-};
-
-static hb_subset_face_data_t *
-_hb_subset_face_data_create (void)
-{
- hb_subset_face_data_t *data = (hb_subset_face_data_t *) calloc (1, sizeof (hb_subset_face_data_t));
- if (unlikely (!data))
- return nullptr;
-
- data->tables.init ();
-
- return data;
-}
-
-static void
-_hb_subset_face_data_destroy (void *user_data)
-{
- hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data;
-
- for (unsigned int i = 0; i < data->tables.len; i++)
- hb_blob_destroy (data->tables[i].blob);
-
- data->tables.fini ();
-
- free (data);
-}
-
-static hb_blob_t *
-_hb_subset_face_data_reference_blob (hb_subset_face_data_t *data)
-{
-
- unsigned int table_count = data->tables.len;
- unsigned int face_length = table_count * 16 + 12;
-
- for (unsigned int i = 0; i < table_count; i++)
- face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
-
- char *buf = (char *) malloc (face_length);
- if (unlikely (!buf))
- return nullptr;
-
- hb_serialize_context_t c (buf, face_length);
- OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
-
- bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
- hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
-
- Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
- Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
- bool ret = f->serialize_single (&c,
- sfnt_tag,
- tags_supplier,
- blobs_supplier,
- table_count);
-
- c.end_serialize ();
-
- if (unlikely (!ret))
- {
- free (buf);
- return nullptr;
- }
-
- return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
-}
-
-static hb_blob_t *
-_hb_subset_face_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
+template<typename TableType>
+static bool
+_subset (hb_subset_plan_t *plan)
{
- hb_subset_face_data_t *data = (hb_subset_face_data_t *) user_data;
-
- if (!tag)
- return _hb_subset_face_data_reference_blob (data);
-
- hb_subset_face_data_t::table_entry_t *entry = data->tables.lsearch (tag);
- if (entry)
- return hb_blob_reference (entry->blob);
-
- return nullptr;
-}
+ hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
+ const TableType *table = source_blob->as<TableType> ();
-/* TODO: Move this to hb-face.h and rename to hb_face_builder_create()
- * with hb_face_builder_add_table(). */
-hb_face_t *
-hb_subset_face_create (void)
-{
- hb_subset_face_data_t *data = _hb_subset_face_data_create ();
- if (unlikely (!data)) return hb_face_get_empty ();
+ hb_tag_t tag = TableType::tableTag;
+ hb_bool_t result = false;
+ if (source_blob->data)
+ result = table->subset (plan);
+ else
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG(tag));
- return hb_face_create_for_tables (_hb_subset_face_reference_table,
- data,
- _hb_subset_face_data_destroy);
+ hb_blob_destroy (source_blob);
+ DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG(tag), result ? "success" : "FAILED!");
+ return result;
}
-hb_bool_t
-hb_subset_face_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
-{
- if (unlikely (face->destroy != (hb_destroy_func_t) _hb_subset_face_data_destroy))
- return false;
-
- hb_subset_face_data_t *data = (hb_subset_face_data_t *) face->user_data;
- hb_subset_face_data_t::table_entry_t *entry = data->tables.push ();
-
- entry->tag = tag;
- entry->blob = hb_blob_reference (blob);
-
- return true;
-}
static bool
_subset_table (hb_subset_plan_t *plan,
@@ -270,6 +177,14 @@ _subset_table (hb_subset_plan_t *plan,
case HB_OT_TAG_post:
result = _subset<const OT::post> (plan);
break;
+
+ case HB_OT_TAG_GSUB:
+ result = _subset2<const OT::GSUB> (plan);
+ break;
+ case HB_OT_TAG_GPOS:
+ result = _subset2<const OT::GPOS> (plan);
+ break;
+
default:
hb_blob_t *source_table = hb_face_reference_table(plan->source, tag);
if (likely (source_table))
@@ -298,7 +213,7 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag)
case HB_TAG ('G', 'D', 'E', 'F'): /* temporary */
case HB_TAG ('G', 'P', 'O', 'S'): /* temporary */
case HB_TAG ('G', 'S', 'U', 'B'): /* temporary */
- return plan->drop_ot_layout;
+ return plan->drop_layout;
// Drop these tables below by default, list pulled
// from fontTools:
case HB_TAG ('B', 'A', 'S', 'E'):
@@ -327,19 +242,17 @@ _should_drop_table(hb_subset_plan_t *plan, hb_tag_t tag)
/**
* hb_subset:
* @source: font face data to be subset.
- * @profile: profile to use for the subsetting.
* @input: input to use for the subsetting.
*
- * Subsets a font according to provided profile and input.
+ * Subsets a font according to provided input.
**/
hb_face_t *
hb_subset (hb_face_t *source,
- hb_subset_profile_t *profile,
hb_subset_input_t *input)
{
- if (unlikely (!profile || !input || !source)) return hb_face_get_empty();
+ if (unlikely (!input || !source)) return hb_face_get_empty();
- hb_subset_plan_t *plan = hb_subset_plan_create (source, profile, input);
+ hb_subset_plan_t *plan = hb_subset_plan_create (source, input);
hb_tag_t table_tags[32];
unsigned int offset = 0, count;
@@ -358,23 +271,9 @@ hb_subset (hb_face_t *source,
success = success && _subset_table (plan, tag);
}
offset += count;
- } while (count == ARRAY_LENGTH (table_tags));
+ } while (success && count == ARRAY_LENGTH (table_tags));
hb_face_t *result = success ? hb_face_reference(plan->dest) : hb_face_get_empty();
hb_subset_plan_destroy (plan);
return result;
}
-
-/**
- * hb_subset_get_all_codepoints:
- * @source: font face data to load.
- * @out: set to add the all codepoints covered by font face, source.
- */
-void
-hb_subset_get_all_codepoints (hb_face_t *source, hb_set_t *out)
-{
- OT::cmap::accelerator_t cmap;
- cmap.init (source);
- cmap.get_all_codepoints (out);
- cmap.fini();
-}
diff --git a/src/hb-subset.h b/src/hb-subset.h
index f6d2ae0a0..8b07a45e9 100644
--- a/src/hb-subset.h
+++ b/src/hb-subset.h
@@ -32,20 +32,6 @@
HB_BEGIN_DECLS
/*
- * hb_subset_profile_t
- * Things that change based on target environment, e.g. OS.
- * Threadsafe for multiple concurrent subset operations.
- */
-
-typedef struct hb_subset_profile_t hb_subset_profile_t;
-
-HB_EXTERN hb_subset_profile_t *
-hb_subset_profile_create (void);
-
-HB_EXTERN void
-hb_subset_profile_destroy (hb_subset_profile_t *profile);
-
-/*
* hb_subset_input_t
*
* Things that change based on the input. Characters to keep, etc.
@@ -68,21 +54,24 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input);
HB_EXTERN hb_set_t *
hb_subset_input_glyph_set (hb_subset_input_t *subset_input);
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_hints (hb_subset_input_t *subset_input);
+HB_EXTERN void
+hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input,
+ hb_bool_t drop_hints);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input);
+
+HB_EXTERN void
+hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input,
+ hb_bool_t drop_layout);
+HB_EXTERN hb_bool_t
+hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input);
-HB_EXTERN hb_bool_t *
-hb_subset_input_drop_ot_layout (hb_subset_input_t *subset_input);
/* hb_subset() */
HB_EXTERN hb_face_t *
hb_subset (hb_face_t *source,
- hb_subset_profile_t *profile,
hb_subset_input_t *input);
-/* hb_subset_get_all_codepoints */
-HB_EXTERN void
-hb_subset_get_all_codepoints (hb_face_t *source, hb_set_t *out);
HB_END_DECLS
diff --git a/src/hb-subset.hh b/src/hb-subset.hh
new file mode 100644
index 000000000..9cdd388d7
--- /dev/null
+++ b/src/hb-subset.hh
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2018 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger, Roderick Sheeter
+ */
+
+#ifndef HB_SUBSET_HH
+#define HB_SUBSET_HH
+
+
+#include "hb.hh"
+
+#include "hb-subset.h"
+
+#include "hb-machinery.hh"
+#include "hb-subset-input.hh"
+#include "hb-subset-plan.hh"
+
+struct hb_subset_context_t :
+ hb_dispatch_context_t<hb_subset_context_t, bool, HB_DEBUG_SUBSET>
+{
+ inline const char *get_name (void) { return "SUBSET"; }
+ template <typename T>
+ inline bool dispatch (const T &obj) { return obj.subset (this); }
+ static bool default_return_value (void) { return true; }
+ bool stop_sublookup_iteration (bool r) const { return false; }
+
+ hb_subset_plan_t *plan;
+ hb_serialize_context_t *serializer;
+ unsigned int debug_depth;
+
+ hb_subset_context_t (hb_subset_plan_t *plan_,
+ hb_serialize_context_t *serializer_) :
+ plan (plan_),
+ serializer (serializer_),
+ debug_depth (0) {}
+};
+
+
+#endif /* HB_SUBSET_HH */
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index 56d13e7cd..3179683c2 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -14,10 +14,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-unicode-private.hh"
-#include "hb-machinery-private.hh"
+#include "hb-machinery.hh"
#include "ucdn.h"
@@ -182,15 +181,6 @@ hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs 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_UNUSED,
- 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_UNUSED,
hb_codepoint_t unicode,
@@ -231,16 +221,10 @@ hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs HB_UNUSED,
return ucdn_decompose(ab, a, b);
}
-static unsigned int
-hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED,
- hb_codepoint_t u, hb_codepoint_t *decomposed,
- void *user_data HB_UNUSED)
-{
- return ucdn_compat_decompose(u, decomposed);
-}
-
+#ifdef HB_USE_ATEXIT
static void free_static_ucdn_funcs (void);
+#endif
static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_ucdn_unicode_funcs_lazy_loader_t>
{
@@ -248,10 +232,12 @@ static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
{
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
-#define HB_UNICODE_FUNC_IMPLEMENT(name) \
- hb_unicode_funcs_set_##name##_func (funcs, hb_ucdn_##name, nullptr, nullptr);
- HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
+ hb_unicode_funcs_set_combining_class_func (funcs, hb_ucdn_combining_class, nullptr, nullptr);
+ hb_unicode_funcs_set_general_category_func (funcs, hb_ucdn_general_category, nullptr, nullptr);
+ hb_unicode_funcs_set_mirroring_func (funcs, hb_ucdn_mirroring, nullptr, nullptr);
+ hb_unicode_funcs_set_script_func (funcs, hb_ucdn_script, nullptr, nullptr);
+ hb_unicode_funcs_set_compose_func (funcs, hb_ucdn_compose, nullptr, nullptr);
+ hb_unicode_funcs_set_decompose_func (funcs, hb_ucdn_decompose, nullptr, nullptr);
hb_unicode_funcs_make_immutable (funcs);
@@ -273,6 +259,9 @@ void free_static_ucdn_funcs (void)
extern "C" HB_INTERNAL
hb_unicode_funcs_t *
+hb_ucdn_get_unicode_funcs (void);
+
+hb_unicode_funcs_t *
hb_ucdn_get_unicode_funcs (void)
{
return static_ucdn_funcs.get_unconst ();
diff --git a/src/hb-unicode-emoji-table.hh b/src/hb-unicode-emoji-table.hh
new file mode 100644
index 000000000..41199de53
--- /dev/null
+++ b/src/hb-unicode-emoji-table.hh
@@ -0,0 +1,269 @@
+/* == Start of generated table == */
+/*
+ * The following tables are generated by running:
+ *
+ * ./gen-emoji-table.py emoji-data.txt
+ *
+ * on file with this header:
+ *
+ * # emoji-data.txt
+ * # Date: 2018-02-07, 07:55:18 GMT
+ * # © 2018 Unicode®, Inc.
+ * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+ * # For terms of use, see http://www.unicode.org/terms_of_use.html
+ * #
+ * # Emoji Data for UTS #51
+ * # Version: 11.0
+ * #
+ * # For documentation and usage, see http://www.unicode.org/reports/tr51
+ */
+
+#ifndef HB_UNICODE_EMOJI_TABLE_HH
+#define HB_UNICODE_EMOJI_TABLE_HH
+
+#include "hb-unicode.hh"
+
+
+static const struct hb_unicode_range_t _hb_unicode_emoji_Extended_Pictographic_table[] =
+{
+ {0x00A9, 0x00A9},
+ {0x00AE, 0x00AE},
+ {0x203C, 0x203C},
+ {0x2049, 0x2049},
+ {0x2122, 0x2122},
+ {0x2139, 0x2139},
+ {0x2194, 0x2199},
+ {0x21A9, 0x21AA},
+ {0x231A, 0x231B},
+ {0x2328, 0x2328},
+ {0x2388, 0x2388},
+ {0x23CF, 0x23CF},
+ {0x23E9, 0x23F3},
+ {0x23F8, 0x23FA},
+ {0x24C2, 0x24C2},
+ {0x25AA, 0x25AB},
+ {0x25B6, 0x25B6},
+ {0x25C0, 0x25C0},
+ {0x25FB, 0x25FE},
+ {0x2600, 0x2605},
+ {0x2607, 0x2612},
+ {0x2614, 0x2615},
+ {0x2616, 0x2617},
+ {0x2618, 0x2618},
+ {0x2619, 0x2619},
+ {0x261A, 0x266F},
+ {0x2670, 0x2671},
+ {0x2672, 0x267D},
+ {0x267E, 0x267F},
+ {0x2680, 0x2685},
+ {0x2690, 0x2691},
+ {0x2692, 0x269C},
+ {0x269D, 0x269D},
+ {0x269E, 0x269F},
+ {0x26A0, 0x26A1},
+ {0x26A2, 0x26B1},
+ {0x26B2, 0x26B2},
+ {0x26B3, 0x26BC},
+ {0x26BD, 0x26BF},
+ {0x26C0, 0x26C3},
+ {0x26C4, 0x26CD},
+ {0x26CE, 0x26CE},
+ {0x26CF, 0x26E1},
+ {0x26E2, 0x26E2},
+ {0x26E3, 0x26E3},
+ {0x26E4, 0x26E7},
+ {0x26E8, 0x26FF},
+ {0x2700, 0x2700},
+ {0x2701, 0x2704},
+ {0x2705, 0x2705},
+ {0x2708, 0x2709},
+ {0x270A, 0x270B},
+ {0x270C, 0x2712},
+ {0x2714, 0x2714},
+ {0x2716, 0x2716},
+ {0x271D, 0x271D},
+ {0x2721, 0x2721},
+ {0x2728, 0x2728},
+ {0x2733, 0x2734},
+ {0x2744, 0x2744},
+ {0x2747, 0x2747},
+ {0x274C, 0x274C},
+ {0x274E, 0x274E},
+ {0x2753, 0x2755},
+ {0x2757, 0x2757},
+ {0x2763, 0x2767},
+ {0x2795, 0x2797},
+ {0x27A1, 0x27A1},
+ {0x27B0, 0x27B0},
+ {0x27BF, 0x27BF},
+ {0x2934, 0x2935},
+ {0x2B05, 0x2B07},
+ {0x2B1B, 0x2B1C},
+ {0x2B50, 0x2B50},
+ {0x2B55, 0x2B55},
+ {0x3030, 0x3030},
+ {0x303D, 0x303D},
+ {0x3297, 0x3297},
+ {0x3299, 0x3299},
+ {0x1F000, 0x1F02B},
+ {0x1F02C, 0x1F02F},
+ {0x1F030, 0x1F093},
+ {0x1F094, 0x1F09F},
+ {0x1F0A0, 0x1F0AE},
+ {0x1F0AF, 0x1F0B0},
+ {0x1F0B1, 0x1F0BE},
+ {0x1F0BF, 0x1F0BF},
+ {0x1F0C0, 0x1F0C0},
+ {0x1F0C1, 0x1F0CF},
+ {0x1F0D0, 0x1F0D0},
+ {0x1F0D1, 0x1F0DF},
+ {0x1F0E0, 0x1F0F5},
+ {0x1F0F6, 0x1F0FF},
+ {0x1F10D, 0x1F10F},
+ {0x1F12F, 0x1F12F},
+ {0x1F16C, 0x1F16F},
+ {0x1F170, 0x1F171},
+ {0x1F17E, 0x1F17E},
+ {0x1F17F, 0x1F17F},
+ {0x1F18E, 0x1F18E},
+ {0x1F191, 0x1F19A},
+ {0x1F1AD, 0x1F1E5},
+ {0x1F201, 0x1F202},
+ {0x1F203, 0x1F20F},
+ {0x1F21A, 0x1F21A},
+ {0x1F22F, 0x1F22F},
+ {0x1F232, 0x1F23A},
+ {0x1F23C, 0x1F23F},
+ {0x1F249, 0x1F24F},
+ {0x1F250, 0x1F251},
+ {0x1F252, 0x1F25F},
+ {0x1F260, 0x1F265},
+ {0x1F266, 0x1F2FF},
+ {0x1F300, 0x1F320},
+ {0x1F321, 0x1F32C},
+ {0x1F32D, 0x1F32F},
+ {0x1F330, 0x1F335},
+ {0x1F336, 0x1F336},
+ {0x1F337, 0x1F37C},
+ {0x1F37D, 0x1F37D},
+ {0x1F37E, 0x1F37F},
+ {0x1F380, 0x1F393},
+ {0x1F394, 0x1F39F},
+ {0x1F3A0, 0x1F3C4},
+ {0x1F3C5, 0x1F3C5},
+ {0x1F3C6, 0x1F3CA},
+ {0x1F3CB, 0x1F3CE},
+ {0x1F3CF, 0x1F3D3},
+ {0x1F3D4, 0x1F3DF},
+ {0x1F3E0, 0x1F3F0},
+ {0x1F3F1, 0x1F3F7},
+ {0x1F3F8, 0x1F3FA},
+ {0x1F400, 0x1F43E},
+ {0x1F43F, 0x1F43F},
+ {0x1F440, 0x1F440},
+ {0x1F441, 0x1F441},
+ {0x1F442, 0x1F4F7},
+ {0x1F4F8, 0x1F4F8},
+ {0x1F4F9, 0x1F4FC},
+ {0x1F4FD, 0x1F4FE},
+ {0x1F4FF, 0x1F4FF},
+ {0x1F500, 0x1F53D},
+ {0x1F546, 0x1F54A},
+ {0x1F54B, 0x1F54F},
+ {0x1F550, 0x1F567},
+ {0x1F568, 0x1F579},
+ {0x1F57A, 0x1F57A},
+ {0x1F57B, 0x1F5A3},
+ {0x1F5A4, 0x1F5A4},
+ {0x1F5A5, 0x1F5FA},
+ {0x1F5FB, 0x1F5FF},
+ {0x1F600, 0x1F600},
+ {0x1F601, 0x1F610},
+ {0x1F611, 0x1F611},
+ {0x1F612, 0x1F614},
+ {0x1F615, 0x1F615},
+ {0x1F616, 0x1F616},
+ {0x1F617, 0x1F617},
+ {0x1F618, 0x1F618},
+ {0x1F619, 0x1F619},
+ {0x1F61A, 0x1F61A},
+ {0x1F61B, 0x1F61B},
+ {0x1F61C, 0x1F61E},
+ {0x1F61F, 0x1F61F},
+ {0x1F620, 0x1F625},
+ {0x1F626, 0x1F627},
+ {0x1F628, 0x1F62B},
+ {0x1F62C, 0x1F62C},
+ {0x1F62D, 0x1F62D},
+ {0x1F62E, 0x1F62F},
+ {0x1F630, 0x1F633},
+ {0x1F634, 0x1F634},
+ {0x1F635, 0x1F640},
+ {0x1F641, 0x1F642},
+ {0x1F643, 0x1F644},
+ {0x1F645, 0x1F64F},
+ {0x1F680, 0x1F6C5},
+ {0x1F6C6, 0x1F6CF},
+ {0x1F6D0, 0x1F6D0},
+ {0x1F6D1, 0x1F6D2},
+ {0x1F6D3, 0x1F6D4},
+ {0x1F6D5, 0x1F6DF},
+ {0x1F6E0, 0x1F6EC},
+ {0x1F6ED, 0x1F6EF},
+ {0x1F6F0, 0x1F6F3},
+ {0x1F6F4, 0x1F6F6},
+ {0x1F6F7, 0x1F6F8},
+ {0x1F6F9, 0x1F6F9},
+ {0x1F6FA, 0x1F6FF},
+ {0x1F774, 0x1F77F},
+ {0x1F7D5, 0x1F7D8},
+ {0x1F7D9, 0x1F7FF},
+ {0x1F80C, 0x1F80F},
+ {0x1F848, 0x1F84F},
+ {0x1F85A, 0x1F85F},
+ {0x1F888, 0x1F88F},
+ {0x1F8AE, 0x1F8FF},
+ {0x1F90C, 0x1F90F},
+ {0x1F910, 0x1F918},
+ {0x1F919, 0x1F91E},
+ {0x1F91F, 0x1F91F},
+ {0x1F920, 0x1F927},
+ {0x1F928, 0x1F92F},
+ {0x1F930, 0x1F930},
+ {0x1F931, 0x1F932},
+ {0x1F933, 0x1F93A},
+ {0x1F93C, 0x1F93E},
+ {0x1F93F, 0x1F93F},
+ {0x1F940, 0x1F945},
+ {0x1F947, 0x1F94B},
+ {0x1F94C, 0x1F94C},
+ {0x1F94D, 0x1F94F},
+ {0x1F950, 0x1F95E},
+ {0x1F95F, 0x1F96B},
+ {0x1F96C, 0x1F970},
+ {0x1F971, 0x1F972},
+ {0x1F973, 0x1F976},
+ {0x1F977, 0x1F979},
+ {0x1F97A, 0x1F97A},
+ {0x1F97B, 0x1F97B},
+ {0x1F97C, 0x1F97F},
+ {0x1F980, 0x1F984},
+ {0x1F985, 0x1F991},
+ {0x1F992, 0x1F997},
+ {0x1F998, 0x1F9A2},
+ {0x1F9A3, 0x1F9AF},
+ {0x1F9B0, 0x1F9B9},
+ {0x1F9BA, 0x1F9BF},
+ {0x1F9C0, 0x1F9C0},
+ {0x1F9C1, 0x1F9C2},
+ {0x1F9C3, 0x1F9CF},
+ {0x1F9D0, 0x1F9E6},
+ {0x1F9E7, 0x1F9FF},
+ {0x1FA00, 0x1FA5F},
+ {0x1FA60, 0x1FA6D},
+ {0x1FA6E, 0x1FFFD},
+};
+
+#endif /* HB_UNICODE_EMOJI_TABLE_HH */
+
+/* == End of generated table == */
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 8cb417233..7b821b46d 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -28,9 +28,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
-#include "hb-unicode-private.hh"
+#include "hb-unicode.hh"
@@ -308,6 +308,8 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
{
if (unlikely (hb_object_is_inert (ufuncs)))
return;
+ if (ufuncs->immutable)
+ return;
ufuncs->immutable = true;
}
@@ -450,7 +452,7 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
}
-/* See hb-unicode-private.hh for details. */
+/* See hb-unicode.hh for details. */
const uint8_t
_hb_modified_combining_class[256] =
{
@@ -562,3 +564,19 @@ _hb_modified_combining_class[256] =
241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
255, /* HB_UNICODE_COMBINING_CLASS_INVALID */
};
+
+
+/*
+ * Emoji
+ */
+
+#include "hb-unicode-emoji-table.hh"
+
+bool
+_hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp)
+{
+ return hb_bsearch_r (&cp, _hb_unicode_emoji_Extended_Pictographic_table,
+ ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table),
+ sizeof (hb_unicode_range_t),
+ hb_unicode_range_t::cmp, nullptr);
+}
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index 2657f4813..df0b91f01 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -40,6 +40,14 @@
HB_BEGIN_DECLS
+/**
+ * HB_UNICODE_MAX
+ *
+ * Since: 1.9.0
+ **/
+#define HB_UNICODE_MAX 0x10FFFFu
+
+
/* hb_unicode_general_category_t */
/* Unicode Character Database property: General_Category (gc) */
@@ -222,9 +230,6 @@ hb_unicode_funcs_get_parent (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,
- hb_codepoint_t unicode,
- void *user_data);
typedef hb_unicode_general_category_t (*hb_unicode_general_category_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
@@ -246,32 +251,6 @@ 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 */
/**
@@ -291,22 +270,6 @@ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
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: 0.9.2
- **/
-HB_EXTERN void
-hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
- 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):
@@ -386,22 +349,6 @@ hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
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: 0.9.2
- **/
-HB_EXTERN 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 */
/**
@@ -414,15 +361,6 @@ hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
/**
- * hb_unicode_eastasian_width:
- *
- * Since: 0.9.2
- **/
-HB_EXTERN unsigned int
-hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
- hb_codepoint_t unicode);
-
-/**
* hb_unicode_general_category:
*
* Since: 0.9.2
@@ -461,11 +399,6 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *a,
hb_codepoint_t *b);
-HB_EXTERN 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 */
diff --git a/src/hb-unicode-private.hh b/src/hb-unicode.hh
index fb16ba437..6d6a4fa0c 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode.hh
@@ -28,10 +28,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_UNICODE_PRIVATE_HH
-#define HB_UNICODE_PRIVATE_HH
+#ifndef HB_UNICODE_HH
+#define HB_UNICODE_HH
-#include "hb-private.hh"
+#include "hb.hh"
extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
@@ -101,24 +101,23 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
return ret;
}
-
inline unsigned int
- modified_combining_class (hb_codepoint_t unicode)
+ modified_combining_class (hb_codepoint_t u)
{
/* XXX This hack belongs to the Myanmar shaper. */
- if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
+ if (unlikely (u == 0x1037u)) u = 0x103Au;
/* XXX This hack belongs to the USE shaper (for Tai Tham):
* Reorder SAKOT to ensure it comes after any tone marks. */
- if (unlikely (unicode == 0x1A60u)) return 254;
+ if (unlikely (u == 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;
+ if (unlikely (u == 0x0FC6u)) return 254;
/* Reorder TSA -PHRU to reorder before U+0F74 */
- if (unlikely (unicode == 0x0F39u)) return 127;
+ if (unlikely (u == 0x0F39u)) return 127;
- return _hb_modified_combining_class[combining_class (unicode)];
+ return _hb_modified_combining_class[combining_class (u)];
}
static inline hb_bool_t
@@ -267,7 +266,9 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
DECLARE_NULL_INSTANCE (hb_unicode_funcs_t);
-/* Modified combining marks */
+/*
+ * Modified combining marks
+ */
/* Hebrew
*
@@ -360,10 +361,37 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t);
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
-#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \
- (FLAG_UNSAFE (gen_cat) & \
- (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
- FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
- FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
-#endif /* HB_UNICODE_PRIVATE_HH */
+/*
+ * Ranges, used for bsearch tables.
+ */
+
+struct hb_unicode_range_t
+{
+ static int
+ cmp (const void *_key, const void *_item, void *_arg)
+ {
+ hb_codepoint_t cp = *((hb_codepoint_t *) _key);
+ const hb_unicode_range_t *range = (hb_unicode_range_t *) _item;
+
+ if (cp < range->start)
+ return -1;
+ else if (cp <= range->end)
+ return 0;
+ else
+ return +1;
+ }
+
+ hb_codepoint_t start;
+ hb_codepoint_t end;
+};
+
+/*
+ * Emoji.
+ */
+
+HB_INTERNAL bool
+_hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp);
+
+
+#endif /* HB_UNICODE_HH */
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 11b7384fa..44a67ae4c 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -24,9 +24,9 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#define HB_SHAPER uniscribe
-#include "hb-shaper-impl-private.hh"
+#include "hb-shaper-impl.hh"
#include <windows.h>
#include <usp10.h>
@@ -34,7 +34,7 @@
#include "hb-uniscribe.h"
-#include "hb-open-file-private.hh"
+#include "hb-open-file.hh"
#include "hb-ot-name-table.hh"
#include "hb-ot-tag.h"
@@ -392,7 +392,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
name.stringOffset.set (name.get_size ());
for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
{
- OT::NameRecord &record = name.nameRecord[i];
+ OT::NameRecord &record = name.nameRecordZ[i];
record.platformID.set (3);
record.encodingID.set (1);
record.languageID.set (0x0409u); /* English */
@@ -717,7 +717,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
{
active_feature_t *feature = active_features.find (&event->feature);
if (feature)
- active_features.remove (feature - active_features.arrayZ);
+ active_features.remove (feature - active_features.arrayZ());
}
}
@@ -728,7 +728,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
for (unsigned int i = 0; i < range_records.len; i++)
{
range_record_t *range = &range_records[i];
- range->props.potfRecords = feature_records.arrayZ + reinterpret_cast<uintptr_t> (range->props.potfRecords);
+ range->props.potfRecords = feature_records.arrayZ() + reinterpret_cast<uintptr_t> (range->props.potfRecords);
}
}
@@ -902,8 +902,8 @@ retry:
&items[i].a,
script_tags[i],
language_tag,
- range_char_counts.arrayZ,
- range_properties.arrayZ,
+ range_char_counts.arrayZ(),
+ range_properties.arrayZ(),
range_properties.len,
pchars + chars_offset,
item_chars_len,
@@ -943,8 +943,8 @@ retry:
&items[i].a,
script_tags[i],
language_tag,
- range_char_counts.arrayZ,
- range_properties.arrayZ,
+ range_char_counts.arrayZ(),
+ range_properties.arrayZ(),
range_properties.len,
pchars + chars_offset,
log_clusters + chars_offset,
diff --git a/src/hb-utf-private.hh b/src/hb-utf.hh
index 211eb4dc0..eccb632e4 100644
--- a/src/hb-utf-private.hh
+++ b/src/hb-utf.hh
@@ -24,10 +24,10 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_UTF_PRIVATE_HH
-#define HB_UTF_PRIVATE_HH
+#ifndef HB_UTF_HH
+#define HB_UTF_HH
-#include "hb-private.hh"
+#include "hb.hh"
struct hb_utf8_t
@@ -279,4 +279,4 @@ struct hb_latin1_t
}
};
-#endif /* HB_UTF_PRIVATE_HH */
+#endif /* HB_UTF_HH */
diff --git a/src/hb-vector-private.hh b/src/hb-vector.hh
index 1ef20d438..766e5fb8e 100644
--- a/src/hb-vector-private.hh
+++ b/src/hb-vector.hh
@@ -25,45 +25,52 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_VECTOR_PRIVATE_HH
-#define HB_VECTOR_PRIVATE_HH
+#ifndef HB_VECTOR_HH
+#define HB_VECTOR_HH
-#include "hb-private.hh"
+#include "hb.hh"
template <typename Type, unsigned int StaticSize=8>
struct hb_vector_t
{
unsigned int len;
+ private:
unsigned int allocated; /* == 0 means allocation failed. */
- Type *arrayZ;
+ Type *arrayZ_;
Type static_array[StaticSize];
+ public:
void init (void)
{
len = 0;
allocated = ARRAY_LENGTH (static_array);
- arrayZ = static_array;
+ arrayZ_ = nullptr;
}
+ inline Type * arrayZ (void)
+ { return arrayZ_ ? arrayZ_ : static_array; }
+ inline const Type * arrayZ (void) const
+ { return arrayZ_ ? arrayZ_ : static_array; }
+
inline Type& operator [] (unsigned int i)
{
if (unlikely (i >= len))
return Crap (Type);
- return arrayZ[i];
+ return arrayZ()[i];
}
inline const Type& operator [] (unsigned int i) const
{
if (unlikely (i >= len))
return Null(Type);
- return arrayZ[i];
+ return arrayZ()[i];
}
inline Type *push (void)
{
if (unlikely (!resize (len + 1)))
return &Crap(Type);
- return &arrayZ[len - 1];
+ return &arrayZ()[len - 1];
}
inline Type *push (const Type& v)
{
@@ -72,6 +79,8 @@ struct hb_vector_t
return p;
}
+ inline bool in_error (void) const { return allocated == 0; }
+
/* Allocate for size but don't adjust len. */
inline bool alloc (unsigned int size)
{
@@ -89,17 +98,17 @@ struct hb_vector_t
Type *new_array = nullptr;
- if (arrayZ == static_array)
+ if (!arrayZ_)
{
new_array = (Type *) calloc (new_allocated, sizeof (Type));
if (new_array)
- memcpy (new_array, arrayZ, len * sizeof (Type));
+ memcpy (new_array, static_array, len * sizeof (Type));
}
else
{
bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
if (likely (!overflows))
- new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
+ new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type));
}
if (unlikely (!new_array))
@@ -108,7 +117,7 @@ struct hb_vector_t
return false;
}
- arrayZ = new_array;
+ arrayZ_ = new_array;
allocated = new_allocated;
return true;
@@ -121,7 +130,7 @@ struct hb_vector_t
return false;
if (size > len)
- memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
+ memset (arrayZ() + len, 0, (size - len) * sizeof (*arrayZ()));
len = size;
return true;
@@ -135,12 +144,13 @@ struct hb_vector_t
inline void remove (unsigned int i)
{
- if (unlikely (i >= len))
- return;
- memmove (static_cast<void *> (&arrayZ[i]),
- static_cast<void *> (&arrayZ[i + 1]),
- (len - i - 1) * sizeof (Type));
- len--;
+ if (unlikely (i >= len))
+ return;
+ Type *array = arrayZ();
+ memmove (static_cast<void *> (&array[i]),
+ static_cast<void *> (&array[i + 1]),
+ (len - i - 1) * sizeof (Type));
+ len--;
}
inline void shrink (int size_)
@@ -151,41 +161,55 @@ struct hb_vector_t
}
template <typename T>
- inline Type *find (T v) {
+ inline Type *find (T v)
+ {
+ Type *array = arrayZ();
for (unsigned int i = 0; i < len; i++)
- if (arrayZ[i] == v)
- return &arrayZ[i];
+ if (array[i] == v)
+ return &array[i];
return nullptr;
}
template <typename T>
- inline const Type *find (T v) const {
+ inline const Type *find (T v) const
+ {
+ const Type *array = arrayZ();
for (unsigned int i = 0; i < len; i++)
- if (arrayZ[i] == v)
- return &arrayZ[i];
+ if (array[i] == v)
+ return &array[i];
return nullptr;
}
inline void qsort (int (*cmp)(const void*, const void*))
{
- ::qsort (arrayZ, len, sizeof (Type), cmp);
+ ::qsort (arrayZ(), len, sizeof (Type), cmp);
}
inline void qsort (void)
{
- ::qsort (arrayZ, len, sizeof (Type), Type::cmp);
+ ::qsort (arrayZ(), len, sizeof (Type), Type::cmp);
}
inline void qsort (unsigned int start, unsigned int end)
{
- ::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
+ ::qsort (arrayZ() + start, end - start, sizeof (Type), Type::cmp);
}
template <typename T>
inline Type *lsearch (const T &x)
{
+ Type *array = arrayZ();
+ for (unsigned int i = 0; i < len; i++)
+ if (0 == array[i].cmp (&x))
+ return &array[i];
+ return nullptr;
+ }
+ template <typename T>
+ inline const Type *lsearch (const T &x) const
+ {
+ const Type *array = arrayZ();
for (unsigned int i = 0; i < len; i++)
- if (0 == this->arrayZ[i].cmp (&x))
- return &arrayZ[i];
+ if (0 == array[i].cmp (&x))
+ return &array[i];
return nullptr;
}
@@ -193,22 +217,23 @@ struct hb_vector_t
inline Type *bsearch (const T &x)
{
unsigned int i;
- return bfind (x, &i) ? &arrayZ[i] : nullptr;
+ return bfind (x, &i) ? &arrayZ()[i] : nullptr;
}
template <typename T>
inline const Type *bsearch (const T &x) const
{
unsigned int i;
- return bfind (x, &i) ? &arrayZ[i] : nullptr;
+ return bfind (x, &i) ? &arrayZ()[i] : nullptr;
}
template <typename T>
inline bool bfind (const T &x, unsigned int *i) const
{
int min = 0, max = (int) this->len - 1;
+ const Type *array = this->arrayZ();
while (min <= max)
{
int mid = (min + max) / 2;
- int c = this->arrayZ[mid].cmp (&x);
+ int c = array[mid].cmp (&x);
if (c < 0)
max = mid - 1;
else if (c > 0)
@@ -219,20 +244,29 @@ struct hb_vector_t
return true;
}
}
- if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
+ if (max < 0 || (max < (int) this->len && array[max].cmp (&x) > 0))
max++;
*i = max;
return false;
}
+ inline void fini_deep (void)
+ {
+ Type *array = arrayZ();
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ array[i].fini ();
+ fini ();
+ }
+
inline void fini (void)
{
- if (arrayZ != static_array)
- free (arrayZ);
- arrayZ = nullptr;
+ if (arrayZ_)
+ free (arrayZ_);
+ arrayZ_ = nullptr;
allocated = len = 0;
}
};
-#endif /* HB_VECTOR_PRIVATE_HH */
+#endif /* HB_VECTOR_HH */
diff --git a/src/hb-version.h b/src/hb-version.h
index e0816d1e6..a8db51606 100644
--- a/src/hb-version.h
+++ b/src/hb-version.h
@@ -36,11 +36,11 @@
HB_BEGIN_DECLS
-#define HB_VERSION_MAJOR 1
-#define HB_VERSION_MINOR 8
-#define HB_VERSION_MICRO 8
+#define HB_VERSION_MAJOR 2
+#define HB_VERSION_MINOR 0
+#define HB_VERSION_MICRO 2
-#define HB_VERSION_STRING "1.8.8"
+#define HB_VERSION_STRING "2.0.2"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
diff --git a/src/hb-warning.cc b/src/hb-warning.cc
index f7a87b5ab..9fb410038 100644
--- a/src/hb-warning.cc
+++ b/src/hb-warning.cc
@@ -24,14 +24,14 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#if defined(HB_ATOMIC_INT_NIL)
#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
-#error "Check hb-atomic-private.hh for possible resolutions."
+#error "Check hb-atomic.hh for possible resolutions."
#endif
#if defined(HB_MUTEX_IMPL_NIL)
#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe"
-#error "Check hb-mutex-private.hh for possible resolutions."
+#error "Check hb-mutex.hh for possible resolutions."
#endif
diff --git a/src/hb-private.hh b/src/hb.hh
index efe7bda9e..098b56604 100644
--- a/src/hb-private.hh
+++ b/src/hb.hh
@@ -26,8 +26,8 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_PRIVATE_HH
-#define HB_PRIVATE_HH
+#ifndef HB_HH
+#define HB_HH
#define _GNU_SOURCE 1
@@ -35,12 +35,18 @@
#include "config.h"
#endif
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif
+
+#if defined (_MSC_VER) && defined (HB_DLL_EXPORT)
+#define HB_EXTERN __declspec (dllexport) extern
+#endif
+
#include "hb.h"
#define HB_H_IN
-#ifdef HAVE_OT
#include "hb-ot.h"
#define HB_OT_H_IN
-#endif
#include <math.h>
#include <stdlib.h>
@@ -174,8 +180,10 @@ struct _hb_alignof
# if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC)
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
# elif defined(__MINGW32__)
- /* We use -export-symbols on mingw32, since it does not support visibility
- * attribute. */
+ /* We use -export-symbols on mingw32, since it does not support visibility attributes. */
+# define HB_INTERNAL
+# elif defined (_MSC_VER) && defined (HB_DLL_EXPORT)
+ /* We do not try to export internal symbols on Visual Studio */
# define HB_INTERNAL
#else
# define HB_INTERNAL
@@ -229,6 +237,15 @@ struct _hb_alignof
# define HB_FALLTHROUGH /* FALLTHROUGH */
#endif
+#if defined(__clang__)
+/* Disable certain sanitizer errors. */
+/* https://github.com/harfbuzz/harfbuzz/issues/1247 */
+#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow")))
+#else
+#define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW
+#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,
@@ -237,7 +254,9 @@ struct _hb_alignof
# undef _WIN32_WINNT
# endif
# ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0600
+# if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+# define _WIN32_WINNT 0x0600
+# endif
# endif
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN 1
@@ -468,13 +487,21 @@ _hb_memalign(void **memptr, size_t alignment, size_t size)
#endif
+/*
+ * For lack of a better place, put Zawgyi script hack here.
+ * https://github.com/harfbuzz/harfbuzz/issues/1162
+ */
+
+#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g'))
+
+
/* Headers we include for everyone. Keep sorted. They express dependency amongst
* themselves, but no other file should include them.*/
-#include "hb-atomic-private.hh"
+#include "hb-atomic.hh"
#include "hb-debug.hh"
#include "hb-dsalgs.hh"
-#include "hb-mutex-private.hh"
+#include "hb-mutex.hh"
#include "hb-null.hh"
-#include "hb-object-private.hh"
+#include "hb-object.hh"
-#endif /* HB_PRIVATE_HH */
+#endif /* HB_HH */
diff --git a/src/main.cc b/src/main.cc
index 98a1320bf..490b76e5b 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -25,9 +25,9 @@
*/
#include "hb-static.cc"
-#include "hb-open-file-private.hh"
+#include "hb-open-file.hh"
#include "hb-ot-layout-gdef-table.hh"
-#include "hb-ot-layout-gsubgpos-private.hh"
+#include "hb-ot-layout-gsubgpos.hh"
#ifdef HAVE_GLIB
#include <glib.h>
diff --git a/src/sample.py b/src/sample.py
index 8f97195f2..5d65aa09e 100755
--- a/src/sample.py
+++ b/src/sample.py
@@ -54,11 +54,11 @@ if False:
# buffer:
hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
# Otherwise, then following handles both narrow and wide
- # Python builds:
+ # Python builds (the first item in the array is BOM, so we skip it):
elif sys.maxunicode == 0x10FFFF:
- hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32')), 0, -1)
+ hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32'))[1:], 0, -1)
else:
- hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16')), 0, -1)
+ hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16'))[1:], 0, -1)
hb.buffer_guess_segment_properties (buf)
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
index 39eb13da7..a91f4f7e9 100644
--- a/src/test-buffer-serialize.cc
+++ b/src/test-buffer-serialize.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb.h"
#include "hb-ot.h"
diff --git a/src/test-size-params.cc b/src/test-size-params.cc
index 3c43852b3..e53a47d8d 100644
--- a/src/test-size-params.cc
+++ b/src/test-size-params.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb.h"
#include "hb-ot.h"
diff --git a/src/test-unicode-ranges.cc b/src/test-unicode-ranges.cc
index dbc5fa426..d9342d7bb 100644
--- a/src/test-unicode-ranges.cc
+++ b/src/test-unicode-ranges.cc
@@ -24,24 +24,24 @@
* Google Author(s): Garret Rieger
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb-ot-os2-unicode-ranges.hh"
-void
+static void
test (hb_codepoint_t cp, unsigned int bit)
{
- if (OT::hb_get_unicode_range_bit (cp) != bit)
+ if (OT::_hb_ot_os2_get_unicode_range_bit (cp) != bit)
{
fprintf (stderr, "got incorrect bit (%d) for cp 0x%X. Should have been %d.",
- OT::hb_get_unicode_range_bit (cp),
+ OT::_hb_ot_os2_get_unicode_range_bit (cp),
cp,
bit);
abort();
}
}
-void
+static void
test_get_unicode_range_bit (void)
{
test (0x0000, 0);
diff --git a/src/test-would-substitute.cc b/src/test-would-substitute.cc
index 1836d720c..268f7db98 100644
--- a/src/test-would-substitute.cc
+++ b/src/test-would-substitute.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb.h"
#include "hb-ot.h"
diff --git a/src/test.cc b/src/test.cc
index cf59e00ac..f0eace8c4 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -24,7 +24,7 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#include "hb.hh"
#include "hb.h"
diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt
index b540eb505..0c7337cb5 100644
--- a/test/api/CMakeLists.txt
+++ b/test/api/CMakeLists.txt
@@ -3,6 +3,8 @@ if (HB_HAVE_GLIB)
extract_make_variable (TEST_PROGS ${MAKEFILEAM})
list (APPEND TEST_PROGS
+ test-ot-color
+ test-ot-name
test-ot-tag
test-c
test-cplusplus
diff --git a/test/api/Makefile.am b/test/api/Makefile.am
index a20334498..45a34e64d 100644
--- a/test/api/Makefile.am
+++ b/test/api/Makefile.am
@@ -16,6 +16,8 @@ EXTRA_DIST += CMakeLists.txt
EXTRA_DIST += fonts
+LINK = $(CXXLINK)
+
if HAVE_GLIB
AM_CPPFLAGS = -DSRCDIR="\"$(srcdir)\"" -I$(top_srcdir)/src/ -I$(top_builddir)/src/ $(GLIB_CFLAGS)
LDADD = $(top_builddir)/src/libharfbuzz.la $(GLIB_LIBS)
@@ -28,13 +30,14 @@ noinst_PROGRAMS = $(TEST_PROGS)
TEST_PROGS = \
test-blob \
test-buffer \
+ test-collect-unicodes \
test-common \
test-font \
+ test-map \
test-object \
test-set \
test-shape \
test-subset \
- test-subset-codepoints \
test-subset-cmap \
test-subset-glyf \
test-subset-hdmx \
@@ -67,13 +70,24 @@ test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la $(ICU_LIBS)
endif
-if HAVE_OT
-
TEST_PROGS += \
test-ot-color \
+ test-ot-name \
test-ot-tag \
$(NULL)
+
+if HAVE_PTHREAD
+if HAVE_FREETYPE
+TEST_PROGS += test-multithread
+test_multithread_CFLAGS = $(CFLAGS) $(PTHREAD_CFLAGS) $(FREETYPE_CFLAGS)
+test_multithread_LDADD = $(LDADD) $(PTHREAD_LIBS) $(FREETYPE_LIBS)
+# The auto-generated link rule somehow includes CFLAGS as well. Without
+# it, pthread link fails, because, who knows why, $PTHREAD_LIBS is empty.
+test_multithread_LINK = $(LINK) $(PTHREAD_CFLAGS)
+endif
+endif
+
if HAVE_FREETYPE
TEST_PROGS += \
test-ot-math \
@@ -82,7 +96,6 @@ test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS)
test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS)
endif # HAVE_FREETYPE
-endif # HAVE_OT
# Tests for header compilation
TEST_PROGS += \
@@ -154,13 +167,18 @@ symbols-tested.txt: $(TEST_PROGS)
$(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \
| grep ' U hb_' | sed 's/.* U hb_/hb_/' \
| sort | uniq > $@.tmp && mv $@.tmp $@
+symbols-tested-or-deprecated.txt: symbols-tested.txt $(top_builddir)/src/harfbuzz-deprecated.def
+ $(AM_V_GEN)cat $^ | sort | uniq > $@.tmp; mv $@.tmp $@
symbols-exported.txt: $(top_builddir)/src/.libs/libharfbuzz.so
$(AM_V_GEN)$(top_builddir)/libtool --mode=execute nm $^ \
| grep ' T ' | sed 's/.* T //' | grep -v '^\(_init\|_fini\)$$' \
| sort | uniq > $@.tmp && mv $@.tmp $@
-symbols-untested.txt: symbols-tested.txt symbols-exported.txt
+symbols-untested.txt: symbols-tested-or-deprecated.txt symbols-exported.txt
$(AM_V_GEN)diff $^ > $@.tmp; mv $@.tmp $@
-CLEANFILES += symbols-tested.txt symbols-exported.txt symbols-untested.txt
+CLEANFILES += symbols-tested.txt \
+ symbols-exported.txt \
+ symbols-untested.txt \
+ symbols-tested-or-deprecated.txt
check-symbols: symbols-untested.txt
@! cat $^ | grep .
diff --git a/test/api/fonts/Roboto-Regular.multihdmx.a.ttf b/test/api/fonts/Roboto-Regular.multihdmx.a.ttf
new file mode 100644
index 000000000..dd82178fd
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.multihdmx.a.ttf
Binary files differ
diff --git a/test/api/fonts/Roboto-Regular.multihdmx.abc.ttf b/test/api/fonts/Roboto-Regular.multihdmx.abc.ttf
new file mode 100644
index 000000000..03dd8b6b7
--- /dev/null
+++ b/test/api/fonts/Roboto-Regular.multihdmx.abc.ttf
Binary files differ
diff --git a/test/api/fonts/cv01.otf b/test/api/fonts/cv01.otf
new file mode 100644
index 000000000..01dbf01f3
--- /dev/null
+++ b/test/api/fonts/cv01.otf
Binary files differ
diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h
index c34f394b9..5f5cd8d00 100644
--- a/test/api/hb-subset-test.h
+++ b/test/api/hb-subset-test.h
@@ -51,12 +51,21 @@ static inline hb_face_t *
hb_subset_test_open_font (const char *font_path)
{
#if GLIB_CHECK_VERSION(2,37,2)
- char* path = g_test_build_filename(G_TEST_DIST, font_path, NULL);
+ char *path = g_test_build_filename (G_TEST_DIST, font_path, NULL);
#else
- char* path = g_strdup(font_path);
+ char *path = g_strdup (font_path);
#endif
- return hb_face_create (hb_blob_create_from_file (path), 0);
+ hb_blob_t *blob = hb_blob_create_from_file (path);
+ if (hb_blob_get_length (blob) == 0)
+ g_error ("Font not found.");
+
+ hb_face_t *face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+
+ g_free (path);
+
+ return face;
}
static inline hb_subset_input_t *
@@ -72,11 +81,9 @@ static inline hb_face_t *
hb_subset_test_create_subset (hb_face_t *source,
hb_subset_input_t *input)
{
- hb_subset_profile_t *profile = hb_subset_profile_create();
- hb_face_t *subset = hb_subset (source, profile, input);
+ hb_face_t *subset = hb_subset (source, input);
g_assert (subset);
- hb_subset_profile_destroy (profile);
hb_subset_input_destroy (input);
return subset;
}
diff --git a/test/api/hb-test.h b/test/api/hb-test.h
index 307845f62..39d091b60 100644
--- a/test/api/hb-test.h
+++ b/test/api/hb-test.h
@@ -42,6 +42,7 @@ HB_BEGIN_DECLS
/* Just in case */
#undef G_DISABLE_ASSERT
+#define HB_UNUSED G_GNUC_UNUSED
/* Misc */
diff --git a/test/api/test-blob.c b/test/api/test-blob.c
index d566f4e9d..7914a26ce 100644
--- a/test/api/test-blob.c
+++ b/test/api/test-blob.c
@@ -195,7 +195,7 @@ fixture_init (fixture_t *fixture, gconstpointer user_data)
}
static void
-fixture_finish (fixture_t *fixture, gconstpointer user_data)
+fixture_finish (fixture_t *fixture, gconstpointer user_data HB_UNUSED)
{
hb_blob_destroy (fixture->blob);
g_assert_cmpint (fixture->freed, ==, 1);
diff --git a/test/api/test-buffer.c b/test/api/test-buffer.c
index 5c98a9a16..5fba3b228 100644
--- a/test/api/test-buffer.c
+++ b/test/api/test-buffer.c
@@ -92,14 +92,14 @@ fixture_init (fixture_t *fixture, gconstpointer user_data)
}
static void
-fixture_finish (fixture_t *fixture, gconstpointer user_data)
+fixture_finish (fixture_t *fixture, gconstpointer user_data HB_UNUSED)
{
hb_buffer_destroy (fixture->buffer);
}
static void
-test_buffer_properties (fixture_t *fixture, gconstpointer user_data)
+test_buffer_properties (fixture_t *fixture, gconstpointer user_data HB_UNUSED)
{
hb_buffer_t *b = fixture->buffer;
hb_unicode_funcs_t *ufuncs;
@@ -294,7 +294,7 @@ test_buffer_contents (fixture_t *fixture, gconstpointer user_data)
}
static void
-test_buffer_positions (fixture_t *fixture, gconstpointer user_data)
+test_buffer_positions (fixture_t *fixture, gconstpointer user_data HB_UNUSED)
{
hb_buffer_t *b = fixture->buffer;
unsigned int i, len, len2;
@@ -319,7 +319,7 @@ test_buffer_positions (fixture_t *fixture, gconstpointer user_data)
}
static void
-test_buffer_allocation (fixture_t *fixture, gconstpointer user_data)
+test_buffer_allocation (fixture_t *fixture, gconstpointer user_data HB_UNUSED)
{
hb_buffer_t *b = fixture->buffer;
diff --git a/test/api/test-c.c b/test/api/test-c.c
index 4b43b8379..061f35cdc 100644
--- a/test/api/test-c.c
+++ b/test/api/test-c.c
@@ -32,6 +32,7 @@
#endif
#include <hb.h>
+#include <hb-ot.h>
#ifdef HAVE_GLIB
#include <hb-glib.h>
@@ -45,10 +46,6 @@
#include <hb-ft.h>
#endif
-#ifdef HAVE_OT
-#include <hb-ot.h>
-#endif
-
#ifdef HAVE_UNISCRIBE
#include <hb-uniscribe.h>
#endif
@@ -58,7 +55,7 @@
#endif
int
-main (int argc, char **argv)
+main (void)
{
return !*hb_shape_list_shapers ();
}
diff --git a/test/api/test-subset-codepoints.c b/test/api/test-collect-unicodes.c
index 3bd1fe062..f7a781302 100644
--- a/test/api/test-subset-codepoints.c
+++ b/test/api/test-collect-unicodes.c
@@ -28,14 +28,15 @@
#include "hb-subset-test.h"
static void
-test_get_all_codepoints_format4 (void)
+test_collect_unicodes_format4 (void)
{
hb_face_t *face = hb_subset_test_open_font("fonts/Roboto-Regular.abc.format4.ttf");
hb_set_t *codepoints = hb_set_create();
+ hb_codepoint_t cp;
- hb_subset_get_all_codepoints (face, codepoints);
+ hb_face_collect_unicodes (face, codepoints);
- hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+ cp = HB_SET_VALUE_INVALID;
g_assert (hb_set_next (codepoints, &cp));
g_assert_cmpuint (0x61, ==, cp);
g_assert (hb_set_next (codepoints, &cp));
@@ -49,14 +50,15 @@ test_get_all_codepoints_format4 (void)
}
static void
-test_get_all_codepoints_format12 (void)
+test_collect_unicodes_format12 (void)
{
hb_face_t *face = hb_subset_test_open_font("fonts/Roboto-Regular.abc.format12.ttf");
hb_set_t *codepoints = hb_set_create();
+ hb_codepoint_t cp;
- hb_subset_get_all_codepoints (face, codepoints);
+ hb_face_collect_unicodes (face, codepoints);
- hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+ cp = HB_SET_VALUE_INVALID;
g_assert (hb_set_next (codepoints, &cp));
g_assert_cmpuint (0x61, ==, cp);
g_assert (hb_set_next (codepoints, &cp));
@@ -70,14 +72,15 @@ test_get_all_codepoints_format12 (void)
}
static void
-test_get_all_codepoints (void)
+test_collect_unicodes (void)
{
hb_face_t *face = hb_subset_test_open_font("fonts/Roboto-Regular.abc.ttf");
hb_set_t *codepoints = hb_set_create();
+ hb_codepoint_t cp;
- hb_subset_get_all_codepoints (face, codepoints);
+ hb_face_collect_unicodes (face, codepoints);
- hb_codepoint_t cp = HB_SET_VALUE_INVALID;
+ cp = HB_SET_VALUE_INVALID;
g_assert (hb_set_next (codepoints, &cp));
g_assert_cmpuint (0x61, ==, cp);
g_assert (hb_set_next (codepoints, &cp));
@@ -95,9 +98,9 @@ main (int argc, char **argv)
{
hb_test_init (&argc, &argv);
- hb_test_add (test_get_all_codepoints);
- hb_test_add (test_get_all_codepoints_format4);
- hb_test_add (test_get_all_codepoints_format12);
+ hb_test_add (test_collect_unicodes);
+ hb_test_add (test_collect_unicodes_format4);
+ hb_test_add (test_collect_unicodes_format12);
return hb_test_run();
}
diff --git a/test/api/test-common.c b/test/api/test-common.c
index f6f0d4851..e9fae1351 100644
--- a/test/api/test-common.c
+++ b/test/api/test-common.c
@@ -32,7 +32,6 @@
static void
test_types_int (void)
{
- /* We already ASSERT_STATIC these in hb-private.h, but anyway */
g_assert_cmpint (sizeof (int8_t), ==, 1);
g_assert_cmpint (sizeof (uint8_t), ==, 1);
g_assert_cmpint (sizeof (int16_t), ==, 2);
diff --git a/test/api/test-font.c b/test/api/test-font.c
index 527dfcdc1..3d81cf961 100644
--- a/test/api/test-font.c
+++ b/test/api/test-font.c
@@ -83,7 +83,7 @@ free_up (void *user_data)
}
static hb_blob_t *
-get_table (hb_face_t *face, hb_tag_t tag, void *user_data)
+get_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data HB_UNUSED)
{
if (tag == HB_TAG ('a','b','c','d'))
return hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
@@ -210,10 +210,10 @@ test_fontfuncs_nil (void)
}
static hb_bool_t
-contour_point_func1 (hb_font_t *font, void *font_data,
- hb_codepoint_t glyph, unsigned int point_index,
+contour_point_func1 (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED,
+ hb_codepoint_t glyph, unsigned int point_index HB_UNUSED,
hb_position_t *x, hb_position_t *y,
- void *user_data)
+ void *user_data HB_UNUSED)
{
if (glyph == 1) {
*x = 2;
@@ -230,10 +230,10 @@ contour_point_func1 (hb_font_t *font, void *font_data,
}
static hb_bool_t
-contour_point_func2 (hb_font_t *font, void *font_data,
+contour_point_func2 (hb_font_t *font, void *font_data HB_UNUSED,
hb_codepoint_t glyph, unsigned int point_index,
hb_position_t *x, hb_position_t *y,
- void *user_data)
+ void *user_data HB_UNUSED)
{
if (glyph == 1) {
*x = 6;
@@ -246,9 +246,9 @@ contour_point_func2 (hb_font_t *font, void *font_data,
}
static hb_position_t
-glyph_h_advance_func1 (hb_font_t *font, void *font_data,
+glyph_h_advance_func1 (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED,
hb_codepoint_t glyph,
- void *user_data)
+ void *user_data HB_UNUSED)
{
if (glyph == 1)
return 8;
@@ -361,8 +361,74 @@ test_fontfuncs_subclassing (void)
hb_font_destroy (font3);
+ hb_font_destroy (font2);
+}
+
+static hb_bool_t
+nominal_glyph_func (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t unicode HB_UNUSED,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+{
+ *glyph = 0;
+ return FALSE;
+}
+
+static unsigned int
+nominal_glyphs_func (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ unsigned int count HB_UNUSED,
+ const hb_codepoint_t *first_unicode HB_UNUSED,
+ unsigned int unicode_stride HB_UNUSED,
+ hb_codepoint_t *first_glyph HB_UNUSED,
+ unsigned int glyph_stride HB_UNUSED,
+ void *user_data HB_UNUSED)
+{
+ return 0;
}
+static void
+test_fontfuncs_parallels (void)
+{
+ hb_blob_t *blob;
+ hb_face_t *face;
+
+ hb_font_funcs_t *ffuncs1;
+ hb_font_funcs_t *ffuncs2;
+
+ hb_font_t *font0;
+ hb_font_t *font1;
+ hb_font_t *font2;
+
+ blob = hb_blob_create (test_data, sizeof (test_data), HB_MEMORY_MODE_READONLY, NULL, NULL);
+ face = hb_face_create (blob, 0);
+ hb_blob_destroy (blob);
+ font0 = hb_font_create (face);
+ hb_face_destroy (face);
+
+ /* setup sub-font1 */
+ font1 = hb_font_create_sub_font (font0);
+ hb_font_destroy (font0);
+ ffuncs1 = hb_font_funcs_create ();
+ hb_font_funcs_set_nominal_glyph_func (ffuncs1, nominal_glyph_func, NULL, NULL);
+ hb_font_set_funcs (font1, ffuncs1, NULL, NULL);
+ hb_font_funcs_destroy (ffuncs1);
+
+ /* setup sub-font2 */
+ font2 = hb_font_create_sub_font (font1);
+ hb_font_destroy (font1);
+ ffuncs2 = hb_font_funcs_create ();
+ hb_font_funcs_set_nominal_glyphs_func (ffuncs1, nominal_glyphs_func, NULL, NULL);
+ hb_font_set_funcs (font2, ffuncs2, NULL, NULL);
+ hb_font_funcs_destroy (ffuncs2);
+
+ /* Just test that calling get_nominal_glyph doesn't infinite-loop. */
+ hb_codepoint_t glyph;
+ hb_font_get_nominal_glyph (font2, 0x0020u, &glyph);
+
+ hb_font_destroy (font2);
+}
static void
test_font_empty (void)
@@ -542,6 +608,7 @@ main (int argc, char **argv)
hb_test_add (test_fontfuncs_empty);
hb_test_add (test_fontfuncs_nil);
hb_test_add (test_fontfuncs_subclassing);
+ hb_test_add (test_fontfuncs_parallels);
hb_test_add (test_font_empty);
hb_test_add (test_font_properties);
diff --git a/test/api/test-map.c b/test/api/test-map.c
new file mode 100644
index 000000000..0d8be0bbb
--- /dev/null
+++ b/test/api/test-map.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright © 2018 Ebrahim Byagowi
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include "hb-test.h"
+
+/* Unit tests for hb-map.h */
+
+
+static void
+test_map_basic (void)
+{
+ hb_map_t *empty = hb_map_get_empty ();
+ g_assert (hb_map_is_empty (empty));
+ g_assert (!hb_map_allocation_successful (empty));
+ hb_map_destroy (empty);
+
+ hb_map_t *m = hb_map_create ();
+ g_assert (hb_map_allocation_successful (m));
+ g_assert (hb_map_is_empty (m));
+
+ hb_map_set (m, 213, 223);
+ hb_map_set (m, 643, 675);
+ g_assert_cmpint (hb_map_get_population (m), ==, 2);
+
+ g_assert_cmpint (hb_map_get (m, 213), ==, 223);
+ g_assert (!hb_map_has (m, 123));
+ g_assert (hb_map_has (m, 213));
+
+ hb_map_del (m, 213);
+ g_assert (!hb_map_has (m, 213));
+
+ g_assert_cmpint (hb_map_get (m, 643), ==, 675);
+ hb_map_set (m, 237, 673);
+ g_assert (hb_map_has (m, 237));
+ hb_map_clear (m);
+ g_assert (!hb_map_has (m, 237));
+ g_assert (!hb_map_has (m, 643));
+ g_assert_cmpint (hb_map_get_population (m), ==, 0);
+
+ hb_map_destroy (m);
+}
+
+static void
+test_map_userdata (void)
+{
+ hb_map_t *m = hb_map_create ();
+
+ hb_user_data_key_t key[2];
+ int *data = (int *) malloc (sizeof (int));
+ *data = 3123;
+ hb_map_set_user_data (m, &key[0], data, free, TRUE);
+ g_assert_cmpint (*((int *) hb_map_get_user_data (m, &key[0])), ==, 3123);
+
+ int *data2 = (int *) malloc (sizeof (int));
+ *data2 = 6343;
+ hb_map_set_user_data (m, &key[0], data2, free, FALSE);
+ g_assert_cmpint (*((int *) hb_map_get_user_data (m, &key[0])), ==, 3123);
+ hb_map_set_user_data (m, &key[0], data2, free, TRUE);
+ g_assert_cmpint (*((int *) hb_map_get_user_data (m, &key[0])), ==, 6343);
+
+ hb_map_destroy (m);
+}
+
+static void
+test_map_refcount (void)
+{
+ hb_map_t *m = hb_map_create ();
+ hb_map_set (m, 213, 223);
+ g_assert_cmpint (hb_map_get (m, 213), ==, 223);
+
+ hb_map_t *m2 = hb_map_reference (m);
+ hb_map_destroy (m);
+
+ /* We copied its reference so it is still usable after one destroy */
+ g_assert (hb_map_has (m, 213));
+ g_assert (hb_map_has (m2, 213));
+
+ hb_map_destroy (m2);
+
+ /* Now you can't access them anymore */
+}
+
+int
+main (int argc, char **argv)
+{
+ hb_test_init (&argc, &argv);
+
+ hb_test_add (test_map_basic);
+ hb_test_add (test_map_userdata);
+ hb_test_add (test_map_refcount);
+
+ return hb_test_run();
+}
diff --git a/test/api/test-multithread.c b/test/api/test-multithread.c
new file mode 100644
index 000000000..7b62a0298
--- /dev/null
+++ b/test/api/test-multithread.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright © 2018 Ebrahim Byagowi
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <pthread.h>
+
+#include <hb.h>
+#include <hb-ft.h>
+#include <hb-ot.h>
+#include <glib.h>
+
+static const char *font_path = "fonts/Inconsolata-Regular.abc.ttf";
+static const char *text = "abc";
+
+static int num_threads = 30;
+static int num_iters = 200;
+
+static hb_font_t *font;
+static hb_buffer_t *ref_buffer;
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+fill_the_buffer (hb_buffer_t *buffer)
+{
+ hb_buffer_add_utf8 (buffer, text, -1, 0, -1);
+ hb_buffer_guess_segment_properties (buffer);
+ hb_shape (font, buffer, NULL, 0);
+}
+
+static void
+validity_check (hb_buffer_t *buffer) {
+ if (hb_buffer_diff (ref_buffer, buffer, (hb_codepoint_t) -1, 0))
+ {
+ fprintf (stderr, "One of the buffers was different from the reference.\n");
+ char out[255];
+
+ hb_buffer_serialize_glyphs (buffer, 0, hb_buffer_get_length (ref_buffer),
+ out, sizeof (out), NULL,
+ font, HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+ HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES);
+ fprintf (stderr, "Actual: %s\n", out);
+
+ hb_buffer_serialize_glyphs (ref_buffer, 0, hb_buffer_get_length (ref_buffer),
+ out, sizeof (out), NULL,
+ font, HB_BUFFER_SERIALIZE_FORMAT_TEXT,
+ HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES);
+ fprintf (stderr, "Expected: %s\n", out);
+
+ exit (1);
+ }
+}
+
+static void *
+thread_func (void *data)
+{
+ hb_buffer_t *buffer = (hb_buffer_t *) data;
+
+ pthread_mutex_lock (&mutex);
+ pthread_mutex_unlock (&mutex);
+
+ int i;
+ for (i = 0; i < num_iters; i++)
+ {
+ hb_buffer_clear_contents (buffer);
+ fill_the_buffer (buffer);
+ validity_check (buffer);
+ }
+
+ return 0;
+}
+
+static void
+test_body (void)
+{
+ int i;
+ pthread_t *threads = calloc (num_threads, sizeof (pthread_t));
+ hb_buffer_t **buffers = calloc (num_threads, sizeof (hb_buffer_t *));
+
+ pthread_mutex_lock (&mutex);
+
+ for (i = 0; i < num_threads; i++)
+ {
+ hb_buffer_t *buffer = hb_buffer_create ();
+ buffers[i] = buffer;
+ pthread_create (&threads[i], NULL, thread_func, buffer);
+ }
+
+ /* Let them loose! */
+ pthread_mutex_unlock (&mutex);
+
+ for (i = 0; i < num_threads; i++)
+ {
+ pthread_join (threads[i], NULL);
+ hb_buffer_destroy (buffers[i]);
+ }
+
+ free (buffers);
+ free (threads);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+#if GLIB_CHECK_VERSION(2,37,2)
+ gchar *default_path = g_test_build_filename (G_TEST_DIST, font_path, NULL);
+#else
+ gchar *default_path = g_strdup (font_path);
+#endif
+
+ char *path = argc > 1 && *argv[1] ? argv[1] : (char *) default_path;
+ if (argc > 2)
+ num_threads = atoi (argv[2]);
+ if (argc > 3)
+ num_iters = atoi (argv[3]);
+ if (argc > 4)
+ text = argv[4];
+
+ /* Dummy call to alleviate _guess_segment_properties thread safety-ness
+ * https://github.com/harfbuzz/harfbuzz/issues/1191 */
+ hb_language_get_default ();
+
+ hb_blob_t *blob = hb_blob_create_from_file (path);
+ if (hb_blob_get_length (blob) == 0)
+ g_error ("Font not found.");
+
+ hb_face_t *face = hb_face_create (blob, 0);
+ font = hb_font_create (face);
+
+ /* Fill the reference */
+ ref_buffer = hb_buffer_create ();
+ fill_the_buffer (ref_buffer);
+
+ /* Unnecessary, since version 2 it is ot-font by default */
+ hb_ot_font_set_funcs (font);
+ test_body ();
+
+ /* Test hb-ft in multithread */
+ hb_ft_font_set_funcs (font);
+ test_body ();
+
+ hb_buffer_destroy (ref_buffer);
+
+ hb_font_destroy (font);
+ hb_face_destroy (face);
+ hb_blob_destroy (blob);
+
+ g_free (default_path);
+
+ return 0;
+}
diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c
index 22584d20e..254f01556 100644
--- a/test/api/test-ot-color.c
+++ b/test/api/test-ot-color.c
@@ -99,6 +99,7 @@ static hb_face_t *cpal_v0 = NULL;
static hb_face_t *cpal_v1 = NULL;
+#if 0
#define assert_color_rgba(colors, i, r, g, b, a) G_STMT_START { \
const hb_ot_color_t *_colors = (colors); \
const size_t _i = (i); \
@@ -122,7 +123,6 @@ static hb_face_t *cpal_v1 = NULL;
} G_STMT_END
-#if 0
static void
test_hb_ot_color_get_palette_count (void)
{
diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c
index d071c8895..7f500157e 100644
--- a/test/api/test-ot-math.c
+++ b/test/api/test-ot-math.c
@@ -100,10 +100,14 @@ test_has_data (void)
hb_face = hb_face_get_empty ();
hb_font = hb_font_create (hb_face);
g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
+ hb_font_destroy (hb_font);
+ hb_face_destroy (hb_face);
hb_font = hb_font_get_empty ();
hb_face = hb_font_get_face (hb_font);
g_assert(!hb_ot_math_has_data (hb_face)); // MATH table not available
+ hb_font_destroy (hb_font);
+ hb_face_destroy (hb_face);
cleanupFreeType();
}
diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c
new file mode 100644
index 000000000..2da504acc
--- /dev/null
+++ b/test/api/test-ot-name.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2018 Ebrahim Byagowi
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ */
+
+#include "hb-test.h"
+
+#include <hb-ot.h>
+
+static const char *font_path = "fonts/cv01.otf";
+static hb_face_t *face;
+
+static void
+test_ot_layout_feature_get_name_ids_and_characters (void)
+{
+ hb_tag_t cv01 = HB_TAG ('c','v','0','1');
+ unsigned int feature_index;
+ if (!hb_ot_layout_language_find_feature (face,
+ HB_OT_TAG_GSUB,
+ 0,
+ HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+ cv01,
+ &feature_index))
+ g_error ("Failed to find feature index");
+
+ hb_name_id_t label_id;
+ hb_name_id_t tooltip_id;
+ hb_name_id_t sample_id;
+ unsigned int num_named_parameters;
+ hb_name_id_t first_param_id;
+ if (!hb_ot_layout_feature_get_name_ids (face, HB_OT_TAG_GSUB, feature_index,
+ &label_id, &tooltip_id, &sample_id,
+ &num_named_parameters, &first_param_id))
+ g_error ("Failed to get name ids");
+
+ g_assert_cmpint (label_id, ==, 256);
+ g_assert_cmpint (tooltip_id, ==, 257);
+ g_assert_cmpint (sample_id, ==, 258);
+ g_assert_cmpint (num_named_parameters, ==, 2);
+ g_assert_cmpint (first_param_id, ==, 259);
+
+ hb_codepoint_t characters[100];
+ unsigned int char_count = 100;
+
+ unsigned int all_chars;
+ all_chars = hb_ot_layout_feature_get_characters (face, HB_OT_TAG_GSUB, feature_index,
+ 0, &char_count, characters);
+
+ g_assert_cmpint (all_chars, ==, 2);
+ g_assert_cmpint (char_count, ==, 2);
+ g_assert_cmpint (characters[0], ==, 10);
+ g_assert_cmpint (characters[1], ==, 24030);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+#if GLIB_CHECK_VERSION(2,37,2)
+ gchar *default_path = g_test_build_filename (G_TEST_DIST, font_path, NULL);
+#else
+ gchar *default_path = g_strdup (font_path);
+#endif
+
+ hb_blob_t *blob;
+
+ char *path = argc > 1 && *argv[1] ? argv[1] : (char *) default_path;
+ blob = hb_blob_create_from_file (path);
+ if (hb_blob_get_length (blob) == 0)
+ g_error ("Font not found.");
+
+ face = hb_face_create (blob, 0);
+
+ hb_test_add (test_ot_layout_feature_get_name_ids_and_characters);
+
+ unsigned int result = hb_test_run ();
+ hb_face_destroy (face);
+ hb_blob_destroy (blob);
+ g_free (default_path);
+ return result;
+}
diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c
index e821b3625..f89c25deb 100644
--- a/test/api/test-ot-tag.c
+++ b/test/api/test-ot-tag.c
@@ -37,50 +37,86 @@ static void
test_simple_tags (const char *s, hb_script_t script)
{
hb_script_t tag;
- hb_tag_t t1, t2;
+ unsigned int count = 2;
+ hb_tag_t t[2];
g_test_message ("Testing script %c%c%c%c: tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s);
tag = hb_tag_from_string (s, -1);
- hb_ot_tags_from_script (script, &t1, &t2);
+ hb_ot_tags_from_script_and_language (script,
+ HB_LANGUAGE_INVALID,
+ &count, t, NULL, NULL);
- g_assert_cmphex (t1, ==, tag);
- g_assert_cmphex (t2, ==, HB_OT_TAG_DEFAULT_SCRIPT);
+ if (count)
+ g_assert_cmphex (t[0], ==, tag);
+ else
+ g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, tag);
g_assert_cmphex (hb_ot_tag_to_script (tag), ==, script);
}
static void
-test_indic_tags (const char *s1, const char *s2, hb_script_t script)
+test_script_tags_from_language (const char *s, const char *lang_s, hb_script_t script)
{
- hb_script_t tag1, tag2;
- hb_script_t t1, t2;
+ hb_script_t tag;
+ unsigned int count = 1;
+ hb_script_t t;
+
+ g_test_message ("Testing script %c%c%c%c: script tag %s, language tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s, lang_s);
+ tag = hb_tag_from_string (s, -1);
+
+ hb_ot_tags_from_script_and_language (script, hb_language_from_string (lang_s, -1), &count, &t, NULL, NULL);
- g_test_message ("Testing script %c%c%c%c: new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2);
+ if (count != 0)
+ {
+ g_assert_cmpuint (count, ==, 1);
+ g_assert_cmphex (t, ==, tag);
+ }
+}
+
+static void
+test_indic_tags (const char *s1, const char *s2, const char *s3, hb_script_t script)
+{
+ hb_script_t tag1, tag2, tag3;
+ hb_script_t t[3];
+ unsigned int count = 3;
+
+ g_test_message ("Testing script %c%c%c%c: USE tag %s, new tag %s, old tag %s", HB_UNTAG (hb_script_to_iso15924_tag (script)), s1, s2, s3);
tag1 = hb_tag_from_string (s1, -1);
tag2 = hb_tag_from_string (s2, -1);
+ tag3 = hb_tag_from_string (s3, -1);
- hb_ot_tags_from_script (script, &t1, &t2);
+ hb_ot_tags_from_script_and_language (script,
+ HB_LANGUAGE_INVALID,
+ &count, t, NULL, NULL);
- g_assert_cmphex (t1, ==, tag1);
- g_assert_cmphex (t2, ==, tag2);
+ g_assert_cmpuint (count, ==, 3);
+ g_assert_cmphex (t[0], ==, tag1);
+ g_assert_cmphex (t[1], ==, tag2);
+ g_assert_cmphex (t[2], ==, tag3);
g_assert_cmphex (hb_ot_tag_to_script (tag1), ==, script);
g_assert_cmphex (hb_ot_tag_to_script (tag2), ==, script);
+ g_assert_cmphex (hb_ot_tag_to_script (tag3), ==, script);
}
static void
test_ot_tag_script_degenerate (void)
{
- hb_tag_t t1, t2;
+ hb_script_t t[2];
+ unsigned int count = 2;
g_assert_cmphex (HB_TAG_CHAR4 ("DFLT"), ==, HB_OT_TAG_DEFAULT_SCRIPT);
/* HIRAGANA and KATAKANA both map to 'kana' */
test_simple_tags ("kana", HB_SCRIPT_KATAKANA);
- hb_ot_tags_from_script (HB_SCRIPT_HIRAGANA, &t1, &t2);
- g_assert_cmphex (t1, ==, HB_TAG_CHAR4 ("kana"));
- g_assert_cmphex (t2, ==, HB_OT_TAG_DEFAULT_SCRIPT);
+
+ hb_ot_tags_from_script_and_language (HB_SCRIPT_HIRAGANA,
+ HB_LANGUAGE_INVALID,
+ &count, t, NULL, NULL);
+
+ g_assert_cmpuint (count, ==, 1);
+ g_assert_cmphex (t[0], ==, HB_TAG_CHAR4 ("kana"));
test_simple_tags ("DFLT", HB_SCRIPT_INVALID);
@@ -121,18 +157,40 @@ test_ot_tag_script_simple (void)
}
static void
+test_ot_tag_script_from_language (void)
+{
+ test_script_tags_from_language (NULL, NULL, HB_SCRIPT_INVALID);
+ test_script_tags_from_language (NULL, "en", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("copt", "en", HB_SCRIPT_COPTIC);
+ test_script_tags_from_language (NULL, "x-hbsc", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("copt", "x-hbsc", HB_SCRIPT_COPTIC);
+ test_script_tags_from_language ("abc ", "x-hbscabc", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("deva", "x-hbscdeva", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("dev2", "x-hbscdev2", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("dev3", "x-hbscdev3", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("copt", "x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID);
+ test_script_tags_from_language (NULL, "en-x-hbsc", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("copt", "en-x-hbsc", HB_SCRIPT_COPTIC);
+ test_script_tags_from_language ("abc ", "en-x-hbscabc", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("deva", "en-x-hbscdeva", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("dev2", "en-x-hbscdev2", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("dev3", "en-x-hbscdev3", HB_SCRIPT_INVALID);
+ test_script_tags_from_language ("copt", "en-x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID);
+}
+
+static void
test_ot_tag_script_indic (void)
{
- test_indic_tags ("bng2", "beng", HB_SCRIPT_BENGALI);
- test_indic_tags ("dev2", "deva", HB_SCRIPT_DEVANAGARI);
- test_indic_tags ("gjr2", "gujr", HB_SCRIPT_GUJARATI);
- test_indic_tags ("gur2", "guru", HB_SCRIPT_GURMUKHI);
- test_indic_tags ("knd2", "knda", HB_SCRIPT_KANNADA);
- test_indic_tags ("mlm2", "mlym", HB_SCRIPT_MALAYALAM);
- 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);
+ test_indic_tags ("bng3", "bng2", "beng", HB_SCRIPT_BENGALI);
+ test_indic_tags ("dev3", "dev2", "deva", HB_SCRIPT_DEVANAGARI);
+ test_indic_tags ("gjr3", "gjr2", "gujr", HB_SCRIPT_GUJARATI);
+ test_indic_tags ("gur3", "gur2", "guru", HB_SCRIPT_GURMUKHI);
+ test_indic_tags ("knd3", "knd2", "knda", HB_SCRIPT_KANNADA);
+ test_indic_tags ("mlm3", "mlm2", "mlym", HB_SCRIPT_MALAYALAM);
+ test_indic_tags ("ory3", "ory2", "orya", HB_SCRIPT_ORIYA);
+ test_indic_tags ("tml3", "tml2", "taml", HB_SCRIPT_TAMIL);
+ test_indic_tags ("tel3", "tel2", "telu", HB_SCRIPT_TELUGU);
+ test_indic_tags ("mym3", "mym2", "mymr", HB_SCRIPT_MYANMAR);
}
@@ -147,7 +205,16 @@ test_language_two_way (const char *tag_s, const char *lang_s)
g_test_message ("Testing language %s <-> tag %s", lang_s, tag_s);
- g_assert_cmphex (tag, ==, hb_ot_tag_from_language (lang));
+ hb_tag_t tag2;
+ unsigned int count = 1;
+ hb_ot_tags_from_script_and_language (HB_SCRIPT_INVALID,
+ lang,
+ NULL, NULL, &count, &tag2);
+
+ if (count)
+ g_assert_cmphex (tag, ==, tag2);
+ else
+ g_assert_cmphex (tag, ==, HB_TAG_CHAR4 ("dflt"));
g_assert (lang == hb_ot_tag_to_language (tag));
}
@@ -159,7 +226,16 @@ test_tag_from_language (const char *tag_s, const char *lang_s)
g_test_message ("Testing language %s -> tag %s", lang_s, tag_s);
- g_assert_cmphex (tag, ==, hb_ot_tag_from_language (lang));
+ hb_tag_t tag2;
+ unsigned int count = 1;
+ hb_ot_tags_from_script_and_language (HB_SCRIPT_INVALID,
+ lang,
+ NULL, NULL, &count, &tag2);
+
+ if (count)
+ g_assert_cmphex (tag, ==, tag2);
+ else
+ g_assert_cmphex (tag, ==, HB_TAG_CHAR4 ("dflt"));
}
static void
@@ -174,6 +250,32 @@ test_tag_to_language (const char *tag_s, const char *lang_s)
}
static void
+test_tags_to_script_and_language (const char *script_tag_s,
+ const char *lang_tag_s,
+ const char *script_s,
+ const char *lang_s)
+{
+ hb_script_t actual_script[1];
+ hb_language_t actual_lang[1];
+ hb_tag_t script_tag = hb_tag_from_string (script_tag_s, -1);
+ hb_tag_t lang_tag = hb_tag_from_string (lang_tag_s, -1);
+ hb_ot_tags_to_script_and_language (script_tag, lang_tag, actual_script, actual_lang);
+ g_assert_cmphex (*actual_script, ==, hb_tag_from_string (script_s, -1));
+ g_assert_cmpstr (hb_language_to_string (*actual_lang), ==, lang_s);
+}
+
+static void
+test_ot_tags_to_script_and_language (void)
+{
+ test_tags_to_script_and_language ("DFLT", "ENG", "", "en-x-hbscdflt");
+ test_tags_to_script_and_language ("latn", "ENG", "Latn", "en");
+ test_tags_to_script_and_language ("deva", "MAR", "Deva", "mr-x-hbscdeva");
+ test_tags_to_script_and_language ("dev2", "MAR", "Deva", "mr-x-hbscdev2");
+ test_tags_to_script_and_language ("dev3", "MAR", "Deva", "mr");
+ test_tags_to_script_and_language ("qaa", "QTZ0", "Qaaa", "x-hbotqtz0-hbscqaa");
+}
+
+static void
test_ot_tag_language (void)
{
g_assert_cmphex (HB_TAG_CHAR4 ("dflt"), ==, HB_OT_TAG_DEFAULT_LANGUAGE);
@@ -230,27 +332,27 @@ test_ot_tag_language (void)
test_language_two_way ("TUA", "tru"); /* Turoyo Aramaic */
- 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 ("ZHH", "zh-mo"); /* Chinese (Macao) */
test_tag_from_language ("ZHH", "zh-hant-mo"); /* Chinese (Macao) */
- test_tag_from_language ("ZHH", "zh-hk"); /* Chinese (Hong Kong) */
+ test_language_two_way ("ZHH", "zh-HK"); /* Chinese (Hong Kong) */
test_tag_from_language ("ZHH", "zH-HanT-hK"); /* Chinese (Hong Kong) */
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_language_two_way ("ZHS", "zh-Hans"); /* Chinese (Simplified) */
+ test_language_two_way ("ZHT", "zh-Hant"); /* Chinese (Traditional) */
test_tag_from_language ("ZHS", "zh-xx"); /* Chinese (Other) */
+ test_tag_from_language ("ZHS", "zh-Hans-TW");
+
+ test_tag_from_language ("ZHH", "yue");
+ test_tag_from_language ("ZHH", "yue-Hant");
+ test_tag_from_language ("ZHS", "yue-Hans");
+
test_tag_from_language ("ZHS", "zh"); /* Chinese */
test_tag_from_language ("ZHS", "zh-xx");
- 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");
test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc");
@@ -262,39 +364,64 @@ test_ot_tag_language (void)
test_tag_from_language ("XYZ", "xyz"); /* Unknown ISO 639-3 */
test_tag_from_language ("XYZ", "xyz-qw"); /* Unknown ISO 639-3 */
+ /*
+ * Invalid input. The precise answer does not matter, as long as it
+ * does not crash or get into an infinite loop.
+ */
+ test_tag_from_language ("IPPH", "-fonipa");
+
+ /*
+ * Tags that contain "-fonipa" as a substring but which do not contain
+ * the subtag "fonipa".
+ */
+ test_tag_from_language ("ENG", "en-fonipax");
+ test_tag_from_language ("ENG", "en-x-fonipa");
+ test_tag_from_language ("ENG", "en-a-fonipa");
+ test_tag_from_language ("ENG", "en-a-qwe-b-fonipa");
+
/* International Phonetic Alphabet */
test_tag_from_language ("IPPH", "en-fonipa");
+ test_tag_from_language ("IPPH", "en-fonipax-fonipa");
test_tag_from_language ("IPPH", "rm-CH-fonipa-sursilv-x-foobar");
- test_tag_from_language ("IPPH", "und-fonipa");
+ test_language_two_way ("IPPH", "und-fonipa");
test_tag_from_language ("IPPH", "zh-fonipa");
- test_tag_to_language ("IPPH", "und-fonipa");
/* North American Phonetic Alphabet (Americanist Phonetic Notation) */
test_tag_from_language ("APPH", "en-fonnapa");
test_tag_from_language ("APPH", "chr-fonnapa");
- test_tag_from_language ("APPH", "und-fonnapa");
- test_tag_to_language ("APPH", "und-fonnapa");
+ test_language_two_way ("APPH", "und-fonnapa");
+
+ /* Khutsuri Georgian */
+ test_tag_from_language ("KGE", "ka-Geok");
+ test_language_two_way ("KGE", "und-Geok");
+
+ /* Irish Traditional */
+ test_language_two_way ("IRT", "ga-Latg");
+
+ /* Moldavian */
+ test_language_two_way ("MOL", "ro-MD");
+
+ /* Polytonic Greek */
+ test_language_two_way ("PGR", "el-polyton");
+ test_tag_from_language ("PGR", "el-CY-polyton");
/* Estrangela Syriac */
test_tag_from_language ("SYRE", "aii-Syre");
test_tag_from_language ("SYRE", "de-Syre");
test_tag_from_language ("SYRE", "syr-Syre");
- test_tag_from_language ("SYRE", "und-Syre");
- test_tag_to_language ("SYRE", "und-Syre");
+ test_language_two_way ("SYRE", "und-Syre");
/* Western Syriac */
test_tag_from_language ("SYRJ", "aii-Syrj");
test_tag_from_language ("SYRJ", "de-Syrj");
test_tag_from_language ("SYRJ", "syr-Syrj");
- test_tag_from_language ("SYRJ", "und-Syrj");
- test_tag_to_language ("SYRJ", "und-Syrj");
+ test_language_two_way ("SYRJ", "und-Syrj");
/* Eastern Syriac */
test_tag_from_language ("SYRN", "aii-Syrn");
test_tag_from_language ("SYRN", "de-Syrn");
test_tag_from_language ("SYRN", "syr-Syrn");
- test_tag_from_language ("SYRN", "und-Syrn");
- test_tag_to_language ("SYRN", "und-Syrn");
+ test_language_two_way ("SYRN", "und-Syrn");
/* Test that x-hbot overrides the base language */
test_tag_from_language ("ABC", "fa-x-hbotabc-zxc");
@@ -303,6 +430,77 @@ test_ot_tag_language (void)
test_tag_from_language ("ABC", "zh-cn-x-hbotabc-zxc");
test_tag_from_language ("ABC", "zh-xy-x-hbotabc-zxc");
test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-zxc");
+
+ /* Unnormalized BCP 47 tags */
+ test_tag_from_language ("ARA", "ar-aao");
+ test_tag_from_language ("JBO", "art-lojban");
+ test_tag_from_language ("KOK", "kok-gom");
+ test_tag_from_language ("LTZ", "i-lux");
+ test_tag_from_language ("MNG", "drh");
+ test_tag_from_language ("MOR", "ar-ary");
+ test_tag_from_language ("MOR", "ar-ary-DZ");
+ test_tag_from_language ("NOR", "no-bok");
+ test_tag_from_language ("NYN", "no-nyn");
+ test_tag_from_language ("ZHS", "i-hak");
+ test_tag_from_language ("ZHS", "zh-guoyu");
+ test_tag_from_language ("ZHS", "zh-min");
+ test_tag_from_language ("ZHS", "zh-min-nan");
+ test_tag_from_language ("ZHS", "zh-xiang");
+
+ /* A UN M.49 region code, not an extended language subtag */
+ test_tag_from_language ("ARA", "ar-001");
+}
+
+static void
+test_tags (hb_script_t script,
+ const char *lang_s,
+ unsigned int script_count,
+ unsigned int language_count,
+ unsigned int expected_script_count,
+ unsigned int expected_language_count,
+ ...)
+{
+ va_list expected_tags;
+ unsigned int i;
+ hb_tag_t *script_tags = malloc (script_count * sizeof (hb_tag_t));
+ hb_tag_t *language_tags = malloc (language_count * sizeof (hb_tag_t));
+ g_assert (script_tags);
+ g_assert (language_tags);
+ hb_language_t lang = hb_language_from_string (lang_s, -1);
+ va_start (expected_tags, expected_language_count);
+
+ hb_ot_tags_from_script_and_language (script, lang, &script_count, script_tags, &language_count, language_tags);
+
+ g_assert_cmpuint (script_count, ==, expected_script_count);
+ g_assert_cmpuint (language_count, ==, expected_language_count);
+
+ for (i = 0; i < script_count + language_count; i++)
+ {
+ hb_tag_t expected_tag = hb_tag_from_string (va_arg (expected_tags, const char *), -1);
+ hb_tag_t actual_tag = i < script_count ? script_tags[i] : language_tags[i - script_count];
+ g_assert_cmphex (actual_tag, ==, expected_tag);
+ }
+
+ free (script_tags);
+ free (language_tags);
+ va_end (expected_tags);
+}
+
+static void
+test_ot_tag_full (void)
+{
+ test_tags (HB_SCRIPT_INVALID, "en", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "ENG");
+ test_tags (HB_SCRIPT_INVALID, "en-x-hbscdflt", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "DFLT", "ENG");
+ test_tags (HB_SCRIPT_LATIN, "en", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "latn", "ENG");
+ test_tags (HB_SCRIPT_LATIN, "en", 0, 0, 0, 0);
+ test_tags (HB_SCRIPT_INVALID, "und-fonnapa", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "APPH");
+ test_tags (HB_SCRIPT_INVALID, "en-fonnapa", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "APPH");
+ test_tags (HB_SCRIPT_INVALID, "x-hbot1234-hbsc5678", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234");
+ test_tags (HB_SCRIPT_INVALID, "x-hbsc5678-hbot1234", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 1, 1, "5678", "1234");
+ test_tags (HB_SCRIPT_MALAYALAM, "ml", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 3, 2, "mlm3", "mlm2", "mlym", "MAL", "MLR");
+ test_tags (HB_SCRIPT_MALAYALAM, "ml", 1, 1, 1, 1, "mlm3", "MAL");
+ test_tags (HB_SCRIPT_INVALID, "xyz", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 1, "XYZ");
+ test_tags (HB_SCRIPT_INVALID, "xy", HB_OT_MAX_TAGS_PER_SCRIPT, HB_OT_MAX_TAGS_PER_LANGUAGE, 0, 0);
}
int
@@ -312,9 +510,14 @@ main (int argc, char **argv)
hb_test_add (test_ot_tag_script_degenerate);
hb_test_add (test_ot_tag_script_simple);
+ hb_test_add (test_ot_tag_script_from_language);
hb_test_add (test_ot_tag_script_indic);
+ hb_test_add (test_ot_tags_to_script_and_language);
+
hb_test_add (test_ot_tag_language);
+ hb_test_add (test_ot_tag_full);
+
return hb_test_run();
}
diff --git a/test/api/test-set.c b/test/api/test-set.c
index 338a610c9..aa2b388ea 100644
--- a/test/api/test-set.c
+++ b/test/api/test-set.c
@@ -118,6 +118,9 @@ test_set_basic (void)
g_assert (!hb_set_has (s, 801));
g_assert (!hb_set_has (s, 802));
+ hb_set_del (s, 800);
+ g_assert (!hb_set_has (s, 800));
+
hb_set_destroy (s);
}
@@ -262,6 +265,7 @@ test_set_algebra (void)
hb_set_destroy (s);
hb_set_destroy (o);
+ hb_set_destroy (o2);
}
static void
@@ -380,10 +384,6 @@ test_set_empty (void)
test_empty (b);
- hb_set_invert (b);
-
- test_empty (b);
-
g_assert (!hb_set_allocation_successful (b));
hb_set_clear (b);
diff --git a/test/api/test-shape.c b/test/api/test-shape.c
index 6232e7382..146cf0f4a 100644
--- a/test/api/test-shape.c
+++ b/test/api/test-shape.c
@@ -41,9 +41,9 @@
static const char test_data[] = "test\0data";
static hb_position_t
-glyph_h_advance_func (hb_font_t *font, void *font_data,
+glyph_h_advance_func (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED,
hb_codepoint_t glyph,
- void *user_data)
+ void *user_data HB_UNUSED)
{
switch (glyph) {
case 1: return 10;
@@ -54,10 +54,10 @@ glyph_h_advance_func (hb_font_t *font, void *font_data,
}
static hb_bool_t
-glyph_func (hb_font_t *font, void *font_data,
- hb_codepoint_t unicode, hb_codepoint_t variant_selector,
+glyph_func (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED,
+ hb_codepoint_t unicode,
hb_codepoint_t *glyph,
- void *user_data)
+ void *user_data HB_UNUSED)
{
switch (unicode) {
case 'T': *glyph = 1; return TRUE;
@@ -68,9 +68,9 @@ glyph_func (hb_font_t *font, void *font_data,
}
static hb_position_t
-glyph_h_kerning_func (hb_font_t *font, void *font_data,
+glyph_h_kerning_func (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED,
hb_codepoint_t left, hb_codepoint_t right,
- void *user_data)
+ void *user_data HB_UNUSED)
{
if (left == 1 && right == 2)
return -2;
@@ -101,7 +101,7 @@ test_shape (void)
ffuncs = hb_font_funcs_create ();
hb_font_funcs_set_glyph_h_advance_func (ffuncs, glyph_h_advance_func, NULL, NULL);
- hb_font_funcs_set_glyph_func (ffuncs, glyph_func, malloc (10), free);
+ hb_font_funcs_set_nominal_glyph_func (ffuncs, glyph_func, malloc (10), free);
hb_font_funcs_set_glyph_h_kerning_func (ffuncs, glyph_h_kerning_func, NULL, NULL);
hb_font_set_funcs (font, ffuncs, NULL, NULL);
hb_font_funcs_destroy (ffuncs);
diff --git a/test/api/test-subset-glyf.c b/test/api/test-subset-glyf.c
index e4440e0fe..05c7f8cfe 100644
--- a/test/api/test-subset-glyf.c
+++ b/test/api/test-subset-glyf.c
@@ -105,16 +105,18 @@ test_subset_glyf_with_gsub (void)
{
hb_face_t *face_fil = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fil.ttf");
hb_face_t *face_fi = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fi.ttf");
+ hb_subset_input_t *input;
+ hb_face_t *face_subset;
hb_set_t *codepoints = hb_set_create();
hb_set_add (codepoints, 102); // f
hb_set_add (codepoints, 105); // i
- hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+ input = hb_subset_test_create_input (codepoints);
hb_set_destroy (codepoints);
- *hb_subset_input_drop_ot_layout (input) = false;
+ hb_subset_input_set_drop_layout (input, false);
- hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
+ face_subset = hb_subset_test_create_subset (face_fil, input);
hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f'));
hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a'));
@@ -130,16 +132,18 @@ test_subset_glyf_without_gsub (void)
{
hb_face_t *face_fil = hb_subset_test_open_font ("fonts/Roboto-Regular.gsub.fil.ttf");
hb_face_t *face_fi = hb_subset_test_open_font ("fonts/Roboto-Regular.nogsub.fi.ttf");
+ hb_subset_input_t *input;
+ hb_face_t *face_subset;
hb_set_t *codepoints = hb_set_create();
hb_set_add (codepoints, 102); // f
hb_set_add (codepoints, 105); // i
- hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
+ input = hb_subset_test_create_input (codepoints);
hb_set_destroy (codepoints);
- *hb_subset_input_drop_ot_layout (input) = true;
+ hb_subset_input_set_drop_layout (input, true);
- hb_face_t *face_subset = hb_subset_test_create_subset (face_fil, input);
+ face_subset = hb_subset_test_create_subset (face_fil, input);
hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f'));
hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a'));
@@ -183,7 +187,7 @@ test_subset_glyf_strip_hints_simple (void)
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'c');
input = hb_subset_test_create_input (codepoints);
- *hb_subset_input_drop_hints(input) = true;
+ hb_subset_input_set_drop_hints (input, true);
face_abc_subset = hb_subset_test_create_subset (face_abc, input);
hb_set_destroy (codepoints);
@@ -207,7 +211,7 @@ test_subset_glyf_strip_hints_composite (void)
hb_face_t *face_generated_subset;
hb_set_add (codepoints, 0x1fc);
input = hb_subset_test_create_input (codepoints);
- *hb_subset_input_drop_hints(input) = true;
+ hb_subset_input_set_drop_hints (input, true);
face_generated_subset = hb_subset_test_create_subset (face_components, input);
hb_set_destroy (codepoints);
@@ -224,7 +228,7 @@ test_subset_glyf_strip_hints_composite (void)
static void
test_subset_glyf_strip_hints_invalid (void)
{
- hb_face_t *face = hb_subset_test_open_font ("fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a");
+ hb_face_t *face = hb_subset_test_open_font ("../fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a");
hb_set_t *codepoints = hb_set_create();
const hb_codepoint_t text[] =
@@ -233,16 +237,19 @@ test_subset_glyf_strip_hints_invalid (void)
'3', '@', '_', '%', '&', ')', '*', '$', '!'
};
unsigned int i;
+ hb_subset_input_t *input;
+ hb_face_t *face_subset;
+
for (i = 0; i < sizeof (text) / sizeof (hb_codepoint_t); i++)
{
hb_set_add (codepoints, text[i]);
}
- hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
- *hb_subset_input_drop_hints(input) = true;
+ input = hb_subset_test_create_input (codepoints);
+ hb_subset_input_set_drop_hints (input, true);
hb_set_destroy (codepoints);
- hb_face_t *face_subset = hb_subset_test_create_subset (face, input);
+ face_subset = hb_subset_test_create_subset (face, input);
g_assert (face_subset);
g_assert (face_subset == hb_face_get_empty ());
diff --git a/test/api/test-subset-hdmx.c b/test/api/test-subset-hdmx.c
index c78009b6b..8496f9e8f 100644
--- a/test/api/test-subset-hdmx.c
+++ b/test/api/test-subset-hdmx.c
@@ -51,23 +51,42 @@ test_subset_hdmx_simple_subset (void)
}
static void
+test_subset_hdmx_multiple_device_records (void)
+{
+ hb_face_t *face_abc = hb_subset_test_open_font ("fonts/Roboto-Regular.multihdmx.abc.ttf");
+ hb_face_t *face_a = hb_subset_test_open_font ("fonts/Roboto-Regular.multihdmx.a.ttf");
+
+ hb_set_t *codepoints = hb_set_create ();
+ hb_face_t *face_abc_subset;
+ hb_set_add (codepoints, 'a');
+ face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
+ hb_set_destroy (codepoints);
+
+ hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('h','d','m','x'));
+
+ hb_face_destroy (face_abc_subset);
+ hb_face_destroy (face_abc);
+ hb_face_destroy (face_a);
+}
+
+static void
test_subset_hdmx_invalid (void)
{
- hb_face_t *face = hb_subset_test_open_font("fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a");
+ hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a");
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+ hb_face_t *subset;
+
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'b');
hb_set_add (codepoints, 'c');
- hb_subset_profile_t *profile = hb_subset_profile_create();
- hb_face_t *subset = hb_subset (face, profile, input);
+ subset = hb_subset (face, input);
g_assert (subset);
g_assert (subset == hb_face_get_empty ());
hb_subset_input_destroy (input);
- hb_subset_profile_destroy (profile);
hb_face_destroy (subset);
hb_face_destroy (face);
}
@@ -75,21 +94,21 @@ test_subset_hdmx_invalid (void)
static void
test_subset_hdmx_fails_sanitize (void)
{
- hb_face_t *face = hb_subset_test_open_font("fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016");
+ hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016");
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+ hb_face_t *subset;
+
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'b');
hb_set_add (codepoints, 'c');
- hb_subset_profile_t *profile = hb_subset_profile_create();
- hb_face_t *subset = hb_subset (face, profile, input);
+ subset = hb_subset (face, input);
g_assert (subset);
g_assert (subset == hb_face_get_empty ());
hb_subset_input_destroy (input);
- hb_subset_profile_destroy (profile);
hb_face_destroy (subset);
hb_face_destroy (face);
}
@@ -119,6 +138,7 @@ main (int argc, char **argv)
hb_test_init (&argc, &argv);
hb_test_add (test_subset_hdmx_simple_subset);
+ hb_test_add (test_subset_hdmx_multiple_device_records);
hb_test_add (test_subset_hdmx_invalid);
hb_test_add (test_subset_hdmx_fails_sanitize);
hb_test_add (test_subset_hdmx_noop);
diff --git a/test/api/test-subset-hmtx.c b/test/api/test-subset-hmtx.c
index 0ed62562b..1a5a44dc5 100644
--- a/test/api/test-subset-hmtx.c
+++ b/test/api/test-subset-hmtx.c
@@ -153,7 +153,8 @@ test_subset_hmtx_noop (void)
static void
test_subset_invalid_hmtx (void)
{
- hb_face_t *face = hb_subset_test_open_font("fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480");
+ hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480");
+ hb_face_t *subset;
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
@@ -161,13 +162,11 @@ test_subset_invalid_hmtx (void)
hb_set_add (codepoints, 'b');
hb_set_add (codepoints, 'c');
- hb_subset_profile_t *profile = hb_subset_profile_create();
- hb_face_t *subset = hb_subset (face, profile, input);
+ subset = hb_subset (face, input);
g_assert (subset);
g_assert (subset == hb_face_get_empty ());
hb_subset_input_destroy (input);
- hb_subset_profile_destroy (profile);
hb_face_destroy (subset);
hb_face_destroy (face);
}
diff --git a/test/api/test-subset-post.c b/test/api/test-subset-post.c
index 948b18a23..c14741e4a 100644
--- a/test/api/test-subset-post.c
+++ b/test/api/test-subset-post.c
@@ -34,11 +34,12 @@ test_post_drops_glyph_names (void)
{
hb_face_t *face_full = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E,6975,73E0,5EA6,8F38,6E05.ttf");
hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E.ttf");
+ hb_face_t *face_full_subset;
hb_set_t *codepoints = hb_set_create ();
hb_set_add (codepoints, 0x660E);
- hb_face_t *face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints));
+ face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints));
hb_set_destroy (codepoints);
hb_subset_test_check (face_subset, face_full_subset, HB_TAG ('p','o','s','t'));
diff --git a/test/api/test-subset-vmtx.c b/test/api/test-subset-vmtx.c
index 437f0c2f5..40ea8f872 100644
--- a/test/api/test-subset-vmtx.c
+++ b/test/api/test-subset-vmtx.c
@@ -48,11 +48,12 @@ test_subset_vmtx_simple_subset (void)
{
hb_face_t *face_full = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E,6975,73E0,5EA6,8F38,6E05.ttf");
hb_face_t *face_subset = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E.ttf");
+ hb_face_t *face_full_subset;
hb_set_t *codepoints = hb_set_create ();
hb_set_add (codepoints, 0x660E);
- hb_face_t *face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints));
+ face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints));
hb_set_destroy (codepoints);
check_num_vmetrics(face_full_subset, 1); /* nothing has same width */
@@ -67,6 +68,7 @@ static void
test_subset_vmtx_noop (void)
{
hb_face_t *face_full = hb_subset_test_open_font ("fonts/Mplus1p-Regular.660E,6975,73E0,5EA6,8F38,6E05.ttf");
+ hb_face_t *face_full_subset;
hb_set_t *codepoints = hb_set_create();
hb_set_add (codepoints, 0x660E);
@@ -75,7 +77,7 @@ test_subset_vmtx_noop (void)
hb_set_add (codepoints, 0x5EA6);
hb_set_add (codepoints, 0x8F38);
hb_set_add (codepoints, 0x6E05);
- hb_face_t *face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints));
+ face_full_subset = hb_subset_test_create_subset (face_full, hb_subset_test_create_input (codepoints));
hb_set_destroy (codepoints);
check_num_vmetrics(face_full_subset, 1); /* all have the same width */
diff --git a/test/api/test-subset.c b/test/api/test-subset.c
index 6d2bf06e1..aaed03176 100644
--- a/test/api/test-subset.c
+++ b/test/api/test-subset.c
@@ -32,21 +32,21 @@
static void
test_subset_32_tables (void)
{
- hb_face_t *face = hb_subset_test_open_font("fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653");
+ hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653");
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+ hb_face_t *subset;
+
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'b');
hb_set_add (codepoints, 'c');
- hb_subset_profile_t *profile = hb_subset_profile_create();
- hb_face_t *subset = hb_subset (face, profile, input);
+ subset = hb_subset (face, input);
g_assert (subset);
g_assert (subset != hb_face_get_empty ());
hb_subset_input_destroy (input);
- hb_subset_profile_destroy (profile);
hb_face_destroy (subset);
hb_face_destroy (face);
}
@@ -54,21 +54,21 @@ test_subset_32_tables (void)
static void
test_subset_no_inf_loop (void)
{
- hb_face_t *face = hb_subset_test_open_font("fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016");
+ hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016");
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+ hb_face_t *subset;
+
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'b');
hb_set_add (codepoints, 'c');
- hb_subset_profile_t *profile = hb_subset_profile_create();
- hb_face_t *subset = hb_subset (face, profile, input);
+ subset = hb_subset (face, input);
g_assert (subset);
g_assert (subset == hb_face_get_empty ());
hb_subset_input_destroy (input);
- hb_subset_profile_destroy (profile);
hb_face_destroy (subset);
hb_face_destroy (face);
}
@@ -76,21 +76,21 @@ test_subset_no_inf_loop (void)
static void
test_subset_crash (void)
{
- hb_face_t *face = hb_subset_test_open_font("fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249");
+ hb_face_t *face = hb_subset_test_open_font("../fuzzing/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249");
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
+ hb_face_t *subset;
+
hb_set_add (codepoints, 'a');
hb_set_add (codepoints, 'b');
hb_set_add (codepoints, 'c');
- hb_subset_profile_t *profile = hb_subset_profile_create();
- hb_face_t *subset = hb_subset (face, profile, input);
+ subset = hb_subset (face, input);
g_assert (subset);
g_assert (subset == hb_face_get_empty ());
hb_subset_input_destroy (input);
- hb_subset_profile_destroy (profile);
hb_face_destroy (subset);
hb_face_destroy (face);
}
diff --git a/test/api/test-unicode.c b/test/api/test-unicode.c
index 88f12e779..6195bb286 100644
--- a/test/api/test-unicode.c
+++ b/test/api/test-unicode.c
@@ -160,69 +160,6 @@ static const test_pair_t combining_class_tests_more[] =
{ 0x111111, 0 }
};
-static const test_pair_t eastasian_width_tests[] =
-{
- /* Neutral */
- { 0x0000, 1 },
- { 0x0483, 1 },
- { 0x0641, 1 },
- { 0xFFFC, 1 },
- { 0x10000, 1 },
- { 0xE0001, 1 },
-
- /* Narrow */
- { 0x0020, 1 },
- { 0x0041, 1 },
- { 0x27E6, 1 },
-
- /* Halfwidth */
- { 0x20A9, 1 },
- { 0xFF61, 1 },
- { 0xFF69, 1 },
- { 0xFFEE, 1 },
-
- /* Ambiguous */
- { 0x00A1, 1 },
- { 0x00D8, 1 },
- { 0x02DD, 1 },
- { 0xE0100, 1 },
- { 0x100000, 1 },
-
- /* Fullwidth */
- { 0x3000, 2 },
- { 0xFF60, 2 },
-
- /* Wide */
- { 0x2329, 2 },
- { 0x3001, 2 },
- { 0xFE69, 2 },
- { 0x30000, 2 },
- { 0x3FFFD, 2 },
-
- { 0x111111, 1 }
-};
-static const test_pair_t eastasian_width_tests_more[] =
-{
- /* Default Wide blocks */
- { 0x4DBF, 2 },
- { 0x9FFF, 2 },
- { 0xFAFF, 2 },
- { 0x2A6DF, 2 },
- { 0x2B73F, 2 },
- { 0x2B81F, 2 },
- { 0x2FA1F, 2 },
-
- /* Uniode-5.2 character additions */
- /* Wide */
- { 0x115F, 2 },
-
- /* Uniode-6.0 character additions */
- /* Wide */
- { 0x2B740, 2 },
- { 0x1B000, 2 },
-
- { 0x111111, 1 }
-};
static const test_pair_t general_category_tests[] =
{
@@ -469,7 +406,6 @@ typedef struct {
static const property_t properties[] =
{
PROPERTY (combining_class, 0),
- PROPERTY (eastasian_width, 1),
PROPERTY (general_category, (unsigned int) HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER),
PROPERTY (mirroring, RETURNS_UNICODE_ITSELF),
PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN)
@@ -645,18 +581,18 @@ typedef struct {
} data_fixture_t;
static void
-data_fixture_init (data_fixture_t *f, gconstpointer user_data)
+data_fixture_init (data_fixture_t *f, gconstpointer user_data HB_UNUSED)
{
f->data[0].value = MAGIC0;
f->data[1].value = MAGIC1;
}
static void
-data_fixture_finish (data_fixture_t *f, gconstpointer user_data)
+data_fixture_finish (data_fixture_t *f HB_UNUSED, gconstpointer user_data HB_UNUSED)
{
}
static void
-test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data)
+test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data HB_UNUSED)
{
hb_unicode_funcs_t *uf, *aa;
@@ -678,7 +614,7 @@ test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data)
}
static void
-test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data)
+test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data HB_UNUSED)
{
hb_unicode_funcs_t *uf, *aa;
@@ -697,7 +633,7 @@ test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data)
}
static void
-test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data)
+test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data HB_UNUSED)
{
hb_unicode_funcs_t *uf, *aa;
@@ -786,7 +722,6 @@ 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,56 +784,6 @@ test_unicode_normalization (gconstpointer user_data)
g_assert (hb_unicode_decompose (uf, 0xD4CC, &a, &b) && a == 0x1111 && b == 0x1171);
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);
}
diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt
index 2a45ef649..577d13cea 100644
--- a/test/fuzzing/CMakeLists.txt
+++ b/test/fuzzing/CMakeLists.txt
@@ -2,7 +2,6 @@ if (HB_CHECK)
file (READ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am" MAKEFILEAM)
extract_make_variable (hb_shape_fuzzer_SOURCES ${MAKEFILEAM})
extract_make_variable (hb_subset_fuzzer_SOURCES ${MAKEFILEAM})
- extract_make_variable (hb_subset_get_codepoints_fuzzer_SOURCES ${MAKEFILEAM})
# TODO: enable these two
#extract_make_variable (FUZZING_CPPFLAGS ${MAKEFILEAM}) # extracting regex fail
@@ -16,17 +15,13 @@ if (HB_CHECK)
add_executable (hb-subset-fuzzer ${hb_subset_fuzzer_SOURCES})
target_link_libraries (hb-subset-fuzzer harfbuzz-subset)
- add_executable (hb-subset-get-codepoints-fuzzer ${hb_subset_get_codepoints_fuzzer_SOURCES})
- target_link_libraries (hb-subset-get-codepoints-fuzzer harfbuzz-subset)
-
target_compile_definitions(hb-shape-fuzzer PUBLIC ${FUZZING_CPPFLAGS})
target_compile_definitions(hb-subset-fuzzer PUBLIC ${FUZZING_CPPFLAGS})
- target_compile_definitions(hb-subset-get-codepoints-fuzzer PUBLIC ${FUZZING_CPPFLAGS})
add_test (NAME hb-shape-fuzzer
COMMAND "${PYTHON_EXECUTABLE}" run-shape-fuzzer-tests.py $<TARGET_FILE:hb-shape-fuzzer>
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_test (NAME hb-subset-fuzzer
- COMMAND "${PYTHON_EXECUTABLE}" run-subset-fuzzer-tests.py $<TARGET_FILE:hb-subset-fuzzer> $<TARGET_FILE:hb-subset-get-codepoints-fuzzer>
+ COMMAND "${PYTHON_EXECUTABLE}" run-subset-fuzzer-tests.py $<TARGET_FILE:hb-subset-fuzzer>
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif ()
diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am
index 5af5a7339..250608861 100644
--- a/test/fuzzing/Makefile.am
+++ b/test/fuzzing/Makefile.am
@@ -18,12 +18,12 @@ EXTRA_DIST += \
run-shape-fuzzer-tests.py \
run-subset-fuzzer-tests.py \
CMakeLists.txt \
+ fonts \
$(NULL)
check_PROGRAMS = \
hb-shape-fuzzer \
hb-subset-fuzzer \
- hb-subset-get-codepoints-fuzzer \
$(NULL)
AM_CPPFLAGS = \
@@ -65,21 +65,6 @@ hb_subset_fuzzer_DEPENDENCIES = \
lib \
$(NULL)
-hb_subset_get_codepoints_fuzzer_SOURCES = \
- hb-fuzzer.hh \
- hb-subset-get-codepoints-fuzzer.cc \
- main.cc \
- $(NULL)
-hb_subset_get_codepoints_fuzzer_LDADD = \
- $(top_builddir)/src/libharfbuzz-subset-fuzzing.la \
- $(NULL)
-hb_subset_get_codepoints_fuzzer_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- $(NULL)
-hb_subset_get_codepoints_fuzzer_DEPENDENCIES = \
- lib \
- $(NULL)
-
check:
EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-shape-fuzzer-tests.py
EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" $(srcdir)/run-subset-fuzzer-tests.py
diff --git a/test/shaping/data/in-house/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf b/test/fuzzing/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6
index 203603110..203603110 100644
--- a/test/shaping/data/in-house/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf
+++ b/test/fuzzing/fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf b/test/fuzzing/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf
index c71e85a84..c71e85a84 100644
--- a/test/shaping/data/in-house/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf
+++ b/test/fuzzing/fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/205edd09bd3d141cc9580f650109556cc28b22cb.ttf b/test/fuzzing/fonts/205edd09bd3d141cc9580f650109556cc28b22cb
index 4e0ce0a48..4e0ce0a48 100644
--- a/test/shaping/data/in-house/fonts/205edd09bd3d141cc9580f650109556cc28b22cb.ttf
+++ b/test/fuzzing/fonts/205edd09bd3d141cc9580f650109556cc28b22cb
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/217a934cfe15c548b572c203dceb2befdf026462.ttf b/test/fuzzing/fonts/217a934cfe15c548b572c203dceb2befdf026462
index 12b91a09f..12b91a09f 100644
--- a/test/shaping/data/in-house/fonts/217a934cfe15c548b572c203dceb2befdf026462.ttf
+++ b/test/fuzzing/fonts/217a934cfe15c548b572c203dceb2befdf026462
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3511ff5c1647150595846ac414c595cccac34f18.ttf b/test/fuzzing/fonts/3511ff5c1647150595846ac414c595cccac34f18
index 789abf7a8..789abf7a8 100644
--- a/test/shaping/data/in-house/fonts/3511ff5c1647150595846ac414c595cccac34f18.ttf
+++ b/test/fuzzing/fonts/3511ff5c1647150595846ac414c595cccac34f18
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf b/test/fuzzing/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3
index b284c9864..b284c9864 100644
--- a/test/shaping/data/in-house/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf
+++ b/test/fuzzing/fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf b/test/fuzzing/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b
index a5c0156c1..a5c0156c1 100644
--- a/test/shaping/data/in-house/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf
+++ b/test/fuzzing/fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf b/test/fuzzing/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0
index 5d72fdfe3..5d72fdfe3 100644
--- a/test/shaping/data/in-house/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf
+++ b/test/fuzzing/fonts/558661aa659912f4d30ecd27bd09835171a8e2b0
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf b/test/fuzzing/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8
index 9b4d23f5a..9b4d23f5a 100644
--- a/test/shaping/data/in-house/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf
+++ b/test/fuzzing/fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/641bd9db850193064d17575053ae2bf8ec149ddc.ttf b/test/fuzzing/fonts/641bd9db850193064d17575053ae2bf8ec149ddc
index 66cefd4d8..66cefd4d8 100644
--- a/test/shaping/data/in-house/fonts/641bd9db850193064d17575053ae2bf8ec149ddc.ttf
+++ b/test/fuzzing/fonts/641bd9db850193064d17575053ae2bf8ec149ddc
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf b/test/fuzzing/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f
index 8eed14d94..8eed14d94 100644
--- a/test/shaping/data/in-house/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf
+++ b/test/fuzzing/fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a34a9191d9376bda419836effeef7e75c1386016.ttf b/test/fuzzing/fonts/a34a9191d9376bda419836effeef7e75c1386016
index a358833c2..a358833c2 100644
--- a/test/shaping/data/in-house/fonts/a34a9191d9376bda419836effeef7e75c1386016.ttf
+++ b/test/fuzzing/fonts/a34a9191d9376bda419836effeef7e75c1386016
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf b/test/fuzzing/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e
index 3cd5b5671..3cd5b5671 100644
--- a/test/shaping/data/in-house/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf
+++ b/test/fuzzing/fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf b/test/fuzzing/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2
index 500276df5..500276df5 100644
--- a/test/shaping/data/in-house/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf
+++ b/test/fuzzing/fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-5517117891805184 b/test/fuzzing/fonts/clusterfuzz-testcase-5517117891805184
new file mode 100644
index 000000000..0c7b518ba
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-5517117891805184
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-6107935408390144 b/test/fuzzing/fonts/clusterfuzz-testcase-6107935408390144
new file mode 100644
index 000000000..4c81a8660
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-6107935408390144
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ef2511f215aa3ca847cbfffbf861793b42170875.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-4666056377368576
index 6a3af4657..6a3af4657 100644
--- a/test/shaping/data/in-house/fonts/ef2511f215aa3ca847cbfffbf861793b42170875.ttf
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-4666056377368576
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528
new file mode 100644
index 000000000..cbb81acba
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-5662671558934528
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6243458541944832 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6243458541944832
new file mode 100644
index 000000000..64864aa5c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6243458541944832
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6303297511096320
index 3fb9951bb..3fb9951bb 100644
--- a/test/shaping/data/in-house/fonts/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6303297511096320
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6696647723581440 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6696647723581440
new file mode 100644
index 000000000..8b1c29305
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-fuzzer-6696647723581440
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5634395566768128 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5634395566768128
new file mode 100644
index 000000000..cd1a2934f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5634395566768128
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5688420752424960 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5688420752424960
new file mode 100644
index 000000000..1fe962b85
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5688420752424960
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5728971283496960 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5728971283496960
new file mode 100644
index 000000000..25d7bf1de
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5728971283496960
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5746142327865344 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5746142327865344
new file mode 100644
index 000000000..1c1607b73
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5746142327865344
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5750379279548416 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5750379279548416
new file mode 100644
index 000000000..f014d4b68
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5750379279548416
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-4884742786777088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-4884742786777088
new file mode 100644
index 000000000..ac7da9f9a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-4884742786777088
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5255344882188288 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5255344882188288
new file mode 100644
index 000000000..ab1aede1f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5255344882188288
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/233c1e252e737ca79e03a9fd56b71aaa4a230f2b.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5720051798769664
index 999f29622..999f29622 100644
--- a/test/shaping/data/in-house/fonts/233c1e252e737ca79e03a9fd56b71aaa4a230f2b.ttf
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5720051798769664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5924299061854208 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5924299061854208
new file mode 100644
index 000000000..a8ea33283
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-5924299061854208
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-6460279560863744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-6460279560863744
new file mode 100644
index 000000000..1cbe75a51
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-6460279560863744
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5973566991106048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5973566991106048
new file mode 100644
index 000000000..984bb4bd5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5973566991106048
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4523479581851648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4523479581851648
new file mode 100644
index 000000000..1d16d70bc
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4523479581851648
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4535496598355968
index ba8092854..ba8092854 100644
--- a/test/shaping/data/in-house/fonts/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4535496598355968
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4548492505645056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4548492505645056
new file mode 100644
index 000000000..065080f3a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4548492505645056
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/243798dd281c1c77c065958e1ff467420faa9bde.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4595692015190016
index dd8506eff..dd8506eff 100644
--- a/test/shaping/data/in-house/fonts/243798dd281c1c77c065958e1ff467420faa9bde.ttf
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4595692015190016
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4687441845813248 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4687441845813248
new file mode 100644
index 000000000..d3e9f4694
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4687441845813248
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4706238090706944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4706238090706944
new file mode 100644
index 000000000..269813a61
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4706238090706944
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4769173588672512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4769173588672512
new file mode 100644
index 000000000..5426914d0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4769173588672512
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4827735151083520 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4827735151083520
new file mode 100644
index 000000000..f5f1255e0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4827735151083520
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4841745322868736 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4841745322868736
new file mode 100644
index 000000000..5e0f74d4f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4841745322868736
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4884742786777088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4884742786777088
new file mode 100644
index 000000000..ac7da9f9a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-4884742786777088
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5216838347653120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5216838347653120
new file mode 100644
index 000000000..23cc59087
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5216838347653120
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5255344882188288 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5255344882188288
new file mode 100644
index 000000000..ab1aede1f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5255344882188288
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5294584596791296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5294584596791296
new file mode 100644
index 000000000..bc1657958
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5294584596791296
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5303930168803328 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5303930168803328
new file mode 100644
index 000000000..805fe4d4d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5303930168803328
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5331901587914752
index 41897b693..41897b693 100644
--- a/test/shaping/data/in-house/fonts/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5331901587914752
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5388906574905344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5388906574905344
new file mode 100644
index 000000000..5f7ff7c72
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5388906574905344
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5517117891805184 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5517117891805184
new file mode 100644
index 000000000..0c7b518ba
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5517117891805184
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5617496443846656 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5617496443846656
new file mode 100644
index 000000000..aeffab5db
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5617496443846656
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5672141338968064 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5672141338968064
new file mode 100644
index 000000000..3c8303fd6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5672141338968064
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5700697074958336 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5700697074958336
new file mode 100644
index 000000000..2664e3070
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5700697074958336
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5713868010553344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5713868010553344
new file mode 100644
index 000000000..ee0a721b5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5713868010553344
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5720051798769664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5720051798769664
new file mode 100644
index 000000000..999f29622
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5720051798769664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5924299061854208 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5924299061854208
new file mode 100644
index 000000000..a8ea33283
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-5924299061854208
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6023178755244032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6023178755244032
new file mode 100644
index 000000000..b0da1527d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6023178755244032
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6111685556305920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6111685556305920
new file mode 100644
index 000000000..8c1940d85
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6111685556305920
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6160439919509504
index eb374002d..eb374002d 100644
--- a/test/shaping/data/in-house/fonts/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6160439919509504
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6210176798425088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6210176798425088
new file mode 100644
index 000000000..1c62961ec
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6210176798425088
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6260579246276608 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6260579246276608
new file mode 100644
index 000000000..036a20611
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6260579246276608
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6264625609834496 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6264625609834496
new file mode 100644
index 000000000..035dd72f1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6264625609834496
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6278851874258944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6278851874258944
new file mode 100644
index 000000000..775c91886
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6278851874258944
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6424351550210048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6424351550210048
new file mode 100644
index 000000000..afb08c52d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6424351550210048
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6460279560863744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6460279560863744
new file mode 100644
index 000000000..1cbe75a51
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6460279560863744
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6576177596596224 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6576177596596224
new file mode 100644
index 000000000..35171ee31
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6576177596596224
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6595199411159040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6595199411159040
new file mode 100644
index 000000000..a4d503d40
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6595199411159040
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6624904746106880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6624904746106880
new file mode 100644
index 000000000..fcc1b6435
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6624904746106880
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6723367514144768 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6723367514144768
new file mode 100644
index 000000000..55b1ef885
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-fuzzer-6723367514144768
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5630246225707008 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5630246225707008
new file mode 100644
index 000000000..ab534e31f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5630246225707008
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5633985665826816 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5633985665826816
new file mode 100644
index 000000000..387d7fd46
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5633985665826816
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5635082459545600 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5635082459545600
new file mode 100644
index 000000000..6d0feff4d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5635082459545600
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5649959857160192 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5649959857160192
new file mode 100644
index 000000000..72e702ec6
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5649959857160192
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5650286710882304 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5650286710882304
new file mode 100644
index 000000000..95322e184
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5650286710882304
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652019562414080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652019562414080
new file mode 100644
index 000000000..8e859800f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652019562414080
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5656511058018304 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5656511058018304
new file mode 100644
index 000000000..bb68572e9
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5656511058018304
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5659641787187200 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5659641787187200
new file mode 100644
index 000000000..8a63dc4c8
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5659641787187200
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5664873493561344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5664873493561344
new file mode 100644
index 000000000..dfc36d897
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5664873493561344
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5668791174823936 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5668791174823936
new file mode 100644
index 000000000..1f750c11c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5668791174823936
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5672261407735808 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5672261407735808
new file mode 100644
index 000000000..629754944
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5672261407735808
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5674361600606208 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5674361600606208
new file mode 100644
index 000000000..1d4f84a98
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5674361600606208
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5677421274071040 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5677421274071040
new file mode 100644
index 000000000..3be3b91c2
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5677421274071040
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5679244475105280 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5679244475105280
new file mode 100644
index 000000000..2894bdc0f
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5679244475105280
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5685596677210112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5685596677210112
new file mode 100644
index 000000000..d9937a347
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5685596677210112
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5688420752424960 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5688420752424960
new file mode 100644
index 000000000..e9f01a232
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5688420752424960
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5695615258853376 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5695615258853376
new file mode 100644
index 000000000..af43a4433
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5695615258853376
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5696686572175360 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5696686572175360
new file mode 100644
index 000000000..c6e8bfd86
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5696686572175360
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718464350650368 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718464350650368
new file mode 100644
index 000000000..d511e9d10
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718464350650368
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718889451749376 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718889451749376
new file mode 100644
index 000000000..6360579be
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5718889451749376
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5719982789361664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5719982789361664
new file mode 100644
index 000000000..0515086a1
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5719982789361664
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5725129603022848 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5725129603022848
new file mode 100644
index 000000000..8ba0f9df5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5725129603022848
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5726089628876800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5726089628876800
new file mode 100644
index 000000000..61750d4a0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5726089628876800
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5729361857085440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5729361857085440
new file mode 100644
index 000000000..a6ecc6107
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5729361857085440
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5733166795456512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5733166795456512
new file mode 100644
index 000000000..dfaf6d9d7
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5733166795456512
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5734736291430400 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5734736291430400
new file mode 100644
index 000000000..31c805cbc
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5734736291430400
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5738888765636608 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5738888765636608
new file mode 100644
index 000000000..28e72df7d
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5738888765636608
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5740171484463104 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5740171484463104
new file mode 100644
index 000000000..aef0d924c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5740171484463104
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5750379279548416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5750379279548416
new file mode 100644
index 000000000..b4551bfc2
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5750379279548416
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762490181353472 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762490181353472
new file mode 100644
index 000000000..db06a1ccd
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762490181353472
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762953198960640 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762953198960640
new file mode 100644
index 000000000..9d64eafd9
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5762953198960640
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5764636557705216 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5764636557705216
new file mode 100644
index 000000000..b07416b07
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5764636557705216
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5359635656605696 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5359635656605696
new file mode 100644
index 000000000..8a659c654
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5359635656605696
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016
index 55541f749..55541f749 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5521982557782016
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872
index 6307ddd4b..6307ddd4b 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5542653037903872
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016
index 8c647a8a4..8c647a8a4 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609911946838016
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5629878397829120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5629878397829120
new file mode 100644
index 000000000..a055cdb42
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5629878397829120
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5651059347816448 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5651059347816448
new file mode 100644
index 000000000..b2e4034c0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5651059347816448
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5669437462544384 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5669437462544384
new file mode 100644
index 000000000..c4eb9091c
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5669437462544384
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480
index 49bcb3098..49bcb3098 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5670861909524480
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5690658895953920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5690658895953920
new file mode 100644
index 000000000..abafa4bc4
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5690658895953920
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695279609675776 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695279609675776
new file mode 100644
index 000000000..f01626233
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695279609675776
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696607199166464 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696607199166464
new file mode 100644
index 000000000..ca4fcd74e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5696607199166464
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711951464759296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711951464759296
new file mode 100644
index 000000000..b20e8496b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711951464759296
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5718215406125056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5718215406125056
new file mode 100644
index 000000000..a6d87dafb
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5718215406125056
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5743250149736448 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5743250149736448
new file mode 100644
index 000000000..b17c94996
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5743250149736448
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747265633779712 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747265633779712
new file mode 100644
index 000000000..463e0c14e
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747265633779712
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560
index d622c2563..d622c2563 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5750092395970560
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758598970343424 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758598970343424
new file mode 100644
index 000000000..7087f63eb
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758598970343424
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5765071062958080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5765071062958080
new file mode 100644
index 000000000..1f9be049a
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5765071062958080
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6543700493598720 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6543700493598720
new file mode 100644
index 000000000..c0e981197
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6543700493598720
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016
index 6206f0776..6206f0776 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6651660668502016
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5203067375976448 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5203067375976448
new file mode 100644
index 000000000..cf92d88a0
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5203067375976448
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5630904853069824 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5630904853069824
new file mode 100644
index 000000000..7c242eef5
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5630904853069824
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5687638085337088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5687638085337088
new file mode 100644
index 000000000..e8706f39b
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5687638085337088
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920
new file mode 100644
index 000000000..f57262179
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5736539338833920
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5930139383758848 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5930139383758848
new file mode 100644
index 000000000..940fbd503
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5930139383758848
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648
index b506d2a5a..b506d2a5a 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-5973295416475648
Binary files differ
diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912
index ffcea6460..ffcea6460 100644
--- a/test/api/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6136125075750912
Binary files differ
diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6394290358976512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6394290358976512
new file mode 100644
index 000000000..8ee7752aa
--- /dev/null
+++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-get-codepoints-fuzzer-6394290358976512
Binary files differ
diff --git a/test/api/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249 b/test/fuzzing/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249
index b6b47ffe3..b6b47ffe3 100644
--- a/test/api/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249
+++ b/test/fuzzing/fonts/crash-4b60576767ee4d9fe1cc10959d89baf73d4e8249
Binary files differ
diff --git a/test/api/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54 b/test/fuzzing/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54
index 00be056e6..00be056e6 100644
--- a/test/api/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54
+++ b/test/fuzzing/fonts/crash-b577db318b30f2851828a4c9ef97cb30678b1b54
Binary files differ
diff --git a/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a b/test/fuzzing/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
index 1af243ebc..1af243ebc 100644
--- a/test/api/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
+++ b/test/fuzzing/fonts/crash-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
Binary files differ
diff --git a/test/api/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480 b/test/fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480
index 890c4498f..890c4498f 100644
--- a/test/api/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480
+++ b/test/fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf b/test/fuzzing/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467
index e9884ea85..e9884ea85 100644
--- a/test/shaping/data/in-house/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf
+++ b/test/fuzzing/fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/fab39d60d758cb586db5a504f218442cd1395725.ttf b/test/fuzzing/fonts/fab39d60d758cb586db5a504f218442cd1395725
index 451ed0477..451ed0477 100644
--- a/test/shaping/data/in-house/fonts/fab39d60d758cb586db5a504f218442cd1395725.ttf
+++ b/test/fuzzing/fonts/fab39d60d758cb586db5a504f218442cd1395725
Binary files differ
diff --git a/test/api/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653 b/test/fuzzing/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653
index 0bb0f0f01..0bb0f0f01 100644
--- a/test/api/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653
+++ b/test/fuzzing/fonts/oom-6ef8c96d3710262511bcc730dce9c00e722cb653
Binary files differ
diff --git a/test/api/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a b/test/fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
index 1af243ebc..1af243ebc 100644
--- a/test/api/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
+++ b/test/fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a
Binary files differ
diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc
index 79f322297..b5a6c12e0 100644
--- a/test/fuzzing/hb-shape-fuzzer.cc
+++ b/test/fuzzing/hb-shape-fuzzer.cc
@@ -5,29 +5,29 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
- hb_blob_t *blob = hb_blob_create((const char *)data, size,
- HB_MEMORY_MODE_READONLY, NULL, NULL);
- hb_face_t *face = hb_face_create(blob, 0);
- hb_font_t *font = hb_font_create(face);
- hb_ot_font_set_funcs(font);
- hb_font_set_scale(font, 12, 12);
+ hb_blob_t *blob = hb_blob_create ((const char *)data, size,
+ HB_MEMORY_MODE_READONLY, NULL, NULL);
+ hb_face_t *face = hb_face_create (blob, 0);
+ hb_font_t *font = hb_font_create (face);
+ hb_ot_font_set_funcs (font);
+ hb_font_set_scale (font, 12, 12);
{
const char text[] = "ABCDEXYZ123@_%&)*$!";
- hb_buffer_t *buffer = hb_buffer_create();
- hb_buffer_add_utf8(buffer, text, -1, 0, -1);
- hb_buffer_guess_segment_properties(buffer);
- hb_shape(font, buffer, NULL, 0);
- hb_buffer_destroy(buffer);
+ hb_buffer_t *buffer = hb_buffer_create ();
+ hb_buffer_add_utf8 (buffer, text, -1, 0, -1);
+ hb_buffer_guess_segment_properties (buffer);
+ hb_shape (font, buffer, NULL, 0);
+ hb_buffer_destroy (buffer);
}
uint32_t text32[16];
- if (size > sizeof(text32)) {
- memcpy(text32, data + size - sizeof(text32), sizeof(text32));
- hb_buffer_t *buffer = hb_buffer_create();
- hb_buffer_add_utf32(buffer, text32, sizeof(text32)/sizeof(text32[0]), 0, -1);
- hb_buffer_guess_segment_properties(buffer);
- hb_shape(font, buffer, NULL, 0);
+ if (size > sizeof (text32)) {
+ memcpy(text32, data + size - sizeof (text32), sizeof (text32));
+ hb_buffer_t *buffer = hb_buffer_create ();
+ hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1);
+ hb_buffer_guess_segment_properties (buffer);
+ hb_shape (font, buffer, NULL, 0);
unsigned int len = hb_buffer_get_length (buffer);
hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);
@@ -41,12 +41,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
hb_font_get_glyph_extents (font, info.codepoint, &extents);
}
- hb_buffer_destroy(buffer);
+ hb_buffer_destroy (buffer);
}
- hb_font_destroy(font);
- hb_face_destroy(face);
- hb_blob_destroy(blob);
+ hb_font_destroy (font);
+ hb_face_destroy (face);
+ hb_blob_destroy (blob);
return 0;
}
diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc
index 28ce921c8..3a71f221f 100644
--- a/test/fuzzing/hb-subset-fuzzer.cc
+++ b/test/fuzzing/hb-subset-fuzzer.cc
@@ -6,17 +6,16 @@
#include "hb-subset.h"
-void trySubset (hb_face_t *face,
- const hb_codepoint_t text[],
- int text_length,
- bool drop_hints,
- bool drop_ot_layout)
+static void
+trySubset (hb_face_t *face,
+ const hb_codepoint_t text[],
+ int text_length,
+ bool drop_hints,
+ bool drop_layout)
{
- hb_subset_profile_t *profile = hb_subset_profile_create ();
-
hb_subset_input_t *input = hb_subset_input_create_or_fail ();
- *hb_subset_input_drop_hints (input) = drop_hints;
- *hb_subset_input_drop_ot_layout (input) = drop_ot_layout;
+ hb_subset_input_set_drop_hints (input, drop_hints);
+ hb_subset_input_set_drop_layout (input, drop_layout);
hb_set_t *codepoints = hb_subset_input_unicode_set (input);
for (int i = 0; i < text_length; i++)
@@ -24,23 +23,23 @@ void trySubset (hb_face_t *face,
hb_set_add (codepoints, text[i]);
}
- hb_face_t *result = hb_subset (face, profile, input);
+ hb_face_t *result = hb_subset (face, input);
hb_face_destroy (result);
hb_subset_input_destroy (input);
- hb_subset_profile_destroy (profile);
}
-void trySubset (hb_face_t *face,
- const hb_codepoint_t text[],
- int text_length)
+static void
+trySubset (hb_face_t *face,
+ const hb_codepoint_t text[],
+ int text_length)
{
for (unsigned int drop_hints = 0; drop_hints < 2; drop_hints++)
{
- for (unsigned int drop_ot_layout = 0; drop_ot_layout < 2; drop_ot_layout++)
+ for (unsigned int drop_layout = 0; drop_layout < 2; drop_layout++)
{
trySubset (face, text, text_length,
- (bool) drop_hints, (bool) drop_ot_layout);
+ (bool) drop_hints, (bool) drop_layout);
}
}
}
@@ -48,22 +47,27 @@ void trySubset (hb_face_t *face,
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
hb_blob_t *blob = hb_blob_create ((const char *)data, size,
- HB_MEMORY_MODE_READONLY, NULL, NULL);
+ HB_MEMORY_MODE_READONLY, NULL, NULL);
hb_face_t *face = hb_face_create (blob, 0);
+ /* Just test this API here quickly. */
+ hb_set_t *output = hb_set_create();
+ hb_face_collect_unicodes (face, output);
+ hb_set_destroy (output);
+
const hb_codepoint_t text[] =
{
- 'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2',
- '3', '@', '_', '%', '&', ')', '*', '$', '!'
+ 'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2',
+ '3', '@', '_', '%', '&', ')', '*', '$', '!'
};
trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t));
hb_codepoint_t text_from_data[16];
if (size > sizeof(text_from_data)) {
- memcpy(text_from_data,
- data + size - sizeof(text_from_data),
- sizeof(text_from_data));
+ memcpy (text_from_data,
+ data + size - sizeof(text_from_data),
+ sizeof(text_from_data));
unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t);
trySubset (face, text_from_data, text_size);
}
diff --git a/test/fuzzing/hb-subset-get-codepoints-fuzzer.cc b/test/fuzzing/hb-subset-get-codepoints-fuzzer.cc
deleted file mode 100644
index 38f338ba4..000000000
--- a/test/fuzzing/hb-subset-get-codepoints-fuzzer.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "hb-fuzzer.hh"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "hb-subset.h"
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
- hb_blob_t *blob = hb_blob_create ((const char *)data, size,
- HB_MEMORY_MODE_READONLY, NULL, NULL);
- hb_face_t *face = hb_face_create (blob, 0);
-
- hb_set_t *output = hb_set_create();
- hb_subset_get_all_codepoints (face, output);
-
- hb_set_destroy (output);
- hb_face_destroy (face);
- hb_blob_destroy (blob);
-
- return 0;
-}
diff --git a/test/fuzzing/main.cc b/test/fuzzing/main.cc
index 4692f7b5f..f15247cdb 100644
--- a/test/fuzzing/main.cc
+++ b/test/fuzzing/main.cc
@@ -1,21 +1,23 @@
#include "hb-fuzzer.hh"
-#include <iostream>
-#include <iterator>
-#include <fstream>
+#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
-std::string FileToString(const std::string &Path) {
- /* TODO This silently passes if file does not exist. Fix it! */
- std::ifstream T(Path.c_str());
- return std::string((std::istreambuf_iterator<char>(T)),
- std::istreambuf_iterator<char>());
-}
-
int main(int argc, char **argv) {
+ hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
+ unsigned int len;
+ const char *font_data = hb_blob_get_data (blob, &len);
+ if (len == 0)
+ {
+ printf ("Font not found.\n");
+ exit (1);
+ }
+
for (int i = 1; i < argc; i++) {
- std::string s = FileToString(argv[i]);
- std::cout << argv[i] << std::endl;
- LLVMFuzzerTestOneInput((const unsigned char*)s.data(), s.size());
+ printf ("%s\n", argv[i]);
+ LLVMFuzzerTestOneInput((const uint8_t *) font_data, len);
}
+
+ hb_blob_destroy (blob);
}
diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py
index fea0b01b4..53c4f501a 100755
--- a/test/fuzzing/run-shape-fuzzer-tests.py
+++ b/test/fuzzing/run-shape-fuzzer-tests.py
@@ -2,7 +2,54 @@
from __future__ import print_function, division, absolute_import
-import sys, os, subprocess
+import sys, os, subprocess, tempfile, threading
+
+
+def which(program):
+ # https://stackoverflow.com/a/377028
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+ fpath, _ = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+
+ return None
+
+
+def cmd(command):
+ # https://stackoverflow.com/a/4408409
+ # https://stackoverflow.com/a/10012262
+ with tempfile.TemporaryFile() as tempf:
+ p = subprocess.Popen (command, stderr=tempf)
+ is_killed = {'value': False}
+
+ def timeout(p, is_killed):
+ is_killed['value'] = True
+ p.kill()
+ timer = threading.Timer (2, timeout, [p, is_killed])
+
+ try:
+ timer.start()
+ p.wait ()
+ tempf.seek (0)
+ text = tempf.read().decode ("utf-8").strip ()
+ returncode = p.returncode
+ finally:
+ timer.cancel()
+
+ if is_killed['value']:
+ text = 'error: timeout, ' + text
+ returncode = 1
+
+ return text, returncode
+
srcdir = os.environ.get ("srcdir", ".")
EXEEXT = os.environ.get ("EXEEXT", "")
@@ -20,14 +67,30 @@ please provide it as the first argument to the tool""")
print ('hb_shape_fuzzer:', hb_shape_fuzzer)
fails = 0
-parent_path = os.path.join (srcdir, "..", "shaping", "data", "in-house", "tests")
-for line in open (os.path.join (parent_path, "fuzzed.tests")):
- font = line.split (":")[0]
- font_path = os.path.join (parent_path, font)
+valgrind = None
+if os.environ.get('RUN_VALGRIND', ''):
+ valgrind = which ('valgrind')
+
+parent_path = os.path.join (srcdir, "fonts")
+for file in os.listdir (parent_path):
+ path = os.path.join(parent_path, file)
+
+ text, returncode = cmd ([hb_shape_fuzzer, path])
+ print (text)
+
+ failed = False
+ if returncode != 0 or 'error' in text:
+ print ('failure on %s' % file)
+ failed = True
- p = subprocess.Popen ([hb_shape_fuzzer, font_path])
+ if valgrind:
+ text, returncode = cmd ([valgrind, '--error-exitcode=1', hb_shape_fuzzer, path])
+ if returncode:
+ print (text)
+ print ('failure on %s' % file)
+ failed = True
- if p.wait () != 0:
+ if failed:
fails = fails + 1
if fails:
diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py
index 013628860..d4e3487f0 100755
--- a/test/fuzzing/run-subset-fuzzer-tests.py
+++ b/test/fuzzing/run-subset-fuzzer-tests.py
@@ -8,7 +8,6 @@ srcdir = os.environ.get ("srcdir", ".")
EXEEXT = os.environ.get ("EXEEXT", "")
top_builddir = os.environ.get ("top_builddir", ".")
hb_subset_fuzzer = os.path.join (top_builddir, "hb-subset-fuzzer" + EXEEXT)
-hb_subset_get_codepoints_fuzzer = os.path.join (top_builddir, "hb-subset-get-codepoints-fuzzer" + EXEEXT)
if not os.path.exists (hb_subset_fuzzer):
if len (sys.argv) < 2 or not os.path.exists (sys.argv[1]):
@@ -18,35 +17,29 @@ please provide it as the first argument to the tool""")
hb_subset_fuzzer = sys.argv[1]
-if not os.path.exists (hb_subset_get_codepoints_fuzzer):
- if len (sys.argv) < 3 or not os.path.exists (sys.argv[2]):
- print ("""Failed to find hb-subset-get-codepoints-fuzzer binary automatically,
-please provide it as the second argument to the tool""")
- sys.exit (1)
-
- hb_subset_get_codepoints_fuzzer = sys.argv[2]
-
print ('hb_subset_fuzzer:', hb_subset_fuzzer)
fails = 0
-parent_path = os.path.join (srcdir, "..", "subset", "data", "fonts")
-print ("running subset fuzzer against fonts in %s" % parent_path)
-for file in os.listdir (parent_path):
- path = os.path.join(parent_path, file)
+def run_dir (parent_path):
+ global fails
+ print ("running subset fuzzer against fonts in %s" % parent_path)
+ for file in os.listdir (parent_path):
+ path = os.path.join(parent_path, file)
- print ("running subset fuzzer against %s" % path)
- p = subprocess.Popen ([hb_subset_fuzzer, path])
+ print ("running subset fuzzer against %s" % path)
+ p = subprocess.Popen ([hb_subset_fuzzer, path])
- if p.wait () != 0:
- print ("failed for %s" % path)
- fails = fails + 1
+ if p.wait () != 0:
+ print ("failed for %s" % path)
+ fails = fails + 1
- print ("running subset get codepoints fuzzer against %s" % path)
- p = subprocess.Popen ([hb_subset_get_codepoints_fuzzer, path])
+ if p.wait () != 0:
+ print ("failed for %s" % path)
+ fails = fails + 1
- if p.wait () != 0:
- print ("failed for %s" % path)
- fails = fails + 1
+run_dir (os.path.join (srcdir, "..", "subset", "data", "fonts"))
+# TODO running these tests very slow tests. Fix and re-enable
+#run_dir (os.path.join (srcdir, "fonts"))
if fails:
print ("%i subset fuzzer related tests failed." % fails)
diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am
index 732033650..5ca9bc197 100644
--- a/test/shaping/Makefile.am
+++ b/test/shaping/Makefile.am
@@ -8,6 +8,8 @@ SUBDIRS = data
# Convenience targets:
lib:
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+libs:
+ @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
EXTRA_DIST += \
README.md \
diff --git a/test/shaping/data/in-house/Makefile.sources b/test/shaping/data/in-house/Makefile.sources
index ef16faed4..6e21ddd4c 100644
--- a/test/shaping/data/in-house/Makefile.sources
+++ b/test/shaping/data/in-house/Makefile.sources
@@ -1,18 +1,20 @@
TESTS = \
+ tests/aat-trak.tests \
tests/arabic-fallback-shaping.tests \
tests/arabic-feature-order.tests \
tests/arabic-like-joining.tests \
+ tests/arabic-mark-attach.tests \
tests/arabic-mark-order.tests \
tests/arabic-stch.tests \
tests/automatic-fractions.tests \
tests/cluster.tests \
+ tests/collections.tests \
tests/color-fonts.tests \
tests/context-matching.tests \
tests/cursive-positioning.tests \
tests/default-ignorables.tests \
- tests/emoji-flag-tags.tests \
+ tests/emoji.tests \
tests/fallback-positioning.tests \
- tests/fuzzed.tests \
tests/hangul-jamo.tests \
tests/hyphens.tests \
tests/indic-consonant-with-stacker.tests \
@@ -25,13 +27,18 @@ TESTS = \
tests/indic-script-extensions.tests \
tests/indic-special-cases.tests \
tests/indic-syllable.tests \
+ tests/indic-vowel-letter-spoofing.tests \
+ tests/khmer-mark-order.tests \
+ tests/khmer-misc.tests \
tests/language-tags.tests \
tests/ligature-id.tests \
tests/mark-attachment.tests \
tests/mark-filtering-sets.tests \
tests/mongolian-variation-selector.tests \
tests/myanmar-syllable.tests \
+ tests/myanmar-zawgyi.tests \
tests/none-directional.tests \
+ tests/rand.tests \
tests/spaces.tests \
tests/simple.tests \
tests/sinhala.tests \
@@ -39,6 +46,7 @@ TESTS = \
tests/tibetan-contractions-2.tests \
tests/tibetan-vowels.tests \
tests/use.tests \
+ tests/use-indic3.tests \
tests/use-marchen.tests \
tests/use-syllable.tests \
tests/variations-rvrn.tests \
diff --git a/test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf b/test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf
new file mode 100644
index 000000000..ee540f3bd
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf b/test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf
new file mode 100644
index 000000000..383aee66e
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf b/test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf
new file mode 100644
index 000000000..13c4d8a3b
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf b/test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf
new file mode 100644
index 000000000..ef94d3fc5
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf b/test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf
new file mode 100644
index 000000000..cebd37571
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf b/test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf
new file mode 100644
index 000000000..63c0c71bd
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf b/test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf
new file mode 100644
index 000000000..14de6a184
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf b/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf
new file mode 100644
index 000000000..588ce3b93
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf b/test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf
new file mode 100644
index 000000000..a6f1c9df3
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf b/test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf
new file mode 100644
index 000000000..1328e13ca
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf b/test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf
new file mode 100644
index 000000000..c3e4167fe
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf b/test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf
new file mode 100644
index 000000000..ffdddf325
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf b/test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf
new file mode 100644
index 000000000..a749cdf42
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/881642af1667ae30a54e58de8be904566d00508f.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf b/test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf
new file mode 100644
index 000000000..1841cf37b
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/TestDFONT.dfont b/test/shaping/data/in-house/fonts/TestDFONT.dfont
new file mode 100644
index 000000000..a6ea7009b
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/TestDFONT.dfont
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/TestTRAK.ttf b/test/shaping/data/in-house/fonts/TestTRAK.ttf
new file mode 100644
index 000000000..07ae3afd8
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/TestTRAK.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/TestTTC.ttc b/test/shaping/data/in-house/fonts/TestTTC.ttc
new file mode 100644
index 000000000..a21fe89dc
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/TestTTC.ttc
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf b/test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf
new file mode 100644
index 000000000..a64eceac6
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf b/test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf
new file mode 100644
index 000000000..9cd40d4e7
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/af85624080af5627fb050f570d148a62f04fda74.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf b/test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf
new file mode 100644
index 000000000..a9dc202b5
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf b/test/shaping/data/in-house/fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf
deleted file mode 100644
index fba200f10..000000000
--- a/test/shaping/data/in-house/fonts/bb29ce50df2bdba2d10726427c6b7609bf460e04.ttf
+++ /dev/null
Binary files differ
diff --git a/test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf b/test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf
new file mode 100644
index 000000000..dbd928aa0
--- /dev/null
+++ b/test/shaping/data/in-house/fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf
Binary files differ
diff --git a/test/shaping/data/in-house/tests/aat-trak.tests b/test/shaping/data/in-house/tests/aat-trak.tests
new file mode 100644
index 000000000..48b224f33
--- /dev/null
+++ b/test/shaping/data/in-house/tests/aat-trak.tests
@@ -0,0 +1,8 @@
+../fonts/TestTRAK.ttf::U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
+../fonts/TestTRAK.ttf:--font-ptem=.5:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
+../fonts/TestTRAK.ttf:--font-ptem=1:U+0041,U+0042,U+0043:[A.alt=0@100,0+1200|B=1@100,0+1200|C.alt=2@100,0+1200]
+../fonts/TestTRAK.ttf:--font-ptem=2:U+0041,U+0042,U+0043:[A.alt=0@93,0+1187|B=1@93,0+1187|C.alt=2@93,0+1187]
+../fonts/TestTRAK.ttf:--font-ptem=9:U+0041,U+0042,U+0043:[A.alt=0+1000|B=1+1000|C.alt=2+1000]
+../fonts/TestTRAK.ttf:--font-ptem=24:U+0041,U+0042,U+0043:[A.alt=0@-12,0+976|B=1@-12,0+976|C.alt=2@-12,0+976]
+../fonts/TestTRAK.ttf:--font-ptem=72:U+0041,U+0042,U+0043:[A.alt=0@-50,0+900|B=1@-50,0+900|C.alt=2@-50,0+900]
+../fonts/TestTRAK.ttf:--font-ptem=144:U+0041,U+0042,U+0043:[A.alt=0@-107,0+786|B=1@-107,0+786|C.alt=2@-107,0+786]
diff --git a/test/shaping/data/in-house/tests/arabic-mark-attach.tests b/test/shaping/data/in-house/tests/arabic-mark-attach.tests
new file mode 100644
index 000000000..a577e51ad
--- /dev/null
+++ b/test/shaping/data/in-house/tests/arabic-mark-attach.tests
@@ -0,0 +1 @@
+../fonts/641ca9d7808b01cafa9a666c13811c9b56eb9c52.ttf::U+064A,U+0633,U+06E1,U+200D,U+0654,U+064E,U+0644:[afii57444.zz04=6+1091|afii57454=1@75,925+0|uni0654=1+0|space=1+0|uni06E1=1@950,1115+0|afii57427.zz03_calt=1+1847|afii57450.zz21=0+345]
diff --git a/test/shaping/data/in-house/tests/collections.tests b/test/shaping/data/in-house/tests/collections.tests
new file mode 100644
index 000000000..85653c543
--- /dev/null
+++ b/test/shaping/data/in-house/tests/collections.tests
@@ -0,0 +1,6 @@
+../fonts/TestDFONT.dfont:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241]
+../fonts/TestDFONT.dfont:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000]
+../fonts/TestDFONT.dfont:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000]
+../fonts/TestTTC.ttc:--face-index=0 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241]
+../fonts/TestTTC.ttc:--face-index=1 --font-funcs=ot:U+2026,U+0020,U+002E:[ellipsis=0+723|space=1+250|period=2+241]
+../fonts/TestTTC.ttc:--face-index=2 --font-funcs=ot:U+2026,U+0020,U+002E:[gid0=0+1000|gid0=1+1000|gid0=2+1000]
diff --git a/test/shaping/data/in-house/tests/cursive-positioning.tests b/test/shaping/data/in-house/tests/cursive-positioning.tests
index 74d283db8..15a1ffc9c 100644
--- a/test/shaping/data/in-house/tests/cursive-positioning.tests
+++ b/test/shaping/data/in-house/tests/cursive-positioning.tests
@@ -2,3 +2,4 @@
../fonts/298c9e1d955f10f6f72c6915c3c6ff9bf9695cec.ttf::U+0643,U+0645,U+0645,U+062B,U+0644:[gid8=4+738|gid5=3@441,1197+0|gid6=3@0,432+405|gid9=2@0,477+500|gid9=1@0,577+452|gid10=0@20,1177+207]
#../fonts/706c5d7b625f207bc0d874c67237aad6f1e9cd6f.ttf::U+0B1F,U+0B4D,U+0B1A,U+0B4D,U+0B1A:[ttaorya=0+1307|casubscriptorya=0@-242,104+-231|casubscriptnarroworya=0@20,104+507]
../fonts/07f054357ff8638bac3711b422a1e31180bba863.ttf:--font-funcs=ot --no-glyph-names:U+0606,U+06E1:[2=0@40,502+0|1=0+1000]
+../fonts/9fc3e6960b3520e5304033ef5fd540285f72f14d.ttf::U+16F0A,U+16F57,U+16F8F:[u16F0A=0+422|u16F57=0@0,209+338|u16F8F=0+0]
diff --git a/test/shaping/data/in-house/tests/emoji-flag-tags.tests b/test/shaping/data/in-house/tests/emoji-flag-tags.tests
deleted file mode 100644
index 189de55a5..000000000
--- a/test/shaping/data/in-house/tests/emoji-flag-tags.tests
+++ /dev/null
@@ -1,2 +0,0 @@
-../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=1+0|space=2+0|space=3+0|space=4+0|space=5+0]
-../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200]
diff --git a/test/shaping/data/in-house/tests/emoji.tests b/test/shaping/data/in-house/tests/emoji.tests
new file mode 100644
index 000000000..8d9b2541f
--- /dev/null
+++ b/test/shaping/data/in-house/tests/emoji.tests
@@ -0,0 +1,4 @@
+../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0055,U+E0053,U+E0064,U+E0065,U+E007F:[u1F3F4=0+2126|space=1+0|space=2+0|space=3+0|space=4+0|space=5+0]
+../fonts/53374c7ca3657be37efde7ed02ae34229a56ae1f.ttf::U+1F3F4,U+E0064,U+E0065,U+E007F:[de=0+3200]
+../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=l:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
+../fonts/3cf6f8ac6d647473a43a3100e7494b202b2cfafe.ttf:--font-funcs=ot --direction=r:U+1F481,U+1F3FB,U+200D,U+2642,U+FE0F:[gid7=0+2550]
diff --git a/test/shaping/data/in-house/tests/fuzzed.tests b/test/shaping/data/in-house/tests/fuzzed.tests
deleted file mode 100644
index 43a193341..000000000
--- a/test/shaping/data/in-house/tests/fuzzed.tests
+++ /dev/null
@@ -1,23 +0,0 @@
-../fonts/1a6f1687b7a221f9f2c834b0b360d3c8463b6daf.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/5a5daf5eb5a4db77a2baa3ad9c7a6ed6e0655fa8.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/0509e80afb379d16560e9e47bdd7d888bebdebc6.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/641bd9db850193064d17575053ae2bf8ec149ddc.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/375d6ae32a3cbe52fbf81a4e5777e3377675d5a3.ttf:--font-funcs=ot:U+0041:[gid0=0+4352]
-../fonts/8240789f6d12d4cfc4b5e8e6f246c3701bcf861f.ttf:--font-funcs=ot:U+0041:[gid0=0+1024]
-../fonts/b9e2aaa0d75fcef6971ec3a96d806ba4a6b31fe2.ttf:--font-funcs=ot:U+0041:[gid0=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid8=0+1000|gid3=0+1000|gid0=0+1000|gid1=0+1000|gid1=0+1000]
-../fonts/43979b90b2dd929723cf4fe1715990bcb9c9a56b.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/3511ff5c1647150595846ac414c595cccac34f18.ttf:--font-funcs=ot --no-positions --no-clusters --no-glyph-names:U+0041:[0|512|15104|11004|3408|18244|17872|17961|0|992|15616|0|14151|20559|20992|5440|256|0|10|8960|256|1024|1490|0|768|4096|256|2216|0|256|256|0|768|10752|11004|3408|18244|17734|53248|256|0|512|14848|10793|57344|768|18227|20285|20480|0|256|0|810|0|11004|3408|18244|17734|53289|57344|768|15667|71|0|20559|21248|256|0|2816|2776|0|51516|0|32|26209|28005|65249|29690|0|51548|0|2454|28783|29556|1291|3458|80|0|2804|210|28786|25968|45763|50546|0|59136|0|38144|256|0|2560|30208|52224|580|17996|21504|6734|108|116|24846|1024|0|255|65280|256|0|8704|1345|23109|8192|10823|21076|8192|12877|20300|8192|6738|20301|8192|16980|21067|8251|18944|255|65280|15360|256|255|65280|256|768|255|65280|256|768|255|65280|256|1024|12|65280|256|1280|255|65280|256|1536|1899|25970|110|11264|27502|29285|12907|25974|28160|14443|25970|28288|3|118|18259|21826|45716|46369|0|0|1|16|17|256|4|16|18244|17734|28|12|0|284|0|28|18256|20307|45114|47616|226|10296|0|57927|1|0|0|21248|5440|256|0|10|768|256|1024|512|0|297|16|24833|28774|10794|2304|29|32|42|64515|42|42|64525|20551|17477|18128|10720|3|61|3408|18244|17734|53289|57344|768|15616|512|55|10576|20307|0|255|56063|53504|42|42|64525|12288|18176|80|20307|1|0|62]
-../fonts/fab39d60d758cb586db5a504f218442cd1395725.ttf:--font-funcs=ot:U+0041,U+0041:[gid0=0+1000|gid0=1+1000]
-../fonts/205edd09bd3d141cc9580f650109556cc28b22cb.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/217a934cfe15c548b572c203dceb2befdf026462.ttf:--font-funcs=ot:U+0061,U+0061,U+0061:[]
-../fonts/558661aa659912f4d30ecd27bd09835171a8e2b0.ttf:--font-funcs=ot:U+FFFD,U+E0100,U+FFFD,U+E0010:[]
-../fonts/a34a9191d9376bda419836effeef7e75c1386016.ttf:--font-funcs=ot:U+0041:[]
-../fonts/a69118c2c2ada48ff803d9149daa54c9ebdae30e.ttf:--font-funcs=ot:U+0041:[gid0=0+1229]
-../fonts/b6acef662e0beb8d5fcf5b61c6b0ca69537b7402.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/e88c339237f52d21e01c55f01b9c1b4cc14a0467.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/243798dd281c1c77c065958e1ff467420faa9bde.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/dd9f0c7c7c36f75a18be0cab1cddf8f3ab0f366b.ttf:--font-funcs=ot --no-positions --no-clusters --no-glyph-names:U+0041:[0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|0|2|0|0|0|2|0|0|2|0|0|2|0|0|2|0|0|2|0|0|0|2|0|0|2|0|0|2|0|0|2|0]
-../fonts/ef2511f215aa3ca847cbfffbf861793b42170875.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/9d8a94a67932a3ab75a596fc8b5c6d0392ca9e49.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/bbf4a308c402f0678c3e82844892a4da2ebe598f.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
-../fonts/233c1e252e737ca79e03a9fd56b71aaa4a230f2b.ttf:--font-funcs=ot:U+0041:[gid0=0+1000]
diff --git a/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests b/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests
index 87b36035a..6b75137fe 100644
--- a/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests
+++ b/test/shaping/data/in-house/tests/indic-joiner-candrabindu.tests
@@ -1,2 +1,2 @@
../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200D,U+0B01:[omorya=0+1450]
-../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200C,U+0B01:[oorya=0+1309|space=0+0|candrabinduorya=0+0]
+../fonts/5028afb650b1bb718ed2131e872fbcce57828fff.ttf::U+0B13,U+200C,U+0B01:[oorya=0+1309|space=1+0|candrabinduorya=1+0]
diff --git a/test/shaping/data/in-house/tests/indic-joiners.tests b/test/shaping/data/in-house/tests/indic-joiners.tests
index dca83f87d..80e392cfc 100644
--- a/test/shaping/data/in-house/tests/indic-joiners.tests
+++ b/test/shaping/data/in-house/tests/indic-joiners.tests
@@ -1,6 +1,6 @@
-../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=1+0|uni17ca=1+0|uni17b8=1@0,300+0|space=7+600]
+../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=4+0|uni17ca=4+0|uni17b8=4@0,300+0|space=7+600]
../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+17CA,U+17B8:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|uni17bb=1@-75,-700+0|uni17b8=1+0]
-../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200C,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni093F.750=3+397|uni092F=3+924]
+../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200C,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=2+0|uni093F.750=3+397|uni092F=3+924]
../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924]
-../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=3+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924]
+../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=5+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924]
../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924]
diff --git a/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests b/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests
new file mode 100644
index 000000000..f8305a312
--- /dev/null
+++ b/test/shaping/data/in-house/tests/indic-vowel-letter-spoofing.tests
@@ -0,0 +1,53 @@
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0904,U+0020,U+0905,U+0946:[ashortdeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|eshortvowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0906,U+0020,U+0905,U+093E:[aadeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|aavowelsigndeva=2+259]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0908,U+0020,U+0930,U+094D,U+0907:[iideva=0+491|space=1+260|uni25CC=2+510|rephdeva=2+0|ideva=2+491]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090A,U+0020,U+0909,U+0941:[uudeva=0+765|space=1+260|udeva=2+548|uni25CC=2+510|uvowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090D,U+0020,U+090F,U+0945:[ecandradeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|ecandravowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+090E,U+0020,U+090F,U+0946:[eshortdeva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|eshortvowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0910,U+0020,U+090F,U+0947:[aideva=0+553|space=1+260|edeva=2+553|uni25CC=2+510|evowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0911,U+0020,U+0905,U+0949,U+0020,U+0906,U+0945:[ocandradeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ocandravowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|ecandravowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0912,U+0020,U+0905,U+094A,U+0020,U+0906,U+0946:[oshortdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|oshortvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|eshortvowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0913,U+0020,U+0905,U+094B,U+0020,U+0906,U+0947:[odeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ovowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|evowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0914,U+0020,U+0905,U+094C,U+0020,U+0906,U+0948:[audeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|auvowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|aivowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0972,U+0020,U+0905,U+0945:[acandradeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|ecandravowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0973,U+0020,U+0905,U+093A:[oedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|oevowelsigndeva=2+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0974,U+0020,U+0905,U+093B,U+0020,U+0906,U+093A:[ooedeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|ooevowelsigndeva=2+259|space=4+260|aadeva=5+1023|uni25CC=5+510|oevowelsigndeva=5+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0975,U+0020,U+0905,U+094F:[awdeva=0+1023|space=1+260|adeva=2+764|uni25CC=2+510|awvowelsigndeva=2+259]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0976,U+0020,U+0905,U+0956:[uedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uevowelsigndeva=2@50,0+0]
+../fonts/1a5face3fcbd929d228235c2f72bbd6f8eb37424.ttf::U+0977,U+0020,U+0905,U+0957:[uuedeva=0+764|space=1+260|adeva=2+764|uni25CC=2+510|uuevowelsigndeva=2@50,0+0]
+../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+0986,U+0020,U+0985,U+09BE:[aabeng=0+1158|space=1+260|abeng=2+893|uni25CC=2+510|aavowelsignbeng=2+266]
+../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+09E0,U+0020,U+098B,U+09C3:[rrvocalicbeng=0+853|space=1+260|rvocalicbeng=2+853|uni25CC=2+510|rvocalicvowelsignbeng=2+0]
+../fonts/881642af1667ae30a54e58de8be904566d00508f.ttf::U+09E1,U+0020,U+098C,U+09E2:[llvocalicbeng=0+639|space=1+260|lvocalicbeng=2+639|uni25CC=2+510|lvocalicvowelsignbeng=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A06,U+0020,U+0A05,U+0A3E:[aaguru=0+2001|space=1+532|aguru=2+1520|uni25CC=2+1044|aamatraguru=2+481]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A07,U+0020,U+0A72,U+0A3F:[iguru=0+1671|space=1+532|iriguru=2+1141|imatraguru=2+530|uni25CC=2+1044]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A08,U+0020,U+0A72,U+0A40:[iiguru=0+1671|space=1+532|iriguru=2+1141|uni25CC=2+1044|iimatraguru=2+530]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A09,U+0020,U+0A73,U+0A41:[uguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|umatraguru=2@102,0+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A0A,U+0020,U+0A73,U+0A42:[uuguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|uumatraguru=2@102,0+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A0F,U+0020,U+0A72,U+0A47:[eeguru=0+1141|space=1+532|iriguru=2+1141|uni25CC=2+1044|eematraguru=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A10,U+0020,U+0A05,U+0A48:[aiguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aimatraguru=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A13,U+0020,U+0A73,U+0A4B:[ooguru=0+1356|space=1+532|uraguru=2+1356|uni25CC=2+1044|oomatraguru=2+0]
+../fonts/604026ae5aaca83c49cd8416909d71ba3e1c1194.ttf::U+0A14,U+0020,U+0A05,U+0A4C:[auguru=0+1520|space=1+532|aguru=2+1520|uni25CC=2+1044|aumatraguru=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A86,U+0020,U+0A85,U+0ABE:[gid3=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid10=2+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A8D,U+0020,U+0A85,U+0AC5:[gid4=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid11=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A8F,U+0020,U+0A85,U+0AC7:[gid5=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid12=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A90,U+0020,U+0A85,U+0AC8:[gid6=0+1808|gid1=1+612|gid2=2+1808|gid17=2+1044|gid13=2+0]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A91,U+0020,U+0A85,U+0AC9:[gid7=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid14=2+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A93,U+0020,U+0A85,U+0ACB,U+0020,U+0A85,U+0ABE,U+0AC5:[gid8=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid15=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid11=5+0|gid10=5+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0A94,U+0020,U+0A85,U+0ACC,U+0020,U+0A85,U+0ABE,U+0AC8:[gid9=0+2351|gid1=1+612|gid2=2+1808|gid17=2+1044|gid16=2+543|gid1=4+612|gid2=5+1808|gid17=5+1044|gid13=5+0|gid10=5+543]
+../fonts/738d9f3b8c2dfd03875bf35a61d28fd78faf17c8.ttf::U+0AC9,U+0020,U+0AC5,U+0ABE:[gid17=0+1044|gid14=0+543|gid1=1+612|gid17=1+1044|gid11=1+0|gid17=1+1044|gid10=1+543]
+../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B06,U+0020,U+0B05,U+0B3E:[aaorya=0+1681|space=1+881|aorya=2+1284|uni25CC=2+1044|aavowelsignorya=2+387]
+../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B10,U+0020,U+0B0F,U+0B57:[aiorya=0+1681|space=1+881|eorya=2+1315|uni25CC=2+1044|aulengthmarkorya=2+387]
+../fonts/2c25beb56d9c556622d56b0b5d02b4670c034f89.ttf::U+0B14,U+0020,U+0B13,U+0B57:[auorya=0+1679|space=1+881|oorya=2+1309|uni25CC=2+1044|aulengthmarkorya=2+387]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C13,U+0020,U+0C12,U+0C55:[gid3=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid12=2+0]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C14,U+0020,U+0C12,U+0C4C:[gid4=0+1497|gid1=1+580|gid2=2+1497|gid13=2+1184|gid11=2+634]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C40,U+0020,U+0C3F,U+0C55:[gid13=0+1184|gid6=0+0|gid1=1+580|gid13=1+1184|gid5=1+0|gid13=1+1184|gid12=1+0]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C47,U+0020,U+0C46,U+0C55:[gid13=0+1184|gid8=0+0|gid1=1+580|gid13=1+1184|gid7=1+0|gid13=1+1184|gid12=1+0]
+../fonts/03e3f463c3a985bc42096620cc415342818454fb.ttf::U+0C4B,U+0020,U+0C4A,U+0C55:[gid13=0+1184|gid10=0+634|gid1=1+580|gid13=1+1184|gid9=1+634|gid13=1+1184|gid12=1+0]
+../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0C8A,U+0020,U+0C89,U+0CBE:[gid3=0+3269|gid1=1+590|gid2=2+2502|gid10=2+1184|gid7=2+919]
+../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0C94,U+0020,U+0C92,U+0CCC:[gid6=0+1596|gid1=1+590|gid5=2+1590|gid10=2+1184|gid8=2+880]
+../fonts/7d18685e1529e4ceaad5b6095dfab2f9789e5bce.ttf::U+0CE0,U+0020,U+0C8B,U+0CBE:[gid9=0+3214|gid1=1+590|gid4=2+2440|gid10=2+1184|gid7=2+919]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D08,U+0020,U+0D07,U+0D57:[gid3=0+3574|gid1=1+632|gid2=2+2019|gid14=2+1184|gid13=2+1555]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D0A,U+0020,U+0D09,U+0D57:[gid5=0+2972|gid1=1+632|gid4=2+1417|gid14=2+1184|gid13=2+1555]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D10,U+0020,U+0D0E,U+0D46:[gid7=0+4073|gid1=1+632|gid6=2+2608|gid12=2+1465|gid14=2+1184]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D13,U+0020,U+0D12,U+0D3E:[gid9=0+2557|gid1=1+632|gid8=2+1524|gid14=2+1184|gid11=2+1033]
+../fonts/af85624080af5627fb050f570d148a62f04fda74.ttf::U+0D14,U+0020,U+0D12,U+0D57:[gid10=0+3073|gid1=1+632|gid8=2+1524|gid14=2+1184|gid13=2+1555]
diff --git a/test/shaping/data/in-house/tests/khmer-mark-order.tests b/test/shaping/data/in-house/tests/khmer-mark-order.tests
new file mode 100644
index 000000000..d581dd15b
--- /dev/null
+++ b/test/shaping/data/in-house/tests/khmer-mark-order.tests
@@ -0,0 +1,25 @@
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni1794=3+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17C1,U+17B8,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17C1,U+17BB,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17C1,U+17B8,U+17BB,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17C1,U+17BB,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17BB=0@-20,-26+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=6+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17BE,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17C9,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17C9=0@-32,-29+0|uni17B8=0@-32,237+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17BE,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17CA,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17BB=0@-6,-26+0|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=5+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17BE,U+17B8,U+17BB,U+1794:[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17BE,U+17BB,U+17B8,U+1794:[uni17C1=0+288|uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17B8=0@-20,-84+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17B8,U+17BE,U+17BB,U+1794:[uni179F=0+928|uni17B8=0@-32,-29+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni1794=4+635]
+../fonts/b6031119874ae9ff1dd65383a335e361c0962220.ttf::U+179F,U+17B8,U+17BB,U+17BE,U+1794:[uni179F=0+928|uni17B8=0@-32,-29+0|uni25CC=0+635|uni17BB=0@-20,-26+0|uni17C1=0+288|uni25CC=0+635|uni17B8=0@-20,-84+0|uni1794=4+635]
diff --git a/test/shaping/data/in-house/tests/language-tags.tests b/test/shaping/data/in-house/tests/language-tags.tests
index 4c62113f4..c7be1802b 100644
--- a/test/shaping/data/in-house/tests/language-tags.tests
+++ b/test/shaping/data/in-house/tests/language-tags.tests
@@ -10,3 +10,4 @@
../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-HK:U+004A:[gid6=0+1000]
../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-mo:U+004A:[gid6=0+1000]
../fonts/6991b13ce889466be6de3f66e891de2bc0f117ee.ttf:--language=zh-Hant-mo:U+004A:[gid6=0+1000]
+../fonts/d3129450fafe5e5c98cfc25a4e71809b1b4d2855.ttf:--language=dv --no-glyph-names:U+007C:[2=0+156]
diff --git a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests b/test/shaping/data/in-house/tests/mongolian-variation-selector.tests
index efb4cf4eb..c5e35c890 100644
--- a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests
+++ b/test/shaping/data/in-house/tests/mongolian-variation-selector.tests
@@ -1,4 +1,19 @@
../fonts/37033cc5cf37bb223d7355153016b6ccece93b28.ttf::U+1826,U+180B,U+1826:[uni1826.E85E_ue.init1=0+599|uni1826.E856_ue.fina=2+750]
../fonts/ef86fe710cfea877bbe0dbb6946a1f88d0661031.ttf::U+1820,U+180B:[uni1820.E821_a.isol1=0+1199]
-../fonts/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=19+0|space=22+500|uni182D.E8E2_g.init=23+1000|space=23+0|uni182D.E8E5_g.medi1=25+800|space=25+0|space=28+500|uni182D.EA1D_g.init2=29+950|space=29+0|space=32+500|uni182D.EA1E_g.init3=33+650|space=33+0|space=36+500|space=36+0|uni182D.E8E4_g.medi=38+800|space=38+0|space=38+0|uni182D.E8E5_g.medi1=41+800|space=41+0|space=44+500|space=44+0|uni182D.E8E6_g.medi2=46+650|space=46+0|space=49+500|space=49+0|uni182D.E8E6_g.medi2=51+650|space=51+0|space=54+500|space=54+0|uni182D.E8E4_g.medi=56+800|space=56+0|uni182D.E8E8_g.fina1=58+1250|space=60+500|space=60+0|uni182D.E8E9_g.fina2=62+1050|space=64+500|uni1820.E820_a.isol=65+1550|space=65+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=73+0|space=73+0|uni182D.E8E5_g.medi1=76+800|uni1820.E823_a.medi=77+400|space=77+0|space=79+500|space=79+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]
../fonts/a34a7b00f22ffb5fd7eef6933b81c7e71bc2cdfb.ttf::U+180A,U+1868,U+180A,U+1868,U+180B,U+180A,U+1868,U+180C,U+180A,U+1868,U+180D,U+180A:[gid1=0+268|gid10=1+778|gid1=2+268|gid9=3+575|gid1=5+268|gid10=6+778|gid1=8+268|gid8=9+575|gid1=11+268]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+183A,U+1823,U+182E,U+182B,U+1822,U+1826,U+180B,U+1832,U+180B,U+1827,U+1837:[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]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+182D,U+180B:[uni182D.E8E2_g.init=0+1000|uni182D.E8E8_g.fina1=1+1250]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180C:[uni182D.EA1B_g.isol2=0+1000]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180D,U+200D:[uni182D.EA1E_g.init3=0+650|space=0+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+200D,U+182D,U+180B,U+200D:[uni182D.E8E2_g.init=0+1000|space=0+0|uni182D.E8E5_g.medi1=2+800|space=2+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180C,U+200D:[uni182D.EA1D_g.init2=0+950|space=0+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182D,U+180D,U+200D:[uni182D.EA1E_g.init3=0+650|space=0+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+200D,U+200D,U+182D,U+180B,U+200D:[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|space=1+0|uni182D.E8E5_g.medi1=4+800|space=4+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180C,U+200D:[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180D,U+200D:[space=0+0|uni182D.E8E6_g.medi2=1+650|space=1+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+200D,U+182D,U+180B:[space=0+0|uni182D.E8E4_g.medi=1+800|space=1+0|uni182D.E8E8_g.fina1=3+1250]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+180C:[space=0+0|uni182D.E8E9_g.fina2=1+1050]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1820,U+200C,U+182D,U+1820,U+1837:[uni1820.E820_a.isol=0+1550|space=1+0|uni182D.E8E2_g.init=2+1000|uni1820.E823_a.medi=3+400|uni1837.E931_r.fina=4+750]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D:[uni1830.E90B_s.init=0+850|uni1824.E844_u.medi=1+600|uni1837.E930_r.medi=2+600|space=2+0|space=2+0|uni182D.E8E5_g.medi1=5+800|uni1820.E823_a.medi=6+400|space=6+0]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+1824,U+182F,U+1822:[space=0+0|uni182D.E8E5_g.medi1=1+800|uni1824.E844_u.medi=2+600|uni182F.E908_l.medi=3+400|uni1822.E837_i.fina=4+600]
+../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni182A1820.E875_ba.init=0+1000|uni1822.E836_i.medi2=2+1000|uni182D.E8E8_g.fina1=3+1250|space=4+0|uni1820.E827_a.fina2=5+600|uni202F.nobreak=6+500|uni1836.E92B_y.init1=7+500|uni1822.E834_i.medi=8+500|uni1828.E866_n.fina=9+850]
diff --git a/test/shaping/data/in-house/tests/myanmar-zawgyi.tests b/test/shaping/data/in-house/tests/myanmar-zawgyi.tests
new file mode 100644
index 000000000..b79d4fb40
--- /dev/null
+++ b/test/shaping/data/in-house/tests/myanmar-zawgyi.tests
@@ -0,0 +1 @@
+../fonts/ab14b4eb9d7a67e293f51d30d719add06c9d6e06.ttf:--script=Qaag:U+1000,U+103A,U+1004,U+1037,U+1039,U+1041:[Ka=0+2217|Ya-Semivowel=0+286|Nga=2+1247|Dot Below=2+0|Virama-Killer=2+0|One-Myanmar=5+1247]
diff --git a/test/shaping/data/in-house/tests/rand.tests b/test/shaping/data/in-house/tests/rand.tests
new file mode 100644
index 000000000..df324b921
--- /dev/null
+++ b/test/shaping/data/in-house/tests/rand.tests
@@ -0,0 +1,3 @@
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=-rand:U+0054,U+0055,U+0056:[1=0+560|2=1+602|3=2+602]
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names --features=rand=2:U+0054,U+0055,U+0056:[5=0+560|8=1+602|11=2+602]
+../fonts/5bb74492f5e0ffa1fbb72e4c881be035120b6513.ttf:--no-glyph-names:U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056,U+0054,U+0055,U+0056:[5=0+560|7=1+602|10=2+602|4=3+560|7=4+602|10=5+602|6=6+560|9=7+602|10=8+602|5=9+560|8=10+602|12=11+602]
diff --git a/test/shaping/data/in-house/tests/use-indic3.tests b/test/shaping/data/in-house/tests/use-indic3.tests
new file mode 100644
index 000000000..8c3ae1398
--- /dev/null
+++ b/test/shaping/data/in-house/tests/use-indic3.tests
@@ -0,0 +1 @@
+../fonts/3c96e7a303c58475a8c750bf4289bbe73784f37d.ttf::U+0C95,U+0CCD,U+0CB0:[uni0C95=0+1176|uni0CB0_uni0CCD.blwf=0+275]
diff --git a/test/shaping/data/in-house/tests/use-syllable.tests b/test/shaping/data/in-house/tests/use-syllable.tests
index 5d2fab39c..d8f1dff14 100644
--- a/test/shaping/data/in-house/tests/use-syllable.tests
+++ b/test/shaping/data/in-house/tests/use-syllable.tests
@@ -6,3 +6,6 @@
../fonts/373e67bf41ca264e260a9716162b71a23549e885.ttf:--no-glyph-names:U+A8AC,U+A8B4,U+A8B5:[2=0+377|3=0+242|4=0+210]
../fonts/59a585a63b3df608fbeef00956c8c108deec7de6.ttf:--no-glyph-names:U+1BC7,U+1BEA,U+1BF3:[1=0+749|2=0+402|4=0+535|3=0+401]
../fonts/1ed7e9064f008f62de6ff0207bb4dd29409597a5.ttf::U+11064,U+1107F,U+11052,U+11065,U+1107F,U+11053:[brm_num100.1=0+2224|brm_num1000.2=3+1834]
+../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+11042,U+11046:[brm_KA=0+754|brm_vowelEE=0@-383,0+0|brm_virama=0@-524,0+0]
+../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+11044,U+11046:[brm_KA=0+754|brm_vowelOO=0@-647,0+0|brm_virama=0@-524,0+0]
+../fonts/28f497629c04ceb15546c9a70e0730125ed6698d.ttf::U+11013,U+1103C:[brm_KA=0+754|brm_vowelU=0@-403,0+0]
diff --git a/test/shaping/data/in-house/tests/vertical.tests b/test/shaping/data/in-house/tests/vertical.tests
index 17df28e6a..b18119225 100644
--- a/test/shaping/data/in-house/tests/vertical.tests
+++ b/test/shaping/data/in-house/tests/vertical.tests
@@ -1,3 +1,3 @@
../fonts/191826b9643e3f124d865d617ae609db6a2ce203.ttf:--direction=t --font-funcs=ft:U+300C:[uni300C.vert=0@-512,-578+0,-1024]
../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ft:U+0041,U+0042:[gid1=0@-654,-2128+0,-2789|gid2=1@-665,-2125+0,-2789]
-../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ot:U+0041,U+0042:[gid1=0@-654,-2189+0,-2789|gid2=1@-665,-2189+0,-2789]
+../fonts/f9b1dd4dcb515e757789a22cb4241107746fd3d0.ttf:--direction=t --font-funcs=ot:U+0041,U+0042:[gid1=0@-654,-1468+0,-2048|gid2=1@-665,-1462+0,-2048]
diff --git a/test/shaping/data/text-rendering-tests/DISABLED b/test/shaping/data/text-rendering-tests/DISABLED
index 58de258f8..ef987a4df 100644
--- a/test/shaping/data/text-rendering-tests/DISABLED
+++ b/test/shaping/data/text-rendering-tests/DISABLED
@@ -1,34 +1,8 @@
+tests/MORX-41.tests
+
# Non-Unicode cmap
tests/CMAP-3.tests
-# Not hooked up
-tests/MORX-1.tests
-tests/MORX-2.tests
-tests/MORX-3.tests
-tests/MORX-4.tests
-tests/MORX-5.tests
-tests/MORX-6.tests
-tests/MORX-7.tests
-tests/MORX-8.tests
-tests/MORX-9.tests
-tests/MORX-10.tests
-tests/MORX-11.tests
-tests/MORX-12.tests
-tests/MORX-13.tests
-tests/MORX-14.tests
-tests/MORX-16.tests
-tests/MORX-17.tests
-tests/MORX-18.tests
-tests/MORX-19.tests
-tests/MORX-20.tests
-tests/MORX-21.tests
-tests/MORX-22.tests
-tests/MORX-23.tests
-tests/MORX-25.tests
-tests/MORX-26.tests
-tests/MORX-27.tests
-tests/MORX-28.tests
-
# Rounding differences
tests/SHARAN-1.tests
tests/SHBALI-1.tests
diff --git a/test/shaping/data/text-rendering-tests/Makefile.sources b/test/shaping/data/text-rendering-tests/Makefile.sources
index 4be9d05d7..5e0db6bd8 100644
--- a/test/shaping/data/text-rendering-tests/Makefile.sources
+++ b/test/shaping/data/text-rendering-tests/Makefile.sources
@@ -15,6 +15,7 @@ TESTS = \
tests/GPOS-5.tests \
tests/GSUB-1.tests \
tests/GSUB-2.tests \
+ tests/GSUB-3.tests \
tests/GVAR-1.tests \
tests/GVAR-2.tests \
tests/GVAR-3.tests \
@@ -28,12 +29,6 @@ TESTS = \
tests/HVAR-2.tests \
tests/KERN-1.tests \
tests/KERN-2.tests \
- tests/SHBALI-3.tests \
- tests/SHKNDA-1.tests \
- $(NULL)
-
-DISBALED_TESTS = \
- tests/CMAP-3.tests \
tests/MORX-10.tests \
tests/MORX-11.tests \
tests/MORX-12.tests \
@@ -48,18 +43,38 @@ DISBALED_TESTS = \
tests/MORX-21.tests \
tests/MORX-22.tests \
tests/MORX-23.tests \
+ tests/MORX-24.tests \
tests/MORX-25.tests \
tests/MORX-26.tests \
tests/MORX-27.tests \
tests/MORX-28.tests \
+ tests/MORX-29.tests \
tests/MORX-2.tests \
+ tests/MORX-30.tests \
+ tests/MORX-31.tests \
+ tests/MORX-32.tests \
+ tests/MORX-33.tests \
+ tests/MORX-34.tests \
+ tests/MORX-35.tests \
+ tests/MORX-36.tests \
+ tests/MORX-37.tests \
+ tests/MORX-38.tests \
+ tests/MORX-39.tests \
tests/MORX-3.tests \
+ tests/MORX-40.tests \
tests/MORX-4.tests \
tests/MORX-5.tests \
tests/MORX-6.tests \
tests/MORX-7.tests \
tests/MORX-8.tests \
tests/MORX-9.tests \
+ tests/SHBALI-3.tests \
+ tests/SHKNDA-1.tests \
+ $(NULL)
+
+DISBALED_TESTS = \
+ tests/MORX-41.tests \
+ tests/CMAP-3.tests \
tests/SHARAN-1.tests \
tests/SHBALI-1.tests \
tests/SHBALI-2.tests \
diff --git a/test/shaping/data/text-rendering-tests/extract-tests.py b/test/shaping/data/text-rendering-tests/extract-tests.py
index 36963e5e1..27d568615 100755
--- a/test/shaping/data/text-rendering-tests/extract-tests.py
+++ b/test/shaping/data/text-rendering-tests/extract-tests.py
@@ -28,12 +28,13 @@ def glyphstr(glyphs):
html = ET.fromstring(sys.stdin.read())
found = False
+
for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces):
found = True
name = elt.get(ns('ft:id'))
text = elt.get(ns('ft:render'))
font = elt.get(ns('ft:font'))
- vars = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
+ variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
glyphs = []
for use in elt.findall(".//use"):
x = int(use.get('x'))
@@ -43,8 +44,19 @@ for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces):
glyphname = '.'.join(href[1:].split('/')[1].split('.')[1:])
glyphs.append((glyphname, x, y))
opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft'
- if vars:
- opts = opts + ' --variations=%s' % vars
+ if variations:
+ opts = opts + ' --variations=%s' % variations
print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs)))
+for elt in html.findall(".//*[@class='should-not-crash'][@ft:id]", namespaces):
+ found = True
+ name = elt.get(ns('ft:id'))
+ text = elt.get(ns('ft:render'))
+ font = elt.get(ns('ft:font'))
+ variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',')
+ opts = ''
+ if variations:
+ opts = '--variations=%s' % variations
+ print ("../fonts/%s:%s:%s:*" % (font, opts, unistr(text)))
+
sys.exit(0 if found else 1)
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf
new file mode 100644
index 000000000..8fce4ac4d
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf
new file mode 100644
index 000000000..37d0b6377
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf
new file mode 100644
index 000000000..98ebe3329
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf
new file mode 100644
index 000000000..29a41d0a3
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf
new file mode 100644
index 000000000..f15706317
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf
new file mode 100644
index 000000000..a70dadccf
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf
new file mode 100644
index 000000000..c106ae945
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf
new file mode 100644
index 000000000..c64c12c06
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf
new file mode 100644
index 000000000..22057f18c
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf
new file mode 100644
index 000000000..6676e5274
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf
new file mode 100644
index 000000000..5cab73e5a
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf
new file mode 100644
index 000000000..07ed76c1b
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf
new file mode 100644
index 000000000..271dddb01
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf
new file mode 100644
index 000000000..9f015ca59
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf
Binary files differ
diff --git a/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests b/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests
new file mode 100644
index 000000000..c2f7e6ef2
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/GSUB-3.tests
@@ -0,0 +1 @@
+../fonts/TestGSUBThree.ttf::U+006C,U+006F,U+006C:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-24.tests b/test/shaping/data/text-rendering-tests/tests/MORX-24.tests
new file mode 100644
index 000000000..79a3d7bb1
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-24.tests
@@ -0,0 +1 @@
+../fonts/TestMORXTwentyfour.ttf::U+0041,U+0042,U+0043,U+0044,U+0045:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-29.tests b/test/shaping/data/text-rendering-tests/tests/MORX-29.tests
new file mode 100644
index 000000000..82fd96300
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-29.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|I@4268,0|N@5098,0|S@5928,0|M@6758,0|Y@7588,0|Y@7920,0|A@8252,0|Z@9082,0|Z@9404,0]
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|I@5098,0|N@5928,0|S@6758,0|Y@7588,0|Y@7920,0|B@8252,0|Z@9082,0|Z@9404,0]
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0043,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|I@5762,0|N@6592,0|S@7422,0|C@8252,0|Z@9082,0|Z@9404,0]
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+004D,U+004D,U+0059,U+0059,U+0044,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|X@2710,0|X@3074,0|M@3438,0|M@4268,0|Y@5098,0|Y@5430,0|D@5762,0|I@6592,0|N@7422,0|S@8252,0|Z@9082,0|Z@9404,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-30.tests b/test/shaping/data/text-rendering-tests/tests/MORX-30.tests
new file mode 100644
index 000000000..ad4ab2170
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-30.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|I@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0]
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|I@2710,0|N@3540,0|S@4370,0|N@5200,0|S@6030,0|M@6860,0|X@7690,0|X@8054,0|X@8418,0|A@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0]
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|I@1880,0|N@2710,0|S@3540,0|M@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|A@10276,0|Z@11106,0|Z@11428,0]
+../fonts/TestMORXTwentynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0050,U+0051,U+0052,U+004D,U+004D,U+0058,U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A:[P|Q@333,0|R@699,0|M@1050,0|M@1880,0|I@2710,0|N@3540,0|S@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|X@8054,0|X@8418,0|B@8782,0|Y@9612,0|Y@9944,0|B@10276,0|Z@11106,0|Z@11428,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-31.tests b/test/shaping/data/text-rendering-tests/tests/MORX-31.tests
new file mode 100644
index 000000000..6cc40b6e1
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-31.tests
@@ -0,0 +1,8 @@
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0041,U+0059,U+0059,U+0041,U+005A,U+005A:[X|X@364,0|I@728,0|N@1558,0|S@2388,0|A@3218,0|Y@4048,0|Y@4380,0|A@4712,0|Z@5542,0|Z@5864,0]
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0041,U+0059,U+0059,U+0042,U+0059,U+0059:[X|X@364,0|A@728,0|I@1558,0|N@2388,0|S@3218,0|Y@4048,0|Y@4380,0|B@4712,0|Y@5542,0|Y@5874,0]
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0042,U+0059,U+0059,U+0041,U+005A,U+005A:[X|X@364,0|I@728,0|N@1558,0|S@2388,0|B@3218,0|Y@4048,0|Y@4380,0|A@4712,0|Z@5542,0|Z@5864,0]
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0058,U+0042,U+0059,U+0059,U+0042,U+005A,U+005A:[X|X@364,0|B@728,0|I@1558,0|N@2388,0|S@3218,0|Y@4048,0|Y@4380,0|B@4712,0|Z@5542,0|Z@5864,0]
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0041:[I|N@830,0|S@1660,0|M@2490,0|P@3320,0|Q@3653,0|R@4019,0|I@4370,0|N@5200,0|S@6030,0|A@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0]
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0041,U+0058,U+0059,U+005A,U+0042:[I|N@830,0|S@1660,0|M@2490,0|P@3320,0|Q@3653,0|R@4019,0|A@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0]
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0041:[M|I@830,0|N@1660,0|S@2490,0|P@3320,0|Q@3653,0|R@4019,0|I@4370,0|N@5200,0|S@6030,0|B@6860,0|X@7690,0|Y@8054,0|Z@8386,0|A@8708,0]
+../fonts/TestMORXThirtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+004D,U+0050,U+0051,U+0052,U+0042,U+0058,U+0059,U+005A,U+0042:[M|I@830,0|N@1660,0|S@2490,0|P@3320,0|Q@3653,0|R@4019,0|B@4370,0|I@5200,0|N@6030,0|S@6860,0|X@7690,0|Y@8054,0|Z@8386,0|B@8708,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-32.tests b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
new file mode 100644
index 000000000..87c115252
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-32.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@364,0|Y@1194,0]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B]
+../fonts/TestMORXThirtytwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0042,U+0059:[X|B@364,0|Y@1194,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-33.tests b/test/shaping/data/text-rendering-tests/tests/MORX-33.tests
new file mode 100644
index 000000000..17d080a60
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-33.tests
@@ -0,0 +1,3 @@
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0]
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0068,U+0061,U+0068,U+0061:[h|a@618,0|h@1179,0|a@1797,0|h@2358,0|a@2976,0|h@3537,0|a@4155,0]
+../fonts/TestMORXThirtythree.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0068:[a|h@561,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-34.tests b/test/shaping/data/text-rendering-tests/tests/MORX-34.tests
new file mode 100644
index 000000000..8c309df84
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-34.tests
@@ -0,0 +1 @@
+../fonts/TestMORXThirtyfour.ttf::U+0068,U+0061:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-35.tests b/test/shaping/data/text-rendering-tests/tests/MORX-35.tests
new file mode 100644
index 000000000..a0331852e
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-35.tests
@@ -0,0 +1,2 @@
+../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A|B@639,0|C@1265,0|E@1861,0]
+../fonts/TestMORXThirtyfive.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0058,U+0041,U+0059:[X|A@586,0|B@1225,0|C@1851,0|E@2447,0|Y@3003,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-36.tests b/test/shaping/data/text-rendering-tests/tests/MORX-36.tests
new file mode 100644
index 000000000..6b2340e6d
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-36.tests
@@ -0,0 +1 @@
+../fonts/TestMORXThirtysix.ttf::U+0041:*
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-37.tests b/test/shaping/data/text-rendering-tests/tests/MORX-37.tests
new file mode 100644
index 000000000..f28c5e2aa
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-37.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A.alt|B.alt@1000,0]
+../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B|A@650,0]
+../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1|uni05D0@542,0]
+../fonts/TestMORXThirtyseven.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0.alt|uni05D1.alt@1000,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-38.tests b/test/shaping/data/text-rendering-tests/tests/MORX-38.tests
new file mode 100644
index 000000000..abefe29b4
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-38.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A.alt|B.alt@1000,0]
+../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B|A@650,0]
+../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1.alt|uni05D0.alt@1000,0]
+../fonts/TestMORXThirtyeight.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0|uni05D1@606,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-39.tests b/test/shaping/data/text-rendering-tests/tests/MORX-39.tests
new file mode 100644
index 000000000..83bfa52b9
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-39.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A|B@639,0]
+../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B.alt|A.alt@1000,0]
+../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1.alt|uni05D0.alt@1000,0]
+../fonts/TestMORXThirtynine.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0|uni05D1@606,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-40.tests b/test/shaping/data/text-rendering-tests/tests/MORX-40.tests
new file mode 100644
index 000000000..c99155e2a
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-40.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041,U+0042:[A|B@639,0]
+../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042,U+0041:[B.alt|A.alt@1000,0]
+../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D0,U+05D1:[uni05D1|uni05D0@542,0]
+../fonts/TestMORXForty.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+05D1,U+05D0:[uni05D0.alt|uni05D1.alt@1000,0]
diff --git a/test/shaping/data/text-rendering-tests/tests/MORX-41.tests b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
new file mode 100644
index 000000000..84dca89ae
--- /dev/null
+++ b/test/shaping/data/text-rendering-tests/tests/MORX-41.tests
@@ -0,0 +1,4 @@
+../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0063:[a_c]
+../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0062,U+0063:[b_c]
+../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0063,U+0063:[c]
+../fonts/TestMORXFourtyone.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0061,U+0062,U+0063,U+0063:[a|b_c@561,0|c@1631,0]
diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py
index 8348dc269..c9a44033b 100644
--- a/test/shaping/hb_test_tools.py
+++ b/test/shaping/hb_test_tools.py
@@ -4,6 +4,10 @@ from __future__ import print_function, division, absolute_import
import sys, os, re, difflib, unicodedata, errno, cgi
from itertools import *
+try:
+ import unicodedata2 as unicodedata
+except Exception:
+ pass
diff_symbols = "-+=*&^%$#@!~/"
diff_colors = ['red', 'green', 'blue']
diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh
index 93ebcfc99..4ab74f0f9 100755
--- a/test/shaping/record-test.sh
+++ b/test/shaping/record-test.sh
@@ -3,8 +3,9 @@
dir=`mktemp -d`
out=/dev/stdout
-if test "x${1:0:3}" == 'x-o='; then
- out=${1:3}
+if test "x$1" == 'x-o'; then
+ shift
+ out=$1
shift
fi
hb_shape=$1
diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py
index 73b61c21a..f77a17c3d 100755
--- a/test/shaping/run-tests.py
+++ b/test/shaping/run-tests.py
@@ -2,16 +2,16 @@
from __future__ import print_function, division, absolute_import
-import sys, os, subprocess
+import sys, os, subprocess, tempfile
def cmd(command):
- p = subprocess.Popen (
- command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- p.wait ()
- print (p.stderr.read (), end="") # file=sys.stderr
- return p.stdout.read ().decode ("utf-8").strip (), p.returncode
-
+ # https://stackoverflow.com/a/4408409
+ with tempfile.TemporaryFile() as tempf:
+ p = subprocess.Popen (command, stdout=tempf, stderr=sys.stdout)
+ p.wait ()
+ tempf.seek(0)
+ return tempf.read().decode ("utf-8").strip (), p.returncode
args = sys.argv[1:]
if not args or sys.argv[1].find('hb-shape') == -1 or not os.path.exists (sys.argv[1]):
@@ -19,8 +19,6 @@ if not args or sys.argv[1].find('hb-shape') == -1 or not os.path.exists (sys.arg
sys.exit (1)
hb_shape, args = args[0], args[1:]
-extra_options = "--verify"
-
fails = 0
reference = False
@@ -48,6 +46,11 @@ for filename in args:
cwd = os.path.dirname(filename)
fontfile = os.path.normpath (os.path.join (cwd, fontfile))
+ extra_options = ["--shaper=ot"]
+ glyphs_expected = glyphs_expected.strip()
+ if glyphs_expected != '*':
+ extra_options.append("--verify")
+
if line.startswith ("#"):
if not reference:
print ("# %s %s --unicodes %s" % (hb_shape, fontfile, unicodes))
@@ -55,19 +58,19 @@ for filename in args:
if not reference:
print ("%s %s %s %s --unicodes %s" %
- (hb_shape, fontfile, extra_options, options, unicodes))
+ (hb_shape, fontfile, ' '.join(extra_options), options, unicodes))
glyphs1, returncode = cmd ([hb_shape, "--font-funcs=ft",
- fontfile, extra_options, "--unicodes",
+ fontfile] + extra_options + ["--unicodes",
unicodes] + (options.split (' ') if options else []))
if returncode:
- print ("hb-shape --font-funcs=ft failed.") # file=sys.stderr
+ print ("ERROR: hb-shape --font-funcs=ft failed.") # file=sys.stderr
fails = fails + 1
#continue
glyphs2, returncode = cmd ([hb_shape, "--font-funcs=ot",
- fontfile, extra_options, "--unicodes",
+ fontfile] + extra_options + ["--unicodes",
unicodes] + (options.split (' ') if options else []))
if returncode:
@@ -75,7 +78,7 @@ for filename in args:
fails = fails + 1
#continue
- if glyphs1 != glyphs2:
+ if glyphs1 != glyphs2 and glyphs_expected != '*':
print ("FT funcs: " + glyphs1) # file=sys.stderr
print ("OT funcs: " + glyphs2) # file=sys.stderr
fails = fails + 1
@@ -84,7 +87,7 @@ for filename in args:
print (":".join ([fontfile, options, unicodes, glyphs1]))
continue
- if glyphs1.strip() != glyphs_expected.strip():
+ if glyphs1.strip() != glyphs_expected and glyphs_expected != '*':
print ("Actual: " + glyphs1) # file=sys.stderr
print ("Expected: " + glyphs_expected) # file=sys.stderr
fails = fails + 1
diff --git a/test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt
new file mode 100644
index 000000000..f09dbc8f5
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-bengali/bengali-vowel-letters.txt
@@ -0,0 +1,3 @@
+আ অা
+ৠ ঋৃ
+ৡ ঌৢ
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt
new file mode 100644
index 000000000..426543658
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-atomic-consonants.txt
@@ -0,0 +1,33 @@
+ख ख्ा ख्‍ा
+ग ग्ा ग्‍ा
+घ घ्ा घ्‍ा
+च च्ा च्‍ा
+ज ज्ा ज्‍ा
+झ झ्ा झ्‍ा
+ञ ञ्ा ञ्‍ा
+ण ण्ा ण्‍ा
+त त्ा त्‍ा
+थ थ्ा थ्‍ा
+ध ध्ा ध्‍ा
+न न्ा न्‍ा
+ऩ ऩ्ा ऩ्‍ा ऩ्ा ऩ्‍ा
+प प्ा प्‍ा
+ब ब्ा ब्‍ा
+भ भ्ा भ्‍ा
+म म्ा म्‍ा
+य य्ा य्‍ा
+ल ल्ा ल्‍ा
+व व्ा व्‍ा
+श श्ा श्‍ा
+ष ष्ा ष्‍ा
+स स्ा स्‍ा
+ख़ ख़्ा ख़्‍ा ख़्ा ख़्‍ा
+ग़ ग़्ा ग़्‍ा ग़्ा ग़्‍ा
+ज़ ज़्ा ज़्‍ा ज़्ा ज़्‍ा
+य़ य़्ा य़्‍ा य़्ा य़्‍ा
+ॹ ॹ्ा ॹ्‍ा
+ॺ ॺ्ा ॺ्‍ा
+ज़ ॻ्ा ॻ्‍ा
+ॼ ॼ्ा ॼ्‍ा
+ॾ ॾ्ा ॾ्‍ा
+ॿ ॿ्ा ॿ्‍ा
diff --git a/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt
new file mode 100644
index 000000000..5a41252f2
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-devanagari/devanagari-vowel-letters.txt
@@ -0,0 +1,17 @@
+ऄ अॆ
+आ अा
+ई र्इ
+ऊ उु
+ऍ एॅ
+ऎ एॆ
+ऐ एे
+ऑ अॉ आॅ
+ऒ अॊ आॆ
+ओ अो आे
+औ अौ आै
+ॲ अॅ
+ॳ अऺ
+ॴ अऻ आऺ
+ॵ अॏ
+ॶ अॖ
+ॷ अॗ
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt
new file mode 100644
index 000000000..add4332b3
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-gujarati/gujarati-vowel-letters.txt
@@ -0,0 +1,8 @@
+આ અા
+ઍ અૅ
+એ અે
+ઐ અૈ
+ઑ અૉ
+ઓ અો અાૅ
+ઔ અૌ અાૈ
+ૉ ૅા
diff --git a/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt
new file mode 100644
index 000000000..b2adaabd2
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-gurmukhi/gurmukhi-vowel-letters.txt
@@ -0,0 +1,9 @@
+ਆ ਅਾ
+ਇ ੲਿ
+ਈ ੲੀ
+ਉ ੳੁ
+ਊ ੳੂ
+ਏ ੲੇ
+ਐ ਅੈ
+ਓ ੳੋ
+ਔ ਅੌ
diff --git a/test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt
new file mode 100644
index 000000000..cc05db93f
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-kannada/kannada-vowel-letters.txt
@@ -0,0 +1,3 @@
+ಊ ಉಾ
+ಔ ಒೌ
+ೠ ಋಾ
diff --git a/test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt
new file mode 100644
index 000000000..061c642f7
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-malayalam/malayalam-vowel-letters.txt
@@ -0,0 +1,5 @@
+ഈ ഇൗ
+ഊ ഉൗ
+ഐ എെ
+ഓ ഒാ
+ഔ ഒൗ
diff --git a/test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt
new file mode 100644
index 000000000..e8d24cb57
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-oriya/oriya-vowel-letters.txt
@@ -0,0 +1,3 @@
+ଆ ଅା
+ଐ ଏୗ
+ଔ ଓୗ
diff --git a/test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt b/test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt
new file mode 100644
index 000000000..c3cfc84cd
--- /dev/null
+++ b/test/shaping/texts/in-house/shaper-indic/script-telugu/telugu-vowel-letters.txt
@@ -0,0 +1,5 @@
+ఓ ఒౕ
+ఔ ఒౌ
+ీ ిౕ
+ే ెౕ
+ో ొౕ
diff --git a/test/subset/Makefile.am b/test/subset/Makefile.am
index 336d33dfb..1673cfbd1 100644
--- a/test/subset/Makefile.am
+++ b/test/subset/Makefile.am
@@ -7,7 +7,7 @@ SUBDIRS = data
# Convenience targets:
lib:
- @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
+ @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs
EXTRA_DIST += \
CMakeLists.txt \
diff --git a/util/Makefile.am b/util/Makefile.am
index d4ab9cdc5..85f9edaa0 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -47,17 +47,16 @@ hb_shape_SOURCES = $(HB_SHAPE_sources)
bin_PROGRAMS += hb-shape
hb_subset_SOURCES = $(HB_SUBSET_CLI_sources)
-hb_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la
+hb_subset_LDADD = \
+ $(LDADD) \
+ $(top_builddir)/src/libharfbuzz-subset.la
bin_PROGRAMS += hb-subset
-if HAVE_OT
hb_ot_shape_closure_SOURCES = $(HB_OT_SHAPE_CLOSURE_sources)
bin_PROGRAMS += hb-ot-shape-closure
-endif # HAVE_OT
endif # HAVE_GLIB
-#if HAVE_OT
#if HAVE_FONTCONFIG
#hb_fc_list_SOURCES = \
# hb-fc.cc \
@@ -70,6 +69,5 @@ endif # HAVE_GLIB
# $(NULL)
#bin_PROGRAMS += hb-fc-list
#endif # HAVE_FONTCONFIG
-#endif # HAVE_OT
-include $(top_srcdir)/git.mk
diff --git a/util/ansi-print.cc b/util/ansi-print.cc
index 0daee1f02..5e2845cf1 100644
--- a/util/ansi-print.cc
+++ b/util/ansi-print.cc
@@ -71,7 +71,7 @@ struct color_t
{
static color_t from_ansi (unsigned int x)
{
- color_t c = {(0xFF<<24) | ((0xFF*(x&1))<<16) | ((0xFF*((x >> 1)&1))<<8) | (0xFF*((x >> 2)&1))};
+ color_t c = {(0xFFu<<24) | ((0xFFu*(x&1))<<16) | ((0xFFu*((x >> 1)&1))<<8) | (0xFFu*((x >> 2)&1))};
return c;
}
unsigned int to_ansi (void)
@@ -223,7 +223,7 @@ struct biimage_t
uint8_t * const data;
};
-const char *
+static const char *
block_best (const biimage_t &bi, bool *inverse)
{
assert (bi.width <= CELL_W);
diff --git a/util/ansi-print.hh b/util/ansi-print.hh
index 1ea5b3742..9640d892d 100644
--- a/util/ansi-print.hh
+++ b/util/ansi-print.hh
@@ -27,8 +27,7 @@
#ifndef ANSI_PRINT_HH
#define ANSI_PRINT_HH
-#include "hb-private.hh"
-#include <hb.h> /* for int types */
+#include "hb.hh"
void
ansi_print_image_rgb24 (const uint32_t *data,
diff --git a/util/hb-subset.cc b/util/hb-subset.cc
index 20617554c..3f0963c3f 100644
--- a/util/hb-subset.cc
+++ b/util/hb-subset.cc
@@ -29,7 +29,6 @@
#include "main-font-text.hh"
#include "hb-subset.h"
-#include "hb-subset-private.hh"
/*
* Command line interface to the harfbuzz font subsetter.
@@ -90,19 +89,17 @@ struct subset_consumer_t
void finish (const font_options_t *font_opts)
{
- input->drop_hints = subset_options.drop_hints;
+ hb_subset_input_set_drop_hints (input, subset_options.drop_hints);
- hb_subset_profile_t *subset_profile = hb_subset_profile_create();
hb_face_t *face = hb_font_get_face (font);
- hb_face_t *new_face = hb_subset(face, subset_profile, input);
+ hb_face_t *new_face = hb_subset(face, input);
hb_blob_t *result = hb_face_reference_blob (new_face);
failed = !hb_blob_get_length (result);
if (!failed)
write_file (options.output_file, result);
- hb_subset_profile_destroy (subset_profile);
hb_subset_input_destroy (input);
hb_blob_destroy (result);
hb_face_destroy (new_face);
diff --git a/util/hb-view.cc b/util/hb-view.cc
index ef75e6da7..69a4c9504 100644
--- a/util/hb-view.cc
+++ b/util/hb-view.cc
@@ -30,7 +30,7 @@
#include "view-cairo.hh"
#define DEFAULT_FONT_SIZE 256
-#define SUBPIXEL_BITS 8
+#define SUBPIXEL_BITS 6
int
main (int argc, char **argv)
diff --git a/util/helper-cairo-ansi.hh b/util/helper-cairo-ansi.hh
index cf18ea495..bc2313219 100644
--- a/util/helper-cairo-ansi.hh
+++ b/util/helper-cairo-ansi.hh
@@ -27,7 +27,7 @@
#ifndef HELPER_CAIRO_ANSI_HH
#define HELPER_CAIRO_ANSI_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include <cairo.h>
diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc
index 3eaf90a74..7a698f30b 100644
--- a/util/helper-cairo.cc
+++ b/util/helper-cairo.cc
@@ -64,11 +64,13 @@ _cairo_eps_surface_create_for_stream (cairo_write_func_t write_func,
static FT_Library ft_library;
+#ifdef HAVE_ATEXIT
static inline
void free_ft_library (void)
{
FT_Done_FreeType (ft_library);
}
+#endif
cairo_scaled_font_t *
helper_cairo_create_scaled_font (const font_options_t *font_opts)
@@ -125,7 +127,7 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
}
#endif
- cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
+ cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, font_opts->ft_load_flags);
}
cairo_matrix_t ctm, font_matrix;
cairo_font_options_t *font_options;
diff --git a/util/helper-cairo.hh b/util/helper-cairo.hh
index 50bc0af09..1613ce427 100644
--- a/util/helper-cairo.hh
+++ b/util/helper-cairo.hh
@@ -27,7 +27,7 @@
#ifndef HELPER_CAIRO_HH
#define HELPER_CAIRO_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include "options.hh"
#include <cairo.h>
diff --git a/util/main-font-text.hh b/util/main-font-text.hh
index 3390371c5..01bd2d4d9 100644
--- a/util/main-font-text.hh
+++ b/util/main-font-text.hh
@@ -27,7 +27,7 @@
#ifndef HB_MAIN_FONT_TEXT_HH
#define HB_MAIN_FONT_TEXT_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include "options.hh"
/* main() body for utilities taking font and processing text.*/
diff --git a/util/options.cc b/util/options.cc
index 57cc4aa8d..5661cd059 100644
--- a/util/options.cc
+++ b/util/options.cc
@@ -29,11 +29,9 @@
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
-#ifdef HAVE_OT
#include <hb-ot.h>
-#endif
-struct supported_font_funcs_t {
+static struct supported_font_funcs_t {
char name[4];
void (*func) (hb_font_t *);
} supported_font_funcs[] =
@@ -41,9 +39,7 @@ struct supported_font_funcs_t {
#ifdef HAVE_FREETYPE
{"ft", hb_ft_font_set_funcs},
#endif
-#ifdef HAVE_OT
{"ot", hb_ot_font_set_funcs},
-#endif
};
@@ -172,9 +168,9 @@ parse_margin (const char *name G_GNUC_UNUSED,
view_options_t *view_opts = (view_options_t *) data;
view_options_t::margin_t &m = view_opts->margin;
switch (sscanf (arg, "%lf%*[ ,]%lf%*[ ,]%lf%*[ ,]%lf", &m.t, &m.r, &m.b, &m.l)) {
- case 1: m.r = m.t;
- case 2: m.b = m.t;
- case 3: m.l = m.r;
+ case 1: m.r = m.t; HB_FALLTHROUGH;
+ case 2: m.b = m.t; HB_FALLTHROUGH;
+ case 3: m.l = m.r; HB_FALLTHROUGH;
case 4: return true;
default:
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
@@ -415,11 +411,12 @@ shape_options_t::add_options (option_parser_t *parser)
{"eot", 0, 0, G_OPTION_ARG_NONE, &this->eot, "Treat text as end-of-paragraph", nullptr},
{"preserve-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->preserve_default_ignorables, "Preserve Default-Ignorable characters", nullptr},
{"remove-default-ignorables",0, 0, G_OPTION_ARG_NONE, &this->remove_default_ignorables, "Remove Default-Ignorable characters", nullptr},
+ {"invisible-glyph", 0, 0, G_OPTION_ARG_INT, &this->invisible_glyph, "Glyph value to replace Default-Ignorables with", nullptr},
{"utf8-clusters", 0, 0, G_OPTION_ARG_NONE, &this->utf8_clusters, "Use UTF8 byte indices, not char indices", nullptr},
{"cluster-level", 0, 0, G_OPTION_ARG_INT, &this->cluster_level, "Cluster merging level (default: 0)", "0/1/2"},
{"normalize-glyphs",0, 0, G_OPTION_ARG_NONE, &this->normalize_glyphs, "Rearrange glyph clusters in nominal order", nullptr},
{"verify", 0, 0, G_OPTION_ARG_NONE, &this->verify, "Perform sanity checks on shaping results", nullptr},
- {"num-iterations", 0, 0, G_OPTION_ARG_INT, &this->num_iterations, "Run shaper N times (default: 1)", "N"},
+ {"num-iterations", 'n', 0, G_OPTION_ARG_INT, &this->num_iterations, "Run shaper N times (default: 1)", "N"},
{nullptr}
};
parser->add_group (entries,
@@ -489,7 +486,7 @@ parse_font_size (const char *name G_GNUC_UNUSED,
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 1: font_opts->font_size_y = font_opts->font_size_x; HB_FALLTHROUGH;
case 2: return true;
default:
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
@@ -507,7 +504,7 @@ parse_font_ppem (const char *name G_GNUC_UNUSED,
{
font_options_t *font_opts = (font_options_t *) data;
switch (sscanf (arg, "%d%*[ ,]%d", &font_opts->x_ppem, &font_opts->y_ppem)) {
- case 1: font_opts->y_ppem = font_opts->x_ppem;
+ case 1: font_opts->y_ppem = font_opts->x_ppem; HB_FALLTHROUGH;
case 2: return true;
default:
g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
@@ -556,6 +553,7 @@ font_options_t::add_options (option_parser_t *parser)
{"font-ppem", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_ppem, "Set x,y pixels per EM (default: 0; disabled)", "1/2 integers"},
{"font-ptem", 0, 0, G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"},
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
+ {"ft-load-flags", 0, 0, G_OPTION_ARG_INT, &this->ft_load_flags, "Set FreeType load-flags (default: 2)", "integer"},
{nullptr}
};
parser->add_group (entries,
@@ -662,7 +660,7 @@ font_options_t::get_font (void) const
blob = hb_blob_create_from_file (font_path);
if (blob == hb_blob_get_empty ())
- fail (false, "No such file or directory");
+ fail (false, "Couldn't read or find %s, or it was empty.", font_path);
/* Create the face */
hb_face_t *face = hb_face_create (blob, face_index);
@@ -717,6 +715,9 @@ font_options_t::get_font (void) const
}
}
set_font_funcs (font);
+#ifdef HAVE_FREETYPE
+ hb_ft_font_set_load_flags (font, ft_load_flags);
+#endif
return font;
}
diff --git a/util/options.hh b/util/options.hh
index 2160d5ec3..dd628590e 100644
--- a/util/options.hh
+++ b/util/options.hh
@@ -27,7 +27,7 @@
#ifndef OPTIONS_HH
#define OPTIONS_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include <stdlib.h>
#include <stddef.h>
@@ -46,9 +46,7 @@
#endif
#include <hb.h>
-#ifdef HAVE_OT
#include <hb-ot.h>
-#endif
#include <glib.h>
#include <glib/gprintf.h>
@@ -56,16 +54,19 @@ void fail (hb_bool_t suggest_help, const char *format, ...) G_GNUC_NORETURN G_GN
struct option_group_t
{
+ virtual ~option_group_t (void) {}
+
virtual void add_options (struct option_parser_t *parser) = 0;
- virtual void pre_parse (GError **error G_GNUC_UNUSED) {};
- virtual void post_parse (GError **error G_GNUC_UNUSED) {};
+ virtual void pre_parse (GError **error G_GNUC_UNUSED) {}
+ virtual void post_parse (GError **error G_GNUC_UNUSED) {}
};
struct option_parser_t
{
- option_parser_t (const char *usage) {
+ option_parser_t (const char *usage)
+ {
memset (this, 0, sizeof (*this));
usage_str = usage;
context = g_option_context_new (usage);
@@ -73,7 +74,8 @@ struct option_parser_t
add_main_options ();
}
- ~option_parser_t (void) {
+ ~option_parser_t (void)
+ {
g_option_context_free (context);
g_ptr_array_foreach (to_free, (GFunc) g_free, nullptr);
g_ptr_array_free (to_free, TRUE);
@@ -113,7 +115,8 @@ struct option_parser_t
struct view_options_t : option_group_t
{
- view_options_t (option_parser_t *parser) {
+ view_options_t (option_parser_t *parser)
+ {
annotate = false;
fore = nullptr;
back = nullptr;
@@ -122,7 +125,7 @@ struct view_options_t : option_group_t
add_options (parser);
}
- ~view_options_t (void)
+ virtual ~view_options_t (void)
{
g_free (fore);
g_free (back);
@@ -150,6 +153,7 @@ struct shape_options_t : option_group_t
num_features = 0;
shapers = nullptr;
utf8_clusters = false;
+ invisible_glyph = 0;
cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT;
normalize_glyphs = false;
verify = false;
@@ -157,7 +161,7 @@ struct shape_options_t : option_group_t
add_options (parser);
}
- ~shape_options_t (void)
+ virtual ~shape_options_t (void)
{
g_free (direction);
g_free (language);
@@ -180,6 +184,7 @@ struct shape_options_t : option_group_t
(preserve_default_ignorables ? HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES : 0) |
(remove_default_ignorables ? HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES : 0) |
0));
+ hb_buffer_set_invisible_glyph (buffer, invisible_glyph);
hb_buffer_set_cluster_level (buffer, cluster_level);
hb_buffer_guess_segment_properties (buffer);
}
@@ -430,6 +435,7 @@ struct shape_options_t : option_group_t
unsigned int num_features;
char **shapers;
hb_bool_t utf8_clusters;
+ hb_codepoint_t invisible_glyph;
hb_buffer_cluster_level_t cluster_level;
hb_bool_t normalize_glyphs;
hb_bool_t verify;
@@ -454,13 +460,15 @@ struct font_options_t : option_group_t
face_index = 0;
font_size_x = font_size_y = default_font_size;
font_funcs = nullptr;
+ ft_load_flags = 2;
blob = nullptr;
font = nullptr;
add_options (parser);
}
- ~font_options_t (void) {
+ virtual ~font_options_t (void)
+ {
g_free (font_file);
free (variations);
g_free (font_funcs);
@@ -484,6 +492,7 @@ struct font_options_t : option_group_t
mutable double font_size_x;
mutable double font_size_y;
char *font_funcs;
+ int ft_load_flags;
private:
mutable hb_font_t *font;
@@ -492,7 +501,8 @@ struct font_options_t : option_group_t
struct text_options_t : option_group_t
{
- text_options_t (option_parser_t *parser) {
+ text_options_t (option_parser_t *parser)
+ {
text_before = nullptr;
text_after = nullptr;
@@ -506,7 +516,8 @@ struct text_options_t : option_group_t
add_options (parser);
}
- ~text_options_t (void) {
+ virtual ~text_options_t (void)
+ {
g_free (text_before);
g_free (text_after);
g_free (text);
@@ -544,7 +555,8 @@ struct text_options_t : option_group_t
struct output_options_t : option_group_t
{
output_options_t (option_parser_t *parser,
- const char **supported_formats_ = nullptr) {
+ const char **supported_formats_ = nullptr)
+ {
output_file = nullptr;
output_format = nullptr;
supported_formats = supported_formats_;
@@ -554,7 +566,8 @@ struct output_options_t : option_group_t
add_options (parser);
}
- ~output_options_t (void) {
+ virtual ~output_options_t (void)
+ {
g_free (output_file);
g_free (output_format);
if (fp)
@@ -573,7 +586,7 @@ struct output_options_t : option_group_t
if (output_format)
{
output_format++; /* skip the dot */
- output_format = strdup (output_format);
+ output_format = g_strdup (output_format);
}
}
diff --git a/util/shape-consumer.hh b/util/shape-consumer.hh
index fa419f185..da0d88033 100644
--- a/util/shape-consumer.hh
+++ b/util/shape-consumer.hh
@@ -27,7 +27,7 @@
#ifndef HB_SHAPE_CONSUMER_HH
#define HB_SHAPE_CONSUMER_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include "options.hh"
diff --git a/util/view-cairo.hh b/util/view-cairo.hh
index 00df68c29..5be3523ad 100644
--- a/util/view-cairo.hh
+++ b/util/view-cairo.hh
@@ -27,7 +27,7 @@
#ifndef VIEW_CAIRO_HH
#define VIEW_CAIRO_HH
-#include "hb-private.hh"
+#include "hb.hh"
#include "options.hh"
#include "helper-cairo.hh"
@@ -46,7 +46,7 @@ struct view_cairo_t
void init (hb_buffer_t *buffer, const font_options_t *font_opts)
{
lines = g_array_new (false, false, sizeof (helper_cairo_line_t));
- scale_bits = -font_opts->subpixel_bits;
+ scale_bits = - (int) font_opts->subpixel_bits;
}
void new_line (void)
{