summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am317
-rwxr-xr-xsrc/check-c-linkage-decls.sh12
-rwxr-xr-xsrc/check-defs.sh44
-rwxr-xr-xsrc/check-header-guards.sh4
-rwxr-xr-xsrc/check-includes.sh16
-rwxr-xr-xsrc/check-internal-symbols.sh34
-rwxr-xr-xsrc/check-libstdc++.sh16
-rwxr-xr-xsrc/check-static-inits.sh39
-rwxr-xr-xsrc/check-symbols.sh43
-rwxr-xr-xsrc/gen-arabic-table.py172
-rwxr-xr-xsrc/gen-indic-table.py90
-rw-r--r--src/harfbuzz-gobject.pc.in12
-rw-r--r--src/harfbuzz-icu.pc.in13
-rw-r--r--src/harfbuzz.pc.in11
-rw-r--r--src/hb-atomic-private.hh59
-rw-r--r--src/hb-blob.cc166
-rw-r--r--src/hb-blob.h27
-rw-r--r--src/hb-buffer-deserialize-json.rl132
-rw-r--r--src/hb-buffer-deserialize-text.rl126
-rw-r--r--src/hb-buffer-private.hh78
-rw-r--r--src/hb-buffer-serialize.cc399
-rw-r--r--src/hb-buffer.cc1085
-rw-r--r--src/hb-buffer.h172
-rw-r--r--src/hb-cache-private.hh2
-rw-r--r--src/hb-common.cc248
-rw-r--r--src/hb-common.h350
-rw-r--r--src/hb-coretext.cc1194
-rw-r--r--src/hb-coretext.h60
-rw-r--r--src/hb-deprecated.h (renamed from src/hb-version.h)37
-rw-r--r--src/hb-face-private.hh107
-rw-r--r--src/hb-face.cc481
-rw-r--r--src/hb-face.h117
-rw-r--r--src/hb-fallback-shape.cc116
-rw-r--r--src/hb-font-private.hh299
-rw-r--r--src/hb-font.cc930
-rw-r--r--src/hb-font.h220
-rw-r--r--src/hb-ft.cc153
-rw-r--r--src/hb-ft.h59
-rw-r--r--src/hb-glib.cc75
-rw-r--r--src/hb-glib.h3
-rw-r--r--src/hb-gobject-enums.cc.tmpl11
-rw-r--r--src/hb-gobject-enums.h.tmpl (renamed from src/indic.cc)43
-rw-r--r--src/hb-gobject-structs.cc91
-rw-r--r--src/hb-gobject-structs.h95
-rw-r--r--src/hb-gobject.h37
-rw-r--r--src/hb-graphite2.cc420
-rw-r--r--src/hb-graphite2.h12
-rw-r--r--src/hb-icu.cc126
-rw-r--r--src/hb-icu.h1
-rw-r--r--src/hb-mutex-private.hh19
-rw-r--r--src/hb-object-private.hh125
-rw-r--r--src/hb-open-file-private.hh51
-rw-r--r--src/hb-open-type-private.hh602
-rw-r--r--src/hb-ot-cmap-table.hh528
-rw-r--r--src/hb-ot-font.cc348
-rw-r--r--src/hb-ot-font.h (renamed from src/hb-fallback-shape-private.hh)22
-rw-r--r--src/hb-ot-head-table.hh24
-rw-r--r--src/hb-ot-hhea-table.hh79
-rw-r--r--src/hb-ot-hmtx-table.hh50
-rw-r--r--src/hb-ot-layout-common-private.hh624
-rw-r--r--src/hb-ot-layout-gdef-table.hh108
-rw-r--r--src/hb-ot-layout-gpos-table.hh973
-rw-r--r--src/hb-ot-layout-gsub-table.hh1250
-rw-r--r--src/hb-ot-layout-gsubgpos-private.hh1825
-rw-r--r--src/hb-ot-layout-jstf-table.hh233
-rw-r--r--src/hb-ot-layout-private.hh422
-rw-r--r--src/hb-ot-layout.cc775
-rw-r--r--src/hb-ot-layout.h153
-rw-r--r--src/hb-ot-map-private.hh220
-rw-r--r--src/hb-ot-map.cc234
-rw-r--r--src/hb-ot-maxp-table.hh20
-rw-r--r--src/hb-ot-name-table.hh26
-rw-r--r--src/hb-ot-shape-complex-arabic-fallback.hh354
-rw-r--r--src/hb-ot-shape-complex-arabic-table.hh1243
-rw-r--r--src/hb-ot-shape-complex-arabic-win1256.hh323
-rw-r--r--src/hb-ot-shape-complex-arabic.cc401
-rw-r--r--src/hb-ot-shape-complex-default.cc (renamed from src/hb-graphite2-private.hh)32
-rw-r--r--src/hb-ot-shape-complex-hangul.cc426
-rw-r--r--src/hb-ot-shape-complex-hebrew.cc172
-rw-r--r--src/hb-ot-shape-complex-indic-machine.hh293
-rw-r--r--src/hb-ot-shape-complex-indic-machine.rl95
-rw-r--r--src/hb-ot-shape-complex-indic-private.hh314
-rw-r--r--src/hb-ot-shape-complex-indic-table.cc (renamed from src/hb-ot-shape-complex-indic-table.hh)734
-rw-r--r--src/hb-ot-shape-complex-indic.cc1793
-rw-r--r--src/hb-ot-shape-complex-misc.cc193
-rw-r--r--src/hb-ot-shape-complex-myanmar-machine.rl128
-rw-r--r--src/hb-ot-shape-complex-myanmar.cc571
-rw-r--r--src/hb-ot-shape-complex-private.hh322
-rw-r--r--src/hb-ot-shape-complex-sea-machine.rl102
-rw-r--r--src/hb-ot-shape-complex-sea.cc380
-rw-r--r--src/hb-ot-shape-complex-thai.cc381
-rw-r--r--src/hb-ot-shape-complex-tibetan.cc61
-rw-r--r--src/hb-ot-shape-fallback-private.hh49
-rw-r--r--src/hb-ot-shape-fallback.cc485
-rw-r--r--src/hb-ot-shape-normalize-private.hh33
-rw-r--r--src/hb-ot-shape-normalize.cc293
-rw-r--r--src/hb-ot-shape-private.hh99
-rw-r--r--src/hb-ot-shape.cc805
-rw-r--r--src/hb-ot-shape.h53
-rw-r--r--src/hb-ot-tag.cc553
-rw-r--r--src/hb-ot.h9
-rw-r--r--src/hb-private.hh510
-rw-r--r--src/hb-set-private.hh253
-rw-r--r--src/hb-set.cc340
-rw-r--r--src/hb-set.h62
-rw-r--r--src/hb-shape-plan-private.hh62
-rw-r--r--src/hb-shape-plan.cc492
-rw-r--r--src/hb-shape-plan.h89
-rw-r--r--src/hb-shape.cc394
-rw-r--r--src/hb-shape.h15
-rw-r--r--src/hb-shaper-impl-private.hh (renamed from src/hb-uniscribe-private.hh)19
-rw-r--r--src/hb-shaper-list.hh55
-rw-r--r--src/hb-shaper-private.hh108
-rw-r--r--src/hb-shaper.cc111
-rw-r--r--src/hb-tt-font.cc243
-rw-r--r--src/hb-ucdn.cc231
-rw-r--r--src/hb-ucdn/COPYING13
-rw-r--r--src/hb-ucdn/Makefile.am18
-rw-r--r--src/hb-ucdn/Makefile.in543
-rw-r--r--src/hb-ucdn/README41
-rw-r--r--src/hb-ucdn/ucdn.c281
-rw-r--r--src/hb-ucdn/ucdn.h358
-rw-r--r--src/hb-ucdn/unicodedata_db.h5017
-rw-r--r--src/hb-unicode-private.hh276
-rw-r--r--src/hb-unicode.cc370
-rw-r--r--src/hb-unicode.h272
-rw-r--r--src/hb-uniscribe.cc1028
-rw-r--r--src/hb-uniscribe.h1
-rw-r--r--src/hb-utf-private.hh278
-rw-r--r--src/hb-version.h.in10
-rw-r--r--src/hb-warning.cc11
-rw-r--r--src/hb.h3
-rw-r--r--src/main.cc16
-rwxr-xr-xsrc/sample.py52
-rw-r--r--src/test-buffer-serialize.cc129
-rw-r--r--src/test-size-params.cc96
-rw-r--r--src/test-would-substitute.cc106
-rw-r--r--src/test.cc136
138 files changed, 31699 insertions, 8102 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 344cc57..c99967f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,15 +1,21 @@
# Process this file with automake to produce Makefile.in
NULL =
+SUBDIRS =
+DIST_SUBDIRS =
BUILT_SOURCES =
EXTRA_DIST =
CLEANFILES =
DISTCLEANFILES =
MAINTAINERCLEANFILES =
+DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
-# The following warning options are useful for debugging: -Wpadded -Wcast-align
+# The following warning options are useful for debugging: -Wpadded
#AM_CXXFLAGS =
+# Convenience targets:
+lib: libharfbuzz.la
+
lib_LTLIBRARIES = libharfbuzz.la
HBCFLAGS =
@@ -17,18 +23,22 @@ HBLIBS =
HBSOURCES = \
hb-atomic-private.hh \
hb-blob.cc \
+ hb-buffer-deserialize-json.hh \
+ hb-buffer-deserialize-text.hh \
hb-buffer-private.hh \
+ hb-buffer-serialize.cc \
hb-buffer.cc \
hb-cache-private.hh \
hb-common.cc \
- hb-fallback-shape-private.hh \
- hb-fallback-shape.cc \
+ hb-face-private.hh \
+ hb-face.cc \
hb-font-private.hh \
hb-font.cc \
hb-mutex-private.hh \
hb-object-private.hh \
hb-open-file-private.hh \
hb-open-type-private.hh \
+ hb-ot-cmap-table.hh \
hb-ot-head-table.hh \
hb-ot-hhea-table.hh \
hb-ot-hmtx-table.hh \
@@ -39,9 +49,15 @@ HBSOURCES = \
hb-set-private.hh \
hb-set.cc \
hb-shape.cc \
- hb-tt-font.cc \
+ hb-shape-plan-private.hh \
+ hb-shape-plan.cc \
+ hb-shaper-list.hh \
+ hb-shaper-impl-private.hh \
+ hb-shaper-private.hh \
+ hb-shaper.cc \
hb-unicode-private.hh \
hb-unicode.cc \
+ hb-utf-private.hh \
hb-warning.cc \
$(NULL)
HBHEADERS = \
@@ -49,44 +65,74 @@ HBHEADERS = \
hb-blob.h \
hb-buffer.h \
hb-common.h \
+ hb-deprecated.h \
+ hb-face.h \
hb-font.h \
hb-set.h \
hb-shape.h \
+ hb-shape-plan.h \
hb-unicode.h \
+ $(NULL)
+HBNODISTHEADERS = \
hb-version.h \
$(NULL)
if HAVE_OT
HBSOURCES += \
+ hb-ot-font.cc \
hb-ot-layout.cc \
hb-ot-layout-common-private.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
hb-ot-layout-gsubgpos-private.hh \
hb-ot-layout-gsub-table.hh \
+ hb-ot-layout-jstf-table.hh \
hb-ot-layout-private.hh \
hb-ot-map.cc \
hb-ot-map-private.hh \
hb-ot-shape.cc \
hb-ot-shape-complex-arabic.cc \
+ hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-table.hh \
+ hb-ot-shape-complex-arabic-win1256.hh \
+ hb-ot-shape-complex-default.cc \
+ hb-ot-shape-complex-hangul.cc \
+ hb-ot-shape-complex-hebrew.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic-machine.hh \
hb-ot-shape-complex-indic-private.hh \
- hb-ot-shape-complex-indic-table.hh \
- hb-ot-shape-complex-misc.cc \
+ hb-ot-shape-complex-indic-table.cc \
+ hb-ot-shape-complex-myanmar.cc \
+ hb-ot-shape-complex-myanmar-machine.hh \
+ hb-ot-shape-complex-sea.cc \
+ hb-ot-shape-complex-sea-machine.hh \
+ hb-ot-shape-complex-thai.cc \
+ hb-ot-shape-complex-tibetan.cc \
hb-ot-shape-complex-private.hh \
hb-ot-shape-normalize-private.hh \
hb-ot-shape-normalize.cc \
+ hb-ot-shape-fallback-private.hh \
+ hb-ot-shape-fallback.cc \
hb-ot-shape-private.hh \
$(NULL)
HBHEADERS += \
hb-ot.h \
+ hb-ot-font.h \
hb-ot-layout.h \
+ hb-ot-shape.h \
hb-ot-tag.h \
$(NULL)
endif
+if HAVE_FALLBACK
+HBSOURCES += hb-fallback-shape.cc
+endif
+
+if HAVE_PTHREAD
+HBCFLAGS += $(PTHREAD_CFLAGS)
+HBLIBS += $(PTHREAD_LIBS)
+endif
+
if HAVE_GLIB
HBCFLAGS += $(GLIB_CFLAGS)
HBLIBS += $(GLIB_LIBS)
@@ -94,28 +140,6 @@ HBSOURCES += hb-glib.cc
HBHEADERS += hb-glib.h
endif
-if HAVE_GOBJECT
-HBCFLAGS += $(GOBJECT_CFLAGS)
-HBLIBS += $(GOBJECT_LIBS)
-HBSOURCES += hb-gobject-structs.cc
-nodist_HBSOURCES = hb-gobject-enums.cc
-HBHEADERS += hb-gobject.h
-BUILT_SOURCES += hb-gobject-enums.cc
-EXTRA_DIST += hb-gobject-enums.cc.tmpl
-DISTCLEANFILES += hb-gobject-enums.cc
-
-hb-gobject-enums.cc: hb-gobject-enums.cc.tmpl $(HBHEADERS)
- $(AM_V_GEN) $(GLIB_MKENUMS) --template $^ > "$@.tmp" && \
- mv "$@.tmp" "$@" || ( $(RM) "@.tmp" && false )
-endif
-
-if HAVE_ICU
-HBCFLAGS += $(ICU_CFLAGS)
-HBLIBS += $(ICU_LIBS)
-HBSOURCES += hb-icu.cc
-HBHEADERS += hb-icu.h
-endif
-
if HAVE_FREETYPE
HBCFLAGS += $(FREETYPE_CFLAGS)
HBLIBS += $(FREETYPE_LIBS)
@@ -126,89 +150,258 @@ endif
if HAVE_GRAPHITE2
HBCFLAGS += $(GRAPHITE2_CFLAGS)
HBLIBS += $(GRAPHITE2_LIBS)
-HBSOURCES += hb-graphite2.cc hb-graphite2-private.hh
+HBSOURCES += hb-graphite2.cc
HBHEADERS += hb-graphite2.h
endif
if HAVE_UNISCRIBE
HBCFLAGS += $(UNISCRIBE_CFLAGS)
HBLIBS += $(UNISCRIBE_LIBS)
-HBSOURCES += hb-uniscribe.cc hb-uniscribe-private.hh
+HBSOURCES += hb-uniscribe.cc
HBHEADERS += hb-uniscribe.h
endif
-# Use a C linker, not C++; Don't link to libstdc++
+if HAVE_CORETEXT
+HBCFLAGS += $(CORETEXT_CFLAGS)
+HBLIBS += $(CORETEXT_LIBS)
+HBSOURCES += hb-coretext.cc
+HBHEADERS += hb-coretext.h
+endif
+
+if HAVE_UCDN
+SUBDIRS += hb-ucdn
+HBCFLAGS += -I$(srcdir)/hb-ucdn
+HBLIBS += hb-ucdn/libhb-ucdn.la
+HBSOURCES += hb-ucdn.cc
+endif
+DIST_SUBDIRS += hb-ucdn
+
+
+# Put the library together
+
+if OS_WIN32
+export_symbols = -export-symbols harfbuzz.def
+harfbuzz_def_dependency = harfbuzz.def
+libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
+else
+# Use a C linker for GCC, not C++; Don't link to libstdc++
+if HAVE_GCC
libharfbuzz_la_LINK = $(LINK) $(libharfbuzz_la_LDFLAGS)
-libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
-nodist_libharfbuzz_la_SOURCES = $(nodist_HBSOURCES)
+else
+libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
+endif
+endif
+
+libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) $(HBNODISTHEADERS)
libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
-libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
libharfbuzz_la_LIBADD = $(HBLIBS)
+EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
pkginclude_HEADERS = $(HBHEADERS)
-nodist_pkginclude_HEADERS = hb-version.h
+nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = harfbuzz.pc
+EXTRA_DIST += harfbuzz.pc.in
+
+if HAVE_ICU
+lib_LTLIBRARIES += libharfbuzz-icu.la
+libharfbuzz_icu_la_SOURCES = hb-icu.cc
+libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
+libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
+pkginclude_HEADERS += hb-icu.h
+pkgconfig_DATA += harfbuzz-icu.pc
+endif
+EXTRA_DIST += harfbuzz-icu.pc.in
+
+if HAVE_GOBJECT
+lib_LTLIBRARIES += libharfbuzz-gobject.la
+libharfbuzz_gobject_la_SOURCES = hb-gobject-structs.cc
+nodist_libharfbuzz_gobject_la_SOURCES = hb-gobject-enums.cc
+libharfbuzz_gobject_la_CPPFLAGS = $(GOBJECT_CFLAGS)
+libharfbuzz_gobject_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
+libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
+pkginclude_HEADERS += hb-gobject.h hb-gobject-structs.h
+nodist_pkginclude_HEADERS += hb-gobject-enums.h
+pkgconfig_DATA += harfbuzz-gobject.pc
+
+BUILT_SOURCES += \
+ hb-gobject-enums.cc \
+ hb-gobject-enums.h \
+ $(NULL)
+DISTCLEANFILES += \
+ hb-gobject-enums.cc \
+ hb-gobject-enums.h \
+ $(NULL)
+hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
+ $(AM_V_GEN) $(GLIB_MKENUMS) \
+ --identifier-prefix hb_ --symbol-prefix hb_gobject \
+ --template $^ | \
+ sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
+ || ($(RM) "$@"; false)
+endif
+EXTRA_DIST += \
+ harfbuzz-gobject.pc.in \
+ hb-gobject-enums.cc.tmpl \
+ hb-gobject-enums.h.tmpl \
+ $(NULL)
+
+
+%.pc: %.pc.in $(top_builddir)/config.status
+ $(AM_V_GEN) \
+ $(SED) -e 's@%prefix%@$(prefix)@g' \
+ -e 's@%exec_prefix%@$(exec_prefix)@g' \
+ -e 's@%libdir%@$(libdir)@g' \
+ -e 's@%includedir%@$(includedir)@g' \
+ -e 's@%VERSION%@$(VERSION)@g' \
+ "$<" > "$@" \
+ || ($(RM) "$@"; false)
+
+CLEANFILES += $(pkgconfig_DATA)
+
+
+CLEANFILES += harfbuzz.def
+harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
+ $(AM_V_GEN) (echo EXPORTS; \
+ (cat $^ || echo 'hb_ERROR ()' ) | \
+ $(EGREP) '^hb_.* \(' | \
+ sed -e 's/ (.*//' | \
+ LANG=C sort; \
+ echo LIBRARY libharfbuzz-$(HB_VERSION_MAJOR).dll; \
+ ) >"$@"
+ @ ! grep -q hb_ERROR "$@" \
+ || ($(RM) "$@"; false)
GENERATORS = \
gen-arabic-table.py \
gen-indic-table.py \
$(NULL)
-
EXTRA_DIST += $(GENERATORS)
unicode-tables: arabic-table indic-table
indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt
- $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.hh.tmp && \
- mv hb-ot-shape-complex-indic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-indic-table.hh || \
- ($(RM) hb-ot-shape-complex-indic-table.hh.tmp; false)
+ $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
+ || ($(RM) hb-ot-shape-complex-indic-table.cc; false)
-arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
- $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh.tmp && \
- mv hb-ot-shape-complex-arabic-table.hh.tmp $(srcdir)/hb-ot-shape-complex-arabic-table.hh || \
- ($(RM) hb-ot-shape-complex-arabic-table.hh.tmp; false)
+arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
+ $(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh \
+ || ($(RM) hb-ot-shape-complex-arabic-table.hh; false)
+built-sources: $(BUILT_SOURCES)
-.PHONY: unicode-tables arabic-table indic-table
+.PHONY: unicode-tables arabic-table indic-table built-sources
-BUILT_SOURCES += hb-ot-shape-complex-indic-machine.hh
-EXTRA_DIST += hb-ot-shape-complex-indic-machine.rl
-hb-ot-shape-complex-indic-machine.hh: hb-ot-shape-complex-indic-machine.rl
- $(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \
- mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false )
+RAGEL_GENERATED = \
+ $(srcdir)/hb-buffer-deserialize-json.hh \
+ $(srcdir)/hb-buffer-deserialize-text.hh \
+ $(srcdir)/hb-ot-shape-complex-indic-machine.hh \
+ $(srcdir)/hb-ot-shape-complex-myanmar-machine.hh \
+ $(srcdir)/hb-ot-shape-complex-sea-machine.hh \
+ $(NULL)
+BUILT_SOURCES += $(RAGEL_GENERATED)
+EXTRA_DIST += \
+ hb-buffer-deserialize-json.rl \
+ hb-buffer-deserialize-text.rl \
+ hb-ot-shape-complex-indic-machine.rl \
+ hb-ot-shape-complex-myanmar-machine.rl \
+ hb-ot-shape-complex-sea-machine.rl \
+ $(NULL)
+MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
+$(srcdir)/%.hh: $(srcdir)/%.rl
+ $(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
+ || ($(RM) "$@"; false)
-noinst_PROGRAMS = main indic
+noinst_PROGRAMS = \
+ main \
+ test \
+ test-buffer-serialize \
+ test-size-params \
+ test-would-substitute \
+ $(NULL)
bin_PROGRAMS =
main_SOURCES = main.cc
main_CPPFLAGS = $(HBCFLAGS)
main_LDADD = libharfbuzz.la $(HBLIBS)
-indic_SOURCES = indic.cc
-indic_CPPFLAGS = $(HBCFLAGS)
-indic_LDADD = libharfbuzz.la $(HBLIBS)
+test_SOURCES = test.cc
+test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
+test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
+
+test_would_substitute_SOURCES = test-would-substitute.cc
+test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
+test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
+
+test_size_params_SOURCES = test-size-params.cc
+test_size_params_CPPFLAGS = $(HBCFLAGS)
+test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
+
+test_buffer_serialize_SOURCES = test-buffer-serialize.cc
+test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
+test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
dist_check_SCRIPTS = \
check-c-linkage-decls.sh \
+ check-defs.sh \
check-header-guards.sh \
- check-internal-symbols.sh \
check-includes.sh \
+ check-libstdc++.sh \
+ check-static-inits.sh \
+ check-symbols.sh \
$(NULL)
-if HAVE_ICU
-else
-dist_check_SCRIPTS += check-libstdc++.sh
-endif
-
TESTS = $(dist_check_SCRIPTS)
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
HBSOURCES="$(HBSOURCES)" \
- HBHEADERS="$(HBHEADERS)" \
+ HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \
+ $(NULL)
+
+if HAVE_INTROSPECTION
+
+-include $(INTROSPECTION_MAKEFILE)
+INTROSPECTION_GIRS = HarfBuzz-$(HB_VERSION_MAJOR).0.gir # What does the 0 mean anyway?!
+INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
+INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+INTROSPECTION_SCANNER_ENV = CC="$(CC)"
+
+HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
+HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
+HarfBuzz_0_0_gir_CFLAGS = \
+ $(INCLUDES) \
+ $(HBCFLAGS) \
+ -DHB_H \
+ -DHB_H_IN \
+ -DHB_OT_H \
+ -DHB_OT_H_IN \
+ -DHB_GOBJECT_H \
+ -DHB_GOBJECT_H_IN \
+ $(NULL)
+HarfBuzz_0_0_gir_LIBS = \
+ libharfbuzz.la \
+ libharfbuzz-gobject.la \
+ $(NULL)
+HarfBuzz_0_0_gir_FILES = \
+ $(HBHEADERS) \
+ $(HBNODISTHEADERS) \
+ $(HBSOURCES) \
+ hb-gobject-enums.cc \
+ hb-gobject-enums.h \
+ hb-gobject-structs.cc \
+ hb-gobject-structs.h \
$(NULL)
-scan:
- g-ir-scanner $(HBCFLAGS) $(HBHEADERS) -n hb --strip-prefix=hb --library libharfbuzz.la
+girdir = $(datadir)/gir-1.0
+gir_DATA = $(INTROSPECTION_GIRS)
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(gir_DATA) $(typelib_DATA)
+
+endif
-include $(top_srcdir)/git.mk
diff --git a/src/check-c-linkage-decls.sh b/src/check-c-linkage-decls.sh
index e7c95ab..b10310f 100755
--- a/src/check-c-linkage-decls.sh
+++ b/src/check-c-linkage-decls.sh
@@ -6,13 +6,21 @@ export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
for x in $HBHEADERS; do
test -f $srcdir/$x && x=$srcdir/$x
if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then
- echo "Ouch, file $x does not HB_BEGIN_DECLS / HB_END_DECLS"
+ echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should"
+ stat=1
+ fi
+done
+for x in $HBSOURCES; do
+ test -f $srcdir/$x && x=$srcdir/$x
+ if grep -q HB_BEGIN_DECLS "$x" || grep -q HB_END_DECLS "$x"; then
+ echo "Ouch, file $x has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn't"
stat=1
fi
done
diff --git a/src/check-defs.sh b/src/check-defs.sh
new file mode 100755
index 0000000..65a2467
--- /dev/null
+++ b/src/check-defs.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+test -z "$MAKE" && MAKE=make
+stat=0
+
+if which nm 2>/dev/null >/dev/null; then
+ :
+else
+ echo "check-defs.sh: 'nm' not found; skipping test"
+ exit 77
+fi
+
+defs="harfbuzz.def"
+$MAKE $defs > /dev/null
+tested=false
+for def in $defs; do
+ lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
+ so=.libs/lib${lib}.so
+
+ EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
+
+ if test -f "$so"; then
+
+ echo "Checking that $so has the same symbol list as $def"
+ {
+ echo EXPORTS
+ echo "$EXPORTED_SYMBOLS"
+ # cheat: copy the last line from the def file!
+ tail -n1 "$def"
+ } | diff "$def" - >&2 || stat=1
+
+ tested=true
+ fi
+done
+if ! $tested; then
+ echo "check-defs.sh: libharfbuzz shared library not found; skipping test"
+ exit 77
+fi
+
+exit $stat
diff --git a/src/check-header-guards.sh b/src/check-header-guards.sh
index af9fa7f..9a3302c 100755
--- a/src/check-header-guards.sh
+++ b/src/check-header-guards.sh
@@ -6,8 +6,8 @@ export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
for x in $HBHEADERS $HBSOURCES; do
diff --git a/src/check-includes.sh b/src/check-includes.sh
index 79323a7..902f235 100755
--- a/src/check-includes.sh
+++ b/src/check-includes.sh
@@ -6,16 +6,14 @@ export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
-test "x$HBHEADERS" = x && HBHEADERS=`find . -maxdepth 1 -name 'hb*.h'`
-test "x$HBSOURCES" = x && HBSOURCES=`find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
-
-
-cd "$srcdir"
+test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
+test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
for x in $HBHEADERS; do
+ test -f "$srcdir/$x" && x="$srcdir/$x"
grep '#.*\<include\>' "$x" /dev/null | head -n 1
done |
grep -v '"hb-common[.]h"' |
@@ -28,7 +26,8 @@ grep . >&2 && stat=1
echo 'Checking that source files #include "hb-*private.hh" first (or none)'
for x in $HBSOURCES; do
- grep '#.*\<include\>' "$x" /dev/null | head -n 1
+ test -f "$srcdir/$x" && x="$srcdir/$x"
+ grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
done |
grep -v '"hb-.*private[.]hh"' |
grep -v 'hb-private[.]hh:' |
@@ -36,7 +35,10 @@ grep . >&2 && stat=1
echo 'Checking that there is no #include <hb.*.h>'
-grep '#.*\<include\>.*<.*hb' $HBHEADERS $HBSOURCES >&2 && stat=1
+for x in $HBHEADERS $HBSOURCES; do
+ test -f "$srcdir/$x" && x="$srcdir/$x"
+ grep '#.*\<include\>.*<.*hb' "$x" /dev/null >&2 && stat=1
+done
exit $stat
diff --git a/src/check-internal-symbols.sh b/src/check-internal-symbols.sh
deleted file mode 100755
index a24a693..0000000
--- a/src/check-internal-symbols.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-test -z "$srcdir" && srcdir=.
-stat=0
-
-
-if which nm 2>/dev/null >/dev/null; then
- :
-else
- echo "check-internal-symbols.sh: 'nm' not found; skipping test"
- exit 77
-fi
-
-tested=false
-for suffix in so; do
- so=.libs/libharfbuzz.$suffix
- if test -f "$so"; then
- echo "Checking that we are exposing internal symbols"
- if nm $so | grep ' T ' | grep -v ' T _fini\>\| T _init\>\| T hb_'; then
- echo "Ouch, internal symbols exposed"
- stat=1
- fi
- tested=true
- fi
-done
-if ! $tested; then
- echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
- exit 77
-fi
-
-exit $stat
diff --git a/src/check-libstdc++.sh b/src/check-libstdc++.sh
index 0521532..27deb42 100755
--- a/src/check-libstdc++.sh
+++ b/src/check-libstdc++.sh
@@ -17,17 +17,17 @@ fi
tested=false
for suffix in so dylib; do
so=.libs/libharfbuzz.$suffix
- if test -f "$so"; then
- echo "Checking that we are not linking to libstdc++"
- if ldd $so | grep 'libstdc[+][+]'; then
- echo "Ouch, linked to libstdc++"
- stat=1
- fi
- tested=true
+ if ! test -f "$so"; then continue; fi
+
+ echo "Checking that we are not linking to libstdc++"
+ if ldd $so | grep 'libstdc[+][+]'; then
+ echo "Ouch, linked to libstdc++"
+ stat=1
fi
+ tested=true
done
if ! $tested; then
- echo "check-internal-symbols.sh: libharfbuzz shared library not found; skipping test"
+ echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"
exit 77
fi
diff --git a/src/check-static-inits.sh b/src/check-static-inits.sh
new file mode 100755
index 0000000..1446fa7
--- /dev/null
+++ b/src/check-static-inits.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+stat=0
+
+
+if which objdump 2>/dev/null >/dev/null; then
+ :
+else
+ echo "check-static-inits.sh: 'objdump' not found; skipping test"
+ exit 77
+fi
+
+OBJS=.libs/*.o
+if test "x`echo $OBJS`" = "x$OBJS" 2>/dev/null >/dev/null; then
+ echo "check-static-inits.sh: object files not found; skipping test"
+ exit 77
+fi
+
+echo "Checking that no object file has static initializers"
+for obj in $OBJS; do
+ if objdump -t "$obj" | grep '[.][cd]tors' | grep -v '\<00*\>'; then
+ echo "Ouch, $obj has static initializers/finalizers"
+ stat=1
+ fi
+done
+
+echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff"
+for obj in $OBJS; do
+ if objdump -t "$obj" | grep '__cxa_'; then
+ echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff"
+ stat=1
+ fi
+done
+
+exit $stat
diff --git a/src/check-symbols.sh b/src/check-symbols.sh
new file mode 100755
index 0000000..b2bf43f
--- /dev/null
+++ b/src/check-symbols.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+test -z "$srcdir" && srcdir=.
+stat=0
+
+
+if which nm 2>/dev/null >/dev/null; then
+ :
+else
+ echo "check-symbols.sh: 'nm' not found; skipping test"
+ exit 77
+fi
+
+echo "Checking that we are not exposing internal symbols"
+tested=false
+for suffix in so dylib; do
+ so=.libs/libharfbuzz.$suffix
+ if ! test -f "$so"; then continue; fi
+
+ EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
+
+ prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
+
+ # On mac, C symbols are prefixed with _
+ if test $suffix = dylib; then prefix="_$prefix"; fi
+
+ echo "Processing $so"
+ if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}_"; then
+ echo "Ouch, internal symbols exposed"
+ stat=1
+ fi
+
+ tested=true
+done
+if ! $tested; then
+ echo "check-symbols.sh: no shared library found; skipping test"
+ exit 77
+fi
+
+exit $stat
diff --git a/src/gen-arabic-table.py b/src/gen-arabic-table.py
index 2d3c881..308435f 100755
--- a/src/gen-arabic-table.py
+++ b/src/gen-arabic-table.py
@@ -3,34 +3,48 @@
import sys
import os.path
-if len (sys.argv) != 3:
- print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt"
+if len (sys.argv) != 4:
+ print >>sys.stderr, "usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
sys.exit (1)
files = [file (x) for x in sys.argv[1:]]
-headers = [[files[0].readline (), files[0].readline ()]]
+headers = [[files[0].readline (), files[0].readline ()], [files[2].readline (), files[2].readline ()]]
headers.append (["UnicodeData.txt does not have a header."])
while files[0].readline ().find ('##################') < 0:
pass
+blocks = {}
+def read_blocks(f):
+ global blocks
+ for line in f:
-def print_joining_table(f):
+ j = line.find ('#')
+ if j >= 0:
+ line = line[:j]
- print
- print "static const uint8_t joining_table[] ="
- print "{"
+ fields = [x.strip () for x in line.split (';')]
+ if len (fields) == 1:
+ continue
+
+ uu = fields[0].split ('..')
+ start = int (uu[0], 16)
+ if len (uu) == 1:
+ end = start
+ else:
+ end = int (uu[1], 16)
+
+ t = fields[1]
+
+ for u in range (start, end + 1):
+ blocks[u] = t
+
+def print_joining_table(f):
- min_u = 0x110000
- max_u = 0
- num = 0
- last = -1
- block = ''
+ values = {}
for line in f:
if line[0] == '#':
- if line.find (" characters"):
- block = line[2:].strip ()
continue
fields = [x.strip () for x in line.split (';')]
@@ -38,43 +52,100 @@ def print_joining_table(f):
continue
u = int (fields[0], 16)
- if u == 0x200C or u == 0x200D:
- continue
- if u < last:
- raise Exception ("Input data character not sorted", u)
- min_u = min (min_u, u)
- max_u = max (max_u, u)
- num += 1
-
- if block:
- print "\n /* %s */\n" % block
- block = ''
-
- if last != -1:
- last += 1
- while last < u:
- print " JOINING_TYPE_X, /* %04X */" % last
- last += 1
- else:
- last = u
if fields[3] in ["ALAPH", "DALATH RISH"]:
value = "JOINING_GROUP_" + fields[3].replace(' ', '_')
else:
value = "JOINING_TYPE_" + fields[2]
- print " %s, /* %s */" % (value, '; '.join(fields))
+ values[u] = value
+
+ short_value = {}
+ for value in set([v for v in values.values()] + ['JOINING_TYPE_X']):
+ short = ''.join(x[0] for x in value.split('_')[2:])
+ assert short not in short_value.values()
+ short_value[value] = short
print
- print "};"
+ for value,short in short_value.items():
+ print "#define %s %s" % (short, value)
+
+ uu = sorted(values.keys())
+ num = len(values)
+ all_blocks = set([blocks[u] for u in uu])
+
+ last = -100000
+ ranges = []
+ for u in uu:
+ if u - last <= 1+16*5:
+ ranges[-1][-1] = u
+ else:
+ ranges.append([u,u])
+ last = u
+
print
- print "#define JOINING_TABLE_FIRST 0x%04X" % min_u
- print "#define JOINING_TABLE_LAST 0x%04X" % max_u
+ print "static const uint8_t joining_table[] ="
+ print "{"
+ last_block = None
+ offset = 0
+ for start,end in ranges:
+
+ print
+ print "#define joining_offset_0x%04xu %d" % (start, offset)
+
+ for u in range(start, end+1):
+
+ block = blocks.get(u, last_block)
+ value = values.get(u, "JOINING_TYPE_X")
+
+ if block != last_block or u == start:
+ if u != start:
+ print
+ if block in all_blocks:
+ print "\n /* %s */" % block
+ else:
+ print "\n /* FILLER */"
+ last_block = block
+ if u % 32 != 0:
+ print
+ print " /* %04X */" % (u//32*32), " " * (u % 32),
+
+ if u % 32 == 0:
+ print
+ print " /* %04X */ " % u,
+ sys.stdout.write("%s," % short_value[value])
+ print
+
+ offset += end - start + 1
+ print
+ occupancy = num * 100. / offset
+ print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
print
- occupancy = num * 100 / (max_u - min_u + 1)
- # Maintain at least 40% occupancy in the table */
- if occupancy < 40:
- raise Exception ("Table too sparse, please investigate: ", occupancy)
+ page_bits = 12;
+ print
+ print "static unsigned int"
+ print "joining_type (hb_codepoint_t u)"
+ print "{"
+ print " switch (u >> %d)" % page_bits
+ print " {"
+ pages = set([u>>page_bits for u in [s for s,e in ranges]+[e for s,e in ranges]])
+ for p in sorted(pages):
+ print " case 0x%0Xu:" % p
+ for (start,end) in ranges:
+ if p not in [start>>page_bits, end>>page_bits]: continue
+ offset = "joining_offset_0x%04xu" % start
+ print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
+ print " break;"
+ print ""
+ print " default:"
+ print " break;"
+ print " }"
+ print " return X;"
+ print "}"
+ print
+ for value,short in short_value.items():
+ print "#undef %s" % (short)
+ print
def print_shaping_table(f):
@@ -122,15 +193,15 @@ def print_shaping_table(f):
keys = shapes.keys ()
min_u, max_u = min (keys), max (keys)
for u in range (min_u, max_u + 1):
- s = [shapes[u][shape] if u in shapes and shape in shapes[u] else u
+ s = [shapes[u][shape] if u in shapes and shape in shapes[u] else 0
for shape in ['initial', 'medial', 'final', 'isolated']]
- value = ', '.join ("0x%04X" % c for c in s)
+ value = ', '.join ("0x%04Xu" % c for c in s)
print " {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else "")
print "};"
print
- print "#define SHAPING_TABLE_FIRST 0x%04X" % min_u
- print "#define SHAPING_TABLE_LAST 0x%04X" % max_u
+ print "#define SHAPING_TABLE_FIRST 0x%04Xu" % min_u
+ print "#define SHAPING_TABLE_LAST 0x%04Xu" % max_u
print
ligas = {}
@@ -148,9 +219,9 @@ def print_shaping_table(f):
ligas[liga[0]].append ((liga[1], c))
max_i = max (len (ligas[l]) for l in ligas)
print
- print "static const struct {"
+ print "static const struct ligature_set_t {"
print " uint16_t first;"
- print " struct {"
+ print " struct ligature_pairs_t {"
print " uint16_t second;"
print " uint16_t ligature;"
print " } ligatures[%d];" % max_i
@@ -160,9 +231,9 @@ def print_shaping_table(f):
keys.sort ()
for first in keys:
- print " { 0x%04X, {" % (first)
+ print " { 0x%04Xu, {" % (first)
for liga in ligas[first]:
- print " { 0x%04X, 0x%04X }, /* %s */" % (liga[0], liga[1], names[liga[1]])
+ print " { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]])
print " }},"
print "};"
@@ -174,7 +245,7 @@ print "/* == Start of generated table == */"
print "/*"
print " * The following table is generated by running:"
print " *"
-print " * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt"
+print " * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
print " *"
print " * on files with these headers:"
print " *"
@@ -187,6 +258,7 @@ print "#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
print "#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
print
+read_blocks (files[2])
print_joining_table (files[0])
print_shaping_table (files[1])
diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py
index 94aa2ab..f5716bd 100755
--- a/src/gen-indic-table.py
+++ b/src/gen-indic-table.py
@@ -6,11 +6,12 @@ if len (sys.argv) != 4:
print >>sys.stderr, "usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt"
sys.exit (1)
+BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
+
files = [file (x) for x in sys.argv[1:]]
headers = [[f.readline () for i in range (2)] for f in files]
-blocks = {}
data = [{} for f in files]
values = [{} for f in files]
for i, f in enumerate (files):
@@ -35,10 +36,7 @@ for i, f in enumerate (files):
for u in range (start, end + 1):
data[i][u] = t
- values[i][t] = values[i].get (t, 0) + 1
-
- if i == 2:
- blocks[t] = (start, end)
+ values[i][t] = values[i].get (t, 0) + end - start + 1
# Merge data into one dict:
defaults = ('Other', 'Not_Applicable', 'No_Block')
@@ -52,10 +50,15 @@ for i,d in enumerate (data):
if not u in combined:
combined[u] = list (defaults)
combined[u][i] = v
+combined = {k:v for k,v in combined.items() if v[2] not in BLACKLISTED_BLOCKS}
data = combined
del combined
num = len (data)
+for u in [0x17CD, 0x17CE, 0x17CF, 0x17D0, 0x17D3]:
+ if data[u][0] == 'Other':
+ data[u][0] = "Vowel_Dependent"
+
# Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
singles = {}
for u in [0x00A0, 0x25CC]:
@@ -75,13 +78,16 @@ for h in headers:
print " * %s" % (l.strip())
print " */"
print
-print "#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH"
-print "#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH"
+print '#include "hb-ot-shape-complex-indic-private.hh"'
print
# Shorten values
short = [{
"Bindu": 'Bi',
+ "Cantillation_Mark": 'Ca',
+ "Joiner": 'ZWJ',
+ "Non_Joiner": 'ZWNJ',
+ "Number": 'Nd',
"Visarga": 'Vs',
"Vowel": 'Vo',
"Vowel_Dependent": 'M',
@@ -89,14 +95,14 @@ short = [{
},{
"Not_Applicable": 'x',
}]
-all_shorts = [[],[]]
+all_shorts = [{},{}]
# Add some of the values, to make them more readable, and to avoid duplicates
for i in range (2):
for v,s in short[i].items ():
- all_shorts[i].append (s)
+ all_shorts[i][s] = v
what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
what_short = ["ISC", "IMC"]
@@ -111,8 +117,8 @@ for i in range (2):
else:
s = ''.join ([c for c in v_no_and if ord ('A') <= ord (c) <= ord ('Z')])
if s in all_shorts[i]:
- raise Exception ("Duplicate short value alias", v, s)
- all_shorts[i].append (s)
+ raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
+ all_shorts[i][s] = v
short[i][v] = s
print "#define %s_%s %s_%s %s/* %3d chars; %s */" % \
(what_short[i], s, what[i], v.upper (), \
@@ -125,11 +131,16 @@ print
total = 0
used = 0
+last_block = None
def print_block (block, start, end, data):
- print
- print
- print " /* %s (%04X..%04X) */" % (block, start, end)
+ global total, used, last_block
+ if block and block != last_block:
+ print
+ print
+ print " /* %s */" % block
num = 0
+ assert start % 8 == 0
+ assert (end+1) % 8 == 0
for u in range (start, end+1):
if u % 8 == 0:
print
@@ -139,14 +150,15 @@ def print_block (block, start, end, data):
d = data.get (u, defaults)
sys.stdout.write ("%9s" % ("_(%s,%s)," % (short[0][d[0]], short[1][d[1]])))
- global total, used
total += end - start + 1
used += num
+ if block:
+ last_block = block
uu = data.keys ()
uu.sort ()
-last = -1
+last = -100000
num = 0
offset = 0
starts = []
@@ -156,11 +168,16 @@ for u in uu:
if u <= last:
continue
block = data[u][2]
- (start, end) = blocks[block]
+
+ start = u//8*8
+ end = start+1
+ while end in uu and block == data[end][2]:
+ end += 1
+ end = (end-1)//8*8 + 7
if start != last + 1:
- if start - last <= 33:
- print_block ("FILLER", last+1, start-1, data)
+ if start - last <= 1+16*3:
+ print_block (None, last+1, start-1, data)
last = start-1
else:
if last >= 0:
@@ -168,7 +185,7 @@ for u in uu:
offset += ends[-1] - starts[-1]
print
print
- print "#define indic_offset_0x%04x %d" % (start, offset)
+ print "#define indic_offset_0x%04xu %d" % (start, offset)
starts.append (start)
print_block (block, start, end, data)
@@ -177,19 +194,30 @@ ends.append (last + 1)
offset += ends[-1] - starts[-1]
print
print
-print "#define indic_offset_total %d" % offset
-print
occupancy = used * 100. / total
-print "}; /* Table occupancy: %d%% */" % occupancy
+page_bits = 12
+print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
print
-print "static INDIC_TABLE_ELEMENT_TYPE"
-print "get_indic_categories (hb_codepoint_t u)"
+print "INDIC_TABLE_ELEMENT_TYPE"
+print "hb_indic_get_categories (hb_codepoint_t u)"
print "{"
-for (start,end) in zip (starts, ends):
- offset = "indic_offset_0x%04x" % start
- print " if (0x%04X <= u && u <= 0x%04X) return indic_table[u - 0x%04X + %s];" % (start, end, start, offset)
-for u,d in singles.items ():
- print " if (unlikely (u == 0x%04X)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
+print " switch (u >> %d)" % page_bits
+print " {"
+pages = set([u>>page_bits for u in starts+ends+singles.keys()])
+for p in sorted(pages):
+ print " case 0x%0Xu:" % p
+ for (start,end) in zip (starts, ends):
+ if p not in [start>>page_bits, end>>page_bits]: continue
+ offset = "indic_offset_0x%04xu" % start
+ print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
+ for u,d in singles.items ():
+ if p != u>>page_bits: continue
+ print " if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
+ print " break;"
+ print ""
+print " default:"
+print " break;"
+print " }"
print " return _(x,x);"
print "}"
print
@@ -202,8 +230,6 @@ for i in range (2):
print "#undef %s_%s" % \
(what_short[i], short[i][v])
print
-print "#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */"
-print
print "/* == End of generated table == */"
# Maintain at least 30% occupancy in the table */
diff --git a/src/harfbuzz-gobject.pc.in b/src/harfbuzz-gobject.pc.in
new file mode 100644
index 0000000..7008360
--- /dev/null
+++ b/src/harfbuzz-gobject.pc.in
@@ -0,0 +1,12 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library GObject integration
+Version: %VERSION%
+
+Requires: harfbuzz gobject-2.0 glib-2.0
+Libs: -L${libdir} -lharfbuzz-gobject
+Cflags: -I${includedir}/harfbuzz
diff --git a/src/harfbuzz-icu.pc.in b/src/harfbuzz-icu.pc.in
new file mode 100644
index 0000000..949869a
--- /dev/null
+++ b/src/harfbuzz-icu.pc.in
@@ -0,0 +1,13 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library ICU integration
+Version: %VERSION%
+
+Requires: harfbuzz
+Requires.private: icu-uc
+Libs: -L${libdir} -lharfbuzz-icu
+Cflags: -I${includedir}/harfbuzz
diff --git a/src/harfbuzz.pc.in b/src/harfbuzz.pc.in
new file mode 100644
index 0000000..7f27bbb
--- /dev/null
+++ b/src/harfbuzz.pc.in
@@ -0,0 +1,11 @@
+prefix=%prefix%
+exec_prefix=%exec_prefix%
+libdir=%libdir%
+includedir=%includedir%
+
+Name: harfbuzz
+Description: HarfBuzz text shaping library
+Version: %VERSION%
+
+Libs: -L${libdir} -lharfbuzz
+Cflags: -I${includedir}/harfbuzz
diff --git a/src/hb-atomic-private.hh b/src/hb-atomic-private.hh
index c543a8d..e6738b7 100644
--- a/src/hb-atomic-private.hh
+++ b/src/hb-atomic-private.hh
@@ -42,30 +42,54 @@
#if 0
-#elif !defined(HB_NO_MT) && defined(_MSC_VER) && _MSC_VER >= 1600
+#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
-#include <intrin.h>
-#pragma intrinsic(_InterlockedExchangeAdd, _InterlockedCompareExchangePointer)
+#include <windows.h>
-typedef long hb_atomic_int_t;
-#define hb_atomic_int_add(AI, V) _InterlockedExchangeAdd (&(AI), (V))
+/* MinGW has a convoluted history of supporting MemoryBarrier
+ * properly. As such, define a function to wrap the whole
+ * thing. */
+static inline void _HBMemoryBarrier (void) {
+#if !defined(MemoryBarrier)
+ long dummy = 0;
+ InterlockedExchange (&dummy, 1);
+#else
+ MemoryBarrier ();
+#endif
+}
-#define hb_atomic_ptr_get(P) (MemoryBarrier (), (void *) *(P))
-#define hb_atomic_ptr_cmpexch(P,O,N) (_InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
+typedef LONG hb_atomic_int_t;
+#define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
+
+#define hb_atomic_ptr_get(P) (_HBMemoryBarrier (), (void *) *(P))
+#define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
#elif !defined(HB_NO_MT) && defined(__APPLE__)
#include <libkern/OSAtomic.h>
+#ifdef __MAC_OS_X_MIN_REQUIRED
+#include <AvailabilityMacros.h>
+#elif defined(__IPHONE_OS_MIN_REQUIRED)
+#include <Availability.h>
+#endif
typedef int32_t hb_atomic_int_t;
#define hb_atomic_int_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
#define hb_atomic_ptr_get(P) (OSMemoryBarrier (), (void *) *(P))
+#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
+#else
+#if __ppc64__ || __x86_64__ || __aarch64__
+#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
+#else
+#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
+#endif
+#endif
-#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) && !defined(__MINGW32__)
+#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
typedef int hb_atomic_int_t;
#define hb_atomic_int_add(AI, V) __sync_fetch_and_add (&(AI), (V))
@@ -73,18 +97,17 @@ typedef int hb_atomic_int_t;
#define hb_atomic_ptr_get(P) (void *) (__sync_synchronize (), *(P))
#define hb_atomic_ptr_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
-#elif !defined(HB_NO_MT) && defined(HAVE_GLIB)
-#include <glib.h>
-typedef int hb_atomic_int_t;
-#if GLIB_CHECK_VERSION(2,29,5)
-#define hb_atomic_int_add(AI, V) g_atomic_int_add (&(AI), (V))
-#else
-#define hb_atomic_int_add(AI, V) g_atomic_int_exchange_and_add (&(AI), (V))
-#endif
+#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
+
+#include <atomic.h>
+#include <mbarrier.h>
+
+typedef unsigned int hb_atomic_int_t;
+#define hb_atomic_int_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
-#define hb_atomic_ptr_get(P) g_atomic_pointer_get (P)
-#define hb_atomic_ptr_cmpexch(P,O,N) g_atomic_pointer_compare_and_exchange ((void **) (P), (void *) (O), (void *) (N))
+#define hb_atomic_ptr_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P))
+#define hb_atomic_ptr_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
#elif !defined(HB_NO_MT)
diff --git a/src/hb-blob.cc b/src/hb-blob.cc
index 3cc2d9d..8759a25 100644
--- a/src/hb-blob.cc
+++ b/src/hb-blob.cc
@@ -24,9 +24,13 @@
* Red Hat Author(s): Behdad Esfahbod
*/
+/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 199309L
+#endif
+
#include "hb-private.hh"
-#include "hb-blob.h"
#include "hb-object-private.hh"
#ifdef HAVE_SYS_MMAN_H
@@ -46,7 +50,7 @@
#endif
-struct _hb_blob_t {
+struct hb_blob_t {
hb_object_header_t header;
ASSERT_POD ();
@@ -73,6 +77,22 @@ _hb_blob_destroy_user_data (hb_blob_t *blob)
}
}
+/**
+ * hb_blob_create: (skip)
+ * @data: Pointer to blob data.
+ * @length: Length of @data in bytes.
+ * @mode: Memory mode for @data.
+ * @user_data: Data parameter to pass to @destroy.
+ * @destroy: Callback to call when @data is not needed anymore.
+ *
+ * Creates a new "blob" object wrapping @data. The @mode parameter is used
+ * to negotiate ownership and lifecycle of @data.
+ *
+ * Return value: New blob, or the empty blob if something failed or if @length is
+ * zero. Destroy with hb_blob_destroy().
+ *
+ * Since: 1.0
+ **/
hb_blob_t *
hb_blob_create (const char *data,
unsigned int length,
@@ -82,7 +102,10 @@ hb_blob_create (const char *data,
{
hb_blob_t *blob;
- if (!length || !(blob = hb_object_create<hb_blob_t> ())) {
+ if (!length ||
+ length >= 1u << 31 ||
+ data + length < data /* overflows */ ||
+ !(blob = hb_object_create<hb_blob_t> ())) {
if (destroy)
destroy (user_data);
return hb_blob_get_empty ();
@@ -106,6 +129,26 @@ hb_blob_create (const char *data,
return blob;
}
+/**
+ * hb_blob_create_sub_blob:
+ * @parent: Parent blob.
+ * @offset: Start offset of sub-blob within @parent, in bytes.
+ * @length: Length of sub-blob.
+ *
+ * Returns a blob that represents a range of bytes in @parent. The new
+ * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it
+ * will never modify data in the parent blob. The parent data is not
+ * expected to be modified, and will result in undefined behavior if it
+ * is.
+ *
+ * Makes @parent immutable.
+ *
+ * Return value: New blob, or the empty blob if something failed or if
+ * @length is zero or @offset is beyond the end of @parent's data. Destroy
+ * with hb_blob_destroy().
+ *
+ * Since: 1.0
+ **/
hb_blob_t *
hb_blob_create_sub_blob (hb_blob_t *parent,
unsigned int offset,
@@ -120,13 +163,24 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
blob = hb_blob_create (parent->data + offset,
MIN (length, parent->length - offset),
- parent->mode,
+ HB_MEMORY_MODE_READONLY,
hb_blob_reference (parent),
(hb_destroy_func_t) hb_blob_destroy);
return blob;
}
+/**
+ * hb_blob_get_empty:
+ *
+ * Returns the singleton empty blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: (transfer full): the empty blob.
+ *
+ * Since: 1.0
+ **/
hb_blob_t *
hb_blob_get_empty (void)
{
@@ -146,12 +200,36 @@ hb_blob_get_empty (void)
return const_cast<hb_blob_t *> (&_hb_blob_nil);
}
+/**
+ * hb_blob_reference: (skip)
+ * @blob: a blob.
+ *
+ * Increases the reference count on @blob.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Return value: @blob.
+ *
+ * Since: 1.0
+ **/
hb_blob_t *
hb_blob_reference (hb_blob_t *blob)
{
return hb_object_reference (blob);
}
+/**
+ * hb_blob_destroy: (skip)
+ * @blob: a blob.
+ *
+ * Descreases the reference count on @blob, and if it reaches zero, destroys
+ * @blob, freeing all memory, possibly calling the destroy-callback the blob
+ * was created for if it has not been called already.
+ *
+ * See TODO:link object types for more information.
+ *
+ * Since: 1.0
+ **/
void
hb_blob_destroy (hb_blob_t *blob)
{
@@ -162,6 +240,18 @@ hb_blob_destroy (hb_blob_t *blob)
free (blob);
}
+/**
+ * hb_blob_set_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to set.
+ * @data: data to set.
+ * @destroy: callback to call when @data is not needed anymore.
+ * @replace: whether to replace an existing data with the same key.
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_blob_set_user_data (hb_blob_t *blob,
hb_user_data_key_t *key,
@@ -172,6 +262,17 @@ hb_blob_set_user_data (hb_blob_t *blob,
return hb_object_set_user_data (blob, key, data, destroy, replace);
}
+/**
+ * hb_blob_get_user_data: (skip)
+ * @blob: a blob.
+ * @key: key for data to get.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
void *
hb_blob_get_user_data (hb_blob_t *blob,
hb_user_data_key_t *key)
@@ -180,6 +281,14 @@ hb_blob_get_user_data (hb_blob_t *blob,
}
+/**
+ * hb_blob_make_immutable:
+ * @blob: a blob.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_blob_make_immutable (hb_blob_t *blob)
{
@@ -189,6 +298,16 @@ hb_blob_make_immutable (hb_blob_t *blob)
blob->immutable = true;
}
+/**
+ * hb_blob_is_immutable:
+ * @blob: a blob.
+ *
+ *
+ *
+ * Return value: TODO
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_blob_is_immutable (hb_blob_t *blob)
{
@@ -196,12 +315,33 @@ hb_blob_is_immutable (hb_blob_t *blob)
}
+/**
+ * hb_blob_get_length:
+ * @blob: a blob.
+ *
+ *
+ *
+ * Return value: the length of blob data in bytes.
+ *
+ * Since: 1.0
+ **/
unsigned int
hb_blob_get_length (hb_blob_t *blob)
{
return blob->length;
}
+/**
+ * hb_blob_get_data:
+ * @blob: a blob.
+ * @length: (out):
+ *
+ *
+ *
+ * Returns: (transfer none) (array length=length):
+ *
+ * Since: 1.0
+ **/
const char *
hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
{
@@ -211,6 +351,22 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
return blob->data;
}
+/**
+ * hb_blob_get_data_writable:
+ * @blob: a blob.
+ * @length: (out): output length of the writable data.
+ *
+ * Tries to make blob data writable (possibly copying it) and
+ * return pointer to data.
+ *
+ * Fails if blob has been made immutable, or if memory allocation
+ * fails.
+ *
+ * Returns: (transfer none) (array length=length): Writable blob data,
+ * or %NULL if failed.
+ *
+ * Since: 1.0
+ **/
char *
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
{
@@ -321,5 +477,3 @@ _try_writable (hb_blob_t *blob)
return true;
}
-
-
diff --git a/src/hb-blob.h b/src/hb-blob.h
index 360310b..b2419ab 100644
--- a/src/hb-blob.h
+++ b/src/hb-blob.h
@@ -36,6 +36,25 @@
HB_BEGIN_DECLS
+/*
+ * Note re various memory-modes:
+ *
+ * - In no case shall the HarfBuzz client modify memory
+ * that is passed to HarfBuzz in a blob. If there is
+ * any such possibility, MODE_DUPLICATE should be used
+ * such that HarfBuzz makes a copy immediately,
+ *
+ * - Use MODE_READONLY otherse, unless you really really
+ * really know what you are doing,
+ *
+ * - MODE_WRITABLE is appropriate if you really made a
+ * copy of data solely for the purpose of passing to
+ * HarfBuzz and doing that just once (no reuse!),
+ *
+ * - If the font is mmap()ed, it's ok to use
+ * READONLY_MAY_MAKE_WRITABLE, however, using that mode
+ * correctly is very tricky. Use MODE_READONLY instead.
+ */
typedef enum {
HB_MEMORY_MODE_DUPLICATE,
HB_MEMORY_MODE_READONLY,
@@ -43,7 +62,7 @@ typedef enum {
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
} hb_memory_mode_t;
-typedef struct _hb_blob_t hb_blob_t;
+typedef struct hb_blob_t hb_blob_t;
hb_blob_t *
hb_blob_create (const char *data,
@@ -52,6 +71,12 @@ hb_blob_create (const char *data,
void *user_data,
hb_destroy_func_t destroy);
+/* Always creates with MEMORY_MODE_READONLY.
+ * Even if the parent blob is writable, we don't
+ * want the user of the sub-blob to be able to
+ * modify the parent data as that data may be
+ * shared among multiple sub-blobs.
+ */
hb_blob_t *
hb_blob_create_sub_blob (hb_blob_t *parent,
unsigned int offset,
diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl
new file mode 100644
index 0000000..91b350f
--- /dev/null
+++ b/src/hb-buffer-deserialize-json.rl
@@ -0,0 +1,132 @@
+/*
+ * Copyright © 2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
+#define HB_BUFFER_DESERIALIZE_JSON_HH
+
+#include "hb-private.hh"
+
+%%{
+
+machine deserialize_json;
+alphtype unsigned char;
+write data;
+
+action clear_item {
+ memset (&info, 0, sizeof (info));
+ memset (&pos , 0, sizeof (pos ));
+}
+
+action add_item {
+ buffer->add_info (info);
+ if (buffer->in_error)
+ return false;
+ buffer->pos[buffer->len - 1] = pos;
+ *end_ptr = p;
+}
+
+action tok {
+ tok = p;
+}
+
+action parse_glyph {
+ if (!hb_font_glyph_from_string (font,
+ tok, p - tok,
+ &info.codepoint))
+ return false;
+}
+
+action parse_gid { if (!parse_uint (tok, p, &info.codepoint)) return false; }
+action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+
+unum = '0' | [1-9] digit*;
+num = '-'? unum;
+
+comma = space* ',' space*;
+colon = space* ':' space*;
+
+glyph_id = unum;
+glyph_name = alpha (alnum|'_'|'.'|'-')*;
+
+glyph_string = '"' (glyph_name >tok %parse_glyph) '"';
+glyph_number = (glyph_id >tok %parse_gid);
+
+glyph = "\"g\"" colon (glyph_string | glyph_number);
+cluster = "\"cl\"" colon (unum >tok %parse_cluster);
+xoffset = "\"dx\"" colon (num >tok %parse_x_offset);
+yoffset = "\"dy\"" colon (num >tok %parse_y_offset);
+xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
+yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
+
+element = glyph | cluster | xoffset | yoffset | xadvance | yadvance;
+item =
+ ( '{' space* element (comma element)* space* '}')
+ >clear_item
+ @add_item
+ ;
+
+main := space* item (comma item)* space* (','|']')?;
+
+}%%
+
+static hb_bool_t
+_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
+ const char *buf,
+ unsigned int buf_len,
+ const char **end_ptr,
+ hb_font_t *font)
+{
+ const char *p = buf, *pe = buf + buf_len;
+
+ /* Ensure we have positions. */
+ (void) hb_buffer_get_glyph_positions (buffer, NULL);
+
+ while (p < pe && ISSPACE (*p))
+ p++;
+ if (p < pe && *p == (buffer->len ? ',' : '['))
+ {
+ *end_ptr = ++p;
+ }
+
+ const char *tok = NULL;
+ int cs;
+ hb_glyph_info_t info = {0};
+ hb_glyph_position_t pos = {0};
+ %%{
+ write init;
+ write exec;
+ }%%
+
+ *end_ptr = p;
+
+ return p == pe && *(p-1) != ']';
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl
new file mode 100644
index 0000000..8a682f7
--- /dev/null
+++ b/src/hb-buffer-deserialize-text.rl
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_HH
+
+#include "hb-private.hh"
+
+%%{
+
+machine deserialize_text;
+alphtype unsigned char;
+write data;
+
+action clear_item {
+ memset (&info, 0, sizeof (info));
+ memset (&pos , 0, sizeof (pos ));
+}
+
+action add_item {
+ buffer->add_info (info);
+ if (buffer->in_error)
+ return false;
+ buffer->pos[buffer->len - 1] = pos;
+ *end_ptr = p;
+}
+
+action tok {
+ tok = p;
+}
+
+action parse_glyph {
+ if (!hb_font_glyph_from_string (font,
+ tok, p - tok,
+ &info.codepoint))
+ return false;
+}
+
+action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
+action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
+action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
+action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
+action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
+
+unum = '0' | [1-9] digit*;
+num = '-'? unum;
+
+glyph_id = unum;
+glyph_name = alpha (alnum|'_'|'.'|'-')*;
+
+glyph = (glyph_id | glyph_name) >tok %parse_glyph;
+cluster = '=' (unum >tok %parse_cluster);
+offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset );
+advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
+item =
+ (
+ glyph
+ cluster?
+ offsets?
+ advances?
+ )
+ >clear_item
+ %add_item
+ ;
+
+main := space* item (space* '|' space* item)* space* ('|'|']')?;
+
+}%%
+
+static hb_bool_t
+_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
+ const char *buf,
+ unsigned int buf_len,
+ const char **end_ptr,
+ hb_font_t *font)
+{
+ const char *p = buf, *pe = buf + buf_len;
+
+ /* Ensure we have positions. */
+ (void) hb_buffer_get_glyph_positions (buffer, NULL);
+
+ while (p < pe && ISSPACE (*p))
+ p++;
+ if (p < pe && *p == (buffer->len ? '|' : '['))
+ {
+ *end_ptr = ++p;
+ }
+
+ const char *eof = pe, *tok = NULL;
+ int cs;
+ hb_glyph_info_t info = {0};
+ hb_glyph_position_t pos = {0};
+ %%{
+ write init;
+ write exec;
+ }%%
+
+ *end_ptr = p;
+
+ return p == pe && *(p-1) != ']';
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */
diff --git a/src/hb-buffer-private.hh b/src/hb-buffer-private.hh
index b539f26..069f925 100644
--- a/src/hb-buffer-private.hh
+++ b/src/hb-buffer-private.hh
@@ -1,7 +1,7 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009,2010 Red Hat, Inc.
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -31,33 +31,30 @@
#define HB_BUFFER_PRIVATE_HH
#include "hb-private.hh"
-#include "hb-buffer.h"
#include "hb-object-private.hh"
#include "hb-unicode-private.hh"
-
ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
-typedef struct _hb_segment_properties_t {
- hb_direction_t direction;
- hb_script_t script;
- hb_language_t language;
- ASSERT_POD ();
-} hb_segment_properties_t;
+/*
+ * hb_buffer_t
+ */
-struct _hb_buffer_t {
+struct hb_buffer_t {
hb_object_header_t header;
ASSERT_POD ();
/* Information about how the text in the buffer should be treated */
-
hb_unicode_funcs_t *unicode; /* Unicode functions */
- hb_segment_properties_t props; /* Script, language, direction */
+ hb_buffer_flags_t flags; /* BOT / EOT / etc. */
+ hb_codepoint_t replacement; /* U+FFFD or something else. */
/* Buffer contents */
+ hb_buffer_content_type_t content_type;
+ hb_segment_properties_t props; /* Script, language, direction */
bool in_error; /* Allocation failed */
bool have_output; /* Whether we have an output buffer going on */
@@ -81,49 +78,80 @@ struct _hb_buffer_t {
inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; }
inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; }
+ inline bool has_separate_output (void) const { return info != out_info; }
+
unsigned int serial;
+
+ /* These reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
uint8_t allocated_var_bytes[8];
const char *allocated_var_owner[8];
+ /* Text before / after the main buffer contents.
+ * Always in Unicode, and ordered outward.
+ * Index 0 is for "pre-context", 1 for "post-context". */
+ static const unsigned int CONTEXT_LENGTH = 5;
+ hb_codepoint_t context[2][CONTEXT_LENGTH];
+ unsigned int context_len[2];
+
/* Methods */
HB_INTERNAL void reset (void);
+ HB_INTERNAL void clear (void);
inline unsigned int backtrack_len (void) const
{ return have_output? out_len : idx; }
+ inline unsigned int lookahead_len (void) const
+ { return len - idx; }
inline unsigned int next_serial (void) { return serial++; }
HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner);
HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner);
+ HB_INTERNAL void assert_var (unsigned int byte_i, unsigned int count, const char *owner);
HB_INTERNAL void deallocate_var_all (void);
HB_INTERNAL void add (hb_codepoint_t codepoint,
- hb_mask_t mask,
unsigned int cluster);
+ HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
HB_INTERNAL void reverse (void);
HB_INTERNAL void reverse_clusters (void);
- HB_INTERNAL void guess_properties (void);
+ HB_INTERNAL void guess_segment_properties (void);
HB_INTERNAL void swap_buffers (void);
+ HB_INTERNAL void remove_output (void);
HB_INTERNAL void clear_output (void);
HB_INTERNAL void clear_positions (void);
- HB_INTERNAL void replace_glyphs_be16 (unsigned int num_in,
- unsigned int num_out,
- const uint16_t *glyph_data_be);
+
HB_INTERNAL void replace_glyphs (unsigned int num_in,
unsigned int num_out,
const hb_codepoint_t *glyph_data);
+
HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
/* Makes a copy of the glyph at idx to output and replace glyph_index */
HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
+ HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info);
/* Copies glyph at idx to output but doesn't advance idx */
HB_INTERNAL void copy_glyph (void);
+ HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
/* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */
- HB_INTERNAL void next_glyph (void);
+ inline void
+ next_glyph (void)
+ {
+ if (have_output)
+ {
+ if (unlikely (out_info != info || out_len != idx)) {
+ if (unlikely (!make_room_for (1, 1))) return;
+ out_info[out_len] = info[idx];
+ }
+ out_len++;
+ }
+
+ idx++;
+ }
+
/* Advance idx without copying to output. */
inline void skip_glyph (void) { idx++; }
@@ -151,11 +179,18 @@ struct _hb_buffer_t {
HB_INTERNAL bool enlarge (unsigned int size);
inline bool ensure (unsigned int size)
- { return likely (size <= allocated) ? true : enlarge (size); }
+ { return likely (!size || size < allocated) ? true : enlarge (size); }
+
+ inline bool ensure_inplace (unsigned int size)
+ { return likely (!size || size < allocated); }
HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
+ HB_INTERNAL bool shift_forward (unsigned int count);
- HB_INTERNAL void *get_scratch_buffer (unsigned int *size);
+ typedef long scratch_buffer_t;
+ HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
+
+ inline void clear_context (unsigned int side) { context_len[side] = 0; }
};
@@ -166,7 +201,8 @@ struct _hb_buffer_t {
HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var)
#define HB_BUFFER_DEALLOCATE_VAR(b, var) \
HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var)
-
+#define HB_BUFFER_ASSERT_VAR(b, var) \
+ HB_BUFFER_XALLOCATE_VAR (b, assert_var, var (), #var)
#endif /* HB_BUFFER_PRIVATE_HH */
diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc
new file mode 100644
index 0000000..406d69d
--- /dev/null
+++ b/src/hb-buffer-serialize.cc
@@ -0,0 +1,399 @@
+/*
+ * Copyright © 2012,2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-buffer-private.hh"
+
+
+static const char *serialize_formats[] = {
+ "text",
+ "json",
+ NULL
+};
+
+/**
+ * hb_buffer_serialize_list_formats:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+const char **
+hb_buffer_serialize_list_formats (void)
+{
+ return serialize_formats;
+}
+
+/**
+ * hb_buffer_serialize_format_from_string:
+ * @str:
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len)
+{
+ /* Upper-case it. */
+ return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u);
+}
+
+/**
+ * hb_buffer_serialize_format_to_string:
+ * @format:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
+{
+ switch (format)
+ {
+ case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
+ case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
+ default:
+ case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL;
+ }
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+ unsigned int *buf_consumed,
+ hb_font_t *font,
+ hb_buffer_serialize_flags_t flags)
+{
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+ hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+
+ *buf_consumed = 0;
+ for (unsigned int i = start; i < end; i++)
+ {
+ char b[1024];
+ char *p = b;
+
+ /* In the following code, we know b is large enough that no overflow can happen. */
+
+#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END
+
+ if (i)
+ *p++ = ',';
+
+ *p++ = '{';
+
+ APPEND ("\"g\":");
+ if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+ {
+ char g[128];
+ hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
+ *p++ = '"';
+ for (char *q = g; *q; q++) {
+ if (*q == '"')
+ *p++ = '\\';
+ *p++ = *q;
+ }
+ *p++ = '"';
+ }
+ else
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+
+ if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
+ }
+
+ if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+ {
+ p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
+ pos[i].x_offset, pos[i].y_offset);
+ p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
+ pos[i].x_advance, pos[i].y_advance);
+ }
+
+ *p++ = '}';
+
+ unsigned int l = p - b;
+ if (buf_size > l)
+ {
+ memcpy (buf, b, l);
+ buf += l;
+ buf_size -= l;
+ *buf_consumed += l;
+ *buf = '\0';
+ } else
+ return i - start;
+ }
+
+ return end - start;
+}
+
+static unsigned int
+_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+ unsigned int *buf_consumed,
+ hb_font_t *font,
+ hb_buffer_serialize_flags_t flags)
+{
+ hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
+ hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL);
+
+ *buf_consumed = 0;
+ for (unsigned int i = start; i < end; i++)
+ {
+ char b[1024];
+ char *p = b;
+
+ /* In the following code, we know b is large enough that no overflow can happen. */
+
+ if (i)
+ *p++ = '|';
+
+ if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES))
+ {
+ hb_font_glyph_to_string (font, info[i].codepoint, p, 128);
+ p += strlen (p);
+ }
+ else
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
+
+ if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
+ }
+
+ if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
+ {
+ if (pos[i].x_offset || pos[i].y_offset)
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
+
+ *p++ = '+';
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
+ if (pos[i].y_advance)
+ p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
+ }
+
+ unsigned int l = p - b;
+ if (buf_size > l)
+ {
+ memcpy (buf, b, l);
+ buf += l;
+ buf_size -= l;
+ *buf_consumed += l;
+ *buf = '\0';
+ } else
+ return i - start;
+ }
+
+ return end - start;
+}
+
+/* Returns number of items, starting at start, that were serialized. */
+/**
+ * hb_buffer_serialize_glyphs:
+ * @buffer: a buffer.
+ * @start:
+ * @end:
+ * @buf: (array length=buf_size):
+ * @buf_size:
+ * @buf_consumed: (out):
+ * @font:
+ * @format:
+ * @flags:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+ unsigned int *buf_consumed, /* May be NULL */
+ hb_font_t *font, /* May be NULL */
+ hb_buffer_serialize_format_t format,
+ hb_buffer_serialize_flags_t flags)
+{
+ assert (start <= end && end <= buffer->len);
+
+ unsigned int sconsumed;
+ if (!buf_consumed)
+ buf_consumed = &sconsumed;
+ *buf_consumed = 0;
+
+ assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+ buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+ if (unlikely (start == end))
+ return 0;
+
+ if (!font)
+ font = hb_font_get_empty ();
+
+ switch (format)
+ {
+ case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+ return _hb_buffer_serialize_glyphs_text (buffer, start, end,
+ buf, buf_size, buf_consumed,
+ font, flags);
+
+ case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+ return _hb_buffer_serialize_glyphs_json (buffer, start, end,
+ buf, buf_size, buf_consumed,
+ font, flags);
+
+ default:
+ case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+ return 0;
+
+ }
+}
+
+
+static hb_bool_t
+parse_uint (const char *pp, const char *end, uint32_t *pv)
+{
+ char buf[32];
+ unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+ strncpy (buf, pp, len);
+ buf[len] = '\0';
+
+ char *p = buf;
+ char *pend = p;
+ uint32_t v;
+
+ errno = 0;
+ v = strtol (p, &pend, 10);
+ if (errno || p == pend || pend - p != end - pp)
+ return false;
+
+ *pv = v;
+ return true;
+}
+
+static hb_bool_t
+parse_int (const char *pp, const char *end, int32_t *pv)
+{
+ char buf[32];
+ unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
+ strncpy (buf, pp, len);
+ buf[len] = '\0';
+
+ char *p = buf;
+ char *pend = p;
+ int32_t v;
+
+ errno = 0;
+ v = strtol (p, &pend, 10);
+ if (errno || p == pend || pend - p != end - pp)
+ return false;
+
+ *pv = v;
+ return true;
+}
+
+#include "hb-buffer-deserialize-json.hh"
+#include "hb-buffer-deserialize-text.hh"
+
+/**
+ * hb_buffer_deserialize_glyphs:
+ * @buffer: a buffer.
+ * @buf: (array length=buf_len):
+ * @buf_len:
+ * @end_ptr: (out):
+ * @font:
+ * @format:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+ const char *buf,
+ int buf_len, /* -1 means nul-terminated */
+ const char **end_ptr, /* May be NULL */
+ hb_font_t *font, /* May be NULL */
+ hb_buffer_serialize_format_t format)
+{
+ const char *end;
+ if (!end_ptr)
+ end_ptr = &end;
+ *end_ptr = buf;
+
+ assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
+ buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+ if (buf_len == -1)
+ buf_len = strlen (buf);
+
+ if (!buf_len)
+ {
+ *end_ptr = buf;
+ return false;
+ }
+
+ hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+ if (!font)
+ font = hb_font_get_empty ();
+
+ switch (format)
+ {
+ case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
+ return _hb_buffer_deserialize_glyphs_text (buffer,
+ buf, buf_len, end_ptr,
+ font);
+
+ case HB_BUFFER_SERIALIZE_FORMAT_JSON:
+ return _hb_buffer_deserialize_glyphs_json (buffer,
+ buf, buf_len, end_ptr,
+ font);
+
+ default:
+ case HB_BUFFER_SERIALIZE_FORMAT_INVALID:
+ return false;
+
+ }
+}
diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc
index e2c34f1..b9fe263 100644
--- a/src/hb-buffer.cc
+++ b/src/hb-buffer.cc
@@ -1,7 +1,7 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009,2010 Red Hat, Inc.
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -28,17 +28,35 @@
*/
#include "hb-buffer-private.hh"
-
-#include <string.h>
-
+#include "hb-utf-private.hh"
#ifndef HB_DEBUG_BUFFER
#define HB_DEBUG_BUFFER (HB_DEBUG+0)
#endif
-#define _HB_BUFFER_UNICODE_FUNCS_DEFAULT (const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default))
-#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID }
+
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+ const hb_segment_properties_t *b)
+{
+ return a->direction == b->direction &&
+ a->script == b->script &&
+ a->language == b->language &&
+ a->reserved1 == b->reserved1 &&
+ a->reserved2 == b->reserved2;
+
+}
+
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p)
+{
+ return (unsigned int) p->direction ^
+ (unsigned int) p->script ^
+ (intptr_t) (p->language);
+}
+
+
/* Here is how the buffer works internally:
*
@@ -76,7 +94,7 @@ hb_buffer_t::enlarge (unsigned int size)
if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
goto done;
- while (size > new_allocated)
+ while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 32;
ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
@@ -121,17 +139,35 @@ hb_buffer_t::make_room_for (unsigned int num_in,
return true;
}
-void *
+bool
+hb_buffer_t::shift_forward (unsigned int count)
+{
+ assert (have_output);
+ if (unlikely (!ensure (len + count))) return false;
+
+ memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
+ len += count;
+ idx += count;
+
+ return true;
+}
+
+hb_buffer_t::scratch_buffer_t *
hb_buffer_t::get_scratch_buffer (unsigned int *size)
{
have_output = false;
have_positions = false;
+
out_len = 0;
- *size = allocated * sizeof (pos[0]);
- return pos;
+ out_info = info;
+
+ assert ((uintptr_t) pos % sizeof (scratch_buffer_t) == 0);
+ *size = allocated * sizeof (pos[0]) / sizeof (scratch_buffer_t);
+ return (scratch_buffer_t *) (void *) pos;
}
+
/* HarfBuzz-Internal API */
void
@@ -141,11 +177,23 @@ hb_buffer_t::reset (void)
return;
hb_unicode_funcs_destroy (unicode);
- unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT;
+ unicode = hb_unicode_funcs_get_default ();
+ flags = HB_BUFFER_FLAG_DEFAULT;
+ replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+
+ clear ();
+}
+
+void
+hb_buffer_t::clear (void)
+{
+ if (unlikely (hb_object_is_inert (this)))
+ return;
- hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT;
+ hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
props = default_props;
+ content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
in_error = false;
have_output = false;
have_positions = false;
@@ -153,17 +201,18 @@ hb_buffer_t::reset (void)
idx = 0;
len = 0;
out_len = 0;
+ out_info = info;
serial = 0;
memset (allocated_var_bytes, 0, sizeof allocated_var_bytes);
memset (allocated_var_owner, 0, sizeof allocated_var_owner);
- out_info = info;
+ memset (context, 0, sizeof context);
+ memset (context_len, 0, sizeof context_len);
}
void
hb_buffer_t::add (hb_codepoint_t codepoint,
- hb_mask_t mask,
unsigned int cluster)
{
hb_glyph_info_t *glyph;
@@ -174,13 +223,37 @@ hb_buffer_t::add (hb_codepoint_t codepoint,
memset (glyph, 0, sizeof (*glyph));
glyph->codepoint = codepoint;
- glyph->mask = mask;
+ glyph->mask = 1;
glyph->cluster = cluster;
len++;
}
void
+hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
+{
+ if (unlikely (!ensure (len + 1))) return;
+
+ info[len] = glyph_info;
+
+ len++;
+}
+
+
+void
+hb_buffer_t::remove_output (void)
+{
+ if (unlikely (hb_object_is_inert (this)))
+ return;
+
+ have_output = false;
+ have_positions = false;
+
+ out_len = 0;
+ out_info = info;
+}
+
+void
hb_buffer_t::clear_output (void)
{
if (unlikely (hb_object_is_inert (this)))
@@ -202,6 +275,9 @@ hb_buffer_t::clear_positions (void)
have_output = false;
have_positions = true;
+ out_len = 0;
+ out_info = info;
+
memset (pos, 0, sizeof (pos[0]) * len);
}
@@ -230,46 +306,17 @@ hb_buffer_t::swap_buffers (void)
idx = 0;
}
-void
-hb_buffer_t::replace_glyphs_be16 (unsigned int num_in,
- unsigned int num_out,
- const uint16_t *glyph_data_be)
-{
- if (!make_room_for (num_in, num_out)) return;
-
- hb_glyph_info_t orig_info = info[idx];
- for (unsigned int i = 1; i < num_in; i++)
- {
- hb_glyph_info_t *inf = &info[idx + i];
- orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
- }
-
- hb_glyph_info_t *pinfo = &out_info[out_len];
- for (unsigned int i = 0; i < num_out; i++)
- {
- *pinfo = orig_info;
- pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]);
- pinfo++;
- }
-
- idx += num_in;
- out_len += num_out;
-}
void
hb_buffer_t::replace_glyphs (unsigned int num_in,
unsigned int num_out,
const uint32_t *glyph_data)
{
- if (!make_room_for (num_in, num_out)) return;
+ if (unlikely (!make_room_for (num_in, num_out))) return;
- hb_glyph_info_t orig_info = info[idx];
- for (unsigned int i = 1; i < num_in; i++)
- {
- hb_glyph_info_t *inf = &info[idx + i];
- orig_info.cluster = MIN (orig_info.cluster, inf->cluster);
- }
+ merge_clusters (idx, idx + num_in);
+ hb_glyph_info_t orig_info = info[idx];
hb_glyph_info_t *pinfo = &out_info[out_len];
for (unsigned int i = 0; i < num_out; i++)
{
@@ -285,7 +332,7 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
void
hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
{
- if (!make_room_for (0, 1)) return;
+ if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = info[idx];
out_info[out_len].codepoint = glyph_index;
@@ -294,46 +341,77 @@ hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
}
void
-hb_buffer_t::copy_glyph (void)
+hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
{
- if (!make_room_for (0, 1)) return;
+ if (unlikely (!make_room_for (0, 1))) return;
- out_info[out_len] = info[idx];
+ out_info[out_len] = glyph_info;
out_len++;
}
void
-hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+hb_buffer_t::copy_glyph (void)
{
- if (!make_room_for (1, 1)) return;
+ if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = info[idx];
- out_info[out_len].codepoint = glyph_index;
- idx++;
out_len++;
}
-void
-hb_buffer_t::next_glyph (void)
+bool
+hb_buffer_t::move_to (unsigned int i)
{
- if (have_output)
+ if (!have_output)
{
- if (out_info != info)
- {
- if (unlikely (!ensure (out_len + 1))) return;
- out_info[out_len] = info[idx];
- }
- else if (out_len != idx)
- out_info[out_len] = info[idx];
+ assert (i <= len);
+ idx = i;
+ return true;
+ }
- out_len++;
+ assert (i <= out_len + (len - idx));
+
+ if (out_len < i)
+ {
+ unsigned int count = i - out_len;
+ if (unlikely (!make_room_for (count, count))) return false;
+
+ memmove (out_info + out_len, info + idx, count * sizeof (out_info[0]));
+ idx += count;
+ out_len += count;
+ }
+ else if (out_len > i)
+ {
+ /* Tricky part: rewinding... */
+ unsigned int count = out_len - i;
+
+ if (unlikely (idx < count && !shift_forward (count + 32))) return false;
+
+ assert (idx >= count);
+
+ idx -= count;
+ out_len -= count;
+ memmove (info + idx, out_info + out_len, count * sizeof (out_info[0]));
}
+ return true;
+}
+
+void
+hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
+{
+ if (unlikely (out_info != info || out_len != idx)) {
+ if (unlikely (!make_room_for (1, 1))) return;
+ out_info[out_len] = info[idx];
+ }
+ out_info[out_len].codepoint = glyph_index;
+
idx++;
+ out_len++;
}
+
void
hb_buffer_t::set_masks (hb_mask_t value,
hb_mask_t mask,
@@ -365,7 +443,7 @@ hb_buffer_t::reverse_range (unsigned int start,
{
unsigned int i, j;
- if (start == end - 1)
+ if (end - start < 2)
return;
for (i = start, j = end - 1; i < j; i++, j--) {
@@ -376,7 +454,7 @@ hb_buffer_t::reverse_range (unsigned int start,
info[j] = t;
}
- if (pos) {
+ if (have_positions) {
for (i = start, j = end - 1; i < j; i++, j--) {
hb_glyph_position_t t;
@@ -423,32 +501,77 @@ void
hb_buffer_t::merge_clusters (unsigned int start,
unsigned int end)
{
- unsigned int cluster = this->info[start].cluster;
+#ifdef HB_NO_MERGE_CLUSTERS
+ return;
+#endif
+
+ if (unlikely (end - start < 2))
+ return;
+
+ unsigned int cluster = info[start].cluster;
for (unsigned int i = start + 1; i < end; i++)
- cluster = MIN (cluster, this->info[i].cluster);
+ cluster = MIN (cluster, info[i].cluster);
+
+ /* Extend end */
+ while (end < len && info[end - 1].cluster == info[end].cluster)
+ end++;
+
+ /* Extend start */
+ while (idx < start && info[start - 1].cluster == info[start].cluster)
+ start--;
+
+ /* If we hit the start of buffer, continue in out-buffer. */
+ if (idx == start)
+ for (unsigned i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
+ out_info[i - 1].cluster = cluster;
+
for (unsigned int i = start; i < end; i++)
- this->info[i].cluster = cluster;
+ info[i].cluster = cluster;
}
void
hb_buffer_t::merge_out_clusters (unsigned int start,
unsigned int end)
{
- unsigned int cluster = this->out_info[start].cluster;
+#ifdef HB_NO_MERGE_CLUSTERS
+ return;
+#endif
+
+ if (unlikely (end - start < 2))
+ return;
+
+ unsigned int cluster = out_info[start].cluster;
for (unsigned int i = start + 1; i < end; i++)
- cluster = MIN (cluster, this->out_info[i].cluster);
+ cluster = MIN (cluster, out_info[i].cluster);
+
+ /* Extend start */
+ while (start && out_info[start - 1].cluster == out_info[start].cluster)
+ start--;
+
+ /* Extend end */
+ while (end < out_len && out_info[end - 1].cluster == out_info[end].cluster)
+ end++;
+
+ /* If we hit the end of out-buffer, continue in buffer. */
+ if (end == out_len)
+ for (unsigned i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
+ info[i].cluster = cluster;
+
for (unsigned int i = start; i < end; i++)
- this->out_info[i].cluster = cluster;
+ out_info[i].cluster = cluster;
}
void
-hb_buffer_t::guess_properties (void)
+hb_buffer_t::guess_segment_properties (void)
{
+ assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+ (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+
/* If script is set to INVALID, guess from buffer contents */
if (props.script == HB_SCRIPT_INVALID) {
for (unsigned int i = 0; i < len; i++) {
- hb_script_t script = hb_unicode_script (unicode, info[i].codepoint);
+ hb_script_t script = unicode->script (info[i].codepoint);
if (likely (script != HB_SCRIPT_COMMON &&
script != HB_SCRIPT_INHERITED &&
script != HB_SCRIPT_UNKNOWN)) {
@@ -487,7 +610,7 @@ void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const c
{
assert (byte_i < 8 && byte_i + count <= 8);
- if (DEBUG (BUFFER))
+ if (DEBUG_ENABLED (BUFFER))
dump_var_allocation (this);
DEBUG_MSG (BUFFER, this,
"Allocating var bytes %d..%d for %s",
@@ -502,7 +625,7 @@ void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const c
void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner)
{
- if (DEBUG (BUFFER))
+ if (DEBUG_ENABLED (BUFFER))
dump_var_allocation (this);
DEBUG_MSG (BUFFER, this,
@@ -517,6 +640,22 @@ void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const
}
}
+void hb_buffer_t::assert_var (unsigned int byte_i, unsigned int count, const char *owner)
+{
+ if (DEBUG_ENABLED (BUFFER))
+ dump_var_allocation (this);
+
+ DEBUG_MSG (BUFFER, this,
+ "Asserting var bytes %d..%d for %s",
+ byte_i, byte_i + count - 1, owner);
+
+ assert (byte_i < 8 && byte_i + count <= 8);
+ for (unsigned int i = byte_i; i < byte_i + count; i++) {
+ assert (allocated_var_bytes[i]);
+ assert (0 == strcmp (allocated_var_owner[i], owner));
+ }
+}
+
void hb_buffer_t::deallocate_var_all (void)
{
memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes));
@@ -525,8 +664,17 @@ void hb_buffer_t::deallocate_var_all (void)
/* Public API */
+/**
+ * hb_buffer_create: (Xconstructor)
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
hb_buffer_t *
-hb_buffer_create ()
+hb_buffer_create (void)
{
hb_buffer_t *buffer;
@@ -538,29 +686,61 @@ hb_buffer_create ()
return buffer;
}
+/**
+ * hb_buffer_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_buffer_t *
hb_buffer_get_empty (void)
{
static const hb_buffer_t _hb_buffer_nil = {
HB_OBJECT_HEADER_STATIC,
- _HB_BUFFER_UNICODE_FUNCS_DEFAULT,
- _HB_BUFFER_PROPS_DEFAULT,
+ const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
+ HB_BUFFER_FLAG_DEFAULT,
+ HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
+ HB_BUFFER_CONTENT_TYPE_INVALID,
+ HB_SEGMENT_PROPERTIES_DEFAULT,
true, /* in_error */
true, /* have_output */
true /* have_positions */
+
+ /* Zero is good enough for everything else. */
};
return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
}
+/**
+ * hb_buffer_reference: (skip)
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_buffer_t *
hb_buffer_reference (hb_buffer_t *buffer)
{
return hb_object_reference (buffer);
}
+/**
+ * hb_buffer_destroy: (skip)
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_destroy (hb_buffer_t *buffer)
{
@@ -574,6 +754,20 @@ hb_buffer_destroy (hb_buffer_t *buffer)
free (buffer);
}
+/**
+ * hb_buffer_set_user_data: (skip)
+ * @buffer: a buffer.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key,
@@ -584,6 +778,17 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
return hb_object_set_user_data (buffer, key, data, destroy, replace);
}
+/**
+ * hb_buffer_get_user_data: (skip)
+ * @buffer: a buffer.
+ * @key:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
void *
hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key)
@@ -592,27 +797,89 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
}
+/**
+ * hb_buffer_set_content_type:
+ * @buffer: a buffer.
+ * @content_type:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_content_type (hb_buffer_t *buffer,
+ hb_buffer_content_type_t content_type)
+{
+ buffer->content_type = content_type;
+}
+
+/**
+ * hb_buffer_get_content_type:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_buffer_content_type_t
+hb_buffer_get_content_type (hb_buffer_t *buffer)
+{
+ return buffer->content_type;
+}
+
+
+/**
+ * hb_buffer_set_unicode_funcs:
+ * @buffer: a buffer.
+ * @unicode_funcs:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
- hb_unicode_funcs_t *unicode)
+ hb_unicode_funcs_t *unicode_funcs)
{
if (unlikely (hb_object_is_inert (buffer)))
return;
- if (!unicode)
- unicode = _HB_BUFFER_UNICODE_FUNCS_DEFAULT;
+ if (!unicode_funcs)
+ unicode_funcs = hb_unicode_funcs_get_default ();
- hb_unicode_funcs_reference (unicode);
+
+ hb_unicode_funcs_reference (unicode_funcs);
hb_unicode_funcs_destroy (buffer->unicode);
- buffer->unicode = unicode;
+ buffer->unicode = unicode_funcs;
}
+/**
+ * hb_buffer_get_unicode_funcs:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_unicode_funcs_t *
hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
{
return buffer->unicode;
}
+/**
+ * hb_buffer_set_direction:
+ * @buffer: a buffer.
+ * @direction:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction)
@@ -624,12 +891,31 @@ hb_buffer_set_direction (hb_buffer_t *buffer,
buffer->props.direction = direction;
}
+/**
+ * hb_buffer_get_direction:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_direction_t
hb_buffer_get_direction (hb_buffer_t *buffer)
{
return buffer->props.direction;
}
+/**
+ * hb_buffer_set_script:
+ * @buffer: a buffer.
+ * @script:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_set_script (hb_buffer_t *buffer,
hb_script_t script)
@@ -640,12 +926,31 @@ hb_buffer_set_script (hb_buffer_t *buffer,
buffer->props.script = script;
}
+/**
+ * hb_buffer_get_script:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_script_t
hb_buffer_get_script (hb_buffer_t *buffer)
{
return buffer->props.script;
}
+/**
+ * hb_buffer_set_language:
+ * @buffer: a buffer.
+ * @language:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_set_language (hb_buffer_t *buffer,
hb_language_t language)
@@ -656,40 +961,221 @@ hb_buffer_set_language (hb_buffer_t *buffer,
buffer->props.language = language;
}
+/**
+ * hb_buffer_get_language:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_language_t
hb_buffer_get_language (hb_buffer_t *buffer)
{
return buffer->props.language;
}
+/**
+ * hb_buffer_set_segment_properties:
+ * @buffer: a buffer.
+ * @props:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+ const hb_segment_properties_t *props)
+{
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->props = *props;
+}
+
+/**
+ * hb_buffer_get_segment_properties:
+ * @buffer: a buffer.
+ * @props:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+ hb_segment_properties_t *props)
+{
+ *props = buffer->props;
+}
+
+
+/**
+ * hb_buffer_set_flags:
+ * @buffer: a buffer.
+ * @flags:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_flags (hb_buffer_t *buffer,
+ hb_buffer_flags_t flags)
+{
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->flags = flags;
+}
+
+/**
+ * hb_buffer_get_flags:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer)
+{
+ return buffer->flags;
+}
+
+
+/**
+ * hb_buffer_set_replacement_codepoint:
+ * @buffer: a buffer.
+ * @replacement:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
+ hb_codepoint_t replacement)
+{
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ buffer->replacement = replacement;
+}
+
+/**
+ * hb_buffer_get_replacement_codepoint:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
+{
+ return buffer->replacement;
+}
+
+/**
+ * hb_buffer_reset:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_reset (hb_buffer_t *buffer)
{
buffer->reset ();
}
+/**
+ * hb_buffer_clear_contents:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_clear_contents (hb_buffer_t *buffer)
+{
+ buffer->clear ();
+}
+
+/**
+ * hb_buffer_pre_allocate:
+ * @buffer: a buffer.
+ * @size:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
{
return buffer->ensure (size);
}
+/**
+ * hb_buffer_allocation_successful:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_buffer_allocation_successful (hb_buffer_t *buffer)
{
return !buffer->in_error;
}
+/**
+ * hb_buffer_add:
+ * @buffer: a buffer.
+ * @codepoint:
+ * @cluster:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_add (hb_buffer_t *buffer,
hb_codepoint_t codepoint,
- hb_mask_t mask,
unsigned int cluster)
{
- buffer->add (codepoint, mask, cluster);
+ buffer->add (codepoint, cluster);
+ buffer->clear_context (1);
}
+/**
+ * hb_buffer_set_length:
+ * @buffer: a buffer.
+ * @length:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_buffer_set_length (hb_buffer_t *buffer,
unsigned int length)
@@ -708,16 +1194,45 @@ hb_buffer_set_length (hb_buffer_t *buffer,
}
buffer->len = length;
+
+ if (!length)
+ {
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
+ buffer->clear_context (0);
+ }
+ buffer->clear_context (1);
+
return true;
}
+/**
+ * hb_buffer_get_length:
+ * @buffer: a buffer.
+ *
+ * Returns the number of items in the buffer.
+ *
+ * Return value: buffer length.
+ *
+ * Since: 1.0
+ **/
unsigned int
hb_buffer_get_length (hb_buffer_t *buffer)
{
return buffer->len;
}
-/* Return value valid as long as buffer not modified */
+/**
+ * hb_buffer_get_glyph_infos:
+ * @buffer: a buffer.
+ * @length: (out): output array length.
+ *
+ * Returns buffer glyph information array. Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph information array.
+ *
+ * Since: 1.0
+ **/
hb_glyph_info_t *
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
unsigned int *length)
@@ -728,7 +1243,18 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
return (hb_glyph_info_t *) buffer->info;
}
-/* Return value valid as long as buffer not modified */
+/**
+ * hb_buffer_get_glyph_positions:
+ * @buffer: a buffer.
+ * @length: (out): output length.
+ *
+ * Returns buffer glyph position array. Returned pointer
+ * is valid as long as buffer contents are not modified.
+ *
+ * Return value: (transfer none) (array length=length): buffer glyph position array.
+ *
+ * Since: 1.0
+ **/
hb_glyph_position_t *
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
unsigned int *length)
@@ -742,88 +1268,147 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
return (hb_glyph_position_t *) buffer->pos;
}
+/**
+ * hb_buffer_reverse:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer contents.
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_reverse (hb_buffer_t *buffer)
{
buffer->reverse ();
}
+/**
+ * hb_buffer_reverse_clusters:
+ * @buffer: a buffer.
+ *
+ * Reverses buffer clusters. That is, the buffer contents are
+ * reversed, then each cluster (consecutive items having the
+ * same cluster number) are reversed again.
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_reverse_clusters (hb_buffer_t *buffer)
{
buffer->reverse_clusters ();
}
+/**
+ * hb_buffer_guess_segment_properties:
+ * @buffer: a buffer.
+ *
+ * Sets unset buffer segment properties based on buffer Unicode
+ * contents. If buffer is not empty, it must have content type
+ * %HB_BUFFER_CONTENT_TYPE_UNICODE.
+ *
+ * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it
+ * will be set to the Unicode script of the first character in
+ * the buffer that has a script other than %HB_SCRIPT_COMMON,
+ * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN.
+ *
+ * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
+ * it will be set to the natural horizontal direction of the
+ * buffer script as returned by hb_script_get_horizontal_direction().
+ *
+ * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
+ * it will be set to the process's default language as returned by
+ * hb_language_get_default(). This may change in the future by
+ * taking buffer script into consideration when choosing a language.
+ *
+ * Since: 1.0
+ **/
void
-hb_buffer_guess_properties (hb_buffer_t *buffer)
-{
- buffer->guess_properties ();
-}
-
-#define ADD_UTF(T) \
- HB_STMT_START { \
- if (text_length == -1) { \
- text_length = 0; \
- const T *p = (const T *) text; \
- while (*p) { \
- text_length++; \
- p++; \
- } \
- } \
- if (item_length == -1) \
- item_length = text_length - item_offset; \
- buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \
- const T *next = (const T *) text + item_offset; \
- const T *end = next + item_length; \
- while (next < end) { \
- hb_codepoint_t u; \
- const T *old_next = next; \
- next = UTF_NEXT (next, end, u); \
- hb_buffer_add (buffer, u, 1, old_next - (const T *) text); \
- } \
- } HB_STMT_END
-
-
-#define UTF8_COMPUTE(Char, Mask, Len) \
- if (Char < 128) { Len = 1; Mask = 0x7f; } \
- else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
- else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
- else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
- else Len = 0;
-
-static inline const uint8_t *
-hb_utf8_next (const uint8_t *text,
- const uint8_t *end,
- hb_codepoint_t *unicode)
-{
- uint8_t c = *text;
- unsigned int mask, len;
-
- /* TODO check for overlong sequences? */
-
- UTF8_COMPUTE (c, mask, len);
- if (unlikely (!len || (unsigned int) (end - text) < len)) {
- *unicode = -1;
- return text + 1;
- } else {
- hb_codepoint_t result;
- unsigned int i;
- result = c & mask;
- for (i = 1; i < len; i++)
- {
- if (unlikely ((text[i] & 0xc0) != 0x80))
- {
- *unicode = -1;
- return text + 1;
- }
- result <<= 6;
- result |= (text[i] & 0x3f);
- }
- *unicode = result;
- return text + len;
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer)
+{
+ buffer->guess_segment_properties ();
+}
+
+template <typename utf_t>
+static inline void
+hb_buffer_add_utf (hb_buffer_t *buffer,
+ const typename utf_t::codepoint_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length)
+{
+ typedef typename utf_t::codepoint_t T;
+ const hb_codepoint_t replacement = buffer->replacement;
+
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
+ (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
+
+ if (unlikely (hb_object_is_inert (buffer)))
+ return;
+
+ if (text_length == -1)
+ text_length = utf_t::strlen (text);
+
+ if (item_length == -1)
+ item_length = text_length - item_offset;
+
+ buffer->ensure (buffer->len + item_length * sizeof (T) / 4);
+
+ /* If buffer is empty and pre-context provided, install it.
+ * This check is written this way, to make sure people can
+ * provide pre-context in one add_utf() call, then provide
+ * text in a follow-up call. See:
+ *
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=801410#c13
+ */
+ if (!buffer->len && item_offset > 0)
+ {
+ /* Add pre-context */
+ buffer->clear_context (0);
+ const T *prev = text + item_offset;
+ const T *start = text;
+ while (start < prev && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
+ {
+ hb_codepoint_t u;
+ prev = utf_t::prev (prev, start, &u, replacement);
+ buffer->context[0][buffer->context_len[0]++] = u;
+ }
}
+
+ const T *next = text + item_offset;
+ const T *end = next + item_length;
+ while (next < end)
+ {
+ hb_codepoint_t u;
+ const T *old_next = next;
+ next = utf_t::next (next, end, &u, replacement);
+ buffer->add (u, old_next - (const T *) text);
+ }
+
+ /* Add post-context */
+ buffer->clear_context (1);
+ end = text + text_length;
+ while (next < end && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
+ {
+ hb_codepoint_t u;
+ next = utf_t::next (next, end, &u, replacement);
+ buffer->context[1][buffer->context_len[1]++] = u;
+ }
+
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_UNICODE;
}
+/**
+ * hb_buffer_add_utf8:
+ * @buffer: a buffer.
+ * @text: (array length=text_length) (element-type uint8_t):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_add_utf8 (hb_buffer_t *buffer,
const char *text,
@@ -831,45 +1416,43 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
-#define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U))
- ADD_UTF (uint8_t);
-#undef UTF_NEXT
-}
-
-static inline const uint16_t *
-hb_utf16_next (const uint16_t *text,
- const uint16_t *end,
- hb_codepoint_t *unicode)
-{
- uint16_t c = *text++;
-
- if (unlikely (c >= 0xd800 && c < 0xdc00)) {
- /* high surrogate */
- uint16_t l;
- if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) {
- /* low surrogate */
- *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
- text++;
- } else
- *unicode = -1;
- } else
- *unicode = c;
-
- return text;
+ hb_buffer_add_utf<hb_utf8_t> (buffer, (const uint8_t *) text, text_length, item_offset, item_length);
}
+/**
+ * hb_buffer_add_utf16:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_add_utf16 (hb_buffer_t *buffer,
const uint16_t *text,
int text_length,
unsigned int item_offset,
- int item_length)
+ int item_length)
{
-#define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U))
- ADD_UTF (uint16_t);
-#undef UTF_NEXT
+ hb_buffer_add_utf<hb_utf16_t> (buffer, text, text_length, item_offset, item_length);
}
+/**
+ * hb_buffer_add_utf32:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_buffer_add_utf32 (hb_buffer_t *buffer,
const uint32_t *text,
@@ -877,9 +1460,135 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
-#define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1)
- ADD_UTF (uint32_t);
-#undef UTF_NEXT
+ hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
+}
+
+/**
+ * hb_buffer_add_latin1:
+ * @buffer: a buffer.
+ * @text: (array length=text_length) (element-type uint8_t):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_add_latin1 (hb_buffer_t *buffer,
+ const uint8_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length)
+{
+ hb_buffer_add_utf<hb_latin1_t> (buffer, text, text_length, item_offset, item_length);
}
+/**
+ * hb_buffer_add_codepoints:
+ * @buffer: a buffer.
+ * @text: (array length=text_length):
+ * @text_length:
+ * @item_offset:
+ * @item_length:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_add_codepoints (hb_buffer_t *buffer,
+ const hb_codepoint_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length)
+{
+ hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
+}
+
+
+static int
+compare_info_codepoint (const hb_glyph_info_t *pa,
+ const hb_glyph_info_t *pb)
+{
+ return (int) pb->codepoint - (int) pa->codepoint;
+}
+
+static inline void
+normalize_glyphs_cluster (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end,
+ bool backward)
+{
+ hb_glyph_position_t *pos = buffer->pos;
+
+ /* Total cluster advance */
+ hb_position_t total_x_advance = 0, total_y_advance = 0;
+ for (unsigned int i = start; i < end; i++)
+ {
+ total_x_advance += pos[i].x_advance;
+ total_y_advance += pos[i].y_advance;
+ }
+ hb_position_t x_advance = 0, y_advance = 0;
+ for (unsigned int i = start; i < end; i++)
+ {
+ pos[i].x_offset += x_advance;
+ pos[i].y_offset += y_advance;
+
+ x_advance += pos[i].x_advance;
+ y_advance += pos[i].y_advance;
+
+ pos[i].x_advance = 0;
+ pos[i].y_advance = 0;
+ }
+
+ if (backward)
+ {
+ /* Transfer all cluster advance to the last glyph. */
+ pos[end - 1].x_advance = total_x_advance;
+ pos[end - 1].y_advance = total_y_advance;
+
+ hb_bubble_sort (buffer->info + start, end - start - 1, compare_info_codepoint, buffer->pos + start);
+ } else {
+ /* Transfer all cluster advance to the first glyph. */
+ pos[start].x_advance += total_x_advance;
+ pos[start].y_advance += total_y_advance;
+ for (unsigned int i = start + 1; i < end; i++) {
+ pos[i].x_offset -= total_x_advance;
+ pos[i].y_offset -= total_y_advance;
+ }
+ hb_bubble_sort (buffer->info + start + 1, end - start - 1, compare_info_codepoint, buffer->pos + start + 1);
+ }
+}
+
+/**
+ * hb_buffer_normalize_glyphs:
+ * @buffer: a buffer.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
+{
+ assert (buffer->have_positions);
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
+
+ bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+
+ unsigned int count = buffer->len;
+ if (unlikely (!count)) return;
+ hb_glyph_info_t *info = buffer->info;
+
+ unsigned int start = 0;
+ unsigned int end;
+ for (end = start + 1; end < count; end++)
+ if (info[start].cluster != info[end].cluster) {
+ normalize_glyphs_cluster (buffer, start, end, backward);
+ start = end;
+ }
+ normalize_glyphs_cluster (buffer, start, end, backward);
+}
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
index fe53197..e5b46d8 100644
--- a/src/hb-buffer.h
+++ b/src/hb-buffer.h
@@ -1,7 +1,7 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009 Red Hat, Inc.
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -36,13 +36,12 @@
#include "hb-common.h"
#include "hb-unicode.h"
+#include "hb-font.h"
HB_BEGIN_DECLS
-typedef struct _hb_buffer_t hb_buffer_t;
-
-typedef struct _hb_glyph_info_t {
+typedef struct hb_glyph_info_t {
hb_codepoint_t codepoint;
hb_mask_t mask;
uint32_t cluster;
@@ -52,7 +51,7 @@ typedef struct _hb_glyph_info_t {
hb_var_int_t var2;
} hb_glyph_info_t;
-typedef struct _hb_glyph_position_t {
+typedef struct hb_glyph_position_t {
hb_position_t x_advance;
hb_position_t y_advance;
hb_position_t x_offset;
@@ -63,6 +62,36 @@ typedef struct _hb_glyph_position_t {
} hb_glyph_position_t;
+typedef struct hb_segment_properties_t {
+ hb_direction_t direction;
+ hb_script_t script;
+ hb_language_t language;
+ /*< private >*/
+ void *reserved1;
+ void *reserved2;
+} hb_segment_properties_t;
+
+#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
+ HB_SCRIPT_INVALID, \
+ HB_LANGUAGE_INVALID, \
+ NULL, \
+ NULL}
+
+hb_bool_t
+hb_segment_properties_equal (const hb_segment_properties_t *a,
+ const hb_segment_properties_t *b);
+
+unsigned int
+hb_segment_properties_hash (const hb_segment_properties_t *p);
+
+
+
+/*
+ * hb_buffer_t
+ */
+
+typedef struct hb_buffer_t hb_buffer_t;
+
hb_buffer_t *
hb_buffer_create (void);
@@ -87,6 +116,20 @@ hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key);
+typedef enum {
+ HB_BUFFER_CONTENT_TYPE_INVALID = 0,
+ HB_BUFFER_CONTENT_TYPE_UNICODE,
+ HB_BUFFER_CONTENT_TYPE_GLYPHS
+} hb_buffer_content_type_t;
+
+void
+hb_buffer_set_content_type (hb_buffer_t *buffer,
+ hb_buffer_content_type_t content_type);
+
+hb_buffer_content_type_t
+hb_buffer_get_content_type (hb_buffer_t *buffer);
+
+
void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode_funcs);
@@ -112,15 +155,59 @@ void
hb_buffer_set_language (hb_buffer_t *buffer,
hb_language_t language);
+
hb_language_t
hb_buffer_get_language (hb_buffer_t *buffer);
+void
+hb_buffer_set_segment_properties (hb_buffer_t *buffer,
+ const hb_segment_properties_t *props);
+
+void
+hb_buffer_get_segment_properties (hb_buffer_t *buffer,
+ hb_segment_properties_t *props);
+
+void
+hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
+
+
+typedef enum { /*< flags >*/
+ HB_BUFFER_FLAG_DEFAULT = 0x00000000u,
+ HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
+ HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
+ HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u
+} hb_buffer_flags_t;
+
+void
+hb_buffer_set_flags (hb_buffer_t *buffer,
+ hb_buffer_flags_t flags);
+
+hb_buffer_flags_t
+hb_buffer_get_flags (hb_buffer_t *buffer);
+
+
+
+#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
+
+/* Sets codepoint used to replace invalid UTF-8/16/32 entries.
+ * Default is 0xFFFDu. */
+void
+hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
+ hb_codepoint_t replacement);
+
+hb_codepoint_t
+hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
+
/* Resets the buffer. Afterwards it's as if it was just created,
* except that it has a larger buffer allocated perhaps... */
void
hb_buffer_reset (hb_buffer_t *buffer);
+/* Like reset, but does NOT clear unicode_funcs and replacement_codepoint. */
+void
+hb_buffer_clear_contents (hb_buffer_t *buffer);
+
/* Returns false if allocation failed */
hb_bool_t
hb_buffer_pre_allocate (hb_buffer_t *buffer,
@@ -137,16 +224,12 @@ hb_buffer_reverse (hb_buffer_t *buffer);
void
hb_buffer_reverse_clusters (hb_buffer_t *buffer);
-void
-hb_buffer_guess_properties (hb_buffer_t *buffer);
-
/* Filling the buffer in */
void
hb_buffer_add (hb_buffer_t *buffer,
hb_codepoint_t codepoint,
- hb_mask_t mask,
unsigned int cluster);
void
@@ -170,6 +253,22 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length);
+/* Allows only access to first 256 Unicode codepoints. */
+void
+hb_buffer_add_latin1 (hb_buffer_t *buffer,
+ const uint8_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length);
+
+/* Like add_utf32 but does NOT check for invalid Unicode codepoints. */
+void
+hb_buffer_add_codepoints (hb_buffer_t *buffer,
+ const hb_codepoint_t *text,
+ int text_length,
+ unsigned int item_offset,
+ int item_length);
+
/* Clears any new items added at the end */
hb_bool_t
@@ -193,6 +292,61 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
unsigned int *length);
+/* Reorders a glyph buffer to have canonical in-cluster glyph order / position.
+ * The resulting clusters should behave identical to pre-reordering clusters.
+ * NOTE: This has nothing to do with Unicode normalization. */
+void
+hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
+
+
+/*
+ * Serialize
+ */
+
+typedef enum { /*< flags >*/
+ HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000u,
+ HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u,
+ HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u,
+ HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u
+} hb_buffer_serialize_flags_t;
+
+typedef enum {
+ HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'),
+ HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'),
+ HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE
+} hb_buffer_serialize_format_t;
+
+/* len=-1 means str is NUL-terminated. */
+hb_buffer_serialize_format_t
+hb_buffer_serialize_format_from_string (const char *str, int len);
+
+const char *
+hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
+
+const char **
+hb_buffer_serialize_list_formats (void);
+
+/* Returns number of items, starting at start, that were serialized. */
+unsigned int
+hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end,
+ char *buf,
+ unsigned int buf_size,
+ unsigned int *buf_consumed, /* May be NULL */
+ hb_font_t *font, /* May be NULL */
+ hb_buffer_serialize_format_t format,
+ hb_buffer_serialize_flags_t flags);
+
+hb_bool_t
+hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
+ const char *buf,
+ int buf_len, /* -1 means nul-terminated */
+ const char **end_ptr, /* May be NULL */
+ hb_font_t *font, /* May be NULL */
+ hb_buffer_serialize_format_t format);
+
+
HB_END_DECLS
#endif /* HB_BUFFER_H */
diff --git a/src/hb-cache-private.hh b/src/hb-cache-private.hh
index a0928a0..19b70b7 100644
--- a/src/hb-cache-private.hh
+++ b/src/hb-cache-private.hh
@@ -49,6 +49,8 @@ struct hb_cache_t
unsigned int v = values[k];
if ((v >> value_bits) != (key >> cache_bits))
return false;
+ *value = v & ((1<<value_bits)-1);
+ return true;
}
inline bool set (unsigned int key, unsigned int value)
diff --git a/src/hb-common.cc b/src/hb-common.cc
index 331d255..1516211 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -28,36 +28,81 @@
#include "hb-private.hh"
-#include "hb-version.h"
-
#include "hb-mutex-private.hh"
#include "hb-object-private.hh"
#include <locale.h>
+/* hb_options_t */
+
+hb_options_union_t _hb_options;
+
+void
+_hb_options_init (void)
+{
+ hb_options_union_t u;
+ u.i = 0;
+ u.opts.initialized = 1;
+
+ char *c = getenv ("HB_OPTIONS");
+ u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
+
+ /* This is idempotent and threadsafe. */
+ _hb_options = u;
+}
+
/* hb_tag_t */
+/**
+ * hb_tag_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_tag_t
-hb_tag_from_string (const char *s, int len)
+hb_tag_from_string (const char *str, int len)
{
char tag[4];
unsigned int i;
- if (!s || !len || !*s)
+ if (!str || !len || !*str)
return HB_TAG_NONE;
if (len < 0 || len > 4)
len = 4;
- for (i = 0; i < (unsigned) len && s[i]; i++)
- tag[i] = s[i];
+ for (i = 0; i < (unsigned) len && str[i]; i++)
+ tag[i] = str[i];
for (; i < 4; i++)
tag[i] = ' ';
return HB_TAG_CHAR4 (tag);
}
+/**
+ * hb_tag_to_string:
+ * @tag:
+ * @buf: (array fixed-size=4):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_tag_to_string (hb_tag_t tag, char *buf)
+{
+ buf[0] = (char) (uint8_t) (tag >> 24);
+ buf[1] = (char) (uint8_t) (tag >> 16);
+ buf[2] = (char) (uint8_t) (tag >> 8);
+ buf[3] = (char) (uint8_t) (tag >> 0);
+}
+
/* hb_direction_t */
@@ -68,6 +113,17 @@ const char direction_strings[][4] = {
"btt"
};
+/**
+ * hb_direction_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_direction_t
hb_direction_from_string (const char *str, int len)
{
@@ -85,6 +141,16 @@ hb_direction_from_string (const char *str, int len)
return HB_DIRECTION_INVALID;
}
+/**
+ * hb_direction_to_string:
+ * @direction:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
const char *
hb_direction_to_string (hb_direction_t direction)
{
@@ -98,7 +164,7 @@ hb_direction_to_string (hb_direction_t direction)
/* hb_language_t */
-struct _hb_language_t {
+struct hb_language_impl_t {
const char s[1];
};
@@ -160,7 +226,7 @@ struct hb_language_item_t {
return *this;
}
- void finish (void) { free (lang); }
+ void finish (void) { free ((void *) lang); }
};
@@ -168,6 +234,7 @@ struct hb_language_item_t {
static hb_language_item_t *langs;
+#ifdef HB_USE_ATEXIT
static
void free_langs (void)
{
@@ -178,6 +245,7 @@ void free_langs (void)
langs = next;
}
}
+#endif
static hb_language_item_t *
lang_find_or_insert (const char *key)
@@ -197,11 +265,12 @@ retry:
*lang = key;
if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
+ lang->finish ();
free (lang);
goto retry;
}
-#ifdef HAVE_ATEXIT
+#ifdef HB_USE_ATEXIT
if (!first_lang)
atexit (free_langs); /* First person registers atexit() callback. */
#endif
@@ -210,17 +279,32 @@ retry:
}
+/**
+ * hb_language_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_language_t
hb_language_from_string (const char *str, int len)
{
+ char strbuf[64];
+
if (!str || !len || !*str)
return HB_LANGUAGE_INVALID;
- char strbuf[32];
- if (len >= 0) {
+ if (len >= 0)
+ {
+ /* NUL-terminate it. */
len = MIN (len, (int) sizeof (strbuf) - 1);
- str = (char *) memcpy (strbuf, str, len);
+ memcpy (strbuf, str, len);
strbuf[len] = '\0';
+ str = strbuf;
}
hb_language_item_t *item = lang_find_or_insert (str);
@@ -228,6 +312,16 @@ hb_language_from_string (const char *str, int len)
return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
}
+/**
+ * hb_language_to_string:
+ * @language:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
const char *
hb_language_to_string (hb_language_t language)
{
@@ -235,20 +329,24 @@ hb_language_to_string (hb_language_t language)
return language->s;
}
+/**
+ * hb_language_get_default:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_language_t
hb_language_get_default (void)
{
- static hb_language_t default_language;
-
- if (!default_language) {
- /* This block is not quite threadsafe, but is not as bad as
- * it looks since it's idempotent. As long as pointer ops
- * are atomic, we are safe. */
+ static hb_language_t default_language = HB_LANGUAGE_INVALID;
- /* I hear that setlocale() doesn't honor env vars on Windows,
- * but for now we ignore that. */
-
- default_language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+ hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
+ if (unlikely (language == HB_LANGUAGE_INVALID)) {
+ language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
+ (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
}
return default_language;
@@ -257,6 +355,16 @@ hb_language_get_default (void)
/* hb_script_t */
+/**
+ * hb_script_from_iso15924_tag:
+ * @tag:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag)
{
@@ -264,7 +372,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
return HB_SCRIPT_INVALID;
/* Be lenient, adjust case (one capital letter followed by three small letters) */
- tag = (tag & 0xDFDFDFDF) | 0x00202020;
+ tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
switch (tag) {
@@ -284,25 +392,56 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
}
/* If it looks right, just use the tag as a script */
- if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060)
+ if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
return (hb_script_t) tag;
/* Otherwise, return unknown */
return HB_SCRIPT_UNKNOWN;
}
+/**
+ * hb_script_from_string:
+ * @s: (array length=len) (element-type uint8_t):
+ * @len:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_script_t
hb_script_from_string (const char *s, int len)
{
return hb_script_from_iso15924_tag (hb_tag_from_string (s, len));
}
+/**
+ * hb_script_to_iso15924_tag:
+ * @script:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_tag_t
hb_script_to_iso15924_tag (hb_script_t script)
{
return (hb_tag_t) script;
}
+/**
+ * hb_script_get_horizontal_direction:
+ * @script:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_direction_t
hb_script_get_horizontal_direction (hb_script_t script)
{
@@ -346,6 +485,14 @@ hb_script_get_horizontal_direction (hb_script_t script)
case HB_SCRIPT_MEROITIC_CURSIVE:
case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
+ /* Unicode-7.0 additions */
+ case HB_SCRIPT_MANICHAEAN:
+ case HB_SCRIPT_MENDE_KIKAKUI:
+ case HB_SCRIPT_NABATAEAN:
+ case HB_SCRIPT_OLD_NORTH_ARABIAN:
+ case HB_SCRIPT_PALMYRENE:
+ case HB_SCRIPT_PSALTER_PAHLAVI:
+
return HB_DIRECTION_RTL;
}
@@ -359,8 +506,7 @@ bool
hb_user_data_array_t::set (hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
- hb_bool_t replace,
- hb_mutex_t &lock)
+ hb_bool_t replace)
{
if (!key)
return false;
@@ -378,23 +524,26 @@ hb_user_data_array_t::set (hb_user_data_key_t *key,
}
void *
-hb_user_data_array_t::get (hb_user_data_key_t *key,
- hb_mutex_t &lock)
+hb_user_data_array_t::get (hb_user_data_key_t *key)
{
hb_user_data_item_t item = {NULL };
return items.find (key, &item, lock) ? item.data : NULL;
}
-void
-hb_user_data_array_t::finish (hb_mutex_t &lock)
-{
- items.finish (lock);
-}
-
/* hb_version */
+/**
+ * hb_version:
+ * @major: (out): Library major version component.
+ * @minor: (out): Library minor version component.
+ * @micro: (out): Library micro version component.
+ *
+ * Returns library version as three integer components.
+ *
+ * Since: 1.0
+ **/
void
hb_version (unsigned int *major,
unsigned int *minor,
@@ -405,18 +554,37 @@ hb_version (unsigned int *major,
*micro = HB_VERSION_MICRO;
}
+/**
+ * hb_version_string:
+ *
+ * Returns library version as a string with three components.
+ *
+ * Return value: library version string.
+ *
+ * Since: 1.0
+ **/
const char *
hb_version_string (void)
{
return HB_VERSION_STRING;
}
+/**
+ * hb_version_atleast:
+ * @major:
+ * @minor:
+ * @micro:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_version_check (unsigned int major,
- unsigned int minor,
- unsigned int micro)
+hb_version_atleast (unsigned int major,
+ unsigned int minor,
+ unsigned int micro)
{
- return HB_VERSION_CHECK (major, minor, micro);
+ return HB_VERSION_ATLEAST (major, minor, micro);
}
-
-
diff --git a/src/hb-common.h b/src/hb-common.h
index 562b04c..b6ce3f7 100644
--- a/src/hb-common.h
+++ b/src/hb-common.h
@@ -33,6 +33,7 @@
#ifndef HB_COMMON_H
#define HB_COMMON_H
+#ifndef HB_BEGIN_DECLS
# ifdef __cplusplus
# define HB_BEGIN_DECLS extern "C" {
# define HB_END_DECLS }
@@ -40,8 +41,7 @@
# define HB_BEGIN_DECLS
# define HB_END_DECLS
# endif /* !__cplusplus */
-
-HB_BEGIN_DECLS
+#endif
#if !defined (HB_DONT_DEFINE_STDINT)
@@ -67,6 +67,8 @@ typedef unsigned __int64 uint64_t;
#endif
+HB_BEGIN_DECLS
+
typedef int hb_bool_t;
@@ -88,13 +90,20 @@ typedef union _hb_var_int_t {
typedef uint32_t hb_tag_t;
-#define HB_TAG(a,b,c,d) ((hb_tag_t)((((uint8_t)(a))<<24)|(((uint8_t)(b))<<16)|(((uint8_t)(c))<<8)|((uint8_t)(d))))
+#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
#define HB_TAG_NONE HB_TAG(0,0,0,0)
+#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
+#define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff)
-/* len=-1 means str is NUL-terminated */
-hb_tag_t hb_tag_from_string (const char *str, int len);
+/* len=-1 means str is NUL-terminated. */
+hb_tag_t
+hb_tag_from_string (const char *str, int len);
+
+/* buf should have 4 bytes. */
+void
+hb_tag_to_string (hb_tag_t tag, char *buf);
/* hb_direction_t */
@@ -114,17 +123,18 @@ hb_direction_from_string (const char *str, int len);
const char *
hb_direction_to_string (hb_direction_t direction);
+#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
+/* Direction must be valid for the following */
#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4)
#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6)
#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4)
#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5)
-#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
-#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1)) /* Direction must be valid */
+#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
/* hb_language_t */
-typedef struct _hb_language_t *hb_language_t;
+typedef const struct hb_language_impl_t *hb_language_t;
/* len=-1 means str is NUL-terminated */
hb_language_t
@@ -139,178 +149,166 @@ hb_language_t
hb_language_get_default (void);
-/* hb_unicode_general_category_t */
-
-typedef enum
-{
- HB_UNICODE_GENERAL_CATEGORY_CONTROL, /* Cc */
- HB_UNICODE_GENERAL_CATEGORY_FORMAT, /* Cf */
- HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, /* Cn */
- HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, /* Co */
- HB_UNICODE_GENERAL_CATEGORY_SURROGATE, /* Cs */
- HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, /* Ll */
- HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, /* Lm */
- HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, /* Lo */
- HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, /* Lt */
- HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, /* Lu */
- HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, /* Mc */
- HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, /* Me */
- HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, /* Mn */
- HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, /* Nd */
- HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, /* Nl */
- HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, /* No */
- HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, /* Pc */
- HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, /* Pd */
- HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, /* Pe */
- HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, /* Pf */
- HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, /* Pi */
- HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, /* Po */
- HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, /* Ps */
- HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, /* Sc */
- HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, /* Sk */
- HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, /* Sm */
- HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, /* So */
- HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, /* Zl */
- HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, /* Zp */
- HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR /* Zs */
-} hb_unicode_general_category_t;
-
-
/* hb_script_t */
/* http://unicode.org/iso15924/ */
/* http://goo.gl/x9ilM */
+/* Unicode Character Database property: Script (sc) */
typedef enum
{
- /* Unicode-1.1 additions */
- HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'),
- HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'),
- HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'),
- HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'),
- HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'),
- HB_SCRIPT_CANADIAN_ABORIGINAL = HB_TAG ('C','a','n','s'),
- HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'),
- HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'),
- HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'),
- HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'),
- HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'),
- HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'),
- HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'),
- HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'),
- HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'),
- HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'),
- HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'),
- HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'),
- HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'),
- HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'),
- HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'),
- HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'),
- HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'),
- HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'),
- HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'),
- HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'),
- HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'),
- HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'),
- HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'),
- HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'),
- HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'),
- HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'),
- HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'),
-
- /* Unicode-2.0 additions */
- HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'),
-
- /* Unicode-3.0 additions */
- HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'),
- HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'),
- HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'),
- HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'),
- HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'),
-
- /* Unicode-3.1 additions */
- HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'),
- HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'),
- HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'),
-
- /* Unicode-3.2 additions */
- HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'),
- HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'),
- HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'),
- HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'),
-
- /* Unicode-4.0 additions */
- HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'),
- HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'),
- HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'),
- HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'),
- HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'),
- HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'),
- HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'),
- HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'),
-
- /* Unicode-4.1 additions */
- HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'),
- HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'),
- HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'),
- HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'),
- HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'),
- HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'),
- HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'),
-
- /* Unicode-5.0 additions */
- HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'),
- HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'),
- HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'),
- HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'),
- HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'),
- HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'),
-
- /* Unicode-5.1 additions */
- HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'),
- HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'),
- HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'),
- HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'),
- HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'),
- HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'),
- HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'),
- HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'),
- HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'),
- HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'),
- HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'),
-
- /* Unicode-5.2 additions */
- HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'),
- HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'),
- HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'),
- HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'),
- HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'),
- HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'),
- HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'),
- HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'),
- HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'),
- HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'),
- HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'),
- HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'),
- HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'),
- HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'),
- HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'),
-
- /* Unicode-6.0 additions */
- HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'),
- HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'),
- HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'),
-
- /* Unicode-6.1 additions */
- HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'),
- HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'),
- HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'),
- HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'),
- HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'),
- HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'),
- HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
-
- /* No script set */
- HB_SCRIPT_INVALID = HB_TAG_NONE
+ /*1.1*/ HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'),
+ /*1.1*/ HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'),
+ /*5.0*/ HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'),
+
+ /*1.1*/ HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'),
+ /*1.1*/ HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'),
+ /*1.1*/ HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'),
+ /*1.1*/ HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'),
+ /*1.1*/ HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'),
+ /*1.1*/ HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'),
+ /*1.1*/ HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'),
+ /*1.1*/ HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'),
+ /*1.1*/ HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'),
+ /*1.1*/ HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'),
+ /*1.1*/ HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'),
+ /*1.1*/ HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'),
+ /*1.1*/ HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'),
+ /*1.1*/ HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'),
+ /*1.1*/ HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'),
+ /*1.1*/ HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'),
+ /*1.1*/ HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'),
+ /*1.1*/ HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'),
+ /*1.1*/ HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'),
+ /*1.1*/ HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'),
+ /*1.1*/ HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'),
+ /*1.1*/ HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'),
+
+ /*2.0*/ HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'),
+
+ /*3.0*/ HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'),
+ /*3.0*/ HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'),
+ /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'),
+ /*3.0*/ HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'),
+ /*3.0*/ HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'),
+ /*3.0*/ HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'),
+ /*3.0*/ HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'),
+ /*3.0*/ HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'),
+ /*3.0*/ HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'),
+ /*3.0*/ HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'),
+ /*3.0*/ HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'),
+ /*3.0*/ HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'),
+ /*3.0*/ HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'),
+ /*3.0*/ HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'),
+
+ /*3.1*/ HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'),
+ /*3.1*/ HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'),
+ /*3.1*/ HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'),
+
+ /*3.2*/ HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'),
+ /*3.2*/ HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'),
+ /*3.2*/ HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'),
+ /*3.2*/ HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'),
+
+ /*4.0*/ HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'),
+ /*4.0*/ HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'),
+ /*4.0*/ HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'),
+ /*4.0*/ HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'),
+ /*4.0*/ HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'),
+ /*4.0*/ HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'),
+ /*4.0*/ HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'),
+
+ /*4.1*/ HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'),
+ /*4.1*/ HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'),
+ /*4.1*/ HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'),
+ /*4.1*/ HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'),
+ /*4.1*/ HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'),
+ /*4.1*/ HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'),
+ /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'),
+ /*4.1*/ HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'),
+
+ /*5.0*/ HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'),
+ /*5.0*/ HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'),
+ /*5.0*/ HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'),
+ /*5.0*/ HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'),
+ /*5.0*/ HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'),
+
+ /*5.1*/ HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'),
+ /*5.1*/ HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'),
+ /*5.1*/ HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'),
+ /*5.1*/ HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'),
+ /*5.1*/ HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'),
+ /*5.1*/ HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'),
+ /*5.1*/ HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'),
+ /*5.1*/ HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'),
+ /*5.1*/ HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'),
+ /*5.1*/ HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'),
+ /*5.1*/ HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'),
+
+ /*5.2*/ HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'),
+ /*5.2*/ HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'),
+ /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'),
+ /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'),
+ /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'),
+ /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'),
+ /*5.2*/ HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'),
+ /*5.2*/ HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'),
+ /*5.2*/ HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'),
+ /*5.2*/ HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'),
+ /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'),
+ /*5.2*/ HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'),
+ /*5.2*/ HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'),
+ /*5.2*/ HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'),
+ /*5.2*/ HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'),
+
+ /*6.0*/ HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'),
+ /*6.0*/ HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'),
+ /*6.0*/ HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'),
+
+ /*6.1*/ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'),
+ /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'),
+ /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'),
+ /*6.1*/ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'),
+ /*6.1*/ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'),
+ /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'),
+ /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
+
+ /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'),
+ /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'),
+ /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'),
+ /*7.0*/ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'),
+ /*7.0*/ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'),
+ /*7.0*/ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'),
+ /*7.0*/ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'),
+ /*7.0*/ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'),
+ /*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'),
+ /*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'),
+ /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'),
+ /*7.0*/ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'),
+ /*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'),
+ /*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'),
+ /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'),
+ /*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'),
+ /*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'),
+ /*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'),
+ /*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'),
+ /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'),
+ /*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'),
+ /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'),
+ /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'),
+
+ /* No script set. */
+ HB_SCRIPT_INVALID = HB_TAG_NONE,
+
+ /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
+ * without risking undefined behavior. Include both a signed and unsigned max,
+ * since technically enums are int, and indeed, hb_script_t ends up being signed.
+ * See this thread for technicalities:
+ *
+ * http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
+ */
+ _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/
+ _HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
+
} hb_script_t;
@@ -319,7 +317,7 @@ typedef enum
hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag);
-/* suger for tag_from_string() then script_from_iso15924_tag */
+/* sugar for tag_from_string() then script_from_iso15924_tag */
/* len=-1 means s is NUL-terminated */
hb_script_t
hb_script_from_string (const char *s, int len);
@@ -333,7 +331,7 @@ hb_script_get_horizontal_direction (hb_script_t script);
/* User data */
-typedef struct _hb_user_data_key_t {
+typedef struct hb_user_data_key_t {
/*< private >*/
char unused;
} hb_user_data_key_t;
diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc
new file mode 100644
index 0000000..4a45175
--- /dev/null
+++ b/src/hb-coretext.cc
@@ -0,0 +1,1194 @@
+/*
+ * Copyright © 2012,2013 Mozilla Foundation.
+ * Copyright © 2012,2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#define HB_SHAPER coretext
+#define hb_coretext_shaper_face_data_t CGFont
+#include "hb-shaper-impl-private.hh"
+
+#include "hb-coretext.h"
+
+
+#ifndef HB_DEBUG_CORETEXT
+#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
+#endif
+
+
+static void
+release_table_data (void *user_data)
+{
+ CFDataRef cf_data = reinterpret_cast<CFDataRef> (user_data);
+ CFRelease(cf_data);
+}
+
+static hb_blob_t *
+reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+ CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
+ CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
+ if (unlikely (!cf_data))
+ return NULL;
+
+ const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
+ const size_t length = CFDataGetLength (cf_data);
+ if (!data || !length)
+ return NULL;
+
+ return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
+ reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
+ release_table_data);
+}
+
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font)
+{
+ return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
+}
+
+
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
+
+
+/*
+ * shaper face data
+ */
+
+static void
+release_data (void *info, const void *data, size_t size)
+{
+ assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
+ hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
+
+ hb_blob_destroy ((hb_blob_t *) info);
+}
+
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
+{
+ hb_coretext_shaper_face_data_t *data = NULL;
+
+ if (face->destroy == (hb_destroy_func_t) CGFontRelease)
+ {
+ data = CGFontRetain ((CGFontRef) face->user_data);
+ }
+ else
+ {
+ hb_blob_t *blob = hb_face_reference_blob (face);
+ unsigned int blob_length;
+ const char *blob_data = hb_blob_get_data (blob, &blob_length);
+ if (unlikely (!blob_length))
+ DEBUG_MSG (CORETEXT, face, "Face has empty blob");
+
+ CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
+ if (likely (provider))
+ {
+ data = CGFontCreateWithDataProvider (provider);
+ CGDataProviderRelease (provider);
+ }
+ }
+
+ if (unlikely (!data)) {
+ DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+ }
+
+ return data;
+}
+
+void
+_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
+{
+ CFRelease (data);
+}
+
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face)
+{
+ if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
+ hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+ return face_data;
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_coretext_shaper_font_data_t {
+ CTFontRef ct_font;
+ CGFloat x_mult, y_mult; /* From CT space to HB space. */
+};
+
+hb_coretext_shaper_font_data_t *
+_hb_coretext_shaper_font_data_create (hb_font_t *font)
+{
+ if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
+
+ hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
+ if (unlikely (!data))
+ return NULL;
+
+ hb_face_t *face = font->face;
+ hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+ /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
+ CGFloat font_size = 36.; /* Default... */
+ /* No idea if the following is even a good idea. */
+ if (font->y_ppem)
+ font_size = font->y_ppem;
+
+ if (font_size < 0)
+ font_size = -font_size;
+ data->x_mult = (CGFloat) font->x_scale / font_size;
+ data->y_mult = (CGFloat) font->y_scale / font_size;
+ data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
+ if (unlikely (!data->ct_font)) {
+ DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
+ free (data);
+ return NULL;
+ }
+
+ return data;
+}
+
+void
+_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
+{
+ CFRelease (data->ct_font);
+ free (data);
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_coretext_shaper_shape_plan_data_t {};
+
+hb_coretext_shaper_shape_plan_data_t *
+_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
+ const hb_feature_t *user_features HB_UNUSED,
+ unsigned int num_user_features HB_UNUSED)
+{
+ return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font)
+{
+ if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL;
+ hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+ return font_data->ct_font;
+}
+
+
+/*
+ * shaper
+ */
+
+struct feature_record_t {
+ unsigned int feature;
+ unsigned int setting;
+};
+
+struct active_feature_t {
+ feature_record_t rec;
+ unsigned int order;
+
+ static int cmp (const active_feature_t *a, const active_feature_t *b) {
+ return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
+ a->order < b->order ? -1 : a->order > b->order ? 1 :
+ a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
+ 0;
+ }
+ bool operator== (const active_feature_t *f) {
+ return cmp (this, f) == 0;
+ }
+};
+
+struct feature_event_t {
+ unsigned int index;
+ bool start;
+ active_feature_t feature;
+
+ static int cmp (const feature_event_t *a, const feature_event_t *b) {
+ return a->index < b->index ? -1 : a->index > b->index ? 1 :
+ a->start < b->start ? -1 : a->start > b->start ? 1 :
+ active_feature_t::cmp (&a->feature, &b->feature);
+ }
+};
+
+struct range_record_t {
+ CTFontRef font;
+ unsigned int index_first; /* == start */
+ unsigned int index_last; /* == end - 1 */
+};
+
+
+/* The following enum members are added in OS X 10.8. */
+#define kAltHalfWidthTextSelector 6
+#define kAltProportionalTextSelector 5
+#define kAlternateHorizKanaOffSelector 1
+#define kAlternateHorizKanaOnSelector 0
+#define kAlternateKanaType 34
+#define kAlternateVertKanaOffSelector 3
+#define kAlternateVertKanaOnSelector 2
+#define kCaseSensitiveLayoutOffSelector 1
+#define kCaseSensitiveLayoutOnSelector 0
+#define kCaseSensitiveLayoutType 33
+#define kCaseSensitiveSpacingOffSelector 3
+#define kCaseSensitiveSpacingOnSelector 2
+#define kContextualAlternatesOffSelector 1
+#define kContextualAlternatesOnSelector 0
+#define kContextualAlternatesType 36
+#define kContextualLigaturesOffSelector 19
+#define kContextualLigaturesOnSelector 18
+#define kContextualSwashAlternatesOffSelector 5
+#define kContextualSwashAlternatesOnSelector 4
+#define kDefaultLowerCaseSelector 0
+#define kDefaultUpperCaseSelector 0
+#define kHistoricalLigaturesOffSelector 21
+#define kHistoricalLigaturesOnSelector 20
+#define kHojoCharactersSelector 12
+#define kJIS2004CharactersSelector 11
+#define kLowerCasePetiteCapsSelector 2
+#define kLowerCaseSmallCapsSelector 1
+#define kLowerCaseType 37
+#define kMathematicalGreekOffSelector 11
+#define kMathematicalGreekOnSelector 10
+#define kNLCCharactersSelector 13
+#define kQuarterWidthTextSelector 4
+#define kScientificInferiorsSelector 4
+#define kStylisticAltEightOffSelector 17
+#define kStylisticAltEightOnSelector 16
+#define kStylisticAltEighteenOffSelector 37
+#define kStylisticAltEighteenOnSelector 36
+#define kStylisticAltElevenOffSelector 23
+#define kStylisticAltElevenOnSelector 22
+#define kStylisticAltFifteenOffSelector 31
+#define kStylisticAltFifteenOnSelector 30
+#define kStylisticAltFiveOffSelector 11
+#define kStylisticAltFiveOnSelector 10
+#define kStylisticAltFourOffSelector 9
+#define kStylisticAltFourOnSelector 8
+#define kStylisticAltFourteenOffSelector 29
+#define kStylisticAltFourteenOnSelector 28
+#define kStylisticAltNineOffSelector 19
+#define kStylisticAltNineOnSelector 18
+#define kStylisticAltNineteenOffSelector 39
+#define kStylisticAltNineteenOnSelector 38
+#define kStylisticAltOneOffSelector 3
+#define kStylisticAltOneOnSelector 2
+#define kStylisticAltSevenOffSelector 15
+#define kStylisticAltSevenOnSelector 14
+#define kStylisticAltSeventeenOffSelector 35
+#define kStylisticAltSeventeenOnSelector 34
+#define kStylisticAltSixOffSelector 13
+#define kStylisticAltSixOnSelector 12
+#define kStylisticAltSixteenOffSelector 33
+#define kStylisticAltSixteenOnSelector 32
+#define kStylisticAltTenOffSelector 21
+#define kStylisticAltTenOnSelector 20
+#define kStylisticAltThirteenOffSelector 27
+#define kStylisticAltThirteenOnSelector 26
+#define kStylisticAltThreeOffSelector 7
+#define kStylisticAltThreeOnSelector 6
+#define kStylisticAltTwelveOffSelector 25
+#define kStylisticAltTwelveOnSelector 24
+#define kStylisticAltTwentyOffSelector 41
+#define kStylisticAltTwentyOnSelector 40
+#define kStylisticAltTwoOffSelector 5
+#define kStylisticAltTwoOnSelector 4
+#define kStylisticAlternativesType 35
+#define kSwashAlternatesOffSelector 3
+#define kSwashAlternatesOnSelector 2
+#define kThirdWidthTextSelector 3
+#define kTraditionalNamesCharactersSelector 14
+#define kUpperCasePetiteCapsSelector 2
+#define kUpperCaseSmallCapsSelector 1
+#define kUpperCaseType 38
+
+/* Table data courtesy of Apple. */
+static const struct feature_mapping_t {
+ FourCharCode otFeatureTag;
+ uint16_t aatFeatureType;
+ uint16_t selectorToEnable;
+ uint16_t selectorToDisable;
+} feature_mappings[] = {
+ { 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector },
+ { 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector },
+ { 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector },
+ { 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector },
+ { 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector },
+ { 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector },
+ { 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector },
+ { 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector },
+ { 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 },
+ { 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector },
+ { 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 },
+ { 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 },
+ { 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector },
+ { 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, },
+ { 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector },
+ { 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector },
+ { 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 },
+ { 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 },
+ { 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector },
+ { 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 },
+ { 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 },
+ { 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 },
+ { 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 },
+ { 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector },
+ { 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 },
+ { 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector },
+ { 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 },
+ { 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 },
+ { 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector },
+ { 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 },
+ { 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector },
+ { 'pkna', kTextSpacingType, kProportionalTextSelector, 7 },
+ { 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 },
+ { 'pwid', kTextSpacingType, kProportionalTextSelector, 7 },
+ { 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 },
+ { 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector },
+ { 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector },
+ { 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector },
+ { 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 },
+ { 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector },
+ { 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector },
+ { 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector },
+ { 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector },
+ { 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector },
+ { 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector },
+ { 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector },
+ { 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector },
+ { 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector },
+ { 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector },
+ { 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector },
+ { 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector },
+ { 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector },
+ { 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector },
+ { 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector },
+ { 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector },
+ { 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector },
+ { 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector },
+ { 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector },
+ { 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector },
+ { 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector },
+ { 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector },
+ { 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector },
+ { 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector },
+ { 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 },
+ { 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 },
+ { 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 },
+ { 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 },
+ { 'unic', kLetterCaseType, 14, 15 },
+ { 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 },
+ { 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector },
+ { 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 },
+ { 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector },
+ { 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 },
+ { 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector },
+ { 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector },
+};
+
+static int
+_hb_feature_mapping_cmp (const void *key_, const void *entry_)
+{
+ unsigned int key = * (unsigned int *) key_;
+ const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
+ return key < entry->otFeatureTag ? -1 :
+ key > entry->otFeatureTag ? 1 :
+ 0;
+}
+
+hb_bool_t
+_hb_coretext_shape (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features)
+{
+ hb_face_t *face = font->face;
+ hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+ hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+ /* Attach marks to their bases, to match the 'ot' shaper.
+ * Adapted from hb-ot-shape:hb_form_clusters().
+ * Note that this only makes us be closer to the 'ot' shaper,
+ * but by no means the same. For example, if there's
+ * B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
+ * continue pointing to B2 even though B2 was merged into B1's
+ * cluster... */
+ {
+ hb_unicode_funcs_t *unicode = buffer->unicode;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 1; i < count; i++)
+ if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (info[i].codepoint)))
+ buffer->merge_clusters (i - 1, i + 1);
+ }
+
+ hb_auto_array_t<feature_record_t> feature_records;
+ hb_auto_array_t<range_record_t> range_records;
+
+ /*
+ * Set up features.
+ * (copied + modified from code from hb-uniscribe.cc)
+ */
+ if (num_features)
+ {
+ /* Sort features by start/end events. */
+ hb_auto_array_t<feature_event_t> feature_events;
+ for (unsigned int i = 0; i < num_features; i++)
+ {
+ const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
+ feature_mappings,
+ ARRAY_LENGTH (feature_mappings),
+ sizeof (feature_mappings[0]),
+ _hb_feature_mapping_cmp);
+ if (!mapping)
+ continue;
+
+ active_feature_t feature;
+ feature.rec.feature = mapping->aatFeatureType;
+ feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
+ feature.order = i;
+
+ feature_event_t *event;
+
+ event = feature_events.push ();
+ if (unlikely (!event))
+ goto fail_features;
+ event->index = features[i].start;
+ event->start = true;
+ event->feature = feature;
+
+ event = feature_events.push ();
+ if (unlikely (!event))
+ goto fail_features;
+ event->index = features[i].end;
+ event->start = false;
+ event->feature = feature;
+ }
+ feature_events.qsort ();
+ /* Add a strategic final event. */
+ {
+ active_feature_t feature;
+ feature.rec.feature = HB_TAG_NONE;
+ feature.rec.setting = 0;
+ feature.order = num_features + 1;
+
+ feature_event_t *event = feature_events.push ();
+ if (unlikely (!event))
+ goto fail_features;
+ event->index = 0; /* This value does magic. */
+ event->start = false;
+ event->feature = feature;
+ }
+
+ /* Scan events and save features for each range. */
+ hb_auto_array_t<active_feature_t> active_features;
+ unsigned int last_index = 0;
+ for (unsigned int i = 0; i < feature_events.len; i++)
+ {
+ feature_event_t *event = &feature_events[i];
+
+ if (event->index != last_index)
+ {
+ /* Save a snapshot of active features and the range. */
+ range_record_t *range = range_records.push ();
+ if (unlikely (!range))
+ goto fail_features;
+
+ if (active_features.len)
+ {
+ CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+ /* TODO sort and resolve conflicting features? */
+ /* active_features.qsort (); */
+ for (unsigned int j = 0; j < active_features.len; j++)
+ {
+ CFStringRef keys[2] = {
+ kCTFontFeatureTypeIdentifierKey,
+ kCTFontFeatureSelectorIdentifierKey
+ };
+ CFNumberRef values[2] = {
+ CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
+ CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
+ };
+ CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
+ (const void **) keys,
+ (const void **) values,
+ 2,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease (values[0]);
+ CFRelease (values[1]);
+
+ CFArrayAppendValue (features_array, dict);
+ CFRelease (dict);
+
+ }
+
+ CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+ (const void **) &kCTFontFeatureSettingsAttribute,
+ (const void **) &features_array,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease (features_array);
+
+ CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+ CFRelease (attributes);
+
+ range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+ CFRelease (font_desc);
+ }
+ else
+ {
+ range->font = NULL;
+ }
+
+ range->index_first = last_index;
+ range->index_last = event->index - 1;
+
+ last_index = event->index;
+ }
+
+ if (event->start) {
+ active_feature_t *feature = active_features.push ();
+ if (unlikely (!feature))
+ goto fail_features;
+ *feature = event->feature;
+ } else {
+ active_feature_t *feature = active_features.find (&event->feature);
+ if (feature)
+ active_features.remove (feature - active_features.array);
+ }
+ }
+
+ if (!range_records.len) /* No active feature found. */
+ goto fail_features;
+ }
+ else
+ {
+ fail_features:
+ num_features = 0;
+ }
+
+ unsigned int scratch_size;
+ hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+
+#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
+ Type *name = (Type *) scratch; \
+ { \
+ unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+ if (unlikely (_consumed > scratch_size)) \
+ { \
+ on_no_room; \
+ assert (0); \
+ } \
+ scratch += _consumed; \
+ scratch_size -= _consumed; \
+ }
+
+ ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
+ unsigned int chars_len = 0;
+ for (unsigned int i = 0; i < buffer->len; i++) {
+ hb_codepoint_t c = buffer->info[i].codepoint;
+ if (likely (c <= 0xFFFFu))
+ pchars[chars_len++] = c;
+ else if (unlikely (c > 0x10FFFFu))
+ pchars[chars_len++] = 0xFFFDu;
+ else {
+ pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+ pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+ }
+ }
+
+ ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
+ chars_len = 0;
+ for (unsigned int i = 0; i < buffer->len; i++)
+ {
+ hb_codepoint_t c = buffer->info[i].codepoint;
+ unsigned int cluster = buffer->info[i].cluster;
+ log_clusters[chars_len++] = cluster;
+ if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+ log_clusters[chars_len++] = cluster; /* Surrogates. */
+ }
+
+#define FAIL(...) \
+ HB_STMT_START { \
+ DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
+ ret = false; \
+ goto fail; \
+ } HB_STMT_END;
+
+ bool ret = true;
+ CFStringRef string_ref = NULL;
+ CTLineRef line = NULL;
+
+ if (0)
+ {
+resize_and_retry:
+ DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
+ /* string_ref uses the scratch-buffer for backing store, and line references
+ * string_ref (via attr_string). We must release those before resizing buffer. */
+ assert (string_ref);
+ assert (line);
+ CFRelease (string_ref);
+ CFRelease (line);
+ string_ref = NULL;
+ line = NULL;
+
+ /* Get previous start-of-scratch-area, that we use later for readjusting
+ * our existing scratch arrays. */
+ unsigned int old_scratch_used;
+ hb_buffer_t::scratch_buffer_t *old_scratch;
+ old_scratch = buffer->get_scratch_buffer (&old_scratch_used);
+ old_scratch_used = scratch - old_scratch;
+
+ if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+ FAIL ("Buffer resize failed");
+
+ /* Adjust scratch, pchars, and log_cluster arrays. This is ugly, but really the
+ * cleanest way to do without completely restructuring the rest of this shaper. */
+ scratch = buffer->get_scratch_buffer (&scratch_size);
+ pchars = reinterpret_cast<UniChar *> (((char *) scratch + ((char *) pchars - (char *) old_scratch)));
+ log_clusters = reinterpret_cast<unsigned int *> (((char *) scratch + ((char *) log_clusters - (char *) old_scratch)));
+ scratch += old_scratch_used;
+ scratch_size -= old_scratch_used;
+ }
+retry:
+ {
+ string_ref = CFStringCreateWithCharactersNoCopy (NULL,
+ pchars, chars_len,
+ kCFAllocatorNull);
+ if (unlikely (!string_ref))
+ FAIL ("CFStringCreateWithCharactersNoCopy failed");
+
+ /* Create an attributed string, populate it, and create a line from it, then release attributed string. */
+ {
+ CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (kCFAllocatorDefault,
+ chars_len);
+ if (unlikely (!attr_string))
+ FAIL ("CFAttributedStringCreateMutable failed");
+ CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
+ if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+ {
+ CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+ kCTVerticalFormsAttributeName, kCFBooleanTrue);
+ }
+
+ if (buffer->props.language)
+ {
+/* What's the iOS equivalent of this check?
+ * The symbols was introduced in iOS 7.0.
+ * At any rate, our fallback is safe and works fine. */
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
+# define kCTLanguageAttributeName CFSTR ("NSLanguage")
+#endif
+ CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
+ hb_language_to_string (buffer->props.language),
+ kCFStringEncodingUTF8,
+ kCFAllocatorNull);
+ if (unlikely (!lang))
+ FAIL ("CFStringCreateWithCStringNoCopy failed");
+ CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+ kCTLanguageAttributeName, lang);
+ CFRelease (lang);
+ }
+ CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
+ kCTFontAttributeName, font_data->ct_font);
+
+ if (num_features)
+ {
+ unsigned int start = 0;
+ range_record_t *last_range = &range_records[0];
+ for (unsigned int k = 0; k < chars_len; k++)
+ {
+ range_record_t *range = last_range;
+ while (log_clusters[k] < range->index_first)
+ range--;
+ while (log_clusters[k] > range->index_last)
+ range++;
+ if (range != last_range)
+ {
+ if (last_range->font)
+ CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, k - start),
+ kCTFontAttributeName, last_range->font);
+
+ start = k;
+ }
+
+ last_range = range;
+ }
+ if (start != chars_len && last_range->font)
+ CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
+ kCTFontAttributeName, last_range->font);
+ }
+
+ int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
+ CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
+ CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
+ (const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
+ (const void **) &level_number,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (unlikely (!options))
+ FAIL ("CFDictionaryCreate failed");
+
+ CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
+ CFRelease (options);
+ CFRelease (attr_string);
+ if (unlikely (!typesetter))
+ FAIL ("CTTypesetterCreateWithAttributedStringAndOptions failed");
+
+ line = CTTypesetterCreateLine (typesetter, CFRangeMake(0, 0));
+ CFRelease (typesetter);
+ if (unlikely (!line))
+ FAIL ("CTTypesetterCreateLine failed");
+ }
+
+ CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
+ unsigned int num_runs = CFArrayGetCount (glyph_runs);
+ DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
+
+ buffer->len = 0;
+ uint32_t status_and = ~0, status_or = 0;
+ double advances_so_far = 0;
+
+ const CFRange range_all = CFRangeMake (0, 0);
+
+ for (unsigned int i = 0; i < num_runs; i++)
+ {
+ CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex (glyph_runs, i));
+ CTRunStatus run_status = CTRunGetStatus (run);
+ status_or |= run_status;
+ status_and &= run_status;
+ DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
+ double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
+ if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
+ run_advance = -run_advance;
+ DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
+
+ /* CoreText does automatic font fallback (AKA "cascading") for characters
+ * not supported by the requested font, and provides no way to turn it off,
+ * so we must detect if the returned run uses a font other than the requested
+ * one and fill in the buffer with .notdef glyphs instead of random glyph
+ * indices from a different font.
+ */
+ CFDictionaryRef attributes = CTRunGetAttributes (run);
+ CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
+ if (!CFEqual (run_ct_font, font_data->ct_font))
+ {
+ /* The run doesn't use our main font instance. We have to figure out
+ * whether font fallback happened, or this is just CoreText giving us
+ * another CTFont using the same underlying CGFont. CoreText seems
+ * to do that in a variety of situations, one of which being vertical
+ * text, but also perhaps for caching reasons.
+ *
+ * First, see if it uses any of our subfonts created to set font features...
+ *
+ * Next, compare the CGFont to the one we used to create our fonts.
+ * Even this doesn't work all the time.
+ *
+ * Finally, we compare PS names, which I don't think are unique...
+ *
+ * Looks like if we really want to be sure here we have to modify the
+ * font to change the name table, similar to what we do in the uniscribe
+ * backend.
+ *
+ * However, even that wouldn't work if we were passed in the CGFont to
+ * begin with.
+ *
+ * Webkit uses a slightly different approach: it installs LastResort
+ * as fallback chain, and then checks PS name of used font against
+ * LastResort. That one is safe for any font except for LastResort,
+ * as opposed to ours, which can fail if we are using any uninstalled
+ * font that has the same name as an installed font.
+ *
+ * See: http://github.com/behdad/harfbuzz/pull/36
+ */
+ bool matched = false;
+ for (unsigned int i = 0; i < range_records.len; i++)
+ if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
+ {
+ matched = true;
+ break;
+ }
+ if (!matched)
+ {
+ CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
+ if (run_cg_font)
+ {
+ matched = CFEqual (run_cg_font, face_data);
+ CFRelease (run_cg_font);
+ }
+ }
+ if (!matched)
+ {
+ CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
+ CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
+ CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
+ CFRelease (run_ps_name);
+ CFRelease (font_ps_name);
+ if (result == kCFCompareEqualTo)
+ matched = true;
+ }
+ if (!matched)
+ {
+ CFRange range = CTRunGetStringRange (run);
+ DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
+ range.location, range.location + range.length);
+ if (!buffer->ensure_inplace (buffer->len + range.length))
+ goto resize_and_retry;
+ hb_glyph_info_t *info = buffer->info + buffer->len;
+
+ hb_codepoint_t notdef = 0;
+ hb_direction_t dir = buffer->props.direction;
+ hb_position_t x_advance, y_advance, x_offset, y_offset;
+ hb_font_get_glyph_advance_for_direction (font, notdef, dir, &x_advance, &y_advance);
+ hb_font_get_glyph_origin_for_direction (font, notdef, dir, &x_offset, &y_offset);
+ hb_position_t advance = x_advance + y_advance;
+ x_offset = -x_offset;
+ y_offset = -y_offset;
+
+ unsigned int old_len = buffer->len;
+ for (CFIndex j = range.location; j < range.location + range.length; j++)
+ {
+ UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
+ if (hb_in_range<UniChar> (ch, 0xDC00u, 0xDFFFu) && range.location < j)
+ {
+ ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
+ if (hb_in_range<UniChar> (ch, 0xD800u, 0xDBFFu))
+ /* This is the second of a surrogate pair. Don't need .notdef
+ * for this one. */
+ continue;
+ }
+ if (buffer->unicode->is_default_ignorable (ch))
+ continue;
+
+ info->codepoint = notdef;
+ info->cluster = log_clusters[j];
+
+ info->mask = advance;
+ info->var1.u32 = x_offset;
+ info->var2.u32 = y_offset;
+
+ info++;
+ buffer->len++;
+ }
+ if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+ buffer->reverse_range (old_len, buffer->len);
+ advances_so_far += run_advance;
+ continue;
+ }
+ }
+
+ unsigned int num_glyphs = CTRunGetGlyphCount (run);
+ if (num_glyphs == 0)
+ continue;
+
+ if (!buffer->ensure_inplace (buffer->len + num_glyphs))
+ goto resize_and_retry;
+
+ hb_glyph_info_t *run_info = buffer->info + buffer->len;
+
+ /* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
+ * succeed, and so copying data to our own buffer will be rare. Reports
+ * have it that this changed in OS X 10.10 Yosemite, and NULL is returned
+ * frequently. At any rate, we can test that codepath by setting USE_PTR
+ * to false. */
+
+#define USE_PTR true
+
+#define SCRATCH_SAVE() \
+ unsigned int scratch_size_saved = scratch_size; \
+ hb_buffer_t::scratch_buffer_t *scratch_saved = scratch
+
+#define SCRATCH_RESTORE() \
+ scratch_size = scratch_size_saved; \
+ scratch = scratch_saved;
+
+ { /* Setup glyphs */
+ SCRATCH_SAVE();
+ const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
+ if (!glyphs) {
+ ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
+ CTRunGetGlyphs (run, range_all, glyph_buf);
+ glyphs = glyph_buf;
+ }
+ const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
+ if (!string_indices) {
+ ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
+ CTRunGetStringIndices (run, range_all, index_buf);
+ string_indices = index_buf;
+ }
+ hb_glyph_info_t *info = run_info;
+ for (unsigned int j = 0; j < num_glyphs; j++)
+ {
+ info->codepoint = glyphs[j];
+ info->cluster = log_clusters[string_indices[j]];
+ info++;
+ }
+ SCRATCH_RESTORE();
+ }
+ {
+ /* Setup positions.
+ * Note that CoreText does not return advances for glyphs. As such,
+ * for all but last glyph, we use the delta position to next glyph as
+ * advance (in the advance direction only), and for last glyph we set
+ * whatever is needed to make the whole run's advance add up. */
+ SCRATCH_SAVE();
+ const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
+ if (!positions) {
+ ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
+ CTRunGetPositions (run, range_all, position_buf);
+ positions = position_buf;
+ }
+ hb_glyph_info_t *info = run_info;
+ CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
+ if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+ {
+ hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
+ for (unsigned int j = 0; j < num_glyphs; j++)
+ {
+ double advance;
+ if (likely (j + 1 < num_glyphs))
+ advance = positions[j + 1].x - positions[j].x;
+ else /* last glyph */
+ advance = run_advance - (positions[j].x - positions[0].x);
+ info->mask = advance * x_mult;
+ info->var1.u32 = x_offset;
+ info->var2.u32 = positions[j].y * y_mult;
+ info++;
+ }
+ }
+ else
+ {
+ hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
+ for (unsigned int j = 0; j < num_glyphs; j++)
+ {
+ double advance;
+ if (likely (j + 1 < num_glyphs))
+ advance = positions[j + 1].y - positions[j].y;
+ else /* last glyph */
+ advance = run_advance - (positions[j].y - positions[0].y);
+ info->mask = advance * y_mult;
+ info->var1.u32 = positions[j].x * x_mult;
+ info->var2.u32 = y_offset;
+ info++;
+ }
+ }
+ SCRATCH_RESTORE();
+ advances_so_far += run_advance;
+ }
+#undef SCRATCH_RESTORE
+#undef SCRATCH_SAVE
+#undef USE_PTR
+#undef ALLOCATE_ARRAY
+
+ buffer->len += num_glyphs;
+ }
+
+ /* Make sure all runs had the expected direction. */
+ bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
+ assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
+ assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
+
+ buffer->clear_positions ();
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+ for (unsigned int i = 0; i < count; i++)
+ {
+ pos->x_advance = info->mask;
+ pos->x_offset = info->var1.u32;
+ pos->y_offset = info->var2.u32;
+ info++, pos++;
+ }
+ else
+ for (unsigned int i = 0; i < count; i++)
+ {
+ pos->y_advance = info->mask;
+ pos->x_offset = info->var1.u32;
+ pos->y_offset = info->var2.u32;
+ info++, pos++;
+ }
+
+ /* Fix up clusters so that we never return out-of-order indices;
+ * if core text has reordered glyphs, we'll merge them to the
+ * beginning of the reordered cluster. CoreText is nice enough
+ * to tell us whenever it has produced nonmonotonic results...
+ * Note that we assume the input clusters were nonmonotonic to
+ * begin with.
+ *
+ * This does *not* mean we'll form the same clusters as Uniscribe
+ * or the native OT backend, only that the cluster indices will be
+ * monotonic in the output buffer. */
+ if (count > 1 && (status_or & kCTRunStatusNonMonotonic))
+ {
+ hb_glyph_info_t *info = buffer->info;
+ if (HB_DIRECTION_IS_FORWARD (buffer->props.direction))
+ {
+ unsigned int cluster = info[count - 1].cluster;
+ for (unsigned int i = count - 1; i > 0; i--)
+ {
+ cluster = MIN (cluster, info[i - 1].cluster);
+ info[i - 1].cluster = cluster;
+ }
+ }
+ else
+ {
+ unsigned int cluster = info[0].cluster;
+ for (unsigned int i = 1; i < count; i++)
+ {
+ cluster = MIN (cluster, info[i].cluster);
+ info[i].cluster = cluster;
+ }
+ }
+ }
+ }
+
+#undef FAIL
+
+fail:
+ if (string_ref)
+ CFRelease (string_ref);
+ if (line)
+ CFRelease (line);
+
+ for (unsigned int i = 0; i < range_records.len; i++)
+ if (range_records[i].font)
+ CFRelease (range_records[i].font);
+
+ return ret;
+}
+
+
+/*
+ * AAT shaper
+ */
+
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font)
+
+
+/*
+ * shaper face data
+ */
+
+struct hb_coretext_aat_shaper_face_data_t {};
+
+hb_coretext_aat_shaper_face_data_t *
+_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
+{
+ hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
+ /* Umm, we just reference the table to check whether it exists.
+ * Maybe add better API for this? */
+ if (!hb_blob_get_length (mort_blob))
+ {
+ hb_blob_destroy (mort_blob);
+ mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
+ if (!hb_blob_get_length (mort_blob))
+ {
+ hb_blob_destroy (mort_blob);
+ return NULL;
+ }
+ }
+ hb_blob_destroy (mort_blob);
+
+ return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+}
+
+void
+_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_coretext_aat_shaper_font_data_t {};
+
+hb_coretext_aat_shaper_font_data_t *
+_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
+{
+ return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
+}
+
+void
+_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_coretext_aat_shaper_shape_plan_data_t {};
+
+hb_coretext_aat_shaper_shape_plan_data_t *
+_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
+ const hb_feature_t *user_features HB_UNUSED,
+ unsigned int num_user_features HB_UNUSED)
+{
+ return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features)
+{
+ return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
+}
diff --git a/src/hb-coretext.h b/src/hb-coretext.h
new file mode 100644
index 0000000..25267bc
--- /dev/null
+++ b/src/hb-coretext.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2012 Mozilla Foundation.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Mozilla Author(s): Jonathan Kew
+ */
+
+#ifndef HB_CORETEXT_H
+#define HB_CORETEXT_H
+
+#include "hb.h"
+
+#include <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+# include <CoreText/CoreText.h>
+# include <CoreGraphics/CoreGraphics.h>
+#else
+# include <ApplicationServices/ApplicationServices.h>
+#endif
+
+HB_BEGIN_DECLS
+
+
+#define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
+#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
+
+
+hb_face_t *
+hb_coretext_face_create (CGFontRef cg_font);
+
+
+CGFontRef
+hb_coretext_face_get_cg_font (hb_face_t *face);
+
+CTFontRef
+hb_coretext_font_get_ct_font (hb_font_t *font);
+
+
+HB_END_DECLS
+
+#endif /* HB_CORETEXT_H */
diff --git a/src/hb-version.h b/src/hb-deprecated.h
index 43ec9cf..30ae4b1 100644
--- a/src/hb-version.h
+++ b/src/hb-deprecated.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -28,39 +28,24 @@
#error "Include <hb.h> instead."
#endif
-#ifndef HB_VERSION_H
-#define HB_VERSION_H
+#ifndef HB_DEPRECATED_H
+#define HB_DEPRECATED_H
#include "hb-common.h"
+#include "hb-unicode.h"
+#include "hb-font.h"
HB_BEGIN_DECLS
+#ifndef HB_DISABLE_DEPRECATED
-#define HB_VERSION_MAJOR 0
-#define HB_VERSION_MINOR 9
-#define HB_VERSION_MICRO 0
+#define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS
-#define HB_VERSION_STRING "0.9.0"
-
-#define HB_VERSION_CHECK(major,minor,micro) \
- ((major)*10000+(minor)*100+(micro) >= \
- HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
-
-
-void
-hb_version (unsigned int *major,
- unsigned int *minor,
- unsigned int *micro);
-
-const char *
-hb_version_string (void);
-
-hb_bool_t
-hb_version_check (unsigned int major,
- unsigned int minor,
- unsigned int micro);
+#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT
+#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_BUFFER_SERIALIZE_FLAG_DEFAULT
+#endif
HB_END_DECLS
-#endif /* HB_VERSION_H */
+#endif /* HB_DEPRECATED_H */
diff --git a/src/hb-face-private.hh b/src/hb-face-private.hh
new file mode 100644
index 0000000..c4266ff
--- /dev/null
+++ b/src/hb-face-private.hh
@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2011 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_FACE_PRIVATE_HH
+#define HB_FACE_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+
+
+/*
+ * hb_face_t
+ */
+
+struct hb_face_t {
+ hb_object_header_t header;
+ ASSERT_POD ();
+
+ hb_bool_t immutable;
+
+ hb_reference_table_func_t reference_table_func;
+ void *user_data;
+ hb_destroy_func_t destroy;
+
+ unsigned int index;
+ mutable unsigned int upem;
+ mutable unsigned int num_glyphs;
+
+ struct hb_shaper_data_t shaper_data;
+
+ struct plan_node_t {
+ hb_shape_plan_t *shape_plan;
+ plan_node_t *next;
+ } *shape_plans;
+
+
+ inline hb_blob_t *reference_table (hb_tag_t tag) const
+ {
+ hb_blob_t *blob;
+
+ if (unlikely (!reference_table_func))
+ return hb_blob_get_empty ();
+
+ blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
+ if (unlikely (!blob))
+ return hb_blob_get_empty ();
+
+ return blob;
+ }
+
+ inline HB_PURE_FUNC unsigned int get_upem (void) const
+ {
+ if (unlikely (!upem))
+ load_upem ();
+ return upem;
+ }
+
+ inline unsigned int get_num_glyphs (void) const
+ {
+ if (unlikely (num_glyphs == (unsigned int) -1))
+ load_num_glyphs ();
+ return num_glyphs;
+ }
+
+ private:
+ HB_INTERNAL void load_upem (void) const;
+ HB_INTERNAL void load_num_glyphs (void) const;
+};
+
+extern HB_INTERNAL const hb_face_t _hb_face_nil;
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_FACE_PRIVATE_HH */
diff --git a/src/hb-face.cc b/src/hb-face.cc
new file mode 100644
index 0000000..9348af7
--- /dev/null
+++ b/src/hb-face.cc
@@ -0,0 +1,481 @@
+/*
+ * Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot-layout-private.hh"
+
+#include "hb-font-private.hh"
+#include "hb-open-file-private.hh"
+#include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
+
+#include "hb-cache-private.hh"
+
+#include <string.h>
+
+
+/*
+ * hb_face_t
+ */
+
+const hb_face_t _hb_face_nil = {
+ HB_OBJECT_HEADER_STATIC,
+
+ true, /* immutable */
+
+ NULL, /* reference_table_func */
+ NULL, /* user_data */
+ NULL, /* destroy */
+
+ 0, /* index */
+ 1000, /* upem */
+ 0, /* num_glyphs */
+
+ {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+ },
+
+ NULL, /* shape_plans */
+};
+
+
+/**
+ * hb_face_create_for_tables:
+ * @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
+ void *user_data,
+ hb_destroy_func_t destroy)
+{
+ hb_face_t *face;
+
+ if (!reference_table_func || !(face = hb_object_create<hb_face_t> ())) {
+ if (destroy)
+ destroy (user_data);
+ return hb_face_get_empty ();
+ }
+
+ face->reference_table_func = reference_table_func;
+ face->user_data = user_data;
+ face->destroy = destroy;
+
+ face->upem = 0;
+ face->num_glyphs = (unsigned int) -1;
+
+ return face;
+}
+
+
+typedef struct hb_face_for_data_closure_t {
+ hb_blob_t *blob;
+ unsigned int index;
+} hb_face_for_data_closure_t;
+
+static hb_face_for_data_closure_t *
+_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
+{
+ hb_face_for_data_closure_t *closure;
+
+ closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
+ if (unlikely (!closure))
+ return NULL;
+
+ closure->blob = blob;
+ closure->index = index;
+
+ return closure;
+}
+
+static void
+_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
+{
+ hb_blob_destroy (closure->blob);
+ free (closure);
+}
+
+static hb_blob_t *
+_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+ hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
+
+ if (tag == HB_TAG_NONE)
+ return hb_blob_reference (data->blob);
+
+ const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
+ const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+
+ const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
+
+ hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
+
+ return blob;
+}
+
+/**
+ * hb_face_create: (Xconstructor)
+ * @blob:
+ * @index:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_create (hb_blob_t *blob,
+ unsigned int index)
+{
+ hb_face_t *face;
+
+ if (unlikely (!blob || !hb_blob_get_length (blob)))
+ return hb_face_get_empty ();
+
+ hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
+
+ if (unlikely (!closure))
+ return hb_face_get_empty ();
+
+ face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
+ closure,
+ (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
+
+ hb_face_set_index (face, index);
+
+ return face;
+}
+
+/**
+ * hb_face_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_get_empty (void)
+{
+ return const_cast<hb_face_t *> (&_hb_face_nil);
+}
+
+
+/**
+ * hb_face_reference: (skip)
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_face_reference (hb_face_t *face)
+{
+ return hb_object_reference (face);
+}
+
+/**
+ * hb_face_destroy: (skip)
+ * @face: a face.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_destroy (hb_face_t *face)
+{
+ if (!hb_object_destroy (face)) return;
+
+ for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
+ {
+ hb_face_t::plan_node_t *next = node->next;
+ hb_shape_plan_destroy (node->shape_plan);
+ free (node);
+ node = next;
+ }
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+ if (face->destroy)
+ face->destroy (face->user_data);
+
+ free (face);
+}
+
+/**
+ * hb_face_set_user_data: (skip)
+ * @face: a face.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_face_set_user_data (hb_face_t *face,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace)
+{
+ return hb_object_set_user_data (face, key, data, destroy, replace);
+}
+
+/**
+ * hb_face_get_user_data: (skip)
+ * @face: a face.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+void *
+hb_face_get_user_data (hb_face_t *face,
+ hb_user_data_key_t *key)
+{
+ return hb_object_get_user_data (face, key);
+}
+
+/**
+ * hb_face_make_immutable:
+ * @face: a face.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_make_immutable (hb_face_t *face)
+{
+ if (unlikely (hb_object_is_inert (face)))
+ return;
+
+ face->immutable = true;
+}
+
+/**
+ * hb_face_is_immutable:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face)
+{
+ return face->immutable;
+}
+
+
+/**
+ * hb_face_reference_table:
+ * @face: a face.
+ * @tag:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+ hb_tag_t tag)
+{
+ return face->reference_table (tag);
+}
+
+/**
+ * hb_face_reference_blob:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face)
+{
+ return face->reference_table (HB_TAG_NONE);
+}
+
+/**
+ * hb_face_set_index:
+ * @face: a face.
+ * @index:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_index (hb_face_t *face,
+ unsigned int index)
+{
+ if (face->immutable)
+ return;
+
+ face->index = index;
+}
+
+/**
+ * hb_face_get_index:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_index (hb_face_t *face)
+{
+ return face->index;
+}
+
+/**
+ * hb_face_set_upem:
+ * @face: a face.
+ * @upem:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_upem (hb_face_t *face,
+ unsigned int upem)
+{
+ if (face->immutable)
+ return;
+
+ face->upem = upem;
+}
+
+/**
+ * hb_face_get_upem:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_upem (hb_face_t *face)
+{
+ return face->get_upem ();
+}
+
+void
+hb_face_t::load_upem (void) const
+{
+ hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
+ const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
+ upem = head_table->get_upem ();
+ hb_blob_destroy (head_blob);
+}
+
+/**
+ * hb_face_set_glyph_count:
+ * @face: a face.
+ * @glyph_count:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_face_set_glyph_count (hb_face_t *face,
+ unsigned int glyph_count)
+{
+ if (face->immutable)
+ return;
+
+ face->num_glyphs = glyph_count;
+}
+
+/**
+ * hb_face_get_glyph_count:
+ * @face: a face.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face)
+{
+ return face->get_num_glyphs ();
+}
+
+void
+hb_face_t::load_num_glyphs (void) const
+{
+ hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
+ const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
+ num_glyphs = maxp_table->get_num_glyphs ();
+ hb_blob_destroy (maxp_blob);
+}
+
+
diff --git a/src/hb-face.h b/src/hb-face.h
new file mode 100644
index 0000000..f682c46
--- /dev/null
+++ b/src/hb-face.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2009 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_FACE_H
+#define HB_FACE_H
+
+#include "hb-common.h"
+#include "hb-blob.h"
+
+HB_BEGIN_DECLS
+
+
+/*
+ * hb_face_t
+ */
+
+typedef struct hb_face_t hb_face_t;
+
+hb_face_t *
+hb_face_create (hb_blob_t *blob,
+ unsigned int index);
+
+typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data);
+
+/* calls destroy() when not needing user_data anymore */
+hb_face_t *
+hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
+ void *user_data,
+ hb_destroy_func_t destroy);
+
+hb_face_t *
+hb_face_get_empty (void);
+
+hb_face_t *
+hb_face_reference (hb_face_t *face);
+
+void
+hb_face_destroy (hb_face_t *face);
+
+hb_bool_t
+hb_face_set_user_data (hb_face_t *face,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+
+void *
+hb_face_get_user_data (hb_face_t *face,
+ hb_user_data_key_t *key);
+
+void
+hb_face_make_immutable (hb_face_t *face);
+
+hb_bool_t
+hb_face_is_immutable (hb_face_t *face);
+
+
+hb_blob_t *
+hb_face_reference_table (hb_face_t *face,
+ hb_tag_t tag);
+
+hb_blob_t *
+hb_face_reference_blob (hb_face_t *face);
+
+void
+hb_face_set_index (hb_face_t *face,
+ unsigned int index);
+
+unsigned int
+hb_face_get_index (hb_face_t *face);
+
+void
+hb_face_set_upem (hb_face_t *face,
+ unsigned int upem);
+
+unsigned int
+hb_face_get_upem (hb_face_t *face);
+
+void
+hb_face_set_glyph_count (hb_face_t *face,
+ unsigned int glyph_count);
+
+unsigned int
+hb_face_get_glyph_count (hb_face_t *face);
+
+
+HB_END_DECLS
+
+#endif /* HB_FACE_H */
diff --git a/src/hb-fallback-shape.cc b/src/hb-fallback-shape.cc
index 5939887..9d061a9 100644
--- a/src/hb-fallback-shape.cc
+++ b/src/hb-fallback-shape.cc
@@ -24,37 +24,117 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-fallback-shape-private.hh"
+#define HB_SHAPER fallback
+#include "hb-shaper-impl-private.hh"
-#include "hb-buffer-private.hh"
+
+/*
+ * shaper face data
+ */
+
+struct hb_fallback_shaper_face_data_t {};
+
+hb_fallback_shaper_face_data_t *
+_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED)
+{
+ return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_fallback_shaper_font_data_t {};
+
+hb_fallback_shaper_font_data_t *
+_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+ return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_fallback_shaper_shape_plan_data_t {};
+
+hb_fallback_shaper_shape_plan_data_t *
+_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
+ const hb_feature_t *user_features HB_UNUSED,
+ unsigned int num_user_features HB_UNUSED)
+{
+ return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
hb_bool_t
-_hb_fallback_shape (hb_font_t *font,
+_hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
+ hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features HB_UNUSED,
unsigned int num_features HB_UNUSED)
{
- buffer->guess_properties ();
+ /* TODO
+ *
+ * - Apply fallback kern.
+ * - Handle Variation Selectors?
+ * - Apply normalization?
+ *
+ * This will make the fallback shaper into a dumb "TrueType"
+ * shaper which many people unfortunately still request.
+ */
- unsigned int count = buffer->len;
-
- for (unsigned int i = 0; i < count; i++)
- hb_font_get_glyph (font, buffer->info[i].codepoint, 0, &buffer->info[i].codepoint);
+ hb_codepoint_t space;
+ bool has_space = font->get_glyph (' ', 0, &space);
buffer->clear_positions ();
- for (unsigned int i = 0; i < count; i++) {
- hb_font_get_glyph_advance_for_direction (font, buffer->info[i].codepoint,
- buffer->props.direction,
- &buffer->pos[i].x_advance,
- &buffer->pos[i].y_advance);
- hb_font_subtract_glyph_origin_for_direction (font, buffer->info[i].codepoint,
- buffer->props.direction,
- &buffer->pos[i].x_offset,
- &buffer->pos[i].y_offset);
+ hb_direction_t direction = buffer->props.direction;
+ hb_unicode_funcs_t *unicode = buffer->unicode;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (has_space && unicode->is_default_ignorable (info[i].codepoint)) {
+ info[i].codepoint = space;
+ pos[i].x_advance = 0;
+ pos[i].y_advance = 0;
+ continue;
+ }
+ font->get_glyph (info[i].codepoint, 0, &info[i].codepoint);
+ font->get_glyph_advance_for_direction (info[i].codepoint,
+ direction,
+ &pos[i].x_advance,
+ &pos[i].y_advance);
+ font->subtract_glyph_origin_for_direction (info[i].codepoint,
+ direction,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
}
- if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+ if (HB_DIRECTION_IS_BACKWARD (direction))
hb_buffer_reverse (buffer);
return true;
diff --git a/src/hb-font-private.hh b/src/hb-font-private.hh
index 91a4304..33bbf71 100644
--- a/src/hb-font-private.hh
+++ b/src/hb-font-private.hh
@@ -31,8 +31,9 @@
#include "hb-private.hh"
-#include "hb-font.h"
#include "hb-object-private.hh"
+#include "hb-face-private.hh"
+#include "hb-shaper-private.hh"
@@ -54,7 +55,7 @@
HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
/* ^--- Add new callbacks here */
-struct _hb_font_funcs_t {
+struct hb_font_funcs_t {
hb_object_header_t header;
ASSERT_POD ();
@@ -82,32 +83,12 @@ struct _hb_font_funcs_t {
};
-/*
- * hb_face_t
- */
-
-struct _hb_face_t {
- hb_object_header_t header;
- ASSERT_POD ();
-
- hb_bool_t immutable;
-
- hb_reference_table_func_t reference_table;
- void *user_data;
- hb_destroy_func_t destroy;
-
- struct hb_ot_layout_t *ot_layout;
-
- unsigned int index;
- unsigned int upem;
-};
-
/*
* hb_font_t
*/
-struct _hb_font_t {
+struct hb_font_t {
hb_object_header_t header;
ASSERT_POD ();
@@ -126,6 +107,8 @@ struct _hb_font_t {
void *user_data;
hb_destroy_func_t destroy;
+ struct hb_shaper_data_t shaper_data;
+
/* Convert from font-space to user-space */
inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
@@ -134,12 +117,12 @@ struct _hb_font_t {
/* Convert from parent-font user-space to our user-space */
inline hb_position_t parent_scale_x_distance (hb_position_t v) {
if (unlikely (parent && parent->x_scale != x_scale))
- return v * (int64_t) this->x_scale / this->parent->x_scale;
+ return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
return v;
}
inline hb_position_t parent_scale_y_distance (hb_position_t v) {
if (unlikely (parent && parent->y_scale != y_scale))
- return v * (int64_t) this->y_scale / this->parent->y_scale;
+ return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
return v;
}
inline hb_position_t parent_scale_x_position (hb_position_t v) {
@@ -159,10 +142,274 @@ struct _hb_font_t {
}
+ /* Public getters */
+
+ inline hb_bool_t has_glyph (hb_codepoint_t unicode)
+ {
+ hb_codepoint_t glyph;
+ return get_glyph (unicode, 0, &glyph);
+ }
+
+ inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph)
+ {
+ *glyph = 0;
+ return klass->get.glyph (this, user_data,
+ unicode, variation_selector, glyph,
+ klass->user_data.glyph);
+ }
+
+ inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
+ {
+ return klass->get.glyph_h_advance (this, user_data,
+ glyph,
+ klass->user_data.glyph_h_advance);
+ }
+
+ inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
+ {
+ return klass->get.glyph_v_advance (this, user_data,
+ glyph,
+ klass->user_data.glyph_v_advance);
+ }
+
+ inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = *y = 0;
+ return klass->get.glyph_h_origin (this, user_data,
+ glyph, x, y,
+ klass->user_data.glyph_h_origin);
+ }
+
+ inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = *y = 0;
+ return klass->get.glyph_v_origin (this, user_data,
+ glyph, x, y,
+ klass->user_data.glyph_v_origin);
+ }
+
+ inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+ {
+ return klass->get.glyph_h_kerning (this, user_data,
+ left_glyph, right_glyph,
+ klass->user_data.glyph_h_kerning);
+ }
+
+ inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
+ {
+ return klass->get.glyph_v_kerning (this, user_data,
+ top_glyph, bottom_glyph,
+ klass->user_data.glyph_v_kerning);
+ }
+
+ inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents)
+ {
+ memset (extents, 0, sizeof (*extents));
+ return klass->get.glyph_extents (this, user_data,
+ glyph,
+ extents,
+ klass->user_data.glyph_extents);
+ }
+
+ inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = *y = 0;
+ return klass->get.glyph_contour_point (this, user_data,
+ glyph, point_index,
+ x, y,
+ klass->user_data.glyph_contour_point);
+ }
+
+ inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
+ char *name, unsigned int size)
+ {
+ if (size) *name = '\0';
+ return klass->get.glyph_name (this, user_data,
+ glyph,
+ name, size,
+ klass->user_data.glyph_name);
+ }
+
+ inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph)
+ {
+ *glyph = 0;
+ if (len == -1) len = strlen (name);
+ return klass->get.glyph_from_name (this, user_data,
+ name, len,
+ glyph,
+ klass->user_data.glyph_from_name);
+ }
+
+
+ /* A bit higher-level, and with fallback */
+
+ inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+ *x = get_glyph_h_advance (glyph);
+ *y = 0;
+ } else {
+ *x = 0;
+ *y = get_glyph_v_advance (glyph);
+ }
+ }
+
+ /* Internal only */
+ inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y)
+ {
+ *x = get_glyph_h_advance (glyph) / 2;
+
+ /* TODO use font_metics.ascent */
+ *y = y_scale;
+ }
+
+ inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
+ {
+ if (!get_glyph_h_origin (glyph, x, y) &&
+ get_glyph_v_origin (glyph, x, y))
+ {
+ hb_position_t dx, dy;
+ guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+ *x -= dx; *y -= dy;
+ }
+ }
+ else
+ {
+ if (!get_glyph_v_origin (glyph, x, y) &&
+ get_glyph_h_origin (glyph, x, y))
+ {
+ hb_position_t dx, dy;
+ guess_v_origin_minus_h_origin (glyph, &dx, &dy);
+ *x += dx; *y += dy;
+ }
+ }
+ }
+
+ inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+ {
+ hb_position_t origin_x, origin_y;
+
+ get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+ *x += origin_x;
+ *y += origin_y;
+ }
+
+ inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+ {
+ hb_position_t origin_x, origin_y;
+
+ get_glyph_origin_for_direction (glyph, direction, &origin_x, &origin_y);
+
+ *x -= origin_x;
+ *y -= origin_y;
+ }
+
+ inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+ {
+ if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
+ *x = get_glyph_h_kerning (first_glyph, second_glyph);
+ *y = 0;
+ } else {
+ *x = 0;
+ *y = get_glyph_v_kerning (first_glyph, second_glyph);
+ }
+ }
+
+ inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
+ hb_direction_t direction,
+ hb_glyph_extents_t *extents)
+ {
+ hb_bool_t ret = get_glyph_extents (glyph, extents);
+
+ if (ret)
+ subtract_glyph_origin_for_direction (glyph, direction, &extents->x_bearing, &extents->y_bearing);
+
+ return ret;
+ }
+
+ inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
+ hb_direction_t direction,
+ hb_position_t *x, hb_position_t *y)
+ {
+ hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
+
+ if (ret)
+ subtract_glyph_origin_for_direction (glyph, direction, x, y);
+
+ return ret;
+ }
+
+ /* Generates gidDDD if glyph has no name. */
+ inline void
+ glyph_to_string (hb_codepoint_t glyph,
+ char *s, unsigned int size)
+ {
+ if (get_glyph_name (glyph, s, size)) return;
+
+ if (size && snprintf (s, size, "gid%u", glyph) < 0)
+ *s = '\0';
+ }
+
+ /* Parses gidDDD and uniUUUU strings automatically. */
+ inline hb_bool_t
+ glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph)
+ {
+ if (get_glyph_from_name (s, len, glyph)) return true;
+
+ if (len == -1) len = strlen (s);
+
+ /* Straight glyph index. */
+ if (hb_codepoint_parse (s, len, 10, glyph))
+ return true;
+
+ if (len > 3)
+ {
+ /* gidDDD syntax for glyph indices. */
+ if (0 == strncmp (s, "gid", 3) &&
+ hb_codepoint_parse (s + 3, len - 3, 10, glyph))
+ return true;
+
+ /* uniUUUU and other Unicode character indices. */
+ hb_codepoint_t unichar;
+ if (0 == strncmp (s, "uni", 3) &&
+ hb_codepoint_parse (s + 3, len - 3, 16, &unichar) &&
+ get_glyph (unichar, 0, glyph))
+ return true;
+ }
+
+ return false;
+ }
+
private:
- inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); }
+ inline hb_position_t em_scale (int16_t v, int scale) { return (hb_position_t) (v * (int64_t) scale / face->get_upem ()); }
};
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#endif /* HB_FONT_PRIVATE_HH */
diff --git a/src/hb-font.cc b/src/hb-font.cc
index 109caff..d42db59 100644
--- a/src/hb-font.cc
+++ b/src/hb-font.cc
@@ -1,5 +1,6 @@
/*
* Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
@@ -29,16 +31,15 @@
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
-#include "hb-blob.h"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
+#include "hb-ot-maxp-table.hh"
#include "hb-cache-private.hh"
#include <string.h>
-
/*
* hb_font_funcs_t
*/
@@ -52,7 +53,7 @@ hb_font_get_glyph_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent)
- return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph);
+ return font->parent->get_glyph (unicode, variation_selector, glyph);
*glyph = 0;
return false;
@@ -65,7 +66,7 @@ hb_font_get_glyph_h_advance_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent)
- return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph));
+ return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
return font->x_scale;
}
@@ -77,7 +78,7 @@ hb_font_get_glyph_v_advance_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent)
- return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph));
+ return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
return font->y_scale;
}
@@ -91,7 +92,7 @@ hb_font_get_glyph_h_origin_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent, glyph, x, y);
+ hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
@@ -110,7 +111,7 @@ hb_font_get_glyph_v_origin_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent, glyph, x, y);
+ hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
@@ -128,7 +129,7 @@ hb_font_get_glyph_h_kerning_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent)
- return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph));
+ return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
return 0;
}
@@ -141,7 +142,7 @@ hb_font_get_glyph_v_kerning_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent)
- return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph));
+ return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
return 0;
}
@@ -154,9 +155,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_extents (font->parent,
- glyph,
- extents);
+ hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
if (ret) {
font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
font->parent_scale_distance (&extents->width, &extents->height);
@@ -178,7 +177,7 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent, glyph, point_index, x, y);
+ hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
if (ret)
font->parent_scale_position (x, y);
return ret;
@@ -196,9 +195,9 @@ hb_font_get_glyph_name_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent)
- return hb_font_get_glyph_name (font->parent, glyph, name, size);
+ return font->parent->get_glyph_name (glyph, name, size);
- snprintf (name, size, "gid%u", glyph);
+ if (size) *name = '\0';
return false;
}
@@ -210,7 +209,7 @@ hb_font_get_glyph_from_name_nil (hb_font_t *font,
void *user_data HB_UNUSED)
{
if (font->parent)
- return hb_font_get_glyph_from_name (font->parent, name, len, glyph);
+ return font->parent->get_glyph_from_name (name, len, glyph);
*glyph = 0;
return false;
@@ -230,6 +229,15 @@ static const hb_font_funcs_t _hb_font_funcs_nil = {
};
+/**
+ * hb_font_funcs_create: (Xconstructor)
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_font_funcs_t *
hb_font_funcs_create (void)
{
@@ -243,18 +251,45 @@ hb_font_funcs_create (void)
return ffuncs;
}
+/**
+ * hb_font_funcs_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_font_funcs_t *
hb_font_funcs_get_empty (void)
{
return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil);
}
+/**
+ * hb_font_funcs_reference: (skip)
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_font_funcs_t *
hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
{
return hb_object_reference (ffuncs);
}
+/**
+ * hb_font_funcs_destroy: (skip)
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
{
@@ -268,6 +303,20 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
free (ffuncs);
}
+/**
+ * hb_font_funcs_set_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key,
@@ -278,6 +327,17 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
return hb_object_set_user_data (ffuncs, key, data, destroy, replace);
}
+/**
+ * hb_font_funcs_get_user_data: (skip)
+ * @ffuncs: font functions.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
void *
hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key)
@@ -286,15 +346,33 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
}
+/**
+ * hb_font_funcs_make_immutable:
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
{
- if (hb_object_is_inert (ffuncs))
+ if (unlikely (hb_object_is_inert (ffuncs)))
return;
ffuncs->immutable = true;
}
+/**
+ * hb_font_funcs_is_immutable:
+ * @ffuncs: font functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
{
@@ -334,476 +412,424 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
+/* Public getters */
+
+/**
+ * hb_font_get_glyph:
+ * @font: a font.
+ * @unicode:
+ * @variation_selector:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph (hb_font_t *font,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
{
- *glyph = 0;
- return font->klass->get.glyph (font, font->user_data,
- unicode, variation_selector, glyph,
- font->klass->user_data.glyph);
+ return font->get_glyph (unicode, variation_selector, glyph);
}
+/**
+ * hb_font_get_glyph_h_advance:
+ * @font: a font.
+ * @glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_position_t
hb_font_get_glyph_h_advance (hb_font_t *font,
hb_codepoint_t glyph)
{
- return font->klass->get.glyph_h_advance (font, font->user_data,
- glyph,
- font->klass->user_data.glyph_h_advance);
+ return font->get_glyph_h_advance (glyph);
}
+/**
+ * hb_font_get_glyph_v_advance:
+ * @font: a font.
+ * @glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_position_t
hb_font_get_glyph_v_advance (hb_font_t *font,
hb_codepoint_t glyph)
{
- return font->klass->get.glyph_v_advance (font, font->user_data,
- glyph,
- font->klass->user_data.glyph_v_advance);
+ return font->get_glyph_v_advance (glyph);
}
+/**
+ * hb_font_get_glyph_h_origin:
+ * @font: a font.
+ * @glyph:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_h_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
- *x = *y = 0;
- return font->klass->get.glyph_h_origin (font, font->user_data,
- glyph, x, y,
- font->klass->user_data.glyph_h_origin);
+ return font->get_glyph_h_origin (glyph, x, y);
}
+/**
+ * hb_font_get_glyph_v_origin:
+ * @font: a font.
+ * @glyph:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_v_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
- *x = *y = 0;
- return font->klass->get.glyph_v_origin (font, font->user_data,
- glyph, x, y,
- font->klass->user_data.glyph_v_origin);
+ return font->get_glyph_v_origin (glyph, x, y);
}
+/**
+ * hb_font_get_glyph_h_kerning:
+ * @font: a font.
+ * @left_glyph:
+ * @right_glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
{
- return font->klass->get.glyph_h_kerning (font, font->user_data,
- left_glyph, right_glyph,
- font->klass->user_data.glyph_h_kerning);
+ return font->get_glyph_h_kerning (left_glyph, right_glyph);
}
+/**
+ * hb_font_get_glyph_v_kerning:
+ * @font: a font.
+ * @top_glyph:
+ * @bottom_glyph:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
- hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
+ hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
{
- return font->klass->get.glyph_v_kerning (font, font->user_data,
- left_glyph, right_glyph,
- font->klass->user_data.glyph_v_kerning);
+ return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
}
+/**
+ * hb_font_get_glyph_extents:
+ * @font: a font.
+ * @glyph:
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents)
{
- memset (extents, 0, sizeof (*extents));
- return font->klass->get.glyph_extents (font, font->user_data,
- glyph,
- extents,
- font->klass->user_data.glyph_extents);
+ return font->get_glyph_extents (glyph, extents);
}
+/**
+ * hb_font_get_glyph_contour_point:
+ * @font: a font.
+ * @glyph:
+ * @point_index:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_contour_point (hb_font_t *font,
hb_codepoint_t glyph, unsigned int point_index,
hb_position_t *x, hb_position_t *y)
{
- *x = *y = 0;
- return font->klass->get.glyph_contour_point (font, font->user_data,
- glyph, point_index,
- x, y,
- font->klass->user_data.glyph_contour_point);
+ return font->get_glyph_contour_point (glyph, point_index, x, y);
}
+/**
+ * hb_font_get_glyph_name:
+ * @font: a font.
+ * @glyph:
+ * @name: (array length=size):
+ * @size:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_name (hb_font_t *font,
hb_codepoint_t glyph,
char *name, unsigned int size)
{
- return font->klass->get.glyph_name (font, font->user_data,
- glyph,
- name, size,
- font->klass->user_data.glyph_name);
+ return font->get_glyph_name (glyph, name, size);
}
+/**
+ * hb_font_get_glyph_from_name:
+ * @font: a font.
+ * @name: (array length=len):
+ * @len:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_from_name (hb_font_t *font,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph)
{
- return font->klass->get.glyph_from_name (font, font->user_data,
- name, len,
- glyph,
- font->klass->user_data.glyph_from_name);
+ return font->get_glyph_from_name (name, len, glyph);
}
/* A bit higher-level, and with fallback */
+/**
+ * hb_font_get_glyph_advance_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_get_glyph_advance_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
- if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
- *x = hb_font_get_glyph_h_advance (font, glyph);
- *y = 0;
- } else {
- *x = 0;
- *y = hb_font_get_glyph_v_advance (font, glyph);
- }
+ return font->get_glyph_advance_for_direction (glyph, direction, x, y);
}
-static void
-guess_v_origin_minus_h_origin (hb_font_t *font,
- hb_codepoint_t glyph,
- hb_position_t *x, hb_position_t *y)
-{
- *x = hb_font_get_glyph_h_advance (font, glyph) / 2;
-
- /* TODO use font_metics.ascent */
- *y = font->y_scale;
-}
-
-
+/**
+ * hb_font_get_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_get_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
- if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
- hb_bool_t ret = hb_font_get_glyph_h_origin (font, glyph, x, y);
- if (!ret && (ret = hb_font_get_glyph_v_origin (font, glyph, x, y))) {
- hb_position_t dx, dy;
- guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
- *x -= dx; *y -= dy;
- }
- } else {
- hb_bool_t ret = hb_font_get_glyph_v_origin (font, glyph, x, y);
- if (!ret && (ret = hb_font_get_glyph_h_origin (font, glyph, x, y))) {
- hb_position_t dx, dy;
- guess_v_origin_minus_h_origin (font, glyph, &dx, &dy);
- *x += dx; *y += dy;
- }
- }
+ return font->get_glyph_origin_for_direction (glyph, direction, x, y);
}
+/**
+ * hb_font_add_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_add_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
- hb_position_t origin_x, origin_y;
-
- hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
-
- *x += origin_x;
- *y += origin_y;
+ return font->add_glyph_origin_for_direction (glyph, direction, x, y);
}
+/**
+ * hb_font_subtract_glyph_origin_for_direction:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
- hb_position_t origin_x, origin_y;
-
- hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y);
-
- *x -= origin_x;
- *y -= origin_y;
+ return font->subtract_glyph_origin_for_direction (glyph, direction, x, y);
}
+/**
+ * hb_font_get_glyph_kerning_for_direction:
+ * @font: a font.
+ * @first_glyph:
+ * @second_glyph:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
- if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
- *x = hb_font_get_glyph_h_kerning (font, first_glyph, second_glyph);
- *y = 0;
- } else {
- *x = 0;
- *y = hb_font_get_glyph_v_kerning (font, first_glyph, second_glyph);
- }
+ return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y);
}
+/**
+ * hb_font_get_glyph_extents_for_origin:
+ * @font: a font.
+ * @glyph:
+ * @direction:
+ * @extents: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_glyph_extents_t *extents)
{
- hb_bool_t ret = hb_font_get_glyph_extents (font, glyph, extents);
-
- if (ret)
- hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, &extents->x_bearing, &extents->y_bearing);
-
- return ret;
+ return font->get_glyph_extents_for_origin (glyph, direction, extents);
}
+/**
+ * hb_font_get_glyph_contour_point_for_origin:
+ * @font: a font.
+ * @glyph:
+ * @point_index:
+ * @direction:
+ * @x: (out):
+ * @y: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
hb_codepoint_t glyph, unsigned int point_index,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
- hb_bool_t ret = hb_font_get_glyph_contour_point (font, glyph, point_index, x, y);
-
- if (ret)
- hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, x, y);
-
- return ret;
-}
-
-
-/*
- * hb_face_t
- */
-
-static const hb_face_t _hb_face_nil = {
- HB_OBJECT_HEADER_STATIC,
-
- true, /* immutable */
-
- NULL, /* reference_table */
- NULL, /* user_data */
- NULL, /* destroy */
-
- NULL, /* ot_layout */
-
- 0, /* index */
- 1000 /* upem */
-};
-
-
-hb_face_t *
-hb_face_create_for_tables (hb_reference_table_func_t reference_table,
- void *user_data,
- hb_destroy_func_t destroy)
-{
- hb_face_t *face;
-
- if (!reference_table || !(face = hb_object_create<hb_face_t> ())) {
- if (destroy)
- destroy (user_data);
- return hb_face_get_empty ();
- }
-
- face->reference_table = reference_table;
- face->user_data = user_data;
- face->destroy = destroy;
-
- face->ot_layout = _hb_ot_layout_create (face);
-
- face->upem = 0;
-
- return face;
-}
-
-
-typedef struct _hb_face_for_data_closure_t {
- hb_blob_t *blob;
- unsigned int index;
-} hb_face_for_data_closure_t;
-
-static hb_face_for_data_closure_t *
-_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
-{
- hb_face_for_data_closure_t *closure;
-
- closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
- if (unlikely (!closure))
- return NULL;
-
- closure->blob = blob;
- closure->index = index;
-
- return closure;
-}
-
-static void
-_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
-{
- hb_blob_destroy (closure->blob);
- free (closure);
-}
-
-static hb_blob_t *
-_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
-{
- hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
-
- if (tag == HB_TAG_NONE)
- return hb_blob_reference (data->blob);
-
- const OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob);
- const OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
-
- const OpenTypeTable &table = ot_face.get_table_by_tag (tag);
-
- hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
-
- return blob;
-}
-
-hb_face_t *
-hb_face_create (hb_blob_t *blob,
- unsigned int index)
-{
- hb_face_t *face;
-
- if (unlikely (!blob || !hb_blob_get_length (blob)))
- return hb_face_get_empty ();
-
- hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
-
- if (unlikely (!closure))
- return hb_face_get_empty ();
-
- face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
- closure,
- (hb_destroy_func_t) _hb_face_for_data_closure_destroy);
-
- hb_face_set_index (face, index);
-
- return face;
-}
-
-hb_face_t *
-hb_face_get_empty (void)
-{
- return const_cast<hb_face_t *> (&_hb_face_nil);
-}
-
-
-hb_face_t *
-hb_face_reference (hb_face_t *face)
-{
- return hb_object_reference (face);
-}
-
-void
-hb_face_destroy (hb_face_t *face)
-{
- if (!hb_object_destroy (face)) return;
-
- _hb_ot_layout_destroy (face->ot_layout);
-
- if (face->destroy)
- face->destroy (face->user_data);
-
- free (face);
-}
-
-hb_bool_t
-hb_face_set_user_data (hb_face_t *face,
- hb_user_data_key_t *key,
- void * data,
- hb_destroy_func_t destroy,
- hb_bool_t replace)
-{
- return hb_object_set_user_data (face, key, data, destroy, replace);
-}
-
-void *
-hb_face_get_user_data (hb_face_t *face,
- hb_user_data_key_t *key)
-{
- return hb_object_get_user_data (face, key);
+ return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y);
}
+/* Generates gidDDD if glyph has no name. */
+/**
+ * hb_font_glyph_to_string:
+ * @font: a font.
+ * @glyph:
+ * @s: (array length=size):
+ * @size:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
-hb_face_make_immutable (hb_face_t *face)
+hb_font_glyph_to_string (hb_font_t *font,
+ hb_codepoint_t glyph,
+ char *s, unsigned int size)
{
- if (hb_object_is_inert (face))
- return;
-
- face->immutable = true;
+ font->glyph_to_string (glyph, s, size);
}
+/* Parses gidDDD and uniUUUU strings automatically. */
+/**
+ * hb_font_glyph_from_string:
+ * @font: a font.
+ * @s: (array length=len) (element-type uint8_t):
+ * @len:
+ * @glyph: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_face_is_immutable (hb_face_t *face)
+hb_font_glyph_from_string (hb_font_t *font,
+ const char *s, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph)
{
- return face->immutable;
-}
-
-
-hb_blob_t *
-hb_face_reference_table (hb_face_t *face,
- hb_tag_t tag)
-{
- hb_blob_t *blob;
-
- if (unlikely (!face || !face->reference_table))
- return hb_blob_get_empty ();
-
- blob = face->reference_table (face, tag, face->user_data);
- if (unlikely (!blob))
- return hb_blob_get_empty ();
-
- return blob;
-}
-
-hb_blob_t *
-hb_face_reference_blob (hb_face_t *face)
-{
- return hb_face_reference_table (face, HB_TAG_NONE);
-}
-
-void
-hb_face_set_index (hb_face_t *face,
- unsigned int index)
-{
- if (hb_object_is_inert (face))
- return;
-
- face->index = index;
-}
-
-unsigned int
-hb_face_get_index (hb_face_t *face)
-{
- return face->index;
-}
-
-void
-hb_face_set_upem (hb_face_t *face,
- unsigned int upem)
-{
- if (hb_object_is_inert (face))
- return;
-
- face->upem = upem;
-}
-
-unsigned int
-hb_face_get_upem (hb_face_t *face)
-{
- if (unlikely (!face->upem)) {
- hb_blob_t *head_blob = Sanitizer<head>::sanitize (hb_face_reference_table (face, HB_OT_TAG_head));
- const head *head_table = Sanitizer<head>::lock_instance (head_blob);
- face->upem = head_table->get_upem ();
- hb_blob_destroy (head_blob);
- }
- return face->upem;
+ return font->glyph_from_string (s, len, glyph);
}
@@ -811,6 +837,16 @@ hb_face_get_upem (hb_face_t *face)
* hb_font_t
*/
+/**
+ * hb_font_create: (Xconstructor)
+ * @face: a face.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_font_t *
hb_font_create (hb_face_t *face)
{
@@ -830,6 +866,16 @@ hb_font_create (hb_face_t *face)
return font;
}
+/**
+ * hb_font_create_sub_font:
+ * @parent: parent font.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_font_t *
hb_font_create_sub_font (hb_font_t *parent)
{
@@ -852,6 +898,15 @@ hb_font_create_sub_font (hb_font_t *parent)
return font;
}
+/**
+ * hb_font_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full)
+ *
+ * Since: 1.0
+ **/
hb_font_t *
hb_font_get_empty (void)
{
@@ -871,32 +926,75 @@ hb_font_get_empty (void)
const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
NULL, /* user_data */
- NULL /* destroy */
+ NULL, /* destroy */
+
+ {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+ }
};
return const_cast<hb_font_t *> (&_hb_font_nil);
}
+/**
+ * hb_font_reference: (skip)
+ * @font: a font.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_font_t *
hb_font_reference (hb_font_t *font)
{
return hb_object_reference (font);
}
+/**
+ * hb_font_destroy: (skip)
+ * @font: a font.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_destroy (hb_font_t *font)
{
if (!hb_object_destroy (font)) return;
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+ if (font->destroy)
+ font->destroy (font->user_data);
+
hb_font_destroy (font->parent);
hb_face_destroy (font->face);
hb_font_funcs_destroy (font->klass);
- if (font->destroy)
- font->destroy (font->user_data);
free (font);
}
+/**
+ * hb_font_set_user_data: (skip)
+ * @font: a font.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_set_user_data (hb_font_t *font,
hb_user_data_key_t *key,
@@ -907,6 +1005,17 @@ hb_font_set_user_data (hb_font_t *font,
return hb_object_set_user_data (font, key, data, destroy, replace);
}
+/**
+ * hb_font_get_user_data: (skip)
+ * @font: a font.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
void *
hb_font_get_user_data (hb_font_t *font,
hb_user_data_key_t *key)
@@ -914,27 +1023,65 @@ hb_font_get_user_data (hb_font_t *font,
return hb_object_get_user_data (font, key);
}
+/**
+ * hb_font_make_immutable:
+ * @font: a font.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_make_immutable (hb_font_t *font)
{
- if (hb_object_is_inert (font))
+ if (unlikely (hb_object_is_inert (font)))
return;
font->immutable = true;
}
+/**
+ * hb_font_is_immutable:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_font_is_immutable (hb_font_t *font)
{
return font->immutable;
}
+/**
+ * hb_font_get_parent:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
hb_font_t *
hb_font_get_parent (hb_font_t *font)
{
return font->parent;
}
+/**
+ * hb_font_get_face:
+ * @font: a font.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
hb_face_t *
hb_font_get_face (hb_font_t *font)
{
@@ -942,15 +1089,26 @@ hb_font_get_face (hb_font_t *font)
}
+/**
+ * hb_font_set_funcs:
+ * @font: a font.
+ * @klass: (closure font_data) (destroy destroy) (scope notified):
+ * @font_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_set_funcs (hb_font_t *font,
hb_font_funcs_t *klass,
- void *user_data,
+ void *font_data,
hb_destroy_func_t destroy)
{
if (font->immutable) {
if (destroy)
- destroy (user_data);
+ destroy (font_data);
return;
}
@@ -963,30 +1121,50 @@ hb_font_set_funcs (hb_font_t *font,
hb_font_funcs_reference (klass);
hb_font_funcs_destroy (font->klass);
font->klass = klass;
- font->user_data = user_data;
+ font->user_data = font_data;
font->destroy = destroy;
}
+/**
+ * hb_font_set_funcs_data:
+ * @font: a font.
+ * @font_data: (destroy destroy) (scope notified):
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_set_funcs_data (hb_font_t *font,
- void *user_data,
+ void *font_data,
hb_destroy_func_t destroy)
{
/* Destroy user_data? */
if (font->immutable) {
if (destroy)
- destroy (user_data);
+ destroy (font_data);
return;
}
if (font->destroy)
font->destroy (font->user_data);
- font->user_data = user_data;
+ font->user_data = font_data;
font->destroy = destroy;
}
+/**
+ * hb_font_set_scale:
+ * @font: a font.
+ * @x_scale:
+ * @y_scale:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_set_scale (hb_font_t *font,
int x_scale,
@@ -999,6 +1177,16 @@ hb_font_set_scale (hb_font_t *font,
font->y_scale = y_scale;
}
+/**
+ * hb_font_get_scale:
+ * @font: a font.
+ * @x_scale: (out):
+ * @y_scale: (out):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_get_scale (hb_font_t *font,
int *x_scale,
@@ -1008,6 +1196,16 @@ hb_font_get_scale (hb_font_t *font,
if (y_scale) *y_scale = font->y_scale;
}
+/**
+ * hb_font_set_ppem:
+ * @font: a font.
+ * @x_ppem:
+ * @y_ppem:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_set_ppem (hb_font_t *font,
unsigned int x_ppem,
@@ -1020,6 +1218,16 @@ hb_font_set_ppem (hb_font_t *font,
font->y_ppem = y_ppem;
}
+/**
+ * hb_font_get_ppem:
+ * @font: a font.
+ * @x_ppem: (out):
+ * @y_ppem: (out):
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_get_ppem (hb_font_t *font,
unsigned int *x_ppem,
@@ -1028,5 +1236,3 @@ hb_font_get_ppem (hb_font_t *font,
if (x_ppem) *x_ppem = font->x_ppem;
if (y_ppem) *y_ppem = font->y_ppem;
}
-
-
diff --git a/src/hb-font.h b/src/hb-font.h
index b98759b..7273db4 100644
--- a/src/hb-font.h
+++ b/src/hb-font.h
@@ -32,85 +32,19 @@
#define HB_FONT_H
#include "hb-common.h"
-#include "hb-blob.h"
+#include "hb-face.h"
HB_BEGIN_DECLS
-typedef struct _hb_face_t hb_face_t;
-typedef struct _hb_font_t hb_font_t;
-
-/*
- * hb_face_t
- */
-
-hb_face_t *
-hb_face_create (hb_blob_t *blob,
- unsigned int index);
-
-typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data);
-
-/* calls destroy() when not needing user_data anymore */
-hb_face_t *
-hb_face_create_for_tables (hb_reference_table_func_t reference_table,
- void *user_data,
- hb_destroy_func_t destroy);
-
-hb_face_t *
-hb_face_get_empty (void);
-
-hb_face_t *
-hb_face_reference (hb_face_t *face);
-
-void
-hb_face_destroy (hb_face_t *face);
-
-hb_bool_t
-hb_face_set_user_data (hb_face_t *face,
- hb_user_data_key_t *key,
- void * data,
- hb_destroy_func_t destroy,
- hb_bool_t replace);
-
-
-void *
-hb_face_get_user_data (hb_face_t *face,
- hb_user_data_key_t *key);
-
-void
-hb_face_make_immutable (hb_face_t *face);
-
-hb_bool_t
-hb_face_is_immutable (hb_face_t *face);
-
-
-hb_blob_t *
-hb_face_reference_table (hb_face_t *face,
- hb_tag_t tag);
-
-hb_blob_t *
-hb_face_reference_blob (hb_face_t *face);
-
-void
-hb_face_set_index (hb_face_t *face,
- unsigned int index);
-
-unsigned int
-hb_face_get_index (hb_face_t *face);
-
-void
-hb_face_set_upem (hb_face_t *face,
- unsigned int upem);
-
-unsigned int
-hb_face_get_upem (hb_face_t *face);
+typedef struct hb_font_t hb_font_t;
/*
* hb_font_funcs_t
*/
-typedef struct _hb_font_funcs_t hb_font_funcs_t;
+typedef struct hb_font_funcs_t hb_font_funcs_t;
hb_font_funcs_t *
hb_font_funcs_create (void);
@@ -143,9 +77,10 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
-/* funcs */
-typedef struct _hb_glyph_extents_t
+/* glyph extents */
+
+typedef struct hb_glyph_extents_t
{
hb_position_t x_bearing;
hb_position_t y_bearing;
@@ -204,54 +139,180 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
/* func setters */
+/**
+ * hb_font_funcs_set_glyph_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
- hb_font_get_glyph_func_t glyph_func,
+ hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_font_funcs_set_glyph_h_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_advance_func_t func,
void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_advance_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_advance_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_font_funcs_set_glyph_h_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_origin_func_t func,
void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_origin_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_origin_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_font_funcs_set_glyph_h_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_v_kerning_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_font_funcs_set_glyph_extents_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_extents_func_t func,
void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_contour_point_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_contour_point_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_font_funcs_set_glyph_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
- hb_font_get_glyph_name_func_t glyph_func,
+ hb_font_get_glyph_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
+
+/**
+ * hb_font_funcs_set_glyph_from_name_func:
+ * @ffuncs: font functions.
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
- hb_font_get_glyph_from_name_func_t glyph_func,
+ hb_font_get_glyph_from_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
@@ -346,6 +407,17 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
+/* Generates gidDDD if glyph has no name. */
+void
+hb_font_glyph_to_string (hb_font_t *font,
+ hb_codepoint_t glyph,
+ char *s, unsigned int size);
+/* Parses gidDDD and uniUUUU strings automatically. */
+hb_bool_t
+hb_font_glyph_from_string (hb_font_t *font,
+ const char *s, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph);
+
/*
* hb_font_t
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index 0589c9e..322f93a 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -51,16 +51,16 @@
* In particular, FT_Get_Advance() without the NO_HINTING flag seems to be
* buggy.
*
- * - We don't handle / allow for emboldening / obliqueing.
- *
- * - Rounding, etc?
- *
- * - In the future, we should add constructors to create fonts in font space.
+ * FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
+ * would work fine. However, we also abuse this API for performing in font-space,
+ * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
+ * for that, such that no rounding etc happens. As such, we don't set ppem, and
+ * pass NO_HINTING around. This seems to work best, until we go ahead and add a full
+ * load_flags API.
*
- * - I believe transforms are not correctly implemented. FreeType does not
- * provide any API to get to the transform/delta set on the face. :(
+ * - We don't handle / allow for emboldening / obliqueing.
*
- * - Always use FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH?
+ * - In the future, we should add constructors to create fonts in font space?
*
* - FT_Load_Glyph() is exteremely costly. Do something about it?
*/
@@ -77,13 +77,10 @@ hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
{
FT_Face ft_face = (FT_Face) font_data;
-#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
if (unlikely (variation_selector)) {
*glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
- if (*glyph)
- return true;
+ return *glyph != 0;
}
-#endif
*glyph = FT_Get_Char_Index (ft_face, unicode);
return *glyph != 0;
@@ -102,7 +99,10 @@ hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
return 0;
- return v >> 10;
+ if (font->x_scale < 0)
+ v = -v;
+
+ return (v + (1<<9)) >> 10;
}
static hb_position_t
@@ -118,9 +118,12 @@ hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
return 0;
+ if (font->y_scale < 0)
+ v = -v;
+
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
* have a Y growing upward. Hence the extra negation. */
- return -v >> 10;
+ return (-v + (1<<9)) >> 10;
}
static hb_bool_t
@@ -144,7 +147,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
FT_Face ft_face = (FT_Face) font_data;
- int load_flags = FT_LOAD_DEFAULT;
+ int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
return false;
@@ -154,11 +157,16 @@ hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
*x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX;
*y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
+ if (font->x_scale < 0)
+ *x = -*x;
+ if (font->y_scale < 0)
+ *y = -*y;
+
return true;
}
static hb_position_t
-hb_ft_get_glyph_h_kerning (hb_font_t *font HB_UNUSED,
+hb_ft_get_glyph_h_kerning (hb_font_t *font,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
@@ -167,7 +175,8 @@ hb_ft_get_glyph_h_kerning (hb_font_t *font HB_UNUSED,
FT_Face ft_face = (FT_Face) font_data;
FT_Vector kerningv;
- if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerningv))
+ FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
+ if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv))
return 0;
return kerningv.x;
@@ -192,7 +201,7 @@ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
FT_Face ft_face = (FT_Face) font_data;
- int load_flags = FT_LOAD_DEFAULT;
+ int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags)))
return false;
@@ -200,7 +209,7 @@ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
extents->width = ft_face->glyph->metrics.width;
- extents->height = ft_face->glyph->metrics.height;
+ extents->height = -ft_face->glyph->metrics.height;
return true;
}
@@ -232,7 +241,7 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
}
static hb_bool_t
-hb_ft_get_glyph_name (hb_font_t *font,
+hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
char *name, unsigned int size,
@@ -241,14 +250,14 @@ hb_ft_get_glyph_name (hb_font_t *font,
FT_Face ft_face = (FT_Face) font_data;
hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
- if (!ret)
- snprintf (name, size, "gid%u", glyph);
+ if (ret && (size && !*name))
+ ret = false;
return ret;
}
static hb_bool_t
-hb_ft_get_glyph_from_name (hb_font_t *font,
+hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *font_data,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
@@ -267,6 +276,15 @@ hb_ft_get_glyph_from_name (hb_font_t *font,
*glyph = FT_Get_Name_Index (ft_face, buf);
}
+ if (*glyph == 0)
+ {
+ /* Check whether the given name was actually the name of glyph 0. */
+ char buf[128];
+ if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
+ len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
+ return true;
+ }
+
return *glyph != 0;
}
@@ -317,7 +335,16 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
buffer, free);
}
-
+/**
+ * hb_ft_face_create:
+ * @ft_face: (destroy destroy) (scope notified):
+ * @destroy:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 1.0
+ **/
hb_face_t *
hb_ft_face_create (FT_Face ft_face,
hb_destroy_func_t destroy)
@@ -329,11 +356,7 @@ hb_ft_face_create (FT_Face ft_face,
blob = hb_blob_create ((const char *) ft_face->stream->base,
(unsigned int) ft_face->stream->size,
- /* TODO: We assume that it's mmap()'ed, but FreeType code
- * suggests that there are cases we reach here but font is
- * not mmapped. For example, when mmap() fails. No idea
- * how to deal with it better here. */
- HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
+ HB_MEMORY_MODE_READONLY,
ft_face, destroy);
face = hb_face_create (blob, ft_face->face_index);
hb_blob_destroy (blob);
@@ -347,12 +370,37 @@ hb_ft_face_create (FT_Face ft_face,
return face;
}
+/**
+ * hb_ft_face_create_referenced:
+ * @ft_face:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 1.0
+ **/
+hb_face_t *
+hb_ft_face_create_referenced (FT_Face ft_face)
+{
+ FT_Reference_Face (ft_face);
+ return hb_ft_face_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
+}
+
static void
hb_ft_face_finalize (FT_Face ft_face)
{
hb_face_destroy ((hb_face_t *) ft_face->generic.data);
}
+/**
+ * hb_ft_face_create_cached:
+ * @ft_face:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 1.0
+ **/
hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face)
{
@@ -374,6 +422,16 @@ _do_nothing (void)
}
+/**
+ * hb_ft_font_create:
+ * @ft_face: (destroy destroy) (scope notified):
+ * @destroy:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 1.0
+ **/
hb_font_t *
hb_ft_font_create (FT_Face ft_face,
hb_destroy_func_t destroy)
@@ -388,25 +446,45 @@ hb_ft_font_create (FT_Face ft_face,
_hb_ft_get_font_funcs (),
ft_face, (hb_destroy_func_t) _do_nothing);
hb_font_set_scale (font,
- ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
- ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
+ (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16),
+ (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16));
+#if 0 /* hb-ft works in no-hinting model */
hb_font_set_ppem (font,
ft_face->size->metrics.x_ppem,
ft_face->size->metrics.y_ppem);
+#endif
return font;
}
+/**
+ * hb_ft_font_create_referenced:
+ * @ft_face:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ * Since: 1.0
+ **/
+hb_font_t *
+hb_ft_font_create_referenced (FT_Face ft_face)
+{
+ FT_Reference_Face (ft_face);
+ return hb_ft_font_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
+}
+
/* Thread-safe, lock-free, FT_Library */
static FT_Library ft_library;
+#ifdef HB_USE_ATEXIT
static
void free_ft_library (void)
{
FT_Done_FreeType (ft_library);
}
+#endif
static FT_Library
get_ft_library (void)
@@ -425,7 +503,7 @@ retry:
goto retry;
}
-#ifdef HAVE_ATEXIT
+#ifdef HB_USE_ATEXIT
atexit (free_ft_library); /* First person registers atexit() callback. */
#endif
}
@@ -464,9 +542,18 @@ hb_ft_font_set_funcs (hb_font_t *font)
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
FT_Set_Char_Size (ft_face,
- font->x_scale, font->y_scale,
+ abs (font->x_scale), abs (font->y_scale),
+ 0, 0);
+#if 0
font->x_ppem * 72 * 64 / font->x_scale,
font->y_ppem * 72 * 64 / font->y_scale);
+#endif
+ if (font->x_scale < 0 || font->y_scale < 0)
+ {
+ FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
+ 0, font->y_scale < 0 ? -1 : +1};
+ FT_Set_Transform (ft_face, &matrix, NULL);
+ }
ft_face->generic.data = blob;
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
diff --git a/src/hb-ft.h b/src/hb-ft.h
index 696251e..92f4b36 100644
--- a/src/hb-ft.h
+++ b/src/hb-ft.h
@@ -34,19 +34,76 @@
HB_BEGIN_DECLS
-/* Note: FreeType is not thread-safe. Hence, these functions are not either. */
+/*
+ * Note: FreeType is not thread-safe.
+ * Hence, these functions are not either.
+ */
+
+/*
+ * hb-face from ft-face.
+ */
+/* This one creates a new hb-face for given ft-face.
+ * When the returned hb-face is destroyed, the destroy
+ * callback is called (if not NULL), with the ft-face passed
+ * to it.
+ *
+ * The client is responsible to make sure that ft-face is
+ * destroyed after hb-face is destroyed.
+ *
+ * Most often you don't want this function. You should use either
+ * hb_ft_face_create_cached(), or hb_ft_face_create_referenced().
+ * In particular, if you are going to pass NULL as destroy, you
+ * probably should use (the more recent) hb_ft_face_create_referenced()
+ * instead.
+ */
hb_face_t *
hb_ft_face_create (FT_Face ft_face,
hb_destroy_func_t destroy);
+/* This version is like hb_ft_face_create(), except that it caches
+ * the hb-face using the generic pointer of the ft-face. This means
+ * that subsequent calls to this function with the same ft-face will
+ * return the same hb-face (correctly referenced).
+ *
+ * Client is still responsible for making sure that ft-face is destroyed
+ * after hb-face is.
+ */
hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face);
+/* This version is like hb_ft_face_create(), except that it calls
+ * FT_Reference_Face() on ft-face, as such keeping ft-face alive
+ * as long as the hb-face is.
+ *
+ * This is the most convenient version to use. Use it unless you have
+ * very good reasons not to.
+ */
+hb_face_t *
+hb_ft_face_create_referenced (FT_Face ft_face);
+
+
+/*
+ * hb-font from ft-face.
+ */
+
+/*
+ * Note:
+ *
+ * Set face size on ft-face before creating hb-font from it.
+ * Otherwise hb-ft would NOT pick up the font size correctly.
+ */
+
+/* See notes on hb_ft_face_create(). Same issues re lifecycle-management
+ * apply here. Use hb_ft_font_create_referenced() if you can. */
hb_font_t *
hb_ft_font_create (FT_Face ft_face,
hb_destroy_func_t destroy);
+/* See notes on hb_ft_face_create_referenced() re lifecycle-management
+ * issues. */
+hb_font_t *
+hb_ft_font_create_referenced (FT_Face ft_face);
/* Makes an hb_font_t use FreeType internally to implement font functions. */
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 6b655dd..61dff5e 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -77,7 +77,7 @@ glib_script_to_script[] =
HB_SCRIPT_THAANA,
HB_SCRIPT_THAI,
HB_SCRIPT_TIBETAN,
- HB_SCRIPT_CANADIAN_ABORIGINAL,
+ HB_SCRIPT_CANADIAN_SYLLABICS,
HB_SCRIPT_YI,
HB_SCRIPT_TAGALOG,
HB_SCRIPT_HANUNOO,
@@ -192,13 +192,13 @@ hb_glib_script_from_script (hb_script_t script)
}
-static unsigned int
+static hb_unicode_combining_class_t
hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
- return g_unichar_combining_class (unicode);
+ return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode);
}
static unsigned int
@@ -250,12 +250,9 @@ hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
/* We don't ifdef-out the fallback code such that compiler always
* sees it and makes sure it's compilable. */
- if (!a || !b)
- return false;
-
gchar utf8[12];
gchar *normalized;
- gint len;
+ int len;
hb_bool_t ret;
len = g_unichar_to_utf8 (a, utf8);
@@ -292,7 +289,7 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
gchar utf8[6];
gchar *normalized;
- gint len;
+ int len;
hb_bool_t ret;
len = g_unichar_to_utf8 (ab, utf8);
@@ -336,23 +333,63 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return ret;
}
+static unsigned int
+hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed,
+ void *user_data HB_UNUSED)
+{
+#if GLIB_CHECK_VERSION(2,29,12)
+ return g_unichar_fully_decompose (u, true, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN);
+#endif
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_glib_unicode_funcs;
-const hb_unicode_funcs_t _hb_glib_unicode_funcs = {
- HB_OBJECT_HEADER_STATIC,
+ /* If the user doesn't have GLib >= 2.29.12 we have to perform
+ * a round trip to UTF-8 and the associated memory management dance. */
+ gchar utf8[6];
+ gchar *utf8_decomposed, *c;
+ gsize utf8_len, utf8_decomposed_len, i;
- NULL, /* parent */
- true, /* immutable */
- {
-#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
- HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
- }
-};
+ /* Convert @u to UTF-8 and normalise it in NFKD mode. This performs the compatibility decomposition. */
+ utf8_len = g_unichar_to_utf8 (u, utf8);
+ utf8_decomposed = g_utf8_normalize (utf8, utf8_len, G_NORMALIZE_NFKD);
+ utf8_decomposed_len = g_utf8_strlen (utf8_decomposed, -1);
+
+ assert (utf8_decomposed_len <= HB_UNICODE_MAX_DECOMPOSITION_LEN);
+
+ for (i = 0, c = utf8_decomposed; i < utf8_decomposed_len; i++, c = g_utf8_next_char (c))
+ *decomposed++ = g_utf8_get_char (c);
+
+ g_free (utf8_decomposed);
+
+ return utf8_decomposed_len;
+}
hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void)
{
+ static const hb_unicode_funcs_t _hb_glib_unicode_funcs = {
+ HB_OBJECT_HEADER_STATIC,
+
+ NULL, /* parent */
+ true, /* immutable */
+ {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
+ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+ }
+ };
+
return const_cast<hb_unicode_funcs_t *> (&_hb_glib_unicode_funcs);
}
+hb_blob_t *
+hb_glib_blob_create (GBytes *gbytes)
+{
+ gsize size = 0;
+ gconstpointer data = g_bytes_get_data (gbytes, &size);
+ return hb_blob_create ((const char *) data,
+ size,
+ HB_MEMORY_MODE_READONLY,
+ g_bytes_ref (gbytes),
+ (hb_destroy_func_t) g_bytes_unref);
+}
diff --git a/src/hb-glib.h b/src/hb-glib.h
index 63a9d33..1a8f42e 100644
--- a/src/hb-glib.h
+++ b/src/hb-glib.h
@@ -46,6 +46,9 @@ hb_glib_script_from_script (hb_script_t script);
hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void);
+hb_blob_t *
+hb_glib_blob_create (GBytes *gbytes);
+
HB_END_DECLS
diff --git a/src/hb-gobject-enums.cc.tmpl b/src/hb-gobject-enums.cc.tmpl
index 05abd89..ca458a3 100644
--- a/src/hb-gobject-enums.cc.tmpl
+++ b/src/hb-gobject-enums.cc.tmpl
@@ -45,13 +45,12 @@
/*** END file-production ***/
/*** BEGIN value-header ***/
-inline static /* TODO(behdad) disable these for now until we fix them... */
GType
@enum_name@_get_type (void)
{
- static volatile gsize g_define_type_id__volatile = 0;
+ static gsize type_id = 0;
- if (g_once_init_enter (&g_define_type_id__volatile))
+ if (g_once_init_enter (&type_id))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
@@ -63,12 +62,12 @@ GType
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
- GType g_define_type_id =
+ GType id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
- g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ g_once_init_leave (&type_id, id);
}
- return g_define_type_id__volatile;
+ return type_id;
}
/*** END value-tail ***/
diff --git a/src/indic.cc b/src/hb-gobject-enums.h.tmpl
index 3b44076..6ecda06 100644
--- a/src/indic.cc
+++ b/src/hb-gobject-enums.h.tmpl
@@ -1,5 +1,6 @@
+/*** BEGIN file-header ***/
/*
- * Copyright © 2012 Google, Inc.
+ * Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -24,23 +25,31 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-ot-shape-complex-indic-private.hh"
+#ifndef HB_GOBJECT_H_IN
+#error "Include <hb-gobject.h> instead."
+#endif
-int
-main (void)
-{
- hb_unicode_funcs_t *funcs = hb_unicode_funcs_get_default ();
+#ifndef HB_GOBJECT_ENUMS_H
+#define HB_GOBJECT_ENUMS_H
- printf ("There are split matras without a Unicode decomposition:\n");
- for (hb_codepoint_t u = 0; u < 0x110000; u++)
- {
- unsigned int type = get_indic_categories (u);
+#include "hb.h"
- unsigned int category = type & 0x0F;
- unsigned int position = type >> 4;
+#include <glib-object.h>
- hb_codepoint_t a, b;
- if (!hb_unicode_decompose (funcs, u, &a, &b))
- printf ("U+%04X %x %x\n", u, category, position);
- }
-}
+HB_BEGIN_DECLS
+
+
+/*** END file-header ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name@_get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
+
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+
+HB_END_DECLS
+
+#endif /* HB_GOBJECT_ENUMS_H */
+/*** END file-tail ***/
diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc
index cec4854..2451b66 100644
--- a/src/hb-gobject-structs.cc
+++ b/src/hb-gobject-structs.cc
@@ -37,27 +37,84 @@
#include "hb-gobject.h"
-#define _HB_DEFINE_BOXED_TYPE(Name,underscore_name,copy_func,free_func) \
+#define HB_DEFINE_BOXED_TYPE(name,copy_func,free_func) \
GType \
-underscore_name##_get_type (void) \
+hb_gobject_##name##_get_type (void) \
{ \
- static volatile gsize type = 0; \
- if (g_once_init_enter (&type)) { \
- GType t = g_boxed_type_register_static (g_intern_static_string (#Name), \
- (GBoxedCopyFunc) copy_func, \
- (GBoxedFreeFunc) free_func); \
- g_once_init_leave (&type, t); \
+ static gsize type_id = 0; \
+ if (g_once_init_enter (&type_id)) { \
+ GType id = g_boxed_type_register_static (g_intern_static_string ("hb_" #name "_t"), \
+ (GBoxedCopyFunc) copy_func, \
+ (GBoxedFreeFunc) free_func); \
+ g_once_init_leave (&type_id, id); \
} \
- return type; \
+ return type_id; \
}
-#define HB_DEFINE_BOXED_TYPE(name) \
- _HB_DEFINE_BOXED_TYPE (hb_##name, hb_gobject_##name, hb_##name##_reference, hb_##name##_destroy);
+#define HB_DEFINE_OBJECT_TYPE(name) \
+ HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
-HB_DEFINE_BOXED_TYPE (buffer)
-HB_DEFINE_BOXED_TYPE (blob)
-HB_DEFINE_BOXED_TYPE (face)
-HB_DEFINE_BOXED_TYPE (font)
-HB_DEFINE_BOXED_TYPE (font_funcs)
-HB_DEFINE_BOXED_TYPE (unicode_funcs)
+HB_DEFINE_OBJECT_TYPE (buffer)
+HB_DEFINE_OBJECT_TYPE (blob)
+HB_DEFINE_OBJECT_TYPE (face)
+HB_DEFINE_OBJECT_TYPE (font)
+HB_DEFINE_OBJECT_TYPE (font_funcs)
+HB_DEFINE_OBJECT_TYPE (set)
+HB_DEFINE_OBJECT_TYPE (shape_plan)
+HB_DEFINE_OBJECT_TYPE (unicode_funcs)
+
+static hb_feature_t *feature_reference (hb_feature_t *g)
+{
+ hb_feature_t *c = (hb_feature_t *) calloc (1, sizeof (hb_feature_t));
+ if (unlikely (!c)) return NULL;
+ *c = *g;
+ return c;
+}
+static void feature_destroy (hb_feature_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (feature, feature_reference, feature_destroy)
+
+static hb_glyph_info_t *glyph_info_reference (hb_glyph_info_t *g)
+{
+ hb_glyph_info_t *c = (hb_glyph_info_t *) calloc (1, sizeof (hb_glyph_info_t));
+ if (unlikely (!c)) return NULL;
+ *c = *g;
+ return c;
+}
+static void glyph_info_destroy (hb_glyph_info_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (glyph_info, glyph_info_reference, glyph_info_destroy)
+
+static hb_glyph_position_t *glyph_position_reference (hb_glyph_position_t *g)
+{
+ hb_glyph_position_t *c = (hb_glyph_position_t *) calloc (1, sizeof (hb_glyph_position_t));
+ if (unlikely (!c)) return NULL;
+ *c = *g;
+ return c;
+}
+static void glyph_position_destroy (hb_glyph_position_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (glyph_position, glyph_position_reference, glyph_position_destroy)
+
+static hb_segment_properties_t *segment_properties_reference (hb_segment_properties_t *g)
+{
+ hb_segment_properties_t *c = (hb_segment_properties_t *) calloc (1, sizeof (hb_segment_properties_t));
+ if (unlikely (!c)) return NULL;
+ *c = *g;
+ return c;
+}
+static void segment_properties_destroy (hb_segment_properties_t *g) { free (g); }
+HB_DEFINE_BOXED_TYPE (segment_properties, segment_properties_reference, segment_properties_destroy)
+
+static hb_user_data_key_t user_data_key_reference (hb_user_data_key_t l) { return l; }
+static void user_data_key_destroy (hb_user_data_key_t l) { }
+HB_DEFINE_BOXED_TYPE (user_data_key, user_data_key_reference, user_data_key_destroy)
+
+
+static hb_language_t *language_reference (hb_language_t *l)
+{
+ hb_language_t *c = (hb_language_t *) calloc (1, sizeof (hb_language_t));
+ if (unlikely (!c)) return NULL;
+ *c = *l;
+ return c;
+}
+static void language_destroy (hb_language_t *l) { free (l); }
+HB_DEFINE_BOXED_TYPE (language, language_reference, language_destroy)
diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h
new file mode 100644
index 0000000..4a88d56
--- /dev/null
+++ b/src/hb-gobject-structs.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2011 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_GOBJECT_H_IN
+#error "Include <hb-gobject.h> instead."
+#endif
+
+#ifndef HB_GOBJECT_STRUCTS_H
+#define HB_GOBJECT_STRUCTS_H
+
+#include "hb.h"
+
+#include <glib-object.h>
+
+HB_BEGIN_DECLS
+
+
+/* Object types */
+
+GType hb_gobject_blob_get_type (void);
+#define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
+
+GType hb_gobject_buffer_get_type (void);
+#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
+
+GType hb_gobject_face_get_type (void);
+#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
+
+GType hb_gobject_font_get_type (void);
+#define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
+
+GType hb_gobject_font_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
+
+GType hb_gobject_set_get_type (void);
+#define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
+
+GType hb_gobject_shape_plan_get_type (void);
+#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
+
+GType hb_gobject_unicode_funcs_get_type (void);
+#define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
+
+/* Value types */
+
+GType hb_gobject_feature_get_type (void);
+#define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ())
+
+GType hb_gobject_glyph_info_get_type (void);
+#define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ())
+
+GType hb_gobject_glyph_position_get_type (void);
+#define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ())
+
+GType hb_gobject_segment_properties_get_type (void);
+#define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
+
+GType hb_gobject_user_data_key_get_type (void);
+#define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
+
+/* Currently gobject-introspection doesn't understand that hb_language_t
+ * can be passed by-value. As such we box it up. May remove in the
+ * future.
+ *
+ * https://bugzilla.gnome.org/show_bug.cgi?id=707656
+ */
+GType hb_gobject_language_get_type (void);
+#define HB_GOBJECT_TYPE_LANGUAGE (hb_gobject_language_get_type ())
+
+HB_END_DECLS
+
+#endif /* HB_GOBJECT_H */
diff --git a/src/hb-gobject.h b/src/hb-gobject.h
index 4f23fdd..ea1bd25 100644
--- a/src/hb-gobject.h
+++ b/src/hb-gobject.h
@@ -26,44 +26,15 @@
#ifndef HB_GOBJECT_H
#define HB_GOBJECT_H
+#define HB_GOBJECT_H_IN
#include "hb.h"
-#include <glib-object.h>
+#include "hb-gobject-enums.h"
+#include "hb-gobject-structs.h"
HB_BEGIN_DECLS
-
-
-/* Objects */
-
-#define HB_GOBJECT_TYPE_BLOB hb_gobject_blob_get_type ()
-GType
-hb_gobject_blob_get_type (void);
-
-#define HB_GOBJECT_TYPE_BUFFER hb_gobject_buffer_get_type ()
-GType
-hb_gobject_buffer_get_type (void);
-
-#define HB_GOBJECT_TYPE_FACE hb_gobject_face_get_type ()
-GType
-hb_gobject_face_get_type (void);
-
-#define HB_GOBJECT_TYPE_FONT hb_gobject_font_get_type ()
-GType
-hb_gobject_font_get_type (void);
-
-#define HB_GOBJECT_TYPE_FONT_FUNCS hb_gobject_font_funcs_get_type ()
-GType
-hb_gobject_font_funcs_get_type (void);
-
-#define HB_GOBJECT_TYPE_UNICODE_FUNCS hb_gobject_unicode_funcs_get_type ()
-GType
-hb_gobject_unicode_funcs_get_type (void);
-
-
-/* Enums */
-
-
HB_END_DECLS
+#undef HB_GOBJECT_H_IN
#endif /* HB_GOBJECT_H */
diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc
index 3fa9f79..807c330 100644
--- a/src/hb-graphite2.cc
+++ b/src/hb-graphite2.cc
@@ -1,7 +1,7 @@
/*
* Copyright © 2011 Martin Hosken
* Copyright © 2011 SIL International
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -26,79 +26,65 @@
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
+#define HB_SHAPER graphite2
+#define hb_graphite2_shaper_font_data_t gr_font
+#include "hb-shaper-impl-private.hh"
#include "hb-graphite2.h"
-#include "hb-buffer-private.hh"
-#include "hb-font-private.hh"
-#include "hb-ot-tag.h"
-
-#include <graphite2/Font.h>
#include <graphite2/Segment.h>
-struct hb_gr_cluster_t {
- unsigned int base_char;
- unsigned int num_chars;
- unsigned int base_glyph;
- unsigned int num_glyphs;
-};
+HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
-typedef struct hb_gr_tablelist_t {
- hb_blob_t *blob;
- struct hb_gr_tablelist_t *next;
- unsigned int tag;
-} hb_gr_tablelist_t;
+/*
+ * shaper face data
+ */
-static struct hb_gr_face_data_t {
- hb_face_t *face;
- gr_face *grface;
- hb_gr_tablelist_t *tlist;
-} _hb_gr_face_data_nil = {NULL, NULL};
+typedef struct hb_graphite2_tablelist_t {
+ struct hb_graphite2_tablelist_t *next;
+ hb_blob_t *blob;
+ unsigned int tag;
+} hb_graphite2_tablelist_t;
-static struct hb_gr_font_data_t {
- gr_font *grfont;
+struct hb_graphite2_shaper_face_data_t {
+ hb_face_t *face;
gr_face *grface;
-} _hb_gr_font_data_nil = {NULL, NULL};
-
+ hb_graphite2_tablelist_t *tlist;
+};
-static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *len)
+static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
{
- hb_gr_tablelist_t *pl = NULL, *p;
- hb_gr_face_data_t *face = (hb_gr_face_data_t *) data;
- hb_gr_tablelist_t *tlist = face->tlist;
-
- for (p = tlist; p; p = p->next)
- if (p->tag == tag ) {
- unsigned int tlen;
- const char *d = hb_blob_get_data (p->blob, &tlen);
- *len = tlen;
- return d;
- } else
- pl = p;
-
- if (!face->face)
- return NULL;
- hb_blob_t *blob = hb_face_reference_table (face->face, tag);
+ hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
+ hb_graphite2_tablelist_t *tlist = face_data->tlist;
- if (!pl || pl->blob)
+ hb_blob_t *blob = NULL;
+
+ for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
+ if (p->tag == tag) {
+ blob = p->blob;
+ break;
+ }
+
+ if (unlikely (!blob))
{
- p = (hb_gr_tablelist_t *) malloc (sizeof (hb_gr_tablelist_t));
- if (!p) {
+ blob = face_data->face->reference_table (tag);
+
+ hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
+ if (unlikely (!p)) {
hb_blob_destroy (blob);
return NULL;
}
- p->next = NULL;
- if (pl)
- pl->next = p;
- else
- face->tlist = p;
- pl = p;
+ p->blob = blob;
+ p->tag = tag;
+
+ /* TODO Not thread-safe, but fairly harmless.
+ * We can do the double-chcked pointer cmpexch thing here. */
+ p->next = face_data->tlist;
+ face_data->tlist = p;
}
- pl->blob = blob;
- pl->tag = tag;
unsigned int tlen;
const char *d = hb_blob_get_data (blob, &tlen);
@@ -106,183 +92,215 @@ static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *
return d;
}
-static float hb_gr_get_advance (const void *hb_font, unsigned short gid)
+hb_graphite2_shaper_face_data_t *
+_hb_graphite2_shaper_face_data_create (hb_face_t *face)
{
- return hb_font_get_glyph_h_advance ((hb_font_t *) hb_font, gid);
+ hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
+ /* Umm, we just reference the table to check whether it exists.
+ * Maybe add better API for this? */
+ if (!hb_blob_get_length (silf_blob))
+ {
+ hb_blob_destroy (silf_blob);
+ return NULL;
+ }
+ hb_blob_destroy (silf_blob);
+
+ hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
+ if (unlikely (!data))
+ return NULL;
+
+ data->face = face;
+ data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
+
+ if (unlikely (!data->grface)) {
+ free (data);
+ return NULL;
+ }
+
+ return data;
}
-static void _hb_gr_face_data_destroy (void *data)
+void
+_hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data)
{
- hb_gr_face_data_t *f = (hb_gr_face_data_t *) data;
- hb_gr_tablelist_t *tlist = f->tlist;
+ hb_graphite2_tablelist_t *tlist = data->tlist;
+
while (tlist)
{
- hb_gr_tablelist_t *old = tlist;
+ hb_graphite2_tablelist_t *old = tlist;
hb_blob_destroy (tlist->blob);
tlist = tlist->next;
free (old);
}
- gr_face_destroy (f->grface);
-}
-static void _hb_gr_font_data_destroy (void *data)
-{
- hb_gr_font_data_t *f = (hb_gr_font_data_t *) data;
+ gr_face_destroy (data->grface);
- gr_font_destroy (f->grfont);
- free (f);
+ free (data);
}
-static hb_user_data_key_t hb_gr_data_key;
-
-static hb_gr_face_data_t *
-_hb_gr_face_get_data (hb_face_t *face)
+gr_face *
+hb_graphite2_face_get_gr_face (hb_face_t *face)
{
- hb_gr_face_data_t *data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
- if (likely (data)) return data;
-
- data = (hb_gr_face_data_t *) calloc (1, sizeof (hb_gr_face_data_t));
- if (unlikely (!data))
- return &_hb_gr_face_data_nil;
+ if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
+ return HB_SHAPER_DATA_GET (face)->grface;
+}
- hb_blob_t *silf_blob = hb_face_reference_table (face, HB_GRAPHITE_TAG_Silf);
- if (!hb_blob_get_length (silf_blob))
- {
- hb_blob_destroy (silf_blob);
- return &_hb_gr_face_data_nil;
- }
+/*
+ * shaper font data
+ */
- data->face = face;
- data->grface = gr_make_face (data, &hb_gr_get_table, gr_face_default);
+static float hb_graphite2_get_advance (const void *hb_font, unsigned short gid)
+{
+ return ((hb_font_t *) hb_font)->get_glyph_h_advance (gid);
+}
+hb_graphite2_shaper_font_data_t *
+_hb_graphite2_shaper_font_data_create (hb_font_t *font)
+{
+ if (unlikely (!hb_graphite2_shaper_face_data_ensure (font->face))) return NULL;
- if (unlikely (!hb_face_set_user_data (face, &hb_gr_data_key, data,
- (hb_destroy_func_t) _hb_gr_face_data_destroy,
- false)))
- {
- _hb_gr_face_data_destroy (data);
- data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key);
- if (data)
- return data;
- else
- return &_hb_gr_face_data_nil;
- }
+ hb_face_t *face = font->face;
+ hb_graphite2_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
- return data;
+ return gr_make_font_with_advance_fn (font->x_scale, font, &hb_graphite2_get_advance, face_data->grface);
}
-static hb_gr_font_data_t *
-_hb_gr_font_get_data (hb_font_t *font)
+void
+_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
{
- hb_gr_font_data_t *data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
- if (likely (data)) return data;
-
- data = (hb_gr_font_data_t *) calloc (1, sizeof (hb_gr_font_data_t));
- if (unlikely (!data))
- return &_hb_gr_font_data_nil;
-
+ gr_font_destroy (data);
+}
- hb_blob_t *silf_blob = hb_face_reference_table (font->face, HB_GRAPHITE_TAG_Silf);
- if (!hb_blob_get_length (silf_blob))
- {
- hb_blob_destroy (silf_blob);
- return &_hb_gr_font_data_nil;
- }
+gr_font *
+hb_graphite2_font_get_gr_font (hb_font_t *font)
+{
+ if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL;
+ return HB_SHAPER_DATA_GET (font);
+}
- data->grface = _hb_gr_face_get_data (font->face)->grface;
- int scale;
- hb_font_get_scale (font, &scale, NULL);
- data->grfont = gr_make_font_with_advance_fn (scale, font, &hb_gr_get_advance, data->grface);
+/*
+ * shaper shape_plan data
+ */
- if (unlikely (!hb_font_set_user_data (font, &hb_gr_data_key, data,
- (hb_destroy_func_t) _hb_gr_font_data_destroy,
- false)))
- {
- _hb_gr_font_data_destroy (data);
- data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key);
- if (data)
- return data;
- else
- return &_hb_gr_font_data_nil;
- }
+struct hb_graphite2_shaper_shape_plan_data_t {};
- return data;
+hb_graphite2_shaper_shape_plan_data_t *
+_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
+ const hb_feature_t *user_features HB_UNUSED,
+ unsigned int num_user_features HB_UNUSED)
+{
+ return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
-
-hb_bool_t
-_hb_graphite_shape (hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *features,
- unsigned int num_features)
+void
+_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shaper_shape_plan_data_t *data HB_UNUSED)
{
+}
- buffer->guess_properties ();
-
- /* XXX We do a hell of a lot of stuff just to figure out this font
- * is not graphite! Shouldn't do. */
-
- hb_gr_font_data_t *data = _hb_gr_font_get_data (font);
- if (!data->grface) return false;
- unsigned int charlen;
- hb_glyph_info_t *bufferi = hb_buffer_get_glyph_infos (buffer, &charlen);
+/*
+ * shaper
+ */
- int success = 0;
+struct hb_graphite2_cluster_t {
+ unsigned int base_char;
+ unsigned int num_chars;
+ unsigned int base_glyph;
+ unsigned int num_glyphs;
+ unsigned int cluster;
+};
- if (!charlen) return true;
+hb_bool_t
+_hb_graphite2_shape (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features)
+{
+ hb_face_t *face = font->face;
+ gr_face *grface = HB_SHAPER_DATA_GET (face)->grface;
+ gr_font *grfont = HB_SHAPER_DATA_GET (font);
const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
- const char *lang_end = strchr (lang, '-');
+ const char *lang_end = lang ? strchr (lang, '-') : NULL;
int lang_len = lang_end ? lang_end - lang : -1;
- gr_feature_val *feats = gr_face_featureval_for_lang (data->grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
+ gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
while (num_features--)
{
- const gr_feature_ref *fref = gr_face_find_fref (data->grface, features->tag);
+ const gr_feature_ref *fref = gr_face_find_fref (grface, features->tag);
if (fref)
gr_fref_set_feature_value (fref, features->value, feats);
features++;
}
- hb_codepoint_t *gids = NULL, *pg;
- hb_gr_cluster_t *clusters = NULL;
gr_segment *seg = NULL;
- uint32_t *text = NULL;
const gr_slot *is;
unsigned int ci = 0, ic = 0;
float curradvx = 0., curradvy = 0.;
- unsigned int glyphlen = 0;
- unsigned int *p;
- text = (uint32_t *) malloc ((charlen + 1) * sizeof (uint32_t));
- if (!text) goto dieout;
+ unsigned int scratch_size;
+ hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+
+ uint32_t *chars = (uint32_t *) scratch;
- p = text;
- for (unsigned int i = 0; i < charlen; ++i)
- *p++ = bufferi++->codepoint;
- *p = 0;
+ for (unsigned int i = 0; i < buffer->len; ++i)
+ chars[i] = buffer->info[i].codepoint;
hb_tag_t script_tag[2];
hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
- seg = gr_make_seg (data->grfont, data->grface,
+ seg = gr_make_seg (grfont, grface,
script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
feats,
- gr_utf32, text, charlen,
+ gr_utf32, chars, buffer->len,
2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
- if (!seg) goto dieout;
- glyphlen = gr_seg_n_slots (seg);
- clusters = (hb_gr_cluster_t *) calloc (charlen, sizeof (hb_gr_cluster_t));
- if (!glyphlen || !clusters) goto dieout;
+ if (unlikely (!seg)) {
+ if (feats) gr_featureval_destroy (feats);
+ return false;
+ }
+
+ unsigned int glyph_count = gr_seg_n_slots (seg);
+ if (unlikely (!glyph_count)) {
+ if (feats) gr_featureval_destroy (feats);
+ gr_seg_destroy (seg);
+ return false;
+ }
+
+ scratch = buffer->get_scratch_buffer (&scratch_size);
+ while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
+ DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
+ {
+ if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+ {
+ if (feats) gr_featureval_destroy (feats);
+ gr_seg_destroy (seg);
+ return false;
+ }
+ scratch = buffer->get_scratch_buffer (&scratch_size);
+ }
+
+#define ALLOCATE_ARRAY(Type, name, len) \
+ Type *name = (Type *) scratch; \
+ { \
+ unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+ assert (_consumed <= scratch_size); \
+ scratch += _consumed; \
+ scratch_size -= _consumed; \
+ }
+
+ ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
+ ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
- gids = (hb_codepoint_t *) malloc (glyphlen * sizeof (hb_codepoint_t));
- if (!gids) goto dieout;
+#undef ALLOCATE_ARRAY
- pg = gids;
+ memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
+
+ hb_codepoint_t *pg = gids;
+ clusters[0].cluster = buffer->info[0].cluster;
for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
{
unsigned int before = gr_slot_before (is);
@@ -298,8 +316,9 @@ _hb_graphite_shape (hb_font_t *font,
if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
{
- hb_gr_cluster_t *c = clusters + ci + 1;
+ hb_graphite2_cluster_t *c = clusters + ci + 1;
c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
+ c->cluster = buffer->info[c->base_char].cluster;
c->num_chars = before - c->base_char;
c->base_glyph = ic;
c->num_glyphs = 0;
@@ -312,39 +331,46 @@ _hb_graphite_shape (hb_font_t *font,
}
ci++;
- buffer->clear_output ();
+ //buffer->clear_output ();
for (unsigned int i = 0; i < ci; ++i)
- buffer->replace_glyphs (clusters[i].num_chars, clusters[i].num_glyphs, gids + clusters[i].base_glyph);
- buffer->swap_buffers ();
+ {
+ for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
+ {
+ hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
+ info->codepoint = gids[clusters[i].base_glyph + j];
+ info->cluster = clusters[i].cluster;
+ }
+ }
+ buffer->len = glyph_count;
+ //buffer->swap_buffers ();
+
+ if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ curradvx = gr_seg_advance_X(seg);
hb_glyph_position_t *pPos;
for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
is; pPos++, is = gr_slot_next_in_segment (is))
{
- pPos->x_offset = gr_slot_origin_X(is) - curradvx;
- pPos->y_offset = gr_slot_origin_Y(is) - curradvy;
- pPos->x_advance = gr_slot_advance_X(is, data->grface, data->grfont);
- pPos->y_advance = gr_slot_advance_Y(is, data->grface, data->grfont);
-// if (pPos->x_advance < 0 && gr_slot_attached_to(is))
-// pPos->x_advance = 0;
- curradvx += pPos->x_advance;
+ pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+ pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
+ pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
+ pPos->y_advance = gr_slot_advance_Y (is, grface, grfont);
+ if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+ curradvx -= pPos->x_advance;
+ pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+ if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+ curradvx += pPos->x_advance;
+ pPos->y_offset = gr_slot_origin_Y (is) - curradvy;
curradvy += pPos->y_advance;
}
- pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
-
- /* TODO(behdad):
- * This shaper is badly broken with RTL text. It returns glyphs
- * in the logical order!
- */
-// if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
-// hb_buffer_reverse (buffer);
-
- success = 1;
-
-dieout:
- if (gids) free (gids);
- if (clusters) free (clusters);
- if (seg) gr_seg_destroy (seg);
- if (text) free (text);
- return success;
+ if (!HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+ pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
+
+ if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
+ hb_buffer_reverse_clusters (buffer);
+
+ if (feats) gr_featureval_destroy (feats);
+ gr_seg_destroy (seg);
+
+ return true;
}
diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h
index 2d16cc8..3eae54a 100644
--- a/src/hb-graphite2.h
+++ b/src/hb-graphite2.h
@@ -28,12 +28,20 @@
#include "hb.h"
+#include <graphite2/Font.h>
+
HB_BEGIN_DECLS
-#define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f')
+#define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
+
+
+gr_face *
+hb_graphite2_face_get_gr_face (hb_face_t *face);
+
+gr_font *
+hb_graphite2_font_get_gr_font (hb_font_t *font);
-/* TODO add gr_font/face etc getters and other glue API */
HB_END_DECLS
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index aead6dd..24cec9d 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -33,11 +33,10 @@
#include "hb-unicode-private.hh"
-#include <unicode/uversion.h>
#include <unicode/uchar.h>
#include <unicode/unorm.h>
#include <unicode/ustring.h>
-
+#include <unicode/uversion.h>
hb_script_t
@@ -63,13 +62,13 @@ hb_icu_script_from_script (hb_script_t script)
}
-static unsigned int
+static hb_unicode_combining_class_t
hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
- return u_getCombiningClass (unicode);
+ return (hb_unicode_combining_class_t) u_getCombiningClass (unicode);
}
static unsigned int
@@ -164,6 +163,10 @@ hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return hb_icu_script_to_script (scriptCode);
}
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+static const UNormalizer2 *normalizer;
+#endif
+
static hb_bool_t
hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t a,
@@ -171,11 +174,20 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t *ab,
void *user_data HB_UNUSED)
{
- if (!a || !b)
- return false;
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ {
+ UChar32 ret = unorm2_composePair (normalizer, a, b);
+ if (ret < 0) return false;
+ *ab = ret;
+ return true;
+ }
+#endif
+
+ /* We don't ifdef-out the fallback code such that compiler always
+ * sees it and makes sure it's compilable. */
UChar utf16[4], normalized[5];
- int len;
+ unsigned int len;
hb_bool_t ret, err;
UErrorCode icu_err;
@@ -207,8 +219,34 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t *b,
void *user_data HB_UNUSED)
{
- UChar utf16[2], normalized[20];
- int len;
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ {
+ UChar decomposed[4];
+ int len;
+ UErrorCode icu_err = U_ZERO_ERROR;
+ len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
+ ARRAY_LENGTH (decomposed), &icu_err);
+ if (U_FAILURE (icu_err) || len < 0) return false;
+
+ len = u_countChar32 (decomposed, len);
+ if (len == 1) {
+ U16_GET_UNSAFE (decomposed, 0, *a);
+ *b = 0;
+ return *a != ab;
+ } else if (len == 2) {
+ len =0;
+ U16_NEXT_UNSAFE (decomposed, len, *a);
+ U16_NEXT_UNSAFE (decomposed, len, *b);
+ }
+ return true;
+ }
+#endif
+
+ /* We don't ifdef-out the fallback code such that compiler always
+ * sees it and makes sure it's compilable. */
+
+ UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
+ unsigned int len;
hb_bool_t ret, err;
UErrorCode icu_err;
@@ -255,13 +293,15 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
} else {
/* If decomposed to more than two characters, take the last one,
* and recompose the rest to get the first component. */
- U16_PREV_UNSAFE (normalized, len, *b);
- UChar recomposed[20];
+ U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */
+ UChar recomposed[18 * 2];
icu_err = U_ZERO_ERROR;
len = unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
if (U_FAILURE (icu_err))
return false;
/* We expect that recomposed has exactly one character now. */
+ if (unlikely (u_countChar32 (recomposed, len) != 1))
+ return false;
U16_GET_UNSAFE (recomposed, 0, *a);
ret = true;
}
@@ -269,24 +309,62 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return ret;
}
+static unsigned int
+hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed,
+ void *user_data HB_UNUSED)
+{
+ UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
+ unsigned int len;
+ int32_t utf32_len;
+ hb_bool_t err;
+ UErrorCode icu_err;
+
+ /* Copy @u into a UTF-16 array to be passed to ICU. */
+ len = 0;
+ err = false;
+ U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err);
+ if (err)
+ return 0;
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_icu_unicode_funcs;
-const hb_unicode_funcs_t _hb_icu_unicode_funcs = {
- HB_OBJECT_HEADER_STATIC,
+ /* Normalise the codepoint using NFKD mode. */
+ icu_err = U_ZERO_ERROR;
+ len = unorm_normalize (utf16, len, UNORM_NFKD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
+ if (icu_err)
+ return 0;
+
+ /* Convert the decomposed form from UTF-16 to UTF-32. */
+ icu_err = U_ZERO_ERROR;
+ u_strToUTF32 ((UChar32*) decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN, &utf32_len, normalized, len, &icu_err);
+ if (icu_err)
+ return 0;
+
+ return utf32_len;
+}
- NULL, /* parent */
- true, /* immutable */
- {
-#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
- HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_UNICODE_FUNC_IMPLEMENT
- }
-};
hb_unicode_funcs_t *
hb_icu_get_unicode_funcs (void)
{
- return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
-}
+ static const hb_unicode_funcs_t _hb_icu_unicode_funcs = {
+ HB_OBJECT_HEADER_STATIC,
+ NULL, /* parent */
+ true, /* immutable */
+ {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name,
+ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+ }
+ };
+#if U_ICU_VERSION_MAJOR_NUM >= 49
+ if (!hb_atomic_ptr_get (&normalizer)) {
+ UErrorCode icu_err = U_ZERO_ERROR;
+ /* We ignore failure in getNFCInstace(). */
+ (void) hb_atomic_ptr_cmpexch (&normalizer, NULL, unorm2_getNFCInstance (&icu_err));
+ }
+#endif
+ return const_cast<hb_unicode_funcs_t *> (&_hb_icu_unicode_funcs);
+}
diff --git a/src/hb-icu.h b/src/hb-icu.h
index d22a8e1..f2f35f0 100644
--- a/src/hb-icu.h
+++ b/src/hb-icu.h
@@ -33,7 +33,6 @@
#include <unicode/uscript.h>
-
HB_BEGIN_DECLS
diff --git a/src/hb-mutex-private.hh b/src/hb-mutex-private.hh
index f9bd679..a8ea39c 100644
--- a/src/hb-mutex-private.hh
+++ b/src/hb-mutex-private.hh
@@ -42,12 +42,16 @@
#if 0
-#elif !defined(HB_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__)
+#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#include <windows.h>
typedef CRITICAL_SECTION hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 }
+#define HB_MUTEX_IMPL_INIT {0}
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
+#else
#define hb_mutex_impl_init(M) InitializeCriticalSection (M)
+#endif
#define hb_mutex_impl_lock(M) EnterCriticalSection (M)
#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
@@ -64,17 +68,6 @@ typedef pthread_mutex_t hb_mutex_impl_t;
#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
-#elif !defined(HB_NO_MT) && defined(HAVE_GLIB)
-
-#include <glib.h>
-typedef GStaticMutex hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT G_STATIC_MUTEX_INIT
-#define hb_mutex_impl_init(M) g_static_mutex_init (M)
-#define hb_mutex_impl_lock(M) g_static_mutex_lock (M)
-#define hb_mutex_impl_unlock(M) g_static_mutex_unlock (M)
-#define hb_mutex_impl_finish(M) g_static_mutex_free (M)
-
-
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
diff --git a/src/hb-object-private.hh b/src/hb-object-private.hh
index 96d1bd3..7bd0f16 100644
--- a/src/hb-object-private.hh
+++ b/src/hb-object-private.hh
@@ -65,11 +65,9 @@ struct hb_reference_count_t
/* user_data */
-#define HB_USER_DATA_ARRAY_INIT {HB_LOCKABLE_SET_INIT}
+#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT}
struct hb_user_data_array_t
{
- /* TODO Add tracing. */
-
struct hb_user_data_item_t {
hb_user_data_key_t *key;
void *data;
@@ -81,20 +79,19 @@ struct hb_user_data_array_t
void finish (void) { if (destroy) destroy (data); }
};
+ hb_mutex_t lock;
hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items;
- inline void init (void) { items.init (); }
+ inline void init (void) { lock.init (); items.init (); }
HB_INTERNAL bool set (hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
- hb_bool_t replace,
- hb_mutex_t &lock);
+ hb_bool_t replace);
- HB_INTERNAL void *get (hb_user_data_key_t *key,
- hb_mutex_t &lock);
+ HB_INTERNAL void *get (hb_user_data_key_t *key);
- HB_INTERNAL void finish (hb_mutex_t &lock);
+ inline void finish (void) { items.finish (lock); lock.finish (); }
};
@@ -103,75 +100,9 @@ struct hb_user_data_array_t
struct hb_object_header_t
{
hb_reference_count_t ref_count;
- hb_mutex_t lock;
hb_user_data_array_t user_data;
-#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_MUTEX_INIT, HB_USER_DATA_ARRAY_INIT}
-
- static inline void *create (unsigned int size) {
- hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size);
-
- if (likely (obj))
- obj->init ();
-
- return obj;
- }
-
- inline void init (void) {
- ref_count.init (1);
- lock.init ();
- user_data.init ();
- }
-
- inline bool is_inert (void) const {
- return unlikely (ref_count.is_invalid ());
- }
-
- inline void reference (void) {
- if (unlikely (!this || this->is_inert ()))
- return;
- ref_count.inc ();
- }
-
- inline bool destroy (void) {
- if (unlikely (!this || this->is_inert ()))
- return false;
- if (ref_count.dec () != 1)
- return false;
-
- ref_count.finish (); /* Do this before user_data */
- user_data.finish (lock);
- lock.finish ();
-
- return true;
- }
-
- inline bool set_user_data (hb_user_data_key_t *key,
- void * data,
- hb_destroy_func_t destroy_func,
- hb_bool_t replace) {
- if (unlikely (!this || this->is_inert ()))
- return false;
-
- return user_data.set (key, data, destroy_func, replace, lock);
- }
-
- inline void *get_user_data (hb_user_data_key_t *key) {
- if (unlikely (!this || this->is_inert ()))
- return NULL;
-
- return user_data.get (key, lock);
- }
-
- inline void trace (const char *function) const {
- if (unlikely (!this)) return;
- /* XXX We cannot use DEBUG_MSG_FUNC here since that one currecntly only
- * prints the class name and throws away the template info. */
- DEBUG_MSG (OBJECT, (void *) this,
- "%s refcount=%d",
- function,
- this ? ref_count.ref_count : 0);
- }
+#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT}
private:
ASSERT_POD ();
@@ -183,32 +114,56 @@ struct hb_object_header_t
template <typename Type>
static inline void hb_object_trace (const Type *obj, const char *function)
{
- obj->header.trace (function);
+ DEBUG_MSG (OBJECT, (void *) obj,
+ "%s refcount=%d",
+ function,
+ obj ? obj->header.ref_count.ref_count : 0);
}
+
template <typename Type>
static inline Type *hb_object_create (void)
{
- Type *obj = (Type *) hb_object_header_t::create (sizeof (Type));
+ Type *obj = (Type *) calloc (1, sizeof (Type));
+
+ if (unlikely (!obj))
+ return obj;
+
+ hb_object_init (obj);
hb_object_trace (obj, HB_FUNC);
return obj;
}
template <typename Type>
+static inline void hb_object_init (Type *obj)
+{
+ obj->header.ref_count.init (1);
+ obj->header.user_data.init ();
+}
+template <typename Type>
static inline bool hb_object_is_inert (const Type *obj)
{
- return unlikely (obj->header.is_inert ());
+ return unlikely (obj->header.ref_count.is_invalid ());
}
template <typename Type>
static inline Type *hb_object_reference (Type *obj)
{
hb_object_trace (obj, HB_FUNC);
- obj->header.reference ();
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return obj;
+ obj->header.ref_count.inc ();
return obj;
}
template <typename Type>
static inline bool hb_object_destroy (Type *obj)
{
hb_object_trace (obj, HB_FUNC);
- return obj->header.destroy ();
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return false;
+ if (obj->header.ref_count.dec () != 1)
+ return false;
+
+ obj->header.ref_count.finish (); /* Do this before user_data */
+ obj->header.user_data.finish ();
+ return true;
}
template <typename Type>
static inline bool hb_object_set_user_data (Type *obj,
@@ -217,14 +172,18 @@ static inline bool hb_object_set_user_data (Type *obj,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
- return obj->header.set_user_data (key, data, destroy, replace);
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return false;
+ return obj->header.user_data.set (key, data, destroy, replace);
}
template <typename Type>
static inline void *hb_object_get_user_data (Type *obj,
hb_user_data_key_t *key)
{
- return obj->header.get_user_data (key);
+ if (unlikely (!obj || hb_object_is_inert (obj)))
+ return NULL;
+ return obj->header.user_data.get (key);
}
diff --git a/src/hb-open-file-private.hh b/src/hb-open-file-private.hh
index ce18580..178bc7c 100644
--- a/src/hb-open-file-private.hh
+++ b/src/hb-open-file-private.hh
@@ -32,6 +32,8 @@
#include "hb-open-type-private.hh"
+namespace OT {
+
/*
*
@@ -51,8 +53,9 @@ struct TTCHeader;
typedef struct TableRecord
{
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -100,17 +103,18 @@ typedef struct OffsetTable
}
public:
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
}
- private:
+ protected:
Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
USHORT numTables; /* Number of tables. */
- USHORT searchRange; /* (Maximum power of 2 <= numTables) x 16 */
- USHORT entrySelector; /* Log2(maximum power of 2 <= numTables). */
- USHORT rangeShift; /* NumTables x 16-searchRange. */
+ USHORT searchRangeZ; /* (Maximum power of 2 <= numTables) x 16 */
+ USHORT entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */
+ USHORT rangeShiftZ; /* NumTables x 16-searchRange. */
TableRecord tables[VAR]; /* TableRecord entries. numTables items */
public:
DEFINE_SIZE_ARRAY (12, tables);
@@ -128,16 +132,17 @@ struct TTCHeaderVersion1
inline unsigned int get_face_count (void) const { return table.len; }
inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (table.sanitize (c, this));
}
- private:
+ protected:
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion version; /* Version of the TTC Header (1.0),
- * 0x00010000 */
- LongOffsetLongArrayOf<OffsetTable>
+ * 0x00010000u */
+ ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
@@ -167,8 +172,9 @@ struct TTCHeader
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false);
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
@@ -177,12 +183,12 @@ struct TTCHeader
}
}
- private:
+ protected:
union {
struct {
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion version; /* Version of the TTC Header (1.0 or 2.0),
- * 0x00010000 or 0x00020000 */
+ * 0x00010000u or 0x00020000u */
} header;
TTCHeaderVersion1 version1;
} u;
@@ -195,6 +201,8 @@ struct TTCHeader
struct OpenTypeFontFile
{
+ static const hb_tag_t tableTag = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
+
static const hb_tag_t CFFTag = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */
static const hb_tag_t TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */
static const hb_tag_t TTCTag = HB_TAG ('t','t','c','f'); /* TrueType Collection */
@@ -229,8 +237,9 @@ struct OpenTypeFontFile
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false);
switch (u.tag) {
case CFFTag: /* All the non-collection tags */
@@ -242,7 +251,7 @@ struct OpenTypeFontFile
}
}
- private:
+ protected:
union {
Tag tag; /* 4-byte identifier. */
OpenTypeFontFace fontFace;
@@ -253,5 +262,7 @@ struct OpenTypeFontFile
};
+} /* namespace OT */
+
#endif /* HB_OPEN_FILE_PRIVATE_HH */
diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh
index 5d90e5b..75a0f56 100644
--- a/src/hb-open-type-private.hh
+++ b/src/hb-open-type-private.hh
@@ -31,7 +31,8 @@
#include "hb-private.hh"
-#include "hb-blob.h"
+
+namespace OT {
@@ -41,36 +42,36 @@
/* Cast to struct T, reference to reference */
template<typename Type, typename TObject>
-inline const Type& CastR(const TObject &X)
+static inline const Type& CastR(const TObject &X)
{ return reinterpret_cast<const Type&> (X); }
template<typename Type, typename TObject>
-inline Type& CastR(TObject &X)
+static inline Type& CastR(TObject &X)
{ return reinterpret_cast<Type&> (X); }
/* Cast to struct T, pointer to pointer */
template<typename Type, typename TObject>
-inline const Type* CastP(const TObject *X)
+static inline const Type* CastP(const TObject *X)
{ return reinterpret_cast<const Type*> (X); }
template<typename Type, typename TObject>
-inline Type* CastP(TObject *X)
+static inline Type* CastP(TObject *X)
{ return reinterpret_cast<Type*> (X); }
/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
* location pointed to by P plus Ofs bytes. */
template<typename Type>
-inline const Type& StructAtOffset(const void *P, unsigned int offset)
+static inline const Type& StructAtOffset(const void *P, unsigned int offset)
{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
template<typename Type>
-inline Type& StructAtOffset(void *P, unsigned int offset)
+static inline Type& StructAtOffset(void *P, unsigned int offset)
{ return * reinterpret_cast<Type*> ((char *) P + offset); }
/* StructAfter<T>(X) returns the struct T& that is placed after X.
* Works with X of variable size also. X must implement get_size() */
template<typename Type, typename TObject>
-inline const Type& StructAfter(const TObject &X)
+static inline const Type& StructAfter(const TObject &X)
{ return StructAtOffset<Type>(&X, X.get_size()); }
template<typename Type, typename TObject>
-inline Type& StructAfter(TObject &X)
+static inline Type& StructAfter(TObject &X)
{ return StructAtOffset<Type>(&X, X.get_size()); }
@@ -130,20 +131,21 @@ inline Type& StructAfter(TObject &X)
*/
/* Global nul-content Null pool. Enlarge as necessary. */
-static const void *_NullPool[64 / sizeof (void *)];
+/* TODO This really should be a extern HB_INTERNAL and defined somewhere... */
+static const void *_NullPool[(256+8) / sizeof (void *)];
/* Generic nul-content Null objects. */
template <typename Type>
static inline const Type& Null (void) {
- ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
+ ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool));
return *CastP<Type> (_NullPool);
}
/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
#define DEFINE_NULL_DATA(Type, data) \
-static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
+static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \
template <> \
-inline const Type& Null<Type> (void) { \
+/*static*/ inline const Type& Null<Type> (void) { \
return *CastP<Type> (_Null##Type); \
} /* The following line really exists such that we end in a place needing semicolon */ \
ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
@@ -162,12 +164,29 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
#endif
-#define TRACE_SANITIZE() \
- hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, "");
+#define TRACE_SANITIZE(this) \
+ hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "");
+/* This limits sanitizing time on really broken fonts. */
+#ifndef HB_SANITIZE_MAX_EDITS
+#define HB_SANITIZE_MAX_EDITS 100
+#endif
struct hb_sanitize_context_t
{
+ inline const char *get_name (void) { return "SANITIZE"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
+ typedef bool return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format)
+ { return format->sanitize (this); }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
+ static return_t default_return_value (void) { return true; }
+ bool stop_sublookup_iteration (const return_t r) const { return !r; }
+
inline void init (hb_blob_t *b)
{
this->blob = hb_blob_reference (b);
@@ -178,10 +197,11 @@ struct hb_sanitize_context_t
{
this->start = hb_blob_get_data (this->blob, NULL);
this->end = this->start + hb_blob_get_length (this->blob);
+ assert (this->start <= this->end); /* Must not overflow. */
this->edit_count = 0;
this->debug_depth = 0;
- DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1,
+ DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
"start [%p..%p] (%lu bytes)",
this->start, this->end,
(unsigned long) (this->end - this->start));
@@ -189,7 +209,7 @@ struct hb_sanitize_context_t
inline void end_processing (void)
{
- DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1,
+ DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
"end [%p..%p] %u edit requests",
this->start, this->end, this->edit_count);
@@ -201,26 +221,31 @@ struct hb_sanitize_context_t
inline bool check_range (const void *base, unsigned int len) const
{
const char *p = (const char *) base;
+ bool ok = this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len;
- hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
- "check_range [%p..%p] (%d bytes) in [%p..%p]",
- p, p + len, len,
- this->start, this->end);
+ DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+ "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
+ p, p + len, len,
+ this->start, this->end,
+ ok ? "OK" : "OUT-OF-RANGE");
- return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len));
+ return likely (ok);
}
inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
{
const char *p = (const char *) base;
bool overflows = _hb_unsigned_int_mul_overflows (len, record_size);
+ unsigned int array_size = record_size * len;
+ bool ok = !overflows && this->check_range (base, array_size);
- hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
- "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]",
- p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
- this->start, this->end);
+ DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+ "check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
+ p, p + (record_size * len), record_size, len, (unsigned int) array_size,
+ this->start, this->end,
+ overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
- return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len)));
+ return likely (ok);
}
template <typename Type>
@@ -231,16 +256,29 @@ struct hb_sanitize_context_t
inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
{
+ if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
+ return false;
+
const char *p = (const char *) base;
this->edit_count++;
- hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL,
- "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
- this->edit_count,
- p, p + len, len,
- this->start, this->end);
+ DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+ "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
+ this->edit_count,
+ p, p + len, len,
+ this->start, this->end,
+ this->writable ? "GRANTED" : "DENIED");
+
+ return this->writable;
+ }
- return TRACE_RETURN (this->writable);
+ template <typename Type, typename ValueType>
+ inline bool try_set (const Type *obj, const ValueType &v) {
+ if (this->may_edit (obj, obj->static_size)) {
+ const_cast<Type *> (obj)->set (v);
+ return true;
+ }
+ return false;
}
mutable unsigned int debug_depth;
@@ -257,7 +295,7 @@ template <typename Type>
struct Sanitizer
{
static hb_blob_t *sanitize (hb_blob_t *blob) {
- hb_sanitize_context_t c[1] = {{0}};
+ hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}};
bool sane;
/* TODO is_sane() stuff */
@@ -265,7 +303,7 @@ struct Sanitizer
c->init (blob);
retry:
- DEBUG_MSG_FUNC (SANITIZE, blob, "start");
+ DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
c->start_processing ();
@@ -279,13 +317,13 @@ struct Sanitizer
sane = t->sanitize (c);
if (sane) {
if (c->edit_count) {
- DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count);
+ DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count);
/* sanitize again to ensure no toe-stepping */
c->edit_count = 0;
sane = t->sanitize (c);
if (c->edit_count) {
- DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count);
+ DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
sane = false;
}
}
@@ -298,7 +336,7 @@ struct Sanitizer
if (c->start) {
c->writable = true;
/* ok, we made it writable by relocating. try again */
- DEBUG_MSG_FUNC (SANITIZE, blob, "retry");
+ DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
goto retry;
}
}
@@ -306,7 +344,7 @@ struct Sanitizer
c->end_processing ();
- DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED");
+ DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
if (sane)
return blob;
else {
@@ -324,6 +362,162 @@ struct Sanitizer
+/*
+ * Serialize
+ */
+
+#ifndef HB_DEBUG_SERIALIZE
+#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
+#endif
+
+
+#define TRACE_SERIALIZE(this) \
+ hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
+ (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
+ "");
+
+
+struct hb_serialize_context_t
+{
+ inline hb_serialize_context_t (void *start, unsigned int size)
+ {
+ this->start = (char *) start;
+ this->end = this->start + size;
+
+ this->ran_out_of_room = false;
+ this->head = this->start;
+ this->debug_depth = 0;
+ }
+
+ template <typename Type>
+ inline Type *start_serialize (void)
+ {
+ DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
+ "start [%p..%p] (%lu bytes)",
+ this->start, this->end,
+ (unsigned long) (this->end - this->start));
+
+ return start_embed<Type> ();
+ }
+
+ inline void end_serialize (void)
+ {
+ DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
+ "end [%p..%p] serialized %d bytes; %s",
+ this->start, this->end,
+ (int) (this->head - this->start),
+ this->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
+
+ }
+
+ template <typename Type>
+ inline Type *copy (void)
+ {
+ assert (!this->ran_out_of_room);
+ unsigned int len = this->head - this->start;
+ void *p = malloc (len);
+ if (p)
+ memcpy (p, this->start, len);
+ return reinterpret_cast<Type *> (p);
+ }
+
+ template <typename Type>
+ inline Type *allocate_size (unsigned int size)
+ {
+ if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
+ this->ran_out_of_room = true;
+ return NULL;
+ }
+ memset (this->head, 0, size);
+ char *ret = this->head;
+ this->head += size;
+ return reinterpret_cast<Type *> (ret);
+ }
+
+ template <typename Type>
+ inline Type *allocate_min (void)
+ {
+ return this->allocate_size<Type> (Type::min_size);
+ }
+
+ template <typename Type>
+ inline Type *start_embed (void)
+ {
+ Type *ret = reinterpret_cast<Type *> (this->head);
+ return ret;
+ }
+
+ template <typename Type>
+ inline Type *embed (const Type &obj)
+ {
+ unsigned int size = obj.get_size ();
+ Type *ret = this->allocate_size<Type> (size);
+ if (unlikely (!ret)) return NULL;
+ memcpy (ret, obj, size);
+ return ret;
+ }
+
+ template <typename Type>
+ inline Type *extend_min (Type &obj)
+ {
+ unsigned int size = obj.min_size;
+ assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
+ if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+ return reinterpret_cast<Type *> (&obj);
+ }
+
+ template <typename Type>
+ inline Type *extend (Type &obj)
+ {
+ unsigned int size = obj.get_size ();
+ assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
+ if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return NULL;
+ return reinterpret_cast<Type *> (&obj);
+ }
+
+ inline void truncate (void *head)
+ {
+ assert (this->start < head && head <= this->head);
+ this->head = (char *) head;
+ }
+
+ unsigned int debug_depth;
+ char *start, *end, *head;
+ bool ran_out_of_room;
+};
+
+template <typename Type>
+struct Supplier
+{
+ inline Supplier (const Type *array, unsigned int len_)
+ {
+ head = array;
+ len = len_;
+ }
+ inline const Type operator [] (unsigned int i) const
+ {
+ if (unlikely (i >= len)) return Type ();
+ return head[i];
+ }
+
+ inline void advance (unsigned int count)
+ {
+ if (unlikely (count > len))
+ count = len;
+ len -= count;
+ head += count;
+ }
+
+ private:
+ inline Supplier (const Supplier<Type> &); /* Disallow copy */
+ inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
+
+ unsigned int len;
+ const Type *head;
+};
+
+
+
/*
*
@@ -341,57 +535,95 @@ struct Sanitizer
template <typename Type, int Bytes> struct BEInt;
-/* LONGTERMTODO: On machines allowing unaligned access, we can make the
- * following tighter by using byteswap instructions on ints directly. */
template <typename Type>
struct BEInt<Type, 2>
{
public:
- inline void set (Type i) { hb_be_uint16_put (v,i); }
- inline operator Type (void) const { return hb_be_uint16_get (v); }
- inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_eq (v, o.v); }
- inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
+ inline void set (Type V)
+ {
+ v[0] = (V >> 8) & 0xFF;
+ v[1] = (V ) & 0xFF;
+ }
+ inline operator Type (void) const
+ {
+ return (v[0] << 8)
+ + (v[1] );
+ }
private: uint8_t v[2];
};
template <typename Type>
+struct BEInt<Type, 3>
+{
+ public:
+ inline void set (Type V)
+ {
+ v[0] = (V >> 16) & 0xFF;
+ v[1] = (V >> 8) & 0xFF;
+ v[2] = (V ) & 0xFF;
+ }
+ inline operator Type (void) const
+ {
+ return (v[0] << 16)
+ + (v[1] << 8)
+ + (v[2] );
+ }
+ private: uint8_t v[3];
+};
+template <typename Type>
struct BEInt<Type, 4>
{
public:
- inline void set (Type i) { hb_be_uint32_put (v,i); }
- inline operator Type (void) const { return hb_be_uint32_get (v); }
- inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_eq (v, o.v); }
- inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
+ inline void set (Type V)
+ {
+ v[0] = (V >> 24) & 0xFF;
+ v[1] = (V >> 16) & 0xFF;
+ v[2] = (V >> 8) & 0xFF;
+ v[3] = (V ) & 0xFF;
+ }
+ inline operator Type (void) const
+ {
+ return (v[0] << 24)
+ + (v[1] << 16)
+ + (v[2] << 8)
+ + (v[3] );
+ }
private: uint8_t v[4];
};
/* Integer types in big-endian order and no alignment requirement */
-template <typename Type>
+template <typename Type, unsigned int Size>
struct IntType
{
inline void set (Type i) { v.set (i); }
inline operator Type(void) const { return v; }
- inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
- inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
- inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
+ inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
+ static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
+ inline int cmp (Type a) const
+ {
+ Type b = v;
+ if (sizeof (Type) < sizeof (int))
+ return (int) a - (int) b;
+ else
+ return a < b ? -1 : a == b ? 0 : +1;
+ }
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (likely (c->check_struct (this)));
}
protected:
- BEInt<Type, sizeof (Type)> v;
+ BEInt<Type, Size> v;
public:
- DEFINE_SIZE_STATIC (sizeof (Type));
+ DEFINE_SIZE_STATIC (Size);
};
-/* Typedef these to avoid clash with windows.h */
-#define USHORT HB_USHORT
-#define SHORT HB_SHORT
-#define ULONG HB_ULONG
-#define LONG HB_LONG
-typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
-typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
-typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
-typedef IntType<int32_t> LONG; /* 32-bit signed integer. */
+typedef uint8_t BYTE; /* 8-bit unsigned integer. */
+typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */
+typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */
+typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */
+typedef IntType<int32_t, 4> LONG; /* 32-bit signed integer. */
+typedef IntType<uint32_t, 3> UINT24; /* 24-bit unsigned integer. */
/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */
typedef SHORT FWORD;
@@ -403,11 +635,12 @@ typedef USHORT UFWORD;
* 1904. The value is represented as a signed 64-bit integer. */
struct LONGDATETIME
{
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (likely (c->check_struct (this)));
}
- private:
+ protected:
LONG major;
ULONG minor;
public:
@@ -427,33 +660,45 @@ struct Tag : ULONG
DEFINE_NULL_DATA (Tag, " ");
/* Glyph index number, same as uint16 (length = 16 bits) */
-typedef USHORT GlyphID;
+struct GlyphID : USHORT {
+ static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); }
+ inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; }
+};
/* Script/language-system/feature index */
struct Index : USHORT {
- static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
+ static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
};
DEFINE_NULL_DATA (Index, "\xff\xff");
-/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
-typedef USHORT Offset;
-
-/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
-typedef ULONG LongOffset;
+/* Offset, Null offset = 0 */
+template <typename Type=USHORT>
+struct Offset : Type
+{
+ inline bool is_null (void) const { return 0 == *this; }
+ public:
+ DEFINE_SIZE_STATIC (sizeof(Type));
+};
/* CheckSum */
struct CheckSum : ULONG
{
- static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
+ /* This is reference implementation from the spec. */
+ static inline uint32_t CalcTableChecksum (const ULONG *Table, uint32_t Length)
{
uint32_t Sum = 0L;
- ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
+ const ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
while (Table < EndPtr)
Sum += *Table++;
return Sum;
}
+
+ /* Note: data should be 4byte aligned and have 4byte padding at the end. */
+ inline void set_for_data (const void *data, unsigned int length)
+ { set (CalcTableChecksum ((const ULONG *) data, length)); }
+
public:
DEFINE_SIZE_STATIC (4);
};
@@ -467,8 +712,9 @@ struct FixedVersion
{
inline uint32_t to_int (void) const { return (major << 16) + minor; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -481,12 +727,12 @@ struct FixedVersion
/*
- * Template subclasses of Offset and LongOffset that do the dereferencing.
+ * Template subclasses of Offset that do the dereferencing.
* Use: (base+offset)
*/
-template <typename OffsetType, typename Type>
-struct GenericOffsetTo : OffsetType
+template <typename Type, typename OffsetType=USHORT>
+struct OffsetTo : Offset<OffsetType>
{
inline const Type& operator () (const void *base) const
{
@@ -495,50 +741,52 @@ struct GenericOffsetTo : OffsetType
return StructAtOffset<Type> (base, offset);
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
- TRACE_SANITIZE ();
+ inline Type& serialize (hb_serialize_context_t *c, const void *base)
+ {
+ Type *t = c->start_embed<Type> ();
+ this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
+ return *t;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
unsigned int offset = *this;
if (unlikely (!offset)) return TRACE_RETURN (true);
- Type &obj = StructAtOffset<Type> (base, offset);
+ const Type &obj = StructAtOffset<Type> (base, offset);
return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
}
template <typename T>
- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
unsigned int offset = *this;
if (unlikely (!offset)) return TRACE_RETURN (true);
- Type &obj = StructAtOffset<Type> (base, offset);
+ const Type &obj = StructAtOffset<Type> (base, offset);
return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
}
- private:
/* Set the offset to Null */
- inline bool neuter (hb_sanitize_context_t *c) {
- if (c->may_edit (this, this->static_size)) {
- this->set (0); /* 0 is Null offset */
- return true;
- }
- return false;
+ inline bool neuter (hb_sanitize_context_t *c) const {
+ return c->try_set (this, 0);
}
+ DEFINE_SIZE_STATIC (sizeof(OffsetType));
};
template <typename Base, typename OffsetType, typename Type>
-inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
-
-template <typename Type>
-struct OffsetTo : GenericOffsetTo<Offset, Type> {};
-
-template <typename Type>
-struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
+static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType> &offset) { return offset (base); }
+template <typename Base, typename OffsetType, typename Type>
+static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset) { return offset (base); }
/*
* Array Types
*/
-template <typename LenType, typename Type>
-struct GenericArrayOf
+/* An array with a number of elements. */
+template <typename Type, typename LenType=USHORT>
+struct ArrayOf
{
const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
{
@@ -557,11 +805,38 @@ struct GenericArrayOf
if (unlikely (i >= len)) return Null(Type);
return array[i];
}
+ inline Type& operator [] (unsigned int i)
+ {
+ return array[i];
+ }
inline unsigned int get_size (void) const
{ return len.static_size + len * Type::static_size; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ unsigned int items_len)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ len.set (items_len); /* TODO(serialize) Overflow? */
+ if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<Type> &items,
+ unsigned int items_len)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false);
+ for (unsigned int i = 0; i < items_len; i++)
+ array[i] = items[i];
+ items.advance (items_len);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
/* Note: for structs that do not reference other structs,
@@ -575,8 +850,9 @@ struct GenericArrayOf
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
@@ -585,8 +861,9 @@ struct GenericArrayOf
return TRACE_RETURN (true);
}
template <typename T>
- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
@@ -595,9 +872,20 @@ struct GenericArrayOf
return TRACE_RETURN (true);
}
+ template <typename SearchType>
+ inline int lsearch (const SearchType &x) const
+ {
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ if (!this->array[i].cmp (x))
+ return i;
+ return -1;
+ }
+
private:
- inline bool sanitize_shallow (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
}
@@ -608,26 +896,10 @@ struct GenericArrayOf
DEFINE_SIZE_ARRAY (sizeof (LenType), array);
};
-/* An array with a USHORT number of elements. */
-template <typename Type>
-struct ArrayOf : GenericArrayOf<USHORT, Type> {};
-
-/* An array with a ULONG number of elements. */
-template <typename Type>
-struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
-
/* Array of Offset's */
template <typename Type>
struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
-/* Array of LongOffset's */
-template <typename Type>
-struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
-
-/* LongArray of LongOffset's */
-template <typename Type>
-struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
-
/* Array of offsets relative to the beginning of the array itself. */
template <typename Type>
struct OffsetListOf : OffsetArrayOf<Type>
@@ -638,21 +910,22 @@ struct OffsetListOf : OffsetArrayOf<Type>
return this+this->array[i];
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
}
template <typename T>
- inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
}
};
-/* An array with a USHORT number of elements,
- * starting at second element. */
-template <typename Type>
+/* An array starting at second element. */
+template <typename Type, typename LenType=USHORT>
struct HeadlessArrayOf
{
inline const Type& operator [] (unsigned int i) const
@@ -663,13 +936,30 @@ struct HeadlessArrayOf
inline unsigned int get_size (void) const
{ return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
- inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<Type> &items,
+ unsigned int items_len)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ len.set (items_len); /* TODO(serialize) Overflow? */
+ if (unlikely (!items_len)) return TRACE_RETURN (true);
+ if (unlikely (!c->extend (*this))) return TRACE_RETURN (false);
+ for (unsigned int i = 0; i < items_len - 1; i++)
+ array[i] = items[i];
+ items.advance (items_len - 1);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+ {
return c->check_struct (this)
&& c->check_array (this, Type::static_size, len);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
/* Note: for structs that do not reference other structs,
@@ -684,27 +974,39 @@ struct HeadlessArrayOf
return TRACE_RETURN (true);
}
- USHORT len;
+ LenType len;
Type array[VAR];
public:
- DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
+ DEFINE_SIZE_ARRAY (sizeof (LenType), array);
};
/* An array with sorted elements. Supports binary searching. */
-template <typename Type>
-struct SortedArrayOf : ArrayOf<Type> {
-
+template <typename Type, typename LenType=USHORT>
+struct SortedArrayOf : ArrayOf<Type, LenType>
+{
template <typename SearchType>
- inline int search (const SearchType &x) const {
- struct Cmp {
- static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); }
- };
- const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp);
- return p ? p - this->array : -1;
+ inline int bsearch (const SearchType &x) const
+ {
+ /* Hand-coded bsearch here since this is in the hot inner loop. */
+ int min = 0, max = (int) this->len - 1;
+ while (min <= max)
+ {
+ int mid = (min + max) / 2;
+ int c = this->array[mid].cmp (x);
+ if (c < 0)
+ max = mid - 1;
+ else if (c > 0)
+ min = mid + 1;
+ else
+ return mid;
+ }
+ return -1;
}
};
+} /* namespace OT */
+
#endif /* HB_OPEN_TYPE_PRIVATE_HH */
diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh
new file mode 100644
index 0000000..0482312
--- /dev/null
+++ b/src/hb-ot-cmap-table.hh
@@ -0,0 +1,528 @@
+/*
+ * Copyright © 2014 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_CMAP_TABLE_HH
+#define HB_OT_CMAP_TABLE_HH
+
+#include "hb-open-type-private.hh"
+
+
+namespace OT {
+
+
+/*
+ * cmap -- Character To Glyph Index Mapping Table
+ */
+
+#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
+
+
+struct CmapSubtableFormat0
+{
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+ {
+ hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0;
+ if (!gid)
+ return false;
+ *glyph = gid;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this));
+ }
+
+ protected:
+ USHORT format; /* Format number is set to 0. */
+ USHORT lengthZ; /* Byte length of this subtable. */
+ USHORT languageZ; /* Ignore. */
+ BYTE glyphIdArray[256];/* An array that maps character
+ * code to glyph index values. */
+ public:
+ DEFINE_SIZE_STATIC (6 + 256);
+};
+
+struct CmapSubtableFormat4
+{
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+ {
+ unsigned int segCount;
+ const USHORT *endCount;
+ const USHORT *startCount;
+ const USHORT *idDelta;
+ const USHORT *idRangeOffset;
+ const USHORT *glyphIdArray;
+ unsigned int glyphIdArrayLength;
+
+ segCount = this->segCountX2 / 2;
+ endCount = this->values;
+ startCount = endCount + segCount + 1;
+ idDelta = startCount + segCount;
+ idRangeOffset = idDelta + segCount;
+ glyphIdArray = idRangeOffset + segCount;
+ glyphIdArrayLength = (this->length - 16 - 8 * segCount) / 2;
+
+ /* Custom two-array bsearch. */
+ int min = 0, max = (int) segCount - 1;
+ unsigned int i;
+ while (min <= max)
+ {
+ int mid = (min + max) / 2;
+ if (codepoint < startCount[mid])
+ max = mid - 1;
+ else if (codepoint > endCount[mid])
+ min = mid + 1;
+ else
+ {
+ i = mid;
+ goto found;
+ }
+ }
+ return false;
+
+ found:
+ hb_codepoint_t gid;
+ unsigned int rangeOffset = idRangeOffset[i];
+ if (rangeOffset == 0)
+ gid = codepoint + idDelta[i];
+ else
+ {
+ /* Somebody has been smoking... */
+ unsigned int index = rangeOffset / 2 + (codepoint - startCount[i]) + i - segCount;
+ if (unlikely (index >= glyphIdArrayLength))
+ return false;
+ gid = glyphIdArray[index];
+ if (unlikely (!gid))
+ return false;
+ gid += idDelta[i];
+ }
+
+ *glyph = gid & 0xFFFFu;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!c->check_struct (this)))
+ return TRACE_RETURN (false);
+
+ if (unlikely (!c->check_range (this, length)))
+ {
+ /* Some broken fonts have too long of a "length" value.
+ * If that is the case, just change the value to truncate
+ * the subtable at the end of the blob. */
+ uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535,
+ (uintptr_t) (c->end -
+ (char *) this));
+ if (!c->try_set (&length, new_length))
+ return TRACE_RETURN (false);
+ }
+
+ return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length);
+ }
+
+ protected:
+ USHORT format; /* Format number is set to 4. */
+ USHORT length; /* This is the length in bytes of the
+ * subtable. */
+ USHORT languageZ; /* Ignore. */
+ USHORT segCountX2; /* 2 x segCount. */
+ USHORT searchRangeZ; /* 2 * (2**floor(log2(segCount))) */
+ USHORT entrySelectorZ; /* log2(searchRange/2) */
+ USHORT rangeShiftZ; /* 2 x segCount - searchRange */
+
+ USHORT values[VAR];
+#if 0
+ USHORT endCount[segCount]; /* End characterCode for each segment,
+ * last=0xFFFFu. */
+ USHORT reservedPad; /* Set to 0. */
+ USHORT startCount[segCount]; /* Start character code for each segment. */
+ SHORT idDelta[segCount]; /* Delta for all character codes in segment. */
+ USHORT idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */
+ USHORT glyphIdArray[VAR]; /* Glyph index array (arbitrary length) */
+#endif
+
+ public:
+ DEFINE_SIZE_ARRAY (14, values);
+};
+
+struct CmapSubtableLongGroup
+{
+ friend struct CmapSubtableFormat12;
+ friend struct CmapSubtableFormat13;
+
+ int cmp (hb_codepoint_t codepoint) const
+ {
+ if (codepoint < startCharCode) return -1;
+ if (codepoint > endCharCode) return +1;
+ return 0;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this));
+ }
+
+ private:
+ ULONG startCharCode; /* First character code in this group. */
+ ULONG endCharCode; /* Last character code in this group. */
+ ULONG glyphID; /* Glyph index; interpretation depends on
+ * subtable format. */
+ public:
+ DEFINE_SIZE_STATIC (12);
+};
+
+template <typename UINT>
+struct CmapSubtableTrimmed
+{
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+ {
+ /* Rely on our implicit array bound-checking. */
+ hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode];
+ if (!gid)
+ return false;
+ *glyph = gid;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c));
+ }
+
+ protected:
+ UINT formatReserved; /* Subtable format and (maybe) padding. */
+ UINT lengthZ; /* Byte length of this subtable. */
+ UINT languageZ; /* Ignore. */
+ UINT startCharCode; /* First character code covered. */
+ ArrayOf<GlyphID, UINT>
+ glyphIdArray; /* Array of glyph index values for character
+ * codes in the range. */
+ public:
+ DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray);
+};
+
+struct CmapSubtableFormat6 : CmapSubtableTrimmed<USHORT> {};
+struct CmapSubtableFormat10 : CmapSubtableTrimmed<ULONG > {};
+
+template <typename T>
+struct CmapSubtableLongSegmented
+{
+ inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
+ {
+ int i = groups.bsearch (codepoint);
+ if (i == -1)
+ return false;
+ *glyph = T::group_get_glyph (groups[i], codepoint);
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
+ }
+
+ protected:
+ USHORT format; /* Subtable format; set to 12. */
+ USHORT reservedZ; /* Reserved; set to 0. */
+ ULONG lengthZ; /* Byte length of this subtable. */
+ ULONG languageZ; /* Ignore. */
+ SortedArrayOf<CmapSubtableLongGroup, ULONG>
+ groups; /* Groupings. */
+ public:
+ DEFINE_SIZE_ARRAY (16, groups);
+};
+
+struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
+{
+ static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+ hb_codepoint_t u)
+ { return group.glyphID + (u - group.startCharCode); }
+};
+
+struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
+{
+ static inline hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
+ hb_codepoint_t u HB_UNUSED)
+ { return group.glyphID; }
+};
+
+typedef enum
+{
+ GLYPH_VARIANT_NOT_FOUND = 0,
+ GLYPH_VARIANT_FOUND = 1,
+ GLYPH_VARIANT_USE_DEFAULT = 2
+} glyph_variant_t;
+
+struct UnicodeValueRange
+{
+ inline int cmp (const hb_codepoint_t &codepoint) const
+ {
+ if (codepoint < startUnicodeValue) return -1;
+ if (codepoint > startUnicodeValue + additionalCount) return +1;
+ return 0;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this));
+ }
+
+ UINT24 startUnicodeValue; /* First value in this range. */
+ BYTE additionalCount; /* Number of additional values in this
+ * range. */
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+typedef SortedArrayOf<UnicodeValueRange, ULONG> DefaultUVS;
+
+struct UVSMapping
+{
+ inline int cmp (const hb_codepoint_t &codepoint) const
+ {
+ return unicodeValue.cmp (codepoint);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this));
+ }
+
+ UINT24 unicodeValue; /* Base Unicode value of the UVS */
+ GlyphID glyphID; /* Glyph ID of the UVS */
+ public:
+ DEFINE_SIZE_STATIC (5);
+};
+
+typedef SortedArrayOf<UVSMapping, ULONG> NonDefaultUVS;
+
+struct VariationSelectorRecord
+{
+ inline glyph_variant_t get_glyph (hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph,
+ const void *base) const
+ {
+ int i;
+ const DefaultUVS &defaults = base+defaultUVS;
+ i = defaults.bsearch (codepoint);
+ if (i != -1)
+ return GLYPH_VARIANT_USE_DEFAULT;
+ const NonDefaultUVS &nonDefaults = base+nonDefaultUVS;
+ i = nonDefaults.bsearch (codepoint);
+ if (i != -1)
+ {
+ *glyph = nonDefaults[i].glyphID;
+ return GLYPH_VARIANT_FOUND;
+ }
+ return GLYPH_VARIANT_NOT_FOUND;
+ }
+
+ inline int cmp (const hb_codepoint_t &variation_selector) const
+ {
+ return varSelector.cmp (variation_selector);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) &&
+ defaultUVS.sanitize (c, base) &&
+ nonDefaultUVS.sanitize (c, base));
+ }
+
+ UINT24 varSelector; /* Variation selector. */
+ OffsetTo<DefaultUVS, ULONG>
+ defaultUVS; /* Offset to Default UVS Table. May be 0. */
+ OffsetTo<NonDefaultUVS, ULONG>
+ nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
+ public:
+ DEFINE_SIZE_STATIC (11);
+};
+
+struct CmapSubtableFormat14
+{
+ inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph) const
+ {
+ return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) &&
+ record.sanitize (c, this));
+ }
+
+ protected:
+ USHORT format; /* Format number is set to 0. */
+ ULONG lengthZ; /* Byte length of this subtable. */
+ SortedArrayOf<VariationSelectorRecord, ULONG>
+ record; /* Variation selector records; sorted
+ * in increasing order of `varSelector'. */
+ public:
+ DEFINE_SIZE_ARRAY (10, record);
+};
+
+struct CmapSubtable
+{
+ /* Note: We intentionally do NOT implement subtable formats 2 and 8. */
+
+ inline bool get_glyph (hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph) const
+ {
+ switch (u.format) {
+ case 0: return u.format0 .get_glyph(codepoint, glyph);
+ case 4: return u.format4 .get_glyph(codepoint, glyph);
+ case 6: return u.format6 .get_glyph(codepoint, glyph);
+ case 10: return u.format10.get_glyph(codepoint, glyph);
+ case 12: return u.format12.get_glyph(codepoint, glyph);
+ case 13: return u.format13.get_glyph(codepoint, glyph);
+ case 14:
+ default: return false;
+ }
+ }
+
+ inline glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph) const
+ {
+ switch (u.format) {
+ case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph);
+ default: return GLYPH_VARIANT_NOT_FOUND;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ switch (u.format) {
+ case 0: return TRACE_RETURN (u.format0 .sanitize (c));
+ case 4: return TRACE_RETURN (u.format4 .sanitize (c));
+ case 6: return TRACE_RETURN (u.format6 .sanitize (c));
+ case 10: return TRACE_RETURN (u.format10.sanitize (c));
+ case 12: return TRACE_RETURN (u.format12.sanitize (c));
+ case 13: return TRACE_RETURN (u.format13.sanitize (c));
+ case 14: return TRACE_RETURN (u.format14.sanitize (c));
+ default:return TRACE_RETURN (true);
+ }
+ }
+
+ protected:
+ union {
+ USHORT format; /* Format identifier */
+ CmapSubtableFormat0 format0;
+ CmapSubtableFormat4 format4;
+ CmapSubtableFormat6 format6;
+ CmapSubtableFormat10 format10;
+ CmapSubtableFormat12 format12;
+ CmapSubtableFormat13 format13;
+ CmapSubtableFormat14 format14;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+};
+
+
+struct EncodingRecord
+{
+ inline int cmp (const EncodingRecord &other) const
+ {
+ int ret;
+ ret = platformID.cmp (other.platformID);
+ if (ret) return ret;
+ ret = encodingID.cmp (other.encodingID);
+ if (ret) return ret;
+ return 0;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) &&
+ subtable.sanitize (c, base));
+ }
+
+ USHORT platformID; /* Platform ID. */
+ USHORT encodingID; /* Platform-specific encoding ID. */
+ OffsetTo<CmapSubtable, ULONG>
+ subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct cmap
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_cmap;
+
+ inline const CmapSubtable *find_subtable (unsigned int platform_id,
+ unsigned int encoding_id) const
+ {
+ EncodingRecord key;
+ key.platformID.set (platform_id);
+ key.encodingID.set (encoding_id);
+
+ /* Note: We can use bsearch, but since it has no performance
+ * implications, we use lsearch and as such accept fonts with
+ * unsorted subtable list. */
+ int result = encodingRecord./*bsearch*/lsearch (key);
+ if (result == -1 || !encodingRecord[result].subtable)
+ return NULL;
+
+ return &(this+encodingRecord[result].subtable);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) &&
+ likely (version == 0) &&
+ encodingRecord.sanitize (c, this));
+ }
+
+ USHORT version; /* Table version number (0). */
+ SortedArrayOf<EncodingRecord>
+ encodingRecord; /* Encoding tables. */
+ public:
+ DEFINE_SIZE_ARRAY (4, encodingRecord);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_CMAP_TABLE_HH */
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
new file mode 100644
index 0000000..2af2f54
--- /dev/null
+++ b/src/hb-ot-font.cc
@@ -0,0 +1,348 @@
+/*
+ * Copyright © 2011,2014 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
+ */
+
+#include "hb-private.hh"
+
+#include "hb-ot.h"
+
+#include "hb-font-private.hh"
+
+#include "hb-ot-cmap-table.hh"
+#include "hb-ot-hhea-table.hh"
+#include "hb-ot-hmtx-table.hh"
+
+
+struct hb_ot_face_metrics_accelerator_t
+{
+ unsigned int num_metrics;
+ unsigned int num_advances;
+ unsigned int default_advance;
+ const OT::_mtx *table;
+ hb_blob_t *blob;
+
+ inline void init (hb_face_t *face,
+ hb_tag_t _hea_tag, hb_tag_t _mtx_tag,
+ unsigned int default_advance)
+ {
+ this->default_advance = default_advance;
+ this->num_metrics = face->get_num_glyphs ();
+
+ hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
+ const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
+ this->num_advances = _hea->numberOfLongMetrics;
+ hb_blob_destroy (_hea_blob);
+
+ this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
+ if (unlikely (!this->num_advances ||
+ 2 * (this->num_advances + this->num_metrics) < hb_blob_get_length (this->blob)))
+ {
+ this->num_metrics = this->num_advances = 0;
+ hb_blob_destroy (this->blob);
+ this->blob = hb_blob_get_empty ();
+ }
+ this->table = OT::Sanitizer<OT::_mtx>::lock_instance (this->blob);
+ }
+
+ inline void fini (void)
+ {
+ hb_blob_destroy (this->blob);
+ }
+
+ inline unsigned int get_advance (hb_codepoint_t glyph) const
+ {
+ if (unlikely (glyph >= this->num_metrics))
+ {
+ /* If this->num_metrics is zero, it means we don't have the metrics table
+ * for this direction: return one EM. Otherwise, it means that the glyph
+ * index is out of bound: return zero. */
+ if (this->num_metrics)
+ return 0;
+ else
+ return this->default_advance;
+ }
+
+ if (glyph >= this->num_advances)
+ glyph = this->num_advances - 1;
+
+ return this->table->longMetric[glyph].advance;
+ }
+};
+
+struct hb_ot_face_cmap_accelerator_t
+{
+ const OT::CmapSubtable *table;
+ const OT::CmapSubtable *uvs_table;
+ hb_blob_t *blob;
+
+ inline void init (hb_face_t *face)
+ {
+ this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
+ const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
+ const OT::CmapSubtable *subtable = NULL;
+ const OT::CmapSubtable *subtable_uvs = NULL;
+
+ /* 32-bit subtables. */
+ if (!subtable) subtable = cmap->find_subtable (3, 10);
+ if (!subtable) subtable = cmap->find_subtable (0, 6);
+ if (!subtable) subtable = cmap->find_subtable (0, 4);
+ /* 16-bit subtables. */
+ if (!subtable) subtable = cmap->find_subtable (3, 1);
+ if (!subtable) subtable = cmap->find_subtable (0, 3);
+ if (!subtable) subtable = cmap->find_subtable (0, 2);
+ if (!subtable) subtable = cmap->find_subtable (0, 1);
+ if (!subtable) subtable = cmap->find_subtable (0, 0);
+ /* Meh. */
+ if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
+
+ /* UVS subtable. */
+ if (!subtable_uvs) subtable_uvs = cmap->find_subtable (0, 5);
+ /* Meh. */
+ if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtable);
+
+ this->table = subtable;
+ this->uvs_table = subtable_uvs;
+ }
+
+ inline void fini (void)
+ {
+ hb_blob_destroy (this->blob);
+ }
+
+ inline bool get_glyph (hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph) const
+ {
+ if (unlikely (variation_selector))
+ {
+ switch (this->uvs_table->get_glyph_variant (unicode,
+ variation_selector,
+ glyph))
+ {
+ case OT::GLYPH_VARIANT_NOT_FOUND: return false;
+ case OT::GLYPH_VARIANT_FOUND: return true;
+ case OT::GLYPH_VARIANT_USE_DEFAULT: break;
+ }
+ }
+
+ return this->table->get_glyph (unicode, glyph);
+ }
+};
+
+
+struct hb_ot_font_t
+{
+ hb_ot_face_cmap_accelerator_t cmap;
+ hb_ot_face_metrics_accelerator_t h_metrics;
+ hb_ot_face_metrics_accelerator_t v_metrics;
+};
+
+
+static hb_ot_font_t *
+_hb_ot_font_create (hb_font_t *font)
+{
+ hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
+ hb_face_t *face = font->face;
+
+ if (unlikely (!ot_font))
+ return NULL;
+
+ unsigned int upem = face->get_upem ();
+
+ ot_font->cmap.init (face);
+ ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1);
+ ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, upem); /* TODO Can we do this lazily? */
+
+ return ot_font;
+}
+
+static void
+_hb_ot_font_destroy (hb_ot_font_t *ot_font)
+{
+ ot_font->cmap.fini ();
+ ot_font->h_metrics.fini ();
+ ot_font->v_metrics.fini ();
+
+ free (ot_font);
+}
+
+
+static hb_bool_t
+hb_ot_get_glyph (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+
+{
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ return ot_font->cmap.get_glyph (unicode, variation_selector, glyph);
+}
+
+static hb_position_t
+hb_ot_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+{
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ return font->em_scale_x (ot_font->h_metrics.get_advance (glyph));
+}
+
+static hb_position_t
+hb_ot_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ void *user_data HB_UNUSED)
+{
+ const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
+ return font->em_scale_y (-ot_font->v_metrics.get_advance (glyph));
+}
+
+static hb_bool_t
+hb_ot_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t glyph HB_UNUSED,
+ hb_position_t *x HB_UNUSED,
+ hb_position_t *y HB_UNUSED,
+ void *user_data HB_UNUSED)
+{
+ /* We always work in the horizontal coordinates. */
+ return true;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ hb_position_t *x,
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+{
+ /* TODO */
+ return false;
+}
+
+static hb_position_t
+hb_ot_get_glyph_h_kerning (hb_font_t *font,
+ void *font_data,
+ hb_codepoint_t left_glyph,
+ hb_codepoint_t right_glyph,
+ void *user_data HB_UNUSED)
+{
+ /* TODO */
+ return 0;
+}
+
+static hb_position_t
+hb_ot_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
+ void *font_data HB_UNUSED,
+ hb_codepoint_t top_glyph HB_UNUSED,
+ hb_codepoint_t bottom_glyph HB_UNUSED,
+ void *user_data HB_UNUSED)
+{
+ /* OpenType doesn't have vertical-kerning other than GPOS. */
+ return 0;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t *extents,
+ void *user_data HB_UNUSED)
+{
+ /* TODO */
+ return false;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ unsigned int point_index,
+ hb_position_t *x,
+ hb_position_t *y,
+ void *user_data HB_UNUSED)
+{
+ /* TODO */
+ return false;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ hb_codepoint_t glyph,
+ char *name, unsigned int size,
+ void *user_data HB_UNUSED)
+{
+ /* TODO */
+ return false;
+}
+
+static hb_bool_t
+hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ const char *name, int len, /* -1 means nul-terminated */
+ hb_codepoint_t *glyph,
+ void *user_data HB_UNUSED)
+{
+ /* TODO */
+ return false;
+}
+
+
+static hb_font_funcs_t *
+_hb_ot_get_font_funcs (void)
+{
+ static const hb_font_funcs_t ot_ffuncs = {
+ HB_OBJECT_HEADER_STATIC,
+
+ true, /* immutable */
+
+ {
+#define HB_FONT_FUNC_IMPLEMENT(name) hb_ot_get_##name,
+ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_FONT_FUNC_IMPLEMENT
+ }
+ };
+
+ return const_cast<hb_font_funcs_t *> (&ot_ffuncs);
+}
+
+
+void
+hb_ot_font_set_funcs (hb_font_t *font)
+{
+ hb_ot_font_t *ot_font = _hb_ot_font_create (font);
+ if (unlikely (!ot_font))
+ return;
+
+ hb_font_set_funcs (font,
+ _hb_ot_get_font_funcs (),
+ ot_font,
+ (hb_destroy_func_t) _hb_ot_font_destroy);
+}
diff --git a/src/hb-fallback-shape-private.hh b/src/hb-ot-font.h
index 159456d..7a8c04a 100644
--- a/src/hb-fallback-shape-private.hh
+++ b/src/hb-ot-font.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -21,27 +21,21 @@
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
- * Google Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
-#ifndef HB_FALLBACK_SHAPE_PRIVATE_HH
-#define HB_FALLBACK_SHAPE_PRIVATE_HH
-
-#include "hb-private.hh"
-
-#include "hb-shape.h"
+#ifndef HB_OT_FONT_H
+#define HB_OT_FONT_H
+#include "hb.h"
HB_BEGIN_DECLS
-HB_INTERNAL hb_bool_t
-_hb_fallback_shape (hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *features,
- unsigned int num_features);
+void
+hb_ot_font_set_funcs (hb_font_t *font);
HB_END_DECLS
-#endif /* HB_FALLBACK_SHAPE_PRIVATE_HH */
+#endif /* HB_OT_FONT_H */
diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh
index 32d64ca..268f133 100644
--- a/src/hb-ot-head-table.hh
+++ b/src/hb-ot-head-table.hh
@@ -32,6 +32,8 @@
#include "hb-open-type-private.hh"
+namespace OT {
+
/*
* head -- Font Header
@@ -41,27 +43,29 @@
struct head
{
- static const hb_tag_t Tag = HB_OT_TAG_head;
+ static const hb_tag_t tableTag = HB_OT_TAG_head;
- inline unsigned int get_upem (void) const {
+ inline unsigned int get_upem (void) const
+ {
unsigned int upem = unitsPerEm;
- /* If no valid head table found, assume 1000, which matches typicaly Type1 usage. */
+ /* If no valid head table found, assume 1000, which matches typical Type1 usage. */
return 16 <= upem && upem <= 16384 ? upem : 1000;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
}
- private:
+ protected:
FixedVersion version; /* Version of the head table--currently
- * 0x00010000 for version 1.0. */
+ * 0x00010000u for version 1.0. */
FixedVersion fontRevision; /* Set by font manufacturer. */
ULONG checkSumAdjustment; /* To compute: set it to 0, sum the
* entire font as ULONG, then store
- * 0xB1B0AFBA - sum. */
- ULONG magicNumber; /* Set to 0x5F0F3CF5. */
+ * 0xB1B0AFBAu - sum. */
+ ULONG magicNumber; /* Set to 0x5F0F3CF5u. */
USHORT flags; /* Bit 0: Baseline for font at y=0;
* Bit 1: Left sidebearing point at x=0;
* Bit 2: Instructions may depend on point size;
@@ -141,5 +145,7 @@ struct head
};
+} /* namespace OT */
+
#endif /* HB_OT_HEAD_TABLE_HH */
diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh
index 2eea05a..992fe55 100644
--- a/src/hb-ot-hhea-table.hh
+++ b/src/hb-ot-hhea-table.hh
@@ -30,63 +30,74 @@
#include "hb-open-type-private.hh"
+namespace OT {
+
/*
* hhea -- The Horizontal Header Table
+ * vhea -- The Vertical Header Table
*/
#define HB_OT_TAG_hhea HB_TAG('h','h','e','a')
+#define HB_OT_TAG_vhea HB_TAG('v','h','e','a')
-struct hhea
+struct _hea
{
- static const hb_tag_t Tag = HB_OT_TAG_hhea;
+ static const hb_tag_t tableTag = HB_TAG('_','h','e','a');
+
+ static const hb_tag_t hheaTag = HB_OT_TAG_hhea;
+ static const hb_tag_t vheaTag = HB_OT_TAG_vhea;
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
}
- private:
- FixedVersion version; /* 0x00010000 for version 1.0. */
- FWORD ascender; /* Typographic ascent. <a
- * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
- * (Distance from baseline of highest
- * ascender)</a> */
- FWORD descender; /* Typographic descent. <a
- * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html">
- * (Distance from baseline of lowest
- * descender)</a> */
- FWORD lineGap; /* Typographic line gap. Negative
- * LineGap values are treated as zero
- * in Windows 3.1, System 6, and
- * System 7. */
- UFWORD advanceWidthMax; /* Maximum advance width value in
- * 'hmtx' table. */
- FWORD minLeftSideBearing; /* Minimum left sidebearing value in
- * 'hmtx' table. */
- FWORD minRightSideBearing; /* Minimum right sidebearing value;
+ public:
+ FixedVersion version; /* 0x00010000u for version 1.0. */
+ FWORD ascender; /* Typographic ascent. */
+ FWORD descender; /* Typographic descent. */
+ FWORD lineGap; /* Typographic line gap. */
+ UFWORD advanceMax; /* Maximum advance width/height value in
+ * metrics table. */
+ FWORD minLeadingBearing; /* Minimum left/top sidebearing value in
+ * metrics table. */
+ FWORD minTrailingBearing; /* Minimum right/bottom sidebearing value;
* calculated as Min(aw - lsb -
- * (xMax - xMin)). */
- FWORD xMaxExtent; /* Max(lsb + (xMax - xMin)). */
+ * (xMax - xMin)) for horizontal. */
+ FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)),
+ * vertical: minLeadingBearing+(yMax-yMin). */
SHORT caretSlopeRise; /* Used to calculate the slope of the
- * cursor (rise/run); 1 for vertical. */
- SHORT caretSlopeRun; /* 0 for vertical. */
+ * cursor (rise/run); 1 for vertical caret,
+ * 0 for horizontal.*/
+ SHORT caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */
SHORT caretOffset; /* The amount by which a slanted
* highlight on a glyph needs
* to be shifted to produce the
* best appearance. Set to 0 for
- * non--slanted fonts */
- SHORT reserved1; /* set to 0 */
- SHORT reserved2; /* set to 0 */
- SHORT reserved3; /* set to 0 */
- SHORT reserved4; /* set to 0 */
+ * non-slanted fonts. */
+ SHORT reserved1; /* Set to 0. */
+ SHORT reserved2; /* Set to 0. */
+ SHORT reserved3; /* Set to 0. */
+ SHORT reserved4; /* Set to 0. */
SHORT metricDataFormat; /* 0 for current format. */
- USHORT numberOfHMetrics; /* Number of hMetric entries in 'hmtx'
- * table */
+ USHORT numberOfLongMetrics; /* Number of LongMetric entries in metric
+ * table. */
public:
DEFINE_SIZE_STATIC (36);
};
+struct hhea : _hea {
+ static const hb_tag_t tableTag = HB_OT_TAG_hhea;
+};
+struct vhea : _hea {
+ static const hb_tag_t tableTag = HB_OT_TAG_vhea;
+};
+
+
+} /* namespace OT */
+
#endif /* HB_OT_HHEA_TABLE_HH */
diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh
index 35cfb48..a0e3855 100644
--- a/src/hb-ot-hmtx-table.hh
+++ b/src/hb-ot-hmtx-table.hh
@@ -30,35 +30,43 @@
#include "hb-open-type-private.hh"
+namespace OT {
+
/*
* hmtx -- The Horizontal Metrics Table
+ * vmtx -- The Vertical Metrics Table
*/
#define HB_OT_TAG_hmtx HB_TAG('h','m','t','x')
+#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
-struct LongHorMetric
+struct LongMetric
{
- USHORT advanceWidth;
- SHORT lsb;
+ USHORT advance; /* Advance width/height. */
+ SHORT lsb; /* Leading (left/top) side bearing. */
public:
DEFINE_SIZE_STATIC (4);
};
-struct hmtx
+struct _mtx
{
- static const hb_tag_t Tag = HB_OT_TAG_hmtx;
+ static const hb_tag_t tableTag = HB_TAG('_','m','t','x');
+
+ static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
+ static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
/* We don't check for anything specific here. The users of the
* struct do all the hard work... */
return TRACE_RETURN (true);
}
- private:
- LongHorMetric longHorMetric[VAR]; /* Paired advance width and left side
+ public:
+ LongMetric longMetric[VAR]; /* Paired advance width and leading
* bearing values for each glyph. The
* value numOfHMetrics comes from
* the 'hhea' table. If the font is
@@ -66,21 +74,31 @@ struct hmtx
* be in the array, but that entry is
* required. The last entry applies to
* all subsequent glyphs. */
- SHORT leftSideBearingX[VAR]; /* Here the advanceWidth is assumed
- * to be the same as the advanceWidth
+ SHORT leadingBearingX[VAR]; /* Here the advance is assumed
+ * to be the same as the advance
* for the last entry above. The
* number of entries in this array is
* derived from numGlyphs (from 'maxp'
- * table) minus numberOfHMetrics. This
- * generally is used with a run of
- * monospaced glyphs (e.g., Kanji
+ * table) minus numberOfLongMetrics.
+ * This generally is used with a run
+ * of monospaced glyphs (e.g., Kanji
* fonts or Courier fonts). Only one
* run is allowed and it must be at
* the end. This allows a monospaced
- * font to vary the left side bearing
+ * font to vary the side bearing
* values for each glyph. */
public:
- DEFINE_SIZE_ARRAY2 (0, longHorMetric, leftSideBearingX);
+ DEFINE_SIZE_ARRAY2 (0, longMetric, leadingBearingX);
+};
+
+struct hmtx : _mtx {
+ static const hb_tag_t tableTag = HB_OT_TAG_hmtx;
+};
+struct vmtx : _mtx {
+ static const hb_tag_t tableTag = HB_OT_TAG_vmtx;
};
+} /* namespace OT */
+
+
#endif /* HB_OT_HMTX_TABLE_HH */
diff --git a/src/hb-ot-layout-common-private.hh b/src/hb-ot-layout-common-private.hh
index 2943a7f..3db7f57 100644
--- a/src/hb-ot-layout-common-private.hh
+++ b/src/hb-ot-layout-common-private.hh
@@ -34,8 +34,18 @@
#include "hb-set-private.hh"
-#define NOT_COVERED ((unsigned int) 0x110000)
+namespace OT {
+
+
+#define TRACE_DISPATCH(this, format) \
+ hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "format %d", (int) format);
+
+
+#define NOT_COVERED ((unsigned int) -1)
#define MAX_NESTING_LEVEL 8
+#define MAX_CONTEXT_LENGTH 64
@@ -57,9 +67,15 @@ struct Record
return tag.cmp (a);
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
- TRACE_SANITIZE ();
- return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base));
+ struct sanitize_closure_t {
+ hb_tag_t tag;
+ const void *list_base;
+ };
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
+ const sanitize_closure_t closure = {tag, base};
+ return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
}
Tag tag; /* 4-byte Tag identifier */
@@ -94,7 +110,8 @@ struct RecordArrayOf : SortedArrayOf<Record<Type> > {
}
inline bool find_index (hb_tag_t tag, unsigned int *index) const
{
- int i = this->search (tag);
+ /* If we want to allow non-sorted data, we can lsearch(). */
+ int i = this->/*lsearch*/bsearch (tag);
if (i != -1) {
if (index) *index = i;
return true;
@@ -111,8 +128,9 @@ struct RecordListOf : RecordArrayOf<Type>
inline const Type& operator [] (unsigned int i) const
{ return this+RecordArrayOf<Type>::operator [](i).offset; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
}
};
@@ -121,12 +139,12 @@ struct RecordListOf : RecordArrayOf<Type>
struct RangeRecord
{
inline int cmp (hb_codepoint_t g) const {
- hb_codepoint_t a = start, b = end;
- return g < a ? -1 : g <= b ? 0 : +1 ;
+ return g < start ? -1 : g <= end ? 0 : +1 ;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -134,6 +152,11 @@ struct RangeRecord
return glyphs->intersects (start, end);
}
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const {
+ glyphs->add_range (start, end);
+ }
+
GlyphID start; /* First GlyphID in the range */
GlyphID end; /* Last GlyphID in the range */
USHORT value; /* Value */
@@ -176,24 +199,26 @@ struct LangSys
unsigned int *feature_indexes /* OUT */) const
{ return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
- inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
+ inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
inline unsigned int get_required_feature_index (void) const
{
- if (reqFeatureIndex == 0xffff)
+ if (reqFeatureIndex == 0xFFFFu)
return Index::NOT_FOUND_INDEX;
return reqFeatureIndex;;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c,
+ const Record<LangSys>::sanitize_closure_t * = NULL) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
}
- Offset lookupOrder; /* = Null (reserved for an offset to a
+ Offset<> lookupOrderZ; /* = Null (reserved for an offset to a
* reordering table) */
USHORT reqFeatureIndex;/* Index of a feature required for this
* language system--if no required features
- * = 0xFFFF */
+ * = 0xFFFFu */
IndexArray featureIndex; /* Array of indices into the FeatureList */
public:
DEFINE_SIZE_ARRAY (6, featureIndex);
@@ -222,12 +247,14 @@ struct Script
inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c,
+ const Record<Script>::sanitize_closure_t * = NULL) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
}
- private:
+ protected:
OffsetTo<LangSys>
defaultLangSys; /* Offset to DefaultLangSys table--from
* beginning of Script table--may be Null */
@@ -241,6 +268,224 @@ struct Script
typedef RecordListOf<Script> ScriptList;
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+struct FeatureParamsSize
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
+
+ /* This subtable has some "history", if you will. Some earlier versions of
+ * Adobe tools calculated the offset of the FeatureParams sutable from the
+ * beginning of the FeatureList table! Now, that is dealt with in the
+ * Feature implementation. But we still need to be able to tell junk from
+ * real data. Note: We don't check that the nameID actually exists.
+ *
+ * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk :
+ *
+ * Yes, it is correct that a new version of the AFDKO (version 2.0) will be
+ * coming out soon, and that the makeotf program will build a font with a
+ * 'size' feature that is correct by the specification.
+ *
+ * The specification for this feature tag is in the "OpenType Layout Tag
+ * Registry". You can see a copy of this at:
+ * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size
+ *
+ * Here is one set of rules to determine if the 'size' feature is built
+ * correctly, or as by the older versions of MakeOTF. You may be able to do
+ * better.
+ *
+ * Assume that the offset to the size feature is according to specification,
+ * and make the following value checks. If it fails, assume the the size
+ * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it.
+ * If this fails, reject the 'size' feature. The older makeOTF's calculated the
+ * offset from the beginning of the FeatureList table, rather than from the
+ * beginning of the 'size' Feature table.
+ *
+ * If "design size" == 0:
+ * fails check
+ *
+ * Else if ("subfamily identifier" == 0 and
+ * "range start" == 0 and
+ * "range end" == 0 and
+ * "range start" == 0 and
+ * "menu name ID" == 0)
+ * passes check: this is the format used when there is a design size
+ * specified, but there is no recommended size range.
+ *
+ * Else if ("design size" < "range start" or
+ * "design size" > "range end" or
+ * "range end" <= "range start" or
+ * "menu name ID" < 256 or
+ * "menu name ID" > 32767 or
+ * menu name ID is not a name ID which is actually in the name table)
+ * fails test
+ * Else
+ * passes test.
+ */
+
+ if (!designSize)
+ return TRACE_RETURN (false);
+ else if (subfamilyID == 0 &&
+ subfamilyNameID == 0 &&
+ rangeStart == 0 &&
+ rangeEnd == 0)
+ return TRACE_RETURN (true);
+ else if (designSize < rangeStart ||
+ designSize > rangeEnd ||
+ subfamilyNameID < 256 ||
+ subfamilyNameID > 32767)
+ return TRACE_RETURN (false);
+ else
+ return TRACE_RETURN (true);
+ }
+
+ USHORT designSize; /* Represents the design size in 720/inch
+ * units (decipoints). The design size entry
+ * must be non-zero. When there is a design
+ * size but no recommended size range, the
+ * rest of the array will consist of zeros. */
+ USHORT subfamilyID; /* Has no independent meaning, but serves
+ * as an identifier that associates fonts
+ * in a subfamily. All fonts which share a
+ * Preferred or Font Family name and which
+ * differ only by size range shall have the
+ * same subfamily value, and no fonts which
+ * differ in weight or style shall have the
+ * same subfamily value. If this value is
+ * zero, the remaining fields in the array
+ * will be ignored. */
+ USHORT subfamilyNameID;/* If the preceding value is non-zero, this
+ * value must be set in the range 256 - 32767
+ * (inclusive). It records the value of a
+ * field in the name table, which must
+ * contain English-language strings encoded
+ * in Windows Unicode and Macintosh Roman,
+ * and may contain additional strings
+ * localized to other scripts and languages.
+ * Each of these strings is the name an
+ * application should use, in combination
+ * with the family name, to represent the
+ * subfamily in a menu. Applications will
+ * choose the appropriate version based on
+ * their selection criteria. */
+ USHORT rangeStart; /* Large end of the recommended usage range
+ * (inclusive), stored in 720/inch units
+ * (decipoints). */
+ USHORT rangeEnd; /* Small end of the recommended usage range
+ (exclusive), stored in 720/inch units
+ * (decipoints). */
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
+struct FeatureParamsStylisticSet
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ /* Right now minorVersion is at zero. Which means, any table supports
+ * the uiNameID field. */
+ return TRACE_RETURN (c->check_struct (this));
+ }
+
+ USHORT version; /* (set to 0): This corresponds to a “minor”
+ * version number. Additional data may be
+ * added to the end of this Feature Parameters
+ * table in the future. */
+
+ USHORT uiNameID; /* The 'name' table name ID that specifies a
+ * string (or strings, for multiple languages)
+ * for a user-interface label for this
+ * feature. The values of uiLabelNameId and
+ * sampleTextNameId are expected to be in the
+ * font-specific name ID range (256-32767),
+ * though that is not a requirement in this
+ * Feature Parameters specification. The
+ * user-interface label for the feature can
+ * be provided in multiple languages. An
+ * English string should be included as a
+ * fallback. The string should be kept to a
+ * minimal length to fit comfortably with
+ * different application interfaces. */
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
+struct FeatureParamsCharacterVariants
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) &&
+ characters.sanitize (c));
+ }
+
+ USHORT format; /* Format number is set to 0. */
+ USHORT featUILableNameID; /* The ‘name’ table name ID that
+ * specifies a string (or strings,
+ * for multiple languages) for a
+ * user-interface label for this
+ * feature. (May be NULL.) */
+ USHORT featUITooltipTextNameID;/* The ‘name’ table name ID that
+ * specifies a string (or strings,
+ * for multiple languages) that an
+ * application can use for tooltip
+ * text for this feature. (May be
+ * NULL.) */
+ USHORT sampleTextNameID; /* The ‘name’ table name ID that
+ * specifies sample text that
+ * illustrates the effect of this
+ * feature. (May be NULL.) */
+ USHORT numNamedParameters; /* Number of named parameters. (May
+ * be zero.) */
+ USHORT firstParamUILabelNameID;/* The first ‘name’ table name ID
+ * used to specify strings for
+ * user-interface labels for the
+ * feature parameters. (Must be zero
+ * if numParameters is zero.) */
+ ArrayOf<UINT24>
+ characters; /* Array of the Unicode Scalar Value
+ * of the characters for which this
+ * feature provides glyph variants.
+ * (May be zero.) */
+ public:
+ DEFINE_SIZE_ARRAY (14, characters);
+};
+
+struct FeatureParams
+{
+ inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
+ {
+ TRACE_SANITIZE (this);
+ if (tag == HB_TAG ('s','i','z','e'))
+ return TRACE_RETURN (u.size.sanitize (c));
+ if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+ return TRACE_RETURN (u.stylisticSet.sanitize (c));
+ if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+ return TRACE_RETURN (u.characterVariants.sanitize (c));
+ return TRACE_RETURN (true);
+ }
+
+ inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const
+ {
+ if (tag == HB_TAG ('s','i','z','e'))
+ return u.size;
+ return Null(FeatureParamsSize);
+ }
+
+ private:
+ union {
+ FeatureParamsSize size;
+ FeatureParamsStylisticSet stylisticSet;
+ FeatureParamsCharacterVariants characterVariants;
+ } u;
+ DEFINE_SIZE_STATIC (17);
+};
+
struct Feature
{
inline unsigned int get_lookup_count (void) const
@@ -252,12 +497,55 @@ struct Feature
unsigned int *lookup_tags /* OUT */) const
{ return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- return TRACE_RETURN (c->check_struct (this) && lookupIndex.sanitize (c));
+ inline const FeatureParams &get_feature_params (void) const
+ { return this+featureParams; }
+
+ inline bool sanitize (hb_sanitize_context_t *c,
+ const Record<Feature>::sanitize_closure_t *closure) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
+ return TRACE_RETURN (false);
+
+ /* Some earlier versions of Adobe tools calculated the offset of the
+ * FeatureParams subtable from the beginning of the FeatureList table!
+ *
+ * If sanitizing "failed" for the FeatureParams subtable, try it with the
+ * alternative location. We would know sanitize "failed" if old value
+ * of the offset was non-zero, but it's zeroed now.
+ *
+ * Only do this for the 'size' feature, since at the time of the faulty
+ * Adobe tools, only the 'size' feature had FeatureParams defined.
+ */
+
+ OffsetTo<FeatureParams> orig_offset = featureParams;
+ if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
+ return TRACE_RETURN (false);
+
+ if (likely (orig_offset.is_null ()))
+ return TRACE_RETURN (true);
+
+ if (featureParams == 0 && closure &&
+ closure->tag == HB_TAG ('s','i','z','e') &&
+ closure->list_base && closure->list_base < this)
+ {
+ unsigned int new_offset_int = (unsigned int) orig_offset -
+ (((char *) this) - ((char *) closure->list_base));
+
+ OffsetTo<FeatureParams> new_offset;
+ /* Check that it did not overflow. */
+ new_offset.set (new_offset_int);
+ if (new_offset == new_offset_int &&
+ c->try_set (&featureParams, new_offset) &&
+ !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
+ return TRACE_RETURN (false);
+ }
+
+ return TRACE_RETURN (true);
}
- Offset featureParams; /* Offset to Feature Parameters table (if one
+ OffsetTo<FeatureParams>
+ featureParams; /* Offset to Feature Parameters table (if one
* has been defined for the feature), relative
* to the beginning of the Feature Table; = Null
* if not required */
@@ -289,6 +577,17 @@ struct Lookup
{
inline unsigned int get_subtable_count (void) const { return subTable.len; }
+ template <typename SubTableType>
+ inline const SubTableType& get_subtable (unsigned int i) const
+ { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
+
+ template <typename SubTableType>
+ inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
+ { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+ template <typename SubTableType>
+ inline OffsetArrayOf<SubTableType>& get_subtables (void)
+ { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+
inline unsigned int get_type (void) const { return lookupType; }
/* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
@@ -305,21 +604,55 @@ struct Lookup
return flag;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ template <typename SubTableType, typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ unsigned int lookup_type = get_type ();
+ TRACE_DISPATCH (this, lookup_type);
+ unsigned int count = get_subtable_count ();
+ for (unsigned int i = 0; i < count; i++) {
+ typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
+ if (c->stop_sublookup_iteration (r))
+ return TRACE_RETURN (r);
+ }
+ return TRACE_RETURN (c->default_return_value ());
+ }
+
+ inline bool serialize (hb_serialize_context_t *c,
+ unsigned int lookup_type,
+ uint32_t lookup_props,
+ unsigned int num_subtables)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ lookupType.set (lookup_type);
+ lookupFlag.set (lookup_props & 0xFFFFu);
+ if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false);
+ if (lookupFlag & LookupFlag::UseMarkFilteringSet)
+ {
+ USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+ markFilteringSet.set (lookup_props >> 16);
+ }
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
/* Real sanitize of the subtables is done by GSUB/GPOS/... */
if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
- if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
+ if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
- USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+ const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
}
return TRACE_RETURN (true);
}
+ private:
USHORT lookupType; /* Different enumerations for GSUB and GPOS */
USHORT lookupFlag; /* Lookup qualifiers */
- ArrayOf<Offset>
+ ArrayOf<Offset<> >
subTable; /* Array of SubTables */
USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
* structure. This field is only present if bit
@@ -342,14 +675,28 @@ struct CoverageFormat1
private:
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
- int i = glyphArray.search (glyph_id);
- if (i != -1)
- return i;
- return NOT_COVERED;
+ int i = glyphArray.bsearch (glyph_id);
+ ASSERT_STATIC (((unsigned int) -1) == NOT_COVERED);
+ return i;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ glyphArray.len.set (num_glyphs);
+ if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false);
+ for (unsigned int i = 0; i < num_glyphs; i++)
+ glyphArray[i] = glyphs[i];
+ glyphs.advance (num_glyphs);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (glyphArray.sanitize (c));
}
@@ -357,6 +704,15 @@ struct CoverageFormat1
return glyphs->has (glyphArray[index]);
}
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const {
+ unsigned int count = glyphArray.len;
+ for (unsigned int i = 0; i < count; i++)
+ glyphs->add (glyphArray[i]);
+ }
+
+ public:
+ /* Older compilers need this to be public. */
struct Iter {
inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; };
inline bool more (void) { return i < c->glyphArray.len; }
@@ -368,8 +724,9 @@ struct CoverageFormat1
const struct CoverageFormat1 *c;
unsigned int i;
};
-
private:
+
+ protected:
USHORT coverageFormat; /* Format identifier--format = 1 */
SortedArrayOf<GlyphID>
glyphArray; /* Array of GlyphIDs--in numerical order */
@@ -384,7 +741,7 @@ struct CoverageFormat2
private:
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
- int i = rangeRecord.search (glyph_id);
+ int i = rangeRecord.bsearch (glyph_id);
if (i != -1) {
const RangeRecord &range = rangeRecord[i];
return (unsigned int) range.value + (glyph_id - range.start);
@@ -392,8 +749,41 @@ struct CoverageFormat2
return NOT_COVERED;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+
+ if (unlikely (!num_glyphs)) return TRACE_RETURN (true);
+
+ unsigned int num_ranges = 1;
+ for (unsigned int i = 1; i < num_glyphs; i++)
+ if (glyphs[i - 1] + 1 != glyphs[i])
+ num_ranges++;
+ rangeRecord.len.set (num_ranges);
+ if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false);
+
+ unsigned int range = 0;
+ rangeRecord[range].start = glyphs[0];
+ rangeRecord[range].value.set (0);
+ for (unsigned int i = 1; i < num_glyphs; i++)
+ if (glyphs[i - 1] + 1 != glyphs[i]) {
+ range++;
+ rangeRecord[range].start = glyphs[i];
+ rangeRecord[range].value.set (i);
+ rangeRecord[range].end = glyphs[i];
+ } else {
+ rangeRecord[range].end = glyphs[i];
+ }
+ glyphs.advance (num_glyphs);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (rangeRecord.sanitize (c));
}
@@ -412,6 +802,15 @@ struct CoverageFormat2
return false;
}
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const {
+ unsigned int count = rangeRecord.len;
+ for (unsigned int i = 0; i < count; i++)
+ rangeRecord[i].add_coverage (glyphs);
+ }
+
+ public:
+ /* Older compilers need this to be public. */
struct Iter {
inline void init (const CoverageFormat2 &c_) {
c = &c_;
@@ -437,8 +836,9 @@ struct CoverageFormat2
const struct CoverageFormat2 *c;
unsigned int i, j, coverage;
};
-
private:
+
+ protected:
USHORT coverageFormat; /* Format identifier--format = 2 */
SortedArrayOf<RangeRecord>
rangeRecord; /* Array of glyph ranges--ordered by
@@ -450,8 +850,6 @@ struct CoverageFormat2
struct Coverage
{
- inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
-
inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
switch (u.format) {
@@ -461,8 +859,27 @@ struct Coverage
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ unsigned int num_ranges = 1;
+ for (unsigned int i = 1; i < num_glyphs; i++)
+ if (glyphs[i - 1] + 1 != glyphs[i])
+ num_ranges++;
+ u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2);
+ switch (u.format) {
+ case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs));
+ case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs));
+ default:return TRACE_RETURN (false);
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -489,21 +906,30 @@ struct Coverage
}
}
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const {
+ switch (u.format) {
+ case 1: u.format1.add_coverage (glyphs); break;
+ case 2: u.format2.add_coverage (glyphs); break;
+ default: break;
+ }
+ }
+
struct Iter {
Iter (void) : format (0) {};
inline void init (const Coverage &c_) {
format = c_.u.format;
switch (format) {
- case 1: return u.format1.init (c_.u.format1);
- case 2: return u.format2.init (c_.u.format2);
- default:return;
+ case 1: u.format1.init (c_.u.format1); return;
+ case 2: u.format2.init (c_.u.format2); return;
+ default: return;
}
}
inline bool more (void) {
switch (format) {
case 1: return u.format1.more ();
case 2: return u.format2.more ();
- default:return true;
+ default:return false;
}
}
inline void next (void) {
@@ -517,14 +943,14 @@ struct Coverage
switch (format) {
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
- default:return true;
+ default:return 0;
}
}
inline uint16_t get_coverage (void) {
switch (format) {
case 1: return u.format1.get_coverage ();
case 2: return u.format2.get_coverage ();
- default:return true;
+ default:return -1;
}
}
@@ -536,7 +962,7 @@ struct Coverage
} u;
};
- private:
+ protected:
union {
USHORT format; /* Format identifier */
CoverageFormat1 format1;
@@ -558,24 +984,48 @@ struct ClassDefFormat1
private:
inline unsigned int get_class (hb_codepoint_t glyph_id) const
{
- if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
- return classValue[glyph_id - startGlyph];
+ unsigned int i = (unsigned int) (glyph_id - startGlyph);
+ if (unlikely (i < classValue.len))
+ return classValue[i];
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
}
+ template <typename set_t>
+ inline void add_class (set_t *glyphs, unsigned int klass) const {
+ unsigned int count = classValue.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (classValue[i] == klass)
+ glyphs->add (startGlyph + i);
+ }
+
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
unsigned int count = classValue.len;
+ if (klass == 0)
+ {
+ /* Match if there's any glyph that is not listed! */
+ hb_codepoint_t g = -1;
+ if (!hb_set_next (glyphs, &g))
+ return false;
+ if (g < startGlyph)
+ return true;
+ g = startGlyph + count - 1;
+ if (hb_set_next (glyphs, &g))
+ return true;
+ /* Fall through. */
+ }
for (unsigned int i = 0; i < count; i++)
if (classValue[i] == klass && glyphs->has (startGlyph + i))
return true;
return false;
}
+ protected:
USHORT classFormat; /* Format identifier--format = 1 */
GlyphID startGlyph; /* First GlyphID of the classValueArray */
ArrayOf<USHORT>
@@ -591,25 +1041,51 @@ struct ClassDefFormat2
private:
inline unsigned int get_class (hb_codepoint_t glyph_id) const
{
- int i = rangeRecord.search (glyph_id);
- if (i != -1)
+ int i = rangeRecord.bsearch (glyph_id);
+ if (unlikely (i != -1))
return rangeRecord[i].value;
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (rangeRecord.sanitize (c));
}
+ template <typename set_t>
+ inline void add_class (set_t *glyphs, unsigned int klass) const {
+ unsigned int count = rangeRecord.len;
+ for (unsigned int i = 0; i < count; i++)
+ if (rangeRecord[i].value == klass)
+ rangeRecord[i].add_coverage (glyphs);
+ }
+
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
unsigned int count = rangeRecord.len;
+ if (klass == 0)
+ {
+ /* Match if there's any glyph that is not listed! */
+ hb_codepoint_t g = (hb_codepoint_t) -1;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (!hb_set_next (glyphs, &g))
+ break;
+ if (g < rangeRecord[i].start)
+ return true;
+ g = rangeRecord[i].end;
+ }
+ if (g != (hb_codepoint_t) -1 && hb_set_next (glyphs, &g))
+ return true;
+ /* Fall through. */
+ }
for (unsigned int i = 0; i < count; i++)
if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs))
return true;
return false;
}
+ protected:
USHORT classFormat; /* Format identifier--format = 2 */
SortedArrayOf<RangeRecord>
rangeRecord; /* Array of glyph ranges--ordered by
@@ -620,8 +1096,6 @@ struct ClassDefFormat2
struct ClassDef
{
- inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
-
inline unsigned int get_class (hb_codepoint_t glyph_id) const
{
switch (u.format) {
@@ -631,8 +1105,9 @@ struct ClassDef
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -641,6 +1116,14 @@ struct ClassDef
}
}
+ inline void add_class (hb_set_t *glyphs, unsigned int klass) const {
+ switch (u.format) {
+ case 1: u.format1.add_class (glyphs, klass); return;
+ case 2: u.format2.add_class (glyphs, klass); return;
+ default:return;
+ }
+ }
+
inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
switch (u.format) {
case 1: return u.format1.intersects_class (glyphs, klass);
@@ -649,7 +1132,7 @@ struct ClassDef
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
ClassDefFormat1 format1;
@@ -681,7 +1164,7 @@ struct Device
if (!pixels) return 0;
- return pixels * (int64_t) scale / ppem;
+ return (int) (pixels * (int64_t) scale / ppem);
}
@@ -698,7 +1181,7 @@ struct Device
unsigned int byte = deltaValue[s >> (4 - f)];
unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
- unsigned int mask = (0xFFFF >> (16 - (1 << f)));
+ unsigned int mask = (0xFFFFu >> (16 - (1 << f)));
int delta = bits & mask;
@@ -715,12 +1198,13 @@ struct Device
return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
}
- private:
+ protected:
USHORT startSize; /* Smallest size to correct--in ppem */
USHORT endSize; /* Largest size to correct--in ppem */
USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3
@@ -734,5 +1218,7 @@ struct Device
};
+} /* namespace OT */
+
#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
diff --git a/src/hb-ot-layout-gdef-table.hh b/src/hb-ot-layout-gdef-table.hh
index f29fc14..7a6c04d 100644
--- a/src/hb-ot-layout-gdef-table.hh
+++ b/src/hb-ot-layout-gdef-table.hh
@@ -34,6 +34,8 @@
#include "hb-font-private.hh"
+namespace OT {
+
/*
* Attachment List Table
@@ -49,7 +51,7 @@ struct AttachList
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{
- unsigned int index = (this+coverage) (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (point_count)
@@ -69,12 +71,13 @@ struct AttachList
return points.len;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
}
- private:
+ protected:
OffsetTo<Coverage>
coverage; /* Offset to Coverage table -- from
* beginning of AttachList table */
@@ -99,12 +102,13 @@ struct CaretValueFormat1
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
- private:
+ protected:
USHORT caretValueFormat; /* Format identifier--format = 1 */
SHORT coordinate; /* X or Y value, in design units */
public:
@@ -119,18 +123,19 @@ struct CaretValueFormat2
inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
{
hb_position_t x, y;
- if (hb_font_get_glyph_contour_point_for_origin (font, glyph_id, caretValuePoint, direction, &x, &y))
+ if (font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y))
return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
else
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
- private:
+ protected:
USHORT caretValueFormat; /* Format identifier--format = 2 */
USHORT caretValuePoint; /* Contour point index on glyph */
public:
@@ -148,12 +153,13 @@ struct CaretValueFormat3
font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this));
}
- private:
+ protected:
USHORT caretValueFormat; /* Format identifier--format = 3 */
SHORT coordinate; /* X or Y value, in design units */
OffsetTo<Device>
@@ -176,8 +182,9 @@ struct CaretValue
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -187,7 +194,7 @@ struct CaretValue
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
CaretValueFormat1 format1;
@@ -217,12 +224,13 @@ struct LigGlyph
return carets.len;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (carets.sanitize (c, this));
}
- private:
+ protected:
OffsetArrayOf<CaretValue>
carets; /* Offset array of CaretValue tables
* --from beginning of LigGlyph table
@@ -240,7 +248,7 @@ struct LigCaretList
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
- unsigned int index = (this+coverage) (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (caret_count)
@@ -251,12 +259,13 @@ struct LigCaretList
return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
}
- private:
+ protected:
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of LigCaretList table */
@@ -273,14 +282,15 @@ struct MarkGlyphSetsFormat1
inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
- LongOffsetArrayOf<Coverage>
+ ArrayOf<OffsetTo<Coverage, ULONG> >
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
@@ -297,8 +307,9 @@ struct MarkGlyphSets
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -306,7 +317,7 @@ struct MarkGlyphSets
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
MarkGlyphSetsFormat1 format1;
@@ -322,7 +333,7 @@ struct MarkGlyphSets
struct GDEF
{
- static const hb_tag_t Tag = HB_OT_TAG_GDEF;
+ static const hb_tag_t tableTag = HB_OT_TAG_GDEF;
enum GlyphClasses {
UnclassifiedGlyph = 0,
@@ -335,6 +346,8 @@ struct GDEF
inline bool has_glyph_classes (void) const { return glyphClassDef != 0; }
inline unsigned int get_glyph_class (hb_codepoint_t glyph) const
{ return (this+glyphClassDef).get_class (glyph); }
+ inline void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
+ { (this+glyphClassDef).add_class (glyphs, klass); }
inline bool has_mark_attachment_types (void) const { return markAttachClassDef != 0; }
inline unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
@@ -356,19 +369,20 @@ struct GDEF
hb_position_t *caret_array /* OUT */) const
{ return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); }
- inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002 && markGlyphSetsDef[0] != 0; }
+ inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; }
inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
- { return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+ { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (version.sanitize (c) &&
likely (version.major == 1) &&
glyphClassDef.sanitize (c, this) &&
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
- (version.to_int () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this)));
+ (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this)));
}
@@ -379,22 +393,24 @@ struct GDEF
{
unsigned int klass = get_glyph_class (glyph);
+ ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs);
+ ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures);
+ ASSERT_STATIC ((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks);
+
switch (klass) {
- default:
- case UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
- case BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
- case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
- case ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
+ default: return 0;
+ case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
+ case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
case MarkGlyph:
klass = get_mark_attachment_type (glyph);
- return HB_OT_LAYOUT_GLYPH_CLASS_MARK | (klass << 8);
+ return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
}
}
- private:
+ protected:
FixedVersion version; /* Version of the GDEF table--currently
- * 0x00010002 */
+ * 0x00010002u */
OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
@@ -421,5 +437,7 @@ struct GDEF
};
+} /* namespace OT */
+
#endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 71c13a2..d88f787 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1,6 +1,6 @@
/*
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
- * Copyright © 2010,2012 Google, Inc.
+ * Copyright © 2010,2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -32,6 +32,8 @@
#include "hb-ot-layout-gsubgpos-private.hh"
+namespace OT {
+
/* buffer **position** var allocations */
#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
@@ -47,18 +49,18 @@ typedef Value ValueRecord[VAR];
struct ValueFormat : USHORT
{
enum Flags {
- xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
- yPlacement = 0x0002, /* Includes vertical adjustment for placement */
- xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
- yAdvance = 0x0008, /* Includes vertical adjustment for advance */
- xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
- yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
- xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
- yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
- ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
- reserved = 0xF000, /* For future use */
-
- devices = 0x00F0 /* Mask for having any Device table */
+ xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */
+ yPlacement = 0x0002u, /* Includes vertical adjustment for placement */
+ xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */
+ yAdvance = 0x0008u, /* Includes vertical adjustment for advance */
+ xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */
+ yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */
+ xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */
+ yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */
+ ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */
+ reserved = 0xF000u, /* For future use */
+
+ devices = 0x00F0u /* Mask for having any Device table */
};
/* All fields are options. Only those available advance the value pointer. */
@@ -107,11 +109,13 @@ struct ValueFormat : USHORT
if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
if (format & xAdvance) {
- if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
+ if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
+ values++;
}
/* y_advance values grow downward but font-space grows upward, hence negation */
if (format & yAdvance) {
- if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
+ if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
+ values++;
}
if (!has_device ()) return;
@@ -123,22 +127,27 @@ struct ValueFormat : USHORT
/* pixel -> fractional pixel */
if (format & xPlaDevice) {
- if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
+ if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font);
+ values++;
}
if (format & yPlaDevice) {
- if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
+ if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font);
+ values++;
}
if (format & xAdvDevice) {
- if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
+ if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
+ values++;
}
if (format & yAdvDevice) {
/* y_advance values grow downward but font-space grows upward, hence negation */
- if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
+ if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
+ values++;
}
}
private:
- inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
+ inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ {
unsigned int format = *this;
if (format & xPlacement) values++;
@@ -169,13 +178,15 @@ struct ValueFormat : USHORT
return (format & devices) != 0;
}
- inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
- TRACE_SANITIZE ();
+ inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
}
- inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
- TRACE_SANITIZE ();
+ inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+ {
+ TRACE_SANITIZE (this);
unsigned int len = get_len ();
if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
@@ -192,8 +203,9 @@ struct ValueFormat : USHORT
}
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
- inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
- TRACE_SANITIZE ();
+ inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+ {
+ TRACE_SANITIZE (this);
if (!has_device ()) return TRACE_RETURN (true);
@@ -210,9 +222,6 @@ struct ValueFormat : USHORT
struct AnchorFormat1
{
- friend struct Anchor;
-
- private:
inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
@@ -220,12 +229,13 @@ struct AnchorFormat1
*y = font->em_scale_y (yCoordinate);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
SHORT xCoordinate; /* Horizontal value--in design units */
SHORT yCoordinate; /* Vertical value--in design units */
@@ -235,29 +245,27 @@ struct AnchorFormat1
struct AnchorFormat2
{
- friend struct Anchor;
-
- private:
inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
hb_position_t *x, hb_position_t *y) const
{
unsigned int x_ppem = font->x_ppem;
unsigned int y_ppem = font->y_ppem;
hb_position_t cx, cy;
- hb_bool_t ret = false;
+ hb_bool_t ret;
- if (x_ppem || y_ppem)
- ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
- *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
- *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
+ ret = (x_ppem || y_ppem) &&
+ font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
+ *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
+ *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 2 */
SHORT xCoordinate; /* Horizontal value--in design units */
SHORT yCoordinate; /* Vertical value--in design units */
@@ -268,9 +276,6 @@ struct AnchorFormat2
struct AnchorFormat3
{
- friend struct Anchor;
-
- private:
inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
hb_position_t *x, hb_position_t *y) const
{
@@ -283,12 +288,13 @@ struct AnchorFormat3
*y += (this+yDeviceTable).get_x_delta (font);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 3 */
SHORT xCoordinate; /* Horizontal value--in design units */
SHORT yCoordinate; /* Vertical value--in design units */
@@ -318,8 +324,9 @@ struct Anchor
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
case 1: return TRACE_RETURN (u.format1.sanitize (c));
@@ -329,7 +336,7 @@ struct Anchor
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
AnchorFormat1 format1;
@@ -343,29 +350,32 @@ struct Anchor
struct AnchorMatrix
{
- inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
+ inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
+ *found = false;
if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
- return this+matrix[row * cols + col];
+ *found = !matrixZ[row * cols + col].is_null ();
+ return this+matrixZ[row * cols + col];
}
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
+ {
+ TRACE_SANITIZE (this);
if (!c->check_struct (this)) return TRACE_RETURN (false);
if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
unsigned int count = rows * cols;
- if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
+ if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
for (unsigned int i = 0; i < count; i++)
- if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
+ if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
USHORT rows; /* Number of rows */
- private:
+ protected:
OffsetTo<Anchor>
- matrix[VAR]; /* Matrix of offsets to Anchor tables--
+ matrixZ[VAR]; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */
public:
- DEFINE_SIZE_ARRAY (2, matrix);
+ DEFINE_SIZE_ARRAY (2, matrixZ);
};
@@ -373,12 +383,13 @@ struct MarkRecord
{
friend struct MarkArray;
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
}
- private:
+ protected:
USHORT klass; /* Class defined for this mark */
OffsetTo<Anchor>
markAnchor; /* Offset to Anchor table--from
@@ -394,29 +405,35 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
const AnchorMatrix &anchors, unsigned int class_count,
unsigned int glyph_pos) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
unsigned int mark_class = record.klass;
const Anchor& mark_anchor = this + record.markAnchor;
- const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
+ bool found;
+ const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+ /* If this subtable doesn't have an anchor for this base and this class,
+ * return false such that the subsequent subtables have a chance at it. */
+ if (unlikely (!found)) return TRACE_RETURN (false);
hb_position_t mark_x, mark_y, base_x, base_y;
- mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y);
- glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+ mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
+ glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
- hb_glyph_position_t &o = c->buffer->cur_pos();
+ hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = base_x - mark_x;
o.y_offset = base_y - mark_y;
- o.attach_lookback() = c->buffer->idx - glyph_pos;
+ o.attach_lookback() = buffer->idx - glyph_pos;
- c->buffer->idx++;
+ buffer->idx++;
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
}
};
@@ -426,28 +443,40 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
struct SinglePosFormat1
{
- friend struct SinglePos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
- private:
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
valueFormat.apply_value (c->font, c->direction, this,
- values, c->buffer->cur_pos());
+ values, buffer->cur_pos());
- c->buffer->idx++;
+ buffer->idx++;
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && valueFormat.sanitize_value (c, this, values));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -463,31 +492,43 @@ struct SinglePosFormat1
struct SinglePosFormat2
{
- friend struct SinglePos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
- private:
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
if (likely (index >= valueCount)) return TRACE_RETURN (false);
valueFormat.apply_value (c->font, c->direction, this,
&values[index * valueFormat.get_len ()],
- c->buffer->cur_pos());
+ buffer->cur_pos());
- c->buffer->idx++;
+ buffer->idx++;
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && valueFormat.sanitize_values (c, this, values, valueCount));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -503,30 +544,19 @@ struct SinglePosFormat2
struct SinglePos
{
- friend struct PosLookupSubTable;
-
- private:
- inline bool apply (hb_apply_context_t *c) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- case 2: return TRACE_RETURN (u.format2.apply (c));
- default:return TRACE_RETURN (false);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ case 2: return TRACE_RETURN (c->dispatch (u.format2));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT format; /* Format identifier */
SinglePosFormat1 format1;
@@ -539,7 +569,7 @@ struct PairValueRecord
{
friend struct PairSet;
- private:
+ protected:
GlyphID secondGlyph; /* GlyphID of second glyph in the
* pair--first glyph is listed in the
* Coverage table */
@@ -553,83 +583,126 @@ struct PairSet
{
friend struct PairPosFormat1;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c,
+ const ValueFormat *valueFormats) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ unsigned int len1 = valueFormats[0].get_len ();
+ unsigned int len2 = valueFormats[1].get_len ();
+ unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+
+ const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ c->input->add (record->secondGlyph);
+ record = &StructAtOffset<PairValueRecord> (record, record_size);
+ }
+ }
+
inline bool apply (hb_apply_context_t *c,
const ValueFormat *valueFormats,
unsigned int pos) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+ const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
unsigned int count = len;
- const PairValueRecord *record = CastP<PairValueRecord> (array);
- for (unsigned int i = 0; i < count; i++)
+
+ /* Hand-coded bsearch. */
+ if (unlikely (!count))
+ return TRACE_RETURN (false);
+ hb_codepoint_t x = buffer->info[pos].codepoint;
+ int min = 0, max = (int) count - 1;
+ while (min <= max)
{
- if (c->buffer->info[pos].codepoint == record->secondGlyph)
+ int mid = (min + max) / 2;
+ const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
+ hb_codepoint_t mid_x = record->secondGlyph;
+ if (x < mid_x)
+ max = mid - 1;
+ else if (x > mid_x)
+ min = mid + 1;
+ else
{
valueFormats[0].apply_value (c->font, c->direction, this,
- &record->values[0], c->buffer->cur_pos());
+ &record->values[0], buffer->cur_pos());
valueFormats[1].apply_value (c->font, c->direction, this,
- &record->values[len1], c->buffer->pos[pos]);
+ &record->values[len1], buffer->pos[pos]);
if (len2)
pos++;
- c->buffer->idx = pos;
+ buffer->idx = pos;
return TRACE_RETURN (true);
}
- record = &StructAtOffset<PairValueRecord> (record, record_size);
}
return TRACE_RETURN (false);
}
struct sanitize_closure_t {
- void *base;
- ValueFormat *valueFormats;
+ const void *base;
+ const ValueFormat *valueFormats;
unsigned int len1; /* valueFormats[0].get_len() */
unsigned int stride; /* 1 + len1 + len2 */
};
- inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+ {
+ TRACE_SANITIZE (this);
if (!(c->check_struct (this)
- && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
+ && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
unsigned int count = len;
- PairValueRecord *record = CastP<PairValueRecord> (array);
+ const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
&& closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
}
- private:
+ protected:
USHORT len; /* Number of PairValueRecords */
- USHORT array[VAR]; /* Array of PairValueRecords--ordered
+ USHORT arrayZ[VAR]; /* Array of PairValueRecords--ordered
* by GlyphID of the second glyph */
public:
- DEFINE_SIZE_ARRAY (2, array);
+ DEFINE_SIZE_ARRAY (2, arrayZ);
};
struct PairPosFormat1
{
- friend struct PairPos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+ unsigned int count = pairSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
+ }
- private:
- inline bool apply (hb_apply_context_t *c) const
+ inline const Coverage &get_coverage (void) const
{
- TRACE_APPLY ();
- hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+ return this+coverage;
+ }
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return TRACE_RETURN (false);
return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
@@ -643,7 +716,7 @@ struct PairPosFormat1
return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -663,43 +736,62 @@ struct PairPosFormat1
struct PairPosFormat2
{
- friend struct PairPos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ /* (this+coverage).add_coverage (c->input); // Don't need this. */
+
+ unsigned int count1 = class1Count;
+ const ClassDef &klass1 = this+classDef1;
+ for (unsigned int i = 0; i < count1; i++)
+ klass1.add_class (c->input, i);
+
+ unsigned int count2 = class2Count;
+ const ClassDef &klass2 = this+classDef2;
+ for (unsigned int i = 0; i < count2; i++)
+ klass2.add_class (c->input, i);
+ }
- private:
- inline bool apply (hb_apply_context_t *c) const
+ inline const Coverage &get_coverage (void) const
{
- TRACE_APPLY ();
- hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+ return this+coverage;
+ }
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return TRACE_RETURN (false);
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int record_len = len1 + len2;
- unsigned int klass1 = (this+classDef1) (c->buffer->cur().codepoint);
- unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint);
+ unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
+ unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
valueFormat1.apply_value (c->font, c->direction, this,
- v, c->buffer->cur_pos());
+ v, buffer->cur_pos());
valueFormat2.apply_value (c->font, c->direction, this,
- v + len1, c->buffer->pos[skippy_iter.idx]);
+ v + len1, buffer->pos[skippy_iter.idx]);
- c->buffer->idx = skippy_iter.idx;
+ buffer->idx = skippy_iter.idx;
if (len2)
- c->buffer->idx++;
+ buffer->idx++;
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!(c->check_struct (this)
&& coverage.sanitize (c, this)
&& classDef1.sanitize (c, this)
@@ -715,7 +807,7 @@ struct PairPosFormat2
valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -747,30 +839,19 @@ struct PairPosFormat2
struct PairPos
{
- friend struct PosLookupSubTable;
-
- private:
- inline bool apply (hb_apply_context_t *c) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- case 2: return TRACE_RETURN (u.format2.apply (c));
- default:return TRACE_RETURN (false);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ case 2: return TRACE_RETURN (c->dispatch (u.format2));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT format; /* Format identifier */
PairPosFormat1 format1;
@@ -783,12 +864,13 @@ struct EntryExitRecord
{
friend struct CursivePosFormat1;
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
}
- private:
+ protected:
OffsetTo<Anchor>
entryAnchor; /* Offset to EntryAnchor table--from
* beginning of CursivePos
@@ -803,35 +885,43 @@ struct EntryExitRecord
struct CursivePosFormat1
{
- friend struct CursivePos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
- private:
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
/* We don't handle mark glyphs here. */
- if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) return TRACE_RETURN (false);
+ if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
- hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
- const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->cur().codepoint)];
+ const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
if (!this_record.exitAnchor) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return TRACE_RETURN (false);
- const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)];
+ const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
if (!next_record.entryAnchor) return TRACE_RETURN (false);
- unsigned int i = c->buffer->idx;
+ unsigned int i = buffer->idx;
unsigned int j = skippy_iter.idx;
hb_position_t entry_x, entry_y, exit_x, exit_y;
- (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
- (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
+ (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
+ (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
- hb_glyph_position_t *pos = c->buffer->pos;
+ hb_glyph_position_t *pos = buffer->pos;
hb_position_t d;
/* Main-direction adjustment */
@@ -884,16 +974,17 @@ struct CursivePosFormat1
pos[j].x_offset = exit_x - entry_x;
}
- c->buffer->idx = j;
+ buffer->idx = j;
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -907,28 +998,18 @@ struct CursivePosFormat1
struct CursivePos
{
- friend struct PosLookupSubTable;
-
- private:
- inline bool apply (hb_apply_context_t *c) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- default:return TRACE_RETURN (false);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT format; /* Format identifier */
CursivePosFormat1 format1;
@@ -943,36 +1024,53 @@ typedef AnchorMatrix BaseArray; /* base-major--
struct MarkBasePosFormat1
{
- friend struct MarkBasePos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+markCoverage).add_coverage (c->input);
+ (this+baseCoverage).add_coverage (c->input);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+markCoverage;
+ }
- private:
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a non-mark glyph */
- unsigned int property;
- hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
- if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
-
- /* The following assertion is too strong, so we've disabled it. */
- if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
-
- unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+ do {
+ if (!skippy_iter.prev ()) return TRACE_RETURN (false);
+ /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
+ if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
+ skippy_iter.reject ();
+ } while (1);
+
+ /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
+ if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
+
+ unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
if (base_index == NOT_COVERED) return TRACE_RETURN (false);
return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
markCoverage; /* Offset to MarkCoverage table--from
@@ -993,28 +1091,18 @@ struct MarkBasePosFormat1
struct MarkBasePos
{
- friend struct PosLookupSubTable;
-
- private:
- inline bool apply (hb_apply_context_t *c) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_APPLY ();
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- default:return TRACE_RETURN (false);
- }
- }
-
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
MarkBasePosFormat1 format1;
@@ -1034,25 +1122,36 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
struct MarkLigPosFormat1
{
- friend struct MarkLigPos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+markCoverage).add_coverage (c->input);
+ (this+ligatureCoverage).add_coverage (c->input);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+markCoverage;
+ }
- private:
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint);
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a non-mark glyph */
- unsigned int property;
- hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
- if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
+ if (!skippy_iter.prev ()) return TRACE_RETURN (false);
- /* The following assertion is too strong, so we've disabled it. */
- if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
+ /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
+ if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
unsigned int j = skippy_iter.idx;
- unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
+ unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
const LigatureArray& lig_array = this+ligatureArray;
@@ -1062,32 +1161,30 @@ struct MarkLigPosFormat1
unsigned int comp_count = lig_attach.rows;
if (unlikely (!comp_count)) return TRACE_RETURN (false);
- unsigned int comp_index;
/* We must now check whether the ligature ID of the current mark glyph
* is identical to the ligature ID of the found ligature. If yes, we
* can directly use the component index. If not, we attach the mark
* glyph to the last component of the ligature. */
- if (get_lig_id (c->buffer->info[j]) &&
- get_lig_id (c->buffer->cur()) &&
- get_lig_comp (c->buffer->cur()) > 0)
- {
- comp_index = get_lig_comp (c->buffer->cur()) - 1;
- if (comp_index >= comp_count)
- comp_index = comp_count - 1;
- }
+ unsigned int comp_index;
+ unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+ unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+ unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+ if (lig_id && lig_id == mark_id && mark_comp > 0)
+ comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
else
comp_index = comp_count - 1;
return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
markCoverage; /* Offset to Mark Coverage table--from
@@ -1109,28 +1206,18 @@ struct MarkLigPosFormat1
struct MarkLigPos
{
- friend struct PosLookupSubTable;
-
- private:
- inline bool apply (hb_apply_context_t *c) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_APPLY ();
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- default:return TRACE_RETURN (false);
- }
- }
-
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
MarkLigPosFormat1 format1;
@@ -1145,46 +1232,71 @@ typedef AnchorMatrix Mark2Array; /* mark2-major--
struct MarkMarkPosFormat1
{
- friend struct MarkMarkPos;
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+mark1Coverage).add_coverage (c->input);
+ (this+mark2Coverage).add_coverage (c->input);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+mark1Coverage;
+ }
- private:
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int mark1_index = (this+mark1Coverage) (c->buffer->cur().codepoint);
+ TRACE_APPLY (this);
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a suitable mark glyph until a non-mark glyph */
- unsigned int property;
- hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
- if (!skippy_iter.prev (&property)) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
+ if (!skippy_iter.prev ()) return TRACE_RETURN (false);
- if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return TRACE_RETURN (false);
+ if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
unsigned int j = skippy_iter.idx;
- /* Two marks match only if they belong to the same base, or same component
- * of the same ligature. That is, the component numbers must match, and
- * if those are non-zero, the ligid number should also match. */
- if ((get_lig_comp (c->buffer->cur())) ||
- (get_lig_comp (c->buffer->info[j]) > 0 &&
- get_lig_id (c->buffer->cur())))
- return TRACE_RETURN (false);
+ unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
+ unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+ unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
+ unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
+
+ if (likely (id1 == id2)) {
+ if (id1 == 0) /* Marks belonging to the same base. */
+ goto good;
+ else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
+ goto good;
+ } else {
+ /* If ligature ids don't match, it may be the case that one of the marks
+ * itself is a ligature. In which case match. */
+ if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
+ goto good;
+ }
+
+ /* Didn't match. */
+ return TRACE_RETURN (false);
- unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
+ good:
+ unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint);
if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
&& mark2Array.sanitize (c, this, (unsigned int) classCount));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
mark1Coverage; /* Offset to Combining Mark1 Coverage
@@ -1207,28 +1319,18 @@ struct MarkMarkPosFormat1
struct MarkMarkPos
{
- friend struct PosLookupSubTable;
-
- private:
- inline bool apply (hb_apply_context_t *c) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- default:return TRACE_RETURN (false);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT format; /* Format identifier */
MarkMarkPosFormat1 format1;
@@ -1236,48 +1338,13 @@ struct MarkMarkPos
};
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-
-struct ContextPos : Context
-{
- friend struct PosLookupSubTable;
+struct ContextPos : Context {};
- private:
- inline bool apply (hb_apply_context_t *c) const
- {
- TRACE_APPLY ();
- return TRACE_RETURN (Context::apply (c, position_lookup));
- }
-};
+struct ChainContextPos : ChainContext {};
-struct ChainContextPos : ChainContext
+struct ExtensionPos : Extension<ExtensionPos>
{
- friend struct PosLookupSubTable;
-
- private:
- inline bool apply (hb_apply_context_t *c) const
- {
- TRACE_APPLY ();
- return TRACE_RETURN (ChainContext::apply (c, position_lookup));
- }
-};
-
-
-struct ExtensionPos : Extension
-{
- friend struct PosLookupSubTable;
-
- private:
- inline const struct PosLookupSubTable& get_subtable (void) const
- {
- unsigned int offset = get_offset ();
- if (unlikely (!offset)) return Null(PosLookupSubTable);
- return StructAtOffset<PosLookupSubTable> (this, offset);
- }
-
- inline bool apply (hb_apply_context_t *c) const;
-
- inline bool sanitize (hb_sanitize_context_t *c);
+ typedef struct PosLookupSubTable LookupSubTable;
};
@@ -1303,40 +1370,27 @@ struct PosLookupSubTable
Extension = 9
};
- inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
{
- TRACE_APPLY ();
- switch (lookup_type) {
- case Single: return TRACE_RETURN (u.single.apply (c));
- case Pair: return TRACE_RETURN (u.pair.apply (c));
- case Cursive: return TRACE_RETURN (u.cursive.apply (c));
- case MarkBase: return TRACE_RETURN (u.markBase.apply (c));
- case MarkLig: return TRACE_RETURN (u.markLig.apply (c));
- case MarkMark: return TRACE_RETURN (u.markMark.apply (c));
- case Context: return TRACE_RETURN (u.c.apply (c));
- case ChainContext: return TRACE_RETURN (u.chainContext.apply (c));
- case Extension: return TRACE_RETURN (u.extension.apply (c));
- default: return TRACE_RETURN (false);
- }
- }
-
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
- TRACE_SANITIZE ();
+ TRACE_DISPATCH (this, lookup_type);
+ /* The sub_format passed to may_dispatch is unnecessary but harmless. */
+ if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
switch (lookup_type) {
- case Single: return TRACE_RETURN (u.single.sanitize (c));
- case Pair: return TRACE_RETURN (u.pair.sanitize (c));
- case Cursive: return TRACE_RETURN (u.cursive.sanitize (c));
- case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c));
- case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c));
- case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c));
- case Context: return TRACE_RETURN (u.c.sanitize (c));
- case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
- case Extension: return TRACE_RETURN (u.extension.sanitize (c));
- default: return TRACE_RETURN (true);
+ case Single: return TRACE_RETURN (u.single.dispatch (c));
+ case Pair: return TRACE_RETURN (u.pair.dispatch (c));
+ case Cursive: return TRACE_RETURN (u.cursive.dispatch (c));
+ case MarkBase: return TRACE_RETURN (u.markBase.dispatch (c));
+ case MarkLig: return TRACE_RETURN (u.markLig.dispatch (c));
+ case MarkMark: return TRACE_RETURN (u.markMark.dispatch (c));
+ case Context: return TRACE_RETURN (u.context.dispatch (c));
+ case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c));
+ case Extension: return TRACE_RETURN (u.extension.dispatch (c));
+ default: return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT sub_format;
SinglePos single;
@@ -1345,7 +1399,7 @@ struct PosLookupSubTable
MarkBasePos markBase;
MarkLigPos markLig;
MarkMarkPos markMark;
- ContextPos c;
+ ContextPos context;
ChainContextPos chainContext;
ExtensionPos extension;
} u;
@@ -1357,48 +1411,47 @@ struct PosLookupSubTable
struct PosLookup : Lookup
{
inline const PosLookupSubTable& get_subtable (unsigned int i) const
- { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
+ { return Lookup::get_subtable<PosLookupSubTable> (i); }
- inline bool apply_once (hb_apply_context_t *c) const
+ inline bool is_reverse (void) const
{
- unsigned int lookup_type = get_type ();
-
- if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property))
- return false;
-
- for (unsigned int i = 0; i < get_subtable_count (); i++)
- if (get_subtable (i).apply (c, lookup_type))
- return true;
-
return false;
}
- inline bool apply_string (hb_apply_context_t *c) const
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ return TRACE_RETURN (dispatch (c));
+ }
+
+ inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- bool ret = false;
+ TRACE_COLLECT_GLYPHS (this);
+ return TRACE_RETURN (dispatch (c));
+ }
- if (unlikely (!c->buffer->len))
- return false;
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const
+ {
+ hb_add_coverage_context_t<set_t> c (glyphs);
+ dispatch (&c);
+ }
- c->set_lookup (*this);
+ static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
- c->buffer->idx = 0;
- while (c->buffer->idx < c->buffer->len)
- {
- if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
- ret = true;
- else
- c->buffer->idx++;
- }
+ template <typename context_t>
+ static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
- return ret;
- }
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ { return Lookup::dispatch<PosLookupSubTable> (c); }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
- OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
- return TRACE_RETURN (list.sanitize (c, this, get_type ()));
+ const OffsetArrayOf<PosLookupSubTable> &list = get_subtables<PosLookupSubTable> ();
+ return TRACE_RETURN (dispatch (c));
}
};
@@ -1410,21 +1463,19 @@ typedef OffsetListOf<PosLookup> PosLookupList;
struct GPOS : GSUBGPOS
{
- static const hb_tag_t Tag = HB_OT_TAG_GPOS;
+ static const hb_tag_t tableTag = HB_OT_TAG_GPOS;
inline const PosLookup& get_lookup (unsigned int i) const
{ return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
- inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
- { return get_lookup (lookup_index).apply_string (c); }
+ static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
- static inline void position_start (hb_buffer_t *buffer);
- static inline void position_finish (hb_buffer_t *buffer);
-
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
- OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
+ const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
return TRACE_RETURN (list.sanitize (c, this));
}
public:
@@ -1435,20 +1486,20 @@ struct GPOS : GSUBGPOS
static void
fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
{
- unsigned int j = pos[i].cursive_chain();
- if (likely (!j))
- return;
+ unsigned int j = pos[i].cursive_chain();
+ if (likely (!j))
+ return;
- j += i;
+ j += i;
- pos[i].cursive_chain() = 0;
+ pos[i].cursive_chain() = 0;
- fix_cursive_minor_offset (pos, j, direction);
+ fix_cursive_minor_offset (pos, j, direction);
- if (HB_DIRECTION_IS_HORIZONTAL (direction))
- pos[i].y_offset += pos[j].y_offset;
- else
- pos[i].x_offset += pos[j].x_offset;
+ if (HB_DIRECTION_IS_HORIZONTAL (direction))
+ pos[i].y_offset += pos[j].y_offset;
+ else
+ pos[i].x_offset += pos[j].x_offset;
}
static void
@@ -1459,8 +1510,6 @@ fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t di
unsigned int j = i - pos[i].attach_lookback();
- pos[i].x_advance = 0;
- pos[i].y_advance = 0;
pos[i].x_offset += pos[j].x_offset;
pos[i].y_offset += pos[j].y_offset;
@@ -1477,7 +1526,7 @@ fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t di
}
void
-GPOS::position_start (hb_buffer_t *buffer)
+GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
buffer->clear_positions ();
@@ -1487,8 +1536,10 @@ GPOS::position_start (hb_buffer_t *buffer)
}
void
-GPOS::position_finish (hb_buffer_t *buffer)
+GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
+ _hb_buffer_assert_gsubgpos_vars (buffer);
+
unsigned int len;
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
hb_direction_t direction = buffer->props.direction;
@@ -1500,42 +1551,28 @@ GPOS::position_finish (hb_buffer_t *buffer)
/* Handle attachments */
for (unsigned int i = 0; i < len; i++)
fix_mark_attachment (pos, i, direction);
-
- HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
- HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
- HB_BUFFER_DEALLOCATE_VAR (buffer, props_cache);
}
/* Out-of-class implementation for methods recursing */
-inline bool ExtensionPos::apply (hb_apply_context_t *c) const
+template <typename context_t>
+/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
{
- TRACE_APPLY ();
- return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
-inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
-{
- TRACE_SANITIZE ();
- if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
- unsigned int offset = get_offset ();
- if (unlikely (!offset)) return TRACE_RETURN (true);
- return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()));
+ const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
+ const PosLookup &l = gpos.get_lookup (lookup_index);
+ return l.dispatch (c);
}
-static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
{
- const GPOS &gpos = *(c->face->ot_layout->gpos);
+ const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
const PosLookup &l = gpos.get_lookup (lookup_index);
-
- if (unlikely (c->nesting_level_left == 0))
- return false;
-
- hb_apply_context_t new_c (*c);
- new_c.nesting_level_left--;
- new_c.set_lookup (l);
- return l.apply_once (&new_c);
+ unsigned int saved_lookup_props = c->lookup_props;
+ c->set_lookup (l);
+ bool ret = l.dispatch (c);
+ c->set_lookup_props (saved_lookup_props);
+ return ret;
}
@@ -1543,5 +1580,7 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i
#undef cursive_chain
+} /* namespace OT */
+
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index f6a7575..ebe4c9e 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1,6 +1,6 @@
/*
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
- * Copyright © 2010,2012 Google, Inc.
+ * Copyright © 2010,2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -32,50 +32,78 @@
#include "hb-ot-layout-gsubgpos-private.hh"
+namespace OT {
+
struct SingleSubstFormat1
{
- friend struct SingleSubst;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
hb_codepoint_t glyph_id = iter.get_glyph ();
if (c->glyphs->has (glyph_id))
- c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
+ c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
+ }
+ }
+
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ Coverage::Iter iter;
+ for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ hb_codepoint_t glyph_id = iter.get_glyph ();
+ c->input->add (glyph_id);
+ c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
}
}
- inline bool would_apply (hb_codepoint_t glyph_id) const
+ inline const Coverage &get_coverage (void) const
{
- return (this+coverage) (glyph_id) != NOT_COVERED;
+ return this+coverage;
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+ return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage) (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
/* According to the Adobe Annotated OpenType Suite, result is always
* limited to 16bit. */
- glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
+ glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
c->replace_glyph (glyph_id);
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ unsigned int num_glyphs,
+ int delta)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+ deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -88,13 +116,9 @@ struct SingleSubstFormat1
struct SingleSubstFormat2
{
- friend struct SingleSubst;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
if (c->glyphs->has (iter.get_glyph ()))
@@ -102,16 +126,32 @@ struct SingleSubstFormat2
}
}
- inline bool would_apply (hb_codepoint_t glyph_id) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- return (this+coverage) (glyph_id) != NOT_COVERED;
+ TRACE_COLLECT_GLYPHS (this);
+ Coverage::Iter iter;
+ for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ c->input->add (iter.get_glyph ());
+ c->output->add (substitute[iter.get_coverage ()]);
+ }
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+ return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage) (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
@@ -122,12 +162,25 @@ struct SingleSubstFormat2
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<GlyphID> &substitutes,
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
+ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -141,50 +194,46 @@ struct SingleSubstFormat2
struct SingleSubst
{
- friend struct SubstLookupSubTable;
-
- private:
-
- inline void closure (hb_closure_context_t *c) const
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<GlyphID> &substitutes,
+ unsigned int num_glyphs)
{
- TRACE_CLOSURE ();
- switch (u.format) {
- case 1: u.format1.closure (c); break;
- case 2: u.format2.closure (c); break;
- default: break;
- }
- }
-
- inline bool would_apply (hb_codepoint_t glyph_id) const
- {
- switch (u.format) {
- case 1: return u.format1.would_apply (glyph_id);
- case 2: return u.format2.would_apply (glyph_id);
- default:return false;
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+ unsigned int format = 2;
+ int delta = 0;
+ if (num_glyphs) {
+ format = 1;
+ /* TODO(serialize) check for wrap-around */
+ delta = substitutes[0] - glyphs[0];
+ for (unsigned int i = 1; i < num_glyphs; i++)
+ if (delta != substitutes[i] - glyphs[i]) {
+ format = 2;
+ break;
+ }
}
- }
-
- inline bool apply (hb_apply_context_t *c) const
- {
- TRACE_APPLY ();
+ u.format.set (format);
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- case 2: return TRACE_RETURN (u.format2.apply (c));
+ case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
+ case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
default:return TRACE_RETURN (false);
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ case 2: return TRACE_RETURN (c->dispatch (u.format2));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
SingleSubstFormat1 format1;
@@ -195,36 +244,74 @@ struct SingleSubst
struct Sequence
{
- friend struct MultipleSubstFormat1;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
unsigned int count = substitute.len;
for (unsigned int i = 0; i < count; i++)
c->glyphs->add (substitute[i]);
}
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ unsigned int count = substitute.len;
+ for (unsigned int i = 0; i < count; i++)
+ c->output->add (substitute[i]);
+ }
+
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
- if (unlikely (!substitute.len)) return TRACE_RETURN (false);
+ TRACE_APPLY (this);
+ unsigned int count = substitute.len;
- unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0;
- c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array, klass);
+ /* TODO:
+ * Testing shows that Uniscribe actually allows zero-len susbstitute,
+ * which essentially deletes a glyph. We don't allow for now. It
+ * can be confusing to the client since the cluster from the deleted
+ * glyph won't be merged with any output cluster... Also, currently
+ * buffer->move_to() makes assumptions about this too. Perhaps fix
+ * in the future after figuring out what to do with the clusters.
+ */
+ if (unlikely (!count)) return TRACE_RETURN (false);
+
+ /* Special-case to make it in-place and not consider this
+ * as a "multiplied" substitution. */
+ if (unlikely (count == 1))
+ {
+ c->replace_glyph (substitute.array[0]);
+ return TRACE_RETURN (true);
+ }
+
+ unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
+ HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+
+ for (unsigned int i = 0; i < count; i++) {
+ _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+ c->output_glyph_for_component (substitute.array[i], klass);
+ }
+ c->buffer->skip_glyph ();
return TRACE_RETURN (true);
}
- public:
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (substitute.sanitize (c));
}
- private:
+ protected:
ArrayOf<GlyphID>
substitute; /* String of GlyphIDs to substitute */
public:
@@ -233,13 +320,9 @@ struct Sequence
struct MultipleSubstFormat1
{
- friend struct MultipleSubst;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
if (c->glyphs->has (iter.get_glyph ()))
@@ -247,27 +330,61 @@ struct MultipleSubstFormat1
}
}
- inline bool would_apply (hb_codepoint_t glyph_id) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- return (this+coverage) (glyph_id) != NOT_COVERED;
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+ unsigned int count = sequence.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+sequence[i]).collect_glyphs (c);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+ return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
return TRACE_RETURN ((this+sequence[index]).apply (c));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<unsigned int> &substitute_len_list,
+ unsigned int num_glyphs,
+ Supplier<GlyphID> &substitute_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
+ for (unsigned int i = 0; i < num_glyphs; i++)
+ if (unlikely (!sequence[i].serialize (c, this).serialize (c,
+ substitute_glyphs_list,
+ substitute_len_list[i]))) return TRACE_RETURN (false);
+ substitute_len_list.advance (num_glyphs);
+ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -281,46 +398,34 @@ struct MultipleSubstFormat1
struct MultipleSubst
{
- friend struct SubstLookupSubTable;
-
- private:
-
- inline void closure (hb_closure_context_t *c) const
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<unsigned int> &substitute_len_list,
+ unsigned int num_glyphs,
+ Supplier<GlyphID> &substitute_glyphs_list)
{
- TRACE_CLOSURE ();
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+ unsigned int format = 1;
+ u.format.set (format);
switch (u.format) {
- case 1: u.format1.closure (c); break;
- default: break;
- }
- }
-
- inline bool would_apply (hb_codepoint_t glyph_id) const
- {
- switch (u.format) {
- case 1: return u.format1.would_apply (glyph_id);
- default:return false;
- }
- }
-
- inline bool apply (hb_apply_context_t *c) const
- {
- TRACE_APPLY ();
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
+ case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
default:return TRACE_RETURN (false);
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
MultipleSubstFormat1 format1;
@@ -333,13 +438,9 @@ typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
struct AlternateSubstFormat1
{
- friend struct AlternateSubst;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
if (c->glyphs->has (iter.get_glyph ())) {
@@ -351,17 +452,36 @@ struct AlternateSubstFormat1
}
}
- inline bool would_apply (hb_codepoint_t glyph_id) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- return (this+coverage) (glyph_id) != NOT_COVERED;
+ TRACE_COLLECT_GLYPHS (this);
+ Coverage::Iter iter;
+ for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ c->input->add (iter.get_glyph ());
+ const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
+ unsigned int count = alt_set.len;
+ for (unsigned int i = 0; i < count; i++)
+ c->output->add (alt_set[i]);
+ }
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+ return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
}
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage) (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
const AlternateSet &alt_set = this+alternateSet[index];
@@ -384,12 +504,31 @@ struct AlternateSubstFormat1
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<unsigned int> &alternate_len_list,
+ unsigned int num_glyphs,
+ Supplier<GlyphID> &alternate_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
+ for (unsigned int i = 0; i < num_glyphs; i++)
+ if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
+ alternate_glyphs_list,
+ alternate_len_list[i]))) return TRACE_RETURN (false);
+ alternate_len_list.advance (num_glyphs);
+ if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -403,46 +542,34 @@ struct AlternateSubstFormat1
struct AlternateSubst
{
- friend struct SubstLookupSubTable;
-
- private:
-
- inline void closure (hb_closure_context_t *c) const
- {
- TRACE_CLOSURE ();
- switch (u.format) {
- case 1: u.format1.closure (c); break;
- default: break;
- }
- }
-
- inline bool would_apply (hb_codepoint_t glyph_id) const
- {
- switch (u.format) {
- case 1: return u.format1.would_apply (glyph_id);
- default:return false;
- }
- }
-
- inline bool apply (hb_apply_context_t *c) const
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &glyphs,
+ Supplier<unsigned int> &alternate_len_list,
+ unsigned int num_glyphs,
+ Supplier<GlyphID> &alternate_glyphs_list)
{
- TRACE_APPLY ();
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+ unsigned int format = 1;
+ u.format.set (format);
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
+ case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
default:return TRACE_RETURN (false);
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
AlternateSubstFormat1 format1;
@@ -452,13 +579,9 @@ struct AlternateSubst
struct Ligature
{
- friend struct LigatureSet;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
unsigned int count = component.len;
for (unsigned int i = 1; i < count; i++)
if (!c->glyphs->has (component[i]))
@@ -466,78 +589,90 @@ struct Ligature
c->glyphs->add (ligGlyph);
}
- inline bool would_apply (hb_codepoint_t second) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- return component.len == 2 && component[1] == second;
+ TRACE_COLLECT_GLYPHS (this);
+ unsigned int count = component.len;
+ for (unsigned int i = 1; i < count; i++)
+ c->input->add (component[i]);
+ c->output->add (ligGlyph);
}
- inline bool apply (hb_apply_context_t *c) const
+ inline bool would_apply (hb_would_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int count = component.len;
- if (unlikely (count < 2)) return TRACE_RETURN (false);
-
- hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
+ TRACE_WOULD_APPLY (this);
+ if (c->len != component.len)
+ return TRACE_RETURN (false);
- bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
- bool found_non_mark = false;
+ for (unsigned int i = 1; i < c->len; i++)
+ if (likely (c->glyphs[i] != component[i]))
+ return TRACE_RETURN (false);
- for (unsigned int i = 1; i < count; i++)
- {
- unsigned int property;
+ return TRACE_RETURN (true);
+ }
- if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int count = component.len;
- found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
+ if (unlikely (!count)) return TRACE_RETURN (false);
- if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return TRACE_RETURN (false);
+ /* Special-case to make it in-place and not consider this
+ * as a "ligated" substitution. */
+ if (unlikely (count == 1))
+ {
+ c->replace_glyph (ligGlyph);
+ return TRACE_RETURN (true);
}
- unsigned int klass = first_was_mark && found_non_mark ? HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE : 0;
-
- /* Allocate new ligature id */
- unsigned int lig_id = allocate_lig_id (c->buffer);
- set_lig_props (c->buffer->cur(), lig_id, 0);
+ bool is_mark_ligature = false;
+ unsigned int total_component_count = 0;
- if (skippy_iter.idx < c->buffer->idx + count) /* No input glyphs skipped */
- {
- c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph, klass);
- }
- else
- {
- c->replace_glyph (ligGlyph);
+ unsigned int match_length = 0;
+ unsigned int match_positions[MAX_CONTEXT_LENGTH];
- /* Now we must do a second loop to copy the skipped glyphs to
- `out' and assign component values to it. We start with the
- glyph after the first component. Glyphs between component
- i and i+1 belong to component i. Together with the lig_id
- value it is later possible to check whether a specific
- component value really belongs to a given ligature. */
+ if (likely (!match_input (c, count,
+ &component[1],
+ match_glyph,
+ NULL,
+ &match_length,
+ match_positions,
+ &is_mark_ligature,
+ &total_component_count)))
+ return TRACE_RETURN (false);
- for (unsigned int i = 1; i < count; i++)
- {
- while (c->should_mark_skip_current_glyph ())
- {
- set_lig_props (c->buffer->cur(), lig_id, i);
- c->replace_glyph (c->buffer->cur().codepoint);
- }
+ ligate_input (c,
+ count,
+ match_positions,
+ match_length,
+ ligGlyph,
+ is_mark_ligature,
+ total_component_count);
- /* Skip the base glyph */
- c->buffer->idx++;
- }
- }
+ return TRACE_RETURN (true);
+ }
+ inline bool serialize (hb_serialize_context_t *c,
+ GlyphID ligature,
+ Supplier<GlyphID> &components, /* Starting from second */
+ unsigned int num_components /* Including first component */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ ligGlyph = ligature;
+ if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
return TRACE_RETURN (true);
}
public:
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
}
- private:
+ protected:
GlyphID ligGlyph; /* GlyphID of ligature to substitute */
HeadlessArrayOf<GlyphID>
component; /* Array of component GlyphIDs--start
@@ -549,33 +684,38 @@ struct Ligature
struct LigatureSet
{
- friend struct LigatureSubstFormat1;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
unsigned int num_ligs = ligature.len;
for (unsigned int i = 0; i < num_ligs; i++)
(this+ligature[i]).closure (c);
}
- inline bool would_apply (hb_codepoint_t second) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ unsigned int num_ligs = ligature.len;
+ for (unsigned int i = 0; i < num_ligs; i++)
+ (this+ligature[i]).collect_glyphs (c);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
{
+ TRACE_WOULD_APPLY (this);
unsigned int num_ligs = ligature.len;
for (unsigned int i = 0; i < num_ligs; i++)
{
const Ligature &lig = this+ligature[i];
- if (lig.would_apply (second))
- return true;
+ if (lig.would_apply (c))
+ return TRACE_RETURN (true);
}
- return false;
+ return TRACE_RETURN (false);
}
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
unsigned int num_ligs = ligature.len;
for (unsigned int i = 0; i < num_ligs; i++)
{
@@ -586,13 +726,32 @@ struct LigatureSet
return TRACE_RETURN (false);
}
- public:
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &ligatures,
+ Supplier<unsigned int> &component_count_list,
+ unsigned int num_ligatures,
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
+ for (unsigned int i = 0; i < num_ligatures; i++)
+ if (unlikely (!ligature[i].serialize (c, this).serialize (c,
+ ligatures[i],
+ component_list,
+ component_count_list[i]))) return TRACE_RETURN (false);
+ ligatures.advance (num_ligatures);
+ component_count_list.advance (num_ligatures);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (ligature.sanitize (c, this));
}
- private:
+ protected:
OffsetArrayOf<Ligature>
ligature; /* Array LigatureSet tables
* ordered by preference */
@@ -602,13 +761,9 @@ struct LigatureSet
struct LigatureSubstFormat1
{
- friend struct LigatureSubst;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
Coverage::Iter iter;
for (iter.init (this+coverage); iter.more (); iter.next ()) {
if (c->glyphs->has (iter.get_glyph ()))
@@ -616,31 +771,72 @@ struct LigatureSubstFormat1
}
}
- inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- unsigned int index;
- return (index = (this+coverage) (first)) != NOT_COVERED &&
- (this+ligatureSet[index]).would_apply (second);
+ TRACE_COLLECT_GLYPHS (this);
+ Coverage::Iter iter;
+ for (iter.init (this+coverage); iter.more (); iter.next ()) {
+ c->input->add (iter.get_glyph ());
+ (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
+ }
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
+ if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+
+ const LigatureSet &lig_set = this+ligatureSet[index];
+ return TRACE_RETURN (lig_set.would_apply (c));
}
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
- unsigned int index = (this+coverage) (glyph_id);
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
const LigatureSet &lig_set = this+ligatureSet[index];
return TRACE_RETURN (lig_set.apply (c));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &first_glyphs,
+ Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+ unsigned int num_first_glyphs,
+ Supplier<GlyphID> &ligatures_list,
+ Supplier<unsigned int> &component_count_list,
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
+ if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
+ for (unsigned int i = 0; i < num_first_glyphs; i++)
+ if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
+ ligatures_list,
+ component_count_list,
+ ligature_per_first_glyph_count_list[i],
+ component_list))) return TRACE_RETURN (false);
+ ligature_per_first_glyph_count_list.advance (num_first_glyphs);
+ if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
+ return TRACE_RETURN (true);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -654,46 +850,37 @@ struct LigatureSubstFormat1
struct LigatureSubst
{
- friend struct SubstLookupSubTable;
-
- private:
-
- inline void closure (hb_closure_context_t *c) const
- {
- TRACE_CLOSURE ();
- switch (u.format) {
- case 1: u.format1.closure (c); break;
- default: break;
- }
- }
-
- inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
+ inline bool serialize (hb_serialize_context_t *c,
+ Supplier<GlyphID> &first_glyphs,
+ Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+ unsigned int num_first_glyphs,
+ Supplier<GlyphID> &ligatures_list,
+ Supplier<unsigned int> &component_count_list,
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
{
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
+ unsigned int format = 1;
+ u.format.set (format);
switch (u.format) {
- case 1: return u.format1.would_apply (first, second);
- default:return false;
- }
- }
-
- inline bool apply (hb_apply_context_t *c) const
- {
- TRACE_APPLY ();
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
+ case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
+ ligatures_list, component_count_list, component_list));
default:return TRACE_RETURN (false);
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
LigatureSubstFormat1 format1;
@@ -701,68 +888,13 @@ struct LigatureSubst
};
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
-
-struct ContextSubst : Context
-{
- friend struct SubstLookupSubTable;
-
- private:
-
- inline void closure (hb_closure_context_t *c) const
- {
- TRACE_CLOSURE ();
- return Context::closure (c, closure_lookup);
- }
+struct ContextSubst : Context {};
- inline bool apply (hb_apply_context_t *c) const
- {
- TRACE_APPLY ();
- return TRACE_RETURN (Context::apply (c, substitute_lookup));
- }
-};
+struct ChainContextSubst : ChainContext {};
-struct ChainContextSubst : ChainContext
+struct ExtensionSubst : Extension<ExtensionSubst>
{
- friend struct SubstLookupSubTable;
-
- private:
-
- inline void closure (hb_closure_context_t *c) const
- {
- TRACE_CLOSURE ();
- return ChainContext::closure (c, closure_lookup);
- }
-
- inline bool apply (hb_apply_context_t *c) const
- {
- TRACE_APPLY ();
- return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
- }
-};
-
-
-struct ExtensionSubst : Extension
-{
- friend struct SubstLookupSubTable;
- friend struct SubstLookup;
-
- private:
- inline const struct SubstLookupSubTable& get_subtable (void) const
- {
- unsigned int offset = get_offset ();
- if (unlikely (!offset)) return Null(SubstLookupSubTable);
- return StructAtOffset<SubstLookupSubTable> (this, offset);
- }
-
- inline void closure (hb_closure_context_t *c) const;
- inline bool would_apply (hb_codepoint_t glyph_id) const;
- inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const;
-
- inline bool apply (hb_apply_context_t *c) const;
-
- inline bool sanitize (hb_sanitize_context_t *c);
+ typedef struct SubstLookupSubTable LookupSubTable;
inline bool is_reverse (void) const;
};
@@ -770,13 +902,9 @@ struct ExtensionSubst : Extension
struct ReverseChainSingleSubstFormat1
{
- friend struct ReverseChainSingleSubst;
-
- private:
-
inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
unsigned int count;
@@ -799,13 +927,48 @@ struct ReverseChainSingleSubstFormat1
}
}
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+ unsigned int count;
+
+ (this+coverage).add_coverage (c->input);
+
+ count = backtrack.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+backtrack[i]).add_coverage (c->before);
+
+ count = lookahead.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+lookahead[i]).add_coverage (c->after);
+
+ const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+ count = substitute.len;
+ for (unsigned int i = 0; i < count; i++)
+ c->output->add (substitute[i]);
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+ return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
+ }
+
inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
return TRACE_RETURN (false); /* No chaining to this type */
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
@@ -819,26 +982,29 @@ struct ReverseChainSingleSubstFormat1
match_coverage, this,
1))
{
- c->buffer->cur().codepoint = substitute[index];
- c->buffer->idx--; /* Reverse! */
+ c->replace_glyph_inplace (substitute[index]);
+ /* Note: We DON'T decrease buffer->idx. The main loop does it
+ * for us. This is useful for preventing surprises if someone
+ * calls us through a Context lookup. */
return TRACE_RETURN (true);
}
return TRACE_RETURN (false);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return TRACE_RETURN (false);
- OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
if (!lookahead.sanitize (c, this))
return TRACE_RETURN (false);
- ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+ const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
return TRACE_RETURN (substitute.sanitize (c));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -860,38 +1026,18 @@ struct ReverseChainSingleSubstFormat1
struct ReverseChainSingleSubst
{
- friend struct SubstLookupSubTable;
-
- private:
-
- inline void closure (hb_closure_context_t *c) const
- {
- TRACE_CLOSURE ();
- switch (u.format) {
- case 1: u.format1.closure (c); break;
- default: break;
- }
- }
-
- inline bool apply (hb_apply_context_t *c) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c));
- default:return TRACE_RETURN (false);
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT format; /* Format identifier */
ReverseChainSingleSubstFormat1 format1;
@@ -919,84 +1065,33 @@ struct SubstLookupSubTable
ReverseChainSingle = 8
};
- inline void closure (hb_closure_context_t *c,
- unsigned int lookup_type) const
- {
- TRACE_CLOSURE ();
- switch (lookup_type) {
- case Single: u.single.closure (c); break;
- case Multiple: u.multiple.closure (c); break;
- case Alternate: u.alternate.closure (c); break;
- case Ligature: u.ligature.closure (c); break;
- case Context: u.c.closure (c); break;
- case ChainContext: u.chainContext.closure (c); break;
- case Extension: u.extension.closure (c); break;
- case ReverseChainSingle: u.reverseChainContextSingle.closure (c); break;
- default: break;
- }
- }
-
- inline bool would_apply (hb_codepoint_t glyph_id,
- unsigned int lookup_type) const
- {
- switch (lookup_type) {
- case Single: return u.single.would_apply (glyph_id);
- case Multiple: return u.multiple.would_apply (glyph_id);
- case Alternate: return u.alternate.would_apply (glyph_id);
- case Extension: return u.extension.would_apply (glyph_id);
- default: return false;
- }
- }
- inline bool would_apply (hb_codepoint_t first,
- hb_codepoint_t second,
- unsigned int lookup_type) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
{
+ TRACE_DISPATCH (this, lookup_type);
+ /* The sub_format passed to may_dispatch is unnecessary but harmless. */
+ if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
switch (lookup_type) {
- case Ligature: return u.ligature.would_apply (first, second);
- case Extension: return u.extension.would_apply (first, second);
- default: return false;
+ case Single: return TRACE_RETURN (u.single.dispatch (c));
+ case Multiple: return TRACE_RETURN (u.multiple.dispatch (c));
+ case Alternate: return TRACE_RETURN (u.alternate.dispatch (c));
+ case Ligature: return TRACE_RETURN (u.ligature.dispatch (c));
+ case Context: return TRACE_RETURN (u.context.dispatch (c));
+ case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c));
+ case Extension: return TRACE_RETURN (u.extension.dispatch (c));
+ case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
+ default: return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
- {
- TRACE_APPLY ();
- switch (lookup_type) {
- case Single: return TRACE_RETURN (u.single.apply (c));
- case Multiple: return TRACE_RETURN (u.multiple.apply (c));
- case Alternate: return TRACE_RETURN (u.alternate.apply (c));
- case Ligature: return TRACE_RETURN (u.ligature.apply (c));
- case Context: return TRACE_RETURN (u.c.apply (c));
- case ChainContext: return TRACE_RETURN (u.chainContext.apply (c));
- case Extension: return TRACE_RETURN (u.extension.apply (c));
- case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
- default: return TRACE_RETURN (false);
- }
- }
-
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
- TRACE_SANITIZE ();
- switch (lookup_type) {
- case Single: return TRACE_RETURN (u.single.sanitize (c));
- case Multiple: return TRACE_RETURN (u.multiple.sanitize (c));
- case Alternate: return TRACE_RETURN (u.alternate.sanitize (c));
- case Ligature: return TRACE_RETURN (u.ligature.sanitize (c));
- case Context: return TRACE_RETURN (u.c.sanitize (c));
- case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
- case Extension: return TRACE_RETURN (u.extension.sanitize (c));
- case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
- default: return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT sub_format;
SingleSubst single;
MultipleSubst multiple;
AlternateSubst alternate;
LigatureSubst ligature;
- ContextSubst c;
+ ContextSubst context;
ChainContextSubst chainContext;
ExtensionSubst extension;
ReverseChainSingleSubst reverseChainContextSingle;
@@ -1009,7 +1104,7 @@ struct SubstLookupSubTable
struct SubstLookup : Lookup
{
inline const SubstLookupSubTable& get_subtable (unsigned int i) const
- { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
+ { return Lookup::get_subtable<SubstLookupSubTable> (i); }
inline static bool lookup_type_is_reverse (unsigned int lookup_type)
{ return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
@@ -1022,110 +1117,126 @@ struct SubstLookup : Lookup
return lookup_type_is_reverse (type);
}
- inline void closure (hb_closure_context_t *c) const
+ inline bool apply (hb_apply_context_t *c) const
{
- unsigned int lookup_type = get_type ();
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++)
- get_subtable (i).closure (c, lookup_type);
+ TRACE_APPLY (this);
+ return TRACE_RETURN (dispatch (c));
}
- inline bool would_apply (hb_codepoint_t glyph_id) const
+ inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
{
- unsigned int lookup_type = get_type ();
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++)
- if (get_subtable (i).would_apply (glyph_id, lookup_type))
- return true;
- return false;
+ TRACE_CLOSURE (this);
+ c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
+ return TRACE_RETURN (dispatch (c));
}
- inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const
+
+ inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{
- unsigned int lookup_type = get_type ();
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++)
- if (get_subtable (i).would_apply (first, second, lookup_type))
- return true;
- return false;
+ TRACE_COLLECT_GLYPHS (this);
+ c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
+ return TRACE_RETURN (dispatch (c));
}
- inline bool apply_once (hb_apply_context_t *c) const
+ template <typename set_t>
+ inline void add_coverage (set_t *glyphs) const
{
- unsigned int lookup_type = get_type ();
+ hb_add_coverage_context_t<set_t> c (glyphs);
+ dispatch (&c);
+ }
- if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property))
- return false;
+ inline bool would_apply (hb_would_apply_context_t *c,
+ const hb_ot_layout_lookup_accelerator_t *accel) const
+ {
+ TRACE_WOULD_APPLY (this);
+ if (unlikely (!c->len)) return TRACE_RETURN (false);
+ if (!accel->may_have (c->glyphs[0])) return TRACE_RETURN (false);
+ return TRACE_RETURN (dispatch (c));
+ }
- if (unlikely (lookup_type == SubstLookupSubTable::Extension))
- {
- /* The spec says all subtables should have the same type.
- * This is specially important if one has a reverse type!
- *
- * This is rather slow to do this here for every glyph,
- * but it's easiest, and who uses extension lookups anyway?!*/
- unsigned int type = get_subtable(0).u.extension.get_type ();
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 1; i < count; i++)
- if (get_subtable(i).u.extension.get_type () != type)
- return false;
- }
+ static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++)
- if (get_subtable (i).apply (c, lookup_type))
- return true;
+ inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
+ unsigned int i)
+ { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
- return false;
+ inline bool serialize_single (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ Supplier<GlyphID> &glyphs,
+ Supplier<GlyphID> &substitutes,
+ unsigned int num_glyphs)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
+ return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
}
- inline bool apply_string (hb_apply_context_t *c) const
+ inline bool serialize_multiple (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ Supplier<GlyphID> &glyphs,
+ Supplier<unsigned int> &substitute_len_list,
+ unsigned int num_glyphs,
+ Supplier<GlyphID> &substitute_glyphs_list)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
+ return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
+ substitute_glyphs_list));
+ }
+
+ inline bool serialize_alternate (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ Supplier<GlyphID> &glyphs,
+ Supplier<unsigned int> &alternate_len_list,
+ unsigned int num_glyphs,
+ Supplier<GlyphID> &alternate_glyphs_list)
{
- bool ret = false;
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
+ return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
+ alternate_glyphs_list));
+ }
+
+ inline bool serialize_ligature (hb_serialize_context_t *c,
+ uint32_t lookup_props,
+ Supplier<GlyphID> &first_glyphs,
+ Supplier<unsigned int> &ligature_per_first_glyph_count_list,
+ unsigned int num_first_glyphs,
+ Supplier<GlyphID> &ligatures_list,
+ Supplier<unsigned int> &component_count_list,
+ Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
+ return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
+ ligatures_list, component_count_list, component_list));
+ }
- if (unlikely (!c->buffer->len))
- return false;
+ template <typename context_t>
+ static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
- c->set_lookup (*this);
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ { return Lookup::dispatch<SubstLookupSubTable> (c); }
- if (likely (!is_reverse ()))
- {
- /* in/out forward substitution */
- c->buffer->clear_output ();
- c->buffer->idx = 0;
- while (c->buffer->idx < c->buffer->len)
- {
- if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
- ret = true;
- else
- c->buffer->next_glyph ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
+ const OffsetArrayOf<SubstLookupSubTable> &list = get_subtables<SubstLookupSubTable> ();
+ if (unlikely (!dispatch (c))) return TRACE_RETURN (false);
- }
- if (ret)
- c->buffer->swap_buffers ();
- }
- else
+ if (unlikely (get_type () == SubstLookupSubTable::Extension))
{
- /* in-place backward substitution */
- c->buffer->idx = c->buffer->len - 1;
- do
- {
- if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
- ret = true;
- else
- c->buffer->idx--;
-
- }
- while ((int) c->buffer->idx >= 0);
+ /* The spec says all subtables of an Extension lookup should
+ * have the same type. This is specially important if one has
+ * a reverse type! */
+ unsigned int type = get_subtable (0).u.extension.get_type ();
+ unsigned int count = get_subtable_count ();
+ for (unsigned int i = 1; i < count; i++)
+ if (get_subtable (i).u.extension.get_type () != type)
+ return TRACE_RETURN (false);
}
-
- return ret;
- }
-
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
- OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
- return TRACE_RETURN (list.sanitize (c, this, get_type ()));
+ return TRACE_RETURN (true);
}
};
@@ -1137,25 +1248,19 @@ typedef OffsetListOf<SubstLookup> SubstLookupList;
struct GSUB : GSUBGPOS
{
- static const hb_tag_t Tag = HB_OT_TAG_GSUB;
+ static const hb_tag_t tableTag = HB_OT_TAG_GSUB;
inline const SubstLookup& get_lookup (unsigned int i) const
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
- inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const
- { return get_lookup (lookup_index).apply_string (c); }
-
- static inline void substitute_start (hb_buffer_t *buffer);
- static inline void substitute_finish (hb_buffer_t *buffer);
+ static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
- inline void closure_lookup (hb_closure_context_t *c,
- unsigned int lookup_index) const
- { return get_lookup (lookup_index).closure (c); }
-
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
- OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
+ const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
return TRACE_RETURN (list.sanitize (c, this));
}
public:
@@ -1164,90 +1269,57 @@ struct GSUB : GSUBGPOS
void
-GSUB::substitute_start (hb_buffer_t *buffer)
+GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
{
- HB_BUFFER_ALLOCATE_VAR (buffer, props_cache);
- HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
- HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
+ _hb_buffer_assert_gsubgpos_vars (buffer);
+ const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
- buffer->info[i].props_cache() = buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
+ {
+ _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
+ _hb_glyph_info_clear_lig_props (&buffer->info[i]);
+ buffer->info[i].syllable() = 0;
+ }
}
void
-GSUB::substitute_finish (hb_buffer_t *buffer HB_UNUSED)
+GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
{
}
/* Out-of-class implementation for methods recursing */
-inline void ExtensionSubst::closure (hb_closure_context_t *c) const
-{
- get_subtable ().closure (c, get_type ());
-}
-
-inline bool ExtensionSubst::would_apply (hb_codepoint_t glyph_id) const
-{
- return get_subtable ().would_apply (glyph_id, get_type ());
-}
-
-inline bool ExtensionSubst::would_apply (hb_codepoint_t first, hb_codepoint_t second) const
-{
- return get_subtable ().would_apply (first, second, get_type ());
-}
-
-inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
-{
- TRACE_APPLY ();
- return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
-}
-
-inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
-{
- TRACE_SANITIZE ();
- if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
- unsigned int offset = get_offset ();
- if (unlikely (!offset)) return TRACE_RETURN (true);
- return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
-}
-
-inline bool ExtensionSubst::is_reverse (void) const
+/*static*/ inline bool ExtensionSubst::is_reverse (void) const
{
unsigned int type = get_type ();
if (unlikely (type == SubstLookupSubTable::Extension))
- return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
+ return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
return SubstLookup::lookup_type_is_reverse (type);
}
-static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
+template <typename context_t>
+/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
{
- const GSUB &gsub = *(c->face->ot_layout->gsub);
+ const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
const SubstLookup &l = gsub.get_lookup (lookup_index);
-
- if (unlikely (c->nesting_level_left == 0))
- return;
-
- c->nesting_level_left--;
- l.closure (c);
- c->nesting_level_left++;
+ return l.dispatch (c);
}
-static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
{
- const GSUB &gsub = *(c->face->ot_layout->gsub);
+ const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
const SubstLookup &l = gsub.get_lookup (lookup_index);
-
- if (unlikely (c->nesting_level_left == 0))
- return false;
-
- hb_apply_context_t new_c (*c);
- new_c.nesting_level_left--;
- new_c.set_lookup (l);
- return l.apply_once (&new_c);
+ unsigned int saved_lookup_props = c->lookup_props;
+ c->set_lookup (l);
+ bool ret = l.dispatch (c);
+ c->set_lookup_props (saved_lookup_props);
+ return ret;
}
+} /* namespace OT */
+
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 12cb694..cbc6840 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -31,231 +31,599 @@
#include "hb-buffer-private.hh"
#include "hb-ot-layout-gdef-table.hh"
+#include "hb-set-private.hh"
-
-/* unique ligature id */
-/* component number in the ligature (0 = base) */
-static inline void
-set_lig_props (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp)
-{
- info.lig_props() = (lig_id << 4) | (lig_comp & 0x0F);
-}
-static inline unsigned int
-get_lig_id (hb_glyph_info_t &info)
-{
- return info.lig_props() >> 4;
-}
-static inline unsigned int
-get_lig_comp (hb_glyph_info_t &info)
-{
- return info.lig_props() & 0x0F;
-}
-
-static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
- uint8_t lig_id = buffer->next_serial () & 0x0F;
- if (unlikely (!lig_id))
- lig_id = allocate_lig_id (buffer); /* in case of overflow */
- return lig_id;
-}
-
+namespace OT {
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif
-#define TRACE_CLOSURE() \
- hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
-
-
-/* TODO Add TRACE_RETURN annotation for would_apply */
-
+#define TRACE_CLOSURE(this) \
+ hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "");
struct hb_closure_context_t
{
+ inline const char *get_name (void) { return "CLOSURE"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
+ typedef hb_void_t return_t;
+ typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
+ static return_t default_return_value (void) { return HB_VOID; }
+ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+ return_t recurse (unsigned int lookup_index)
+ {
+ if (unlikely (nesting_level_left == 0 || !recurse_func))
+ return default_return_value ();
+
+ nesting_level_left--;
+ recurse_func (this, lookup_index);
+ nesting_level_left++;
+ return HB_VOID;
+ }
+
hb_face_t *face;
hb_set_t *glyphs;
+ recurse_func_t recurse_func;
unsigned int nesting_level_left;
unsigned int debug_depth;
-
hb_closure_context_t (hb_face_t *face_,
hb_set_t *glyphs_,
unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
- face (face_), glyphs (glyphs_),
+ face (face_),
+ glyphs (glyphs_),
+ recurse_func (NULL),
nesting_level_left (nesting_level_left_),
debug_depth (0) {}
+
+ void set_recurse_func (recurse_func_t func) { recurse_func = func; }
};
-#ifndef HB_DEBUG_APPLY
-#define HB_DEBUG_APPLY (HB_DEBUG+0)
+#ifndef HB_DEBUG_WOULD_APPLY
+#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
#endif
-#define TRACE_APPLY() \
- hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->cur().codepoint);
+#define TRACE_WOULD_APPLY(this) \
+ hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "%d glyphs", c->len);
+struct hb_would_apply_context_t
+{
+ inline const char *get_name (void) { return "WOULD_APPLY"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
+ typedef bool return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
+ static return_t default_return_value (void) { return false; }
+ bool stop_sublookup_iteration (return_t r) const { return r; }
+ hb_face_t *face;
+ const hb_codepoint_t *glyphs;
+ unsigned int len;
+ bool zero_context;
+ unsigned int debug_depth;
-struct hb_apply_context_t
+ hb_would_apply_context_t (hb_face_t *face_,
+ const hb_codepoint_t *glyphs_,
+ unsigned int len_,
+ bool zero_context_) :
+ face (face_),
+ glyphs (glyphs_),
+ len (len_),
+ zero_context (zero_context_),
+ debug_depth (0) {}
+};
+
+
+
+#ifndef HB_DEBUG_COLLECT_GLYPHS
+#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
+#endif
+
+#define TRACE_COLLECT_GLYPHS(this) \
+ hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "");
+
+struct hb_collect_glyphs_context_t
{
- hb_font_t *font;
+ inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
+ typedef hb_void_t return_t;
+ typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
+ static return_t default_return_value (void) { return HB_VOID; }
+ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+ return_t recurse (unsigned int lookup_index)
+ {
+ if (unlikely (nesting_level_left == 0 || !recurse_func))
+ return default_return_value ();
+
+ /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
+ * past the previous check. For GSUB, we only want to collect the output
+ * glyphs in the recursion. If output is not requested, we can go home now.
+ *
+ * Note further, that the above is not exactly correct. A recursed lookup
+ * is allowed to match input that is not matched in the context, but that's
+ * not how most fonts are built. It's possible to relax that and recurse
+ * with all sets here if it proves to be an issue.
+ */
+
+ if (output == hb_set_get_empty ())
+ return HB_VOID;
+
+ /* Return if new lookup was recursed to before. */
+ if (recursed_lookups.has (lookup_index))
+ return HB_VOID;
+
+ hb_set_t *old_before = before;
+ hb_set_t *old_input = input;
+ hb_set_t *old_after = after;
+ before = input = after = hb_set_get_empty ();
+
+ nesting_level_left--;
+ recurse_func (this, lookup_index);
+ nesting_level_left++;
+
+ before = old_before;
+ input = old_input;
+ after = old_after;
+
+ recursed_lookups.add (lookup_index);
+
+ return HB_VOID;
+ }
+
hb_face_t *face;
- hb_buffer_t *buffer;
- hb_direction_t direction;
- hb_mask_t lookup_mask;
+ hb_set_t *before;
+ hb_set_t *input;
+ hb_set_t *after;
+ hb_set_t *output;
+ recurse_func_t recurse_func;
+ hb_set_t recursed_lookups;
unsigned int nesting_level_left;
- unsigned int lookup_props;
- unsigned int property; /* propety of first glyph */
unsigned int debug_depth;
+ hb_collect_glyphs_context_t (hb_face_t *face_,
+ hb_set_t *glyphs_before, /* OUT. May be NULL */
+ hb_set_t *glyphs_input, /* OUT. May be NULL */
+ hb_set_t *glyphs_after, /* OUT. May be NULL */
+ hb_set_t *glyphs_output, /* OUT. May be NULL */
+ unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
+ face (face_),
+ before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
+ input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
+ after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
+ output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
+ recurse_func (NULL),
+ recursed_lookups (),
+ nesting_level_left (nesting_level_left_),
+ debug_depth (0)
+ {
+ recursed_lookups.init ();
+ }
+ ~hb_collect_glyphs_context_t (void)
+ {
+ recursed_lookups.fini ();
+ }
- hb_apply_context_t (hb_font_t *font_,
- hb_face_t *face_,
- hb_buffer_t *buffer_,
- hb_mask_t lookup_mask_) :
- font (font_), face (face_), buffer (buffer_),
- direction (buffer_->props.direction),
- lookup_mask (lookup_mask_),
- nesting_level_left (MAX_NESTING_LEVEL),
- lookup_props (0), property (0), debug_depth (0) {}
+ void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+};
+
+
+
+#ifndef HB_DEBUG_GET_COVERAGE
+#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
+#endif
- void set_lookup (const Lookup &l) {
- lookup_props = l.get_props ();
+template <typename set_t>
+struct hb_add_coverage_context_t
+{
+ inline const char *get_name (void) { return "GET_COVERAGE"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE;
+ typedef const Coverage &return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
+ static return_t default_return_value (void) { return Null(Coverage); }
+ bool stop_sublookup_iteration (return_t r) const
+ {
+ r.add_coverage (set);
+ return false;
}
- struct mark_skipping_forward_iterator_t
+ hb_add_coverage_context_t (set_t *set_) :
+ set (set_),
+ debug_depth (0) {}
+
+ set_t *set;
+ unsigned int debug_depth;
+};
+
+
+
+#ifndef HB_DEBUG_APPLY
+#define HB_DEBUG_APPLY (HB_DEBUG+0)
+#endif
+
+#define TRACE_APPLY(this) \
+ hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
+
+struct hb_apply_context_t
+{
+ struct matcher_t
{
- inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
- unsigned int start_index_,
- unsigned int num_items_,
- bool context_match = false)
- {
- c = c_;
- idx = start_index_;
- num_items = num_items_;
- mask = context_match ? -1 : c->lookup_mask;
- syllable = context_match ? 0 : c->buffer->cur().syllable ();
- end = c->buffer->len;
- }
- inline bool has_no_chance (void) const
- {
- return unlikely (num_items && idx + num_items >= end);
- }
- inline bool next (unsigned int *property_out,
- unsigned int lookup_props)
+ inline matcher_t (void) :
+ lookup_props (0),
+ ignore_zwnj (false),
+ ignore_zwj (false),
+ mask (-1),
+#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
+ syllable arg1(0),
+#undef arg1
+ match_func (NULL),
+ match_data (NULL) {};
+
+ typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+
+ inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
+ inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
+ inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
+ inline void set_mask (hb_mask_t mask_) { mask = mask_; }
+ inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
+ inline void set_match_func (match_func_t match_func_,
+ const void *match_data_)
+ { match_func = match_func_; match_data = match_data_; }
+
+ enum may_match_t {
+ MATCH_NO,
+ MATCH_YES,
+ MATCH_MAYBE
+ };
+
+ inline may_match_t may_match (const hb_glyph_info_t &info,
+ const USHORT *glyph_data) const
{
- assert (num_items > 0);
- do
- {
- if (has_no_chance ())
- return false;
- idx++;
- } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out));
- num_items--;
- return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
+ if (!(info.mask & mask) ||
+ (syllable && syllable != info.syllable ()))
+ return MATCH_NO;
+
+ if (match_func)
+ return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
+
+ return MATCH_MAYBE;
}
- inline bool next (unsigned int *property_out = NULL)
+
+ enum may_skip_t {
+ SKIP_NO,
+ SKIP_YES,
+ SKIP_MAYBE
+ };
+
+ inline may_skip_t
+ may_skip (const hb_apply_context_t *c,
+ const hb_glyph_info_t &info) const
{
- return next (property_out, c->lookup_props);
+ if (!c->check_glyph_property (&info, lookup_props))
+ return SKIP_YES;
+
+ if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
+ (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
+ (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
+ !_hb_glyph_info_ligated (&info)))
+ return SKIP_MAYBE;
+
+ return SKIP_NO;
}
- unsigned int idx;
- private:
- hb_apply_context_t *c;
- unsigned int num_items;
+ protected:
+ unsigned int lookup_props;
+ bool ignore_zwnj;
+ bool ignore_zwj;
hb_mask_t mask;
uint8_t syllable;
- unsigned int end;
+ match_func_t match_func;
+ const void *match_data;
};
- struct mark_skipping_backward_iterator_t
+ struct skipping_iterator_t
{
- inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_,
- unsigned int start_index_,
- unsigned int num_items_,
- hb_mask_t mask_ = 0,
- bool match_syllable_ = true)
+ inline void init (hb_apply_context_t *c_, bool context_match = false)
{
c = c_;
- idx = start_index_;
- num_items = num_items_;
- mask = mask_ ? mask_ : c->lookup_mask;
- syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
+ match_glyph_data = NULL,
+ matcher.set_match_func (NULL, NULL);
+ matcher.set_lookup_props (c->lookup_props);
+ /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
+ matcher.set_ignore_zwnj (context_match || c->table_index == 1);
+ /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
+ matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
+ matcher.set_mask (context_match ? -1 : c->lookup_mask);
}
- inline bool has_no_chance (void) const
+ inline void set_lookup_props (unsigned int lookup_props)
{
- return unlikely (idx < num_items);
+ matcher.set_lookup_props (lookup_props);
+ }
+ inline void set_match_func (matcher_t::match_func_t match_func,
+ const void *match_data,
+ const USHORT glyph_data[])
+ {
+ matcher.set_match_func (match_func, match_data);
+ match_glyph_data = glyph_data;
+ }
+
+ inline void reset (unsigned int start_index_,
+ unsigned int num_items_)
+ {
+ idx = start_index_;
+ num_items = num_items_;
+ end = c->buffer->len;
+ matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
}
- inline bool prev (unsigned int *property_out,
- unsigned int lookup_props)
+
+ inline void reject (void) { num_items++; match_glyph_data--; }
+
+ inline bool next (void)
{
assert (num_items > 0);
- do
+ while (idx + num_items < end)
{
- if (has_no_chance ())
+ idx++;
+ const hb_glyph_info_t &info = c->buffer->info[idx];
+
+ matcher_t::may_skip_t skip = matcher.may_skip (c, info);
+ if (unlikely (skip == matcher_t::SKIP_YES))
+ continue;
+
+ matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+ if (match == matcher_t::MATCH_YES ||
+ (match == matcher_t::MATCH_MAYBE &&
+ skip == matcher_t::SKIP_NO))
+ {
+ num_items--;
+ match_glyph_data++;
+ return true;
+ }
+
+ if (skip == matcher_t::SKIP_NO)
return false;
- idx--;
- } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out));
- num_items--;
- return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
+ }
+ return false;
}
- inline bool prev (unsigned int *property_out = NULL)
+ inline bool prev (void)
{
- return prev (property_out, c->lookup_props);
+ assert (num_items > 0);
+ while (idx >= num_items)
+ {
+ idx--;
+ const hb_glyph_info_t &info = c->buffer->out_info[idx];
+
+ matcher_t::may_skip_t skip = matcher.may_skip (c, info);
+ if (unlikely (skip == matcher_t::SKIP_YES))
+ continue;
+
+ matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
+ if (match == matcher_t::MATCH_YES ||
+ (match == matcher_t::MATCH_MAYBE &&
+ skip == matcher_t::SKIP_NO))
+ {
+ num_items--;
+ match_glyph_data++;
+ return true;
+ }
+
+ if (skip == matcher_t::SKIP_NO)
+ return false;
+ }
+ return false;
}
unsigned int idx;
- private:
+ protected:
hb_apply_context_t *c;
+ matcher_t matcher;
+ const USHORT *match_glyph_data;
+
unsigned int num_items;
- hb_mask_t mask;
- uint8_t syllable;
+ unsigned int end;
};
- inline bool should_mark_skip_current_glyph (void) const
+
+ inline const char *get_name (void) { return "APPLY"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+ typedef bool return_t;
+ typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.apply (this); }
+ static return_t default_return_value (void) { return false; }
+ bool stop_sublookup_iteration (return_t r) const { return r; }
+ return_t recurse (unsigned int lookup_index)
{
- return _hb_ot_layout_skip_mark (face, &buffer->cur(), lookup_props, NULL);
+ if (unlikely (nesting_level_left == 0 || !recurse_func))
+ return default_return_value ();
+
+ nesting_level_left--;
+ bool ret = recurse_func (this, lookup_index);
+ nesting_level_left++;
+ return ret;
}
+ unsigned int table_index; /* GSUB/GPOS */
+ hb_font_t *font;
+ hb_face_t *face;
+ hb_buffer_t *buffer;
+ hb_direction_t direction;
+ hb_mask_t lookup_mask;
+ bool auto_zwj;
+ recurse_func_t recurse_func;
+ unsigned int nesting_level_left;
+ unsigned int lookup_props;
+ const GDEF &gdef;
+ bool has_glyph_classes;
+ skipping_iterator_t iter_input, iter_context;
+ unsigned int debug_depth;
+
+ hb_apply_context_t (unsigned int table_index_,
+ hb_font_t *font_,
+ hb_buffer_t *buffer_) :
+ table_index (table_index_),
+ font (font_), face (font->face), buffer (buffer_),
+ direction (buffer_->props.direction),
+ lookup_mask (1),
+ auto_zwj (true),
+ recurse_func (NULL),
+ nesting_level_left (MAX_NESTING_LEVEL),
+ lookup_props (0),
+ gdef (*hb_ot_layout_from_face (face)->gdef),
+ has_glyph_classes (gdef.has_glyph_classes ()),
+ iter_input (),
+ iter_context (),
+ debug_depth (0) {}
+
+ inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
+ inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
+ inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+ inline void set_lookup (const Lookup &l) { set_lookup_props (l.get_props ()); }
+ inline void set_lookup_props (unsigned int lookup_props_)
+ {
+ lookup_props = lookup_props_;
+ iter_input.init (this, false);
+ iter_context.init (this, true);
+ }
- inline void replace_glyph (hb_codepoint_t glyph_index,
- unsigned int klass = 0) const
+ inline bool
+ match_properties_mark (hb_codepoint_t glyph,
+ unsigned int glyph_props,
+ unsigned int lookup_props) const
{
- buffer->cur().props_cache() = klass; /*XXX if has gdef? */
+ /* If using mark filtering sets, the high short of
+ * lookup_props has the set index.
+ */
+ if (lookup_props & LookupFlag::UseMarkFilteringSet)
+ return gdef.mark_set_covers (lookup_props >> 16, glyph);
+
+ /* The second byte of lookup_props has the meaning
+ * "ignore marks of attachment type different than
+ * the attachment type specified."
+ */
+ if (lookup_props & LookupFlag::MarkAttachmentType)
+ return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
+
+ return true;
+ }
+
+ inline bool
+ check_glyph_property (const hb_glyph_info_t *info,
+ unsigned int lookup_props) const
+ {
+ hb_codepoint_t glyph = info->codepoint;
+ unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
+
+ /* Not covered, if, for example, glyph class is ligature and
+ * lookup_props includes LookupFlags::IgnoreLigatures
+ */
+ if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
+ return false;
+
+ if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
+ return match_properties_mark (glyph, glyph_props, lookup_props);
+
+ return true;
+ }
+
+ inline void _set_glyph_props (hb_codepoint_t glyph_index,
+ unsigned int class_guess = 0,
+ bool ligature = false,
+ bool component = false) const
+ {
+ unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
+ HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
+ add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
+ if (ligature)
+ {
+ add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
+ /* In the only place that the MULTIPLIED bit is used, Uniscribe
+ * seems to only care about the "last" transformation between
+ * Ligature and Multiple substitions. Ie. if you ligate, expand,
+ * and ligate again, it forgives the multiplication and acts as
+ * if only ligation happened. As such, clear MULTIPLIED bit.
+ */
+ add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+ }
+ if (component)
+ add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
+ if (likely (has_glyph_classes))
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
+ else if (class_guess)
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
+ }
+
+ inline void replace_glyph (hb_codepoint_t glyph_index) const
+ {
+ _set_glyph_props (glyph_index);
+ buffer->replace_glyph (glyph_index);
+ }
+ inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
+ {
+ _set_glyph_props (glyph_index);
+ buffer->cur().codepoint = glyph_index;
+ }
+ inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
+ unsigned int class_guess) const
+ {
+ _set_glyph_props (glyph_index, class_guess, true);
buffer->replace_glyph (glyph_index);
}
- inline void replace_glyphs_be16 (unsigned int num_in,
- unsigned int num_out,
- const uint16_t *glyph_data_be,
- unsigned int klass = 0) const
+ inline void output_glyph_for_component (hb_codepoint_t glyph_index,
+ unsigned int class_guess) const
{
- buffer->cur().props_cache() = klass; /* XXX if has gdef? */
- buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be);
+ _set_glyph_props (glyph_index, class_guess, false, true);
+ buffer->output_glyph (glyph_index);
}
};
typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
+typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
-typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
-typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
struct ContextClosureFuncs
{
intersects_func_t intersects;
- closure_lookup_func_t closure;
+};
+struct ContextCollectGlyphsFuncs
+{
+ collect_glyphs_func_t collect;
};
struct ContextApplyFuncs
{
match_func_t match;
- apply_lookup_func_t apply;
};
+
static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
{
return glyphs->has (value);
@@ -284,48 +652,237 @@ static inline bool intersects_array (hb_closure_context_t *c,
}
+static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
+{
+ glyphs->add (value);
+}
+static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+ const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+ class_def.add_class (glyphs, value);
+}
+static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
+{
+ const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+ (data+coverage).add_coverage (glyphs);
+}
+static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
+ hb_set_t *glyphs,
+ unsigned int count,
+ const USHORT values[],
+ collect_glyphs_func_t collect_func,
+ const void *collect_data)
+{
+ for (unsigned int i = 0; i < count; i++)
+ collect_func (glyphs, values[i], collect_data);
+}
+
+
static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
{
return glyph_id == value;
}
-
static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
{
const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
return class_def.get_class (glyph_id) == value;
}
-
static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
{
const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
}
+static inline bool would_match_input (hb_would_apply_context_t *c,
+ unsigned int count, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ match_func_t match_func,
+ const void *match_data)
+{
+ if (count != c->len)
+ return false;
+ for (unsigned int i = 1; i < count; i++)
+ if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
+ return false;
+
+ return true;
+}
static inline bool match_input (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph (not matched) */
const USHORT input[], /* Array of input values--start with second glyph */
match_func_t match_func,
const void *match_data,
- unsigned int *end_offset = NULL)
+ unsigned int *end_offset,
+ unsigned int match_positions[MAX_CONTEXT_LENGTH],
+ bool *p_is_mark_ligature = NULL,
+ unsigned int *p_total_component_count = NULL)
{
- hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
- if (skippy_iter.has_no_chance ())
- return false;
+ TRACE_APPLY (NULL);
+
+ if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
+
+ hb_buffer_t *buffer = c->buffer;
+
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, count - 1);
+ skippy_iter.set_match_func (match_func, match_data, input);
+
+ /*
+ * This is perhaps the trickiest part of OpenType... Remarks:
+ *
+ * - If all components of the ligature were marks, we call this a mark ligature.
+ *
+ * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
+ * it as a ligature glyph.
+ *
+ * - Ligatures cannot be formed across glyphs attached to different components
+ * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
+ * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
+ * However, it would be wrong to ligate that SHADDA,FATHA sequence.o
+ * There is an exception to this: If a ligature tries ligating with marks that
+ * belong to it itself, go ahead, assuming that the font designer knows what
+ * they are doing (otherwise it can break Indic stuff when a matra wants to
+ * ligate with a conjunct...)
+ */
+
+ bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
+
+ unsigned int total_component_count = 0;
+ total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+ unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+ unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
+
+ match_positions[0] = buffer->idx;
for (unsigned int i = 1; i < count; i++)
{
- if (!skippy_iter.next ())
- return false;
+ if (!skippy_iter.next ()) return TRACE_RETURN (false);
+
+ match_positions[i] = skippy_iter.idx;
+
+ unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
+ unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
+
+ if (first_lig_id && first_lig_comp) {
+ /* If first component was attached to a previous ligature component,
+ * all subsequent components should be attached to the same ligature
+ * component, otherwise we shouldn't ligate them. */
+ if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
+ return TRACE_RETURN (false);
+ } else {
+ /* If first component was NOT attached to a previous ligature component,
+ * all subsequent components should also NOT be attached to any ligature
+ * component, unless they are attached to the first component itself! */
+ if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
+ return TRACE_RETURN (false);
+ }
- if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data)))
- return false;
+ is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
+ total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
}
- if (end_offset)
- *end_offset = skippy_iter.idx - c->buffer->idx + 1;
+ *end_offset = skippy_iter.idx - buffer->idx + 1;
- return true;
+ if (p_is_mark_ligature)
+ *p_is_mark_ligature = is_mark_ligature;
+
+ if (p_total_component_count)
+ *p_total_component_count = total_component_count;
+
+ return TRACE_RETURN (true);
+}
+static inline void ligate_input (hb_apply_context_t *c,
+ unsigned int count, /* Including the first glyph */
+ unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
+ unsigned int match_length,
+ hb_codepoint_t lig_glyph,
+ bool is_mark_ligature,
+ unsigned int total_component_count)
+{
+ TRACE_APPLY (NULL);
+
+ hb_buffer_t *buffer = c->buffer;
+
+ buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
+
+ /*
+ * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
+ * the ligature to keep its old ligature id. This will allow it to attach to
+ * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
+ * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
+ * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
+ * later, we don't want them to lose their ligature id/component, otherwise
+ * GPOS will fail to correctly position the mark ligature on top of the
+ * LAM,LAM,HEH ligature. See:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=676343
+ *
+ * - If a ligature is formed of components that some of which are also ligatures
+ * themselves, and those ligature components had marks attached to *their*
+ * components, we have to attach the marks to the new ligature component
+ * positions! Now *that*'s tricky! And these marks may be following the
+ * last component of the whole sequence, so we should loop forward looking
+ * for them and update them.
+ *
+ * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
+ * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
+ * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
+ * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
+ * the new ligature with a component value of 2.
+ *
+ * This in fact happened to a font... See:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=437633
+ */
+
+ unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
+ unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
+ unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+ unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+ unsigned int components_so_far = last_num_components;
+
+ if (!is_mark_ligature)
+ {
+ _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
+ if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+ {
+ _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
+ _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
+ }
+ }
+ c->replace_glyph_with_ligature (lig_glyph, klass);
+
+ for (unsigned int i = 1; i < count; i++)
+ {
+ while (buffer->idx < match_positions[i])
+ {
+ if (!is_mark_ligature) {
+ unsigned int new_lig_comp = components_so_far - last_num_components +
+ MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
+ _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
+ }
+ buffer->next_glyph ();
+ }
+
+ last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
+ last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
+ components_so_far += last_num_components;
+
+ /* Skip the base glyph */
+ buffer->idx++;
+ }
+
+ if (!is_mark_ligature && last_lig_id) {
+ /* Re-adjust components for any marks following. */
+ for (unsigned int i = buffer->idx; i < buffer->len; i++) {
+ if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
+ unsigned int new_lig_comp = components_so_far - last_num_components +
+ MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
+ _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
+ } else
+ break;
+ }
+ }
+ TRACE_RETURN (true);
}
static inline bool match_backtrack (hb_apply_context_t *c,
@@ -334,20 +891,17 @@ static inline bool match_backtrack (hb_apply_context_t *c,
match_func_t match_func,
const void *match_data)
{
- hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
- if (skippy_iter.has_no_chance ())
- return false;
+ TRACE_APPLY (NULL);
+
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+ skippy_iter.reset (c->buffer->backtrack_len (), count);
+ skippy_iter.set_match_func (match_func, match_data, backtrack);
for (unsigned int i = 0; i < count; i++)
- {
if (!skippy_iter.prev ())
- return false;
-
- if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
- return false;
- }
+ return TRACE_RETURN (false);
- return true;
+ return TRACE_RETURN (true);
}
static inline bool match_lookahead (hb_apply_context_t *c,
@@ -357,28 +911,26 @@ static inline bool match_lookahead (hb_apply_context_t *c,
const void *match_data,
unsigned int offset)
{
- hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
- if (skippy_iter.has_no_chance ())
- return false;
+ TRACE_APPLY (NULL);
+
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+ skippy_iter.reset (c->buffer->idx + offset - 1, count);
+ skippy_iter.set_match_func (match_func, match_data, lookahead);
for (unsigned int i = 0; i < count; i++)
- {
if (!skippy_iter.next ())
- return false;
-
- if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
- return false;
- }
+ return TRACE_RETURN (false);
- return true;
+ return TRACE_RETURN (true);
}
struct LookupRecord
{
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -391,71 +943,96 @@ struct LookupRecord
};
-static inline void closure_lookup (hb_closure_context_t *c,
- unsigned int lookupCount,
- const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
- closure_lookup_func_t closure_func)
+template <typename context_t>
+static inline void recurse_lookups (context_t *c,
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
{
for (unsigned int i = 0; i < lookupCount; i++)
- closure_func (c, lookupRecord->lookupListIndex);
+ c->recurse (lookupRecord[i].lookupListIndex);
}
static inline bool apply_lookup (hb_apply_context_t *c,
unsigned int count, /* Including the first glyph */
+ unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
unsigned int lookupCount,
const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
- apply_lookup_func_t apply_func)
+ unsigned int match_length)
{
- unsigned int end = c->buffer->len;
- if (unlikely (count == 0 || c->buffer->idx + count > end))
- return false;
+ TRACE_APPLY (NULL);
- /* TODO We don't support lookupRecord arrays that are not increasing:
- * Should be easy for in_place ones at least. */
+ hb_buffer_t *buffer = c->buffer;
+ unsigned int end;
- /* Note: If sublookup is reverse, it will underflow after the first loop
- * and we jump out of it. Not entirely disastrous. So we don't check
- * for reverse lookup here.
- */
- for (unsigned int i = 0; i < count; /* NOP */)
+ /* All positions are distance from beginning of *output* buffer.
+ * Adjust. */
{
- if (unlikely (c->buffer->idx == end))
- return true;
- while (c->should_mark_skip_current_glyph ())
- {
- /* No lookup applied for this index */
- c->buffer->next_glyph ();
- if (unlikely (c->buffer->idx == end))
- return true;
- }
+ unsigned int bl = buffer->backtrack_len ();
+ end = bl + match_length;
- if (lookupCount && i == lookupRecord->sequenceIndex)
- {
- unsigned int old_pos = c->buffer->idx;
+ int delta = bl - buffer->idx;
+ /* Convert positions to new indexing. */
+ for (unsigned int j = 0; j < count; j++)
+ match_positions[j] += delta;
+ }
- /* Apply a lookup */
- bool done = apply_func (c, lookupRecord->lookupListIndex);
+ for (unsigned int i = 0; i < lookupCount; i++)
+ {
+ unsigned int idx = lookupRecord[i].sequenceIndex;
+ if (idx >= count)
+ continue;
+
+ buffer->move_to (match_positions[idx]);
+
+ unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
+ if (!c->recurse (lookupRecord[i].lookupListIndex))
+ continue;
+
+ unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
+ int delta = new_len - orig_len;
- lookupRecord++;
- lookupCount--;
- /* Err, this is wrong if the lookup jumped over some glyphs */
- i += c->buffer->idx - old_pos;
- if (unlikely (c->buffer->idx == end))
- return true;
+ if (!delta)
+ continue;
- if (!done)
- goto not_applied;
+ /* Recursed lookup changed buffer len. Adjust. */
+
+ /* end can't go back past the current match position.
+ * Note: this is only true because we do NOT allow MultipleSubst
+ * with zero sequence len. */
+ end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
+
+ unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
+
+ if (delta > 0)
+ {
+ if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
+ break;
}
else
{
- not_applied:
- /* No lookup applied for this index */
- c->buffer->next_glyph ();
- i++;
+ /* NOTE: delta is negative. */
+ delta = MAX (delta, (int) next - (int) count);
+ next -= delta;
}
+
+ /* Shift! */
+ memmove (match_positions + next + delta, match_positions + next,
+ (count - next) * sizeof (match_positions[0]));
+ next += delta;
+ count += delta;
+
+ /* Fill in new entries. */
+ for (unsigned int j = idx + 1; j < next; j++)
+ match_positions[j] = match_positions[j - 1] + 1;
+
+ /* And fixup the rest. */
+ for (; next < count; next++)
+ match_positions[next] += delta;
}
- return true;
+ buffer->move_to (end);
+
+ return TRACE_RETURN (true);
}
@@ -468,6 +1045,12 @@ struct ContextClosureLookupContext
const void *intersects_data;
};
+struct ContextCollectGlyphsLookupContext
+{
+ ContextCollectGlyphsFuncs funcs;
+ const void *collect_data;
+};
+
struct ContextApplyLookupContext
{
ContextApplyFuncs funcs;
@@ -484,12 +1067,35 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
if (intersects_array (c,
inputCount ? inputCount - 1 : 0, input,
lookup_context.funcs.intersects, lookup_context.intersects_data))
- closure_lookup (c,
- lookupCount, lookupRecord,
- lookup_context.funcs.closure);
+ recurse_lookups (c,
+ lookupCount, lookupRecord);
}
+static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[],
+ ContextCollectGlyphsLookupContext &lookup_context)
+{
+ collect_array (c, c->input,
+ inputCount ? inputCount - 1 : 0, input,
+ lookup_context.funcs.collect, lookup_context.collect_data);
+ recurse_lookups (c,
+ lookupCount, lookupRecord);
+}
+static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ unsigned int lookupCount HB_UNUSED,
+ const LookupRecord lookupRecord[] HB_UNUSED,
+ ContextApplyLookupContext &lookup_context)
+{
+ return would_match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match, lookup_context.match_data);
+}
static inline bool context_apply_lookup (hb_apply_context_t *c,
unsigned int inputCount, /* Including the first glyph (not matched) */
const USHORT input[], /* Array of input values--start with second glyph */
@@ -497,74 +1103,111 @@ static inline bool context_apply_lookup (hb_apply_context_t *c,
const LookupRecord lookupRecord[],
ContextApplyLookupContext &lookup_context)
{
+ unsigned int match_length = 0;
+ unsigned int match_positions[MAX_CONTEXT_LENGTH];
return match_input (c,
inputCount, input,
- lookup_context.funcs.match, lookup_context.match_data)
+ lookup_context.funcs.match, lookup_context.match_data,
+ &match_length, match_positions)
&& apply_lookup (c,
- inputCount,
+ inputCount, match_positions,
lookupCount, lookupRecord,
- lookup_context.funcs.apply);
+ match_length);
}
struct Rule
{
- friend struct RuleSet;
-
- private:
-
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{
- TRACE_CLOSURE ();
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
+ TRACE_CLOSURE (this);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
context_closure_lookup (c,
- inputCount, input,
+ inputCount, inputZ,
lookupCount, lookupRecord,
lookup_context);
}
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+ context_collect_glyphs_lookup (c,
+ inputCount, inputZ,
+ lookupCount, lookupRecord,
+ lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+ {
+ TRACE_WOULD_APPLY (this);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+ return TRACE_RETURN (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
+ }
+
inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
{
- TRACE_APPLY ();
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
- return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
+ TRACE_APPLY (this);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
+ return TRACE_RETURN (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
}
public:
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return inputCount.sanitize (c)
&& lookupCount.sanitize (c)
- && c->check_range (input,
- input[0].static_size * inputCount
+ && c->check_range (inputZ,
+ inputZ[0].static_size * inputCount
+ lookupRecordX[0].static_size * lookupCount);
}
- private:
+ protected:
USHORT inputCount; /* Total number of glyphs in input
* glyph sequence--includes the first
* glyph */
USHORT lookupCount; /* Number of LookupRecords */
- USHORT input[VAR]; /* Array of match inputs--start with
+ USHORT inputZ[VAR]; /* Array of match inputs--start with
* second glyph */
LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
* design order */
public:
- DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
+ DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
};
struct RuleSet
{
inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
unsigned int num_rules = rule.len;
for (unsigned int i = 0; i < num_rules; i++)
(this+rule[i]).closure (c, lookup_context);
}
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ (this+rule[i]).collect_glyphs (c, lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
+ {
+ TRACE_WOULD_APPLY (this);
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ {
+ if ((this+rule[i]).would_apply (c, lookup_context))
+ return TRACE_RETURN (true);
+ }
+ return TRACE_RETURN (false);
+ }
+
inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
unsigned int num_rules = rule.len;
for (unsigned int i = 0; i < num_rules; i++)
{
@@ -574,12 +1217,13 @@ struct RuleSet
return TRACE_RETURN (false);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (rule.sanitize (c, this));
}
- private:
+ protected:
OffsetArrayOf<Rule>
rule; /* Array of Rule tables
* ordered by preference */
@@ -590,18 +1234,14 @@ struct RuleSet
struct ContextFormat1
{
- friend struct Context;
-
- private:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
const Coverage &cov = (this+coverage);
struct ContextClosureLookupContext lookup_context = {
- {intersects_glyph, closure_func},
+ {intersects_glyph},
NULL
};
@@ -613,27 +1253,60 @@ struct ContextFormat1
}
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+
+ struct ContextCollectGlyphsLookupContext lookup_context = {
+ {collect_glyph},
+ NULL
+ };
+
+ unsigned int count = ruleSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+
+ const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
+ struct ContextApplyLookupContext lookup_context = {
+ {match_glyph},
+ NULL
+ };
+ return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED))
return TRACE_RETURN (false);
const RuleSet &rule_set = this+ruleSet[index];
struct ContextApplyLookupContext lookup_context = {
- {match_glyph, apply_func},
+ {match_glyph},
NULL
};
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -648,21 +1321,17 @@ struct ContextFormat1
struct ContextFormat2
{
- friend struct Context;
-
- private:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
if (!(this+coverage).intersects (c->glyphs))
return;
const ClassDef &class_def = this+classDef;
struct ContextClosureLookupContext lookup_context = {
- {intersects_class, closure_func},
- NULL
+ {intersects_class},
+ &class_def
};
unsigned int count = ruleSet.len;
@@ -673,28 +1342,64 @@ struct ContextFormat2
}
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+
+ const ClassDef &class_def = this+classDef;
+ struct ContextCollectGlyphsLookupContext lookup_context = {
+ {collect_class},
+ &class_def
+ };
+
+ unsigned int count = ruleSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ TRACE_WOULD_APPLY (this);
+
+ const ClassDef &class_def = this+classDef;
+ unsigned int index = class_def.get_class (c->glyphs[0]);
+ const RuleSet &rule_set = this+ruleSet[index];
+ struct ContextApplyLookupContext lookup_context = {
+ {match_class},
+ &class_def
+ };
+ return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
const ClassDef &class_def = this+classDef;
- index = class_def (c->buffer->cur().codepoint);
+ index = class_def.get_class (c->buffer->cur().codepoint);
const RuleSet &rule_set = this+ruleSet[index];
struct ContextApplyLookupContext lookup_context = {
- {match_class, apply_func},
+ {match_class},
&class_def
};
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -712,104 +1417,114 @@ struct ContextFormat2
struct ContextFormat3
{
- friend struct Context;
-
- private:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
- if (!(this+coverage[0]).intersects (c->glyphs))
+ TRACE_CLOSURE (this);
+ if (!(this+coverageZ[0]).intersects (c->glyphs))
return;
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
struct ContextClosureLookupContext lookup_context = {
- {intersects_coverage, closure_func},
+ {intersects_coverage},
this
};
context_closure_lookup (c,
- glyphCount, (const USHORT *) (coverage + 1),
+ glyphCount, (const USHORT *) (coverageZ + 1),
lookupCount, lookupRecord,
lookup_context);
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverageZ[0]).add_coverage (c->input);
+
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+ struct ContextCollectGlyphsLookupContext lookup_context = {
+ {collect_coverage},
+ this
+ };
+
+ context_collect_glyphs_lookup (c,
+ glyphCount, (const USHORT *) (coverageZ + 1),
+ lookupCount, lookupRecord,
+ lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
+ struct ContextApplyLookupContext lookup_context = {
+ {match_coverage},
+ this
+ };
+ return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
{
- TRACE_APPLY ();
- unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
+ return this+coverageZ[0];
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
- const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
struct ContextApplyLookupContext lookup_context = {
- {match_coverage, apply_func},
+ {match_coverage},
this
};
- return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
+ return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!c->check_struct (this)) return TRACE_RETURN (false);
unsigned int count = glyphCount;
- if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
+ if (!count) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */
+ if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false);
for (unsigned int i = 0; i < count; i++)
- if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
- LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
+ if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 3 */
USHORT glyphCount; /* Number of glyphs in the input glyph
* sequence */
USHORT lookupCount; /* Number of LookupRecords */
OffsetTo<Coverage>
- coverage[VAR]; /* Array of offsets to Coverage
+ coverageZ[VAR]; /* Array of offsets to Coverage
* table in glyph sequence order */
LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
* design order */
public:
- DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
+ DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
};
struct Context
{
- protected:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: u.format1.closure (c, closure_func); break;
- case 2: u.format2.closure (c, closure_func); break;
- case 3: u.format3.closure (c, closure_func); break;
- default: break;
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ case 2: return TRACE_RETURN (c->dispatch (u.format2));
+ case 3: return TRACE_RETURN (c->dispatch (u.format3));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
- {
- TRACE_APPLY ();
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
- case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
- case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
- default:return TRACE_RETURN (false);
- }
- }
-
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- case 3: return TRACE_RETURN (u.format3.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT format; /* Format identifier */
ContextFormat1 format1;
@@ -827,6 +1542,12 @@ struct ChainContextClosureLookupContext
const void *intersects_data[3];
};
+struct ChainContextCollectGlyphsLookupContext
+{
+ ContextCollectGlyphsFuncs funcs;
+ const void *collect_data[3];
+};
+
struct ChainContextApplyLookupContext
{
ContextApplyFuncs funcs;
@@ -850,12 +1571,52 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
&& intersects_array (c,
inputCount ? inputCount - 1 : 0, input,
lookup_context.funcs.intersects, lookup_context.intersects_data[1])
- && intersects_array (c,
+ && intersects_array (c,
lookaheadCount, lookahead,
lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
- closure_lookup (c,
- lookupCount, lookupRecord,
- lookup_context.funcs.closure);
+ recurse_lookups (c,
+ lookupCount, lookupRecord);
+}
+
+static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
+ unsigned int backtrackCount,
+ const USHORT backtrack[],
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ unsigned int lookaheadCount,
+ const USHORT lookahead[],
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[],
+ ChainContextCollectGlyphsLookupContext &lookup_context)
+{
+ collect_array (c, c->before,
+ backtrackCount, backtrack,
+ lookup_context.funcs.collect, lookup_context.collect_data[0]);
+ collect_array (c, c->input,
+ inputCount ? inputCount - 1 : 0, input,
+ lookup_context.funcs.collect, lookup_context.collect_data[1]);
+ collect_array (c, c->after,
+ lookaheadCount, lookahead,
+ lookup_context.funcs.collect, lookup_context.collect_data[2]);
+ recurse_lookups (c,
+ lookupCount, lookupRecord);
+}
+
+static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
+ unsigned int backtrackCount,
+ const USHORT backtrack[] HB_UNUSED,
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ unsigned int lookaheadCount,
+ const USHORT lookahead[] HB_UNUSED,
+ unsigned int lookupCount HB_UNUSED,
+ const LookupRecord lookupRecord[] HB_UNUSED,
+ ChainContextApplyLookupContext &lookup_context)
+{
+ return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
+ && would_match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match, lookup_context.match_data[1]);
}
static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
@@ -869,33 +1630,30 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
const LookupRecord lookupRecord[],
ChainContextApplyLookupContext &lookup_context)
{
- unsigned int lookahead_offset;
- return match_backtrack (c,
- backtrackCount, backtrack,
- lookup_context.funcs.match, lookup_context.match_data[0])
- && match_input (c,
+ unsigned int match_length = 0;
+ unsigned int match_positions[MAX_CONTEXT_LENGTH];
+ return match_input (c,
inputCount, input,
lookup_context.funcs.match, lookup_context.match_data[1],
- &lookahead_offset)
+ &match_length, match_positions)
+ && match_backtrack (c,
+ backtrackCount, backtrack,
+ lookup_context.funcs.match, lookup_context.match_data[0])
&& match_lookahead (c,
lookaheadCount, lookahead,
lookup_context.funcs.match, lookup_context.match_data[2],
- lookahead_offset)
+ match_length)
&& apply_lookup (c,
- inputCount,
+ inputCount, match_positions,
lookupCount, lookupRecord,
- lookup_context.funcs.apply);
+ match_length);
}
struct ChainRule
{
- friend struct ChainRuleSet;
-
- private:
-
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -907,9 +1665,36 @@ struct ChainRule
lookup_context);
}
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ chain_context_collect_glyphs_lookup (c,
+ backtrack.len, backtrack.array,
+ input.len, input.array,
+ lookahead.len, lookahead.array,
+ lookup.len, lookup.array,
+ lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ {
+ TRACE_WOULD_APPLY (this);
+ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ return TRACE_RETURN (chain_context_would_apply_lookup (c,
+ backtrack.len, backtrack.array,
+ input.len, input.array,
+ lookahead.len, lookahead.array, lookup.len,
+ lookup.array, lookup_context));
+ }
+
inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
@@ -920,19 +1705,19 @@ struct ChainRule
lookup.array, lookup_context));
}
- public:
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
- HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
if (!input.sanitize (c)) return TRACE_RETURN (false);
- ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
- ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
return TRACE_RETURN (lookup.sanitize (c));
}
- private:
+ protected:
ArrayOf<USHORT>
backtrack; /* Array of backtracking values
* (to be matched before the input
@@ -954,15 +1739,34 @@ struct ChainRuleSet
{
inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
unsigned int num_rules = rule.len;
for (unsigned int i = 0; i < num_rules; i++)
(this+rule[i]).closure (c, lookup_context);
}
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ (this+rule[i]).collect_glyphs (c, lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
+ {
+ TRACE_WOULD_APPLY (this);
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ if ((this+rule[i]).would_apply (c, lookup_context))
+ return TRACE_RETURN (true);
+
+ return TRACE_RETURN (false);
+ }
+
inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
unsigned int num_rules = rule.len;
for (unsigned int i = 0; i < num_rules; i++)
if ((this+rule[i]).apply (c, lookup_context))
@@ -971,12 +1775,13 @@ struct ChainRuleSet
return TRACE_RETURN (false);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (rule.sanitize (c, this));
}
- private:
+ protected:
OffsetArrayOf<ChainRule>
rule; /* Array of ChainRule tables
* ordered by preference */
@@ -986,17 +1791,13 @@ struct ChainRuleSet
struct ChainContextFormat1
{
- friend struct ChainContext;
-
- private:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
const Coverage &cov = (this+coverage);
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_glyph, closure_func},
+ {intersects_glyph},
{NULL, NULL, NULL}
};
@@ -1008,26 +1809,59 @@ struct ChainContextFormat1
}
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+
+ struct ChainContextCollectGlyphsLookupContext lookup_context = {
+ {collect_glyph},
+ {NULL, NULL, NULL}
+ };
+
+ unsigned int count = ruleSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+
+ const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
+ struct ChainContextApplyLookupContext lookup_context = {
+ {match_glyph},
+ {NULL, NULL, NULL}
+ };
+ return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
{
- TRACE_APPLY ();
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ return this+coverage;
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
const ChainRuleSet &rule_set = this+ruleSet[index];
struct ChainContextApplyLookupContext lookup_context = {
- {match_glyph, apply_func},
+ {match_glyph},
{NULL, NULL, NULL}
};
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -1041,13 +1875,9 @@ struct ChainContextFormat1
struct ChainContextFormat2
{
- friend struct ChainContext;
-
- private:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
if (!(this+coverage).intersects (c->glyphs))
return;
@@ -1056,7 +1886,7 @@ struct ChainContextFormat2
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_class, closure_func},
+ {intersects_class},
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
@@ -1070,20 +1900,65 @@ struct ChainContextFormat2
}
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ (this+coverage).add_coverage (c->input);
+
+ const ClassDef &backtrack_class_def = this+backtrackClassDef;
+ const ClassDef &input_class_def = this+inputClassDef;
+ const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+ struct ChainContextCollectGlyphsLookupContext lookup_context = {
+ {collect_class},
+ {&backtrack_class_def,
+ &input_class_def,
+ &lookahead_class_def}
+ };
+
+ unsigned int count = ruleSet.len;
+ for (unsigned int i = 0; i < count; i++)
+ (this+ruleSet[i]).collect_glyphs (c, lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
{
- TRACE_APPLY ();
- unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
+ TRACE_WOULD_APPLY (this);
+
+ const ClassDef &backtrack_class_def = this+backtrackClassDef;
+ const ClassDef &input_class_def = this+inputClassDef;
+ const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+ unsigned int index = input_class_def.get_class (c->glyphs[0]);
+ const ChainRuleSet &rule_set = this+ruleSet[index];
+ struct ChainContextApplyLookupContext lookup_context = {
+ {match_class},
+ {&backtrack_class_def,
+ &input_class_def,
+ &lookahead_class_def}
+ };
+ return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ return this+coverage;
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
- index = input_class_def (c->buffer->cur().codepoint);
+ index = input_class_def.get_class (c->buffer->cur().codepoint);
const ChainRuleSet &rule_set = this+ruleSet[index];
struct ChainContextApplyLookupContext lookup_context = {
- {match_class, apply_func},
+ {match_class},
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
@@ -1091,14 +1966,15 @@ struct ChainContextFormat2
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
ruleSet.sanitize (c, this));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
@@ -1124,13 +2000,9 @@ struct ChainContextFormat2
struct ChainContextFormat3
{
- friend struct ChainContext;
-
- private:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ inline void closure (hb_closure_context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_CLOSURE (this);
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
if (!(this+input[0]).intersects (c->glyphs))
@@ -1139,7 +2011,7 @@ struct ChainContextFormat3
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
struct ChainContextClosureLookupContext lookup_context = {
- {intersects_coverage, closure_func},
+ {intersects_coverage},
{this, this, this}
};
chain_context_closure_lookup (c,
@@ -1150,18 +2022,63 @@ struct ChainContextFormat3
lookup_context);
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+ {
+ TRACE_COLLECT_GLYPHS (this);
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+ (this+input[0]).add_coverage (c->input);
+
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ struct ChainContextCollectGlyphsLookupContext lookup_context = {
+ {collect_coverage},
+ {this, this, this}
+ };
+ chain_context_collect_glyphs_lookup (c,
+ backtrack.len, (const USHORT *) backtrack.array,
+ input.len, (const USHORT *) input.array + 1,
+ lookahead.len, (const USHORT *) lookahead.array,
+ lookup.len, lookup.array,
+ lookup_context);
+ }
+
+ inline bool would_apply (hb_would_apply_context_t *c) const
+ {
+ TRACE_WOULD_APPLY (this);
+
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ struct ChainContextApplyLookupContext lookup_context = {
+ {match_coverage},
+ {this, this, this}
+ };
+ return TRACE_RETURN (chain_context_would_apply_lookup (c,
+ backtrack.len, (const USHORT *) backtrack.array,
+ input.len, (const USHORT *) input.array + 1,
+ lookahead.len, (const USHORT *) lookahead.array,
+ lookup.len, lookup.array, lookup_context));
+ }
+
+ inline const Coverage &get_coverage (void) const
+ {
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ return this+input[0];
+ }
+
+ inline bool apply (hb_apply_context_t *c) const
{
- TRACE_APPLY ();
+ TRACE_APPLY (this);
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
- unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
+ unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
struct ChainContextApplyLookupContext lookup_context = {
- {match_coverage, apply_func},
+ {match_coverage},
{this, this, this}
};
return TRACE_RETURN (chain_context_apply_lookup (c,
@@ -1171,18 +2088,20 @@ struct ChainContextFormat3
lookup.len, lookup.array, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
- OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
if (!input.sanitize (c, this)) return TRACE_RETURN (false);
- OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+ if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
- ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
return TRACE_RETURN (lookup.sanitize (c));
}
- private:
+ protected:
USHORT format; /* Format identifier--format = 3 */
OffsetArrayOf<Coverage>
backtrack; /* Array of coverage tables
@@ -1205,42 +2124,20 @@ struct ChainContextFormat3
struct ChainContext
{
- protected:
-
- inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
{
- TRACE_CLOSURE ();
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: u.format1.closure (c, closure_func); break;
- case 2: u.format2.closure (c, closure_func); break;
- case 3: u.format3.closure (c, closure_func); break;
- default: break;
+ case 1: return TRACE_RETURN (c->dispatch (u.format1));
+ case 2: return TRACE_RETURN (c->dispatch (u.format2));
+ case 3: return TRACE_RETURN (c->dispatch (u.format3));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
- {
- TRACE_APPLY ();
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
- case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
- case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
- default:return TRACE_RETURN (false);
- }
- }
-
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- case 3: return TRACE_RETURN (u.format3.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
- private:
+ protected:
union {
USHORT format; /* Format identifier */
ChainContextFormat1 format1;
@@ -1250,20 +2147,35 @@ struct ChainContext
};
+template <typename T>
struct ExtensionFormat1
{
- friend struct Extension;
-
- protected:
inline unsigned int get_type (void) const { return extensionLookupType; }
- inline unsigned int get_offset (void) const { return extensionOffset; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- return TRACE_RETURN (c->check_struct (this));
+ template <typename X>
+ inline const X& get_subtable (void) const
+ {
+ unsigned int offset = extensionOffset;
+ if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+ return StructAtOffset<typename T::LookupSubTable> (this, offset);
+ }
+
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, format);
+ if (unlikely (!c->may_dispatch (this, this))) TRACE_RETURN (c->default_return_value ());
+ return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
+ }
+
+ /* This is called from may_dispatch() above with hb_sanitize_context_t. */
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) && extensionOffset != 0);
}
- private:
+ protected:
USHORT format; /* Format identifier. Set to 1. */
USHORT extensionLookupType; /* Lookup type of subtable referenced
* by ExtensionOffset (i.e. the
@@ -1274,6 +2186,7 @@ struct ExtensionFormat1
DEFINE_SIZE_STATIC (8);
};
+template <typename T>
struct Extension
{
inline unsigned int get_type (void) const
@@ -1283,27 +2196,30 @@ struct Extension
default:return 0;
}
}
- inline unsigned int get_offset (void) const
+ template <typename X>
+ inline const X& get_subtable (void) const
{
switch (u.format) {
- case 1: return u.format1.get_offset ();
- default:return 0;
+ case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
+ default:return Null(typename T::LookupSubTable);
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (u.format1.dispatch (c));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- private:
+ protected:
union {
USHORT format; /* Format identifier */
- ExtensionFormat1 format1;
+ ExtensionFormat1<T> format1;
} u;
};
@@ -1332,8 +2248,8 @@ struct GSUBGPOS
inline unsigned int get_feature_count (void) const
{ return (this+featureList).len; }
- inline const Tag& get_feature_tag (unsigned int i) const
- { return (this+featureList).get_tag (i); }
+ inline hb_tag_t get_feature_tag (unsigned int i) const
+ { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
inline unsigned int get_feature_tags (unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */) const
@@ -1348,8 +2264,9 @@ struct GSUBGPOS
inline const Lookup& get_lookup (unsigned int i) const
{ return (this+lookupList)[i]; }
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
featureList.sanitize (c, this) &&
@@ -1358,7 +2275,7 @@ struct GSUBGPOS
protected:
FixedVersion version; /* Version of the GSUB/GPOS table--initially set
- * to 0x00010000 */
+ * to 0x00010000u */
OffsetTo<ScriptList>
scriptList; /* ScriptList table */
OffsetTo<FeatureList>
@@ -1370,5 +2287,7 @@ struct GSUBGPOS
};
+} /* namespace OT */
+
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
diff --git a/src/hb-ot-layout-jstf-table.hh b/src/hb-ot-layout-jstf-table.hh
new file mode 100644
index 0000000..739dfd9
--- /dev/null
+++ b/src/hb-ot-layout-jstf-table.hh
@@ -0,0 +1,233 @@
+/*
+ * Copyright © 2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_LAYOUT_JSTF_TABLE_HH
+#define HB_OT_LAYOUT_JSTF_TABLE_HH
+
+#include "hb-open-type-private.hh"
+#include "hb-ot-layout-gpos-table.hh"
+
+
+namespace OT {
+
+
+/*
+ * JstfModList -- Justification Modification List Tables
+ */
+
+typedef IndexArray JstfModList;
+
+
+/*
+ * JstfMax -- Justification Maximum Table
+ */
+
+typedef OffsetListOf<PosLookup> JstfMax;
+
+
+/*
+ * JstfPriority -- Justification Priority Table
+ */
+
+struct JstfPriority
+{
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (c->check_struct (this) &&
+ shrinkageEnableGSUB.sanitize (c, this) &&
+ shrinkageDisableGSUB.sanitize (c, this) &&
+ shrinkageEnableGPOS.sanitize (c, this) &&
+ shrinkageDisableGPOS.sanitize (c, this) &&
+ shrinkageJstfMax.sanitize (c, this) &&
+ extensionEnableGSUB.sanitize (c, this) &&
+ extensionDisableGSUB.sanitize (c, this) &&
+ extensionEnableGPOS.sanitize (c, this) &&
+ extensionDisableGPOS.sanitize (c, this) &&
+ extensionJstfMax.sanitize (c, this));
+ }
+
+ protected:
+ OffsetTo<JstfModList>
+ shrinkageEnableGSUB; /* Offset to Shrinkage Enable GSUB
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfModList>
+ shrinkageDisableGSUB; /* Offset to Shrinkage Disable GSUB
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfModList>
+ shrinkageEnableGPOS; /* Offset to Shrinkage Enable GPOS
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfModList>
+ shrinkageDisableGPOS; /* Offset to Shrinkage Disable GPOS
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfMax>
+ shrinkageJstfMax; /* Offset to Shrinkage JstfMax table--
+ * from beginning of JstfPriority table
+ * --may be NULL */
+ OffsetTo<JstfModList>
+ extensionEnableGSUB; /* Offset to Extension Enable GSUB
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfModList>
+ extensionDisableGSUB; /* Offset to Extension Disable GSUB
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfModList>
+ extensionEnableGPOS; /* Offset to Extension Enable GPOS
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfModList>
+ extensionDisableGPOS; /* Offset to Extension Disable GPOS
+ * JstfModList table--from beginning of
+ * JstfPriority table--may be NULL */
+ OffsetTo<JstfMax>
+ extensionJstfMax; /* Offset to Extension JstfMax table--
+ * from beginning of JstfPriority table
+ * --may be NULL */
+
+ public:
+ DEFINE_SIZE_STATIC (20);
+};
+
+
+/*
+ * JstfLangSys -- Justification Language System Table
+ */
+
+struct JstfLangSys : OffsetListOf<JstfPriority>
+{
+ inline bool sanitize (hb_sanitize_context_t *c,
+ const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (OffsetListOf<JstfPriority>::sanitize (c));
+ }
+};
+
+
+/*
+ * ExtenderGlyphs -- Extender Glyph Table
+ */
+
+typedef SortedArrayOf<GlyphID> ExtenderGlyphs;
+
+
+/*
+ * JstfScript -- The Justification Table
+ */
+
+struct JstfScript
+{
+ inline unsigned int get_lang_sys_count (void) const
+ { return langSys.len; }
+ inline const Tag& get_lang_sys_tag (unsigned int i) const
+ { return langSys.get_tag (i); }
+ inline unsigned int get_lang_sys_tags (unsigned int start_offset,
+ unsigned int *lang_sys_count /* IN/OUT */,
+ hb_tag_t *lang_sys_tags /* OUT */) const
+ { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
+ inline const JstfLangSys& get_lang_sys (unsigned int i) const
+ {
+ if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
+ return this+langSys[i].offset;
+ }
+ inline bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
+ { return langSys.find_index (tag, index); }
+
+ inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
+ inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+ inline bool sanitize (hb_sanitize_context_t *c,
+ const Record<JstfScript>::sanitize_closure_t * = NULL) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (extenderGlyphs.sanitize (c, this) &&
+ defaultLangSys.sanitize (c, this) &&
+ langSys.sanitize (c, this));
+ }
+
+ protected:
+ OffsetTo<ExtenderGlyphs>
+ extenderGlyphs; /* Offset to ExtenderGlyph table--from beginning
+ * of JstfScript table-may be NULL */
+ OffsetTo<JstfLangSys>
+ defaultLangSys; /* Offset to DefaultJstfLangSys table--from
+ * beginning of JstfScript table--may be Null */
+ RecordArrayOf<JstfLangSys>
+ langSys; /* Array of JstfLangSysRecords--listed
+ * alphabetically by LangSysTag */
+ public:
+ DEFINE_SIZE_ARRAY (6, langSys);
+};
+
+
+/*
+ * JSTF -- The Justification Table
+ */
+
+struct JSTF
+{
+ static const hb_tag_t tableTag = HB_OT_TAG_JSTF;
+
+ inline unsigned int get_script_count (void) const
+ { return scriptList.len; }
+ inline const Tag& get_script_tag (unsigned int i) const
+ { return scriptList.get_tag (i); }
+ inline unsigned int get_script_tags (unsigned int start_offset,
+ unsigned int *script_count /* IN/OUT */,
+ hb_tag_t *script_tags /* OUT */) const
+ { return scriptList.get_tags (start_offset, script_count, script_tags); }
+ inline const JstfScript& get_script (unsigned int i) const
+ { return this+scriptList[i].offset; }
+ inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
+ { return scriptList.find_index (tag, index); }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
+ scriptList.sanitize (c, this));
+ }
+
+ protected:
+ FixedVersion version; /* Version of the JSTF table--initially set
+ * to 0x00010000u */
+ RecordArrayOf<JstfScript>
+ scriptList; /* Array of JstfScripts--listed
+ * alphabetically by ScriptTag */
+ public:
+ DEFINE_SIZE_ARRAY (6, scriptList);
+};
+
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_LAYOUT_JSTF_TABLE_HH */
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index f860e7b..47fecd2 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -1,5 +1,6 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_LAYOUT_PRIVATE_HH
@@ -29,43 +31,79 @@
#include "hb-private.hh"
-#include "hb-ot-layout.h"
-
#include "hb-font-private.hh"
#include "hb-buffer-private.hh"
-#include "hb-ot-shape-complex-private.hh"
-
+#include "hb-set-private.hh"
/*
* GDEF
*/
-/* XXX cleanup */
-typedef enum {
- HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0001,
- HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 0x0002,
- HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 0x0004,
- HB_OT_LAYOUT_GLYPH_CLASS_MARK = 0x0008,
- HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 0x0010
-} hb_ot_layout_glyph_class_t;
+typedef enum
+{
+ /* The following three match LookupFlags::Ignore* numbers. */
+ HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x02u,
+ HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE = 0x04u,
+ HB_OT_LAYOUT_GLYPH_PROPS_MARK = 0x08u,
+ /* The following are used internally; not derived from GDEF. */
+ HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED = 0x10u,
+ HB_OT_LAYOUT_GLYPH_PROPS_LIGATED = 0x20u,
+ HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED = 0x40u,
-HB_INTERNAL unsigned int
-_hb_ot_layout_get_glyph_property (hb_face_t *face,
- hb_glyph_info_t *info);
+ HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
+ HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+ HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
+} hb_ot_layout_glyph_class_mask_t;
-HB_INTERNAL hb_bool_t
-_hb_ot_layout_check_glyph_property (hb_face_t *face,
- hb_glyph_info_t *ginfo,
- unsigned int lookup_props,
- unsigned int *property_out);
+
+/*
+ * GSUB/GPOS
+ */
HB_INTERNAL hb_bool_t
-_hb_ot_layout_skip_mark (hb_face_t *face,
- hb_glyph_info_t *ginfo,
- unsigned int lookup_props,
- unsigned int *property_out);
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
+ unsigned int lookup_index,
+ const hb_codepoint_t *glyphs,
+ unsigned int glyphs_length,
+ hb_bool_t zero_context);
+
+
+/* Should be called before all the substitute_lookup's are done. */
+HB_INTERNAL void
+hb_ot_layout_substitute_start (hb_font_t *font,
+ hb_buffer_t *buffer);
+
+
+struct hb_ot_layout_lookup_accelerator_t;
+
+namespace OT {
+ struct hb_apply_context_t;
+ struct SubstLookup;
+}
+
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+ const OT::SubstLookup &lookup,
+ const hb_ot_layout_lookup_accelerator_t &accel);
+
+
+/* Should be called after all the substitute_lookup's are done */
+HB_INTERNAL void
+hb_ot_layout_substitute_finish (hb_font_t *font,
+ hb_buffer_t *buffer);
+
+
+/* Should be called before all the position_lookup's are done. Resets positions to zero. */
+HB_INTERNAL void
+hb_ot_layout_position_start (hb_font_t *font,
+ hb_buffer_t *buffer);
+
+/* Should be called after all the position_lookup's are done */
+HB_INTERNAL void
+hb_ot_layout_position_finish (hb_font_t *font,
+ hb_buffer_t *buffer);
@@ -73,15 +111,48 @@ _hb_ot_layout_skip_mark (hb_face_t *face,
* hb_ot_layout_t
*/
+namespace OT {
+ struct GDEF;
+ struct GSUB;
+ struct GPOS;
+}
+
+struct hb_ot_layout_lookup_accelerator_t
+{
+ template <typename TLookup>
+ inline void init (const TLookup &lookup)
+ {
+ digest.init ();
+ lookup.add_coverage (&digest);
+ }
+
+ inline void fini (void)
+ {
+ }
+
+ inline bool may_have (hb_codepoint_t g) const {
+ return digest.may_have (g);
+ }
+
+ private:
+ hb_set_digest_t digest;
+};
+
struct hb_ot_layout_t
{
hb_blob_t *gdef_blob;
hb_blob_t *gsub_blob;
hb_blob_t *gpos_blob;
- const struct GDEF *gdef;
- const struct GSUB *gsub;
- const struct GPOS *gpos;
+ const struct OT::GDEF *gdef;
+ const struct OT::GSUB *gsub;
+ const struct OT::GPOS *gpos;
+
+ unsigned int gsub_lookup_count;
+ unsigned int gpos_lookup_count;
+
+ hb_ot_layout_lookup_accelerator_t *gsub_accels;
+ hb_ot_layout_lookup_accelerator_t *gpos_accels;
};
@@ -92,5 +163,302 @@ HB_INTERNAL void
_hb_ot_layout_destroy (hb_ot_layout_t *layout);
+#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
+
+
+/*
+ * Buffer var routines.
+ */
+
+/* buffer var allocations, used during the entire shaping process */
+#define unicode_props0() var2.u8[0]
+#define unicode_props1() var2.u8[1]
+
+/* buffer var allocations, used during the GSUB/GPOS processing */
+#define glyph_props() var1.u16[0] /* GDEF glyph properties */
+#define lig_props() var1.u8[2] /* GSUB/GPOS ligature tracking */
+#define syllable() var1.u8[3] /* GSUB/GPOS shaping boundaries */
+
+/* unicode_props */
+
+enum {
+ MASK0_ZWJ = 0x20u,
+ MASK0_ZWNJ = 0x40u,
+ MASK0_IGNORABLE = 0x80u,
+ MASK0_GEN_CAT = 0x1Fu
+};
+
+static inline void
+_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
+{
+ /* XXX This shouldn't be inlined, or at least not while is_default_ignorable() is inline. */
+ info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) |
+ (unicode->is_default_ignorable (info->codepoint) ? MASK0_IGNORABLE : 0) |
+ (info->codepoint == 0x200Cu ? MASK0_ZWNJ : 0) |
+ (info->codepoint == 0x200Du ? MASK0_ZWJ : 0);
+ info->unicode_props1() = unicode->modified_combining_class (info->codepoint);
+}
+
+static inline void
+_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
+ hb_unicode_general_category_t gen_cat)
+{
+ info->unicode_props0() = (unsigned int) gen_cat | ((info->unicode_props0()) & ~MASK0_GEN_CAT);
+}
+
+static inline hb_unicode_general_category_t
+_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
+{
+ return (hb_unicode_general_category_t) (info->unicode_props0() & MASK0_GEN_CAT);
+}
+
+static inline void
+_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
+ unsigned int modified_class)
+{
+ info->unicode_props1() = modified_class;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
+{
+ return info->unicode_props1();
+}
+
+static inline hb_bool_t
+_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
+{
+ return !!(info->unicode_props0() & MASK0_IGNORABLE);
+}
+
+static inline hb_bool_t
+_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
+{
+ return !!(info->unicode_props0() & MASK0_ZWNJ);
+}
+
+static inline hb_bool_t
+_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
+{
+ return !!(info->unicode_props0() & MASK0_ZWJ);
+}
+
+static inline void
+_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
+{
+ info->unicode_props0() ^= MASK0_ZWNJ | MASK0_ZWJ;
+}
+
+/* lig_props: aka lig_id / lig_comp
+ *
+ * When a ligature is formed:
+ *
+ * - The ligature glyph and any marks in between all the same newly allocated
+ * lig_id,
+ * - The ligature glyph will get lig_num_comps set to the number of components
+ * - The marks get lig_comp > 0, reflecting which component of the ligature
+ * they were applied to.
+ * - This is used in GPOS to attach marks to the right component of a ligature
+ * in MarkLigPos,
+ * - Note that when marks are ligated together, much of the above is skipped
+ * and the current lig_id reused.
+ *
+ * When a multiple-substitution is done:
+ *
+ * - All resulting glyphs will have lig_id = 0,
+ * - The resulting glyphs will have lig_comp = 0, 1, 2, ... respectively.
+ * - This is used in GPOS to attach marks to the first component of a
+ * multiple substitution in MarkBasePos.
+ *
+ * The numbers are also used in GPOS to do mark-to-mark positioning only
+ * to marks that belong to the same component of the same ligature.
+ */
+
+static inline void
+_hb_glyph_info_clear_lig_props (hb_glyph_info_t *info)
+{
+ info->lig_props() = 0;
+}
+
+#define IS_LIG_BASE 0x10
+
+static inline void
+_hb_glyph_info_set_lig_props_for_ligature (hb_glyph_info_t *info,
+ unsigned int lig_id,
+ unsigned int lig_num_comps)
+{
+ info->lig_props() = (lig_id << 5) | IS_LIG_BASE | (lig_num_comps & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_mark (hb_glyph_info_t *info,
+ unsigned int lig_id,
+ unsigned int lig_comp)
+{
+ info->lig_props() = (lig_id << 5) | (lig_comp & 0x0F);
+}
+
+static inline void
+_hb_glyph_info_set_lig_props_for_component (hb_glyph_info_t *info, unsigned int comp)
+{
+ _hb_glyph_info_set_lig_props_for_mark (info, 0, comp);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
+{
+ return info->lig_props() >> 5;
+}
+
+static inline bool
+_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
+{
+ return !!(info->lig_props() & IS_LIG_BASE);
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_comp (const hb_glyph_info_t *info)
+{
+ if (_hb_glyph_info_ligated_internal (info))
+ return 0;
+ else
+ return info->lig_props() & 0x0F;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info)
+{
+ if ((info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) &&
+ _hb_glyph_info_ligated_internal (info))
+ return info->lig_props() & 0x0F;
+ else
+ return 1;
+}
+
+static inline uint8_t
+_hb_allocate_lig_id (hb_buffer_t *buffer) {
+ uint8_t lig_id = buffer->next_serial () & 0x07;
+ if (unlikely (!lig_id))
+ lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */
+ return lig_id;
+}
+
+/* glyph_props: */
+
+static inline void
+_hb_glyph_info_set_glyph_props (hb_glyph_info_t *info, unsigned int props)
+{
+ info->glyph_props() = props;
+}
+
+static inline unsigned int
+_hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
+{
+ return info->glyph_props();
+}
+
+static inline bool
+_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
+{
+ return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
+}
+
+static inline bool
+_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
+{
+ return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
+}
+
+static inline bool
+_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
+{
+ return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+}
+
+static inline bool
+_hb_glyph_info_substituted (const hb_glyph_info_t *info)
+{
+ return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+}
+
+static inline bool
+_hb_glyph_info_ligated (const hb_glyph_info_t *info)
+{
+ return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
+}
+
+static inline bool
+_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
+{
+ return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+}
+
+static inline bool
+_hb_glyph_info_ligated_and_didnt_multiply (const hb_glyph_info_t *info)
+{
+ return _hb_glyph_info_ligated (info) && !_hb_glyph_info_multiplied (info);
+}
+
+static inline void
+_hb_glyph_info_clear_ligated_and_multiplied (hb_glyph_info_t *info)
+{
+ info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
+ HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+}
+
+
+/* Allocation / deallocation. */
+
+static inline void
+_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
+{
+ HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props0);
+ HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props1);
+}
+
+static inline void
+_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
+{
+ HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props0);
+ HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props1);
+}
+
+static inline void
+_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
+{
+ HB_BUFFER_ASSERT_VAR (buffer, unicode_props0);
+ HB_BUFFER_ASSERT_VAR (buffer, unicode_props1);
+}
+
+static inline void
+_hb_buffer_allocate_gsubgpos_vars (hb_buffer_t *buffer)
+{
+ HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
+ HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
+ HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
+}
+
+static inline void
+_hb_buffer_deallocate_gsubgpos_vars (hb_buffer_t *buffer)
+{
+ HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
+ HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
+ HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
+}
+
+static inline void
+_hb_buffer_assert_gsubgpos_vars (hb_buffer_t *buffer)
+{
+ HB_BUFFER_ASSERT_VAR (buffer, glyph_props);
+ HB_BUFFER_ASSERT_VAR (buffer, lig_props);
+ HB_BUFFER_ASSERT_VAR (buffer, syllable);
+}
+
+/* Make sure no one directly touches our props... */
+#undef unicode_props0
+#undef unicode_props1
+#undef lig_props
+#undef glyph_props
+
#endif /* HB_OT_LAYOUT_PRIVATE_HH */
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 0621f86..b1e69e8 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -2,6 +2,7 @@
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2006 Behdad Esfahbod
* Copyright © 2007,2008,2009 Red Hat, Inc.
+ * Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -24,6 +25,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-layout-private.hh"
@@ -31,28 +33,49 @@
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
-#include "hb-ot-maxp-table.hh"
+#include "hb-ot-layout-jstf-table.hh"
+#include "hb-ot-map-private.hh"
#include <stdlib.h>
#include <string.h>
+HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
hb_ot_layout_t *
_hb_ot_layout_create (hb_face_t *face)
{
- /* TODO Remove this object altogether */
hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
+ if (unlikely (!layout))
+ return NULL;
- layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GDEF));
- layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
+ layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
+ layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
- layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GSUB));
- layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
+ layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
+ layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
- layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
- layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
+ layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
+ layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
+
+ layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
+ layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
+
+ layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+ layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
+
+ if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
+ (layout->gpos_lookup_count && !layout->gpos_accels)))
+ {
+ _hb_ot_layout_destroy (layout);
+ return NULL;
+ }
+
+ for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+ layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
+ for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+ layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
return layout;
}
@@ -60,6 +83,14 @@ _hb_ot_layout_create (hb_face_t *face)
void
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
{
+ for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
+ layout->gsub_accels[i].fini ();
+ for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
+ layout->gpos_accels[i].fini ();
+
+ free (layout->gsub_accels);
+ free (layout->gpos_accels);
+
hb_blob_destroy (layout->gdef_blob);
hb_blob_destroy (layout->gsub_blob);
hb_blob_destroy (layout->gpos_blob);
@@ -67,20 +98,23 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
free (layout);
}
-static inline const GDEF&
+static inline const OT::GDEF&
_get_gdef (hb_face_t *face)
{
- return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
+ return *hb_ot_layout_from_face (face)->gdef;
}
-static inline const GSUB&
+static inline const OT::GSUB&
_get_gsub (hb_face_t *face)
{
- return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
+ return *hb_ot_layout_from_face (face)->gsub;
}
-static inline const GPOS&
+static inline const OT::GPOS&
_get_gpos (hb_face_t *face)
{
- return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
+ return *hb_ot_layout_from_face (face)->gpos;
}
@@ -94,85 +128,21 @@ hb_ot_layout_has_glyph_classes (hb_face_t *face)
return _get_gdef (face).has_glyph_classes ();
}
-unsigned int
-_hb_ot_layout_get_glyph_property (hb_face_t *face,
- hb_glyph_info_t *info)
-{
- if (!info->props_cache())
- {
- const GDEF &gdef = _get_gdef (face);
- info->props_cache() = gdef.get_glyph_props (info->codepoint);
- }
-
- return info->props_cache();
-}
-
-static hb_bool_t
-_hb_ot_layout_match_properties (hb_face_t *face,
- hb_codepoint_t codepoint,
- unsigned int glyph_props,
- unsigned int lookup_props)
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_face_t *face,
+ hb_codepoint_t glyph)
{
- /* Not covered, if, for example, glyph class is ligature and
- * lookup_props includes LookupFlags::IgnoreLigatures
- */
- if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
- return false;
-
- if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
- {
- /* If using mark filtering sets, the high short of
- * lookup_props has the set index.
- */
- if (lookup_props & LookupFlag::UseMarkFilteringSet)
- return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint);
-
- /* The second byte of lookup_props has the meaning
- * "ignore marks of attachment type different than
- * the attachment type specified."
- */
- if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType)
- return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
- }
-
- return true;
+ return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
}
-hb_bool_t
-_hb_ot_layout_check_glyph_property (hb_face_t *face,
- hb_glyph_info_t *ginfo,
- unsigned int lookup_props,
- unsigned int *property_out)
-{
- unsigned int property;
-
- property = _hb_ot_layout_get_glyph_property (face, ginfo);
- (void) (property_out && (*property_out = property));
-
- return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
-}
-
-hb_bool_t
-_hb_ot_layout_skip_mark (hb_face_t *face,
- hb_glyph_info_t *ginfo,
- unsigned int lookup_props,
- unsigned int *property_out)
+void
+hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
+ hb_ot_layout_glyph_class_t klass,
+ hb_set_t *glyphs /* OUT */)
{
- unsigned int property;
-
- property = _hb_ot_layout_get_glyph_property (face, ginfo);
- (void) (property_out && (*property_out = property));
-
- /* If it's a mark, skip it we don't accept it. */
- if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
- return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props);
-
- /* If not a mark, don't skip. */
- return false;
+ return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
}
-
-
unsigned int
hb_ot_layout_get_attach_points (hb_face_t *face,
hb_codepoint_t glyph,
@@ -194,18 +164,19 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
}
+
/*
* GSUB/GPOS
*/
-static const GSUBGPOS&
+static const OT::GSUBGPOS&
get_gsubgpos_table (hb_face_t *face,
hb_tag_t table_tag)
{
switch (table_tag) {
case HB_OT_TAG_GSUB: return _get_gsub (face);
case HB_OT_TAG_GPOS: return _get_gpos (face);
- default: return Null(GSUBGPOS);
+ default: return OT::Null(OT::GSUBGPOS);
}
}
@@ -217,19 +188,21 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */)
{
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
return g.get_script_tags (start_offset, script_count, script_tags);
}
+#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
+
hb_bool_t
hb_ot_layout_table_find_script (hb_face_t *face,
hb_tag_t table_tag,
hb_tag_t script_tag,
unsigned int *script_index)
{
- ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
if (g.find_script_index (script_tag, script_index))
return true;
@@ -243,6 +216,11 @@ hb_ot_layout_table_find_script (hb_face_t *face,
if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
return false;
+ /* try with 'latn'; some old fonts put their features there even though
+ they're really trying to support Thai, for example :( */
+ if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
+ return false;
+
if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
return false;
}
@@ -254,8 +232,8 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
unsigned int *script_index,
hb_tag_t *chosen_script)
{
- ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
while (*script_tags)
{
@@ -283,7 +261,6 @@ hb_ot_layout_table_choose_script (hb_face_t *face,
/* try with 'latn'; some old fonts put their features there even though
they're really trying to support Thai, for example :( */
-#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n')
if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
if (chosen_script)
*chosen_script = HB_OT_TAG_LATIN_SCRIPT;
@@ -303,7 +280,7 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */)
{
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
return g.get_feature_tags (start_offset, feature_count, feature_tags);
}
@@ -317,7 +294,7 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face,
unsigned int *language_count /* IN/OUT */,
hb_tag_t *language_tags /* OUT */)
{
- const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
+ const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
return s.get_lang_sys_tags (start_offset, language_count, language_tags);
}
@@ -329,8 +306,8 @@ hb_ot_layout_script_find_language (hb_face_t *face,
hb_tag_t language_tag,
unsigned int *language_index)
{
- ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
- const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
+ ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
+ const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
if (s.find_lang_sys_index (language_tag, language_index))
return true;
@@ -350,9 +327,28 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
unsigned int language_index,
unsigned int *feature_index)
{
- const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
+ return hb_ot_layout_language_get_required_feature (face,
+ table_tag,
+ script_index,
+ language_index,
+ feature_index,
+ NULL);
+}
- if (feature_index) *feature_index = l.get_required_feature_index ();
+hb_bool_t
+hb_ot_layout_language_get_required_feature (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int *feature_index,
+ hb_tag_t *feature_tag)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+ unsigned int index = l.get_required_feature_index ();
+ if (feature_index) *feature_index = index;
+ if (feature_tag) *feature_tag = g.get_feature_tag (index);
return l.has_required_feature ();
}
@@ -366,8 +362,8 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
unsigned int *feature_indexes /* OUT */)
{
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
- const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
}
@@ -381,8 +377,8 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */)
{
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
- const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
@@ -405,9 +401,9 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
hb_tag_t feature_tag,
unsigned int *feature_index)
{
- ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
- const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+ ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
unsigned int num_features = l.get_feature_count ();
for (unsigned int i = 0; i < num_features; i++) {
@@ -424,91 +420,576 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
}
unsigned int
-hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
- hb_tag_t table_tag,
- unsigned int feature_index,
- unsigned int start_offset,
- unsigned int *lookup_count /* IN/OUT */,
- unsigned int *lookup_indexes /* OUT */)
+hb_ot_layout_feature_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int start_offset,
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_indexes /* OUT */)
{
- const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
- const Feature &f = g.get_feature (feature_index);
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::Feature &f = g.get_feature (feature_index);
return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
}
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t *face,
+ hb_tag_t table_tag)
+{
+ switch (table_tag)
+ {
+ case HB_OT_TAG_GSUB:
+ {
+ return hb_ot_layout_from_face (face)->gsub_lookup_count;
+ }
+ case HB_OT_TAG_GPOS:
+ {
+ return hb_ot_layout_from_face (face)->gpos_lookup_count;
+ }
+ }
+ return 0;
+}
+
+static void
+_hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ hb_set_t *lookup_indexes /* OUT */)
+{
+ unsigned int lookup_indices[32];
+ unsigned int offset, len;
+
+ offset = 0;
+ do {
+ len = ARRAY_LENGTH (lookup_indices);
+ hb_ot_layout_feature_get_lookups (face,
+ table_tag,
+ feature_index,
+ offset, &len,
+ lookup_indices);
+
+ for (unsigned int i = 0; i < len; i++)
+ lookup_indexes->add (lookup_indices[i]);
+
+ offset += len;
+ } while (len == ARRAY_LENGTH (lookup_indices));
+}
+
+static void
+_hb_ot_layout_collect_lookups_features (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_index,
+ const hb_tag_t *features,
+ hb_set_t *lookup_indexes /* OUT */)
+{
+ if (!features)
+ {
+ unsigned int required_feature_index;
+ if (hb_ot_layout_language_get_required_feature (face,
+ table_tag,
+ script_index,
+ language_index,
+ &required_feature_index,
+ NULL))
+ _hb_ot_layout_collect_lookups_lookups (face,
+ table_tag,
+ required_feature_index,
+ lookup_indexes);
+
+ /* All features */
+ unsigned int feature_indices[32];
+ unsigned int offset, len;
+
+ offset = 0;
+ do {
+ len = ARRAY_LENGTH (feature_indices);
+ hb_ot_layout_language_get_feature_indexes (face,
+ table_tag,
+ script_index,
+ language_index,
+ offset, &len,
+ feature_indices);
+
+ for (unsigned int i = 0; i < len; i++)
+ _hb_ot_layout_collect_lookups_lookups (face,
+ table_tag,
+ feature_indices[i],
+ lookup_indexes);
+
+ offset += len;
+ } while (len == ARRAY_LENGTH (feature_indices));
+ }
+ else
+ {
+ for (; *features; features++)
+ {
+ unsigned int feature_index;
+ if (hb_ot_layout_language_find_feature (face,
+ table_tag,
+ script_index,
+ language_index,
+ *features,
+ &feature_index))
+ _hb_ot_layout_collect_lookups_lookups (face,
+ table_tag,
+ feature_index,
+ lookup_indexes);
+ }
+ }
+}
+
+static void
+_hb_ot_layout_collect_lookups_languages (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ const hb_tag_t *languages,
+ const hb_tag_t *features,
+ hb_set_t *lookup_indexes /* OUT */)
+{
+ _hb_ot_layout_collect_lookups_features (face,
+ table_tag,
+ script_index,
+ HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
+ features,
+ lookup_indexes);
+
+ if (!languages)
+ {
+ /* All languages */
+ unsigned int count = hb_ot_layout_script_get_language_tags (face,
+ table_tag,
+ script_index,
+ 0, NULL, NULL);
+ for (unsigned int language_index = 0; language_index < count; language_index++)
+ _hb_ot_layout_collect_lookups_features (face,
+ table_tag,
+ script_index,
+ language_index,
+ features,
+ lookup_indexes);
+ }
+ else
+ {
+ for (; *languages; languages++)
+ {
+ unsigned int language_index;
+ if (hb_ot_layout_script_find_language (face,
+ table_tag,
+ script_index,
+ *languages,
+ &language_index))
+ _hb_ot_layout_collect_lookups_features (face,
+ table_tag,
+ script_index,
+ language_index,
+ features,
+ lookup_indexes);
+ }
+ }
+}
+
+void
+hb_ot_layout_collect_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ const hb_tag_t *scripts,
+ const hb_tag_t *languages,
+ const hb_tag_t *features,
+ hb_set_t *lookup_indexes /* OUT */)
+{
+ if (!scripts)
+ {
+ /* All scripts */
+ unsigned int count = hb_ot_layout_table_get_script_tags (face,
+ table_tag,
+ 0, NULL, NULL);
+ for (unsigned int script_index = 0; script_index < count; script_index++)
+ _hb_ot_layout_collect_lookups_languages (face,
+ table_tag,
+ script_index,
+ languages,
+ features,
+ lookup_indexes);
+ }
+ else
+ {
+ for (; *scripts; scripts++)
+ {
+ unsigned int script_index;
+ if (hb_ot_layout_table_find_script (face,
+ table_tag,
+ *scripts,
+ &script_index))
+ _hb_ot_layout_collect_lookups_languages (face,
+ table_tag,
+ script_index,
+ languages,
+ features,
+ lookup_indexes);
+ }
+ }
+}
+
+void
+hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int lookup_index,
+ hb_set_t *glyphs_before, /* OUT. May be NULL */
+ hb_set_t *glyphs_input, /* OUT. May be NULL */
+ hb_set_t *glyphs_after, /* OUT. May be NULL */
+ hb_set_t *glyphs_output /* OUT. May be NULL */)
+{
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
+
+ OT::hb_collect_glyphs_context_t c (face,
+ glyphs_before,
+ glyphs_input,
+ glyphs_after,
+ glyphs_output);
+
+ switch (table_tag)
+ {
+ case HB_OT_TAG_GSUB:
+ {
+ const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+ l.collect_glyphs (&c);
+ return;
+ }
+ case HB_OT_TAG_GPOS:
+ {
+ const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
+ l.collect_glyphs (&c);
+ return;
+ }
+ }
+}
+
/*
- * GSUB
+ * OT::GSUB
*/
hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face)
{
- return &_get_gsub (face) != &Null(GSUB);
+ return &_get_gsub (face) != &OT::Null(OT::GSUB);
}
-void
-hb_ot_layout_substitute_start (hb_buffer_t *buffer)
+hb_bool_t
+hb_ot_layout_lookup_would_substitute (hb_face_t *face,
+ unsigned int lookup_index,
+ const hb_codepoint_t *glyphs,
+ unsigned int glyphs_length,
+ hb_bool_t zero_context)
{
- GSUB::substitute_start (buffer);
+ if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
+ return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
}
hb_bool_t
-hb_ot_layout_substitute_lookup (hb_face_t *face,
- hb_buffer_t *buffer,
- unsigned int lookup_index,
- hb_mask_t mask)
+hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
+ unsigned int lookup_index,
+ const hb_codepoint_t *glyphs,
+ unsigned int glyphs_length,
+ hb_bool_t zero_context)
{
- hb_apply_context_t c (NULL, face, buffer, mask);
- return _get_gsub (face).substitute_lookup (&c, lookup_index);
+ if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
+ OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);
+
+ const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
+
+ return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
}
void
-hb_ot_layout_substitute_finish (hb_buffer_t *buffer HB_UNUSED)
+hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
{
- GSUB::substitute_finish (buffer);
+ OT::GSUB::substitute_start (font, buffer);
}
void
-hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
- hb_set_t *glyphs,
- unsigned int lookup_index)
+hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
{
- hb_closure_context_t c (face, glyphs);
- _get_gsub (face).closure_lookup (&c, lookup_index);
+ OT::GSUB::substitute_finish (font, buffer);
+}
+
+void
+hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
+ unsigned int lookup_index,
+ hb_set_t *glyphs)
+{
+ OT::hb_closure_context_t c (face, glyphs);
+
+ const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);
+
+ l.closure (&c);
}
/*
- * GPOS
+ * OT::GPOS
*/
hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face)
{
- return &_get_gpos (face) != &Null(GPOS);
+ return &_get_gpos (face) != &OT::Null(OT::GPOS);
}
void
-hb_ot_layout_position_start (hb_buffer_t *buffer)
+hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
{
- GPOS::position_start (buffer);
+ OT::GPOS::position_start (font, buffer);
+}
+
+void
+hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
+{
+ OT::GPOS::position_finish (font, buffer);
}
hb_bool_t
-hb_ot_layout_position_lookup (hb_font_t *font,
- hb_buffer_t *buffer,
- unsigned int lookup_index,
- hb_mask_t mask)
+hb_ot_layout_get_size_params (hb_face_t *face,
+ unsigned int *design_size, /* OUT. May be NULL */
+ unsigned int *subfamily_id, /* OUT. May be NULL */
+ unsigned int *subfamily_name_id, /* OUT. May be NULL */
+ unsigned int *range_start, /* OUT. May be NULL */
+ unsigned int *range_end /* OUT. May be NULL */)
+{
+ const OT::GPOS &gpos = _get_gpos (face);
+ const hb_tag_t tag = HB_TAG ('s','i','z','e');
+
+ unsigned int num_features = gpos.get_feature_count ();
+ for (unsigned int i = 0; i < num_features; i++)
+ {
+ if (tag == gpos.get_feature_tag (i))
+ {
+ const OT::Feature &f = gpos.get_feature (i);
+ const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
+
+ if (params.designSize)
+ {
+#define PARAM(a, A) if (a) *a = params.A
+ PARAM (design_size, designSize);
+ PARAM (subfamily_id, subfamilyID);
+ PARAM (subfamily_name_id, subfamilyNameID);
+ PARAM (range_start, rangeStart);
+ PARAM (range_end, rangeEnd);
+#undef PARAM
+
+ return true;
+ }
+ }
+ }
+
+#define PARAM(a, A) if (a) *a = 0
+ PARAM (design_size, designSize);
+ PARAM (subfamily_id, subfamilyID);
+ PARAM (subfamily_name_id, subfamilyNameID);
+ PARAM (range_start, rangeStart);
+ PARAM (range_end, rangeEnd);
+#undef PARAM
+
+ return false;
+}
+
+
+/*
+ * Parts of different types are implemented here such that they have direct
+ * access to GSUB/GPOS lookups.
+ */
+
+
+struct GSUBProxy
{
- hb_apply_context_t c (font, font->face, buffer, mask);
- return _get_gpos (font->face).position_lookup (&c, lookup_index);
+ static const unsigned int table_index = 0;
+ static const bool inplace = false;
+ typedef OT::SubstLookup Lookup;
+
+ GSUBProxy (hb_face_t *face) :
+ table (*hb_ot_layout_from_face (face)->gsub),
+ accels (hb_ot_layout_from_face (face)->gsub_accels) {}
+
+ const OT::GSUB &table;
+ const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+struct GPOSProxy
+{
+ static const unsigned int table_index = 1;
+ static const bool inplace = true;
+ typedef OT::PosLookup Lookup;
+
+ GPOSProxy (hb_face_t *face) :
+ table (*hb_ot_layout_from_face (face)->gpos),
+ accels (hb_ot_layout_from_face (face)->gpos_accels) {}
+
+ const OT::GPOS &table;
+ const hb_ot_layout_lookup_accelerator_t *accels;
+};
+
+
+template <typename Obj>
+static inline bool
+apply_forward (OT::hb_apply_context_t *c,
+ const Obj &obj,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+{
+ bool ret = false;
+ hb_buffer_t *buffer = c->buffer;
+ while (buffer->idx < buffer->len)
+ {
+ if (accel.may_have (buffer->cur().codepoint) &&
+ (buffer->cur().mask & c->lookup_mask) &&
+ c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
+ obj.apply (c))
+ ret = true;
+ else
+ buffer->next_glyph ();
+ }
+ return ret;
}
-void
-hb_ot_layout_position_finish (hb_buffer_t *buffer)
+template <typename Obj>
+static inline bool
+apply_backward (OT::hb_apply_context_t *c,
+ const Obj &obj,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+{
+ bool ret = false;
+ hb_buffer_t *buffer = c->buffer;
+ do
+ {
+ if (accel.may_have (buffer->cur().codepoint) &&
+ (buffer->cur().mask & c->lookup_mask) &&
+ c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
+ obj.apply (c))
+ ret = true;
+ /* The reverse lookup doesn't "advance" cursor (for good reason). */
+ buffer->idx--;
+
+ }
+ while ((int) buffer->idx >= 0);
+ return ret;
+}
+
+struct hb_apply_forward_context_t
+{
+ inline const char *get_name (void) { return "APPLY_FORWARD"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+ typedef bool return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
+ static return_t default_return_value (void) { return false; }
+ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
+
+ hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
+ const hb_ot_layout_lookup_accelerator_t &accel_) :
+ c (c_),
+ accel (accel_),
+ debug_depth (0) {}
+
+ OT::hb_apply_context_t *c;
+ const hb_ot_layout_lookup_accelerator_t &accel;
+ unsigned int debug_depth;
+};
+
+template <typename Proxy>
+static inline void
+apply_string (OT::hb_apply_context_t *c,
+ const typename Proxy::Lookup &lookup,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+{
+ hb_buffer_t *buffer = c->buffer;
+
+ if (unlikely (!buffer->len || !c->lookup_mask))
+ return;
+
+ c->set_lookup (lookup);
+
+ if (likely (!lookup.is_reverse ()))
+ {
+ /* in/out forward substitution/positioning */
+ if (Proxy::table_index == 0)
+ buffer->clear_output ();
+ buffer->idx = 0;
+
+ bool ret;
+ if (lookup.get_subtable_count () == 1)
+ {
+ hb_apply_forward_context_t c_forward (c, accel);
+ ret = lookup.dispatch (&c_forward);
+ }
+ else
+ ret = apply_forward (c, lookup, accel);
+ if (ret)
+ {
+ if (!Proxy::inplace)
+ buffer->swap_buffers ();
+ else
+ assert (!buffer->has_separate_output ());
+ }
+ }
+ else
+ {
+ /* in-place backward substitution/positioning */
+ if (Proxy::table_index == 0)
+ buffer->remove_output ();
+ buffer->idx = buffer->len - 1;
+
+ apply_backward (c, lookup, accel);
+ }
+}
+
+template <typename Proxy>
+inline void hb_ot_map_t::apply (const Proxy &proxy,
+ const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer) const
+{
+ const unsigned int table_index = proxy.table_index;
+ unsigned int i = 0;
+ OT::hb_apply_context_t c (table_index, font, buffer);
+ c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
+
+ for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
+ const stage_map_t *stage = &stages[table_index][stage_index];
+ for (; i < stage->last_lookup; i++)
+ {
+ unsigned int lookup_index = lookups[table_index][i].index;
+ c.set_lookup_mask (lookups[table_index][i].mask);
+ c.set_auto_zwj (lookups[table_index][i].auto_zwj);
+ apply_string<Proxy> (&c,
+ proxy.table.get_lookup (lookup_index),
+ proxy.accels[lookup_index]);
+ }
+
+ if (stage->pause_func)
+ {
+ buffer->clear_output ();
+ stage->pause_func (plan, font, buffer);
+ }
+ }
+}
+
+void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
{
- GPOS::position_finish (buffer);
+ GSUBProxy proxy (font->face);
+ apply (proxy, plan, font, buffer);
}
+void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
+{
+ GPOSProxy proxy (font->face);
+ apply (proxy, plan, font, buffer);
+}
+HB_INTERNAL void
+hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
+ const OT::SubstLookup &lookup,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+{
+ apply_string<GSUBProxy> (c, lookup, accel);
+}
diff --git a/src/hb-ot-layout.h b/src/hb-ot-layout.h
index b8b5baf..949678a 100644
--- a/src/hb-ot-layout.h
+++ b/src/hb-ot-layout.h
@@ -41,6 +41,8 @@ HB_BEGIN_DECLS
#define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
#define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
#define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
+#define HB_OT_TAG_JSTF HB_TAG('J','S','T','F')
+
/*
* GDEF
@@ -49,6 +51,24 @@ HB_BEGIN_DECLS
hb_bool_t
hb_ot_layout_has_glyph_classes (hb_face_t *face);
+typedef enum {
+ HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0,
+ HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 1,
+ HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 2,
+ HB_OT_LAYOUT_GLYPH_CLASS_MARK = 3,
+ HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 4
+} hb_ot_layout_glyph_class_t;
+
+hb_ot_layout_glyph_class_t
+hb_ot_layout_get_glyph_class (hb_face_t *face,
+ hb_codepoint_t glyph);
+
+void
+hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
+ hb_ot_layout_glyph_class_t klass,
+ hb_set_t *glyphs /* OUT */);
+
+
/* Not that useful. Provides list of attach points for a glyph that a
* client may want to cache */
unsigned int
@@ -72,9 +92,9 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font,
* GSUB/GPOS feature query and enumeration interface
*/
-#define HB_OT_LAYOUT_NO_SCRIPT_INDEX ((unsigned int) 0xFFFF)
-#define HB_OT_LAYOUT_NO_FEATURE_INDEX ((unsigned int) 0xFFFF)
-#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX ((unsigned int) 0xFFFF)
+#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
+#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
+#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
unsigned int
hb_ot_layout_table_get_script_tags (hb_face_t *face,
@@ -126,6 +146,14 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
unsigned int language_index,
unsigned int *feature_index);
+hb_bool_t
+hb_ot_layout_language_get_required_feature (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int script_index,
+ unsigned int language_index,
+ unsigned int *feature_index,
+ hb_tag_t *feature_tag);
+
unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
hb_tag_t table_tag,
@@ -153,12 +181,60 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
unsigned int *feature_index);
unsigned int
-hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
+hb_ot_layout_feature_get_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int feature_index,
+ unsigned int start_offset,
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_indexes /* OUT */);
+
+unsigned int
+hb_ot_layout_table_get_lookup_count (hb_face_t *face,
+ hb_tag_t table_tag);
+
+
+void
+hb_ot_layout_collect_lookups (hb_face_t *face,
+ hb_tag_t table_tag,
+ const hb_tag_t *scripts,
+ const hb_tag_t *languages,
+ const hb_tag_t *features,
+ hb_set_t *lookup_indexes /* OUT */);
+
+void
+hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned int lookup_index,
+ hb_set_t *glyphs_before, /* OUT. May be NULL */
+ hb_set_t *glyphs_input, /* OUT. May be NULL */
+ hb_set_t *glyphs_after, /* OUT. May be NULL */
+ hb_set_t *glyphs_output /* OUT. May be NULL */);
+
+#ifdef HB_NOT_IMPLEMENTED
+typedef struct
+{
+ const hb_codepoint_t *before,
+ unsigned int before_length,
+ const hb_codepoint_t *input,
+ unsigned int input_length,
+ const hb_codepoint_t *after,
+ unsigned int after_length,
+} hb_ot_layout_glyph_sequence_t;
+
+typedef hb_bool_t
+(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font,
+ hb_tag_t table_tag,
+ unsigned int lookup_index,
+ const hb_ot_layout_glyph_sequence_t *sequence,
+ void *user_data);
+
+void
+Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
hb_tag_t table_tag,
- unsigned int feature_index,
- unsigned int start_offset,
- unsigned int *lookup_count /* IN/OUT */,
- unsigned int *lookup_indexes /* OUT */);
+ unsigned int lookup_index,
+ hb_ot_layout_glyph_sequence_func_t callback,
+ void *user_data);
+#endif
/*
@@ -168,25 +244,31 @@ hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face);
-/* Should be called before all the substitute_lookup's are done. */
-void
-hb_ot_layout_substitute_start (hb_buffer_t *buffer);
-
hb_bool_t
-hb_ot_layout_substitute_lookup (hb_face_t *face,
- hb_buffer_t *buffer,
- unsigned int lookup_index,
- hb_mask_t mask);
+hb_ot_layout_lookup_would_substitute (hb_face_t *face,
+ unsigned int lookup_index,
+ const hb_codepoint_t *glyphs,
+ unsigned int glyphs_length,
+ hb_bool_t zero_context);
-/* Should be called after all the substitute_lookup's are done */
void
-hb_ot_layout_substitute_finish (hb_buffer_t *buffer);
+hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
+ unsigned int lookup_index,
+ hb_set_t *glyphs
+ /*TODO , hb_bool_t inclusive */);
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
+hb_bool_t
+Xhb_ot_layout_lookup_substitute (hb_font_t *font,
+ unsigned int lookup_index,
+ const hb_ot_layout_glyph_sequence_t *sequence,
+ unsigned int out_size,
+ hb_codepoint_t *glyphs_out, /* OUT */
+ unsigned int *clusters_out, /* OUT */
+ unsigned int *out_length /* OUT */);
+#endif
-void
-hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
- hb_set_t *glyphs,
- unsigned int lookup_index);
/*
* GPOS
@@ -195,19 +277,24 @@ hb_ot_layout_substitute_closure_lookup (hb_face_t *face,
hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face);
-/* Should be called before all the position_lookup's are done. Resets positions to zero. */
-void
-hb_ot_layout_position_start (hb_buffer_t *buffer);
-
+#ifdef HB_NOT_IMPLEMENTED
+/* Note: You better have GDEF when using this API, or marks won't do much. */
hb_bool_t
-hb_ot_layout_position_lookup (hb_font_t *font,
- hb_buffer_t *buffer,
- unsigned int lookup_index,
- hb_mask_t mask);
+Xhb_ot_layout_lookup_position (hb_font_t *font,
+ unsigned int lookup_index,
+ const hb_ot_layout_glyph_sequence_t *sequence,
+ hb_glyph_position_t *positions /* IN / OUT */);
+#endif
-/* Should be called after all the position_lookup's are done */
-void
-hb_ot_layout_position_finish (hb_buffer_t *buffer);
+/* Optical 'size' feature info. Returns true if found.
+ * http://www.microsoft.com/typography/otspec/features_pt.htm#size */
+hb_bool_t
+hb_ot_layout_get_size_params (hb_face_t *face,
+ unsigned int *design_size, /* OUT. May be NULL */
+ unsigned int *subfamily_id, /* OUT. May be NULL */
+ unsigned int *subfamily_name_id, /* OUT. May be NULL */
+ unsigned int *range_start, /* OUT. May be NULL */
+ unsigned int *range_end /* OUT. May be NULL */);
HB_END_DECLS
diff --git a/src/hb-ot-map-private.hh b/src/hb-ot-map-private.hh
index 3811206..86b7e9f 100644
--- a/src/hb-ot-map-private.hh
+++ b/src/hb-ot-map-private.hh
@@ -1,6 +1,6 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
- * Copyright © 2010,2011 Google, Inc.
+ * Copyright © 2010,2011,2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -31,9 +31,8 @@
#include "hb-buffer-private.hh"
-#include "hb-ot-layout.h"
-
+struct hb_ot_shape_plan_t;
static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
@@ -43,46 +42,6 @@ struct hb_ot_map_t
public:
- hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
-
- typedef void (*gsub_pause_func_t) (const hb_ot_map_t *map, hb_face_t *face, hb_buffer_t *buffer, void *user_data);
- typedef void (*gpos_pause_func_t) (const hb_ot_map_t *map, hb_font_t *font, hb_buffer_t *buffer, void *user_data);
-
- inline hb_mask_t get_global_mask (void) const { return global_mask; }
-
- inline hb_mask_t get_mask (hb_tag_t tag, unsigned int *shift = NULL) const {
- const feature_map_t *map = features.bsearch (&tag);
- if (shift) *shift = map ? map->shift : 0;
- return map ? map->mask : 0;
- }
-
- inline hb_mask_t get_1_mask (hb_tag_t tag) const {
- const feature_map_t *map = features.bsearch (&tag);
- return map ? map->_1_mask : 0;
- }
-
- inline hb_tag_t get_chosen_script (unsigned int table_index) const
- { return chosen_script[table_index]; }
-
- inline void substitute (hb_face_t *face, hb_buffer_t *buffer) const
- { apply (0, (hb_ot_map_t::apply_lookup_func_t) hb_ot_layout_substitute_lookup, face, buffer); }
- inline void position (hb_font_t *font, hb_buffer_t *buffer) const
- { apply (1, (hb_ot_map_t::apply_lookup_func_t) hb_ot_layout_position_lookup, font, buffer); }
-
- HB_INTERNAL void substitute_closure (hb_face_t *face,
- hb_set_t *glyphs) const;
-
-
- inline void finish (void) {
- features.finish ();
- lookups[0].finish ();
- lookups[1].finish ();
- pauses[0].finish ();
- pauses[1].finish ();
- }
-
- private:
-
struct feature_map_t {
hb_tag_t tag; /* should be first for our bsearch to work */
unsigned int index[2]; /* GSUB/GPOS */
@@ -90,78 +49,160 @@ struct hb_ot_map_t
unsigned int shift;
hb_mask_t mask;
hb_mask_t _1_mask; /* mask for value=1, for quick access */
+ unsigned int needs_fallback : 1;
+ unsigned int auto_zwj : 1;
static int cmp (const feature_map_t *a, const feature_map_t *b)
{ return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
};
struct lookup_map_t {
- unsigned int index;
+ unsigned short index;
+ unsigned short auto_zwj : 1;
hb_mask_t mask;
static int cmp (const lookup_map_t *a, const lookup_map_t *b)
{ return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
};
- typedef void (*pause_func_t) (const hb_ot_map_t *map, void *face_or_font, hb_buffer_t *buffer, void *user_data);
- typedef struct {
- pause_func_t func;
- void *user_data;
- } pause_callback_t;
+ typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
- struct pause_map_t {
- unsigned int num_lookups; /* Cumulative */
- pause_callback_t callback;
+ struct stage_map_t {
+ unsigned int last_lookup; /* Cumulative */
+ pause_func_t pause_func;
};
- typedef hb_bool_t (*apply_lookup_func_t) (void *face_or_font,
- hb_buffer_t *buffer,
- unsigned int lookup_index,
- hb_mask_t mask);
+
+ hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
+
+ inline hb_mask_t get_global_mask (void) const { return global_mask; }
+
+ inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = NULL) const {
+ const feature_map_t *map = features.bsearch (&feature_tag);
+ if (shift) *shift = map ? map->shift : 0;
+ return map ? map->mask : 0;
+ }
+
+ inline bool needs_fallback (hb_tag_t feature_tag) const {
+ const feature_map_t *map = features.bsearch (&feature_tag);
+ return map ? map->needs_fallback : false;
+ }
+
+ inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const {
+ const feature_map_t *map = features.bsearch (&feature_tag);
+ return map ? map->_1_mask : 0;
+ }
+
+ inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
+ const feature_map_t *map = features.bsearch (&feature_tag);
+ return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
+ }
+
+ inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
+ const feature_map_t *map = features.bsearch (&feature_tag);
+ return map ? map->stage[table_index] : (unsigned int) -1;
+ }
+
+ inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
+ const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
+ if (unlikely (stage == (unsigned int) -1)) {
+ *plookups = NULL;
+ *lookup_count = 0;
+ return;
+ }
+ assert (stage <= stages[table_index].len);
+ unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
+ unsigned int end = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
+ *plookups = &lookups[table_index][start];
+ *lookup_count = end - start;
+ }
+
+ HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
+ template <typename Proxy>
+ HB_INTERNAL inline void apply (const Proxy &proxy,
+ const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+ HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+ HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
+
+ inline void finish (void) {
+ features.finish ();
+ for (unsigned int table_index = 0; table_index < 2; table_index++)
+ {
+ lookups[table_index].finish ();
+ stages[table_index].finish ();
+ }
+ }
+
+ public:
+ hb_tag_t chosen_script[2];
+ bool found_script[2];
+
+ private:
HB_INTERNAL void add_lookups (hb_face_t *face,
unsigned int table_index,
unsigned int feature_index,
- hb_mask_t mask);
-
- HB_INTERNAL void apply (unsigned int table_index,
- hb_ot_map_t::apply_lookup_func_t apply_lookup_func,
- void *face_or_font,
- hb_buffer_t *buffer) const;
+ hb_mask_t mask,
+ bool auto_zwj);
hb_mask_t global_mask;
- hb_tag_t chosen_script[2];
hb_prealloced_array_t<feature_map_t, 8> features;
hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */
- hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */
+ hb_prealloced_array_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
+};
+
+enum hb_ot_map_feature_flags_t {
+ F_NONE = 0x0000u,
+ F_GLOBAL = 0x0001u,
+ F_HAS_FALLBACK = 0x0002u,
+ F_MANUAL_ZWJ = 0x0004u
};
+/* Macro version for where const is desired. */
+#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
+static inline hb_ot_map_feature_flags_t
+operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
+static inline hb_ot_map_feature_flags_t
+operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
+static inline hb_ot_map_feature_flags_t
+operator ~ (hb_ot_map_feature_flags_t r)
+{ return hb_ot_map_feature_flags_t (~(unsigned int) r); }
+static inline hb_ot_map_feature_flags_t&
+operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
+{ l = l | r; return l; }
+static inline hb_ot_map_feature_flags_t&
+operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
+{ l = l & r; return l; }
struct hb_ot_map_builder_t
{
public:
- hb_ot_map_builder_t (void) { memset (this, 0, sizeof (*this)); }
+ HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
+ const hb_segment_properties_t *props_);
- HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global);
+ HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value,
+ hb_ot_map_feature_flags_t flags);
- inline void add_bool_feature (hb_tag_t tag, bool global = true)
- { add_feature (tag, 1, global); }
+ inline void add_global_bool_feature (hb_tag_t tag)
+ { add_feature (tag, 1, F_GLOBAL); }
- inline void add_gsub_pause (hb_ot_map_t::gsub_pause_func_t pause_func, void *user_data)
- { add_pause (0, (hb_ot_map_t::pause_func_t) pause_func, user_data); }
- inline void add_gpos_pause (hb_ot_map_t::gpos_pause_func_t pause_func, void *user_data)
- { add_pause (1, (hb_ot_map_t::pause_func_t) pause_func, user_data); }
+ inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
+ { add_pause (0, pause_func); }
+ inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
+ { add_pause (1, pause_func); }
- HB_INTERNAL void compile (hb_face_t *face,
- const hb_segment_properties_t *props,
- struct hb_ot_map_t &m);
+ HB_INTERNAL void compile (struct hb_ot_map_t &m);
inline void finish (void) {
feature_infos.finish ();
- pauses[0].finish ();
- pauses[1].finish ();
+ for (unsigned int table_index = 0; table_index < 2; table_index++)
+ {
+ stages[table_index].finish ();
+ }
}
private:
@@ -170,7 +211,7 @@ struct hb_ot_map_builder_t
hb_tag_t tag;
unsigned int seq; /* sequence#, used for stable sorting only */
unsigned int max_value;
- bool global; /* whether the feature applies value to every glyph in the buffer */
+ hb_ot_map_feature_flags_t flags;
unsigned int default_value; /* for non-global features, what should the unset glyphs take */
unsigned int stage[2]; /* GSUB/GPOS */
@@ -178,16 +219,27 @@ struct hb_ot_map_builder_t
{ return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); }
};
- struct pause_info_t {
- unsigned int stage;
- hb_ot_map_t::pause_callback_t callback;
+ struct stage_info_t {
+ unsigned int index;
+ hb_ot_map_t::pause_func_t pause_func;
};
- HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data);
+ HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
+
+ public:
+
+ hb_face_t *face;
+ hb_segment_properties_t props;
+
+ hb_tag_t chosen_script[2];
+ bool found_script[2];
+ unsigned int script_index[2], language_index[2];
+
+ private:
unsigned int current_stage[2]; /* GSUB/GPOS */
- hb_prealloced_array_t<feature_info_t,16> feature_infos;
- hb_prealloced_array_t<pause_info_t, 1> pauses[2]; /* GSUB/GPOS */
+ hb_prealloced_array_t<feature_info_t, 32> feature_infos;
+ hb_prealloced_array_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */
};
diff --git a/src/hb-ot-map.cc b/src/hb-ot-map.cc
index bebf3ed..4985eb2 100644
--- a/src/hb-ot-map.cc
+++ b/src/hb-ot-map.cc
@@ -1,6 +1,6 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
- * Copyright © 2010,2011 Google, Inc.
+ * Copyright © 2010,2011,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -28,150 +28,154 @@
#include "hb-ot-map-private.hh"
-#include "hb-ot-shape-private.hh"
-
+#include "hb-ot-layout-private.hh"
void
hb_ot_map_t::add_lookups (hb_face_t *face,
unsigned int table_index,
unsigned int feature_index,
- hb_mask_t mask)
+ hb_mask_t mask,
+ bool auto_zwj)
{
unsigned int lookup_indices[32];
unsigned int offset, len;
+ unsigned int table_lookup_count;
+
+ table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
offset = 0;
do {
len = ARRAY_LENGTH (lookup_indices);
- hb_ot_layout_feature_get_lookup_indexes (face,
- table_tags[table_index],
- feature_index,
- offset, &len,
- lookup_indices);
+ hb_ot_layout_feature_get_lookups (face,
+ table_tags[table_index],
+ feature_index,
+ offset, &len,
+ lookup_indices);
- for (unsigned int i = 0; i < len; i++) {
+ for (unsigned int i = 0; i < len; i++)
+ {
+ if (lookup_indices[i] >= table_lookup_count)
+ continue;
hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
if (unlikely (!lookup))
return;
lookup->mask = mask;
lookup->index = lookup_indices[i];
+ lookup->auto_zwj = auto_zwj;
}
offset += len;
} while (len == ARRAY_LENGTH (lookup_indices));
}
+hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
+ const hb_segment_properties_t *props_)
+{
+ memset (this, 0, sizeof (*this));
+
+ face = face_;
+ props = *props_;
+
+
+ /* Fetch script/language indices for GSUB/GPOS. We need these later to skip
+ * features not available in either table and not waste precious bits for them. */
+
+ hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
+ hb_tag_t language_tag;
+
+ hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
+ language_tag = hb_ot_tag_from_language (props.language);
+
+ for (unsigned int table_index = 0; table_index < 2; table_index++) {
+ hb_tag_t table_tag = table_tags[table_index];
+ found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
+ hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+ }
+}
-void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global)
+void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
+ hb_ot_map_feature_flags_t flags)
{
feature_info_t *info = feature_infos.push();
if (unlikely (!info)) return;
+ if (unlikely (!tag)) return;
info->tag = tag;
info->seq = feature_infos.len;
info->max_value = value;
- info->global = global;
- info->default_value = global ? value : 0;
+ info->flags = flags;
+ info->default_value = (flags & F_GLOBAL) ? value : 0;
info->stage[0] = current_stage[0];
info->stage[1] = current_stage[1];
}
-void hb_ot_map_t::apply (unsigned int table_index,
- hb_ot_map_t::apply_lookup_func_t apply_lookup_func,
- void *face_or_font,
- hb_buffer_t *buffer) const
-{
- unsigned int i = 0;
-
- for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
- const pause_map_t *pause = &pauses[table_index][pause_index];
- for (; i < pause->num_lookups; i++)
- apply_lookup_func (face_or_font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
-
- pause->callback.func (this, face_or_font, buffer, pause->callback.user_data);
- }
-
- for (; i < lookups[table_index].len; i++)
- apply_lookup_func (face_or_font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask);
-}
-void hb_ot_map_t::substitute_closure (hb_face_t *face,
- hb_set_t *glyphs) const
+void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
{
- unsigned int table_index = 0;
- unsigned int i = 0;
-
- for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) {
- const pause_map_t *pause = &pauses[table_index][pause_index];
- for (; i < pause->num_lookups; i++)
- hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index);
- }
-
- for (; i < lookups[table_index].len; i++)
- hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index);
+ for (unsigned int i = 0; i < lookups[table_index].len; i++)
+ hb_set_add (lookups_out, lookups[table_index][i].index);
}
-void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data)
+void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
{
- if (pause_func) {
- pause_info_t *p = pauses[table_index].push ();
- if (likely (p)) {
- p->stage = current_stage[table_index];
- p->callback.func = pause_func;
- p->callback.user_data = user_data;
- }
+ stage_info_t *s = stages[table_index].push ();
+ if (likely (s)) {
+ s->index = current_stage[table_index];
+ s->pause_func = pause_func;
}
current_stage[table_index]++;
}
void
-hb_ot_map_builder_t::compile (hb_face_t *face,
- const hb_segment_properties_t *props,
- hb_ot_map_t &m)
+hb_ot_map_builder_t::compile (hb_ot_map_t &m)
{
- m.global_mask = 1;
+ m.global_mask = 1;
- if (!feature_infos.len)
- return;
-
-
- /* Fetch script/language indices for GSUB/GPOS. We need these later to skip
- * features not available in either table and not waste precious bits for them. */
-
- hb_tag_t script_tags[3] = {HB_TAG_NONE};
- hb_tag_t language_tag;
-
- hb_ot_tags_from_script (props->script, &script_tags[0], &script_tags[1]);
- language_tag = hb_ot_tag_from_language (props->language);
+ unsigned int required_feature_index[2];
+ hb_tag_t required_feature_tag[2];
+ /* We default to applying required feature in stage 0. If the required
+ * feature has a tag that is known to the shaper, we apply required feature
+ * in the stage for that tag.
+ */
+ unsigned int required_feature_stage[2] = {0, 0};
- unsigned int script_index[2], language_index[2];
- for (unsigned int table_index = 0; table_index < 2; table_index++) {
- hb_tag_t table_tag = table_tags[table_index];
- hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &m.chosen_script[table_index]);
- hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
+ for (unsigned int table_index = 0; table_index < 2; table_index++)
+ {
+ m.chosen_script[table_index] = chosen_script[table_index];
+ m.found_script[table_index] = found_script[table_index];
+
+ hb_ot_layout_language_get_required_feature (face,
+ table_tags[table_index],
+ script_index[table_index],
+ language_index[table_index],
+ &required_feature_index[table_index],
+ &required_feature_tag[table_index]);
}
+ if (!feature_infos.len)
+ return;
/* Sort features and merge duplicates */
{
- feature_infos.sort ();
+ feature_infos.qsort ();
unsigned int j = 0;
for (unsigned int i = 1; i < feature_infos.len; i++)
if (feature_infos[i].tag != feature_infos[j].tag)
feature_infos[++j] = feature_infos[i];
else {
- if (feature_infos[i].global) {
- feature_infos[j].global = true;
+ if (feature_infos[i].flags & F_GLOBAL) {
+ feature_infos[j].flags |= F_GLOBAL;
feature_infos[j].max_value = feature_infos[i].max_value;
feature_infos[j].default_value = feature_infos[i].default_value;
} else {
- feature_infos[j].global = false;
+ feature_infos[j].flags &= ~F_GLOBAL;
feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
+ /* Inherit default_value from j */
}
+ feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
- /* Inherit default_value from j */
}
feature_infos.shrink (j + 1);
}
@@ -179,12 +183,13 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
/* Allocate bits now */
unsigned int next_bit = 1;
- for (unsigned int i = 0; i < feature_infos.len; i++) {
+ for (unsigned int i = 0; i < feature_infos.len; i++)
+ {
const feature_info_t *info = &feature_infos[i];
unsigned int bits_needed;
- if (info->global && info->max_value == 1)
+ if ((info->flags & F_GLOBAL) && info->max_value == 1)
/* Uses the global bit */
bits_needed = 0;
else
@@ -194,16 +199,24 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
continue; /* Feature disabled, or not enough bits. */
- bool found = false;
+ hb_bool_t found = false;
unsigned int feature_index[2];
for (unsigned int table_index = 0; table_index < 2; table_index++)
+ {
+ if (required_feature_tag[table_index] == info->tag)
+ {
+ required_feature_stage[table_index] = info->stage[table_index];
+ found = true;
+ continue;
+ }
found |= hb_ot_layout_language_find_feature (face,
table_tags[table_index],
script_index[table_index],
language_index[table_index],
info->tag,
&feature_index[table_index]);
- if (!found)
+ }
+ if (!found && !(info->flags & F_HAS_FALLBACK))
continue;
@@ -216,7 +229,8 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
map->index[1] = feature_index[1];
map->stage[0] = info->stage[0];
map->stage[1] = info->stage[1];
- if (info->global && info->max_value == 1) {
+ map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
+ if ((info->flags & F_GLOBAL) && info->max_value == 1) {
/* Uses the global bit */
map->shift = 0;
map->mask = 1;
@@ -224,66 +238,68 @@ hb_ot_map_builder_t::compile (hb_face_t *face,
map->shift = next_bit;
map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
next_bit += bits_needed;
- if (info->global)
- m.global_mask |= (info->default_value << map->shift) & map->mask;
+ m.global_mask |= (info->default_value << map->shift) & map->mask;
}
map->_1_mask = (1 << map->shift) & map->mask;
+ map->needs_fallback = !found;
}
feature_infos.shrink (0); /* Done with these */
- add_gsub_pause (NULL, NULL);
- add_gpos_pause (NULL, NULL);
-
- for (unsigned int table_index = 0; table_index < 2; table_index++) {
- hb_tag_t table_tag = table_tags[table_index];
+ add_gsub_pause (NULL);
+ add_gpos_pause (NULL);
+ for (unsigned int table_index = 0; table_index < 2; table_index++)
+ {
/* Collect lookup indices for features */
- unsigned int required_feature_index;
- if (hb_ot_layout_language_get_required_feature_index (face,
- table_tag,
- script_index[table_index],
- language_index[table_index],
- &required_feature_index))
- m.add_lookups (face, table_index, required_feature_index, 1);
-
- unsigned int pause_index = 0;
+ unsigned int stage_index = 0;
unsigned int last_num_lookups = 0;
for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
{
+ if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
+ required_feature_stage[table_index] == stage)
+ m.add_lookups (face, table_index,
+ required_feature_index[table_index],
+ 1 /* mask */,
+ true /* auto_zwj */);
+
for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage)
- m.add_lookups (face, table_index, m.features[i].index[table_index], m.features[i].mask);
+ m.add_lookups (face, table_index,
+ m.features[i].index[table_index],
+ m.features[i].mask,
+ m.features[i].auto_zwj);
/* Sort lookups and merge duplicates */
if (last_num_lookups < m.lookups[table_index].len)
{
- m.lookups[table_index].sort (last_num_lookups, m.lookups[table_index].len);
+ m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len);
unsigned int j = last_num_lookups;
for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)
if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
m.lookups[table_index][++j] = m.lookups[table_index][i];
else
+ {
m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
+ m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
+ }
m.lookups[table_index].shrink (j + 1);
}
last_num_lookups = m.lookups[table_index].len;
- if (pause_index < pauses[table_index].len && pauses[table_index][pause_index].stage == stage) {
- hb_ot_map_t::pause_map_t *pause_map = m.pauses[table_index].push ();
- if (likely (pause_map)) {
- pause_map->num_lookups = last_num_lookups;
- pause_map->callback = pauses[table_index][pause_index].callback;
+ if (stage_index < stages[table_index].len && stages[table_index][stage_index].index == stage) {
+ hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
+ if (likely (stage_map)) {
+ stage_map->last_lookup = last_num_lookups;
+ stage_map->pause_func = stages[table_index][stage_index].pause_func;
}
- pause_index++;
+ stage_index++;
}
}
}
}
-
-
diff --git a/src/hb-ot-maxp-table.hh b/src/hb-ot-maxp-table.hh
index e270490..0d9a0fa 100644
--- a/src/hb-ot-maxp-table.hh
+++ b/src/hb-ot-maxp-table.hh
@@ -30,6 +30,8 @@
#include "hb-open-type-private.hh"
+namespace OT {
+
/*
* maxp -- The Maximum Profile Table
@@ -39,27 +41,31 @@
struct maxp
{
- static const hb_tag_t Tag = HB_OT_TAG_maxp;
+ static const hb_tag_t tableTag = HB_OT_TAG_maxp;
- inline unsigned int get_num_glyphs (void) const {
+ inline unsigned int get_num_glyphs (void) const
+ {
return numGlyphs;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
- likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000)));
+ likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000u)));
}
/* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
- private:
+ protected:
FixedVersion version; /* Version of the maxp table (0.5 or 1.0),
- * 0x00005000 or 0x00010000. */
+ * 0x00005000u or 0x00010000u. */
USHORT numGlyphs; /* The number of glyphs in the font. */
public:
DEFINE_SIZE_STATIC (6);
};
+} /* namespace OT */
+
#endif /* HB_OT_MAXP_TABLE_HH */
diff --git a/src/hb-ot-name-table.hh b/src/hb-ot-name-table.hh
index 9077c8c..21450c6 100644
--- a/src/hb-ot-name-table.hh
+++ b/src/hb-ot-name-table.hh
@@ -30,6 +30,8 @@
#include "hb-open-type-private.hh"
+namespace OT {
+
/*
* name -- The Naming Table
@@ -54,8 +56,9 @@ struct NameRecord
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
+ TRACE_SANITIZE (this);
/* We can check from base all the way up to the end of string... */
return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
}
@@ -72,7 +75,7 @@ struct NameRecord
struct name
{
- static const hb_tag_t Tag = HB_OT_TAG_name;
+ static const hb_tag_t tableTag = HB_OT_TAG_name;
inline unsigned int get_name (unsigned int platform_id,
unsigned int encoding_id,
@@ -96,8 +99,11 @@ struct name
return length;
}
- inline bool sanitize_records (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline unsigned int get_size (void) const
+ { return min_size + count * nameRecord[0].min_size; }
+
+ inline bool sanitize_records (hb_sanitize_context_t *c) const {
+ TRACE_SANITIZE (this);
char *string_pool = (char *) this + stringOffset;
unsigned int _count = count;
for (unsigned int i = 0; i < _count; i++)
@@ -105,8 +111,9 @@ struct name
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE ();
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
likely (format == 0 || format == 1) &&
c->check_array (nameRecord, nameRecord[0].static_size, count) &&
@@ -114,15 +121,16 @@ struct name
}
/* We only implement format 0 for now. */
- private:
USHORT format; /* Format selector (=0/1). */
USHORT count; /* Number of name records. */
- Offset stringOffset; /* Offset to start of string storage (from start of table). */
+ Offset<> stringOffset; /* Offset to start of string storage (from start of table). */
NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */
public:
DEFINE_SIZE_ARRAY (6, nameRecord);
};
+} /* namespace OT */
+
#endif /* HB_OT_NAME_TABLE_HH */
diff --git a/src/hb-ot-shape-complex-arabic-fallback.hh b/src/hb-ot-shape-complex-arabic-fallback.hh
new file mode 100644
index 0000000..a77f24e
--- /dev/null
+++ b/src/hb-ot-shape-complex-arabic-fallback.hh
@@ -0,0 +1,354 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
+#define HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-private.hh"
+#include "hb-ot-layout-gsub-table.hh"
+
+
+/* Features ordered the same as the entries in shaping_table rows,
+ * followed by rlig. Don't change. */
+static const hb_tag_t arabic_fallback_features[] =
+{
+ HB_TAG('i','n','i','t'),
+ HB_TAG('m','e','d','i'),
+ HB_TAG('f','i','n','a'),
+ HB_TAG('i','s','o','l'),
+ HB_TAG('r','l','i','g'),
+};
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font,
+ unsigned int feature_index)
+{
+ OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+ OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1];
+ unsigned int num_glyphs = 0;
+
+ /* Populate arrays */
+ for (hb_codepoint_t u = SHAPING_TABLE_FIRST; u < SHAPING_TABLE_LAST + 1; u++)
+ {
+ hb_codepoint_t s = shaping_table[u - SHAPING_TABLE_FIRST][feature_index];
+ hb_codepoint_t u_glyph, s_glyph;
+
+ if (!s ||
+ !hb_font_get_glyph (font, u, 0, &u_glyph) ||
+ !hb_font_get_glyph (font, s, 0, &s_glyph) ||
+ u_glyph == s_glyph ||
+ u_glyph > 0xFFFFu || s_glyph > 0xFFFFu)
+ continue;
+
+ glyphs[num_glyphs].set (u_glyph);
+ substitutes[num_glyphs].set (s_glyph);
+
+ num_glyphs++;
+ }
+
+ if (!num_glyphs)
+ return NULL;
+
+ /* Bubble-sort!
+ * May not be good-enough for presidential candidate interviews, but good-enough for us... */
+ hb_bubble_sort (&glyphs[0], num_glyphs, OT::GlyphID::cmp, &substitutes[0]);
+
+ OT::Supplier<OT::GlyphID> glyphs_supplier (glyphs, num_glyphs);
+ OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
+
+ /* Each glyph takes four bytes max, and there's some overhead. */
+ char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128];
+ OT::hb_serialize_context_t c (buf, sizeof (buf));
+ OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
+ bool ret = lookup->serialize_single (&c,
+ OT::LookupFlag::IgnoreMarks,
+ glyphs_supplier,
+ substitutes_supplier,
+ num_glyphs);
+ c.end_serialize ();
+ /* TODO sanitize the results? */
+
+ return ret ? c.copy<OT::SubstLookup> () : NULL;
+}
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font)
+{
+ OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)];
+ unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)];
+ unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)];
+ unsigned int num_first_glyphs = 0;
+
+ /* We know that all our ligatures are 2-component */
+ OT::GlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)];
+ unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)];
+ OT::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */];
+ unsigned int num_ligatures = 0;
+
+ /* Populate arrays */
+
+ /* Sort out the first-glyphs */
+ for (unsigned int first_glyph_idx = 0; first_glyph_idx < ARRAY_LENGTH (first_glyphs); first_glyph_idx++)
+ {
+ hb_codepoint_t first_u = ligature_table[first_glyph_idx].first;
+ hb_codepoint_t first_glyph;
+ if (!hb_font_get_glyph (font, first_u, 0, &first_glyph))
+ continue;
+ first_glyphs[num_first_glyphs].set (first_glyph);
+ ligature_per_first_glyph_count_list[num_first_glyphs] = 0;
+ first_glyphs_indirection[num_first_glyphs] = first_glyph_idx;
+ num_first_glyphs++;
+ }
+ hb_bubble_sort (&first_glyphs[0], num_first_glyphs, OT::GlyphID::cmp, &first_glyphs_indirection[0]);
+
+ /* Now that the first-glyphs are sorted, walk again, populate ligatures. */
+ for (unsigned int i = 0; i < num_first_glyphs; i++)
+ {
+ unsigned int first_glyph_idx = first_glyphs_indirection[i];
+
+ for (unsigned int second_glyph_idx = 0; second_glyph_idx < ARRAY_LENGTH (ligature_table[0].ligatures); second_glyph_idx++)
+ {
+ hb_codepoint_t second_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].second;
+ hb_codepoint_t ligature_u = ligature_table[first_glyph_idx].ligatures[second_glyph_idx].ligature;
+ hb_codepoint_t second_glyph, ligature_glyph;
+ if (!second_u ||
+ !hb_font_get_glyph (font, second_u, 0, &second_glyph) ||
+ !hb_font_get_glyph (font, ligature_u, 0, &ligature_glyph))
+ continue;
+
+ ligature_per_first_glyph_count_list[i]++;
+
+ ligature_list[num_ligatures].set (ligature_glyph);
+ component_count_list[num_ligatures] = 2;
+ component_list[num_ligatures].set (second_glyph);
+ num_ligatures++;
+ }
+ }
+
+ if (!num_ligatures)
+ return NULL;
+
+ OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs);
+ OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs);
+ OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures);
+ OT::Supplier<unsigned int > component_count_supplier (component_count_list, num_ligatures);
+ OT::Supplier<OT::GlyphID> component_supplier (component_list, num_ligatures);
+
+ /* 16 bytes per ligature ought to be enough... */
+ char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128];
+ OT::hb_serialize_context_t c (buf, sizeof (buf));
+ OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
+ bool ret = lookup->serialize_ligature (&c,
+ OT::LookupFlag::IgnoreMarks,
+ first_glyphs_supplier,
+ ligature_per_first_glyph_count_supplier,
+ num_first_glyphs,
+ ligatures_supplier,
+ component_count_supplier,
+ component_supplier);
+
+ c.end_serialize ();
+ /* TODO sanitize the results? */
+
+ return ret ? c.copy<OT::SubstLookup> () : NULL;
+}
+
+static OT::SubstLookup *
+arabic_fallback_synthesize_lookup (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ unsigned int feature_index)
+{
+ if (feature_index < 4)
+ return arabic_fallback_synthesize_lookup_single (plan, font, feature_index);
+ else
+ return arabic_fallback_synthesize_lookup_ligature (plan, font);
+}
+
+#define ARABIC_FALLBACK_MAX_LOOKUPS 5
+
+struct arabic_fallback_plan_t
+{
+ ASSERT_POD ();
+
+ unsigned int num_lookups;
+ bool free_lookups;
+
+ hb_mask_t mask_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+ OT::SubstLookup *lookup_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+ hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
+};
+
+static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
+
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
+#define HB_WITH_WIN1256
+#endif
+
+#ifdef HB_WITH_WIN1256
+#include "hb-ot-shape-complex-arabic-win1256.hh"
+#endif
+
+struct ManifestLookup {
+ OT::Tag tag;
+ OT::OffsetTo<OT::SubstLookup> lookupOffset;
+};
+typedef OT::ArrayOf<ManifestLookup> Manifest;
+
+static bool
+arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan,
+ const hb_ot_shape_plan_t *plan,
+ hb_font_t *font)
+{
+#ifdef HB_WITH_WIN1256
+ /* Does this font look like it's Windows-1256-encoded? */
+ hb_codepoint_t g;
+ if (!(hb_font_get_glyph (font, 0x0627u, 0, &g) && g == 199 /* ALEF */ &&
+ hb_font_get_glyph (font, 0x0644u, 0, &g) && g == 225 /* LAM */ &&
+ hb_font_get_glyph (font, 0x0649u, 0, &g) && g == 236 /* ALEF MAKSURA */ &&
+ hb_font_get_glyph (font, 0x064Au, 0, &g) && g == 237 /* YEH */ &&
+ hb_font_get_glyph (font, 0x0652u, 0, &g) && g == 250 /* SUKUN */))
+ return false;
+
+ const Manifest &manifest = reinterpret_cast<const Manifest&> (arabic_win1256_gsub_lookups.manifest);
+ ASSERT_STATIC (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup)
+ <= ARABIC_FALLBACK_MAX_LOOKUPS);
+ /* TODO sanitize the table? */
+
+ unsigned j = 0;
+ unsigned int count = manifest.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ fallback_plan->mask_array[j] = plan->map.get_1_mask (manifest[i].tag);
+ if (fallback_plan->mask_array[j])
+ {
+ fallback_plan->lookup_array[j] = const_cast<OT::SubstLookup*> (&(&manifest+manifest[i].lookupOffset));
+ if (fallback_plan->lookup_array[j])
+ {
+ fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+ j++;
+ }
+ }
+ }
+
+ fallback_plan->num_lookups = j;
+ fallback_plan->free_lookups = false;
+
+ return j > 0;
+#else
+ return false;
+#endif
+}
+
+static bool
+arabic_fallback_plan_init_unicode (arabic_fallback_plan_t *fallback_plan,
+ const hb_ot_shape_plan_t *plan,
+ hb_font_t *font)
+{
+ ASSERT_STATIC (ARRAY_LENGTH_CONST(arabic_fallback_features) <= ARABIC_FALLBACK_MAX_LOOKUPS);
+ unsigned int j = 0;
+ for (unsigned int i = 0; i < ARRAY_LENGTH(arabic_fallback_features) ; i++)
+ {
+ fallback_plan->mask_array[j] = plan->map.get_1_mask (arabic_fallback_features[i]);
+ if (fallback_plan->mask_array[j])
+ {
+ fallback_plan->lookup_array[j] = arabic_fallback_synthesize_lookup (plan, font, i);
+ if (fallback_plan->lookup_array[j])
+ {
+ fallback_plan->accel_array[j].init (*fallback_plan->lookup_array[j]);
+ j++;
+ }
+ }
+ }
+
+ fallback_plan->num_lookups = j;
+ fallback_plan->free_lookups = true;
+
+ return j > 0;
+}
+
+static arabic_fallback_plan_t *
+arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font)
+{
+ arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
+ if (unlikely (!fallback_plan))
+ return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
+
+ fallback_plan->num_lookups = 0;
+ fallback_plan->free_lookups = false;
+
+ /* Try synthesizing GSUB table using Unicode Arabic Presentation Forms,
+ * in case the font has cmap entries for the presentation-forms characters. */
+ if (arabic_fallback_plan_init_unicode (fallback_plan, plan, font))
+ return fallback_plan;
+
+ /* See if this looks like a Windows-1256-encoded font. If it does, use a
+ * hand-coded GSUB table. */
+ if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
+ return fallback_plan;
+
+ free (fallback_plan);
+ return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
+}
+
+static void
+arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
+{
+ if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
+ return;
+
+ for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
+ if (fallback_plan->lookup_array[i])
+ {
+ fallback_plan->accel_array[i].fini ();
+ if (fallback_plan->free_lookups)
+ free (fallback_plan->lookup_array[i]);
+ }
+
+ free (fallback_plan);
+}
+
+static void
+arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ OT::hb_apply_context_t c (0, font, buffer);
+ for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
+ if (fallback_plan->lookup_array[i]) {
+ c.set_lookup_mask (fallback_plan->mask_array[i]);
+ hb_ot_layout_substitute_lookup (&c,
+ *fallback_plan->lookup_array[i],
+ fallback_plan->accel_array[i]);
+ }
+}
+
+
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_FALLBACK_HH */
diff --git a/src/hb-ot-shape-complex-arabic-table.hh b/src/hb-ot-shape-complex-arabic-table.hh
index df85086..1710049 100644
--- a/src/hb-ot-shape-complex-arabic-table.hh
+++ b/src/hb-ot-shape-complex-arabic-table.hh
@@ -2,12 +2,14 @@
/*
* The following table is generated by running:
*
- * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt
+ * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
*
* on files with these headers:
*
- * # ArabicShaping-6.1.0.txt
- * # Date: 2011-04-15, 23:16:00 GMT [KW]
+ * # ArabicShaping-7.0.0.txt
+ * # Date: 2014-02-14, 21:00:00 GMT [RP, KW, LI]
+ * # Blocks-7.0.0.txt
+ * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
* UnicodeData.txt does not have a header.
*/
@@ -15,924 +17,363 @@
#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
+#define X JOINING_TYPE_X
+#define R JOINING_TYPE_R
+#define U JOINING_TYPE_U
+#define A JOINING_GROUP_ALAPH
+#define DR JOINING_GROUP_DALATH_RISH
+#define L JOINING_TYPE_L
+#define C JOINING_TYPE_C
+#define D JOINING_TYPE_D
+
static const uint8_t joining_table[] =
{
- /* Arabic Characters */
-
- JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */
- JOINING_TYPE_U, /* 0601; ARABIC SIGN SANAH; U; No_Joining_Group */
- JOINING_TYPE_U, /* 0602; ARABIC FOOTNOTE MARKER; U; No_Joining_Group */
- JOINING_TYPE_U, /* 0603; ARABIC SIGN SAFHA; U; No_Joining_Group */
- JOINING_TYPE_U, /* 0604; ARABIC SIGN SAMVAT; U; No_Joining_Group */
- JOINING_TYPE_X, /* 0605 */
- JOINING_TYPE_X, /* 0606 */
- JOINING_TYPE_X, /* 0607 */
- JOINING_TYPE_U, /* 0608; ARABIC RAY; U; No_Joining_Group */
- JOINING_TYPE_X, /* 0609 */
- JOINING_TYPE_X, /* 060A */
- JOINING_TYPE_U, /* 060B; AFGHANI SIGN; U; No_Joining_Group */
- JOINING_TYPE_X, /* 060C */
- JOINING_TYPE_X, /* 060D */
- JOINING_TYPE_X, /* 060E */
- JOINING_TYPE_X, /* 060F */
- JOINING_TYPE_X, /* 0610 */
- JOINING_TYPE_X, /* 0611 */
- JOINING_TYPE_X, /* 0612 */
- JOINING_TYPE_X, /* 0613 */
- JOINING_TYPE_X, /* 0614 */
- JOINING_TYPE_X, /* 0615 */
- JOINING_TYPE_X, /* 0616 */
- JOINING_TYPE_X, /* 0617 */
- JOINING_TYPE_X, /* 0618 */
- JOINING_TYPE_X, /* 0619 */
- JOINING_TYPE_X, /* 061A */
- JOINING_TYPE_X, /* 061B */
- JOINING_TYPE_X, /* 061C */
- JOINING_TYPE_X, /* 061D */
- JOINING_TYPE_X, /* 061E */
- JOINING_TYPE_X, /* 061F */
- JOINING_TYPE_D, /* 0620; DOTLESS YEH WITH SEPARATE RING BELOW; D; YEH */
- JOINING_TYPE_U, /* 0621; HAMZA; U; No_Joining_Group */
- JOINING_TYPE_R, /* 0622; ALEF WITH MADDA ABOVE; R; ALEF */
- JOINING_TYPE_R, /* 0623; ALEF WITH HAMZA ABOVE; R; ALEF */
- JOINING_TYPE_R, /* 0624; WAW WITH HAMZA ABOVE; R; WAW */
- JOINING_TYPE_R, /* 0625; ALEF WITH HAMZA BELOW; R; ALEF */
- JOINING_TYPE_D, /* 0626; DOTLESS YEH WITH HAMZA ABOVE; D; YEH */
- JOINING_TYPE_R, /* 0627; ALEF; R; ALEF */
- JOINING_TYPE_D, /* 0628; BEH; D; BEH */
- JOINING_TYPE_R, /* 0629; TEH MARBUTA; R; TEH MARBUTA */
- JOINING_TYPE_D, /* 062A; DOTLESS BEH WITH 2 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 062B; DOTLESS BEH WITH 3 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 062C; HAH WITH DOT BELOW; D; HAH */
- JOINING_TYPE_D, /* 062D; HAH; D; HAH */
- JOINING_TYPE_D, /* 062E; HAH WITH DOT ABOVE; D; HAH */
- JOINING_TYPE_R, /* 062F; DAL; R; DAL */
- JOINING_TYPE_R, /* 0630; DAL WITH DOT ABOVE; R; DAL */
- JOINING_TYPE_R, /* 0631; REH; R; REH */
- JOINING_TYPE_R, /* 0632; REH WITH DOT ABOVE; R; REH */
- JOINING_TYPE_D, /* 0633; SEEN; D; SEEN */
- JOINING_TYPE_D, /* 0634; SEEN WITH 3 DOTS ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 0635; SAD; D; SAD */
- JOINING_TYPE_D, /* 0636; SAD WITH DOT ABOVE; D; SAD */
- JOINING_TYPE_D, /* 0637; TAH; D; TAH */
- JOINING_TYPE_D, /* 0638; TAH WITH DOT ABOVE; D; TAH */
- JOINING_TYPE_D, /* 0639; AIN; D; AIN */
- JOINING_TYPE_D, /* 063A; AIN WITH DOT ABOVE; D; AIN */
- JOINING_TYPE_D, /* 063B; KEHEH WITH 2 DOTS ABOVE; D; GAF */
- JOINING_TYPE_D, /* 063C; KEHEH WITH 3 DOTS BELOW; D; GAF */
- JOINING_TYPE_D, /* 063D; FARSI YEH WITH INVERTED V ABOVE; D; FARSI YEH */
- JOINING_TYPE_D, /* 063E; FARSI YEH WITH 2 DOTS ABOVE; D; FARSI YEH */
- JOINING_TYPE_D, /* 063F; FARSI YEH WITH 3 DOTS ABOVE; D; FARSI YEH */
- JOINING_TYPE_C, /* 0640; TATWEEL; C; No_Joining_Group */
- JOINING_TYPE_D, /* 0641; FEH; D; FEH */
- JOINING_TYPE_D, /* 0642; QAF; D; QAF */
- JOINING_TYPE_D, /* 0643; KAF; D; KAF */
- JOINING_TYPE_D, /* 0644; LAM; D; LAM */
- JOINING_TYPE_D, /* 0645; MEEM; D; MEEM */
- JOINING_TYPE_D, /* 0646; NOON; D; NOON */
- JOINING_TYPE_D, /* 0647; HEH; D; HEH */
- JOINING_TYPE_R, /* 0648; WAW; R; WAW */
- JOINING_TYPE_D, /* 0649; DOTLESS YEH; D; YEH */
- JOINING_TYPE_D, /* 064A; YEH; D; YEH */
- JOINING_TYPE_X, /* 064B */
- JOINING_TYPE_X, /* 064C */
- JOINING_TYPE_X, /* 064D */
- JOINING_TYPE_X, /* 064E */
- JOINING_TYPE_X, /* 064F */
- JOINING_TYPE_X, /* 0650 */
- JOINING_TYPE_X, /* 0651 */
- JOINING_TYPE_X, /* 0652 */
- JOINING_TYPE_X, /* 0653 */
- JOINING_TYPE_X, /* 0654 */
- JOINING_TYPE_X, /* 0655 */
- JOINING_TYPE_X, /* 0656 */
- JOINING_TYPE_X, /* 0657 */
- JOINING_TYPE_X, /* 0658 */
- JOINING_TYPE_X, /* 0659 */
- JOINING_TYPE_X, /* 065A */
- JOINING_TYPE_X, /* 065B */
- JOINING_TYPE_X, /* 065C */
- JOINING_TYPE_X, /* 065D */
- JOINING_TYPE_X, /* 065E */
- JOINING_TYPE_X, /* 065F */
- JOINING_TYPE_X, /* 0660 */
- JOINING_TYPE_X, /* 0661 */
- JOINING_TYPE_X, /* 0662 */
- JOINING_TYPE_X, /* 0663 */
- JOINING_TYPE_X, /* 0664 */
- JOINING_TYPE_X, /* 0665 */
- JOINING_TYPE_X, /* 0666 */
- JOINING_TYPE_X, /* 0667 */
- JOINING_TYPE_X, /* 0668 */
- JOINING_TYPE_X, /* 0669 */
- JOINING_TYPE_X, /* 066A */
- JOINING_TYPE_X, /* 066B */
- JOINING_TYPE_X, /* 066C */
- JOINING_TYPE_X, /* 066D */
- JOINING_TYPE_D, /* 066E; DOTLESS BEH; D; BEH */
- JOINING_TYPE_D, /* 066F; DOTLESS QAF; D; QAF */
- JOINING_TYPE_X, /* 0670 */
- JOINING_TYPE_R, /* 0671; ALEF WITH WASLA ABOVE; R; ALEF */
- JOINING_TYPE_R, /* 0672; ALEF WITH WAVY HAMZA ABOVE; R; ALEF */
- JOINING_TYPE_R, /* 0673; ALEF WITH WAVY HAMZA BELOW; R; ALEF */
- JOINING_TYPE_U, /* 0674; HIGH HAMZA; U; No_Joining_Group */
- JOINING_TYPE_R, /* 0675; HIGH HAMZA ALEF; R; ALEF */
- JOINING_TYPE_R, /* 0676; HIGH HAMZA WAW; R; WAW */
- JOINING_TYPE_R, /* 0677; HIGH HAMZA WAW WITH DAMMA ABOVE; R; WAW */
- JOINING_TYPE_D, /* 0678; HIGH HAMZA DOTLESS YEH; D; YEH */
- JOINING_TYPE_D, /* 0679; DOTLESS BEH WITH TAH ABOVE; D; BEH */
- JOINING_TYPE_D, /* 067A; DOTLESS BEH WITH VERTICAL 2 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 067B; DOTLESS BEH WITH VERTICAL 2 DOTS BELOW; D; BEH */
- JOINING_TYPE_D, /* 067C; DOTLESS BEH WITH ATTACHED RING BELOW AND 2 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 067D; DOTLESS BEH WITH INVERTED 3 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 067E; DOTLESS BEH WITH 3 DOTS BELOW; D; BEH */
- JOINING_TYPE_D, /* 067F; DOTLESS BEH WITH 4 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 0680; DOTLESS BEH WITH 4 DOTS BELOW; D; BEH */
- JOINING_TYPE_D, /* 0681; HAH WITH HAMZA ABOVE; D; HAH */
- JOINING_TYPE_D, /* 0682; HAH WITH VERTICAL 2 DOTS ABOVE; D; HAH */
- JOINING_TYPE_D, /* 0683; HAH WITH 2 DOTS BELOW; D; HAH */
- JOINING_TYPE_D, /* 0684; HAH WITH VERTICAL 2 DOTS BELOW; D; HAH */
- JOINING_TYPE_D, /* 0685; HAH WITH 3 DOTS ABOVE; D; HAH */
- JOINING_TYPE_D, /* 0686; HAH WITH 3 DOTS BELOW; D; HAH */
- JOINING_TYPE_D, /* 0687; HAH WITH 4 DOTS BELOW; D; HAH */
- JOINING_TYPE_R, /* 0688; DAL WITH TAH ABOVE; R; DAL */
- JOINING_TYPE_R, /* 0689; DAL WITH ATTACHED RING BELOW; R; DAL */
- JOINING_TYPE_R, /* 068A; DAL WITH DOT BELOW; R; DAL */
- JOINING_TYPE_R, /* 068B; DAL WITH DOT BELOW AND TAH ABOVE; R; DAL */
- JOINING_TYPE_R, /* 068C; DAL WITH 2 DOTS ABOVE; R; DAL */
- JOINING_TYPE_R, /* 068D; DAL WITH 2 DOTS BELOW; R; DAL */
- JOINING_TYPE_R, /* 068E; DAL WITH 3 DOTS ABOVE; R; DAL */
- JOINING_TYPE_R, /* 068F; DAL WITH INVERTED 3 DOTS ABOVE; R; DAL */
- JOINING_TYPE_R, /* 0690; DAL WITH 4 DOTS ABOVE; R; DAL */
- JOINING_TYPE_R, /* 0691; REH WITH TAH ABOVE; R; REH */
- JOINING_TYPE_R, /* 0692; REH WITH V ABOVE; R; REH */
- JOINING_TYPE_R, /* 0693; REH WITH ATTACHED RING BELOW; R; REH */
- JOINING_TYPE_R, /* 0694; REH WITH DOT BELOW; R; REH */
- JOINING_TYPE_R, /* 0695; REH WITH V BELOW; R; REH */
- JOINING_TYPE_R, /* 0696; REH WITH DOT BELOW AND DOT WITHIN; R; REH */
- JOINING_TYPE_R, /* 0697; REH WITH 2 DOTS ABOVE; R; REH */
- JOINING_TYPE_R, /* 0698; REH WITH 3 DOTS ABOVE; R; REH */
- JOINING_TYPE_R, /* 0699; REH WITH 4 DOTS ABOVE; R; REH */
- JOINING_TYPE_D, /* 069A; SEEN WITH DOT BELOW AND DOT ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 069B; SEEN WITH 3 DOTS BELOW; D; SEEN */
- JOINING_TYPE_D, /* 069C; SEEN WITH 3 DOTS BELOW AND 3 DOTS ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 069D; SAD WITH 2 DOTS BELOW; D; SAD */
- JOINING_TYPE_D, /* 069E; SAD WITH 3 DOTS ABOVE; D; SAD */
- JOINING_TYPE_D, /* 069F; TAH WITH 3 DOTS ABOVE; D; TAH */
- JOINING_TYPE_D, /* 06A0; AIN WITH 3 DOTS ABOVE; D; AIN */
- JOINING_TYPE_D, /* 06A1; DOTLESS FEH; D; FEH */
- JOINING_TYPE_D, /* 06A2; DOTLESS FEH WITH DOT BELOW; D; FEH */
- JOINING_TYPE_D, /* 06A3; FEH WITH DOT BELOW; D; FEH */
- JOINING_TYPE_D, /* 06A4; DOTLESS FEH WITH 3 DOTS ABOVE; D; FEH */
- JOINING_TYPE_D, /* 06A5; DOTLESS FEH WITH 3 DOTS BELOW; D; FEH */
- JOINING_TYPE_D, /* 06A6; DOTLESS FEH WITH 4 DOTS ABOVE; D; FEH */
- JOINING_TYPE_D, /* 06A7; DOTLESS QAF WITH DOT ABOVE; D; QAF */
- JOINING_TYPE_D, /* 06A8; DOTLESS QAF WITH 3 DOTS ABOVE; D; QAF */
- JOINING_TYPE_D, /* 06A9; KEHEH; D; GAF */
- JOINING_TYPE_D, /* 06AA; SWASH KAF; D; SWASH KAF */
- JOINING_TYPE_D, /* 06AB; KEHEH WITH ATTACHED RING BELOW; D; GAF */
- JOINING_TYPE_D, /* 06AC; KAF WITH DOT ABOVE; D; KAF */
- JOINING_TYPE_D, /* 06AD; KAF WITH 3 DOTS ABOVE; D; KAF */
- JOINING_TYPE_D, /* 06AE; KAF WITH 3 DOTS BELOW; D; KAF */
- JOINING_TYPE_D, /* 06AF; GAF; D; GAF */
- JOINING_TYPE_D, /* 06B0; GAF WITH ATTACHED RING BELOW; D; GAF */
- JOINING_TYPE_D, /* 06B1; GAF WITH 2 DOTS ABOVE; D; GAF */
- JOINING_TYPE_D, /* 06B2; GAF WITH 2 DOTS BELOW; D; GAF */
- JOINING_TYPE_D, /* 06B3; GAF WITH VERTICAL 2 DOTS BELOW; D; GAF */
- JOINING_TYPE_D, /* 06B4; GAF WITH 3 DOTS ABOVE; D; GAF */
- JOINING_TYPE_D, /* 06B5; LAM WITH V ABOVE; D; LAM */
- JOINING_TYPE_D, /* 06B6; LAM WITH DOT ABOVE; D; LAM */
- JOINING_TYPE_D, /* 06B7; LAM WITH 3 DOTS ABOVE; D; LAM */
- JOINING_TYPE_D, /* 06B8; LAM WITH 3 DOTS BELOW; D; LAM */
- JOINING_TYPE_D, /* 06B9; NOON WITH DOT BELOW; D; NOON */
- JOINING_TYPE_D, /* 06BA; DOTLESS NOON; D; NOON */
- JOINING_TYPE_D, /* 06BB; DOTLESS NOON WITH TAH ABOVE; D; NOON */
- JOINING_TYPE_D, /* 06BC; NOON WITH ATTACHED RING BELOW; D; NOON */
- JOINING_TYPE_D, /* 06BD; NYA; D; NYA */
- JOINING_TYPE_D, /* 06BE; KNOTTED HEH; D; KNOTTED HEH */
- JOINING_TYPE_D, /* 06BF; HAH WITH 3 DOTS BELOW AND DOT ABOVE; D; HAH */
- JOINING_TYPE_R, /* 06C0; DOTLESS TEH MARBUTA WITH HAMZA ABOVE; R; TEH MARBUTA */
- JOINING_TYPE_D, /* 06C1; HEH GOAL; D; HEH GOAL */
- JOINING_TYPE_D, /* 06C2; HEH GOAL WITH HAMZA ABOVE; D; HEH GOAL */
- JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL */
- JOINING_TYPE_R, /* 06C4; WAW WITH ATTACHED RING WITHIN; R; WAW */
- JOINING_TYPE_R, /* 06C5; WAW WITH BAR; R; WAW */
- JOINING_TYPE_R, /* 06C6; WAW WITH V ABOVE; R; WAW */
- JOINING_TYPE_R, /* 06C7; WAW WITH DAMMA ABOVE; R; WAW */
- JOINING_TYPE_R, /* 06C8; WAW WITH ALEF ABOVE; R; WAW */
- JOINING_TYPE_R, /* 06C9; WAW WITH INVERTED V ABOVE; R; WAW */
- JOINING_TYPE_R, /* 06CA; WAW WITH 2 DOTS ABOVE; R; WAW */
- JOINING_TYPE_R, /* 06CB; WAW WITH 3 DOTS ABOVE; R; WAW */
- JOINING_TYPE_D, /* 06CC; FARSI YEH; D; FARSI YEH */
- JOINING_TYPE_R, /* 06CD; YEH WITH TAIL; R; YEH WITH TAIL */
- JOINING_TYPE_D, /* 06CE; FARSI YEH WITH V ABOVE; D; FARSI YEH */
- JOINING_TYPE_R, /* 06CF; WAW WITH DOT ABOVE; R; WAW */
- JOINING_TYPE_D, /* 06D0; DOTLESS YEH WITH VERTICAL 2 DOTS BELOW; D; YEH */
- JOINING_TYPE_D, /* 06D1; DOTLESS YEH WITH 3 DOTS BELOW; D; YEH */
- JOINING_TYPE_R, /* 06D2; YEH BARREE; R; YEH BARREE */
- JOINING_TYPE_R, /* 06D3; YEH BARREE WITH HAMZA ABOVE; R; YEH BARREE */
- JOINING_TYPE_X, /* 06D4 */
- JOINING_TYPE_R, /* 06D5; DOTLESS TEH MARBUTA; R; TEH MARBUTA */
- JOINING_TYPE_X, /* 06D6 */
- JOINING_TYPE_X, /* 06D7 */
- JOINING_TYPE_X, /* 06D8 */
- JOINING_TYPE_X, /* 06D9 */
- JOINING_TYPE_X, /* 06DA */
- JOINING_TYPE_X, /* 06DB */
- JOINING_TYPE_X, /* 06DC */
- JOINING_TYPE_U, /* 06DD; ARABIC END OF AYAH; U; No_Joining_Group */
- JOINING_TYPE_X, /* 06DE */
- JOINING_TYPE_X, /* 06DF */
- JOINING_TYPE_X, /* 06E0 */
- JOINING_TYPE_X, /* 06E1 */
- JOINING_TYPE_X, /* 06E2 */
- JOINING_TYPE_X, /* 06E3 */
- JOINING_TYPE_X, /* 06E4 */
- JOINING_TYPE_X, /* 06E5 */
- JOINING_TYPE_X, /* 06E6 */
- JOINING_TYPE_X, /* 06E7 */
- JOINING_TYPE_X, /* 06E8 */
- JOINING_TYPE_X, /* 06E9 */
- JOINING_TYPE_X, /* 06EA */
- JOINING_TYPE_X, /* 06EB */
- JOINING_TYPE_X, /* 06EC */
- JOINING_TYPE_X, /* 06ED */
- JOINING_TYPE_R, /* 06EE; DAL WITH INVERTED V ABOVE; R; DAL */
- JOINING_TYPE_R, /* 06EF; REH WITH INVERTED V ABOVE; R; REH */
- JOINING_TYPE_X, /* 06F0 */
- JOINING_TYPE_X, /* 06F1 */
- JOINING_TYPE_X, /* 06F2 */
- JOINING_TYPE_X, /* 06F3 */
- JOINING_TYPE_X, /* 06F4 */
- JOINING_TYPE_X, /* 06F5 */
- JOINING_TYPE_X, /* 06F6 */
- JOINING_TYPE_X, /* 06F7 */
- JOINING_TYPE_X, /* 06F8 */
- JOINING_TYPE_X, /* 06F9 */
- JOINING_TYPE_D, /* 06FA; SEEN WITH DOT BELOW AND 3 DOTS ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 06FB; SAD WITH DOT BELOW AND DOT ABOVE; D; SAD */
- JOINING_TYPE_D, /* 06FC; AIN WITH DOT BELOW AND DOT ABOVE; D; AIN */
- JOINING_TYPE_X, /* 06FD */
- JOINING_TYPE_X, /* 06FE */
- JOINING_TYPE_D, /* 06FF; KNOTTED HEH WITH INVERTED V ABOVE; D; KNOTTED HEH */
-
- /* Syriac Characters */
-
- JOINING_TYPE_X, /* 0700 */
- JOINING_TYPE_X, /* 0701 */
- JOINING_TYPE_X, /* 0702 */
- JOINING_TYPE_X, /* 0703 */
- JOINING_TYPE_X, /* 0704 */
- JOINING_TYPE_X, /* 0705 */
- JOINING_TYPE_X, /* 0706 */
- JOINING_TYPE_X, /* 0707 */
- JOINING_TYPE_X, /* 0708 */
- JOINING_TYPE_X, /* 0709 */
- JOINING_TYPE_X, /* 070A */
- JOINING_TYPE_X, /* 070B */
- JOINING_TYPE_X, /* 070C */
- JOINING_TYPE_X, /* 070D */
- JOINING_TYPE_X, /* 070E */
- JOINING_TYPE_X, /* 070F */
- JOINING_GROUP_ALAPH, /* 0710; ALAPH; R; ALAPH */
- JOINING_TYPE_X, /* 0711 */
- JOINING_TYPE_D, /* 0712; BETH; D; BETH */
- JOINING_TYPE_D, /* 0713; GAMAL; D; GAMAL */
- JOINING_TYPE_D, /* 0714; GAMAL GARSHUNI; D; GAMAL */
- JOINING_GROUP_DALATH_RISH, /* 0715; DALATH; R; DALATH RISH */
- JOINING_GROUP_DALATH_RISH, /* 0716; DOTLESS DALATH RISH; R; DALATH RISH */
- JOINING_TYPE_R, /* 0717; HE; R; HE */
- JOINING_TYPE_R, /* 0718; WAW; R; SYRIAC WAW */
- JOINING_TYPE_R, /* 0719; ZAIN; R; ZAIN */
- JOINING_TYPE_D, /* 071A; HETH; D; HETH */
- JOINING_TYPE_D, /* 071B; TETH; D; TETH */
- JOINING_TYPE_D, /* 071C; TETH GARSHUNI; D; TETH */
- JOINING_TYPE_D, /* 071D; YUDH; D; YUDH */
- JOINING_TYPE_R, /* 071E; YUDH HE; R; YUDH HE */
- JOINING_TYPE_D, /* 071F; KAPH; D; KAPH */
- JOINING_TYPE_D, /* 0720; LAMADH; D; LAMADH */
- JOINING_TYPE_D, /* 0721; MIM; D; MIM */
- JOINING_TYPE_D, /* 0722; NUN; D; NUN */
- JOINING_TYPE_D, /* 0723; SEMKATH; D; SEMKATH */
- JOINING_TYPE_D, /* 0724; FINAL SEMKATH; D; FINAL SEMKATH */
- JOINING_TYPE_D, /* 0725; E; D; E */
- JOINING_TYPE_D, /* 0726; PE; D; PE */
- JOINING_TYPE_D, /* 0727; REVERSED PE; D; REVERSED PE */
- JOINING_TYPE_R, /* 0728; SADHE; R; SADHE */
- JOINING_TYPE_D, /* 0729; QAPH; D; QAPH */
- JOINING_GROUP_DALATH_RISH, /* 072A; RISH; R; DALATH RISH */
- JOINING_TYPE_D, /* 072B; SHIN; D; SHIN */
- JOINING_TYPE_R, /* 072C; TAW; R; TAW */
- JOINING_TYPE_D, /* 072D; PERSIAN BHETH; D; BETH */
- JOINING_TYPE_D, /* 072E; PERSIAN GHAMAL; D; GAMAL */
- JOINING_GROUP_DALATH_RISH, /* 072F; PERSIAN DHALATH; R; DALATH RISH */
- JOINING_TYPE_X, /* 0730 */
- JOINING_TYPE_X, /* 0731 */
- JOINING_TYPE_X, /* 0732 */
- JOINING_TYPE_X, /* 0733 */
- JOINING_TYPE_X, /* 0734 */
- JOINING_TYPE_X, /* 0735 */
- JOINING_TYPE_X, /* 0736 */
- JOINING_TYPE_X, /* 0737 */
- JOINING_TYPE_X, /* 0738 */
- JOINING_TYPE_X, /* 0739 */
- JOINING_TYPE_X, /* 073A */
- JOINING_TYPE_X, /* 073B */
- JOINING_TYPE_X, /* 073C */
- JOINING_TYPE_X, /* 073D */
- JOINING_TYPE_X, /* 073E */
- JOINING_TYPE_X, /* 073F */
- JOINING_TYPE_X, /* 0740 */
- JOINING_TYPE_X, /* 0741 */
- JOINING_TYPE_X, /* 0742 */
- JOINING_TYPE_X, /* 0743 */
- JOINING_TYPE_X, /* 0744 */
- JOINING_TYPE_X, /* 0745 */
- JOINING_TYPE_X, /* 0746 */
- JOINING_TYPE_X, /* 0747 */
- JOINING_TYPE_X, /* 0748 */
- JOINING_TYPE_X, /* 0749 */
- JOINING_TYPE_X, /* 074A */
- JOINING_TYPE_X, /* 074B */
- JOINING_TYPE_X, /* 074C */
- JOINING_TYPE_R, /* 074D; SOGDIAN ZHAIN; R; ZHAIN */
- JOINING_TYPE_D, /* 074E; SOGDIAN KHAPH; D; KHAPH */
- JOINING_TYPE_D, /* 074F; SOGDIAN FE; D; FE */
-
- /* Arabic Supplement Characters */
-
- JOINING_TYPE_D, /* 0750; DOTLESS BEH WITH HORIZONTAL 3 DOTS BELOW; D; BEH */
- JOINING_TYPE_D, /* 0751; BEH WITH 3 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 0752; DOTLESS BEH WITH INVERTED 3 DOTS BELOW; D; BEH */
- JOINING_TYPE_D, /* 0753; DOTLESS BEH WITH INVERTED 3 DOTS BELOW AND 2 DOTS ABOVE; D; BEH */
- JOINING_TYPE_D, /* 0754; DOTLESS BEH WITH 2 DOTS BELOW AND DOT ABOVE; D; BEH */
- JOINING_TYPE_D, /* 0755; DOTLESS BEH WITH INVERTED V BELOW; D; BEH */
- JOINING_TYPE_D, /* 0756; DOTLESS BEH WITH V ABOVE; D; BEH */
- JOINING_TYPE_D, /* 0757; HAH WITH 2 DOTS ABOVE; D; HAH */
- JOINING_TYPE_D, /* 0758; HAH WITH INVERTED 3 DOTS BELOW; D; HAH */
- JOINING_TYPE_R, /* 0759; DAL WITH VERTICAL 2 DOTS BELOW AND TAH ABOVE; R; DAL */
- JOINING_TYPE_R, /* 075A; DAL WITH INVERTED V BELOW; R; DAL */
- JOINING_TYPE_R, /* 075B; REH WITH BAR; R; REH */
- JOINING_TYPE_D, /* 075C; SEEN WITH 4 DOTS ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 075D; AIN WITH 2 DOTS ABOVE; D; AIN */
- JOINING_TYPE_D, /* 075E; AIN WITH INVERTED 3 DOTS ABOVE; D; AIN */
- JOINING_TYPE_D, /* 075F; AIN WITH VERTICAL 2 DOTS ABOVE; D; AIN */
- JOINING_TYPE_D, /* 0760; DOTLESS FEH WITH 2 DOTS BELOW; D; FEH */
- JOINING_TYPE_D, /* 0761; DOTLESS FEH WITH INVERTED 3 DOTS BELOW; D; FEH */
- JOINING_TYPE_D, /* 0762; KEHEH WITH DOT ABOVE; D; GAF */
- JOINING_TYPE_D, /* 0763; KEHEH WITH 3 DOTS ABOVE; D; GAF */
- JOINING_TYPE_D, /* 0764; KEHEH WITH INVERTED 3 DOTS BELOW; D; GAF */
- JOINING_TYPE_D, /* 0765; MEEM WITH DOT ABOVE; D; MEEM */
- JOINING_TYPE_D, /* 0766; MEEM WITH DOT BELOW; D; MEEM */
- JOINING_TYPE_D, /* 0767; NOON WITH 2 DOTS BELOW; D; NOON */
- JOINING_TYPE_D, /* 0768; NOON WITH TAH ABOVE; D; NOON */
- JOINING_TYPE_D, /* 0769; NOON WITH V ABOVE; D; NOON */
- JOINING_TYPE_D, /* 076A; LAM WITH BAR; D; LAM */
- JOINING_TYPE_R, /* 076B; REH WITH VERTICAL 2 DOTS ABOVE; R; REH */
- JOINING_TYPE_R, /* 076C; REH WITH HAMZA ABOVE; R; REH */
- JOINING_TYPE_D, /* 076D; SEEN WITH VERTICAL 2 DOTS ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 076E; HAH WITH TAH BELOW; D; HAH */
- JOINING_TYPE_D, /* 076F; HAH WITH TAH AND 2 DOTS BELOW; D; HAH */
- JOINING_TYPE_D, /* 0770; SEEN WITH 2 DOTS AND TAH ABOVE; D; SEEN */
- JOINING_TYPE_R, /* 0771; REH WITH 2 DOTS AND TAH ABOVE; R; REH */
- JOINING_TYPE_D, /* 0772; HAH WITH TAH ABOVE; D; HAH */
- JOINING_TYPE_R, /* 0773; ALEF WITH DIGIT TWO ABOVE; R; ALEF */
- JOINING_TYPE_R, /* 0774; ALEF WITH DIGIT THREE ABOVE; R; ALEF */
- JOINING_TYPE_D, /* 0775; FARSI YEH WITH DIGIT TWO ABOVE; D; FARSI YEH */
- JOINING_TYPE_D, /* 0776; FARSI YEH WITH DIGIT THREE ABOVE; D; FARSI YEH */
- JOINING_TYPE_D, /* 0777; DOTLESS YEH WITH DIGIT FOUR BELOW; D; YEH */
- JOINING_TYPE_R, /* 0778; WAW WITH DIGIT TWO ABOVE; R; WAW */
- JOINING_TYPE_R, /* 0779; WAW WITH DIGIT THREE ABOVE; R; WAW */
- JOINING_TYPE_D, /* 077A; BURUSHASKI YEH BARREE WITH DIGIT TWO ABOVE; D; BURUSHASKI YEH BARREE */
- JOINING_TYPE_D, /* 077B; BURUSHASKI YEH BARREE WITH DIGIT THREE ABOVE; D; BURUSHASKI YEH BARREE */
- JOINING_TYPE_D, /* 077C; HAH WITH DIGIT FOUR BELOW; D; HAH */
- JOINING_TYPE_D, /* 077D; SEEN WITH DIGIT FOUR ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 077E; SEEN WITH INVERTED V ABOVE; D; SEEN */
- JOINING_TYPE_D, /* 077F; KAF WITH 2 DOTS ABOVE; D; KAF */
-
- /* N'Ko Characters */
-
- JOINING_TYPE_X, /* 0780 */
- JOINING_TYPE_X, /* 0781 */
- JOINING_TYPE_X, /* 0782 */
- JOINING_TYPE_X, /* 0783 */
- JOINING_TYPE_X, /* 0784 */
- JOINING_TYPE_X, /* 0785 */
- JOINING_TYPE_X, /* 0786 */
- JOINING_TYPE_X, /* 0787 */
- JOINING_TYPE_X, /* 0788 */
- JOINING_TYPE_X, /* 0789 */
- JOINING_TYPE_X, /* 078A */
- JOINING_TYPE_X, /* 078B */
- JOINING_TYPE_X, /* 078C */
- JOINING_TYPE_X, /* 078D */
- JOINING_TYPE_X, /* 078E */
- JOINING_TYPE_X, /* 078F */
- JOINING_TYPE_X, /* 0790 */
- JOINING_TYPE_X, /* 0791 */
- JOINING_TYPE_X, /* 0792 */
- JOINING_TYPE_X, /* 0793 */
- JOINING_TYPE_X, /* 0794 */
- JOINING_TYPE_X, /* 0795 */
- JOINING_TYPE_X, /* 0796 */
- JOINING_TYPE_X, /* 0797 */
- JOINING_TYPE_X, /* 0798 */
- JOINING_TYPE_X, /* 0799 */
- JOINING_TYPE_X, /* 079A */
- JOINING_TYPE_X, /* 079B */
- JOINING_TYPE_X, /* 079C */
- JOINING_TYPE_X, /* 079D */
- JOINING_TYPE_X, /* 079E */
- JOINING_TYPE_X, /* 079F */
- JOINING_TYPE_X, /* 07A0 */
- JOINING_TYPE_X, /* 07A1 */
- JOINING_TYPE_X, /* 07A2 */
- JOINING_TYPE_X, /* 07A3 */
- JOINING_TYPE_X, /* 07A4 */
- JOINING_TYPE_X, /* 07A5 */
- JOINING_TYPE_X, /* 07A6 */
- JOINING_TYPE_X, /* 07A7 */
- JOINING_TYPE_X, /* 07A8 */
- JOINING_TYPE_X, /* 07A9 */
- JOINING_TYPE_X, /* 07AA */
- JOINING_TYPE_X, /* 07AB */
- JOINING_TYPE_X, /* 07AC */
- JOINING_TYPE_X, /* 07AD */
- JOINING_TYPE_X, /* 07AE */
- JOINING_TYPE_X, /* 07AF */
- JOINING_TYPE_X, /* 07B0 */
- JOINING_TYPE_X, /* 07B1 */
- JOINING_TYPE_X, /* 07B2 */
- JOINING_TYPE_X, /* 07B3 */
- JOINING_TYPE_X, /* 07B4 */
- JOINING_TYPE_X, /* 07B5 */
- JOINING_TYPE_X, /* 07B6 */
- JOINING_TYPE_X, /* 07B7 */
- JOINING_TYPE_X, /* 07B8 */
- JOINING_TYPE_X, /* 07B9 */
- JOINING_TYPE_X, /* 07BA */
- JOINING_TYPE_X, /* 07BB */
- JOINING_TYPE_X, /* 07BC */
- JOINING_TYPE_X, /* 07BD */
- JOINING_TYPE_X, /* 07BE */
- JOINING_TYPE_X, /* 07BF */
- JOINING_TYPE_X, /* 07C0 */
- JOINING_TYPE_X, /* 07C1 */
- JOINING_TYPE_X, /* 07C2 */
- JOINING_TYPE_X, /* 07C3 */
- JOINING_TYPE_X, /* 07C4 */
- JOINING_TYPE_X, /* 07C5 */
- JOINING_TYPE_X, /* 07C6 */
- JOINING_TYPE_X, /* 07C7 */
- JOINING_TYPE_X, /* 07C8 */
- JOINING_TYPE_X, /* 07C9 */
- JOINING_TYPE_D, /* 07CA; NKO A; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07CB; NKO EE; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07CC; NKO I; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07CD; NKO E; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07CE; NKO U; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07CF; NKO OO; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D0; NKO O; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D1; NKO DAGBASINNA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D2; NKO N; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D3; NKO BA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D4; NKO PA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D5; NKO TA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D6; NKO JA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D7; NKO CHA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D8; NKO DA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07D9; NKO RA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07DA; NKO RRA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07DB; NKO SA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07DC; NKO GBA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07DD; NKO FA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07DE; NKO KA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07DF; NKO LA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E0; NKO NA WOLOSO; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E1; NKO MA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E2; NKO NYA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E3; NKO NA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E4; NKO HA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E5; NKO WA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E6; NKO YA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E7; NKO NYA WOLOSO; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E8; NKO JONA JA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07E9; NKO JONA CHA; D; No_Joining_Group */
- JOINING_TYPE_D, /* 07EA; NKO JONA RA; D; No_Joining_Group */
- JOINING_TYPE_X, /* 07EB */
- JOINING_TYPE_X, /* 07EC */
- JOINING_TYPE_X, /* 07ED */
- JOINING_TYPE_X, /* 07EE */
- JOINING_TYPE_X, /* 07EF */
- JOINING_TYPE_X, /* 07F0 */
- JOINING_TYPE_X, /* 07F1 */
- JOINING_TYPE_X, /* 07F2 */
- JOINING_TYPE_X, /* 07F3 */
- JOINING_TYPE_X, /* 07F4 */
- JOINING_TYPE_X, /* 07F5 */
- JOINING_TYPE_X, /* 07F6 */
- JOINING_TYPE_X, /* 07F7 */
- JOINING_TYPE_X, /* 07F8 */
- JOINING_TYPE_X, /* 07F9 */
- JOINING_TYPE_C, /* 07FA; NKO LAJANYALAN; C; No_Joining_Group */
-
- /* Mandaic Characters */
-
- JOINING_TYPE_X, /* 07FB */
- JOINING_TYPE_X, /* 07FC */
- JOINING_TYPE_X, /* 07FD */
- JOINING_TYPE_X, /* 07FE */
- JOINING_TYPE_X, /* 07FF */
- JOINING_TYPE_X, /* 0800 */
- JOINING_TYPE_X, /* 0801 */
- JOINING_TYPE_X, /* 0802 */
- JOINING_TYPE_X, /* 0803 */
- JOINING_TYPE_X, /* 0804 */
- JOINING_TYPE_X, /* 0805 */
- JOINING_TYPE_X, /* 0806 */
- JOINING_TYPE_X, /* 0807 */
- JOINING_TYPE_X, /* 0808 */
- JOINING_TYPE_X, /* 0809 */
- JOINING_TYPE_X, /* 080A */
- JOINING_TYPE_X, /* 080B */
- JOINING_TYPE_X, /* 080C */
- JOINING_TYPE_X, /* 080D */
- JOINING_TYPE_X, /* 080E */
- JOINING_TYPE_X, /* 080F */
- JOINING_TYPE_X, /* 0810 */
- JOINING_TYPE_X, /* 0811 */
- JOINING_TYPE_X, /* 0812 */
- JOINING_TYPE_X, /* 0813 */
- JOINING_TYPE_X, /* 0814 */
- JOINING_TYPE_X, /* 0815 */
- JOINING_TYPE_X, /* 0816 */
- JOINING_TYPE_X, /* 0817 */
- JOINING_TYPE_X, /* 0818 */
- JOINING_TYPE_X, /* 0819 */
- JOINING_TYPE_X, /* 081A */
- JOINING_TYPE_X, /* 081B */
- JOINING_TYPE_X, /* 081C */
- JOINING_TYPE_X, /* 081D */
- JOINING_TYPE_X, /* 081E */
- JOINING_TYPE_X, /* 081F */
- JOINING_TYPE_X, /* 0820 */
- JOINING_TYPE_X, /* 0821 */
- JOINING_TYPE_X, /* 0822 */
- JOINING_TYPE_X, /* 0823 */
- JOINING_TYPE_X, /* 0824 */
- JOINING_TYPE_X, /* 0825 */
- JOINING_TYPE_X, /* 0826 */
- JOINING_TYPE_X, /* 0827 */
- JOINING_TYPE_X, /* 0828 */
- JOINING_TYPE_X, /* 0829 */
- JOINING_TYPE_X, /* 082A */
- JOINING_TYPE_X, /* 082B */
- JOINING_TYPE_X, /* 082C */
- JOINING_TYPE_X, /* 082D */
- JOINING_TYPE_X, /* 082E */
- JOINING_TYPE_X, /* 082F */
- JOINING_TYPE_X, /* 0830 */
- JOINING_TYPE_X, /* 0831 */
- JOINING_TYPE_X, /* 0832 */
- JOINING_TYPE_X, /* 0833 */
- JOINING_TYPE_X, /* 0834 */
- JOINING_TYPE_X, /* 0835 */
- JOINING_TYPE_X, /* 0836 */
- JOINING_TYPE_X, /* 0837 */
- JOINING_TYPE_X, /* 0838 */
- JOINING_TYPE_X, /* 0839 */
- JOINING_TYPE_X, /* 083A */
- JOINING_TYPE_X, /* 083B */
- JOINING_TYPE_X, /* 083C */
- JOINING_TYPE_X, /* 083D */
- JOINING_TYPE_X, /* 083E */
- JOINING_TYPE_X, /* 083F */
- JOINING_TYPE_R, /* 0840; MANDAIC HALQA; R; No_Joining_Group */
- JOINING_TYPE_D, /* 0841; MANDAIC AB; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0842; MANDAIC AG; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0843; MANDAIC AD; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0844; MANDAIC AH; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0845; MANDAIC USHENNA; D; No_Joining_Group */
- JOINING_TYPE_R, /* 0846; MANDAIC AZ; R; No_Joining_Group */
- JOINING_TYPE_D, /* 0847; MANDAIC IT; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0848; MANDAIC ATT; D; No_Joining_Group */
- JOINING_TYPE_R, /* 0849; MANDAIC AKSA; R; No_Joining_Group */
- JOINING_TYPE_D, /* 084A; MANDAIC AK; D; No_Joining_Group */
- JOINING_TYPE_D, /* 084B; MANDAIC AL; D; No_Joining_Group */
- JOINING_TYPE_D, /* 084C; MANDAIC AM; D; No_Joining_Group */
- JOINING_TYPE_D, /* 084D; MANDAIC AN; D; No_Joining_Group */
- JOINING_TYPE_D, /* 084E; MANDAIC AS; D; No_Joining_Group */
- JOINING_TYPE_R, /* 084F; MANDAIC IN; R; No_Joining_Group */
- JOINING_TYPE_D, /* 0850; MANDAIC AP; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0851; MANDAIC ASZ; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0852; MANDAIC AQ; D; No_Joining_Group */
- JOINING_TYPE_D, /* 0853; MANDAIC AR; D; No_Joining_Group */
- JOINING_TYPE_R, /* 0854; MANDAIC ASH; R; No_Joining_Group */
- JOINING_TYPE_D, /* 0855; MANDAIC AT; D; No_Joining_Group */
- JOINING_TYPE_U, /* 0856; MANDAIC DUSHENNA; U; No_Joining_Group */
- JOINING_TYPE_U, /* 0857; MANDAIC KAD; U; No_Joining_Group */
- JOINING_TYPE_U, /* 0858; MANDAIC AIN; U; No_Joining_Group */
-
- /* Arabic Extended-A Characters */
-
- JOINING_TYPE_X, /* 0859 */
- JOINING_TYPE_X, /* 085A */
- JOINING_TYPE_X, /* 085B */
- JOINING_TYPE_X, /* 085C */
- JOINING_TYPE_X, /* 085D */
- JOINING_TYPE_X, /* 085E */
- JOINING_TYPE_X, /* 085F */
- JOINING_TYPE_X, /* 0860 */
- JOINING_TYPE_X, /* 0861 */
- JOINING_TYPE_X, /* 0862 */
- JOINING_TYPE_X, /* 0863 */
- JOINING_TYPE_X, /* 0864 */
- JOINING_TYPE_X, /* 0865 */
- JOINING_TYPE_X, /* 0866 */
- JOINING_TYPE_X, /* 0867 */
- JOINING_TYPE_X, /* 0868 */
- JOINING_TYPE_X, /* 0869 */
- JOINING_TYPE_X, /* 086A */
- JOINING_TYPE_X, /* 086B */
- JOINING_TYPE_X, /* 086C */
- JOINING_TYPE_X, /* 086D */
- JOINING_TYPE_X, /* 086E */
- JOINING_TYPE_X, /* 086F */
- JOINING_TYPE_X, /* 0870 */
- JOINING_TYPE_X, /* 0871 */
- JOINING_TYPE_X, /* 0872 */
- JOINING_TYPE_X, /* 0873 */
- JOINING_TYPE_X, /* 0874 */
- JOINING_TYPE_X, /* 0875 */
- JOINING_TYPE_X, /* 0876 */
- JOINING_TYPE_X, /* 0877 */
- JOINING_TYPE_X, /* 0878 */
- JOINING_TYPE_X, /* 0879 */
- JOINING_TYPE_X, /* 087A */
- JOINING_TYPE_X, /* 087B */
- JOINING_TYPE_X, /* 087C */
- JOINING_TYPE_X, /* 087D */
- JOINING_TYPE_X, /* 087E */
- JOINING_TYPE_X, /* 087F */
- JOINING_TYPE_X, /* 0880 */
- JOINING_TYPE_X, /* 0881 */
- JOINING_TYPE_X, /* 0882 */
- JOINING_TYPE_X, /* 0883 */
- JOINING_TYPE_X, /* 0884 */
- JOINING_TYPE_X, /* 0885 */
- JOINING_TYPE_X, /* 0886 */
- JOINING_TYPE_X, /* 0887 */
- JOINING_TYPE_X, /* 0888 */
- JOINING_TYPE_X, /* 0889 */
- JOINING_TYPE_X, /* 088A */
- JOINING_TYPE_X, /* 088B */
- JOINING_TYPE_X, /* 088C */
- JOINING_TYPE_X, /* 088D */
- JOINING_TYPE_X, /* 088E */
- JOINING_TYPE_X, /* 088F */
- JOINING_TYPE_X, /* 0890 */
- JOINING_TYPE_X, /* 0891 */
- JOINING_TYPE_X, /* 0892 */
- JOINING_TYPE_X, /* 0893 */
- JOINING_TYPE_X, /* 0894 */
- JOINING_TYPE_X, /* 0895 */
- JOINING_TYPE_X, /* 0896 */
- JOINING_TYPE_X, /* 0897 */
- JOINING_TYPE_X, /* 0898 */
- JOINING_TYPE_X, /* 0899 */
- JOINING_TYPE_X, /* 089A */
- JOINING_TYPE_X, /* 089B */
- JOINING_TYPE_X, /* 089C */
- JOINING_TYPE_X, /* 089D */
- JOINING_TYPE_X, /* 089E */
- JOINING_TYPE_X, /* 089F */
- JOINING_TYPE_D, /* 08A0; DOTLESS BEH WITH V BELOW; D; BEH */
- JOINING_TYPE_X, /* 08A1 */
- JOINING_TYPE_D, /* 08A2; HAH WITH DOT BELOW AND 2 DOTS ABOVE; D; HAH */
- JOINING_TYPE_D, /* 08A3; TAH WITH 2 DOTS ABOVE; D; TAH */
- JOINING_TYPE_D, /* 08A4; DOTLESS FEH WITH DOT BELOW AND 3 DOTS ABOVE; D; FEH */
- JOINING_TYPE_D, /* 08A5; QAF WITH DOT BELOW; D; QAF */
- JOINING_TYPE_D, /* 08A6; LAM WITH DOUBLE BAR; D; LAM */
- JOINING_TYPE_D, /* 08A7; MEEM WITH 3 DOTS ABOVE; D; MEEM */
- JOINING_TYPE_D, /* 08A8; YEH WITH HAMZA ABOVE; D; YEH */
- JOINING_TYPE_D, /* 08A9; YEH WITH DOT ABOVE; D; YEH */
- JOINING_TYPE_R, /* 08AA; REH WITH LOOP; R; REH */
- JOINING_TYPE_R, /* 08AB; WAW WITH DOT WITHIN; R; WAW */
- JOINING_TYPE_R, /* 08AC; ROHINGYA YEH; R; ROHINGYA YEH */
+#define joining_offset_0x0600u 0
-};
+ /* Arabic */
+
+ /* 0600 */ U,U,U,U,U,U,X,X,U,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 0620 */ D,U,R,R,R,R,D,R,D,R,D,D,D,D,D,R,R,R,R,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 0640 */ C,D,D,D,D,D,D,D,R,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 0660 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,D,D,X,R,R,R,U,R,R,R,D,D,D,D,D,D,D,D,
+ /* 0680 */ D,D,D,D,D,D,D,D,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,D,D,D,D,D,D,
+ /* 06A0 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 06C0 */ R,D,D,R,R,R,R,R,R,R,R,R,D,R,D,R,D,D,R,R,X,R,X,X,X,X,X,X,X,U,X,X,
+ /* 06E0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,R,R,X,X,X,X,X,X,X,X,X,X,D,D,D,X,X,D,
+
+ /* Syriac */
+
+ /* 0700 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,A,X,D,D,D,DR,DR,R,R,R,D,D,D,D,R,D,
+ /* 0720 */ D,D,D,D,D,D,D,D,R,D,DR,D,R,D,D,DR,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 0740 */ X,X,X,X,X,X,X,X,X,X,X,X,X,R,D,D,
+
+ /* Arabic Supplement */
+
+ /* 0740 */ D,D,D,D,D,D,D,D,D,R,R,R,D,D,D,D,
+ /* 0760 */ D,D,D,D,D,D,D,D,D,D,D,R,R,D,D,D,D,R,D,R,R,D,D,D,R,R,D,D,D,D,D,D,
+
+ /* FILLER */
+
+ /* 0780 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 07A0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+ /* NKo */
+
+ /* 07C0 */ X,X,X,X,X,X,X,X,X,X,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 07E0 */ D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,C,X,X,X,X,X,
+
+ /* FILLER */
+
+ /* 0800 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 0820 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+ /* Mandaic */
+
+ /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X,
+ /* 0860 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+ /* Arabic Extended-A */
+
+ /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,
+
+#define joining_offset_0x1806u 691
+
+ /* Mongolian */
+
+ /* 1800 */ U,D,X,X,C,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 1820 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 1840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 1860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,
+ /* 1880 */ U,U,U,U,U,U,U,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* 18A0 */ D,D,D,D,D,D,D,D,D,X,D,
+
+#define joining_offset_0x200cu 856
+
+ /* General Punctuation */
+
+ /* 2000 */ U,C,
+
+#define joining_offset_0x2066u 858
+
+ /* General Punctuation */
+
+ /* 2060 */ U,U,U,U,
+
+#define joining_offset_0xa840u 862
+
+ /* Phags-pa */
+
+ /* A840 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
+ /* A860 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,L,U,
+
+#define joining_offset_0x10ac0u 914
+
+ /* Manichaean */
+
+ /* 10AC0 */ D,D,D,D,D,R,U,R,U,R,R,U,U,L,R,R,R,R,R,D,D,D,D,L,D,D,D,D,D,R,D,D,
+ /* 10AE0 */ D,R,U,U,R,X,X,X,X,X,X,D,D,D,D,R,
+
+#define joining_offset_0x10b80u 962
+
+ /* Psalter Pahlavi */
+
+ /* 10B80 */ D,R,D,R,R,R,D,D,D,R,D,D,R,D,R,R,D,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+ /* 10BA0 */ X,X,X,X,X,X,X,X,X,R,R,R,R,D,D,U,
+
+}; /* Table items: 1010; occupancy: 57% */
+
+
+static unsigned int
+joining_type (hb_codepoint_t u)
+{
+ switch (u >> 12)
+ {
+ case 0x0u:
+ if (hb_in_range (u, 0x0600u, 0x08B2u)) return joining_table[u - 0x0600u + joining_offset_0x0600u];
+ break;
+
+ case 0x1u:
+ if (hb_in_range (u, 0x1806u, 0x18AAu)) return joining_table[u - 0x1806u + joining_offset_0x1806u];
+ break;
+
+ case 0x2u:
+ if (hb_in_range (u, 0x200Cu, 0x200Du)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
+ if (hb_in_range (u, 0x2066u, 0x2069u)) return joining_table[u - 0x2066u + joining_offset_0x2066u];
+ break;
+
+ case 0xAu:
+ if (hb_in_range (u, 0xA840u, 0xA873u)) return joining_table[u - 0xA840u + joining_offset_0xa840u];
+ break;
+
+ case 0x10u:
+ if (hb_in_range (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
+ if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
+ break;
+
+ default:
+ break;
+ }
+ return X;
+}
-#define JOINING_TABLE_FIRST 0x0600
-#define JOINING_TABLE_LAST 0x08AC
+#undef X
+#undef R
+#undef U
+#undef A
+#undef DR
+#undef L
+#undef C
+#undef D
static const uint16_t shaping_table[][4] =
{
- {0x0621, 0x0621, 0x0621, 0xFE80}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
- {0x0622, 0x0622, 0xFE82, 0xFE81}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
- {0x0623, 0x0623, 0xFE84, 0xFE83}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
- {0x0624, 0x0624, 0xFE86, 0xFE85}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
- {0x0625, 0x0625, 0xFE88, 0xFE87}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
- {0xFE8B, 0xFE8C, 0xFE8A, 0xFE89}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
- {0x0627, 0x0627, 0xFE8E, 0xFE8D}, /* U+0627 ARABIC LETTER ALEF */
- {0xFE91, 0xFE92, 0xFE90, 0xFE8F}, /* U+0628 ARABIC LETTER BEH */
- {0x0629, 0x0629, 0xFE94, 0xFE93}, /* U+0629 ARABIC LETTER TEH MARBUTA */
- {0xFE97, 0xFE98, 0xFE96, 0xFE95}, /* U+062A ARABIC LETTER TEH */
- {0xFE9B, 0xFE9C, 0xFE9A, 0xFE99}, /* U+062B ARABIC LETTER THEH */
- {0xFE9F, 0xFEA0, 0xFE9E, 0xFE9D}, /* U+062C ARABIC LETTER JEEM */
- {0xFEA3, 0xFEA4, 0xFEA2, 0xFEA1}, /* U+062D ARABIC LETTER HAH */
- {0xFEA7, 0xFEA8, 0xFEA6, 0xFEA5}, /* U+062E ARABIC LETTER KHAH */
- {0x062F, 0x062F, 0xFEAA, 0xFEA9}, /* U+062F ARABIC LETTER DAL */
- {0x0630, 0x0630, 0xFEAC, 0xFEAB}, /* U+0630 ARABIC LETTER THAL */
- {0x0631, 0x0631, 0xFEAE, 0xFEAD}, /* U+0631 ARABIC LETTER REH */
- {0x0632, 0x0632, 0xFEB0, 0xFEAF}, /* U+0632 ARABIC LETTER ZAIN */
- {0xFEB3, 0xFEB4, 0xFEB2, 0xFEB1}, /* U+0633 ARABIC LETTER SEEN */
- {0xFEB7, 0xFEB8, 0xFEB6, 0xFEB5}, /* U+0634 ARABIC LETTER SHEEN */
- {0xFEBB, 0xFEBC, 0xFEBA, 0xFEB9}, /* U+0635 ARABIC LETTER SAD */
- {0xFEBF, 0xFEC0, 0xFEBE, 0xFEBD}, /* U+0636 ARABIC LETTER DAD */
- {0xFEC3, 0xFEC4, 0xFEC2, 0xFEC1}, /* U+0637 ARABIC LETTER TAH */
- {0xFEC7, 0xFEC8, 0xFEC6, 0xFEC5}, /* U+0638 ARABIC LETTER ZAH */
- {0xFECB, 0xFECC, 0xFECA, 0xFEC9}, /* U+0639 ARABIC LETTER AIN */
- {0xFECF, 0xFED0, 0xFECE, 0xFECD}, /* U+063A ARABIC LETTER GHAIN */
- {0x063B, 0x063B, 0x063B, 0x063B}, /* U+063B */
- {0x063C, 0x063C, 0x063C, 0x063C}, /* U+063C */
- {0x063D, 0x063D, 0x063D, 0x063D}, /* U+063D */
- {0x063E, 0x063E, 0x063E, 0x063E}, /* U+063E */
- {0x063F, 0x063F, 0x063F, 0x063F}, /* U+063F */
- {0x0640, 0x0640, 0x0640, 0x0640}, /* U+0640 */
- {0xFED3, 0xFED4, 0xFED2, 0xFED1}, /* U+0641 ARABIC LETTER FEH */
- {0xFED7, 0xFED8, 0xFED6, 0xFED5}, /* U+0642 ARABIC LETTER QAF */
- {0xFEDB, 0xFEDC, 0xFEDA, 0xFED9}, /* U+0643 ARABIC LETTER KAF */
- {0xFEDF, 0xFEE0, 0xFEDE, 0xFEDD}, /* U+0644 ARABIC LETTER LAM */
- {0xFEE3, 0xFEE4, 0xFEE2, 0xFEE1}, /* U+0645 ARABIC LETTER MEEM */
- {0xFEE7, 0xFEE8, 0xFEE6, 0xFEE5}, /* U+0646 ARABIC LETTER NOON */
- {0xFEEB, 0xFEEC, 0xFEEA, 0xFEE9}, /* U+0647 ARABIC LETTER HEH */
- {0x0648, 0x0648, 0xFEEE, 0xFEED}, /* U+0648 ARABIC LETTER WAW */
- {0xFBE8, 0xFBE9, 0xFEF0, 0xFEEF}, /* U+0649 ARABIC LETTER */
- {0xFEF3, 0xFEF4, 0xFEF2, 0xFEF1}, /* U+064A ARABIC LETTER YEH */
- {0x064B, 0x064B, 0x064B, 0x064B}, /* U+064B */
- {0x064C, 0x064C, 0x064C, 0x064C}, /* U+064C */
- {0x064D, 0x064D, 0x064D, 0x064D}, /* U+064D */
- {0x064E, 0x064E, 0x064E, 0x064E}, /* U+064E */
- {0x064F, 0x064F, 0x064F, 0x064F}, /* U+064F */
- {0x0650, 0x0650, 0x0650, 0x0650}, /* U+0650 */
- {0x0651, 0x0651, 0x0651, 0x0651}, /* U+0651 */
- {0x0652, 0x0652, 0x0652, 0x0652}, /* U+0652 */
- {0x0653, 0x0653, 0x0653, 0x0653}, /* U+0653 */
- {0x0654, 0x0654, 0x0654, 0x0654}, /* U+0654 */
- {0x0655, 0x0655, 0x0655, 0x0655}, /* U+0655 */
- {0x0656, 0x0656, 0x0656, 0x0656}, /* U+0656 */
- {0x0657, 0x0657, 0x0657, 0x0657}, /* U+0657 */
- {0x0658, 0x0658, 0x0658, 0x0658}, /* U+0658 */
- {0x0659, 0x0659, 0x0659, 0x0659}, /* U+0659 */
- {0x065A, 0x065A, 0x065A, 0x065A}, /* U+065A */
- {0x065B, 0x065B, 0x065B, 0x065B}, /* U+065B */
- {0x065C, 0x065C, 0x065C, 0x065C}, /* U+065C */
- {0x065D, 0x065D, 0x065D, 0x065D}, /* U+065D */
- {0x065E, 0x065E, 0x065E, 0x065E}, /* U+065E */
- {0x065F, 0x065F, 0x065F, 0x065F}, /* U+065F */
- {0x0660, 0x0660, 0x0660, 0x0660}, /* U+0660 */
- {0x0661, 0x0661, 0x0661, 0x0661}, /* U+0661 */
- {0x0662, 0x0662, 0x0662, 0x0662}, /* U+0662 */
- {0x0663, 0x0663, 0x0663, 0x0663}, /* U+0663 */
- {0x0664, 0x0664, 0x0664, 0x0664}, /* U+0664 */
- {0x0665, 0x0665, 0x0665, 0x0665}, /* U+0665 */
- {0x0666, 0x0666, 0x0666, 0x0666}, /* U+0666 */
- {0x0667, 0x0667, 0x0667, 0x0667}, /* U+0667 */
- {0x0668, 0x0668, 0x0668, 0x0668}, /* U+0668 */
- {0x0669, 0x0669, 0x0669, 0x0669}, /* U+0669 */
- {0x066A, 0x066A, 0x066A, 0x066A}, /* U+066A */
- {0x066B, 0x066B, 0x066B, 0x066B}, /* U+066B */
- {0x066C, 0x066C, 0x066C, 0x066C}, /* U+066C */
- {0x066D, 0x066D, 0x066D, 0x066D}, /* U+066D */
- {0x066E, 0x066E, 0x066E, 0x066E}, /* U+066E */
- {0x066F, 0x066F, 0x066F, 0x066F}, /* U+066F */
- {0x0670, 0x0670, 0x0670, 0x0670}, /* U+0670 */
- {0x0671, 0x0671, 0xFB51, 0xFB50}, /* U+0671 ARABIC LETTER ALEF WASLA */
- {0x0672, 0x0672, 0x0672, 0x0672}, /* U+0672 */
- {0x0673, 0x0673, 0x0673, 0x0673}, /* U+0673 */
- {0x0674, 0x0674, 0x0674, 0x0674}, /* U+0674 */
- {0x0675, 0x0675, 0x0675, 0x0675}, /* U+0675 */
- {0x0676, 0x0676, 0x0676, 0x0676}, /* U+0676 */
- {0x0677, 0x0677, 0x0677, 0xFBDD}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
- {0x0678, 0x0678, 0x0678, 0x0678}, /* U+0678 */
- {0xFB68, 0xFB69, 0xFB67, 0xFB66}, /* U+0679 ARABIC LETTER TTEH */
- {0xFB60, 0xFB61, 0xFB5F, 0xFB5E}, /* U+067A ARABIC LETTER TTEHEH */
- {0xFB54, 0xFB55, 0xFB53, 0xFB52}, /* U+067B ARABIC LETTER BEEH */
- {0x067C, 0x067C, 0x067C, 0x067C}, /* U+067C */
- {0x067D, 0x067D, 0x067D, 0x067D}, /* U+067D */
- {0xFB58, 0xFB59, 0xFB57, 0xFB56}, /* U+067E ARABIC LETTER PEH */
- {0xFB64, 0xFB65, 0xFB63, 0xFB62}, /* U+067F ARABIC LETTER TEHEH */
- {0xFB5C, 0xFB5D, 0xFB5B, 0xFB5A}, /* U+0680 ARABIC LETTER BEHEH */
- {0x0681, 0x0681, 0x0681, 0x0681}, /* U+0681 */
- {0x0682, 0x0682, 0x0682, 0x0682}, /* U+0682 */
- {0xFB78, 0xFB79, 0xFB77, 0xFB76}, /* U+0683 ARABIC LETTER NYEH */
- {0xFB74, 0xFB75, 0xFB73, 0xFB72}, /* U+0684 ARABIC LETTER DYEH */
- {0x0685, 0x0685, 0x0685, 0x0685}, /* U+0685 */
- {0xFB7C, 0xFB7D, 0xFB7B, 0xFB7A}, /* U+0686 ARABIC LETTER TCHEH */
- {0xFB80, 0xFB81, 0xFB7F, 0xFB7E}, /* U+0687 ARABIC LETTER TCHEHEH */
- {0x0688, 0x0688, 0xFB89, 0xFB88}, /* U+0688 ARABIC LETTER DDAL */
- {0x0689, 0x0689, 0x0689, 0x0689}, /* U+0689 */
- {0x068A, 0x068A, 0x068A, 0x068A}, /* U+068A */
- {0x068B, 0x068B, 0x068B, 0x068B}, /* U+068B */
- {0x068C, 0x068C, 0xFB85, 0xFB84}, /* U+068C ARABIC LETTER DAHAL */
- {0x068D, 0x068D, 0xFB83, 0xFB82}, /* U+068D ARABIC LETTER DDAHAL */
- {0x068E, 0x068E, 0xFB87, 0xFB86}, /* U+068E ARABIC LETTER DUL */
- {0x068F, 0x068F, 0x068F, 0x068F}, /* U+068F */
- {0x0690, 0x0690, 0x0690, 0x0690}, /* U+0690 */
- {0x0691, 0x0691, 0xFB8D, 0xFB8C}, /* U+0691 ARABIC LETTER RREH */
- {0x0692, 0x0692, 0x0692, 0x0692}, /* U+0692 */
- {0x0693, 0x0693, 0x0693, 0x0693}, /* U+0693 */
- {0x0694, 0x0694, 0x0694, 0x0694}, /* U+0694 */
- {0x0695, 0x0695, 0x0695, 0x0695}, /* U+0695 */
- {0x0696, 0x0696, 0x0696, 0x0696}, /* U+0696 */
- {0x0697, 0x0697, 0x0697, 0x0697}, /* U+0697 */
- {0x0698, 0x0698, 0xFB8B, 0xFB8A}, /* U+0698 ARABIC LETTER JEH */
- {0x0699, 0x0699, 0x0699, 0x0699}, /* U+0699 */
- {0x069A, 0x069A, 0x069A, 0x069A}, /* U+069A */
- {0x069B, 0x069B, 0x069B, 0x069B}, /* U+069B */
- {0x069C, 0x069C, 0x069C, 0x069C}, /* U+069C */
- {0x069D, 0x069D, 0x069D, 0x069D}, /* U+069D */
- {0x069E, 0x069E, 0x069E, 0x069E}, /* U+069E */
- {0x069F, 0x069F, 0x069F, 0x069F}, /* U+069F */
- {0x06A0, 0x06A0, 0x06A0, 0x06A0}, /* U+06A0 */
- {0x06A1, 0x06A1, 0x06A1, 0x06A1}, /* U+06A1 */
- {0x06A2, 0x06A2, 0x06A2, 0x06A2}, /* U+06A2 */
- {0x06A3, 0x06A3, 0x06A3, 0x06A3}, /* U+06A3 */
- {0xFB6C, 0xFB6D, 0xFB6B, 0xFB6A}, /* U+06A4 ARABIC LETTER VEH */
- {0x06A5, 0x06A5, 0x06A5, 0x06A5}, /* U+06A5 */
- {0xFB70, 0xFB71, 0xFB6F, 0xFB6E}, /* U+06A6 ARABIC LETTER PEHEH */
- {0x06A7, 0x06A7, 0x06A7, 0x06A7}, /* U+06A7 */
- {0x06A8, 0x06A8, 0x06A8, 0x06A8}, /* U+06A8 */
- {0xFB90, 0xFB91, 0xFB8F, 0xFB8E}, /* U+06A9 ARABIC LETTER KEHEH */
- {0x06AA, 0x06AA, 0x06AA, 0x06AA}, /* U+06AA */
- {0x06AB, 0x06AB, 0x06AB, 0x06AB}, /* U+06AB */
- {0x06AC, 0x06AC, 0x06AC, 0x06AC}, /* U+06AC */
- {0xFBD5, 0xFBD6, 0xFBD4, 0xFBD3}, /* U+06AD ARABIC LETTER NG */
- {0x06AE, 0x06AE, 0x06AE, 0x06AE}, /* U+06AE */
- {0xFB94, 0xFB95, 0xFB93, 0xFB92}, /* U+06AF ARABIC LETTER GAF */
- {0x06B0, 0x06B0, 0x06B0, 0x06B0}, /* U+06B0 */
- {0xFB9C, 0xFB9D, 0xFB9B, 0xFB9A}, /* U+06B1 ARABIC LETTER NGOEH */
- {0x06B2, 0x06B2, 0x06B2, 0x06B2}, /* U+06B2 */
- {0xFB98, 0xFB99, 0xFB97, 0xFB96}, /* U+06B3 ARABIC LETTER GUEH */
- {0x06B4, 0x06B4, 0x06B4, 0x06B4}, /* U+06B4 */
- {0x06B5, 0x06B5, 0x06B5, 0x06B5}, /* U+06B5 */
- {0x06B6, 0x06B6, 0x06B6, 0x06B6}, /* U+06B6 */
- {0x06B7, 0x06B7, 0x06B7, 0x06B7}, /* U+06B7 */
- {0x06B8, 0x06B8, 0x06B8, 0x06B8}, /* U+06B8 */
- {0x06B9, 0x06B9, 0x06B9, 0x06B9}, /* U+06B9 */
- {0x06BA, 0x06BA, 0xFB9F, 0xFB9E}, /* U+06BA ARABIC LETTER NOON GHUNNA */
- {0xFBA2, 0xFBA3, 0xFBA1, 0xFBA0}, /* U+06BB ARABIC LETTER RNOON */
- {0x06BC, 0x06BC, 0x06BC, 0x06BC}, /* U+06BC */
- {0x06BD, 0x06BD, 0x06BD, 0x06BD}, /* U+06BD */
- {0xFBAC, 0xFBAD, 0xFBAB, 0xFBAA}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
- {0x06BF, 0x06BF, 0x06BF, 0x06BF}, /* U+06BF */
- {0x06C0, 0x06C0, 0xFBA5, 0xFBA4}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
- {0xFBA8, 0xFBA9, 0xFBA7, 0xFBA6}, /* U+06C1 ARABIC LETTER HEH GOAL */
- {0x06C2, 0x06C2, 0x06C2, 0x06C2}, /* U+06C2 */
- {0x06C3, 0x06C3, 0x06C3, 0x06C3}, /* U+06C3 */
- {0x06C4, 0x06C4, 0x06C4, 0x06C4}, /* U+06C4 */
- {0x06C5, 0x06C5, 0xFBE1, 0xFBE0}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
- {0x06C6, 0x06C6, 0xFBDA, 0xFBD9}, /* U+06C6 ARABIC LETTER OE */
- {0x06C7, 0x06C7, 0xFBD8, 0xFBD7}, /* U+06C7 ARABIC LETTER U */
- {0x06C8, 0x06C8, 0xFBDC, 0xFBDB}, /* U+06C8 ARABIC LETTER YU */
- {0x06C9, 0x06C9, 0xFBE3, 0xFBE2}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
- {0x06CA, 0x06CA, 0x06CA, 0x06CA}, /* U+06CA */
- {0x06CB, 0x06CB, 0xFBDF, 0xFBDE}, /* U+06CB ARABIC LETTER VE */
- {0xFBFE, 0xFBFF, 0xFBFD, 0xFBFC}, /* U+06CC ARABIC LETTER FARSI YEH */
- {0x06CD, 0x06CD, 0x06CD, 0x06CD}, /* U+06CD */
- {0x06CE, 0x06CE, 0x06CE, 0x06CE}, /* U+06CE */
- {0x06CF, 0x06CF, 0x06CF, 0x06CF}, /* U+06CF */
- {0xFBE6, 0xFBE7, 0xFBE5, 0xFBE4}, /* U+06D0 ARABIC LETTER E */
- {0x06D1, 0x06D1, 0x06D1, 0x06D1}, /* U+06D1 */
- {0x06D2, 0x06D2, 0xFBAF, 0xFBAE}, /* U+06D2 ARABIC LETTER YEH BARREE */
- {0x06D3, 0x06D3, 0xFBB1, 0xFBB0}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
+ {0x0000u, 0x0000u, 0x0000u, 0xFE80u}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */
+ {0x0000u, 0x0000u, 0xFE82u, 0xFE81u}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */
+ {0x0000u, 0x0000u, 0xFE84u, 0xFE83u}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */
+ {0x0000u, 0x0000u, 0xFE86u, 0xFE85u}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */
+ {0x0000u, 0x0000u, 0xFE88u, 0xFE87u}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */
+ {0xFE8Bu, 0xFE8Cu, 0xFE8Au, 0xFE89u}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */
+ {0x0000u, 0x0000u, 0xFE8Eu, 0xFE8Du}, /* U+0627 ARABIC LETTER ALEF */
+ {0xFE91u, 0xFE92u, 0xFE90u, 0xFE8Fu}, /* U+0628 ARABIC LETTER BEH */
+ {0x0000u, 0x0000u, 0xFE94u, 0xFE93u}, /* U+0629 ARABIC LETTER TEH MARBUTA */
+ {0xFE97u, 0xFE98u, 0xFE96u, 0xFE95u}, /* U+062A ARABIC LETTER TEH */
+ {0xFE9Bu, 0xFE9Cu, 0xFE9Au, 0xFE99u}, /* U+062B ARABIC LETTER THEH */
+ {0xFE9Fu, 0xFEA0u, 0xFE9Eu, 0xFE9Du}, /* U+062C ARABIC LETTER JEEM */
+ {0xFEA3u, 0xFEA4u, 0xFEA2u, 0xFEA1u}, /* U+062D ARABIC LETTER HAH */
+ {0xFEA7u, 0xFEA8u, 0xFEA6u, 0xFEA5u}, /* U+062E ARABIC LETTER KHAH */
+ {0x0000u, 0x0000u, 0xFEAAu, 0xFEA9u}, /* U+062F ARABIC LETTER DAL */
+ {0x0000u, 0x0000u, 0xFEACu, 0xFEABu}, /* U+0630 ARABIC LETTER THAL */
+ {0x0000u, 0x0000u, 0xFEAEu, 0xFEADu}, /* U+0631 ARABIC LETTER REH */
+ {0x0000u, 0x0000u, 0xFEB0u, 0xFEAFu}, /* U+0632 ARABIC LETTER ZAIN */
+ {0xFEB3u, 0xFEB4u, 0xFEB2u, 0xFEB1u}, /* U+0633 ARABIC LETTER SEEN */
+ {0xFEB7u, 0xFEB8u, 0xFEB6u, 0xFEB5u}, /* U+0634 ARABIC LETTER SHEEN */
+ {0xFEBBu, 0xFEBCu, 0xFEBAu, 0xFEB9u}, /* U+0635 ARABIC LETTER SAD */
+ {0xFEBFu, 0xFEC0u, 0xFEBEu, 0xFEBDu}, /* U+0636 ARABIC LETTER DAD */
+ {0xFEC3u, 0xFEC4u, 0xFEC2u, 0xFEC1u}, /* U+0637 ARABIC LETTER TAH */
+ {0xFEC7u, 0xFEC8u, 0xFEC6u, 0xFEC5u}, /* U+0638 ARABIC LETTER ZAH */
+ {0xFECBu, 0xFECCu, 0xFECAu, 0xFEC9u}, /* U+0639 ARABIC LETTER AIN */
+ {0xFECFu, 0xFED0u, 0xFECEu, 0xFECDu}, /* U+063A ARABIC LETTER GHAIN */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063B */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063C */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063D */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063E */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+063F */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0640 */
+ {0xFED3u, 0xFED4u, 0xFED2u, 0xFED1u}, /* U+0641 ARABIC LETTER FEH */
+ {0xFED7u, 0xFED8u, 0xFED6u, 0xFED5u}, /* U+0642 ARABIC LETTER QAF */
+ {0xFEDBu, 0xFEDCu, 0xFEDAu, 0xFED9u}, /* U+0643 ARABIC LETTER KAF */
+ {0xFEDFu, 0xFEE0u, 0xFEDEu, 0xFEDDu}, /* U+0644 ARABIC LETTER LAM */
+ {0xFEE3u, 0xFEE4u, 0xFEE2u, 0xFEE1u}, /* U+0645 ARABIC LETTER MEEM */
+ {0xFEE7u, 0xFEE8u, 0xFEE6u, 0xFEE5u}, /* U+0646 ARABIC LETTER NOON */
+ {0xFEEBu, 0xFEECu, 0xFEEAu, 0xFEE9u}, /* U+0647 ARABIC LETTER HEH */
+ {0x0000u, 0x0000u, 0xFEEEu, 0xFEEDu}, /* U+0648 ARABIC LETTER WAW */
+ {0xFBE8u, 0xFBE9u, 0xFEF0u, 0xFEEFu}, /* U+0649 ARABIC LETTER */
+ {0xFEF3u, 0xFEF4u, 0xFEF2u, 0xFEF1u}, /* U+064A ARABIC LETTER YEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064B */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064C */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064D */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064E */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+064F */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0650 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0651 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0652 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0653 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0654 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0655 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0656 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0657 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0658 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0659 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065A */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065B */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065C */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065D */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065E */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+065F */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0660 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0661 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0662 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0663 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0664 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0665 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0666 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0667 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0668 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0669 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066A */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066B */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066C */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066D */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066E */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+066F */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0670 */
+ {0x0000u, 0x0000u, 0xFB51u, 0xFB50u}, /* U+0671 ARABIC LETTER ALEF WASLA */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0672 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0673 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0674 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0675 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0676 */
+ {0x0000u, 0x0000u, 0x0000u, 0xFBDDu}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0678 */
+ {0xFB68u, 0xFB69u, 0xFB67u, 0xFB66u}, /* U+0679 ARABIC LETTER TTEH */
+ {0xFB60u, 0xFB61u, 0xFB5Fu, 0xFB5Eu}, /* U+067A ARABIC LETTER TTEHEH */
+ {0xFB54u, 0xFB55u, 0xFB53u, 0xFB52u}, /* U+067B ARABIC LETTER BEEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+067C */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+067D */
+ {0xFB58u, 0xFB59u, 0xFB57u, 0xFB56u}, /* U+067E ARABIC LETTER PEH */
+ {0xFB64u, 0xFB65u, 0xFB63u, 0xFB62u}, /* U+067F ARABIC LETTER TEHEH */
+ {0xFB5Cu, 0xFB5Du, 0xFB5Bu, 0xFB5Au}, /* U+0680 ARABIC LETTER BEHEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0681 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0682 */
+ {0xFB78u, 0xFB79u, 0xFB77u, 0xFB76u}, /* U+0683 ARABIC LETTER NYEH */
+ {0xFB74u, 0xFB75u, 0xFB73u, 0xFB72u}, /* U+0684 ARABIC LETTER DYEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0685 */
+ {0xFB7Cu, 0xFB7Du, 0xFB7Bu, 0xFB7Au}, /* U+0686 ARABIC LETTER TCHEH */
+ {0xFB80u, 0xFB81u, 0xFB7Fu, 0xFB7Eu}, /* U+0687 ARABIC LETTER TCHEHEH */
+ {0x0000u, 0x0000u, 0xFB89u, 0xFB88u}, /* U+0688 ARABIC LETTER DDAL */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0689 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068A */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068B */
+ {0x0000u, 0x0000u, 0xFB85u, 0xFB84u}, /* U+068C ARABIC LETTER DAHAL */
+ {0x0000u, 0x0000u, 0xFB83u, 0xFB82u}, /* U+068D ARABIC LETTER DDAHAL */
+ {0x0000u, 0x0000u, 0xFB87u, 0xFB86u}, /* U+068E ARABIC LETTER DUL */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+068F */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0690 */
+ {0x0000u, 0x0000u, 0xFB8Du, 0xFB8Cu}, /* U+0691 ARABIC LETTER RREH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0692 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0693 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0694 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0695 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0696 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0697 */
+ {0x0000u, 0x0000u, 0xFB8Bu, 0xFB8Au}, /* U+0698 ARABIC LETTER JEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+0699 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069A */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069B */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069C */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069D */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069E */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+069F */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A0 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A1 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A2 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A3 */
+ {0xFB6Cu, 0xFB6Du, 0xFB6Bu, 0xFB6Au}, /* U+06A4 ARABIC LETTER VEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A5 */
+ {0xFB70u, 0xFB71u, 0xFB6Fu, 0xFB6Eu}, /* U+06A6 ARABIC LETTER PEHEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A7 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06A8 */
+ {0xFB90u, 0xFB91u, 0xFB8Fu, 0xFB8Eu}, /* U+06A9 ARABIC LETTER KEHEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AA */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AB */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AC */
+ {0xFBD5u, 0xFBD6u, 0xFBD4u, 0xFBD3u}, /* U+06AD ARABIC LETTER NG */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06AE */
+ {0xFB94u, 0xFB95u, 0xFB93u, 0xFB92u}, /* U+06AF ARABIC LETTER GAF */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B0 */
+ {0xFB9Cu, 0xFB9Du, 0xFB9Bu, 0xFB9Au}, /* U+06B1 ARABIC LETTER NGOEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B2 */
+ {0xFB98u, 0xFB99u, 0xFB97u, 0xFB96u}, /* U+06B3 ARABIC LETTER GUEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B4 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B5 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B6 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B7 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B8 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06B9 */
+ {0x0000u, 0x0000u, 0xFB9Fu, 0xFB9Eu}, /* U+06BA ARABIC LETTER NOON GHUNNA */
+ {0xFBA2u, 0xFBA3u, 0xFBA1u, 0xFBA0u}, /* U+06BB ARABIC LETTER RNOON */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BC */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BD */
+ {0xFBACu, 0xFBADu, 0xFBABu, 0xFBAAu}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06BF */
+ {0x0000u, 0x0000u, 0xFBA5u, 0xFBA4u}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */
+ {0xFBA8u, 0xFBA9u, 0xFBA7u, 0xFBA6u}, /* U+06C1 ARABIC LETTER HEH GOAL */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C2 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C3 */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06C4 */
+ {0x0000u, 0x0000u, 0xFBE1u, 0xFBE0u}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */
+ {0x0000u, 0x0000u, 0xFBDAu, 0xFBD9u}, /* U+06C6 ARABIC LETTER OE */
+ {0x0000u, 0x0000u, 0xFBD8u, 0xFBD7u}, /* U+06C7 ARABIC LETTER U */
+ {0x0000u, 0x0000u, 0xFBDCu, 0xFBDBu}, /* U+06C8 ARABIC LETTER YU */
+ {0x0000u, 0x0000u, 0xFBE3u, 0xFBE2u}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CA */
+ {0x0000u, 0x0000u, 0xFBDFu, 0xFBDEu}, /* U+06CB ARABIC LETTER VE */
+ {0xFBFEu, 0xFBFFu, 0xFBFDu, 0xFBFCu}, /* U+06CC ARABIC LETTER FARSI YEH */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CD */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CE */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06CF */
+ {0xFBE6u, 0xFBE7u, 0xFBE5u, 0xFBE4u}, /* U+06D0 ARABIC LETTER E */
+ {0x0000u, 0x0000u, 0x0000u, 0x0000u}, /* U+06D1 */
+ {0x0000u, 0x0000u, 0xFBAFu, 0xFBAEu}, /* U+06D2 ARABIC LETTER YEH BARREE */
+ {0x0000u, 0x0000u, 0xFBB1u, 0xFBB0u}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */
};
-#define SHAPING_TABLE_FIRST 0x0621
-#define SHAPING_TABLE_LAST 0x06D3
+#define SHAPING_TABLE_FIRST 0x0621u
+#define SHAPING_TABLE_LAST 0x06D3u
-static const struct {
+static const struct ligature_set_t {
uint16_t first;
- struct {
+ struct ligature_pairs_t {
uint16_t second;
uint16_t ligature;
} ligatures[4];
} ligature_table[] =
{
- { 0xFEDF, {
- { 0xFE88, 0xFEF9 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
- { 0xFE82, 0xFEF5 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
- { 0xFE8E, 0xFEFB }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
- { 0xFE84, 0xFEF7 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
+ { 0xFEDFu, {
+ { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */
+ { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */
+ { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */
+ { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */
}},
- { 0xFEE0, {
- { 0xFE88, 0xFEFA }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
- { 0xFE82, 0xFEF6 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
- { 0xFE8E, 0xFEFC }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
- { 0xFE84, 0xFEF8 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
+ { 0xFEE0u, {
+ { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */
+ { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */
+ { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */
+ { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */
}},
};
diff --git a/src/hb-ot-shape-complex-arabic-win1256.hh b/src/hb-ot-shape-complex-arabic-win1256.hh
new file mode 100644
index 0000000..8edd3ba
--- /dev/null
+++ b/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -0,0 +1,323 @@
+/*
+ * Copyright © 2014 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+
+
+/*
+ * The macros in the first part of this file are generic macros that can
+ * be used to define the bytes for OpenType table data in code in a
+ * readable manner. We can move the macros to reside with their respective
+ * struct types, but since we only use these to define one data table, the
+ * Windows-1256 Arabic shaping table in this file, we keep them here.
+ */
+
+
+/* First we measure, then we cut. */
+#ifndef OT_MEASURE
+#define OT_MEASURE
+#define OT_TABLE_START static const struct TABLE_NAME {
+#define OT_TABLE_END }
+#define OT_LABEL_START(Name) unsigned char Name[
+#define OT_LABEL_END ];
+#define OT_BYTE(u8) +1/*byte*/
+#define OT_USHORT(u16) +2/*bytes*/
+#else
+#undef OT_MEASURE
+#define OT_TABLE_START TABLE_NAME = {
+#define OT_TABLE_END };
+#define OT_LABEL_START(Name) {
+#define OT_LABEL_END },
+#define OT_BYTE(u8) (u8),
+#define OT_USHORT(u16) (unsigned char)((u16)>>8), (unsigned char)((u16)&0xFFu),
+#define OT_COUNT(Name, ItemSize) ((unsigned int) sizeof(((struct TABLE_NAME*)0)->Name) \
+ / (unsigned int)(ItemSize) \
+ /* OT_ASSERT it's divisible (and positive). */)
+#define OT_DISTANCE(From,To) ((unsigned int) \
+ ((char*)(&((struct TABLE_NAME*)0)->To) - \
+ (char*)(&((struct TABLE_NAME*)0)->From)) \
+ /* OT_ASSERT it's positive. */)
+#endif
+
+
+#define OT_LABEL(Name) \
+ OT_LABEL_END \
+ OT_LABEL_START(Name)
+
+/* Whenever we receive an argument that is a list, it will expand to
+ * contain commas. That cannot be passed to another macro because the
+ * commas will throw off the preprocessor. The solution is to wrap
+ * the passed-in argument in OT_LIST() before passing to the next macro.
+ * Unfortunately this trick requires vararg macros. */
+#define OT_LIST(...) __VA_ARGS__
+
+
+/*
+ * Basic Types
+ */
+
+#define OT_TAG(a,b,c,d) \
+ OT_BYTE(a) OT_BYTE(b) OT_BYTE(c) OT_BYTE(d)
+
+#define OT_OFFSET(From, To) /* Offset from From to To in bytes */ \
+ OT_USHORT(OT_DISTANCE(From, To))
+
+#define OT_GLYPHID /* GlyphID */ \
+ OT_USHORT
+
+#define OT_UARRAY(Name, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(OT_COUNT(Name##Data, 2)) \
+ OT_LABEL(Name##Data) \
+ Items \
+ OT_LABEL_END
+
+#define OT_UHEADLESSARRAY(Name, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(OT_COUNT(Name##Data, 2) + 1) \
+ OT_LABEL(Name##Data) \
+ Items \
+ OT_LABEL_END
+
+
+/*
+ * Common Types
+ */
+
+#define OT_LOOKUP_FLAG_IGNORE_MARKS 0x08u
+
+#define OT_LOOKUP(Name, LookupType, LookupFlag, SubLookupOffsets) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(LookupType) \
+ OT_USHORT(LookupFlag) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##SubLookupOffsetsArray, OT_LIST(SubLookupOffsets))
+
+#define OT_SUBLOOKUP(Name, SubFormat, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(SubFormat) \
+ Items
+
+#define OT_COVERAGE1(Name, Items) \
+ OT_LABEL_START(Name) \
+ OT_USHORT(1) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##Glyphs, OT_LIST(Items))
+
+
+/*
+ * GSUB
+ */
+
+#define OT_LOOKUP_TYPE_SUBST_SINGLE 1u
+#define OT_LOOKUP_TYPE_SUBST_LIGATURE 4u
+
+#define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
+ OT_SUBLOOKUP(Name, 2, \
+ OT_OFFSET(Name, Name##Coverage) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##Substitute, OT_LIST(ToGlyphs)) \
+ ) \
+ OT_COVERAGE1(Name##Coverage, OT_LIST(FromGlyphs)) \
+ /* ASSERT_STATIC_EXPR len(FromGlyphs) == len(ToGlyphs) */
+
+#define OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(Name, FirstGlyphs, LigatureSetOffsets) \
+ OT_SUBLOOKUP(Name, 1, \
+ OT_OFFSET(Name, Name##Coverage) \
+ OT_LABEL_END \
+ OT_UARRAY(Name##LigatureSetOffsetsArray, OT_LIST(LigatureSetOffsets)) \
+ ) \
+ OT_COVERAGE1(Name##Coverage, OT_LIST(FirstGlyphs)) \
+ /* ASSERT_STATIC_EXPR len(FirstGlyphs) == len(LigatureSetOffsets) */
+
+#define OT_LIGATURE_SET(Name, LigatureSetOffsets) \
+ OT_UARRAY(Name, OT_LIST(LigatureSetOffsets))
+
+#define OT_LIGATURE(Name, Components, LigGlyph) \
+ OT_LABEL_START(Name) \
+ LigGlyph \
+ OT_LABEL_END \
+ OT_UHEADLESSARRAY(Name##ComponentsArray, OT_LIST(Components))
+
+/*
+ *
+ * Start of Windows-1256 shaping table.
+ *
+ */
+
+/* Table name. */
+#define TABLE_NAME arabic_win1256_gsub_lookups
+
+/* Table manifest. */
+#define MANIFEST(Items) \
+ OT_LABEL_START(manifest) \
+ OT_USHORT(OT_COUNT(manifestData, 6)) \
+ OT_LABEL(manifestData) \
+ Items \
+ OT_LABEL_END
+
+#define MANIFEST_LOOKUP(Tag, Name) \
+ Tag \
+ OT_OFFSET(manifest, Name)
+
+/* Shorthand. */
+#define G OT_GLYPHID
+
+/*
+ * Table Start
+ */
+OT_TABLE_START
+
+
+/*
+ * Manifest
+ */
+MANIFEST(
+ MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligLookup)
+ MANIFEST_LOOKUP(OT_TAG('i','n','i','t'), initLookup)
+ MANIFEST_LOOKUP(OT_TAG('m','e','d','i'), mediLookup)
+ MANIFEST_LOOKUP(OT_TAG('f','i','n','a'), finaLookup)
+ MANIFEST_LOOKUP(OT_TAG('r','l','i','g'), rligMarksLookup)
+)
+
+/*
+ * Lookups
+ */
+OT_LOOKUP(initLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(initLookup, initmediSubLookup)
+ OT_OFFSET(initLookup, initSubLookup)
+)
+OT_LOOKUP(mediLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(mediLookup, initmediSubLookup)
+ OT_OFFSET(mediLookup, mediSubLookup)
+ OT_OFFSET(mediLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(finaLookup, OT_LOOKUP_TYPE_SUBST_SINGLE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(finaLookup, finaSubLookup)
+ /* We don't need this one currently as the sequence inherits masks
+ * from the first item. Just in case we change that in the future
+ * to be smart about Arabic masks when ligating... */
+ OT_OFFSET(finaLookup, medifinaLamAlefSubLookup)
+)
+OT_LOOKUP(rligLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, OT_LOOKUP_FLAG_IGNORE_MARKS,
+ OT_OFFSET(rligLookup, lamAlefLigaturesSubLookup)
+)
+OT_LOOKUP(rligMarksLookup, OT_LOOKUP_TYPE_SUBST_LIGATURE, 0,
+ OT_OFFSET(rligMarksLookup, shaddaLigaturesSubLookup)
+)
+
+/*
+ * init/medi/fina forms
+ */
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initmediSubLookup,
+ G(198) G(200) G(201) G(202) G(203) G(204) G(205) G(206) G(211)
+ G(212) G(213) G(214) G(223) G(225) G(227) G(228) G(236) G(237),
+ G(162) G(4) G(5) G(5) G(6) G(7) G(9) G(11) G(13)
+ G(14) G(15) G(26) G(140) G(141) G(142) G(143) G(154) G(154)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(initSubLookup,
+ G(218) G(219) G(221) G(222) G(229),
+ G(27) G(30) G(128) G(131) G(144)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(mediSubLookup,
+ G(218) G(219) G(221) G(222) G(229),
+ G(28) G(31) G(129) G(138) G(149)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(finaSubLookup,
+ G(194) G(195) G(197) G(198) G(199) G(201) G(204) G(205) G(206)
+ G(218) G(219) G(229) G(236) G(237),
+ G(2) G(1) G(3) G(181) G(0) G(159) G(8) G(10) G(12)
+ G(29) G(127) G(152) G(160) G(156)
+)
+OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(medifinaLamAlefSubLookup,
+ G(165) G(178) G(180) G(252),
+ G(170) G(179) G(185) G(255)
+)
+
+/*
+ * Lam+Alef ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(lamAlefLigaturesSubLookup,
+ G(225),
+ OT_OFFSET(lamAlefLigaturesSubLookup, lamLigatureSet)
+)
+OT_LIGATURE_SET(lamLigatureSet,
+ OT_OFFSET(lamLigatureSet, lamInitLigature1)
+ OT_OFFSET(lamLigatureSet, lamInitLigature2)
+ OT_OFFSET(lamLigatureSet, lamInitLigature3)
+ OT_OFFSET(lamLigatureSet, lamInitLigature4)
+)
+OT_LIGATURE(lamInitLigature1, G(199), G(165))
+OT_LIGATURE(lamInitLigature2, G(195), G(178))
+OT_LIGATURE(lamInitLigature3, G(194), G(180))
+OT_LIGATURE(lamInitLigature4, G(197), G(252))
+
+/*
+ * Shadda ligatures
+ */
+OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1(shaddaLigaturesSubLookup,
+ G(248),
+ OT_OFFSET(shaddaLigaturesSubLookup, shaddaLigatureSet)
+)
+OT_LIGATURE_SET(shaddaLigatureSet,
+ OT_OFFSET(shaddaLigatureSet, shaddaLigature1)
+ OT_OFFSET(shaddaLigatureSet, shaddaLigature2)
+ OT_OFFSET(shaddaLigatureSet, shaddaLigature3)
+)
+OT_LIGATURE(shaddaLigature1, G(243), G(172))
+OT_LIGATURE(shaddaLigature2, G(245), G(173))
+OT_LIGATURE(shaddaLigature3, G(246), G(175))
+
+/*
+ * Table end
+ */
+OT_TABLE_END
+
+
+/*
+ * Clean up
+ */
+#undef OT_TABLE_START
+#undef OT_TABLE_END
+#undef OT_LABEL_START
+#undef OT_LABEL_END
+#undef OT_BYTE
+#undef OT_USHORT
+#undef OT_DISTANCE
+#undef OT_COUNT
+
+/*
+ * Include a second time to get the table data...
+ */
+#if 0
+#include "hb-private.hh" /* Make check-includes.sh happy. */
+#endif
+#ifdef OT_MEASURE
+#include "hb-ot-shape-complex-arabic-win1256.hh"
+#endif
+
+#define HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH
+#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_WIN1256_HH */
diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc
index 54460f0..ae90864 100644
--- a/src/hb-ot-shape-complex-arabic.cc
+++ b/src/hb-ot-shape-complex-arabic.cc
@@ -1,5 +1,5 @@
/*
- * Copyright © 2010 Google, Inc.
+ * Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -28,9 +28,8 @@
#include "hb-ot-shape-private.hh"
-
/* buffer var allocations */
-#define arabic_shaping_action() complex_var_temporary_u8() /* arabic shaping action */
+#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
/*
@@ -38,17 +37,16 @@
*/
enum {
JOINING_TYPE_U = 0,
- JOINING_TYPE_R = 1,
- JOINING_TYPE_D = 2,
+ JOINING_TYPE_L = 1,
+ JOINING_TYPE_R = 2,
+ JOINING_TYPE_D = 3,
JOINING_TYPE_C = JOINING_TYPE_D,
- JOINING_GROUP_ALAPH = 3,
- JOINING_GROUP_DALATH_RISH = 4,
- NUM_STATE_MACHINE_COLS = 5,
-
- /* We deliberately don't have a JOINING_TYPE_L since that's unused in Unicode. */
+ JOINING_GROUP_ALAPH = 4,
+ JOINING_GROUP_DALATH_RISH = 5,
+ NUM_STATE_MACHINE_COLS = 6,
- JOINING_TYPE_T = 6,
- JOINING_TYPE_X = 7 /* means: use general-category to choose between U or T. */
+ JOINING_TYPE_T = 7,
+ JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */
};
/*
@@ -59,77 +57,45 @@ enum {
static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
{
- if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, JOINING_TABLE_LAST))) {
- unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST];
- if (likely (j_type != JOINING_TYPE_X))
- return j_type;
- }
-
- /* Mongolian joining data is not in ArabicJoining.txt yet */
- if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF)))
- {
- /* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */
- if (gen_cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A)
- return JOINING_TYPE_D;
- }
-
- if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) {
- return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C;
- }
-
- return (FLAG(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))) ?
- JOINING_TYPE_T : JOINING_TYPE_U;
-}
-
-static hb_codepoint_t get_arabic_shape (hb_codepoint_t u, unsigned int shape)
-{
- if (likely (hb_in_range<hb_codepoint_t> (u, SHAPING_TABLE_FIRST, SHAPING_TABLE_LAST)) && shape < 4)
- return shaping_table[u - SHAPING_TABLE_FIRST][shape];
- return u;
+ unsigned int j_type = joining_type(u);
+ if (likely (j_type != JOINING_TYPE_X))
+ return j_type;
+
+ return (FLAG(gen_cat) &
+ (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
+ FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
+ FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))
+ ) ? JOINING_TYPE_T : JOINING_TYPE_U;
}
-static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second)
-{
- if (unlikely (!second)) return 0;
- for (unsigned i = 0; i < ARRAY_LENGTH (ligature_table); i++)
- if (ligature_table[i].first == first)
- for (unsigned j = 0; j < ARRAY_LENGTH (ligature_table[i].ligatures); j++)
- if (ligature_table[i].ligatures[j].second == second)
- return ligature_table[i].ligatures[j].ligature;
- return 0;
-}
+#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
-static const hb_tag_t arabic_syriac_features[] =
+static const hb_tag_t arabic_features[] =
{
- HB_TAG('i','n','i','t'),
- HB_TAG('m','e','d','i'),
- HB_TAG('f','i','n','a'),
HB_TAG('i','s','o','l'),
- /* Syriac */
- HB_TAG('m','e','d','2'),
+ HB_TAG('f','i','n','a'),
HB_TAG('f','i','n','2'),
HB_TAG('f','i','n','3'),
+ HB_TAG('m','e','d','i'),
+ HB_TAG('m','e','d','2'),
+ HB_TAG('i','n','i','t'),
HB_TAG_NONE
};
/* Same order as the feature array */
enum {
- INIT,
- MEDI,
- FINA,
ISOL,
-
- /* Syriac */
- MED2,
+ FINA,
FIN2,
FIN3,
+ MEDI,
+ MED2,
+ INIT,
NONE,
- COMMON_NUM_FEATURES = 4,
- SYRIAC_NUM_FEATURES = 7,
- TOTAL_NUM_FEATURES = NONE
+ ARABIC_NUM_FEATURES = NONE
};
static const struct arabic_state_table_entry {
@@ -138,162 +104,279 @@ static const struct arabic_state_table_entry {
uint16_t next_state;
} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
{
- /* jt_U, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */
+ /* jt_U, jt_L, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */
/* State 0: prev was U, not willing to join. */
- { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
+ { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, },
/* State 1: prev was R or ISOL/ALAPH, not willing to join. */
- { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
+ { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, },
- /* State 2: prev was D/ISOL, willing to join. */
- { {NONE,NONE,0}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
+ /* State 2: prev was D/L in ISOL form, willing to join. */
+ { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, },
- /* State 3: prev was D/FINA, willing to join. */
- { {NONE,NONE,0}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
+ /* State 3: prev was D in FINA form, willing to join. */
+ { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, },
/* State 4: prev was FINA ALAPH, not willing to join. */
- { {NONE,NONE,0}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
+ { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, },
/* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */
- { {NONE,NONE,0}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
+ { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, },
/* State 6: prev was DALATH/RISH, not willing to join. */
- { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
+ { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, }
};
+static void
+nuke_joiners (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
-void
-_hb_ot_shape_complex_collect_features_arabic (hb_ot_map_builder_t *map,
- const hb_segment_properties_t *props)
+static void
+arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+static void
+collect_features_arabic (hb_ot_shape_planner_t *plan)
{
- /* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together,
- * then rlig and calt each in their own stage. This makes IranNastaliq's ALLAH
- * ligature work correctly. It's unfortunate though...
+ hb_ot_map_builder_t *map = &plan->map;
+
+ /* We apply features according to the Arabic spec, with pauses
+ * in between most.
*
- * This also makes Arial Bold in Windows7 work. See:
+ * The pause between init/medi/... and rlig is required. See eg:
* https://bugzilla.mozilla.org/show_bug.cgi?id=644184
*
- * TODO: Add test cases for these two.
+ * The pauses between init/medi/... themselves are not necessarily
+ * needed as only one of those features is applied to any character.
+ * The only difference it makes is when fonts have contextual
+ * substitutions. We now follow the order of the spec, which makes
+ * for better experience if that's what Uniscribe is doing.
+ *
+ * At least for Arabic, looks like Uniscribe has a pause between
+ * rlig and calt. Otherwise the IranNastaliq's ALLAH ligature won't
+ * work. However, testing shows that rlig and calt are applied
+ * together for Mongolian in Uniscribe. As such, we only add a
+ * pause for Arabic, not other scripts.
*/
- map->add_bool_feature (HB_TAG('c','c','m','p'));
- map->add_bool_feature (HB_TAG('l','o','c','l'));
-
- map->add_gsub_pause (NULL, NULL);
-
- unsigned int num_features = props->script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
- for (unsigned int i = 0; i < num_features; i++)
- map->add_bool_feature (arabic_syriac_features[i], false);
+ map->add_gsub_pause (nuke_joiners);
- map->add_gsub_pause (NULL, NULL);
+ map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+ map->add_global_bool_feature (HB_TAG('l','o','c','l'));
- map->add_bool_feature (HB_TAG('r','l','i','g'));
- map->add_gsub_pause (NULL, NULL);
+ map->add_gsub_pause (NULL);
- map->add_bool_feature (HB_TAG('c','a','l','t'));
- map->add_gsub_pause (NULL, NULL);
+ for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++)
+ {
+ bool has_fallback = plan->props.script == HB_SCRIPT_ARABIC && !FEATURE_IS_SYRIAC (arabic_features[i]);
+ map->add_feature (arabic_features[i], 1, has_fallback ? F_HAS_FALLBACK : F_NONE);
+ map->add_gsub_pause (NULL);
+ }
- /* ArabicOT spec enables 'cswh' for Arabic where as for basic shaper it's disabled by default. */
- map->add_bool_feature (HB_TAG('c','s','w','h'));
+ map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK);
+ if (plan->props.script == HB_SCRIPT_ARABIC)
+ map->add_gsub_pause (arabic_fallback_shape);
+
+ map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+ map->add_gsub_pause (NULL);
+
+ /* The spec includes 'cswh'. Earlier versions of Windows
+ * used to enable this by default, but testing suggests
+ * that Windows 8 and later do not enable it by default,
+ * and spec now says 'Off by default'.
+ * We disabled this in ae23c24c32.
+ * Note that IranNastaliq uses this feature extensively
+ * to fixup broken glyph sequences. Oh well...
+ * Test case: U+0643,U+0640,U+0631. */
+ //map->add_global_bool_feature (HB_TAG('c','s','w','h'));
+ map->add_global_bool_feature (HB_TAG('m','s','e','t'));
}
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_arabic (void)
+#include "hb-ot-shape-complex-arabic-fallback.hh"
+
+struct arabic_shape_plan_t
{
- return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
-}
+ ASSERT_POD ();
+ /* The "+ 1" in the next array is to accommodate for the "NONE" command,
+ * which is not an OpenType feature, but this simplifies the code by not
+ * having to do a "if (... < NONE) ..." and just rely on the fact that
+ * mask_array[NONE] == 0. */
+ hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
-static void
-arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer)
+ bool do_fallback;
+ arabic_fallback_plan_t *fallback_plan;
+};
+
+static void *
+data_create_arabic (const hb_ot_shape_plan_t *plan)
{
- unsigned int count = buffer->len;
- hb_codepoint_t glyph;
-
- /* Shape to presentation forms */
- for (unsigned int i = 0; i < count; i++) {
- hb_codepoint_t u = buffer->info[i].codepoint;
- hb_codepoint_t shaped = get_arabic_shape (u, buffer->info[i].arabic_shaping_action());
- if (shaped != u && hb_font_get_glyph (font, shaped, 0, &glyph))
- buffer->info[i].codepoint = shaped;
+ arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
+ if (unlikely (!arabic_plan))
+ return NULL;
+
+ arabic_plan->do_fallback = plan->props.script == HB_SCRIPT_ARABIC;
+ for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) {
+ arabic_plan->mask_array[i] = plan->map.get_1_mask (arabic_features[i]);
+ arabic_plan->do_fallback = arabic_plan->do_fallback &&
+ (FEATURE_IS_SYRIAC (arabic_features[i]) ||
+ plan->map.needs_fallback (arabic_features[i]));
}
- /* Mandatory ligatures */
- buffer->clear_output ();
- for (buffer->idx = 0; buffer->idx + 1 < count;) {
- hb_codepoint_t ligature = get_ligature (buffer->cur().codepoint,
- buffer->cur(+1).codepoint);
- if (likely (!ligature) || !(hb_font_get_glyph (font, ligature, 0, &glyph))) {
- buffer->next_glyph ();
- continue;
- }
+ return arabic_plan;
+}
+
+static void
+data_destroy_arabic (void *data)
+{
+ arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
- buffer->replace_glyphs (2, 1, &ligature);
+ arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
- /* Technically speaking we can skip marks and stuff, like the GSUB path does.
- * But who cares, we're in fallback! */
- }
- for (; buffer->idx < count;)
- buffer->next_glyph ();
- buffer->swap_buffers ();
+ free (data);
}
-void
-_hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map,
- hb_buffer_t *buffer,
- hb_font_t *font)
+static void
+arabic_joining (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
- unsigned int prev = 0, state = 0;
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int prev = (unsigned int) -1, state = 0;
- HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
+ /* Check pre-context */
+ for (unsigned int i = 0; i < buffer->context_len[0]; i++)
+ {
+ unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i]));
+
+ if (unlikely (this_type == JOINING_TYPE_T))
+ continue;
+
+ const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+ state = entry->next_state;
+ break;
+ }
for (unsigned int i = 0; i < count; i++)
{
- unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i]));
+ unsigned int this_type = get_joining_type (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
if (unlikely (this_type == JOINING_TYPE_T)) {
- buffer->info[i].arabic_shaping_action() = NONE;
+ info[i].arabic_shaping_action() = NONE;
continue;
}
const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
- if (entry->prev_action != NONE)
- buffer->info[prev].arabic_shaping_action() = entry->prev_action;
+ if (entry->prev_action != NONE && prev != (unsigned int) -1)
+ info[prev].arabic_shaping_action() = entry->prev_action;
- buffer->info[i].arabic_shaping_action() = entry->curr_action;
+ info[i].arabic_shaping_action() = entry->curr_action;
prev = i;
state = entry->next_state;
}
- hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0};
- hb_mask_t total_masks = 0;
- unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES;
- for (unsigned int i = 0; i < num_masks; i++) {
- mask_array[i] = map->get_1_mask (arabic_syriac_features[i]);
- total_masks |= mask_array[i];
- }
+ for (unsigned int i = 0; i < buffer->context_len[1]; i++)
+ {
+ unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i]));
+
+ if (unlikely (this_type == JOINING_TYPE_T))
+ continue;
- if (total_masks) {
- /* Has OpenType tables */
- for (unsigned int i = 0; i < count; i++)
- buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()];
- } else if (buffer->props.script == HB_SCRIPT_ARABIC) {
- /* Fallback Arabic shaping to Presentation Forms */
- /* Pitfalls:
- * - This path fires if user force-set init/medi/fina/isol off,
- * - If font does not declare script 'arab', well, what to do?
- * Most probably it's safe to assume that init/medi/fina/isol
- * still mean Arabic shaping, although they do not have to.
- */
- arabic_fallback_shape (font, buffer);
+ const arabic_state_table_entry *entry = &arabic_state_table[state][this_type];
+ if (entry->prev_action != NONE && prev != (unsigned int) -1)
+ info[prev].arabic_shaping_action() = entry->prev_action;
+ break;
}
+}
+
+static void
+mongolian_variation_selectors (hb_buffer_t *buffer)
+{
+ /* Copy arabic_shaping_action() from base to Mongolian variation selectors. */
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 1; i < count; i++)
+ if (unlikely (hb_in_range (info[i].codepoint, 0x180Bu, 0x180Du)))
+ info[i].arabic_shaping_action() = info[i - 1].arabic_shaping_action();
+}
+
+static void
+setup_masks_arabic (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font HB_UNUSED)
+{
+ HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
+
+ const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+
+ arabic_joining (buffer);
+ if (plan->props.script == HB_SCRIPT_MONGOLIAN)
+ mongolian_variation_selectors (buffer);
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ info[i].mask |= arabic_plan->mask_array[info[i].arabic_shaping_action()];
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
+static void
+nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if (_hb_glyph_info_is_zwj (&info[i]))
+ _hb_glyph_info_flip_joiners (&info[i]);
+}
+
+static void
+arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
+
+ if (!arabic_plan->do_fallback)
+ return;
+
+retry:
+ arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan);
+ if (unlikely (!fallback_plan))
+ {
+ /* This sucks. We need a font to build the fallback plan... */
+ fallback_plan = arabic_fallback_plan_create (plan, font);
+ if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast<arabic_shape_plan_t *> (arabic_plan))->fallback_plan, NULL, fallback_plan))) {
+ arabic_fallback_plan_destroy (fallback_plan);
+ goto retry;
+ }
+ }
+
+ arabic_fallback_plan_shape (fallback_plan, font, buffer);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
+{
+ "arabic",
+ collect_features_arabic,
+ NULL, /* override_features */
+ data_create_arabic,
+ data_destroy_arabic,
+ NULL, /* preprocess_text_arabic */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ setup_masks_arabic,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+ true, /* fallback_position */
+};
diff --git a/src/hb-graphite2-private.hh b/src/hb-ot-shape-complex-default.cc
index 644ea75..f7f097e 100644
--- a/src/hb-graphite2-private.hh
+++ b/src/hb-ot-shape-complex-default.cc
@@ -1,5 +1,5 @@
/*
- * Copyright © 2012 Google, Inc.
+ * Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -24,19 +24,21 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_GRAPHITE2_PRIVATE_HH
-#define HB_GRAPHITE2_PRIVATE_HH
+#include "hb-ot-shape-complex-private.hh"
-#include "hb-private.hh"
-#include "hb-graphite2.h"
-
-
-HB_INTERNAL hb_bool_t
-_hb_graphite2_shape (hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *features,
- unsigned int num_features);
-
-
-#endif /* HB_GRAPHITE2_PRIVATE_HH */
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
+{
+ "default",
+ NULL, /* collect_features */
+ NULL, /* override_features */
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+ true, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-hangul.cc b/src/hb-ot-shape-complex-hangul.cc
new file mode 100644
index 0000000..6ac18b0
--- /dev/null
+++ b/src/hb-ot-shape-complex-hangul.cc
@@ -0,0 +1,426 @@
+/*
+ * Copyright © 2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* Hangul shaper */
+
+
+/* Same order as the feature array below */
+enum {
+ NONE,
+
+ LJMO,
+ VJMO,
+ TJMO,
+
+ FIRST_HANGUL_FEATURE = LJMO,
+ HANGUL_FEATURE_COUNT = TJMO + 1
+};
+
+static const hb_tag_t hangul_features[HANGUL_FEATURE_COUNT] =
+{
+ HB_TAG_NONE,
+ HB_TAG('l','j','m','o'),
+ HB_TAG('v','j','m','o'),
+ HB_TAG('t','j','m','o')
+};
+
+static void
+collect_features_hangul (hb_ot_shape_planner_t *plan)
+{
+ hb_ot_map_builder_t *map = &plan->map;
+
+ for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++)
+ map->add_feature (hangul_features[i], 1, F_NONE);
+}
+
+static void
+override_features_hangul (hb_ot_shape_planner_t *plan)
+{
+ /* Uniscribe does not apply 'calt' for Hangul, and certain fonts
+ * (Noto Sans CJK, Source Sans Han, etc) apply all of jamo lookups
+ * in calt, which is not desirable. */
+ plan->map.add_feature (HB_TAG('c','a','l','t'), 0, F_GLOBAL);
+}
+
+struct hangul_shape_plan_t
+{
+ ASSERT_POD ();
+
+ hb_mask_t mask_array[HANGUL_FEATURE_COUNT];
+};
+
+static void *
+data_create_hangul (const hb_ot_shape_plan_t *plan)
+{
+ hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
+ if (unlikely (!hangul_plan))
+ return NULL;
+
+ for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++)
+ hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]);
+
+ return hangul_plan;
+}
+
+static void
+data_destroy_hangul (void *data)
+{
+ free (data);
+}
+
+/* Constants for algorithmic hangul syllable [de]composition. */
+#define LBase 0x1100u
+#define VBase 0x1161u
+#define TBase 0x11A7u
+#define LCount 19u
+#define VCount 21u
+#define TCount 28u
+#define SBase 0xAC00u
+#define NCount (VCount * TCount)
+#define SCount (LCount * NCount)
+
+#define isCombiningL(u) (hb_in_range ((u), LBase, LBase+LCount-1))
+#define isCombiningV(u) (hb_in_range ((u), VBase, VBase+VCount-1))
+#define isCombiningT(u) (hb_in_range ((u), TBase+1, TBase+TCount-1))
+#define isCombinedS(u) (hb_in_range ((u), SBase, SBase+SCount-1))
+
+#define isL(u) (hb_in_ranges ((u), 0x1100u, 0x115Fu, 0xA960u, 0xA97Cu))
+#define isV(u) (hb_in_ranges ((u), 0x1160u, 0x11A7u, 0xD7B0u, 0xD7C6u))
+#define isT(u) (hb_in_ranges ((u), 0x11A8u, 0x11FFu, 0xD7CBu, 0xD7FBu))
+
+#define isHangulTone(u) (hb_in_range ((u), 0x302Eu, 0x302Fu))
+
+/* buffer var allocations */
+#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
+
+static bool
+is_zero_width_char (hb_font_t *font,
+ hb_codepoint_t unicode)
+{
+ hb_codepoint_t glyph;
+ return hb_font_get_glyph (font, unicode, 0, &glyph) && hb_font_get_glyph_h_advance (font, glyph) == 0;
+}
+
+static void
+preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font)
+{
+ HB_BUFFER_ALLOCATE_VAR (buffer, hangul_shaping_feature);
+
+ /* Hangul syllables come in two shapes: LV, and LVT. Of those:
+ *
+ * - LV can be precomposed, or decomposed. Lets call those
+ * <LV> and <L,V>,
+ * - LVT can be fully precomposed, partically precomposed, or
+ * fully decomposed. Ie. <LVT>, <LV,T>, or <L,V,T>.
+ *
+ * The composition / decomposition is mechanical. However, not
+ * all <L,V> sequences compose, and not all <LV,T> sequences
+ * compose.
+ *
+ * Here are the specifics:
+ *
+ * - <L>: U+1100..115F, U+A960..A97F
+ * - <V>: U+1160..11A7, U+D7B0..D7C7
+ * - <T>: U+11A8..11FF, U+D7CB..D7FB
+ *
+ * - Only the <L,V> sequences for the 11xx ranges combine.
+ * - Only <LV,T> sequences for T in U+11A8..11C3 combine.
+ *
+ * Here is what we want to accomplish in this shaper:
+ *
+ * - If the whole syllable can be precomposed, do that,
+ * - Otherwise, fully decompose and apply ljmo/vjmo/tjmo features.
+ * - If a valid syllable is followed by a Hangul tone mark, reorder the tone
+ * mark to precede the whole syllable - unless it is a zero-width glyph, in
+ * which case we leave it untouched, assuming it's designed to overstrike.
+ *
+ * That is, of the different possible syllables:
+ *
+ * <L>
+ * <L,V>
+ * <L,V,T>
+ * <LV>
+ * <LVT>
+ * <LV, T>
+ *
+ * - <L> needs no work.
+ *
+ * - <LV> and <LVT> can stay the way they are if the font supports them, otherwise we
+ * should fully decompose them if font supports.
+ *
+ * - <L,V> and <L,V,T> we should compose if the whole thing can be composed.
+ *
+ * - <LV,T> we should compose if the whole thing can be composed, otherwise we should
+ * decompose.
+ */
+
+ buffer->clear_output ();
+ unsigned int start = 0, end = 0; /* Extent of most recently seen syllable;
+ * valid only if start < end
+ */
+ unsigned int count = buffer->len;
+
+ for (buffer->idx = 0; buffer->idx < count;)
+ {
+ hb_codepoint_t u = buffer->cur().codepoint;
+
+ if (isHangulTone (u))
+ {
+ /*
+ * We could cache the width of the tone marks and the existence of dotted-circle,
+ * but the use of the Hangul tone mark characters seems to be rare enough that
+ * I didn't bother for now.
+ */
+ if (start < end && end == buffer->out_len)
+ {
+ /* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
+ buffer->next_glyph ();
+ if (!is_zero_width_char (font, u))
+ {
+ hb_glyph_info_t *info = buffer->out_info;
+ hb_glyph_info_t tone = info[end];
+ memmove (&info[start + 1], &info[start], (end - start) * sizeof (hb_glyph_info_t));
+ info[start] = tone;
+ }
+ /* Merge clusters across the (possibly reordered) syllable+tone.
+ * We want to merge even in the zero-width tone mark case here,
+ * so that clustering behavior isn't dependent on how the tone mark
+ * is handled by the font.
+ */
+ buffer->merge_out_clusters (start, end + 1);
+ }
+ else
+ {
+ /* No valid syllable as base for tone mark; try to insert dotted circle. */
+ if (font->has_glyph (0x25CCu))
+ {
+ hb_codepoint_t chars[2];
+ if (!is_zero_width_char (font, u)) {
+ chars[0] = u;
+ chars[1] = 0x25CCu;
+ } else {
+ chars[0] = 0x25CCu;
+ chars[1] = u;
+ }
+ buffer->replace_glyphs (1, 2, chars);
+ }
+ else
+ {
+ /* No dotted circle available in the font; just leave tone mark untouched. */
+ buffer->next_glyph ();
+ }
+ }
+ start = end = buffer->out_len;
+ continue;
+ }
+
+ start = buffer->out_len; /* Remember current position as a potential syllable start;
+ * will only be used if we set end to a later position.
+ */
+
+ if (isL (u) && buffer->idx + 1 < count)
+ {
+ hb_codepoint_t l = u;
+ hb_codepoint_t v = buffer->cur(+1).codepoint;
+ if (isV (v))
+ {
+ /* Have <L,V> or <L,V,T>. */
+ hb_codepoint_t t = 0;
+ unsigned int tindex = 0;
+ if (buffer->idx + 2 < count)
+ {
+ t = buffer->cur(+2).codepoint;
+ if (isT (t))
+ tindex = t - TBase; /* Only used if isCombiningT (t); otherwise invalid. */
+ else
+ t = 0; /* The next character was not a trailing jamo. */
+ }
+
+ /* We've got a syllable <L,V,T?>; see if it can potentially be composed. */
+ if (isCombiningL (l) && isCombiningV (v) && (t == 0 || isCombiningT (t)))
+ {
+ /* Try to compose; if this succeeds, end is set to start+1. */
+ hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
+ if (font->has_glyph (s))
+ {
+ buffer->replace_glyphs (t ? 3 : 2, 1, &s);
+ if (unlikely (buffer->in_error))
+ return;
+ end = start + 1;
+ continue;
+ }
+ }
+
+ /* We didn't compose, either because it's an Old Hangul syllable without a
+ * precomposed character in Unicode, or because the font didn't support the
+ * necessary precomposed glyph.
+ * Set jamo features on the individual glyphs, and advance past them.
+ */
+ buffer->cur().hangul_shaping_feature() = LJMO;
+ buffer->next_glyph ();
+ buffer->cur().hangul_shaping_feature() = VJMO;
+ buffer->next_glyph ();
+ if (t)
+ {
+ buffer->cur().hangul_shaping_feature() = TJMO;
+ buffer->next_glyph ();
+ end = start + 3;
+ }
+ else
+ end = start + 2;
+ buffer->merge_out_clusters (start, end);
+ continue;
+ }
+ }
+
+ else if (isCombinedS (u))
+ {
+ /* Have <LV>, <LVT>, or <LV,T> */
+ hb_codepoint_t s = u;
+ bool has_glyph = font->has_glyph (s);
+ unsigned int lindex = (s - SBase) / NCount;
+ unsigned int nindex = (s - SBase) % NCount;
+ unsigned int vindex = nindex / TCount;
+ unsigned int tindex = nindex % TCount;
+
+ if (!tindex &&
+ buffer->idx + 1 < count &&
+ isCombiningT (buffer->cur(+1).codepoint))
+ {
+ /* <LV,T>, try to combine. */
+ unsigned int new_tindex = buffer->cur(+1).codepoint - TBase;
+ hb_codepoint_t new_s = s + new_tindex;
+ if (font->has_glyph (new_s))
+ {
+ buffer->replace_glyphs (2, 1, &new_s);
+ if (unlikely (buffer->in_error))
+ return;
+ end = start + 1;
+ continue;
+ }
+ }
+
+ /* Otherwise, decompose if font doesn't support <LV> or <LVT>,
+ * or if having non-combining <LV,T>. Note that we already handled
+ * combining <LV,T> above. */
+ if (!has_glyph ||
+ (!tindex &&
+ buffer->idx + 1 < count &&
+ isT (buffer->cur(+1).codepoint)))
+ {
+ hb_codepoint_t decomposed[3] = {LBase + lindex,
+ VBase + vindex,
+ TBase + tindex};
+ if (font->has_glyph (decomposed[0]) &&
+ font->has_glyph (decomposed[1]) &&
+ (!tindex || font->has_glyph (decomposed[2])))
+ {
+ unsigned int s_len = tindex ? 3 : 2;
+ buffer->replace_glyphs (1, s_len, decomposed);
+ if (unlikely (buffer->in_error))
+ return;
+
+ /* We decomposed S: apply jamo features to the individual glyphs
+ * that are now in buffer->out_info.
+ */
+ hb_glyph_info_t *info = buffer->out_info;
+
+ /* If we decomposed an LV because of a non-combining T following,
+ * we want to include this T in the syllable.
+ */
+ if (has_glyph && !tindex)
+ {
+ buffer->next_glyph ();
+ s_len++;
+ }
+ end = start + s_len;
+
+ unsigned int i = start;
+ info[i++].hangul_shaping_feature() = LJMO;
+ info[i++].hangul_shaping_feature() = VJMO;
+ if (i < end)
+ info[i++].hangul_shaping_feature() = TJMO;
+ buffer->merge_out_clusters (start, end);
+ continue;
+ }
+ }
+
+ if (has_glyph)
+ {
+ /* We didn't decompose the S, so just advance past it. */
+ end = start + 1;
+ buffer->next_glyph ();
+ continue;
+ }
+ }
+
+ /* Didn't find a recognizable syllable, so we leave end <= start;
+ * this will prevent tone-mark reordering happening.
+ */
+ buffer->next_glyph ();
+ }
+ buffer->swap_buffers ();
+}
+
+static void
+setup_masks_hangul (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font HB_UNUSED)
+{
+ const hangul_shape_plan_t *hangul_plan = (const hangul_shape_plan_t *) plan->data;
+
+ if (likely (hangul_plan))
+ {
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++, info++)
+ info->mask |= hangul_plan->mask_array[info->hangul_shaping_feature()];
+ }
+
+ HB_BUFFER_DEALLOCATE_VAR (buffer, hangul_shaping_feature);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
+{
+ "hangul",
+ collect_features_hangul,
+ override_features_hangul,
+ data_create_hangul, /* data_create */
+ data_destroy_hangul, /* data_destroy */
+ preprocess_text_hangul,
+ HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
+ NULL, /* decompose */
+ NULL, /* compose */
+ setup_masks_hangul, /* setup_masks */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+ false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-hebrew.cc b/src/hb-ot-shape-complex-hebrew.cc
new file mode 100644
index 0000000..c7b7a5e
--- /dev/null
+++ b/src/hb-ot-shape-complex-hebrew.cc
@@ -0,0 +1,172 @@
+/*
+ * Copyright © 2010,2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+static bool
+compose_hebrew (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab)
+{
+ /* Hebrew presentation-form shaping.
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=728866
+ * Hebrew presentation forms with dagesh, for characters U+05D0..05EA;
+ * Note that some letters do not have a dagesh presForm encoded.
+ */
+ static const hb_codepoint_t sDageshForms[0x05EAu - 0x05D0u + 1] = {
+ 0xFB30u, /* ALEF */
+ 0xFB31u, /* BET */
+ 0xFB32u, /* GIMEL */
+ 0xFB33u, /* DALET */
+ 0xFB34u, /* HE */
+ 0xFB35u, /* VAV */
+ 0xFB36u, /* ZAYIN */
+ 0x0000u, /* HET */
+ 0xFB38u, /* TET */
+ 0xFB39u, /* YOD */
+ 0xFB3Au, /* FINAL KAF */
+ 0xFB3Bu, /* KAF */
+ 0xFB3Cu, /* LAMED */
+ 0x0000u, /* FINAL MEM */
+ 0xFB3Eu, /* MEM */
+ 0x0000u, /* FINAL NUN */
+ 0xFB40u, /* NUN */
+ 0xFB41u, /* SAMEKH */
+ 0x0000u, /* AYIN */
+ 0xFB43u, /* FINAL PE */
+ 0xFB44u, /* PE */
+ 0x0000u, /* FINAL TSADI */
+ 0xFB46u, /* TSADI */
+ 0xFB47u, /* QOF */
+ 0xFB48u, /* RESH */
+ 0xFB49u, /* SHIN */
+ 0xFB4Au /* TAV */
+ };
+
+ bool found = c->unicode->compose (a, b, ab);
+
+ if (!found && !c->plan->has_mark)
+ {
+ /* Special-case Hebrew presentation forms that are excluded from
+ * standard normalization, but wanted for old fonts. */
+ switch (b) {
+ case 0x05B4u: /* HIRIQ */
+ if (a == 0x05D9u) { /* YOD */
+ *ab = 0xFB1Du;
+ found = true;
+ }
+ break;
+ case 0x05B7u: /* patah */
+ if (a == 0x05F2u) { /* YIDDISH YOD YOD */
+ *ab = 0xFB1Fu;
+ found = true;
+ } else if (a == 0x05D0u) { /* ALEF */
+ *ab = 0xFB2Eu;
+ found = true;
+ }
+ break;
+ case 0x05B8u: /* QAMATS */
+ if (a == 0x05D0u) { /* ALEF */
+ *ab = 0xFB2Fu;
+ found = true;
+ }
+ break;
+ case 0x05B9u: /* HOLAM */
+ if (a == 0x05D5u) { /* VAV */
+ *ab = 0xFB4Bu;
+ found = true;
+ }
+ break;
+ case 0x05BCu: /* DAGESH */
+ if (a >= 0x05D0u && a <= 0x05EAu) {
+ *ab = sDageshForms[a - 0x05D0u];
+ found = (*ab != 0);
+ } else if (a == 0xFB2Au) { /* SHIN WITH SHIN DOT */
+ *ab = 0xFB2Cu;
+ found = true;
+ } else if (a == 0xFB2Bu) { /* SHIN WITH SIN DOT */
+ *ab = 0xFB2Du;
+ found = true;
+ }
+ break;
+ case 0x05BFu: /* RAFE */
+ switch (a) {
+ case 0x05D1u: /* BET */
+ *ab = 0xFB4Cu;
+ found = true;
+ break;
+ case 0x05DBu: /* KAF */
+ *ab = 0xFB4Du;
+ found = true;
+ break;
+ case 0x05E4u: /* PE */
+ *ab = 0xFB4Eu;
+ found = true;
+ break;
+ }
+ break;
+ case 0x05C1u: /* SHIN DOT */
+ if (a == 0x05E9u) { /* SHIN */
+ *ab = 0xFB2Au;
+ found = true;
+ } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
+ *ab = 0xFB2Cu;
+ found = true;
+ }
+ break;
+ case 0x05C2u: /* SIN DOT */
+ if (a == 0x05E9u) { /* SHIN */
+ *ab = 0xFB2Bu;
+ found = true;
+ } else if (a == 0xFB49u) { /* SHIN WITH DAGESH */
+ *ab = 0xFB2Du;
+ found = true;
+ }
+ break;
+ }
+ }
+
+ return found;
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
+{
+ "hebrew",
+ NULL, /* collect_features */
+ NULL, /* override_features */
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ compose_hebrew,
+ NULL, /* setup_masks */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+ true, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-indic-machine.hh b/src/hb-ot-shape-complex-indic-machine.hh
deleted file mode 100644
index db1396b..0000000
--- a/src/hb-ot-shape-complex-indic-machine.hh
+++ /dev/null
@@ -1,293 +0,0 @@
-
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
-/*
- * Copyright © 2011,2012 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH
-
-#include "hb-private.hh"
-
-HB_BEGIN_DECLS
-
-
-#line 38 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
-static const unsigned char _indic_syllable_machine_trans_keys[] = {
- 5u, 5u, 1u, 2u, 1u, 2u, 5u, 5u, 1u, 5u, 1u, 2u, 5u, 5u, 1u, 13u,
- 4u, 11u, 4u, 11u, 5u, 11u, 1u, 10u, 1u, 10u, 10u, 10u, 10u, 10u, 4u, 10u,
- 5u, 10u, 8u, 10u, 5u, 10u, 6u, 10u, 9u, 10u, 4u, 11u, 1u, 13u, 4u, 10u,
- 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 8u, 10u, 10u, 10u, 10u, 10u, 4u, 10u,
- 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 8u, 10u, 10u, 10u, 10u, 10u, 0
-};
-
-static const char _indic_syllable_machine_key_spans[] = {
- 1, 2, 2, 1, 5, 2, 1, 13,
- 8, 8, 7, 10, 10, 1, 1, 7,
- 6, 3, 6, 5, 2, 8, 13, 7,
- 7, 6, 7, 6, 3, 1, 1, 7,
- 7, 6, 7, 6, 3, 1, 1
-};
-
-static const unsigned char _indic_syllable_machine_index_offsets[] = {
- 0, 2, 5, 8, 10, 16, 19, 21,
- 35, 44, 53, 61, 72, 83, 85, 87,
- 95, 102, 106, 113, 119, 122, 131, 145,
- 153, 161, 168, 176, 183, 187, 189, 191,
- 199, 207, 214, 222, 229, 233, 235
-};
-
-static const char _indic_syllable_machine_indicies[] = {
- 1, 0, 2, 2, 0, 4, 4, 3,
- 5, 3, 4, 4, 3, 3, 5, 3,
- 7, 7, 6, 8, 6, 2, 10, 11,
- 9, 9, 9, 9, 9, 9, 9, 9,
- 12, 12, 9, 14, 15, 16, 16, 17,
- 18, 19, 20, 13, 21, 15, 16, 16,
- 17, 18, 19, 20, 13, 15, 16, 16,
- 17, 18, 19, 20, 13, 2, 2, 13,
- 13, 13, 22, 22, 13, 18, 19, 13,
- 2, 2, 13, 13, 13, 13, 13, 13,
- 18, 19, 13, 19, 13, 23, 13, 24,
- 25, 13, 13, 17, 18, 19, 13, 25,
- 13, 13, 17, 18, 19, 13, 17, 18,
- 19, 13, 26, 13, 13, 17, 18, 19,
- 13, 27, 27, 13, 18, 19, 13, 18,
- 19, 13, 14, 28, 16, 16, 17, 18,
- 19, 20, 13, 2, 2, 11, 13, 13,
- 22, 22, 13, 18, 19, 13, 12, 12,
- 13, 30, 5, 31, 32, 33, 34, 35,
- 29, 4, 5, 31, 32, 33, 34, 35,
- 29, 5, 31, 32, 33, 34, 35, 29,
- 36, 37, 29, 29, 33, 34, 35, 29,
- 37, 29, 29, 33, 34, 35, 29, 33,
- 34, 35, 29, 35, 29, 38, 29, 40,
- 8, 41, 41, 42, 43, 44, 39, 7,
- 8, 41, 41, 42, 43, 44, 39, 8,
- 41, 41, 42, 43, 44, 39, 45, 46,
- 39, 39, 42, 43, 44, 39, 46, 39,
- 39, 42, 43, 44, 39, 42, 43, 44,
- 39, 44, 39, 47, 39, 0
-};
-
-static const char _indic_syllable_machine_trans_targs[] = {
- 7, 1, 8, 7, 25, 2, 7, 33,
- 5, 7, 21, 23, 31, 7, 9, 11,
- 0, 15, 13, 14, 18, 10, 12, 7,
- 16, 17, 19, 20, 22, 7, 24, 3,
- 4, 26, 29, 30, 27, 28, 7, 7,
- 32, 6, 34, 37, 38, 35, 36, 7
-};
-
-static const char _indic_syllable_machine_trans_actions[] = {
- 1, 0, 2, 3, 2, 0, 4, 2,
- 0, 7, 2, 2, 2, 8, 2, 0,
- 0, 0, 0, 0, 0, 2, 0, 9,
- 0, 0, 0, 0, 0, 10, 2, 0,
- 0, 0, 0, 0, 0, 0, 11, 12,
- 2, 0, 0, 0, 0, 0, 0, 13
-};
-
-static const char _indic_syllable_machine_to_state_actions[] = {
- 0, 0, 0, 0, 0, 0, 0, 5,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0
-};
-
-static const char _indic_syllable_machine_from_state_actions[] = {
- 0, 0, 0, 0, 0, 0, 0, 6,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0
-};
-
-static const unsigned char _indic_syllable_machine_eof_trans[] = {
- 1, 1, 4, 4, 4, 7, 7, 0,
- 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 30,
- 30, 30, 30, 30, 30, 30, 30, 40,
- 40, 40, 40, 40, 40, 40, 40
-};
-
-static const int indic_syllable_machine_start = 7;
-static const int indic_syllable_machine_first_final = 7;
-static const int indic_syllable_machine_error = -1;
-
-static const int indic_syllable_machine_en_main = 7;
-
-
-#line 38 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-
-
-#line 79 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-
-#define process_syllable(func) \
- HB_STMT_START { \
- /* fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); */ \
- for (unsigned int i = last; i < p+1; i++) \
- info[i].syllable() = syllable_serial; \
- PASTE (initial_reordering_, func) (map, buffer, mask_array, last, p+1); \
- last = p+1; \
- syllable_serial++; \
- if (unlikely (!syllable_serial)) syllable_serial++; \
- } HB_STMT_END
-
-static void
-find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array)
-{
- unsigned int p, pe, eof, ts, te, act;
- int cs;
- hb_glyph_info_t *info = buffer->info;
-
-#line 170 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
- {
- cs = indic_syllable_machine_start;
- ts = 0;
- te = 0;
- act = 0;
- }
-
-#line 101 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-
- p = 0;
- pe = eof = buffer->len;
-
- unsigned int last = 0;
- uint8_t syllable_serial = 1;
-
-#line 187 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
- {
- int _slen;
- int _trans;
- const unsigned char *_keys;
- const char *_inds;
- if ( p == pe )
- goto _test_eof;
-_resume:
- switch ( _indic_syllable_machine_from_state_actions[cs] ) {
- case 6:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {ts = p;}
- break;
-#line 201 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
- }
-
- _keys = _indic_syllable_machine_trans_keys + (cs<<1);
- _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs];
-
- _slen = _indic_syllable_machine_key_spans[cs];
- _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) &&
- ( info[p].indic_category()) <= _keys[1] ?
- ( info[p].indic_category()) - _keys[0] : _slen ];
-
-_eof_trans:
- cs = _indic_syllable_machine_trans_targs[_trans];
-
- if ( _indic_syllable_machine_trans_actions[_trans] == 0 )
- goto _again;
-
- switch ( _indic_syllable_machine_trans_actions[_trans] ) {
- case 2:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;}
- break;
- case 9:
-#line 72 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;{ process_syllable (consonant_syllable); }}
- break;
- case 11:
-#line 73 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;{ process_syllable (vowel_syllable); }}
- break;
- case 13:
-#line 74 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;{ process_syllable (standalone_cluster); }}
- break;
- case 7:
-#line 75 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p+1;{ process_syllable (non_indic); }}
- break;
- case 8:
-#line 72 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ process_syllable (consonant_syllable); }}
- break;
- case 10:
-#line 73 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ process_syllable (vowel_syllable); }}
- break;
- case 12:
-#line 74 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {te = p;p--;{ process_syllable (standalone_cluster); }}
- break;
- case 1:
-#line 72 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ process_syllable (consonant_syllable); }}
- break;
- case 3:
-#line 73 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ process_syllable (vowel_syllable); }}
- break;
- case 4:
-#line 74 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {{p = ((te))-1;}{ process_syllable (standalone_cluster); }}
- break;
-#line 263 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
- }
-
-_again:
- switch ( _indic_syllable_machine_to_state_actions[cs] ) {
- case 5:
-#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl"
- {ts = 0;}
- break;
-#line 272 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp"
- }
-
- if ( ++p != pe )
- goto _resume;
- _test_eof: {}
- if ( p == eof )
- {
- if ( _indic_syllable_machine_eof_trans[cs] > 0 ) {
- _trans = _indic_syllable_machine_eof_trans[cs] - 1;
- goto _eof_trans;
- }
- }
-
- }
-
-#line 110 "../../src/hb-ot-shape-complex-indic-machine.rl"
-
-}
-
-HB_END_DECLS
-
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-indic-machine.rl b/src/hb-ot-shape-complex-indic-machine.rl
index 93ca29a..694b235 100644
--- a/src/hb-ot-shape-complex-indic-machine.rl
+++ b/src/hb-ot-shape-complex-indic-machine.rl
@@ -29,8 +29,6 @@
#include "hb-private.hh"
-HB_BEGIN_DECLS
-
%%{
machine indic_syllable_machine;
alphtype unsigned char;
@@ -42,57 +40,76 @@ HB_BEGIN_DECLS
# Same order as enum indic_category_t. Not sure how to avoid duplication.
X = 0;
C = 1;
-Ra = 2;
-V = 3;
-N = 4;
-H = 5;
-ZWNJ = 6;
-ZWJ = 7;
-M = 8;
-SM = 9;
-VD = 10;
-A = 11;
-NBSP = 12;
-DOTTEDCIRCLE = 13;
-
-c = C | Ra;
-n = N N?;
-z = ZWJ|ZWNJ;
-matra_group = M N? H?;
-syllable_tail = SM? (VD VD?)?;
-place_holder = NBSP | DOTTEDCIRCLE;
-
-
-consonant_syllable = (c.n? (H.z?|z.H))* c.n? A? (H.z? | matra_group*)? syllable_tail;
-vowel_syllable = (Ra H)? V n? (z?.H.c | ZWJ.c)* matra_group* syllable_tail;
-standalone_cluster = (Ra H)? place_holder n? (z? H c)* matra_group* syllable_tail;
+V = 2;
+N = 3;
+H = 4;
+ZWNJ = 5;
+ZWJ = 6;
+M = 7;
+SM = 8;
+VD = 9;
+A = 10;
+PLACEHOLDER = 11;
+DOTTEDCIRCLE = 12;
+RS = 13;
+Coeng = 14;
+Repha = 15;
+Ra = 16;
+CM = 17;
+Symbol= 18;
+CM2 = 31;
+
+c = (C | Ra); # is_consonant
+n = ((ZWNJ?.RS)? (N.N?)?); # is_consonant_modifier
+z = ZWJ|ZWNJ; # is_joiner
+h = H | Coeng; # is_halant_or_coeng
+reph = (Ra H | Repha); # possible reph
+
+cn = c.ZWJ?.n?;
+forced_rakar = ZWJ H ZWJ Ra;
+symbol = Symbol.N?;
+matra_group = z{0,3}.M.N?.(H | forced_rakar)?;
+syllable_tail = (z?.SM.SM?.ZWNJ?)? A{0,3}? VD{0,2};
+place_holder = PLACEHOLDER | DOTTEDCIRCLE;
+halant_group = (z?.h.(ZWJ.N?)?);
+final_halant_group = halant_group | h.ZWNJ;
+medial_group = CM?.CM2?;
+halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4}) (Coeng (cn|V))?;
+
+
+consonant_syllable = Repha? (cn.halant_group){0,4} cn medial_group halant_or_matra_group syllable_tail;
+vowel_syllable = reph? V.n? (ZWJ | (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail);
+standalone_cluster = (Repha? PLACEHOLDER | reph? DOTTEDCIRCLE).n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
+symbol_cluster = symbol syllable_tail;
+broken_cluster = reph? n? (halant_group.cn){0,4} medial_group halant_or_matra_group syllable_tail;
other = any;
main := |*
- consonant_syllable => { process_syllable (consonant_syllable); };
- vowel_syllable => { process_syllable (vowel_syllable); };
- standalone_cluster => { process_syllable (standalone_cluster); };
- other => { process_syllable (non_indic); };
+ consonant_syllable => { found_syllable (consonant_syllable); };
+ vowel_syllable => { found_syllable (vowel_syllable); };
+ standalone_cluster => { found_syllable (standalone_cluster); };
+ symbol_cluster => { found_syllable (symbol_cluster); };
+ broken_cluster => { found_syllable (broken_cluster); };
+ other => { found_syllable (non_indic_cluster); };
*|;
}%%
-#define process_syllable(func) \
+#define found_syllable(syllable_type) \
HB_STMT_START { \
- /* fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); */ \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
for (unsigned int i = last; i < p+1; i++) \
- info[i].syllable() = syllable_serial; \
- PASTE (initial_reordering_, func) (map, buffer, mask_array, last, p+1); \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
last = p+1; \
syllable_serial++; \
- if (unlikely (!syllable_serial)) syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
static void
-find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array)
+find_syllables (hb_buffer_t *buffer)
{
- unsigned int p, pe, eof, ts, te, act;
+ unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
int cs;
hb_glyph_info_t *info = buffer->info;
%%{
@@ -104,12 +121,10 @@ find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_arr
pe = eof = buffer->len;
unsigned int last = 0;
- uint8_t syllable_serial = 1;
+ unsigned int syllable_serial = 1;
%%{
write exec;
}%%
}
-HB_END_DECLS
-
#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-indic-private.hh b/src/hb-ot-shape-complex-indic-private.hh
index 64af0da..d8dfc65 100644
--- a/src/hb-ot-shape-complex-indic-private.hh
+++ b/src/hb-ot-shape-complex-indic-private.hh
@@ -31,13 +31,10 @@
#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-private.hh" /* XXX Remove */
-/* buffer var allocations */
-#define indic_category() complex_var_persistent_u8_0() /* indic_category_t */
-#define indic_position() complex_var_persistent_u8_1() /* indic_matra_category_t */
-
-#define INDIC_TABLE_ELEMENT_TYPE uint8_t
+#define INDIC_TABLE_ELEMENT_TYPE uint16_t
/* Cateories used in the OpenType spec:
* https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx
@@ -46,225 +43,140 @@
* Not sure how to avoid duplication. */
enum indic_category_t {
OT_X = 0,
- OT_C,
- OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */
- OT_V,
- OT_N,
- OT_H,
- OT_ZWNJ,
- OT_ZWJ,
- OT_M,
- OT_SM,
- OT_VD,
- OT_A,
- OT_NBSP,
- OT_DOTTEDCIRCLE /* Not in the spec, but special in Uniscribe. /Very very/ special! */
+ OT_C = 1,
+ OT_V = 2,
+ OT_N = 3,
+ OT_H = 4,
+ OT_ZWNJ = 5,
+ OT_ZWJ = 6,
+ OT_M = 7,
+ OT_SM = 8,
+ OT_VD = 9,
+ OT_A = 10,
+ OT_PLACEHOLDER = 11,
+ OT_DOTTEDCIRCLE = 12,
+ OT_RS = 13, /* Register Shifter, used in Khmer OT spec. */
+ OT_Coeng = 14, /* Khmer-style Virama. */
+ OT_Repha = 15, /* Atomically-encoded logical or visual repha. */
+ OT_Ra = 16,
+ OT_CM = 17, /* Consonant-Medial. */
+ OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */
+ OT_CM2 = 31 /* Consonant-Medial, second slot. */
};
+#define MEDIAL_FLAGS (FLAG (OT_CM) | FLAG (OT_CM2))
+
+/* Note:
+ *
+ * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
+ * cannot happen in a consonant syllable. The plus side however is, we can call the
+ * consonant syllable logic from the vowel syllable function and get it all right! */
+#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE))
+#define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))
+#define HALANT_OR_COENG_FLAGS (FLAG (OT_H) | FLAG (OT_Coeng))
+
+
/* Visual positions in a syllable from left to right. */
enum indic_position_t {
+ POS_START,
+
POS_RA_TO_BECOME_REPH,
POS_PRE_M,
POS_PRE_C,
+
POS_BASE_C,
+ POS_AFTER_MAIN,
+
POS_ABOVE_C,
+
+ POS_BEFORE_SUB,
POS_BELOW_C,
- POS_ABOVE_M,
- POS_BELOW_M,
+ POS_AFTER_SUB,
+
+ POS_BEFORE_POST,
POS_POST_C,
- POS_POST_M,
- POS_SMVD
+ POS_AFTER_POST,
+
+ POS_FINAL_C,
+ POS_SMVD,
+
+ POS_END
};
/* Categories used in IndicSyllabicCategory.txt from UCD. */
enum indic_syllabic_category_t {
- INDIC_SYLLABIC_CATEGORY_OTHER = OT_X,
-
- INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_X,
- INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
- INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_C,
- INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_C,
- INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
- INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
- INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_X,
- INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
- INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_X,
- INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
- INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM,
- INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V,
- INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M,
- INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V
+ INDIC_SYLLABIC_CATEGORY_OTHER = OT_X,
+
+ INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_Symbol,
+ INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
+ INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
+ INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
+ INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
+ INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_H, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
+ INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
+ INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
+ INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
+ INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
+ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_H, /* TODO */
+ INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
+ INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
+ INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
+ INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
+ INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM,
+ INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V,
+ INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M,
+ INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V
};
/* Categories used in IndicSMatraCategory.txt from UCD */
enum indic_matra_category_t {
- INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_BASE_C,
-
- INDIC_MATRA_CATEGORY_LEFT = POS_PRE_M,
- INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_M,
- INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_M,
- INDIC_MATRA_CATEGORY_RIGHT = POS_POST_M,
-
- /* We don't really care much about these since we decompose them
- * in the generic pre-shaping layer. They will only be used if
- * the font does not cover the decomposition. In which case, we
- * define these as aliases to the place we want the split-matra
- * glyph to show up. Quite arbitrary.
- *
- * TODO: There are some split matras without Unicode decompositions.
- * We have to figure out what to do with them.
- */
- INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = POS_POST_M,
- INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = POS_PRE_M,
- INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = POS_BELOW_M,
- INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = POS_POST_M,
- INDIC_MATRA_CATEGORY_TOP_AND_LEFT = POS_PRE_M,
- INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = POS_PRE_M,
- INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = POS_POST_M,
-
- INDIC_MATRA_CATEGORY_INVISIBLE = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
- INDIC_MATRA_CATEGORY_OVERSTRUCK = INDIC_MATRA_CATEGORY_NOT_APPLICABLE,
- INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = INDIC_MATRA_CATEGORY_NOT_APPLICABLE
+ INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_END,
+
+ INDIC_MATRA_CATEGORY_LEFT = POS_PRE_C,
+ INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_C,
+ INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_C,
+ INDIC_MATRA_CATEGORY_RIGHT = POS_POST_C,
+
+ /* These should resolve to the position of the last part of the split sequence. */
+ INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
+ INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
+ INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM,
+ INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
+ INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_TOP,
+ INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
+ INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
+
+ INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN,
+ INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
};
/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation
* because gcc fails to optimize the latter and fills the table in at runtime. */
#define INDIC_COMBINE_CATEGORIES(S,M) \
- (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \
- ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \
- ((M << 4) | S))
-
-
-#include "hb-ot-shape-complex-indic-table.hh"
-
-/* XXX
- * This is a hack for now. We should:
- * 1. Move this data into the main Indic table,
- * and/or
- * 2. Probe font lookups to determine consonant positions.
- */
-static const struct consonant_position_t {
- hb_codepoint_t u;
- indic_position_t position;
-} consonant_positions[] = {
- {0x0930, POS_BELOW_C},
- {0x09AC, POS_BELOW_C},
- {0x09AF, POS_POST_C},
- {0x09B0, POS_BELOW_C},
- {0x09F0, POS_BELOW_C},
- {0x0A2F, POS_POST_C},
- {0x0A30, POS_BELOW_C},
- {0x0A35, POS_BELOW_C},
- {0x0A39, POS_BELOW_C},
- {0x0AB0, POS_BELOW_C},
- {0x0B24, POS_BELOW_C},
- {0x0B28, POS_BELOW_C},
- {0x0B2C, POS_BELOW_C},
- {0x0B2D, POS_BELOW_C},
- {0x0B2E, POS_BELOW_C},
- {0x0B2F, POS_POST_C},
- {0x0B30, POS_BELOW_C},
- {0x0B32, POS_BELOW_C},
- {0x0B33, POS_BELOW_C},
- {0x0B5F, POS_POST_C},
- {0x0B71, POS_BELOW_C},
- {0x0C15, POS_BELOW_C},
- {0x0C16, POS_BELOW_C},
- {0x0C17, POS_BELOW_C},
- {0x0C18, POS_BELOW_C},
- {0x0C19, POS_BELOW_C},
- {0x0C1A, POS_BELOW_C},
- {0x0C1B, POS_BELOW_C},
- {0x0C1C, POS_BELOW_C},
- {0x0C1D, POS_BELOW_C},
- {0x0C1E, POS_BELOW_C},
- {0x0C1F, POS_BELOW_C},
- {0x0C20, POS_BELOW_C},
- {0x0C21, POS_BELOW_C},
- {0x0C22, POS_BELOW_C},
- {0x0C23, POS_BELOW_C},
- {0x0C24, POS_BELOW_C},
- {0x0C25, POS_BELOW_C},
- {0x0C26, POS_BELOW_C},
- {0x0C27, POS_BELOW_C},
- {0x0C28, POS_BELOW_C},
- {0x0C2A, POS_BELOW_C},
- {0x0C2B, POS_BELOW_C},
- {0x0C2C, POS_BELOW_C},
- {0x0C2D, POS_BELOW_C},
- {0x0C2E, POS_BELOW_C},
- {0x0C2F, POS_BELOW_C},
- {0x0C30, POS_BELOW_C},
- {0x0C32, POS_BELOW_C},
- {0x0C33, POS_BELOW_C},
- {0x0C35, POS_BELOW_C},
- {0x0C36, POS_BELOW_C},
- {0x0C37, POS_BELOW_C},
- {0x0C38, POS_BELOW_C},
- {0x0C39, POS_BELOW_C},
- {0x0C95, POS_BELOW_C},
- {0x0C96, POS_BELOW_C},
- {0x0C97, POS_BELOW_C},
- {0x0C98, POS_BELOW_C},
- {0x0C99, POS_BELOW_C},
- {0x0C9A, POS_BELOW_C},
- {0x0C9B, POS_BELOW_C},
- {0x0C9C, POS_BELOW_C},
- {0x0C9D, POS_BELOW_C},
- {0x0C9E, POS_BELOW_C},
- {0x0C9F, POS_BELOW_C},
- {0x0CA0, POS_BELOW_C},
- {0x0CA1, POS_BELOW_C},
- {0x0CA2, POS_BELOW_C},
- {0x0CA3, POS_BELOW_C},
- {0x0CA4, POS_BELOW_C},
- {0x0CA5, POS_BELOW_C},
- {0x0CA6, POS_BELOW_C},
- {0x0CA7, POS_BELOW_C},
- {0x0CA8, POS_BELOW_C},
- {0x0CAA, POS_BELOW_C},
- {0x0CAB, POS_BELOW_C},
- {0x0CAC, POS_BELOW_C},
- {0x0CAD, POS_BELOW_C},
- {0x0CAE, POS_BELOW_C},
- {0x0CAF, POS_BELOW_C},
- {0x0CB0, POS_BELOW_C},
- {0x0CB2, POS_BELOW_C},
- {0x0CB3, POS_BELOW_C},
- {0x0CB5, POS_BELOW_C},
- {0x0CB6, POS_BELOW_C},
- {0x0CB7, POS_BELOW_C},
- {0x0CB8, POS_BELOW_C},
- {0x0CB9, POS_BELOW_C},
- {0x0CDE, POS_BELOW_C},
- {0x0D2F, POS_POST_C},
- {0x0D30, POS_POST_C},
- {0x0D32, POS_BELOW_C},
- {0x0D35, POS_POST_C},
-};
-
-/* XXX
- * This is a hack for now. We should move this data into the main Indic table.
- * Or completely remove it and just check in the tables.
- */
-static const hb_codepoint_t ra_chars[] = {
- 0x0930, /* Devanagari */
- 0x09B0, /* Bengali */
- 0x09F0, /* Bengali */
- 0x0A30, /* Gurmukhi */ /* No Reph */
- 0x0AB0, /* Gujarati */
- 0x0B30, /* Oriya */
- 0x0BB0, /* Tamil */ /* No Reph */
- 0x0C30, /* Telugu */ /* No Reph */
- 0x0CB0, /* Kannada */
- 0x0D30, /* Malayalam */ /* No Reph */
-};
-
+ (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || \
+ ( \
+ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
+ S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
+ S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
+ S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
+ S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
+ S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
+ false)) + \
+ ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
+ ((M << 8) | S))
+
+HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
+hb_indic_get_categories (hb_codepoint_t u);
#endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */
diff --git a/src/hb-ot-shape-complex-indic-table.hh b/src/hb-ot-shape-complex-indic-table.cc
index 5b4b344..2e159a1 100644
--- a/src/hb-ot-shape-complex-indic-table.hh
+++ b/src/hb-ot-shape-complex-indic-table.cc
@@ -6,55 +6,63 @@
*
* on files with these headers:
*
- * # IndicSyllabicCategory-6.1.0.txt
- * # Date: 2011-08-31, 23:54:00 GMT [KW]
- * # IndicMatraCategory-6.1.0.txt
- * # Date: 2011-08-31, 23:50:00 GMT [KW]
- * # Blocks-6.1.0.txt
- * # Date: 2011-06-14, 18:26:00 GMT [KW, LI]
+ * # IndicSyllabicCategory-7.0.0.txt
+ * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+ * # IndicMatraCategory-7.0.0.txt
+ * # Date: 2014-06-03, 07:00:00 GMT [KW, LI, AG, RP]
+ * # Blocks-7.0.0.txt
+ * # Date: 2014-04-03, 23:23:00 GMT [RP, KW]
*/
-#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
-#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH
-
-
-#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 11 chars; Avagraha */
-#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 34 chars; Bindu */
-#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 123 chars; Consonant */
-#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 2 chars; Consonant_Dead */
-#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 17 chars; Consonant_Final */
-#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 1 chars; Consonant_Head_Letter */
-#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 12 chars; Consonant_Medial */
-#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 4 chars; Consonant_Placeholder */
-#define ISC_CR INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA /* 5 chars; Consonant_Repha */
-#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 10 chars; Consonant_Subjoined */
+#include "hb-ot-shape-complex-indic-private.hh"
+
+
+#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 13 chars; Avagraha */
+#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 59 chars; Bindu */
+#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */
+#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 30 chars; Cantillation_Mark */
+#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1744 chars; Consonant */
+#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 7 chars; Consonant_Dead */
+#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 61 chars; Consonant_Final */
+#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */
+#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 19 chars; Consonant_Medial */
+#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 11 chars; Consonant_Placeholder */
+#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 1 chars; Consonant_Preceding_Repha */
+#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 61 chars; Consonant_Subjoined */
+#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */
+#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 2 chars; Gemination_Mark */
+#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 7 chars; Invisible_Stacker */
+#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */
#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */
-#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 12 chars; Nukta */
+#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */
+#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 18 chars; Nukta */
+#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 408 chars; Number */
+#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */
#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
-#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 1 chars; Register_Shifter */
-#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 3 chars; Tone_Letter */
-#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 16 chars; Tone_Mark */
-#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 34 chars; Virama */
-#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 25 chars; Visarga */
-#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 5 chars; Vowel */
-#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 165 chars; Vowel_Dependent */
-#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 59 chars; Vowel_Independent */
-
-#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 65 chars; Bottom */
+#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 15 chars; Pure_Killer */
+#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 3 chars; Register_Shifter */
+#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */
+#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 62 chars; Tone_Mark */
+#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 22 chars; Virama */
+#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 29 chars; Visarga */
+#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */
+#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 553 chars; Vowel_Dependent */
+#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 395 chars; Vowel_Independent */
+
+#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 142 chars; Bottom */
#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */
-#define IMC_I INDIC_MATRA_CATEGORY_INVISIBLE /* 6 chars; Invisible */
-#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 30 chars; Left */
-#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 8 chars; Left_And_Right */
+#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 57 chars; Left */
+#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 21 chars; Left_And_Right */
#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */
#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 2 chars; Overstruck */
-#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 75 chars; Right */
-#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 83 chars; Top */
-#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 6 chars; Top_And_Bottom */
+#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 163 chars; Right */
+#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 169 chars; Top */
+#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */
#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */
-#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 4 chars; Top_And_Left */
-#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 2 chars; Top_And_Left_And_Right */
-#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 8 chars; Top_And_Right */
-#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 5 chars; Visual_Order_Left */
+#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */
+#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */
+#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */
+#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 15 chars; Visual_Order_Left */
#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
@@ -62,10 +70,26 @@
static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
-#define indic_offset_0x0900 0
+#define indic_offset_0x0028u 0
+
+
+ /* Basic Latin */
+
+ /* 0028 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x), _(x,x),
+ /* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0038 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0x00d0u 24
+
+ /* Latin-1 Supplement */
- /* Devanagari (0900..097F) */
+ /* 00D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x),
+
+#define indic_offset_0x0900u 32
+
+
+ /* Devanagari */
/* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -77,14 +101,14 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,x), _(A,x), _(M,R), _(M,L),
/* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
/* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R),
- /* 0950 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(M,B),
+ /* 0950 */ _(x,x), _(TM,x), _(TM,x), _(x,x), _(x,x), _(M,T), _(M,B), _(M,B),
/* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0970 */ _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
- /* 0978 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 0978 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* Bengali (0980..09FF) */
+ /* Bengali */
/* 0980 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
@@ -98,12 +122,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x),
/* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 09D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
- /* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 09E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 09F0 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 09F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Gurmukhi (0A00..0A7F) */
+ /* Gurmukhi */
/* 0A00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
@@ -117,12 +141,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x),
/* 0A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x),
- /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0A68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0A70 */ _(Bi,x), _(x,x), _(CP,x), _(CP,x), _(x,x), _(CM,x), _(x,x), _(x,x),
+ /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 0A70 */ _(Bi,x), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,x), _(x,x), _(x,x),
/* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Gujarati (0A80..0AFF) */
+ /* Gujarati */
/* 0A80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x),
@@ -136,12 +160,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x),
/* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0AE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Oriya (0B00..0B7F) */
+ /* Oriya */
/* 0B00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
@@ -155,12 +179,12 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x),
/* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,TR),
/* 0B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
- /* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0B70 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Tamil (0B80..0BFF) */
+ /* Tamil */
/* 0B80 */ _(x,x), _(x,x), _(Bi,x), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x),
@@ -174,33 +198,33 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x),
/* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0BE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0BE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0BF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Telugu (0C00..0C7F) */
+ /* Telugu */
- /* 0C00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+ /* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(A,x), _(M,T), _(M,T),
/* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T),
/* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x),
/* 0C58 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0C68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0C78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Kannada (0C80..0CFF) */
+ /* Kannada */
- /* 0C80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0C80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -212,14 +236,14 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
/* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x),
- /* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0CF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Malayalam (0D00..0D7F) */
+ /* Malayalam */
- /* 0D00 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 0D00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -228,15 +252,15 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D38 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(A,x), _(M,R), _(M,R),
/* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L),
- /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(CR,x), _(x,x),
+ /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,x), _(x,x),
/* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0D68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0D78 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x),
- /* Sinhala (0D80..0DFF) */
+ /* Sinhala */
/* 0D80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -249,86 +273,15 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 0DC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
/* 0DC8 */ _(x,x), _(x,x), _(V,T), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0DD0 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(x,x), _(M,B), _(x,x),
- /* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR), _(M,LR), _(M,LR), _(M,R),
- /* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0DE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR),_(M,TLR), _(M,LR), _(M,R),
+ /* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0DF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Thai (0E00..0E7F) */
-
- /* 0E00 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0E08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0E10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0E18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0E20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0E28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
- /* 0E30 */ _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T), _(M,T),
- /* 0E38 */ _(M,B), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0E40 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL), _(M,R), _(x,x), _(M,T),
- /* 0E48 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(Bi,x), _(V,T), _(x,x),
- /* 0E50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0E58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0E60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0E68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0E70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0E78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Lao (0E80..0EFF) */
-
- /* 0E80 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(C,x),
- /* 0E88 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(C,x), _(x,x), _(x,x),
- /* 0E90 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0E98 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0EA0 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x),
- /* 0EA8 */ _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
- /* 0EB0 */ _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T), _(M,T),
- /* 0EB8 */ _(M,B), _(M,B), _(x,x), _(M,T), _(CM,x), _(CM,x), _(x,x), _(x,x),
- /* 0EC0 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL), _(x,x), _(x,x), _(x,x),
- /* 0EC8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(Bi,x), _(x,x), _(x,x),
- /* 0ED0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0ED8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x),
- /* 0EE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0EE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0EF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0EF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Tibetan (0F00..0FFF) */
-
- /* 0F00 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F10 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F18 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F20 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F28 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F30 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0F40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0F48 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0F50 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0F58 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0F60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 0F68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
- /* 0F70 */ _(x,x), _(M,B), _(M,T), _(M,TB), _(M,B), _(M,B), _(M,TB), _(M,TB),
- /* 0F78 */ _(M,TB), _(M,TB), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(Vs,x),
- /* 0F80 */ _(M,T), _(M,TB), _(Bi,x), _(Bi,x), _(V,B), _(A,x), _(x,x), _(x,x),
- /* 0F88 */_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x), _(CS,x), _(CS,x), _(CS,x),
- /* 0F90 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
- /* 0F98 */ _(x,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
- /* 0FA0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
- /* 0FA8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
- /* 0FB0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x),
- /* 0FB8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x),
- /* 0FC0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0FC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0FD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0FD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0FE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0FE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0FF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 0FF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* Myanmar (1000..109F) */
+
+#define indic_offset_0x1000u 1304
+
+
+ /* Myanmar */
/* 1000 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1008 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -337,9 +290,9 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B),
/* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(TM,x),
- /* 1038 */ _(Vs,x), _(V,I), _(V,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(C,x),
- /* 1040 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1048 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1038 */ _(Vs,x), _(IS,x), _(PK,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(C,x),
+ /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x),
/* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R),
/* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,x), _(CM,x),
/* 1060 */ _(CM,x), _(C,x), _(M,R), _(TM,x), _(TM,x), _(C,x), _(C,x), _(M,R),
@@ -348,41 +301,41 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1080 */ _(C,x), _(C,x), _(CM,x), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,x),
/* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(TM,x),
- /* 1090 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1098 */ _(x,x), _(x,x), _(TM,x), _(TM,x), _(M,R), _(M,T), _(x,x), _(x,x),
+ /* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1098 */ _(Nd,x), _(Nd,x), _(TM,x), _(TM,x), _(M,R), _(M,T), _(x,x), _(x,x),
-#define indic_offset_0x1700 1952
+#define indic_offset_0x1700u 1464
- /* Tagalog (1700..171F) */
+ /* Tagalog */
/* 1700 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1708 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x),
- /* 1710 */ _(C,x), _(C,x), _(M,T), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x),
+ /* 1710 */ _(C,x), _(C,x), _(M,T), _(M,B), _(PK,B), _(x,x), _(x,x), _(x,x),
/* 1718 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Hanunoo (1720..173F) */
+ /* Hanunoo */
/* 1720 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1728 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1730 */ _(C,x), _(C,x), _(M,T), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x),
+ /* 1730 */ _(C,x), _(C,x), _(M,T), _(M,B), _(PK,B), _(x,x), _(x,x), _(x,x),
/* 1738 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Buhid (1740..175F) */
+ /* Buhid */
/* 1740 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1748 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1750 */ _(C,x), _(C,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1758 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Tagbanwa (1760..177F) */
+ /* Tagbanwa */
/* 1760 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1768 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x),
/* 1770 */ _(C,x), _(x,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1778 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Khmer (1780..17FF) */
+ /* Khmer */
/* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1788 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -393,31 +346,29 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T),
/* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR),
/* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,x), _(Vs,x),
- /* 17C8 */ _(M,R), _(RS,x), _(RS,x), _(x,x), _(CR,x), _(x,x), _(x,x), _(x,x),
- /* 17D0 */ _(x,x), _(V,T), _(V,I), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(RS,T),_(CSR,T), _(M,T), _(M,T), _(M,T),
+ /* 17D0 */ _(M,T), _(PK,T), _(IS,x), _(M,T), _(x,x), _(x,x), _(x,x), _(x,x),
/* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,x), _(x,x), _(x,x),
- /* 17E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 17E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 17F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 17F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 17E8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x1900 2208
+#define indic_offset_0x1900u 1704
- /* Limbu (1900..194F) */
+ /* Limbu */
/* 1900 */ _(CP,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1908 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
+ /* 1918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
/* 1920 */ _(M,T), _(M,T), _(M,B), _(M,R), _(M,R), _(M,TR), _(M,TR), _(M,T),
/* 1928 */ _(M,T), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* 1938 */ _(CF,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1940 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1948 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1940 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
+ /* 1948 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
- /* Tai Le (1950..197F) */
+ /* Tai Le */
/* 1950 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -426,7 +377,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 1970 */ _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(x,x), _(x,x), _(x,x),
/* 1978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* New Tai Lue (1980..19DF) */
+ /* New Tai Lue */
/* 1980 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1988 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -438,24 +389,21 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 19B8 */ _(M,R), _(M,R), _(M,L), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
/* 19C0 */ _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* 19C8 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 19D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* FILLER (19E0..19FF) */
-
+ /* 19D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 19D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 19F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Buginese (1A00..1A1F) */
+ /* Buginese */
/* 1A00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T),
- /* 1A18 */ _(M,B), _(M,L), _(M,R), _(M,L), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1A18 */ _(M,B), _(M,L), _(M,R), _(M,T), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Tai Tham (1A20..1AAF) */
+ /* Tai Tham */
/* 1A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -463,25 +411,23 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 1A38 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1A48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x),
- /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,x), _(CM,x), _(CF,x),
+ /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,L), _(CM,x), _(CF,x),
/* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x),
- /* 1A60 */ _(V,I), _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T),
+ /* 1A60 */ _(IS,x), _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T),
/* 1A68 */ _(M,T), _(M,B), _(M,B), _(M,T), _(M,B), _(M,R), _(M,L), _(M,L),
/* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,x), _(TM,x), _(TM,x),
/* 1A78 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1A80 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1A88 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1A90 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1A98 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1AA0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1AA8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1A80 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1A88 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1A90 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1A98 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x1b00 2640
+#define indic_offset_0x1b00u 2120
- /* Balinese (1B00..1B7F) */
+ /* Balinese */
- /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x),
/* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1B10 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -491,36 +437,36 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 1B38 */ _(M,B), _(M,B), _(M,B), _(M,BR), _(M,TB),_(M,TBR), _(M,L), _(M,L),
/* 1B40 */ _(M,LR), _(M,LR), _(M,T), _(M,TR), _(V,R), _(C,x), _(C,x), _(C,x),
/* 1B48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1B50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1B58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Sundanese (1B80..1BBF) */
+ /* Sundanese */
- /* 1B80 */ _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 1B80 */ _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1B88 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1B98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BA0 */ _(C,x), _(CS,x), _(CS,x), _(CS,x), _(M,T), _(M,B), _(M,L), _(M,R),
- /* 1BA8 */ _(M,T), _(M,T), _(V,R), _(V,x), _(CS,x), _(CS,x), _(C,x), _(C,x),
- /* 1BB0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1BB8 */ _(x,x), _(x,x), _(A,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x),
+ /* 1BA8 */ _(M,T), _(M,T), _(PK,R), _(IS,x), _(CS,x), _(CS,x), _(C,x), _(C,x),
+ /* 1BB0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1BB8 */ _(Nd,x), _(Nd,x), _(A,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x),
- /* Batak (1BC0..1BFF) */
+ /* Batak */
/* 1BC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1BD8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
- /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,x), _(M,x),
- /* 1BE8 */ _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x),
- /* 1BF0 */ _(CF,x), _(CF,x), _(V,R), _(V,R), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,x), _(M,R),
+ /* 1BE8 */ _(M,T), _(M,T), _(M,R), _(M,R), _(M,R), _(M,T), _(M,R), _(M,T),
+ /* 1BF0 */ _(CF,x), _(CF,x), _(PK,R), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Lepcha (1C00..1C4F) */
+ /* Lepcha */
/* 1C00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1C08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -528,41 +474,45 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 1C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,x), _(CS,x), _(M,R), _(M,L),
/* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,x), _(CF,x), _(CF,x),
- /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,x), _(Bi,x), _(x,x), _(N,x),
+ /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,L), _(Bi,L), _(x,x), _(N,x),
/* 1C38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1C40 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1C48 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x),
+ /* 1C40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 1C48 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x),
-#define indic_offset_0x1cd0 2976
+#define indic_offset_0x1cd0u 2456
- /* Vedic Extensions (1CD0..1CFF) */
+ /* Vedic Extensions */
- /* 1CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1CE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1CD0 */ _(TM,x), _(TM,x), _(TM,x), _(x,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+ /* 1CD8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x),
+ /* 1CE0 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 1CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 1CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(TM,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0x2008u 2496
+
+
+ /* General Punctuation */
-#define indic_offset_0xa800 3024
+ /* 2008 */ _(x,x), _(x,x), _(x,x), _(x,x),_(ZWNJ,x),_(ZWJ,x), _(x,x), _(x,x),
+ /* 2010 */ _(x,x), _(x,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
+#define indic_offset_0xa800u 2512
- /* Syloti Nagri (A800..A82F) */
- /* A800 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(V,T), _(C,x),
+ /* Syloti Nagri */
+
+ /* A800 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(PK,T), _(C,x),
/* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A810 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A818 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A820 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,B), _(M,T), _(M,R),
/* A828 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* FILLER (A830..A83F) */
-
/* A830 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A838 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Phags-pa (A840..A87F) */
+ /* Phags-pa */
/* A840 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A848 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -573,7 +523,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* A870 */ _(C,x), _(CS,x), _(C,x), _(Bi,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A878 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Saurashtra (A880..A8DF) */
+ /* Saurashtra */
/* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -585,44 +535,41 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* A8B8 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R),
/* A8C0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), _(x,x),
/* A8C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A8D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A8D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A8D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A8D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* FILLER (A8E0..A8FF) */
+ /* Devanagari Extended */
- /* A8E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A8E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A8F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A8E0 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+ /* A8E8 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x),
+ /* A8F0 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Kayah Li (A900..A92F) */
+ /* Kayah Li */
- /* A900 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A908 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A900 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A908 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A920 */ _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x),
/* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(x,x),
- /* Rejang (A930..A95F) */
+ /* Rejang */
/* A930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A938 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A940 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,B),
/* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,x),
- /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(V,R), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(PK,R), _(x,x), _(x,x), _(x,x), _(x,x),
/* A958 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
- /* FILLER (A960..A97F) */
-
/* A960 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A970 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Javanese (A980..A9DF) */
+ /* Javanese */
- /* A980 */ _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* A980 */ _(Bi,x), _(Bi,x),_(CSR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* A988 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
/* A990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -632,17 +579,17 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,x), _(CM,x), _(CM,x),
/* A9C0 */ _(V,BR), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* A9C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A9D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A9D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A9D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A9D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* FILLER (A9E0..A9FF) */
+ /* Myanmar Extended-B */
- /* A9E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A9E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A9F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* A9F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(C,x),
+ /* A9E8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* A9F8 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
- /* Cham (AA00..AA5F) */
+ /* Cham */
/* AA00 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
/* AA08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -650,21 +597,21 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* AA18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA28 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,T), _(M,L),
- /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(x,x),
+ /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,x), _(CM,L), _(CM,x), _(CM,x), _(x,x),
/* AA38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x), _(x,x),
- /* AA50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* AA58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AA50 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* AA58 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Myanmar Extended-A (AA60..AA7F) */
+ /* Myanmar Extended-A */
/* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x),
- /* Tai Viet (AA80..AADF) */
+ /* Tai Viet */
/* AA80 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA88 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -679,31 +626,30 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* AAD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* AAD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Meetei Mayek Extensions (AAE0..AAFF) */
+ /* Meetei Mayek Extensions */
/* AAE0 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AAE8 */ _(C,x), _(C,x), _(C,x), _(M,L), _(M,B), _(M,T), _(M,L), _(M,R),
- /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,x), _(V,I), _(x,x),
- /* AAF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,x), _(IS,x), _(x,x),
-#define indic_offset_0xabc0 3792
+#define indic_offset_0xabc0u 3272
- /* Meetei Mayek (ABC0..ABFF) */
+ /* Meetei Mayek */
/* ABC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* ABC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x),
/* ABD0 */ _(C,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* ABD8 */ _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x),
/* ABE0 */ _(CF,x), _(CF,x), _(CF,x), _(M,R), _(M,R), _(M,T), _(M,R), _(M,R),
- /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(V,B), _(x,x), _(x,x),
- /* ABF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* ABF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(PK,B), _(x,x), _(x,x),
+ /* ABF0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* ABF8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x10a00 3856
+#define indic_offset_0x10a00u 3336
- /* Kharoshthi (10A00..10A5F) */
+ /* Kharoshthi */
/* 10A00 */ _(C,x), _(M,O), _(M,B), _(M,B), _(x,x), _(M,T), _(M,O), _(x,x),
/* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(x,x), _(Bi,x), _(Vs,x),
@@ -712,16 +658,13 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 10A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 10A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 10A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 10A38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(V,I),
- /* 10A40 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 10A48 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 10A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 10A58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 10A38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(IS,x),
+ /* 10A40 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
-#define indic_offset_0x11000 3952
+#define indic_offset_0x11000u 3408
- /* Brahmi (11000..1107F) */
+ /* Brahmi */
/* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -733,14 +676,14 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 11038 */ _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B),
/* 11040 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x),
/* 11048 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11050 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11058 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11060 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11068 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11050 */ _(x,x), _(x,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),
+ /* 11058 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),
+ /* 11060 */_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x),_(BJN,x), _(Nd,x), _(Nd,x),
+ /* 11068 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 11070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 11078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(NJ,x),
- /* Kaithi (11080..110CF) */
+ /* Kaithi */
/* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
@@ -750,13 +693,11 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 110A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 110B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,R),
/* 110B8 */ _(M,R), _(V,B), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 110C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 110C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x11100 4160
+#define indic_offset_0x11100u 3600
- /* Chakma (11100..1114F) */
+ /* Chakma */
/* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
/* 11108 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -764,15 +705,21 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 11118 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 11120 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T),
/* 11128 */ _(M,T), _(M,T), _(M,B), _(M,B), _(M,L), _(M,T), _(M,TB), _(M,TB),
- /* 11130 */ _(M,T), _(M,B), _(M,B), _(V,I), _(V,T), _(x,x), _(x,x), _(x,x),
- /* 11138 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11130 */ _(M,T), _(M,B), _(M,B), _(IS,x), _(PK,T), _(x,x), _(Nd,x), _(Nd,x),
+ /* 11138 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 11140 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 11148 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-#define indic_offset_0x11180 4240
+ /* Mahajani */
+ /* 11150 */ _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(C,x), _(C,x), _(C,x),
+ /* 11158 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11160 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11168 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11170 */ _(C,x), _(C,x), _(C,x), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11178 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* Sharada (11180..111DF) */
+ /* Sharada */
/* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
@@ -784,13 +731,116 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 111B8 */ _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,TR),
/* 111C0 */ _(V,R), _(A,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 111C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 111D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 111D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_0x11680 4336
-
-
- /* Takri (11680..116CF) */
+ /* 111D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 111D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Sinhala Archaic Numbers */
+
+ /* 111E0 */ _(x,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 111E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 111F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x),
+ /* 111F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Khojki */
+
+ /* 11200 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11208 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11210 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11218 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11220 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11228 */ _(C,x), _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,R), _(M,B),
+ /* 11230 */ _(M,T), _(M,T), _(M,TR), _(M,TR), _(Bi,x), _(V,R), _(N,x), _(GM,T),
+
+#define indic_offset_0x112b0u 3912
+
+
+ /* Khudawadi */
+
+ /* 112B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 112B8 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112C0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112C8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112D0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 112D8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Bi,x),
+ /* 112E0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
+ /* 112E8 */ _(M,T), _(N,x), _(PK,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 112F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 112F8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Grantha */
+
+ /* 11300 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11308 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
+ /* 11310 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
+ /* 11318 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11320 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11328 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11330 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
+ /* 11338 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,R),
+ /* 11340 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(x,x), _(M,L),
+ /* 11348 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,R), _(x,x), _(x,x),
+ /* 11350 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
+ /* 11358 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11360 */ _(VI,x), _(VI,x), _(M,R), _(M,R), _(x,x), _(x,x), _(Ca,x), _(Ca,x),
+ /* 11368 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
+ /* 11370 */ _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0x11480u 4112
+
+
+ /* Tirhuta */
+
+ /* 11480 */ _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11488 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x),
+ /* 11490 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11498 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 114B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
+ /* 114B8 */ _(M,B), _(M,L), _(M,T), _(M,TL), _(M,LR), _(M,R), _(M,LR), _(Bi,x),
+ /* 114C0 */ _(Bi,x), _(Vs,x), _(V,B), _(N,x), _(A,x), _(x,x), _(x,x), _(x,x),
+ /* 114C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 114D0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 114D8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0x11580u 4208
+
+
+ /* Siddham */
+
+ /* 11580 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11588 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
+ /* 11590 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11598 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 115A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 115A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,R),
+ /* 115B0 */ _(M,L), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x),
+ /* 115B8 */ _(M,L), _(M,TL), _(M,LR),_(M,TLR), _(Bi,x), _(Bi,x), _(Vs,x), _(V,B),
+ /* 115C0 */ _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+#define indic_offset_0x11600u 4280
+
+
+ /* Modi */
+
+ /* 11600 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
+ /* 11608 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x),
+ /* 11610 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11618 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11620 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11628 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
+ /* 11630 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,B),
+ /* 11638 */ _(M,B), _(M,T), _(M,T), _(M,R), _(M,R), _(Bi,x), _(Vs,x), _(V,B),
+ /* 11640 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11648 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11650 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 11658 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11660 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11668 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11670 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+ /* 11678 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
+
+ /* Takri */
/* 11680 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 11688 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
@@ -800,30 +850,57 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
/* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(Vs,x), _(M,T), _(M,L), _(M,R),
/* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(N,x),
/* 116B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 116C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
- /* 116C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-
-#define indic_offset_total 4416
+ /* 116C0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
+ /* 116C8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
-}; /* Table occupancy: 60% */
+}; /* Table items: 4488; occupancy: 73% */
-static INDIC_TABLE_ELEMENT_TYPE
-get_indic_categories (hb_codepoint_t u)
+INDIC_TABLE_ELEMENT_TYPE
+hb_indic_get_categories (hb_codepoint_t u)
{
- if (0x0900 <= u && u <= 0x10A0) return indic_table[u - 0x0900 + indic_offset_0x0900];
- if (0x1700 <= u && u <= 0x1800) return indic_table[u - 0x1700 + indic_offset_0x1700];
- if (0x1900 <= u && u <= 0x1AB0) return indic_table[u - 0x1900 + indic_offset_0x1900];
- if (0x1B00 <= u && u <= 0x1C50) return indic_table[u - 0x1B00 + indic_offset_0x1b00];
- if (0x1CD0 <= u && u <= 0x1D00) return indic_table[u - 0x1CD0 + indic_offset_0x1cd0];
- if (0xA800 <= u && u <= 0xAB00) return indic_table[u - 0xA800 + indic_offset_0xa800];
- if (0xABC0 <= u && u <= 0xAC00) return indic_table[u - 0xABC0 + indic_offset_0xabc0];
- if (0x10A00 <= u && u <= 0x10A60) return indic_table[u - 0x10A00 + indic_offset_0x10a00];
- if (0x11000 <= u && u <= 0x110D0) return indic_table[u - 0x11000 + indic_offset_0x11000];
- if (0x11100 <= u && u <= 0x11150) return indic_table[u - 0x11100 + indic_offset_0x11100];
- if (0x11180 <= u && u <= 0x111E0) return indic_table[u - 0x11180 + indic_offset_0x11180];
- if (0x11680 <= u && u <= 0x116D0) return indic_table[u - 0x11680 + indic_offset_0x11680];
- if (unlikely (u == 0x00A0)) return _(CP,x);
- if (unlikely (u == 0x25CC)) return _(CP,x);
+ switch (u >> 12)
+ {
+ case 0x0u:
+ if (hb_in_range (u, 0x0028u, 0x003Fu)) return indic_table[u - 0x0028u + indic_offset_0x0028u];
+ if (hb_in_range (u, 0x00D0u, 0x00D7u)) return indic_table[u - 0x00D0u + indic_offset_0x00d0u];
+ if (hb_in_range (u, 0x0900u, 0x0DF7u)) return indic_table[u - 0x0900u + indic_offset_0x0900u];
+ if (unlikely (u == 0x00A0u)) return _(CP,x);
+ break;
+
+ case 0x1u:
+ if (hb_in_range (u, 0x1000u, 0x109Fu)) return indic_table[u - 0x1000u + indic_offset_0x1000u];
+ if (hb_in_range (u, 0x1700u, 0x17EFu)) return indic_table[u - 0x1700u + indic_offset_0x1700u];
+ if (hb_in_range (u, 0x1900u, 0x1A9Fu)) return indic_table[u - 0x1900u + indic_offset_0x1900u];
+ if (hb_in_range (u, 0x1B00u, 0x1C4Fu)) return indic_table[u - 0x1B00u + indic_offset_0x1b00u];
+ if (hb_in_range (u, 0x1CD0u, 0x1CF7u)) return indic_table[u - 0x1CD0u + indic_offset_0x1cd0u];
+ break;
+
+ case 0x2u:
+ if (hb_in_range (u, 0x2008u, 0x2017u)) return indic_table[u - 0x2008u + indic_offset_0x2008u];
+ if (unlikely (u == 0x25CCu)) return _(CP,x);
+ break;
+
+ case 0xAu:
+ if (hb_in_range (u, 0xA800u, 0xAAF7u)) return indic_table[u - 0xA800u + indic_offset_0xa800u];
+ if (hb_in_range (u, 0xABC0u, 0xABFFu)) return indic_table[u - 0xABC0u + indic_offset_0xabc0u];
+ break;
+
+ case 0x10u:
+ if (hb_in_range (u, 0x10A00u, 0x10A47u)) return indic_table[u - 0x10A00u + indic_offset_0x10a00u];
+ break;
+
+ case 0x11u:
+ if (hb_in_range (u, 0x11000u, 0x110BFu)) return indic_table[u - 0x11000u + indic_offset_0x11000u];
+ if (hb_in_range (u, 0x11100u, 0x11237u)) return indic_table[u - 0x11100u + indic_offset_0x11100u];
+ if (hb_in_range (u, 0x112B0u, 0x11377u)) return indic_table[u - 0x112B0u + indic_offset_0x112b0u];
+ if (hb_in_range (u, 0x11480u, 0x114DFu)) return indic_table[u - 0x11480u + indic_offset_0x11480u];
+ if (hb_in_range (u, 0x11580u, 0x115C7u)) return indic_table[u - 0x11580u + indic_offset_0x11580u];
+ if (hb_in_range (u, 0x11600u, 0x116CFu)) return indic_table[u - 0x11600u + indic_offset_0x11600u];
+ break;
+
+ default:
+ break;
+ }
return _(x,x);
}
@@ -831,17 +908,27 @@ get_indic_categories (hb_codepoint_t u)
#undef ISC_A
#undef ISC_Bi
+#undef ISC_BJN
+#undef ISC_Ca
#undef ISC_C
#undef ISC_CD
#undef ISC_CF
#undef ISC_CHL
#undef ISC_CM
#undef ISC_CP
-#undef ISC_CR
+#undef ISC_CPR
#undef ISC_CS
+#undef ISC_CSR
+#undef ISC_GM
+#undef ISC_IS
+#undef ISC_ZWJ
#undef ISC_ML
+#undef ISC_ZWNJ
#undef ISC_N
+#undef ISC_Nd
+#undef ISC_NJ
#undef ISC_x
+#undef ISC_PK
#undef ISC_RS
#undef ISC_TL
#undef ISC_TM
@@ -853,7 +940,6 @@ get_indic_categories (hb_codepoint_t u)
#undef IMC_B
#undef IMC_BR
-#undef IMC_I
#undef IMC_L
#undef IMC_LR
#undef IMC_x
@@ -867,6 +953,4 @@ get_indic_categories (hb_codepoint_t u)
#undef IMC_TR
#undef IMC_VOL
-#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */
-
/* == End of generated table == */
diff --git a/src/hb-ot-shape-complex-indic.cc b/src/hb-ot-shape-complex-indic.cc
index f168fe1..7723600 100644
--- a/src/hb-ot-shape-complex-indic.cc
+++ b/src/hb-ot-shape-complex-indic.cc
@@ -25,198 +25,608 @@
*/
#include "hb-ot-shape-complex-indic-private.hh"
-#include "hb-ot-shape-private.hh"
+#include "hb-ot-layout-private.hh"
-struct indic_options_t
+/* buffer var allocations */
+#define indic_category() complex_var_u8_0() /* indic_category_t */
+#define indic_position() complex_var_u8_1() /* indic_position_t */
+
+
+/*
+ * Indic shaper.
+ */
+
+
+#define IN_HALF_BLOCK(u, Base) (((u) & ~0x7Fu) == (Base))
+
+#define IS_DEVA(u) (IN_HALF_BLOCK (u, 0x0900u))
+#define IS_BENG(u) (IN_HALF_BLOCK (u, 0x0980u))
+#define IS_GURU(u) (IN_HALF_BLOCK (u, 0x0A00u))
+#define IS_GUJR(u) (IN_HALF_BLOCK (u, 0x0A80u))
+#define IS_ORYA(u) (IN_HALF_BLOCK (u, 0x0B00u))
+#define IS_TAML(u) (IN_HALF_BLOCK (u, 0x0B80u))
+#define IS_TELU(u) (IN_HALF_BLOCK (u, 0x0C00u))
+#define IS_KNDA(u) (IN_HALF_BLOCK (u, 0x0C80u))
+#define IS_MLYM(u) (IN_HALF_BLOCK (u, 0x0D00u))
+#define IS_SINH(u) (IN_HALF_BLOCK (u, 0x0D80u))
+#define IS_KHMR(u) (IN_HALF_BLOCK (u, 0x1780u))
+
+
+#define MATRA_POS_LEFT(u) POS_PRE_M
+#define MATRA_POS_RIGHT(u) ( \
+ IS_DEVA(u) ? POS_AFTER_SUB : \
+ IS_BENG(u) ? POS_AFTER_POST : \
+ IS_GURU(u) ? POS_AFTER_POST : \
+ IS_GUJR(u) ? POS_AFTER_POST : \
+ IS_ORYA(u) ? POS_AFTER_POST : \
+ IS_TAML(u) ? POS_AFTER_POST : \
+ IS_TELU(u) ? (u <= 0x0C42u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
+ IS_KNDA(u) ? (u < 0x0CC3u || u > 0xCD6u ? POS_BEFORE_SUB : POS_AFTER_SUB) : \
+ IS_MLYM(u) ? POS_AFTER_POST : \
+ IS_SINH(u) ? POS_AFTER_SUB : \
+ IS_KHMR(u) ? POS_AFTER_POST : \
+ /*default*/ POS_AFTER_SUB \
+ )
+#define MATRA_POS_TOP(u) ( /* BENG and MLYM don't have top matras. */ \
+ IS_DEVA(u) ? POS_AFTER_SUB : \
+ IS_GURU(u) ? POS_AFTER_POST : /* Deviate from spec */ \
+ IS_GUJR(u) ? POS_AFTER_SUB : \
+ IS_ORYA(u) ? POS_AFTER_MAIN : \
+ IS_TAML(u) ? POS_AFTER_SUB : \
+ IS_TELU(u) ? POS_BEFORE_SUB : \
+ IS_KNDA(u) ? POS_BEFORE_SUB : \
+ IS_SINH(u) ? POS_AFTER_SUB : \
+ IS_KHMR(u) ? POS_AFTER_POST : \
+ /*default*/ POS_AFTER_SUB \
+ )
+#define MATRA_POS_BOTTOM(u) ( \
+ IS_DEVA(u) ? POS_AFTER_SUB : \
+ IS_BENG(u) ? POS_AFTER_SUB : \
+ IS_GURU(u) ? POS_AFTER_POST : \
+ IS_GUJR(u) ? POS_AFTER_POST : \
+ IS_ORYA(u) ? POS_AFTER_SUB : \
+ IS_TAML(u) ? POS_AFTER_POST : \
+ IS_TELU(u) ? POS_BEFORE_SUB : \
+ IS_KNDA(u) ? POS_BEFORE_SUB : \
+ IS_MLYM(u) ? POS_AFTER_POST : \
+ IS_SINH(u) ? POS_AFTER_SUB : \
+ IS_KHMR(u) ? POS_AFTER_POST : \
+ /*default*/ POS_AFTER_SUB \
+ )
+
+static inline indic_position_t
+matra_position (hb_codepoint_t u, indic_position_t side)
{
- int initialized : 1;
- int uniscribe_bug_compatible : 1;
-};
+ switch ((int) side)
+ {
+ case POS_PRE_C: return MATRA_POS_LEFT (u);
+ case POS_POST_C: return MATRA_POS_RIGHT (u);
+ case POS_ABOVE_C: return MATRA_POS_TOP (u);
+ case POS_BELOW_C: return MATRA_POS_BOTTOM (u);
+ };
+ return side;
+}
-union indic_options_union_t {
- int i;
- indic_options_t opts;
+/* XXX
+ * This is a hack for now. We should move this data into the main Indic table.
+ * Or completely remove it and just check in the tables.
+ */
+static const hb_codepoint_t ra_chars[] = {
+ 0x0930u, /* Devanagari */
+ 0x09B0u, /* Bengali */
+ 0x09F0u, /* Bengali */
+ 0x0A30u, /* Gurmukhi */ /* No Reph */
+ 0x0AB0u, /* Gujarati */
+ 0x0B30u, /* Oriya */
+ 0x0BB0u, /* Tamil */ /* No Reph */
+ 0x0C30u, /* Telugu */ /* Reph formed only with ZWJ */
+ 0x0CB0u, /* Kannada */
+ 0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */
+
+ 0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
+
+ 0x179Au, /* Khmer */ /* No Reph, Visual Repha */
};
-ASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t));
-static indic_options_union_t
-indic_options_init (void)
+static inline bool
+is_ra (hb_codepoint_t u)
{
- indic_options_union_t u;
- u.i = 0;
- u.opts.initialized = 1;
+ for (unsigned int i = 0; i < ARRAY_LENGTH (ra_chars); i++)
+ if (u == ra_chars[i])
+ return true;
+ return false;
+}
- char *c = getenv ("HB_OT_INDIC_OPTIONS");
- u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
+static inline bool
+is_one_of (const hb_glyph_info_t &info, unsigned int flags)
+{
+ /* If it ligated, all bets are off. */
+ if (_hb_glyph_info_ligated (&info)) return false;
+ return !!(FLAG (info.indic_category()) & flags);
+}
- return u;
+static inline bool
+is_joiner (const hb_glyph_info_t &info)
+{
+ return is_one_of (info, JOINER_FLAGS);
}
-inline indic_options_t
-indic_options (void)
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
{
- static indic_options_union_t options;
+ return is_one_of (info, CONSONANT_FLAGS);
+}
+
+static inline bool
+is_halant_or_coeng (const hb_glyph_info_t &info)
+{
+ return is_one_of (info, HALANT_OR_COENG_FLAGS);
+}
+
+static inline void
+set_indic_properties (hb_glyph_info_t &info)
+{
+ hb_codepoint_t u = info.codepoint;
+ unsigned int type = hb_indic_get_categories (u);
+ indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+ indic_position_t pos = (indic_position_t) (type >> 8);
+
+
+ /*
+ * Re-assign category
+ */
+
- if (unlikely (!options.i)) {
- /* This is idempotent and threadsafe. */
- options = indic_options_init ();
+ /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
+ * treats a whole bunch of characters similarly.
+ * TESTS: For example, for U+0951:
+ * U+092E,U+0947,U+0952
+ * U+092E,U+0952,U+0947
+ * U+092E,U+0947,U+0951
+ * U+092E,U+0951,U+0947
+ * U+092E,U+0951,U+0952
+ * U+092E,U+0952,U+0951
+ */
+ if (unlikely (hb_in_ranges (u, 0x0951u, 0x0952u,
+ 0x1CD0u, 0x1CD2u,
+ 0x1CD4u, 0x1CE1u) ||
+ u == 0x1CF4u))
+ cat = OT_A;
+ /* The following act more like the Bindus. */
+ else if (unlikely (hb_in_range (u, 0x0953u, 0x0954u)))
+ cat = OT_SM;
+ /* The following act like consonants. */
+ else if (unlikely (hb_in_ranges (u, 0x0A72u, 0x0A73u,
+ 0x1CF5u, 0x1CF6u)))
+ cat = OT_C;
+ /* TODO: The following should only be allowed after a Visarga.
+ * For now, just treat them like regular tone marks. */
+ else if (unlikely (hb_in_range (u, 0x1CE2u, 0x1CE8u)))
+ cat = OT_A;
+ /* TODO: The following should only be allowed after some of
+ * the nasalization marks, maybe only for U+1CE9..U+1CF1.
+ * For now, just treat them like tone marks. */
+ else if (unlikely (u == 0x1CEDu))
+ cat = OT_A;
+ /* The following take marks in standalone clusters, similar to Avagraha. */
+ else if (unlikely (hb_in_ranges (u, 0xA8F2u, 0xA8F7u,
+ 0x1CE9u, 0x1CECu,
+ 0x1CEEu, 0x1CF1u)))
+ {
+ cat = OT_Symbol;
+ ASSERT_STATIC ((int) INDIC_SYLLABIC_CATEGORY_AVAGRAHA == OT_Symbol);
+ }
+ else if (unlikely (hb_in_range (u, 0x17CDu, 0x17D1u) ||
+ u == 0x17CBu || u == 0x17D3u || u == 0x17DDu)) /* Khmer Various signs */
+ {
+ /* These are like Top Matras. */
+ cat = OT_M;
+ pos = POS_ABOVE_C;
}
+ else if (unlikely (u == 0x17C6u)) cat = OT_N; /* Khmer Bindu doesn't like to be repositioned. */
+ else if (unlikely (u == 0x17D2u)) cat = OT_Coeng; /* Khmer coeng */
+ else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u)))
+ cat = OT_PLACEHOLDER;
+ else if (unlikely (u == 0x25CCu)) cat = OT_DOTTEDCIRCLE;
+ else if (unlikely (u == 0xA982u)) cat = OT_SM; /* Javanese repha. */
+ else if (unlikely (u == 0xA9BEu)) cat = OT_CM2; /* Javanese medial ya. */
+ else if (unlikely (u == 0xA9BDu)) { cat = OT_M; pos = POS_POST_C; } /* Javanese vocalic r. */
+
+
+ /*
+ * Re-assign position.
+ */
- return options.opts;
-}
+ if ((FLAG (cat) & CONSONANT_FLAGS))
+ {
+ pos = POS_BASE_C;
+ if (is_ra (u))
+ cat = OT_Ra;
+ }
+ else if (cat == OT_M)
+ {
+ pos = matra_position (u, pos);
+ }
+ else if ((FLAG (cat) & (FLAG (OT_SM) | FLAG (OT_VD) | FLAG (OT_A) | FLAG (OT_Symbol))))
+ {
+ pos = POS_SMVD;
+ }
+ if (unlikely (u == 0x0B01u)) pos = POS_BEFORE_SUB; /* Oriya Bindu is BeforeSub in the spec. */
-static int
-compare_codepoint (const void *pa, const void *pb)
-{
- hb_codepoint_t a = * (hb_codepoint_t *) pa;
- hb_codepoint_t b = * (hb_codepoint_t *) pb;
- return a < b ? -1 : a == b ? 0 : +1;
+
+ info.indic_category() = cat;
+ info.indic_position() = pos;
}
-static indic_position_t
-consonant_position (hb_codepoint_t u)
-{
- consonant_position_t *record;
+/*
+ * Things above this line should ideally be moved to the Indic table itself.
+ */
- record = (consonant_position_t *) bsearch (&u, consonant_positions,
- ARRAY_LENGTH (consonant_positions),
- sizeof (consonant_positions[0]),
- compare_codepoint);
- return record ? record->position : POS_BASE_C;
-}
+/*
+ * Indic configurations. Note that we do not want to keep every single script-specific
+ * behavior in these tables necessarily. This should mainly be used for per-script
+ * properties that are cheaper keeping here, than in the code. Ie. if, say, one and
+ * only one script has an exception, that one script can be if'ed directly in the code,
+ * instead of adding a new flag in these structs.
+ */
-static bool
-is_ra (hb_codepoint_t u)
+enum base_position_t {
+ BASE_POS_FIRST,
+ BASE_POS_LAST_SINHALA,
+ BASE_POS_LAST
+};
+enum reph_position_t {
+ REPH_POS_AFTER_MAIN = POS_AFTER_MAIN,
+ REPH_POS_BEFORE_SUB = POS_BEFORE_SUB,
+ REPH_POS_AFTER_SUB = POS_AFTER_SUB,
+ REPH_POS_BEFORE_POST = POS_BEFORE_POST,
+ REPH_POS_AFTER_POST = POS_AFTER_POST,
+ REPH_POS_DONT_CARE = POS_RA_TO_BECOME_REPH
+};
+enum reph_mode_t {
+ REPH_MODE_IMPLICIT, /* Reph formed out of initial Ra,H sequence. */
+ REPH_MODE_EXPLICIT, /* Reph formed out of initial Ra,H,ZWJ sequence. */
+ REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
+ REPH_MODE_LOG_REPHA /* Encoded Repha character, needs reordering. */
+};
+enum blwf_mode_t {
+ BLWF_MODE_PRE_AND_POST, /* Below-forms feature applied to pre-base and post-base. */
+ BLWF_MODE_POST_ONLY /* Below-forms feature applied to post-base only. */
+};
+enum pref_len_t {
+ PREF_LEN_1 = 1,
+ PREF_LEN_2 = 2,
+ PREF_LEN_DONT_CARE = PREF_LEN_2
+};
+struct indic_config_t
{
- return !!bsearch (&u, ra_chars,
- ARRAY_LENGTH (ra_chars),
- sizeof (ra_chars[0]),
- compare_codepoint);
-}
+ hb_script_t script;
+ bool has_old_spec;
+ hb_codepoint_t virama;
+ base_position_t base_pos;
+ reph_position_t reph_pos;
+ reph_mode_t reph_mode;
+ blwf_mode_t blwf_mode;
+ pref_len_t pref_len;
+};
-static bool
-is_joiner (const hb_glyph_info_t &info)
+static const indic_config_t indic_configs[] =
{
- return !!(FLAG (info.indic_category()) & (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)));
-}
+ /* Default. Should be first. */
+ {HB_SCRIPT_INVALID, false, 0,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+ {HB_SCRIPT_DEVANAGARI,true, 0x094Du,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+ {HB_SCRIPT_BENGALI, true, 0x09CDu,BASE_POS_LAST, REPH_POS_AFTER_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+ {HB_SCRIPT_GURMUKHI, true, 0x0A4Du,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+ {HB_SCRIPT_GUJARATI, true, 0x0ACDu,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+ {HB_SCRIPT_ORIYA, true, 0x0B4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+ {HB_SCRIPT_TAMIL, true, 0x0BCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+ {HB_SCRIPT_TELUGU, true, 0x0C4Du,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
+ {HB_SCRIPT_KANNADA, true, 0x0CCDu,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT, BLWF_MODE_POST_ONLY, PREF_LEN_2},
+ {HB_SCRIPT_MALAYALAM, true, 0x0D4Du,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+ {HB_SCRIPT_SINHALA, false,0x0DCAu,BASE_POS_LAST_SINHALA,
+ REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT, BLWF_MODE_PRE_AND_POST, PREF_LEN_DONT_CARE},
+ {HB_SCRIPT_KHMER, false,0x17D2u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_2},
+ {HB_SCRIPT_JAVANESE, false,0xA9C0u,BASE_POS_FIRST,REPH_POS_DONT_CARE, REPH_MODE_VIS_REPHA,BLWF_MODE_PRE_AND_POST, PREF_LEN_1},
+};
-static bool
-is_consonant (const hb_glyph_info_t &info)
-{
- /* Note:
- *
- * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
- * cannot happen in a consonant syllable. The plus side however is, we can call the
- * consonant syllable logic from the vowel syllable function and get it all right! */
- return !!(FLAG (info.indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)));
-}
+
+
+/*
+ * Indic shaper.
+ */
struct feature_list_t {
hb_tag_t tag;
- hb_bool_t is_global;
+ hb_ot_map_feature_flags_t flags;
};
static const feature_list_t
-indic_basic_features[] =
-{
- {HB_TAG('n','u','k','t'), true},
- {HB_TAG('a','k','h','n'), false},
- {HB_TAG('r','p','h','f'), false},
- {HB_TAG('r','k','r','f'), true},
- {HB_TAG('p','r','e','f'), false},
- {HB_TAG('b','l','w','f'), false},
- {HB_TAG('h','a','l','f'), false},
- {HB_TAG('p','s','t','f'), false},
- {HB_TAG('c','j','c','t'), false},
- {HB_TAG('v','a','t','u'), true},
+indic_features[] =
+{
+ /*
+ * Basic features.
+ * These features are applied in order, one at a time, after initial_reordering.
+ */
+ {HB_TAG('n','u','k','t'), F_GLOBAL},
+ {HB_TAG('a','k','h','n'), F_GLOBAL},
+ {HB_TAG('r','p','h','f'), F_NONE},
+ {HB_TAG('r','k','r','f'), F_GLOBAL},
+ {HB_TAG('p','r','e','f'), F_NONE},
+ {HB_TAG('b','l','w','f'), F_NONE},
+ {HB_TAG('a','b','v','f'), F_NONE},
+ {HB_TAG('h','a','l','f'), F_NONE},
+ {HB_TAG('p','s','t','f'), F_NONE},
+ {HB_TAG('v','a','t','u'), F_GLOBAL},
+ {HB_TAG('c','j','c','t'), F_GLOBAL},
+ {HB_TAG('c','f','a','r'), F_NONE},
+ /*
+ * Other features.
+ * These features are applied all at once, after final_reordering.
+ * Default Bengali font in Windows for example has intermixed
+ * lookups for init,pres,abvs,blws features.
+ */
+ {HB_TAG('i','n','i','t'), F_NONE},
+ {HB_TAG('p','r','e','s'), F_GLOBAL},
+ {HB_TAG('a','b','v','s'), F_GLOBAL},
+ {HB_TAG('b','l','w','s'), F_GLOBAL},
+ {HB_TAG('p','s','t','s'), F_GLOBAL},
+ {HB_TAG('h','a','l','n'), F_GLOBAL},
+ /* Positioning features, though we don't care about the types. */
+ {HB_TAG('d','i','s','t'), F_GLOBAL},
+ {HB_TAG('a','b','v','m'), F_GLOBAL},
+ {HB_TAG('b','l','w','m'), F_GLOBAL},
};
-/* Same order as the indic_basic_features array */
+/*
+ * Must be in the same order as the indic_features array.
+ */
enum {
_NUKT,
- AKHN,
+ _AKHN,
RPHF,
_RKRF,
PREF,
BLWF,
+ ABVF,
HALF,
PSTF,
- CJCT,
- VATU
-};
-
-static const feature_list_t
-indic_other_features[] =
-{
- {HB_TAG('i','n','i','t'), false},
- {HB_TAG('p','r','e','s'), true},
- {HB_TAG('a','b','v','s'), true},
- {HB_TAG('b','l','w','s'), true},
- {HB_TAG('p','s','t','s'), true},
- {HB_TAG('h','a','l','n'), true},
-
- {HB_TAG('d','i','s','t'), true},
- {HB_TAG('a','b','v','m'), true},
- {HB_TAG('b','l','w','m'), true},
-};
-
-/* Same order as the indic_other_features array */
-enum {
- INIT
+ _VATU,
+ _CJCT,
+ CFAR,
+
+ INIT,
+ _PRES,
+ _ABVS,
+ _BLWS,
+ _PSTS,
+ _HALN,
+ _DIST,
+ _ABVM,
+ _BLWM,
+
+ INDIC_NUM_FEATURES,
+ INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
};
-
static void
-initial_reordering (const hb_ot_map_t *map,
- hb_face_t *face,
- hb_buffer_t *buffer,
- void *user_data HB_UNUSED);
+setup_syllables (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
static void
-final_reordering (const hb_ot_map_t *map,
- hb_face_t *face,
- hb_buffer_t *buffer,
- void *user_data HB_UNUSED);
+final_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+static void
+clear_syllables (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
-void
-_hb_ot_shape_complex_collect_features_indic (hb_ot_map_builder_t *map,
- const hb_segment_properties_t *props HB_UNUSED)
+static void
+collect_features_indic (hb_ot_shape_planner_t *plan)
{
- map->add_bool_feature (HB_TAG('l','o','c','l'));
+ hb_ot_map_builder_t *map = &plan->map;
+
+ /* Do this before any lookups have been applied. */
+ map->add_gsub_pause (setup_syllables);
+
+ map->add_global_bool_feature (HB_TAG('l','o','c','l'));
/* The Indic specs do not require ccmp, but we apply it here since if
* there is a use of it, it's typically at the beginning. */
- map->add_bool_feature (HB_TAG('c','c','m','p'));
+ map->add_global_bool_feature (HB_TAG('c','c','m','p'));
- map->add_gsub_pause (initial_reordering, NULL);
- for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) {
- map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global);
- map->add_gsub_pause (NULL, NULL);
+ unsigned int i = 0;
+ map->add_gsub_pause (initial_reordering);
+ for (; i < INDIC_BASIC_FEATURES; i++) {
+ map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
+ map->add_gsub_pause (NULL);
+ }
+ map->add_gsub_pause (final_reordering);
+ for (; i < INDIC_NUM_FEATURES; i++) {
+ map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ);
}
- map->add_gsub_pause (final_reordering, NULL);
+ map->add_global_bool_feature (HB_TAG('c','a','l','t'));
+ map->add_global_bool_feature (HB_TAG('c','l','i','g'));
+
+ map->add_gsub_pause (clear_syllables);
+}
- for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++) {
- map->add_bool_feature (indic_other_features[i].tag, indic_other_features[i].is_global);
- map->add_gsub_pause (NULL, NULL);
+static void
+override_features_indic (hb_ot_shape_planner_t *plan)
+{
+ /* Uniscribe does not apply 'kern' in Khmer. */
+ if (hb_options ().uniscribe_bug_compatible)
+ {
+ switch ((hb_tag_t) plan->props.script)
+ {
+ case HB_SCRIPT_KHMER:
+ plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL);
+ break;
+ }
}
+
+ plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
}
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_indic (void)
+struct would_substitute_feature_t
+{
+ inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_)
+ {
+ zero_context = zero_context_;
+ map->get_stage_lookups (0/*GSUB*/,
+ map->get_feature_stage (0/*GSUB*/, feature_tag),
+ &lookups, &count);
+ }
+
+ inline bool would_substitute (const hb_codepoint_t *glyphs,
+ unsigned int glyphs_count,
+ hb_face_t *face) const
+ {
+ for (unsigned int i = 0; i < count; i++)
+ if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context))
+ return true;
+ return false;
+ }
+
+ private:
+ const hb_ot_map_t::lookup_map_t *lookups;
+ unsigned int count;
+ bool zero_context;
+};
+
+struct indic_shape_plan_t
{
- /* We want split matras decomposed by the common shaping logic. */
- return HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
+ ASSERT_POD ();
+
+ inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
+ {
+ hb_codepoint_t glyph = virama_glyph;
+ if (unlikely (virama_glyph == (hb_codepoint_t) -1))
+ {
+ if (!config->virama || !font->get_glyph (config->virama, 0, &glyph))
+ glyph = 0;
+ /* Technically speaking, the spec says we should apply 'locl' to virama too.
+ * Maybe one day... */
+
+ /* Our get_glyph() function needs a font, so we can't get the virama glyph
+ * during shape planning... Instead, overwrite it here. It's safe. Don't worry! */
+ (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
+ }
+
+ *pglyph = glyph;
+ return glyph != 0;
+ }
+
+ const indic_config_t *config;
+
+ bool is_old_spec;
+ hb_codepoint_t virama_glyph;
+
+ would_substitute_feature_t rphf;
+ would_substitute_feature_t pref;
+ would_substitute_feature_t blwf;
+ would_substitute_feature_t pstf;
+
+ hb_mask_t mask_array[INDIC_NUM_FEATURES];
+};
+
+static void *
+data_create_indic (const hb_ot_shape_plan_t *plan)
+{
+ indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
+ if (unlikely (!indic_plan))
+ return NULL;
+
+ indic_plan->config = &indic_configs[0];
+ for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
+ if (plan->props.script == indic_configs[i].script) {
+ indic_plan->config = &indic_configs[i];
+ break;
+ }
+
+ indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
+ indic_plan->virama_glyph = (hb_codepoint_t) -1;
+
+ /* Use zero-context would_substitute() matching for new-spec of the main
+ * Indic scripts, and scripts with one spec only, but not for old-specs. */
+ bool zero_context = !indic_plan->is_old_spec;
+ indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f'), zero_context);
+ indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context);
+ indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context);
+ indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context);
+
+ for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
+ indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ?
+ 0 : plan->map.get_1_mask (indic_features[i].tag);
+
+ return indic_plan;
+}
+
+static void
+data_destroy_indic (void *data)
+{
+ free (data);
+}
+
+static indic_position_t
+consonant_position_from_face (const indic_shape_plan_t *indic_plan,
+ const hb_codepoint_t consonant,
+ const hb_codepoint_t virama,
+ hb_face_t *face)
+{
+ /* For old-spec, the order of glyphs is Consonant,Virama,
+ * whereas for new-spec, it's Virama,Consonant. However,
+ * some broken fonts (like Free Sans) simply copied lookups
+ * from old-spec to new-spec without modification.
+ * And oddly enough, Uniscribe seems to respect those lookups.
+ * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds
+ * base at 0. The font however, only has lookups matching
+ * 930,94D in 'blwf', not the expected 94D,930 (with new-spec
+ * table). As such, we simply match both sequences. Seems
+ * to work. */
+ hb_codepoint_t glyphs[3] = {virama, consonant, virama};
+ if (indic_plan->blwf.would_substitute (glyphs , 2, face) ||
+ indic_plan->blwf.would_substitute (glyphs+1, 2, face))
+ return POS_BELOW_C;
+ if (indic_plan->pstf.would_substitute (glyphs , 2, face) ||
+ indic_plan->pstf.would_substitute (glyphs+1, 2, face))
+ return POS_POST_C;
+ unsigned int pref_len = indic_plan->config->pref_len;
+ if ((pref_len == PREF_LEN_2 &&
+ (indic_plan->pref.would_substitute (glyphs , 2, face) ||
+ indic_plan->pref.would_substitute (glyphs+1, 2, face)))
+ || (pref_len == PREF_LEN_1 &&
+ indic_plan->pref.would_substitute (glyphs+1, 1, face)))
+ return POS_POST_C;
+ return POS_BASE_C;
}
-void
-_hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map HB_UNUSED,
- hb_buffer_t *buffer,
- hb_font_t *font HB_UNUSED)
+enum syllable_type_t {
+ consonant_syllable,
+ vowel_syllable,
+ standalone_cluster,
+ symbol_cluster,
+ broken_cluster,
+ non_indic_cluster,
+};
+
+#include "hb-ot-shape-complex-indic-machine.hh"
+
+
+static void
+setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_buffer_t *buffer,
+ hb_font_t *font HB_UNUSED)
{
HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
@@ -225,39 +635,17 @@ _hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map HB_UNUSED,
* and setup masks later on in a pause-callback. */
unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
- {
- hb_glyph_info_t &info = buffer->info[i];
- unsigned int type = get_indic_categories (info.codepoint);
-
- info.indic_category() = type & 0x0F;
- info.indic_position() = type >> 4;
-
- /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe
- * treats U+0951..U+0952 all as OT_VD.
- * TESTS:
- * U+092E,U+0947,U+0952
- * U+092E,U+0952,U+0947
- * U+092E,U+0947,U+0951
- * U+092E,U+0951,U+0947
- * */
- if (unlikely (hb_in_range<hb_codepoint_t> (info.codepoint, 0x0951, 0x0954)))
- info.indic_category() = OT_VD;
-
- if (info.indic_category() == OT_C) {
- info.indic_position() = consonant_position (info.codepoint);
- if (is_ra (info.codepoint))
- info.indic_category() = OT_Ra;
- } else if (info.indic_category() == OT_SM ||
- info.indic_category() == OT_VD) {
- info.indic_position() = POS_SMVD;
- } else if (unlikely (info.codepoint == 0x200C))
- info.indic_category() = OT_ZWNJ;
- else if (unlikely (info.codepoint == 0x200D))
- info.indic_category() = OT_ZWJ;
- else if (unlikely (info.codepoint == 0x25CC))
- info.indic_category() = OT_DOTTEDCIRCLE;
- }
+ set_indic_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ find_syllables (buffer);
}
static int
@@ -269,13 +657,44 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
return a < b ? -1 : a == b ? 0 : +1;
}
+
+
+static void
+update_consonant_positions (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
+
+ if (indic_plan->config->base_pos != BASE_POS_LAST)
+ return;
+
+ hb_codepoint_t virama;
+ if (indic_plan->get_virama_glyph (font, &virama))
+ {
+ hb_face_t *face = font->face;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if (info[i].indic_position() == POS_BASE_C)
+ {
+ hb_codepoint_t consonant = info[i].codepoint;
+ info[i].indic_position() = consonant_position_from_face (indic_plan, consonant, virama, face);
+ }
+ }
+}
+
+
/* Rules from:
* https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
static void
-initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array,
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
+ const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
hb_glyph_info_t *info = buffer->info;
@@ -301,54 +720,144 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
* and has more than one consonant, Ra is excluded from candidates for
* base consonants. */
unsigned int limit = start;
- if (mask_array[RPHF] &&
+ if (indic_plan->config->reph_pos != REPH_POS_DONT_CARE &&
+ indic_plan->mask_array[RPHF] &&
start + 3 <= end &&
- info[start].indic_category() == OT_Ra &&
- info[start + 1].indic_category() == OT_H &&
- !is_joiner (info[start + 2]))
+ (
+ (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
+ (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
+ ))
{
- limit += 2;
- base = start;
- has_reph = true;
- };
-
- /* -> starting from the end of the syllable, move backwards */
- unsigned int i = end;
- do {
- i--;
- /* -> until a consonant is found */
- if (is_consonant (info[i]))
+ /* See if it matches the 'rphf' feature. */
+ hb_codepoint_t glyphs[3] = {info[start].codepoint,
+ info[start + 1].codepoint,
+ indic_plan->config->reph_mode == REPH_MODE_EXPLICIT ?
+ info[start + 2].codepoint : 0};
+ if (indic_plan->rphf.would_substitute (glyphs, 2, face) ||
+ (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT &&
+ indic_plan->rphf.would_substitute (glyphs, 3, face)))
{
- /* -> that does not have a below-base or post-base form
- * (post-base forms have to follow below-base forms), */
- if (info[i].indic_position() != POS_BELOW_C &&
- info[i].indic_position() != POS_POST_C)
- {
- base = i;
- break;
- }
+ limit += 2;
+ while (limit < end && is_joiner (info[limit]))
+ limit++;
+ base = start;
+ has_reph = true;
+ }
+ } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha)
+ {
+ limit += 1;
+ while (limit < end && is_joiner (info[limit]))
+ limit++;
+ base = start;
+ has_reph = true;
+ }
- /* -> or that is not a pre-base reordering Ra,
- *
- * TODO
+ switch (indic_plan->config->base_pos)
+ {
+ default:
+ assert (false);
+ /* fallthrough */
+
+ case BASE_POS_LAST:
+ {
+ /* -> starting from the end of the syllable, move backwards */
+ unsigned int i = end;
+ bool seen_below = false;
+ do {
+ i--;
+ /* -> until a consonant is found */
+ if (is_consonant (info[i]))
+ {
+ /* -> that does not have a below-base or post-base form
+ * (post-base forms have to follow below-base forms), */
+ if (info[i].indic_position() != POS_BELOW_C &&
+ (info[i].indic_position() != POS_POST_C || seen_below))
+ {
+ base = i;
+ break;
+ }
+ if (info[i].indic_position() == POS_BELOW_C)
+ seen_below = true;
+
+ /* -> or that is not a pre-base reordering Ra,
+ *
+ * IMPLEMENTATION NOTES:
+ *
+ * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped
+ * by the logic above already.
+ */
+
+ /* -> or arrive at the first consonant. The consonant stopped at will
+ * be the base. */
+ base = i;
+ }
+ else
+ {
+ /* A ZWJ after a Halant stops the base search, and requests an explicit
+ * half form.
+ * A ZWJ before a Halant, requests a subjoined form instead, and hence
+ * search continues. This is particularly important for Bengali
+ * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */
+ if (start < i &&
+ info[i].indic_category() == OT_ZWJ &&
+ info[i - 1].indic_category() == OT_H)
+ break;
+ }
+ } while (i > limit);
+ }
+ break;
+
+ case BASE_POS_LAST_SINHALA:
+ {
+ /* Sinhala base positioning is slightly different from main Indic, in that:
+ * 1. Its ZWJ behavior is different,
+ * 2. We don't need to look into the font for consonant positions.
*/
- /* -> or arrive at the first consonant. The consonant stopped at will
- * be the base. */
- base = i;
+ if (!has_reph)
+ base = limit;
+
+ /* Find the last base consonant that is not blocked by ZWJ. If there is
+ * a ZWJ right before a base consonant, that would request a subjoined form. */
+ for (unsigned int i = limit; i < end; i++)
+ if (is_consonant (info[i]))
+ {
+ if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
+ break;
+ else
+ base = i;
+ }
+
+ /* Mark all subsequent consonants as below. */
+ for (unsigned int i = base + 1; i < end; i++)
+ if (is_consonant (info[i]))
+ info[i].indic_position() = POS_BELOW_C;
}
- else
- if (is_joiner (info[i]))
- break;
- } while (i > limit);
- if (base < start)
- base = start; /* Just in case... */
+ break;
+
+ case BASE_POS_FIRST:
+ {
+ /* The first consonant is always the base. */
+ assert (indic_plan->config->reph_mode == REPH_MODE_VIS_REPHA);
+ assert (!has_reph);
+
+ base = start;
+
+ /* Mark all subsequent consonants as below. */
+ for (unsigned int i = base + 1; i < end; i++)
+ if (is_consonant (info[i]))
+ info[i].indic_position() = POS_BELOW_C;
+ }
+ break;
+ }
/* -> If the syllable starts with Ra + Halant (in a script that has Reph)
* and has more than one consonant, Ra is excluded from candidates for
- * base consonants. */
- if (has_reph && base == start) {
+ * base consonants.
+ *
+ * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */
+ if (has_reph && base == start && limit - base <= 2) {
/* Have no other consonant, so Reph is not formed and Ra becomes base. */
has_reph = false;
}
@@ -390,24 +899,56 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
/* Reorder characters */
for (unsigned int i = start; i < base; i++)
- info[i].indic_position() = POS_PRE_C;
- info[base].indic_position() = POS_BASE_C;
+ info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position());
+
+ if (base < end)
+ info[base].indic_position() = POS_BASE_C;
+
+ /* Mark final consonants. A final consonant is one appearing after a matra,
+ * like in Khmer. */
+ for (unsigned int i = base + 1; i < end; i++)
+ if (info[i].indic_category() == OT_M) {
+ for (unsigned int j = i + 1; j < end; j++)
+ if (is_consonant (info[j])) {
+ info[j].indic_position() = POS_FINAL_C;
+ break;
+ }
+ break;
+ }
/* Handle beginning Ra */
if (has_reph)
info[start].indic_position() = POS_RA_TO_BECOME_REPH;
/* For old-style Indic script tags, move the first post-base Halant after
- * last consonant. */
- if ((map->get_chosen_script (0) & 0x000000FF) != '2') {
- /* We should only do this for Indic scripts which have a version two I guess. */
+ * last consonant.
+ *
+ * Reports suggest that in some scripts Uniscribe does this only if there
+ * is *not* a Halant after last consonant already (eg. Kannada), while it
+ * does it unconditionally in other scripts (eg. Malayalam). We don't
+ * currently know about other scripts, so we single out Malayalam for now.
+ *
+ * Kannada test case:
+ * U+0C9A,U+0CCD,U+0C9A,U+0CCD
+ * With some versions of Lohit Kannada.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=59118
+ *
+ * Malayalam test case:
+ * U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
+ * With lohit-ttf-20121122/Lohit-Malayalam.ttf
+ */
+ if (indic_plan->is_old_spec)
+ {
+ bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM;
for (unsigned int i = base + 1; i < end; i++)
- if (info[i].indic_category() == OT_H) {
+ if (info[i].indic_category() == OT_H)
+ {
unsigned int j;
for (j = end - 1; j > i; j--)
- if (is_consonant (info[j]))
+ if (is_consonant (info[j]) ||
+ (disallow_double_halants && info[j].indic_category() == OT_H))
break;
- if (j > i) {
+ if (info[j].indic_category() != OT_H && j > i) {
/* Move Halant to after last consonant. */
hb_glyph_info_t t = info[i];
memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
@@ -417,43 +958,99 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
}
}
- /* Attach ZWJ, ZWNJ, nukta, and halant to previous char to move with them. */
- if (!indic_options ().uniscribe_bug_compatible)
+ /* Attach misc marks to previous char to move with them. */
{
- /* Please update the Uniscribe branch when touching this! */
- for (unsigned int i = start + 1; i < end; i++)
- if ((FLAG (info[i].indic_category()) & (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H))))
- info[i].indic_position() = info[i - 1].indic_position();
- } else {
- /*
- * Uniscribe doesn't move the Halant with Left Matra.
- * TEST: U+092B,U+093F,U+094DE
- */
- /* Please update the non-Uniscribe branch when touching this! */
- for (unsigned int i = start + 1; i < end; i++)
- if ((FLAG (info[i].indic_category()) & (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H)))) {
- info[i].indic_position() = info[i - 1].indic_position();
- if (info[i].indic_category() == OT_H && info[i].indic_position() == POS_PRE_M)
+ indic_position_t last_pos = POS_START;
+ for (unsigned int i = start; i < end; i++)
+ {
+ if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | HALANT_OR_COENG_FLAGS)))
+ {
+ info[i].indic_position() = last_pos;
+ if (unlikely (info[i].indic_category() == OT_H &&
+ info[i].indic_position() == POS_PRE_M))
+ {
+ /*
+ * Uniscribe doesn't move the Halant with Left Matra.
+ * TEST: U+092B,U+093F,U+094DE
+ * We follow. This is important for the Sinhala
+ * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA
+ * where U+0DD9 is a left matra and U+0DCA is the virama.
+ * We don't want to move the virama with the left matra.
+ * TEST: U+0D9A,U+0DDA
+ */
for (unsigned int j = i; j > start; j--)
if (info[j - 1].indic_position() != POS_PRE_M) {
info[i].indic_position() = info[j - 1].indic_position();
break;
}
+ }
+ } else if (info[i].indic_position() != POS_SMVD) {
+ last_pos = (indic_position_t) info[i].indic_position();
}
+ }
+ }
+ /* For post-base consonants let them own anything before them
+ * since the last consonant or matra. */
+ {
+ unsigned int last = base;
+ for (unsigned int i = base + 1; i < end; i++)
+ if (is_consonant (info[i]))
+ {
+ for (unsigned int j = last + 1; j < i; j++)
+ if (info[j].indic_position() < POS_SMVD)
+ info[j].indic_position() = info[i].indic_position();
+ last = i;
+ } else if (info[i].indic_category() == OT_M)
+ last = i;
}
- /* We do bubble-sort, skip malicious clusters attempts */
- if (end - start < 64)
+
{
+ /* Use syllable() for sort accounting temporarily. */
+ unsigned int syllable = info[start].syllable();
+ for (unsigned int i = start; i < end; i++)
+ info[i].syllable() = i - start;
+
/* Sit tight, rock 'n roll! */
hb_bubble_sort (info + start, end - start, compare_indic_order);
/* Find base again */
base = end;
for (unsigned int i = start; i < end; i++)
- if (info[i].indic_position() == POS_BASE_C) {
- base = i;
+ if (info[i].indic_position() == POS_BASE_C)
+ {
+ base = i;
break;
}
+ /* Things are out-of-control for post base positions, they may shuffle
+ * around like crazy. In old-spec mode, we move halants around, so in
+ * that case merge all clusters after base. Otherwise, check the sort
+ * order and merge as needed.
+ * For pre-base stuff, we handle cluster issues in final reordering. */
+ if (indic_plan->is_old_spec || end - base > 127)
+ buffer->merge_clusters (base, end);
+ else
+ {
+ /* Note! syllable() is a one-byte field. */
+ for (unsigned int i = base; i < end; i++)
+ if (info[i].syllable() != 255)
+ {
+ unsigned int max = i;
+ unsigned int j = start + info[i].syllable();
+ while (j != i)
+ {
+ max = MAX (max, j);
+ unsigned int next = start + info[j].syllable();
+ info[j].syllable() = 255; /* So we don't process j later again. */
+ j = next;
+ }
+ if (i != max)
+ buffer->merge_clusters (i, max + 1);
+ }
+ }
+
+ /* Put syllable back in. */
+ for (unsigned int i = start; i < end; i++)
+ info[i].syllable() = syllable;
}
/* Setup masks now */
@@ -463,21 +1060,86 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
/* Reph */
for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
- info[i].mask |= mask_array[RPHF];
+ info[i].mask |= indic_plan->mask_array[RPHF];
/* Pre-base */
- mask = mask_array[HALF] | mask_array[AKHN] | mask_array[CJCT];
+ mask = indic_plan->mask_array[HALF];
+ if (!indic_plan->is_old_spec &&
+ indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST)
+ mask |= indic_plan->mask_array[BLWF];
for (unsigned int i = start; i < base; i++)
info[i].mask |= mask;
/* Base */
- mask = mask_array[AKHN] | mask_array[CJCT];
- info[base].mask |= mask;
+ mask = 0;
+ if (base < end)
+ info[base].mask |= mask;
/* Post-base */
- mask = mask_array[BLWF] | mask_array[PSTF] | mask_array[CJCT];
+ mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
for (unsigned int i = base + 1; i < end; i++)
info[i].mask |= mask;
}
+ if (indic_plan->is_old_spec &&
+ buffer->props.script == HB_SCRIPT_DEVANAGARI)
+ {
+ /* Old-spec eye-lash Ra needs special handling. From the
+ * spec:
+ *
+ * "The feature 'below-base form' is applied to consonants
+ * having below-base forms and following the base consonant.
+ * The exception is vattu, which may appear below half forms
+ * as well as below the base glyph. The feature 'below-base
+ * form' will be applied to all such occurrences of Ra as well."
+ *
+ * Test case: U+0924,U+094D,U+0930,U+094d,U+0915
+ * with Sanskrit 2003 font.
+ *
+ * However, note that Ra,Halant,ZWJ is the correct way to
+ * request eyelash form of Ra, so we wouldbn't inhibit it
+ * in that sequence.
+ *
+ * Test case: U+0924,U+094D,U+0930,U+094d,U+200D,U+0915
+ */
+ for (unsigned int i = start; i + 1 < base; i++)
+ if (info[i ].indic_category() == OT_Ra &&
+ info[i+1].indic_category() == OT_H &&
+ (i + 2 == base ||
+ info[i+2].indic_category() != OT_ZWJ))
+ {
+ info[i ].mask |= indic_plan->mask_array[BLWF];
+ info[i+1].mask |= indic_plan->mask_array[BLWF];
+ }
+ }
+
+ unsigned int pref_len = indic_plan->config->pref_len;
+ if (indic_plan->mask_array[PREF] && base + pref_len < end)
+ {
+ assert (1 <= pref_len && pref_len <= 2);
+ /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
+ for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
+ hb_codepoint_t glyphs[2];
+ for (unsigned int j = 0; j < pref_len; j++)
+ glyphs[j] = info[i + j].codepoint;
+ if (indic_plan->pref.would_substitute (glyphs, pref_len, face))
+ {
+ for (unsigned int j = 0; j < pref_len; j++)
+ info[i++].mask |= indic_plan->mask_array[PREF];
+
+ /* Mark the subsequent stuff with 'cfar'. Used in Khmer.
+ * Read the feature spec.
+ * This allows distinguishing the following cases with MS Khmer fonts:
+ * U+1784,U+17D2,U+179A,U+17D2,U+1782
+ * U+1784,U+17D2,U+1782,U+17D2,U+179A
+ */
+ if (indic_plan->mask_array[CFAR])
+ for (; i < end; i++)
+ info[i].mask |= indic_plan->mask_array[CFAR];
+
+ break;
+ }
+ }
+ }
+
/* Apply ZWJ/ZWNJ effects */
for (unsigned int i = start + 1; i < end; i++)
if (is_joiner (info[i])) {
@@ -487,9 +1149,13 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
do {
j--;
- info[j].mask &= ~mask_array[CJCT];
+ /* ZWJ/ZWNJ should disable CJCT. They do that by simply
+ * being there, since we don't skip them for the CJCT
+ * feature (ie. F_MANUAL_ZWJ) */
+
+ /* A ZWNJ disables HALF. */
if (non_joiner)
- info[j].mask &= ~mask_array[HALF];
+ info[j].mask &= ~indic_plan->mask_array[HALF];
} while (j > start && !is_consonant (info[j]));
}
@@ -497,25 +1163,25 @@ initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buff
static void
-initial_reordering_vowel_syllable (const hb_ot_map_t *map,
+initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
hb_buffer_t *buffer,
- hb_mask_t *mask_array,
unsigned int start, unsigned int end)
{
/* We made the vowels look like consonants. So let's call the consonant logic! */
- initial_reordering_consonant_syllable (map, buffer, mask_array, start, end);
+ initial_reordering_consonant_syllable (plan, face, buffer, start, end);
}
static void
-initial_reordering_standalone_cluster (const hb_ot_map_t *map,
+initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
hb_buffer_t *buffer,
- hb_mask_t *mask_array,
unsigned int start, unsigned int end)
{
- /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain.
- * Only if not in compatibility mode that is... */
+ /* We treat placeholder/dotted-circle as if they are consonants, so we
+ * should just chain. Only if not in compatibility mode that is... */
- if (indic_options ().uniscribe_bug_compatible)
+ if (hb_options ().uniscribe_bug_compatible)
{
/* For dotted-circle, this is what Uniscribe does:
* If dotted-circle is the last glyph, it just does nothing.
@@ -524,41 +1190,169 @@ initial_reordering_standalone_cluster (const hb_ot_map_t *map,
return;
}
- initial_reordering_consonant_syllable (map, buffer, mask_array, start, end);
+ initial_reordering_consonant_syllable (plan, face, buffer, start, end);
}
static void
-initial_reordering_non_indic (const hb_ot_map_t *map HB_UNUSED,
- hb_buffer_t *buffer HB_UNUSED,
- hb_mask_t *mask_array HB_UNUSED,
- unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+{
+ /* We already inserted dotted-circles, so just call the standalone_cluster. */
+ initial_reordering_standalone_cluster (plan, face, buffer, start, end);
+}
+
+static void
+initial_reordering_symbol_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ hb_buffer_t *buffer HB_UNUSED,
+ unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+ /* Nothing to do right now. If we ever switch to using the output
+ * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+static void
+initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ hb_buffer_t *buffer HB_UNUSED,
+ unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
{
/* Nothing to do right now. If we ever switch to using the output
* buffer in the reordering process, we'd need to next_glyph() here. */
}
-#include "hb-ot-shape-complex-indic-machine.hh"
static void
-initial_reordering (const hb_ot_map_t *map,
- hb_face_t *face HB_UNUSED,
- hb_buffer_t *buffer,
- void *user_data HB_UNUSED)
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
{
- hb_mask_t mask_array[ARRAY_LENGTH (indic_basic_features)] = {0};
- unsigned int num_masks = ARRAY_LENGTH (indic_basic_features);
- for (unsigned int i = 0; i < num_masks; i++)
- mask_array[i] = map->get_1_mask (indic_basic_features[i].tag);
+ syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+ switch (syllable_type) {
+ case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+ case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return;
+ case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return;
+ case symbol_cluster: initial_reordering_symbol_cluster (plan, face, buffer, start, end); return;
+ case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
+ case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return;
+ }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ /* Note: This loop is extra overhead, but should not be measurable. */
+ bool has_broken_syllables = false;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if ((info[i].syllable() & 0x0F) == broken_cluster)
+ {
+ has_broken_syllables = true;
+ break;
+ }
+ if (likely (!has_broken_syllables))
+ return;
+
+
+ hb_codepoint_t dottedcircle_glyph;
+ if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+ return;
+
+ hb_glyph_info_t dottedcircle = {0};
+ dottedcircle.codepoint = 0x25CCu;
+ set_indic_properties (dottedcircle);
+ dottedcircle.codepoint = dottedcircle_glyph;
- find_syllables (map, buffer, mask_array);
+ buffer->clear_output ();
+
+ buffer->idx = 0;
+ unsigned int last_syllable = 0;
+ while (buffer->idx < buffer->len)
+ {
+ unsigned int syllable = buffer->cur().syllable();
+ syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+ if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+ {
+ last_syllable = syllable;
+
+ hb_glyph_info_t info = dottedcircle;
+ info.cluster = buffer->cur().cluster;
+ info.mask = buffer->cur().mask;
+ info.syllable() = buffer->cur().syllable();
+ /* TODO Set glyph_props? */
+
+ /* Insert dottedcircle after possible Repha. */
+ while (buffer->idx < buffer->len &&
+ last_syllable == buffer->cur().syllable() &&
+ buffer->cur().indic_category() == OT_Repha)
+ buffer->next_glyph ();
+
+ buffer->output_info (info);
+ }
+ else
+ buffer->next_glyph ();
+ }
+
+ buffer->swap_buffers ();
}
static void
-final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
+initial_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ update_consonant_positions (plan, font, buffer);
+ insert_dotted_circles (plan, font, buffer);
+
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+ if (unlikely (!count)) return;
+ unsigned int last = 0;
+ unsigned int last_syllable = info[0].syllable();
+ for (unsigned int i = 1; i < count; i++)
+ if (last_syllable != info[i].syllable()) {
+ initial_reordering_syllable (plan, font->face, buffer, last, i);
+ last = i;
+ last_syllable = info[last].syllable();
+ }
+ initial_reordering_syllable (plan, font->face, buffer, last, count);
+}
+
+static void
+final_reordering_syllable (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
unsigned int start, unsigned int end)
{
+ const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
hb_glyph_info_t *info = buffer->info;
+
+ /* This function relies heavily on halant glyphs. Lots of ligation
+ * and possibly multiplication substitutions happened prior to this
+ * phase, and that might have messed up our properties. Recover
+ * from a particular case of that where we're fairly sure that a
+ * class of OT_H is desired but has been lost. */
+ if (indic_plan->virama_glyph)
+ {
+ unsigned int virama_glyph = indic_plan->virama_glyph;
+ for (unsigned int i = start; i < end; i++)
+ if (info[i].codepoint == virama_glyph &&
+ _hb_glyph_info_ligated (&info[i]) &&
+ _hb_glyph_info_multiplied (&info[i]))
+ {
+ /* This will make sure that this glyph passes is_halant_or_coeng() test. */
+ info[i].indic_category() = OT_H;
+ _hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
+ }
+ }
+
+
/* 4. Final reordering:
*
* After the localized forms and basic shaping forms GSUB features have been
@@ -567,22 +1361,46 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
* cluster.
*/
+ bool try_pref = !!indic_plan->mask_array[PREF];
+
/* Find base again */
- unsigned int base = end;
- for (unsigned int i = start; i < end; i++)
- if (info[i].indic_position() == POS_BASE_C) {
- base = i;
+ unsigned int base;
+ for (base = start; base < end; base++)
+ if (info[base].indic_position() >= POS_BASE_C)
+ {
+ if (try_pref && base + 1 < end && indic_plan->config->pref_len == 2)
+ {
+ for (unsigned int i = base + 1; i < end; i++)
+ if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+ {
+ if (!(_hb_glyph_info_substituted (&info[i]) &&
+ _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
+ {
+ /* Ok, this was a 'pref' candidate but didn't form any.
+ * Base is around here... */
+ base = i;
+ while (base < end && is_halant_or_coeng (info[base]))
+ base++;
+ info[base].indic_position() = POS_BASE_C;
+
+ try_pref = false;
+ }
+ break;
+ }
+ }
+
+ if (start < base && info[base].indic_position() > POS_BASE_C)
+ base--;
break;
}
+ if (base == end && start < base &&
+ is_one_of (info[base - 1], FLAG (OT_ZWJ)))
+ base--;
+ if (base < end)
+ while (start < base &&
+ is_one_of (info[base], (FLAG (OT_N) | HALANT_OR_COENG_FLAGS)))
+ base--;
- if (base == start) {
- /* There's no Reph, and no left Matra to reposition. Just merge the cluster
- * and go home. */
- buffer->merge_clusters (start, end);
- return;
- }
-
- unsigned int start_of_last_cluster = base;
/* o Reorder matras:
*
@@ -594,29 +1412,55 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
* halant, position is moved after it.
*/
+ if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
{
- unsigned int new_matra_pos = base - 1;
- while (new_matra_pos > start &&
- !(FLAG (info[new_matra_pos].indic_category()) & (FLAG (OT_M) | FLAG (OT_H))))
- new_matra_pos--;
- /* If we found no Halant we are done. Otherwise only proceed if the Halant does
- * not belong to the Matra itself! */
- if (info[new_matra_pos].indic_category() == OT_H &&
- info[new_matra_pos].indic_position() != POS_PRE_M) {
- /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
- if (new_matra_pos + 1 < end && is_joiner (info[new_matra_pos + 1]))
- new_matra_pos++;
+ /* If we lost track of base, alas, position before last thingy. */
+ unsigned int new_pos = base == end ? base - 2 : base - 1;
+
+ /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
+ * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
+ * We want to position matra after them.
+ */
+ if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
+ {
+ while (new_pos > start &&
+ !(is_one_of (info[new_pos], (FLAG (OT_M) | HALANT_OR_COENG_FLAGS))))
+ new_pos--;
+
+ /* If we found no Halant we are done.
+ * Otherwise only proceed if the Halant does
+ * not belong to the Matra itself! */
+ if (is_halant_or_coeng (info[new_pos]) &&
+ info[new_pos].indic_position() != POS_PRE_M)
+ {
+ /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
+ if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
+ new_pos++;
+ }
+ else
+ new_pos = start; /* No move. */
+ }
+ if (start < new_pos && info[new_pos].indic_position () != POS_PRE_M)
+ {
/* Now go see if there's actually any matras... */
- for (unsigned int i = new_matra_pos; i > start; i--)
+ for (unsigned int i = new_pos; i > start; i--)
if (info[i - 1].indic_position () == POS_PRE_M)
{
- unsigned int old_matra_pos = i - 1;
- hb_glyph_info_t matra = info[old_matra_pos];
- memmove (&info[old_matra_pos], &info[old_matra_pos + 1], (new_matra_pos - old_matra_pos) * sizeof (info[0]));
- info[new_matra_pos] = matra;
- start_of_last_cluster = MIN (new_matra_pos, start_of_last_cluster);
- new_matra_pos--;
+ unsigned int old_pos = i - 1;
+ hb_glyph_info_t tmp = info[old_pos];
+ memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
+ info[new_pos] = tmp;
+ if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
+ base--;
+ buffer->merge_clusters (new_pos, MIN (end, base + 1));
+ new_pos--;
+ }
+ } else {
+ for (unsigned int i = start; i < base; i++)
+ if (info[i].indic_position () == POS_PRE_M) {
+ buffer->merge_clusters (i, MIN (end, base + 1));
+ break;
}
}
}
@@ -631,56 +1475,29 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
* before post-base consonant forms, and after post-base consonant forms.
*/
- /* If there's anything after the Ra that has the REPH pos, it ought to be halant.
- * Which means that the font has failed to ligate the Reph. In which case, we
- * shouldn't move. */
+ /* Two cases:
+ *
+ * - If repha is encoded as a sequence of characters (Ra,H or Ra,H,ZWJ), then
+ * we should only move it if the sequence ligated to the repha form.
+ *
+ * - If repha is encoded separately and in the logical position, we should only
+ * move it if it did NOT ligate. If it ligated, it's probably the font trying
+ * to make it work without the reordering.
+ */
if (start + 1 < end &&
info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
- info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH)
+ ((info[start].indic_category() == OT_Repha) ^
+ _hb_glyph_info_ligated_and_didnt_multiply (&info[start])))
{
- unsigned int new_reph_pos;
-
- enum reph_position_t {
- REPH_AFTER_MAIN,
- REPH_BEFORE_SUBSCRIPT,
- REPH_AFTER_SUBSCRIPT,
- REPH_BEFORE_POSTSCRIPT,
- REPH_AFTER_POSTSCRIPT
- } reph_pos;
-
- /* XXX Figure out old behavior too */
- switch ((hb_tag_t) buffer->props.script)
- {
- case HB_SCRIPT_MALAYALAM:
- case HB_SCRIPT_ORIYA:
- reph_pos = REPH_AFTER_MAIN;
- break;
-
- case HB_SCRIPT_GURMUKHI:
- reph_pos = REPH_BEFORE_SUBSCRIPT;
- break;
-
- case HB_SCRIPT_BENGALI:
- reph_pos = REPH_AFTER_SUBSCRIPT;
- break;
-
- default:
- case HB_SCRIPT_DEVANAGARI:
- case HB_SCRIPT_GUJARATI:
- reph_pos = REPH_BEFORE_POSTSCRIPT;
- break;
-
- case HB_SCRIPT_KANNADA:
- case HB_SCRIPT_TAMIL:
- case HB_SCRIPT_TELUGU:
- reph_pos = REPH_AFTER_POSTSCRIPT;
- break;
- }
+ unsigned int new_reph_pos;
+ reph_position_t reph_pos = indic_plan->config->reph_pos;
+
+ assert (reph_pos != REPH_POS_DONT_CARE);
/* 1. If reph should be positioned after post-base consonant forms,
* proceed to step 5.
*/
- if (reph_pos == REPH_AFTER_POSTSCRIPT)
+ if (reph_pos == REPH_POS_AFTER_POST)
{
goto reph_step_5;
}
@@ -698,10 +1515,11 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
*/
{
new_reph_pos = start + 1;
- while (new_reph_pos < base && info[new_reph_pos].indic_category() != OT_H)
+ while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
new_reph_pos++;
- if (new_reph_pos < base && info[new_reph_pos].indic_category() == OT_H) {
+ if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+ {
/* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
new_reph_pos++;
@@ -713,9 +1531,13 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
* first consonant not ligated with main, or find the first
* consonant that is not a potential pre-base reordering Ra.
*/
- if (reph_pos == REPH_AFTER_MAIN)
+ if (reph_pos == REPH_POS_AFTER_MAIN)
{
- /* XXX */
+ new_reph_pos = base;
+ while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
+ new_reph_pos++;
+ if (new_reph_pos < end)
+ goto reph_move;
}
/* 4. If reph should be positioned before post-base consonant, find
@@ -724,11 +1546,11 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
* first matra, syllable modifier sign or vedic sign.
*/
/* This is our take on what step 4 is trying to say (and failing, BADLY). */
- if (reph_pos == REPH_AFTER_SUBSCRIPT)
+ if (reph_pos == REPH_POS_AFTER_SUB)
{
new_reph_pos = base;
while (new_reph_pos < end &&
- !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_POST_M) | FLAG (POS_SMVD))))
+ !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
new_reph_pos++;
if (new_reph_pos < end)
goto reph_move;
@@ -743,7 +1565,18 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
*/
reph_step_5:
{
- /* XXX */
+ /* Copied from step 2. */
+ new_reph_pos = start + 1;
+ while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
+ new_reph_pos++;
+
+ if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos]))
+ {
+ /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
+ if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
+ new_reph_pos++;
+ goto reph_move;
+ }
}
/* 6. Otherwise, reorder reph to the end of the syllable.
@@ -760,8 +1593,8 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
* Uniscribe doesn't do this.
* TEST: U+0930,U+094D,U+0915,U+094B,U+094D
*/
- if (!indic_options ().uniscribe_bug_compatible &&
- unlikely (info[new_reph_pos].indic_category() == OT_H)) {
+ if (!hb_options ().uniscribe_bug_compatible &&
+ unlikely (is_halant_or_coeng (info[new_reph_pos]))) {
for (unsigned int i = base + 1; i < new_reph_pos; i++)
if (info[i].indic_category() == OT_M) {
/* Ok, got it. */
@@ -773,11 +1606,14 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
reph_move:
{
+ buffer->merge_clusters (start, new_reph_pos + 1);
+
/* Move */
hb_glyph_info_t reph = info[start];
memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
info[new_reph_pos] = reph;
- start_of_last_cluster = start; /* Yay, one big cluster! */
+ if (start < base && base <= new_reph_pos)
+ base--;
}
}
@@ -786,88 +1622,263 @@ final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array,
*
* If a pre-base reordering consonant is found, reorder it according to
* the following rules:
- *
- * 1. Only reorder a glyph produced by substitution during application
- * of the feature. (Note that a font may shape a Ra consonant with
- * the feature generally but block it in certain contexts.)
- *
- * 2. Try to find a target position the same way as for pre-base matra.
- * If it is found, reorder pre-base consonant glyph.
- *
- * 3. If position is not found, reorder immediately before main
- * consonant.
*/
- /* TODO */
+ if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
+ {
+ unsigned int pref_len = indic_plan->config->pref_len;
+ for (unsigned int i = base + 1; i < end; i++)
+ if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
+ {
+ /* 1. Only reorder a glyph produced by substitution during application
+ * of the <pref> feature. (Note that a font may shape a Ra consonant with
+ * the feature generally but block it in certain contexts.)
+ */
+ /* Note: We just check that something got substituted. We don't check that
+ * the <pref> feature actually did it...
+ *
+ * If pref len is longer than one, then only reorder if it ligated. If
+ * pref len is one, only reorder if it didn't ligate with other things. */
+ if (_hb_glyph_info_substituted (&info[i]) &&
+ ((pref_len == 1) ^ _hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
+ {
+ /*
+ * 2. Try to find a target position the same way as for pre-base matra.
+ * If it is found, reorder pre-base consonant glyph.
+ *
+ * 3. If position is not found, reorder immediately before main
+ * consonant.
+ */
+
+ unsigned int new_pos = base;
+ /* Malayalam / Tamil do not have "half" forms or explicit virama forms.
+ * The glyphs formed by 'half' are Chillus or ligated explicit viramas.
+ * We want to position matra after them.
+ */
+ if (buffer->props.script != HB_SCRIPT_MALAYALAM && buffer->props.script != HB_SCRIPT_TAMIL)
+ {
+ while (new_pos > start &&
+ !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
+ new_pos--;
+
+ /* In Khmer coeng model, a H,Ra can go *after* matras. If it goes after a
+ * split matra, it should be reordered to *before* the left part of such matra. */
+ if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
+ {
+ unsigned int old_pos = i;
+ for (unsigned int i = base + 1; i < old_pos; i++)
+ if (info[i].indic_category() == OT_M)
+ {
+ new_pos--;
+ break;
+ }
+ }
+ }
+ if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
+ {
+ /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
+ if (new_pos < end && is_joiner (info[new_pos]))
+ new_pos++;
+ }
+
+ {
+ unsigned int old_pos = i;
+ buffer->merge_clusters (new_pos, old_pos + 1);
+ hb_glyph_info_t tmp = info[old_pos];
+ memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
+ info[new_pos] = tmp;
+ if (new_pos <= base && base < old_pos)
+ base++;
+ }
+ }
+
+ break;
+ }
+ }
/* Apply 'init' to the Left Matra if it's a word start. */
if (info[start].indic_position () == POS_PRE_M &&
(!start ||
!(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) &
- (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))))
- info[start].mask |= mask_array[INIT];
-
-
+ FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
+ info[start].mask |= indic_plan->mask_array[INIT];
- /* Finish off the clusters and go home! */
- if (!indic_options ().uniscribe_bug_compatible)
+ /*
+ * Finish off the clusters and go home!
+ */
+ if (hb_options ().uniscribe_bug_compatible)
{
- /* This is what Uniscribe does. Ie. add cluster boundaries after Halant,ZWNJ.
- * This means, half forms are submerged into the main consonants cluster.
- * This is unnecessary, and makes cursor positioning harder, but that's what
- * Uniscribe does. */
- unsigned int cluster_start = start;
- for (unsigned int i = start + 1; i < start_of_last_cluster; i++)
- if (info[i - 1].indic_category() == OT_H && info[i].indic_category() == OT_ZWNJ) {
- i++;
- buffer->merge_clusters (cluster_start, i);
- cluster_start = i;
- }
- start_of_last_cluster = cluster_start;
- }
+ switch ((hb_tag_t) plan->props.script)
+ {
+ case HB_SCRIPT_TAMIL:
+ case HB_SCRIPT_SINHALA:
+ break;
- buffer->merge_clusters (start_of_last_cluster, end);
+ default:
+ /* Uniscribe merges the entire cluster... Except for Tamil & Sinhala.
+ * This means, half forms are submerged into the main consonants cluster.
+ * This is unnecessary, and makes cursor positioning harder, but that's what
+ * Uniscribe does. */
+ buffer->merge_clusters (start, end);
+ break;
+ }
+ }
}
static void
-final_reordering (const hb_ot_map_t *map,
- hb_face_t *face HB_UNUSED,
- hb_buffer_t *buffer,
- void *user_data HB_UNUSED)
+final_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
- if (!count) return;
-
- hb_mask_t mask_array[ARRAY_LENGTH (indic_other_features)] = {0};
- unsigned int num_masks = ARRAY_LENGTH (indic_other_features);
- for (unsigned int i = 0; i < num_masks; i++)
- mask_array[i] = map->get_1_mask (indic_other_features[i].tag);
+ if (unlikely (!count)) return;
hb_glyph_info_t *info = buffer->info;
unsigned int last = 0;
unsigned int last_syllable = info[0].syllable();
for (unsigned int i = 1; i < count; i++)
if (last_syllable != info[i].syllable()) {
- final_reordering_syllable (buffer, mask_array, last, i);
+ final_reordering_syllable (plan, buffer, last, i);
last = i;
last_syllable = info[last].syllable();
}
- final_reordering_syllable (buffer, mask_array, last, count);
+ final_reordering_syllable (plan, buffer, last, count);
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
}
+static void
+clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ info[i].syllable() = 0;
+}
+
+
+static bool
+decompose_indic (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b)
+{
+ switch (ab)
+ {
+ /* Don't decompose these. */
+ case 0x0931u : return false;
+ case 0x0B94u : return false;
+
+ /*
+ * Decompose split matras that don't have Unicode decompositions.
+ */
+
+ case 0x0F77u : *a = 0x0FB2u; *b= 0x0F81u; return true;
+ case 0x0F79u : *a = 0x0FB3u; *b= 0x0F81u; return true;
+ case 0x17BEu : *a = 0x17C1u; *b= 0x17BEu; return true;
+ case 0x17BFu : *a = 0x17C1u; *b= 0x17BFu; return true;
+ case 0x17C0u : *a = 0x17C1u; *b= 0x17C0u; return true;
+ case 0x17C4u : *a = 0x17C1u; *b= 0x17C4u; return true;
+ case 0x17C5u : *a = 0x17C1u; *b= 0x17C5u; return true;
+ case 0x1925u : *a = 0x1920u; *b= 0x1923u; return true;
+ case 0x1926u : *a = 0x1920u; *b= 0x1924u; return true;
+ case 0x1B3Cu : *a = 0x1B42u; *b= 0x1B3Cu; return true;
+ case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
+ case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
+#if 0
+ /* This one has no decomposition in Unicode, but needs no decomposition either. */
+ /* case 0x0AC9u : return false; */
+ case 0x0B57u : *a = no decomp, -> RIGHT; return true;
+ case 0x1C29u : *a = no decomp, -> LEFT; return true;
+ case 0xA9C0u : *a = no decomp, -> RIGHT; return true;
+ case 0x111BuF : *a = no decomp, -> ABOVE; return true;
+#endif
+ }
+
+ if ((ab == 0x0DDAu || hb_in_range (ab, 0x0DDCu, 0x0DDEu)))
+ {
+ /*
+ * Sinhala split matras... Let the fun begin.
+ *
+ * These four characters have Unicode decompositions. However, Uniscribe
+ * decomposes them "Khmer-style", that is, it uses the character itself to
+ * get the second half. The first half of all four decompositions is always
+ * U+0DD9.
+ *
+ * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are
+ * broken with Uniscribe. But we need to support them. As such, we only
+ * do the Uniscribe-style decomposition if the character is transformed into
+ * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to
+ * Unicode decomposition.
+ *
+ * Note that we can't unconditionally use Unicode decomposition. That would
+ * break some other fonts, that are designed to work with Uniscribe, and
+ * don't have positioning features for the Unicode-style decomposition.
+ *
+ * Argh...
+ *
+ * The Uniscribe behavior is now documented in the newly published Sinhala
+ * spec in 2012:
+ *
+ * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping
+ */
+
+ const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data;
+
+ hb_codepoint_t glyph;
+
+ if (hb_options ().uniscribe_bug_compatible ||
+ (c->font->get_glyph (ab, 0, &glyph) &&
+ indic_plan->pstf.would_substitute (&glyph, 1, c->font->face)))
+ {
+ /* Ok, safe to use Uniscribe-style decomposition. */
+ *a = 0x0DD9u;
+ *b = ab;
+ return true;
+ }
+ }
+
+ return c->unicode->decompose (ab, a, b);
+}
+
+static bool
+compose_indic (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab)
+{
+ /* Avoid recomposing split matras. */
+ if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a)))
+ return false;
+
+ /* Composition-exclusion exceptions that we want to recompose. */
+ if (a == 0x09AFu && b == 0x09BCu) { *ab = 0x09DFu; return true; }
+
+ return c->unicode->compose (a, b, ab);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
+{
+ "indic",
+ collect_features_indic,
+ override_features_indic,
+ data_create_indic,
+ data_destroy_indic,
+ NULL, /* preprocess_text */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+ decompose_indic,
+ compose_indic,
+ setup_masks_indic,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+ false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-misc.cc b/src/hb-ot-shape-complex-misc.cc
deleted file mode 100644
index d93d4c6..0000000
--- a/src/hb-ot-shape-complex-misc.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright © 2010 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb-ot-shape-complex-private.hh"
-
-
-/* TODO Add kana, and other small shapers here */
-
-/* When adding trivial shapers, eg. kana, hangul, etc, we can either
- * add a full shaper enum value for them, or switch on the script in
- * the default complex shaper. The former is faster, so I think that's
- * what we would do, and hence the default complex shaper shall remain
- * empty.
- */
-
-void
-_hb_ot_shape_complex_collect_features_default (hb_ot_map_builder_t *map HB_UNUSED,
- const hb_segment_properties_t *props HB_UNUSED)
-{
-}
-
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_default (void)
-{
- return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
-}
-
-void
-_hb_ot_shape_complex_setup_masks_default (hb_ot_map_t *map HB_UNUSED,
- hb_buffer_t *buffer HB_UNUSED,
- hb_font_t *font HB_UNUSED)
-{
-}
-
-
-
-/* Hangul shaper */
-
-static const hb_tag_t hangul_features[] =
-{
- HB_TAG('l','j','m','o'),
- HB_TAG('v','j','m','o'),
- HB_TAG('t','j','m','o'),
-};
-
-void
-_hb_ot_shape_complex_collect_features_hangul (hb_ot_map_builder_t *map,
- const hb_segment_properties_t *props HB_UNUSED)
-{
- for (unsigned int i = 0; i < ARRAY_LENGTH (hangul_features); i++)
- map->add_bool_feature (hangul_features[i]);
-}
-
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_hangul (void)
-{
- return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
-}
-
-void
-_hb_ot_shape_complex_setup_masks_hangul (hb_ot_map_t *map HB_UNUSED,
- hb_buffer_t *buffer HB_UNUSED,
- hb_font_t *font HB_UNUSED)
-{
-}
-
-
-
-/* Thai / Lao shaper */
-
-void
-_hb_ot_shape_complex_collect_features_thai (hb_ot_map_builder_t *map HB_UNUSED,
- const hb_segment_properties_t *props HB_UNUSED)
-{
-}
-
-hb_ot_shape_normalization_mode_t
-_hb_ot_shape_complex_normalization_preference_thai (void)
-{
- return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL;
-}
-
-void
-_hb_ot_shape_complex_setup_masks_thai (hb_ot_map_t *map HB_UNUSED,
- hb_buffer_t *buffer,
- hb_font_t *font HB_UNUSED)
-{
- /* The following is NOT specified in the MS OT Thai spec, however, it seems
- * to be what Uniscribe and other engines implement. According to Eric Muller:
- *
- * When you have a sara am, decompose it in nikhahit + sara a, *and* mode the
- * nihka hit backwards over any *tone* mark (0E48-0E4B).
- *
- * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
- *
- * This reordering is legit only when the nikhahit comes from a sara am, not
- * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
- * not what a u↪ser wanted, but the rendering is nevertheless nikhahit above
- * chattawa.
- *
- * Same for Lao.
- */
-
- /*
- * Here are the characters of significance:
- *
- * Thai Lao
- * SARA AM: U+0E33 U+0EB3
- * SARA AA: U+0E32 U+0EB2
- * Nikhahit: U+0E4D U+0ECD
- *
- * Tone marks:
- * Thai: <0E48..0E4B> CCC=107
- * Lao: <0EC8..0ECB> CCC=122
- *
- * Note how the Lao versions are the same as Thai + 0x80.
- */
-
- /* We only get one script at a time, so a script-agnostic implementation
- * is adequate here. */
-#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33)
-#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D)
-#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
-#define IS_TONE_MARK(x) (((x) & ~0x0083) == 0x0E48)
-
- buffer->clear_output ();
- unsigned int count = buffer->len;
- for (buffer->idx = 0; buffer->idx < count;)
- {
- hb_codepoint_t u = buffer->cur().codepoint;
- if (likely (!IS_SARA_AM (u))) {
- buffer->next_glyph ();
- continue;
- }
-
- /* Is SARA AM. Decompose and reorder. */
- hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
- hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
- buffer->replace_glyphs (1, 2, decomposed);
- if (unlikely (buffer->in_error))
- return;
-
- /* Ok, let's see... */
- unsigned int end = buffer->out_len;
- unsigned int start = end - 2;
- while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
- start--;
-
- /* Move Nikhahit (end-2) to the beginning */
- hb_glyph_info_t t = buffer->out_info[end - 2];
- memmove (buffer->out_info + start + 1,
- buffer->out_info + start,
- sizeof (buffer->out_info[0]) * (end - start - 2));
- buffer->out_info[start] = t;
-
- /* XXX Make this easier! */
- /* Make cluster */
- for (; start > 0 && buffer->out_info[start - 1].cluster == buffer->out_info[start].cluster; start--)
- ;
- for (; buffer->idx < count;)
- if (buffer->cur().cluster == buffer->prev().cluster)
- buffer->next_glyph ();
- else
- break;
- end = buffer->out_len;
-
- buffer->merge_out_clusters (start, end);
- }
- buffer->swap_buffers ();
-}
diff --git a/src/hb-ot-shape-complex-myanmar-machine.rl b/src/hb-ot-shape-complex-myanmar-machine.rl
new file mode 100644
index 0000000..9649a91
--- /dev/null
+++ b/src/hb-ot-shape-complex-myanmar-machine.rl
@@ -0,0 +1,128 @@
+/*
+ * Copyright © 2011,2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
+
+#include "hb-private.hh"
+
+%%{
+ machine myanmar_syllable_machine;
+ alphtype unsigned char;
+ write data;
+}%%
+
+%%{
+
+# Same order as enum myanmar_category_t. Not sure how to avoid duplication.
+A = 10;
+As = 18;
+C = 1;
+D = 19;
+D0 = 20;
+DB = 3;
+GB = 11;
+H = 4;
+IV = 2;
+MH = 21;
+MR = 22;
+MW = 23;
+MY = 24;
+PT = 25;
+V = 8;
+VAbv = 26;
+VBlw = 27;
+VPre = 28;
+VPst = 29;
+VS = 30;
+ZWJ = 6;
+ZWNJ = 5;
+Ra = 16;
+P = 31;
+
+j = ZWJ|ZWNJ; # Joiners
+k = (Ra As H); # Kinzi
+
+c = C|Ra; # is_consonant
+
+medial_group = MY? MR? MW? MH? As?;
+main_vowel_group = VPre* VAbv* VBlw* A* (DB As?)?;
+post_vowel_group = VPst MH? As* VAbv* A* (DB As?)?;
+pwo_tone_group = PT A* DB? As?;
+
+complex_syllable_tail = As* medial_group main_vowel_group post_vowel_group* pwo_tone_group* V* j?;
+syllable_tail = (H | complex_syllable_tail);
+
+consonant_syllable = k? (c|IV|D|GB).VS? (H (c|IV).VS?)* syllable_tail;
+punctuation_cluster = P V;
+broken_cluster = k? VS? syllable_tail;
+other = any;
+
+main := |*
+ consonant_syllable => { found_syllable (consonant_syllable); };
+ j => { found_syllable (non_myanmar_cluster); };
+ punctuation_cluster => { found_syllable (punctuation_cluster); };
+ broken_cluster => { found_syllable (broken_cluster); };
+ other => { found_syllable (non_myanmar_cluster); };
+*|;
+
+
+}%%
+
+#define found_syllable(syllable_type) \
+ HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+ for (unsigned int i = last; i < p+1; i++) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ last = p+1; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+ unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+ %%{
+ write init;
+ getkey info[p].myanmar_category();
+ }%%
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int last = 0;
+ unsigned int syllable_serial = 1;
+ %%{
+ write exec;
+ }%%
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-myanmar.cc b/src/hb-ot-shape-complex-myanmar.cc
new file mode 100644
index 0000000..d016380
--- /dev/null
+++ b/src/hb-ot-shape-complex-myanmar.cc
@@ -0,0 +1,571 @@
+/*
+ * Copyright © 2011,2012,2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-indic-private.hh"
+
+/* buffer var allocations */
+#define myanmar_category() complex_var_u8_0() /* myanmar_category_t */
+#define myanmar_position() complex_var_u8_1() /* myanmar_position_t */
+
+
+/*
+ * Myanmar shaper.
+ */
+
+static const hb_tag_t
+basic_features[] =
+{
+ /*
+ * Basic features.
+ * These features are applied in order, one at a time, after initial_reordering.
+ */
+ HB_TAG('r','p','h','f'),
+ HB_TAG('p','r','e','f'),
+ HB_TAG('b','l','w','f'),
+ HB_TAG('p','s','t','f'),
+};
+static const hb_tag_t
+other_features[] =
+{
+ /*
+ * Other features.
+ * These features are applied all at once, after final_reordering.
+ */
+ HB_TAG('p','r','e','s'),
+ HB_TAG('a','b','v','s'),
+ HB_TAG('b','l','w','s'),
+ HB_TAG('p','s','t','s'),
+ /* Positioning features, though we don't care about the types. */
+ HB_TAG('d','i','s','t'),
+ /* Pre-release version of Windows 8 Myanmar font had abvm,blwm
+ * features. The released Windows 8 version of the font (as well
+ * as the released spec) used 'mark' instead. The Windows 8
+ * shaper however didn't apply 'mark' but did apply 'mkmk'.
+ * Perhaps it applied abvm/blwm. This was fixed in a Windows 8
+ * update, so now it applies mark/mkmk. We are guessing that
+ * it still applies abvm/blwm too.
+ */
+ HB_TAG('a','b','v','m'),
+ HB_TAG('b','l','w','m'),
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+static void
+collect_features_myanmar (hb_ot_shape_planner_t *plan)
+{
+ hb_ot_map_builder_t *map = &plan->map;
+
+ /* Do this before any lookups have been applied. */
+ map->add_gsub_pause (setup_syllables);
+
+ map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+ /* The Indic specs do not require ccmp, but we apply it here since if
+ * there is a use of it, it's typically at the beginning. */
+ map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+
+
+ map->add_gsub_pause (initial_reordering);
+ for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+ {
+ map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+ map->add_gsub_pause (NULL);
+ }
+ map->add_gsub_pause (final_reordering);
+ for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+ map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+}
+
+static void
+override_features_myanmar (hb_ot_shape_planner_t *plan)
+{
+ plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+}
+
+
+enum syllable_type_t {
+ consonant_syllable,
+ punctuation_cluster,
+ broken_cluster,
+ non_myanmar_cluster,
+};
+
+#include "hb-ot-shape-complex-myanmar-machine.hh"
+
+
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum myanmar_category_t {
+ OT_As = 18, /* Asat */
+ OT_D = 19, /* Digits except zero */
+ OT_D0 = 20, /* Digit zero */
+ OT_DB = OT_N, /* Dot below */
+ OT_GB = OT_PLACEHOLDER,
+ OT_MH = 21, /* Various consonant medial types */
+ OT_MR = 22, /* Various consonant medial types */
+ OT_MW = 23, /* Various consonant medial types */
+ OT_MY = 24, /* Various consonant medial types */
+ OT_PT = 25, /* Pwo and other tones */
+ OT_VAbv = 26,
+ OT_VBlw = 27,
+ OT_VPre = 28,
+ OT_VPst = 29,
+ OT_VS = 30, /* Variation selectors */
+ OT_P = 31 /* Punctuation */
+};
+
+
+static inline bool
+is_one_of (const hb_glyph_info_t &info, unsigned int flags)
+{
+ /* If it ligated, all bets are off. */
+ if (_hb_glyph_info_ligated (&info)) return false;
+ return !!(FLAG (info.myanmar_category()) & flags);
+}
+
+static inline bool
+is_consonant (const hb_glyph_info_t &info)
+{
+ return is_one_of (info, CONSONANT_FLAGS);
+}
+
+
+static inline void
+set_myanmar_properties (hb_glyph_info_t &info)
+{
+ hb_codepoint_t u = info.codepoint;
+ unsigned int type = hb_indic_get_categories (u);
+ indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+ indic_position_t pos = (indic_position_t) (type >> 8);
+
+ /* Myanmar
+ * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm#analyze
+ */
+ if (unlikely (hb_in_range (u, 0xFE00u, 0xFE0Fu)))
+ cat = (indic_category_t) OT_VS;
+
+ switch (u)
+ {
+ case 0x104Eu:
+ cat = (indic_category_t) OT_C; /* The spec says C, IndicSyllableCategory doesn't have. */
+ break;
+
+ case 0x002Du: case 0x00A0u: case 0x00D7u: case 0x2012u:
+ case 0x2013u: case 0x2014u: case 0x2015u: case 0x2022u:
+ case 0x25CCu: case 0x25FBu: case 0x25FCu: case 0x25FDu:
+ case 0x25FEu:
+ cat = (indic_category_t) OT_GB;
+ break;
+
+ case 0x1004u: case 0x101Bu: case 0x105Au:
+ cat = (indic_category_t) OT_Ra;
+ break;
+
+ case 0x1032u: case 0x1036u:
+ cat = (indic_category_t) OT_A;
+ break;
+
+ case 0x103Au:
+ cat = (indic_category_t) OT_As;
+ break;
+
+ case 0x1041u: case 0x1042u: case 0x1043u: case 0x1044u:
+ case 0x1045u: case 0x1046u: case 0x1047u: case 0x1048u:
+ case 0x1049u: case 0x1090u: case 0x1091u: case 0x1092u:
+ case 0x1093u: case 0x1094u: case 0x1095u: case 0x1096u:
+ case 0x1097u: case 0x1098u: case 0x1099u:
+ cat = (indic_category_t) OT_D;
+ break;
+
+ case 0x1040u:
+ cat = (indic_category_t) OT_D; /* XXX The spec says D0, but Uniscribe doesn't seem to do. */
+ break;
+
+ case 0x103Eu: case 0x1060u:
+ cat = (indic_category_t) OT_MH;
+ break;
+
+ case 0x103Cu:
+ cat = (indic_category_t) OT_MR;
+ break;
+
+ case 0x103Du: case 0x1082u:
+ cat = (indic_category_t) OT_MW;
+ break;
+
+ case 0x103Bu: case 0x105Eu: case 0x105Fu:
+ cat = (indic_category_t) OT_MY;
+ break;
+
+ case 0x1063u: case 0x1064u: case 0x1069u: case 0x106Au:
+ case 0x106Bu: case 0x106Cu: case 0x106Du: case 0xAA7Bu:
+ cat = (indic_category_t) OT_PT;
+ break;
+
+ case 0x1038u: case 0x1087u: case 0x1088u: case 0x1089u:
+ case 0x108Au: case 0x108Bu: case 0x108Cu: case 0x108Du:
+ case 0x108Fu: case 0x109Au: case 0x109Bu: case 0x109Cu:
+ cat = (indic_category_t) OT_SM;
+ break;
+
+ case 0x104Au: case 0x104Bu:
+ cat = (indic_category_t) OT_P;
+ break;
+ }
+
+ if (cat == OT_M)
+ {
+ switch ((int) pos)
+ {
+ case POS_PRE_C: cat = (indic_category_t) OT_VPre;
+ pos = POS_PRE_M; break;
+ case POS_ABOVE_C: cat = (indic_category_t) OT_VAbv; break;
+ case POS_BELOW_C: cat = (indic_category_t) OT_VBlw; break;
+ case POS_POST_C: cat = (indic_category_t) OT_VPst; break;
+ }
+ }
+
+ info.myanmar_category() = (myanmar_category_t) cat;
+ info.myanmar_position() = pos;
+}
+
+
+
+static void
+setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_buffer_t *buffer,
+ hb_font_t *font HB_UNUSED)
+{
+ HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
+ HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
+
+ /* We cannot setup masks here. We save information about characters
+ * and setup masks later on in a pause-callback. */
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ set_myanmar_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ find_syllables (buffer);
+}
+
+static int
+compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+{
+ int a = pa->myanmar_position();
+ int b = pb->myanmar_position();
+
+ return a < b ? -1 : a == b ? 0 : +1;
+}
+
+
+/* Rules from:
+ * http://www.microsoft.com/typography/OpenTypeDev/myanmar/intro.htm */
+
+static void
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+{
+ hb_glyph_info_t *info = buffer->info;
+
+ unsigned int base = end;
+ bool has_reph = false;
+
+ {
+ unsigned int limit = start;
+ if (start + 3 <= end &&
+ info[start ].myanmar_category() == OT_Ra &&
+ info[start+1].myanmar_category() == OT_As &&
+ info[start+2].myanmar_category() == OT_H)
+ {
+ limit += 3;
+ base = start;
+ has_reph = true;
+ }
+
+ {
+ if (!has_reph)
+ base = limit;
+
+ for (unsigned int i = limit; i < end; i++)
+ if (is_consonant (info[i]))
+ {
+ base = i;
+ break;
+ }
+ }
+ }
+
+ /* Reorder! */
+ {
+ unsigned int i = start;
+ for (; i < start + (has_reph ? 3 : 0); i++)
+ info[i].myanmar_position() = POS_AFTER_MAIN;
+ for (; i < base; i++)
+ info[i].myanmar_position() = POS_PRE_C;
+ if (i < end)
+ {
+ info[i].myanmar_position() = POS_BASE_C;
+ i++;
+ }
+ indic_position_t pos = POS_AFTER_MAIN;
+ /* The following loop may be ugly, but it implements all of
+ * Myanmar reordering! */
+ for (; i < end; i++)
+ {
+ if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */
+ {
+ info[i].myanmar_position() = POS_PRE_C;
+ continue;
+ }
+ if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */
+ {
+ continue;
+ }
+
+ if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw)
+ {
+ pos = POS_BELOW_C;
+ info[i].myanmar_position() = pos;
+ continue;
+ }
+
+ if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A)
+ {
+ info[i].myanmar_position() = POS_BEFORE_SUB;
+ continue;
+ }
+ if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw)
+ {
+ info[i].myanmar_position() = pos;
+ continue;
+ }
+ if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
+ {
+ pos = POS_AFTER_SUB;
+ info[i].myanmar_position() = pos;
+ continue;
+ }
+ info[i].myanmar_position() = pos;
+ }
+ }
+
+ buffer->merge_clusters (start, end);
+ /* Sit tight, rock 'n roll! */
+ hb_bubble_sort (info + start, end - start, compare_myanmar_order);
+}
+
+static void
+initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+{
+ /* We already inserted dotted-circles, so just call the consonant_syllable. */
+ initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+}
+
+static void
+initial_reordering_punctuation_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ hb_buffer_t *buffer HB_UNUSED,
+ unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+ /* Nothing to do right now. If we ever switch to using the output
+ * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+static void
+initial_reordering_non_myanmar_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ hb_buffer_t *buffer HB_UNUSED,
+ unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+ /* Nothing to do right now. If we ever switch to using the output
+ * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+
+static void
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+{
+ syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+ switch (syllable_type) {
+ case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+ case punctuation_cluster: initial_reordering_punctuation_cluster (plan, face, buffer, start, end); return;
+ case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
+ case non_myanmar_cluster: initial_reordering_non_myanmar_cluster (plan, face, buffer, start, end); return;
+ }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ /* Note: This loop is extra overhead, but should not be measurable. */
+ bool has_broken_syllables = false;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if ((info[i].syllable() & 0x0F) == broken_cluster)
+ {
+ has_broken_syllables = true;
+ break;
+ }
+ if (likely (!has_broken_syllables))
+ return;
+
+
+ hb_codepoint_t dottedcircle_glyph;
+ if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+ return;
+
+ hb_glyph_info_t dottedcircle = {0};
+ dottedcircle.codepoint = 0x25CCu;
+ set_myanmar_properties (dottedcircle);
+ dottedcircle.codepoint = dottedcircle_glyph;
+
+ buffer->clear_output ();
+
+ buffer->idx = 0;
+ unsigned int last_syllable = 0;
+ while (buffer->idx < buffer->len)
+ {
+ unsigned int syllable = buffer->cur().syllable();
+ syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+ if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+ {
+ last_syllable = syllable;
+
+ hb_glyph_info_t info = dottedcircle;
+ info.cluster = buffer->cur().cluster;
+ info.mask = buffer->cur().mask;
+ info.syllable() = buffer->cur().syllable();
+
+ buffer->output_info (info);
+ }
+ else
+ buffer->next_glyph ();
+ }
+
+ buffer->swap_buffers ();
+}
+
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ insert_dotted_circles (plan, font, buffer);
+
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+ if (unlikely (!count)) return;
+ unsigned int last = 0;
+ unsigned int last_syllable = info[0].syllable();
+ for (unsigned int i = 1; i < count; i++)
+ if (last_syllable != info[i].syllable()) {
+ initial_reordering_syllable (plan, font->face, buffer, last, i);
+ last = i;
+ last_syllable = info[last].syllable();
+ }
+ initial_reordering_syllable (plan, font->face, buffer, last, count);
+}
+
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+
+ /* Zero syllables now... */
+ for (unsigned int i = 0; i < count; i++)
+ info[i].syllable() = 0;
+
+ HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
+ HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
+}
+
+
+/* Uniscribe seems to have a shaper for 'mymr' that is like the
+ * generic shaper, except that it zeros mark advances GDEF_LATE. */
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_old =
+{
+ "default",
+ NULL, /* collect_features */
+ NULL, /* override_features */
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+ true, /* fallback_position */
+};
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
+{
+ "myanmar",
+ collect_features_myanmar,
+ override_features_myanmar,
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ setup_masks_myanmar,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+ false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-private.hh b/src/hb-ot-shape-complex-private.hh
index e0d93a6..e268933 100644
--- a/src/hb-ot-shape-complex-private.hh
+++ b/src/hb-ot-shape-complex-private.hh
@@ -29,78 +29,188 @@
#include "hb-private.hh"
-#include "hb-ot-map-private.hh"
+#include "hb-ot-shape-private.hh"
#include "hb-ot-shape-normalize-private.hh"
-/* buffer var allocations, used during the entire shaping process */
-#define unicode_props0() var1.u8[0]
-#define unicode_props1() var1.u8[1]
+/* buffer var allocations, used by complex shapers */
+#define complex_var_u8_0() var2.u8[2]
+#define complex_var_u8_1() var2.u8[3]
-/* buffer var allocations, used during the GSUB/GPOS processing */
-#define props_cache() var1.u16[1] /* GSUB/GPOS glyph_props cache */
-#define syllable() var2.u8[0] /* GSUB/GPOS shaping boundaries */
-#define lig_props() var2.u8[1] /* GSUB/GPOS ligature tracking */
-/* buffer var allocations, used by complex shapers */
-#define complex_var_persistent_u8_0() var2.u8[2]
-#define complex_var_persistent_u8_1() var2.u8[3]
-#define complex_var_temporary_u8() var2.u8[0]
+enum hb_ot_shape_zero_width_marks_type_t {
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+// HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
+
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
+};
+/* Master OT shaper list */
#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_old) \
HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
+ HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
/* ^--- Add new shapers here */
-enum hb_ot_complex_shaper_t {
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) hb_ot_complex_shaper_##name,
- HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
- /* Just here to avoid enum trailing comma: */
- hb_ot_complex_shaper_generic = hb_ot_complex_shaper_default
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+
+struct hb_ot_complex_shaper_t
+{
+ char name[8];
+
+ /* collect_features()
+ * Called during shape_plan().
+ * Shapers should use plan->map to add their features and callbacks.
+ * May be NULL.
+ */
+ void (*collect_features) (hb_ot_shape_planner_t *plan);
+
+ /* override_features()
+ * Called during shape_plan().
+ * Shapers should use plan->map to override features and add callbacks after
+ * common features are added.
+ * May be NULL.
+ */
+ void (*override_features) (hb_ot_shape_planner_t *plan);
+
+
+ /* data_create()
+ * Called at the end of shape_plan().
+ * Whatever shapers return will be accessible through plan->data later.
+ * If NULL is returned, means a plan failure.
+ */
+ void *(*data_create) (const hb_ot_shape_plan_t *plan);
+
+ /* data_destroy()
+ * Called when the shape_plan is being destroyed.
+ * plan->data is passed here for destruction.
+ * If NULL is returned, means a plan failure.
+ * May be NULL.
+ */
+ void (*data_destroy) (void *data);
+
+
+ /* preprocess_text()
+ * Called during shape().
+ * Shapers can use to modify text before shaping starts.
+ * May be NULL.
+ */
+ void (*preprocess_text) (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font);
+
+
+ hb_ot_shape_normalization_mode_t normalization_preference;
+
+ /* decompose()
+ * Called during shape()'s normalization.
+ * May be NULL.
+ */
+ bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b);
+
+ /* compose()
+ * Called during shape()'s normalization.
+ * May be NULL.
+ */
+ bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab);
+
+ /* setup_masks()
+ * Called during shape().
+ * Shapers should use map to get feature masks and set on buffer.
+ * Shapers may NOT modify characters.
+ * May be NULL.
+ */
+ void (*setup_masks) (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font);
+
+ hb_ot_shape_zero_width_marks_type_t zero_width_marks;
+
+ bool fallback_position;
};
-static inline hb_ot_complex_shaper_t
-hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
+#define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name;
+HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
+#undef HB_COMPLEX_SHAPER_IMPLEMENT
+
+
+static inline const hb_ot_complex_shaper_t *
+hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
{
- switch ((hb_tag_t) props->script)
+ switch ((hb_tag_t) planner->props.script)
{
default:
- return hb_ot_complex_shaper_default;
+ return &_hb_ot_complex_shaper_default;
/* Unicode-1.1 additions */
case HB_SCRIPT_ARABIC:
+
+ /* Unicode-3.0 additions */
case HB_SCRIPT_MONGOLIAN:
case HB_SCRIPT_SYRIAC:
/* Unicode-5.0 additions */
case HB_SCRIPT_NKO:
+ case HB_SCRIPT_PHAGS_PA:
/* Unicode-6.0 additions */
case HB_SCRIPT_MANDAIC:
- return hb_ot_complex_shaper_arabic;
+ /* Unicode-7.0 additions */
+ case HB_SCRIPT_MANICHAEAN:
+ case HB_SCRIPT_PSALTER_PAHLAVI:
+
+ /* For Arabic script, use the Arabic shaper even if no OT script tag was found.
+ * This is because we do fallback shaping for Arabic script (and not others). */
+ if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
+ planner->props.script == HB_SCRIPT_ARABIC)
+ return &_hb_ot_complex_shaper_arabic;
+ else
+ return &_hb_ot_complex_shaper_default;
/* Unicode-1.1 additions */
- case HB_SCRIPT_HANGUL:
+ case HB_SCRIPT_THAI:
+ case HB_SCRIPT_LAO:
- return hb_ot_complex_shaper_hangul;
+ return &_hb_ot_complex_shaper_thai;
/* Unicode-1.1 additions */
- case HB_SCRIPT_THAI:
- case HB_SCRIPT_LAO:
+ case HB_SCRIPT_HANGUL:
- return hb_ot_complex_shaper_thai;
+ return &_hb_ot_complex_shaper_hangul;
+ /* Unicode-2.0 additions */
+ case HB_SCRIPT_TIBETAN:
+
+ return &_hb_ot_complex_shaper_tibetan;
+
+
+ /* Unicode-1.1 additions */
+ case HB_SCRIPT_HEBREW:
+
+ return &_hb_ot_complex_shaper_hebrew;
+
/* ^--- Add new shapers here */
@@ -127,9 +237,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
/* Unicode-5.1 additions */
case HB_SCRIPT_SAURASHTRA:
- /* Unicode-5.2 additions */
- case HB_SCRIPT_MEETEI_MAYEK:
-
/* Unicode-6.0 additions */
case HB_SCRIPT_BATAK:
case HB_SCRIPT_BRAHMI:
@@ -142,9 +249,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
case HB_SCRIPT_LAO:
case HB_SCRIPT_THAI:
- /* Unicode-2.0 additions */
- case HB_SCRIPT_TIBETAN:
-
/* Unicode-3.2 additions */
case HB_SCRIPT_TAGALOG:
case HB_SCRIPT_TAGBANWA:
@@ -154,11 +258,10 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
case HB_SCRIPT_TAI_LE:
/* Unicode-4.1 additions */
+ case HB_SCRIPT_KHAROSHTHI:
+ case HB_SCRIPT_NEW_TAI_LUE:
case HB_SCRIPT_SYLOTI_NAGRI:
- /* Unicode-5.0 additions */
- case HB_SCRIPT_PHAGS_PA:
-
/* Unicode-5.1 additions */
case HB_SCRIPT_KAYAH_LI:
@@ -166,12 +269,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
case HB_SCRIPT_TAI_VIET:
- /* May need Indic treatment in the future? */
-
- /* Unicode-3.0 additions */
- case HB_SCRIPT_MYANMAR:
-
-
#endif
/* Unicode-1.1 additions */
@@ -186,19 +283,12 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
case HB_SCRIPT_TELUGU:
/* Unicode-3.0 additions */
- case HB_SCRIPT_KHMER:
case HB_SCRIPT_SINHALA:
- /* Unicode-4.1 additions */
- case HB_SCRIPT_BUGINESE:
- case HB_SCRIPT_KHAROSHTHI:
- case HB_SCRIPT_NEW_TAI_LUE:
-
/* Unicode-5.0 additions */
case HB_SCRIPT_BALINESE:
/* Unicode-5.1 additions */
- case HB_SCRIPT_CHAM:
case HB_SCRIPT_LEPCHA:
case HB_SCRIPT_REJANG:
case HB_SCRIPT_SUNDANESE:
@@ -206,105 +296,67 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props)
/* Unicode-5.2 additions */
case HB_SCRIPT_JAVANESE:
case HB_SCRIPT_KAITHI:
- case HB_SCRIPT_TAI_THAM:
+ case HB_SCRIPT_MEETEI_MAYEK:
+
+ /* Unicode-6.0 additions */
/* Unicode-6.1 additions */
case HB_SCRIPT_CHAKMA:
case HB_SCRIPT_SHARADA:
case HB_SCRIPT_TAKRI:
- return hb_ot_complex_shaper_indic;
-
- /* ^--- Add new shapers here */
- }
-}
-
-
-
-/*
- * collect_features()
- *
- * Called during shape_plan().
- *
- * Shapers should use map to add their features and callbacks.
- */
-
-typedef void hb_ot_shape_complex_collect_features_func_t (hb_ot_map_builder_t *map, const hb_segment_properties_t *props);
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
- HB_INTERNAL hb_ot_shape_complex_collect_features_func_t _hb_ot_shape_complex_collect_features_##name;
- HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+ /* If the designer designed the font for the 'DFLT' script,
+ * use the default shaper. Otherwise, use the Indic shaper.
+ * Note that for some simple scripts, there may not be *any*
+ * GSUB/GPOS needed, so there may be no scripts found! */
+ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+ return &_hb_ot_complex_shaper_default;
+ else
+ return &_hb_ot_complex_shaper_indic;
-static inline void
-hb_ot_shape_complex_collect_features (hb_ot_complex_shaper_t shaper,
- hb_ot_map_builder_t *map,
- const hb_segment_properties_t *props)
-{
- switch (shaper) {
- default:
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
- case hb_ot_complex_shaper_##name: _hb_ot_shape_complex_collect_features_##name (map, props); return;
- HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
- }
-}
-
-
-/*
- * normalization_preference()
- *
- * Called during shape_execute().
- *
- * Shapers should return true if it prefers decomposed (NFD) input rather than precomposed (NFC).
- */
-
-typedef hb_ot_shape_normalization_mode_t hb_ot_shape_complex_normalization_preference_func_t (void);
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
- HB_INTERNAL hb_ot_shape_complex_normalization_preference_func_t _hb_ot_shape_complex_normalization_preference_##name;
- HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+ case HB_SCRIPT_KHMER:
+ /* A number of Khmer fonts in the wild don't have a 'pref' feature,
+ * and as such won't shape properly via the Indic shaper;
+ * however, they typically have 'liga' / 'clig' features that implement
+ * the necessary "reordering" by means of ligature substitutions.
+ * So we send such pref-less fonts through the generic shaper instead. */
+ if (planner->map.found_script[0] &&
+ hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB,
+ planner->map.script_index[0],
+ planner->map.language_index[0],
+ HB_TAG ('p','r','e','f'),
+ NULL))
+ return &_hb_ot_complex_shaper_indic;
+ else
+ return &_hb_ot_complex_shaper_default;
-static inline hb_ot_shape_normalization_mode_t
-hb_ot_shape_complex_normalization_preference (hb_ot_complex_shaper_t shaper)
-{
- switch (shaper) {
- default:
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
- case hb_ot_complex_shaper_##name: return _hb_ot_shape_complex_normalization_preference_##name ();
- HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
- }
-}
+ case HB_SCRIPT_MYANMAR:
+ if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
+ return &_hb_ot_complex_shaper_myanmar;
+ else if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
+ return &_hb_ot_complex_shaper_myanmar_old;
+ else
+ return &_hb_ot_complex_shaper_default;
+ /* Unicode-4.1 additions */
+ case HB_SCRIPT_BUGINESE:
-/* setup_masks()
- *
- * Called during shape_execute().
- *
- * Shapers should use map to get feature masks and set on buffer.
- */
+ /* Unicode-5.1 additions */
+ case HB_SCRIPT_CHAM:
-typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font);
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
- HB_INTERNAL hb_ot_shape_complex_setup_masks_func_t _hb_ot_shape_complex_setup_masks_##name;
- HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+ /* Unicode-5.2 additions */
+ case HB_SCRIPT_TAI_THAM:
-static inline void
-hb_ot_shape_complex_setup_masks (hb_ot_complex_shaper_t shaper,
- hb_ot_map_t *map,
- hb_buffer_t *buffer,
- hb_font_t *font)
-{
- switch (shaper) {
- default:
-#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \
- case hb_ot_complex_shaper_##name: _hb_ot_shape_complex_setup_masks_##name (map, buffer, font); return;
- HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS
-#undef HB_COMPLEX_SHAPER_IMPLEMENT
+ /* If the designer designed the font for the 'DFLT' script,
+ * use the default shaper. Otherwise, use the Indic shaper.
+ * Note that for some simple scripts, there may not be *any*
+ * GSUB/GPOS needed, so there may be no scripts found! */
+ if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T'))
+ return &_hb_ot_complex_shaper_default;
+ else
+ return &_hb_ot_complex_shaper_sea;
}
}
-
#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */
diff --git a/src/hb-ot-shape-complex-sea-machine.rl b/src/hb-ot-shape-complex-sea-machine.rl
new file mode 100644
index 0000000..46140fc
--- /dev/null
+++ b/src/hb-ot-shape-complex-sea-machine.rl
@@ -0,0 +1,102 @@
+/*
+ * Copyright © 2011,2012,2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+#define HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH
+
+#include "hb-private.hh"
+
+%%{
+ machine sea_syllable_machine;
+ alphtype unsigned char;
+ write data;
+}%%
+
+%%{
+
+# Same order as enum sea_category_t. Not sure how to avoid duplication.
+C = 1;
+GB = 12; # Generic Base
+H = 4; # Halant
+IV = 2; # Independent Vowel
+MR = 22; # Medial Ra
+CM = 17; # Consonant Medial
+VAbv = 26;
+VBlw = 27;
+VPre = 28;
+VPst = 29;
+T = 3; # Tone Marks
+A = 10; # Anusvara
+
+syllable_tail = (VPre|VAbv|VBlw|VPst|H.C|CM|MR|T|A)*;
+
+consonant_syllable = (C|IV|GB) syllable_tail;
+broken_cluster = syllable_tail;
+other = any;
+
+main := |*
+ consonant_syllable => { found_syllable (consonant_syllable); };
+ broken_cluster => { found_syllable (broken_cluster); };
+ other => { found_syllable (non_sea_cluster); };
+*|;
+
+
+}%%
+
+#define found_syllable(syllable_type) \
+ HB_STMT_START { \
+ if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
+ for (unsigned int i = last; i < p+1; i++) \
+ info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+ last = p+1; \
+ syllable_serial++; \
+ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+ } HB_STMT_END
+
+static void
+find_syllables (hb_buffer_t *buffer)
+{
+ unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED;
+ int cs;
+ hb_glyph_info_t *info = buffer->info;
+ %%{
+ write init;
+ getkey info[p].sea_category();
+ }%%
+
+ p = 0;
+ pe = eof = buffer->len;
+
+ unsigned int last = 0;
+ unsigned int syllable_serial = 1;
+ %%{
+ write exec;
+ }%%
+}
+
+#undef found_syllable
+
+#endif /* HB_OT_SHAPE_COMPLEX_SEA_MACHINE_HH */
diff --git a/src/hb-ot-shape-complex-sea.cc b/src/hb-ot-shape-complex-sea.cc
new file mode 100644
index 0000000..f08b7cc
--- /dev/null
+++ b/src/hb-ot-shape-complex-sea.cc
@@ -0,0 +1,380 @@
+/*
+ * Copyright © 2011,2012,2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-indic-private.hh"
+
+/* buffer var allocations */
+#define sea_category() complex_var_u8_0() /* indic_category_t */
+#define sea_position() complex_var_u8_1() /* indic_position_t */
+
+
+/*
+ * South-East Asian shaper.
+ * Loosely based on the Myanmar spec / shaper.
+ * There is no OpenType spec for this.
+ */
+
+static const hb_tag_t
+basic_features[] =
+{
+ /*
+ * Basic features.
+ * These features are applied in order, one at a time, after initial_reordering.
+ */
+ HB_TAG('p','r','e','f'),
+ HB_TAG('a','b','v','f'),
+ HB_TAG('b','l','w','f'),
+ HB_TAG('p','s','t','f'),
+};
+static const hb_tag_t
+other_features[] =
+{
+ /*
+ * Other features.
+ * These features are applied all at once, after final_reordering.
+ */
+ HB_TAG('p','r','e','s'),
+ HB_TAG('a','b','v','s'),
+ HB_TAG('b','l','w','s'),
+ HB_TAG('p','s','t','s'),
+ /* Positioning features, though we don't care about the types. */
+ HB_TAG('d','i','s','t'),
+};
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+static void
+collect_features_sea (hb_ot_shape_planner_t *plan)
+{
+ hb_ot_map_builder_t *map = &plan->map;
+
+ /* Do this before any lookups have been applied. */
+ map->add_gsub_pause (setup_syllables);
+
+ map->add_global_bool_feature (HB_TAG('l','o','c','l'));
+ /* The Indic specs do not require ccmp, but we apply it here since if
+ * there is a use of it, it's typically at the beginning. */
+ map->add_global_bool_feature (HB_TAG('c','c','m','p'));
+
+ map->add_gsub_pause (initial_reordering);
+ for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++)
+ {
+ map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+ map->add_gsub_pause (NULL);
+ }
+ map->add_gsub_pause (final_reordering);
+ for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++)
+ map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ);
+}
+
+static void
+override_features_sea (hb_ot_shape_planner_t *plan)
+{
+ plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL);
+}
+
+
+enum syllable_type_t {
+ consonant_syllable,
+ broken_cluster,
+ non_sea_cluster,
+};
+
+#include "hb-ot-shape-complex-sea-machine.hh"
+
+
+/* Note: This enum is duplicated in the -machine.rl source file.
+ * Not sure how to avoid duplication. */
+enum sea_category_t {
+// OT_C = 1,
+ OT_GB = 12, /* Generic Base XXX DOTTED CIRCLE only for now */
+// OT_H = 4, /* Halant */
+ OT_IV = 2, /* Independent Vowel */
+ OT_MR = 22, /* Medial Ra */
+// OT_CM = 17, /* Consonant Medial */
+ OT_VAbv = 26,
+ OT_VBlw = 27,
+ OT_VPre = 28,
+ OT_VPst = 29,
+ OT_T = 3, /* Tone Marks */
+// OT_A = 10, /* Anusvara */
+};
+
+static inline void
+set_sea_properties (hb_glyph_info_t &info)
+{
+ hb_codepoint_t u = info.codepoint;
+ unsigned int type = hb_indic_get_categories (u);
+ indic_category_t cat = (indic_category_t) (type & 0x7Fu);
+ indic_position_t pos = (indic_position_t) (type >> 8);
+
+ /* Medial Ra */
+ if (u == 0x1A55u || u == 0xAA34u)
+ cat = (indic_category_t) OT_MR;
+
+ if (cat == OT_M)
+ {
+ switch ((int) pos)
+ {
+ case POS_PRE_C: cat = (indic_category_t) OT_VPre; break;
+ case POS_ABOVE_C: cat = (indic_category_t) OT_VAbv; break;
+ case POS_BELOW_C: cat = (indic_category_t) OT_VBlw; break;
+ case POS_POST_C: cat = (indic_category_t) OT_VPst; break;
+ }
+ }
+
+ info.sea_category() = (sea_category_t) cat;
+ info.sea_position() = pos;
+}
+
+
+static void
+setup_masks_sea (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_buffer_t *buffer,
+ hb_font_t *font HB_UNUSED)
+{
+ HB_BUFFER_ALLOCATE_VAR (buffer, sea_category);
+ HB_BUFFER_ALLOCATE_VAR (buffer, sea_position);
+
+ /* We cannot setup masks here. We save information about characters
+ * and setup masks later on in a pause-callback. */
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ set_sea_properties (info[i]);
+}
+
+static void
+setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ find_syllables (buffer);
+}
+
+static int
+compare_sea_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
+{
+ int a = pa->sea_position();
+ int b = pb->sea_position();
+
+ return a < b ? -1 : a == b ? 0 : +1;
+}
+
+
+static void
+initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+{
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int base = start;
+
+ /* Reorder! */
+ unsigned int i = start;
+ for (; i < base; i++)
+ info[i].sea_position() = POS_PRE_C;
+ if (i < end)
+ {
+ info[i].sea_position() = POS_BASE_C;
+ i++;
+ }
+ for (; i < end; i++)
+ {
+ if (info[i].sea_category() == OT_MR) /* Pre-base reordering */
+ {
+ info[i].sea_position() = POS_PRE_C;
+ continue;
+ }
+ if (info[i].sea_category() == OT_VPre) /* Left matra */
+ {
+ info[i].sea_position() = POS_PRE_M;
+ continue;
+ }
+
+ info[i].sea_position() = POS_AFTER_MAIN;
+ }
+
+ buffer->merge_clusters (start, end);
+ /* Sit tight, rock 'n roll! */
+ hb_bubble_sort (info + start, end - start, compare_sea_order);
+}
+
+static void
+initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+{
+ /* We already inserted dotted-circles, so just call the consonant_syllable. */
+ initial_reordering_consonant_syllable (plan, face, buffer, start, end);
+}
+
+static void
+initial_reordering_non_sea_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ hb_buffer_t *buffer HB_UNUSED,
+ unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
+{
+ /* Nothing to do right now. If we ever switch to using the output
+ * buffer in the reordering process, we'd need to next_glyph() here. */
+}
+
+
+static void
+initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ unsigned int start, unsigned int end)
+{
+ syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F);
+ switch (syllable_type) {
+ case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return;
+ case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return;
+ case non_sea_cluster: initial_reordering_non_sea_cluster (plan, face, buffer, start, end); return;
+ }
+}
+
+static inline void
+insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ /* Note: This loop is extra overhead, but should not be measurable. */
+ bool has_broken_syllables = false;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if ((info[i].syllable() & 0x0F) == broken_cluster)
+ {
+ has_broken_syllables = true;
+ break;
+ }
+ if (likely (!has_broken_syllables))
+ return;
+
+
+ hb_codepoint_t dottedcircle_glyph;
+ if (!font->get_glyph (0x25CCu, 0, &dottedcircle_glyph))
+ return;
+
+ hb_glyph_info_t dottedcircle = {0};
+ dottedcircle.codepoint = 0x25CCu;
+ set_sea_properties (dottedcircle);
+ dottedcircle.codepoint = dottedcircle_glyph;
+
+ buffer->clear_output ();
+
+ buffer->idx = 0;
+ unsigned int last_syllable = 0;
+ while (buffer->idx < buffer->len)
+ {
+ unsigned int syllable = buffer->cur().syllable();
+ syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
+ if (unlikely (last_syllable != syllable && syllable_type == broken_cluster))
+ {
+ last_syllable = syllable;
+
+ hb_glyph_info_t info = dottedcircle;
+ info.cluster = buffer->cur().cluster;
+ info.mask = buffer->cur().mask;
+ info.syllable() = buffer->cur().syllable();
+
+ buffer->output_info (info);
+ }
+ else
+ buffer->next_glyph ();
+ }
+
+ buffer->swap_buffers ();
+}
+
+static void
+initial_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ insert_dotted_circles (plan, font, buffer);
+
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+ if (unlikely (!count)) return;
+ unsigned int last = 0;
+ unsigned int last_syllable = info[0].syllable();
+ for (unsigned int i = 1; i < count; i++)
+ if (last_syllable != info[i].syllable()) {
+ initial_reordering_syllable (plan, font->face, buffer, last, i);
+ last = i;
+ last_syllable = info[last].syllable();
+ }
+ initial_reordering_syllable (plan, font->face, buffer, last, count);
+}
+
+static void
+final_reordering (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+
+ /* Zero syllables now... */
+ for (unsigned int i = 0; i < count; i++)
+ info[i].syllable() = 0;
+
+ HB_BUFFER_DEALLOCATE_VAR (buffer, sea_category);
+ HB_BUFFER_DEALLOCATE_VAR (buffer, sea_position);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
+{
+ "sea",
+ collect_features_sea,
+ override_features_sea,
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ setup_masks_sea,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+ false, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-thai.cc b/src/hb-ot-shape-complex-thai.cc
new file mode 100644
index 0000000..feb7fc7
--- /dev/null
+++ b/src/hb-ot-shape-complex-thai.cc
@@ -0,0 +1,381 @@
+/*
+ * Copyright © 2010,2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+/* Thai / Lao shaper */
+
+
+/* PUA shaping */
+
+
+enum thai_consonant_type_t
+{
+ NC,
+ AC,
+ RC,
+ DC,
+ NOT_CONSONANT,
+ NUM_CONSONANT_TYPES = NOT_CONSONANT
+};
+
+static thai_consonant_type_t
+get_consonant_type (hb_codepoint_t u)
+{
+ if (u == 0x0E1Bu || u == 0x0E1Du || u == 0x0E1Fu/* || u == 0x0E2Cu*/)
+ return AC;
+ if (u == 0x0E0Du || u == 0x0E10u)
+ return RC;
+ if (u == 0x0E0Eu || u == 0x0E0Fu)
+ return DC;
+ if (hb_in_range (u, 0x0E01u, 0x0E2Eu))
+ return NC;
+ return NOT_CONSONANT;
+}
+
+
+enum thai_mark_type_t
+{
+ AV,
+ BV,
+ T,
+ NOT_MARK,
+ NUM_MARK_TYPES = NOT_MARK
+};
+
+static thai_mark_type_t
+get_mark_type (hb_codepoint_t u)
+{
+ if (u == 0x0E31u || hb_in_range (u, 0x0E34u, 0x0E37u) ||
+ u == 0x0E47u || hb_in_range (u, 0x0E4Du, 0x0E4Eu))
+ return AV;
+ if (hb_in_range (u, 0x0E38u, 0x0E3Au))
+ return BV;
+ if (hb_in_range (u, 0x0E48u, 0x0E4Cu))
+ return T;
+ return NOT_MARK;
+}
+
+
+enum thai_action_t
+{
+ NOP,
+ SD, /* Shift combining-mark down */
+ SL, /* Shift combining-mark left */
+ SDL, /* Shift combining-mark down-left */
+ RD /* Remove descender from base */
+};
+
+static hb_codepoint_t
+thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font)
+{
+ struct thai_pua_mapping_t {
+ hb_codepoint_t u;
+ hb_codepoint_t win_pua;
+ hb_codepoint_t mac_pua;
+ } const *pua_mappings = NULL;
+ static const thai_pua_mapping_t SD_mappings[] = {
+ {0x0E48u, 0xF70Au, 0xF88Bu}, /* MAI EK */
+ {0x0E49u, 0xF70Bu, 0xF88Eu}, /* MAI THO */
+ {0x0E4Au, 0xF70Cu, 0xF891u}, /* MAI TRI */
+ {0x0E4Bu, 0xF70Du, 0xF894u}, /* MAI CHATTAWA */
+ {0x0E4Cu, 0xF70Eu, 0xF897u}, /* THANTHAKHAT */
+ {0x0E38u, 0xF718u, 0xF89Bu}, /* SARA U */
+ {0x0E39u, 0xF719u, 0xF89Cu}, /* SARA UU */
+ {0x0E3Au, 0xF71Au, 0xF89Du}, /* PHINTHU */
+ {0x0000u, 0x0000u, 0x0000u}
+ };
+ static const thai_pua_mapping_t SDL_mappings[] = {
+ {0x0E48u, 0xF705u, 0xF88Cu}, /* MAI EK */
+ {0x0E49u, 0xF706u, 0xF88Fu}, /* MAI THO */
+ {0x0E4Au, 0xF707u, 0xF892u}, /* MAI TRI */
+ {0x0E4Bu, 0xF708u, 0xF895u}, /* MAI CHATTAWA */
+ {0x0E4Cu, 0xF709u, 0xF898u}, /* THANTHAKHAT */
+ {0x0000u, 0x0000u, 0x0000u}
+ };
+ static const thai_pua_mapping_t SL_mappings[] = {
+ {0x0E48u, 0xF713u, 0xF88Au}, /* MAI EK */
+ {0x0E49u, 0xF714u, 0xF88Du}, /* MAI THO */
+ {0x0E4Au, 0xF715u, 0xF890u}, /* MAI TRI */
+ {0x0E4Bu, 0xF716u, 0xF893u}, /* MAI CHATTAWA */
+ {0x0E4Cu, 0xF717u, 0xF896u}, /* THANTHAKHAT */
+ {0x0E31u, 0xF710u, 0xF884u}, /* MAI HAN-AKAT */
+ {0x0E34u, 0xF701u, 0xF885u}, /* SARA I */
+ {0x0E35u, 0xF702u, 0xF886u}, /* SARA II */
+ {0x0E36u, 0xF703u, 0xF887u}, /* SARA UE */
+ {0x0E37u, 0xF704u, 0xF888u}, /* SARA UEE */
+ {0x0E47u, 0xF712u, 0xF889u}, /* MAITAIKHU */
+ {0x0E4Du, 0xF711u, 0xF899u}, /* NIKHAHIT */
+ {0x0000u, 0x0000u, 0x0000u}
+ };
+ static const thai_pua_mapping_t RD_mappings[] = {
+ {0x0E0Du, 0xF70Fu, 0xF89Au}, /* YO YING */
+ {0x0E10u, 0xF700u, 0xF89Eu}, /* THO THAN */
+ {0x0000u, 0x0000u, 0x0000u}
+ };
+
+ switch (action) {
+ default: assert (false); /* Fallthrough */
+ case NOP: return u;
+ case SD: pua_mappings = SD_mappings; break;
+ case SDL: pua_mappings = SDL_mappings; break;
+ case SL: pua_mappings = SL_mappings; break;
+ case RD: pua_mappings = RD_mappings; break;
+ }
+ for (; pua_mappings->u; pua_mappings++)
+ if (pua_mappings->u == u)
+ {
+ hb_codepoint_t glyph;
+ if (hb_font_get_glyph (font, pua_mappings->win_pua, 0, &glyph))
+ return pua_mappings->win_pua;
+ if (hb_font_get_glyph (font, pua_mappings->mac_pua, 0, &glyph))
+ return pua_mappings->mac_pua;
+ break;
+ }
+ return u;
+}
+
+
+static enum thai_above_state_t
+{ /* Cluster above looks like: */
+ T0, /* ⣤ */
+ T1, /* ⣼ */
+ T2, /* ⣾ */
+ T3, /* ⣿ */
+ NUM_ABOVE_STATES
+} thai_above_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+ T0, /* NC */
+ T1, /* AC */
+ T0, /* RC */
+ T0, /* DC */
+ T3, /* NOT_CONSONANT */
+};
+
+static const struct thai_above_state_machine_edge_t {
+ thai_action_t action;
+ thai_above_state_t next_state;
+} thai_above_state_machine[NUM_ABOVE_STATES][NUM_MARK_TYPES] =
+{ /*AV*/ /*BV*/ /*T*/
+/*T0*/ {{NOP,T3}, {NOP,T0}, {SD, T3}},
+/*T1*/ {{SL, T2}, {NOP,T1}, {SDL,T2}},
+/*T2*/ {{NOP,T3}, {NOP,T2}, {SL, T3}},
+/*T3*/ {{NOP,T3}, {NOP,T3}, {NOP,T3}},
+};
+
+
+static enum thai_below_state_t
+{
+ B0, /* No descender */
+ B1, /* Removable descender */
+ B2, /* Strict descender */
+ NUM_BELOW_STATES
+} thai_below_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] =
+{
+ B0, /* NC */
+ B0, /* AC */
+ B1, /* RC */
+ B2, /* DC */
+ B2, /* NOT_CONSONANT */
+};
+
+static const struct thai_below_state_machine_edge_t {
+ thai_action_t action;
+ thai_below_state_t next_state;
+} thai_below_state_machine[NUM_BELOW_STATES][NUM_MARK_TYPES] =
+{ /*AV*/ /*BV*/ /*T*/
+/*B0*/ {{NOP,B0}, {NOP,B2}, {NOP, B0}},
+/*B1*/ {{NOP,B1}, {RD, B2}, {NOP, B1}},
+/*B2*/ {{NOP,B2}, {SD, B2}, {NOP, B2}},
+};
+
+
+static void
+do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_buffer_t *buffer,
+ hb_font_t *font)
+{
+ thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT];
+ thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT];
+ unsigned int base = 0;
+
+ hb_glyph_info_t *info = buffer->info;
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ thai_mark_type_t mt = get_mark_type (info[i].codepoint);
+
+ if (mt == NOT_MARK) {
+ thai_consonant_type_t ct = get_consonant_type (info[i].codepoint);
+ above_state = thai_above_start_state[ct];
+ below_state = thai_below_start_state[ct];
+ base = i;
+ continue;
+ }
+
+ const thai_above_state_machine_edge_t &above_edge = thai_above_state_machine[above_state][mt];
+ const thai_below_state_machine_edge_t &below_edge = thai_below_state_machine[below_state][mt];
+ above_state = above_edge.next_state;
+ below_state = below_edge.next_state;
+
+ /* At least one of the above/below actions is NOP. */
+ thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action;
+
+ if (action == RD)
+ info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font);
+ else
+ info[i].codepoint = thai_pua_shape (info[i].codepoint, action, font);
+ }
+}
+
+
+static void
+preprocess_text_thai (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font)
+{
+ /* This function implements the shaping logic documented here:
+ *
+ * http://linux.thai.net/~thep/th-otf/shaping.html
+ *
+ * The first shaping rule listed there is needed even if the font has Thai
+ * OpenType tables. The rest do fallback positioning based on PUA codepoints.
+ * We implement that only if there exist no Thai GSUB in the font.
+ */
+
+ /* The following is NOT specified in the MS OT Thai spec, however, it seems
+ * to be what Uniscribe and other engines implement. According to Eric Muller:
+ *
+ * When you have a SARA AM, decompose it in NIKHAHIT + SARA AA, *and* move the
+ * NIKHAHIT backwards over any tone mark (0E48-0E4B).
+ *
+ * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32>
+ *
+ * This reordering is legit only when the NIKHAHIT comes from a SARA AM, not
+ * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably
+ * not what a user wanted, but the rendering is nevertheless nikhahit above
+ * chattawa.
+ *
+ * Same for Lao.
+ *
+ * Note:
+ *
+ * Uniscribe also does some below-marks reordering. Namely, it positions U+0E3A
+ * after U+0E38 and U+0E39. We do that by modifying the ccc for U+0E3A.
+ * See unicode->modified_combining_class (). Lao does NOT have a U+0E3A
+ * equivalent.
+ */
+
+
+ /*
+ * Here are the characters of significance:
+ *
+ * Thai Lao
+ * SARA AM: U+0E33 U+0EB3
+ * SARA AA: U+0E32 U+0EB2
+ * Nikhahit: U+0E4D U+0ECD
+ *
+ * Testing shows that Uniscribe reorder the following marks:
+ * Thai: <0E31,0E34..0E37,0E47..0E4E>
+ * Lao: <0EB1,0EB4..0EB7,0EC7..0ECE>
+ *
+ * Note how the Lao versions are the same as Thai + 0x80.
+ */
+
+ /* We only get one script at a time, so a script-agnostic implementation
+ * is adequate here. */
+#define IS_SARA_AM(x) (((x) & ~0x0080u) == 0x0E33u)
+#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0x0E33u + 0x0E4Du)
+#define SARA_AA_FROM_SARA_AM(x) ((x) - 1)
+#define IS_TONE_MARK(x) (hb_in_ranges ((x) & ~0x0080u, 0x0E34u, 0x0E37u, 0x0E47u, 0x0E4Eu, 0x0E31u, 0x0E31u))
+
+ buffer->clear_output ();
+ unsigned int count = buffer->len;
+ for (buffer->idx = 0; buffer->idx < count;)
+ {
+ hb_codepoint_t u = buffer->cur().codepoint;
+ if (likely (!IS_SARA_AM (u))) {
+ buffer->next_glyph ();
+ continue;
+ }
+
+ /* Is SARA AM. Decompose and reorder. */
+ hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)),
+ hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))};
+ buffer->replace_glyphs (1, 2, decomposed);
+ if (unlikely (buffer->in_error))
+ return;
+
+ /* Make Nikhahit be recognized as a mark when zeroing widths. */
+ unsigned int end = buffer->out_len;
+ _hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
+
+ /* Ok, let's see... */
+ unsigned int start = end - 2;
+ while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
+ start--;
+
+ if (start + 2 < end)
+ {
+ /* Move Nikhahit (end-2) to the beginning */
+ buffer->merge_out_clusters (start, end);
+ hb_glyph_info_t t = buffer->out_info[end - 2];
+ memmove (buffer->out_info + start + 1,
+ buffer->out_info + start,
+ sizeof (buffer->out_info[0]) * (end - start - 2));
+ buffer->out_info[start] = t;
+ }
+ else
+ {
+ /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the
+ * previous cluster. */
+ if (start)
+ buffer->merge_out_clusters (start - 1, end);
+ }
+ }
+ buffer->swap_buffers ();
+
+ /* If font has Thai GSUB, we are done. */
+ if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0])
+ do_thai_pua_shaping (plan, buffer, font);
+}
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
+{
+ "thai",
+ NULL, /* collect_features */
+ NULL, /* override_features */
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ preprocess_text_thai,
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+ false,/* fallback_position */
+};
diff --git a/src/hb-ot-shape-complex-tibetan.cc b/src/hb-ot-shape-complex-tibetan.cc
new file mode 100644
index 0000000..01465a4
--- /dev/null
+++ b/src/hb-ot-shape-complex-tibetan.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2010,2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-complex-private.hh"
+
+
+static const hb_tag_t tibetan_features[] =
+{
+ HB_TAG('a','b','v','s'),
+ HB_TAG('b','l','w','s'),
+ HB_TAG('a','b','v','m'),
+ HB_TAG('b','l','w','m'),
+ HB_TAG_NONE
+};
+
+static void
+collect_features_tibetan (hb_ot_shape_planner_t *plan)
+{
+ for (const hb_tag_t *script_features = tibetan_features; script_features && *script_features; script_features++)
+ plan->map.add_global_bool_feature (*script_features);
+}
+
+
+const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
+{
+ "default",
+ collect_features_tibetan,
+ NULL, /* override_features */
+ NULL, /* data_create */
+ NULL, /* data_destroy */
+ NULL, /* preprocess_text */
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
+ NULL, /* decompose */
+ NULL, /* compose */
+ NULL, /* setup_masks */
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
+ true, /* fallback_position */
+};
diff --git a/src/hb-ot-shape-fallback-private.hh b/src/hb-ot-shape-fallback-private.hh
new file mode 100644
index 0000000..ec65351
--- /dev/null
+++ b/src/hb-ot-shape-fallback-private.hh
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_SHAPE_FALLBACK_PRIVATE_HH
+#define HB_OT_SHAPE_FALLBACK_PRIVATE_HH
+
+#include "hb-private.hh"
+
+#include "hb-ot-shape-private.hh"
+
+
+HB_INTERNAL void _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+HB_INTERNAL void _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+
+HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer);
+
+
+#endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */
diff --git a/src/hb-ot-shape-fallback.cc b/src/hb-ot-shape-fallback.cc
new file mode 100644
index 0000000..53274b5
--- /dev/null
+++ b/src/hb-ot-shape-fallback.cc
@@ -0,0 +1,485 @@
+/*
+ * Copyright © 2011,2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-ot-shape-fallback-private.hh"
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+static unsigned int
+recategorize_combining_class (hb_codepoint_t u,
+ unsigned int klass)
+{
+ if (klass >= 200)
+ return klass;
+
+ /* Thai / Lao need some per-character work. */
+ if ((u & ~0xFF) == 0x0E00u)
+ {
+ if (unlikely (klass == 0))
+ {
+ switch (u)
+ {
+ case 0x0E31u:
+ case 0x0E34u:
+ case 0x0E35u:
+ case 0x0E36u:
+ case 0x0E37u:
+ case 0x0E47u:
+ case 0x0E4Cu:
+ case 0x0E4Du:
+ case 0x0E4Eu:
+ klass = HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+ break;
+
+ case 0x0EB1u:
+ case 0x0EB4u:
+ case 0x0EB5u:
+ case 0x0EB6u:
+ case 0x0EB7u:
+ case 0x0EBBu:
+ case 0x0ECCu:
+ case 0x0ECDu:
+ klass = HB_UNICODE_COMBINING_CLASS_ABOVE;
+ break;
+
+ case 0x0EBCu:
+ klass = HB_UNICODE_COMBINING_CLASS_BELOW;
+ break;
+ }
+ } else {
+ /* Thai virama is below-right */
+ if (u == 0x0E3Au)
+ klass = HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
+ }
+ }
+
+ switch (klass)
+ {
+
+ /* Hebrew */
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC10: /* sheva */
+ case HB_MODIFIED_COMBINING_CLASS_CCC11: /* hataf segol */
+ case HB_MODIFIED_COMBINING_CLASS_CCC12: /* hataf patah */
+ case HB_MODIFIED_COMBINING_CLASS_CCC13: /* hataf qamats */
+ case HB_MODIFIED_COMBINING_CLASS_CCC14: /* hiriq */
+ case HB_MODIFIED_COMBINING_CLASS_CCC15: /* tsere */
+ case HB_MODIFIED_COMBINING_CLASS_CCC16: /* segol */
+ case HB_MODIFIED_COMBINING_CLASS_CCC17: /* patah */
+ case HB_MODIFIED_COMBINING_CLASS_CCC18: /* qamats */
+ case HB_MODIFIED_COMBINING_CLASS_CCC20: /* qubuts */
+ case HB_MODIFIED_COMBINING_CLASS_CCC22: /* meteg */
+ return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC23: /* rafe */
+ return HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC24: /* shin dot */
+ return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC25: /* sin dot */
+ case HB_MODIFIED_COMBINING_CLASS_CCC19: /* holam */
+ return HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC26: /* point varika */
+ return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC21: /* dagesh */
+ break;
+
+
+ /* Arabic and Syriac */
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC27: /* fathatan */
+ case HB_MODIFIED_COMBINING_CLASS_CCC28: /* dammatan */
+ case HB_MODIFIED_COMBINING_CLASS_CCC30: /* fatha */
+ case HB_MODIFIED_COMBINING_CLASS_CCC31: /* damma */
+ case HB_MODIFIED_COMBINING_CLASS_CCC33: /* shadda */
+ case HB_MODIFIED_COMBINING_CLASS_CCC34: /* sukun */
+ case HB_MODIFIED_COMBINING_CLASS_CCC35: /* superscript alef */
+ case HB_MODIFIED_COMBINING_CLASS_CCC36: /* superscript alaph */
+ return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC29: /* kasratan */
+ case HB_MODIFIED_COMBINING_CLASS_CCC32: /* kasra */
+ return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+
+ /* Thai */
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC103: /* sara u / sara uu */
+ return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC107: /* mai */
+ return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT;
+
+
+ /* Lao */
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */
+ return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */
+ return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+
+ /* Tibetan */
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC129: /* sign aa */
+ return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC130: /* sign i*/
+ return HB_UNICODE_COMBINING_CLASS_ABOVE;
+
+ case HB_MODIFIED_COMBINING_CLASS_CCC132: /* sign u */
+ return HB_UNICODE_COMBINING_CLASS_BELOW;
+
+ }
+
+ return klass;
+}
+
+void
+_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED,
+ hb_font_t *font HB_UNUSED,
+ hb_buffer_t *buffer)
+{
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) {
+ unsigned int combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
+ combining_class = recategorize_combining_class (info[i].codepoint, combining_class);
+ _hb_glyph_info_set_modified_combining_class (&info[i], combining_class);
+ }
+}
+
+
+static void
+zero_mark_advances (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end)
+{
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = start; i < end; i++)
+ if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+ {
+ buffer->pos[i].x_advance = 0;
+ buffer->pos[i].y_advance = 0;
+ }
+}
+
+static inline void
+position_mark (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ hb_glyph_extents_t &base_extents,
+ unsigned int i,
+ unsigned int combining_class)
+{
+ hb_glyph_extents_t mark_extents;
+ if (!font->get_glyph_extents (buffer->info[i].codepoint,
+ &mark_extents))
+ return;
+
+ hb_position_t y_gap = font->y_scale / 16;
+
+ hb_glyph_position_t &pos = buffer->pos[i];
+ pos.x_offset = pos.y_offset = 0;
+
+
+ /* We dont position LEFT and RIGHT marks. */
+
+ /* X positioning */
+ switch (combining_class)
+ {
+ case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
+ case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
+ if (buffer->props.direction == HB_DIRECTION_LTR) {
+ pos.x_offset += base_extents.x_bearing - mark_extents.width / 2 - mark_extents.x_bearing;
+ break;
+ } else if (buffer->props.direction == HB_DIRECTION_RTL) {
+ pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width / 2 - mark_extents.x_bearing;
+ break;
+ }
+ /* Fall through */
+
+ default:
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
+ case HB_UNICODE_COMBINING_CLASS_BELOW:
+ case HB_UNICODE_COMBINING_CLASS_ABOVE:
+ /* Center align. */
+ pos.x_offset += base_extents.x_bearing + (base_extents.width - mark_extents.width) / 2 - mark_extents.x_bearing;
+ break;
+
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
+ case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
+ case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
+ /* Left align. */
+ pos.x_offset += base_extents.x_bearing - mark_extents.x_bearing;
+ break;
+
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
+ case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
+ case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
+ /* Right align. */
+ pos.x_offset += base_extents.x_bearing + base_extents.width - mark_extents.width - mark_extents.x_bearing;
+ break;
+ }
+
+ /* Y positioning */
+ switch (combining_class)
+ {
+ case HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW:
+ case HB_UNICODE_COMBINING_CLASS_BELOW_LEFT:
+ case HB_UNICODE_COMBINING_CLASS_BELOW:
+ case HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT:
+ /* Add gap, fall-through. */
+ base_extents.height -= y_gap;
+
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT:
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW:
+ pos.y_offset = base_extents.y_bearing + base_extents.height - mark_extents.y_bearing;
+ /* Never shift up "below" marks. */
+ if ((y_gap > 0) == (pos.y_offset > 0))
+ {
+ base_extents.height -= pos.y_offset;
+ pos.y_offset = 0;
+ }
+ base_extents.height += mark_extents.height;
+ break;
+
+ case HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE:
+ case HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT:
+ case HB_UNICODE_COMBINING_CLASS_ABOVE:
+ case HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT:
+ /* Add gap, fall-through. */
+ base_extents.y_bearing += y_gap;
+ base_extents.height -= y_gap;
+
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE:
+ case HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT:
+ pos.y_offset = base_extents.y_bearing - (mark_extents.y_bearing + mark_extents.height);
+ /* Don't shift down "above" marks too much. */
+ if ((y_gap > 0) != (pos.y_offset > 0))
+ {
+ unsigned int correction = -pos.y_offset / 2;
+ base_extents.y_bearing += correction;
+ base_extents.height -= correction;
+ pos.y_offset += correction;
+ }
+ base_extents.y_bearing -= mark_extents.height;
+ base_extents.height += mark_extents.height;
+ break;
+ }
+}
+
+static inline void
+position_around_base (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ unsigned int base,
+ unsigned int end)
+{
+ hb_direction_t horiz_dir = HB_DIRECTION_INVALID;
+ hb_glyph_extents_t base_extents;
+ if (!font->get_glyph_extents (buffer->info[base].codepoint,
+ &base_extents))
+ {
+ /* If extents don't work, zero marks and go home. */
+ zero_mark_advances (buffer, base + 1, end);
+ return;
+ }
+ base_extents.x_bearing += buffer->pos[base].x_offset;
+ base_extents.y_bearing += buffer->pos[base].y_offset;
+
+ unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[base]);
+ unsigned int num_lig_components = _hb_glyph_info_get_lig_num_comps (&buffer->info[base]);
+
+ hb_position_t x_offset = 0, y_offset = 0;
+ if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
+ x_offset -= buffer->pos[base].x_advance;
+ y_offset -= buffer->pos[base].y_advance;
+ }
+
+ hb_glyph_extents_t component_extents = base_extents;
+ unsigned int last_lig_component = (unsigned int) -1;
+ unsigned int last_combining_class = 255;
+ hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = base + 1; i < end; i++)
+ if (_hb_glyph_info_get_modified_combining_class (&info[i]))
+ {
+ if (num_lig_components > 1) {
+ unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&info[i]);
+ unsigned int this_lig_component = _hb_glyph_info_get_lig_comp (&info[i]) - 1;
+ /* Conditions for attaching to the last component. */
+ if (!lig_id || lig_id != this_lig_id || this_lig_component >= num_lig_components)
+ this_lig_component = num_lig_components - 1;
+ if (last_lig_component != this_lig_component)
+ {
+ last_lig_component = this_lig_component;
+ last_combining_class = 255;
+ component_extents = base_extents;
+ if (unlikely (horiz_dir == HB_DIRECTION_INVALID)) {
+ if (HB_DIRECTION_IS_HORIZONTAL (plan->props.direction))
+ horiz_dir = plan->props.direction;
+ else
+ horiz_dir = hb_script_get_horizontal_direction (plan->props.script);
+ }
+ if (horiz_dir == HB_DIRECTION_LTR)
+ component_extents.x_bearing += (this_lig_component * component_extents.width) / num_lig_components;
+ else
+ component_extents.x_bearing += ((num_lig_components - 1 - this_lig_component) * component_extents.width) / num_lig_components;
+ component_extents.width /= num_lig_components;
+ }
+ }
+
+ unsigned int this_combining_class = _hb_glyph_info_get_modified_combining_class (&info[i]);
+ if (last_combining_class != this_combining_class)
+ {
+ last_combining_class = this_combining_class;
+ cluster_extents = component_extents;
+ }
+
+ position_mark (plan, font, buffer, cluster_extents, i, this_combining_class);
+
+ buffer->pos[i].x_advance = 0;
+ buffer->pos[i].y_advance = 0;
+ buffer->pos[i].x_offset += x_offset;
+ buffer->pos[i].y_offset += y_offset;
+
+ } else {
+ if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
+ x_offset -= buffer->pos[i].x_advance;
+ y_offset -= buffer->pos[i].y_advance;
+ } else {
+ x_offset += buffer->pos[i].x_advance;
+ y_offset += buffer->pos[i].y_advance;
+ }
+ }
+}
+
+static inline void
+position_cluster (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end)
+{
+ if (end - start < 2)
+ return;
+
+ /* Find the base glyph */
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = start; i < end; i++)
+ if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
+ {
+ /* Find mark glyphs */
+ unsigned int j;
+ for (j = i + 1; j < end; j++)
+ if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j])))
+ break;
+
+ position_around_base (plan, font, buffer, i, j);
+
+ i = j - 1;
+ }
+}
+
+void
+_hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ _hb_buffer_assert_gsubgpos_vars (buffer);
+
+ unsigned int start = 0;
+ unsigned int last_cluster = buffer->info[0].cluster;
+ unsigned int count = buffer->len;
+ for (unsigned int i = 1; i < count; i++)
+ if (buffer->info[i].cluster != last_cluster) {
+ position_cluster (plan, font, buffer, start, i);
+ start = i;
+ last_cluster = buffer->info[i].cluster;
+ }
+ position_cluster (plan, font, buffer, start, count);
+}
+
+
+/* Performs old-style TrueType kerning. */
+void
+_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer)
+{
+ if (!plan->has_kern) return;
+
+ OT::hb_apply_context_t c (1, font, buffer);
+ c.set_lookup_mask (plan->kern_mask);
+ c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
+ OT::hb_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
+ skippy_iter.init (&c);
+
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pos = buffer->pos;
+ for (unsigned int idx = 0; idx < count;)
+ {
+ skippy_iter.reset (idx, 1);
+ if (!skippy_iter.next ())
+ {
+ idx++;
+ continue;
+ }
+
+ hb_position_t x_kern, y_kern;
+ font->get_glyph_kerning_for_direction (info[idx].codepoint,
+ info[skippy_iter.idx].codepoint,
+ buffer->props.direction,
+ &x_kern, &y_kern);
+
+ if (x_kern)
+ {
+ hb_position_t kern1 = x_kern >> 1;
+ hb_position_t kern2 = x_kern - kern1;
+ pos[idx].x_advance += kern1;
+ pos[skippy_iter.idx].x_advance += kern2;
+ pos[skippy_iter.idx].x_offset += kern2;
+ }
+
+ if (y_kern)
+ {
+ hb_position_t kern1 = y_kern >> 1;
+ hb_position_t kern2 = y_kern - kern1;
+ pos[idx].y_advance += kern1;
+ pos[skippy_iter.idx].y_advance += kern2;
+ pos[skippy_iter.idx].y_offset += kern2;
+ }
+
+ idx = skippy_iter.idx;
+ }
+}
diff --git a/src/hb-ot-shape-normalize-private.hh b/src/hb-ot-shape-normalize-private.hh
index bb81f00..c744e26 100644
--- a/src/hb-ot-shape-normalize-private.hh
+++ b/src/hb-ot-shape-normalize-private.hh
@@ -29,18 +29,41 @@
#include "hb-private.hh"
-#include "hb-font.h"
-#include "hb-buffer.h"
+/* buffer var allocations, used during the normalization process */
+#define glyph_index() var1.u32
+
+struct hb_ot_shape_plan_t;
enum hb_ot_shape_normalization_mode_t {
+ HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
- HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL /* including base-to-base composition */
+ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */
+
+ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS
};
-HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font,
+HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
hb_buffer_t *buffer,
- hb_ot_shape_normalization_mode_t mode);
+ hb_font_t *font);
+
+
+struct hb_ot_shape_normalize_context_t
+{
+ const hb_ot_shape_plan_t *plan;
+ hb_buffer_t *buffer;
+ hb_font_t *font;
+ hb_unicode_funcs_t *unicode;
+ bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b);
+ bool (*compose) (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab);
+};
+
#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */
diff --git a/src/hb-ot-shape-normalize.cc b/src/hb-ot-shape-normalize.cc
index 562ba88..8cc64af 100644
--- a/src/hb-ot-shape-normalize.cc
+++ b/src/hb-ot-shape-normalize.cc
@@ -25,6 +25,7 @@
*/
#include "hb-ot-shape-normalize-private.hh"
+#include "hb-ot-shape-complex-private.hh"
#include "hb-ot-shape-private.hh"
@@ -62,96 +63,218 @@
* knowledge too. We need to provide assistance to the itemizer.
*
* - When a font does not support a character but supports its decomposition,
- * well, use the decomposition.
+ * well, use the decomposition (preferring the canonical decomposition, but
+ * falling back to the compatibility decomposition if necessary). The
+ * compatibility decomposition is really nice to have, for characters like
+ * ellipsis, or various-sized space characters.
*
- * - The Indic shaper requests decomposed output. This will handle splitting
- * matra for the Indic shaper.
+ * - The complex shapers can customize the compose and decompose functions to
+ * offload some of their requirements to the normalizer. For example, the
+ * Indic shaper may want to disallow recomposing of two matras.
+ *
+ * - We try compatibility decomposition if decomposing through canonical
+ * decomposition alone failed to find a sequence that the font supports.
+ * We don't try compatibility decomposition recursively during the canonical
+ * decomposition phase. This has minimal impact. There are only a handful
+ * of Greek letter that have canonical decompositions that include characters
+ * with compatibility decomposition. Those can be found using this command:
+ *
+ * egrep "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt
*/
-static void
-output_glyph (hb_buffer_t *buffer, hb_codepoint_t glyph)
+static bool
+decompose_unicode (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t ab,
+ hb_codepoint_t *a,
+ hb_codepoint_t *b)
{
- buffer->output_glyph (glyph);
- _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
+ return c->unicode->decompose (ab, a, b);
}
static bool
-decompose (hb_font_t *font, hb_buffer_t *buffer,
- bool shortest,
- hb_codepoint_t ab)
+compose_unicode (const hb_ot_shape_normalize_context_t *c,
+ hb_codepoint_t a,
+ hb_codepoint_t b,
+ hb_codepoint_t *ab)
+{
+ return c->unicode->compose (a, b, ab);
+}
+
+static inline void
+set_glyph (hb_glyph_info_t &info, hb_font_t *font)
{
- hb_codepoint_t a, b, glyph;
+ font->get_glyph (info.codepoint, 0, &info.glyph_index());
+}
- if (!hb_unicode_decompose (buffer->unicode, ab, &a, &b) ||
- (b && !hb_font_get_glyph (font, b, 0, &glyph)))
- return false;
+static inline void
+output_char (hb_buffer_t *buffer, hb_codepoint_t unichar, hb_codepoint_t glyph)
+{
+ buffer->cur().glyph_index() = glyph;
+ buffer->output_glyph (unichar);
+ _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode);
+}
- bool has_a = hb_font_get_glyph (font, a, 0, &glyph);
+static inline void
+next_char (hb_buffer_t *buffer, hb_codepoint_t glyph)
+{
+ buffer->cur().glyph_index() = glyph;
+ buffer->next_glyph ();
+}
+
+static inline void
+skip_char (hb_buffer_t *buffer)
+{
+ buffer->skip_glyph ();
+}
+
+/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
+static inline unsigned int
+decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab)
+{
+ hb_codepoint_t a, b, a_glyph, b_glyph;
+ hb_buffer_t * const buffer = c->buffer;
+ hb_font_t * const font = c->font;
+
+ if (!c->decompose (c, ab, &a, &b) ||
+ (b && !font->get_glyph (b, 0, &b_glyph)))
+ return 0;
+
+ bool has_a = font->get_glyph (a, 0, &a_glyph);
if (shortest && has_a) {
/* Output a and b */
- output_glyph (buffer, a);
- if (b)
- output_glyph (buffer, b);
- return true;
+ output_char (buffer, a, a_glyph);
+ if (likely (b)) {
+ output_char (buffer, b, b_glyph);
+ return 2;
+ }
+ return 1;
}
- if (decompose (font, buffer, shortest, a)) {
- if (b)
- output_glyph (buffer, b);
- return true;
+ unsigned int ret;
+ if ((ret = decompose (c, shortest, a))) {
+ if (b) {
+ output_char (buffer, b, b_glyph);
+ return ret + 1;
+ }
+ return ret;
}
if (has_a) {
- output_glyph (buffer, a);
- if (b)
- output_glyph (buffer, b);
- return true;
+ output_char (buffer, a, a_glyph);
+ if (likely (b)) {
+ output_char (buffer, b, b_glyph);
+ return 2;
+ }
+ return 1;
}
- return false;
+ return 0;
}
-static void
-decompose_current_glyph (hb_font_t *font, hb_buffer_t *buffer,
- bool shortest)
+/* Returns 0 if didn't decompose, number of resulting characters otherwise. */
+static inline unsigned int
+decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u)
{
- if (decompose (font, buffer, shortest, buffer->cur().codepoint))
- buffer->skip_glyph ();
- else
- buffer->next_glyph ();
+ unsigned int len, i;
+ hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+ hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN];
+
+ len = c->buffer->unicode->decompose_compatibility (u, decomposed);
+ if (!len)
+ return 0;
+
+ for (i = 0; i < len; i++)
+ if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i]))
+ return 0;
+
+ for (i = 0; i < len; i++)
+ output_char (c->buffer, decomposed[i], glyphs[i]);
+
+ return len;
}
-static void
-decompose_single_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
- bool will_recompose)
+static inline void
+decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest)
{
+ hb_buffer_t * const buffer = c->buffer;
+ hb_codepoint_t u = buffer->cur().codepoint;
hb_codepoint_t glyph;
- /* If recomposing and font supports this, we're good to go */
- if (will_recompose && hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph)) {
+ /* Kind of a cute waterfall here... */
+ if (shortest && c->font->get_glyph (u, 0, &glyph))
+ next_char (buffer, glyph);
+ else if (decompose (c, shortest, u))
+ skip_char (buffer);
+ else if (!shortest && c->font->get_glyph (u, 0, &glyph))
+ next_char (buffer, glyph);
+ else if (decompose_compatibility (c, u))
+ skip_char (buffer);
+ else
+ next_char (buffer, glyph); /* glyph is initialized in earlier branches. */
+}
+
+static inline void
+handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
+{
+ /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
+ hb_buffer_t * const buffer = c->buffer;
+ hb_font_t * const font = c->font;
+ for (; buffer->idx < end - 1;) {
+ if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) {
+ /* The next two lines are some ugly lines... But work. */
+ if (font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()))
+ {
+ buffer->replace_glyphs (2, 1, &buffer->cur().codepoint);
+ }
+ else
+ {
+ /* Just pass on the two characters separately, let GSUB do its magic. */
+ set_glyph (buffer->cur(), font);
+ buffer->next_glyph ();
+ set_glyph (buffer->cur(), font);
+ buffer->next_glyph ();
+ }
+ /* Skip any further variation selectors. */
+ while (buffer->idx < end && unlikely (buffer->unicode->is_variation_selector (buffer->cur().codepoint)))
+ {
+ set_glyph (buffer->cur(), font);
+ buffer->next_glyph ();
+ }
+ } else {
+ set_glyph (buffer->cur(), font);
+ buffer->next_glyph ();
+ }
+ }
+ if (likely (buffer->idx < end)) {
+ set_glyph (buffer->cur(), font);
buffer->next_glyph ();
- return;
}
-
- decompose_current_glyph (font, buffer, will_recompose);
}
-static void
-decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer,
- unsigned int end)
+static inline void
+decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
- /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
+ hb_buffer_t * const buffer = c->buffer;
for (unsigned int i = buffer->idx; i < end; i++)
- if (unlikely (_hb_unicode_is_variation_selector (buffer->info[i].codepoint))) {
- while (buffer->idx < end)
- buffer->next_glyph ();
+ if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
+ handle_variation_selector_cluster (c, end, short_circuit);
return;
}
while (buffer->idx < end)
- decompose_current_glyph (font, buffer, false);
+ decompose_current_character (c, short_circuit);
}
+static inline void
+decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit)
+{
+ if (likely (c->buffer->idx + 1 == end))
+ decompose_current_character (c, might_short_circuit);
+ else
+ decompose_multi_char_cluster (c, end, always_short_circuit);
+}
+
+
static int
compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
{
@@ -161,12 +284,28 @@ compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
return a < b ? -1 : a == b ? 0 : +1;
}
+
void
-_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
- hb_ot_shape_normalization_mode_t mode)
+_hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
+ hb_buffer_t *buffer,
+ hb_font_t *font)
{
- bool recompose = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED;
- bool has_multichar_clusters = false;
+ _hb_buffer_assert_unicode_vars (buffer);
+
+ hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
+ const hb_ot_shape_normalize_context_t c = {
+ plan,
+ buffer,
+ font,
+ buffer->unicode,
+ plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
+ plan->shaper->compose ? plan->shaper->compose : compose_unicode
+ };
+
+ bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
+ bool might_short_circuit = always_short_circuit ||
+ (mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
+ mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT);
unsigned int count;
/* We do a fairly straightforward yet custom normalization process in three
@@ -187,20 +326,11 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
if (buffer->cur().cluster != buffer->info[end].cluster)
break;
- if (buffer->idx + 1 == end)
- decompose_single_char_cluster (font, buffer, recompose);
- else {
- decompose_multi_char_cluster (font, buffer, end);
- has_multichar_clusters = true;
- }
+ decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
}
buffer->swap_buffers ();
- if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !has_multichar_clusters)
- return; /* Done! */
-
-
/* Second round, reorder (inplace) */
count = buffer->len;
@@ -228,7 +358,8 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
}
- if (!recompose)
+ if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
+ mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
return;
/* Third round, recompose */
@@ -243,28 +374,34 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer,
while (buffer->idx < count)
{
hb_codepoint_t composed, glyph;
- if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't try to
- * compose a CCC=0 character with it's preceding starter. */
- (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL ||
- _hb_glyph_info_get_modified_combining_class (&buffer->cur()) != 0) &&
+ if (/* We don't try to compose a non-mark character with it's preceding starter.
+ * This is both an optimization to avoid trying to compose every two neighboring
+ * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul
+ * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */
+ HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) &&
/* If there's anything between the starter and this char, they should have CCC
* smaller than this character's. */
(starter == buffer->out_len - 1 ||
_hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) &&
/* And compose. */
- hb_unicode_compose (buffer->unicode,
- buffer->out_info[starter].codepoint,
- buffer->cur().codepoint,
- &composed) &&
+ c.compose (&c,
+ buffer->out_info[starter].codepoint,
+ buffer->cur().codepoint,
+ &composed) &&
/* And the font has glyph for the composite. */
- hb_font_get_glyph (font, composed, 0, &glyph))
+ font->get_glyph (composed, 0, &glyph))
{
- /* Composes. Modify starter and carry on. */
+ /* Composes. */
+ buffer->next_glyph (); /* Copy to out-buffer. */
+ if (unlikely (buffer->in_error))
+ return;
+ buffer->merge_out_clusters (starter, buffer->out_len);
+ buffer->out_len--; /* Remove the second composable. */
+ /* Modify starter and carry on. */
buffer->out_info[starter].codepoint = composed;
- /* XXX update cluster */
+ buffer->out_info[starter].glyph_index() = glyph;
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
- buffer->skip_glyph ();
continue;
}
diff --git a/src/hb-ot-shape-private.hh b/src/hb-ot-shape-private.hh
index df0c705..54ac2c3 100644
--- a/src/hb-ot-shape-private.hh
+++ b/src/hb-ot-shape-private.hh
@@ -30,54 +30,75 @@
#include "hb-private.hh"
#include "hb-ot-map-private.hh"
-#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-layout-private.hh"
+
struct hb_ot_shape_plan_t
{
+ hb_segment_properties_t props;
+ const struct hb_ot_complex_shaper_t *shaper;
hb_ot_map_t map;
- hb_ot_complex_shaper_t shaper;
-
- hb_ot_shape_plan_t (void) : map () {}
- ~hb_ot_shape_plan_t (void) { map.finish (); }
-
- private:
- NO_COPY (hb_ot_shape_plan_t);
+ const void *data;
+ hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask;
+ hb_mask_t kern_mask;
+ unsigned int has_frac : 1;
+ unsigned int has_kern : 1;
+ unsigned int has_mark : 1;
+
+ inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
+ {
+ unsigned int table_index;
+ switch (table_tag) {
+ case HB_OT_TAG_GSUB: table_index = 0; break;
+ case HB_OT_TAG_GPOS: table_index = 1; break;
+ default: return;
+ }
+ map.collect_lookups (table_index, lookups);
+ }
+ inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); }
+ inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); }
+
+ void finish (void) { map.finish (); }
};
-
-
-HB_INTERNAL hb_bool_t
-_hb_ot_shape (hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *features,
- unsigned int num_features);
-
-
-inline void
-_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode)
-{
- info->unicode_props0() = ((unsigned int) hb_unicode_general_category (unicode, info->codepoint)) |
- (_hb_unicode_is_zero_width (info->codepoint) ? 0x80 : 0);
- info->unicode_props1() = _hb_unicode_modified_combining_class (unicode, info->codepoint);
-}
-
-inline hb_unicode_general_category_t
-_hb_glyph_info_get_general_category (const hb_glyph_info_t *info)
+struct hb_ot_shape_planner_t
{
- return (hb_unicode_general_category_t) (info->unicode_props0() & 0x7F);
-}
+ /* In the order that they are filled in. */
+ hb_face_t *face;
+ hb_segment_properties_t props;
+ const struct hb_ot_complex_shaper_t *shaper;
+ hb_ot_map_builder_t map;
+
+ hb_ot_shape_planner_t (const hb_shape_plan_t *master_plan) :
+ face (master_plan->face_unsafe),
+ props (master_plan->props),
+ shaper (NULL),
+ map (face, &props) {}
+ ~hb_ot_shape_planner_t (void) { map.finish (); }
+
+ inline void compile (hb_ot_shape_plan_t &plan)
+ {
+ plan.props = props;
+ plan.shaper = shaper;
+ map.compile (plan.map);
+
+ plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
+ plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
+ plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
+ plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
+
+ plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
+ HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
+
+ plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
+ plan.has_kern = !!plan.kern_mask;
+ plan.has_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k'));
+ }
-inline unsigned int
-_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
-{
- return info->unicode_props1();
-}
+ private:
+ NO_COPY (hb_ot_shape_planner_t);
+};
-inline hb_bool_t
-_hb_glyph_info_is_zero_width (const hb_glyph_info_t *info)
-{
- return !!(info->unicode_props0() & 0x80);
-}
#endif /* HB_OT_SHAPE_PRIVATE_HH */
diff --git a/src/hb-ot-shape.cc b/src/hb-ot-shape.cc
index 19cf680..07adb04 100644
--- a/src/hb-ot-shape.cc
+++ b/src/hb-ot-shape.cc
@@ -1,6 +1,6 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
- * Copyright © 2010,2011 Google, Inc.
+ * Copyright © 2010,2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -26,17 +26,23 @@
* Google Author(s): Behdad Esfahbod
*/
+#define HB_SHAPER ot
+#define hb_ot_shaper_face_data_t hb_ot_layout_t
+#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
+#include "hb-shaper-impl-private.hh"
+
#include "hb-ot-shape-private.hh"
+#include "hb-ot-shape-complex-private.hh"
+#include "hb-ot-shape-fallback-private.hh"
#include "hb-ot-shape-normalize-private.hh"
-#include "hb-font-private.hh"
+#include "hb-ot-layout-private.hh"
+#include "hb-unicode-private.hh"
#include "hb-set-private.hh"
-
-hb_tag_t common_features[] = {
+static hb_tag_t common_features[] = {
HB_TAG('c','c','m','p'),
- HB_TAG('l','i','g','a'),
HB_TAG('l','o','c','l'),
HB_TAG('m','a','r','k'),
HB_TAG('m','k','m','k'),
@@ -44,62 +50,37 @@ hb_tag_t common_features[] = {
};
-hb_tag_t horizontal_features[] = {
+static hb_tag_t horizontal_features[] = {
HB_TAG('c','a','l','t'),
HB_TAG('c','l','i','g'),
HB_TAG('c','u','r','s'),
HB_TAG('k','e','r','n'),
+ HB_TAG('l','i','g','a'),
+ HB_TAG('r','c','l','t'),
};
-/* Note:
- * Technically speaking, vrt2 and vert are mutually exclusive.
- * According to the spec, valt and vpal are also mutually exclusive.
- * But we apply them all for now.
- */
-hb_tag_t vertical_features[] = {
- HB_TAG('v','a','l','t'),
+static hb_tag_t vertical_features[] = {
HB_TAG('v','e','r','t'),
- HB_TAG('v','k','r','n'),
- HB_TAG('v','p','a','l'),
- HB_TAG('v','r','t','2'),
};
-struct hb_ot_shape_planner_t
-{
- hb_ot_map_builder_t map;
- hb_ot_complex_shaper_t shaper;
-
- hb_ot_shape_planner_t (void) : map () {}
- ~hb_ot_shape_planner_t (void) { map.finish (); }
-
- inline void compile (hb_face_t *face,
- const hb_segment_properties_t *props,
- struct hb_ot_shape_plan_t &plan)
- {
- plan.shaper = shaper;
- map.compile (face, props, plan.map);
- }
-
- private:
- NO_COPY (hb_ot_shape_planner_t);
-};
-
static void
hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
const hb_segment_properties_t *props,
const hb_feature_t *user_features,
unsigned int num_user_features)
{
+ hb_ot_map_builder_t *map = &planner->map;
+
switch (props->direction) {
case HB_DIRECTION_LTR:
- planner->map.add_bool_feature (HB_TAG ('l','t','r','a'));
- planner->map.add_bool_feature (HB_TAG ('l','t','r','m'));
+ map->add_global_bool_feature (HB_TAG ('l','t','r','a'));
+ map->add_global_bool_feature (HB_TAG ('l','t','r','m'));
break;
case HB_DIRECTION_RTL:
- planner->map.add_bool_feature (HB_TAG ('r','t','l','a'));
- planner->map.add_bool_feature (HB_TAG ('r','t','l','m'), false);
+ map->add_global_bool_feature (HB_TAG ('r','t','l','a'));
+ map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE);
break;
case HB_DIRECTION_TTB:
case HB_DIRECTION_BTT:
@@ -108,33 +89,122 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
break;
}
-#define ADD_FEATURES(array) \
- HB_STMT_START { \
- for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \
- planner->map.add_bool_feature (array[i]); \
- } HB_STMT_END
+ map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
+ map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
+ map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
- hb_ot_shape_complex_collect_features (planner->shaper, &planner->map, props);
+ if (planner->shaper->collect_features)
+ planner->shaper->collect_features (planner);
- ADD_FEATURES (common_features);
+ for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++)
+ map->add_global_bool_feature (common_features[i]);
if (HB_DIRECTION_IS_HORIZONTAL (props->direction))
- ADD_FEATURES (horizontal_features);
+ for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++)
+ map->add_feature (horizontal_features[i], 1, F_GLOBAL |
+ (horizontal_features[i] == HB_TAG('k','e','r','n') ?
+ F_HAS_FALLBACK : F_NONE));
else
- ADD_FEATURES (vertical_features);
+ for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++)
+ map->add_feature (vertical_features[i], 1, F_GLOBAL |
+ (vertical_features[i] == HB_TAG('v','k','r','n') ?
+ F_HAS_FALLBACK : F_NONE));
-#undef ADD_FEATURES
+ if (planner->shaper->override_features)
+ planner->shaper->override_features (planner);
for (unsigned int i = 0; i < num_user_features; i++) {
const hb_feature_t *feature = &user_features[i];
- planner->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
+ map->add_feature (feature->tag, feature->value,
+ (feature->start == 0 && feature->end == (unsigned int) -1) ?
+ F_GLOBAL : F_NONE);
}
}
+/*
+ * shaper face data
+ */
+
+hb_ot_shaper_face_data_t *
+_hb_ot_shaper_face_data_create (hb_face_t *face)
+{
+ return _hb_ot_layout_create (face);
+}
+
+void
+_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
+{
+ _hb_ot_layout_destroy (data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_ot_shaper_font_data_t {};
+
+hb_ot_shaper_font_data_t *
+_hb_ot_shaper_font_data_create (hb_font_t *font)
+{
+ return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
+{
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+hb_ot_shaper_shape_plan_data_t *
+_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features)
+{
+ hb_ot_shape_plan_t *plan = (hb_ot_shape_plan_t *) calloc (1, sizeof (hb_ot_shape_plan_t));
+ if (unlikely (!plan))
+ return NULL;
+
+ hb_ot_shape_planner_t planner (shape_plan);
+
+ planner.shaper = hb_ot_shape_complex_categorize (&planner);
+
+ hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features);
+
+ planner.compile (*plan);
+
+ if (plan->shaper->data_create) {
+ plan->data = plan->shaper->data_create (plan);
+ if (unlikely (!plan->data))
+ return NULL;
+ }
+
+ return plan;
+}
+
+void
+_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
+{
+ if (plan->shaper->data_destroy)
+ plan->shaper->data_destroy (const_cast<void *> (plan->data));
+
+ plan->finish ();
+
+ free (plan);
+}
+
+
+/*
+ * shaper
+ */
+
struct hb_ot_shape_context_t
{
- /* Input to hb_ot_shape_execute() */
hb_ot_shape_plan_t *plan;
hb_font_t *font;
hb_face_t *face;
@@ -144,51 +214,61 @@ struct hb_ot_shape_context_t
/* Transient stuff */
hb_direction_t target_direction;
- hb_bool_t applied_position_complex;
};
-static void
-hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
-{
- hb_mask_t global_mask = c->plan->map.get_global_mask ();
- c->buffer->reset_masks (global_mask);
-
- hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer, c->font);
-
- for (unsigned int i = 0; i < c->num_user_features; i++)
- {
- const hb_feature_t *feature = &c->user_features[i];
- if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
- unsigned int shift;
- hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift);
- c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
- }
- }
-}
/* Main shaper */
+
/* Prepare */
static void
hb_set_unicode_props (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
- _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode);
+ _hb_glyph_info_set_unicode_props (&info[i], buffer->unicode);
+}
+
+static void
+hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
+{
+ if (!(buffer->flags & HB_BUFFER_FLAG_BOT) ||
+ buffer->context_len[0] ||
+ _hb_glyph_info_get_general_category (&buffer->info[0]) !=
+ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+ return;
+
+ if (!font->has_glyph (0x25CCu))
+ return;
+
+ hb_glyph_info_t dottedcircle = {0};
+ dottedcircle.codepoint = 0x25CCu;
+ _hb_glyph_info_set_unicode_props (&dottedcircle, buffer->unicode);
+
+ buffer->clear_output ();
+
+ buffer->idx = 0;
+ hb_glyph_info_t info = dottedcircle;
+ info.cluster = buffer->cur().cluster;
+ info.mask = buffer->cur().mask;
+ buffer->output_info (info);
+ while (buffer->idx < buffer->len)
+ buffer->next_glyph ();
+
+ buffer->swap_buffers ();
}
static void
hb_form_clusters (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i < count; i++)
- if (FLAG (_hb_glyph_info_get_general_category (&buffer->info[i])) &
- (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) |
- FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
- buffer->info[i].cluster = buffer->info[i - 1].cluster; /* XXX do the min() here */
+ if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))
+ buffer->merge_clusters (i - 1, i + 1);
}
static void
@@ -211,286 +291,478 @@ hb_ensure_native_direction (hb_buffer_t *buffer)
/* Substitute */
-static void
-hb_mirror_chars (hb_ot_shape_context_t *c)
+static inline void
+hb_ot_mirror_chars (hb_ot_shape_context_t *c)
{
- hb_unicode_funcs_t *unicode = c->buffer->unicode;
-
if (HB_DIRECTION_IS_FORWARD (c->target_direction))
return;
- hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
+ hb_buffer_t *buffer = c->buffer;
+ hb_unicode_funcs_t *unicode = buffer->unicode;
+ hb_mask_t rtlm_mask = c->plan->rtlm_mask;
- unsigned int count = c->buffer->len;
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++) {
- hb_codepoint_t codepoint = hb_unicode_mirroring (unicode, c->buffer->info[i].codepoint);
- if (likely (codepoint == c->buffer->info[i].codepoint))
- c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */
+ hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint);
+ if (likely (codepoint == info[i].codepoint))
+ info[i].mask |= rtlm_mask;
else
- c->buffer->info[i].codepoint = codepoint;
+ info[i].codepoint = codepoint;
}
}
-static void
-hb_map_glyphs (hb_font_t *font,
- hb_buffer_t *buffer)
+static inline void
+hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
{
- hb_codepoint_t glyph;
-
- if (unlikely (!buffer->len))
+ if (!c->plan->has_frac)
return;
- buffer->clear_output ();
+ hb_buffer_t *buffer = c->buffer;
- unsigned int count = buffer->len - 1;
- for (buffer->idx = 0; buffer->idx < count;) {
- if (unlikely (_hb_unicode_is_variation_selector (buffer->cur(+1).codepoint))) {
- hb_font_get_glyph (font, buffer->cur().codepoint, buffer->cur(+1).codepoint, &glyph);
- buffer->replace_glyphs (2, 1, &glyph);
- } else {
- hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph);
- buffer->replace_glyph (glyph);
+ /* TODO look in pre/post context text also. */
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (info[i].codepoint == 0x2044u) /* FRACTION SLASH */
+ {
+ unsigned int start = i, end = i + 1;
+ while (start &&
+ _hb_glyph_info_get_general_category (&info[start - 1]) ==
+ HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+ start--;
+ while (end < count &&
+ _hb_glyph_info_get_general_category (&info[end]) ==
+ HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
+ end++;
+
+ for (unsigned int j = start; j < i; j++)
+ info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
+ info[i].mask |= c->plan->frac_mask;
+ for (unsigned int j = i + 1; j < end; j++)
+ info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
+
+ i = end - 1;
}
}
- if (likely (buffer->idx < buffer->len)) {
- hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph);
- buffer->replace_glyph (glyph);
+}
+
+static inline void
+hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
+{
+ hb_ot_map_t *map = &c->plan->map;
+ hb_buffer_t *buffer = c->buffer;
+
+ hb_mask_t global_mask = map->get_global_mask ();
+ buffer->reset_masks (global_mask);
+}
+
+static inline void
+hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
+{
+ hb_ot_map_t *map = &c->plan->map;
+ hb_buffer_t *buffer = c->buffer;
+
+ hb_ot_shape_setup_masks_fraction (c);
+
+ if (c->plan->shaper->setup_masks)
+ c->plan->shaper->setup_masks (c->plan, buffer, c->font);
+
+ for (unsigned int i = 0; i < c->num_user_features; i++)
+ {
+ const hb_feature_t *feature = &c->user_features[i];
+ if (!(feature->start == 0 && feature->end == (unsigned int)-1)) {
+ unsigned int shift;
+ hb_mask_t mask = map->get_mask (feature->tag, &shift);
+ buffer->set_masks (feature->value << shift, mask, feature->start, feature->end);
+ }
}
- buffer->swap_buffers ();
}
-static void
-hb_substitute_default (hb_ot_shape_context_t *c)
+static inline void
+hb_ot_map_glyphs_fast (hb_buffer_t *buffer)
+{
+ /* Normalization process sets up glyph_index(), we just copy it. */
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ info[i].codepoint = info[i].glyph_index();
+}
+
+static inline void
+hb_synthesize_glyph_classes (hb_ot_shape_context_t *c)
+{
+ unsigned int count = c->buffer->len;
+ hb_glyph_info_t *info = c->buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ hb_ot_layout_glyph_class_mask_t klass;
+
+ /* Never mark default-ignorables as marks.
+ * They won't get in the way of lookups anyway,
+ * but having them as mark will cause them to be skipped
+ * over if the lookup-flag says so, but at least for the
+ * Mongolian variation selectors, looks like Uniscribe
+ * marks them as non-mark. Some Mongolian fonts without
+ * GDEF rely on this. Another notable character that
+ * this applies to is COMBINING GRAPHEME JOINER. */
+ klass = (_hb_glyph_info_get_general_category (&info[i]) !=
+ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
+ _hb_glyph_info_is_default_ignorable (&info[i])) ?
+ HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
+ HB_OT_LAYOUT_GLYPH_PROPS_MARK;
+ _hb_glyph_info_set_glyph_props (&info[i], klass);
+ }
+}
+
+static inline void
+hb_ot_substitute_default (hb_ot_shape_context_t *c)
{
- hb_ot_layout_substitute_start (c->buffer);
+ hb_buffer_t *buffer = c->buffer;
+
+ if (c->plan->shaper->preprocess_text)
+ c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
+
+ hb_ot_shape_initialize_masks (c);
+
+ hb_ot_mirror_chars (c);
+
+ HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);
+
+ _hb_ot_shape_normalize (c->plan, buffer, c->font);
- hb_mirror_chars (c);
+ hb_ot_shape_setup_masks (c);
+
+ /* This is unfortunate to go here, but necessary... */
+ if (!hb_ot_layout_has_positioning (c->face))
+ _hb_ot_shape_fallback_position_recategorize_marks (c->plan, c->font, buffer);
- hb_map_glyphs (c->font, c->buffer);
+ hb_ot_map_glyphs_fast (buffer);
+
+ HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_index);
}
-static void
+static inline void
hb_ot_substitute_complex (hb_ot_shape_context_t *c)
{
- if (hb_ot_layout_has_substitution (c->face)) {
- c->plan->map.substitute (c->face, c->buffer);
- }
+ hb_buffer_t *buffer = c->buffer;
+
+ _hb_buffer_allocate_gsubgpos_vars (buffer);
+ hb_ot_layout_substitute_start (c->font, buffer);
+
+ if (!hb_ot_layout_has_glyph_classes (c->face))
+ hb_synthesize_glyph_classes (c);
+
+ c->plan->substitute (c->font, buffer);
- hb_ot_layout_substitute_finish (c->buffer);
+ hb_ot_layout_substitute_finish (c->font, buffer);
return;
}
+static inline void
+hb_ot_substitute (hb_ot_shape_context_t *c)
+{
+ hb_ot_substitute_default (c);
+ hb_ot_substitute_complex (c);
+}
/* Position */
-static void
-hb_position_default (hb_ot_shape_context_t *c)
+static inline void
+adjust_mark_offsets (hb_glyph_position_t *pos)
+{
+ pos->x_offset -= pos->x_advance;
+ pos->y_offset -= pos->y_advance;
+}
+
+static inline void
+zero_mark_width (hb_glyph_position_t *pos)
+{
+ pos->x_advance = 0;
+ pos->y_advance = 0;
+}
+
+static inline void
+zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
{
- hb_ot_layout_position_start (c->buffer);
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
+ {
+ if (adjust_offsets)
+ adjust_mark_offsets (&buffer->pos[i]);
+ zero_mark_width (&buffer->pos[i]);
+ }
+}
+static inline void
+zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
+{
+ unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 0; i < count; i++)
+ if (_hb_glyph_info_is_mark (&info[i]))
+ {
+ if (adjust_offsets)
+ adjust_mark_offsets (&buffer->pos[i]);
+ zero_mark_width (&buffer->pos[i]);
+ }
+}
+
+static inline void
+hb_ot_position_default (hb_ot_shape_context_t *c)
+{
+ hb_direction_t direction = c->buffer->props.direction;
unsigned int count = c->buffer->len;
- for (unsigned int i = 0; i < count; i++) {
- hb_font_get_glyph_advance_for_direction (c->font, c->buffer->info[i].codepoint,
- c->buffer->props.direction,
- &c->buffer->pos[i].x_advance,
- &c->buffer->pos[i].y_advance);
- hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
- c->buffer->props.direction,
- &c->buffer->pos[i].x_offset,
- &c->buffer->pos[i].y_offset);
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ c->font->get_glyph_advance_for_direction (info[i].codepoint,
+ direction,
+ &pos[i].x_advance,
+ &pos[i].y_advance);
+ c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+ direction,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
+
}
}
-static void
+static inline bool
hb_ot_position_complex (hb_ot_shape_context_t *c)
{
+ bool ret = false;
+ unsigned int count = c->buffer->len;
+ bool has_positioning = hb_ot_layout_has_positioning (c->face);
+ /* If the font has no GPOS, AND, no fallback positioning will
+ * happen, AND, direction is forward, then when zeroing mark
+ * widths, we shift the mark with it, such that the mark
+ * is positioned hanging over the previous glyph. When
+ * direction is backward we don't shift and it will end up
+ * hanging over the next glyph after the final reordering.
+ * If fallback positinoing happens or GPOS is present, we don't
+ * care.
+ */
+ bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
+ HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
+
+ switch (c->plan->shaper->zero_width_marks)
+ {
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
+ zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
+ break;
- if (hb_ot_layout_has_positioning (c->face))
+ /* Not currently used for any shaper:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
+ zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
+ break;
+ */
+
+ default:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+ break;
+ }
+
+ if (has_positioning)
{
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
+
/* Change glyph origin to what GPOS expects, apply GPOS, change it back. */
- unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++) {
- hb_font_add_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
- HB_DIRECTION_LTR,
- &c->buffer->pos[i].x_offset,
- &c->buffer->pos[i].y_offset);
+ c->font->add_glyph_origin_for_direction (info[i].codepoint,
+ HB_DIRECTION_LTR,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
}
- c->plan->map.position (c->font, c->buffer);
+ c->plan->position (c->font, c->buffer);
for (unsigned int i = 0; i < count; i++) {
- hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint,
- HB_DIRECTION_LTR,
- &c->buffer->pos[i].x_offset,
- &c->buffer->pos[i].y_offset);
+ c->font->subtract_glyph_origin_for_direction (info[i].codepoint,
+ HB_DIRECTION_LTR,
+ &pos[i].x_offset,
+ &pos[i].y_offset);
}
- c->applied_position_complex = true;
+ ret = true;
}
- hb_ot_layout_position_finish (c->buffer);
-
- return;
-}
+ switch (c->plan->shaper->zero_width_marks)
+ {
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
+ zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
+ break;
-static void
-hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED)
-{
- /* TODO Mark pos */
-}
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
+ zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
+ break;
-static void
-hb_truetype_kern (hb_ot_shape_context_t *c)
-{
- /* TODO Check for kern=0 */
- unsigned int count = c->buffer->len;
- for (unsigned int i = 1; i < count; i++) {
- hb_position_t x_kern, y_kern, kern1, kern2;
- hb_font_get_glyph_kerning_for_direction (c->font,
- c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint,
- c->buffer->props.direction,
- &x_kern, &y_kern);
-
- kern1 = x_kern >> 1;
- kern2 = x_kern - kern1;
- c->buffer->pos[i - 1].x_advance += kern1;
- c->buffer->pos[i].x_advance += kern2;
- c->buffer->pos[i].x_offset += kern2;
-
- kern1 = y_kern >> 1;
- kern2 = y_kern - kern1;
- c->buffer->pos[i - 1].y_advance += kern1;
- c->buffer->pos[i].y_advance += kern2;
- c->buffer->pos[i].y_offset += kern2;
+ default:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE:
+ //case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
+ case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
+ break;
}
+
+ return ret;
}
-static void
-hb_position_complex_fallback_visual (hb_ot_shape_context_t *c)
+static inline void
+hb_ot_position (hb_ot_shape_context_t *c)
{
- hb_truetype_kern (c);
+ hb_ot_layout_position_start (c->font, c->buffer);
+
+ hb_ot_position_default (c);
+
+ hb_bool_t fallback = !hb_ot_position_complex (c);
+
+ hb_ot_layout_position_finish (c->font, c->buffer);
+
+ if (fallback && c->plan->shaper->fallback_position)
+ _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
+
+ if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
+ hb_buffer_reverse (c->buffer);
+
+ /* Visual fallback goes here. */
+
+ if (fallback)
+ _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer);
+
+ _hb_buffer_deallocate_gsubgpos_vars (c->buffer);
}
+
+/* Post-process */
+
static void
-hb_hide_zerowidth (hb_ot_shape_context_t *c)
+hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c)
{
- /* TODO Save the space character in the font? */
+ if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES)
+ return;
+
hb_codepoint_t space;
- if (!hb_font_get_glyph (c->font, ' ', 0, &space))
- return; /* No point! */
+ enum {
+ SPACE_DONT_KNOW,
+ SPACE_AVAILABLE,
+ SPACE_UNAVAILABLE
+ } space_status = SPACE_DONT_KNOW;
unsigned int count = c->buffer->len;
+ hb_glyph_info_t *info = c->buffer->info;
+ hb_glyph_position_t *pos = c->buffer->pos;
+ unsigned int j = 0;
for (unsigned int i = 0; i < count; i++)
- if (unlikely (_hb_glyph_info_is_zero_width (&c->buffer->info[i]))) {
- c->buffer->info[i].codepoint = space;
- c->buffer->pos[i].x_advance = 0;
- c->buffer->pos[i].y_advance = 0;
+ {
+ if (unlikely (!_hb_glyph_info_ligated (&info[i]) &&
+ _hb_glyph_info_is_default_ignorable (&info[i])))
+ {
+ if (space_status == SPACE_DONT_KNOW)
+ space_status = c->font->get_glyph (' ', 0, &space) ? SPACE_AVAILABLE : SPACE_UNAVAILABLE;
+
+ if (space_status == SPACE_AVAILABLE)
+ {
+ info[i].codepoint = space;
+ pos[i].x_advance = 0;
+ pos[i].y_advance = 0;
+ }
+ else
+ continue; /* Delete it. XXX Merge clusters? */
+ }
+ if (j != i)
+ {
+ info[j] = info[i];
+ pos[j] = pos[i];
}
+ j++;
+ }
+ c->buffer->len = j;
}
-/* Do it! */
+/* Pull it all together! */
static void
-hb_ot_shape_execute_internal (hb_ot_shape_context_t *c)
+hb_ot_shape_internal (hb_ot_shape_context_t *c)
{
c->buffer->deallocate_var_all ();
/* Save the original direction, we use it later. */
c->target_direction = c->buffer->props.direction;
- HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props0);
- HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props1);
+ _hb_buffer_allocate_unicode_vars (c->buffer);
- hb_set_unicode_props (c->buffer);
+ c->buffer->clear_output ();
+ hb_set_unicode_props (c->buffer);
+ hb_insert_dotted_circle (c->buffer, c->font);
hb_form_clusters (c->buffer);
hb_ensure_native_direction (c->buffer);
- _hb_ot_shape_normalize (c->font, c->buffer, hb_ot_shape_complex_normalization_preference (c->plan->shaper));
-
- hb_ot_shape_setup_masks (c);
-
- /* SUBSTITUTE */
- {
- hb_substitute_default (c);
-
- hb_ot_substitute_complex (c);
- }
-
- /* POSITION */
- {
- hb_position_default (c);
-
- hb_ot_position_complex (c);
+ hb_ot_substitute (c);
+ hb_ot_position (c);
- hb_bool_t position_fallback = !c->applied_position_complex;
- if (position_fallback)
- hb_position_complex_fallback (c);
+ hb_ot_hide_default_ignorables (c);
- if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction))
- hb_buffer_reverse (c->buffer);
-
- if (position_fallback)
- hb_position_complex_fallback_visual (c);
- }
-
- hb_hide_zerowidth (c);
-
- HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1);
- HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0);
+ _hb_buffer_deallocate_unicode_vars (c->buffer);
c->buffer->props.direction = c->target_direction;
c->buffer->deallocate_var_all ();
}
-static void
-hb_ot_shape_plan_internal (hb_ot_shape_plan_t *plan,
- hb_face_t *face,
- const hb_segment_properties_t *props,
- const hb_feature_t *user_features,
- unsigned int num_user_features)
-{
- hb_ot_shape_planner_t planner;
-
- assert (HB_DIRECTION_IS_VALID (props->direction));
-
- planner.shaper = hb_ot_shape_complex_categorize (props);
-
- hb_ot_shape_collect_features (&planner, props, user_features, num_user_features);
-
- planner.compile (face, props, *plan);
-}
-
-static void
-hb_ot_shape_execute (hb_ot_shape_plan_t *plan,
- hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *user_features,
- unsigned int num_user_features)
-{
- hb_ot_shape_context_t c = {plan, font, font->face, buffer, user_features, num_user_features};
- hb_ot_shape_execute_internal (&c);
-}
hb_bool_t
-_hb_ot_shape (hb_font_t *font,
+_hb_ot_shape (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
- hb_ot_shape_plan_t plan;
+ hb_ot_shape_context_t c = {HB_SHAPER_DATA_GET (shape_plan), font, font->face, buffer, features, num_features};
+ hb_ot_shape_internal (&c);
- buffer->guess_properties ();
+ return true;
+}
- hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
- hb_ot_shape_execute (&plan, font, buffer, features, num_features);
- return true;
+void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+ hb_tag_t table_tag,
+ hb_set_t *lookup_indexes /* OUT */)
+{
+ /* XXX Does the first part always succeed? */
+ HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes);
+}
+
+
+/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */
+static void
+add_char (hb_font_t *font,
+ hb_unicode_funcs_t *unicode,
+ hb_bool_t mirror,
+ hb_codepoint_t u,
+ hb_set_t *glyphs)
+{
+ hb_codepoint_t glyph;
+ if (font->get_glyph (u, 0, &glyph))
+ glyphs->add (glyph);
+ if (mirror)
+ {
+ hb_codepoint_t m = unicode->mirroring (u);
+ if (m != u && font->get_glyph (m, 0, &glyph))
+ glyphs->add (glyph);
+ }
}
@@ -503,26 +775,29 @@ hb_ot_shape_glyphs_closure (hb_font_t *font,
{
hb_ot_shape_plan_t plan;
- buffer->guess_properties ();
-
- hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features);
+ const char *shapers[] = {"ot", NULL};
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
+ features, num_features, shapers);
- /* TODO: normalization? have shapers do closure()? */
- /* TODO: Deal with mirrored chars? */
- hb_map_glyphs (font, buffer);
+ bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL;
- /* Seed it. It's user's responsibility to have cleard glyphs
- * if that's what they desire. */
unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
- hb_set_add (glyphs, buffer->info[i].codepoint);
+ add_char (font, buffer->unicode, mirror, info[i].codepoint, glyphs);
+
+ hb_set_t lookups;
+ lookups.init ();
+ hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups);
/* And find transitive closure. */
hb_set_t copy;
copy.init ();
-
do {
copy.set (glyphs);
- plan.map.substitute_closure (font->face, glyphs);
- } while (!copy.equal (glyphs));
+ for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);)
+ hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs);
+ } while (!copy.is_equal (glyphs));
+
+ hb_shape_plan_destroy (shape_plan);
}
diff --git a/src/hb-ot-shape.h b/src/hb-ot-shape.h
new file mode 100644
index 0000000..1402f54
--- /dev/null
+++ b/src/hb-ot-shape.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_OT_H_IN
+#error "Include <hb-ot.h> instead."
+#endif
+
+#ifndef HB_OT_SHAPE_H
+#define HB_OT_SHAPE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+/* TODO port to shape-plan / set. */
+void
+hb_ot_shape_glyphs_closure (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ hb_set_t *glyphs);
+
+void
+hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
+ hb_tag_t table_tag,
+ hb_set_t *lookup_indexes /* OUT */);
+
+HB_END_DECLS
+
+#endif /* HB_OT_SHAPE_H */
diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc
index ac60e96..878dd79 100644
--- a/src/hb-ot-tag.cc
+++ b/src/hb-ot-tag.cc
@@ -23,11 +23,10 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
- * Google Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#include "hb-private.hh"
-#include "hb-ot.h"
#include <string.h>
@@ -38,6 +37,8 @@
static hb_tag_t
hb_ot_old_tag_from_script (hb_script_t script)
{
+ /* This seems to be accurate as of end of 2012. */
+
switch ((hb_tag_t) script) {
case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT;
@@ -56,7 +57,7 @@ hb_ot_old_tag_from_script (hb_script_t script)
}
/* Else, just change first char to lowercase and return */
- return ((hb_tag_t) script) | 0x20000000;
+ return ((hb_tag_t) script) | 0x20000000u;
}
static hb_script_t
@@ -69,13 +70,13 @@ hb_ot_old_tag_to_script (hb_tag_t tag)
/* Any spaces at the end of the tag are replaced by repeating the last
* letter. Eg 'nko ' -> 'Nkoo' */
- if (unlikely ((tag & 0x0000FF00) == 0x00002000))
- tag |= (tag >> 8) & 0x0000FF00; /* Copy second letter to third */
- if (unlikely ((tag & 0x000000FF) == 0x00000020))
- tag |= (tag >> 8) & 0x000000FF; /* Copy third letter to fourth */
+ if (unlikely ((tag & 0x0000FF00u) == 0x00002000u))
+ tag |= (tag >> 8) & 0x0000FF00u; /* Copy second letter to third */
+ if (unlikely ((tag & 0x000000FFu) == 0x00000020u))
+ tag |= (tag >> 8) & 0x000000FFu; /* Copy third letter to fourth */
/* Change first char to uppercase and return */
- return (hb_script_t) (tag & ~0x20000000);
+ return (hb_script_t) (tag & ~0x20000000u);
}
static hb_tag_t
@@ -91,6 +92,7 @@ hb_ot_new_tag_from_script (hb_script_t script)
case HB_SCRIPT_ORIYA: return HB_TAG('o','r','y','2');
case HB_SCRIPT_TAMIL: return HB_TAG('t','m','l','2');
case HB_SCRIPT_TELUGU: return HB_TAG('t','e','l','2');
+ case HB_SCRIPT_MYANMAR: return HB_TAG('m','y','m','2');
}
return HB_OT_TAG_DEFAULT_SCRIPT;
@@ -109,6 +111,7 @@ hb_ot_new_tag_to_script (hb_tag_t tag)
case HB_TAG('o','r','y','2'): return HB_SCRIPT_ORIYA;
case HB_TAG('t','m','l','2'): return HB_SCRIPT_TAMIL;
case HB_TAG('t','e','l','2'): return HB_SCRIPT_TELUGU;
+ case HB_TAG('m','y','m','2'): return HB_SCRIPT_MYANMAR;
}
return HB_SCRIPT_UNKNOWN;
@@ -143,7 +146,7 @@ hb_ot_tags_from_script (hb_script_t script,
hb_script_t
hb_ot_tag_to_script (hb_tag_t tag)
{
- if (unlikely ((tag & 0x000000FF) == '2'))
+ if (unlikely ((tag & 0x000000FFu) == '2'))
return hb_ot_new_tag_to_script (tag);
return hb_ot_old_tag_to_script (tag);
@@ -153,7 +156,7 @@ hb_ot_tag_to_script (hb_tag_t tag)
/* hb_language_t */
typedef struct {
- char language[6];
+ char language[4];
hb_tag_t tag;
} LangTag;
@@ -163,9 +166,14 @@ typedef struct {
*
* Generated by intersecting the OpenType language tag list from
* Draft OpenType 1.5 spec, with with the ISO 639-3 codes from
- * 2008/08/04, matching on name, and finally adjusted manually.
+ * 2008-08-04, matching on name, and finally adjusted manually.
+ *
+ * Updated on 2012-12-07 with more research into remaining codes.
+ *
+ * Updated on 2013-11-23 based on usage in SIL and Microsoft fonts,
+ * the new proposal from Microsoft, and latest ISO 639-3 names.
*
- * Many items still missing. Those are commented out at the end.
+ * Some items still missing. Those are commented out at the end.
* Keep sorted for bsearch.
*/
@@ -173,46 +181,102 @@ static const LangTag ot_languages[] = {
{"aa", HB_TAG('A','F','R',' ')}, /* Afar */
{"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */
{"abq", HB_TAG('A','B','A',' ')}, /* Abaza */
+ {"ach", HB_TAG('A','C','H',' ')}, /* Acoli */
+ {"ada", HB_TAG('D','N','G',' ')}, /* Dangme */
{"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */
{"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */
+ {"aii", HB_TAG('S','W','A',' ')}, /* Swadaya Aramaic */
+ {"aio", HB_TAG('A','I','O',' ')}, /* Aiton */
{"aiw", HB_TAG('A','R','I',' ')}, /* Aari */
+ {"ak", HB_TAG('T','W','I',' ')}, /* Akan [macrolanguage] */
+ {"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */
{"am", HB_TAG('A','M','H',' ')}, /* Amharic */
- {"ar", HB_TAG('A','R','A',' ')}, /* Arabic */
+ {"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */
+ {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */
+ {"ang", HB_TAG('A','N','G',' ')}, /* Old English (ca. 450-1100) */
+ {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */
+ {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic */
{"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */
+ {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic */
{"as", HB_TAG('A','S','M',' ')}, /* Assamese */
+ {"ast", HB_TAG('A','S','T',' ')}, /* Asturian/Asturleonese/Bable/Leonese */
+ {"ath", HB_TAG('A','T','H',' ')}, /* Athapaskan [family] */
+ {"atv", HB_TAG('A','L','T',' ')}, /* [Northern] Altai */
{"av", HB_TAG('A','V','R',' ')}, /* Avaric */
{"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */
- {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara */
- {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani */
+ {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */
+ {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */
+ {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani */
+ {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani */
{"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */
- {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi */
+ {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */
+ {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolangauge] */
+ {"ban", HB_TAG('B','A','N',' ')}, /* Balinese */
+ {"bar", HB_TAG('B','A','R',' ')}, /* Bavarian */
+ {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */
+ {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé */
+ {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol */
{"bcq", HB_TAG('B','C','H',' ')}, /* Bench */
+ {"be", HB_TAG('B','E','L',' ')}, /* Belarusian */
{"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */
+ {"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */
{"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */
{"bft", HB_TAG('B','L','T',' ')}, /* Balti */
+ {"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */
{"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */
+ {"bgc", HB_TAG('B','G','C',' ')}, /* Haryanvi */
+ {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */
{"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */
+ {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) */
{"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */
- {"bik", HB_TAG('B','I','K',' ')}, /* Bikol */
+ {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */
+ {"bik", HB_TAG('B','I','K',' ')}, /* Bikol [macrolanguage] */
{"bin", HB_TAG('E','D','O',' ')}, /* Bini */
+ {"bjj", HB_TAG('B','J','J',' ')}, /* Kanauji */
+ {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja */
+ {"bla", HB_TAG('B','K','F',' ')}, /* Blackfoot */
+ {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe */
+ {"blk", HB_TAG('B','L','K',' ')}, /* Pa'O/Pa'o Karen */
+ {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol */
{"bm", HB_TAG('B','M','B',' ')}, /* Bambara */
{"bn", HB_TAG('B','E','N',' ')}, /* Bengali */
{"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */
+ {"bpy", HB_TAG('B','P','Y',' ')}, /* Bishnupriya */
+ {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari */
{"br", HB_TAG('B','R','E',' ')}, /* Breton */
+ {"bra", HB_TAG('B','R','I',' ')}, /* Braj Bhasha */
{"brh", HB_TAG('B','R','H',' ')}, /* Brahui */
+ {"brx", HB_TAG('B','R','X',' ')}, /* Bodo (India) */
{"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */
{"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) */
+ {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol */
+ {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */
+ {"bug", HB_TAG('B','U','G',' ')}, /* Buginese */
+ {"bxr", HB_TAG('R','B','U',' ')}, /* Russian Buriat */
+ {"byn", HB_TAG('B','I','L',' ')}, /* Bilen */
{"ca", HB_TAG('C','A','T',' ')}, /* Catalan */
+ {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano */
{"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
{"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */
+ {"cgg", HB_TAG('C','G','G',' ')}, /* Chiga */
+ {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */
+ {"cho", HB_TAG('C','H','O',' ')}, /* Choctaw */
{"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
{"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */
+ {"chy", HB_TAG('C','H','Y',' ')}, /* Cheyenne */
+ {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish (Sorani) */
+ {"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */
{"cop", HB_TAG('C','O','P',' ')}, /* Coptic */
{"cr", HB_TAG('C','R','E',' ')}, /* Cree */
{"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */
+ {"crj", HB_TAG('E','C','R',' ')}, /* [Southern] East Cree */
+ {"crl", HB_TAG('E','C','R',' ')}, /* [Northern] East Cree */
{"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */
{"crx", HB_TAG('C','R','R',' ')}, /* Carrier */
{"cs", HB_TAG('C','S','Y',' ')}, /* Czech */
+ {"csb", HB_TAG('C','S','B',' ')}, /* Kashubian */
+ {"ctg", HB_TAG('C','T','G',' ')}, /* Chittagonian */
+ {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol */
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */
{"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
{"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
@@ -221,123 +285,210 @@ static const LangTag ot_languages[] = {
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */
{"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */
{"de", HB_TAG('D','E','U',' ')}, /* German */
- {"din", HB_TAG('D','N','K',' ')}, /* Dinka */
+ {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri */
+ {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari */
+ {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */
+ {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */
+ {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */
{"dng", HB_TAG('D','U','N',' ')}, /* Dungan */
- {"doi", HB_TAG('D','G','R',' ')}, /* Dogri */
+ {"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */
{"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */
- {"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi */
+ {"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi/Divehi/Maldivian */
+ {"dyu", HB_TAG('J','U','L',' ')}, /* Jula */
{"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */
{"ee", HB_TAG('E','W','E',' ')}, /* Ewe */
{"efi", HB_TAG('E','F','I',' ')}, /* Efik */
+ {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian */
{"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) */
+ {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan */
{"en", HB_TAG('E','N','G',' ')}, /* English */
{"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */
{"eot", HB_TAG('B','T','I',' ')}, /* Beti (Côte d'Ivoire) */
{"es", HB_TAG('E','S','P',' ')}, /* Spanish */
- {"et", HB_TAG('E','T','I',' ')}, /* Estonian */
+ {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */
{"eu", HB_TAG('E','U','Q',' ')}, /* Basque */
{"eve", HB_TAG('E','V','N',' ')}, /* Even */
{"evn", HB_TAG('E','V','K',' ')}, /* Evenki */
- {"fa", HB_TAG('F','A','R',' ')}, /* Persian */
- {"ff", HB_TAG('F','U','L',' ')}, /* Fulah */
+ {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */
+ {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */
{"fi", HB_TAG('F','I','N',' ')}, /* Finnish */
{"fil", HB_TAG('P','I','L',' ')}, /* Filipino */
{"fj", HB_TAG('F','J','I',' ')}, /* Fijian */
{"fo", HB_TAG('F','O','S',' ')}, /* Faroese */
{"fon", HB_TAG('F','O','N',' ')}, /* Fon */
{"fr", HB_TAG('F','R','A',' ')}, /* French */
+ {"frc", HB_TAG('F','R','C',' ')}, /* Cajun French */
+ {"frp", HB_TAG('F','R','P',' ')}, /* Arpitan/Francoprovençal */
{"fur", HB_TAG('F','R','L',' ')}, /* Friulian */
+ {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */
{"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian */
{"ga", HB_TAG('I','R','I',' ')}, /* Irish */
{"gaa", HB_TAG('G','A','D',' ')}, /* Ga */
{"gag", HB_TAG('G','A','G',' ')}, /* Gagauz */
{"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */
{"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
+ {"gez", HB_TAG('G','E','Z',' ')}, /* Ge'ez */
+ {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi */
{"gl", HB_TAG('G','A','L',' ')}, /* Galician */
{"gld", HB_TAG('N','A','N',' ')}, /* Nanai */
- {"gn", HB_TAG('G','U','A',' ')}, /* Guarani */
- {"gon", HB_TAG('G','O','N',' ')}, /* Gondi */
+ {"glk", HB_TAG('G','L','K',' ')}, /* Gilaki */
+ {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
+ {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi */
+ {"gog", HB_TAG('G','O','G',' ')}, /* Gogo */
+ {"gon", HB_TAG('G','O','N',' ')}, /* Gondi [macrolanguage] */
{"grt", HB_TAG('G','R','O',' ')}, /* Garo */
+ {"gru", HB_TAG('S','O','G',' ')}, /* Sodo Gurage */
{"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */
+ {"guc", HB_TAG('G','U','C',' ')}, /* Wayuu */
{"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */
- {"gv", HB_TAG('M','N','X',' ')}, /* Manx Gaelic */
+/*{"guk", HB_TAG('G','U','K',' ')},*/ /* Gumuz (in SIL fonts) */
+ {"guz", HB_TAG('G','U','Z',' ')}, /* Ekegusii/Gusii */
+ {"gv", HB_TAG('M','N','X',' ')}, /* Manx */
{"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
{"har", HB_TAG('H','R','I',' ')}, /* Harari */
+ {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiian */
+ {"hay", HB_TAG('H','A','Y',' ')}, /* Haya */
+ {"haz", HB_TAG('H','A','Z',' ')}, /* Hazaragi */
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
+ {"hz", HB_TAG('H','E','R',' ')}, /* Herero */
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
{"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
+ {"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */
+ {"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */
+ {"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */
+ {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */
{"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */
+ {"hoj", HB_TAG('H','A','R',' ')}, /* Harauti */
{"hr", HB_TAG('H','R','V',' ')}, /* Croatian */
{"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */
- {"ht", HB_TAG('H','A','I',' ')}, /* Haitian */
+ {"ht", HB_TAG('H','A','I',' ')}, /* Haitian/Haitian Creole */
{"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */
{"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */
+ {"hz", HB_TAG('H','E','R',' ')}, /* Herero */
+ {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */
+ {"ibb", HB_TAG('I','B','B',' ')}, /* Ibibio */
{"id", HB_TAG('I','N','D',' ')}, /* Indonesian */
+ {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue/Occidental */
{"ig", HB_TAG('I','B','O',' ')}, /* Igbo */
{"igb", HB_TAG('E','B','I',' ')}, /* Ebira */
+ {"ijc", HB_TAG('I','J','O',' ')}, /* Izon */
+ {"ijo", HB_TAG('I','J','O',' ')}, /* Ijo [family] */
+ {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] */
+ {"ilo", HB_TAG('I','L','O',' ')}, /* Ilokano */
{"inh", HB_TAG('I','N','G',' ')}, /* Ingush */
+ {"io", HB_TAG('I','D','O',' ')}, /* Ido */
{"is", HB_TAG('I','S','L',' ')}, /* Icelandic */
{"it", HB_TAG('I','T','A',' ')}, /* Italian */
- {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut */
+ {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */
{"ja", HB_TAG('J','A','N',' ')}, /* Japanese */
+ {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English */
+ {"jbo", HB_TAG('J','B','O',' ')}, /* Lojban */
{"jv", HB_TAG('J','A','V',' ')}, /* Javanese */
{"ka", HB_TAG('K','A','T',' ')}, /* Georgian */
+ {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */
+ {"kab", HB_TAG('K','A','B',' ')}, /* Kabyle */
{"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
+ {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */
{"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */
+ {"kde", HB_TAG('K','D','E',' ')}, /* Makonde */
{"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */
{"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */
+ {"kex", HB_TAG('K','K','N',' ')}, /* Kokni */
{"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */
{"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */
+ {"kg", HB_TAG('K','O','N',' ')}, /* Kongo [macrolanguage] */
{"kha", HB_TAG('K','S','I',' ')}, /* Khasi */
+ {"khb", HB_TAG('X','B','D',' ')}, /* Lü */
+ {"kht", HB_TAG('K','H','N',' ')}, /* Khamti (Microsoft fonts) */
+/*{"kht", HB_TAG('K','H','T',' ')},*/ /* Khamti (OpenType spec and SIL fonts) */
{"khw", HB_TAG('K','H','W',' ')}, /* Khowar */
- {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu */
+ {"ki", HB_TAG('K','I','K',' ')}, /* Gikuyu/Kikuyu */
+ {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama/Kwanyama */
+ {"kjh", HB_TAG('K','H','A',' ')}, /* Khakass */
+ {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen */
{"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */
{"kl", HB_TAG('G','R','N',' ')}, /* Kalaallisut */
{"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin */
{"km", HB_TAG('K','H','M',' ')}, /* Central Khmer */
+ {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu */
{"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */
{"kn", HB_TAG('K','A','N',' ')}, /* Kannada */
+ {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */
{"ko", HB_TAG('K','O','R',' ')}, /* Korean */
{"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */
- {"kok", HB_TAG('K','O','K',' ')}, /* Konkani */
- {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle */
+ {"kok", HB_TAG('K','O','K',' ')}, /* Konkani [macrolanguage] */
+ {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */
{"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */
{"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */
{"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */
- {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri */
+ {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */
{"kri", HB_TAG('K','R','I',' ')}, /* Krio */
{"krl", HB_TAG('K','R','L',' ')}, /* Karelian */
{"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */
{"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */
- {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish */
+ {"ksh", HB_TAG('K','S','H',' ')}, /* Kölsch */
+/*{"ksw", HB_TAG('K','R','N',' ')},*/ /* S'gaw Karen (Microsoft fonts?) */
+ {"ksw", HB_TAG('K','S','W',' ')}, /* S'gaw Karen (OpenType spec and SIL fonts) */
+ {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */
{"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */
+ {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */
{"kvd", HB_TAG('K','U','I',' ')}, /* Kui (Indonesia) */
+ {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */
+ {"kxc", HB_TAG('K','M','S',' ')}, /* Komso */
{"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */
- {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz */
+ {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz/Kyrgyz */
+ {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */
{"la", HB_TAG('L','A','T',' ')}, /* Latin */
{"lad", HB_TAG('J','U','D',' ')}, /* Ladino */
{"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */
{"lbe", HB_TAG('L','A','K',' ')}, /* Lak */
{"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */
+ {"lez", HB_TAG('L','E','Z',' ')}, /* Lezgi */
+ {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */
+ {"li", HB_TAG('L','I','M',' ')}, /* Limburgan/Limburger/Limburgish */
{"lif", HB_TAG('L','M','B',' ')}, /* Limbu */
+ {"lij", HB_TAG('L','I','J',' ')}, /* Ligurian */
+ {"lis", HB_TAG('L','I','S',' ')}, /* Lisu */
+ {"ljp", HB_TAG('L','J','P',' ')}, /* Lampung Api */
+ {"lki", HB_TAG('L','K','I',' ')}, /* Laki */
{"lld", HB_TAG('L','A','D',' ')}, /* Ladin */
+ {"lmn", HB_TAG('L','A','M',' ')}, /* Lambani */
+ {"lmo", HB_TAG('L','M','O',' ')}, /* Lombard */
{"ln", HB_TAG('L','I','N',' ')}, /* Lingala */
{"lo", HB_TAG('L','A','O',' ')}, /* Lao */
+ {"lrc", HB_TAG('L','R','C',' ')}, /* Northern Luri */
{"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */
+ {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */
+ {"lua", HB_TAG('L','U','B',' ')}, /* Luba-Kasai */
{"luo", HB_TAG('L','U','O',' ')}, /* Luo (Kenya and Tanzania) */
- {"luw", HB_TAG('L','U','O',' ')}, /* Luo (Cameroon) */
+ {"lus", HB_TAG('M','I','Z',' ')}, /* Mizo */
+ {"luy", HB_TAG('L','U','H',' ')}, /* Luyia/Oluluyia [macrolanguage] */
+ {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri */
{"lv", HB_TAG('L','V','I',' ')}, /* Latvian */
{"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */
+ {"mad", HB_TAG('M','A','D',' ')}, /* Madurese */
+ {"mag", HB_TAG('M','A','G',' ')}, /* Magahi */
{"mai", HB_TAG('M','T','H',' ')}, /* Maithili */
+ {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */
+ {"man", HB_TAG('M','N','K',' ')}, /* Manding/Mandingo [macrolanguage] */
{"mdc", HB_TAG('M','L','E',' ')}, /* Male (Papua New Guinea) */
{"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */
+ {"mdr", HB_TAG('M','D','R',' ')}, /* Mandar */
{"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */
{"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */
- {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy */
+ {"mer", HB_TAG('M','E','R',' ')}, /* Meru */
+ {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */
+ {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */
+ {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */
+ {"mhr", HB_TAG('L','M','A',' ')}, /* Low Mari */
{"mi", HB_TAG('M','R','I',' ')}, /* Maori */
+ {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */
{"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */
+ {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka */
+ {"mkw", HB_TAG('M','K','W',' ')}, /* Kituba (Congo) */
{"ml", HB_TAG('M','L','R',' ')}, /* Malayalam */
- {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian */
+ {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan */
+ {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
{"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */
{"mni", HB_TAG('M','N','I',' ')}, /* Manipuri */
{"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */
@@ -345,57 +496,119 @@ static const LangTag ot_languages[] = {
{"mnw", HB_TAG('M','O','N',' ')}, /* Mon */
{"mo", HB_TAG('M','O','L',' ')}, /* Moldavian */
{"moh", HB_TAG('M','O','H',' ')}, /* Mohawk */
+ {"mos", HB_TAG('M','O','S',' ')}, /* Mossi */
{"mpe", HB_TAG('M','A','J',' ')}, /* Majang */
{"mr", HB_TAG('M','A','R',' ')}, /* Marathi */
- {"ms", HB_TAG('M','L','Y',' ')}, /* Malay */
+ {"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */
+ {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
+ {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka */
{"mt", HB_TAG('M','T','S',' ')}, /* Maltese */
- {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari */
+ {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari */
+ {"mus", HB_TAG('M','U','S',' ')}, /* Creek */
+ {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */
+ {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan */
+ {"mwl", HB_TAG('M','W','L',' ')}, /* Mirandese */
+ {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */
+ {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */
{"my", HB_TAG('B','R','M',' ')}, /* Burmese */
{"mym", HB_TAG('M','E','N',' ')}, /* Me'en */
+ {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) */
{"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */
+ {"mzn", HB_TAG('M','Z','N',' ')}, /* Mazanderani */
+ {"na", HB_TAG('N','A','U',' ')}, /* Nauru */
+ {"nag", HB_TAG('N','A','G',' ')}, /* Naga-Assamese */
+ {"nah", HB_TAG('N','A','H',' ')}, /* Nahuatl [family] */
+ {"nap", HB_TAG('N','A','P',' ')}, /* Neapolitan */
{"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål */
{"nco", HB_TAG('S','I','B',' ')}, /* Sibe */
+ {"nd", HB_TAG('N','D','B',' ')}, /* [North] Ndebele */
+ {"ndc", HB_TAG('N','D','C',' ')}, /* Ndau */
+ {"nds", HB_TAG('N','D','S',' ')}, /* Low German/Low Saxon */
{"ne", HB_TAG('N','E','P',' ')}, /* Nepali */
{"new", HB_TAG('N','E','W',' ')}, /* Newari */
{"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */
+ {"nga", HB_TAG('N','G','A',' ')}, /* Ngabaka */
{"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */
{"niu", HB_TAG('N','I','U',' ')}, /* Niuean */
{"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */
{"nl", HB_TAG('N','L','D',' ')}, /* Dutch */
{"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk */
- {"no", HB_TAG('N','O','R',' ')}, /* Norwegian (deprecated) */
+ {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */
+ {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai */
+ {"noe", HB_TAG('N','O','E',' ')}, /* Nimadi */
{"nog", HB_TAG('N','O','G',' ')}, /* Nogai */
+ {"nov", HB_TAG('N','O','V',' ')}, /* Novial */
{"nqo", HB_TAG('N','K','O',' ')}, /* N'Ko */
+ {"nr", HB_TAG('N','D','B',' ')}, /* [South] Ndebele */
{"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */
- {"ny", HB_TAG('C','H','I',' ')}, /* Nyanja */
+ {"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */
+ {"ny", HB_TAG('C','H','I',' ')}, /* Chewa/Chichwa/Nyanja */
+ {"nym", HB_TAG('N','Y','M',' ')}, /* Nyamwezi */
+ {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */
{"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
- {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa */
- {"om", HB_TAG('O','R','O',' ')}, /* Oromo */
+ {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] */
+ {"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */
+ {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
{"or", HB_TAG('O','R','I',' ')}, /* Oriya */
{"os", HB_TAG('O','S','S',' ')}, /* Ossetian */
{"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */
+ {"pag", HB_TAG('P','A','G',' ')}, /* Pangasinan */
+ {"pam", HB_TAG('P','A','M',' ')}, /* Kapampangan/Pampanga */
+ {"pap", HB_TAG('P','A','P',' ')}, /* Papiamento */
+ {"pcc", HB_TAG('P','C','C',' ')}, /* Bouyei */
+ {"pcd", HB_TAG('P','C','D',' ')}, /* Picard */
+ {"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */
+ {"pdc", HB_TAG('P','D','C',' ')}, /* Pennsylvania German */
+ {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian */
+ {"phk", HB_TAG('P','H','K',' ')}, /* Phake */
{"pi", HB_TAG('P','A','L',' ')}, /* Pali */
+ {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk */
{"pl", HB_TAG('P','L','K',' ')}, /* Polish */
+ {"pll", HB_TAG('P','L','G',' ')}, /* [Shwe] Palaung */
{"plp", HB_TAG('P','A','P',' ')}, /* Palpa */
- {"prs", HB_TAG('D','R','I',' ')}, /* Dari */
- {"ps", HB_TAG('P','A','S',' ')}, /* Pushto */
+ {"pms", HB_TAG('P','M','S',' ')}, /* Piemontese */
+ {"pnb", HB_TAG('P','N','B',' ')}, /* Western Panjabi */
+ {"prs", HB_TAG('D','R','I',' ')}, /* Afghan Persian/Dari */
+ {"ps", HB_TAG('P','A','S',' ')}, /* Pashto/Pushto [macrolanguage] */
{"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */
- {"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani */
+ {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen */
+ {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */
+ {"quc", HB_TAG('Q','U','C',' ')}, /* K'iche'/Quiché */
+ {"quz", HB_TAG('Q','U','Z',' ')}, /* Cusco Quechua */
+ {"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani [macrolanguage] */
+ {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung */
+ {"rej", HB_TAG('R','E','J',' ')}, /* Rejang */
{"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */
{"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */
+ {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */
+ {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */
+ {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */
+ {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */
{"ro", HB_TAG('R','O','M',' ')}, /* Romanian */
- {"rom", HB_TAG('R','O','Y',' ')}, /* Romany */
+ {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */
{"ru", HB_TAG('R','U','S',' ')}, /* Russian */
{"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */
+ {"rup", HB_TAG('R','U','P',' ')}, /* Aromanian/Arumanian/Macedo-Romanian */
+ {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
+ {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */
{"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */
{"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */
+ {"sas", HB_TAG('S','A','S',' ')}, /* Sasak */
{"sat", HB_TAG('S','A','T',' ')}, /* Santali */
{"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
+ {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
+ {"scn", HB_TAG('S','C','N',' ')}, /* Sicilian */
+ {"sco", HB_TAG('S','C','O',' ')}, /* Scots */
+ {"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */
{"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */
{"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */
{"seh", HB_TAG('S','N','A',' ')}, /* Sena */
{"sel", HB_TAG('S','E','L',' ')}, /* Selkup */
{"sg", HB_TAG('S','G','O',' ')}, /* Sango */
+ {"sga", HB_TAG('S','G','A',' ')}, /* Old Irish (to 900) */
+ {"sgs", HB_TAG('S','G','S',' ')}, /* Samogitian */
+ {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage */
+/*{"sgw", HB_TAG('S','G','W',' ')},*/ /* Sebat Bet Gurage (in SIL fonts) */
{"shn", HB_TAG('S','H','N',' ')}, /* Shan */
{"si", HB_TAG('S','N','H',' ')}, /* Sinhala */
{"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */
@@ -408,174 +621,160 @@ static const LangTag ot_languages[] = {
{"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */
{"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */
{"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */
+ {"sn", HB_TAG('S','N','A',' ')}, /* Shona */
{"snk", HB_TAG('S','N','K',' ')}, /* Soninke */
{"so", HB_TAG('S','M','L',' ')}, /* Somali */
- {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian */
+ {"sop", HB_TAG('S','O','P',' ')}, /* Songe */
+ {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */
{"sr", HB_TAG('S','R','B',' ')}, /* Serbian */
{"srr", HB_TAG('S','R','R',' ')}, /* Serer */
+ {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */
+ {"st", HB_TAG('S','O','T',' ')}, /* [Southern] Sotho */
+ {"stq", HB_TAG('S','T','Q',' ')}, /* Saterfriesisch */
+ {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e */
+ {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */
+ {"suk", HB_TAG('S','U','K',' ')}, /* Sukama */
{"suq", HB_TAG('S','U','R',' ')}, /* Suri */
{"sv", HB_TAG('S','V','E',' ')}, /* Swedish */
{"sva", HB_TAG('S','V','A',' ')}, /* Svan */
- {"sw", HB_TAG('S','W','K',' ')}, /* Swahili */
+ {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */
{"swb", HB_TAG('C','M','R',' ')}, /* Comorian */
- {"syr", HB_TAG('S','Y','R',' ')}, /* Syriac */
+ {"swh", HB_TAG('S','W','K',' ')}, /* Kiswahili/Swahili */
+ {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati */
+ {"sxu", HB_TAG('S','X','U',' ')}, /* Upper Saxon */
+ {"syl", HB_TAG('S','Y','L',' ')}, /* Sylheti */
+ {"syr", HB_TAG('S','Y','R',' ')}, /* Syriac [macrolanguage] */
+ {"szl", HB_TAG('S','Z','L',' ')}, /* Silesian */
{"ta", HB_TAG('T','A','M',' ')}, /* Tamil */
+ {"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */
{"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */
+ {"tdd", HB_TAG('T','D','D',' ')}, /* Tai Nüa */
{"te", HB_TAG('T','E','L',' ')}, /* Telugu */
+ {"tem", HB_TAG('T','M','N',' ')}, /* Temne */
+ {"tet", HB_TAG('T','E','T',' ')}, /* Tetum */
{"tg", HB_TAG('T','A','J',' ')}, /* Tajik */
{"th", HB_TAG('T','H','A',' ')}, /* Thai */
{"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */
{"tig", HB_TAG('T','G','R',' ')}, /* Tigre */
+ {"tiv", HB_TAG('T','I','V',' ')}, /* Tiv */
{"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */
+ {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */
+ {"tmh", HB_TAG('t','m','h',' ')}, /* Tamashek [macrolanguage] */
{"tn", HB_TAG('T','N','A',' ')}, /* Tswana */
- {"tnz", HB_TAG('T','N','G',' ')}, /* Tonga (Thailand) */
- {"to", HB_TAG('T','N','G',' ')}, /* Tonga (Tonga Islands) */
- {"tog", HB_TAG('T','N','G',' ')}, /* Tonga (Nyasa) */
- {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */
+ {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */
+ {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */
{"tr", HB_TAG('T','R','K',' ')}, /* Turkish */
+ {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo Aramaic */
{"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */
{"tt", HB_TAG('T','A','T',' ')}, /* Tatar */
+ {"tum", HB_TAG('T','U','M',' ')}, /* Tumbuka */
{"tw", HB_TAG('T','W','I',' ')}, /* Twi */
{"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */
+ {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvin */
+ {"tyz", HB_TAG('T','Y','Z',' ')}, /* Tày */
+ {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight */
{"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */
{"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */
{"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */
+ {"umb", HB_TAG('U','M','B',' ')}, /* Umbundu */
{"unr", HB_TAG('M','U','N',' ')}, /* Mundari */
{"ur", HB_TAG('U','R','D',' ')}, /* Urdu */
- {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek */
+ {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */
+ {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek */
+ {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek */
{"ve", HB_TAG('V','E','N',' ')}, /* Venda */
+ {"vec", HB_TAG('V','E','C',' ')}, /* Venetian */
+ {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams */
{"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
+ {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */
+ {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */
+ {"vro", HB_TAG('V','R','O',' ')}, /* Võro */
+ {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */
+ {"war", HB_TAG('W','A','R',' ')}, /* Waray (Philippines) */
{"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
{"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
+ {"wle", HB_TAG('S','I','G',' ')}, /* Wolane */
+ {"wry", HB_TAG('M','A','W',' ')}, /* Merwari */
+ {"wtm", HB_TAG('W','T','M',' ')}, /* Mewati */
{"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
{"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
{"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
+ {"xog", HB_TAG('X','O','G',' ')}, /* Soga */
{"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */
{"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */
- {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish */
+ {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) */
+ {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat (Todo) */
+ {"yao", HB_TAG('Y','A','O',' ')}, /* Yao */
+ {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
{"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */
+ {"za", HB_TAG('Z','H','A',' ')}, /* Chuang/Zhuang [macrolanguage] */
+ {"zea", HB_TAG('Z','E','A',' ')}, /* Zeeuws */
{"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
- {"zu", HB_TAG('Z','U','L',' ')} /* Zulu */
-
- /* I couldn't find the language id for these */
-
-/*{"??", HB_TAG('A','G','W',' ')},*/ /* Agaw */
-/*{"??", HB_TAG('A','L','S',' ')},*/ /* Alsatian */
-/*{"??", HB_TAG('A','L','T',' ')},*/ /* Altai */
-/*{"??", HB_TAG('A','R','K',' ')},*/ /* Arakanese */
-/*{"??", HB_TAG('A','T','H',' ')},*/ /* Athapaskan */
-/*{"??", HB_TAG('B','A','G',' ')},*/ /* Baghelkhandi */
-/*{"??", HB_TAG('B','A','L',' ')},*/ /* Balkar */
-/*{"??", HB_TAG('B','A','U',' ')},*/ /* Baule */
-/*{"??", HB_TAG('B','B','R',' ')},*/ /* Berber */
+ {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */
+ {"zum", HB_TAG('L','R','C',' ')} /* Kumzari */
+
+ /* The corresponding languages IDs for the following IDs are unclear,
+ * overlap, or are architecturally weird. Needs more research. */
+
+/*{"ahg/awn/xan?", HB_TAG('A','G','W',' ')},*/ /* Agaw */
+/*{"gsw?/gsw-FR?", HB_TAG('A','L','S',' ')},*/ /* Alsatian */
+/*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */
/*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */
-/*{"??", HB_TAG('B','E','L',' ')},*/ /* Belarussian */
-/*{"??", HB_TAG('B','I','L',' ')},*/ /* Bilen */
-/*{"??", HB_TAG('B','K','F',' ')},*/ /* Blackfoot */
-/*{"??", HB_TAG('B','L','N',' ')},*/ /* Balante */
-/*{"??", HB_TAG('B','M','L',' ')},*/ /* Bamileke */
-/*{"??", HB_TAG('B','R','I',' ')},*/ /* Braj Bhasha */
-/*{"??", HB_TAG('C','H','G',' ')},*/ /* Chaha Gurage */
-/*{"??", HB_TAG('C','H','H',' ')},*/ /* Chattisgarhi */
-/*{"??", HB_TAG('C','H','K',' ')},*/ /* Chukchi */
-/*{"??", HB_TAG('D','J','R',' ')},*/ /* Djerma */
-/*{"??", HB_TAG('D','N','G',' ')},*/ /* Dangme */
-/*{"??", HB_TAG('E','C','R',' ')},*/ /* Eastern Cree */
-/*{"??", HB_TAG('F','A','N',' ')},*/ /* French Antillean */
-/*{"??", HB_TAG('F','L','E',' ')},*/ /* Flemish */
-/*{"??", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */
-/*{"??", HB_TAG('F','T','A',' ')},*/ /* Futa */
-/*{"??", HB_TAG('G','A','R',' ')},*/ /* Garshuni */
-/*{"??", HB_TAG('G','E','Z',' ')},*/ /* Ge'ez */
-/*{"??", HB_TAG('H','A','L',' ')},*/ /* Halam */
-/*{"??", HB_TAG('H','A','R',' ')},*/ /* Harauti */
-/*{"??", HB_TAG('H','A','W',' ')},*/ /* Hawaiin */
-/*{"??", HB_TAG('H','B','N',' ')},*/ /* Hammer-Banna */
-/*{"??", HB_TAG('H','M','A',' ')},*/ /* High Mari */
-/*{"??", HB_TAG('H','N','D',' ')},*/ /* Hindko */
-/*{"??", HB_TAG('I','J','O',' ')},*/ /* Ijo */
-/*{"??", HB_TAG('I','L','O',' ')},*/ /* Ilokano */
-/*{"??", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
-/*{"??", HB_TAG('J','U','L',' ')},*/ /* Jula */
-/*{"??", HB_TAG('K','A','R',' ')},*/ /* Karachay */
-/*{"??", HB_TAG('K','E','B',' ')},*/ /* Kebena */
-/*{"??", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */
-/*{"??", HB_TAG('K','H','A',' ')},*/ /* Khakass */
-/*{"??", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */
-/*{"??", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */
-/*{"??", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */
-/*{"??", HB_TAG('K','I','S',' ')},*/ /* Kisii */
-/*{"??", HB_TAG('K','K','N',' ')},*/ /* Kokni */
-/*{"??", HB_TAG('K','M','S',' ')},*/ /* Komso */
-/*{"??", HB_TAG('K','O','D',' ')},*/ /* Kodagu */
-/*{"??", HB_TAG('K','O','H',' ')},*/ /* Korean Old Hangul */
-/*{"??", HB_TAG('K','O','N',' ')},*/ /* Kikongo */
-/*{"??", HB_TAG('K','R','K',' ')},*/ /* Karakalpak */
-/*{"??", HB_TAG('K','R','N',' ')},*/ /* Karen */
-/*{"??", HB_TAG('K','U','L',' ')},*/ /* Kulvi */
+/*{"zh?", HB_TAG('C','H','N',' ')},*/ /* Chinese (seen in Microsoft fonts) */
+/*{"acf/gcf?", HB_TAG('F','A','N',' ')},*/ /* French Antillean */
+/*{"enf?/yrk?", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */
+/*{"fuf?", HB_TAG('F','T','A',' ')},*/ /* Futa */
+/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */
+/*{"cfm/rnl?", HB_TAG('H','A','L',' ')},*/ /* Halam */
+/*{"fonipa", HB_TAG('I','P','P','H')},*/ /* Phonetic transcription—IPA conventions */
+/*{"ga-Latg?/Latg?", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
+/*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */
+/*{"alw?/ktb?", HB_TAG('K','E','B',' ')},*/ /* Kebena */
+/*{"Geok", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */
+/*{"kca", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */
+/*{"kca", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */
+/*{"kca", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */
+/*{"guz?/kqs?/kss?", HB_TAG('K','I','S',' ')},*/ /* Kisii */
+/*{"kfa/kfi?/kpb?/xua?/xuj?", HB_TAG('K','O','D',' ')},*/ /* Kodagu */
+/*{"okm?/oko?", HB_TAG('K','O','H',' ')},*/ /* Korean Old Hangul */
+/*{"kon?/ktu?/...", HB_TAG('K','O','N',' ')},*/ /* Kikongo */
+/*{"kfx?", HB_TAG('K','U','L',' ')},*/ /* Kulvi */
/*{"??", HB_TAG('L','A','H',' ')},*/ /* Lahuli */
-/*{"??", HB_TAG('L','A','M',' ')},*/ /* Lambani */
/*{"??", HB_TAG('L','C','R',' ')},*/ /* L-Cree */
-/*{"??", HB_TAG('L','E','Z',' ')},*/ /* Lezgi */
-/*{"??", HB_TAG('L','M','A',' ')},*/ /* Low Mari */
-/*{"??", HB_TAG('L','U','B',' ')},*/ /* Luba */
-/*{"??", HB_TAG('L','U','G',' ')},*/ /* Luganda */
-/*{"??", HB_TAG('L','U','H',' ')},*/ /* Luhya */
-/*{"??", HB_TAG('M','A','K',' ')},*/ /* Makua */
/*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */
-/*{"??", HB_TAG('M','B','N',' ')},*/ /* Mbundu */
-/*{"??", HB_TAG('M','I','Z',' ')},*/ /* Mizo */
-/*{"??", HB_TAG('M','L','N',' ')},*/ /* Malinke */
-/*{"??", HB_TAG('M','N','K',' ')},*/ /* Maninka */
-/*{"??", HB_TAG('M','O','R',' ')},*/ /* Moroccan */
-/*{"??", HB_TAG('N','A','G',' ')},*/ /* Naga-Assamese */
+/*{"mnk?/mlq?/...", HB_TAG('M','L','N',' ')},*/ /* Malinke */
/*{"??", HB_TAG('N','C','R',' ')},*/ /* N-Cree */
-/*{"??", HB_TAG('N','D','B',' ')},*/ /* Ndebele */
-/*{"??", HB_TAG('N','G','R',' ')},*/ /* Nagari */
/*{"??", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */
-/*{"??", HB_TAG('N','K','L',' ')},*/ /* Nkole */
-/*{"??", HB_TAG('N','T','A',' ')},*/ /* Northern Tai */
-/*{"??", HB_TAG('O','C','R',' ')},*/ /* Oji-Cree */
-/*{"??", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */
-/*{"??", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */
-/*{"??", HB_TAG('P','L','G',' ')},*/ /* Palaung */
-/*{"??", HB_TAG('Q','I','N',' ')},*/ /* Chin */
-/*{"??", HB_TAG('R','B','U',' ')},*/ /* Russian Buriat */
+/*{"jpa?/sam?", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */
+/*{"polyton", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */
+/*{"??", HB_TAG('Q','I','N',' ')},*/ /* Asho Chin */
/*{"??", HB_TAG('R','C','R',' ')},*/ /* R-Cree */
-/*{"??", HB_TAG('R','M','S',' ')},*/ /* Rhaeto-Romanic */
-/*{"??", HB_TAG('R','U','A',' ')},*/ /* Ruanda */
-/*{"??", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */
-/*{"??", HB_TAG('S','E','K',' ')},*/ /* Sekota */
-/*{"??", HB_TAG('S','I','G',' ')},*/ /* Silte Gurage */
-/*{"??", HB_TAG('S','L','A',' ')},*/ /* Slavey */
-/*{"??", HB_TAG('S','O','G',' ')},*/ /* Sodo Gurage */
-/*{"??", HB_TAG('S','O','T',' ')},*/ /* Sotho */
-/*{"??", HB_TAG('S','W','A',' ')},*/ /* Swadaya Aramaic */
-/*{"??", HB_TAG('S','W','Z',' ')},*/ /* Swazi */
-/*{"??", HB_TAG('S','X','T',' ')},*/ /* Sutu */
-/*{"??", HB_TAG('T','A','B',' ')},*/ /* Tabasaran */
+/*{"chp?", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */
+/*{"xan?", HB_TAG('S','E','K',' ')},*/ /* Sekota */
+/*{"ngo?", HB_TAG('S','X','T',' ')},*/ /* Sutu */
/*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */
-/*{"??", HB_TAG('T','G','N',' ')},*/ /* Tongan */
-/*{"??", HB_TAG('T','M','N',' ')},*/ /* Temne */
-/*{"??", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */
-/*{"??", HB_TAG('T','O','D',' ')},*/ /* Todo */
-/*{"??", HB_TAG('T','U','A',' ')},*/ /* Turoyo Aramaic */
-/*{"??", HB_TAG('T','U','V',' ')},*/ /* Tuvin */
+/*{"tnz?/tog?/toi?", HB_TAG('T','N','G',' ')},*/ /* Tonga */
+/*{"enh?/yrk?", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */
/*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */
-/*{"??", HB_TAG('X','B','D',' ')},*/ /* Tai Lue */
-/*{"??", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */
+/*{"cre?", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */
/*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */
-/*{"??", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */
+/*{"ii?/Yiii?", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */
/*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */
};
-static const LangTag ot_languages_zh[] = {
+typedef struct {
+ char language[8];
+ hb_tag_t tag;
+} LangTagLong;
+static const LangTagLong ot_languages_zh[] = {
{"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */
{"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */
{"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */
{"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */
- {"zh-tw", HB_TAG('Z','H','T',' ')} /* Chinese (Taiwan) */
+ {"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */
+ {"zh-hans", HB_TAG('Z','H','S',' ')}, /* Chinese (Simplified) */
+ {"zh-hant", HB_TAG('Z','H','T',' ')}, /* Chinese (Traditional) */
};
static int
@@ -607,7 +806,6 @@ hb_tag_t
hb_ot_tag_from_language (hb_language_t language)
{
const char *lang_str, *s;
- const LangTag *lang_tag;
if (language == HB_LANGUAGE_INVALID)
return HB_OT_TAG_DEFAULT_LANGUAGE;
@@ -629,11 +827,14 @@ hb_ot_tag_from_language (hb_language_t language)
}
/* Find a language matching in the first component */
- lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
- ARRAY_LENGTH (ot_languages), sizeof (LangTag),
- (hb_compare_func_t) lang_compare_first_component);
- if (lang_tag)
- return lang_tag->tag;
+ {
+ const LangTag *lang_tag;
+ lang_tag = (LangTag *) bsearch (lang_str, ot_languages,
+ ARRAY_LENGTH (ot_languages), sizeof (LangTag),
+ (hb_compare_func_t) lang_compare_first_component);
+ if (lang_tag)
+ return lang_tag->tag;
+ }
/* Otherwise, check the Chinese ones */
if (0 == lang_compare_first_component (lang_str, "zh"))
@@ -642,8 +843,9 @@ hb_ot_tag_from_language (hb_language_t language)
for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++)
{
+ const LangTagLong *lang_tag;
lang_tag = &ot_languages_zh[i];
- if (lang_matches (lang_tag->language, lang_str))
+ if (lang_matches (lang_str, lang_tag->language))
return lang_tag->tag;
}
@@ -656,7 +858,7 @@ hb_ot_tag_from_language (hb_language_t language)
s = lang_str + strlen (lang_str);
if (s - lang_str == 3) {
/* Assume it's ISO-639-3 and upper-case and use it. */
- return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000;
+ return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u;
}
return HB_OT_TAG_DEFAULT_LANGUAGE;
@@ -675,21 +877,12 @@ hb_ot_tag_to_language (hb_tag_t tag)
return hb_language_from_string (ot_languages[i].language, -1);
/* If tag starts with ZH, it's Chinese */
- if ((tag & 0xFFFF0000) == 0x5A480000) {
+ if ((tag & 0xFFFF0000u) == 0x5A480000u) {
switch (tag) {
case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */
- default: {
- /* Encode the tag... */
- unsigned char buf[14] = "zh-x-hbot";
- buf[9] = tag >> 24;
- buf[10] = (tag >> 16) & 0xFF;
- buf[11] = (tag >> 8) & 0xFF;
- buf[12] = tag & 0xFF;
- if (buf[12] == 0x20)
- buf[12] = '\0';
- buf[13] = '\0';
- return hb_language_from_string ((char *) buf, -1);
- }
+ case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -1); /* Simplified */
+ case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -1); /* Traditional */
+ default: break; /* Fall through */
}
}
diff --git a/src/hb-ot.h b/src/hb-ot.h
index 2d750c3..47c92a5 100644
--- a/src/hb-ot.h
+++ b/src/hb-ot.h
@@ -30,18 +30,13 @@
#include "hb.h"
+#include "hb-ot-font.h"
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
+#include "hb-ot-shape.h"
HB_BEGIN_DECLS
-void
-hb_ot_shape_glyphs_closure (hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *features,
- unsigned int num_features,
- hb_set_t *glyphs);
-
HB_END_DECLS
#undef HB_OT_H_IN
diff --git a/src/hb-private.hh b/src/hb-private.hh
index 0cb049e..6505238 100644
--- a/src/hb-private.hh
+++ b/src/hb-private.hh
@@ -54,31 +54,140 @@
#include <stdarg.h>
+/* Compiler attributes */
-/* Essentials */
-#ifndef NULL
-# define NULL ((void *) 0)
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
+#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
+#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
+#else
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#endif
+
+#ifndef __GNUC__
+#undef __attribute__
+#define __attribute__(x)
+#endif
+
+#if __GNUC__ >= 3
+#define HB_PURE_FUNC __attribute__((pure))
+#define HB_CONST_FUNC __attribute__((const))
+#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
+#else
+#define HB_PURE_FUNC
+#define HB_CONST_FUNC
+#define HB_PRINTF_FUNC(format_idx, arg_idx)
+#endif
+#if __GNUC__ >= 4
+#define HB_UNUSED __attribute__((unused))
+#else
+#define HB_UNUSED
+#endif
+
+#ifndef HB_INTERNAL
+# if !defined(__MINGW32__) && !defined(__CYGWIN__)
+# define HB_INTERNAL __attribute__((__visibility__("hidden")))
+# else
+# define HB_INTERNAL
+# endif
#endif
+#if __GNUC__ >= 3
+#define HB_FUNC __PRETTY_FUNCTION__
+#elif defined(_MSC_VER)
+#define HB_FUNC __FUNCSIG__
+#else
+#define HB_FUNC __func__
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ /* We need Windows Vista for both Uniscribe backend and for
+ * MemoryBarrier. We don't support compiling on Windows XP,
+ * though we run on it fine. */
+# if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0600
+# undef _WIN32_WINNT
+# endif
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0600
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# ifndef STRICT
+# define STRICT 1
+# endif
+
+# if defined(_WIN32_WCE)
+ /* Some things not defined on Windows CE. */
+# define strdup _strdup
+# define getenv(Name) NULL
+# define setlocale(Category, Locale) "C"
+static int errno = 0; /* Use something better? */
+# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
+# define getenv(Name) NULL
+# endif
+# if defined(_MSC_VER) && _MSC_VER < 1900
+# define snprintf _snprintf
+# endif
+#endif
+
+#if HAVE_ATEXIT
+/* atexit() is only safe to be called from shared libraries on certain
+ * platforms. Whitelist.
+ * https://bugs.freedesktop.org/show_bug.cgi?id=82246 */
+# if defined(__linux) && defined(__GLIBC_PREREQ)
+# if __GLIBC_PREREQ(2,3)
+/* From atexit() manpage, it's safe with glibc 2.2.3 on Linux. */
+# define HB_USE_ATEXIT 1
+# endif
+# elif defined(_MSC_VER) || defined(__MINGW32__)
+/* For MSVC:
+ * http://msdn.microsoft.com/en-ca/library/tze57ck3.aspx
+ * http://msdn.microsoft.com/en-ca/library/zk17ww08.aspx
+ * mingw32 headers say atexit is safe to use in shared libraries.
+ */
+# define HB_USE_ATEXIT 1
+# elif defined(__ANDROID__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+/* This was fixed in Android NKD r8 or r8b:
+ * https://code.google.com/p/android/issues/detail?id=6455
+ * which introduced GCC 4.6:
+ * https://developer.android.com/tools/sdk/ndk/index.html
+ */
+# define HB_USE_ATEXIT 1
+# endif
+#endif
/* Basics */
+#ifndef NULL
+# define NULL ((void *) 0)
+#endif
+
#undef MIN
-template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
+template <typename Type>
+static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
#undef MAX
-template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
+template <typename Type>
+static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
+
+static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
+{ return (a + (b - 1)) / b; }
#undef ARRAY_LENGTH
-#define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+template <typename Type, unsigned int n>
+static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
+/* A const version, but does not detect erratically being called on pointers. */
+#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
#define HB_STMT_START do
#define HB_STMT_END while (0)
-#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC1(_line, _cond) HB_UNUSED typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
@@ -125,7 +234,7 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
/* Check _assertion in a method environment */
#define _ASSERT_POD1(_line) \
- inline void _static_assertion_on_line_##_line (void) const \
+ HB_UNUSED inline void _static_assertion_on_line_##_line (void) const \
{ _ASSERT_INSTANCE_POD1 (_line, *this); /* Make sure it's POD. */ }
# define _ASSERT_POD0(_line) _ASSERT_POD1 (_line)
# define ASSERT_POD() _ASSERT_POD0 (__LINE__)
@@ -134,68 +243,10 @@ ASSERT_STATIC (sizeof (hb_var_int_t) == 4);
/* Misc */
-
-#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
-#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
-#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
-#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
-#else
-#define likely(expr) (expr)
-#define unlikely(expr) (expr)
-#endif
-
-#ifndef __GNUC__
-#undef __attribute__
-#define __attribute__(x)
-#endif
-
-#if __GNUC__ >= 3
-#define HB_PURE_FUNC __attribute__((pure))
-#define HB_CONST_FUNC __attribute__((const))
-#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx)))
-#else
-#define HB_PURE_FUNC
-#define HB_CONST_FUNC
-#define HB_PRINTF_FUNC(format_idx, arg_idx)
-#endif
-#if __GNUC__ >= 4
-#define HB_UNUSED __attribute__((unused))
-#else
-#define HB_UNUSED
-#endif
-
-#ifndef HB_INTERNAL
-# ifndef __MINGW32__
-# define HB_INTERNAL __attribute__((__visibility__("hidden")))
-# else
-# define HB_INTERNAL
-# endif
-#endif
-
-
-#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
-#define snprintf _snprintf
-#endif
-
-#ifdef _MSC_VER
-#undef inline
-#define inline __inline
-#endif
-
-#ifdef __STRICT_ANSI__
-#undef inline
-#define inline __inline__
-#endif
-
-
-#if __GNUC__ >= 3
-#define HB_FUNC __PRETTY_FUNCTION__
-#elif defined(_MSC_VER)
-#define HB_FUNC __FUNCSIG__
-#else
-#define HB_FUNC __func__
-#endif
-
+/* Void! */
+struct _hb_void_t {};
+typedef const _hb_void_t &hb_void_t;
+#define HB_VOID (* (const _hb_void_t *) NULL)
/* Return the number of 1 bits in mask. */
static inline HB_CONST_FUNC unsigned int
@@ -205,7 +256,7 @@ _hb_popcount32 (uint32_t mask)
return __builtin_popcount (mask);
#else
/* "HACKMEM 169" */
- register uint32_t y;
+ uint32_t y;
y = (mask >> 1) &033333333333;
y = mask - y - ((y >>1) & 033333333333);
return (((y + (y >> 3)) & 030707070707) % 077);
@@ -219,7 +270,7 @@ _hb_bit_storage (unsigned int number)
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
#else
- register unsigned int n_bits = 0;
+ unsigned int n_bits = 0;
while (number) {
n_bits++;
number >>= 1;
@@ -235,7 +286,7 @@ _hb_ctz (unsigned int number)
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
return likely (number) ? __builtin_ctz (number) : 0;
#else
- register unsigned int n_bits = 0;
+ unsigned int n_bits = 0;
if (unlikely (!number)) return 0;
while (!(number & 1)) {
n_bits++;
@@ -261,8 +312,8 @@ typedef int (*hb_compare_func_t) (const void *, const void *);
/* arrays and maps */
-#define HB_PREALLOCED_ARRAY_INIT {0}
-template <typename Type, unsigned int StaticSize>
+#define HB_PREALLOCED_ARRAY_INIT {0, 0, NULL}
+template <typename Type, unsigned int StaticSize=16>
struct hb_prealloced_array_t
{
unsigned int len;
@@ -310,14 +361,22 @@ struct hb_prealloced_array_t
inline void pop (void)
{
len--;
- /* TODO: shrink array if needed */
+ }
+
+ inline void remove (unsigned int i)
+ {
+ if (unlikely (i >= len))
+ return;
+ memmove (static_cast<void *> (&array[i]),
+ static_cast<void *> (&array[i + 1]),
+ (len - i - 1) * sizeof (Type));
+ len--;
}
inline void shrink (unsigned int l)
{
if (l < len)
len = l;
- /* TODO: shrink array if needed */
}
template <typename T>
@@ -335,14 +394,14 @@ struct hb_prealloced_array_t
return NULL;
}
- inline void sort (void)
+ inline void qsort (void)
{
- qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
+ ::qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp);
}
- inline void sort (unsigned int start, unsigned int end)
+ inline void qsort (unsigned int start, unsigned int end)
{
- qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
+ ::qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp);
}
template <typename T>
@@ -365,6 +424,13 @@ struct hb_prealloced_array_t
}
};
+template <typename Type>
+struct hb_auto_array_t : hb_prealloced_array_t <Type>
+{
+ hb_auto_array_t (void) { hb_prealloced_array_t<Type>::init (); }
+ ~hb_auto_array_t (void) { hb_prealloced_array_t<Type>::finish (); }
+};
+
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
template <typename item_t, typename lock_t>
@@ -442,6 +508,11 @@ struct hb_lockable_set_t
inline void finish (lock_t &l)
{
+ if (!items.len) {
+ /* No need for locking. */
+ items.finish ();
+ return;
+ }
l.lock ();
while (items.len) {
item_t old = items[items.len - 1];
@@ -457,39 +528,14 @@ struct hb_lockable_set_t
};
-
-
-/* Big-endian handling */
-
-static inline uint16_t hb_be_uint16 (const uint16_t v)
-{
- const uint8_t *V = (const uint8_t *) &v;
- return (uint16_t) (V[0] << 8) + V[1];
-}
-
-/* Note, of the following macros, uint16_get is the one called many many times.
- * If there is any optimizations to be done, it's in that macro. However, I
- * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which
- * results in a single ror instruction, does NOT speed this up. In fact, it
- * resulted in a minor slowdown. At any rate, note that v may not be correctly
- * aligned, so I think the current implementation is optimal.
- */
-
-#define hb_be_uint16_put(v,V) HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
-#define hb_be_uint16_get(v) (uint16_t) ((v[0] << 8) + v[1])
-#define hb_be_uint16_eq(a,b) (a[0] == b[0] && a[1] == b[1])
-
-#define hb_be_uint32_put(v,V) HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END
-#define hb_be_uint32_get(v) (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
-#define hb_be_uint32_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
-
-
/* ASCII tag/character handling */
-static inline unsigned char ISALPHA (unsigned char c)
+static inline bool ISALPHA (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
-static inline unsigned char ISALNUM (unsigned char c)
+static inline bool ISALNUM (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
+static inline bool ISSPACE (unsigned char c)
+{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
static inline unsigned char TOUPPER (unsigned char c)
{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
static inline unsigned char TOLOWER (unsigned char c)
@@ -523,10 +569,43 @@ _hb_debug (unsigned int level,
return level < max_level;
}
-#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
-#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0))
+#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
+#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
+
+static inline void
+_hb_print_func (const char *func)
+{
+ if (func)
+ {
+ unsigned int func_len = strlen (func);
+ /* Skip "static" */
+ if (0 == strncmp (func, "static ", 7))
+ func += 7;
+ /* Skip "typename" */
+ if (0 == strncmp (func, "typename ", 9))
+ func += 9;
+ /* Skip return type */
+ const char *space = strchr (func, ' ');
+ if (space)
+ func = space + 1;
+ /* Skip parameter list */
+ const char *paren = strchr (func, '(');
+ if (paren)
+ func_len = paren - func;
+ fprintf (stderr, "%.*s", func_len, func);
+ }
+}
-template <int max_level> inline void
+template <int max_level> static inline void
+_hb_debug_msg_va (const char *what,
+ const void *obj,
+ const char *func,
+ bool indented,
+ unsigned int level,
+ int level_dir,
+ const char *message,
+ va_list ap) HB_PRINTF_FUNC(7, 0);
+template <int max_level> static inline void
_hb_debug_msg_va (const char *what,
const void *obj,
const char *func,
@@ -547,26 +626,28 @@ _hb_debug_msg_va (const char *what,
fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
if (indented) {
- static const char bars[] = "││││││││││││││││││││││││││││││││││││││││";
- fprintf (stderr, "%2d %s├%s",
+/* One may want to add ASCII version of these. See:
+ * https://bugs.freedesktop.org/show_bug.cgi?id=50970 */
+#define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
+#define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+#define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
+#define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
+#define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */
+ static const char bars[] = VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
+ fprintf (stderr, "%2u %s" VRBAR "%s",
level,
- bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), 3 * level),
- level_dir ? (level_dir > 0 ? "╮" : "╯") : "╴");
+ bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), (unsigned int) (sizeof (VBAR) - 1) * level),
+ level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
} else
- fprintf (stderr, " ├╴");
+ fprintf (stderr, " " VRBAR LBAR);
- if (func) {
- /* If there's a class name, just write that. */
- const char *dotdot = strstr (func, "::");
- const char *space = strchr (func, ' ');
- if (space && dotdot && space < dotdot)
- func = space + 1;
- unsigned int func_len = dotdot ? dotdot - func : strlen (func);
- fprintf (stderr, "%.*s: ", func_len, func);
- }
+ _hb_print_func (func);
if (message)
+ {
+ fprintf (stderr, ": ");
vfprintf (stderr, message, ap);
+ }
fprintf (stderr, "\n");
}
@@ -580,7 +661,7 @@ _hb_debug_msg_va<0> (const char *what HB_UNUSED,
const char *message HB_UNUSED,
va_list ap HB_UNUSED) {}
-template <int max_level> inline void
+template <int max_level> static inline void
_hb_debug_msg (const char *what,
const void *obj,
const char *func,
@@ -589,7 +670,7 @@ _hb_debug_msg (const char *what,
int level_dir,
const char *message,
...) HB_PRINTF_FUNC(7, 8);
-template <int max_level> inline void
+template <int max_level> static inline void
_hb_debug_msg (const char *what,
const void *obj,
const char *func,
@@ -629,10 +710,41 @@ _hb_debug_msg<0> (const char *what HB_UNUSED,
/*
+ * Printer
+ */
+
+template <typename T>
+struct hb_printer_t {
+ const char *print (const T&) { return "something"; }
+};
+
+template <>
+struct hb_printer_t<bool> {
+ const char *print (bool v) { return v ? "true" : "false"; }
+};
+
+template <>
+struct hb_printer_t<hb_void_t> {
+ const char *print (hb_void_t) { return ""; }
+};
+
+
+/*
* Trace
*/
-template <int max_level>
+template <typename T>
+static inline void _hb_warn_no_return (bool returned)
+{
+ if (unlikely (!returned)) {
+ fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN. This is a bug, please report.\n");
+ }
+}
+template <>
+/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
+{}
+
+template <int max_level, typename ret_t>
struct hb_auto_trace_t {
explicit inline hb_auto_trace_t (unsigned int *plevel_,
const char *what_,
@@ -650,23 +762,23 @@ struct hb_auto_trace_t {
}
inline ~hb_auto_trace_t (void)
{
- if (unlikely (!returned)) {
- fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN. This is a bug, please report. Level was %d.\n", plevel ? *plevel : -1);
+ _hb_warn_no_return<ret_t> (returned);
+ if (!returned) {
_hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " ");
- return;
}
-
if (plevel) --*plevel;
}
- inline bool ret (bool v)
+ inline ret_t ret (ret_t v, unsigned int line = 0)
{
if (unlikely (returned)) {
fprintf (stderr, "OUCH, double calls to TRACE_RETURN. This is a bug, please report.\n");
return v;
}
- _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, "return %s", v ? "true" : "false");
+ _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1,
+ "return %s (line %d)",
+ hb_printer_t<ret_t>().print (v), line);
if (plevel) --*plevel;
plevel = NULL;
returned = true;
@@ -675,12 +787,12 @@ struct hb_auto_trace_t {
private:
unsigned int *plevel;
- bool returned;
const char *what;
const void *obj;
+ bool returned;
};
-template <> /* Optimize when tracing is disabled */
-struct hb_auto_trace_t<0> {
+template <typename ret_t> /* Optimize when tracing is disabled */
+struct hb_auto_trace_t<0, ret_t> {
explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED,
const char *what HB_UNUSED,
const void *obj HB_UNUSED,
@@ -688,28 +800,44 @@ struct hb_auto_trace_t<0> {
const char *message HB_UNUSED,
...) {}
- template <typename T>
- inline T ret (T v) { return v; }
+ inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
};
-#define TRACE_RETURN(RET) trace.ret (RET)
+#define TRACE_RETURN(RET) trace.ret (RET, __LINE__)
/* Misc */
+template <typename T> class hb_assert_unsigned_t;
+template <> class hb_assert_unsigned_t<unsigned char> {};
+template <> class hb_assert_unsigned_t<unsigned short> {};
+template <> class hb_assert_unsigned_t<unsigned int> {};
+template <> class hb_assert_unsigned_t<unsigned long> {};
-/* Pre-mature optimization:
- * Checks for lo <= u <= hi but with an optimization if lo and hi
- * are only different in a contiguous set of lower-most bits.
- */
-template <typename T> inline bool
+template <typename T> static inline bool
hb_in_range (T u, T lo, T hi)
{
- if ( ((lo^hi) & lo) == 0 &&
- ((lo^hi) & hi) == (lo^hi) &&
- ((lo^hi) & ((lo^hi) + 1)) == 0 )
- return (u & ~(lo^hi)) == lo;
- else
- return lo <= u && u <= hi;
+ /* The sizeof() is here to force template instantiation.
+ * I'm sure there are better ways to do this but can't think of
+ * one right now. Declaring a variable won't work as HB_UNUSED
+ * is unusable on some platforms and unused types are less likely
+ * to generate a warning than unused variables. */
+ ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
+
+ /* The casts below are important as if T is smaller than int,
+ * the subtract results will become a signed int! */
+ return (T)(u - lo) <= (T)(hi - lo);
+}
+
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
+{
+ return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
+}
+
+template <typename T> static inline bool
+hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
+{
+ return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
}
@@ -718,10 +846,11 @@ hb_in_range (T u, T lo, T hi)
* (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
*/
#define FLAG(x) (1<<(x))
+#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
-template <typename T> inline void
-hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+template <typename T, typename T2> static inline void
+hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
{
if (unlikely (!len))
return;
@@ -731,11 +860,21 @@ hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
unsigned int new_k = 0;
for (unsigned int j = 0; j < k; j++)
- if (compar (&array[j], &array[j+1]) > 0) {
- T t;
- t = array[j];
- array[j] = array[j + 1];
- array[j + 1] = t;
+ if (compar (&array[j], &array[j+1]) > 0)
+ {
+ {
+ T t;
+ t = array[j];
+ array[j] = array[j + 1];
+ array[j + 1] = t;
+ }
+ if (array2)
+ {
+ T2 t;
+ t = array2[j];
+ array2[j] = array2[j + 1];
+ array2[j + 1] = t;
+ }
new_k = j;
}
@@ -743,7 +882,58 @@ hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
} while (k);
}
+template <typename T> static inline void
+hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
+{
+ hb_bubble_sort (array, len, compar, (int *) NULL);
+}
+
+static inline hb_bool_t
+hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
+{
+ /* Pain because we don't know whether s is nul-terminated. */
+ char buf[64];
+ len = MIN (ARRAY_LENGTH (buf) - 1, len);
+ strncpy (buf, s, len);
+ buf[len] = '\0';
+
+ char *end;
+ errno = 0;
+ unsigned long v = strtoul (buf, &end, base);
+ if (errno) return false;
+ if (*end) return false;
+ *out = v;
+ return true;
+}
+
+/* Global runtime options. */
+
+struct hb_options_t
+{
+ unsigned int initialized : 1;
+ unsigned int uniscribe_bug_compatible : 1;
+};
+
+union hb_options_union_t {
+ unsigned int i;
+ hb_options_t opts;
+};
+ASSERT_STATIC (sizeof (int) == sizeof (hb_options_union_t));
+
+HB_INTERNAL void
+_hb_options_init (void);
+
+extern HB_INTERNAL hb_options_union_t _hb_options;
+
+static inline hb_options_t
+hb_options (void)
+{
+ if (unlikely (!_hb_options.i))
+ _hb_options_init ();
+
+ return _hb_options.opts;
+}
#endif /* HB_PRIVATE_HH */
diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh
index 5cdf8a0..acba4e9 100644
--- a/src/hb-set-private.hh
+++ b/src/hb-set-private.hh
@@ -28,27 +28,142 @@
#define HB_SET_PRIVATE_HH
#include "hb-private.hh"
-#include "hb-set.h"
#include "hb-object-private.hh"
+/*
+ * The set digests here implement various "filters" that support
+ * "approximate member query". Conceptually these are like Bloom
+ * Filter and Quotient Filter, however, much smaller, faster, and
+ * designed to fit the requirements of our uses for glyph coverage
+ * queries. As a result, our filters have much higher.
+ */
+
+template <typename mask_t, unsigned int shift>
+struct hb_set_digest_lowest_bits_t
+{
+ ASSERT_POD ();
+
+ static const unsigned int mask_bytes = sizeof (mask_t);
+ static const unsigned int mask_bits = sizeof (mask_t) * 8;
+ static const unsigned int num_bits = 0
+ + (mask_bytes >= 1 ? 3 : 0)
+ + (mask_bytes >= 2 ? 1 : 0)
+ + (mask_bytes >= 4 ? 1 : 0)
+ + (mask_bytes >= 8 ? 1 : 0)
+ + (mask_bytes >= 16? 1 : 0)
+ + 0;
+
+ ASSERT_STATIC (shift < sizeof (hb_codepoint_t) * 8);
+ ASSERT_STATIC (shift + num_bits <= sizeof (hb_codepoint_t) * 8);
+
+ inline void init (void) {
+ mask = 0;
+ }
+
+ inline void add (hb_codepoint_t g) {
+ mask |= mask_for (g);
+ }
+
+ inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+ if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+ mask = (mask_t) -1;
+ else {
+ mask_t ma = mask_for (a);
+ mask_t mb = mask_for (b);
+ mask |= mb + (mb - ma) - (mb < ma);
+ }
+ }
+
+ inline bool may_have (hb_codepoint_t g) const {
+ return !!(mask & mask_for (g));
+ }
+
+ private:
+
+ static inline mask_t mask_for (hb_codepoint_t g) {
+ return ((mask_t) 1) << ((g >> shift) & (mask_bits - 1));
+ }
+ mask_t mask;
+};
+
+template <typename head_t, typename tail_t>
+struct hb_set_digest_combiner_t
+{
+ ASSERT_POD ();
+
+ inline void init (void) {
+ head.init ();
+ tail.init ();
+ }
+
+ inline void add (hb_codepoint_t g) {
+ head.add (g);
+ tail.add (g);
+ }
+
+ inline void add_range (hb_codepoint_t a, hb_codepoint_t b) {
+ head.add_range (a, b);
+ tail.add_range (a, b);
+ }
+
+ inline bool may_have (hb_codepoint_t g) const {
+ return head.may_have (g) && tail.may_have (g);
+ }
+
+ private:
+ head_t head;
+ tail_t tail;
+};
+
+
+/*
+ * hb_set_digest_t
+ *
+ * This is a combination of digests that performs "best".
+ * There is not much science to this: it's a result of intuition
+ * and testing.
+ */
+typedef hb_set_digest_combiner_t
+<
+ hb_set_digest_lowest_bits_t<unsigned long, 4>,
+ hb_set_digest_combiner_t
+ <
+ hb_set_digest_lowest_bits_t<unsigned long, 0>,
+ hb_set_digest_lowest_bits_t<unsigned long, 9>
+ >
+> hb_set_digest_t;
+
+
+
+/*
+ * hb_set_t
+ */
+
+
/* TODO Make this faster and memmory efficient. */
-struct _hb_set_t
+struct hb_set_t
{
+ friend struct hb_frozen_set_t;
+
hb_object_header_t header;
ASSERT_POD ();
+ bool in_error;
inline void init (void) {
- header.init ();
+ hb_object_init (this);
clear ();
}
inline void fini (void) {
}
inline void clear (void) {
+ if (unlikely (hb_object_is_inert (this)))
+ return;
+ in_error = false;
memset (elts, 0, sizeof elts);
}
- inline bool empty (void) const {
+ inline bool is_empty (void) const {
for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++)
if (elts[i])
return false;
@@ -56,15 +171,31 @@ struct _hb_set_t
}
inline void add (hb_codepoint_t g)
{
- if (unlikely (g == SENTINEL)) return;
+ if (unlikely (in_error)) return;
+ if (unlikely (g == INVALID)) return;
if (unlikely (g > MAX_G)) return;
elt (g) |= mask (g);
}
+ inline void add_range (hb_codepoint_t a, hb_codepoint_t b)
+ {
+ if (unlikely (in_error)) return;
+ /* TODO Speedup */
+ for (unsigned int i = a; i < b + 1; i++)
+ add (i);
+ }
inline void del (hb_codepoint_t g)
{
+ if (unlikely (in_error)) return;
if (unlikely (g > MAX_G)) return;
elt (g) &= ~mask (g);
}
+ inline void del_range (hb_codepoint_t a, hb_codepoint_t b)
+ {
+ if (unlikely (in_error)) return;
+ /* TODO Speedup */
+ for (unsigned int i = a; i < b + 1; i++)
+ del (i);
+ }
inline bool has (hb_codepoint_t g) const
{
if (unlikely (g > MAX_G)) return false;
@@ -81,7 +212,7 @@ struct _hb_set_t
return true;
return false;
}
- inline bool equal (const hb_set_t *other) const
+ inline bool is_equal (const hb_set_t *other) const
{
for (unsigned int i = 0; i < ELTS; i++)
if (elts[i] != other->elts[i])
@@ -90,54 +221,93 @@ struct _hb_set_t
}
inline void set (const hb_set_t *other)
{
+ if (unlikely (in_error)) return;
for (unsigned int i = 0; i < ELTS; i++)
elts[i] = other->elts[i];
}
inline void union_ (const hb_set_t *other)
{
+ if (unlikely (in_error)) return;
for (unsigned int i = 0; i < ELTS; i++)
elts[i] |= other->elts[i];
}
inline void intersect (const hb_set_t *other)
{
+ if (unlikely (in_error)) return;
for (unsigned int i = 0; i < ELTS; i++)
elts[i] &= other->elts[i];
}
inline void subtract (const hb_set_t *other)
{
+ if (unlikely (in_error)) return;
for (unsigned int i = 0; i < ELTS; i++)
elts[i] &= ~other->elts[i];
}
inline void symmetric_difference (const hb_set_t *other)
{
+ if (unlikely (in_error)) return;
for (unsigned int i = 0; i < ELTS; i++)
elts[i] ^= other->elts[i];
}
- inline bool next (hb_codepoint_t *codepoint)
+ inline void invert (void)
+ {
+ if (unlikely (in_error)) return;
+ for (unsigned int i = 0; i < ELTS; i++)
+ elts[i] = ~elts[i];
+ }
+ inline bool next (hb_codepoint_t *codepoint) const
{
- if (unlikely (*codepoint == SENTINEL)) {
+ if (unlikely (*codepoint == INVALID)) {
hb_codepoint_t i = get_min ();
- if (i != SENTINEL) {
+ if (i != INVALID) {
*codepoint = i;
return true;
- } else
+ } else {
+ *codepoint = INVALID;
return false;
+ }
}
for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++)
if (has (i)) {
*codepoint = i;
return true;
}
+ *codepoint = INVALID;
return false;
}
+ inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+ {
+ hb_codepoint_t i;
+
+ i = *last;
+ if (!next (&i))
+ {
+ *last = *first = INVALID;
+ return false;
+ }
+
+ *last = *first = i;
+ while (next (&i) && i == *last + 1)
+ (*last)++;
+
+ return true;
+ }
+
+ inline unsigned int get_population (void) const
+ {
+ unsigned int count = 0;
+ for (unsigned int i = 0; i < ELTS; i++)
+ count += _hb_popcount32 (elts[i]);
+ return count;
+ }
inline hb_codepoint_t get_min (void) const
{
for (unsigned int i = 0; i < ELTS; i++)
if (elts[i])
- for (unsigned int j = 0; i < BITS; j++)
+ for (unsigned int j = 0; j < BITS; j++)
if (elts[i] & (1 << j))
return i * BITS + j;
- return SENTINEL;
+ return INVALID;
}
inline hb_codepoint_t get_max (void) const
{
@@ -146,7 +316,7 @@ struct _hb_set_t
for (unsigned int j = BITS; j; j--)
if (elts[i - 1] & (1 << (j - 1)))
return (i - 1) * BITS + (j - 1);
- return SENTINEL;
+ return INVALID;
}
typedef uint32_t elt_t;
@@ -155,10 +325,10 @@ struct _hb_set_t
static const unsigned int BITS = (1 << SHIFT);
static const unsigned int MASK = BITS - 1;
static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS;
- static const hb_codepoint_t SENTINEL = (hb_codepoint_t) -1;
+ static const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
- elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+ elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
elt_t elts[ELTS]; /* XXX 8kb */
@@ -167,6 +337,59 @@ struct _hb_set_t
ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
};
+struct hb_frozen_set_t
+{
+ static const unsigned int SHIFT = hb_set_t::SHIFT;
+ static const unsigned int BITS = hb_set_t::BITS;
+ static const unsigned int MASK = hb_set_t::MASK;
+ typedef hb_set_t::elt_t elt_t;
+
+ inline void init (const hb_set_t &set)
+ {
+ start = count = 0;
+ elts = NULL;
+
+ unsigned int max = set.get_max ();
+ if (max == set.INVALID)
+ return;
+ unsigned int min = set.get_min ();
+ const elt_t &min_elt = set.elt (min);
+ const elt_t &max_elt = set.elt (max);
+
+ start = min & ~MASK;
+ count = max - start + 1;
+ unsigned int num_elts = (count + BITS - 1) / BITS;
+ unsigned int elts_size = num_elts * sizeof (elt_t);
+ elts = (elt_t *) malloc (elts_size);
+ if (unlikely (!elts))
+ {
+ start = count = 0;
+ return;
+ }
+ memcpy (elts, &min_elt, elts_size);
+ }
+
+ inline void fini (void)
+ {
+ if (elts)
+ free (elts);
+ }
+
+ inline bool has (hb_codepoint_t g) const
+ {
+ /* hb_codepoint_t is unsigned. */
+ g -= start;
+ if (unlikely (g > count)) return false;
+ return !!(elt (g) & mask (g));
+ }
+
+ elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+ elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
+
+ private:
+ hb_codepoint_t start, count;
+ elt_t *elts;
+};
#endif /* HB_SET_PRIVATE_HH */
diff --git a/src/hb-set.cc b/src/hb-set.cc
index 4225e3c..59a0af4 100644
--- a/src/hb-set.cc
+++ b/src/hb-set.cc
@@ -27,12 +27,18 @@
#include "hb-set-private.hh"
-
/* Public API */
+/**
+ * hb_set_create: (Xconstructor)
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_set_t *
-hb_set_create ()
+hb_set_create (void)
{
hb_set_t *set;
@@ -44,11 +50,19 @@ hb_set_create ()
return set;
}
+/**
+ * hb_set_get_empty:
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_set_t *
hb_set_get_empty (void)
{
static const hb_set_t _hb_set_nil = {
HB_OBJECT_HEADER_STATIC,
+ true, /* in_error */
{0} /* elts */
};
@@ -56,12 +70,26 @@ hb_set_get_empty (void)
return const_cast<hb_set_t *> (&_hb_set_nil);
}
+/**
+ * hb_set_reference: (skip)
+ * @set: a set.
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_set_t *
hb_set_reference (hb_set_t *set)
{
return hb_object_reference (set);
}
+/**
+ * hb_set_destroy: (skip)
+ * @set: a set.
+ *
+ * Since: 1.0
+ **/
void
hb_set_destroy (hb_set_t *set)
{
@@ -72,49 +100,118 @@ hb_set_destroy (hb_set_t *set)
free (set);
}
+/**
+ * hb_set_set_user_data: (skip)
+ * @set: a set.
+ * @key:
+ * @data:
+ * @destroy (closure data):
+ * @replace:
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_set_set_user_data (hb_set_t *set,
- hb_user_data_key_t *key,
- void * data,
- hb_destroy_func_t destroy,
- hb_bool_t replace)
+hb_set_set_user_data (hb_set_t *set,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace)
{
return hb_object_set_user_data (set, key, data, destroy, replace);
}
+/**
+ * hb_set_get_user_data: (skip)
+ * @set: a set.
+ * @key:
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
void *
-hb_set_get_user_data (hb_set_t *set,
- hb_user_data_key_t *key)
+hb_set_get_user_data (hb_set_t *set,
+ hb_user_data_key_t *key)
{
return hb_object_get_user_data (set, key);
}
+/**
+ * hb_set_allocation_successful:
+ * @set: a set.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_set_allocation_successful (hb_set_t *set HB_UNUSED)
+hb_set_allocation_successful (const hb_set_t *set HB_UNUSED)
{
- return true;
+ return !set->in_error;
}
+/**
+ * hb_set_clear:
+ * @set: a set.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_set_clear (hb_set_t *set)
{
set->clear ();
}
+/**
+ * hb_set_is_empty:
+ * @set: a set.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_set_empty (hb_set_t *set)
+hb_set_is_empty (const hb_set_t *set)
{
- return set->empty ();
+ return set->is_empty ();
}
+/**
+ * hb_set_has:
+ * @set: a set.
+ * @codepoint:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_set_has (hb_set_t *set,
+hb_set_has (const hb_set_t *set,
hb_codepoint_t codepoint)
{
return set->has (codepoint);
}
+/**
+ * hb_set_add:
+ * @set: a set.
+ * @codepoint:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_set_add (hb_set_t *set,
hb_codepoint_t codepoint)
@@ -122,6 +219,33 @@ hb_set_add (hb_set_t *set,
set->add (codepoint);
}
+/**
+ * hb_set_add_range:
+ * @set: a set.
+ * @first:
+ * @last:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_set_add_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last)
+{
+ set->add_range (first, last);
+}
+
+/**
+ * hb_set_del:
+ * @set: a set.
+ * @codepoint:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint)
@@ -129,63 +253,219 @@ hb_set_del (hb_set_t *set,
set->del (codepoint);
}
+/**
+ * hb_set_del_range:
+ * @set: a set.
+ * @first:
+ * @last:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_set_del_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last)
+{
+ set->del_range (first, last);
+}
+
+/**
+ * hb_set_is_equal:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_set_equal (hb_set_t *set,
- hb_set_t *other)
+hb_set_is_equal (const hb_set_t *set,
+ const hb_set_t *other)
{
- return set->equal (other);
+ return set->is_equal (other);
}
+/**
+ * hb_set_set:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
-hb_set_set (hb_set_t *set,
- hb_set_t *other)
+hb_set_set (hb_set_t *set,
+ const hb_set_t *other)
{
set->set (other);
}
+/**
+ * hb_set_union:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
-hb_set_union (hb_set_t *set,
- hb_set_t *other)
+hb_set_union (hb_set_t *set,
+ const hb_set_t *other)
{
set->union_ (other);
}
+/**
+ * hb_set_intersect:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
-hb_set_intersect (hb_set_t *set,
- hb_set_t *other)
+hb_set_intersect (hb_set_t *set,
+ const hb_set_t *other)
{
set->intersect (other);
}
+/**
+ * hb_set_subtract:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
-hb_set_subtract (hb_set_t *set,
- hb_set_t *other)
+hb_set_subtract (hb_set_t *set,
+ const hb_set_t *other)
{
set->subtract (other);
}
+/**
+ * hb_set_symmetric_difference:
+ * @set: a set.
+ * @other:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
-hb_set_symmetric_difference (hb_set_t *set,
- hb_set_t *other)
+hb_set_symmetric_difference (hb_set_t *set,
+ const hb_set_t *other)
{
set->symmetric_difference (other);
}
+/**
+ * hb_set_invert:
+ * @set: a set.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_set_invert (hb_set_t *set)
+{
+ set->invert ();
+}
+
+/**
+ * hb_set_get_population:
+ * @set: a set.
+ *
+ * Returns the number of numbers in the set.
+ *
+ * Return value: set population.
+ *
+ * Since: 1.0
+ **/
+unsigned int
+hb_set_get_population (const hb_set_t *set)
+{
+ return set->get_population ();
+}
+
+/**
+ * hb_set_get_min:
+ * @set: a set.
+ *
+ * Finds the minimum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 1.0
+ **/
hb_codepoint_t
-hb_set_min (hb_set_t *set)
+hb_set_get_min (const hb_set_t *set)
{
return set->get_min ();
}
+/**
+ * hb_set_get_max:
+ * @set: a set.
+ *
+ * Finds the maximum number in the set.
+ *
+ * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty.
+ *
+ * Since: 1.0
+ **/
hb_codepoint_t
-hb_set_max (hb_set_t *set)
+hb_set_get_max (const hb_set_t *set)
{
return set->get_max ();
}
+/**
+ * hb_set_next:
+ * @set: a set.
+ * @codepoint: (inout):
+ *
+ *
+ *
+ * Return value: whether there was a next value.
+ *
+ * Since: 1.0
+ **/
hb_bool_t
-hb_set_next (hb_set_t *set,
+hb_set_next (const hb_set_t *set,
hb_codepoint_t *codepoint)
{
return set->next (codepoint);
}
+
+/**
+ * hb_set_next_range:
+ * @set: a set.
+ * @first: (out): output first codepoint in the range.
+ * @last: (inout): input current last and output last codepoint in the range.
+ *
+ * Gets the next consecutive range of numbers in @set that
+ * are greater than current value of @last.
+ *
+ * Return value: whether there was a next range.
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+ hb_codepoint_t *first,
+ hb_codepoint_t *last)
+{
+ return set->next_range (first, last);
+}
diff --git a/src/hb-set.h b/src/hb-set.h
index 9f849cf..bafdae9 100644
--- a/src/hb-set.h
+++ b/src/hb-set.h
@@ -36,7 +36,9 @@
HB_BEGIN_DECLS
-typedef struct _hb_set_t hb_set_t;
+#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+
+typedef struct hb_set_t hb_set_t;
hb_set_t *
@@ -65,16 +67,16 @@ hb_set_get_user_data (hb_set_t *set,
/* Returns false if allocation has failed before */
hb_bool_t
-hb_set_allocation_successful (hb_set_t *set);
+hb_set_allocation_successful (const hb_set_t *set);
void
hb_set_clear (hb_set_t *set);
hb_bool_t
-hb_set_empty (hb_set_t *set);
+hb_set_is_empty (const hb_set_t *set);
hb_bool_t
-hb_set_has (hb_set_t *set,
+hb_set_has (const hb_set_t *set,
hb_codepoint_t codepoint);
/* Right now limited to 16-bit integers. Eventually will do full codepoint range, sans -1
@@ -84,47 +86,67 @@ hb_set_add (hb_set_t *set,
hb_codepoint_t codepoint);
void
+hb_set_add_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last);
+
+void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint);
+void
+hb_set_del_range (hb_set_t *set,
+ hb_codepoint_t first,
+ hb_codepoint_t last);
+
hb_bool_t
-hb_set_equal (hb_set_t *set,
- hb_set_t *other);
+hb_set_is_equal (const hb_set_t *set,
+ const hb_set_t *other);
void
-hb_set_set (hb_set_t *set,
- hb_set_t *other);
+hb_set_set (hb_set_t *set,
+ const hb_set_t *other);
void
-hb_set_union (hb_set_t *set,
- hb_set_t *other);
+hb_set_union (hb_set_t *set,
+ const hb_set_t *other);
void
-hb_set_intersect (hb_set_t *set,
- hb_set_t *other);
+hb_set_intersect (hb_set_t *set,
+ const hb_set_t *other);
void
-hb_set_subtract (hb_set_t *set,
- hb_set_t *other);
+hb_set_subtract (hb_set_t *set,
+ const hb_set_t *other);
void
-hb_set_symmetric_difference (hb_set_t *set,
- hb_set_t *other);
+hb_set_symmetric_difference (hb_set_t *set,
+ const hb_set_t *other);
+
+void
+hb_set_invert (hb_set_t *set);
+
+unsigned int
+hb_set_get_population (const hb_set_t *set);
/* Returns -1 if set empty. */
hb_codepoint_t
-hb_set_min (hb_set_t *set);
+hb_set_get_min (const hb_set_t *set);
/* Returns -1 if set empty. */
hb_codepoint_t
-hb_set_max (hb_set_t *set);
+hb_set_get_max (const hb_set_t *set);
/* Pass -1 in to get started. */
hb_bool_t
-hb_set_next (hb_set_t *set,
+hb_set_next (const hb_set_t *set,
hb_codepoint_t *codepoint);
-/* TODO: Add faster iteration API? */
+/* Pass -1 for first and last to get started. */
+hb_bool_t
+hb_set_next_range (const hb_set_t *set,
+ hb_codepoint_t *first,
+ hb_codepoint_t *last);
HB_END_DECLS
diff --git a/src/hb-shape-plan-private.hh b/src/hb-shape-plan-private.hh
new file mode 100644
index 0000000..607da5e
--- /dev/null
+++ b/src/hb-shape-plan-private.hh
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SHAPE_PLAN_PRIVATE_HH
+#define HB_SHAPE_PLAN_PRIVATE_HH
+
+#include "hb-private.hh"
+#include "hb-object-private.hh"
+#include "hb-shaper-private.hh"
+
+
+struct hb_shape_plan_t
+{
+ hb_object_header_t header;
+ ASSERT_POD ();
+
+ hb_bool_t default_shaper_list;
+ hb_face_t *face_unsafe; /* We don't carry a reference to face. */
+ hb_segment_properties_t props;
+
+ hb_shape_func_t *shaper_func;
+ const char *shaper_name;
+
+ hb_feature_t *user_features;
+ unsigned int num_user_features;
+
+ struct hb_shaper_data_t shaper_data;
+};
+
+#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
+ , const hb_feature_t *user_features \
+ , unsigned int num_user_features
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
+
+
+#endif /* HB_SHAPE_PLAN_PRIVATE_HH */
diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc
new file mode 100644
index 0000000..2166173
--- /dev/null
+++ b/src/hb-shape-plan.cc
@@ -0,0 +1,492 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-shape-plan-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
+
+
+#ifndef HB_DEBUG_SHAPE_PLAN
+#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
+#endif
+
+
+#define HB_SHAPER_IMPLEMENT(shaper) \
+ HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \
+ HB_SHAPER_DATA_ENSURE_DECLARE(shaper, font)
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+
+static void
+hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list)
+{
+ DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
+ "num_features=%d shaper_list=%p",
+ num_user_features,
+ shaper_list);
+
+ const hb_shaper_pair_t *shapers = _hb_shapers_get ();
+
+#define HB_SHAPER_PLAN(shaper) \
+ HB_STMT_START { \
+ if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \
+ HB_SHAPER_DATA (shaper, shape_plan) = \
+ HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \
+ shape_plan->shaper_func = _hb_##shaper##_shape; \
+ shape_plan->shaper_name = #shaper; \
+ return; \
+ } \
+ } HB_STMT_END
+
+ if (likely (!shaper_list)) {
+ for (unsigned int i = 0; i < HB_SHAPERS_COUNT; i++)
+ if (0)
+ ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+ else if (shapers[i].func == _hb_##shaper##_shape) \
+ HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+ } else {
+ for (; *shaper_list; shaper_list++)
+ if (0)
+ ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+ else if (0 == strcmp (*shaper_list, #shaper)) \
+ HB_SHAPER_PLAN (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+ }
+
+#undef HB_SHAPER_PLAN
+}
+
+
+/*
+ * hb_shape_plan_t
+ */
+
+/**
+ * hb_shape_plan_create: (Xconstructor)
+ * @face:
+ * @props:
+ * @user_features: (array length=num_user_features):
+ * @num_user_features:
+ * @shaper_list: (array zero-terminated=1):
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list)
+{
+ DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+ "face=%p num_features=%d shaper_list=%p",
+ face,
+ num_user_features,
+ shaper_list);
+
+ hb_shape_plan_t *shape_plan;
+ hb_feature_t *features = NULL;
+
+ if (unlikely (!face))
+ face = hb_face_get_empty ();
+ if (unlikely (!props || hb_object_is_inert (face)))
+ return hb_shape_plan_get_empty ();
+ if (num_user_features && !(features = (hb_feature_t *) malloc (num_user_features * sizeof (hb_feature_t))))
+ return hb_shape_plan_get_empty ();
+ if (!(shape_plan = hb_object_create<hb_shape_plan_t> ())) {
+ free (features);
+ return hb_shape_plan_get_empty ();
+ }
+
+ assert (props->direction != HB_DIRECTION_INVALID);
+
+ hb_face_make_immutable (face);
+ shape_plan->default_shaper_list = shaper_list == NULL;
+ shape_plan->face_unsafe = face;
+ shape_plan->props = *props;
+ shape_plan->num_user_features = num_user_features;
+ shape_plan->user_features = features;
+ if (num_user_features)
+ memcpy (features, user_features, num_user_features * sizeof (hb_feature_t));
+
+ hb_shape_plan_plan (shape_plan, user_features, num_user_features, shaper_list);
+
+ return shape_plan;
+}
+
+/**
+ * hb_shape_plan_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_get_empty (void)
+{
+ static const hb_shape_plan_t _hb_shape_plan_nil = {
+ HB_OBJECT_HEADER_STATIC,
+
+ true, /* default_shaper_list */
+ NULL, /* face */
+ HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
+
+ NULL, /* shaper_func */
+ NULL, /* shaper_name */
+
+ NULL, /* user_features */
+ 0, /* num_user_featurs */
+
+ {
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+ }
+ };
+
+ return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
+}
+
+/**
+ * hb_shape_plan_reference: (skip)
+ * @shape_plan: a shape plan.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan)
+{
+ return hb_object_reference (shape_plan);
+}
+
+/**
+ * hb_shape_plan_destroy: (skip)
+ * @shape_plan: a shape plan.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan)
+{
+ if (!hb_object_destroy (shape_plan)) return;
+
+#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, shape_plan);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+ free (shape_plan->user_features);
+
+ free (shape_plan);
+}
+
+/**
+ * hb_shape_plan_set_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace)
+{
+ return hb_object_set_user_data (shape_plan, key, data, destroy, replace);
+}
+
+/**
+ * hb_shape_plan_get_user_data: (skip)
+ * @shape_plan: a shape plan.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+void *
+hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key)
+{
+ return hb_object_get_user_data (shape_plan, key);
+}
+
+
+/**
+ * hb_shape_plan_execute:
+ * @shape_plan: a shape plan.
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features)
+{
+ DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan,
+ "num_features=%d shaper_func=%p",
+ num_features,
+ shape_plan->shaper_func);
+
+ if (unlikely (hb_object_is_inert (shape_plan) ||
+ hb_object_is_inert (font) ||
+ hb_object_is_inert (buffer)))
+ return false;
+
+ assert (shape_plan->face_unsafe == font->face);
+ assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props));
+
+#define HB_SHAPER_EXECUTE(shaper) \
+ HB_STMT_START { \
+ return HB_SHAPER_DATA (shaper, shape_plan) && \
+ hb_##shaper##_shaper_font_data_ensure (font) && \
+ _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \
+ } HB_STMT_END
+
+ if (0)
+ ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+ else if (shape_plan->shaper_func == _hb_##shaper##_shape) \
+ HB_SHAPER_EXECUTE (shaper);
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+#undef HB_SHAPER_EXECUTE
+
+ return false;
+}
+
+
+/*
+ * caching
+ */
+
+#if 0
+static unsigned int
+hb_shape_plan_hash (const hb_shape_plan_t *shape_plan)
+{
+ return hb_segment_properties_hash (&shape_plan->props) +
+ shape_plan->default_shaper_list ? 0 : (intptr_t) shape_plan->shaper_func;
+}
+#endif
+
+/* User-feature caching is currently somewhat dumb:
+ * it only finds matches where the feature array is identical,
+ * not cases where the feature lists would be compatible for plan purposes
+ * but have different ranges, for example.
+ */
+struct hb_shape_plan_proposal_t
+{
+ const hb_segment_properties_t props;
+ const char * const *shaper_list;
+ const hb_feature_t *user_features;
+ unsigned int num_user_features;
+ hb_shape_func_t *shaper_func;
+};
+
+static inline hb_bool_t
+hb_shape_plan_user_features_match (const hb_shape_plan_t *shape_plan,
+ const hb_shape_plan_proposal_t *proposal)
+{
+ if (proposal->num_user_features != shape_plan->num_user_features) return false;
+ for (unsigned int i = 0, n = proposal->num_user_features; i < n; i++)
+ if (proposal->user_features[i].tag != shape_plan->user_features[i].tag ||
+ proposal->user_features[i].value != shape_plan->user_features[i].value ||
+ proposal->user_features[i].start != shape_plan->user_features[i].start ||
+ proposal->user_features[i].end != shape_plan->user_features[i].end) return false;
+ return true;
+}
+
+static hb_bool_t
+hb_shape_plan_matches (const hb_shape_plan_t *shape_plan,
+ const hb_shape_plan_proposal_t *proposal)
+{
+ return hb_segment_properties_equal (&shape_plan->props, &proposal->props) &&
+ hb_shape_plan_user_features_match (shape_plan, proposal) &&
+ ((shape_plan->default_shaper_list && proposal->shaper_list == NULL) ||
+ (shape_plan->shaper_func == proposal->shaper_func));
+}
+
+static inline hb_bool_t
+hb_non_global_user_features_present (const hb_feature_t *user_features,
+ unsigned int num_user_features)
+{
+ while (num_user_features)
+ if (user_features->start != 0 || user_features->end != (unsigned int) -1)
+ return true;
+ else
+ num_user_features--, user_features++;
+ return false;
+}
+
+/**
+ * hb_shape_plan_create_cached:
+ * @face:
+ * @props:
+ * @user_features: (array length=num_user_features):
+ * @num_user_features:
+ * @shaper_list: (array zero-terminated=1):
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
+hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list)
+{
+ DEBUG_MSG_FUNC (SHAPE_PLAN, NULL,
+ "face=%p num_features=%d shaper_list=%p",
+ face,
+ num_user_features,
+ shaper_list);
+
+ hb_shape_plan_proposal_t proposal = {
+ *props,
+ shaper_list,
+ user_features,
+ num_user_features,
+ NULL
+ };
+
+ if (shaper_list) {
+ /* Choose shaper. Adapted from hb_shape_plan_plan().
+ * Must choose shaper exactly the same way as that function. */
+ for (const char * const *shaper_item = shaper_list; *shaper_item; shaper_item++)
+ if (0)
+ ;
+#define HB_SHAPER_IMPLEMENT(shaper) \
+ else if (0 == strcmp (*shaper_item, #shaper) && \
+ hb_##shaper##_shaper_face_data_ensure (face)) \
+ { \
+ proposal.shaper_func = _hb_##shaper##_shape; \
+ break; \
+ }
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+ if (unlikely (!proposal.shaper_func))
+ return hb_shape_plan_get_empty ();
+ }
+
+
+retry:
+ hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans);
+ for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next)
+ if (hb_shape_plan_matches (node->shape_plan, &proposal))
+ {
+ DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache");
+ return hb_shape_plan_reference (node->shape_plan);
+ }
+
+ /* Not found. */
+
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, props, user_features, num_user_features, shaper_list);
+
+ /* Don't add the plan to the cache if there were user features with non-global ranges */
+
+ if (hb_non_global_user_features_present (user_features, num_user_features))
+ return shape_plan;
+
+ hb_face_t::plan_node_t *node = (hb_face_t::plan_node_t *) calloc (1, sizeof (hb_face_t::plan_node_t));
+ if (unlikely (!node))
+ return shape_plan;
+
+ node->shape_plan = shape_plan;
+ node->next = cached_plan_nodes;
+
+ if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) {
+ hb_shape_plan_destroy (shape_plan);
+ free (node);
+ goto retry;
+ }
+ DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "inserted into cache");
+
+ return hb_shape_plan_reference (shape_plan);
+}
+
+/**
+ * hb_shape_plan_get_shaper:
+ * @shape_plan: a shape plan.
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
+const char *
+hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan)
+{
+ return shape_plan->shaper_name;
+}
diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h
new file mode 100644
index 0000000..8f54552
--- /dev/null
+++ b/src/hb-shape-plan.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_H_IN
+#error "Include <hb.h> instead."
+#endif
+
+#ifndef HB_SHAPE_PLAN_H
+#define HB_SHAPE_PLAN_H
+
+#include "hb-common.h"
+#include "hb-font.h"
+
+HB_BEGIN_DECLS
+
+typedef struct hb_shape_plan_t hb_shape_plan_t;
+
+hb_shape_plan_t *
+hb_shape_plan_create (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list);
+
+hb_shape_plan_t *
+hb_shape_plan_create_cached (hb_face_t *face,
+ const hb_segment_properties_t *props,
+ const hb_feature_t *user_features,
+ unsigned int num_user_features,
+ const char * const *shaper_list);
+
+hb_shape_plan_t *
+hb_shape_plan_get_empty (void);
+
+hb_shape_plan_t *
+hb_shape_plan_reference (hb_shape_plan_t *shape_plan);
+
+void
+hb_shape_plan_destroy (hb_shape_plan_t *shape_plan);
+
+hb_bool_t
+hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key,
+ void * data,
+ hb_destroy_func_t destroy,
+ hb_bool_t replace);
+
+void *
+hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key);
+
+
+hb_bool_t
+hb_shape_plan_execute (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features);
+
+const char *
+hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan);
+
+
+HB_END_DECLS
+
+#endif /* HB_SHAPE_PLAN_H */
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 163a5bf..4e22c61 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -1,5 +1,6 @@
/*
* Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -22,128 +23,279 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
-#include "hb-shape.h"
-
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
#include "hb-buffer-private.hh"
+#include "hb-font-private.hh"
-#ifdef HAVE_GRAPHITE
-#include "hb-graphite2-private.hh"
-#endif
-#ifdef HAVE_UNISCRIBE
-# include "hb-uniscribe-private.hh"
-#endif
-#ifdef HAVE_OT
-# include "hb-ot-shape-private.hh"
-#endif
-#include "hb-fallback-shape-private.hh"
-
-typedef hb_bool_t (*hb_shape_func_t) (hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *features,
- unsigned int num_features);
-
-#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape}
-static const struct hb_shaper_pair_t {
- char name[16];
- hb_shape_func_t func;
-} all_shapers[] = {
- /* v--- Add new shapers in the right place here */
-#ifdef HAVE_GRAPHITE
- HB_SHAPER_IMPLEMENT (graphite2),
-#endif
-#ifdef HAVE_UNISCRIBE
- HB_SHAPER_IMPLEMENT (uniscribe),
-#endif
-#ifdef HAVE_OT
- HB_SHAPER_IMPLEMENT (ot),
-#endif
- HB_SHAPER_IMPLEMENT (fallback) /* should be last */
-};
-#undef HB_SHAPER_IMPLEMENT
+static bool
+parse_space (const char **pp, const char *end)
+{
+ while (*pp < end && ISSPACE (**pp))
+ (*pp)++;
+ return true;
+}
-/* Thread-safe, lock-free, shapers */
+static bool
+parse_char (const char **pp, const char *end, char c)
+{
+ parse_space (pp, end);
-static hb_shaper_pair_t *static_shapers;
+ if (*pp == end || **pp != c)
+ return false;
-static
-void free_static_shapers (void)
+ (*pp)++;
+ return true;
+}
+
+static bool
+parse_uint (const char **pp, const char *end, unsigned int *pv)
{
- if (unlikely (static_shapers != all_shapers))
- free (static_shapers);
+ char buf[32];
+ unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
+ strncpy (buf, *pp, len);
+ buf[len] = '\0';
+
+ char *p = buf;
+ char *pend = p;
+ unsigned int v;
+
+ /* Intentionally use strtol instead of strtoul, such that
+ * -1 turns into "big number"... */
+ errno = 0;
+ v = strtol (p, &pend, 0);
+ if (errno || p == pend)
+ return false;
+
+ *pv = v;
+ *pp += pend - p;
+ return true;
}
-static const hb_shaper_pair_t *
-get_shapers (void)
+static bool
+parse_bool (const char **pp, const char *end, unsigned int *pv)
{
-retry:
- hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
+ parse_space (pp, end);
+
+ const char *p = *pp;
+ while (*pp < end && ISALPHA(**pp))
+ (*pp)++;
+
+ /* CSS allows on/off as aliases 1/0. */
+ if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
+ *pv = 1;
+ else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
+ *pv = 0;
+ else
+ return false;
+
+ return true;
+}
+
+static bool
+parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
+{
+ if (parse_char (pp, end, '-'))
+ feature->value = 0;
+ else {
+ parse_char (pp, end, '+');
+ feature->value = 1;
+ }
+
+ return true;
+}
- if (unlikely (!shapers))
+static bool
+parse_feature_tag (const char **pp, const char *end, hb_feature_t *feature)
+{
+ parse_space (pp, end);
+
+ char quote = 0;
+
+ if (*pp < end && (**pp == '\'' || **pp == '"'))
{
- char *env = getenv ("HB_SHAPER_LIST");
- if (!env || !*env) {
- hb_atomic_ptr_cmpexch (&static_shapers, NULL, (const hb_shaper_pair_t *) all_shapers);
- return (const hb_shaper_pair_t *) all_shapers;
- }
+ quote = **pp;
+ (*pp)++;
+ }
- /* Not found; allocate one. */
- shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
- if (unlikely (!shapers))
- return (const hb_shaper_pair_t *) all_shapers;
- memcpy (shapers, all_shapers, sizeof (all_shapers));
-
- /* Reorder shaper list to prefer requested shapers. */
- unsigned int i = 0;
- char *end, *p = env;
- for (;;) {
- end = strchr (p, ',');
- if (!end)
- end = p + strlen (p);
-
- for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
- if (end - p == (int) strlen (shapers[j].name) &&
- 0 == strncmp (shapers[j].name, p, end - p))
- {
- /* Reorder this shaper to position i */
- struct hb_shaper_pair_t t = shapers[j];
- memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
- shapers[i] = t;
- i++;
- }
-
- if (!*end)
- break;
- else
- p = end + 1;
- }
+ const char *p = *pp;
+ while (*pp < end && ISALNUM(**pp))
+ (*pp)++;
- if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
- free (shapers);
- goto retry;
- }
+ if (p == *pp || *pp - p > 4)
+ return false;
-#ifdef HAVE_ATEXIT
- atexit (free_static_shapers); /* First person registers atexit() callback. */
-#endif
+ feature->tag = hb_tag_from_string (p, *pp - p);
+
+ if (quote)
+ {
+ /* CSS expects exactly four bytes. And we only allow quotations for
+ * CSS compatibility. So, enforce the length. */
+ if (*pp - p != 4)
+ return false;
+ if (*pp == end || **pp != quote)
+ return false;
+ (*pp)++;
+ }
+
+ return true;
+}
+
+static bool
+parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
+{
+ parse_space (pp, end);
+
+ bool has_start;
+
+ feature->start = 0;
+ feature->end = (unsigned int) -1;
+
+ if (!parse_char (pp, end, '['))
+ return true;
+
+ has_start = parse_uint (pp, end, &feature->start);
+
+ if (parse_char (pp, end, ':')) {
+ parse_uint (pp, end, &feature->end);
+ } else {
+ if (has_start)
+ feature->end = feature->start + 1;
}
- return shapers;
+ return parse_char (pp, end, ']');
+}
+
+static bool
+parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
+{
+ bool had_equal = parse_char (pp, end, '=');
+ bool had_value = parse_uint (pp, end, &feature->value) ||
+ parse_bool (pp, end, &feature->value);
+ /* CSS doesn't use equal-sign between tag and value.
+ * If there was an equal-sign, then there *must* be a value.
+ * A value without an eqaul-sign is ok, but not required. */
+ return !had_equal || had_value;
+}
+
+
+static bool
+parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
+{
+ return parse_feature_value_prefix (pp, end, feature) &&
+ parse_feature_tag (pp, end, feature) &&
+ parse_feature_indices (pp, end, feature) &&
+ parse_feature_value_postfix (pp, end, feature) &&
+ parse_space (pp, end) &&
+ *pp == end;
+}
+
+/**
+ * hb_feature_from_string:
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
+ * @feature: (out) (optional):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature)
+{
+ hb_feature_t feat;
+
+ if (len < 0)
+ len = strlen (str);
+
+ if (likely (parse_one_feature (&str, str + len, &feat)))
+ {
+ if (feature)
+ *feature = feat;
+ return true;
+ }
+
+ if (feature)
+ memset (feature, 0, sizeof (*feature));
+ return false;
+}
+
+/**
+ * hb_feature_to_string:
+ * @feature:
+ * @buf: (array length=size):
+ * @size:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_feature_to_string (hb_feature_t *feature,
+ char *buf, unsigned int size)
+{
+ if (unlikely (!size)) return;
+
+ char s[128];
+ unsigned int len = 0;
+ if (feature->value == 0)
+ s[len++] = '-';
+ hb_tag_to_string (feature->tag, s + len);
+ len += 4;
+ while (len && s[len - 1] == ' ')
+ len--;
+ if (feature->start != 0 || feature->end != (unsigned int) -1)
+ {
+ s[len++] = '[';
+ if (feature->start)
+ len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
+ if (feature->end != feature->start + 1) {
+ s[len++] = ':';
+ if (feature->end != (unsigned int) -1)
+ len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
+ }
+ s[len++] = ']';
+ }
+ if (feature->value > 1)
+ {
+ s[len++] = '=';
+ len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+ }
+ assert (len < ARRAY_LENGTH (s));
+ len = MIN (len, size - 1);
+ memcpy (buf, s, len);
+ buf[len] = '\0';
}
static const char **static_shaper_list;
+#ifdef HB_USE_ATEXIT
static
void free_static_shaper_list (void)
{
free (static_shaper_list);
}
+#endif
+/**
+ * hb_shape_list_shapers:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
const char **
hb_shape_list_shapers (void)
{
@@ -153,15 +305,15 @@ retry:
if (unlikely (!shaper_list))
{
/* Not found; allocate one. */
- shaper_list = (const char **) calloc (1 + ARRAY_LENGTH (all_shapers), sizeof (const char *));
+ shaper_list = (const char **) calloc (1 + HB_SHAPERS_COUNT, sizeof (const char *));
if (unlikely (!shaper_list)) {
static const char *nil_shaper_list[] = {NULL};
return nil_shaper_list;
}
- const hb_shaper_pair_t *shapers = get_shapers ();
+ const hb_shaper_pair_t *shapers = _hb_shapers_get ();
unsigned int i;
- for (i = 0; i < ARRAY_LENGTH (all_shapers); i++)
+ for (i = 0; i < HB_SHAPERS_COUNT; i++)
shaper_list[i] = shapers[i].name;
shaper_list[i] = NULL;
@@ -170,7 +322,7 @@ retry:
goto retry;
}
-#ifdef HAVE_ATEXIT
+#ifdef HB_USE_ATEXIT
atexit (free_static_shaper_list); /* First person registers atexit() callback. */
#endif
}
@@ -179,6 +331,20 @@ retry:
}
+/**
+ * hb_shape_full:
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features:
+ * @shaper_list: (array zero-terminated=1):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_shape_full (hb_font_t *font,
hb_buffer_t *buffer,
@@ -186,27 +352,31 @@ hb_shape_full (hb_font_t *font,
unsigned int num_features,
const char * const *shaper_list)
{
- hb_font_make_immutable (font); /* So we can safely cache stuff on it */
+ if (unlikely (!buffer->len))
+ return true;
- if (likely (!shaper_list)) {
- const hb_shaper_pair_t *shapers = get_shapers ();
- for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
- if (likely (shapers[i].func (font, buffer, features, num_features)))
- return true;
- } else {
- while (*shaper_list) {
- for (unsigned int i = 0; i < ARRAY_LENGTH (all_shapers); i++)
- if (0 == strcmp (*shaper_list, all_shapers[i].name)) {
- if (likely (all_shapers[i].func (font, buffer, features, num_features)))
- return true;
- break;
- }
- shaper_list++;
- }
- }
- return false;
+ assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE);
+
+ hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list);
+ hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features);
+ hb_shape_plan_destroy (shape_plan);
+
+ if (res)
+ buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
+ return res;
}
+/**
+ * hb_shape:
+ * @font: a font.
+ * @buffer: a buffer.
+ * @features: (array length=num_features):
+ * @num_features:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_shape (hb_font_t *font,
hb_buffer_t *buffer,
diff --git a/src/hb-shape.h b/src/hb-shape.h
index 1a0d6cf..10a35cb 100644
--- a/src/hb-shape.h
+++ b/src/hb-shape.h
@@ -1,5 +1,6 @@
/*
* Copyright © 2009 Red Hat, Inc.
+ * Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -22,6 +23,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
@@ -38,13 +40,24 @@
HB_BEGIN_DECLS
-typedef struct _hb_feature_t {
+typedef struct hb_feature_t {
hb_tag_t tag;
uint32_t value;
unsigned int start;
unsigned int end;
} hb_feature_t;
+/* len=-1 means str is NUL-terminated */
+hb_bool_t
+hb_feature_from_string (const char *str, int len,
+ hb_feature_t *feature);
+
+/* Something like 128 bytes is more than enough.
+ * nul-terminates. */
+void
+hb_feature_to_string (hb_feature_t *feature,
+ char *buf, unsigned int size);
+
void
hb_shape (hb_font_t *font,
diff --git a/src/hb-uniscribe-private.hh b/src/hb-shaper-impl-private.hh
index 239ab0c..7844081 100644
--- a/src/hb-uniscribe-private.hh
+++ b/src/hb-shaper-impl-private.hh
@@ -24,19 +24,20 @@
* Google Author(s): Behdad Esfahbod
*/
-#ifndef HB_UNISCRIBE_PRIVATE_HH
-#define HB_UNISCRIBE_PRIVATE_HH
+#ifndef HB_SHAPER_IMPL_PRIVATE_HH
+#define HB_SHAPER_IMPL_PRIVATE_HH
#include "hb-private.hh"
-#include "hb-uniscribe.h"
+#include "hb-shaper-private.hh"
+#include "hb-shape-plan-private.hh"
+#include "hb-font-private.hh"
+#include "hb-buffer-private.hh"
-HB_INTERNAL hb_bool_t
-_hb_uniscribe_shape (hb_font_t *font,
- hb_buffer_t *buffer,
- const hb_feature_t *features,
- unsigned int num_features);
+#ifdef HB_SHAPER
+#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object)
+#endif
-#endif /* HB_UNISCRIBE_PRIVATE_HH */
+#endif /* HB_SHAPER_IMPL_PRIVATE_HH */
diff --git a/src/hb-shaper-list.hh b/src/hb-shaper-list.hh
new file mode 100644
index 0000000..6c537d4
--- /dev/null
+++ b/src/hb-shaper-list.hh
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SHAPER_LIST_HH
+#define HB_SHAPER_LIST_HH
+#endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */
+
+/* v--- Add new shapers in the right place here. */
+
+#ifdef HAVE_GRAPHITE2
+/* Only picks up fonts that have a "Silf" table. */
+HB_SHAPER_IMPLEMENT (graphite2)
+#endif
+#ifdef HAVE_CORETEXT
+/* Only picks up fonts that have a "mort" or "morx" table. */
+HB_SHAPER_IMPLEMENT (coretext_aat)
+#endif
+
+#ifdef HAVE_OT
+HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+#endif
+
+#ifdef HAVE_UNISCRIBE
+HB_SHAPER_IMPLEMENT (uniscribe)
+#endif
+#ifdef HAVE_CORETEXT
+HB_SHAPER_IMPLEMENT (coretext)
+#endif
+
+#ifdef HAVE_FALLBACK
+HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */
+#endif
diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh
new file mode 100644
index 0000000..d1d1146
--- /dev/null
+++ b/src/hb-shaper-private.hh
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_SHAPER_PRIVATE_HH
+#define HB_SHAPER_PRIVATE_HH
+
+#include "hb-private.hh"
+
+typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features);
+
+#define HB_SHAPER_IMPLEMENT(name) \
+ extern "C" HB_INTERNAL hb_shape_func_t _hb_##name##_shape;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+
+struct hb_shaper_pair_t {
+ char name[16];
+ hb_shape_func_t *func;
+};
+
+HB_INTERNAL const hb_shaper_pair_t *
+_hb_shapers_get (void);
+
+
+/* For embedding in face / font / ... */
+struct hb_shaper_data_t {
+#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
+
+/* Means: succeeded, but don't need to keep any data. */
+#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
+
+/* Means: tried but failed to create. */
+#define HB_SHAPER_DATA_INVALID ((void *) -1)
+#define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
+
+#define HB_SHAPER_DATA_TYPE(shaper, object) struct hb_##shaper##_shaper_##object##_data_t
+#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance) (* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
+#define HB_SHAPER_DATA(shaper, object) HB_SHAPER_DATA_INSTANCE (shaper, object, object)
+#define HB_SHAPER_DATA_CREATE_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_create
+#define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_destroy
+
+#define HB_SHAPER_DATA_PROTOTYPE(shaper, object) \
+ HB_SHAPER_DATA_TYPE (shaper, object); /* Type forward declaration. */ \
+ extern "C" HB_INTERNAL HB_SHAPER_DATA_TYPE (shaper, object) * \
+ HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (hb_##object##_t *object HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS); \
+ extern "C" HB_INTERNAL void \
+ HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (HB_SHAPER_DATA_TYPE (shaper, object) *data)
+
+#define HB_SHAPER_DATA_DESTROY(shaper, object) \
+ if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \
+ if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \
+ HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data);
+
+#define HB_SHAPER_DATA_ENSURE_DECLARE(shaper, object) \
+static inline bool \
+hb_##shaper##_shaper_##object##_data_ensure (hb_##object##_t *object) \
+{\
+ retry: \
+ HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
+ if (unlikely (!data)) { \
+ data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \
+ if (unlikely (!data)) \
+ data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \
+ if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), NULL, data)) { \
+ if (data && \
+ data != HB_SHAPER_DATA_INVALID && \
+ data != HB_SHAPER_DATA_SUCCEEDED) \
+ HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \
+ goto retry; \
+ } \
+ } \
+ return data != NULL && !HB_SHAPER_DATA_IS_INVALID (data); \
+}
+
+
+#endif /* HB_SHAPER_PRIVATE_HH */
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
new file mode 100644
index 0000000..580b95c
--- /dev/null
+++ b/src/hb-shaper.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2012 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb-private.hh"
+#include "hb-shaper-private.hh"
+#include "hb-atomic-private.hh"
+
+
+static const hb_shaper_pair_t all_shapers[] = {
+#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape},
+#include "hb-shaper-list.hh"
+#undef HB_SHAPER_IMPLEMENT
+};
+
+
+/* Thread-safe, lock-free, shapers */
+
+static const hb_shaper_pair_t *static_shapers;
+
+#ifdef HB_USE_ATEXIT
+static
+void free_static_shapers (void)
+{
+ if (unlikely (static_shapers != all_shapers))
+ free ((void *) static_shapers);
+}
+#endif
+
+const hb_shaper_pair_t *
+_hb_shapers_get (void)
+{
+retry:
+ hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers);
+
+ if (unlikely (!shapers))
+ {
+ char *env = getenv ("HB_SHAPER_LIST");
+ if (!env || !*env) {
+ (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+ return (const hb_shaper_pair_t *) all_shapers;
+ }
+
+ /* Not found; allocate one. */
+ shapers = (hb_shaper_pair_t *) malloc (sizeof (all_shapers));
+ if (unlikely (!shapers)) {
+ (void) hb_atomic_ptr_cmpexch (&static_shapers, NULL, &all_shapers[0]);
+ return (const hb_shaper_pair_t *) all_shapers;
+ }
+
+ memcpy (shapers, all_shapers, sizeof (all_shapers));
+
+ /* Reorder shaper list to prefer requested shapers. */
+ unsigned int i = 0;
+ char *end, *p = env;
+ for (;;) {
+ end = strchr (p, ',');
+ if (!end)
+ end = p + strlen (p);
+
+ for (unsigned int j = i; j < ARRAY_LENGTH (all_shapers); j++)
+ if (end - p == (int) strlen (shapers[j].name) &&
+ 0 == strncmp (shapers[j].name, p, end - p))
+ {
+ /* Reorder this shaper to position i */
+ struct hb_shaper_pair_t t = shapers[j];
+ memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i));
+ shapers[i] = t;
+ i++;
+ }
+
+ if (!*end)
+ break;
+ else
+ p = end + 1;
+ }
+
+ if (!hb_atomic_ptr_cmpexch (&static_shapers, NULL, shapers)) {
+ free (shapers);
+ goto retry;
+ }
+
+#ifdef HB_USE_ATEXIT
+ atexit (free_static_shapers); /* First person registers atexit() callback. */
+#endif
+ }
+
+ return shapers;
+}
diff --git a/src/hb-tt-font.cc b/src/hb-tt-font.cc
deleted file mode 100644
index 0055ae9..0000000
--- a/src/hb-tt-font.cc
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright © 2011 Google, Inc.
- *
- * This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#include "hb-font-private.hh" /* Shall be first since may include windows.h */
-
-#include "hb-open-type-private.hh"
-
-#include "hb-ot-hhea-table.hh"
-#include "hb-ot-hmtx-table.hh"
-
-#include "hb-blob.h"
-
-#include <string.h>
-
-
-
-#if 0
-struct hb_tt_font_t
-{
- const struct hhea *hhea;
- hb_blob_t *hhea_blob;
-};
-
-
-static hb_tt_font_t *
-_hb_tt_font_create (hb_font_t *font)
-{
- /* TODO Remove this object altogether */
- hb_tt_font_t *tt = (hb_tt_font_t *) calloc (1, sizeof (hb_tt_font_t));
-
- tt->hhea_blob = Sanitizer<hhea>::sanitize (hb_face_reference_table (font->face, HB_OT_TAG_hhea));
- tt->hhea = Sanitizer<hhea>::lock_instance (tt->hhea_blob);
-
- return tt;
-}
-
-static void
-_hb_tt_font_destroy (hb_tt_font_t *tt)
-{
- hb_blob_destroy (tt->hhea_blob);
-
- free (tt);
-}
-
-static inline const hhea&
-_get_hhea (hb_face_t *face)
-{
-// return likely (face->tt && face->tt->hhea) ? *face->tt->hhea : Null(hhea);
-}
-
-
-/*
- * hb_tt_font_funcs_t
- */
-
-static hb_bool_t
-hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t unicode,
- hb_codepoint_t variation_selector,
- hb_codepoint_t *glyph,
- void *user_data HB_UNUSED)
-{
- if (font->parent)
- return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph);
-
- *glyph = 0;
- return false;
-}
-
-static hb_position_t
-hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph,
- void *user_data HB_UNUSED)
-{
- if (font->parent)
- return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph));
-
- return font->x_scale;
-}
-
-static hb_position_t
-hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph,
- void *user_data HB_UNUSED)
-{
- if (font->parent)
- return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph));
-
- return font->y_scale;
-}
-
-static hb_bool_t
-hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph,
- hb_position_t *x,
- hb_position_t *y,
- void *user_data HB_UNUSED)
-{
- if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent,
- glyph,
- x, y);
- if (ret)
- font->parent_scale_position (x, y);
- return ret;
- }
-
- *x = *y = 0;
- return false;
-}
-
-static hb_bool_t
-hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph,
- hb_position_t *x,
- hb_position_t *y,
- void *user_data HB_UNUSED)
-{
- if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent,
- glyph,
- x, y);
- if (ret)
- font->parent_scale_position (x, y);
- return ret;
- }
-
- *x = *y = 0;
- return false;
-}
-
-static hb_position_t
-hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t left_glyph,
- hb_codepoint_t right_glyph,
- void *user_data HB_UNUSED)
-{
- if (font->parent)
- return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph));
-
- return 0;
-}
-
-static hb_position_t
-hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t top_glyph,
- hb_codepoint_t bottom_glyph,
- void *user_data HB_UNUSED)
-{
- if (font->parent)
- return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph));
-
- return 0;
-}
-
-static hb_bool_t
-hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph,
- hb_glyph_extents_t *extents,
- void *user_data HB_UNUSED)
-{
- if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_extents (font->parent,
- glyph,
- extents);
- if (ret) {
- font->parent_scale_position (&extents->x_bearing, &extents->y_bearing);
- font->parent_scale_distance (&extents->width, &extents->height);
- }
- return ret;
- }
-
- memset (extents, 0, sizeof (*extents));
- return false;
-}
-
-static hb_bool_t
-hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
- void *font_data HB_UNUSED,
- hb_codepoint_t glyph,
- unsigned int point_index,
- hb_position_t *x,
- hb_position_t *y,
- void *user_data HB_UNUSED)
-{
- if (font->parent) {
- hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent,
- glyph, point_index,
- x, y);
- if (ret)
- font->parent_scale_position (x, y);
- return ret;
- }
-
- *x = *y = 0;
- return false;
-}
-
-
-static hb_font_funcs_t _hb_font_funcs_nil = {
- HB_OBJECT_HEADER_STATIC,
-
- true, /* immutable */
-
- {
-#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil,
- HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
-#undef HB_FONT_FUNC_IMPLEMENT
- }
-};
-#endif
-
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
new file mode 100644
index 0000000..5b53821
--- /dev/null
+++ b/src/hb-ucdn.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "hb-private.hh"
+
+#include "hb-unicode-private.hh"
+
+#include "ucdn.h"
+
+static const hb_script_t ucdn_script_translate[] =
+{
+ HB_SCRIPT_COMMON,
+ HB_SCRIPT_LATIN,
+ HB_SCRIPT_GREEK,
+ HB_SCRIPT_CYRILLIC,
+ HB_SCRIPT_ARMENIAN,
+ HB_SCRIPT_HEBREW,
+ HB_SCRIPT_ARABIC,
+ HB_SCRIPT_SYRIAC,
+ HB_SCRIPT_THAANA,
+ HB_SCRIPT_DEVANAGARI,
+ HB_SCRIPT_BENGALI,
+ HB_SCRIPT_GURMUKHI,
+ HB_SCRIPT_GUJARATI,
+ HB_SCRIPT_ORIYA,
+ HB_SCRIPT_TAMIL,
+ HB_SCRIPT_TELUGU,
+ HB_SCRIPT_KANNADA,
+ HB_SCRIPT_MALAYALAM,
+ HB_SCRIPT_SINHALA,
+ HB_SCRIPT_THAI,
+ HB_SCRIPT_LAO,
+ HB_SCRIPT_TIBETAN,
+ HB_SCRIPT_MYANMAR,
+ HB_SCRIPT_GEORGIAN,
+ HB_SCRIPT_HANGUL,
+ HB_SCRIPT_ETHIOPIC,
+ HB_SCRIPT_CHEROKEE,
+ HB_SCRIPT_CANADIAN_SYLLABICS,
+ HB_SCRIPT_OGHAM,
+ HB_SCRIPT_RUNIC,
+ HB_SCRIPT_KHMER,
+ HB_SCRIPT_MONGOLIAN,
+ HB_SCRIPT_HIRAGANA,
+ HB_SCRIPT_KATAKANA,
+ HB_SCRIPT_BOPOMOFO,
+ HB_SCRIPT_HAN,
+ HB_SCRIPT_YI,
+ HB_SCRIPT_OLD_ITALIC,
+ HB_SCRIPT_GOTHIC,
+ HB_SCRIPT_DESERET,
+ HB_SCRIPT_INHERITED,
+ HB_SCRIPT_TAGALOG,
+ HB_SCRIPT_HANUNOO,
+ HB_SCRIPT_BUHID,
+ HB_SCRIPT_TAGBANWA,
+ HB_SCRIPT_LIMBU,
+ HB_SCRIPT_TAI_LE,
+ HB_SCRIPT_LINEAR_B,
+ HB_SCRIPT_UGARITIC,
+ HB_SCRIPT_SHAVIAN,
+ HB_SCRIPT_OSMANYA,
+ HB_SCRIPT_CYPRIOT,
+ HB_SCRIPT_BRAILLE,
+ HB_SCRIPT_BUGINESE,
+ HB_SCRIPT_COPTIC,
+ HB_SCRIPT_NEW_TAI_LUE,
+ HB_SCRIPT_GLAGOLITIC,
+ HB_SCRIPT_TIFINAGH,
+ HB_SCRIPT_SYLOTI_NAGRI,
+ HB_SCRIPT_OLD_PERSIAN,
+ HB_SCRIPT_KHAROSHTHI,
+ HB_SCRIPT_BALINESE,
+ HB_SCRIPT_CUNEIFORM,
+ HB_SCRIPT_PHOENICIAN,
+ HB_SCRIPT_PHAGS_PA,
+ HB_SCRIPT_NKO,
+ HB_SCRIPT_SUNDANESE,
+ HB_SCRIPT_LEPCHA,
+ HB_SCRIPT_OL_CHIKI,
+ HB_SCRIPT_VAI,
+ HB_SCRIPT_SAURASHTRA,
+ HB_SCRIPT_KAYAH_LI,
+ HB_SCRIPT_REJANG,
+ HB_SCRIPT_LYCIAN,
+ HB_SCRIPT_CARIAN,
+ HB_SCRIPT_LYDIAN,
+ HB_SCRIPT_CHAM,
+ HB_SCRIPT_TAI_THAM,
+ HB_SCRIPT_TAI_VIET,
+ HB_SCRIPT_AVESTAN,
+ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
+ HB_SCRIPT_SAMARITAN,
+ HB_SCRIPT_LISU,
+ HB_SCRIPT_BAMUM,
+ HB_SCRIPT_JAVANESE,
+ HB_SCRIPT_MEETEI_MAYEK,
+ HB_SCRIPT_IMPERIAL_ARAMAIC,
+ HB_SCRIPT_OLD_SOUTH_ARABIAN,
+ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
+ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
+ HB_SCRIPT_OLD_TURKIC,
+ HB_SCRIPT_KAITHI,
+ HB_SCRIPT_BATAK,
+ HB_SCRIPT_BRAHMI,
+ HB_SCRIPT_MANDAIC,
+ HB_SCRIPT_CHAKMA,
+ HB_SCRIPT_MEROITIC_CURSIVE,
+ HB_SCRIPT_MEROITIC_HIEROGLYPHS,
+ HB_SCRIPT_MIAO,
+ HB_SCRIPT_SHARADA,
+ HB_SCRIPT_SORA_SOMPENG,
+ HB_SCRIPT_TAKRI,
+ HB_SCRIPT_UNKNOWN,
+ HB_SCRIPT_BASSA_VAH,
+ HB_SCRIPT_CAUCASIAN_ALBANIAN,
+ HB_SCRIPT_DUPLOYAN,
+ HB_SCRIPT_ELBASAN,
+ HB_SCRIPT_GRANTHA,
+ HB_SCRIPT_KHOJKI,
+ HB_SCRIPT_KHUDAWADI,
+ HB_SCRIPT_LINEAR_A,
+ HB_SCRIPT_MAHAJANI,
+ HB_SCRIPT_MANICHAEAN,
+ HB_SCRIPT_MENDE_KIKAKUI,
+ HB_SCRIPT_MODI,
+ HB_SCRIPT_MRO,
+ HB_SCRIPT_NABATAEAN,
+ HB_SCRIPT_OLD_NORTH_ARABIAN,
+ HB_SCRIPT_OLD_PERMIC,
+ HB_SCRIPT_PAHAWH_HMONG,
+ HB_SCRIPT_PALMYRENE,
+ HB_SCRIPT_PAU_CIN_HAU,
+ HB_SCRIPT_PSALTER_PAHLAVI,
+ HB_SCRIPT_SIDDHAM,
+ HB_SCRIPT_TIRHUTA,
+ HB_SCRIPT_WARANG_CITI,
+};
+
+static hb_unicode_combining_class_t
+hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+ void *user_data HB_UNUSED)
+{
+ return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode);
+}
+
+static unsigned int
+hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+ void *user_data HB_UNUSED)
+{
+ int w = ucdn_get_east_asian_width(unicode);
+ return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1;
+}
+
+static hb_unicode_general_category_t
+hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+ void *user_data HB_UNUSED)
+{
+ return (hb_unicode_general_category_t)ucdn_get_general_category(unicode);
+}
+
+static hb_codepoint_t
+hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+ void *user_data HB_UNUSED)
+{
+ return ucdn_mirror(unicode);
+}
+
+static hb_script_t
+hb_ucdn_script(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode,
+ void *user_data HB_UNUSED)
+{
+ return ucdn_script_translate[ucdn_get_script(unicode)];
+}
+
+static hb_bool_t
+hb_ucdn_compose(hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab,
+ void *user_data HB_UNUSED)
+{
+ return ucdn_compose(ab, a, b);
+}
+
+static hb_bool_t
+hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b,
+ void *user_data HB_UNUSED)
+{
+ return ucdn_decompose(ab, a, b);
+}
+
+static unsigned int
+hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t u, hb_codepoint_t *decomposed,
+ void *user_data HB_UNUSED)
+{
+ return ucdn_compat_decompose(u, decomposed);
+}
+
+extern "C" HB_INTERNAL
+hb_unicode_funcs_t *
+hb_ucdn_get_unicode_funcs (void)
+{
+ static const hb_unicode_funcs_t _hb_ucdn_unicode_funcs = {
+ HB_OBJECT_HEADER_STATIC,
+
+ NULL, /* parent */
+ true, /* immutable */
+ {
+#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_ucdn_##name,
+ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+#undef HB_UNICODE_FUNC_IMPLEMENT
+ }
+ };
+
+ return const_cast<hb_unicode_funcs_t *> (&_hb_ucdn_unicode_funcs);
+}
+
diff --git a/src/hb-ucdn/COPYING b/src/hb-ucdn/COPYING
new file mode 100644
index 0000000..be5205c
--- /dev/null
+++ b/src/hb-ucdn/COPYING
@@ -0,0 +1,13 @@
+The contents of this directory are licensed under the following terms:
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/src/hb-ucdn/Makefile.am b/src/hb-ucdn/Makefile.am
new file mode 100644
index 0000000..0670b5c
--- /dev/null
+++ b/src/hb-ucdn/Makefile.am
@@ -0,0 +1,18 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_LTLIBRARIES = libhb-ucdn.la
+
+
+libhb_ucdn_la_SOURCES = \
+ ucdn.h \
+ ucdn.c \
+ unicodedata_db.h
+libhb_ucdn_la_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src
+libhb_ucdn_la_LIBADD =
+
+EXTRA_DIST = README COPYING
+
+-include $(top_srcdir)/git.mk
diff --git a/src/hb-ucdn/Makefile.in b/src/hb-ucdn/Makefile.in
new file mode 100644
index 0000000..64e16d2
--- /dev/null
+++ b/src/hb-ucdn/Makefile.in
@@ -0,0 +1,543 @@
+# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/hb-ucdn
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ COPYING
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libhb_ucdn_la_DEPENDENCIES =
+am_libhb_ucdn_la_OBJECTS = ucdn.lo
+libhb_ucdn_la_OBJECTS = $(am_libhb_ucdn_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libhb_ucdn_la_SOURCES)
+DIST_SOURCES = $(libhb_ucdn_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_FT_CFLAGS = @CAIRO_FT_CFLAGS@
+CAIRO_FT_LIBS = @CAIRO_FT_LIBS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CORETEXT_CFLAGS = @CORETEXT_CFLAGS@
+CORETEXT_LIBS = @CORETEXT_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_CFLAGS = @GOBJECT_CFLAGS@
+GOBJECT_LIBS = @GOBJECT_LIBS@
+GRAPHITE2_CFLAGS = @GRAPHITE2_CFLAGS@
+GRAPHITE2_LIBS = @GRAPHITE2_LIBS@
+GREP = @GREP@
+GTHREAD_CFLAGS = @GTHREAD_CFLAGS@
+GTHREAD_LIBS = @GTHREAD_LIBS@
+HB_LIBTOOL_VERSION_INFO = @HB_LIBTOOL_VERSION_INFO@
+HB_VERSION = @HB_VERSION@
+HB_VERSION_MAJOR = @HB_VERSION_MAJOR@
+HB_VERSION_MICRO = @HB_VERSION_MICRO@
+HB_VERSION_MINOR = @HB_VERSION_MINOR@
+ICU_CFLAGS = @ICU_CFLAGS@
+ICU_LE_CFLAGS = @ICU_LE_CFLAGS@
+ICU_LE_LIBS = @ICU_LE_LIBS@
+ICU_LIBS = @ICU_LIBS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+UNISCRIBE_CFLAGS = @UNISCRIBE_CFLAGS@
+UNISCRIBE_LIBS = @UNISCRIBE_LIBS@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libhb-ucdn.la
+libhb_ucdn_la_SOURCES = \
+ ucdn.h \
+ ucdn.c \
+ unicodedata_db.h
+
+libhb_ucdn_CPPFLAGS = \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src
+
+libhb_ucdn_la_LIBADD =
+EXTRA_DIST = README COPYING
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/hb-ucdn/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnits src/hb-ucdn/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libhb-ucdn.la: $(libhb_ucdn_la_OBJECTS) $(libhb_ucdn_la_DEPENDENCIES) $(EXTRA_libhb_ucdn_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libhb_ucdn_la_OBJECTS) $(libhb_ucdn_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucdn.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+-include $(top_srcdir)/git.mk
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/hb-ucdn/README b/src/hb-ucdn/README
new file mode 100644
index 0000000..2f3c552
--- /dev/null
+++ b/src/hb-ucdn/README
@@ -0,0 +1,41 @@
+Contents of this directory are derived from UCDN:
+
+ https://github.com/grigorig/ucdn
+ https://github.com/behdad/ucdn
+
+The original README follows:
+
+
+UCDN - Unicode Database and Normalization
+
+UCDN is a Unicode support library. Currently, it provides access
+to basic character properties contained in the Unicode Character
+Database and low-level normalization functions (pairwise canonical
+composition/decomposition and compatibility decomposition). More
+functionality might be provided in the future, such as additional
+properties, string normalization and encoding conversion.
+
+UCDN uses standard C89 with no particular dependencies or requirements
+except for stdint.h, and can be easily integrated into existing
+projects. However, it can also be used as a standalone library,
+and a CMake build script is provided for this. The first motivation
+behind UCDN development was to provide a standalone set of Unicode
+functions for the HarfBuzz OpenType shaping library. For this purpose,
+a HarfBuzz-specific wrapper is shipped along with it (hb-ucdn.h).
+
+UCDN is published under the ISC license, please see the license header
+in the C source code for more information. The makeunicodata.py script
+required for parsing Unicode database files is licensed under the
+PSF license, please see PYTHON-LICENSE for more information.
+
+UCDN was written by Grigori Goronzy <greg@kinoho.net>.
+
+How to Use
+
+Include ucdn.c, ucdn.h and unicodedata_db.h in your project. Now,
+just use the functions as documented in ucdn.h.
+
+In some cases, it might be necessary to regenerate the Unicode
+database file. The script makeunicodedata.py (Python 3.x required)
+fetches the appropriate files and dumps the compressed database into
+unicodedata_db.h.
diff --git a/src/hb-ucdn/ucdn.c b/src/hb-ucdn/ucdn.c
new file mode 100644
index 0000000..d1a4195
--- /dev/null
+++ b/src/hb-ucdn/ucdn.c
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ucdn.h"
+
+typedef struct {
+ unsigned char category;
+ unsigned char combining;
+ unsigned char bidi_class;
+ unsigned char mirrored;
+ unsigned char east_asian_width;
+ unsigned char normalization_check;
+ unsigned char script;
+} UCDRecord;
+
+typedef struct {
+ unsigned short from, to;
+} MirrorPair;
+
+typedef struct {
+ unsigned int start;
+ short count, index;
+} Reindex;
+
+#include "unicodedata_db.h"
+
+/* constants required for Hangul (de)composition */
+#define SBASE 0xAC00
+#define LBASE 0x1100
+#define VBASE 0x1161
+#define TBASE 0x11A7
+#define SCOUNT 11172
+#define LCOUNT 19
+#define VCOUNT 21
+#define TCOUNT 28
+#define NCOUNT (VCOUNT * TCOUNT)
+
+static const UCDRecord *get_ucd_record(uint32_t code)
+{
+ int index, offset;
+
+ if (code >= 0x110000)
+ index = 0;
+ else {
+ index = index0[code >> (SHIFT1+SHIFT2)] << SHIFT1;
+ offset = (code >> SHIFT2) & ((1<<SHIFT1) - 1);
+ index = index1[index + offset] << SHIFT2;
+ offset = code & ((1<<SHIFT2) - 1);
+ index = index2[index + offset];
+ }
+
+ return &ucd_records[index];
+}
+
+static const unsigned short *get_decomp_record(uint32_t code)
+{
+ int index, offset;
+
+ if (code >= 0x110000)
+ index = 0;
+ else {
+ index = decomp_index0[code >> (DECOMP_SHIFT1+DECOMP_SHIFT2)]
+ << DECOMP_SHIFT1;
+ offset = (code >> DECOMP_SHIFT2) & ((1<<DECOMP_SHIFT1) - 1);
+ index = decomp_index1[index + offset] << DECOMP_SHIFT2;
+ offset = code & ((1<<DECOMP_SHIFT2) - 1);
+ index = decomp_index2[index + offset];
+ }
+
+ return &decomp_data[index];
+}
+
+static int get_comp_index(uint32_t code, const Reindex *idx)
+{
+ int i;
+
+ for (i = 0; idx[i].start; i++) {
+ const Reindex *cur = &idx[i];
+ if (code < cur->start)
+ return -1;
+ if (code <= cur->start + cur->count) {
+ return cur->index + (code - cur->start);
+ }
+ }
+
+ return -1;
+}
+
+static int compare_mp(const void *a, const void *b)
+{
+ MirrorPair *mpa = (MirrorPair *)a;
+ MirrorPair *mpb = (MirrorPair *)b;
+ return mpa->from - mpb->from;
+}
+
+static int hangul_pair_decompose(uint32_t code, uint32_t *a, uint32_t *b)
+{
+ int si = code - SBASE;
+
+ if (si < 0 || si >= SCOUNT)
+ return 0;
+
+ if (si % TCOUNT) {
+ /* LV,T */
+ *a = SBASE + (si / TCOUNT) * TCOUNT;
+ *b = TBASE + (si % TCOUNT);
+ return 3;
+ } else {
+ /* L,V */
+ *a = LBASE + (si / NCOUNT);
+ *b = VBASE + (si % NCOUNT) / TCOUNT;
+ return 2;
+ }
+}
+
+static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b)
+{
+ if (b < VBASE || b >= (TBASE + TCOUNT))
+ return 0;
+
+ if ((a < LBASE || a >= (LBASE + LCOUNT))
+ && (a < SBASE || a >= (SBASE + SCOUNT)))
+ return 0;
+
+ if (a >= SBASE) {
+ /* LV,T */
+ *code = a + (b - TBASE);
+ return 3;
+ } else {
+ /* L,V */
+ int li = a - LBASE;
+ int vi = b - VBASE;
+ *code = SBASE + li * NCOUNT + vi * TCOUNT;
+ return 2;
+ }
+}
+
+static uint32_t decode_utf16(const unsigned short **code_ptr)
+{
+ const unsigned short *code = *code_ptr;
+
+ if ((code[0] & 0xd800) != 0xd800) {
+ *code_ptr += 1;
+ return (uint32_t)code[0];
+ } else {
+ *code_ptr += 2;
+ return 0x10000 + ((uint32_t)code[1] - 0xdc00) +
+ (((uint32_t)code[0] - 0xd800) << 10);
+ }
+}
+
+const char *ucdn_get_unicode_version(void)
+{
+ return UNIDATA_VERSION;
+}
+
+int ucdn_get_combining_class(uint32_t code)
+{
+ return get_ucd_record(code)->combining;
+}
+
+int ucdn_get_east_asian_width(uint32_t code)
+{
+ return get_ucd_record(code)->east_asian_width;
+}
+
+int ucdn_get_general_category(uint32_t code)
+{
+ return get_ucd_record(code)->category;
+}
+
+int ucdn_get_bidi_class(uint32_t code)
+{
+ return get_ucd_record(code)->bidi_class;
+}
+
+int ucdn_get_mirrored(uint32_t code)
+{
+ return get_ucd_record(code)->mirrored;
+}
+
+int ucdn_get_script(uint32_t code)
+{
+ return get_ucd_record(code)->script;
+}
+
+uint32_t ucdn_mirror(uint32_t code)
+{
+ MirrorPair mp = {0};
+ MirrorPair *res;
+
+ if (get_ucd_record(code)->mirrored == 0)
+ return code;
+
+ mp.from = code;
+ res = bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN, sizeof(MirrorPair),
+ compare_mp);
+
+ if (res == NULL)
+ return code;
+ else
+ return res->to;
+}
+
+int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b)
+{
+ const unsigned short *rec;
+ int len;
+
+ if (hangul_pair_decompose(code, a, b))
+ return 1;
+
+ rec = get_decomp_record(code);
+ len = rec[0] >> 8;
+
+ if ((rec[0] & 0xff) != 0 || len == 0)
+ return 0;
+
+ rec++;
+ *a = decode_utf16(&rec);
+ if (len > 1)
+ *b = decode_utf16(&rec);
+ else
+ *b = 0;
+
+ return 1;
+}
+
+int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b)
+{
+ int l, r, index, indexi, offset;
+
+ if (hangul_pair_compose(code, a, b))
+ return 1;
+
+ l = get_comp_index(a, nfc_first);
+ r = get_comp_index(b, nfc_last);
+
+ if (l < 0 || r < 0)
+ return 0;
+
+ indexi = l * TOTAL_LAST + r;
+ index = comp_index0[indexi >> (COMP_SHIFT1+COMP_SHIFT2)] << COMP_SHIFT1;
+ offset = (indexi >> COMP_SHIFT2) & ((1<<COMP_SHIFT1) - 1);
+ index = comp_index1[index + offset] << COMP_SHIFT2;
+ offset = indexi & ((1<<COMP_SHIFT2) - 1);
+ *code = comp_data[index + offset];
+
+ return *code != 0;
+}
+
+int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed)
+{
+ int i, len;
+ const unsigned short *rec = get_decomp_record(code);
+ len = rec[0] >> 8;
+
+ if (len == 0)
+ return 0;
+
+ rec++;
+ for (i = 0; i < len; i++)
+ decomposed[i] = decode_utf16(&rec);
+
+ return len;
+}
diff --git a/src/hb-ucdn/ucdn.h b/src/hb-ucdn/ucdn.h
new file mode 100644
index 0000000..ec8085b
--- /dev/null
+++ b/src/hb-ucdn/ucdn.h
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2012 Grigori Goronzy <greg@kinoho.net>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UCDN_H
+#define UCDN_H
+
+#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__)
+# define HB_BEGIN_VISIBILITY _Pragma ("GCC visibility push(hidden)")
+# define HB_END_VISIBILITY _Pragma ("GCC visibility pop")
+#else
+# define HB_BEGIN_VISIBILITY
+# define HB_END_VISIBILITY
+#endif
+#ifdef __cplusplus
+# define HB_BEGIN_HEADER extern "C" { HB_BEGIN_VISIBILITY
+# define HB_END_HEADER HB_END_VISIBILITY }
+#else
+# define HB_BEGIN_HEADER HB_BEGIN_VISIBILITY
+# define HB_END_HEADER HB_END_VISIBILITY
+#endif
+
+HB_BEGIN_HEADER
+
+#if !defined (HB_DONT_DEFINE_STDINT)
+
+#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
+ defined (_sgi) || defined (__sun) || defined (sun) || \
+ defined (__digital__) || defined (__HP_cc)
+# include <inttypes.h>
+#elif defined (_AIX)
+# include <sys/inttypes.h>
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
+#elif defined (_MSC_VER) && _MSC_VER < 1600
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+# include <stdint.h>
+#endif
+
+#endif
+
+#define UCDN_EAST_ASIAN_F 0
+#define UCDN_EAST_ASIAN_H 1
+#define UCDN_EAST_ASIAN_W 2
+#define UCDN_EAST_ASIAN_NA 3
+#define UCDN_EAST_ASIAN_A 4
+#define UCDN_EAST_ASIAN_N 5
+
+#define UCDN_SCRIPT_COMMON 0
+#define UCDN_SCRIPT_LATIN 1
+#define UCDN_SCRIPT_GREEK 2
+#define UCDN_SCRIPT_CYRILLIC 3
+#define UCDN_SCRIPT_ARMENIAN 4
+#define UCDN_SCRIPT_HEBREW 5
+#define UCDN_SCRIPT_ARABIC 6
+#define UCDN_SCRIPT_SYRIAC 7
+#define UCDN_SCRIPT_THAANA 8
+#define UCDN_SCRIPT_DEVANAGARI 9
+#define UCDN_SCRIPT_BENGALI 10
+#define UCDN_SCRIPT_GURMUKHI 11
+#define UCDN_SCRIPT_GUJARATI 12
+#define UCDN_SCRIPT_ORIYA 13
+#define UCDN_SCRIPT_TAMIL 14
+#define UCDN_SCRIPT_TELUGU 15
+#define UCDN_SCRIPT_KANNADA 16
+#define UCDN_SCRIPT_MALAYALAM 17
+#define UCDN_SCRIPT_SINHALA 18
+#define UCDN_SCRIPT_THAI 19
+#define UCDN_SCRIPT_LAO 20
+#define UCDN_SCRIPT_TIBETAN 21
+#define UCDN_SCRIPT_MYANMAR 22
+#define UCDN_SCRIPT_GEORGIAN 23
+#define UCDN_SCRIPT_HANGUL 24
+#define UCDN_SCRIPT_ETHIOPIC 25
+#define UCDN_SCRIPT_CHEROKEE 26
+#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
+#define UCDN_SCRIPT_OGHAM 28
+#define UCDN_SCRIPT_RUNIC 29
+#define UCDN_SCRIPT_KHMER 30
+#define UCDN_SCRIPT_MONGOLIAN 31
+#define UCDN_SCRIPT_HIRAGANA 32
+#define UCDN_SCRIPT_KATAKANA 33
+#define UCDN_SCRIPT_BOPOMOFO 34
+#define UCDN_SCRIPT_HAN 35
+#define UCDN_SCRIPT_YI 36
+#define UCDN_SCRIPT_OLD_ITALIC 37
+#define UCDN_SCRIPT_GOTHIC 38
+#define UCDN_SCRIPT_DESERET 39
+#define UCDN_SCRIPT_INHERITED 40
+#define UCDN_SCRIPT_TAGALOG 41
+#define UCDN_SCRIPT_HANUNOO 42
+#define UCDN_SCRIPT_BUHID 43
+#define UCDN_SCRIPT_TAGBANWA 44
+#define UCDN_SCRIPT_LIMBU 45
+#define UCDN_SCRIPT_TAI_LE 46
+#define UCDN_SCRIPT_LINEAR_B 47
+#define UCDN_SCRIPT_UGARITIC 48
+#define UCDN_SCRIPT_SHAVIAN 49
+#define UCDN_SCRIPT_OSMANYA 50
+#define UCDN_SCRIPT_CYPRIOT 51
+#define UCDN_SCRIPT_BRAILLE 52
+#define UCDN_SCRIPT_BUGINESE 53
+#define UCDN_SCRIPT_COPTIC 54
+#define UCDN_SCRIPT_NEW_TAI_LUE 55
+#define UCDN_SCRIPT_GLAGOLITIC 56
+#define UCDN_SCRIPT_TIFINAGH 57
+#define UCDN_SCRIPT_SYLOTI_NAGRI 58
+#define UCDN_SCRIPT_OLD_PERSIAN 59
+#define UCDN_SCRIPT_KHAROSHTHI 60
+#define UCDN_SCRIPT_BALINESE 61
+#define UCDN_SCRIPT_CUNEIFORM 62
+#define UCDN_SCRIPT_PHOENICIAN 63
+#define UCDN_SCRIPT_PHAGS_PA 64
+#define UCDN_SCRIPT_NKO 65
+#define UCDN_SCRIPT_SUNDANESE 66
+#define UCDN_SCRIPT_LEPCHA 67
+#define UCDN_SCRIPT_OL_CHIKI 68
+#define UCDN_SCRIPT_VAI 69
+#define UCDN_SCRIPT_SAURASHTRA 70
+#define UCDN_SCRIPT_KAYAH_LI 71
+#define UCDN_SCRIPT_REJANG 72
+#define UCDN_SCRIPT_LYCIAN 73
+#define UCDN_SCRIPT_CARIAN 74
+#define UCDN_SCRIPT_LYDIAN 75
+#define UCDN_SCRIPT_CHAM 76
+#define UCDN_SCRIPT_TAI_THAM 77
+#define UCDN_SCRIPT_TAI_VIET 78
+#define UCDN_SCRIPT_AVESTAN 79
+#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
+#define UCDN_SCRIPT_SAMARITAN 81
+#define UCDN_SCRIPT_LISU 82
+#define UCDN_SCRIPT_BAMUM 83
+#define UCDN_SCRIPT_JAVANESE 84
+#define UCDN_SCRIPT_MEETEI_MAYEK 85
+#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
+#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
+#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
+#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
+#define UCDN_SCRIPT_OLD_TURKIC 90
+#define UCDN_SCRIPT_KAITHI 91
+#define UCDN_SCRIPT_BATAK 92
+#define UCDN_SCRIPT_BRAHMI 93
+#define UCDN_SCRIPT_MANDAIC 94
+#define UCDN_SCRIPT_CHAKMA 95
+#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
+#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
+#define UCDN_SCRIPT_MIAO 98
+#define UCDN_SCRIPT_SHARADA 99
+#define UCDN_SCRIPT_SORA_SOMPENG 100
+#define UCDN_SCRIPT_TAKRI 101
+#define UCDN_SCRIPT_UNKNOWN 102
+#define UCDN_SCRIPT_BASSA_VAH 103
+#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
+#define UCDN_SCRIPT_DUPLOYAN 105
+#define UCDN_SCRIPT_ELBASAN 106
+#define UCDN_SCRIPT_GRANTHA 107
+#define UCDN_SCRIPT_KHOJKI 108
+#define UCDN_SCRIPT_KHUDAWADI 109
+#define UCDN_SCRIPT_LINEAR_A 110
+#define UCDN_SCRIPT_MAHAJANI 111
+#define UCDN_SCRIPT_MANICHAEAN 112
+#define UCDN_SCRIPT_MENDE_KIKAKUI 113
+#define UCDN_SCRIPT_MODI 114
+#define UCDN_SCRIPT_MRO 115
+#define UCDN_SCRIPT_NABATAEAN 116
+#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
+#define UCDN_SCRIPT_OLD_PERMIC 118
+#define UCDN_SCRIPT_PAHAWH_HMONG 119
+#define UCDN_SCRIPT_PALMYRENE 120
+#define UCDN_SCRIPT_PAU_CIN_HAU 121
+#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
+#define UCDN_SCRIPT_SIDDHAM 123
+#define UCDN_SCRIPT_TIRHUTA 124
+#define UCDN_SCRIPT_WARANG_CITI 125
+
+#define UCDN_GENERAL_CATEGORY_CC 0
+#define UCDN_GENERAL_CATEGORY_CF 1
+#define UCDN_GENERAL_CATEGORY_CN 2
+#define UCDN_GENERAL_CATEGORY_CO 3
+#define UCDN_GENERAL_CATEGORY_CS 4
+#define UCDN_GENERAL_CATEGORY_LL 5
+#define UCDN_GENERAL_CATEGORY_LM 6
+#define UCDN_GENERAL_CATEGORY_LO 7
+#define UCDN_GENERAL_CATEGORY_LT 8
+#define UCDN_GENERAL_CATEGORY_LU 9
+#define UCDN_GENERAL_CATEGORY_MC 10
+#define UCDN_GENERAL_CATEGORY_ME 11
+#define UCDN_GENERAL_CATEGORY_MN 12
+#define UCDN_GENERAL_CATEGORY_ND 13
+#define UCDN_GENERAL_CATEGORY_NL 14
+#define UCDN_GENERAL_CATEGORY_NO 15
+#define UCDN_GENERAL_CATEGORY_PC 16
+#define UCDN_GENERAL_CATEGORY_PD 17
+#define UCDN_GENERAL_CATEGORY_PE 18
+#define UCDN_GENERAL_CATEGORY_PF 19
+#define UCDN_GENERAL_CATEGORY_PI 20
+#define UCDN_GENERAL_CATEGORY_PO 21
+#define UCDN_GENERAL_CATEGORY_PS 22
+#define UCDN_GENERAL_CATEGORY_SC 23
+#define UCDN_GENERAL_CATEGORY_SK 24
+#define UCDN_GENERAL_CATEGORY_SM 25
+#define UCDN_GENERAL_CATEGORY_SO 26
+#define UCDN_GENERAL_CATEGORY_ZL 27
+#define UCDN_GENERAL_CATEGORY_ZP 28
+#define UCDN_GENERAL_CATEGORY_ZS 29
+
+#define UCDN_BIDI_CLASS_L 0
+#define UCDN_BIDI_CLASS_LRE 1
+#define UCDN_BIDI_CLASS_LRO 2
+#define UCDN_BIDI_CLASS_R 3
+#define UCDN_BIDI_CLASS_AL 4
+#define UCDN_BIDI_CLASS_RLE 5
+#define UCDN_BIDI_CLASS_RLO 6
+#define UCDN_BIDI_CLASS_PDF 7
+#define UCDN_BIDI_CLASS_EN 8
+#define UCDN_BIDI_CLASS_ES 9
+#define UCDN_BIDI_CLASS_ET 10
+#define UCDN_BIDI_CLASS_AN 11
+#define UCDN_BIDI_CLASS_CS 12
+#define UCDN_BIDI_CLASS_NSM 13
+#define UCDN_BIDI_CLASS_BN 14
+#define UCDN_BIDI_CLASS_B 15
+#define UCDN_BIDI_CLASS_S 16
+#define UCDN_BIDI_CLASS_WS 17
+#define UCDN_BIDI_CLASS_ON 18
+#define UCDN_BIDI_CLASS_LRI 19
+#define UCDN_BIDI_CLASS_RLI 20
+#define UCDN_BIDI_CLASS_FSI 21
+#define UCDN_BIDI_CLASS_PDI 22
+
+/**
+ * Return version of the Unicode database.
+ *
+ * @return Unicode database version
+ */
+const char *ucdn_get_unicode_version(void);
+
+/**
+ * Get combining class of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return combining class value, as defined in UAX#44
+ */
+int ucdn_get_combining_class(uint32_t code);
+
+/**
+ * Get east-asian width of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_EAST_ASIAN_* and as defined in UAX#11.
+ */
+int ucdn_get_east_asian_width(uint32_t code);
+
+/**
+ * Get general category of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_GENERAL_CATEGORY_* and as defined in
+ * UAX#44.
+ */
+int ucdn_get_general_category(uint32_t code);
+
+/**
+ * Get bidirectional class of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_BIDI_CLASS_* and as defined in UAX#44.
+ */
+int ucdn_get_bidi_class(uint32_t code);
+
+/**
+ * Get script of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return value according to UCDN_SCRIPT_* and as defined in UAX#24.
+ */
+int ucdn_get_script(uint32_t code);
+
+/**
+ * Check if codepoint can be mirrored.
+ *
+ * @param code Unicode codepoint
+ * @return 1 if mirrored character exists, otherwise 0
+ */
+int ucdn_get_mirrored(uint32_t code);
+
+/**
+ * Mirror a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @return mirrored codepoint or the original codepoint if no
+ * mirrored character exists
+ */
+uint32_t ucdn_mirror(uint32_t code);
+
+/**
+ * Pairwise canonical decomposition of a codepoint. This includes
+ * Hangul Jamo decomposition (see chapter 3.12 of the Unicode core
+ * specification).
+ *
+ * Hangul is decomposed into L and V jamos for LV forms, and an
+ * LV precomposed syllable and a T jamo for LVT forms.
+ *
+ * @param code Unicode codepoint
+ * @param a filled with first codepoint of decomposition
+ * @param b filled with second codepoint of decomposition, or 0
+ * @return success
+ */
+int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b);
+
+/**
+ * Compatibility decomposition of a codepoint.
+ *
+ * @param code Unicode codepoint
+ * @param decomposed filled with decomposition, must be able to hold 18
+ * characters
+ * @return length of decomposition or 0 in case none exists
+ */
+int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed);
+
+/**
+ * Pairwise canonical composition of two codepoints. This includes
+ * Hangul Jamo composition (see chapter 3.12 of the Unicode core
+ * specification).
+ *
+ * Hangul composition expects either L and V jamos, or an LV
+ * precomposed syllable and a T jamo. This is exactly the inverse
+ * of pairwise Hangul decomposition.
+ *
+ * @param code filled with composition
+ * @param a first codepoint
+ * @param b second codepoint
+ * @return success
+ */
+int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b);
+
+HB_END_HEADER
+
+#endif
diff --git a/src/hb-ucdn/unicodedata_db.h b/src/hb-ucdn/unicodedata_db.h
new file mode 100644
index 0000000..a78d2e6
--- /dev/null
+++ b/src/hb-ucdn/unicodedata_db.h
@@ -0,0 +1,5017 @@
+/* this file was generated by makeunicodedata.py 3.2 */
+
+#define UNIDATA_VERSION "7.0.0"
+/* a list of unique database records */
+static const UCDRecord ucd_records[] = {
+ {2, 0, 18, 0, 5, 0, 102},
+ {0, 0, 14, 0, 5, 0, 0},
+ {0, 0, 16, 0, 5, 0, 0},
+ {0, 0, 15, 0, 5, 0, 0},
+ {0, 0, 17, 0, 5, 0, 0},
+ {29, 0, 17, 0, 3, 0, 0},
+ {21, 0, 18, 0, 3, 0, 0},
+ {21, 0, 10, 0, 3, 0, 0},
+ {23, 0, 10, 0, 3, 0, 0},
+ {22, 0, 18, 1, 3, 0, 0},
+ {18, 0, 18, 1, 3, 0, 0},
+ {25, 0, 9, 0, 3, 0, 0},
+ {21, 0, 12, 0, 3, 0, 0},
+ {17, 0, 9, 0, 3, 0, 0},
+ {13, 0, 8, 0, 3, 0, 0},
+ {25, 0, 18, 1, 3, 0, 0},
+ {25, 0, 18, 0, 3, 0, 0},
+ {9, 0, 0, 0, 3, 0, 1},
+ {24, 0, 18, 0, 3, 0, 0},
+ {16, 0, 18, 0, 3, 0, 0},
+ {5, 0, 0, 0, 3, 0, 1},
+ {29, 0, 12, 0, 5, 0, 0},
+ {21, 0, 18, 0, 4, 0, 0},
+ {23, 0, 10, 0, 4, 0, 0},
+ {26, 0, 18, 0, 3, 0, 0},
+ {24, 0, 18, 0, 4, 0, 0},
+ {26, 0, 18, 0, 5, 0, 0},
+ {7, 0, 0, 0, 4, 0, 1},
+ {20, 0, 18, 1, 5, 0, 0},
+ {1, 0, 14, 0, 4, 0, 0},
+ {26, 0, 18, 0, 4, 0, 0},
+ {26, 0, 10, 0, 4, 0, 0},
+ {25, 0, 10, 0, 4, 0, 0},
+ {15, 0, 8, 0, 4, 0, 0},
+ {5, 0, 0, 0, 5, 0, 0},
+ {19, 0, 18, 1, 5, 0, 0},
+ {15, 0, 18, 0, 4, 0, 0},
+ {9, 0, 0, 0, 5, 0, 1},
+ {9, 0, 0, 0, 4, 0, 1},
+ {25, 0, 18, 0, 4, 0, 0},
+ {5, 0, 0, 0, 4, 0, 1},
+ {5, 0, 0, 0, 5, 0, 1},
+ {7, 0, 0, 0, 5, 0, 1},
+ {8, 0, 0, 0, 5, 0, 1},
+ {6, 0, 0, 0, 5, 0, 1},
+ {6, 0, 18, 0, 5, 0, 0},
+ {6, 0, 0, 0, 5, 0, 0},
+ {24, 0, 18, 0, 5, 0, 0},
+ {6, 0, 18, 0, 4, 0, 0},
+ {6, 0, 0, 0, 4, 0, 0},
+ {24, 0, 18, 0, 5, 0, 34},
+ {12, 230, 13, 0, 4, 0, 40},
+ {12, 232, 13, 0, 4, 0, 40},
+ {12, 220, 13, 0, 4, 0, 40},
+ {12, 216, 13, 0, 4, 0, 40},
+ {12, 202, 13, 0, 4, 0, 40},
+ {12, 1, 13, 0, 4, 0, 40},
+ {12, 240, 13, 0, 4, 0, 40},
+ {12, 0, 13, 0, 4, 0, 40},
+ {12, 233, 13, 0, 4, 0, 40},
+ {12, 234, 13, 0, 4, 0, 40},
+ {9, 0, 0, 0, 5, 0, 2},
+ {5, 0, 0, 0, 5, 0, 2},
+ {24, 0, 18, 0, 5, 0, 2},
+ {2, 0, 18, 0, 5, 0, 102},
+ {6, 0, 0, 0, 5, 0, 2},
+ {21, 0, 18, 0, 5, 0, 0},
+ {9, 0, 0, 0, 4, 0, 2},
+ {5, 0, 0, 0, 4, 0, 2},
+ {9, 0, 0, 0, 5, 0, 54},
+ {5, 0, 0, 0, 5, 0, 54},
+ {25, 0, 18, 0, 5, 0, 2},
+ {9, 0, 0, 0, 5, 0, 3},
+ {9, 0, 0, 0, 4, 0, 3},
+ {5, 0, 0, 0, 4, 0, 3},
+ {5, 0, 0, 0, 5, 0, 3},
+ {26, 0, 0, 0, 5, 0, 3},
+ {12, 230, 13, 0, 5, 0, 3},
+ {12, 230, 13, 0, 5, 0, 40},
+ {11, 0, 13, 0, 5, 0, 3},
+ {9, 0, 0, 0, 5, 0, 4},
+ {6, 0, 0, 0, 5, 0, 4},
+ {21, 0, 0, 0, 5, 0, 4},
+ {5, 0, 0, 0, 5, 0, 4},
+ {21, 0, 0, 0, 5, 0, 0},
+ {17, 0, 18, 0, 5, 0, 4},
+ {26, 0, 18, 0, 5, 0, 4},
+ {23, 0, 10, 0, 5, 0, 4},
+ {12, 220, 13, 0, 5, 0, 5},
+ {12, 230, 13, 0, 5, 0, 5},
+ {12, 222, 13, 0, 5, 0, 5},
+ {12, 228, 13, 0, 5, 0, 5},
+ {12, 10, 13, 0, 5, 0, 5},
+ {12, 11, 13, 0, 5, 0, 5},
+ {12, 12, 13, 0, 5, 0, 5},
+ {12, 13, 13, 0, 5, 0, 5},
+ {12, 14, 13, 0, 5, 0, 5},
+ {12, 15, 13, 0, 5, 0, 5},
+ {12, 16, 13, 0, 5, 0, 5},
+ {12, 17, 13, 0, 5, 0, 5},
+ {12, 18, 13, 0, 5, 0, 5},
+ {12, 19, 13, 0, 5, 0, 5},
+ {12, 20, 13, 0, 5, 0, 5},
+ {12, 21, 13, 0, 5, 0, 5},
+ {12, 22, 13, 0, 5, 0, 5},
+ {17, 0, 3, 0, 5, 0, 5},
+ {12, 23, 13, 0, 5, 0, 5},
+ {21, 0, 3, 0, 5, 0, 5},
+ {12, 24, 13, 0, 5, 0, 5},
+ {12, 25, 13, 0, 5, 0, 5},
+ {7, 0, 3, 0, 5, 0, 5},
+ {1, 0, 11, 0, 5, 0, 6},
+ {1, 0, 11, 0, 5, 0, 0},
+ {25, 0, 18, 0, 5, 0, 6},
+ {25, 0, 4, 0, 5, 0, 6},
+ {21, 0, 10, 0, 5, 0, 6},
+ {23, 0, 4, 0, 5, 0, 6},
+ {21, 0, 12, 0, 5, 0, 0},
+ {21, 0, 4, 0, 5, 0, 6},
+ {26, 0, 18, 0, 5, 0, 6},
+ {12, 230, 13, 0, 5, 0, 6},
+ {12, 30, 13, 0, 5, 0, 6},
+ {12, 31, 13, 0, 5, 0, 6},
+ {12, 32, 13, 0, 5, 0, 6},
+ {21, 0, 4, 0, 5, 0, 0},
+ {1, 0, 4, 0, 5, 0, 0},
+ {7, 0, 4, 0, 5, 0, 6},
+ {6, 0, 4, 0, 5, 0, 0},
+ {12, 27, 13, 0, 5, 0, 40},
+ {12, 28, 13, 0, 5, 0, 40},
+ {12, 29, 13, 0, 5, 0, 40},
+ {12, 30, 13, 0, 5, 0, 40},
+ {12, 31, 13, 0, 5, 0, 40},
+ {12, 32, 13, 0, 5, 0, 40},
+ {12, 33, 13, 0, 5, 0, 40},
+ {12, 34, 13, 0, 5, 0, 40},
+ {12, 220, 13, 0, 5, 0, 40},
+ {12, 220, 13, 0, 5, 0, 6},
+ {13, 0, 11, 0, 5, 0, 0},
+ {21, 0, 11, 0, 5, 0, 6},
+ {12, 35, 13, 0, 5, 0, 40},
+ {6, 0, 4, 0, 5, 0, 6},
+ {13, 0, 8, 0, 5, 0, 6},
+ {26, 0, 4, 0, 5, 0, 6},
+ {21, 0, 4, 0, 5, 0, 7},
+ {1, 0, 4, 0, 5, 0, 7},
+ {7, 0, 4, 0, 5, 0, 7},
+ {12, 36, 13, 0, 5, 0, 7},
+ {12, 230, 13, 0, 5, 0, 7},
+ {12, 220, 13, 0, 5, 0, 7},
+ {7, 0, 4, 0, 5, 0, 8},
+ {12, 0, 13, 0, 5, 0, 8},
+ {13, 0, 3, 0, 5, 0, 65},
+ {7, 0, 3, 0, 5, 0, 65},
+ {12, 230, 13, 0, 5, 0, 65},
+ {12, 220, 13, 0, 5, 0, 65},
+ {6, 0, 3, 0, 5, 0, 65},
+ {26, 0, 18, 0, 5, 0, 65},
+ {21, 0, 18, 0, 5, 0, 65},
+ {7, 0, 3, 0, 5, 0, 81},
+ {12, 230, 13, 0, 5, 0, 81},
+ {6, 0, 3, 0, 5, 0, 81},
+ {21, 0, 3, 0, 5, 0, 81},
+ {7, 0, 3, 0, 5, 0, 94},
+ {12, 220, 13, 0, 5, 0, 94},
+ {21, 0, 3, 0, 5, 0, 94},
+ {12, 27, 13, 0, 5, 0, 6},
+ {12, 28, 13, 0, 5, 0, 6},
+ {12, 29, 13, 0, 5, 0, 6},
+ {12, 0, 13, 0, 5, 0, 9},
+ {10, 0, 0, 0, 5, 0, 9},
+ {7, 0, 0, 0, 5, 0, 9},
+ {12, 7, 13, 0, 5, 0, 9},
+ {12, 9, 13, 0, 5, 0, 9},
+ {12, 230, 13, 0, 5, 0, 9},
+ {13, 0, 0, 0, 5, 0, 9},
+ {21, 0, 0, 0, 5, 0, 9},
+ {6, 0, 0, 0, 5, 0, 9},
+ {7, 0, 0, 0, 5, 0, 10},
+ {12, 0, 13, 0, 5, 0, 10},
+ {10, 0, 0, 0, 5, 0, 10},
+ {12, 7, 13, 0, 5, 0, 10},
+ {12, 9, 13, 0, 5, 0, 10},
+ {13, 0, 0, 0, 5, 0, 10},
+ {23, 0, 10, 0, 5, 0, 10},
+ {15, 0, 0, 0, 5, 0, 10},
+ {26, 0, 0, 0, 5, 0, 10},
+ {12, 0, 13, 0, 5, 0, 11},
+ {10, 0, 0, 0, 5, 0, 11},
+ {7, 0, 0, 0, 5, 0, 11},
+ {12, 7, 13, 0, 5, 0, 11},
+ {12, 9, 13, 0, 5, 0, 11},
+ {13, 0, 0, 0, 5, 0, 11},
+ {12, 0, 13, 0, 5, 0, 12},
+ {10, 0, 0, 0, 5, 0, 12},
+ {7, 0, 0, 0, 5, 0, 12},
+ {12, 7, 13, 0, 5, 0, 12},
+ {12, 9, 13, 0, 5, 0, 12},
+ {13, 0, 0, 0, 5, 0, 12},
+ {21, 0, 0, 0, 5, 0, 12},
+ {23, 0, 10, 0, 5, 0, 12},
+ {12, 0, 13, 0, 5, 0, 13},
+ {10, 0, 0, 0, 5, 0, 13},
+ {7, 0, 0, 0, 5, 0, 13},
+ {12, 7, 13, 0, 5, 0, 13},
+ {12, 9, 13, 0, 5, 0, 13},
+ {13, 0, 0, 0, 5, 0, 13},
+ {26, 0, 0, 0, 5, 0, 13},
+ {15, 0, 0, 0, 5, 0, 13},
+ {12, 0, 13, 0, 5, 0, 14},
+ {7, 0, 0, 0, 5, 0, 14},
+ {10, 0, 0, 0, 5, 0, 14},
+ {12, 9, 13, 0, 5, 0, 14},
+ {13, 0, 0, 0, 5, 0, 14},
+ {15, 0, 0, 0, 5, 0, 14},
+ {26, 0, 18, 0, 5, 0, 14},
+ {23, 0, 10, 0, 5, 0, 14},
+ {12, 0, 13, 0, 5, 0, 15},
+ {10, 0, 0, 0, 5, 0, 15},
+ {7, 0, 0, 0, 5, 0, 15},
+ {12, 9, 13, 0, 5, 0, 15},
+ {12, 84, 13, 0, 5, 0, 15},
+ {12, 91, 13, 0, 5, 0, 15},
+ {13, 0, 0, 0, 5, 0, 15},
+ {15, 0, 18, 0, 5, 0, 15},
+ {26, 0, 0, 0, 5, 0, 15},
+ {12, 0, 13, 0, 5, 0, 16},
+ {10, 0, 0, 0, 5, 0, 16},
+ {7, 0, 0, 0, 5, 0, 16},
+ {12, 7, 13, 0, 5, 0, 16},
+ {12, 0, 0, 0, 5, 0, 16},
+ {12, 9, 13, 0, 5, 0, 16},
+ {13, 0, 0, 0, 5, 0, 16},
+ {12, 0, 13, 0, 5, 0, 17},
+ {10, 0, 0, 0, 5, 0, 17},
+ {7, 0, 0, 0, 5, 0, 17},
+ {12, 9, 13, 0, 5, 0, 17},
+ {13, 0, 0, 0, 5, 0, 17},
+ {15, 0, 0, 0, 5, 0, 17},
+ {26, 0, 0, 0, 5, 0, 17},
+ {10, 0, 0, 0, 5, 0, 18},
+ {7, 0, 0, 0, 5, 0, 18},
+ {12, 9, 13, 0, 5, 0, 18},
+ {12, 0, 13, 0, 5, 0, 18},
+ {13, 0, 0, 0, 5, 0, 18},
+ {21, 0, 0, 0, 5, 0, 18},
+ {7, 0, 0, 0, 5, 0, 19},
+ {12, 0, 13, 0, 5, 0, 19},
+ {12, 103, 13, 0, 5, 0, 19},
+ {12, 9, 13, 0, 5, 0, 19},
+ {23, 0, 10, 0, 5, 0, 0},
+ {6, 0, 0, 0, 5, 0, 19},
+ {12, 107, 13, 0, 5, 0, 19},
+ {21, 0, 0, 0, 5, 0, 19},
+ {13, 0, 0, 0, 5, 0, 19},
+ {7, 0, 0, 0, 5, 0, 20},
+ {12, 0, 13, 0, 5, 0, 20},
+ {12, 118, 13, 0, 5, 0, 20},
+ {6, 0, 0, 0, 5, 0, 20},
+ {12, 122, 13, 0, 5, 0, 20},
+ {13, 0, 0, 0, 5, 0, 20},
+ {7, 0, 0, 0, 5, 0, 21},
+ {26, 0, 0, 0, 5, 0, 21},
+ {21, 0, 0, 0, 5, 0, 21},
+ {12, 220, 13, 0, 5, 0, 21},
+ {13, 0, 0, 0, 5, 0, 21},
+ {15, 0, 0, 0, 5, 0, 21},
+ {12, 216, 13, 0, 5, 0, 21},
+ {22, 0, 18, 1, 5, 0, 21},
+ {18, 0, 18, 1, 5, 0, 21},
+ {10, 0, 0, 0, 5, 0, 21},
+ {12, 129, 13, 0, 5, 0, 21},
+ {12, 130, 13, 0, 5, 0, 21},
+ {12, 0, 13, 0, 5, 0, 21},
+ {12, 132, 13, 0, 5, 0, 21},
+ {12, 230, 13, 0, 5, 0, 21},
+ {12, 9, 13, 0, 5, 0, 21},
+ {26, 0, 0, 0, 5, 0, 0},
+ {7, 0, 0, 0, 5, 0, 22},
+ {10, 0, 0, 0, 5, 0, 22},
+ {12, 0, 13, 0, 5, 0, 22},
+ {12, 7, 13, 0, 5, 0, 22},
+ {12, 9, 13, 0, 5, 0, 22},
+ {13, 0, 0, 0, 5, 0, 22},
+ {21, 0, 0, 0, 5, 0, 22},
+ {12, 220, 13, 0, 5, 0, 22},
+ {26, 0, 0, 0, 5, 0, 22},
+ {9, 0, 0, 0, 5, 0, 23},
+ {7, 0, 0, 0, 5, 0, 23},
+ {6, 0, 0, 0, 5, 0, 23},
+ {7, 0, 0, 0, 2, 0, 24},
+ {7, 0, 0, 0, 5, 0, 24},
+ {7, 0, 0, 0, 5, 0, 25},
+ {12, 230, 13, 0, 5, 0, 25},
+ {21, 0, 0, 0, 5, 0, 25},
+ {15, 0, 0, 0, 5, 0, 25},
+ {26, 0, 18, 0, 5, 0, 25},
+ {7, 0, 0, 0, 5, 0, 26},
+ {17, 0, 18, 0, 5, 0, 27},
+ {7, 0, 0, 0, 5, 0, 27},
+ {21, 0, 0, 0, 5, 0, 27},
+ {29, 0, 17, 0, 5, 0, 28},
+ {7, 0, 0, 0, 5, 0, 28},
+ {22, 0, 18, 1, 5, 0, 28},
+ {18, 0, 18, 1, 5, 0, 28},
+ {7, 0, 0, 0, 5, 0, 29},
+ {14, 0, 0, 0, 5, 0, 29},
+ {7, 0, 0, 0, 5, 0, 41},
+ {12, 0, 13, 0, 5, 0, 41},
+ {12, 9, 13, 0, 5, 0, 41},
+ {7, 0, 0, 0, 5, 0, 42},
+ {12, 0, 13, 0, 5, 0, 42},
+ {12, 9, 13, 0, 5, 0, 42},
+ {7, 0, 0, 0, 5, 0, 43},
+ {12, 0, 13, 0, 5, 0, 43},
+ {7, 0, 0, 0, 5, 0, 44},
+ {12, 0, 13, 0, 5, 0, 44},
+ {7, 0, 0, 0, 5, 0, 30},
+ {12, 0, 13, 0, 5, 0, 30},
+ {10, 0, 0, 0, 5, 0, 30},
+ {12, 9, 13, 0, 5, 0, 30},
+ {21, 0, 0, 0, 5, 0, 30},
+ {6, 0, 0, 0, 5, 0, 30},
+ {23, 0, 10, 0, 5, 0, 30},
+ {12, 230, 13, 0, 5, 0, 30},
+ {13, 0, 0, 0, 5, 0, 30},
+ {15, 0, 18, 0, 5, 0, 30},
+ {21, 0, 18, 0, 5, 0, 31},
+ {17, 0, 18, 0, 5, 0, 31},
+ {12, 0, 13, 0, 5, 0, 31},
+ {1, 0, 14, 0, 5, 0, 31},
+ {13, 0, 0, 0, 5, 0, 31},
+ {7, 0, 0, 0, 5, 0, 31},
+ {6, 0, 0, 0, 5, 0, 31},
+ {12, 228, 13, 0, 5, 0, 31},
+ {7, 0, 0, 0, 5, 0, 45},
+ {12, 0, 13, 0, 5, 0, 45},
+ {10, 0, 0, 0, 5, 0, 45},
+ {12, 222, 13, 0, 5, 0, 45},
+ {12, 230, 13, 0, 5, 0, 45},
+ {12, 220, 13, 0, 5, 0, 45},
+ {26, 0, 18, 0, 5, 0, 45},
+ {21, 0, 18, 0, 5, 0, 45},
+ {13, 0, 0, 0, 5, 0, 45},
+ {7, 0, 0, 0, 5, 0, 46},
+ {7, 0, 0, 0, 5, 0, 55},
+ {10, 0, 0, 0, 5, 0, 55},
+ {13, 0, 0, 0, 5, 0, 55},
+ {15, 0, 0, 0, 5, 0, 55},
+ {26, 0, 18, 0, 5, 0, 55},
+ {26, 0, 18, 0, 5, 0, 30},
+ {7, 0, 0, 0, 5, 0, 53},
+ {12, 230, 13, 0, 5, 0, 53},
+ {12, 220, 13, 0, 5, 0, 53},
+ {10, 0, 0, 0, 5, 0, 53},
+ {12, 0, 13, 0, 5, 0, 53},
+ {21, 0, 0, 0, 5, 0, 53},
+ {7, 0, 0, 0, 5, 0, 77},
+ {10, 0, 0, 0, 5, 0, 77},
+ {12, 0, 13, 0, 5, 0, 77},
+ {12, 9, 13, 0, 5, 0, 77},
+ {12, 230, 13, 0, 5, 0, 77},
+ {12, 220, 13, 0, 5, 0, 77},
+ {13, 0, 0, 0, 5, 0, 77},
+ {21, 0, 0, 0, 5, 0, 77},
+ {6, 0, 0, 0, 5, 0, 77},
+ {11, 0, 13, 0, 5, 0, 40},
+ {12, 0, 13, 0, 5, 0, 61},
+ {10, 0, 0, 0, 5, 0, 61},
+ {7, 0, 0, 0, 5, 0, 61},
+ {12, 7, 13, 0, 5, 0, 61},
+ {10, 9, 0, 0, 5, 0, 61},
+ {13, 0, 0, 0, 5, 0, 61},
+ {21, 0, 0, 0, 5, 0, 61},
+ {26, 0, 0, 0, 5, 0, 61},
+ {12, 230, 13, 0, 5, 0, 61},
+ {12, 220, 13, 0, 5, 0, 61},
+ {12, 0, 13, 0, 5, 0, 66},
+ {10, 0, 0, 0, 5, 0, 66},
+ {7, 0, 0, 0, 5, 0, 66},
+ {10, 9, 0, 0, 5, 0, 66},
+ {12, 9, 13, 0, 5, 0, 66},
+ {13, 0, 0, 0, 5, 0, 66},
+ {7, 0, 0, 0, 5, 0, 92},
+ {12, 7, 13, 0, 5, 0, 92},
+ {10, 0, 0, 0, 5, 0, 92},
+ {12, 0, 13, 0, 5, 0, 92},
+ {10, 9, 0, 0, 5, 0, 92},
+ {21, 0, 0, 0, 5, 0, 92},
+ {7, 0, 0, 0, 5, 0, 67},
+ {10, 0, 0, 0, 5, 0, 67},
+ {12, 0, 13, 0, 5, 0, 67},
+ {12, 7, 13, 0, 5, 0, 67},
+ {21, 0, 0, 0, 5, 0, 67},
+ {13, 0, 0, 0, 5, 0, 67},
+ {13, 0, 0, 0, 5, 0, 68},
+ {7, 0, 0, 0, 5, 0, 68},
+ {6, 0, 0, 0, 5, 0, 68},
+ {21, 0, 0, 0, 5, 0, 68},
+ {21, 0, 0, 0, 5, 0, 66},
+ {12, 1, 13, 0, 5, 0, 40},
+ {10, 0, 0, 0, 5, 0, 0},
+ {7, 0, 0, 0, 5, 0, 0},
+ {6, 0, 0, 0, 5, 0, 3},
+ {12, 234, 13, 0, 5, 0, 40},
+ {12, 214, 13, 0, 5, 0, 40},
+ {12, 202, 13, 0, 5, 0, 40},
+ {12, 233, 13, 0, 5, 0, 40},
+ {8, 0, 0, 0, 5, 0, 2},
+ {29, 0, 17, 0, 5, 0, 0},
+ {1, 0, 14, 0, 5, 0, 0},
+ {1, 0, 14, 0, 5, 0, 40},
+ {1, 0, 0, 0, 5, 0, 0},
+ {1, 0, 3, 0, 5, 0, 0},
+ {17, 0, 18, 0, 4, 0, 0},
+ {17, 0, 18, 0, 5, 0, 0},
+ {20, 0, 18, 0, 4, 0, 0},
+ {19, 0, 18, 0, 4, 0, 0},
+ {22, 0, 18, 0, 5, 0, 0},
+ {20, 0, 18, 0, 5, 0, 0},
+ {27, 0, 17, 0, 5, 0, 0},
+ {28, 0, 15, 0, 5, 0, 0},
+ {1, 0, 1, 0, 5, 0, 0},
+ {1, 0, 5, 0, 5, 0, 0},
+ {1, 0, 7, 0, 5, 0, 0},
+ {1, 0, 2, 0, 5, 0, 0},
+ {1, 0, 6, 0, 5, 0, 0},
+ {21, 0, 10, 0, 4, 0, 0},
+ {21, 0, 10, 0, 5, 0, 0},
+ {16, 0, 18, 0, 5, 0, 0},
+ {25, 0, 12, 0, 5, 0, 0},
+ {22, 0, 18, 1, 5, 0, 0},
+ {18, 0, 18, 1, 5, 0, 0},
+ {25, 0, 18, 0, 5, 0, 0},
+ {1, 0, 19, 0, 5, 0, 0},
+ {1, 0, 20, 0, 5, 0, 0},
+ {1, 0, 21, 0, 5, 0, 0},
+ {1, 0, 22, 0, 5, 0, 0},
+ {15, 0, 8, 0, 5, 0, 0},
+ {25, 0, 9, 0, 5, 0, 0},
+ {6, 0, 0, 0, 4, 0, 1},
+ {23, 0, 10, 0, 1, 0, 0},
+ {9, 0, 0, 0, 5, 0, 0},
+ {5, 0, 0, 0, 4, 0, 0},
+ {26, 0, 10, 0, 5, 0, 0},
+ {25, 0, 18, 1, 5, 0, 0},
+ {15, 0, 18, 0, 5, 0, 0},
+ {14, 0, 0, 0, 4, 0, 1},
+ {14, 0, 0, 0, 5, 0, 1},
+ {25, 0, 18, 1, 4, 0, 0},
+ {25, 0, 10, 0, 5, 0, 0},
+ {22, 0, 18, 1, 2, 0, 0},
+ {18, 0, 18, 1, 2, 0, 0},
+ {26, 0, 0, 0, 4, 0, 0},
+ {26, 0, 0, 0, 5, 0, 52},
+ {9, 0, 0, 0, 5, 0, 56},
+ {5, 0, 0, 0, 5, 0, 56},
+ {26, 0, 18, 0, 5, 0, 54},
+ {12, 230, 13, 0, 5, 0, 54},
+ {21, 0, 18, 0, 5, 0, 54},
+ {15, 0, 18, 0, 5, 0, 54},
+ {5, 0, 0, 0, 5, 0, 23},
+ {7, 0, 0, 0, 5, 0, 57},
+ {6, 0, 0, 0, 5, 0, 57},
+ {21, 0, 0, 0, 5, 0, 57},
+ {12, 9, 13, 0, 5, 0, 57},
+ {26, 0, 18, 0, 2, 0, 35},
+ {26, 0, 18, 0, 2, 0, 0},
+ {29, 0, 17, 0, 0, 0, 0},
+ {21, 0, 18, 0, 2, 0, 0},
+ {6, 0, 0, 0, 2, 0, 35},
+ {7, 0, 0, 0, 2, 0, 0},
+ {14, 0, 0, 0, 2, 0, 35},
+ {17, 0, 18, 0, 2, 0, 0},
+ {22, 0, 18, 0, 2, 0, 0},
+ {18, 0, 18, 0, 2, 0, 0},
+ {12, 218, 13, 0, 2, 0, 40},
+ {12, 228, 13, 0, 2, 0, 40},
+ {12, 232, 13, 0, 2, 0, 40},
+ {12, 222, 13, 0, 2, 0, 40},
+ {10, 224, 0, 0, 2, 0, 24},
+ {6, 0, 0, 0, 2, 0, 0},
+ {7, 0, 0, 0, 2, 0, 32},
+ {12, 8, 13, 0, 2, 0, 40},
+ {24, 0, 18, 0, 2, 0, 0},
+ {6, 0, 0, 0, 2, 0, 32},
+ {7, 0, 0, 0, 2, 0, 33},
+ {6, 0, 0, 0, 2, 0, 33},
+ {7, 0, 0, 0, 2, 0, 34},
+ {26, 0, 0, 0, 2, 0, 0},
+ {15, 0, 0, 0, 2, 0, 0},
+ {26, 0, 0, 0, 2, 0, 24},
+ {26, 0, 18, 0, 2, 0, 24},
+ {15, 0, 0, 0, 4, 0, 0},
+ {15, 0, 18, 0, 2, 0, 0},
+ {26, 0, 0, 0, 2, 0, 33},
+ {7, 0, 0, 0, 2, 0, 35},
+ {2, 0, 18, 0, 2, 0, 35},
+ {2, 0, 18, 0, 2, 0, 102},
+ {7, 0, 0, 0, 2, 0, 36},
+ {6, 0, 0, 0, 2, 0, 36},
+ {26, 0, 18, 0, 2, 0, 36},
+ {7, 0, 0, 0, 5, 0, 82},
+ {6, 0, 0, 0, 5, 0, 82},
+ {21, 0, 0, 0, 5, 0, 82},
+ {7, 0, 0, 0, 5, 0, 69},
+ {6, 0, 0, 0, 5, 0, 69},
+ {21, 0, 18, 0, 5, 0, 69},
+ {13, 0, 0, 0, 5, 0, 69},
+ {7, 0, 0, 0, 5, 0, 3},
+ {21, 0, 18, 0, 5, 0, 3},
+ {6, 0, 18, 0, 5, 0, 3},
+ {7, 0, 0, 0, 5, 0, 83},
+ {14, 0, 0, 0, 5, 0, 83},
+ {12, 230, 13, 0, 5, 0, 83},
+ {21, 0, 0, 0, 5, 0, 83},
+ {24, 0, 0, 0, 5, 0, 0},
+ {7, 0, 0, 0, 5, 0, 58},
+ {12, 0, 13, 0, 5, 0, 58},
+ {12, 9, 13, 0, 5, 0, 58},
+ {10, 0, 0, 0, 5, 0, 58},
+ {26, 0, 18, 0, 5, 0, 58},
+ {15, 0, 0, 0, 5, 0, 0},
+ {7, 0, 0, 0, 5, 0, 64},
+ {21, 0, 18, 0, 5, 0, 64},
+ {10, 0, 0, 0, 5, 0, 70},
+ {7, 0, 0, 0, 5, 0, 70},
+ {12, 9, 13, 0, 5, 0, 70},
+ {21, 0, 0, 0, 5, 0, 70},
+ {13, 0, 0, 0, 5, 0, 70},
+ {13, 0, 0, 0, 5, 0, 71},
+ {7, 0, 0, 0, 5, 0, 71},
+ {12, 0, 13, 0, 5, 0, 71},
+ {12, 220, 13, 0, 5, 0, 71},
+ {21, 0, 0, 0, 5, 0, 71},
+ {7, 0, 0, 0, 5, 0, 72},
+ {12, 0, 13, 0, 5, 0, 72},
+ {10, 0, 0, 0, 5, 0, 72},
+ {10, 9, 0, 0, 5, 0, 72},
+ {21, 0, 0, 0, 5, 0, 72},
+ {12, 0, 13, 0, 5, 0, 84},
+ {10, 0, 0, 0, 5, 0, 84},
+ {7, 0, 0, 0, 5, 0, 84},
+ {12, 7, 13, 0, 5, 0, 84},
+ {10, 9, 0, 0, 5, 0, 84},
+ {21, 0, 0, 0, 5, 0, 84},
+ {13, 0, 0, 0, 5, 0, 84},
+ {6, 0, 0, 0, 5, 0, 22},
+ {7, 0, 0, 0, 5, 0, 76},
+ {12, 0, 13, 0, 5, 0, 76},
+ {10, 0, 0, 0, 5, 0, 76},
+ {13, 0, 0, 0, 5, 0, 76},
+ {21, 0, 0, 0, 5, 0, 76},
+ {7, 0, 0, 0, 5, 0, 78},
+ {12, 230, 13, 0, 5, 0, 78},
+ {12, 220, 13, 0, 5, 0, 78},
+ {6, 0, 0, 0, 5, 0, 78},
+ {21, 0, 0, 0, 5, 0, 78},
+ {7, 0, 0, 0, 5, 0, 85},
+ {10, 0, 0, 0, 5, 0, 85},
+ {12, 0, 13, 0, 5, 0, 85},
+ {21, 0, 0, 0, 5, 0, 85},
+ {6, 0, 0, 0, 5, 0, 85},
+ {12, 9, 13, 0, 5, 0, 85},
+ {13, 0, 0, 0, 5, 0, 85},
+ {2, 0, 18, 0, 2, 0, 24},
+ {4, 0, 0, 0, 5, 0, 102},
+ {3, 0, 0, 0, 4, 0, 102},
+ {2, 0, 18, 0, 4, 0, 102},
+ {12, 26, 13, 0, 5, 0, 5},
+ {25, 0, 9, 0, 5, 0, 5},
+ {24, 0, 4, 0, 5, 0, 6},
+ {18, 0, 18, 0, 5, 0, 0},
+ {16, 0, 18, 0, 2, 0, 0},
+ {21, 0, 12, 0, 2, 0, 0},
+ {21, 0, 10, 0, 2, 0, 0},
+ {25, 0, 9, 0, 2, 0, 0},
+ {17, 0, 9, 0, 2, 0, 0},
+ {25, 0, 18, 1, 2, 0, 0},
+ {25, 0, 18, 0, 2, 0, 0},
+ {23, 0, 10, 0, 2, 0, 0},
+ {21, 0, 18, 0, 0, 0, 0},
+ {21, 0, 10, 0, 0, 0, 0},
+ {23, 0, 10, 0, 0, 0, 0},
+ {22, 0, 18, 1, 0, 0, 0},
+ {18, 0, 18, 1, 0, 0, 0},
+ {25, 0, 9, 0, 0, 0, 0},
+ {21, 0, 12, 0, 0, 0, 0},
+ {17, 0, 9, 0, 0, 0, 0},
+ {13, 0, 8, 0, 0, 0, 0},
+ {25, 0, 18, 1, 0, 0, 0},
+ {25, 0, 18, 0, 0, 0, 0},
+ {9, 0, 0, 0, 0, 0, 1},
+ {24, 0, 18, 0, 0, 0, 0},
+ {16, 0, 18, 0, 0, 0, 0},
+ {5, 0, 0, 0, 0, 0, 1},
+ {21, 0, 18, 0, 1, 0, 0},
+ {22, 0, 18, 1, 1, 0, 0},
+ {18, 0, 18, 1, 1, 0, 0},
+ {7, 0, 0, 0, 1, 0, 33},
+ {6, 0, 0, 0, 1, 0, 0},
+ {7, 0, 0, 0, 1, 0, 24},
+ {26, 0, 18, 0, 0, 0, 0},
+ {26, 0, 18, 0, 1, 0, 0},
+ {25, 0, 18, 0, 1, 0, 0},
+ {1, 0, 18, 0, 5, 0, 0},
+ {7, 0, 0, 0, 5, 0, 47},
+ {14, 0, 18, 0, 5, 0, 2},
+ {15, 0, 18, 0, 5, 0, 2},
+ {26, 0, 18, 0, 5, 0, 2},
+ {7, 0, 0, 0, 5, 0, 73},
+ {7, 0, 0, 0, 5, 0, 74},
+ {7, 0, 0, 0, 5, 0, 37},
+ {15, 0, 0, 0, 5, 0, 37},
+ {7, 0, 0, 0, 5, 0, 38},
+ {14, 0, 0, 0, 5, 0, 38},
+ {7, 0, 0, 0, 5, 0, 118},
+ {12, 230, 13, 0, 5, 0, 118},
+ {7, 0, 0, 0, 5, 0, 48},
+ {21, 0, 0, 0, 5, 0, 48},
+ {7, 0, 0, 0, 5, 0, 59},
+ {21, 0, 0, 0, 5, 0, 59},
+ {14, 0, 0, 0, 5, 0, 59},
+ {9, 0, 0, 0, 5, 0, 39},
+ {5, 0, 0, 0, 5, 0, 39},
+ {7, 0, 0, 0, 5, 0, 49},
+ {7, 0, 0, 0, 5, 0, 50},
+ {13, 0, 0, 0, 5, 0, 50},
+ {7, 0, 0, 0, 5, 0, 106},
+ {7, 0, 0, 0, 5, 0, 104},
+ {21, 0, 0, 0, 5, 0, 104},
+ {7, 0, 0, 0, 5, 0, 110},
+ {7, 0, 3, 0, 5, 0, 51},
+ {7, 0, 3, 0, 5, 0, 86},
+ {21, 0, 3, 0, 5, 0, 86},
+ {15, 0, 3, 0, 5, 0, 86},
+ {7, 0, 3, 0, 5, 0, 120},
+ {26, 0, 3, 0, 5, 0, 120},
+ {15, 0, 3, 0, 5, 0, 120},
+ {7, 0, 3, 0, 5, 0, 116},
+ {15, 0, 3, 0, 5, 0, 116},
+ {7, 0, 3, 0, 5, 0, 63},
+ {15, 0, 3, 0, 5, 0, 63},
+ {21, 0, 18, 0, 5, 0, 63},
+ {7, 0, 3, 0, 5, 0, 75},
+ {21, 0, 3, 0, 5, 0, 75},
+ {7, 0, 3, 0, 5, 0, 97},
+ {7, 0, 3, 0, 5, 0, 96},
+ {7, 0, 3, 0, 5, 0, 60},
+ {12, 0, 13, 0, 5, 0, 60},
+ {12, 220, 13, 0, 5, 0, 60},
+ {12, 230, 13, 0, 5, 0, 60},
+ {12, 1, 13, 0, 5, 0, 60},
+ {12, 9, 13, 0, 5, 0, 60},
+ {15, 0, 3, 0, 5, 0, 60},
+ {21, 0, 3, 0, 5, 0, 60},
+ {7, 0, 3, 0, 5, 0, 87},
+ {15, 0, 3, 0, 5, 0, 87},
+ {21, 0, 3, 0, 5, 0, 87},
+ {7, 0, 3, 0, 5, 0, 117},
+ {15, 0, 3, 0, 5, 0, 117},
+ {7, 0, 3, 0, 5, 0, 112},
+ {26, 0, 3, 0, 5, 0, 112},
+ {12, 230, 13, 0, 5, 0, 112},
+ {12, 220, 13, 0, 5, 0, 112},
+ {15, 0, 3, 0, 5, 0, 112},
+ {21, 0, 3, 0, 5, 0, 112},
+ {7, 0, 3, 0, 5, 0, 79},
+ {21, 0, 18, 0, 5, 0, 79},
+ {7, 0, 3, 0, 5, 0, 88},
+ {15, 0, 3, 0, 5, 0, 88},
+ {7, 0, 3, 0, 5, 0, 89},
+ {15, 0, 3, 0, 5, 0, 89},
+ {7, 0, 3, 0, 5, 0, 122},
+ {21, 0, 3, 0, 5, 0, 122},
+ {15, 0, 3, 0, 5, 0, 122},
+ {7, 0, 3, 0, 5, 0, 90},
+ {15, 0, 11, 0, 5, 0, 6},
+ {10, 0, 0, 0, 5, 0, 93},
+ {12, 0, 13, 0, 5, 0, 93},
+ {7, 0, 0, 0, 5, 0, 93},
+ {12, 9, 13, 0, 5, 0, 93},
+ {21, 0, 0, 0, 5, 0, 93},
+ {15, 0, 18, 0, 5, 0, 93},
+ {13, 0, 0, 0, 5, 0, 93},
+ {12, 0, 13, 0, 5, 0, 91},
+ {10, 0, 0, 0, 5, 0, 91},
+ {7, 0, 0, 0, 5, 0, 91},
+ {12, 9, 13, 0, 5, 0, 91},
+ {12, 7, 13, 0, 5, 0, 91},
+ {21, 0, 0, 0, 5, 0, 91},
+ {1, 0, 0, 0, 5, 0, 91},
+ {7, 0, 0, 0, 5, 0, 100},
+ {13, 0, 0, 0, 5, 0, 100},
+ {12, 230, 13, 0, 5, 0, 95},
+ {7, 0, 0, 0, 5, 0, 95},
+ {12, 0, 13, 0, 5, 0, 95},
+ {10, 0, 0, 0, 5, 0, 95},
+ {12, 9, 13, 0, 5, 0, 95},
+ {13, 0, 0, 0, 5, 0, 95},
+ {21, 0, 0, 0, 5, 0, 95},
+ {7, 0, 0, 0, 5, 0, 111},
+ {12, 7, 13, 0, 5, 0, 111},
+ {21, 0, 0, 0, 5, 0, 111},
+ {12, 0, 13, 0, 5, 0, 99},
+ {10, 0, 0, 0, 5, 0, 99},
+ {7, 0, 0, 0, 5, 0, 99},
+ {10, 9, 0, 0, 5, 0, 99},
+ {21, 0, 0, 0, 5, 0, 99},
+ {13, 0, 0, 0, 5, 0, 99},
+ {15, 0, 0, 0, 5, 0, 18},
+ {7, 0, 0, 0, 5, 0, 108},
+ {10, 0, 0, 0, 5, 0, 108},
+ {12, 0, 13, 0, 5, 0, 108},
+ {10, 9, 0, 0, 5, 0, 108},
+ {12, 7, 13, 0, 5, 0, 108},
+ {21, 0, 0, 0, 5, 0, 108},
+ {7, 0, 0, 0, 5, 0, 109},
+ {12, 0, 13, 0, 5, 0, 109},
+ {10, 0, 0, 0, 5, 0, 109},
+ {12, 7, 13, 0, 5, 0, 109},
+ {12, 9, 13, 0, 5, 0, 109},
+ {13, 0, 0, 0, 5, 0, 109},
+ {12, 0, 13, 0, 5, 0, 107},
+ {10, 0, 0, 0, 5, 0, 107},
+ {7, 0, 0, 0, 5, 0, 107},
+ {12, 7, 13, 0, 5, 0, 107},
+ {10, 9, 0, 0, 5, 0, 107},
+ {12, 230, 13, 0, 5, 0, 107},
+ {7, 0, 0, 0, 5, 0, 124},
+ {10, 0, 0, 0, 5, 0, 124},
+ {12, 0, 13, 0, 5, 0, 124},
+ {12, 9, 13, 0, 5, 0, 124},
+ {12, 7, 13, 0, 5, 0, 124},
+ {21, 0, 0, 0, 5, 0, 124},
+ {13, 0, 0, 0, 5, 0, 124},
+ {7, 0, 0, 0, 5, 0, 123},
+ {10, 0, 0, 0, 5, 0, 123},
+ {12, 0, 13, 0, 5, 0, 123},
+ {12, 9, 13, 0, 5, 0, 123},
+ {12, 7, 13, 0, 5, 0, 123},
+ {21, 0, 0, 0, 5, 0, 123},
+ {7, 0, 0, 0, 5, 0, 114},
+ {10, 0, 0, 0, 5, 0, 114},
+ {12, 0, 13, 0, 5, 0, 114},
+ {12, 9, 13, 0, 5, 0, 114},
+ {21, 0, 0, 0, 5, 0, 114},
+ {13, 0, 0, 0, 5, 0, 114},
+ {7, 0, 0, 0, 5, 0, 101},
+ {12, 0, 13, 0, 5, 0, 101},
+ {10, 0, 0, 0, 5, 0, 101},
+ {10, 9, 0, 0, 5, 0, 101},
+ {12, 7, 13, 0, 5, 0, 101},
+ {13, 0, 0, 0, 5, 0, 101},
+ {9, 0, 0, 0, 5, 0, 125},
+ {5, 0, 0, 0, 5, 0, 125},
+ {13, 0, 0, 0, 5, 0, 125},
+ {15, 0, 0, 0, 5, 0, 125},
+ {7, 0, 0, 0, 5, 0, 125},
+ {7, 0, 0, 0, 5, 0, 121},
+ {7, 0, 0, 0, 5, 0, 62},
+ {14, 0, 0, 0, 5, 0, 62},
+ {21, 0, 0, 0, 5, 0, 62},
+ {7, 0, 0, 0, 5, 0, 80},
+ {7, 0, 0, 0, 5, 0, 115},
+ {13, 0, 0, 0, 5, 0, 115},
+ {21, 0, 0, 0, 5, 0, 115},
+ {7, 0, 0, 0, 5, 0, 103},
+ {12, 1, 13, 0, 5, 0, 103},
+ {21, 0, 0, 0, 5, 0, 103},
+ {7, 0, 0, 0, 5, 0, 119},
+ {12, 230, 13, 0, 5, 0, 119},
+ {21, 0, 0, 0, 5, 0, 119},
+ {26, 0, 0, 0, 5, 0, 119},
+ {6, 0, 0, 0, 5, 0, 119},
+ {13, 0, 0, 0, 5, 0, 119},
+ {15, 0, 0, 0, 5, 0, 119},
+ {7, 0, 0, 0, 5, 0, 98},
+ {10, 0, 0, 0, 5, 0, 98},
+ {12, 0, 13, 0, 5, 0, 98},
+ {6, 0, 0, 0, 5, 0, 98},
+ {7, 0, 0, 0, 5, 0, 105},
+ {26, 0, 0, 0, 5, 0, 105},
+ {12, 0, 13, 0, 5, 0, 105},
+ {12, 1, 13, 0, 5, 0, 105},
+ {21, 0, 0, 0, 5, 0, 105},
+ {10, 216, 0, 0, 5, 0, 0},
+ {10, 226, 0, 0, 5, 0, 0},
+ {12, 230, 13, 0, 5, 0, 2},
+ {25, 0, 0, 0, 5, 0, 0},
+ {13, 0, 8, 0, 5, 0, 0},
+ {7, 0, 3, 0, 5, 0, 113},
+ {15, 0, 3, 0, 5, 0, 113},
+ {12, 220, 13, 0, 5, 0, 113},
+ {26, 0, 0, 0, 2, 0, 32},
+};
+
+#define BIDI_MIRROR_LEN 364
+static const MirrorPair mirror_pairs[] = {
+ {40, 41},
+ {41, 40},
+ {60, 62},
+ {62, 60},
+ {91, 93},
+ {93, 91},
+ {123, 125},
+ {125, 123},
+ {171, 187},
+ {187, 171},
+ {3898, 3899},
+ {3899, 3898},
+ {3900, 3901},
+ {3901, 3900},
+ {5787, 5788},
+ {5788, 5787},
+ {8249, 8250},
+ {8250, 8249},
+ {8261, 8262},
+ {8262, 8261},
+ {8317, 8318},
+ {8318, 8317},
+ {8333, 8334},
+ {8334, 8333},
+ {8712, 8715},
+ {8713, 8716},
+ {8714, 8717},
+ {8715, 8712},
+ {8716, 8713},
+ {8717, 8714},
+ {8725, 10741},
+ {8764, 8765},
+ {8765, 8764},
+ {8771, 8909},
+ {8786, 8787},
+ {8787, 8786},
+ {8788, 8789},
+ {8789, 8788},
+ {8804, 8805},
+ {8805, 8804},
+ {8806, 8807},
+ {8807, 8806},
+ {8808, 8809},
+ {8809, 8808},
+ {8810, 8811},
+ {8811, 8810},
+ {8814, 8815},
+ {8815, 8814},
+ {8816, 8817},
+ {8817, 8816},
+ {8818, 8819},
+ {8819, 8818},
+ {8820, 8821},
+ {8821, 8820},
+ {8822, 8823},
+ {8823, 8822},
+ {8824, 8825},
+ {8825, 8824},
+ {8826, 8827},
+ {8827, 8826},
+ {8828, 8829},
+ {8829, 8828},
+ {8830, 8831},
+ {8831, 8830},
+ {8832, 8833},
+ {8833, 8832},
+ {8834, 8835},
+ {8835, 8834},
+ {8836, 8837},
+ {8837, 8836},
+ {8838, 8839},
+ {8839, 8838},
+ {8840, 8841},
+ {8841, 8840},
+ {8842, 8843},
+ {8843, 8842},
+ {8847, 8848},
+ {8848, 8847},
+ {8849, 8850},
+ {8850, 8849},
+ {8856, 10680},
+ {8866, 8867},
+ {8867, 8866},
+ {8870, 10974},
+ {8872, 10980},
+ {8873, 10979},
+ {8875, 10981},
+ {8880, 8881},
+ {8881, 8880},
+ {8882, 8883},
+ {8883, 8882},
+ {8884, 8885},
+ {8885, 8884},
+ {8886, 8887},
+ {8887, 8886},
+ {8905, 8906},
+ {8906, 8905},
+ {8907, 8908},
+ {8908, 8907},
+ {8909, 8771},
+ {8912, 8913},
+ {8913, 8912},
+ {8918, 8919},
+ {8919, 8918},
+ {8920, 8921},
+ {8921, 8920},
+ {8922, 8923},
+ {8923, 8922},
+ {8924, 8925},
+ {8925, 8924},
+ {8926, 8927},
+ {8927, 8926},
+ {8928, 8929},
+ {8929, 8928},
+ {8930, 8931},
+ {8931, 8930},
+ {8932, 8933},
+ {8933, 8932},
+ {8934, 8935},
+ {8935, 8934},
+ {8936, 8937},
+ {8937, 8936},
+ {8938, 8939},
+ {8939, 8938},
+ {8940, 8941},
+ {8941, 8940},
+ {8944, 8945},
+ {8945, 8944},
+ {8946, 8954},
+ {8947, 8955},
+ {8948, 8956},
+ {8950, 8957},
+ {8951, 8958},
+ {8954, 8946},
+ {8955, 8947},
+ {8956, 8948},
+ {8957, 8950},
+ {8958, 8951},
+ {8968, 8969},
+ {8969, 8968},
+ {8970, 8971},
+ {8971, 8970},
+ {9001, 9002},
+ {9002, 9001},
+ {10088, 10089},
+ {10089, 10088},
+ {10090, 10091},
+ {10091, 10090},
+ {10092, 10093},
+ {10093, 10092},
+ {10094, 10095},
+ {10095, 10094},
+ {10096, 10097},
+ {10097, 10096},
+ {10098, 10099},
+ {10099, 10098},
+ {10100, 10101},
+ {10101, 10100},
+ {10179, 10180},
+ {10180, 10179},
+ {10181, 10182},
+ {10182, 10181},
+ {10184, 10185},
+ {10185, 10184},
+ {10187, 10189},
+ {10189, 10187},
+ {10197, 10198},
+ {10198, 10197},
+ {10205, 10206},
+ {10206, 10205},
+ {10210, 10211},
+ {10211, 10210},
+ {10212, 10213},
+ {10213, 10212},
+ {10214, 10215},
+ {10215, 10214},
+ {10216, 10217},
+ {10217, 10216},
+ {10218, 10219},
+ {10219, 10218},
+ {10220, 10221},
+ {10221, 10220},
+ {10222, 10223},
+ {10223, 10222},
+ {10627, 10628},
+ {10628, 10627},
+ {10629, 10630},
+ {10630, 10629},
+ {10631, 10632},
+ {10632, 10631},
+ {10633, 10634},
+ {10634, 10633},
+ {10635, 10636},
+ {10636, 10635},
+ {10637, 10640},
+ {10638, 10639},
+ {10639, 10638},
+ {10640, 10637},
+ {10641, 10642},
+ {10642, 10641},
+ {10643, 10644},
+ {10644, 10643},
+ {10645, 10646},
+ {10646, 10645},
+ {10647, 10648},
+ {10648, 10647},
+ {10680, 8856},
+ {10688, 10689},
+ {10689, 10688},
+ {10692, 10693},
+ {10693, 10692},
+ {10703, 10704},
+ {10704, 10703},
+ {10705, 10706},
+ {10706, 10705},
+ {10708, 10709},
+ {10709, 10708},
+ {10712, 10713},
+ {10713, 10712},
+ {10714, 10715},
+ {10715, 10714},
+ {10741, 8725},
+ {10744, 10745},
+ {10745, 10744},
+ {10748, 10749},
+ {10749, 10748},
+ {10795, 10796},
+ {10796, 10795},
+ {10797, 10798},
+ {10798, 10797},
+ {10804, 10805},
+ {10805, 10804},
+ {10812, 10813},
+ {10813, 10812},
+ {10852, 10853},
+ {10853, 10852},
+ {10873, 10874},
+ {10874, 10873},
+ {10877, 10878},
+ {10878, 10877},
+ {10879, 10880},
+ {10880, 10879},
+ {10881, 10882},
+ {10882, 10881},
+ {10883, 10884},
+ {10884, 10883},
+ {10891, 10892},
+ {10892, 10891},
+ {10897, 10898},
+ {10898, 10897},
+ {10899, 10900},
+ {10900, 10899},
+ {10901, 10902},
+ {10902, 10901},
+ {10903, 10904},
+ {10904, 10903},
+ {10905, 10906},
+ {10906, 10905},
+ {10907, 10908},
+ {10908, 10907},
+ {10913, 10914},
+ {10914, 10913},
+ {10918, 10919},
+ {10919, 10918},
+ {10920, 10921},
+ {10921, 10920},
+ {10922, 10923},
+ {10923, 10922},
+ {10924, 10925},
+ {10925, 10924},
+ {10927, 10928},
+ {10928, 10927},
+ {10931, 10932},
+ {10932, 10931},
+ {10939, 10940},
+ {10940, 10939},
+ {10941, 10942},
+ {10942, 10941},
+ {10943, 10944},
+ {10944, 10943},
+ {10945, 10946},
+ {10946, 10945},
+ {10947, 10948},
+ {10948, 10947},
+ {10949, 10950},
+ {10950, 10949},
+ {10957, 10958},
+ {10958, 10957},
+ {10959, 10960},
+ {10960, 10959},
+ {10961, 10962},
+ {10962, 10961},
+ {10963, 10964},
+ {10964, 10963},
+ {10965, 10966},
+ {10966, 10965},
+ {10974, 8870},
+ {10979, 8873},
+ {10980, 8872},
+ {10981, 8875},
+ {10988, 10989},
+ {10989, 10988},
+ {10999, 11000},
+ {11000, 10999},
+ {11001, 11002},
+ {11002, 11001},
+ {11778, 11779},
+ {11779, 11778},
+ {11780, 11781},
+ {11781, 11780},
+ {11785, 11786},
+ {11786, 11785},
+ {11788, 11789},
+ {11789, 11788},
+ {11804, 11805},
+ {11805, 11804},
+ {11808, 11809},
+ {11809, 11808},
+ {11810, 11811},
+ {11811, 11810},
+ {11812, 11813},
+ {11813, 11812},
+ {11814, 11815},
+ {11815, 11814},
+ {11816, 11817},
+ {11817, 11816},
+ {12296, 12297},
+ {12297, 12296},
+ {12298, 12299},
+ {12299, 12298},
+ {12300, 12301},
+ {12301, 12300},
+ {12302, 12303},
+ {12303, 12302},
+ {12304, 12305},
+ {12305, 12304},
+ {12308, 12309},
+ {12309, 12308},
+ {12310, 12311},
+ {12311, 12310},
+ {12312, 12313},
+ {12313, 12312},
+ {12314, 12315},
+ {12315, 12314},
+ {65113, 65114},
+ {65114, 65113},
+ {65115, 65116},
+ {65116, 65115},
+ {65117, 65118},
+ {65118, 65117},
+ {65124, 65125},
+ {65125, 65124},
+ {65288, 65289},
+ {65289, 65288},
+ {65308, 65310},
+ {65310, 65308},
+ {65339, 65341},
+ {65341, 65339},
+ {65371, 65373},
+ {65373, 65371},
+ {65375, 65376},
+ {65376, 65375},
+ {65378, 65379},
+ {65379, 65378},
+};
+
+/* Reindexing of NFC first characters. */
+#define TOTAL_FIRST 376
+#define TOTAL_LAST 62
+static const Reindex nfc_first[] = {
+ { 60, 2, 0},
+ { 65, 15, 3},
+ { 82, 8, 19},
+ { 97, 15, 28},
+ { 114, 8, 44},
+ { 168, 0, 53},
+ { 194, 0, 54},
+ { 196, 3, 55},
+ { 202, 0, 59},
+ { 207, 0, 60},
+ { 212, 2, 61},
+ { 216, 0, 64},
+ { 220, 0, 65},
+ { 226, 0, 66},
+ { 228, 3, 67},
+ { 234, 0, 71},
+ { 239, 0, 72},
+ { 244, 2, 73},
+ { 248, 0, 76},
+ { 252, 0, 77},
+ { 258, 1, 78},
+ { 274, 1, 80},
+ { 332, 1, 82},
+ { 346, 1, 84},
+ { 352, 1, 86},
+ { 360, 3, 88},
+ { 383, 0, 92},
+ { 416, 1, 93},
+ { 431, 1, 95},
+ { 439, 0, 97},
+ { 490, 1, 98},
+ { 550, 3, 100},
+ { 558, 1, 104},
+ { 658, 0, 106},
+ { 913, 0, 107},
+ { 917, 0, 108},
+ { 919, 0, 109},
+ { 921, 0, 110},
+ { 927, 0, 111},
+ { 929, 0, 112},
+ { 933, 0, 113},
+ { 937, 0, 114},
+ { 940, 0, 115},
+ { 942, 0, 116},
+ { 945, 0, 117},
+ { 949, 0, 118},
+ { 951, 0, 119},
+ { 953, 0, 120},
+ { 959, 0, 121},
+ { 961, 0, 122},
+ { 965, 0, 123},
+ { 969, 2, 124},
+ { 974, 0, 127},
+ { 978, 0, 128},
+ { 1030, 0, 129},
+ { 1040, 0, 130},
+ { 1043, 0, 131},
+ { 1045, 3, 132},
+ { 1050, 0, 136},
+ { 1054, 0, 137},
+ { 1059, 0, 138},
+ { 1063, 0, 139},
+ { 1067, 0, 140},
+ { 1069, 0, 141},
+ { 1072, 0, 142},
+ { 1075, 0, 143},
+ { 1077, 3, 144},
+ { 1082, 0, 148},
+ { 1086, 0, 149},
+ { 1091, 0, 150},
+ { 1095, 0, 151},
+ { 1099, 0, 152},
+ { 1101, 0, 153},
+ { 1110, 0, 154},
+ { 1140, 1, 155},
+ { 1240, 1, 157},
+ { 1256, 1, 159},
+ { 1575, 0, 161},
+ { 1608, 0, 162},
+ { 1610, 0, 163},
+ { 1729, 0, 164},
+ { 1746, 0, 165},
+ { 1749, 0, 166},
+ { 2344, 0, 167},
+ { 2352, 0, 168},
+ { 2355, 0, 169},
+ { 2503, 0, 170},
+ { 2887, 0, 171},
+ { 2962, 0, 172},
+ { 3014, 1, 173},
+ { 3142, 0, 175},
+ { 3263, 0, 176},
+ { 3270, 0, 177},
+ { 3274, 0, 178},
+ { 3398, 1, 179},
+ { 3545, 0, 181},
+ { 3548, 0, 182},
+ { 4133, 0, 183},
+ { 6917, 0, 184},
+ { 6919, 0, 185},
+ { 6921, 0, 186},
+ { 6923, 0, 187},
+ { 6925, 0, 188},
+ { 6929, 0, 189},
+ { 6970, 0, 190},
+ { 6972, 0, 191},
+ { 6974, 1, 192},
+ { 6978, 0, 194},
+ { 7734, 1, 195},
+ { 7770, 1, 197},
+ { 7778, 1, 199},
+ { 7840, 1, 201},
+ { 7864, 1, 203},
+ { 7884, 1, 205},
+ { 7936, 17, 207},
+ { 7960, 1, 225},
+ { 7968, 17, 227},
+ { 7992, 1, 245},
+ { 8000, 1, 247},
+ { 8008, 1, 249},
+ { 8016, 1, 251},
+ { 8025, 0, 253},
+ { 8032, 16, 254},
+ { 8052, 0, 271},
+ { 8060, 0, 272},
+ { 8118, 0, 273},
+ { 8127, 0, 274},
+ { 8134, 0, 275},
+ { 8182, 0, 276},
+ { 8190, 0, 277},
+ { 8592, 0, 278},
+ { 8594, 0, 279},
+ { 8596, 0, 280},
+ { 8656, 0, 281},
+ { 8658, 0, 282},
+ { 8660, 0, 283},
+ { 8707, 0, 284},
+ { 8712, 0, 285},
+ { 8715, 0, 286},
+ { 8739, 0, 287},
+ { 8741, 0, 288},
+ { 8764, 0, 289},
+ { 8771, 0, 290},
+ { 8773, 0, 291},
+ { 8776, 0, 292},
+ { 8781, 0, 293},
+ { 8801, 0, 294},
+ { 8804, 1, 295},
+ { 8818, 1, 297},
+ { 8822, 1, 299},
+ { 8826, 3, 301},
+ { 8834, 1, 305},
+ { 8838, 1, 307},
+ { 8849, 1, 309},
+ { 8866, 0, 311},
+ { 8872, 1, 312},
+ { 8875, 0, 314},
+ { 8882, 3, 315},
+ { 12358, 0, 319},
+ { 12363, 0, 320},
+ { 12365, 0, 321},
+ { 12367, 0, 322},
+ { 12369, 0, 323},
+ { 12371, 0, 324},
+ { 12373, 0, 325},
+ { 12375, 0, 326},
+ { 12377, 0, 327},
+ { 12379, 0, 328},
+ { 12381, 0, 329},
+ { 12383, 0, 330},
+ { 12385, 0, 331},
+ { 12388, 0, 332},
+ { 12390, 0, 333},
+ { 12392, 0, 334},
+ { 12399, 0, 335},
+ { 12402, 0, 336},
+ { 12405, 0, 337},
+ { 12408, 0, 338},
+ { 12411, 0, 339},
+ { 12445, 0, 340},
+ { 12454, 0, 341},
+ { 12459, 0, 342},
+ { 12461, 0, 343},
+ { 12463, 0, 344},
+ { 12465, 0, 345},
+ { 12467, 0, 346},
+ { 12469, 0, 347},
+ { 12471, 0, 348},
+ { 12473, 0, 349},
+ { 12475, 0, 350},
+ { 12477, 0, 351},
+ { 12479, 0, 352},
+ { 12481, 0, 353},
+ { 12484, 0, 354},
+ { 12486, 0, 355},
+ { 12488, 0, 356},
+ { 12495, 0, 357},
+ { 12498, 0, 358},
+ { 12501, 0, 359},
+ { 12504, 0, 360},
+ { 12507, 0, 361},
+ { 12527, 3, 362},
+ { 12541, 0, 366},
+ { 69785, 0, 367},
+ { 69787, 0, 368},
+ { 69797, 0, 369},
+ { 69937, 1, 370},
+ { 70471, 0, 372},
+ { 70841, 0, 373},
+ { 71096, 1, 374},
+ {0,0,0}
+};
+
+static const Reindex nfc_last[] = {
+ { 768, 4, 0},
+ { 774, 6, 5},
+ { 783, 0, 12},
+ { 785, 0, 13},
+ { 787, 1, 14},
+ { 795, 0, 16},
+ { 803, 5, 17},
+ { 813, 1, 23},
+ { 816, 1, 25},
+ { 824, 0, 27},
+ { 834, 0, 28},
+ { 837, 0, 29},
+ { 1619, 2, 30},
+ { 2364, 0, 33},
+ { 2494, 0, 34},
+ { 2519, 0, 35},
+ { 2878, 0, 36},
+ { 2902, 1, 37},
+ { 3006, 0, 39},
+ { 3031, 0, 40},
+ { 3158, 0, 41},
+ { 3266, 0, 42},
+ { 3285, 1, 43},
+ { 3390, 0, 45},
+ { 3415, 0, 46},
+ { 3530, 0, 47},
+ { 3535, 0, 48},
+ { 3551, 0, 49},
+ { 4142, 0, 50},
+ { 6965, 0, 51},
+ { 12441, 1, 52},
+ { 69818, 0, 54},
+ { 69927, 0, 55},
+ { 70462, 0, 56},
+ { 70487, 0, 57},
+ { 70832, 0, 58},
+ { 70842, 0, 59},
+ { 70845, 0, 60},
+ { 71087, 0, 61},
+ {0,0,0}
+};
+
+#define UCDN_EAST_ASIAN_F 0
+#define UCDN_EAST_ASIAN_H 1
+#define UCDN_EAST_ASIAN_W 2
+#define UCDN_EAST_ASIAN_NA 3
+#define UCDN_EAST_ASIAN_A 4
+#define UCDN_EAST_ASIAN_N 5
+
+#define UCDN_SCRIPT_COMMON 0
+#define UCDN_SCRIPT_LATIN 1
+#define UCDN_SCRIPT_GREEK 2
+#define UCDN_SCRIPT_CYRILLIC 3
+#define UCDN_SCRIPT_ARMENIAN 4
+#define UCDN_SCRIPT_HEBREW 5
+#define UCDN_SCRIPT_ARABIC 6
+#define UCDN_SCRIPT_SYRIAC 7
+#define UCDN_SCRIPT_THAANA 8
+#define UCDN_SCRIPT_DEVANAGARI 9
+#define UCDN_SCRIPT_BENGALI 10
+#define UCDN_SCRIPT_GURMUKHI 11
+#define UCDN_SCRIPT_GUJARATI 12
+#define UCDN_SCRIPT_ORIYA 13
+#define UCDN_SCRIPT_TAMIL 14
+#define UCDN_SCRIPT_TELUGU 15
+#define UCDN_SCRIPT_KANNADA 16
+#define UCDN_SCRIPT_MALAYALAM 17
+#define UCDN_SCRIPT_SINHALA 18
+#define UCDN_SCRIPT_THAI 19
+#define UCDN_SCRIPT_LAO 20
+#define UCDN_SCRIPT_TIBETAN 21
+#define UCDN_SCRIPT_MYANMAR 22
+#define UCDN_SCRIPT_GEORGIAN 23
+#define UCDN_SCRIPT_HANGUL 24
+#define UCDN_SCRIPT_ETHIOPIC 25
+#define UCDN_SCRIPT_CHEROKEE 26
+#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27
+#define UCDN_SCRIPT_OGHAM 28
+#define UCDN_SCRIPT_RUNIC 29
+#define UCDN_SCRIPT_KHMER 30
+#define UCDN_SCRIPT_MONGOLIAN 31
+#define UCDN_SCRIPT_HIRAGANA 32
+#define UCDN_SCRIPT_KATAKANA 33
+#define UCDN_SCRIPT_BOPOMOFO 34
+#define UCDN_SCRIPT_HAN 35
+#define UCDN_SCRIPT_YI 36
+#define UCDN_SCRIPT_OLD_ITALIC 37
+#define UCDN_SCRIPT_GOTHIC 38
+#define UCDN_SCRIPT_DESERET 39
+#define UCDN_SCRIPT_INHERITED 40
+#define UCDN_SCRIPT_TAGALOG 41
+#define UCDN_SCRIPT_HANUNOO 42
+#define UCDN_SCRIPT_BUHID 43
+#define UCDN_SCRIPT_TAGBANWA 44
+#define UCDN_SCRIPT_LIMBU 45
+#define UCDN_SCRIPT_TAI_LE 46
+#define UCDN_SCRIPT_LINEAR_B 47
+#define UCDN_SCRIPT_UGARITIC 48
+#define UCDN_SCRIPT_SHAVIAN 49
+#define UCDN_SCRIPT_OSMANYA 50
+#define UCDN_SCRIPT_CYPRIOT 51
+#define UCDN_SCRIPT_BRAILLE 52
+#define UCDN_SCRIPT_BUGINESE 53
+#define UCDN_SCRIPT_COPTIC 54
+#define UCDN_SCRIPT_NEW_TAI_LUE 55
+#define UCDN_SCRIPT_GLAGOLITIC 56
+#define UCDN_SCRIPT_TIFINAGH 57
+#define UCDN_SCRIPT_SYLOTI_NAGRI 58
+#define UCDN_SCRIPT_OLD_PERSIAN 59
+#define UCDN_SCRIPT_KHAROSHTHI 60
+#define UCDN_SCRIPT_BALINESE 61
+#define UCDN_SCRIPT_CUNEIFORM 62
+#define UCDN_SCRIPT_PHOENICIAN 63
+#define UCDN_SCRIPT_PHAGS_PA 64
+#define UCDN_SCRIPT_NKO 65
+#define UCDN_SCRIPT_SUNDANESE 66
+#define UCDN_SCRIPT_LEPCHA 67
+#define UCDN_SCRIPT_OL_CHIKI 68
+#define UCDN_SCRIPT_VAI 69
+#define UCDN_SCRIPT_SAURASHTRA 70
+#define UCDN_SCRIPT_KAYAH_LI 71
+#define UCDN_SCRIPT_REJANG 72
+#define UCDN_SCRIPT_LYCIAN 73
+#define UCDN_SCRIPT_CARIAN 74
+#define UCDN_SCRIPT_LYDIAN 75
+#define UCDN_SCRIPT_CHAM 76
+#define UCDN_SCRIPT_TAI_THAM 77
+#define UCDN_SCRIPT_TAI_VIET 78
+#define UCDN_SCRIPT_AVESTAN 79
+#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80
+#define UCDN_SCRIPT_SAMARITAN 81
+#define UCDN_SCRIPT_LISU 82
+#define UCDN_SCRIPT_BAMUM 83
+#define UCDN_SCRIPT_JAVANESE 84
+#define UCDN_SCRIPT_MEETEI_MAYEK 85
+#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86
+#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87
+#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88
+#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89
+#define UCDN_SCRIPT_OLD_TURKIC 90
+#define UCDN_SCRIPT_KAITHI 91
+#define UCDN_SCRIPT_BATAK 92
+#define UCDN_SCRIPT_BRAHMI 93
+#define UCDN_SCRIPT_MANDAIC 94
+#define UCDN_SCRIPT_CHAKMA 95
+#define UCDN_SCRIPT_MEROITIC_CURSIVE 96
+#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97
+#define UCDN_SCRIPT_MIAO 98
+#define UCDN_SCRIPT_SHARADA 99
+#define UCDN_SCRIPT_SORA_SOMPENG 100
+#define UCDN_SCRIPT_TAKRI 101
+#define UCDN_SCRIPT_UNKNOWN 102
+#define UCDN_SCRIPT_BASSA_VAH 103
+#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104
+#define UCDN_SCRIPT_DUPLOYAN 105
+#define UCDN_SCRIPT_ELBASAN 106
+#define UCDN_SCRIPT_GRANTHA 107
+#define UCDN_SCRIPT_KHOJKI 108
+#define UCDN_SCRIPT_KHUDAWADI 109
+#define UCDN_SCRIPT_LINEAR_A 110
+#define UCDN_SCRIPT_MAHAJANI 111
+#define UCDN_SCRIPT_MANICHAEAN 112
+#define UCDN_SCRIPT_MENDE_KIKAKUI 113
+#define UCDN_SCRIPT_MODI 114
+#define UCDN_SCRIPT_MRO 115
+#define UCDN_SCRIPT_NABATAEAN 116
+#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117
+#define UCDN_SCRIPT_OLD_PERMIC 118
+#define UCDN_SCRIPT_PAHAWH_HMONG 119
+#define UCDN_SCRIPT_PALMYRENE 120
+#define UCDN_SCRIPT_PAU_CIN_HAU 121
+#define UCDN_SCRIPT_PSALTER_PAHLAVI 122
+#define UCDN_SCRIPT_SIDDHAM 123
+#define UCDN_SCRIPT_TIRHUTA 124
+#define UCDN_SCRIPT_WARANG_CITI 125
+
+#define UCDN_GENERAL_CATEGORY_CC 0
+#define UCDN_GENERAL_CATEGORY_CF 1
+#define UCDN_GENERAL_CATEGORY_CN 2
+#define UCDN_GENERAL_CATEGORY_CO 3
+#define UCDN_GENERAL_CATEGORY_CS 4
+#define UCDN_GENERAL_CATEGORY_LL 5
+#define UCDN_GENERAL_CATEGORY_LM 6
+#define UCDN_GENERAL_CATEGORY_LO 7
+#define UCDN_GENERAL_CATEGORY_LT 8
+#define UCDN_GENERAL_CATEGORY_LU 9
+#define UCDN_GENERAL_CATEGORY_MC 10
+#define UCDN_GENERAL_CATEGORY_ME 11
+#define UCDN_GENERAL_CATEGORY_MN 12
+#define UCDN_GENERAL_CATEGORY_ND 13
+#define UCDN_GENERAL_CATEGORY_NL 14
+#define UCDN_GENERAL_CATEGORY_NO 15
+#define UCDN_GENERAL_CATEGORY_PC 16
+#define UCDN_GENERAL_CATEGORY_PD 17
+#define UCDN_GENERAL_CATEGORY_PE 18
+#define UCDN_GENERAL_CATEGORY_PF 19
+#define UCDN_GENERAL_CATEGORY_PI 20
+#define UCDN_GENERAL_CATEGORY_PO 21
+#define UCDN_GENERAL_CATEGORY_PS 22
+#define UCDN_GENERAL_CATEGORY_SC 23
+#define UCDN_GENERAL_CATEGORY_SK 24
+#define UCDN_GENERAL_CATEGORY_SM 25
+#define UCDN_GENERAL_CATEGORY_SO 26
+#define UCDN_GENERAL_CATEGORY_ZL 27
+#define UCDN_GENERAL_CATEGORY_ZP 28
+#define UCDN_GENERAL_CATEGORY_ZS 29
+
+#define UCDN_BIDI_CLASS_L 0
+#define UCDN_BIDI_CLASS_LRE 1
+#define UCDN_BIDI_CLASS_LRO 2
+#define UCDN_BIDI_CLASS_R 3
+#define UCDN_BIDI_CLASS_AL 4
+#define UCDN_BIDI_CLASS_RLE 5
+#define UCDN_BIDI_CLASS_RLO 6
+#define UCDN_BIDI_CLASS_PDF 7
+#define UCDN_BIDI_CLASS_EN 8
+#define UCDN_BIDI_CLASS_ES 9
+#define UCDN_BIDI_CLASS_ET 10
+#define UCDN_BIDI_CLASS_AN 11
+#define UCDN_BIDI_CLASS_CS 12
+#define UCDN_BIDI_CLASS_NSM 13
+#define UCDN_BIDI_CLASS_BN 14
+#define UCDN_BIDI_CLASS_B 15
+#define UCDN_BIDI_CLASS_S 16
+#define UCDN_BIDI_CLASS_WS 17
+#define UCDN_BIDI_CLASS_ON 18
+#define UCDN_BIDI_CLASS_LRI 19
+#define UCDN_BIDI_CLASS_RLI 20
+#define UCDN_BIDI_CLASS_FSI 21
+#define UCDN_BIDI_CLASS_PDI 22
+
+/* index tables for the database records */
+#define SHIFT1 5
+#define SHIFT2 3
+static const unsigned char index0[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 54, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 55, 56, 57, 57, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 68, 69, 70, 70,
+ 71, 69, 70, 70, 72, 73, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 75, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 70, 96, 70, 97,
+ 98, 99, 100, 101, 102, 103, 70, 104, 70, 105, 70, 70, 70, 70, 70, 106,
+ 106, 106, 107, 108, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 109, 109,
+ 109, 109, 110, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 111, 111, 112, 113, 70, 70, 70, 114, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 115, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 116, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 117, 118,
+ 119, 120, 121, 122, 123, 124, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 125, 70, 70, 70, 70, 70, 126, 70, 127, 128, 129, 130,
+ 131, 132, 133, 134, 135, 70, 70, 70, 70, 70, 70, 70, 52, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 136,
+ 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 137, 138,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 76, 76, 140, 139, 139, 139, 139, 141,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 141, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 142, 143, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 73, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 144, 73,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 144,
+};
+
+static const unsigned short index1[] = {
+ 0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 0, 0, 0, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 31, 32,
+ 33, 34, 35, 27, 30, 29, 27, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 27, 27, 49, 27, 27, 27, 27, 27, 27, 27, 50, 51, 52, 27, 53, 54,
+ 53, 54, 54, 54, 54, 54, 55, 54, 54, 54, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 65, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 97, 97, 97, 98, 98, 98, 98, 99, 100, 101, 101, 101, 101, 102, 103,
+ 101, 101, 101, 101, 101, 101, 104, 105, 101, 101, 101, 101, 101, 101,
+ 101, 101, 101, 101, 101, 101, 106, 107, 107, 107, 108, 109, 110, 111,
+ 111, 111, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 121,
+ 121, 122, 123, 120, 124, 125, 126, 127, 128, 128, 128, 128, 129, 130,
+ 131, 132, 133, 134, 135, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 145, 145,
+ 146, 147, 148, 149, 128, 128, 128, 128, 128, 128, 150, 150, 150, 150,
+ 151, 152, 153, 120, 154, 155, 156, 156, 156, 157, 158, 159, 160, 160,
+ 161, 162, 163, 164, 165, 166, 167, 167, 167, 168, 120, 120, 120, 120,
+ 120, 120, 120, 120, 128, 128, 169, 120, 120, 120, 120, 120, 170, 171,
+ 172, 173, 174, 175, 175, 175, 175, 175, 175, 176, 177, 178, 179, 175,
+ 180, 181, 182, 175, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 210, 211, 120, 212, 213, 214, 215, 215, 216,
+ 217, 218, 219, 220, 221, 120, 222, 223, 224, 120, 225, 226, 227, 228,
+ 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 120, 239, 240,
+ 241, 242, 243, 240, 244, 245, 246, 247, 248, 120, 249, 250, 251, 252,
+ 253, 254, 255, 256, 256, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 120, 264, 265, 266, 267, 268, 268, 267, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 120, 278, 279, 280, 281, 281, 281, 281, 282, 283, 284,
+ 285, 120, 286, 287, 288, 289, 290, 291, 292, 293, 291, 291, 294, 295,
+ 292, 296, 297, 298, 299, 300, 301, 120, 302, 303, 303, 303, 303, 303,
+ 304, 305, 306, 307, 308, 309, 120, 120, 120, 120, 310, 311, 312, 313,
+ 314, 315, 316, 317, 318, 319, 320, 321, 120, 120, 120, 120, 322, 323,
+ 324, 325, 326, 327, 328, 329, 330, 331, 330, 330, 330, 332, 333, 334,
+ 335, 336, 337, 338, 337, 337, 337, 339, 340, 341, 342, 343, 120, 120,
+ 120, 120, 344, 344, 344, 344, 344, 345, 346, 347, 348, 349, 350, 351,
+ 352, 353, 354, 344, 355, 356, 348, 357, 358, 358, 358, 358, 359, 360,
+ 361, 361, 361, 361, 361, 362, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 364, 364, 364, 364, 364, 364, 364, 364, 364, 364,
+ 364, 364, 364, 364, 364, 364, 364, 364, 364, 364, 365, 365, 365, 365,
+ 365, 365, 365, 365, 365, 366, 367, 366, 365, 365, 365, 365, 365, 366,
+ 365, 365, 365, 365, 366, 367, 366, 365, 367, 365, 365, 365, 365, 365,
+ 365, 365, 366, 365, 365, 365, 365, 365, 365, 365, 365, 368, 369, 370,
+ 371, 372, 365, 365, 373, 374, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 376, 120, 377, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 378, 379, 378, 378,
+ 380, 381, 381, 382, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384,
+ 385, 386, 387, 388, 389, 120, 390, 390, 391, 120, 392, 392, 393, 120,
+ 394, 395, 396, 120, 397, 397, 397, 397, 397, 397, 398, 399, 400, 401,
+ 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 412, 412, 412,
+ 413, 412, 412, 412, 412, 412, 412, 120, 412, 412, 412, 412, 412, 414,
+ 378, 378, 378, 378, 378, 378, 378, 378, 415, 120, 416, 416, 416, 417,
+ 418, 419, 420, 421, 422, 423, 424, 424, 424, 425, 426, 120, 427, 427,
+ 427, 427, 427, 428, 429, 429, 430, 431, 432, 433, 434, 434, 434, 434,
+ 435, 435, 436, 437, 438, 438, 438, 438, 438, 438, 439, 440, 441, 442,
+ 443, 444, 445, 446, 445, 446, 447, 448, 449, 450, 120, 120, 120, 120,
+ 120, 120, 120, 120, 451, 452, 452, 452, 452, 452, 453, 454, 455, 456,
+ 457, 458, 459, 460, 461, 462, 463, 464, 464, 464, 465, 466, 467, 468,
+ 469, 469, 469, 469, 470, 471, 472, 473, 474, 474, 474, 474, 475, 476,
+ 477, 478, 479, 480, 481, 482, 483, 483, 483, 484, 120, 120, 120, 120,
+ 120, 120, 120, 120, 485, 120, 486, 487, 488, 489, 490, 491, 54, 54, 54,
+ 54, 492, 493, 56, 56, 56, 56, 56, 494, 495, 496, 54, 497, 54, 54, 54,
+ 498, 56, 56, 56, 499, 500, 501, 502, 503, 503, 503, 504, 505, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 506, 507, 27,
+ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 508, 509, 510, 511, 508, 509,
+ 508, 509, 510, 511, 508, 512, 508, 509, 508, 510, 508, 513, 508, 513,
+ 508, 513, 514, 515, 516, 517, 518, 519, 508, 520, 521, 522, 523, 524,
+ 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538,
+ 539, 540, 56, 541, 542, 543, 542, 544, 120, 120, 545, 546, 547, 548, 549,
+ 120, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562,
+ 563, 562, 564, 565, 566, 567, 568, 569, 570, 571, 572, 571, 573, 574,
+ 571, 575, 571, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586,
+ 587, 588, 589, 590, 591, 586, 586, 592, 593, 594, 595, 596, 586, 586,
+ 597, 577, 598, 599, 586, 586, 600, 586, 586, 571, 601, 602, 571, 603,
+ 604, 605, 606, 606, 606, 606, 606, 606, 606, 606, 607, 571, 571, 608,
+ 609, 577, 577, 610, 571, 571, 571, 571, 576, 611, 571, 571, 612, 571,
+ 571, 571, 571, 613, 120, 120, 120, 571, 612, 120, 120, 614, 614, 614,
+ 614, 614, 615, 615, 616, 617, 617, 617, 617, 617, 617, 617, 617, 617,
+ 618, 614, 614, 619, 619, 619, 619, 619, 619, 619, 619, 619, 620, 619,
+ 619, 619, 619, 620, 571, 619, 619, 621, 571, 622, 572, 623, 624, 625,
+ 626, 572, 571, 621, 575, 571, 577, 627, 628, 624, 629, 571, 571, 571,
+ 571, 630, 571, 571, 571, 631, 632, 571, 571, 571, 571, 571, 633, 571,
+ 634, 571, 633, 635, 636, 619, 619, 637, 619, 619, 619, 571, 571, 571,
+ 571, 571, 571, 571, 638, 571, 571, 575, 571, 571, 639, 640, 614, 641,
+ 641, 642, 571, 571, 571, 571, 571, 643, 644, 645, 646, 647, 648, 577,
+ 577, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649,
+ 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649,
+ 649, 649, 649, 649, 649, 577, 577, 577, 577, 577, 577, 577, 577, 577,
+ 577, 577, 577, 577, 577, 577, 577, 650, 651, 651, 652, 586, 586, 577,
+ 653, 600, 654, 655, 656, 657, 658, 659, 660, 577, 661, 586, 662, 663,
+ 664, 665, 646, 577, 577, 589, 653, 665, 666, 667, 668, 586, 586, 586,
+ 586, 669, 670, 586, 586, 586, 586, 671, 672, 673, 646, 674, 675, 571,
+ 571, 571, 571, 571, 571, 577, 577, 676, 677, 678, 572, 571, 571, 679,
+ 571, 571, 571, 680, 571, 571, 571, 571, 681, 571, 682, 683, 120, 120,
+ 120, 120, 120, 684, 684, 684, 684, 684, 685, 686, 686, 686, 686, 686,
+ 687, 688, 689, 690, 691, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 692, 693, 694, 695, 696, 696, 696, 696, 697, 698, 699, 699, 699, 699,
+ 699, 699, 699, 700, 701, 702, 365, 365, 367, 120, 367, 367, 367, 367,
+ 367, 367, 367, 367, 703, 703, 703, 703, 704, 705, 706, 707, 708, 709,
+ 532, 710, 711, 120, 120, 120, 120, 120, 120, 120, 712, 712, 712, 713,
+ 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 714, 120, 712, 712,
+ 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 712,
+ 712, 712, 712, 712, 712, 712, 712, 712, 712, 712, 715, 120, 120, 120,
+ 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 727, 727,
+ 727, 727, 727, 727, 727, 727, 728, 729, 730, 731, 731, 731, 731, 731,
+ 731, 731, 731, 731, 731, 732, 733, 734, 734, 734, 734, 735, 736, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 737, 738, 739, 734, 734,
+ 734, 740, 716, 716, 716, 716, 717, 120, 731, 731, 741, 741, 741, 742,
+ 743, 744, 739, 739, 739, 745, 746, 747, 741, 741, 741, 748, 743, 744,
+ 739, 739, 739, 739, 749, 747, 739, 750, 751, 751, 751, 751, 751, 752,
+ 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 739, 739, 739,
+ 753, 754, 739, 739, 739, 739, 739, 739, 739, 739, 739, 739, 739, 755,
+ 739, 739, 739, 753, 756, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 758, 759, 571, 571, 571, 571, 571, 571,
+ 571, 571, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 760,
+ 759, 759, 759, 759, 759, 759, 761, 761, 762, 761, 761, 761, 761, 761,
+ 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
+ 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
+ 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
+ 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
+ 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
+ 761, 761, 761, 763, 764, 764, 764, 764, 764, 764, 765, 120, 766, 766,
+ 766, 766, 766, 767, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 769, 768, 768, 770, 771,
+ 120, 120, 101, 101, 101, 101, 101, 772, 773, 774, 101, 101, 101, 775,
+ 776, 776, 776, 776, 776, 776, 776, 776, 777, 778, 779, 120, 64, 64, 780,
+ 781, 782, 27, 783, 27, 27, 27, 27, 27, 27, 27, 784, 785, 27, 786, 787,
+ 27, 27, 788, 789, 120, 120, 120, 120, 120, 120, 120, 790, 791, 792, 793,
+ 794, 794, 795, 796, 797, 798, 799, 799, 799, 799, 799, 799, 800, 120,
+ 801, 802, 802, 802, 802, 802, 803, 804, 805, 806, 807, 808, 809, 809,
+ 810, 811, 812, 813, 814, 814, 815, 816, 817, 817, 818, 819, 820, 821,
+ 363, 363, 363, 822, 823, 824, 824, 824, 824, 824, 825, 826, 827, 828,
+ 829, 830, 831, 344, 348, 832, 833, 833, 833, 833, 833, 834, 835, 120,
+ 836, 837, 838, 839, 344, 344, 840, 841, 842, 842, 842, 842, 842, 842,
+ 843, 844, 845, 120, 120, 846, 847, 848, 849, 120, 850, 850, 850, 120,
+ 367, 367, 54, 54, 54, 54, 54, 851, 852, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 847, 847, 847, 847, 853, 854, 855, 856, 857,
+ 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858,
+ 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858,
+ 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858,
+ 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858,
+ 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858,
+ 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 858, 859,
+ 120, 364, 364, 860, 861, 364, 364, 364, 364, 364, 862, 863, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 864, 863, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 864, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 864, 865,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 867, 868, 868, 868,
+ 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868,
+ 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868,
+ 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868,
+ 869, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868, 868,
+ 870, 759, 759, 759, 759, 871, 120, 872, 873, 121, 874, 875, 876, 877,
+ 121, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 878,
+ 879, 880, 120, 881, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 882, 120, 120, 128, 128, 128, 128, 128,
+ 128, 128, 128, 883, 128, 128, 128, 128, 128, 128, 120, 120, 120, 120,
+ 120, 128, 884, 885, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894,
+ 895, 896, 897, 898, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 899, 900, 901, 902, 903, 904, 905, 905,
+ 906, 907, 908, 908, 909, 910, 911, 912, 911, 911, 911, 911, 913, 914,
+ 914, 914, 915, 916, 916, 916, 917, 918, 919, 120, 920, 921, 922, 921,
+ 921, 923, 921, 921, 924, 921, 925, 921, 925, 120, 120, 120, 120, 921,
+ 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921, 921,
+ 926, 927, 928, 928, 928, 928, 928, 929, 606, 930, 930, 930, 930, 930,
+ 930, 931, 932, 933, 934, 571, 935, 936, 120, 120, 120, 120, 120, 606,
+ 606, 606, 606, 606, 937, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 938, 938, 938, 939, 940, 940, 940,
+ 940, 940, 940, 941, 120, 942, 943, 943, 944, 945, 945, 945, 945, 946,
+ 120, 947, 947, 948, 949, 950, 950, 950, 950, 951, 952, 953, 953, 953,
+ 954, 955, 955, 955, 955, 956, 955, 957, 120, 120, 120, 120, 120, 958,
+ 958, 958, 958, 958, 959, 959, 959, 959, 959, 960, 960, 960, 960, 960,
+ 960, 961, 961, 961, 962, 963, 964, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 965, 965, 965, 965, 965, 120, 966, 966, 966, 966, 966,
+ 966, 967, 968, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 969, 969, 969, 969, 969, 969, 969,
+ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969,
+ 969, 969, 969, 970, 120, 969, 969, 971, 120, 969, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 972, 973, 974, 974, 974, 974, 975, 976, 977, 977, 978, 979, 980,
+ 980, 981, 982, 983, 983, 983, 984, 985, 986, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 987, 987, 988, 989, 990, 990, 990, 991, 120,
+ 120, 120, 120, 120, 120, 120, 120, 992, 992, 992, 992, 993, 993, 993,
+ 994, 120, 120, 120, 120, 120, 120, 120, 120, 995, 996, 997, 998, 999,
+ 999, 1000, 1001, 1002, 120, 1003, 1004, 1005, 1005, 1005, 1006, 1007,
+ 1007, 1007, 1008, 120, 120, 120, 120, 1009, 1010, 1009, 1009, 1011, 1012,
+ 1013, 120, 1014, 1014, 1014, 1014, 1014, 1014, 1015, 1016, 1017, 1017,
+ 1018, 1019, 1020, 1020, 1021, 1022, 1023, 1023, 1024, 1025, 120, 1026,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1027, 1027, 1027, 1027,
+ 1027, 1027, 1027, 1027, 1027, 1028, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1029,
+ 1029, 1029, 1030, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 1031, 1032, 1032, 1032, 1032, 1032, 1032, 1033,
+ 1034, 1035, 1036, 1037, 1038, 1039, 120, 1040, 1041, 1042, 1042, 1042,
+ 1042, 1042, 1043, 1044, 1045, 120, 1046, 1046, 1046, 1047, 1048, 1049,
+ 1050, 1051, 1051, 1051, 1052, 1053, 1054, 1055, 1056, 120, 1057, 1057,
+ 1057, 1057, 1058, 120, 1059, 1060, 1060, 1060, 1060, 1060, 1061, 1062,
+ 1063, 1064, 1065, 1066, 1067, 1068, 1069, 120, 1070, 1070, 1071, 1070,
+ 1070, 1072, 1073, 1074, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 1075, 1075, 1075, 1075, 1075, 1076, 1077, 1078, 1079,
+ 1080, 1081, 1082, 1083, 1084, 1084, 1085, 1086, 1087, 1088, 1089, 1090,
+ 1091, 1092, 1093, 1093, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 1094, 1094, 1094, 1094,
+ 1094, 1094, 1095, 1096, 1097, 120, 1098, 1099, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 1100, 1100, 1100, 1100, 1100, 1101, 1102, 1103, 1104, 1105, 120,
+ 120, 120, 120, 120, 120, 1106, 1106, 1106, 1106, 1106, 1106, 1107, 1108,
+ 1109, 120, 1110, 1111, 120, 120, 120, 120, 1112, 1112, 1112, 1112, 1112,
+ 1113, 1114, 120, 1115, 1116, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 1117, 1117, 1117, 1117, 1118, 1118, 1118, 1118, 1119,
+ 1120, 1121, 1122, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1123,
+ 1123, 1123, 1123, 1123, 1123, 1123, 1124, 1125, 1125, 1125, 1125, 1125,
+ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125,
+ 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1126, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 1127, 1127, 1127,
+ 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1128, 1129,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130,
+ 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130,
+ 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130, 1130,
+ 1130, 1130, 1130, 1130, 1131, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
+ 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
+ 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
+ 776, 1132, 1133, 1133, 1133, 1134, 1135, 1136, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 1137, 1137, 1137, 1138, 1139, 120,
+ 1140, 1140, 1140, 1140, 1140, 1140, 1141, 1142, 1143, 120, 1144, 1145,
+ 1146, 1140, 1140, 1147, 1140, 1140, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 1148, 1148, 1148, 1148, 1148, 1148,
+ 1148, 1148, 1149, 120, 1150, 1151, 1151, 1151, 1151, 1152, 120, 1153,
+ 1154, 1155, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 1156, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157, 1157,
+ 1157, 1157, 1157, 1157, 1158, 1157, 1159, 1157, 1160, 1157, 1161, 1162,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 606, 606, 606,
+ 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606,
+ 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, 1163,
+ 120, 606, 606, 606, 606, 1164, 1165, 606, 606, 606, 606, 606, 606, 1166,
+ 1167, 1168, 1169, 1170, 1171, 606, 606, 606, 1172, 606, 606, 606, 606,
+ 606, 1163, 120, 120, 120, 120, 933, 933, 933, 933, 933, 933, 933, 933,
+ 1173, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 571, 571, 571, 571,
+ 571, 571, 571, 571, 571, 571, 613, 120, 928, 928, 1174, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 1175, 1175, 1175, 1176, 1177, 1177, 1178, 1175, 1175, 1179, 1180, 1177,
+ 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1181, 1182, 1183, 1179, 1184,
+ 1185, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1186, 1187, 1188, 1189,
+ 1177, 1177, 1177, 1190, 1191, 1192, 1193, 1177, 1177, 1178, 1175, 1175,
+ 1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1178, 1175,
+ 1175, 1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177, 1178,
+ 1175, 1175, 1179, 1177, 1177, 1177, 1175, 1175, 1175, 1176, 1177, 1177,
+ 1194, 1175, 1175, 1175, 1195, 1177, 1177, 1196, 1197, 1175, 1175, 1198,
+ 1177, 1177, 1199, 1178, 1175, 1175, 1200, 1177, 1177, 1201, 1202, 1175,
+ 1175, 1203, 1177, 1177, 1177, 1204, 1175, 1175, 1175, 1195, 1177, 1177,
+ 1196, 1205, 1206, 1206, 1206, 1206, 1206, 1206, 1207, 1207, 1207, 1207,
+ 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207,
+ 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1207, 1208, 1209, 1210, 120,
+ 120, 120, 120, 120, 1211, 128, 128, 128, 1212, 1213, 1214, 1215, 1216,
+ 1217, 1212, 1218, 1212, 1214, 1214, 1219, 128, 1220, 128, 1221, 1222,
+ 1220, 128, 1221, 120, 120, 120, 120, 120, 120, 1223, 120, 571, 571, 571,
+ 571, 571, 935, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571,
+ 571, 935, 120, 571, 613, 1224, 571, 1224, 571, 1224, 571, 571, 571, 680,
+ 120, 615, 1225, 617, 617, 617, 1226, 617, 617, 617, 617, 617, 617, 617,
+ 1227, 617, 617, 617, 617, 617, 1228, 120, 120, 120, 120, 120, 120, 120,
+ 120, 1229, 606, 606, 606, 1230, 120, 739, 739, 739, 739, 739, 1231, 739,
+ 1232, 1233, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 120, 571, 571, 571, 571, 571,
+ 1234, 571, 571, 571, 571, 571, 571, 571, 571, 571, 680, 571, 571, 571,
+ 571, 571, 571, 571, 571, 571, 613, 1235, 571, 571, 571, 571, 120, 571,
+ 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571,
+ 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571,
+ 571, 571, 613, 571, 571, 571, 571, 571, 571, 571, 571, 571, 612, 571,
+ 571, 571, 571, 571, 1236, 571, 571, 571, 571, 1237, 571, 571, 571, 571,
+ 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571,
+ 571, 1238, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571,
+ 571, 571, 571, 571, 571, 120, 120, 571, 1234, 935, 120, 571, 571, 571,
+ 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 935, 120, 571,
+ 571, 571, 571, 571, 571, 571, 571, 571, 571, 1234, 120, 120, 120, 120,
+ 120, 571, 935, 571, 571, 571, 571, 571, 571, 571, 120, 571, 683, 571,
+ 571, 571, 571, 571, 120, 571, 571, 571, 680, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 1239, 759, 759, 759, 759, 759, 757, 757, 757, 757, 757,
+ 757, 760, 759, 756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757,
+ 757, 757, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 868, 868, 868, 869, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759,
+ 1240, 1241, 120, 120, 120, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
+ 1242, 1242, 1242, 1242, 1242, 120, 120, 120, 120, 120, 120, 120, 120,
+ 120, 120, 120, 120, 120, 120, 120, 120, 885, 885, 885, 885, 885, 885,
+ 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 885,
+ 885, 885, 885, 885, 885, 885, 885, 885, 885, 885, 120, 120, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866, 866,
+ 866, 1243,
+};
+
+static const unsigned short index2[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 4, 3, 1, 1, 1, 1, 1, 1, 3, 3, 3, 2,
+ 5, 6, 6, 7, 8, 7, 6, 6, 9, 10, 6, 11, 12, 13, 12, 12, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 12, 6, 15, 16, 15, 6, 6, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 9, 6, 10, 18, 19, 18, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 9, 16,
+ 10, 16, 1, 1, 1, 1, 1, 1, 3, 1, 1, 21, 22, 8, 8, 23, 8, 24, 22, 25, 26,
+ 27, 28, 16, 29, 30, 18, 31, 32, 33, 33, 25, 34, 22, 22, 25, 33, 27, 35,
+ 36, 36, 36, 22, 37, 37, 37, 37, 37, 37, 38, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 38, 37, 37, 37, 37, 37, 37, 39, 38, 37, 37, 37, 37, 37, 38, 40,
+ 40, 40, 41, 41, 41, 41, 40, 41, 40, 40, 40, 41, 40, 40, 41, 41, 40, 41,
+ 40, 40, 41, 41, 41, 39, 40, 40, 40, 41, 40, 41, 40, 41, 37, 40, 37, 41,
+ 37, 41, 37, 41, 37, 41, 37, 41, 37, 41, 37, 41, 37, 40, 37, 40, 37, 41,
+ 37, 41, 37, 41, 37, 40, 37, 41, 37, 41, 37, 41, 37, 41, 37, 41, 38, 40,
+ 37, 40, 38, 40, 37, 41, 37, 41, 40, 37, 41, 37, 41, 37, 41, 38, 40, 38,
+ 40, 37, 40, 37, 41, 37, 40, 40, 38, 40, 37, 40, 37, 41, 37, 41, 38, 40,
+ 37, 41, 37, 41, 37, 37, 41, 37, 41, 37, 41, 41, 41, 37, 37, 41, 37, 41,
+ 37, 37, 41, 37, 37, 37, 41, 41, 37, 37, 37, 37, 41, 37, 37, 41, 37, 37,
+ 37, 41, 41, 41, 37, 37, 41, 37, 37, 41, 37, 41, 37, 41, 37, 37, 41, 37,
+ 41, 41, 37, 41, 37, 37, 41, 37, 37, 37, 41, 37, 41, 37, 37, 41, 41, 42,
+ 37, 41, 41, 41, 42, 42, 42, 42, 37, 43, 41, 37, 43, 41, 37, 43, 41, 37,
+ 40, 37, 40, 37, 40, 37, 40, 37, 40, 37, 40, 37, 40, 37, 40, 41, 37, 41,
+ 41, 37, 43, 41, 37, 41, 37, 37, 37, 41, 37, 41, 41, 41, 41, 41, 41, 41,
+ 37, 37, 41, 37, 37, 41, 41, 37, 41, 37, 37, 37, 37, 41, 41, 40, 41, 41,
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 41,
+ 41, 41, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 46, 46, 46, 46, 46,
+ 46, 46, 47, 47, 25, 47, 45, 48, 45, 48, 48, 48, 45, 48, 45, 45, 49, 46,
+ 47, 47, 47, 47, 47, 47, 25, 25, 25, 25, 47, 25, 47, 25, 44, 44, 44, 44,
+ 44, 47, 47, 47, 47, 47, 50, 50, 45, 47, 46, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 53, 53,
+ 53, 53, 52, 54, 53, 53, 53, 53, 53, 55, 55, 53, 53, 53, 53, 55, 55, 53,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 56, 56, 56, 56, 56, 53, 53, 53,
+ 53, 51, 51, 51, 51, 51, 51, 51, 51, 57, 51, 53, 53, 53, 51, 51, 51, 53,
+ 53, 58, 51, 51, 51, 53, 53, 53, 53, 51, 52, 53, 53, 51, 59, 60, 60, 59,
+ 60, 60, 59, 51, 51, 51, 51, 51, 61, 62, 61, 62, 45, 63, 61, 62, 64, 64,
+ 65, 62, 62, 62, 66, 61, 64, 64, 64, 64, 63, 47, 61, 66, 61, 61, 61, 64,
+ 61, 64, 61, 61, 62, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 64, 67, 67, 67, 67, 67, 67, 67, 61, 61, 62, 62, 62, 62,
+ 62, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 62, 68, 68, 68, 68, 68, 68, 68, 62, 62, 62, 62, 62, 61, 62, 62, 61, 61,
+ 61, 62, 62, 62, 61, 62, 61, 62, 61, 62, 61, 62, 61, 62, 69, 70, 69, 70,
+ 69, 70, 69, 70, 69, 70, 69, 70, 69, 70, 62, 62, 62, 62, 61, 62, 71, 61,
+ 62, 61, 61, 62, 62, 61, 61, 61, 72, 73, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74,
+ 74, 74, 74, 74, 75, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 72, 75, 72, 75, 72, 75, 72, 75, 72, 75, 76, 77, 77, 78, 78, 77,
+ 79, 79, 72, 75, 72, 75, 72, 75, 72, 72, 75, 72, 75, 72, 75, 72, 75, 72,
+ 75, 72, 75, 72, 75, 75, 64, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 64, 64, 81, 82, 82, 82, 82,
+ 82, 82, 64, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+ 64, 84, 85, 64, 64, 86, 86, 87, 64, 88, 89, 89, 89, 89, 88, 89, 89, 89,
+ 90, 88, 89, 89, 89, 89, 89, 89, 88, 88, 88, 88, 88, 88, 89, 89, 88, 89,
+ 89, 90, 91, 89, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 107, 89, 88, 107, 100, 64, 64, 64, 64, 64,
+ 64, 64, 64, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 64,
+ 64, 64, 64, 64, 110, 110, 110, 107, 107, 64, 64, 64, 111, 111, 111, 111,
+ 111, 112, 113, 113, 114, 115, 115, 116, 117, 118, 119, 119, 120, 120,
+ 120, 120, 120, 120, 120, 120, 121, 122, 123, 124, 125, 64, 118, 124, 126,
+ 126, 126, 126, 126, 126, 126, 126, 127, 126, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 128, 129, 130, 131, 132, 133, 134, 135, 78, 78, 136,
+ 137, 120, 120, 120, 120, 120, 137, 120, 120, 137, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 115, 139, 139, 118, 126, 126, 140, 126,
+ 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 118, 126, 120, 120,
+ 120, 120, 120, 120, 120, 112, 119, 120, 120, 120, 120, 137, 120, 141,
+ 141, 120, 120, 119, 137, 120, 120, 137, 126, 126, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 126, 126, 126, 143, 143, 126, 144, 144,
+ 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 64, 145, 146,
+ 147, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+ 146, 148, 149, 148, 148, 149, 148, 148, 149, 149, 149, 148, 149, 149,
+ 148, 149, 148, 148, 148, 149, 148, 149, 148, 149, 148, 149, 148, 148, 64,
+ 64, 146, 146, 146, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150,
+ 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151,
+ 150, 64, 64, 64, 64, 64, 64, 152, 152, 152, 152, 152, 152, 152, 152, 152,
+ 152, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 154, 154, 154, 154, 154, 154, 154, 155, 154, 156,
+ 156, 157, 158, 158, 158, 156, 64, 64, 64, 64, 64, 159, 159, 159, 159,
+ 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 160, 160, 160, 160,
+ 161, 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 160, 160, 160,
+ 161, 160, 160, 160, 160, 160, 64, 64, 162, 162, 162, 162, 162, 162, 162,
+ 162, 162, 162, 162, 162, 162, 162, 162, 64, 163, 163, 163, 163, 163, 163,
+ 163, 163, 163, 164, 164, 164, 64, 64, 165, 64, 126, 126, 126, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 120, 120, 137, 120, 120, 137, 120, 120, 120, 137,
+ 137, 137, 166, 167, 168, 120, 120, 120, 137, 120, 120, 137, 137, 120,
+ 120, 120, 120, 120, 169, 169, 169, 170, 171, 171, 171, 171, 171, 171,
+ 171, 171, 171, 171, 171, 171, 171, 171, 169, 170, 172, 171, 170, 170,
+ 170, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 173,
+ 170, 170, 171, 78, 136, 174, 174, 169, 169, 169, 171, 171, 169, 169, 84,
+ 84, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 177, 171, 171,
+ 171, 171, 171, 171, 178, 179, 180, 180, 64, 178, 178, 178, 178, 178, 178,
+ 178, 178, 64, 64, 178, 178, 64, 64, 178, 178, 178, 178, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 64, 178, 178, 178, 178, 178, 178, 178,
+ 64, 178, 64, 64, 64, 178, 178, 178, 178, 64, 64, 181, 178, 180, 180, 180,
+ 179, 179, 179, 179, 64, 64, 180, 180, 64, 64, 180, 180, 182, 178, 64, 64,
+ 64, 64, 64, 64, 64, 64, 180, 64, 64, 64, 64, 178, 178, 64, 178, 178, 178,
+ 179, 179, 64, 64, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 178,
+ 178, 184, 184, 185, 185, 185, 185, 185, 185, 186, 184, 64, 64, 64, 64,
+ 64, 187, 187, 188, 64, 189, 189, 189, 189, 189, 189, 64, 64, 64, 64, 189,
+ 189, 64, 64, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 64, 189, 189, 189, 189, 189, 189, 189, 64, 189, 189, 64, 189,
+ 189, 64, 189, 189, 64, 64, 190, 64, 188, 188, 188, 187, 187, 64, 64, 64,
+ 64, 187, 187, 64, 64, 187, 187, 191, 64, 64, 64, 187, 64, 64, 64, 64, 64,
+ 64, 64, 189, 189, 189, 189, 64, 189, 64, 64, 64, 64, 64, 64, 64, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 187, 187, 189, 189, 189,
+ 187, 64, 64, 64, 193, 193, 194, 64, 195, 195, 195, 195, 195, 195, 195,
+ 195, 195, 64, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 195,
+ 195, 195, 195, 195, 195, 195, 64, 195, 195, 195, 195, 195, 195, 195, 64,
+ 195, 195, 64, 195, 195, 195, 195, 195, 64, 64, 196, 195, 194, 194, 194,
+ 193, 193, 193, 193, 193, 64, 193, 193, 194, 64, 194, 194, 197, 64, 64,
+ 195, 64, 64, 64, 64, 64, 64, 64, 195, 195, 193, 193, 64, 64, 198, 198,
+ 198, 198, 198, 198, 198, 198, 198, 198, 199, 200, 64, 64, 64, 64, 64, 64,
+ 64, 201, 202, 202, 64, 203, 203, 203, 203, 203, 203, 203, 203, 64, 64,
+ 203, 203, 64, 64, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203,
+ 203, 203, 203, 64, 203, 203, 203, 203, 203, 203, 203, 64, 203, 203, 64,
+ 203, 203, 203, 203, 203, 64, 64, 204, 203, 202, 201, 202, 201, 201, 201,
+ 201, 64, 64, 202, 202, 64, 64, 202, 202, 205, 64, 64, 64, 64, 64, 64, 64,
+ 64, 201, 202, 64, 64, 64, 64, 203, 203, 64, 203, 203, 203, 201, 201, 64,
+ 64, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 203, 208, 208,
+ 208, 208, 208, 208, 64, 64, 209, 210, 64, 210, 210, 210, 210, 210, 210,
+ 64, 64, 64, 210, 210, 210, 64, 210, 210, 210, 210, 64, 64, 64, 210, 210,
+ 64, 210, 64, 210, 210, 64, 64, 64, 210, 210, 64, 64, 64, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 64, 64, 64, 64, 211, 211, 209, 211,
+ 211, 64, 64, 64, 211, 211, 211, 64, 211, 211, 211, 212, 64, 64, 210, 64,
+ 64, 64, 64, 64, 64, 211, 64, 64, 64, 64, 64, 64, 213, 213, 213, 213, 213,
+ 213, 213, 213, 213, 213, 214, 214, 214, 215, 215, 215, 215, 215, 215,
+ 216, 215, 64, 64, 64, 64, 64, 217, 218, 218, 218, 64, 219, 219, 219, 219,
+ 219, 219, 219, 219, 64, 219, 219, 219, 64, 219, 219, 219, 219, 219, 219,
+ 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 64, 64, 64, 219, 217,
+ 217, 217, 218, 218, 218, 218, 64, 217, 217, 217, 64, 217, 217, 217, 220,
+ 64, 64, 64, 64, 64, 64, 64, 221, 222, 64, 219, 219, 64, 64, 64, 64, 64,
+ 64, 219, 219, 217, 217, 64, 64, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 224, 224, 224, 224, 224, 224, 224, 225, 64, 226, 227, 227, 64,
+ 228, 228, 228, 228, 228, 228, 228, 228, 64, 228, 228, 228, 64, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228,
+ 228, 228, 64, 228, 228, 228, 228, 228, 64, 64, 229, 228, 227, 230, 227,
+ 227, 227, 227, 227, 64, 230, 227, 227, 64, 227, 227, 226, 231, 64, 64,
+ 64, 64, 64, 64, 64, 227, 227, 64, 64, 64, 64, 64, 64, 64, 228, 64, 228,
+ 228, 226, 226, 64, 64, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
+ 64, 228, 228, 64, 64, 64, 64, 64, 64, 233, 234, 234, 64, 235, 235, 235,
+ 235, 235, 235, 235, 235, 64, 235, 235, 235, 64, 235, 235, 235, 235, 235,
+ 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 64, 64, 235,
+ 234, 234, 234, 233, 233, 233, 233, 64, 234, 234, 234, 64, 234, 234, 234,
+ 236, 235, 64, 64, 64, 64, 64, 64, 64, 64, 234, 235, 235, 233, 233, 64,
+ 64, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 238, 238, 238, 238,
+ 238, 238, 64, 64, 64, 239, 235, 235, 235, 235, 235, 235, 64, 64, 240,
+ 240, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 64, 64, 64, 241, 241, 241, 241, 241, 241, 241,
+ 241, 64, 241, 241, 241, 241, 241, 241, 241, 241, 241, 64, 241, 64, 64,
+ 64, 64, 242, 64, 64, 64, 64, 240, 240, 240, 243, 243, 243, 64, 243, 64,
+ 240, 240, 240, 240, 240, 240, 240, 240, 64, 64, 64, 64, 64, 64, 244, 244,
+ 244, 244, 244, 244, 244, 244, 244, 244, 64, 64, 240, 240, 245, 64, 64,
+ 64, 64, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246,
+ 246, 246, 246, 247, 246, 246, 247, 247, 247, 247, 248, 248, 249, 64, 64,
+ 64, 64, 250, 246, 246, 246, 246, 246, 246, 251, 247, 252, 252, 252, 252,
+ 247, 247, 247, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254,
+ 253, 253, 64, 64, 64, 64, 64, 255, 255, 64, 255, 64, 64, 255, 255, 64,
+ 255, 64, 64, 255, 64, 64, 64, 64, 64, 64, 255, 255, 255, 255, 64, 255,
+ 255, 255, 255, 255, 255, 255, 64, 255, 255, 255, 64, 255, 64, 255, 64,
+ 64, 255, 255, 64, 255, 255, 255, 255, 256, 255, 255, 256, 256, 256, 256,
+ 257, 257, 64, 256, 256, 255, 64, 64, 255, 255, 255, 255, 255, 64, 258,
+ 64, 259, 259, 259, 259, 256, 256, 64, 64, 260, 260, 260, 260, 260, 260,
+ 260, 260, 260, 260, 64, 64, 255, 255, 255, 255, 261, 262, 262, 262, 263,
+ 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263, 263,
+ 262, 263, 262, 262, 262, 264, 264, 262, 262, 262, 262, 262, 262, 265,
+ 265, 265, 265, 265, 265, 265, 265, 265, 265, 266, 266, 266, 266, 266,
+ 266, 266, 266, 266, 266, 262, 264, 262, 264, 262, 267, 268, 269, 268,
+ 269, 270, 270, 261, 261, 261, 261, 261, 261, 261, 261, 64, 261, 261, 261,
+ 261, 261, 261, 261, 261, 261, 261, 261, 261, 64, 64, 64, 64, 271, 272,
+ 273, 274, 273, 273, 273, 273, 273, 272, 272, 272, 272, 273, 270, 272,
+ 273, 275, 275, 276, 263, 275, 275, 261, 261, 261, 261, 261, 273, 273,
+ 273, 273, 273, 273, 273, 273, 273, 273, 273, 64, 273, 273, 273, 273, 273,
+ 273, 273, 273, 273, 273, 273, 273, 64, 262, 262, 262, 262, 262, 262, 262,
+ 262, 264, 262, 262, 262, 262, 262, 262, 64, 262, 262, 263, 263, 263, 263,
+ 263, 277, 277, 277, 277, 263, 263, 64, 64, 64, 64, 64, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 280, 280,
+ 279, 280, 280, 280, 280, 280, 281, 279, 282, 282, 279, 279, 280, 280,
+ 278, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284,
+ 284, 284, 284, 278, 278, 278, 278, 278, 278, 279, 279, 280, 280, 278,
+ 278, 278, 278, 280, 280, 280, 278, 279, 279, 279, 278, 278, 279, 279,
+ 279, 279, 279, 279, 279, 278, 278, 278, 280, 280, 280, 280, 278, 278,
+ 278, 278, 278, 280, 279, 279, 280, 280, 279, 279, 279, 279, 279, 279,
+ 285, 278, 279, 283, 283, 279, 279, 279, 280, 286, 286, 287, 287, 287,
+ 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 64, 287, 64, 64,
+ 64, 64, 64, 287, 64, 64, 288, 288, 288, 288, 288, 288, 288, 288, 288,
+ 288, 288, 84, 289, 288, 288, 288, 290, 290, 290, 290, 290, 290, 290, 290,
+ 291, 291, 291, 291, 291, 291, 291, 291, 292, 292, 292, 292, 292, 292,
+ 292, 292, 292, 64, 292, 292, 292, 292, 64, 64, 292, 292, 292, 292, 292,
+ 292, 292, 64, 292, 292, 292, 64, 64, 293, 293, 293, 294, 294, 294, 294,
+ 294, 294, 294, 294, 294, 295, 295, 295, 295, 295, 295, 295, 295, 295,
+ 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 64, 64, 64, 296,
+ 296, 296, 296, 296, 296, 296, 296, 296, 296, 64, 64, 64, 64, 64, 64, 297,
+ 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 64, 64, 64,
+ 298, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, 299,
+ 299, 299, 299, 299, 299, 299, 299, 300, 300, 299, 301, 302, 302, 302,
+ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302,
+ 302, 303, 304, 64, 64, 64, 305, 305, 305, 305, 305, 305, 305, 305, 305,
+ 305, 305, 84, 84, 84, 306, 306, 306, 305, 305, 305, 305, 305, 305, 305,
+ 305, 64, 64, 64, 64, 64, 64, 64, 307, 307, 307, 307, 307, 307, 307, 307,
+ 307, 307, 307, 307, 307, 64, 307, 307, 307, 307, 308, 308, 309, 64, 64,
+ 64, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 311, 311, 312, 84,
+ 84, 64, 313, 313, 313, 313, 313, 313, 313, 313, 313, 313, 314, 314, 64,
+ 64, 64, 64, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 64, 315, 315, 315, 64, 316, 316, 64, 64, 64, 64, 317, 317, 317, 317,
+ 317, 317, 317, 317, 317, 317, 317, 317, 318, 318, 319, 318, 318, 318,
+ 318, 318, 318, 318, 319, 319, 319, 319, 319, 319, 319, 319, 318, 319,
+ 319, 318, 318, 318, 318, 318, 318, 318, 318, 318, 320, 318, 321, 321,
+ 321, 322, 321, 321, 321, 323, 317, 324, 64, 64, 325, 325, 325, 325, 325,
+ 325, 325, 325, 325, 325, 64, 64, 64, 64, 64, 64, 326, 326, 326, 326, 326,
+ 326, 326, 326, 326, 326, 64, 64, 64, 64, 64, 64, 327, 327, 66, 66, 327,
+ 66, 328, 327, 327, 327, 327, 329, 329, 329, 330, 64, 331, 331, 331, 331,
+ 331, 331, 331, 331, 331, 331, 64, 64, 64, 64, 64, 64, 332, 332, 332, 332,
+ 332, 332, 332, 332, 332, 332, 332, 333, 332, 332, 332, 332, 332, 334,
+ 332, 64, 64, 64, 64, 64, 299, 299, 299, 299, 299, 299, 64, 64, 335, 335,
+ 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 335, 64, 336,
+ 336, 336, 337, 337, 337, 337, 336, 336, 337, 337, 337, 64, 64, 64, 64,
+ 337, 337, 336, 337, 337, 337, 337, 337, 337, 338, 339, 340, 64, 64, 64,
+ 64, 341, 64, 64, 64, 342, 342, 343, 343, 343, 343, 343, 343, 343, 343,
+ 343, 343, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344,
+ 344, 344, 64, 64, 344, 344, 344, 344, 344, 64, 64, 64, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345, 345, 64, 64, 64, 64, 346, 346,
+ 346, 346, 346, 346, 346, 346, 346, 345, 345, 345, 345, 345, 345, 345,
+ 346, 346, 64, 64, 64, 64, 64, 64, 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 348, 64, 64, 64, 349, 349, 350, 350, 350, 350, 350, 350, 350,
+ 350, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, 351,
+ 351, 351, 352, 353, 354, 354, 355, 64, 64, 356, 356, 357, 357, 357, 357,
+ 357, 357, 357, 357, 357, 357, 357, 357, 357, 358, 359, 358, 359, 359,
+ 359, 359, 359, 359, 359, 64, 360, 358, 359, 358, 358, 359, 359, 359, 359,
+ 359, 359, 359, 359, 358, 358, 358, 358, 358, 358, 359, 359, 361, 361,
+ 361, 361, 361, 361, 361, 361, 64, 64, 362, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 64, 64, 64, 64, 64, 64, 364, 364, 364, 364, 364, 364,
+ 364, 365, 364, 364, 364, 364, 364, 364, 64, 64, 78, 78, 78, 78, 78, 136,
+ 136, 136, 136, 136, 136, 78, 78, 136, 366, 64, 367, 367, 367, 367, 368,
+ 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
+ 369, 370, 368, 367, 367, 367, 367, 367, 368, 367, 368, 368, 368, 368,
+ 368, 367, 368, 371, 369, 369, 369, 369, 369, 369, 369, 64, 64, 64, 64,
+ 372, 372, 372, 372, 372, 372, 372, 372, 372, 372, 373, 373, 373, 373,
+ 373, 373, 373, 374, 374, 374, 374, 374, 374, 374, 374, 374, 374, 375,
+ 376, 375, 375, 375, 375, 375, 375, 375, 374, 374, 374, 374, 374, 374,
+ 374, 374, 374, 64, 64, 64, 377, 377, 378, 379, 379, 379, 379, 379, 379,
+ 379, 379, 379, 379, 379, 379, 379, 379, 378, 377, 377, 377, 377, 378,
+ 378, 377, 377, 380, 381, 377, 377, 379, 379, 382, 382, 382, 382, 382,
+ 382, 382, 382, 382, 382, 379, 379, 379, 379, 379, 379, 383, 383, 383,
+ 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 385, 386,
+ 386, 385, 385, 385, 386, 385, 386, 386, 386, 387, 387, 64, 64, 64, 64,
+ 64, 64, 64, 64, 388, 388, 388, 388, 389, 389, 389, 389, 389, 389, 389,
+ 389, 389, 389, 389, 389, 390, 390, 390, 390, 390, 390, 390, 390, 391,
+ 391, 391, 391, 391, 391, 391, 391, 390, 390, 391, 392, 64, 64, 64, 393,
+ 393, 393, 393, 393, 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 64,
+ 64, 64, 389, 389, 389, 395, 395, 395, 395, 395, 395, 395, 395, 395, 395,
+ 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+ 397, 397, 397, 397, 397, 397, 398, 398, 399, 399, 399, 399, 399, 399,
+ 399, 399, 78, 78, 78, 84, 400, 136, 136, 136, 136, 136, 78, 78, 136, 136,
+ 136, 136, 78, 401, 400, 400, 400, 400, 400, 400, 400, 402, 402, 402, 402,
+ 136, 402, 402, 402, 402, 401, 401, 78, 402, 402, 64, 78, 78, 64, 64, 64,
+ 64, 64, 64, 41, 41, 41, 41, 41, 41, 62, 62, 62, 62, 62, 75, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 65, 65, 65, 65, 65, 44, 44, 44, 44, 65, 65, 65,
+ 65, 65, 41, 41, 41, 41, 41, 403, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 65, 78, 78, 136, 78, 78,
+ 78, 78, 78, 78, 78, 136, 78, 78, 404, 405, 136, 406, 78, 78, 78, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 64, 64,
+ 64, 64, 64, 64, 407, 136, 78, 136, 37, 41, 37, 41, 37, 41, 41, 41, 41,
+ 41, 41, 41, 41, 41, 37, 41, 62, 62, 62, 62, 62, 62, 62, 62, 61, 61, 61,
+ 61, 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 64, 64, 61, 61, 61, 61, 61,
+ 61, 64, 64, 64, 61, 64, 61, 64, 61, 64, 61, 408, 408, 408, 408, 408, 408,
+ 408, 408, 62, 62, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 63, 62,
+ 63, 63, 63, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408, 63, 63, 63, 62,
+ 62, 62, 62, 64, 64, 62, 62, 61, 61, 61, 61, 64, 63, 63, 63, 61, 61, 61,
+ 61, 61, 63, 63, 63, 64, 64, 62, 62, 62, 64, 62, 62, 61, 61, 61, 61, 408,
+ 63, 63, 64, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 409, 410,
+ 411, 411, 412, 413, 414, 415, 415, 414, 414, 414, 22, 66, 416, 417, 418,
+ 419, 416, 417, 418, 419, 22, 22, 22, 66, 22, 22, 22, 22, 420, 421, 422,
+ 423, 424, 425, 426, 21, 427, 428, 427, 427, 428, 22, 66, 66, 66, 28, 35,
+ 22, 66, 66, 22, 429, 429, 66, 66, 66, 430, 431, 432, 66, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 433, 66, 429, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 409, 410, 410, 410, 410, 410, 64, 434, 435, 436, 437, 410, 410, 410,
+ 410, 410, 410, 438, 44, 64, 64, 33, 438, 438, 438, 438, 438, 439, 439,
+ 433, 431, 432, 440, 438, 33, 33, 33, 33, 438, 438, 438, 438, 438, 439,
+ 439, 433, 431, 432, 64, 44, 44, 44, 44, 44, 64, 64, 64, 250, 250, 250,
+ 250, 250, 250, 250, 250, 250, 441, 250, 250, 23, 250, 250, 250, 250, 250,
+ 250, 250, 250, 250, 64, 64, 78, 78, 400, 400, 78, 78, 78, 78, 400, 400,
+ 400, 78, 78, 366, 366, 366, 366, 78, 366, 366, 366, 400, 400, 78, 136,
+ 78, 400, 400, 136, 136, 136, 136, 78, 64, 64, 64, 64, 64, 64, 64, 26, 26,
+ 442, 30, 26, 30, 26, 442, 26, 30, 34, 442, 442, 442, 34, 34, 442, 442,
+ 442, 443, 26, 442, 30, 26, 433, 442, 442, 442, 442, 442, 26, 26, 26, 30,
+ 30, 26, 442, 26, 67, 26, 442, 26, 37, 38, 442, 442, 444, 34, 442, 442,
+ 37, 442, 34, 402, 402, 402, 402, 34, 26, 26, 34, 34, 442, 442, 445, 433,
+ 433, 433, 433, 442, 34, 34, 34, 34, 26, 433, 26, 26, 41, 277, 446, 446,
+ 446, 36, 36, 446, 446, 446, 446, 446, 446, 36, 36, 36, 36, 446, 447, 447,
+ 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 448, 448, 448, 448,
+ 447, 447, 448, 448, 448, 448, 448, 448, 448, 448, 448, 37, 41, 448, 448,
+ 448, 448, 36, 64, 64, 64, 64, 64, 64, 39, 39, 39, 39, 39, 30, 30, 30, 30,
+ 30, 433, 433, 26, 26, 26, 26, 433, 26, 26, 433, 26, 26, 433, 26, 26, 26,
+ 26, 26, 26, 26, 433, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 433, 433, 26, 26, 39, 26, 39, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 26, 26, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433, 433, 39, 445, 449, 449, 445, 433,
+ 433, 39, 449, 445, 445, 449, 445, 445, 433, 39, 433, 449, 439, 450, 433,
+ 449, 445, 433, 433, 433, 449, 445, 445, 449, 39, 449, 449, 445, 445, 39,
+ 445, 39, 445, 39, 39, 39, 39, 449, 449, 445, 449, 445, 445, 445, 445,
+ 445, 39, 39, 39, 39, 433, 445, 433, 445, 449, 449, 445, 445, 445, 445,
+ 445, 445, 445, 445, 445, 445, 449, 445, 445, 445, 449, 433, 433, 433,
+ 433, 433, 449, 445, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 445, 449, 39, 445, 433, 449, 449, 449, 449, 445, 445, 449, 449, 433,
+ 433, 449, 449, 445, 445, 449, 449, 445, 445, 449, 449, 445, 445, 445,
+ 445, 445, 433, 433, 445, 445, 445, 445, 433, 433, 39, 433, 433, 445, 39,
+ 433, 433, 433, 433, 433, 433, 433, 433, 445, 445, 433, 39, 445, 445, 445,
+ 433, 433, 433, 433, 433, 445, 449, 433, 445, 445, 445, 445, 445, 433,
+ 433, 445, 445, 433, 433, 433, 433, 445, 445, 445, 445, 445, 445, 445,
+ 445, 433, 433, 431, 432, 431, 432, 26, 26, 26, 26, 26, 26, 30, 26, 26,
+ 26, 26, 26, 445, 445, 26, 26, 26, 26, 26, 26, 26, 451, 452, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 26, 433, 26, 26, 26, 26, 26, 26, 26, 26, 277,
+ 26, 26, 26, 26, 26, 433, 433, 433, 433, 433, 433, 433, 433, 433, 26, 26,
+ 26, 26, 433, 433, 26, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 64, 64, 64,
+ 26, 26, 26, 26, 26, 26, 26, 64, 36, 36, 36, 36, 36, 36, 36, 36, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 453, 453, 453, 453, 453, 453,
+ 453, 453, 453, 453, 453, 453, 453, 453, 446, 36, 36, 36, 36, 36, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 26, 26, 26, 26, 26, 30, 30,
+ 30, 30, 26, 26, 30, 30, 26, 30, 30, 30, 30, 30, 26, 26, 30, 30, 26, 26,
+ 30, 39, 26, 26, 26, 26, 30, 30, 26, 26, 30, 39, 26, 26, 26, 26, 30, 30,
+ 30, 26, 26, 30, 26, 26, 30, 30, 26, 26, 26, 26, 26, 30, 30, 26, 26, 30,
+ 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 30, 26, 30, 26, 30, 26, 30, 26,
+ 26, 26, 26, 26, 30, 30, 26, 30, 30, 30, 26, 30, 30, 30, 30, 26, 30, 30,
+ 26, 39, 26, 26, 26, 26, 26, 26, 30, 30, 26, 26, 26, 26, 277, 26, 26, 26,
+ 26, 26, 26, 26, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 26, 30, 30, 30,
+ 26, 30, 26, 26, 26, 26, 26, 26, 26, 26, 26, 30, 26, 26, 431, 432, 431,
+ 432, 431, 432, 431, 432, 431, 432, 431, 432, 431, 432, 36, 36, 446, 446,
+ 446, 446, 446, 446, 446, 446, 446, 446, 446, 446, 26, 26, 26, 26, 445,
+ 433, 433, 445, 445, 431, 432, 433, 445, 445, 433, 445, 445, 445, 433,
+ 433, 433, 433, 433, 445, 445, 445, 445, 433, 433, 433, 433, 433, 445,
+ 445, 445, 433, 433, 433, 445, 445, 445, 445, 9, 10, 9, 10, 9, 10, 9, 10,
+ 431, 432, 454, 454, 454, 454, 454, 454, 454, 454, 433, 433, 433, 431,
+ 432, 9, 10, 431, 432, 431, 432, 431, 432, 431, 432, 431, 432, 433, 433,
+ 445, 445, 445, 445, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433,
+ 445, 433, 433, 433, 433, 445, 445, 445, 445, 445, 433, 445, 445, 433,
+ 433, 431, 432, 431, 432, 445, 433, 433, 433, 433, 445, 433, 445, 445,
+ 445, 433, 433, 445, 445, 433, 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 445, 445, 445, 445, 445, 445, 433, 433, 431, 432, 433, 433, 433,
+ 433, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 433, 445,
+ 445, 445, 445, 433, 433, 445, 433, 445, 433, 433, 445, 433, 445, 445,
+ 445, 445, 433, 433, 433, 433, 433, 445, 445, 433, 433, 433, 433, 445,
+ 445, 445, 445, 433, 445, 445, 433, 433, 445, 445, 433, 433, 433, 433,
+ 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 445, 433, 433, 445,
+ 445, 445, 445, 445, 445, 445, 445, 433, 445, 445, 445, 445, 445, 445,
+ 445, 445, 433, 433, 433, 433, 433, 445, 433, 445, 433, 433, 433, 445,
+ 445, 445, 445, 445, 433, 433, 433, 433, 445, 433, 433, 433, 445, 445,
+ 445, 445, 445, 433, 445, 433, 433, 433, 433, 433, 433, 433, 26, 26, 433,
+ 433, 433, 433, 433, 433, 26, 26, 26, 26, 26, 26, 26, 26, 30, 30, 30, 26,
+ 26, 26, 26, 64, 64, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 26, 26, 64,
+ 64, 64, 26, 26, 26, 26, 64, 26, 26, 26, 26, 26, 26, 26, 26, 64, 64, 64,
+ 64, 64, 64, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455,
+ 455, 455, 455, 64, 456, 456, 456, 456, 456, 456, 456, 456, 456, 456, 456,
+ 456, 456, 456, 456, 64, 37, 41, 37, 37, 37, 41, 41, 37, 41, 37, 41, 37,
+ 41, 37, 37, 37, 37, 41, 37, 41, 41, 37, 41, 41, 41, 41, 41, 41, 44, 44,
+ 37, 37, 69, 70, 69, 70, 70, 457, 457, 457, 457, 457, 457, 69, 70, 69, 70,
+ 458, 458, 458, 69, 70, 64, 64, 64, 64, 64, 459, 459, 459, 459, 460, 459,
+ 459, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461,
+ 461, 64, 461, 64, 64, 64, 64, 64, 461, 64, 64, 462, 462, 462, 462, 462,
+ 462, 462, 462, 64, 64, 64, 64, 64, 64, 64, 463, 464, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 465, 77, 77, 77, 77, 77, 77, 77, 77,
+ 66, 66, 28, 35, 28, 35, 66, 66, 66, 28, 35, 66, 28, 35, 66, 66, 66, 66,
+ 66, 66, 66, 66, 66, 415, 66, 66, 415, 66, 28, 35, 66, 66, 28, 35, 431,
+ 432, 431, 432, 431, 432, 431, 432, 66, 66, 66, 66, 66, 45, 66, 66, 415,
+ 415, 66, 66, 66, 66, 415, 66, 418, 64, 64, 64, 64, 64, 466, 466, 466,
+ 466, 466, 466, 466, 466, 466, 466, 64, 466, 466, 466, 466, 466, 466, 466,
+ 466, 466, 64, 64, 64, 64, 466, 466, 466, 466, 466, 466, 64, 64, 467, 467,
+ 467, 467, 467, 467, 467, 467, 467, 467, 467, 467, 64, 64, 64, 64, 468,
+ 469, 469, 469, 467, 470, 471, 472, 451, 452, 451, 452, 451, 452, 451,
+ 452, 451, 452, 467, 467, 451, 452, 451, 452, 451, 452, 451, 452, 473,
+ 474, 475, 475, 467, 472, 472, 472, 472, 472, 472, 472, 472, 472, 476,
+ 477, 478, 479, 480, 480, 473, 481, 481, 481, 481, 481, 467, 467, 472,
+ 472, 472, 470, 471, 469, 467, 26, 64, 482, 482, 482, 482, 482, 482, 482,
+ 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482, 482,
+ 482, 64, 64, 483, 483, 484, 484, 485, 485, 482, 473, 486, 486, 486, 486,
+ 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486, 486,
+ 469, 481, 487, 487, 486, 64, 64, 64, 64, 64, 488, 488, 488, 488, 488,
+ 488, 488, 488, 488, 488, 488, 488, 488, 488, 488, 488, 488, 64, 64, 64,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 64,
+ 489, 489, 490, 490, 490, 490, 489, 489, 489, 489, 489, 489, 489, 489,
+ 489, 489, 488, 488, 488, 64, 64, 64, 64, 64, 491, 491, 491, 491, 491,
+ 491, 491, 491, 491, 491, 491, 491, 491, 492, 492, 64, 490, 490, 490, 490,
+ 490, 490, 490, 490, 490, 490, 489, 489, 489, 489, 489, 489, 493, 493,
+ 493, 493, 493, 493, 493, 493, 467, 494, 494, 494, 494, 494, 494, 494,
+ 494, 494, 494, 494, 494, 494, 494, 494, 491, 491, 491, 491, 492, 492,
+ 492, 489, 489, 494, 494, 494, 494, 494, 494, 494, 489, 489, 489, 489,
+ 467, 467, 467, 467, 495, 495, 495, 495, 495, 495, 495, 495, 495, 495,
+ 495, 495, 495, 495, 495, 64, 489, 489, 489, 489, 489, 489, 489, 467, 467,
+ 467, 467, 489, 489, 489, 489, 489, 489, 489, 489, 489, 489, 489, 467,
+ 467, 496, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497, 497,
+ 497, 497, 497, 497, 497, 497, 497, 497, 496, 498, 498, 498, 498, 498,
+ 498, 498, 498, 498, 498, 497, 497, 497, 497, 496, 498, 498, 498, 499,
+ 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 500, 499,
+ 499, 499, 499, 499, 499, 499, 64, 64, 64, 501, 501, 501, 501, 501, 501,
+ 501, 501, 501, 501, 501, 501, 501, 501, 501, 64, 502, 502, 502, 502, 502,
+ 502, 502, 502, 503, 503, 503, 503, 503, 503, 504, 504, 505, 505, 505,
+ 505, 505, 505, 505, 505, 505, 505, 505, 505, 506, 507, 507, 507, 508,
+ 508, 508, 508, 508, 508, 508, 508, 508, 508, 505, 505, 64, 64, 64, 64,
+ 72, 75, 72, 75, 72, 75, 509, 77, 79, 79, 79, 510, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 510, 511, 72, 75, 72, 75, 403, 403, 64, 77, 512, 512,
+ 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 513, 513,
+ 513, 513, 513, 513, 513, 513, 513, 513, 514, 514, 515, 515, 515, 515,
+ 515, 515, 47, 47, 47, 47, 47, 47, 47, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 47, 47, 37, 41, 37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 41, 44, 41,
+ 41, 41, 41, 41, 41, 41, 41, 37, 41, 37, 41, 37, 37, 41, 45, 516, 516, 37,
+ 41, 37, 41, 64, 37, 41, 37, 41, 41, 41, 37, 41, 37, 41, 37, 37, 37, 37,
+ 64, 64, 37, 37, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 42,
+ 44, 44, 41, 42, 42, 42, 42, 42, 517, 517, 518, 517, 517, 517, 519, 517,
+ 517, 517, 517, 518, 517, 517, 517, 517, 517, 517, 517, 517, 517, 517,
+ 517, 517, 517, 517, 517, 520, 520, 518, 518, 520, 521, 521, 521, 521, 64,
+ 64, 64, 64, 522, 522, 522, 522, 522, 522, 277, 277, 250, 444, 64, 64, 64,
+ 64, 64, 64, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523, 523,
+ 524, 524, 524, 524, 525, 525, 526, 526, 526, 526, 526, 526, 526, 526,
+ 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 525, 525, 525, 525,
+ 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 527, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 528, 528, 529, 529, 529, 529, 529, 529, 529,
+ 529, 529, 529, 64, 64, 64, 64, 64, 64, 174, 174, 174, 174, 174, 174, 174,
+ 174, 174, 174, 171, 171, 171, 171, 171, 171, 176, 176, 176, 171, 64, 64,
+ 64, 64, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 531, 531, 531,
+ 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531,
+ 531, 531, 531, 532, 532, 532, 532, 532, 533, 533, 533, 84, 534, 535, 535,
+ 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 535, 536,
+ 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 537, 538, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 539, 290, 290, 290, 290, 290, 64, 64, 64,
+ 540, 540, 540, 541, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542,
+ 542, 542, 542, 542, 542, 543, 541, 541, 540, 540, 540, 540, 541, 541,
+ 540, 541, 541, 541, 544, 545, 545, 545, 545, 545, 545, 545, 545, 545,
+ 545, 545, 545, 545, 64, 46, 546, 546, 546, 546, 546, 546, 546, 546, 546,
+ 546, 64, 64, 64, 64, 545, 545, 278, 278, 278, 278, 278, 280, 547, 278,
+ 283, 283, 278, 278, 278, 278, 278, 64, 548, 548, 548, 548, 548, 548, 548,
+ 548, 548, 549, 549, 549, 549, 549, 549, 550, 550, 549, 549, 550, 550,
+ 549, 549, 64, 548, 548, 548, 549, 548, 548, 548, 548, 548, 548, 548, 548,
+ 549, 550, 64, 64, 551, 551, 551, 551, 551, 551, 551, 551, 551, 551, 64,
+ 64, 552, 552, 552, 552, 547, 278, 278, 278, 278, 278, 278, 286, 286, 286,
+ 278, 279, 280, 279, 278, 278, 553, 553, 553, 553, 553, 553, 553, 553,
+ 554, 553, 554, 554, 555, 553, 553, 554, 554, 553, 553, 553, 553, 553,
+ 554, 554, 553, 554, 553, 64, 64, 64, 64, 64, 64, 64, 64, 553, 553, 556,
+ 557, 557, 558, 558, 558, 558, 558, 558, 558, 558, 558, 558, 558, 559,
+ 560, 560, 559, 559, 561, 561, 558, 562, 562, 559, 563, 64, 64, 292, 292,
+ 292, 292, 292, 292, 64, 41, 41, 41, 516, 44, 44, 44, 44, 64, 64, 64, 64,
+ 41, 62, 64, 64, 558, 558, 558, 559, 559, 560, 559, 559, 560, 559, 559,
+ 561, 559, 563, 64, 64, 564, 564, 564, 564, 564, 564, 564, 564, 564, 564,
+ 64, 64, 64, 64, 64, 64, 290, 565, 565, 565, 565, 565, 565, 565, 565, 565,
+ 565, 565, 565, 565, 565, 565, 565, 565, 565, 290, 64, 64, 64, 64, 291,
+ 291, 291, 291, 291, 291, 291, 64, 64, 64, 64, 291, 291, 291, 291, 291,
+ 291, 291, 291, 291, 64, 64, 64, 64, 566, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 64, 64, 64, 566, 567, 568, 568, 568, 568, 568, 568, 568, 568,
+ 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568,
+ 567, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496,
+ 496, 498, 498, 496, 496, 498, 498, 498, 498, 498, 498, 41, 41, 41, 41,
+ 41, 41, 41, 64, 64, 64, 64, 83, 83, 83, 83, 83, 64, 64, 64, 64, 64, 110,
+ 569, 110, 110, 570, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 64, 110, 110, 110, 110, 110, 64, 110, 64, 110, 110, 64,
+ 110, 110, 64, 110, 110, 126, 126, 571, 571, 571, 571, 571, 571, 571, 571,
+ 571, 571, 571, 571, 571, 571, 571, 571, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 572, 418, 64,
+ 64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 116, 119, 64, 64,
+ 58, 58, 58, 58, 58, 58, 58, 58, 469, 469, 469, 469, 469, 469, 469, 474,
+ 475, 469, 64, 64, 64, 64, 64, 64, 78, 78, 78, 78, 78, 78, 78, 136, 136,
+ 136, 136, 136, 136, 136, 64, 64, 469, 473, 473, 573, 573, 474, 475, 474,
+ 475, 474, 475, 474, 475, 474, 475, 474, 475, 474, 475, 474, 475, 469,
+ 469, 474, 475, 469, 469, 469, 469, 573, 573, 573, 574, 469, 574, 64, 469,
+ 574, 469, 469, 473, 451, 452, 451, 452, 451, 452, 575, 469, 469, 576,
+ 577, 578, 578, 579, 64, 469, 580, 575, 469, 64, 64, 64, 64, 126, 126,
+ 126, 126, 126, 64, 126, 126, 126, 126, 126, 126, 126, 64, 64, 410, 64,
+ 581, 581, 582, 583, 582, 581, 581, 584, 585, 581, 586, 587, 588, 587,
+ 587, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 587, 581, 590,
+ 591, 590, 581, 581, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 592, 592, 592, 584, 581, 585, 593, 594, 593,
+ 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595,
+ 595, 595, 595, 595, 584, 591, 585, 591, 584, 585, 596, 597, 598, 596,
+ 596, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 599, 599,
+ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 600, 601,
+ 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 64,
+ 64, 64, 601, 601, 601, 601, 601, 601, 64, 64, 601, 601, 601, 64, 64, 64,
+ 583, 583, 591, 593, 602, 583, 583, 64, 603, 604, 604, 604, 604, 603, 603,
+ 64, 64, 605, 605, 605, 26, 30, 64, 64, 606, 606, 606, 606, 606, 606, 606,
+ 606, 606, 606, 606, 606, 64, 606, 606, 606, 606, 606, 606, 606, 606, 606,
+ 606, 64, 606, 606, 606, 64, 606, 606, 64, 606, 606, 606, 606, 606, 606,
+ 606, 64, 64, 606, 606, 606, 64, 64, 64, 64, 64, 84, 66, 84, 64, 64, 64,
+ 64, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 64,
+ 64, 64, 277, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607, 607,
+ 607, 608, 608, 608, 608, 609, 609, 609, 609, 609, 609, 609, 609, 609,
+ 609, 609, 609, 609, 609, 609, 609, 609, 608, 608, 609, 64, 64, 64, 26,
+ 26, 26, 26, 64, 64, 64, 64, 609, 64, 64, 64, 64, 64, 64, 64, 277, 277,
+ 277, 277, 277, 136, 64, 64, 610, 610, 610, 610, 610, 610, 610, 610, 610,
+ 610, 610, 610, 610, 64, 64, 64, 611, 611, 611, 611, 611, 611, 611, 611,
+ 611, 64, 64, 64, 64, 64, 64, 64, 136, 438, 438, 438, 438, 438, 438, 438,
+ 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 438, 64, 64, 64,
+ 64, 612, 612, 612, 612, 612, 612, 612, 612, 613, 613, 613, 613, 64, 64,
+ 64, 64, 614, 614, 614, 614, 614, 614, 614, 614, 614, 615, 614, 614, 614,
+ 614, 614, 614, 614, 614, 615, 64, 64, 64, 64, 64, 616, 616, 616, 616,
+ 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 617, 617, 617,
+ 617, 64, 64, 64, 64, 64, 618, 618, 618, 618, 618, 618, 618, 618, 618,
+ 618, 618, 618, 618, 618, 64, 619, 620, 620, 620, 620, 620, 620, 620, 620,
+ 620, 620, 620, 620, 64, 64, 64, 64, 621, 622, 622, 622, 622, 622, 64, 64,
+ 623, 623, 623, 623, 623, 623, 623, 623, 624, 624, 624, 624, 624, 624,
+ 624, 624, 625, 625, 625, 625, 625, 625, 625, 625, 626, 626, 626, 626,
+ 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 64, 64, 627, 627, 627,
+ 627, 627, 627, 627, 627, 627, 627, 64, 64, 64, 64, 64, 64, 628, 628, 628,
+ 628, 628, 628, 628, 628, 629, 629, 629, 629, 629, 629, 629, 629, 629,
+ 629, 629, 629, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 630, 631, 631,
+ 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 64, 631,
+ 631, 631, 631, 631, 631, 64, 64, 632, 632, 632, 632, 632, 632, 64, 64,
+ 632, 64, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632, 632,
+ 632, 632, 632, 632, 632, 632, 632, 64, 632, 632, 64, 64, 64, 632, 64, 64,
+ 632, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633, 633,
+ 633, 64, 634, 635, 635, 635, 635, 635, 635, 635, 635, 636, 636, 636, 636,
+ 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 637, 638,
+ 638, 638, 638, 638, 638, 638, 639, 639, 639, 639, 639, 639, 639, 639,
+ 639, 639, 639, 639, 639, 639, 639, 64, 64, 64, 64, 64, 64, 64, 64, 640,
+ 640, 640, 640, 640, 640, 640, 640, 640, 641, 641, 641, 641, 641, 641,
+ 641, 641, 641, 641, 641, 641, 641, 641, 642, 642, 642, 642, 642, 642, 64,
+ 64, 64, 643, 644, 644, 644, 644, 644, 644, 644, 644, 644, 644, 64, 64,
+ 64, 64, 64, 645, 646, 646, 646, 646, 646, 646, 646, 646, 647, 647, 647,
+ 647, 647, 647, 647, 647, 64, 64, 64, 64, 64, 64, 647, 647, 648, 649, 649,
+ 649, 64, 649, 649, 64, 64, 64, 64, 64, 649, 650, 649, 651, 648, 648, 648,
+ 648, 64, 648, 648, 648, 64, 648, 648, 648, 648, 648, 648, 648, 648, 648,
+ 648, 648, 648, 648, 648, 648, 648, 648, 648, 648, 64, 64, 64, 64, 651,
+ 652, 650, 64, 64, 64, 64, 653, 654, 654, 654, 654, 654, 654, 654, 654,
+ 655, 655, 655, 655, 655, 655, 655, 655, 655, 64, 64, 64, 64, 64, 64, 64,
+ 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 656, 657,
+ 657, 658, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659, 659,
+ 659, 660, 660, 660, 661, 661, 661, 661, 661, 661, 661, 661, 662, 661,
+ 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 661, 663, 664, 64, 64,
+ 64, 64, 665, 665, 665, 665, 665, 666, 666, 666, 666, 666, 666, 666, 64,
+ 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 667, 64,
+ 64, 64, 668, 668, 668, 668, 668, 668, 668, 669, 669, 669, 669, 669, 669,
+ 669, 669, 669, 669, 669, 669, 669, 669, 64, 64, 670, 670, 670, 670, 670,
+ 670, 670, 670, 671, 671, 671, 671, 671, 671, 671, 671, 671, 671, 671, 64,
+ 64, 64, 64, 64, 672, 672, 672, 672, 672, 672, 672, 672, 673, 673, 673,
+ 673, 673, 673, 673, 673, 673, 673, 64, 64, 64, 64, 64, 64, 64, 674, 674,
+ 674, 674, 64, 64, 64, 64, 675, 675, 675, 675, 675, 675, 675, 676, 676,
+ 676, 676, 676, 676, 676, 676, 676, 64, 64, 64, 64, 64, 64, 64, 677, 677,
+ 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 64, 678,
+ 679, 678, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680, 680,
+ 680, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679,
+ 679, 681, 682, 682, 682, 682, 682, 682, 682, 64, 64, 64, 64, 683, 683,
+ 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683, 683,
+ 683, 683, 683, 683, 684, 684, 684, 684, 684, 684, 684, 684, 684, 684, 64,
+ 64, 64, 64, 64, 64, 64, 681, 685, 685, 686, 687, 687, 687, 687, 687, 687,
+ 687, 687, 687, 687, 687, 687, 687, 686, 686, 686, 685, 685, 685, 685,
+ 686, 686, 688, 689, 690, 690, 691, 690, 690, 690, 690, 64, 64, 64, 64,
+ 64, 64, 692, 692, 692, 692, 692, 692, 692, 692, 692, 64, 64, 64, 64, 64,
+ 64, 64, 693, 693, 693, 693, 693, 693, 693, 693, 693, 693, 64, 64, 64, 64,
+ 64, 64, 694, 694, 694, 695, 695, 695, 695, 695, 695, 695, 695, 695, 695,
+ 695, 695, 695, 695, 695, 695, 695, 695, 695, 695, 696, 696, 696, 696,
+ 696, 697, 696, 696, 696, 696, 696, 696, 698, 698, 64, 699, 699, 699, 699,
+ 699, 699, 699, 699, 699, 699, 700, 700, 700, 700, 64, 64, 64, 64, 701,
+ 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 702, 703, 703, 701, 64,
+ 704, 704, 705, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706, 706,
+ 706, 706, 706, 706, 706, 705, 705, 705, 704, 704, 704, 704, 704, 704,
+ 704, 704, 704, 705, 707, 706, 706, 706, 706, 708, 708, 708, 708, 64, 64,
+ 64, 64, 708, 64, 64, 709, 709, 709, 709, 709, 709, 709, 709, 709, 709,
+ 706, 64, 64, 64, 64, 64, 64, 710, 710, 710, 710, 710, 710, 710, 710, 710,
+ 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 64, 64, 64, 711,
+ 711, 711, 711, 711, 711, 711, 711, 711, 711, 64, 711, 711, 711, 711, 711,
+ 711, 711, 711, 711, 712, 712, 712, 713, 713, 713, 712, 712, 713, 714,
+ 715, 713, 716, 716, 716, 716, 716, 716, 64, 64, 717, 717, 717, 717, 717,
+ 717, 717, 717, 717, 717, 717, 717, 717, 717, 717, 718, 719, 719, 719,
+ 718, 718, 718, 718, 718, 718, 720, 721, 64, 64, 64, 64, 64, 722, 722,
+ 722, 722, 722, 722, 722, 722, 722, 722, 64, 64, 64, 64, 64, 64, 64, 723,
+ 724, 724, 64, 725, 725, 725, 725, 725, 725, 725, 725, 64, 64, 725, 725,
+ 64, 64, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725, 725,
+ 725, 64, 725, 725, 725, 725, 725, 725, 725, 64, 725, 725, 64, 725, 725,
+ 725, 725, 725, 64, 64, 726, 725, 724, 724, 723, 724, 724, 724, 724, 64,
+ 64, 724, 724, 64, 64, 724, 724, 727, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 724, 64, 64, 64, 64, 64, 725, 725, 725, 725, 725, 724, 724, 64, 64, 728,
+ 728, 728, 728, 728, 728, 728, 64, 64, 64, 729, 729, 729, 729, 729, 729,
+ 729, 729, 730, 730, 730, 731, 731, 731, 731, 731, 731, 730, 731, 730,
+ 730, 730, 730, 731, 731, 730, 732, 733, 729, 729, 734, 729, 735, 735,
+ 735, 735, 735, 735, 735, 735, 735, 735, 64, 64, 64, 64, 64, 64, 736, 736,
+ 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 736, 737,
+ 737, 737, 738, 738, 738, 738, 64, 64, 737, 737, 737, 737, 738, 738, 737,
+ 739, 740, 741, 741, 741, 741, 741, 741, 741, 741, 741, 64, 64, 64, 64,
+ 64, 64, 742, 742, 742, 742, 742, 742, 742, 742, 743, 743, 743, 744, 744,
+ 744, 744, 744, 744, 744, 744, 743, 743, 744, 743, 745, 744, 746, 746,
+ 746, 742, 64, 64, 64, 747, 747, 747, 747, 747, 747, 747, 747, 747, 747,
+ 64, 64, 64, 64, 64, 64, 748, 748, 748, 748, 748, 748, 748, 748, 748, 748,
+ 748, 749, 750, 749, 750, 750, 749, 749, 749, 749, 749, 749, 751, 752,
+ 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 64, 64, 64, 64, 64, 64,
+ 754, 754, 754, 754, 754, 754, 754, 754, 755, 755, 755, 755, 755, 755,
+ 755, 755, 756, 756, 756, 756, 756, 756, 756, 756, 756, 756, 757, 757,
+ 757, 757, 757, 757, 757, 757, 757, 64, 64, 64, 64, 64, 64, 64, 64, 64,
+ 64, 64, 64, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 64, 64, 64,
+ 64, 64, 64, 64, 760, 760, 760, 760, 760, 760, 760, 760, 760, 64, 64, 64,
+ 64, 64, 64, 64, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761,
+ 761, 761, 761, 761, 64, 762, 762, 762, 762, 762, 64, 64, 64, 763, 763,
+ 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 763, 64, 512,
+ 64, 64, 64, 64, 64, 64, 64, 764, 764, 764, 764, 764, 764, 764, 764, 764,
+ 764, 764, 764, 764, 764, 764, 64, 765, 765, 765, 765, 765, 765, 765, 765,
+ 765, 765, 64, 64, 64, 64, 766, 766, 767, 767, 767, 767, 767, 767, 767,
+ 767, 767, 767, 767, 767, 767, 767, 64, 64, 768, 768, 768, 768, 768, 769,
+ 64, 64, 770, 770, 770, 770, 770, 770, 770, 770, 771, 771, 771, 771, 771,
+ 771, 771, 772, 772, 772, 772, 772, 773, 773, 773, 773, 774, 774, 774,
+ 774, 772, 773, 64, 64, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
+ 64, 776, 776, 776, 776, 776, 776, 776, 64, 770, 770, 770, 770, 770, 64,
+ 64, 64, 64, 64, 770, 770, 770, 777, 777, 777, 777, 777, 777, 777, 777,
+ 777, 777, 777, 777, 777, 64, 64, 64, 777, 778, 778, 778, 778, 778, 778,
+ 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778,
+ 778, 778, 64, 64, 64, 64, 64, 64, 64, 64, 779, 779, 779, 779, 780, 780,
+ 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 780, 486, 482, 64, 64,
+ 64, 64, 64, 64, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781,
+ 64, 64, 64, 64, 64, 781, 781, 781, 781, 781, 64, 64, 64, 781, 64, 64, 64,
+ 64, 64, 64, 64, 781, 781, 64, 64, 782, 783, 784, 785, 410, 410, 410, 410,
+ 64, 64, 64, 64, 277, 277, 277, 277, 277, 277, 64, 64, 277, 277, 277, 277,
+ 277, 277, 277, 64, 64, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 786, 786, 400, 400, 400, 277, 277, 277, 787, 786, 786, 786,
+ 786, 786, 410, 410, 410, 410, 410, 410, 410, 410, 136, 136, 136, 136,
+ 136, 136, 136, 136, 277, 277, 78, 78, 78, 78, 78, 136, 136, 277, 277,
+ 277, 277, 277, 277, 78, 78, 78, 78, 277, 277, 609, 609, 788, 788, 788,
+ 609, 64, 64, 522, 522, 64, 64, 64, 64, 64, 64, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 442, 442, 442,
+ 34, 34, 34, 34, 34, 34, 34, 64, 34, 34, 34, 34, 34, 34, 442, 64, 442,
+ 442, 64, 64, 442, 64, 64, 442, 442, 64, 64, 442, 442, 442, 442, 64, 442,
+ 442, 34, 34, 64, 34, 64, 34, 34, 34, 34, 34, 34, 34, 64, 34, 34, 34, 34,
+ 34, 34, 34, 442, 442, 64, 442, 442, 442, 442, 64, 64, 442, 442, 442, 442,
+ 442, 442, 442, 442, 64, 442, 442, 442, 442, 442, 442, 442, 64, 34, 34,
+ 442, 442, 64, 442, 442, 442, 442, 64, 442, 442, 442, 442, 442, 64, 442,
+ 64, 64, 64, 442, 442, 442, 442, 442, 442, 442, 64, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 64, 64, 442, 789, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 445, 34, 34, 34, 34, 34, 34, 442, 442, 442, 442, 442, 442, 442,
+ 442, 442, 789, 34, 34, 34, 34, 34, 34, 34, 34, 34, 445, 34, 34, 442, 442,
+ 442, 442, 442, 789, 34, 34, 34, 34, 34, 34, 34, 34, 34, 445, 34, 34, 34,
+ 34, 34, 34, 442, 442, 442, 442, 442, 442, 442, 442, 442, 789, 34, 445,
+ 34, 34, 34, 34, 34, 34, 34, 34, 442, 34, 64, 64, 790, 790, 790, 790, 790,
+ 790, 790, 790, 790, 790, 791, 791, 791, 791, 791, 791, 791, 791, 791,
+ 791, 791, 791, 791, 64, 64, 792, 792, 792, 792, 792, 792, 792, 792, 792,
+ 793, 793, 793, 793, 793, 793, 793, 64, 126, 126, 126, 126, 64, 126, 126,
+ 126, 64, 126, 126, 64, 126, 64, 64, 126, 64, 126, 126, 126, 126, 126,
+ 126, 126, 126, 126, 126, 64, 126, 126, 126, 126, 64, 126, 64, 126, 64,
+ 64, 64, 64, 64, 64, 126, 64, 64, 64, 64, 126, 64, 126, 64, 126, 64, 126,
+ 126, 126, 64, 126, 64, 126, 64, 126, 64, 126, 64, 126, 126, 126, 126, 64,
+ 126, 64, 126, 126, 64, 126, 126, 126, 126, 126, 126, 126, 126, 126, 64,
+ 64, 64, 64, 64, 126, 126, 126, 64, 126, 126, 126, 113, 113, 64, 64, 64,
+ 64, 64, 64, 64, 26, 26, 26, 26, 26, 26, 26, 33, 33, 33, 446, 446, 64, 64,
+ 64, 453, 453, 453, 453, 453, 453, 277, 64, 453, 453, 26, 26, 64, 64, 64,
+ 64, 453, 453, 453, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 277, 277,
+ 794, 489, 489, 64, 64, 64, 64, 64, 489, 489, 489, 64, 64, 64, 64, 64,
+ 489, 64, 64, 64, 64, 64, 64, 64, 489, 489, 64, 64, 64, 64, 64, 64, 26,
+ 26, 26, 26, 26, 64, 64, 64, 64, 64, 64, 64, 26, 26, 26, 26, 26, 26, 64,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 64, 26, 26, 26, 26, 26, 26, 64, 64,
+ 26, 26, 26, 497, 497, 497, 497, 497, 497, 496, 498, 498, 498, 498, 498,
+ 498, 498, 64, 64, 64, 410, 64, 64, 64, 64, 64, 64, 410, 410, 410, 410,
+ 410, 410, 410, 410, 568, 568, 568, 568, 568, 567, 64, 64,
+};
+
+/* decomposition data */
+static const unsigned short decomp_data[] = {
+ 0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514,
+ 32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52,
+ 772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512,
+ 65, 770, 512, 65, 771, 512, 65, 776, 512, 65, 778, 512, 67, 807, 512, 69,
+ 768, 512, 69, 769, 512, 69, 770, 512, 69, 776, 512, 73, 768, 512, 73,
+ 769, 512, 73, 770, 512, 73, 776, 512, 78, 771, 512, 79, 768, 512, 79,
+ 769, 512, 79, 770, 512, 79, 771, 512, 79, 776, 512, 85, 768, 512, 85,
+ 769, 512, 85, 770, 512, 85, 776, 512, 89, 769, 512, 97, 768, 512, 97,
+ 769, 512, 97, 770, 512, 97, 771, 512, 97, 776, 512, 97, 778, 512, 99,
+ 807, 512, 101, 768, 512, 101, 769, 512, 101, 770, 512, 101, 776, 512,
+ 105, 768, 512, 105, 769, 512, 105, 770, 512, 105, 776, 512, 110, 771,
+ 512, 111, 768, 512, 111, 769, 512, 111, 770, 512, 111, 771, 512, 111,
+ 776, 512, 117, 768, 512, 117, 769, 512, 117, 770, 512, 117, 776, 512,
+ 121, 769, 512, 121, 776, 512, 65, 772, 512, 97, 772, 512, 65, 774, 512,
+ 97, 774, 512, 65, 808, 512, 97, 808, 512, 67, 769, 512, 99, 769, 512, 67,
+ 770, 512, 99, 770, 512, 67, 775, 512, 99, 775, 512, 67, 780, 512, 99,
+ 780, 512, 68, 780, 512, 100, 780, 512, 69, 772, 512, 101, 772, 512, 69,
+ 774, 512, 101, 774, 512, 69, 775, 512, 101, 775, 512, 69, 808, 512, 101,
+ 808, 512, 69, 780, 512, 101, 780, 512, 71, 770, 512, 103, 770, 512, 71,
+ 774, 512, 103, 774, 512, 71, 775, 512, 103, 775, 512, 71, 807, 512, 103,
+ 807, 512, 72, 770, 512, 104, 770, 512, 73, 771, 512, 105, 771, 512, 73,
+ 772, 512, 105, 772, 512, 73, 774, 512, 105, 774, 512, 73, 808, 512, 105,
+ 808, 512, 73, 775, 514, 73, 74, 514, 105, 106, 512, 74, 770, 512, 106,
+ 770, 512, 75, 807, 512, 107, 807, 512, 76, 769, 512, 108, 769, 512, 76,
+ 807, 512, 108, 807, 512, 76, 780, 512, 108, 780, 514, 76, 183, 514, 108,
+ 183, 512, 78, 769, 512, 110, 769, 512, 78, 807, 512, 110, 807, 512, 78,
+ 780, 512, 110, 780, 514, 700, 110, 512, 79, 772, 512, 111, 772, 512, 79,
+ 774, 512, 111, 774, 512, 79, 779, 512, 111, 779, 512, 82, 769, 512, 114,
+ 769, 512, 82, 807, 512, 114, 807, 512, 82, 780, 512, 114, 780, 512, 83,
+ 769, 512, 115, 769, 512, 83, 770, 512, 115, 770, 512, 83, 807, 512, 115,
+ 807, 512, 83, 780, 512, 115, 780, 512, 84, 807, 512, 116, 807, 512, 84,
+ 780, 512, 116, 780, 512, 85, 771, 512, 117, 771, 512, 85, 772, 512, 117,
+ 772, 512, 85, 774, 512, 117, 774, 512, 85, 778, 512, 117, 778, 512, 85,
+ 779, 512, 117, 779, 512, 85, 808, 512, 117, 808, 512, 87, 770, 512, 119,
+ 770, 512, 89, 770, 512, 121, 770, 512, 89, 776, 512, 90, 769, 512, 122,
+ 769, 512, 90, 775, 512, 122, 775, 512, 90, 780, 512, 122, 780, 258, 115,
+ 512, 79, 795, 512, 111, 795, 512, 85, 795, 512, 117, 795, 514, 68, 381,
+ 514, 68, 382, 514, 100, 382, 514, 76, 74, 514, 76, 106, 514, 108, 106,
+ 514, 78, 74, 514, 78, 106, 514, 110, 106, 512, 65, 780, 512, 97, 780,
+ 512, 73, 780, 512, 105, 780, 512, 79, 780, 512, 111, 780, 512, 85, 780,
+ 512, 117, 780, 512, 220, 772, 512, 252, 772, 512, 220, 769, 512, 252,
+ 769, 512, 220, 780, 512, 252, 780, 512, 220, 768, 512, 252, 768, 512,
+ 196, 772, 512, 228, 772, 512, 550, 772, 512, 551, 772, 512, 198, 772,
+ 512, 230, 772, 512, 71, 780, 512, 103, 780, 512, 75, 780, 512, 107, 780,
+ 512, 79, 808, 512, 111, 808, 512, 490, 772, 512, 491, 772, 512, 439, 780,
+ 512, 658, 780, 512, 106, 780, 514, 68, 90, 514, 68, 122, 514, 100, 122,
+ 512, 71, 769, 512, 103, 769, 512, 78, 768, 512, 110, 768, 512, 197, 769,
+ 512, 229, 769, 512, 198, 769, 512, 230, 769, 512, 216, 769, 512, 248,
+ 769, 512, 65, 783, 512, 97, 783, 512, 65, 785, 512, 97, 785, 512, 69,
+ 783, 512, 101, 783, 512, 69, 785, 512, 101, 785, 512, 73, 783, 512, 105,
+ 783, 512, 73, 785, 512, 105, 785, 512, 79, 783, 512, 111, 783, 512, 79,
+ 785, 512, 111, 785, 512, 82, 783, 512, 114, 783, 512, 82, 785, 512, 114,
+ 785, 512, 85, 783, 512, 117, 783, 512, 85, 785, 512, 117, 785, 512, 83,
+ 806, 512, 115, 806, 512, 84, 806, 512, 116, 806, 512, 72, 780, 512, 104,
+ 780, 512, 65, 775, 512, 97, 775, 512, 69, 807, 512, 101, 807, 512, 214,
+ 772, 512, 246, 772, 512, 213, 772, 512, 245, 772, 512, 79, 775, 512, 111,
+ 775, 512, 558, 772, 512, 559, 772, 512, 89, 772, 512, 121, 772, 259, 104,
+ 259, 614, 259, 106, 259, 114, 259, 633, 259, 635, 259, 641, 259, 119,
+ 259, 121, 514, 32, 774, 514, 32, 775, 514, 32, 778, 514, 32, 808, 514,
+ 32, 771, 514, 32, 779, 259, 611, 259, 108, 259, 115, 259, 120, 259, 661,
+ 256, 768, 256, 769, 256, 787, 512, 776, 769, 256, 697, 514, 32, 837, 256,
+ 59, 514, 32, 769, 512, 168, 769, 512, 913, 769, 256, 183, 512, 917, 769,
+ 512, 919, 769, 512, 921, 769, 512, 927, 769, 512, 933, 769, 512, 937,
+ 769, 512, 970, 769, 512, 921, 776, 512, 933, 776, 512, 945, 769, 512,
+ 949, 769, 512, 951, 769, 512, 953, 769, 512, 971, 769, 512, 953, 776,
+ 512, 965, 776, 512, 959, 769, 512, 965, 769, 512, 969, 769, 258, 946,
+ 258, 952, 258, 933, 512, 978, 769, 512, 978, 776, 258, 966, 258, 960,
+ 258, 954, 258, 961, 258, 962, 258, 920, 258, 949, 258, 931, 512, 1045,
+ 768, 512, 1045, 776, 512, 1043, 769, 512, 1030, 776, 512, 1050, 769, 512,
+ 1048, 768, 512, 1059, 774, 512, 1048, 774, 512, 1080, 774, 512, 1077,
+ 768, 512, 1077, 776, 512, 1075, 769, 512, 1110, 776, 512, 1082, 769, 512,
+ 1080, 768, 512, 1091, 774, 512, 1140, 783, 512, 1141, 783, 512, 1046,
+ 774, 512, 1078, 774, 512, 1040, 774, 512, 1072, 774, 512, 1040, 776, 512,
+ 1072, 776, 512, 1045, 774, 512, 1077, 774, 512, 1240, 776, 512, 1241,
+ 776, 512, 1046, 776, 512, 1078, 776, 512, 1047, 776, 512, 1079, 776, 512,
+ 1048, 772, 512, 1080, 772, 512, 1048, 776, 512, 1080, 776, 512, 1054,
+ 776, 512, 1086, 776, 512, 1256, 776, 512, 1257, 776, 512, 1069, 776, 512,
+ 1101, 776, 512, 1059, 772, 512, 1091, 772, 512, 1059, 776, 512, 1091,
+ 776, 512, 1059, 779, 512, 1091, 779, 512, 1063, 776, 512, 1095, 776, 512,
+ 1067, 776, 512, 1099, 776, 514, 1381, 1410, 512, 1575, 1619, 512, 1575,
+ 1620, 512, 1608, 1620, 512, 1575, 1621, 512, 1610, 1620, 514, 1575, 1652,
+ 514, 1608, 1652, 514, 1735, 1652, 514, 1610, 1652, 512, 1749, 1620, 512,
+ 1729, 1620, 512, 1746, 1620, 512, 2344, 2364, 512, 2352, 2364, 512, 2355,
+ 2364, 512, 2325, 2364, 512, 2326, 2364, 512, 2327, 2364, 512, 2332, 2364,
+ 512, 2337, 2364, 512, 2338, 2364, 512, 2347, 2364, 512, 2351, 2364, 512,
+ 2503, 2494, 512, 2503, 2519, 512, 2465, 2492, 512, 2466, 2492, 512, 2479,
+ 2492, 512, 2610, 2620, 512, 2616, 2620, 512, 2582, 2620, 512, 2583, 2620,
+ 512, 2588, 2620, 512, 2603, 2620, 512, 2887, 2902, 512, 2887, 2878, 512,
+ 2887, 2903, 512, 2849, 2876, 512, 2850, 2876, 512, 2962, 3031, 512, 3014,
+ 3006, 512, 3015, 3006, 512, 3014, 3031, 512, 3142, 3158, 512, 3263, 3285,
+ 512, 3270, 3285, 512, 3270, 3286, 512, 3270, 3266, 512, 3274, 3285, 512,
+ 3398, 3390, 512, 3399, 3390, 512, 3398, 3415, 512, 3545, 3530, 512, 3545,
+ 3535, 512, 3548, 3530, 512, 3545, 3551, 514, 3661, 3634, 514, 3789, 3762,
+ 514, 3755, 3737, 514, 3755, 3745, 257, 3851, 512, 3906, 4023, 512, 3916,
+ 4023, 512, 3921, 4023, 512, 3926, 4023, 512, 3931, 4023, 512, 3904, 4021,
+ 512, 3953, 3954, 512, 3953, 3956, 512, 4018, 3968, 514, 4018, 3969, 512,
+ 4019, 3968, 514, 4019, 3969, 512, 3953, 3968, 512, 3986, 4023, 512, 3996,
+ 4023, 512, 4001, 4023, 512, 4006, 4023, 512, 4011, 4023, 512, 3984, 4021,
+ 512, 4133, 4142, 259, 4316, 512, 6917, 6965, 512, 6919, 6965, 512, 6921,
+ 6965, 512, 6923, 6965, 512, 6925, 6965, 512, 6929, 6965, 512, 6970, 6965,
+ 512, 6972, 6965, 512, 6974, 6965, 512, 6975, 6965, 512, 6978, 6965, 259,
+ 65, 259, 198, 259, 66, 259, 68, 259, 69, 259, 398, 259, 71, 259, 72, 259,
+ 73, 259, 74, 259, 75, 259, 76, 259, 77, 259, 78, 259, 79, 259, 546, 259,
+ 80, 259, 82, 259, 84, 259, 85, 259, 87, 259, 97, 259, 592, 259, 593, 259,
+ 7426, 259, 98, 259, 100, 259, 101, 259, 601, 259, 603, 259, 604, 259,
+ 103, 259, 107, 259, 109, 259, 331, 259, 111, 259, 596, 259, 7446, 259,
+ 7447, 259, 112, 259, 116, 259, 117, 259, 7453, 259, 623, 259, 118, 259,
+ 7461, 259, 946, 259, 947, 259, 948, 259, 966, 259, 967, 261, 105, 261,
+ 114, 261, 117, 261, 118, 261, 946, 261, 947, 261, 961, 261, 966, 261,
+ 967, 259, 1085, 259, 594, 259, 99, 259, 597, 259, 240, 259, 604, 259,
+ 102, 259, 607, 259, 609, 259, 613, 259, 616, 259, 617, 259, 618, 259,
+ 7547, 259, 669, 259, 621, 259, 7557, 259, 671, 259, 625, 259, 624, 259,
+ 626, 259, 627, 259, 628, 259, 629, 259, 632, 259, 642, 259, 643, 259,
+ 427, 259, 649, 259, 650, 259, 7452, 259, 651, 259, 652, 259, 122, 259,
+ 656, 259, 657, 259, 658, 259, 952, 512, 65, 805, 512, 97, 805, 512, 66,
+ 775, 512, 98, 775, 512, 66, 803, 512, 98, 803, 512, 66, 817, 512, 98,
+ 817, 512, 199, 769, 512, 231, 769, 512, 68, 775, 512, 100, 775, 512, 68,
+ 803, 512, 100, 803, 512, 68, 817, 512, 100, 817, 512, 68, 807, 512, 100,
+ 807, 512, 68, 813, 512, 100, 813, 512, 274, 768, 512, 275, 768, 512, 274,
+ 769, 512, 275, 769, 512, 69, 813, 512, 101, 813, 512, 69, 816, 512, 101,
+ 816, 512, 552, 774, 512, 553, 774, 512, 70, 775, 512, 102, 775, 512, 71,
+ 772, 512, 103, 772, 512, 72, 775, 512, 104, 775, 512, 72, 803, 512, 104,
+ 803, 512, 72, 776, 512, 104, 776, 512, 72, 807, 512, 104, 807, 512, 72,
+ 814, 512, 104, 814, 512, 73, 816, 512, 105, 816, 512, 207, 769, 512, 239,
+ 769, 512, 75, 769, 512, 107, 769, 512, 75, 803, 512, 107, 803, 512, 75,
+ 817, 512, 107, 817, 512, 76, 803, 512, 108, 803, 512, 7734, 772, 512,
+ 7735, 772, 512, 76, 817, 512, 108, 817, 512, 76, 813, 512, 108, 813, 512,
+ 77, 769, 512, 109, 769, 512, 77, 775, 512, 109, 775, 512, 77, 803, 512,
+ 109, 803, 512, 78, 775, 512, 110, 775, 512, 78, 803, 512, 110, 803, 512,
+ 78, 817, 512, 110, 817, 512, 78, 813, 512, 110, 813, 512, 213, 769, 512,
+ 245, 769, 512, 213, 776, 512, 245, 776, 512, 332, 768, 512, 333, 768,
+ 512, 332, 769, 512, 333, 769, 512, 80, 769, 512, 112, 769, 512, 80, 775,
+ 512, 112, 775, 512, 82, 775, 512, 114, 775, 512, 82, 803, 512, 114, 803,
+ 512, 7770, 772, 512, 7771, 772, 512, 82, 817, 512, 114, 817, 512, 83,
+ 775, 512, 115, 775, 512, 83, 803, 512, 115, 803, 512, 346, 775, 512, 347,
+ 775, 512, 352, 775, 512, 353, 775, 512, 7778, 775, 512, 7779, 775, 512,
+ 84, 775, 512, 116, 775, 512, 84, 803, 512, 116, 803, 512, 84, 817, 512,
+ 116, 817, 512, 84, 813, 512, 116, 813, 512, 85, 804, 512, 117, 804, 512,
+ 85, 816, 512, 117, 816, 512, 85, 813, 512, 117, 813, 512, 360, 769, 512,
+ 361, 769, 512, 362, 776, 512, 363, 776, 512, 86, 771, 512, 118, 771, 512,
+ 86, 803, 512, 118, 803, 512, 87, 768, 512, 119, 768, 512, 87, 769, 512,
+ 119, 769, 512, 87, 776, 512, 119, 776, 512, 87, 775, 512, 119, 775, 512,
+ 87, 803, 512, 119, 803, 512, 88, 775, 512, 120, 775, 512, 88, 776, 512,
+ 120, 776, 512, 89, 775, 512, 121, 775, 512, 90, 770, 512, 122, 770, 512,
+ 90, 803, 512, 122, 803, 512, 90, 817, 512, 122, 817, 512, 104, 817, 512,
+ 116, 776, 512, 119, 778, 512, 121, 778, 514, 97, 702, 512, 383, 775, 512,
+ 65, 803, 512, 97, 803, 512, 65, 777, 512, 97, 777, 512, 194, 769, 512,
+ 226, 769, 512, 194, 768, 512, 226, 768, 512, 194, 777, 512, 226, 777,
+ 512, 194, 771, 512, 226, 771, 512, 7840, 770, 512, 7841, 770, 512, 258,
+ 769, 512, 259, 769, 512, 258, 768, 512, 259, 768, 512, 258, 777, 512,
+ 259, 777, 512, 258, 771, 512, 259, 771, 512, 7840, 774, 512, 7841, 774,
+ 512, 69, 803, 512, 101, 803, 512, 69, 777, 512, 101, 777, 512, 69, 771,
+ 512, 101, 771, 512, 202, 769, 512, 234, 769, 512, 202, 768, 512, 234,
+ 768, 512, 202, 777, 512, 234, 777, 512, 202, 771, 512, 234, 771, 512,
+ 7864, 770, 512, 7865, 770, 512, 73, 777, 512, 105, 777, 512, 73, 803,
+ 512, 105, 803, 512, 79, 803, 512, 111, 803, 512, 79, 777, 512, 111, 777,
+ 512, 212, 769, 512, 244, 769, 512, 212, 768, 512, 244, 768, 512, 212,
+ 777, 512, 244, 777, 512, 212, 771, 512, 244, 771, 512, 7884, 770, 512,
+ 7885, 770, 512, 416, 769, 512, 417, 769, 512, 416, 768, 512, 417, 768,
+ 512, 416, 777, 512, 417, 777, 512, 416, 771, 512, 417, 771, 512, 416,
+ 803, 512, 417, 803, 512, 85, 803, 512, 117, 803, 512, 85, 777, 512, 117,
+ 777, 512, 431, 769, 512, 432, 769, 512, 431, 768, 512, 432, 768, 512,
+ 431, 777, 512, 432, 777, 512, 431, 771, 512, 432, 771, 512, 431, 803,
+ 512, 432, 803, 512, 89, 768, 512, 121, 768, 512, 89, 803, 512, 121, 803,
+ 512, 89, 777, 512, 121, 777, 512, 89, 771, 512, 121, 771, 512, 945, 787,
+ 512, 945, 788, 512, 7936, 768, 512, 7937, 768, 512, 7936, 769, 512, 7937,
+ 769, 512, 7936, 834, 512, 7937, 834, 512, 913, 787, 512, 913, 788, 512,
+ 7944, 768, 512, 7945, 768, 512, 7944, 769, 512, 7945, 769, 512, 7944,
+ 834, 512, 7945, 834, 512, 949, 787, 512, 949, 788, 512, 7952, 768, 512,
+ 7953, 768, 512, 7952, 769, 512, 7953, 769, 512, 917, 787, 512, 917, 788,
+ 512, 7960, 768, 512, 7961, 768, 512, 7960, 769, 512, 7961, 769, 512, 951,
+ 787, 512, 951, 788, 512, 7968, 768, 512, 7969, 768, 512, 7968, 769, 512,
+ 7969, 769, 512, 7968, 834, 512, 7969, 834, 512, 919, 787, 512, 919, 788,
+ 512, 7976, 768, 512, 7977, 768, 512, 7976, 769, 512, 7977, 769, 512,
+ 7976, 834, 512, 7977, 834, 512, 953, 787, 512, 953, 788, 512, 7984, 768,
+ 512, 7985, 768, 512, 7984, 769, 512, 7985, 769, 512, 7984, 834, 512,
+ 7985, 834, 512, 921, 787, 512, 921, 788, 512, 7992, 768, 512, 7993, 768,
+ 512, 7992, 769, 512, 7993, 769, 512, 7992, 834, 512, 7993, 834, 512, 959,
+ 787, 512, 959, 788, 512, 8000, 768, 512, 8001, 768, 512, 8000, 769, 512,
+ 8001, 769, 512, 927, 787, 512, 927, 788, 512, 8008, 768, 512, 8009, 768,
+ 512, 8008, 769, 512, 8009, 769, 512, 965, 787, 512, 965, 788, 512, 8016,
+ 768, 512, 8017, 768, 512, 8016, 769, 512, 8017, 769, 512, 8016, 834, 512,
+ 8017, 834, 512, 933, 788, 512, 8025, 768, 512, 8025, 769, 512, 8025, 834,
+ 512, 969, 787, 512, 969, 788, 512, 8032, 768, 512, 8033, 768, 512, 8032,
+ 769, 512, 8033, 769, 512, 8032, 834, 512, 8033, 834, 512, 937, 787, 512,
+ 937, 788, 512, 8040, 768, 512, 8041, 768, 512, 8040, 769, 512, 8041, 769,
+ 512, 8040, 834, 512, 8041, 834, 512, 945, 768, 256, 940, 512, 949, 768,
+ 256, 941, 512, 951, 768, 256, 942, 512, 953, 768, 256, 943, 512, 959,
+ 768, 256, 972, 512, 965, 768, 256, 973, 512, 969, 768, 256, 974, 512,
+ 7936, 837, 512, 7937, 837, 512, 7938, 837, 512, 7939, 837, 512, 7940,
+ 837, 512, 7941, 837, 512, 7942, 837, 512, 7943, 837, 512, 7944, 837, 512,
+ 7945, 837, 512, 7946, 837, 512, 7947, 837, 512, 7948, 837, 512, 7949,
+ 837, 512, 7950, 837, 512, 7951, 837, 512, 7968, 837, 512, 7969, 837, 512,
+ 7970, 837, 512, 7971, 837, 512, 7972, 837, 512, 7973, 837, 512, 7974,
+ 837, 512, 7975, 837, 512, 7976, 837, 512, 7977, 837, 512, 7978, 837, 512,
+ 7979, 837, 512, 7980, 837, 512, 7981, 837, 512, 7982, 837, 512, 7983,
+ 837, 512, 8032, 837, 512, 8033, 837, 512, 8034, 837, 512, 8035, 837, 512,
+ 8036, 837, 512, 8037, 837, 512, 8038, 837, 512, 8039, 837, 512, 8040,
+ 837, 512, 8041, 837, 512, 8042, 837, 512, 8043, 837, 512, 8044, 837, 512,
+ 8045, 837, 512, 8046, 837, 512, 8047, 837, 512, 945, 774, 512, 945, 772,
+ 512, 8048, 837, 512, 945, 837, 512, 940, 837, 512, 945, 834, 512, 8118,
+ 837, 512, 913, 774, 512, 913, 772, 512, 913, 768, 256, 902, 512, 913,
+ 837, 514, 32, 787, 256, 953, 514, 32, 787, 514, 32, 834, 512, 168, 834,
+ 512, 8052, 837, 512, 951, 837, 512, 942, 837, 512, 951, 834, 512, 8134,
+ 837, 512, 917, 768, 256, 904, 512, 919, 768, 256, 905, 512, 919, 837,
+ 512, 8127, 768, 512, 8127, 769, 512, 8127, 834, 512, 953, 774, 512, 953,
+ 772, 512, 970, 768, 256, 912, 512, 953, 834, 512, 970, 834, 512, 921,
+ 774, 512, 921, 772, 512, 921, 768, 256, 906, 512, 8190, 768, 512, 8190,
+ 769, 512, 8190, 834, 512, 965, 774, 512, 965, 772, 512, 971, 768, 256,
+ 944, 512, 961, 787, 512, 961, 788, 512, 965, 834, 512, 971, 834, 512,
+ 933, 774, 512, 933, 772, 512, 933, 768, 256, 910, 512, 929, 788, 512,
+ 168, 768, 256, 901, 256, 96, 512, 8060, 837, 512, 969, 837, 512, 974,
+ 837, 512, 969, 834, 512, 8182, 837, 512, 927, 768, 256, 908, 512, 937,
+ 768, 256, 911, 512, 937, 837, 256, 180, 514, 32, 788, 256, 8194, 256,
+ 8195, 258, 32, 258, 32, 258, 32, 258, 32, 258, 32, 257, 32, 258, 32, 258,
+ 32, 258, 32, 257, 8208, 514, 32, 819, 258, 46, 514, 46, 46, 770, 46, 46,
+ 46, 257, 32, 514, 8242, 8242, 770, 8242, 8242, 8242, 514, 8245, 8245,
+ 770, 8245, 8245, 8245, 514, 33, 33, 514, 32, 773, 514, 63, 63, 514, 63,
+ 33, 514, 33, 63, 1026, 8242, 8242, 8242, 8242, 258, 32, 259, 48, 259,
+ 105, 259, 52, 259, 53, 259, 54, 259, 55, 259, 56, 259, 57, 259, 43, 259,
+ 8722, 259, 61, 259, 40, 259, 41, 259, 110, 261, 48, 261, 49, 261, 50,
+ 261, 51, 261, 52, 261, 53, 261, 54, 261, 55, 261, 56, 261, 57, 261, 43,
+ 261, 8722, 261, 61, 261, 40, 261, 41, 261, 97, 261, 101, 261, 111, 261,
+ 120, 261, 601, 261, 104, 261, 107, 261, 108, 261, 109, 261, 110, 261,
+ 112, 261, 115, 261, 116, 514, 82, 115, 770, 97, 47, 99, 770, 97, 47, 115,
+ 262, 67, 514, 176, 67, 770, 99, 47, 111, 770, 99, 47, 117, 258, 400, 514,
+ 176, 70, 262, 103, 262, 72, 262, 72, 262, 72, 262, 104, 262, 295, 262,
+ 73, 262, 73, 262, 76, 262, 108, 262, 78, 514, 78, 111, 262, 80, 262, 81,
+ 262, 82, 262, 82, 262, 82, 515, 83, 77, 770, 84, 69, 76, 515, 84, 77,
+ 262, 90, 256, 937, 262, 90, 256, 75, 256, 197, 262, 66, 262, 67, 262,
+ 101, 262, 69, 262, 70, 262, 77, 262, 111, 258, 1488, 258, 1489, 258,
+ 1490, 258, 1491, 262, 105, 770, 70, 65, 88, 262, 960, 262, 947, 262, 915,
+ 262, 928, 262, 8721, 262, 68, 262, 100, 262, 101, 262, 105, 262, 106,
+ 772, 49, 8260, 55, 772, 49, 8260, 57, 1028, 49, 8260, 49, 48, 772, 49,
+ 8260, 51, 772, 50, 8260, 51, 772, 49, 8260, 53, 772, 50, 8260, 53, 772,
+ 51, 8260, 53, 772, 52, 8260, 53, 772, 49, 8260, 54, 772, 53, 8260, 54,
+ 772, 49, 8260, 56, 772, 51, 8260, 56, 772, 53, 8260, 56, 772, 55, 8260,
+ 56, 516, 49, 8260, 258, 73, 514, 73, 73, 770, 73, 73, 73, 514, 73, 86,
+ 258, 86, 514, 86, 73, 770, 86, 73, 73, 1026, 86, 73, 73, 73, 514, 73, 88,
+ 258, 88, 514, 88, 73, 770, 88, 73, 73, 258, 76, 258, 67, 258, 68, 258,
+ 77, 258, 105, 514, 105, 105, 770, 105, 105, 105, 514, 105, 118, 258, 118,
+ 514, 118, 105, 770, 118, 105, 105, 1026, 118, 105, 105, 105, 514, 105,
+ 120, 258, 120, 514, 120, 105, 770, 120, 105, 105, 258, 108, 258, 99, 258,
+ 100, 258, 109, 772, 48, 8260, 51, 512, 8592, 824, 512, 8594, 824, 512,
+ 8596, 824, 512, 8656, 824, 512, 8660, 824, 512, 8658, 824, 512, 8707,
+ 824, 512, 8712, 824, 512, 8715, 824, 512, 8739, 824, 512, 8741, 824, 514,
+ 8747, 8747, 770, 8747, 8747, 8747, 514, 8750, 8750, 770, 8750, 8750,
+ 8750, 512, 8764, 824, 512, 8771, 824, 512, 8773, 824, 512, 8776, 824,
+ 512, 61, 824, 512, 8801, 824, 512, 8781, 824, 512, 60, 824, 512, 62, 824,
+ 512, 8804, 824, 512, 8805, 824, 512, 8818, 824, 512, 8819, 824, 512,
+ 8822, 824, 512, 8823, 824, 512, 8826, 824, 512, 8827, 824, 512, 8834,
+ 824, 512, 8835, 824, 512, 8838, 824, 512, 8839, 824, 512, 8866, 824, 512,
+ 8872, 824, 512, 8873, 824, 512, 8875, 824, 512, 8828, 824, 512, 8829,
+ 824, 512, 8849, 824, 512, 8850, 824, 512, 8882, 824, 512, 8883, 824, 512,
+ 8884, 824, 512, 8885, 824, 256, 12296, 256, 12297, 263, 49, 263, 50, 263,
+ 51, 263, 52, 263, 53, 263, 54, 263, 55, 263, 56, 263, 57, 519, 49, 48,
+ 519, 49, 49, 519, 49, 50, 519, 49, 51, 519, 49, 52, 519, 49, 53, 519, 49,
+ 54, 519, 49, 55, 519, 49, 56, 519, 49, 57, 519, 50, 48, 770, 40, 49, 41,
+ 770, 40, 50, 41, 770, 40, 51, 41, 770, 40, 52, 41, 770, 40, 53, 41, 770,
+ 40, 54, 41, 770, 40, 55, 41, 770, 40, 56, 41, 770, 40, 57, 41, 1026, 40,
+ 49, 48, 41, 1026, 40, 49, 49, 41, 1026, 40, 49, 50, 41, 1026, 40, 49, 51,
+ 41, 1026, 40, 49, 52, 41, 1026, 40, 49, 53, 41, 1026, 40, 49, 54, 41,
+ 1026, 40, 49, 55, 41, 1026, 40, 49, 56, 41, 1026, 40, 49, 57, 41, 1026,
+ 40, 50, 48, 41, 514, 49, 46, 514, 50, 46, 514, 51, 46, 514, 52, 46, 514,
+ 53, 46, 514, 54, 46, 514, 55, 46, 514, 56, 46, 514, 57, 46, 770, 49, 48,
+ 46, 770, 49, 49, 46, 770, 49, 50, 46, 770, 49, 51, 46, 770, 49, 52, 46,
+ 770, 49, 53, 46, 770, 49, 54, 46, 770, 49, 55, 46, 770, 49, 56, 46, 770,
+ 49, 57, 46, 770, 50, 48, 46, 770, 40, 97, 41, 770, 40, 98, 41, 770, 40,
+ 99, 41, 770, 40, 100, 41, 770, 40, 101, 41, 770, 40, 102, 41, 770, 40,
+ 103, 41, 770, 40, 104, 41, 770, 40, 105, 41, 770, 40, 106, 41, 770, 40,
+ 107, 41, 770, 40, 108, 41, 770, 40, 109, 41, 770, 40, 110, 41, 770, 40,
+ 111, 41, 770, 40, 112, 41, 770, 40, 113, 41, 770, 40, 114, 41, 770, 40,
+ 115, 41, 770, 40, 116, 41, 770, 40, 117, 41, 770, 40, 118, 41, 770, 40,
+ 119, 41, 770, 40, 120, 41, 770, 40, 121, 41, 770, 40, 122, 41, 263, 65,
+ 263, 66, 263, 67, 263, 68, 263, 69, 263, 70, 263, 71, 263, 72, 263, 73,
+ 263, 74, 263, 75, 263, 76, 263, 77, 263, 78, 263, 79, 263, 80, 263, 81,
+ 263, 82, 263, 83, 263, 84, 263, 85, 263, 86, 263, 87, 263, 88, 263, 89,
+ 263, 90, 263, 97, 263, 98, 263, 99, 263, 100, 263, 101, 263, 102, 263,
+ 103, 263, 104, 263, 105, 263, 106, 263, 107, 263, 108, 263, 109, 263,
+ 110, 263, 111, 263, 112, 263, 113, 263, 114, 263, 115, 263, 116, 263,
+ 117, 263, 118, 263, 119, 263, 120, 263, 121, 263, 122, 263, 48, 1026,
+ 8747, 8747, 8747, 8747, 770, 58, 58, 61, 514, 61, 61, 770, 61, 61, 61,
+ 512, 10973, 824, 261, 106, 259, 86, 259, 11617, 258, 27597, 258, 40863,
+ 258, 19968, 258, 20008, 258, 20022, 258, 20031, 258, 20057, 258, 20101,
+ 258, 20108, 258, 20128, 258, 20154, 258, 20799, 258, 20837, 258, 20843,
+ 258, 20866, 258, 20886, 258, 20907, 258, 20960, 258, 20981, 258, 20992,
+ 258, 21147, 258, 21241, 258, 21269, 258, 21274, 258, 21304, 258, 21313,
+ 258, 21340, 258, 21353, 258, 21378, 258, 21430, 258, 21448, 258, 21475,
+ 258, 22231, 258, 22303, 258, 22763, 258, 22786, 258, 22794, 258, 22805,
+ 258, 22823, 258, 22899, 258, 23376, 258, 23424, 258, 23544, 258, 23567,
+ 258, 23586, 258, 23608, 258, 23662, 258, 23665, 258, 24027, 258, 24037,
+ 258, 24049, 258, 24062, 258, 24178, 258, 24186, 258, 24191, 258, 24308,
+ 258, 24318, 258, 24331, 258, 24339, 258, 24400, 258, 24417, 258, 24435,
+ 258, 24515, 258, 25096, 258, 25142, 258, 25163, 258, 25903, 258, 25908,
+ 258, 25991, 258, 26007, 258, 26020, 258, 26041, 258, 26080, 258, 26085,
+ 258, 26352, 258, 26376, 258, 26408, 258, 27424, 258, 27490, 258, 27513,
+ 258, 27571, 258, 27595, 258, 27604, 258, 27611, 258, 27663, 258, 27668,
+ 258, 27700, 258, 28779, 258, 29226, 258, 29238, 258, 29243, 258, 29247,
+ 258, 29255, 258, 29273, 258, 29275, 258, 29356, 258, 29572, 258, 29577,
+ 258, 29916, 258, 29926, 258, 29976, 258, 29983, 258, 29992, 258, 30000,
+ 258, 30091, 258, 30098, 258, 30326, 258, 30333, 258, 30382, 258, 30399,
+ 258, 30446, 258, 30683, 258, 30690, 258, 30707, 258, 31034, 258, 31160,
+ 258, 31166, 258, 31348, 258, 31435, 258, 31481, 258, 31859, 258, 31992,
+ 258, 32566, 258, 32593, 258, 32650, 258, 32701, 258, 32769, 258, 32780,
+ 258, 32786, 258, 32819, 258, 32895, 258, 32905, 258, 33251, 258, 33258,
+ 258, 33267, 258, 33276, 258, 33292, 258, 33307, 258, 33311, 258, 33390,
+ 258, 33394, 258, 33400, 258, 34381, 258, 34411, 258, 34880, 258, 34892,
+ 258, 34915, 258, 35198, 258, 35211, 258, 35282, 258, 35328, 258, 35895,
+ 258, 35910, 258, 35925, 258, 35960, 258, 35997, 258, 36196, 258, 36208,
+ 258, 36275, 258, 36523, 258, 36554, 258, 36763, 258, 36784, 258, 36789,
+ 258, 37009, 258, 37193, 258, 37318, 258, 37324, 258, 37329, 258, 38263,
+ 258, 38272, 258, 38428, 258, 38582, 258, 38585, 258, 38632, 258, 38737,
+ 258, 38750, 258, 38754, 258, 38761, 258, 38859, 258, 38893, 258, 38899,
+ 258, 38913, 258, 39080, 258, 39131, 258, 39135, 258, 39318, 258, 39321,
+ 258, 39340, 258, 39592, 258, 39640, 258, 39647, 258, 39717, 258, 39727,
+ 258, 39730, 258, 39740, 258, 39770, 258, 40165, 258, 40565, 258, 40575,
+ 258, 40613, 258, 40635, 258, 40643, 258, 40653, 258, 40657, 258, 40697,
+ 258, 40701, 258, 40718, 258, 40723, 258, 40736, 258, 40763, 258, 40778,
+ 258, 40786, 258, 40845, 258, 40860, 258, 40864, 264, 32, 258, 12306, 258,
+ 21313, 258, 21316, 258, 21317, 512, 12363, 12441, 512, 12365, 12441, 512,
+ 12367, 12441, 512, 12369, 12441, 512, 12371, 12441, 512, 12373, 12441,
+ 512, 12375, 12441, 512, 12377, 12441, 512, 12379, 12441, 512, 12381,
+ 12441, 512, 12383, 12441, 512, 12385, 12441, 512, 12388, 12441, 512,
+ 12390, 12441, 512, 12392, 12441, 512, 12399, 12441, 512, 12399, 12442,
+ 512, 12402, 12441, 512, 12402, 12442, 512, 12405, 12441, 512, 12405,
+ 12442, 512, 12408, 12441, 512, 12408, 12442, 512, 12411, 12441, 512,
+ 12411, 12442, 512, 12358, 12441, 514, 32, 12441, 514, 32, 12442, 512,
+ 12445, 12441, 521, 12424, 12426, 512, 12459, 12441, 512, 12461, 12441,
+ 512, 12463, 12441, 512, 12465, 12441, 512, 12467, 12441, 512, 12469,
+ 12441, 512, 12471, 12441, 512, 12473, 12441, 512, 12475, 12441, 512,
+ 12477, 12441, 512, 12479, 12441, 512, 12481, 12441, 512, 12484, 12441,
+ 512, 12486, 12441, 512, 12488, 12441, 512, 12495, 12441, 512, 12495,
+ 12442, 512, 12498, 12441, 512, 12498, 12442, 512, 12501, 12441, 512,
+ 12501, 12442, 512, 12504, 12441, 512, 12504, 12442, 512, 12507, 12441,
+ 512, 12507, 12442, 512, 12454, 12441, 512, 12527, 12441, 512, 12528,
+ 12441, 512, 12529, 12441, 512, 12530, 12441, 512, 12541, 12441, 521,
+ 12467, 12488, 258, 4352, 258, 4353, 258, 4522, 258, 4354, 258, 4524, 258,
+ 4525, 258, 4355, 258, 4356, 258, 4357, 258, 4528, 258, 4529, 258, 4530,
+ 258, 4531, 258, 4532, 258, 4533, 258, 4378, 258, 4358, 258, 4359, 258,
+ 4360, 258, 4385, 258, 4361, 258, 4362, 258, 4363, 258, 4364, 258, 4365,
+ 258, 4366, 258, 4367, 258, 4368, 258, 4369, 258, 4370, 258, 4449, 258,
+ 4450, 258, 4451, 258, 4452, 258, 4453, 258, 4454, 258, 4455, 258, 4456,
+ 258, 4457, 258, 4458, 258, 4459, 258, 4460, 258, 4461, 258, 4462, 258,
+ 4463, 258, 4464, 258, 4465, 258, 4466, 258, 4467, 258, 4468, 258, 4469,
+ 258, 4448, 258, 4372, 258, 4373, 258, 4551, 258, 4552, 258, 4556, 258,
+ 4558, 258, 4563, 258, 4567, 258, 4569, 258, 4380, 258, 4573, 258, 4575,
+ 258, 4381, 258, 4382, 258, 4384, 258, 4386, 258, 4387, 258, 4391, 258,
+ 4393, 258, 4395, 258, 4396, 258, 4397, 258, 4398, 258, 4399, 258, 4402,
+ 258, 4406, 258, 4416, 258, 4423, 258, 4428, 258, 4593, 258, 4594, 258,
+ 4439, 258, 4440, 258, 4441, 258, 4484, 258, 4485, 258, 4488, 258, 4497,
+ 258, 4498, 258, 4500, 258, 4510, 258, 4513, 259, 19968, 259, 20108, 259,
+ 19977, 259, 22235, 259, 19978, 259, 20013, 259, 19979, 259, 30002, 259,
+ 20057, 259, 19993, 259, 19969, 259, 22825, 259, 22320, 259, 20154, 770,
+ 40, 4352, 41, 770, 40, 4354, 41, 770, 40, 4355, 41, 770, 40, 4357, 41,
+ 770, 40, 4358, 41, 770, 40, 4359, 41, 770, 40, 4361, 41, 770, 40, 4363,
+ 41, 770, 40, 4364, 41, 770, 40, 4366, 41, 770, 40, 4367, 41, 770, 40,
+ 4368, 41, 770, 40, 4369, 41, 770, 40, 4370, 41, 1026, 40, 4352, 4449, 41,
+ 1026, 40, 4354, 4449, 41, 1026, 40, 4355, 4449, 41, 1026, 40, 4357, 4449,
+ 41, 1026, 40, 4358, 4449, 41, 1026, 40, 4359, 4449, 41, 1026, 40, 4361,
+ 4449, 41, 1026, 40, 4363, 4449, 41, 1026, 40, 4364, 4449, 41, 1026, 40,
+ 4366, 4449, 41, 1026, 40, 4367, 4449, 41, 1026, 40, 4368, 4449, 41, 1026,
+ 40, 4369, 4449, 41, 1026, 40, 4370, 4449, 41, 1026, 40, 4364, 4462, 41,
+ 1794, 40, 4363, 4457, 4364, 4453, 4523, 41, 1538, 40, 4363, 4457, 4370,
+ 4462, 41, 770, 40, 19968, 41, 770, 40, 20108, 41, 770, 40, 19977, 41,
+ 770, 40, 22235, 41, 770, 40, 20116, 41, 770, 40, 20845, 41, 770, 40,
+ 19971, 41, 770, 40, 20843, 41, 770, 40, 20061, 41, 770, 40, 21313, 41,
+ 770, 40, 26376, 41, 770, 40, 28779, 41, 770, 40, 27700, 41, 770, 40,
+ 26408, 41, 770, 40, 37329, 41, 770, 40, 22303, 41, 770, 40, 26085, 41,
+ 770, 40, 26666, 41, 770, 40, 26377, 41, 770, 40, 31038, 41, 770, 40,
+ 21517, 41, 770, 40, 29305, 41, 770, 40, 36001, 41, 770, 40, 31069, 41,
+ 770, 40, 21172, 41, 770, 40, 20195, 41, 770, 40, 21628, 41, 770, 40,
+ 23398, 41, 770, 40, 30435, 41, 770, 40, 20225, 41, 770, 40, 36039, 41,
+ 770, 40, 21332, 41, 770, 40, 31085, 41, 770, 40, 20241, 41, 770, 40,
+ 33258, 41, 770, 40, 33267, 41, 263, 21839, 263, 24188, 263, 25991, 263,
+ 31631, 778, 80, 84, 69, 519, 50, 49, 519, 50, 50, 519, 50, 51, 519, 50,
+ 52, 519, 50, 53, 519, 50, 54, 519, 50, 55, 519, 50, 56, 519, 50, 57, 519,
+ 51, 48, 519, 51, 49, 519, 51, 50, 519, 51, 51, 519, 51, 52, 519, 51, 53,
+ 263, 4352, 263, 4354, 263, 4355, 263, 4357, 263, 4358, 263, 4359, 263,
+ 4361, 263, 4363, 263, 4364, 263, 4366, 263, 4367, 263, 4368, 263, 4369,
+ 263, 4370, 519, 4352, 4449, 519, 4354, 4449, 519, 4355, 4449, 519, 4357,
+ 4449, 519, 4358, 4449, 519, 4359, 4449, 519, 4361, 4449, 519, 4363, 4449,
+ 519, 4364, 4449, 519, 4366, 4449, 519, 4367, 4449, 519, 4368, 4449, 519,
+ 4369, 4449, 519, 4370, 4449, 1287, 4366, 4449, 4535, 4352, 4457, 1031,
+ 4364, 4462, 4363, 4468, 519, 4363, 4462, 263, 19968, 263, 20108, 263,
+ 19977, 263, 22235, 263, 20116, 263, 20845, 263, 19971, 263, 20843, 263,
+ 20061, 263, 21313, 263, 26376, 263, 28779, 263, 27700, 263, 26408, 263,
+ 37329, 263, 22303, 263, 26085, 263, 26666, 263, 26377, 263, 31038, 263,
+ 21517, 263, 29305, 263, 36001, 263, 31069, 263, 21172, 263, 31192, 263,
+ 30007, 263, 22899, 263, 36969, 263, 20778, 263, 21360, 263, 27880, 263,
+ 38917, 263, 20241, 263, 20889, 263, 27491, 263, 19978, 263, 20013, 263,
+ 19979, 263, 24038, 263, 21491, 263, 21307, 263, 23447, 263, 23398, 263,
+ 30435, 263, 20225, 263, 36039, 263, 21332, 263, 22812, 519, 51, 54, 519,
+ 51, 55, 519, 51, 56, 519, 51, 57, 519, 52, 48, 519, 52, 49, 519, 52, 50,
+ 519, 52, 51, 519, 52, 52, 519, 52, 53, 519, 52, 54, 519, 52, 55, 519, 52,
+ 56, 519, 52, 57, 519, 53, 48, 514, 49, 26376, 514, 50, 26376, 514, 51,
+ 26376, 514, 52, 26376, 514, 53, 26376, 514, 54, 26376, 514, 55, 26376,
+ 514, 56, 26376, 514, 57, 26376, 770, 49, 48, 26376, 770, 49, 49, 26376,
+ 770, 49, 50, 26376, 522, 72, 103, 778, 101, 114, 103, 522, 101, 86, 778,
+ 76, 84, 68, 263, 12450, 263, 12452, 263, 12454, 263, 12456, 263, 12458,
+ 263, 12459, 263, 12461, 263, 12463, 263, 12465, 263, 12467, 263, 12469,
+ 263, 12471, 263, 12473, 263, 12475, 263, 12477, 263, 12479, 263, 12481,
+ 263, 12484, 263, 12486, 263, 12488, 263, 12490, 263, 12491, 263, 12492,
+ 263, 12493, 263, 12494, 263, 12495, 263, 12498, 263, 12501, 263, 12504,
+ 263, 12507, 263, 12510, 263, 12511, 263, 12512, 263, 12513, 263, 12514,
+ 263, 12516, 263, 12518, 263, 12520, 263, 12521, 263, 12522, 263, 12523,
+ 263, 12524, 263, 12525, 263, 12527, 263, 12528, 263, 12529, 263, 12530,
+ 1034, 12450, 12497, 12540, 12488, 1034, 12450, 12523, 12501, 12449, 1034,
+ 12450, 12531, 12506, 12450, 778, 12450, 12540, 12523, 1034, 12452, 12491,
+ 12531, 12464, 778, 12452, 12531, 12481, 778, 12454, 12457, 12531, 1290,
+ 12456, 12473, 12463, 12540, 12489, 1034, 12456, 12540, 12459, 12540, 778,
+ 12458, 12531, 12473, 778, 12458, 12540, 12512, 778, 12459, 12452, 12522,
+ 1034, 12459, 12521, 12483, 12488, 1034, 12459, 12525, 12522, 12540, 778,
+ 12460, 12525, 12531, 778, 12460, 12531, 12510, 522, 12462, 12460, 778,
+ 12462, 12491, 12540, 1034, 12461, 12517, 12522, 12540, 1034, 12462,
+ 12523, 12480, 12540, 522, 12461, 12525, 1290, 12461, 12525, 12464, 12521,
+ 12512, 1546, 12461, 12525, 12513, 12540, 12488, 12523, 1290, 12461,
+ 12525, 12527, 12483, 12488, 778, 12464, 12521, 12512, 1290, 12464, 12521,
+ 12512, 12488, 12531, 1290, 12463, 12523, 12476, 12452, 12525, 1034,
+ 12463, 12525, 12540, 12493, 778, 12465, 12540, 12473, 778, 12467, 12523,
+ 12490, 778, 12467, 12540, 12509, 1034, 12469, 12452, 12463, 12523, 1290,
+ 12469, 12531, 12481, 12540, 12512, 1034, 12471, 12522, 12531, 12464, 778,
+ 12475, 12531, 12481, 778, 12475, 12531, 12488, 778, 12480, 12540, 12473,
+ 522, 12487, 12471, 522, 12489, 12523, 522, 12488, 12531, 522, 12490,
+ 12494, 778, 12494, 12483, 12488, 778, 12495, 12452, 12484, 1290, 12497,
+ 12540, 12475, 12531, 12488, 778, 12497, 12540, 12484, 1034, 12496, 12540,
+ 12524, 12523, 1290, 12500, 12450, 12473, 12488, 12523, 778, 12500, 12463,
+ 12523, 522, 12500, 12467, 522, 12499, 12523, 1290, 12501, 12449, 12521,
+ 12483, 12489, 1034, 12501, 12451, 12540, 12488, 1290, 12502, 12483,
+ 12471, 12455, 12523, 778, 12501, 12521, 12531, 1290, 12504, 12463, 12479,
+ 12540, 12523, 522, 12506, 12477, 778, 12506, 12491, 12498, 778, 12504,
+ 12523, 12484, 778, 12506, 12531, 12473, 778, 12506, 12540, 12472, 778,
+ 12505, 12540, 12479, 1034, 12509, 12452, 12531, 12488, 778, 12508, 12523,
+ 12488, 522, 12507, 12531, 778, 12509, 12531, 12489, 778, 12507, 12540,
+ 12523, 778, 12507, 12540, 12531, 1034, 12510, 12452, 12463, 12525, 778,
+ 12510, 12452, 12523, 778, 12510, 12483, 12495, 778, 12510, 12523, 12463,
+ 1290, 12510, 12531, 12471, 12519, 12531, 1034, 12511, 12463, 12525,
+ 12531, 522, 12511, 12522, 1290, 12511, 12522, 12496, 12540, 12523, 522,
+ 12513, 12460, 1034, 12513, 12460, 12488, 12531, 1034, 12513, 12540,
+ 12488, 12523, 778, 12516, 12540, 12489, 778, 12516, 12540, 12523, 778,
+ 12518, 12450, 12531, 1034, 12522, 12483, 12488, 12523, 522, 12522, 12521,
+ 778, 12523, 12500, 12540, 1034, 12523, 12540, 12502, 12523, 522, 12524,
+ 12512, 1290, 12524, 12531, 12488, 12466, 12531, 778, 12527, 12483, 12488,
+ 514, 48, 28857, 514, 49, 28857, 514, 50, 28857, 514, 51, 28857, 514, 52,
+ 28857, 514, 53, 28857, 514, 54, 28857, 514, 55, 28857, 514, 56, 28857,
+ 514, 57, 28857, 770, 49, 48, 28857, 770, 49, 49, 28857, 770, 49, 50,
+ 28857, 770, 49, 51, 28857, 770, 49, 52, 28857, 770, 49, 53, 28857, 770,
+ 49, 54, 28857, 770, 49, 55, 28857, 770, 49, 56, 28857, 770, 49, 57,
+ 28857, 770, 50, 48, 28857, 770, 50, 49, 28857, 770, 50, 50, 28857, 770,
+ 50, 51, 28857, 770, 50, 52, 28857, 778, 104, 80, 97, 522, 100, 97, 522,
+ 65, 85, 778, 98, 97, 114, 522, 111, 86, 522, 112, 99, 522, 100, 109, 778,
+ 100, 109, 178, 778, 100, 109, 179, 522, 73, 85, 522, 24179, 25104, 522,
+ 26157, 21644, 522, 22823, 27491, 522, 26126, 27835, 1034, 26666, 24335,
+ 20250, 31038, 522, 112, 65, 522, 110, 65, 522, 956, 65, 522, 109, 65,
+ 522, 107, 65, 522, 75, 66, 522, 77, 66, 522, 71, 66, 778, 99, 97, 108,
+ 1034, 107, 99, 97, 108, 522, 112, 70, 522, 110, 70, 522, 956, 70, 522,
+ 956, 103, 522, 109, 103, 522, 107, 103, 522, 72, 122, 778, 107, 72, 122,
+ 778, 77, 72, 122, 778, 71, 72, 122, 778, 84, 72, 122, 522, 956, 8467,
+ 522, 109, 8467, 522, 100, 8467, 522, 107, 8467, 522, 102, 109, 522, 110,
+ 109, 522, 956, 109, 522, 109, 109, 522, 99, 109, 522, 107, 109, 778, 109,
+ 109, 178, 778, 99, 109, 178, 522, 109, 178, 778, 107, 109, 178, 778, 109,
+ 109, 179, 778, 99, 109, 179, 522, 109, 179, 778, 107, 109, 179, 778, 109,
+ 8725, 115, 1034, 109, 8725, 115, 178, 522, 80, 97, 778, 107, 80, 97, 778,
+ 77, 80, 97, 778, 71, 80, 97, 778, 114, 97, 100, 1290, 114, 97, 100, 8725,
+ 115, 1546, 114, 97, 100, 8725, 115, 178, 522, 112, 115, 522, 110, 115,
+ 522, 956, 115, 522, 109, 115, 522, 112, 86, 522, 110, 86, 522, 956, 86,
+ 522, 109, 86, 522, 107, 86, 522, 77, 86, 522, 112, 87, 522, 110, 87, 522,
+ 956, 87, 522, 109, 87, 522, 107, 87, 522, 77, 87, 522, 107, 937, 522, 77,
+ 937, 1034, 97, 46, 109, 46, 522, 66, 113, 522, 99, 99, 522, 99, 100,
+ 1034, 67, 8725, 107, 103, 778, 67, 111, 46, 522, 100, 66, 522, 71, 121,
+ 522, 104, 97, 522, 72, 80, 522, 105, 110, 522, 75, 75, 522, 75, 77, 522,
+ 107, 116, 522, 108, 109, 522, 108, 110, 778, 108, 111, 103, 522, 108,
+ 120, 522, 109, 98, 778, 109, 105, 108, 778, 109, 111, 108, 522, 80, 72,
+ 1034, 112, 46, 109, 46, 778, 80, 80, 77, 522, 80, 82, 522, 115, 114, 522,
+ 83, 118, 522, 87, 98, 778, 86, 8725, 109, 778, 65, 8725, 109, 514, 49,
+ 26085, 514, 50, 26085, 514, 51, 26085, 514, 52, 26085, 514, 53, 26085,
+ 514, 54, 26085, 514, 55, 26085, 514, 56, 26085, 514, 57, 26085, 770, 49,
+ 48, 26085, 770, 49, 49, 26085, 770, 49, 50, 26085, 770, 49, 51, 26085,
+ 770, 49, 52, 26085, 770, 49, 53, 26085, 770, 49, 54, 26085, 770, 49, 55,
+ 26085, 770, 49, 56, 26085, 770, 49, 57, 26085, 770, 50, 48, 26085, 770,
+ 50, 49, 26085, 770, 50, 50, 26085, 770, 50, 51, 26085, 770, 50, 52,
+ 26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, 26085, 770,
+ 50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, 51, 49,
+ 26085, 778, 103, 97, 108, 259, 1098, 259, 1100, 259, 42863, 259, 294,
+ 259, 339, 259, 42791, 259, 43831, 259, 619, 259, 43858, 256, 35912, 256,
+ 26356, 256, 36554, 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256,
+ 40860, 256, 40860, 256, 22865, 256, 37329, 256, 21895, 256, 22856, 256,
+ 25078, 256, 30313, 256, 32645, 256, 34367, 256, 34746, 256, 35064, 256,
+ 37007, 256, 27138, 256, 27931, 256, 28889, 256, 29662, 256, 33853, 256,
+ 37226, 256, 39409, 256, 20098, 256, 21365, 256, 27396, 256, 29211, 256,
+ 34349, 256, 40478, 256, 23888, 256, 28651, 256, 34253, 256, 35172, 256,
+ 25289, 256, 33240, 256, 34847, 256, 24266, 256, 26391, 256, 28010, 256,
+ 29436, 256, 37070, 256, 20358, 256, 20919, 256, 21214, 256, 25796, 256,
+ 27347, 256, 29200, 256, 30439, 256, 32769, 256, 34310, 256, 34396, 256,
+ 36335, 256, 38706, 256, 39791, 256, 40442, 256, 30860, 256, 31103, 256,
+ 32160, 256, 33737, 256, 37636, 256, 40575, 256, 35542, 256, 22751, 256,
+ 24324, 256, 31840, 256, 32894, 256, 29282, 256, 30922, 256, 36034, 256,
+ 38647, 256, 22744, 256, 23650, 256, 27155, 256, 28122, 256, 28431, 256,
+ 32047, 256, 32311, 256, 38475, 256, 21202, 256, 32907, 256, 20956, 256,
+ 20940, 256, 31260, 256, 32190, 256, 33777, 256, 38517, 256, 35712, 256,
+ 25295, 256, 27138, 256, 35582, 256, 20025, 256, 23527, 256, 24594, 256,
+ 29575, 256, 30064, 256, 21271, 256, 30971, 256, 20415, 256, 24489, 256,
+ 19981, 256, 27852, 256, 25976, 256, 32034, 256, 21443, 256, 22622, 256,
+ 30465, 256, 33865, 256, 35498, 256, 27578, 256, 36784, 256, 27784, 256,
+ 25342, 256, 33509, 256, 25504, 256, 30053, 256, 20142, 256, 20841, 256,
+ 20937, 256, 26753, 256, 31975, 256, 33391, 256, 35538, 256, 37327, 256,
+ 21237, 256, 21570, 256, 22899, 256, 24300, 256, 26053, 256, 28670, 256,
+ 31018, 256, 38317, 256, 39530, 256, 40599, 256, 40654, 256, 21147, 256,
+ 26310, 256, 27511, 256, 36706, 256, 24180, 256, 24976, 256, 25088, 256,
+ 25754, 256, 28451, 256, 29001, 256, 29833, 256, 31178, 256, 32244, 256,
+ 32879, 256, 36646, 256, 34030, 256, 36899, 256, 37706, 256, 21015, 256,
+ 21155, 256, 21693, 256, 28872, 256, 35010, 256, 35498, 256, 24265, 256,
+ 24565, 256, 25467, 256, 27566, 256, 31806, 256, 29557, 256, 20196, 256,
+ 22265, 256, 23527, 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256,
+ 32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256,
+ 20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256,
+ 20698, 256, 23534, 256, 23615, 256, 26009, 256, 27138, 256, 29134, 256,
+ 30274, 256, 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256,
+ 21129, 256, 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256,
+ 30041, 256, 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256,
+ 38520, 256, 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256,
+ 24900, 256, 26647, 256, 29575, 256, 38534, 256, 21033, 256, 21519, 256,
+ 23653, 256, 26131, 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256,
+ 30178, 256, 32633, 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256,
+ 21311, 256, 28346, 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256,
+ 38563, 256, 40023, 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256,
+ 31435, 256, 31520, 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256,
+ 20160, 256, 33590, 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256,
+ 31958, 256, 23429, 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256,
+ 38477, 256, 35211, 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256,
+ 26228, 256, 20958, 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256,
+ 31077, 256, 31119, 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256,
+ 35576, 256, 36920, 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256,
+ 40372, 256, 37086, 256, 38583, 256, 20398, 256, 20711, 256, 20813, 256,
+ 21193, 256, 21220, 256, 21329, 256, 21917, 256, 22022, 256, 22120, 256,
+ 22592, 256, 22696, 256, 23652, 256, 23662, 256, 24724, 256, 24936, 256,
+ 24974, 256, 25074, 256, 25935, 256, 26082, 256, 26257, 256, 26757, 256,
+ 28023, 256, 28186, 256, 28450, 256, 29038, 256, 29227, 256, 29730, 256,
+ 30865, 256, 31038, 256, 31049, 256, 31048, 256, 31056, 256, 31062, 256,
+ 31069, 256, 31117, 256, 31118, 256, 31296, 256, 31361, 256, 31680, 256,
+ 32244, 256, 32265, 256, 32321, 256, 32626, 256, 32773, 256, 33261, 256,
+ 33401, 256, 33401, 256, 33879, 256, 35088, 256, 35222, 256, 35585, 256,
+ 35641, 256, 36051, 256, 36104, 256, 36790, 256, 36920, 256, 38627, 256,
+ 38911, 256, 38971, 256, 24693, 256, 55376, 57070, 256, 33304, 256, 20006,
+ 256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, 21191,
+ 256, 21242, 256, 21917, 256, 21845, 256, 21913, 256, 21986, 256, 22618,
+ 256, 22707, 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274,
+ 256, 24281, 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840,
+ 256, 24974, 256, 24928, 256, 25074, 256, 25140, 256, 25540, 256, 25628,
+ 256, 25682, 256, 25942, 256, 26228, 256, 26391, 256, 26395, 256, 26454,
+ 256, 27513, 256, 27578, 256, 27969, 256, 28379, 256, 28363, 256, 28450,
+ 256, 28702, 256, 29038, 256, 30631, 256, 29237, 256, 29359, 256, 29482,
+ 256, 29809, 256, 29958, 256, 30011, 256, 30237, 256, 30239, 256, 30410,
+ 256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, 31409,
+ 256, 31680, 256, 31867, 256, 32091, 256, 32244, 256, 32574, 256, 32773,
+ 256, 33618, 256, 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35222,
+ 256, 35519, 256, 35576, 256, 35531, 256, 35585, 256, 35582, 256, 35565,
+ 256, 35641, 256, 35722, 256, 36104, 256, 36664, 256, 36978, 256, 37273,
+ 256, 37494, 256, 38524, 256, 38627, 256, 38742, 256, 38875, 256, 38911,
+ 256, 38923, 256, 38971, 256, 39698, 256, 40860, 256, 55370, 56394, 256,
+ 55370, 56388, 256, 55372, 57301, 256, 15261, 256, 16408, 256, 16441, 256,
+ 55380, 56905, 256, 55383, 56528, 256, 55391, 57043, 256, 40771, 256,
+ 40846, 514, 102, 102, 514, 102, 105, 514, 102, 108, 770, 102, 102, 105,
+ 770, 102, 102, 108, 514, 383, 116, 514, 115, 116, 514, 1396, 1398, 514,
+ 1396, 1381, 514, 1396, 1387, 514, 1406, 1398, 514, 1396, 1389, 512, 1497,
+ 1460, 512, 1522, 1463, 262, 1506, 262, 1488, 262, 1491, 262, 1492, 262,
+ 1499, 262, 1500, 262, 1501, 262, 1512, 262, 1514, 262, 43, 512, 1513,
+ 1473, 512, 1513, 1474, 512, 64329, 1473, 512, 64329, 1474, 512, 1488,
+ 1463, 512, 1488, 1464, 512, 1488, 1468, 512, 1489, 1468, 512, 1490, 1468,
+ 512, 1491, 1468, 512, 1492, 1468, 512, 1493, 1468, 512, 1494, 1468, 512,
+ 1496, 1468, 512, 1497, 1468, 512, 1498, 1468, 512, 1499, 1468, 512, 1500,
+ 1468, 512, 1502, 1468, 512, 1504, 1468, 512, 1505, 1468, 512, 1507, 1468,
+ 512, 1508, 1468, 512, 1510, 1468, 512, 1511, 1468, 512, 1512, 1468, 512,
+ 1513, 1468, 512, 1514, 1468, 512, 1493, 1465, 512, 1489, 1471, 512, 1499,
+ 1471, 512, 1508, 1471, 514, 1488, 1500, 267, 1649, 268, 1649, 267, 1659,
+ 268, 1659, 269, 1659, 270, 1659, 267, 1662, 268, 1662, 269, 1662, 270,
+ 1662, 267, 1664, 268, 1664, 269, 1664, 270, 1664, 267, 1658, 268, 1658,
+ 269, 1658, 270, 1658, 267, 1663, 268, 1663, 269, 1663, 270, 1663, 267,
+ 1657, 268, 1657, 269, 1657, 270, 1657, 267, 1700, 268, 1700, 269, 1700,
+ 270, 1700, 267, 1702, 268, 1702, 269, 1702, 270, 1702, 267, 1668, 268,
+ 1668, 269, 1668, 270, 1668, 267, 1667, 268, 1667, 269, 1667, 270, 1667,
+ 267, 1670, 268, 1670, 269, 1670, 270, 1670, 267, 1671, 268, 1671, 269,
+ 1671, 270, 1671, 267, 1677, 268, 1677, 267, 1676, 268, 1676, 267, 1678,
+ 268, 1678, 267, 1672, 268, 1672, 267, 1688, 268, 1688, 267, 1681, 268,
+ 1681, 267, 1705, 268, 1705, 269, 1705, 270, 1705, 267, 1711, 268, 1711,
+ 269, 1711, 270, 1711, 267, 1715, 268, 1715, 269, 1715, 270, 1715, 267,
+ 1713, 268, 1713, 269, 1713, 270, 1713, 267, 1722, 268, 1722, 267, 1723,
+ 268, 1723, 269, 1723, 270, 1723, 267, 1728, 268, 1728, 267, 1729, 268,
+ 1729, 269, 1729, 270, 1729, 267, 1726, 268, 1726, 269, 1726, 270, 1726,
+ 267, 1746, 268, 1746, 267, 1747, 268, 1747, 267, 1709, 268, 1709, 269,
+ 1709, 270, 1709, 267, 1735, 268, 1735, 267, 1734, 268, 1734, 267, 1736,
+ 268, 1736, 267, 1655, 267, 1739, 268, 1739, 267, 1733, 268, 1733, 267,
+ 1737, 268, 1737, 267, 1744, 268, 1744, 269, 1744, 270, 1744, 269, 1609,
+ 270, 1609, 523, 1574, 1575, 524, 1574, 1575, 523, 1574, 1749, 524, 1574,
+ 1749, 523, 1574, 1608, 524, 1574, 1608, 523, 1574, 1735, 524, 1574, 1735,
+ 523, 1574, 1734, 524, 1574, 1734, 523, 1574, 1736, 524, 1574, 1736, 523,
+ 1574, 1744, 524, 1574, 1744, 525, 1574, 1744, 523, 1574, 1609, 524, 1574,
+ 1609, 525, 1574, 1609, 267, 1740, 268, 1740, 269, 1740, 270, 1740, 523,
+ 1574, 1580, 523, 1574, 1581, 523, 1574, 1605, 523, 1574, 1609, 523, 1574,
+ 1610, 523, 1576, 1580, 523, 1576, 1581, 523, 1576, 1582, 523, 1576, 1605,
+ 523, 1576, 1609, 523, 1576, 1610, 523, 1578, 1580, 523, 1578, 1581, 523,
+ 1578, 1582, 523, 1578, 1605, 523, 1578, 1609, 523, 1578, 1610, 523, 1579,
+ 1580, 523, 1579, 1605, 523, 1579, 1609, 523, 1579, 1610, 523, 1580, 1581,
+ 523, 1580, 1605, 523, 1581, 1580, 523, 1581, 1605, 523, 1582, 1580, 523,
+ 1582, 1581, 523, 1582, 1605, 523, 1587, 1580, 523, 1587, 1581, 523, 1587,
+ 1582, 523, 1587, 1605, 523, 1589, 1581, 523, 1589, 1605, 523, 1590, 1580,
+ 523, 1590, 1581, 523, 1590, 1582, 523, 1590, 1605, 523, 1591, 1581, 523,
+ 1591, 1605, 523, 1592, 1605, 523, 1593, 1580, 523, 1593, 1605, 523, 1594,
+ 1580, 523, 1594, 1605, 523, 1601, 1580, 523, 1601, 1581, 523, 1601, 1582,
+ 523, 1601, 1605, 523, 1601, 1609, 523, 1601, 1610, 523, 1602, 1581, 523,
+ 1602, 1605, 523, 1602, 1609, 523, 1602, 1610, 523, 1603, 1575, 523, 1603,
+ 1580, 523, 1603, 1581, 523, 1603, 1582, 523, 1603, 1604, 523, 1603, 1605,
+ 523, 1603, 1609, 523, 1603, 1610, 523, 1604, 1580, 523, 1604, 1581, 523,
+ 1604, 1582, 523, 1604, 1605, 523, 1604, 1609, 523, 1604, 1610, 523, 1605,
+ 1580, 523, 1605, 1581, 523, 1605, 1582, 523, 1605, 1605, 523, 1605, 1609,
+ 523, 1605, 1610, 523, 1606, 1580, 523, 1606, 1581, 523, 1606, 1582, 523,
+ 1606, 1605, 523, 1606, 1609, 523, 1606, 1610, 523, 1607, 1580, 523, 1607,
+ 1605, 523, 1607, 1609, 523, 1607, 1610, 523, 1610, 1580, 523, 1610, 1581,
+ 523, 1610, 1582, 523, 1610, 1605, 523, 1610, 1609, 523, 1610, 1610, 523,
+ 1584, 1648, 523, 1585, 1648, 523, 1609, 1648, 779, 32, 1612, 1617, 779,
+ 32, 1613, 1617, 779, 32, 1614, 1617, 779, 32, 1615, 1617, 779, 32, 1616,
+ 1617, 779, 32, 1617, 1648, 524, 1574, 1585, 524, 1574, 1586, 524, 1574,
+ 1605, 524, 1574, 1606, 524, 1574, 1609, 524, 1574, 1610, 524, 1576, 1585,
+ 524, 1576, 1586, 524, 1576, 1605, 524, 1576, 1606, 524, 1576, 1609, 524,
+ 1576, 1610, 524, 1578, 1585, 524, 1578, 1586, 524, 1578, 1605, 524, 1578,
+ 1606, 524, 1578, 1609, 524, 1578, 1610, 524, 1579, 1585, 524, 1579, 1586,
+ 524, 1579, 1605, 524, 1579, 1606, 524, 1579, 1609, 524, 1579, 1610, 524,
+ 1601, 1609, 524, 1601, 1610, 524, 1602, 1609, 524, 1602, 1610, 524, 1603,
+ 1575, 524, 1603, 1604, 524, 1603, 1605, 524, 1603, 1609, 524, 1603, 1610,
+ 524, 1604, 1605, 524, 1604, 1609, 524, 1604, 1610, 524, 1605, 1575, 524,
+ 1605, 1605, 524, 1606, 1585, 524, 1606, 1586, 524, 1606, 1605, 524, 1606,
+ 1606, 524, 1606, 1609, 524, 1606, 1610, 524, 1609, 1648, 524, 1610, 1585,
+ 524, 1610, 1586, 524, 1610, 1605, 524, 1610, 1606, 524, 1610, 1609, 524,
+ 1610, 1610, 525, 1574, 1580, 525, 1574, 1581, 525, 1574, 1582, 525, 1574,
+ 1605, 525, 1574, 1607, 525, 1576, 1580, 525, 1576, 1581, 525, 1576, 1582,
+ 525, 1576, 1605, 525, 1576, 1607, 525, 1578, 1580, 525, 1578, 1581, 525,
+ 1578, 1582, 525, 1578, 1605, 525, 1578, 1607, 525, 1579, 1605, 525, 1580,
+ 1581, 525, 1580, 1605, 525, 1581, 1580, 525, 1581, 1605, 525, 1582, 1580,
+ 525, 1582, 1605, 525, 1587, 1580, 525, 1587, 1581, 525, 1587, 1582, 525,
+ 1587, 1605, 525, 1589, 1581, 525, 1589, 1582, 525, 1589, 1605, 525, 1590,
+ 1580, 525, 1590, 1581, 525, 1590, 1582, 525, 1590, 1605, 525, 1591, 1581,
+ 525, 1592, 1605, 525, 1593, 1580, 525, 1593, 1605, 525, 1594, 1580, 525,
+ 1594, 1605, 525, 1601, 1580, 525, 1601, 1581, 525, 1601, 1582, 525, 1601,
+ 1605, 525, 1602, 1581, 525, 1602, 1605, 525, 1603, 1580, 525, 1603, 1581,
+ 525, 1603, 1582, 525, 1603, 1604, 525, 1603, 1605, 525, 1604, 1580, 525,
+ 1604, 1581, 525, 1604, 1582, 525, 1604, 1605, 525, 1604, 1607, 525, 1605,
+ 1580, 525, 1605, 1581, 525, 1605, 1582, 525, 1605, 1605, 525, 1606, 1580,
+ 525, 1606, 1581, 525, 1606, 1582, 525, 1606, 1605, 525, 1606, 1607, 525,
+ 1607, 1580, 525, 1607, 1605, 525, 1607, 1648, 525, 1610, 1580, 525, 1610,
+ 1581, 525, 1610, 1582, 525, 1610, 1605, 525, 1610, 1607, 526, 1574, 1605,
+ 526, 1574, 1607, 526, 1576, 1605, 526, 1576, 1607, 526, 1578, 1605, 526,
+ 1578, 1607, 526, 1579, 1605, 526, 1579, 1607, 526, 1587, 1605, 526, 1587,
+ 1607, 526, 1588, 1605, 526, 1588, 1607, 526, 1603, 1604, 526, 1603, 1605,
+ 526, 1604, 1605, 526, 1606, 1605, 526, 1606, 1607, 526, 1610, 1605, 526,
+ 1610, 1607, 782, 1600, 1614, 1617, 782, 1600, 1615, 1617, 782, 1600,
+ 1616, 1617, 523, 1591, 1609, 523, 1591, 1610, 523, 1593, 1609, 523, 1593,
+ 1610, 523, 1594, 1609, 523, 1594, 1610, 523, 1587, 1609, 523, 1587, 1610,
+ 523, 1588, 1609, 523, 1588, 1610, 523, 1581, 1609, 523, 1581, 1610, 523,
+ 1580, 1609, 523, 1580, 1610, 523, 1582, 1609, 523, 1582, 1610, 523, 1589,
+ 1609, 523, 1589, 1610, 523, 1590, 1609, 523, 1590, 1610, 523, 1588, 1580,
+ 523, 1588, 1581, 523, 1588, 1582, 523, 1588, 1605, 523, 1588, 1585, 523,
+ 1587, 1585, 523, 1589, 1585, 523, 1590, 1585, 524, 1591, 1609, 524, 1591,
+ 1610, 524, 1593, 1609, 524, 1593, 1610, 524, 1594, 1609, 524, 1594, 1610,
+ 524, 1587, 1609, 524, 1587, 1610, 524, 1588, 1609, 524, 1588, 1610, 524,
+ 1581, 1609, 524, 1581, 1610, 524, 1580, 1609, 524, 1580, 1610, 524, 1582,
+ 1609, 524, 1582, 1610, 524, 1589, 1609, 524, 1589, 1610, 524, 1590, 1609,
+ 524, 1590, 1610, 524, 1588, 1580, 524, 1588, 1581, 524, 1588, 1582, 524,
+ 1588, 1605, 524, 1588, 1585, 524, 1587, 1585, 524, 1589, 1585, 524, 1590,
+ 1585, 525, 1588, 1580, 525, 1588, 1581, 525, 1588, 1582, 525, 1588, 1605,
+ 525, 1587, 1607, 525, 1588, 1607, 525, 1591, 1605, 526, 1587, 1580, 526,
+ 1587, 1581, 526, 1587, 1582, 526, 1588, 1580, 526, 1588, 1581, 526, 1588,
+ 1582, 526, 1591, 1605, 526, 1592, 1605, 524, 1575, 1611, 523, 1575, 1611,
+ 781, 1578, 1580, 1605, 780, 1578, 1581, 1580, 781, 1578, 1581, 1580, 781,
+ 1578, 1581, 1605, 781, 1578, 1582, 1605, 781, 1578, 1605, 1580, 781,
+ 1578, 1605, 1581, 781, 1578, 1605, 1582, 780, 1580, 1605, 1581, 781,
+ 1580, 1605, 1581, 780, 1581, 1605, 1610, 780, 1581, 1605, 1609, 781,
+ 1587, 1581, 1580, 781, 1587, 1580, 1581, 780, 1587, 1580, 1609, 780,
+ 1587, 1605, 1581, 781, 1587, 1605, 1581, 781, 1587, 1605, 1580, 780,
+ 1587, 1605, 1605, 781, 1587, 1605, 1605, 780, 1589, 1581, 1581, 781,
+ 1589, 1581, 1581, 780, 1589, 1605, 1605, 780, 1588, 1581, 1605, 781,
+ 1588, 1581, 1605, 780, 1588, 1580, 1610, 780, 1588, 1605, 1582, 781,
+ 1588, 1605, 1582, 780, 1588, 1605, 1605, 781, 1588, 1605, 1605, 780,
+ 1590, 1581, 1609, 780, 1590, 1582, 1605, 781, 1590, 1582, 1605, 780,
+ 1591, 1605, 1581, 781, 1591, 1605, 1581, 781, 1591, 1605, 1605, 780,
+ 1591, 1605, 1610, 780, 1593, 1580, 1605, 780, 1593, 1605, 1605, 781,
+ 1593, 1605, 1605, 780, 1593, 1605, 1609, 780, 1594, 1605, 1605, 780,
+ 1594, 1605, 1610, 780, 1594, 1605, 1609, 780, 1601, 1582, 1605, 781,
+ 1601, 1582, 1605, 780, 1602, 1605, 1581, 780, 1602, 1605, 1605, 780,
+ 1604, 1581, 1605, 780, 1604, 1581, 1610, 780, 1604, 1581, 1609, 781,
+ 1604, 1580, 1580, 780, 1604, 1580, 1580, 780, 1604, 1582, 1605, 781,
+ 1604, 1582, 1605, 780, 1604, 1605, 1581, 781, 1604, 1605, 1581, 781,
+ 1605, 1581, 1580, 781, 1605, 1581, 1605, 780, 1605, 1581, 1610, 781,
+ 1605, 1580, 1581, 781, 1605, 1580, 1605, 781, 1605, 1582, 1580, 781,
+ 1605, 1582, 1605, 781, 1605, 1580, 1582, 781, 1607, 1605, 1580, 781,
+ 1607, 1605, 1605, 781, 1606, 1581, 1605, 780, 1606, 1581, 1609, 780,
+ 1606, 1580, 1605, 781, 1606, 1580, 1605, 780, 1606, 1580, 1609, 780,
+ 1606, 1605, 1610, 780, 1606, 1605, 1609, 780, 1610, 1605, 1605, 781,
+ 1610, 1605, 1605, 780, 1576, 1582, 1610, 780, 1578, 1580, 1610, 780,
+ 1578, 1580, 1609, 780, 1578, 1582, 1610, 780, 1578, 1582, 1609, 780,
+ 1578, 1605, 1610, 780, 1578, 1605, 1609, 780, 1580, 1605, 1610, 780,
+ 1580, 1581, 1609, 780, 1580, 1605, 1609, 780, 1587, 1582, 1609, 780,
+ 1589, 1581, 1610, 780, 1588, 1581, 1610, 780, 1590, 1581, 1610, 780,
+ 1604, 1580, 1610, 780, 1604, 1605, 1610, 780, 1610, 1581, 1610, 780,
+ 1610, 1580, 1610, 780, 1610, 1605, 1610, 780, 1605, 1605, 1610, 780,
+ 1602, 1605, 1610, 780, 1606, 1581, 1610, 781, 1602, 1605, 1581, 781,
+ 1604, 1581, 1605, 780, 1593, 1605, 1610, 780, 1603, 1605, 1610, 781,
+ 1606, 1580, 1581, 780, 1605, 1582, 1610, 781, 1604, 1580, 1605, 780,
+ 1603, 1605, 1605, 780, 1604, 1580, 1605, 780, 1606, 1580, 1581, 780,
+ 1580, 1581, 1610, 780, 1581, 1580, 1610, 780, 1605, 1580, 1610, 780,
+ 1601, 1605, 1610, 780, 1576, 1581, 1610, 781, 1603, 1605, 1605, 781,
+ 1593, 1580, 1605, 781, 1589, 1605, 1605, 780, 1587, 1582, 1610, 780,
+ 1606, 1580, 1610, 779, 1589, 1604, 1746, 779, 1602, 1604, 1746, 1035,
+ 1575, 1604, 1604, 1607, 1035, 1575, 1603, 1576, 1585, 1035, 1605, 1581,
+ 1605, 1583, 1035, 1589, 1604, 1593, 1605, 1035, 1585, 1587, 1608, 1604,
+ 1035, 1593, 1604, 1610, 1607, 1035, 1608, 1587, 1604, 1605, 779, 1589,
+ 1604, 1609, 4619, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, 1593,
+ 1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 2059, 1580, 1604, 32, 1580,
+ 1604, 1575, 1604, 1607, 1035, 1585, 1740, 1575, 1604, 265, 44, 265,
+ 12289, 265, 12290, 265, 58, 265, 59, 265, 33, 265, 63, 265, 12310, 265,
+ 12311, 265, 8230, 265, 8229, 265, 8212, 265, 8211, 265, 95, 265, 95, 265,
+ 40, 265, 41, 265, 123, 265, 125, 265, 12308, 265, 12309, 265, 12304, 265,
+ 12305, 265, 12298, 265, 12299, 265, 12296, 265, 12297, 265, 12300, 265,
+ 12301, 265, 12302, 265, 12303, 265, 91, 265, 93, 258, 8254, 258, 8254,
+ 258, 8254, 258, 8254, 258, 95, 258, 95, 258, 95, 271, 44, 271, 12289,
+ 271, 46, 271, 59, 271, 58, 271, 63, 271, 33, 271, 8212, 271, 40, 271, 41,
+ 271, 123, 271, 125, 271, 12308, 271, 12309, 271, 35, 271, 38, 271, 42,
+ 271, 43, 271, 45, 271, 60, 271, 62, 271, 61, 271, 92, 271, 36, 271, 37,
+ 271, 64, 523, 32, 1611, 526, 1600, 1611, 523, 32, 1612, 523, 32, 1613,
+ 523, 32, 1614, 526, 1600, 1614, 523, 32, 1615, 526, 1600, 1615, 523, 32,
+ 1616, 526, 1600, 1616, 523, 32, 1617, 526, 1600, 1617, 523, 32, 1618,
+ 526, 1600, 1618, 267, 1569, 267, 1570, 268, 1570, 267, 1571, 268, 1571,
+ 267, 1572, 268, 1572, 267, 1573, 268, 1573, 267, 1574, 268, 1574, 269,
+ 1574, 270, 1574, 267, 1575, 268, 1575, 267, 1576, 268, 1576, 269, 1576,
+ 270, 1576, 267, 1577, 268, 1577, 267, 1578, 268, 1578, 269, 1578, 270,
+ 1578, 267, 1579, 268, 1579, 269, 1579, 270, 1579, 267, 1580, 268, 1580,
+ 269, 1580, 270, 1580, 267, 1581, 268, 1581, 269, 1581, 270, 1581, 267,
+ 1582, 268, 1582, 269, 1582, 270, 1582, 267, 1583, 268, 1583, 267, 1584,
+ 268, 1584, 267, 1585, 268, 1585, 267, 1586, 268, 1586, 267, 1587, 268,
+ 1587, 269, 1587, 270, 1587, 267, 1588, 268, 1588, 269, 1588, 270, 1588,
+ 267, 1589, 268, 1589, 269, 1589, 270, 1589, 267, 1590, 268, 1590, 269,
+ 1590, 270, 1590, 267, 1591, 268, 1591, 269, 1591, 270, 1591, 267, 1592,
+ 268, 1592, 269, 1592, 270, 1592, 267, 1593, 268, 1593, 269, 1593, 270,
+ 1593, 267, 1594, 268, 1594, 269, 1594, 270, 1594, 267, 1601, 268, 1601,
+ 269, 1601, 270, 1601, 267, 1602, 268, 1602, 269, 1602, 270, 1602, 267,
+ 1603, 268, 1603, 269, 1603, 270, 1603, 267, 1604, 268, 1604, 269, 1604,
+ 270, 1604, 267, 1605, 268, 1605, 269, 1605, 270, 1605, 267, 1606, 268,
+ 1606, 269, 1606, 270, 1606, 267, 1607, 268, 1607, 269, 1607, 270, 1607,
+ 267, 1608, 268, 1608, 267, 1609, 268, 1609, 267, 1610, 268, 1610, 269,
+ 1610, 270, 1610, 523, 1604, 1570, 524, 1604, 1570, 523, 1604, 1571, 524,
+ 1604, 1571, 523, 1604, 1573, 524, 1604, 1573, 523, 1604, 1575, 524, 1604,
+ 1575, 264, 33, 264, 34, 264, 35, 264, 36, 264, 37, 264, 38, 264, 39, 264,
+ 40, 264, 41, 264, 42, 264, 43, 264, 44, 264, 45, 264, 46, 264, 47, 264,
+ 48, 264, 49, 264, 50, 264, 51, 264, 52, 264, 53, 264, 54, 264, 55, 264,
+ 56, 264, 57, 264, 58, 264, 59, 264, 60, 264, 61, 264, 62, 264, 63, 264,
+ 64, 264, 65, 264, 66, 264, 67, 264, 68, 264, 69, 264, 70, 264, 71, 264,
+ 72, 264, 73, 264, 74, 264, 75, 264, 76, 264, 77, 264, 78, 264, 79, 264,
+ 80, 264, 81, 264, 82, 264, 83, 264, 84, 264, 85, 264, 86, 264, 87, 264,
+ 88, 264, 89, 264, 90, 264, 91, 264, 92, 264, 93, 264, 94, 264, 95, 264,
+ 96, 264, 97, 264, 98, 264, 99, 264, 100, 264, 101, 264, 102, 264, 103,
+ 264, 104, 264, 105, 264, 106, 264, 107, 264, 108, 264, 109, 264, 110,
+ 264, 111, 264, 112, 264, 113, 264, 114, 264, 115, 264, 116, 264, 117,
+ 264, 118, 264, 119, 264, 120, 264, 121, 264, 122, 264, 123, 264, 124,
+ 264, 125, 264, 126, 264, 10629, 264, 10630, 272, 12290, 272, 12300, 272,
+ 12301, 272, 12289, 272, 12539, 272, 12530, 272, 12449, 272, 12451, 272,
+ 12453, 272, 12455, 272, 12457, 272, 12515, 272, 12517, 272, 12519, 272,
+ 12483, 272, 12540, 272, 12450, 272, 12452, 272, 12454, 272, 12456, 272,
+ 12458, 272, 12459, 272, 12461, 272, 12463, 272, 12465, 272, 12467, 272,
+ 12469, 272, 12471, 272, 12473, 272, 12475, 272, 12477, 272, 12479, 272,
+ 12481, 272, 12484, 272, 12486, 272, 12488, 272, 12490, 272, 12491, 272,
+ 12492, 272, 12493, 272, 12494, 272, 12495, 272, 12498, 272, 12501, 272,
+ 12504, 272, 12507, 272, 12510, 272, 12511, 272, 12512, 272, 12513, 272,
+ 12514, 272, 12516, 272, 12518, 272, 12520, 272, 12521, 272, 12522, 272,
+ 12523, 272, 12524, 272, 12525, 272, 12527, 272, 12531, 272, 12441, 272,
+ 12442, 272, 12644, 272, 12593, 272, 12594, 272, 12595, 272, 12596, 272,
+ 12597, 272, 12598, 272, 12599, 272, 12600, 272, 12601, 272, 12602, 272,
+ 12603, 272, 12604, 272, 12605, 272, 12606, 272, 12607, 272, 12608, 272,
+ 12609, 272, 12610, 272, 12611, 272, 12612, 272, 12613, 272, 12614, 272,
+ 12615, 272, 12616, 272, 12617, 272, 12618, 272, 12619, 272, 12620, 272,
+ 12621, 272, 12622, 272, 12623, 272, 12624, 272, 12625, 272, 12626, 272,
+ 12627, 272, 12628, 272, 12629, 272, 12630, 272, 12631, 272, 12632, 272,
+ 12633, 272, 12634, 272, 12635, 272, 12636, 272, 12637, 272, 12638, 272,
+ 12639, 272, 12640, 272, 12641, 272, 12642, 272, 12643, 264, 162, 264,
+ 163, 264, 172, 264, 175, 264, 166, 264, 165, 264, 8361, 272, 9474, 272,
+ 8592, 272, 8593, 272, 8594, 272, 8595, 272, 9632, 272, 9675, 512, 55300,
+ 56473, 55300, 56506, 512, 55300, 56475, 55300, 56506, 512, 55300, 56485,
+ 55300, 56506, 512, 55300, 56625, 55300, 56615, 512, 55300, 56626, 55300,
+ 56615, 512, 55300, 57159, 55300, 57150, 512, 55300, 57159, 55300, 57175,
+ 512, 55301, 56505, 55301, 56506, 512, 55301, 56505, 55301, 56496, 512,
+ 55301, 56505, 55301, 56509, 512, 55301, 56760, 55301, 56751, 512, 55301,
+ 56761, 55301, 56751, 512, 55348, 56663, 55348, 56677, 512, 55348, 56664,
+ 55348, 56677, 512, 55348, 56671, 55348, 56686, 512, 55348, 56671, 55348,
+ 56687, 512, 55348, 56671, 55348, 56688, 512, 55348, 56671, 55348, 56689,
+ 512, 55348, 56671, 55348, 56690, 512, 55348, 56761, 55348, 56677, 512,
+ 55348, 56762, 55348, 56677, 512, 55348, 56763, 55348, 56686, 512, 55348,
+ 56764, 55348, 56686, 512, 55348, 56763, 55348, 56687, 512, 55348, 56764,
+ 55348, 56687, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262,
+ 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262,
+ 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262,
+ 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262,
+ 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262,
+ 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262,
+ 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262,
+ 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262,
+ 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262,
+ 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262,
+ 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
+ 102, 262, 103, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262,
+ 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262,
+ 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66,
+ 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74,
+ 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82,
+ 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90,
+ 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262,
+ 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262,
+ 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262,
+ 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 67, 262, 68,
+ 262, 71, 262, 74, 262, 75, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83,
+ 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97,
+ 262, 98, 262, 99, 262, 100, 262, 102, 262, 104, 262, 105, 262, 106, 262,
+ 107, 262, 108, 262, 109, 262, 110, 262, 112, 262, 113, 262, 114, 262,
+ 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262,
+ 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262,
+ 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262,
+ 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262,
+ 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
+ 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262,
+ 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262,
+ 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65,
+ 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 74, 262, 75, 262, 76,
+ 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 262, 84, 262, 85,
+ 262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100,
+ 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107,
+ 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114,
+ 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121,
+ 262, 122, 262, 65, 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 73,
+ 262, 74, 262, 75, 262, 76, 262, 77, 262, 79, 262, 83, 262, 84, 262, 85,
+ 262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100,
+ 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107,
+ 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114,
+ 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121,
+ 262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71,
+ 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79,
+ 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87,
+ 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101,
+ 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108,
+ 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115,
+ 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122,
+ 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72,
+ 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80,
+ 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88,
+ 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262,
+ 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262,
+ 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262,
+ 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65,
+ 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73,
+ 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81,
+ 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89,
+ 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262,
+ 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262,
+ 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262,
+ 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66,
+ 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74,
+ 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82,
+ 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90,
+ 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262,
+ 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262,
+ 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262,
+ 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67,
+ 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75,
+ 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83,
+ 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97,
+ 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262,
+ 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262,
+ 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262,
+ 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 262, 68,
+ 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76,
+ 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84,
+ 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98,
+ 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262,
+ 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262,
+ 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262,
+ 120, 262, 121, 262, 122, 262, 305, 262, 567, 262, 913, 262, 914, 262,
+ 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262,
+ 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262,
+ 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262,
+ 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262,
+ 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262,
+ 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262,
+ 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262,
+ 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262,
+ 913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262,
+ 920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262,
+ 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262,
+ 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262,
+ 947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262,
+ 954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262,
+ 961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262,
+ 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262,
+ 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 916, 262, 917, 262,
+ 918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 923, 262, 924, 262,
+ 925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262,
+ 932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262,
+ 945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 950, 262, 951, 262,
+ 952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 957, 262, 958, 262,
+ 959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 964, 262, 965, 262,
+ 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262,
+ 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262,
+ 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 922, 262,
+ 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 929, 262,
+ 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 936, 262,
+ 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 949, 262,
+ 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 956, 262,
+ 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 963, 262,
+ 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262,
+ 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262,
+ 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262,
+ 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262,
+ 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262,
+ 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262,
+ 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262,
+ 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262,
+ 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262,
+ 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262,
+ 982, 262, 988, 262, 989, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52,
+ 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50,
+ 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48,
+ 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56,
+ 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54,
+ 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52,
+ 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 1575, 262, 1576, 262,
+ 1580, 262, 1583, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610,
+ 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262,
+ 1601, 262, 1589, 262, 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579,
+ 262, 1582, 262, 1584, 262, 1590, 262, 1592, 262, 1594, 262, 1646, 262,
+ 1722, 262, 1697, 262, 1647, 262, 1576, 262, 1580, 262, 1607, 262, 1581,
+ 262, 1610, 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262,
+ 1593, 262, 1601, 262, 1589, 262, 1602, 262, 1588, 262, 1578, 262, 1579,
+ 262, 1582, 262, 1590, 262, 1594, 262, 1580, 262, 1581, 262, 1610, 262,
+ 1604, 262, 1606, 262, 1587, 262, 1593, 262, 1589, 262, 1602, 262, 1588,
+ 262, 1582, 262, 1590, 262, 1594, 262, 1722, 262, 1647, 262, 1576, 262,
+ 1580, 262, 1607, 262, 1581, 262, 1591, 262, 1610, 262, 1603, 262, 1605,
+ 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262,
+ 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1590, 262, 1592, 262, 1594,
+ 262, 1646, 262, 1697, 262, 1575, 262, 1576, 262, 1580, 262, 1583, 262,
+ 1607, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604,
+ 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262,
+ 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584,
+ 262, 1590, 262, 1592, 262, 1594, 262, 1576, 262, 1580, 262, 1583, 262,
+ 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 262, 1605,
+ 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262,
+ 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 262, 1590,
+ 262, 1592, 262, 1594, 514, 48, 46, 514, 48, 44, 514, 49, 44, 514, 50, 44,
+ 514, 51, 44, 514, 52, 44, 514, 53, 44, 514, 54, 44, 514, 55, 44, 514, 56,
+ 44, 514, 57, 44, 770, 40, 65, 41, 770, 40, 66, 41, 770, 40, 67, 41, 770,
+ 40, 68, 41, 770, 40, 69, 41, 770, 40, 70, 41, 770, 40, 71, 41, 770, 40,
+ 72, 41, 770, 40, 73, 41, 770, 40, 74, 41, 770, 40, 75, 41, 770, 40, 76,
+ 41, 770, 40, 77, 41, 770, 40, 78, 41, 770, 40, 79, 41, 770, 40, 80, 41,
+ 770, 40, 81, 41, 770, 40, 82, 41, 770, 40, 83, 41, 770, 40, 84, 41, 770,
+ 40, 85, 41, 770, 40, 86, 41, 770, 40, 87, 41, 770, 40, 88, 41, 770, 40,
+ 89, 41, 770, 40, 90, 41, 770, 12308, 83, 12309, 263, 67, 263, 82, 519,
+ 67, 68, 519, 87, 90, 266, 65, 266, 66, 266, 67, 266, 68, 266, 69, 266,
+ 70, 266, 71, 266, 72, 266, 73, 266, 74, 266, 75, 266, 76, 266, 77, 266,
+ 78, 266, 79, 266, 80, 266, 81, 266, 82, 266, 83, 266, 84, 266, 85, 266,
+ 86, 266, 87, 266, 88, 266, 89, 266, 90, 522, 72, 86, 522, 77, 86, 522,
+ 83, 68, 522, 83, 83, 778, 80, 80, 86, 522, 87, 67, 515, 77, 67, 515, 77,
+ 68, 522, 68, 74, 522, 12411, 12363, 522, 12467, 12467, 266, 12469, 266,
+ 25163, 266, 23383, 266, 21452, 266, 12487, 266, 20108, 266, 22810, 266,
+ 35299, 266, 22825, 266, 20132, 266, 26144, 266, 28961, 266, 26009, 266,
+ 21069, 266, 24460, 266, 20877, 266, 26032, 266, 21021, 266, 32066, 266,
+ 29983, 266, 36009, 266, 22768, 266, 21561, 266, 28436, 266, 25237, 266,
+ 25429, 266, 19968, 266, 19977, 266, 36938, 266, 24038, 266, 20013, 266,
+ 21491, 266, 25351, 266, 36208, 266, 25171, 266, 31105, 266, 31354, 266,
+ 21512, 266, 28288, 266, 26377, 266, 26376, 266, 30003, 266, 21106, 266,
+ 21942, 770, 12308, 26412, 12309, 770, 12308, 19977, 12309, 770, 12308,
+ 20108, 12309, 770, 12308, 23433, 12309, 770, 12308, 28857, 12309, 770,
+ 12308, 25171, 12309, 770, 12308, 30423, 12309, 770, 12308, 21213, 12309,
+ 770, 12308, 25943, 12309, 263, 24471, 263, 21487, 256, 20029, 256, 20024,
+ 256, 20033, 256, 55360, 56610, 256, 20320, 256, 20398, 256, 20411, 256,
+ 20482, 256, 20602, 256, 20633, 256, 20711, 256, 20687, 256, 13470, 256,
+ 55361, 56890, 256, 20813, 256, 20820, 256, 20836, 256, 20855, 256, 55361,
+ 56604, 256, 13497, 256, 20839, 256, 20877, 256, 55361, 56651, 256, 20887,
+ 256, 20900, 256, 20172, 256, 20908, 256, 20917, 256, 55396, 56799, 256,
+ 20981, 256, 20995, 256, 13535, 256, 21051, 256, 21062, 256, 21106, 256,
+ 21111, 256, 13589, 256, 21191, 256, 21193, 256, 21220, 256, 21242, 256,
+ 21253, 256, 21254, 256, 21271, 256, 21321, 256, 21329, 256, 21338, 256,
+ 21363, 256, 21373, 256, 21375, 256, 21375, 256, 21375, 256, 55362, 56876,
+ 256, 28784, 256, 21450, 256, 21471, 256, 55362, 57187, 256, 21483, 256,
+ 21489, 256, 21510, 256, 21662, 256, 21560, 256, 21576, 256, 21608, 256,
+ 21666, 256, 21750, 256, 21776, 256, 21843, 256, 21859, 256, 21892, 256,
+ 21892, 256, 21913, 256, 21931, 256, 21939, 256, 21954, 256, 22294, 256,
+ 22022, 256, 22295, 256, 22097, 256, 22132, 256, 20999, 256, 22766, 256,
+ 22478, 256, 22516, 256, 22541, 256, 22411, 256, 22578, 256, 22577, 256,
+ 22700, 256, 55365, 56548, 256, 22770, 256, 22775, 256, 22790, 256, 22810,
+ 256, 22818, 256, 22882, 256, 55365, 57000, 256, 55365, 57066, 256, 23020,
+ 256, 23067, 256, 23079, 256, 23000, 256, 23142, 256, 14062, 256, 14076,
+ 256, 23304, 256, 23358, 256, 23358, 256, 55366, 56776, 256, 23491, 256,
+ 23512, 256, 23527, 256, 23539, 256, 55366, 57112, 256, 23551, 256, 23558,
+ 256, 24403, 256, 23586, 256, 14209, 256, 23648, 256, 23662, 256, 23744,
+ 256, 23693, 256, 55367, 56804, 256, 23875, 256, 55367, 56806, 256, 23918,
+ 256, 23915, 256, 23932, 256, 24033, 256, 24034, 256, 14383, 256, 24061,
+ 256, 24104, 256, 24125, 256, 24169, 256, 14434, 256, 55368, 56707, 256,
+ 14460, 256, 24240, 256, 24243, 256, 24246, 256, 24266, 256, 55400, 57234,
+ 256, 24318, 256, 55368, 57137, 256, 55368, 57137, 256, 33281, 256, 24354,
+ 256, 24354, 256, 14535, 256, 55372, 57016, 256, 55384, 56794, 256, 24418,
+ 256, 24427, 256, 14563, 256, 24474, 256, 24525, 256, 24535, 256, 24569,
+ 256, 24705, 256, 14650, 256, 14620, 256, 24724, 256, 55369, 57044, 256,
+ 24775, 256, 24904, 256, 24908, 256, 24910, 256, 24908, 256, 24954, 256,
+ 24974, 256, 25010, 256, 24996, 256, 25007, 256, 25054, 256, 25074, 256,
+ 25078, 256, 25104, 256, 25115, 256, 25181, 256, 25265, 256, 25300, 256,
+ 25424, 256, 55370, 57100, 256, 25405, 256, 25340, 256, 25448, 256, 25475,
+ 256, 25572, 256, 55370, 57329, 256, 25634, 256, 25541, 256, 25513, 256,
+ 14894, 256, 25705, 256, 25726, 256, 25757, 256, 25719, 256, 14956, 256,
+ 25935, 256, 25964, 256, 55372, 56330, 256, 26083, 256, 26360, 256, 26185,
+ 256, 15129, 256, 26257, 256, 15112, 256, 15076, 256, 20882, 256, 20885,
+ 256, 26368, 256, 26268, 256, 32941, 256, 17369, 256, 26391, 256, 26395,
+ 256, 26401, 256, 26462, 256, 26451, 256, 55372, 57283, 256, 15177, 256,
+ 26618, 256, 26501, 256, 26706, 256, 26757, 256, 55373, 56429, 256, 26766,
+ 256, 26655, 256, 26900, 256, 15261, 256, 26946, 256, 27043, 256, 27114,
+ 256, 27304, 256, 55373, 56995, 256, 27355, 256, 15384, 256, 27425, 256,
+ 55374, 56487, 256, 27476, 256, 15438, 256, 27506, 256, 27551, 256, 27578,
+ 256, 27579, 256, 55374, 56973, 256, 55367, 56587, 256, 55374, 57082, 256,
+ 27726, 256, 55375, 56508, 256, 27839, 256, 27853, 256, 27751, 256, 27926,
+ 256, 27966, 256, 28023, 256, 27969, 256, 28009, 256, 28024, 256, 28037,
+ 256, 55375, 56606, 256, 27956, 256, 28207, 256, 28270, 256, 15667, 256,
+ 28363, 256, 28359, 256, 55375, 57041, 256, 28153, 256, 28526, 256, 55375,
+ 57182, 256, 55375, 57230, 256, 28614, 256, 28729, 256, 28702, 256, 28699,
+ 256, 15766, 256, 28746, 256, 28797, 256, 28791, 256, 28845, 256, 55361,
+ 56613, 256, 28997, 256, 55376, 56931, 256, 29084, 256, 55376, 57259, 256,
+ 29224, 256, 29237, 256, 29264, 256, 55377, 56840, 256, 29312, 256, 29333,
+ 256, 55377, 57141, 256, 55378, 56340, 256, 29562, 256, 29579, 256, 16044,
+ 256, 29605, 256, 16056, 256, 16056, 256, 29767, 256, 29788, 256, 29809,
+ 256, 29829, 256, 29898, 256, 16155, 256, 29988, 256, 55379, 56374, 256,
+ 30014, 256, 55379, 56466, 256, 30064, 256, 55368, 56735, 256, 30224, 256,
+ 55379, 57249, 256, 55379, 57272, 256, 55380, 56388, 256, 16380, 256,
+ 16392, 256, 30452, 256, 55380, 56563, 256, 55380, 56562, 256, 55380,
+ 56601, 256, 55380, 56627, 256, 30494, 256, 30495, 256, 30495, 256, 30538,
+ 256, 16441, 256, 30603, 256, 16454, 256, 16534, 256, 55381, 56349, 256,
+ 30798, 256, 30860, 256, 30924, 256, 16611, 256, 55381, 56870, 256, 31062,
+ 256, 55381, 56986, 256, 55381, 57029, 256, 31119, 256, 31211, 256, 16687,
+ 256, 31296, 256, 31306, 256, 31311, 256, 55382, 56700, 256, 55382, 56999,
+ 256, 55382, 56999, 256, 31470, 256, 16898, 256, 55382, 57259, 256, 31686,
+ 256, 31689, 256, 16935, 256, 55383, 56448, 256, 31954, 256, 17056, 256,
+ 31976, 256, 31971, 256, 32000, 256, 55383, 57222, 256, 32099, 256, 17153,
+ 256, 32199, 256, 32258, 256, 32325, 256, 17204, 256, 55384, 56872, 256,
+ 55384, 56903, 256, 17241, 256, 55384, 57049, 256, 32634, 256, 55384,
+ 57150, 256, 32661, 256, 32762, 256, 32773, 256, 55385, 56538, 256, 55385,
+ 56611, 256, 32864, 256, 55385, 56744, 256, 32880, 256, 55372, 57183, 256,
+ 17365, 256, 32946, 256, 33027, 256, 17419, 256, 33086, 256, 23221, 256,
+ 55385, 57255, 256, 55385, 57269, 256, 55372, 57235, 256, 55372, 57244,
+ 256, 33281, 256, 33284, 256, 36766, 256, 17515, 256, 33425, 256, 33419,
+ 256, 33437, 256, 21171, 256, 33457, 256, 33459, 256, 33469, 256, 33510,
+ 256, 55386, 57148, 256, 33509, 256, 33565, 256, 33635, 256, 33709, 256,
+ 33571, 256, 33725, 256, 33767, 256, 33879, 256, 33619, 256, 33738, 256,
+ 33740, 256, 33756, 256, 55387, 56374, 256, 55387, 56683, 256, 55387,
+ 56533, 256, 17707, 256, 34033, 256, 34035, 256, 34070, 256, 55388, 57290,
+ 256, 34148, 256, 55387, 57132, 256, 17757, 256, 17761, 256, 55387, 57265,
+ 256, 55388, 56530, 256, 17771, 256, 34384, 256, 34396, 256, 34407, 256,
+ 34409, 256, 34473, 256, 34440, 256, 34574, 256, 34530, 256, 34681, 256,
+ 34600, 256, 34667, 256, 34694, 256, 17879, 256, 34785, 256, 34817, 256,
+ 17913, 256, 34912, 256, 34915, 256, 55389, 56935, 256, 35031, 256, 35038,
+ 256, 17973, 256, 35066, 256, 13499, 256, 55390, 56494, 256, 55390, 56678,
+ 256, 18110, 256, 18119, 256, 35488, 256, 35565, 256, 35722, 256, 35925,
+ 256, 55391, 56488, 256, 36011, 256, 36033, 256, 36123, 256, 36215, 256,
+ 55391, 57135, 256, 55362, 56324, 256, 36299, 256, 36284, 256, 36336, 256,
+ 55362, 56542, 256, 36564, 256, 36664, 256, 55393, 56786, 256, 55393,
+ 56813, 256, 37012, 256, 37105, 256, 37137, 256, 55393, 57134, 256, 37147,
+ 256, 37432, 256, 37591, 256, 37592, 256, 37500, 256, 37881, 256, 37909,
+ 256, 55394, 57338, 256, 38283, 256, 18837, 256, 38327, 256, 55395, 56695,
+ 256, 18918, 256, 38595, 256, 23986, 256, 38691, 256, 55396, 56645, 256,
+ 55396, 56858, 256, 19054, 256, 19062, 256, 38880, 256, 55397, 56330, 256,
+ 19122, 256, 55397, 56470, 256, 38923, 256, 38923, 256, 38953, 256, 55397,
+ 56758, 256, 39138, 256, 19251, 256, 39209, 256, 39335, 256, 39362, 256,
+ 39422, 256, 19406, 256, 55398, 57136, 256, 39698, 256, 40000, 256, 40189,
+ 256, 19662, 256, 19693, 256, 40295, 256, 55400, 56526, 256, 19704, 256,
+ 55400, 56581, 256, 55400, 56846, 256, 55400, 56977, 256, 40635, 256,
+ 19798, 256, 40697, 256, 40702, 256, 40709, 256, 40719, 256, 40726, 256,
+ 40763, 256, 55401, 56832,
+};
+
+/* index tables for the decomposition data */
+#define DECOMP_SHIFT1 6
+#define DECOMP_SHIFT2 4
+static const unsigned char decomp_index0[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 14, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 16, 5, 5, 5, 5, 17, 18,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 20,
+ 5, 5, 5, 5, 5, 21, 22, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 23, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+};
+
+static const unsigned short decomp_index1[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 0, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0,
+ 25, 0, 26, 27, 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 32, 33, 34, 35, 0,
+ 36, 37, 38, 0, 39, 0, 40, 0, 41, 0, 0, 0, 0, 42, 43, 44, 45, 0, 0, 0, 0,
+ 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 48, 0, 0, 0,
+ 0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 0, 53, 0, 0, 0, 0,
+ 0, 0, 54, 55, 0, 0, 0, 0, 0, 56, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 58, 59, 0, 0, 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0,
+ 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 70,
+ 71, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 0,
+ 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 84, 85, 86, 87, 88, 89, 0, 90, 91, 92, 0, 0, 0, 0,
+ 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
+ 123, 124, 125, 126, 127, 128, 129, 130, 0, 131, 132, 133, 134, 0, 0, 0,
+ 0, 0, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 0, 146, 0,
+ 0, 0, 147, 0, 148, 149, 150, 0, 151, 152, 153, 0, 154, 0, 0, 0, 155, 0,
+ 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157,
+ 158, 159, 160, 161, 162, 163, 164, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0,
+ 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 171, 0, 0, 0, 0, 0, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+ 182, 183, 184, 185, 186, 0, 0, 187, 0, 0, 188, 189, 190, 191, 192, 0,
+ 193, 194, 195, 196, 197, 0, 198, 0, 0, 0, 199, 200, 201, 202, 203, 204,
+ 205, 0, 0, 0, 0, 0, 0, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
+ 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+ 230, 231, 232, 233, 234, 235, 236, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0,
+ 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 243, 244, 245, 246, 247,
+ 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261,
+ 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 0, 0, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 0, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302,
+ 303, 304, 305, 306, 0, 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, 315,
+ 0, 316, 0, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328,
+ 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 0,
+ 347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 352, 0, 0, 0, 0, 353, 354, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378,
+ 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392,
+ 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406,
+ 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 431, 432, 433, 434, 435, 0, 436, 0,
+ 0, 437, 0, 0, 0, 0, 0, 0, 438, 439, 440, 441, 442, 443, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 444, 445,
+ 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459,
+ 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473,
+ 474, 475, 476, 477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static const unsigned short decomp_index2[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27,
+ 31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81,
+ 0, 84, 87, 90, 93, 96, 99, 0, 0, 102, 105, 108, 111, 114, 0, 0, 117, 120,
+ 123, 126, 129, 132, 0, 135, 138, 141, 144, 147, 150, 153, 156, 159, 0,
+ 162, 165, 168, 171, 174, 177, 0, 0, 180, 183, 186, 189, 192, 0, 195, 198,
+ 201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240,
+ 243, 0, 0, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279,
+ 282, 285, 288, 291, 294, 297, 300, 303, 0, 0, 306, 309, 312, 315, 318,
+ 321, 324, 327, 330, 0, 333, 336, 339, 342, 345, 348, 0, 351, 354, 357,
+ 360, 363, 366, 369, 372, 0, 0, 375, 378, 381, 384, 387, 390, 393, 0, 0,
+ 396, 399, 402, 405, 408, 411, 0, 0, 414, 417, 420, 423, 426, 429, 432,
+ 435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 0, 0, 468, 471,
+ 474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513,
+ 516, 519, 522, 525, 528, 531, 534, 537, 539, 542, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 545, 548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584, 587,
+ 590, 593, 596, 599, 602, 605, 608, 611, 614, 617, 620, 623, 0, 626, 629,
+ 632, 635, 638, 641, 0, 0, 644, 647, 650, 653, 656, 659, 662, 665, 668,
+ 671, 674, 677, 680, 683, 686, 689, 0, 0, 692, 695, 698, 701, 704, 707,
+ 710, 713, 716, 719, 722, 725, 728, 731, 734, 737, 740, 743, 746, 749,
+ 752, 755, 758, 761, 764, 767, 770, 773, 776, 779, 782, 785, 788, 791,
+ 794, 797, 0, 0, 800, 803, 0, 0, 0, 0, 0, 0, 806, 809, 812, 815, 818, 821,
+ 824, 827, 830, 833, 836, 839, 842, 845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 848, 850, 852, 854, 856, 858, 860, 862, 864, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 866, 869, 872, 875, 878, 881, 0, 0, 884, 886, 888,
+ 890, 892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 894, 896, 0, 898, 900, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 905, 0, 0, 0,
+ 908, 0, 0, 0, 0, 0, 910, 913, 916, 919, 921, 924, 927, 0, 930, 0, 933,
+ 936, 939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 942, 945, 948, 951, 954, 957, 960, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 963, 966, 969, 972, 975,
+ 0, 978, 980, 982, 984, 987, 990, 992, 0, 0, 0, 0, 0, 0, 0, 0, 0, 994,
+ 996, 998, 0, 1000, 1002, 0, 0, 0, 1004, 0, 0, 0, 0, 0, 0, 1006, 1009, 0,
+ 1012, 0, 0, 0, 1015, 0, 0, 0, 0, 1018, 1021, 1024, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0,
+ 0, 0, 0, 0, 1033, 1036, 0, 1039, 0, 0, 0, 1042, 0, 0, 0, 0, 1045, 1048,
+ 1051, 0, 0, 0, 0, 0, 0, 0, 1054, 1057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1060,
+ 1063, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1069, 1072, 1075, 0,
+ 0, 1078, 1081, 0, 0, 1084, 1087, 1090, 1093, 1096, 1099, 0, 0, 1102,
+ 1105, 1108, 1111, 1114, 1117, 0, 0, 1120, 1123, 1126, 1129, 1132, 1135,
+ 1138, 1141, 1144, 1147, 1150, 1153, 0, 0, 1156, 1159, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1165, 1168,
+ 1171, 1174, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1180, 1183,
+ 1186, 1189, 0, 0, 0, 0, 0, 0, 0, 1192, 0, 1195, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1201, 0, 0, 0, 0, 0, 0, 0, 1204, 0, 0, 1207, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1210, 1213, 1216,
+ 1219, 1222, 1225, 1228, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1234,
+ 1237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1240, 1243, 0, 1246,
+ 0, 0, 0, 1249, 0, 0, 1252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1255, 1258, 1261, 0, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1267,
+ 0, 0, 1270, 1273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1276,
+ 1279, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1285, 1288, 1291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1294, 0, 0, 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, 0, 0, 1300, 1303, 0, 1306,
+ 1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1315, 1318, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1321, 0, 1324, 1327, 1330, 0, 0, 0, 0,
+ 1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1336, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1339, 1342, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1345, 0, 0, 0, 0, 0, 0, 1347, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 0, 0, 0, 1353, 0, 0, 0, 0, 1356, 0, 0,
+ 0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1365, 0, 1368, 1371, 1374, 1377, 1380, 0, 0, 0, 0, 0, 0, 0,
+ 1383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1386, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1389, 0, 0, 0, 0, 1392, 0, 0, 0, 0, 1395, 0, 0, 0, 0,
+ 1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1401, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1409, 0, 1412, 0, 1415, 0,
+ 1418, 0, 1421, 0, 0, 0, 1424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1427, 0, 1430, 0, 0, 1433, 1436, 0, 1439,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1442, 1444, 1446, 0, 1448, 1450, 1452, 1454, 1456, 1458, 1460, 1462,
+ 1464, 1466, 1468, 0, 1470, 1472, 1474, 1476, 1478, 1480, 1482, 1484,
+ 1486, 1488, 1490, 1492, 1494, 1496, 1498, 1500, 1502, 1504, 0, 1506,
+ 1508, 1510, 1512, 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1530,
+ 1532, 1534, 1536, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554,
+ 1556, 1558, 1560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1562, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1564, 1566, 1568, 1570,
+ 1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594,
+ 1596, 1598, 1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614, 1616, 1618,
+ 1620, 1622, 1624, 1626, 1628, 1630, 1632, 1634, 1636, 1638, 1641, 1644,
+ 1647, 1650, 1653, 1656, 1659, 1662, 1665, 1668, 1671, 1674, 1677, 1680,
+ 1683, 1686, 1689, 1692, 1695, 1698, 1701, 1704, 1707, 1710, 1713, 1716,
+ 1719, 1722, 1725, 1728, 1731, 1734, 1737, 1740, 1743, 1746, 1749, 1752,
+ 1755, 1758, 1761, 1764, 1767, 1770, 1773, 1776, 1779, 1782, 1785, 1788,
+ 1791, 1794, 1797, 1800, 1803, 1806, 1809, 1812, 1815, 1818, 1821, 1824,
+ 1827, 1830, 1833, 1836, 1839, 1842, 1845, 1848, 1851, 1854, 1857, 1860,
+ 1863, 1866, 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896,
+ 1899, 1902, 1905, 1908, 1911, 1914, 1917, 1920, 1923, 1926, 1929, 1932,
+ 1935, 1938, 1941, 1944, 1947, 1950, 1953, 1956, 1959, 1962, 1965, 1968,
+ 1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004,
+ 2007, 2010, 2013, 2016, 2019, 2022, 2025, 2028, 2031, 2034, 2037, 2040,
+ 2043, 2046, 2049, 2052, 2055, 2058, 2061, 2064, 2067, 2070, 2073, 2076,
+ 2079, 2082, 2085, 2088, 2091, 2094, 2097, 2100, 2103, 0, 0, 0, 0, 2106,
+ 2109, 2112, 2115, 2118, 2121, 2124, 2127, 2130, 2133, 2136, 2139, 2142,
+ 2145, 2148, 2151, 2154, 2157, 2160, 2163, 2166, 2169, 2172, 2175, 2178,
+ 2181, 2184, 2187, 2190, 2193, 2196, 2199, 2202, 2205, 2208, 2211, 2214,
+ 2217, 2220, 2223, 2226, 2229, 2232, 2235, 2238, 2241, 2244, 2247, 2250,
+ 2253, 2256, 2259, 2262, 2265, 2268, 2271, 2274, 2277, 2280, 2283, 2286,
+ 2289, 2292, 2295, 2298, 2301, 2304, 2307, 2310, 2313, 2316, 2319, 2322,
+ 2325, 2328, 2331, 2334, 2337, 2340, 2343, 2346, 2349, 2352, 2355, 2358,
+ 2361, 2364, 2367, 2370, 2373, 0, 0, 0, 0, 0, 0, 2376, 2379, 2382, 2385,
+ 2388, 2391, 2394, 2397, 2400, 2403, 2406, 2409, 2412, 2415, 2418, 2421,
+ 2424, 2427, 2430, 2433, 2436, 2439, 0, 0, 2442, 2445, 2448, 2451, 2454,
+ 2457, 0, 0, 2460, 2463, 2466, 2469, 2472, 2475, 2478, 2481, 2484, 2487,
+ 2490, 2493, 2496, 2499, 2502, 2505, 2508, 2511, 2514, 2517, 2520, 2523,
+ 2526, 2529, 2532, 2535, 2538, 2541, 2544, 2547, 2550, 2553, 2556, 2559,
+ 2562, 2565, 2568, 2571, 0, 0, 2574, 2577, 2580, 2583, 2586, 2589, 0, 0,
+ 2592, 2595, 2598, 2601, 2604, 2607, 2610, 2613, 0, 2616, 0, 2619, 0,
+ 2622, 0, 2625, 2628, 2631, 2634, 2637, 2640, 2643, 2646, 2649, 2652,
+ 2655, 2658, 2661, 2664, 2667, 2670, 2673, 2676, 2679, 2681, 2684, 2686,
+ 2689, 2691, 2694, 2696, 2699, 2701, 2704, 2706, 2709, 0, 0, 2711, 2714,
+ 2717, 2720, 2723, 2726, 2729, 2732, 2735, 2738, 2741, 2744, 2747, 2750,
+ 2753, 2756, 2759, 2762, 2765, 2768, 2771, 2774, 2777, 2780, 2783, 2786,
+ 2789, 2792, 2795, 2798, 2801, 2804, 2807, 2810, 2813, 2816, 2819, 2822,
+ 2825, 2828, 2831, 2834, 2837, 2840, 2843, 2846, 2849, 2852, 2855, 2858,
+ 2861, 2864, 2867, 0, 2870, 2873, 2876, 2879, 2882, 2885, 2887, 2890,
+ 2893, 2895, 2898, 2901, 2904, 2907, 2910, 0, 2913, 2916, 2919, 2922,
+ 2924, 2927, 2929, 2932, 2935, 2938, 2941, 2944, 2947, 2950, 0, 0, 2952,
+ 2955, 2958, 2961, 2964, 2967, 0, 2969, 2972, 2975, 2978, 2981, 2984,
+ 2987, 2989, 2992, 2995, 2998, 3001, 3004, 3007, 3010, 3012, 3015, 3018,
+ 3020, 0, 0, 3022, 3025, 3028, 0, 3031, 3034, 3037, 3040, 3042, 3045,
+ 3047, 3050, 3052, 0, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069,
+ 3071, 3073, 3075, 0, 0, 0, 0, 0, 0, 3077, 0, 0, 0, 0, 0, 3079, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3082, 3084, 3087, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3091, 0, 0, 0, 3093, 3096, 0, 3100, 3103, 0, 0, 0, 0, 3107, 0, 3110, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3113, 3116, 3119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3122, 0, 0, 0, 0, 0, 0, 0, 3127, 3129, 3131, 0, 0, 3133, 3135,
+ 3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159,
+ 3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183,
+ 3185, 0, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205,
+ 3207, 3209, 3211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3213, 0, 0, 0, 0, 0,
+ 0, 0, 3216, 3220, 3224, 3226, 0, 3229, 3233, 3237, 0, 3239, 3242, 3244,
+ 3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 0, 3262, 3264, 0, 0,
+ 3267, 3269, 3271, 3273, 3275, 0, 0, 3277, 3280, 3284, 0, 3287, 0, 3289,
+ 0, 3291, 0, 3293, 3295, 3297, 3299, 0, 3301, 3303, 3305, 0, 3307, 3309,
+ 3311, 3313, 3315, 3317, 3319, 0, 3321, 3325, 3327, 3329, 3331, 3333, 0,
+ 0, 0, 0, 3335, 3337, 3339, 3341, 3343, 0, 0, 0, 0, 0, 0, 3345, 3349,
+ 3353, 3358, 3362, 3366, 3370, 3374, 3378, 3382, 3386, 3390, 3394, 3398,
+ 3402, 3406, 3409, 3411, 3414, 3418, 3421, 3423, 3426, 3430, 3435, 3438,
+ 3440, 3443, 3447, 3449, 3451, 3453, 3455, 3457, 3460, 3464, 3467, 3469,
+ 3472, 3476, 3481, 3484, 3486, 3489, 3493, 3495, 3497, 3499, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 3501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3505, 3508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3511,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3514, 3517, 3520, 0, 0, 0, 0,
+ 3523, 0, 0, 0, 0, 3526, 0, 0, 3529, 0, 0, 0, 0, 0, 0, 0, 3532, 0, 3535,
+ 0, 0, 0, 0, 0, 3538, 3541, 0, 3545, 3548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 3552, 0, 0, 3555, 0, 0, 3558, 0, 3561, 0, 0, 0, 0, 0,
+ 0, 3564, 0, 3567, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3570, 3573, 3576, 3579,
+ 3582, 0, 0, 3585, 3588, 0, 0, 3591, 3594, 0, 0, 0, 0, 0, 0, 3597, 3600,
+ 0, 0, 3603, 3606, 0, 0, 3609, 3612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 3615, 3618, 3621, 3624, 3627, 3630, 3633, 3636, 0, 0,
+ 0, 0, 0, 0, 3639, 3642, 3645, 3648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3651, 3653, 0, 0, 0, 0, 0, 3655, 3657, 3659, 3661, 3663, 3665, 3667,
+ 3669, 3671, 3673, 3676, 3679, 3682, 3685, 3688, 3691, 3694, 3697, 3700,
+ 3703, 3706, 3710, 3714, 3718, 3722, 3726, 3730, 3734, 3738, 3742, 3747,
+ 3752, 3757, 3762, 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3800, 3803,
+ 3806, 3809, 3812, 3815, 3818, 3821, 3824, 3828, 3832, 3836, 3840, 3844,
+ 3848, 3852, 3856, 3860, 3864, 3868, 3872, 3876, 3880, 3884, 3888, 3892,
+ 3896, 3900, 3904, 3908, 3912, 3916, 3920, 3924, 3928, 3932, 3936, 3940,
+ 3944, 3948, 3952, 3956, 3960, 3964, 3968, 3972, 3974, 3976, 3978, 3980,
+ 3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004,
+ 4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4024, 4026, 4028,
+ 4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046, 4048, 4050, 4052,
+ 4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4078, 0, 0, 0, 0, 0,
+ 0, 0, 4083, 4087, 4090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4097,
+ 4099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4101, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4103, 0, 0, 0, 4105, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121,
+ 4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145,
+ 4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169,
+ 4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193,
+ 4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217,
+ 4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241,
+ 4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265,
+ 4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289,
+ 4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313,
+ 4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337,
+ 4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361,
+ 4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385,
+ 4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409,
+ 4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433,
+ 4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457,
+ 4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481,
+ 4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505,
+ 4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529,
+ 4531, 4533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4535, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4537, 0, 4539, 4541, 4543, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4545, 0, 4548, 0, 4551, 0,
+ 4554, 0, 4557, 0, 4560, 0, 4563, 0, 4566, 0, 4569, 0, 4572, 0, 4575, 0,
+ 4578, 0, 0, 4581, 0, 4584, 0, 4587, 0, 0, 0, 0, 0, 0, 4590, 4593, 0,
+ 4596, 4599, 0, 4602, 4605, 0, 4608, 4611, 0, 4614, 4617, 0, 0, 0, 0, 0,
+ 0, 4620, 0, 0, 0, 0, 0, 0, 4623, 4626, 0, 4629, 4632, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 4635, 0, 4638, 0, 4641, 0, 4644, 0, 4647, 0, 4650, 0,
+ 4653, 0, 4656, 0, 4659, 0, 4662, 0, 4665, 0, 4668, 0, 0, 4671, 0, 4674,
+ 0, 4677, 0, 0, 0, 0, 0, 0, 4680, 4683, 0, 4686, 4689, 0, 4692, 4695, 0,
+ 4698, 4701, 0, 4704, 4707, 0, 0, 0, 0, 0, 0, 4710, 0, 0, 4713, 4716,
+ 4719, 4722, 0, 0, 0, 4725, 4728, 0, 4731, 4733, 4735, 4737, 4739, 4741,
+ 4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765,
+ 4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789,
+ 4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813,
+ 4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837,
+ 4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861,
+ 4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885,
+ 4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909,
+ 4911, 4913, 4915, 4917, 0, 0, 0, 4919, 4921, 4923, 4925, 4927, 4929,
+ 4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4951, 4955, 4959,
+ 4963, 4967, 4971, 4975, 4979, 4983, 4987, 4991, 4995, 4999, 5003, 5008,
+ 5013, 5018, 5023, 5028, 5033, 5038, 5043, 5048, 5053, 5058, 5063, 5068,
+ 5073, 5078, 5086, 0, 5093, 5097, 5101, 5105, 5109, 5113, 5117, 5121,
+ 5125, 5129, 5133, 5137, 5141, 5145, 5149, 5153, 5157, 5161, 5165, 5169,
+ 5173, 5177, 5181, 5185, 5189, 5193, 5197, 5201, 5205, 5209, 5213, 5217,
+ 5221, 5225, 5229, 5233, 5237, 5239, 5241, 5243, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5245, 5249, 5252, 5255, 5258, 5261, 5264, 5267, 5270, 5273, 5276, 5279,
+ 5282, 5285, 5288, 5291, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308,
+ 5310, 5312, 5314, 5316, 5318, 5320, 5322, 5325, 5328, 5331, 5334, 5337,
+ 5340, 5343, 5346, 5349, 5352, 5355, 5358, 5361, 5364, 5370, 5375, 0,
+ 5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, 5396, 5398, 5400,
+ 5402, 5404, 5406, 5408, 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424,
+ 5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448,
+ 5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, 5470, 5472,
+ 5474, 5476, 5479, 5482, 5485, 5488, 5491, 5494, 5497, 5500, 5503, 5506,
+ 5509, 5512, 5515, 5518, 5521, 5524, 5527, 5530, 5533, 5536, 5539, 5542,
+ 5545, 5548, 5552, 5556, 5560, 5563, 5567, 5570, 5574, 5576, 5578, 5580,
+ 5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604,
+ 5606, 5608, 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628,
+ 5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652,
+ 5654, 5656, 5658, 5660, 5662, 5664, 5666, 0, 5668, 5673, 5678, 5683,
+ 5687, 5692, 5696, 5700, 5706, 5711, 5715, 5719, 5723, 5728, 5733, 5737,
+ 5741, 5744, 5748, 5753, 5758, 5761, 5767, 5774, 5780, 5784, 5790, 5796,
+ 5801, 5805, 5809, 5813, 5818, 5824, 5829, 5833, 5837, 5841, 5844, 5847,
+ 5850, 5853, 5857, 5861, 5867, 5871, 5876, 5882, 5886, 5889, 5892, 5898,
+ 5903, 5909, 5913, 5919, 5922, 5926, 5930, 5934, 5938, 5942, 5947, 5951,
+ 5954, 5958, 5962, 5966, 5971, 5975, 5979, 5983, 5989, 5994, 5997, 6003,
+ 6006, 6011, 6016, 6020, 6024, 6028, 6033, 6036, 6040, 6045, 6048, 6054,
+ 6058, 6061, 6064, 6067, 6070, 6073, 6076, 6079, 6082, 6085, 6088, 6092,
+ 6096, 6100, 6104, 6108, 6112, 6116, 6120, 6124, 6128, 6132, 6136, 6140,
+ 6144, 6148, 6152, 6155, 6158, 6162, 6165, 6168, 6171, 6175, 6179, 6182,
+ 6185, 6188, 6191, 6194, 6199, 6202, 6205, 6208, 6211, 6214, 6217, 6220,
+ 6223, 6227, 6232, 6235, 6238, 6241, 6244, 6247, 6250, 6253, 6257, 6261,
+ 6265, 6269, 6272, 6275, 6278, 6281, 6284, 6287, 6290, 6293, 6296, 6299,
+ 6303, 6307, 6310, 6314, 6318, 6322, 6325, 6329, 6333, 6338, 6341, 6345,
+ 6349, 6353, 6357, 6363, 6370, 6373, 6376, 6379, 6382, 6385, 6388, 6391,
+ 6394, 6397, 6400, 6403, 6406, 6409, 6412, 6415, 6418, 6421, 6424, 6429,
+ 6432, 6435, 6438, 6443, 6447, 6450, 6453, 6456, 6459, 6462, 6465, 6468,
+ 6471, 6474, 6477, 6481, 6484, 6487, 6491, 6495, 6498, 6503, 6507, 6510,
+ 6513, 6516, 6519, 6523, 6527, 6530, 6533, 6536, 6539, 6542, 6545, 6548,
+ 6551, 6554, 6558, 6562, 6566, 6570, 6574, 6578, 6582, 6586, 6590, 6594,
+ 6598, 6602, 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, 6638, 6642,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6646, 6648, 0, 0, 6650, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6652, 6654, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6656, 6658, 6660,
+ 6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684,
+ 6686, 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708,
+ 6710, 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732,
+ 6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756,
+ 6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780,
+ 6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804,
+ 6806, 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828,
+ 6830, 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852,
+ 6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876,
+ 6878, 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900,
+ 6902, 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924,
+ 6926, 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948,
+ 6950, 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972,
+ 6974, 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996,
+ 6998, 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020,
+ 7022, 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044,
+ 7046, 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068,
+ 7070, 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092,
+ 7094, 7096, 7098, 7100, 7102, 7104, 7106, 7108, 7110, 7112, 7114, 7116,
+ 7118, 7120, 7122, 7124, 7126, 7128, 7130, 7132, 7134, 7136, 7138, 7140,
+ 7142, 7144, 7146, 7148, 7150, 7152, 7154, 7156, 7158, 7160, 7162, 7164,
+ 7166, 7168, 7170, 7172, 7174, 7176, 7178, 7180, 7182, 7184, 7186, 7188,
+ 7190, 7192, 7194, 7196, 7198, 7200, 7202, 0, 0, 7204, 0, 7206, 0, 0,
+ 7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, 7224, 7226, 0, 7228, 0,
+ 7230, 0, 0, 7232, 7234, 0, 0, 0, 7236, 7238, 7240, 7242, 7244, 7246,
+ 7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 7266, 7268, 7270,
+ 7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, 7290, 7292, 7294,
+ 7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, 7314, 7316, 7318,
+ 7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, 7338, 7340, 7342,
+ 7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, 7362, 7364, 7366,
+ 7368, 7371, 0, 0, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389,
+ 7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413,
+ 7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437,
+ 7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461,
+ 7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485,
+ 7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509,
+ 7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533,
+ 7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557,
+ 7559, 7561, 7563, 7566, 7569, 7572, 7574, 7576, 7578, 7581, 7584, 7587,
+ 7589, 0, 0, 0, 0, 0, 0, 7591, 7594, 7597, 7600, 7604, 7608, 7611, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7614, 7617, 7620, 7623, 7626, 0, 0, 0, 0,
+ 0, 7629, 0, 7632, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651,
+ 7653, 7655, 7658, 7661, 7664, 7667, 7670, 7673, 7676, 7679, 7682, 7685,
+ 7688, 7691, 0, 7694, 7697, 7700, 7703, 7706, 0, 7709, 0, 7712, 7715, 0,
+ 7718, 7721, 0, 7724, 7727, 7730, 7733, 7736, 7739, 7742, 7745, 7748,
+ 7751, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774,
+ 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798,
+ 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822,
+ 7824, 7826, 7828, 7830, 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846,
+ 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870,
+ 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894,
+ 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918,
+ 7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7936, 7938, 7940, 7942,
+ 7944, 7946, 7948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 7950, 7952, 7954, 7956, 7958, 7960, 7962, 7964, 7966, 7968, 7970, 7972,
+ 7974, 7976, 7978, 7980, 7982, 7984, 7986, 7988, 7990, 7992, 7994, 7996,
+ 7999, 8002, 8005, 8008, 8011, 8014, 8017, 8020, 8023, 8026, 8029, 8032,
+ 8035, 8038, 8041, 8044, 8047, 8050, 8052, 8054, 8056, 8058, 8061, 8064,
+ 8067, 8070, 8073, 8076, 8079, 8082, 8085, 8088, 8091, 8094, 8097, 8100,
+ 8103, 8106, 8109, 8112, 8115, 8118, 8121, 8124, 8127, 8130, 8133, 8136,
+ 8139, 8142, 8145, 8148, 8151, 8154, 8157, 8160, 8163, 8166, 8169, 8172,
+ 8175, 8178, 8181, 8184, 8187, 8190, 8193, 8196, 8199, 8202, 8205, 8208,
+ 8211, 8214, 8217, 8220, 8223, 8226, 8229, 8232, 8235, 8238, 8241, 8244,
+ 8247, 8250, 8253, 8256, 8259, 8262, 8265, 8268, 8271, 8274, 8277, 8280,
+ 8283, 8286, 8289, 8292, 8295, 8298, 8301, 8304, 8307, 8310, 8313, 8316,
+ 8319, 8322, 8325, 8328, 8331, 8334, 8337, 8340, 8344, 8348, 8352, 8356,
+ 8360, 8364, 8367, 8370, 8373, 8376, 8379, 8382, 8385, 8388, 8391, 8394,
+ 8397, 8400, 8403, 8406, 8409, 8412, 8415, 8418, 8421, 8424, 8427, 8430,
+ 8433, 8436, 8439, 8442, 8445, 8448, 8451, 8454, 8457, 8460, 8463, 8466,
+ 8469, 8472, 8475, 8478, 8481, 8484, 8487, 8490, 8493, 8496, 8499, 8502,
+ 8505, 8508, 8511, 8514, 8517, 8520, 8523, 8526, 8529, 8532, 8535, 8538,
+ 8541, 8544, 8547, 8550, 8553, 8556, 8559, 8562, 8565, 8568, 8571, 8574,
+ 8577, 8580, 8583, 8586, 8589, 8592, 8595, 8598, 8601, 8604, 8607, 8610,
+ 8613, 8616, 8619, 8622, 8625, 8628, 8631, 8634, 8637, 8640, 8643, 8646,
+ 8649, 8652, 8655, 8658, 8661, 8664, 8667, 8670, 8673, 8676, 8679, 8682,
+ 8685, 8688, 8691, 8694, 8697, 8700, 8703, 8706, 8709, 8712, 8715, 8718,
+ 8721, 8724, 8727, 8730, 8733, 8736, 8739, 8742, 8745, 8748, 8751, 8754,
+ 8757, 8760, 8763, 8766, 8769, 8772, 8775, 8778, 8781, 8784, 8787, 8790,
+ 8794, 8798, 8802, 8805, 8808, 8811, 8814, 8817, 8820, 8823, 8826, 8829,
+ 8832, 8835, 8838, 8841, 8844, 8847, 8850, 8853, 8856, 8859, 8862, 8865,
+ 8868, 8871, 8874, 8877, 8880, 8883, 8886, 8889, 8892, 8895, 8898, 8901,
+ 8904, 8907, 8910, 8913, 8916, 8919, 8922, 8925, 8928, 8931, 8934, 8937,
+ 8940, 8943, 8946, 8949, 8952, 8955, 8958, 8961, 8964, 8967, 8970, 8973,
+ 8976, 8979, 8982, 8985, 8988, 8991, 8994, 8997, 9000, 9003, 9006, 9009,
+ 9012, 9015, 9018, 0, 0, 9021, 9025, 9029, 9033, 9037, 9041, 9045, 9049,
+ 9053, 9057, 9061, 9065, 9069, 9073, 9077, 9081, 9085, 9089, 9093, 9097,
+ 9101, 9105, 9109, 9113, 9117, 9121, 9125, 9129, 9133, 9137, 9141, 9145,
+ 9149, 9153, 9157, 9161, 9165, 9169, 9173, 9177, 9181, 9185, 9189, 9193,
+ 9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9233, 9237, 9241,
+ 9245, 9249, 9253, 9257, 9261, 9265, 9269, 9273, 0, 0, 9277, 9281, 9285,
+ 9289, 9293, 9297, 9301, 9305, 9309, 9313, 9317, 9321, 9325, 9329, 9333,
+ 9337, 9341, 9345, 9349, 9353, 9357, 9361, 9365, 9369, 9373, 9377, 9381,
+ 9385, 9389, 9393, 9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429,
+ 9433, 9437, 9441, 9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477,
+ 9481, 9485, 9489, 0, 0, 0, 0, 0, 0, 0, 0, 9493, 9497, 9501, 9506, 9511,
+ 9516, 9521, 9526, 9531, 9536, 9540, 9559, 9568, 0, 0, 0, 9573, 9575,
+ 9577, 9579, 9581, 9583, 9585, 9587, 9589, 9591, 0, 0, 0, 0, 0, 0, 9593,
+ 9595, 9597, 9599, 9601, 9603, 9605, 9607, 9609, 9611, 9613, 9615, 9617,
+ 9619, 9621, 9623, 9625, 9627, 9629, 9631, 9633, 0, 0, 9635, 9637, 9639,
+ 9641, 9643, 9645, 9647, 9649, 9651, 9653, 9655, 9657, 0, 9659, 9661,
+ 9663, 9665, 9667, 9669, 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685,
+ 9687, 9689, 9691, 9693, 9695, 0, 9697, 9699, 9701, 9703, 0, 0, 0, 0,
+ 9705, 9708, 9711, 0, 9714, 0, 9717, 9720, 9723, 9726, 9729, 9732, 9735,
+ 9738, 9741, 9744, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763,
+ 9765, 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787,
+ 9789, 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811,
+ 9813, 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835,
+ 9837, 9839, 9841, 9843, 9845, 9847, 9849, 9851, 9853, 9855, 9857, 9859,
+ 9861, 9863, 9865, 9867, 9869, 9871, 9873, 9875, 9877, 9879, 9881, 9883,
+ 9885, 9887, 9889, 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907,
+ 9909, 9911, 9913, 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931,
+ 9933, 9935, 9937, 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955,
+ 9957, 9959, 9961, 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979,
+ 9981, 9984, 9987, 9990, 9993, 9996, 9999, 10002, 0, 0, 0, 0, 10005,
+ 10007, 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025,
+ 10027, 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045,
+ 10047, 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065,
+ 10067, 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085,
+ 10087, 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105,
+ 10107, 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125,
+ 10127, 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145,
+ 10147, 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165,
+ 10167, 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185,
+ 10187, 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205,
+ 10207, 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225,
+ 10227, 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245,
+ 10247, 10249, 10251, 10253, 10255, 10257, 10259, 10261, 10263, 10265,
+ 10267, 10269, 10271, 10273, 10275, 10277, 10279, 10281, 10283, 10285,
+ 10287, 10289, 10291, 10293, 10295, 10297, 10299, 10301, 10303, 10305,
+ 10307, 10309, 10311, 10313, 10315, 10317, 10319, 10321, 10323, 10325,
+ 10327, 10329, 10331, 10333, 10335, 10337, 10339, 10341, 10343, 10345,
+ 10347, 10349, 10351, 10353, 10355, 10357, 10359, 10361, 10363, 10365,
+ 10367, 10369, 10371, 10373, 10375, 10377, 10379, 10381, 10383, 0, 0, 0,
+ 10385, 10387, 10389, 10391, 10393, 10395, 0, 0, 10397, 10399, 10401,
+ 10403, 10405, 10407, 0, 0, 10409, 10411, 10413, 10415, 10417, 10419, 0,
+ 0, 10421, 10423, 10425, 0, 0, 0, 10427, 10429, 10431, 10433, 10435,
+ 10437, 10439, 0, 10441, 10443, 10445, 10447, 10449, 10451, 10453, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10455, 0, 10460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 10465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10470, 10475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10480, 10485, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10490, 10495, 0, 10500, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 10505, 10510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 10515, 10520, 10525, 10530, 10535, 10540, 10545, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10550, 10555, 10560,
+ 10565, 10570, 10575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10580,
+ 10582, 10584, 10586, 10588, 10590, 10592, 10594, 10596, 10598, 10600,
+ 10602, 10604, 10606, 10608, 10610, 10612, 10614, 10616, 10618, 10620,
+ 10622, 10624, 10626, 10628, 10630, 10632, 10634, 10636, 10638, 10640,
+ 10642, 10644, 10646, 10648, 10650, 10652, 10654, 10656, 10658, 10660,
+ 10662, 10664, 10666, 10668, 10670, 10672, 10674, 10676, 10678, 10680,
+ 10682, 10684, 10686, 10688, 10690, 10692, 10694, 10696, 10698, 10700,
+ 10702, 10704, 10706, 10708, 10710, 10712, 10714, 10716, 10718, 10720,
+ 10722, 10724, 10726, 10728, 10730, 10732, 10734, 10736, 10738, 10740,
+ 10742, 10744, 10746, 10748, 0, 10750, 10752, 10754, 10756, 10758, 10760,
+ 10762, 10764, 10766, 10768, 10770, 10772, 10774, 10776, 10778, 10780,
+ 10782, 10784, 10786, 10788, 10790, 10792, 10794, 10796, 10798, 10800,
+ 10802, 10804, 10806, 10808, 10810, 10812, 10814, 10816, 10818, 10820,
+ 10822, 10824, 10826, 10828, 10830, 10832, 10834, 10836, 10838, 10840,
+ 10842, 10844, 10846, 10848, 10850, 10852, 10854, 10856, 10858, 10860,
+ 10862, 10864, 10866, 10868, 10870, 10872, 10874, 10876, 10878, 10880,
+ 10882, 10884, 10886, 10888, 10890, 0, 10892, 10894, 0, 0, 10896, 0, 0,
+ 10898, 10900, 0, 0, 10902, 10904, 10906, 10908, 0, 10910, 10912, 10914,
+ 10916, 10918, 10920, 10922, 10924, 10926, 10928, 10930, 10932, 0, 10934,
+ 0, 10936, 10938, 10940, 10942, 10944, 10946, 10948, 0, 10950, 10952,
+ 10954, 10956, 10958, 10960, 10962, 10964, 10966, 10968, 10970, 10972,
+ 10974, 10976, 10978, 10980, 10982, 10984, 10986, 10988, 10990, 10992,
+ 10994, 10996, 10998, 11000, 11002, 11004, 11006, 11008, 11010, 11012,
+ 11014, 11016, 11018, 11020, 11022, 11024, 11026, 11028, 11030, 11032,
+ 11034, 11036, 11038, 11040, 11042, 11044, 11046, 11048, 11050, 11052,
+ 11054, 11056, 11058, 11060, 11062, 11064, 11066, 11068, 11070, 11072,
+ 11074, 11076, 11078, 0, 11080, 11082, 11084, 11086, 0, 0, 11088, 11090,
+ 11092, 11094, 11096, 11098, 11100, 11102, 0, 11104, 11106, 11108, 11110,
+ 11112, 11114, 11116, 0, 11118, 11120, 11122, 11124, 11126, 11128, 11130,
+ 11132, 11134, 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150,
+ 11152, 11154, 11156, 11158, 11160, 11162, 11164, 11166, 11168, 11170,
+ 11172, 0, 11174, 11176, 11178, 11180, 0, 11182, 11184, 11186, 11188,
+ 11190, 0, 11192, 0, 0, 0, 11194, 11196, 11198, 11200, 11202, 11204,
+ 11206, 0, 11208, 11210, 11212, 11214, 11216, 11218, 11220, 11222, 11224,
+ 11226, 11228, 11230, 11232, 11234, 11236, 11238, 11240, 11242, 11244,
+ 11246, 11248, 11250, 11252, 11254, 11256, 11258, 11260, 11262, 11264,
+ 11266, 11268, 11270, 11272, 11274, 11276, 11278, 11280, 11282, 11284,
+ 11286, 11288, 11290, 11292, 11294, 11296, 11298, 11300, 11302, 11304,
+ 11306, 11308, 11310, 11312, 11314, 11316, 11318, 11320, 11322, 11324,
+ 11326, 11328, 11330, 11332, 11334, 11336, 11338, 11340, 11342, 11344,
+ 11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, 11362, 11364,
+ 11366, 11368, 11370, 11372, 11374, 11376, 11378, 11380, 11382, 11384,
+ 11386, 11388, 11390, 11392, 11394, 11396, 11398, 11400, 11402, 11404,
+ 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424,
+ 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444,
+ 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464,
+ 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484,
+ 11486, 11488, 11490, 11492, 11494, 11496, 11498, 11500, 11502, 11504,
+ 11506, 11508, 11510, 11512, 11514, 11516, 11518, 11520, 11522, 11524,
+ 11526, 11528, 11530, 11532, 11534, 11536, 11538, 11540, 11542, 11544,
+ 11546, 11548, 11550, 11552, 11554, 11556, 11558, 11560, 11562, 11564,
+ 11566, 11568, 11570, 11572, 11574, 11576, 11578, 11580, 11582, 11584,
+ 11586, 11588, 11590, 11592, 11594, 11596, 11598, 11600, 11602, 11604,
+ 11606, 11608, 11610, 11612, 11614, 11616, 11618, 11620, 11622, 11624,
+ 11626, 11628, 11630, 11632, 11634, 11636, 11638, 11640, 11642, 11644,
+ 11646, 11648, 11650, 11652, 11654, 11656, 11658, 11660, 11662, 11664,
+ 11666, 11668, 11670, 11672, 11674, 11676, 11678, 11680, 11682, 11684,
+ 11686, 11688, 11690, 11692, 11694, 11696, 11698, 11700, 11702, 11704,
+ 11706, 11708, 11710, 11712, 11714, 11716, 11718, 11720, 11722, 11724,
+ 11726, 11728, 11730, 11732, 11734, 11736, 11738, 11740, 11742, 11744,
+ 11746, 11748, 11750, 11752, 11754, 11756, 11758, 11760, 11762, 11764,
+ 11766, 11768, 11770, 11772, 11774, 11776, 11778, 11780, 11782, 11784,
+ 11786, 11788, 11790, 11792, 11794, 11796, 11798, 11800, 11802, 11804,
+ 11806, 11808, 11810, 11812, 11814, 11816, 11818, 11820, 11822, 11824,
+ 11826, 11828, 11830, 11832, 11834, 11836, 11838, 11840, 11842, 11844,
+ 11846, 11848, 11850, 11852, 11854, 11856, 11858, 11860, 11862, 11864,
+ 11866, 11868, 11870, 11872, 11874, 11876, 11878, 11880, 11882, 11884,
+ 11886, 0, 0, 11888, 11890, 11892, 11894, 11896, 11898, 11900, 11902,
+ 11904, 11906, 11908, 11910, 11912, 11914, 11916, 11918, 11920, 11922,
+ 11924, 11926, 11928, 11930, 11932, 11934, 11936, 11938, 11940, 11942,
+ 11944, 11946, 11948, 11950, 11952, 11954, 11956, 11958, 11960, 11962,
+ 11964, 11966, 11968, 11970, 11972, 11974, 11976, 11978, 11980, 11982,
+ 11984, 11986, 11988, 11990, 11992, 11994, 11996, 11998, 12000, 12002,
+ 12004, 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022,
+ 12024, 12026, 12028, 12030, 12032, 12034, 12036, 12038, 12040, 12042,
+ 12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, 12062,
+ 12064, 12066, 12068, 12070, 12072, 12074, 12076, 12078, 12080, 12082,
+ 12084, 12086, 12088, 12090, 12092, 12094, 12096, 12098, 12100, 12102,
+ 12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, 12120, 12122,
+ 12124, 12126, 12128, 12130, 12132, 12134, 12136, 12138, 12140, 12142,
+ 12144, 12146, 12148, 12150, 12152, 12154, 12156, 12158, 12160, 12162,
+ 12164, 12166, 12168, 12170, 12172, 12174, 12176, 12178, 12180, 12182,
+ 12184, 12186, 12188, 12190, 12192, 12194, 12196, 12198, 12200, 12202,
+ 12204, 12206, 12208, 12210, 12212, 12214, 12216, 12218, 12220, 12222,
+ 12224, 12226, 12228, 12230, 12232, 12234, 12236, 12238, 12240, 12242,
+ 12244, 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262,
+ 12264, 12266, 12268, 12270, 12272, 12274, 12276, 12278, 12280, 12282,
+ 12284, 12286, 12288, 12290, 12292, 12294, 12296, 12298, 12300, 12302,
+ 12304, 12306, 12308, 12310, 12312, 12314, 12316, 12318, 12320, 12322,
+ 12324, 12326, 12328, 12330, 12332, 12334, 12336, 12338, 12340, 12342,
+ 12344, 12346, 12348, 12350, 12352, 12354, 12356, 12358, 12360, 12362,
+ 12364, 12366, 12368, 12370, 12372, 12374, 12376, 12378, 12380, 12382,
+ 12384, 12386, 12388, 12390, 12392, 12394, 12396, 12398, 12400, 12402,
+ 12404, 12406, 12408, 12410, 12412, 12414, 12416, 12418, 12420, 12422,
+ 12424, 12426, 12428, 12430, 12432, 12434, 12436, 12438, 12440, 12442,
+ 12444, 12446, 12448, 12450, 12452, 12454, 12456, 12458, 12460, 12462,
+ 12464, 12466, 12468, 12470, 0, 0, 12472, 12474, 12476, 12478, 12480,
+ 12482, 12484, 12486, 12488, 12490, 12492, 12494, 12496, 12498, 12500,
+ 12502, 12504, 12506, 12508, 12510, 12512, 12514, 12516, 12518, 12520,
+ 12522, 12524, 12526, 12528, 12530, 12532, 12534, 12536, 12538, 12540,
+ 12542, 12544, 12546, 12548, 12550, 12552, 12554, 12556, 12558, 12560,
+ 12562, 12564, 12566, 12568, 12570, 12572, 12574, 12576, 12578, 0, 12580,
+ 12582, 12584, 12586, 12588, 12590, 12592, 12594, 12596, 12598, 12600,
+ 12602, 12604, 12606, 12608, 12610, 12612, 12614, 12616, 12618, 12620,
+ 12622, 12624, 12626, 12628, 12630, 12632, 0, 12634, 12636, 0, 12638, 0,
+ 0, 12640, 0, 12642, 12644, 12646, 12648, 12650, 12652, 12654, 12656,
+ 12658, 12660, 0, 12662, 12664, 12666, 12668, 0, 12670, 0, 12672, 0, 0, 0,
+ 0, 0, 0, 12674, 0, 0, 0, 0, 12676, 0, 12678, 0, 12680, 0, 12682, 12684,
+ 12686, 0, 12688, 12690, 0, 12692, 0, 0, 12694, 0, 12696, 0, 12698, 0,
+ 12700, 0, 12702, 0, 12704, 12706, 0, 12708, 0, 0, 12710, 12712, 12714,
+ 12716, 0, 12718, 12720, 12722, 12724, 12726, 12728, 12730, 0, 12732,
+ 12734, 12736, 12738, 0, 12740, 12742, 12744, 12746, 0, 12748, 0, 12750,
+ 12752, 12754, 12756, 12758, 12760, 12762, 12764, 12766, 12768, 0, 12770,
+ 12772, 12774, 12776, 12778, 12780, 12782, 12784, 12786, 12788, 12790,
+ 12792, 12794, 12796, 12798, 12800, 12802, 0, 0, 0, 0, 0, 12804, 12806,
+ 12808, 0, 12810, 12812, 12814, 12816, 12818, 0, 12820, 12822, 12824,
+ 12826, 12828, 12830, 12832, 12834, 12836, 12838, 12840, 12842, 12844,
+ 12846, 12848, 12850, 12852, 0, 0, 0, 0, 12854, 12857, 12860, 12863,
+ 12866, 12869, 12872, 12875, 12878, 12881, 12884, 0, 0, 0, 0, 0, 12887,
+ 12891, 12895, 12899, 12903, 12907, 12911, 12915, 12919, 12923, 12927,
+ 12931, 12935, 12939, 12943, 12947, 12951, 12955, 12959, 12963, 12967,
+ 12971, 12975, 12979, 12983, 12987, 12991, 12995, 12997, 12999, 13002, 0,
+ 13005, 13007, 13009, 13011, 13013, 13015, 13017, 13019, 13021, 13023,
+ 13025, 13027, 13029, 13031, 13033, 13035, 13037, 13039, 13041, 13043,
+ 13045, 13047, 13049, 13051, 13053, 13055, 13057, 13060, 13063, 13066,
+ 13069, 13073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13076, 13079, 0, 0, 0, 0,
+ 13082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13085, 13088, 13091,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13093, 13095, 13097, 13099, 13101,
+ 13103, 13105, 13107, 13109, 13111, 13113, 13115, 13117, 13119, 13121,
+ 13123, 13125, 13127, 13129, 13131, 13133, 13135, 13137, 13139, 13141,
+ 13143, 13145, 13147, 13149, 13151, 13153, 13155, 13157, 13159, 13161,
+ 13163, 13165, 13167, 13169, 13171, 13173, 13175, 13177, 0, 0, 0, 0, 0,
+ 13179, 13183, 13187, 13191, 13195, 13199, 13203, 13207, 13211, 0, 0, 0,
+ 0, 0, 0, 0, 13215, 13217, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 13219, 13221, 13223, 13225, 13228, 13230, 13232, 13234, 13236, 13238,
+ 13240, 13242, 13244, 13246, 13249, 13251, 13253, 13255, 13257, 13260,
+ 13262, 13264, 13266, 13269, 13271, 13273, 13275, 13277, 13279, 13282,
+ 13284, 13286, 13288, 13290, 13292, 13294, 13296, 13298, 13300, 13302,
+ 13304, 13306, 13308, 13310, 13312, 13314, 13316, 13318, 13320, 13322,
+ 13324, 13326, 13328, 13331, 13333, 13335, 13337, 13340, 13342, 13344,
+ 13346, 13348, 13350, 13352, 13354, 13356, 13358, 13360, 13362, 13364,
+ 13366, 13368, 13370, 13372, 13374, 13376, 13378, 13380, 13382, 13384,
+ 13386, 13388, 13390, 13392, 13394, 13396, 13398, 13400, 13402, 13404,
+ 13407, 13409, 13411, 13413, 13415, 13417, 13419, 13422, 13425, 13427,
+ 13429, 13431, 13433, 13435, 13437, 13439, 13441, 13443, 13445, 13448,
+ 13450, 13452, 13454, 13456, 13459, 13461, 13463, 13465, 13467, 13469,
+ 13471, 13473, 13475, 13477, 13480, 13482, 13485, 13487, 13489, 13491,
+ 13493, 13495, 13497, 13499, 13501, 13503, 13505, 13507, 13510, 13512,
+ 13514, 13516, 13518, 13520, 13523, 13525, 13528, 13531, 13533, 13535,
+ 13537, 13539, 13542, 13545, 13547, 13549, 13551, 13553, 13555, 13557,
+ 13559, 13561, 13563, 13565, 13567, 13570, 13572, 13574, 13576, 13578,
+ 13580, 13582, 13584, 13586, 13588, 13590, 13592, 13594, 13596, 13598,
+ 13600, 13602, 13604, 13606, 13608, 13611, 13613, 13615, 13617, 13619,
+ 13621, 13624, 13626, 13628, 13630, 13632, 13634, 13636, 13638, 13640,
+ 13642, 13644, 13646, 13649, 13651, 13653, 13655, 13657, 13659, 13661,
+ 13663, 13665, 13667, 13669, 13671, 13673, 13675, 13677, 13679, 13681,
+ 13683, 13685, 13688, 13690, 13692, 13694, 13696, 13698, 13701, 13703,
+ 13705, 13707, 13709, 13711, 13713, 13715, 13717, 13720, 13722, 13724,
+ 13726, 13729, 13731, 13733, 13735, 13737, 13739, 13741, 13744, 13747,
+ 13750, 13752, 13755, 13757, 13759, 13761, 13763, 13765, 13767, 13769,
+ 13771, 13773, 13775, 13778, 13780, 13782, 13784, 13786, 13788, 13790,
+ 13793, 13795, 13797, 13800, 13803, 13805, 13807, 13809, 13811, 13813,
+ 13815, 13817, 13819, 13821, 13824, 13826, 13829, 13831, 13834, 13836,
+ 13838, 13840, 13843, 13845, 13847, 13850, 13853, 13855, 13857, 13859,
+ 13861, 13863, 13865, 13867, 13869, 13871, 13873, 13875, 13877, 13879,
+ 13882, 13884, 13887, 13889, 13892, 13894, 13897, 13900, 13903, 13905,
+ 13907, 13909, 13912, 13915, 13918, 13921, 13923, 13925, 13927, 13929,
+ 13931, 13933, 13935, 13937, 13940, 13942, 13944, 13946, 13948, 13951,
+ 13953, 13956, 13959, 13961, 13963, 13965, 13967, 13969, 13971, 13974,
+ 13977, 13980, 13982, 13984, 13987, 13989, 13991, 13993, 13996, 13998,
+ 14000, 14002, 14004, 14006, 14009, 14011, 14013, 14015, 14017, 14019,
+ 14021, 14024, 14027, 14029, 14032, 14034, 14037, 14039, 14041, 14043,
+ 14046, 14049, 14051, 14054, 14056, 14059, 14061, 14063, 14065, 14067,
+ 14069, 14071, 14074, 14077, 14080, 14083, 14085, 14087, 14089, 14091,
+ 14093, 14095, 14097, 14099, 14101, 14103, 14105, 14107, 14110, 14112,
+ 14114, 14116, 14118, 14120, 14122, 14124, 14126, 14128, 14130, 14132,
+ 14134, 14137, 14140, 14143, 14145, 14147, 14149, 14151, 14154, 14156,
+ 14159, 14161, 14163, 14166, 14169, 14171, 14173, 14175, 14177, 14179,
+ 14181, 14183, 14185, 14187, 14189, 14191, 14193, 14195, 14197, 14199,
+ 14201, 14203, 14205, 14207, 14210, 14212, 14214, 14216, 14218, 14220,
+ 14223, 14226, 14228, 14230, 14232, 14234, 14236, 14238, 14241, 14243,
+ 14245, 14247, 14249, 14252, 14255, 14257, 14259, 14261, 14264, 14266,
+ 14268, 14271, 14274, 14276, 14278, 14280, 14283, 14285, 14287, 14289,
+ 14291, 14293, 14295, 14297, 14300, 14302, 14304, 14306, 14309, 14311,
+ 14313, 14315, 14317, 14320, 14323, 14325, 14327, 14329, 14332, 14334,
+ 14337, 14339, 14341, 14343, 14346, 14348, 14350, 14352, 14354, 14356,
+ 14358, 14360, 14363, 14365, 14367, 14369, 14371, 14373, 14375, 14378,
+ 14380, 14383, 14386, 14389, 14391, 14393, 14395, 14397, 14399, 14401,
+ 14403, 14405, 0, 0,
+};
+
+/* NFC pairs */
+#define COMP_SHIFT1 2
+#define COMP_SHIFT2 1
+static const unsigned short comp_index0[] = {
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4,
+ 5, 6, 7, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0,
+ 15, 16, 17, 0, 0, 0, 0, 18, 19, 20, 21, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0,
+ 23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 0, 0, 0, 31, 32, 33, 34,
+ 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 36, 0, 37, 38, 39, 0, 0, 0, 40, 41, 42,
+ 43, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 47, 48, 49, 50, 0, 0, 0, 51,
+ 52, 53, 54, 0, 0, 0, 0, 55, 56, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 0, 0,
+ 0, 0, 61, 62, 63, 0, 0, 0, 0, 0, 64, 65, 66, 67, 0, 0, 0, 68, 69, 70, 71,
+ 0, 0, 0, 0, 72, 0, 73, 0, 0, 0, 0, 0, 74, 0, 75, 0, 0, 0, 0, 0, 76, 0, 0,
+ 0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 80, 81, 82, 83, 0, 0, 0, 0, 84,
+ 85, 86, 0, 0, 0, 0, 0, 87, 88, 0, 89, 0, 0, 0, 90, 91, 0, 92, 0, 0, 0, 0,
+ 0, 93, 94, 95, 0, 0, 0, 0, 96, 97, 98, 99, 0, 0, 0, 0, 100, 0, 0, 0, 0,
+ 0, 0, 101, 102, 0, 103, 0, 0, 0, 0, 104, 105, 106, 107, 0, 0, 0, 0, 108,
+ 109, 110, 111, 0, 0, 0, 0, 112, 113, 0, 0, 0, 0, 0, 114, 115, 116, 117,
+ 0, 0, 0, 0, 118, 119, 120, 121, 0, 0, 0, 0, 122, 0, 123, 0, 0, 0, 0, 124,
+ 125, 126, 127, 128, 0, 0, 0, 129, 130, 131, 132, 0, 0, 0, 0, 133, 134, 0,
+ 0, 0, 0, 0, 0, 135, 136, 137, 138, 0, 0, 0, 139, 140, 141, 142, 0, 0, 0,
+ 0, 0, 143, 144, 145, 0, 0, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0, 150, 0,
+ 151, 0, 0, 0, 0, 152, 153, 154, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0,
+ 156, 157, 158, 0, 0, 0, 0, 0, 159, 160, 161, 162, 0, 0, 0, 163, 0, 0, 0,
+ 164, 0, 0, 0, 165, 166, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 168,
+ 0, 0, 0, 0, 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0,
+ 172, 173, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0,
+ 0, 0, 177, 178, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0,
+ 0, 0, 0, 181, 182, 183, 0, 0, 0, 0, 0, 184, 185, 0, 0, 0, 0, 0, 0, 186,
+ 0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 188, 189, 0, 0, 0, 0, 0, 0,
+ 190, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0,
+ 0, 194, 195, 0, 0, 0, 0, 0, 0, 196, 197, 0, 0, 0, 0, 0, 0, 198, 0, 0, 0,
+ 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 200, 201, 202, 0, 0, 0, 0, 0, 203,
+ 204, 0, 0, 0, 0, 0, 0, 205, 206, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0,
+ 208, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0,
+ 0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0,
+ 0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0,
+ 0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 219, 0,
+ 0, 0, 0, 0, 0, 220, 221, 222, 0, 0, 0, 0, 0, 223, 224, 225, 0, 0, 0, 0,
+ 0, 226, 227, 228, 0, 0, 0, 0, 0, 229, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0,
+ 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 235, 0,
+ 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 238,
+ 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0,
+ 241, 0, 0, 0, 0, 0, 0, 242, 0, 243, 244, 0, 0, 0, 0, 245, 246, 0, 0, 0,
+ 0, 0, 247, 0, 248, 0, 249, 0, 0, 0, 250, 251, 252, 0, 0, 0, 0, 0, 253, 0,
+ 254, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 256, 257, 258, 0, 0, 0, 0, 0,
+ 259, 0, 260, 0, 261, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 263, 0,
+ 0, 0, 264, 265, 266, 0, 267, 0, 0, 0, 268, 0, 269, 0, 0, 0, 0, 0, 270, 0,
+ 271, 272, 0, 0, 0, 0, 273, 274, 0, 275, 0, 0, 0, 276, 0, 277, 0, 0, 0, 0,
+ 0, 0, 0, 278, 0, 0, 0, 0, 0, 279, 280, 281, 282, 0, 0, 0, 0, 283, 284, 0,
+ 285, 0, 0, 0, 286, 0, 0, 0, 287, 0, 0, 0, 288, 0, 0, 0, 289, 0, 0, 0, 0,
+ 0, 0, 290, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 0, 0,
+ 0, 293, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0,
+ 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 298, 299, 0, 0, 0,
+ 0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0,
+ 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 305, 0,
+ 0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 308,
+ 0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0,
+ 311, 312, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0,
+ 0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0,
+ 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0,
+ 0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 323, 0,
+ 0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 326, 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0,
+ 0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0,
+ 0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 334, 0, 0,
+ 0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 336, 337, 0, 0, 0, 0, 0, 0, 0,
+ 338, 0, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 0,
+ 0, 341, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0,
+ 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0,
+ 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 350, 0,
+ 0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 353,
+ 0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0,
+ 356, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0,
+ 0, 359, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 361, 0, 362, 0, 0, 0,
+ 0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 365, 0,
+ 0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 368,
+ 0, 0, 0, 0, 0, 0, 369, 370, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0,
+ 372, 0, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, 0, 0,
+ 0, 375, 0, 0, 376, 0, 0, 0, 0, 377, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 379,
+ 0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0,
+ 382, 0, 0, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 385, 0,
+ 0, 386, 0, 0, 0, 0, 387, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0,
+ 0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0,
+ 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 395, 0, 0, 0, 0, 0,
+ 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0,
+ 0, 0, 0, 399, 0, 0, 400, 0, 0, 0, 0, 401, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0,
+ 403, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 405, 0, 0, 0, 0, 0, 0,
+ 0, 406, 0, 0, 0, 0, 0, 0, 0, 407, 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, 0, 409,
+ 0, 0, 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0,
+ 0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0,
+ 0, 0, 0, 0, 0, 417, 0, 0, 0, 0, 0, 0, 0, 418, 0, 0, 0, 419, 0, 0, 420, 0,
+ 0, 0, 0, 421, 0, 0, 422, 0, 0, 0, 423, 0, 0, 0, 424, 0, 0, 0, 425, 0, 0,
+ 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, 429, 0,
+ 0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 0, 431, 0, 0, 432, 0, 0, 0, 0,
+ 433, 0, 0, 434, 0, 0, 0, 435, 0, 0, 0, 436, 0, 0, 0, 437, 0, 0, 0, 438,
+ 0, 0, 0, 439, 0, 0, 440, 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0,
+ 442, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 444, 0, 0, 0, 0, 0, 0,
+ 0, 445, 0, 0, 0, 0, 0, 0, 0, 446, 0, 0, 0, 447, 0, 0, 0, 448, 0, 0, 0,
+ 449, 0, 0, 450, 0, 0, 0, 0, 0, 0, 0, 451, 0, 0, 0, 0, 0, 0, 0, 452, 0, 0,
+ 0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, 0, 0, 0, 0, 455, 0,
+ 0, 0, 0, 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, 458,
+ 0, 0, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0, 0, 0, 0, 460, 0, 0, 0, 461, 0, 0,
+ 0, 462, 0, 0, 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, 0, 0, 464, 0, 0, 0, 465, 0,
+ 0, 0, 466, 0, 0, 0, 0, 0, 0, 467, 0, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0,
+ 0, 0, 0, 469, 0, 0, 0, 0, 0, 0, 0, 470, 0, 0, 0, 0, 0, 0, 471, 0, 0, 0,
+ 0, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 0, 473, 0, 0, 0, 0, 0, 0, 0, 474, 0,
+ 0, 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 477,
+ 0, 0, 0, 0, 0, 0, 0, 478, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 0,
+ 480, 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0,
+ 0, 483, 0, 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 485, 0, 0, 0, 0,
+ 0, 0, 0, 486, 0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 488, 0, 0, 0,
+ 0, 0, 0, 0, 489, 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0,
+ 0, 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, 0, 0, 494,
+ 0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0,
+ 497, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, 0, 0,
+ 0, 500, 0, 0, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 0, 502, 0, 0, 0, 0,
+ 0, 0, 503, 0, 0, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 0, 505, 0, 0, 0,
+ 0, 0, 0, 0, 506, 0, 0, 0, 0, 0, 0, 507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 508, 0, 0, 0, 0, 0, 0, 0, 509, 0, 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0,
+ 0, 0, 511, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 0, 0,
+ 0, 0, 0, 514, 0, 0, 0, 0, 0, 0, 0, 515, 0, 0, 0, 0, 0, 0, 516, 0, 0, 0,
+ 0, 0, 0, 0, 517, 0, 0, 0, 0, 0, 0, 0, 518, 0, 0, 0, 0, 0, 0, 0, 519, 0,
+ 0, 0, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 0, 522,
+ 0, 0, 0, 0, 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0,
+ 525, 0, 0, 0, 0, 0, 0, 0, 526, 0, 0, 0, 0, 0, 0, 0, 527, 0, 0, 0, 0, 0,
+ 0, 528, 0, 0, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0, 0, 0, 0, 530, 0, 0, 0, 0,
+ 0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 533, 0, 0, 0,
+ 0, 0, 0, 0, 534, 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 536, 0, 0,
+ 0, 0, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 0, 539,
+ 0, 0, 0, 0, 0, 0, 540, 0, 0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, 0,
+ 542, 0, 0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0,
+ 0, 545, 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 547, 0, 0, 0, 0,
+ 0, 0, 548, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, 0,
+ 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 0, 552, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0,
+ 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 556,
+ 0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0,
+ 559, 0, 0, 0, 0, 0, 0, 0, 560, 0, 0, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0, 0,
+ 0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 563, 0, 0, 0, 0, 0, 0, 564,
+};
+
+static const unsigned short comp_index1[] = {
+ 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10,
+ 0, 11, 12, 0, 13, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, 0, 0, 16, 0, 0, 0, 0,
+ 0, 17, 18, 0, 19, 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, 22, 0, 23, 0, 0, 24, 0,
+ 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 33, 34, 0, 35, 0, 36, 37, 38, 0, 0,
+ 0, 0, 0, 39, 0, 0, 0, 40, 41, 42, 43, 0, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0,
+ 0, 46, 0, 47, 0, 48, 0, 0, 49, 0, 50, 0, 51, 0, 0, 52, 53, 54, 55, 56,
+ 57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 0, 62, 0, 0, 0, 0, 0, 63, 64, 0, 0,
+ 65, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, 70, 0, 71,
+ 72, 0, 73, 0, 74, 0, 0, 75, 0, 0, 0, 0, 76, 0, 0, 77, 78, 0, 79, 0, 80,
+ 0, 0, 81, 0, 82, 83, 0, 84, 0, 0, 0, 0, 0, 85, 86, 87, 88, 89, 90, 91, 0,
+ 92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 95, 0, 0, 0, 96, 0, 0, 97, 0, 98, 99, 0,
+ 100, 0, 101, 0, 0, 102, 0, 103, 104, 0, 105, 0, 106, 0, 0, 107, 0, 108,
+ 0, 0, 0, 109, 0, 110, 0, 0, 111, 0, 112, 113, 0, 114, 0, 0, 0, 0, 0, 115,
+ 116, 117, 118, 119, 120, 121, 0, 122, 123, 0, 124, 125, 0, 0, 0, 126, 0,
+ 0, 127, 0, 0, 128, 129, 0, 130, 131, 0, 0, 0, 0, 0, 132, 0, 0, 0, 133,
+ 134, 135, 136, 137, 0, 0, 0, 138, 0, 0, 139, 140, 0, 141, 0, 142, 0, 0,
+ 143, 0, 0, 0, 0, 144, 0, 145, 146, 147, 148, 149, 150, 151, 0, 152, 153,
+ 0, 154, 0, 0, 155, 0, 0, 0, 0, 156, 157, 0, 0, 0, 0, 0, 158, 159, 0, 160,
+ 0, 161, 162, 0, 0, 0, 163, 0, 164, 0, 0, 165, 0, 166, 167, 0, 168, 0,
+ 169, 170, 171, 172, 173, 174, 175, 0, 176, 0, 177, 178, 179, 0, 0, 0, 0,
+ 0, 180, 0, 0, 0, 181, 182, 183, 184, 0, 185, 186, 0, 0, 0, 0, 0, 187, 0,
+ 188, 0, 189, 0, 0, 190, 0, 191, 0, 192, 193, 0, 194, 195, 196, 197, 198,
+ 199, 200, 0, 201, 0, 0, 202, 203, 0, 0, 0, 204, 0, 0, 0, 205, 0, 0, 0, 0,
+ 0, 206, 0, 0, 0, 0, 207, 0, 0, 208, 0, 209, 0, 0, 210, 0, 211, 0, 0, 0,
+ 0, 212, 0, 0, 213, 0, 214, 215, 0, 216, 0, 217, 0, 0, 218, 219, 0, 0, 0,
+ 0, 0, 0, 220, 221, 0, 222, 0, 223, 0, 0, 224, 0, 225, 226, 0, 227, 0, 0,
+ 0, 0, 0, 228, 229, 230, 231, 232, 233, 234, 0, 235, 0, 0, 236, 0, 0, 0,
+ 237, 0, 0, 238, 0, 0, 0, 239, 0, 0, 240, 0, 241, 242, 0, 243, 0, 244, 0,
+ 0, 245, 0, 0, 0, 0, 0, 246, 247, 0, 248, 0, 249, 0, 0, 250, 0, 251, 0, 0,
+ 0, 252, 0, 253, 0, 0, 254, 0, 255, 256, 0, 257, 0, 258, 259, 260, 261,
+ 262, 263, 264, 0, 265, 266, 0, 267, 268, 0, 0, 0, 269, 0, 0, 270, 0, 0,
+ 0, 0, 0, 0, 271, 272, 0, 273, 274, 0, 0, 0, 275, 0, 276, 0, 0, 0, 277,
+ 278, 279, 280, 281, 0, 0, 0, 282, 0, 0, 283, 284, 0, 285, 0, 286, 0, 0,
+ 287, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 289, 0, 290, 0, 0, 0, 0, 291, 292,
+ 0, 0, 293, 0, 0, 0, 0, 294, 295, 0, 0, 0, 0, 0, 0, 296, 0, 297, 0, 0, 0,
+ 0, 298, 0, 0, 299, 300, 0, 0, 301, 0, 0, 302, 0, 0, 0, 0, 0, 0, 303, 304,
+ 0, 0, 305, 0, 0, 306, 0, 307, 308, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0, 0,
+ 0, 0, 311, 0, 312, 0, 0, 313, 0, 0, 0, 0, 0, 314, 315, 0, 0, 316, 0, 0,
+ 0, 0, 317, 318, 0, 0, 0, 0, 0, 0, 319, 0, 320, 0, 0, 0, 0, 321, 0, 0,
+ 322, 323, 0, 0, 324, 0, 0, 325, 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, 328, 0,
+ 0, 329, 0, 330, 331, 0, 0, 0, 0, 0, 332, 333, 0, 0, 0, 0, 0, 0, 334, 0,
+ 335, 0, 0, 336, 0, 0, 0, 0, 0, 337, 338, 0, 0, 339, 0, 0, 340, 341, 0, 0,
+ 342, 0, 0, 343, 0, 0, 0, 0, 0, 0, 344, 0, 0, 345, 0, 0, 346, 0, 0, 0, 0,
+ 0, 347, 0, 0, 348, 0, 0, 349, 0, 0, 350, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0,
+ 352, 0, 353, 0, 0, 354, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 356, 357, 0, 0,
+ 358, 0, 0, 0, 359, 0, 0, 360, 361, 0, 0, 362, 0, 0, 0, 363, 0, 0, 364,
+ 365, 0, 0, 366, 0, 0, 0, 367, 0, 0, 368, 369, 0, 0, 370, 0, 0, 0, 371, 0,
+ 0, 0, 372, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 375, 0, 0, 376, 0,
+ 0, 377, 0, 0, 0, 0, 0, 0, 378, 0, 0, 379, 0, 0, 380, 0, 0, 0, 0, 0, 381,
+ 0, 382, 0, 383, 384, 0, 0, 0, 0, 0, 0, 385, 386, 0, 0, 0, 0, 0, 0, 387,
+ 0, 0, 0, 388, 0, 0, 389, 0, 0, 390, 0, 0, 0, 0, 391, 0, 392, 393, 0, 0,
+ 0, 394, 0, 0, 0, 395, 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 398, 0,
+ 399, 400, 0, 0, 0, 401, 0, 0, 0, 402, 0, 0, 403, 0, 0, 404, 0, 0, 0, 0,
+ 0, 0, 405, 0, 0, 406, 0, 0, 0, 0, 407, 0, 408, 0, 0, 0, 0, 409, 0, 0,
+ 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 413, 0, 0, 414, 0, 0, 0, 0, 0,
+ 0, 415, 416, 0, 417, 418, 0, 0, 0, 419, 0, 0, 420, 0, 0, 0, 0, 421, 0, 0,
+ 422, 0, 0, 423, 0, 0, 0, 424, 0, 425, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0,
+ 0, 428, 429, 0, 0, 0, 0, 0, 0, 430, 0, 0, 431, 0, 0, 0, 0, 432, 0, 433,
+ 0, 0, 0, 0, 434, 0, 435, 0, 0, 0, 0, 0, 0, 436, 437, 0, 0, 438, 0, 0,
+ 439, 0, 440, 441, 0, 0, 0, 442, 0, 0, 443, 0, 444, 445, 0, 446, 447, 0,
+ 0, 448, 0, 0, 0, 449, 0, 450, 451, 0, 0, 0, 452, 0, 0, 0, 0, 0, 453, 0,
+ 454, 455, 0, 456, 457, 0, 0, 0, 0, 0, 0, 458, 0, 0, 459, 0, 460, 461, 0,
+ 0, 0, 462, 0, 0, 463, 0, 464, 465, 0, 466, 467, 0, 0, 468, 0, 0, 0, 469,
+ 0, 470, 471, 0, 0, 0, 472, 0, 0, 0, 0, 0, 473, 0, 474, 475, 0, 476, 477,
+ 0, 0, 0, 0, 0, 0, 478, 0, 0, 479, 0, 0, 480, 0, 0, 0, 0, 0, 481, 0, 0,
+ 482, 0, 0, 0, 483, 0, 0, 484, 0, 0, 485, 0, 0, 0, 0, 0, 0, 486, 0, 0,
+ 487, 488, 0, 489, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 492, 0, 0, 493,
+ 0, 0, 0, 494, 0, 0, 495, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 497, 0, 0, 0,
+ 498, 499, 0, 0, 0, 500, 0, 0, 0, 0, 0, 501, 502, 0, 503, 0, 0, 0, 504, 0,
+ 0, 0, 505, 0, 0, 506, 507, 0, 0, 0, 0, 0, 508, 0, 0, 0, 509, 510, 0, 0,
+ 0, 0, 0, 511, 0, 0, 0, 512, 513, 0, 514, 0, 0, 0, 0, 515, 0, 0, 516, 0,
+ 0, 517, 0, 0, 0, 0, 0, 0, 518, 0, 0, 519, 0, 0, 520, 0, 0, 521, 0, 0, 0,
+ 0, 0, 0, 522, 0, 0, 523, 0, 0, 524, 0, 0, 525, 0, 0, 0, 0, 0, 0, 526, 0,
+ 0, 0, 527, 0, 0, 528, 0, 0, 529, 0, 0, 530, 0, 0, 0, 531, 0, 0, 0, 0, 0,
+ 0, 532, 533, 534, 0, 0, 0, 0, 0, 535, 536, 0, 0, 0, 0, 0, 537, 0, 0, 538,
+ 0, 0, 539, 0, 0, 0, 0, 0, 0, 540, 0, 541, 0, 0, 0, 0, 0, 542, 543, 0, 0,
+ 0, 0, 0, 544, 0, 0, 545, 0, 0, 546, 0, 0, 0, 0, 0, 0, 547, 0, 0, 548, 0,
+ 0, 549, 0, 0, 550, 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 552, 553, 0, 0, 0, 0,
+ 0, 554, 0, 0, 555, 0, 0, 556, 0, 0, 0, 0, 0, 0, 557, 0, 0, 558, 0, 0,
+ 559, 0, 0, 560, 0, 0, 0, 0, 561, 0, 0, 562, 0, 0, 0, 0, 0, 0, 563, 0, 0,
+ 564, 0, 0, 565, 0, 0, 0, 0, 0, 566, 567, 0, 0, 0, 0, 0, 568, 0, 0, 569,
+ 0, 0, 570, 0, 0, 0, 0, 0, 0, 571, 0, 0, 572, 0, 0, 573, 0, 0, 574, 0, 0,
+ 0, 0, 575, 0, 0, 0, 0, 0, 576, 577, 0, 0, 0, 0, 0, 578, 0, 0, 579, 0, 0,
+ 580, 0, 0, 0, 0, 0, 0, 581, 0, 0, 582, 0, 0, 583, 0, 0, 584, 0, 0, 0, 0,
+ 585, 0, 0, 0, 0, 0, 586, 587, 0, 0, 0, 0, 0, 588, 0, 0, 0, 0, 589, 0,
+ 590, 0, 0, 0, 0, 591, 0, 592, 0, 0, 0, 0, 593, 0, 0, 594, 0, 0, 0, 0, 0,
+ 0, 595, 0, 0, 596, 0, 0, 597, 0, 0, 0, 0, 0, 598, 599, 0, 0, 0, 0, 0,
+ 600, 0, 0, 0, 0, 601, 0, 602, 0, 0, 0, 0, 603, 0, 604, 0, 0, 0, 0, 605,
+ 0, 0, 0, 0, 0, 606, 0, 0, 607, 0, 0, 608, 0, 0, 609, 0, 0, 0, 0, 0, 0,
+ 610, 0, 0, 611, 0, 0, 612, 0, 0, 0, 0, 613, 0, 614, 0, 0, 0, 0, 615, 0,
+ 0, 0, 0, 0, 616, 0, 0, 617, 0, 0, 618, 0, 0, 619, 0, 0, 0, 0, 0, 0, 620,
+ 0, 0, 621, 0, 0, 622, 0, 0, 623, 0, 0, 0, 0, 0, 0, 624, 0, 0, 625, 0, 0,
+ 626, 0, 0, 0, 0, 627, 0, 628, 0, 0, 0, 0, 0, 0, 629, 0, 0, 630, 0, 0, 0,
+ 0, 631, 0, 632, 0, 0, 0, 0, 0, 633, 0, 0, 634, 0, 0, 635, 0, 0, 636, 0,
+ 0, 0, 0, 0, 0, 637, 0, 0, 638, 0, 0, 639, 0, 0, 640, 0, 0, 0, 0, 0, 0,
+ 641, 0, 0, 642, 0, 0, 643, 0, 0, 644, 0, 0, 0, 0, 0, 0, 645, 0, 0, 646,
+ 0, 0, 647, 0, 0, 648, 0, 0, 0, 0, 0, 0, 649, 0, 0, 650, 0, 0, 651, 0, 0,
+ 652, 0, 0, 0, 0, 0, 0, 653, 0, 0, 654, 0, 0, 655, 0, 0, 656, 0, 0, 0, 0,
+ 0, 0, 657, 0, 0, 658, 0, 0, 659, 0, 0, 660, 0, 0, 0, 0, 0, 0, 661, 0, 0,
+ 662, 0, 0, 663, 0, 0, 664, 0, 0, 0, 0, 0, 0, 665, 0, 0, 666, 0, 0, 667,
+ 0, 0, 668, 0, 0, 0, 0, 0, 0, 669, 0, 0, 670, 0, 0, 671, 0, 0, 672, 0, 0,
+ 0, 0, 0, 0, 673, 0, 0, 0, 674, 0, 0, 675, 0, 0, 676, 0, 0, 677, 0, 0, 0,
+ 0, 0, 0, 678, 0, 0, 679, 0, 0, 680, 0, 0, 681, 0, 0, 0, 0, 0, 0, 682, 0,
+ 0, 683, 0, 0, 684, 0, 0, 685, 0, 0, 0, 0, 0, 0, 686, 0, 0, 687, 0, 0,
+ 688, 0, 0, 689, 0, 0, 0, 0, 0, 0, 690, 0, 0, 691, 0, 0, 692, 0, 0, 693,
+ 0, 0, 0, 0, 0, 0, 694, 0, 0, 695, 0, 0, 696, 0, 0, 697, 0, 0, 0, 0, 0, 0,
+ 698, 0, 0, 699, 0, 0, 700, 0, 0, 701, 0, 0, 0, 0, 0, 0, 702, 0, 0, 703,
+ 0, 0, 704, 0, 0, 705, 0, 0, 0, 0, 0, 0, 706, 0, 0, 707, 0, 0, 708, 0, 0,
+ 709, 0, 0, 0, 0, 0, 0, 710, 0, 0, 711, 0, 0, 712, 0, 0, 713, 0, 0, 0, 0,
+ 0, 0, 714, 0, 0, 715, 0, 0, 716, 0, 0, 717, 0, 0, 0, 0, 0, 0, 718, 0, 0,
+ 719, 0, 0, 720, 0, 0, 721, 0, 0, 0, 722, 0, 0, 0, 0, 0, 0, 723, 0, 0,
+ 724, 0, 0, 725, 0, 0, 726, 0, 0, 0, 727, 0, 0, 0, 728, 729, 0, 0, 730, 0,
+ 0, 0, 0, 0, 0, 731,
+};
+
+static const unsigned int comp_data[] = {
+ 0, 0, 0, 8814, 0, 8800, 0, 8815, 192, 193, 194, 195, 256, 258, 550, 196,
+ 7842, 197, 0, 461, 512, 514, 0, 7840, 0, 7680, 260, 0, 7682, 0, 0, 7684,
+ 7686, 0, 0, 262, 264, 0, 266, 0, 0, 268, 0, 199, 7690, 0, 0, 270, 0,
+ 7692, 0, 7696, 0, 7698, 7694, 0, 200, 201, 202, 7868, 274, 276, 278, 203,
+ 7866, 0, 0, 282, 516, 518, 0, 7864, 0, 552, 280, 7704, 0, 7706, 7710, 0,
+ 0, 500, 284, 0, 7712, 286, 288, 0, 0, 486, 0, 290, 292, 0, 7714, 7718, 0,
+ 542, 0, 7716, 0, 7720, 7722, 0, 204, 205, 206, 296, 298, 300, 304, 207,
+ 7880, 0, 0, 463, 520, 522, 0, 7882, 302, 0, 0, 7724, 308, 0, 0, 7728, 0,
+ 488, 0, 7730, 0, 310, 7732, 0, 0, 313, 0, 317, 0, 7734, 0, 315, 0, 7740,
+ 7738, 0, 0, 7742, 7744, 0, 0, 7746, 504, 323, 0, 209, 7748, 0, 0, 327, 0,
+ 7750, 0, 325, 0, 7754, 7752, 0, 210, 211, 212, 213, 332, 334, 558, 214,
+ 7886, 0, 336, 465, 524, 526, 416, 7884, 490, 0, 0, 7764, 7766, 0, 0, 340,
+ 7768, 0, 0, 344, 528, 530, 0, 7770, 0, 342, 7774, 0, 0, 346, 348, 0,
+ 7776, 0, 0, 352, 0, 7778, 536, 350, 7786, 0, 0, 356, 0, 7788, 538, 354,
+ 0, 7792, 7790, 0, 217, 218, 219, 360, 362, 364, 0, 220, 7910, 366, 368,
+ 467, 532, 534, 431, 7908, 7794, 0, 370, 7798, 0, 7796, 0, 7804, 0, 7806,
+ 7808, 7810, 372, 0, 7814, 7812, 0, 7816, 7818, 7820, 7922, 221, 374,
+ 7928, 562, 0, 7822, 376, 7926, 0, 0, 7924, 0, 377, 7824, 0, 379, 0, 0,
+ 381, 0, 7826, 7828, 0, 224, 225, 226, 227, 257, 259, 551, 228, 7843, 229,
+ 0, 462, 513, 515, 0, 7841, 0, 7681, 261, 0, 7683, 0, 0, 7685, 7687, 0, 0,
+ 263, 265, 0, 267, 0, 0, 269, 0, 231, 7691, 0, 0, 271, 0, 7693, 0, 7697,
+ 0, 7699, 7695, 0, 232, 233, 234, 7869, 275, 277, 279, 235, 7867, 0, 0,
+ 283, 517, 519, 0, 7865, 0, 553, 281, 7705, 0, 7707, 7711, 0, 0, 501, 285,
+ 0, 7713, 287, 289, 0, 0, 487, 0, 291, 293, 0, 7715, 7719, 0, 543, 0,
+ 7717, 0, 7721, 7723, 0, 7830, 0, 236, 237, 238, 297, 299, 301, 0, 239,
+ 7881, 0, 0, 464, 521, 523, 0, 7883, 303, 0, 0, 7725, 309, 0, 0, 496, 0,
+ 7729, 0, 489, 0, 7731, 0, 311, 7733, 0, 0, 314, 0, 318, 0, 7735, 0, 316,
+ 0, 7741, 7739, 0, 0, 7743, 7745, 0, 0, 7747, 505, 324, 0, 241, 7749, 0,
+ 0, 328, 0, 7751, 0, 326, 0, 7755, 7753, 0, 242, 243, 244, 245, 333, 335,
+ 559, 246, 7887, 0, 337, 466, 525, 527, 417, 7885, 491, 0, 0, 7765, 7767,
+ 0, 0, 341, 7769, 0, 0, 345, 529, 531, 0, 7771, 0, 343, 7775, 0, 0, 347,
+ 349, 0, 7777, 0, 0, 353, 0, 7779, 537, 351, 7787, 7831, 0, 357, 0, 7789,
+ 539, 355, 0, 7793, 7791, 0, 249, 250, 251, 361, 363, 365, 0, 252, 7911,
+ 367, 369, 468, 533, 535, 432, 7909, 7795, 0, 371, 7799, 0, 7797, 0, 7805,
+ 0, 7807, 7809, 7811, 373, 0, 7815, 7813, 0, 7832, 0, 7817, 7819, 7821,
+ 7923, 253, 375, 7929, 563, 0, 7823, 255, 7927, 7833, 0, 7925, 0, 378,
+ 7825, 0, 380, 0, 0, 382, 0, 7827, 7829, 0, 8173, 901, 8129, 0, 7846,
+ 7844, 0, 7850, 7848, 0, 478, 0, 0, 506, 0, 508, 482, 0, 0, 7688, 7872,
+ 7870, 0, 7876, 7874, 0, 0, 7726, 7890, 7888, 0, 7894, 7892, 0, 0, 7756,
+ 556, 0, 0, 7758, 554, 0, 0, 510, 475, 471, 469, 0, 0, 473, 7847, 7845, 0,
+ 7851, 7849, 0, 479, 0, 0, 507, 0, 509, 483, 0, 0, 7689, 7873, 7871, 0,
+ 7877, 7875, 0, 0, 7727, 7891, 7889, 0, 7895, 7893, 0, 0, 7757, 557, 0, 0,
+ 7759, 555, 0, 0, 511, 476, 472, 470, 0, 0, 474, 7856, 7854, 0, 7860,
+ 7858, 0, 7857, 7855, 0, 7861, 7859, 0, 7700, 7702, 7701, 7703, 7760,
+ 7762, 7761, 7763, 7780, 0, 7781, 0, 7782, 0, 7783, 0, 0, 7800, 0, 7801,
+ 0, 7802, 0, 7803, 7835, 0, 7900, 7898, 0, 7904, 7902, 0, 0, 7906, 7901,
+ 7899, 0, 7905, 7903, 0, 0, 7907, 7914, 7912, 0, 7918, 7916, 0, 0, 7920,
+ 7915, 7913, 0, 7919, 7917, 0, 0, 7921, 0, 494, 492, 0, 493, 0, 480, 0,
+ 481, 0, 0, 7708, 0, 7709, 560, 0, 561, 0, 0, 495, 8122, 902, 8121, 8120,
+ 7944, 7945, 0, 8124, 8136, 904, 7960, 7961, 8138, 905, 7976, 7977, 0,
+ 8140, 8154, 906, 8153, 8152, 0, 938, 7992, 7993, 8184, 908, 8008, 8009,
+ 0, 8172, 8170, 910, 8169, 8168, 0, 939, 0, 8025, 8186, 911, 8040, 8041,
+ 0, 8188, 0, 8116, 0, 8132, 8048, 940, 8113, 8112, 7936, 7937, 8118, 8115,
+ 8050, 941, 7952, 7953, 8052, 942, 7968, 7969, 8134, 8131, 8054, 943,
+ 8145, 8144, 0, 970, 7984, 7985, 8150, 0, 8056, 972, 8000, 8001, 8164,
+ 8165, 8058, 973, 8161, 8160, 0, 971, 8016, 8017, 8166, 0, 8060, 974,
+ 8032, 8033, 8182, 8179, 8146, 912, 8151, 0, 8162, 944, 8167, 0, 0, 8180,
+ 0, 979, 0, 980, 0, 1031, 0, 1232, 0, 1234, 0, 1027, 1024, 0, 0, 1238, 0,
+ 1025, 0, 1217, 0, 1244, 0, 1246, 1037, 0, 1250, 1049, 0, 1252, 0, 1036,
+ 0, 1254, 1262, 1038, 0, 1264, 1266, 0, 0, 1268, 0, 1272, 0, 1260, 0,
+ 1233, 0, 1235, 0, 1107, 1104, 0, 0, 1239, 0, 1105, 0, 1218, 0, 1245, 0,
+ 1247, 1117, 0, 1251, 1081, 0, 1253, 0, 1116, 0, 1255, 1263, 1118, 0,
+ 1265, 1267, 0, 0, 1269, 0, 1273, 0, 1261, 0, 1111, 1142, 0, 1143, 0, 0,
+ 1242, 0, 1243, 0, 1258, 0, 1259, 1570, 1571, 1573, 0, 0, 1572, 0, 1574,
+ 0, 1730, 0, 1747, 0, 1728, 0, 2345, 0, 2353, 0, 2356, 2507, 2508, 2891,
+ 2888, 2892, 0, 2964, 0, 0, 3018, 3020, 0, 0, 3019, 0, 3144, 0, 3264,
+ 3274, 3271, 3272, 0, 0, 3275, 0, 3402, 3404, 0, 0, 3403, 0, 3546, 3548,
+ 3550, 0, 3549, 4134, 0, 0, 6918, 0, 6920, 0, 6922, 0, 6924, 0, 6926, 0,
+ 6930, 0, 6971, 0, 6973, 0, 6976, 0, 6977, 0, 6979, 7736, 0, 7737, 0,
+ 7772, 0, 7773, 0, 7784, 0, 7785, 0, 7852, 0, 0, 7862, 7853, 0, 0, 7863,
+ 7878, 0, 7879, 0, 7896, 0, 7897, 0, 7938, 7940, 7942, 8064, 7939, 7941,
+ 7943, 8065, 0, 8066, 0, 8067, 0, 8068, 0, 8069, 0, 8070, 0, 8071, 7946,
+ 7948, 7950, 8072, 7947, 7949, 7951, 8073, 0, 8074, 0, 8075, 0, 8076, 0,
+ 8077, 0, 8078, 0, 8079, 7954, 7956, 7955, 7957, 7962, 7964, 7963, 7965,
+ 7970, 7972, 7974, 8080, 7971, 7973, 7975, 8081, 0, 8082, 0, 8083, 0,
+ 8084, 0, 8085, 0, 8086, 0, 8087, 7978, 7980, 7982, 8088, 7979, 7981,
+ 7983, 8089, 0, 8090, 0, 8091, 0, 8092, 0, 8093, 0, 8094, 0, 8095, 7986,
+ 7988, 7990, 0, 7987, 7989, 7991, 0, 7994, 7996, 7998, 0, 7995, 7997,
+ 7999, 0, 8002, 8004, 8003, 8005, 8010, 8012, 8011, 8013, 8018, 8020,
+ 8022, 0, 8019, 8021, 8023, 0, 8027, 8029, 8031, 0, 8034, 8036, 8038,
+ 8096, 8035, 8037, 8039, 8097, 0, 8098, 0, 8099, 0, 8100, 0, 8101, 0,
+ 8102, 0, 8103, 8042, 8044, 8046, 8104, 8043, 8045, 8047, 8105, 0, 8106,
+ 0, 8107, 0, 8108, 0, 8109, 0, 8110, 0, 8111, 0, 8114, 0, 8130, 0, 8178,
+ 0, 8119, 8141, 8142, 8143, 0, 0, 8135, 0, 8183, 8157, 8158, 8159, 0, 0,
+ 8602, 0, 8603, 0, 8622, 0, 8653, 0, 8655, 0, 8654, 0, 8708, 0, 8713, 0,
+ 8716, 0, 8740, 0, 8742, 0, 8769, 0, 8772, 0, 8775, 0, 8777, 0, 8813, 0,
+ 8802, 0, 8816, 0, 8817, 0, 8820, 0, 8821, 0, 8824, 0, 8825, 0, 8832, 0,
+ 8833, 0, 8928, 0, 8929, 0, 8836, 0, 8837, 0, 8840, 0, 8841, 0, 8930, 0,
+ 8931, 0, 8876, 0, 8877, 0, 8878, 0, 8879, 0, 8938, 0, 8939, 0, 8940, 0,
+ 8941, 12436, 0, 12364, 0, 12366, 0, 12368, 0, 12370, 0, 12372, 0, 12374,
+ 0, 12376, 0, 12378, 0, 12380, 0, 12382, 0, 12384, 0, 12386, 0, 12389, 0,
+ 12391, 0, 12393, 0, 12400, 12401, 12403, 12404, 12406, 12407, 12409,
+ 12410, 12412, 12413, 12446, 0, 12532, 0, 12460, 0, 12462, 0, 12464, 0,
+ 12466, 0, 12468, 0, 12470, 0, 12472, 0, 12474, 0, 12476, 0, 12478, 0,
+ 12480, 0, 12482, 0, 12485, 0, 12487, 0, 12489, 0, 12496, 12497, 12499,
+ 12500, 12502, 12503, 12505, 12506, 12508, 12509, 12535, 0, 12536, 0,
+ 12537, 0, 12538, 0, 12542, 0, 69786, 0, 69788, 0, 69803, 0, 0, 69934, 0,
+ 69935, 70475, 70476, 70844, 70843, 70846, 0, 0, 71098, 0, 71099,
+};
+
diff --git a/src/hb-unicode-private.hh b/src/hb-unicode-private.hh
index fd1fd44..a2c59da 100644
--- a/src/hb-unicode-private.hh
+++ b/src/hb-unicode-private.hh
@@ -1,7 +1,7 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2011 Codethink Limited
- * Copyright © 2010,2011 Google, Inc.
+ * Copyright © 2010,2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -32,11 +32,10 @@
#define HB_UNICODE_PRIVATE_HH
#include "hb-private.hh"
-
-#include "hb-unicode.h"
#include "hb-object-private.hh"
+extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
/*
* hb_unicode_funcs_t
@@ -50,18 +49,19 @@
HB_UNICODE_FUNC_IMPLEMENT (script) \
HB_UNICODE_FUNC_IMPLEMENT (compose) \
HB_UNICODE_FUNC_IMPLEMENT (decompose) \
+ HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility) \
/* ^--- Add new callbacks here */
/* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */
#define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \
- HB_UNICODE_FUNC_IMPLEMENT (unsigned int, combining_class) \
+ HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_combining_class_t, combining_class) \
HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \
HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \
HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \
HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \
/* ^--- Add new simple callbacks here */
-struct _hb_unicode_funcs_t {
+struct hb_unicode_funcs_t {
hb_object_header_t header;
ASSERT_POD ();
@@ -69,7 +69,136 @@ struct _hb_unicode_funcs_t {
bool immutable;
- /* Don't access these directly. Call hb_unicode_*() instead. */
+#define HB_UNICODE_FUNC_IMPLEMENT(return_type, name) \
+ inline return_type name (hb_codepoint_t unicode) { return func.name (this, unicode, user_data.name); }
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+#undef HB_UNICODE_FUNC_IMPLEMENT
+
+ inline hb_bool_t compose (hb_codepoint_t a, hb_codepoint_t b,
+ hb_codepoint_t *ab)
+ {
+ *ab = 0;
+ if (unlikely (!a || !b)) return false;
+ return func.compose (this, a, b, ab, user_data.compose);
+ }
+
+ inline hb_bool_t decompose (hb_codepoint_t ab,
+ hb_codepoint_t *a, hb_codepoint_t *b)
+ {
+ *a = ab; *b = 0;
+ return func.decompose (this, ab, a, b, user_data.decompose);
+ }
+
+ inline unsigned int decompose_compatibility (hb_codepoint_t u,
+ hb_codepoint_t *decomposed)
+ {
+ unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility);
+ if (ret == 1 && u == decomposed[0]) {
+ decomposed[0] = 0;
+ return 0;
+ }
+ decomposed[ret] = 0;
+ return ret;
+ }
+
+
+ inline unsigned int
+ modified_combining_class (hb_codepoint_t unicode)
+ {
+ /* XXX This hack belongs to the Myanmar shaper. */
+ if (unlikely (unicode == 0x1037u)) unicode = 0x103Au;
+
+ /* XXX This hack belongs to the SEA shaper (for Tai Tham):
+ * Reorder SAKOT to ensure it comes after any tone marks. */
+ if (unlikely (unicode == 0x1A60u)) return 254;
+
+ /* XXX This hack belongs to the Tibetan shaper:
+ * Reorder PADMA to ensure it comes after any vowel marks. */
+ if (unlikely (unicode == 0x0FC6u)) return 254;
+
+ return _hb_modified_combining_class[combining_class (unicode)];
+ }
+
+ static inline hb_bool_t
+ is_variation_selector (hb_codepoint_t unicode)
+ {
+ /* U+180B..180D MONGOLIAN FREE VARIATION SELECTORs are handled in the
+ * Arabic shaper. No need to match them here. */
+ return unlikely (hb_in_ranges (unicode,
+ 0xFE00u, 0xFE0Fu, /* VARIATION SELECTOR-1..16 */
+ 0xE0100u, 0xE01EFu)); /* VARIATION SELECTOR-17..256 */
+ }
+
+ /* Default_Ignorable codepoints:
+ *
+ * Note: While U+115F, U+1160, U+3164 and U+FFA0 are Default_Ignorable,
+ * we do NOT want to hide them, as the way Uniscribe has implemented them
+ * is with regular spacing glyphs, and that's the way fonts are made to work.
+ * As such, we make exceptions for those four.
+ *
+ * Unicode 7.0:
+ * $ grep '; Default_Ignorable_Code_Point ' DerivedCoreProperties.txt | sed 's/;.*#/#/'
+ * 00AD # Cf SOFT HYPHEN
+ * 034F # Mn COMBINING GRAPHEME JOINER
+ * 061C # Cf ARABIC LETTER MARK
+ * 115F..1160 # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
+ * 17B4..17B5 # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
+ * 180B..180D # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
+ * 180E # Cf MONGOLIAN VOWEL SEPARATOR
+ * 200B..200F # Cf [5] ZERO WIDTH SPACE..RIGHT-TO-LEFT MARK
+ * 202A..202E # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
+ * 2060..2064 # Cf [5] WORD JOINER..INVISIBLE PLUS
+ * 2065 # Cn <reserved-2065>
+ * 2066..206F # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
+ * 3164 # Lo HANGUL FILLER
+ * FE00..FE0F # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
+ * FEFF # Cf ZERO WIDTH NO-BREAK SPACE
+ * FFA0 # Lo HALFWIDTH HANGUL FILLER
+ * FFF0..FFF8 # Cn [9] <reserved-FFF0>..<reserved-FFF8>
+ * 1BCA0..1BCA3 # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
+ * 1D173..1D17A # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE
+ * E0000 # Cn <reserved-E0000>
+ * E0001 # Cf LANGUAGE TAG
+ * E0002..E001F # Cn [30] <reserved-E0002>..<reserved-E001F>
+ * E0020..E007F # Cf [96] TAG SPACE..CANCEL TAG
+ * E0080..E00FF # Cn [128] <reserved-E0080>..<reserved-E00FF>
+ * E0100..E01EF # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
+ * E01F0..E0FFF # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
+ */
+ static inline hb_bool_t
+ is_default_ignorable (hb_codepoint_t ch)
+ {
+ hb_codepoint_t plane = ch >> 16;
+ if (likely (plane == 0))
+ {
+ /* BMP */
+ hb_codepoint_t page = ch >> 8;
+ switch (page) {
+ case 0x00: return unlikely (ch == 0x00ADu);
+ case 0x03: return unlikely (ch == 0x034Fu);
+ case 0x06: return unlikely (ch == 0x061Cu);
+ case 0x17: return hb_in_range (ch, 0x17B4u, 0x17B5u);
+ case 0x18: return hb_in_range (ch, 0x180Bu, 0x180Eu);
+ case 0x20: return hb_in_ranges (ch, 0x200Bu, 0x200Fu,
+ 0x202Au, 0x202Eu,
+ 0x2060u, 0x206Fu);
+ case 0xFE: return hb_in_range (ch, 0xFE00u, 0xFE0Fu) || ch == 0xFEFFu;
+ case 0xFF: return hb_in_range (ch, 0xFFF0u, 0xFFF8u);
+ default: return false;
+ }
+ }
+ else
+ {
+ /* Other planes */
+ switch (plane) {
+ case 0x01: return hb_in_ranges (ch, 0x1BCA0u, 0x1BCA3u,
+ 0x1D173u, 0x1D17Au);
+ case 0x0E: return hb_in_range (ch, 0xE0000u, 0xE0FFFu);
+ default: return false;
+ }
+ }
+ }
+
struct {
#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name;
@@ -91,69 +220,98 @@ struct _hb_unicode_funcs_t {
};
-#ifdef HAVE_GLIB
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_glib_unicode_funcs;
-#define _hb_unicode_funcs_default _hb_glib_unicode_funcs
-#elif defined(HAVE_ICU)
-extern HB_INTERNAL const hb_unicode_funcs_t _hb_icu_unicode_funcs;
-#define _hb_unicode_funcs_default _hb_icu_unicode_funcs
-#else
-#define HB_UNICODE_FUNCS_NIL 1
extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
-#define _hb_unicode_funcs_default _hb_unicode_funcs_nil
-#endif
-
-HB_INTERNAL unsigned int
-_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
- hb_codepoint_t unicode);
-static inline hb_bool_t
-_hb_unicode_is_variation_selector (hb_codepoint_t unicode)
-{
- return unlikely ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
- (unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SELECTOR-1..16 */
- (unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SELECTOR-17..256 */
-}
+/* Modified combining marks */
-/* Zero-Width invisible characters:
+/* Hebrew
*
- * 00AD SOFT HYPHEN
- * 034F COMBINING GRAPHEME JOINER
+ * We permute the "fixed-position" classes 10-26 into the order
+ * described in the SBL Hebrew manual:
*
- * 200B ZERO WIDTH SPACE
- * 200C ZERO WIDTH NON-JOINER
- * 200D ZERO WIDTH JOINER
- * 200E LEFT-TO-RIGHT MARK
- * 200F RIGHT-TO-LEFT MARK
+ * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
*
- * 2028 LINE SEPARATOR
+ * (as recommended by:
+ * http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
*
- * 202A LEFT-TO-RIGHT EMBEDDING
- * 202B RIGHT-TO-LEFT EMBEDDING
- * 202C POP DIRECTIONAL FORMATTING
- * 202D LEFT-TO-RIGHT OVERRIDE
- * 202E RIGHT-TO-LEFT OVERRIDE
+ * More details here:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC10 22 /* sheva */
+#define HB_MODIFIED_COMBINING_CLASS_CCC11 15 /* hataf segol */
+#define HB_MODIFIED_COMBINING_CLASS_CCC12 16 /* hataf patah */
+#define HB_MODIFIED_COMBINING_CLASS_CCC13 17 /* hataf qamats */
+#define HB_MODIFIED_COMBINING_CLASS_CCC14 23 /* hiriq */
+#define HB_MODIFIED_COMBINING_CLASS_CCC15 18 /* tsere */
+#define HB_MODIFIED_COMBINING_CLASS_CCC16 19 /* segol */
+#define HB_MODIFIED_COMBINING_CLASS_CCC17 20 /* patah */
+#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats */
+#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam */
+#define HB_MODIFIED_COMBINING_CLASS_CCC20 24 /* qubuts */
+#define HB_MODIFIED_COMBINING_CLASS_CCC21 12 /* dagesh */
+#define HB_MODIFIED_COMBINING_CLASS_CCC22 25 /* meteg */
+#define HB_MODIFIED_COMBINING_CLASS_CCC23 13 /* rafe */
+#define HB_MODIFIED_COMBINING_CLASS_CCC24 10 /* shin dot */
+#define HB_MODIFIED_COMBINING_CLASS_CCC25 11 /* sin dot */
+#define HB_MODIFIED_COMBINING_CLASS_CCC26 26 /* point varika */
+
+/*
+ * Arabic
*
- * 2060 WORD JOINER
- * 2061 FUNCTION APPLICATION
- * 2062 INVISIBLE TIMES
- * 2063 INVISIBLE SEPARATOR
+ * Modify to move Shadda (ccc=33) before other marks. See:
+ * http://unicode.org/faq/normalization.html#8
+ * http://unicode.org/faq/normalization.html#9
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC27 28 /* fathatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC28 29 /* dammatan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC29 30 /* kasratan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC30 31 /* fatha */
+#define HB_MODIFIED_COMBINING_CLASS_CCC31 32 /* damma */
+#define HB_MODIFIED_COMBINING_CLASS_CCC32 33 /* kasra */
+#define HB_MODIFIED_COMBINING_CLASS_CCC33 27 /* shadda */
+#define HB_MODIFIED_COMBINING_CLASS_CCC34 34 /* sukun */
+#define HB_MODIFIED_COMBINING_CLASS_CCC35 35 /* superscript alef */
+
+/* Syriac */
+#define HB_MODIFIED_COMBINING_CLASS_CCC36 36 /* superscript alaph */
+
+/* Telugu
+ *
+ * Modify Telugu length marks (ccc=84, ccc=91).
+ * These are the only matras in the main Indic scripts range that have
+ * a non-zero ccc. That makes them reorder with the Halant that is
+ * ccc=9. Just zero them, we don't need them in our Indic shaper.
+ */
+#define HB_MODIFIED_COMBINING_CLASS_CCC84 0 /* length mark */
+#define HB_MODIFIED_COMBINING_CLASS_CCC91 0 /* ai length mark */
+
+/* Thai
*
- * FEFF ZERO WIDTH NO-BREAK SPACE
+ * Modify U+0E38 and U+0E39 (ccc=103) to be reordered before U+0E3A (ccc=9).
+ * Assign 3, which is unassigned otherwise.
+ * Uniscribe does this reordering too.
*/
-static inline hb_bool_t
-_hb_unicode_is_zero_width (hb_codepoint_t ch)
-{
- return ((ch & ~0x007F) == 0x2000 && (
- (ch >= 0x200B && ch <= 0x200F) ||
- (ch >= 0x202A && ch <= 0x202E) ||
- (ch >= 0x2060 && ch <= 0x2063) ||
- (ch == 0x2028)
- )) || unlikely (ch == 0x0009
- || ch == 0x00AD
- || ch == 0x034F
- || ch == 0xFEFF);
-}
+#define HB_MODIFIED_COMBINING_CLASS_CCC103 3 /* sara u / sara uu */
+#define HB_MODIFIED_COMBINING_CLASS_CCC107 107 /* mai * */
+
+/* Lao */
+#define HB_MODIFIED_COMBINING_CLASS_CCC118 118 /* sign u / sign uu */
+#define HB_MODIFIED_COMBINING_CLASS_CCC122 122 /* mai * */
+
+/* Tibetan */
+#define HB_MODIFIED_COMBINING_CLASS_CCC129 129 /* sign aa */
+#define HB_MODIFIED_COMBINING_CLASS_CCC130 130 /* sign i */
+#define HB_MODIFIED_COMBINING_CLASS_CCC132 132 /* sign u */
+
+
+/* Misc */
+
+#define HB_UNICODE_GENERAL_CATEGORY_IS_MARK(gen_cat) \
+ (FLAG (gen_cat) & \
+ (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+
#endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc
index 6a21ef3..fc19006 100644
--- a/src/hb-unicode.cc
+++ b/src/hb-unicode.cc
@@ -1,7 +1,7 @@
/*
* Copyright © 2009 Red Hat, Inc.
- * Copyright © 2011 Codethink Limited
- * Copyright © 2010,2011 Google, Inc.
+ * Copyright © 2011 Codethink Limited
+ * Copyright © 2010,2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -38,12 +38,12 @@
* hb_unicode_funcs_t
*/
-static unsigned int
+static hb_unicode_combining_class_t
hb_unicode_combining_class_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode HB_UNUSED,
void *user_data HB_UNUSED)
{
- return 0;
+ return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED;
}
static unsigned int
@@ -99,13 +99,72 @@ hb_unicode_decompose_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
+static unsigned int
+hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED,
+ hb_codepoint_t u HB_UNUSED,
+ hb_codepoint_t *decomposed HB_UNUSED,
+ void *user_data HB_UNUSED)
+{
+ return 0;
+}
+
+
+#define HB_UNICODE_FUNCS_IMPLEMENT_SET \
+ HB_UNICODE_FUNCS_IMPLEMENT (glib) \
+ HB_UNICODE_FUNCS_IMPLEMENT (icu) \
+ HB_UNICODE_FUNCS_IMPLEMENT (ucdn) \
+ HB_UNICODE_FUNCS_IMPLEMENT (nil) \
+ /* ^--- Add new callbacks before nil */
+
+#define hb_nil_get_unicode_funcs hb_unicode_funcs_get_empty
+
+/* Prototype them all */
+#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
+extern "C" hb_unicode_funcs_t *hb_##set##_get_unicode_funcs (void);
+HB_UNICODE_FUNCS_IMPLEMENT_SET
+#undef HB_UNICODE_FUNCS_IMPLEMENT
+
hb_unicode_funcs_t *
hb_unicode_funcs_get_default (void)
{
- return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_default);
+#define HB_UNICODE_FUNCS_IMPLEMENT(set) \
+ return hb_##set##_get_unicode_funcs ();
+
+#ifdef HAVE_GLIB
+ HB_UNICODE_FUNCS_IMPLEMENT(glib)
+#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN)
+ HB_UNICODE_FUNCS_IMPLEMENT(icu)
+#elif defined(HAVE_UCDN)
+ HB_UNICODE_FUNCS_IMPLEMENT(ucdn)
+#else
+#define HB_UNICODE_FUNCS_NIL 1
+ HB_UNICODE_FUNCS_IMPLEMENT(nil)
+#endif
+
+#undef HB_UNICODE_FUNCS_IMPLEMENT
}
+#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
+#ifdef _MSC_VER
+#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
+#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
+#else
+#warning "Could not find any Unicode functions implementation, you have to provide your own"
+#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
+#endif
+#endif
+
+/**
+ * hb_unicode_funcs_create: (Xconstructor)
+ * @parent: (nullable):
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_unicode_funcs_t *
hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
{
@@ -131,7 +190,6 @@ hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
}
-//extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
HB_OBJECT_HEADER_STATIC,
@@ -144,18 +202,45 @@ const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
}
};
+/**
+ * hb_unicode_funcs_get_empty:
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_unicode_funcs_t *
hb_unicode_funcs_get_empty (void)
{
return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil);
}
+/**
+ * hb_unicode_funcs_reference: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Return value: (transfer full):
+ *
+ * Since: 1.0
+ **/
hb_unicode_funcs_t *
hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
{
return hb_object_reference (ufuncs);
}
+/**
+ * hb_unicode_funcs_destroy: (skip)
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
{
@@ -171,6 +256,20 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
free (ufuncs);
}
+/**
+ * hb_unicode_funcs_set_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key:
+ * @data:
+ * @destroy:
+ * @replace:
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key,
@@ -181,6 +280,17 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
return hb_object_set_user_data (ufuncs, key, data, destroy, replace);
}
+/**
+ * hb_unicode_funcs_get_user_data: (skip)
+ * @ufuncs: Unicode functions.
+ * @key:
+ *
+ *
+ *
+ * Return value: (transfer none):
+ *
+ * Since: 1.0
+ **/
void *
hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key)
@@ -189,21 +299,49 @@ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
}
+/**
+ * hb_unicode_funcs_make_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
{
- if (hb_object_is_inert (ufuncs))
+ if (unlikely (hb_object_is_inert (ufuncs)))
return;
ufuncs->immutable = true;
}
+/**
+ * hb_unicode_funcs_is_immutable:
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs)
{
return ufuncs->immutable;
}
+/**
+ * hb_unicode_funcs_get_parent:
+ * @ufuncs: Unicode functions.
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_unicode_funcs_t *
hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs)
{
@@ -236,7 +374,7 @@ hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \
} \
}
- HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_UNICODE_FUNC_IMPLEMENT
@@ -246,83 +384,185 @@ return_type \
hb_unicode_##name (hb_unicode_funcs_t *ufuncs, \
hb_codepoint_t unicode) \
{ \
- return ufuncs->func.name (ufuncs, unicode, ufuncs->user_data.name); \
+ return ufuncs->name (unicode); \
}
- HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
+HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
#undef HB_UNICODE_FUNC_IMPLEMENT
+/**
+ * hb_unicode_compose:
+ * @ufuncs: Unicode functions.
+ * @a:
+ * @b:
+ * @ab: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_unicode_compose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
- *ab = 0;
- return ufuncs->func.compose (ufuncs, a, b, ab, ufuncs->user_data.compose);
+ return ufuncs->compose (a, b, ab);
}
+/**
+ * hb_unicode_decompose:
+ * @ufuncs: Unicode functions.
+ * @ab:
+ * @a: (out):
+ * @b: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
hb_bool_t
hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b)
{
- *a = ab; *b = 0;
- return ufuncs->func.decompose (ufuncs, ab, a, b, ufuncs->user_data.decompose);
+ return ufuncs->decompose (ab, a, b);
}
-
-
+/**
+ * hb_unicode_decompose_compatibility:
+ * @ufuncs: Unicode functions.
+ * @u:
+ * @decomposed: (out):
+ *
+ *
+ *
+ * Return value:
+ *
+ * Since: 1.0
+ **/
unsigned int
-_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs,
- hb_codepoint_t unicode)
+hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed)
{
- int c = hb_unicode_combining_class (ufuncs, unicode);
-
- if (unlikely (hb_in_range<int> (c, 27, 33)))
- {
- /* Modify the combining-class to suit Arabic better. See:
- * http://unicode.org/faq/normalization.html#8
- * http://unicode.org/faq/normalization.html#9
- */
- c = c == 33 ? 27 : c + 1;
- }
- else if (unlikely (hb_in_range<int> (c, 10, 25)))
- {
- /* The equivalent fix for Hebrew is more complex.
- *
- * We permute the "fixed-position" classes 10-25 into the order
- * described in the SBL Hebrew manual:
- *
- * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf
- *
- * (as recommended by:
- * http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html)
- *
- * More details here:
- * https://bugzilla.mozilla.org/show_bug.cgi?id=662055
- */
- static const int permuted_hebrew_classes[25 - 10 + 1] = {
- /* 10 sheva */ 22,
- /* 11 hataf segol */ 15,
- /* 12 hataf patah */ 16,
- /* 13 hataf qamats */ 17,
- /* 14 hiriq */ 23,
- /* 15 tsere */ 18,
- /* 16 segol */ 19,
- /* 17 patah */ 20,
- /* 18 qamats */ 21,
- /* 19 holam */ 14,
- /* 20 qubuts */ 24,
- /* 21 dagesh */ 12,
- /* 22 meteg */ 25,
- /* 23 rafe */ 13,
- /* 24 shin dot */ 10,
- /* 25 sin dot */ 11,
- };
- c = permuted_hebrew_classes[c - 10];
- }
-
- return c;
+ return ufuncs->decompose_compatibility (u, decomposed);
}
+
+/* See hb-unicode-private.hh for details. */
+const uint8_t
+_hb_modified_combining_class[256] =
+{
+ 0, /* HB_UNICODE_COMBINING_CLASS_NOT_REORDERED */
+ 1, /* HB_UNICODE_COMBINING_CLASS_OVERLAY */
+ 2, 3, 4, 5, 6,
+ 7, /* HB_UNICODE_COMBINING_CLASS_NUKTA */
+ 8, /* HB_UNICODE_COMBINING_CLASS_KANA_VOICING */
+ 9, /* HB_UNICODE_COMBINING_CLASS_VIRAMA */
+
+ /* Hebrew */
+ HB_MODIFIED_COMBINING_CLASS_CCC10,
+ HB_MODIFIED_COMBINING_CLASS_CCC11,
+ HB_MODIFIED_COMBINING_CLASS_CCC12,
+ HB_MODIFIED_COMBINING_CLASS_CCC13,
+ HB_MODIFIED_COMBINING_CLASS_CCC14,
+ HB_MODIFIED_COMBINING_CLASS_CCC15,
+ HB_MODIFIED_COMBINING_CLASS_CCC16,
+ HB_MODIFIED_COMBINING_CLASS_CCC17,
+ HB_MODIFIED_COMBINING_CLASS_CCC18,
+ HB_MODIFIED_COMBINING_CLASS_CCC19,
+ HB_MODIFIED_COMBINING_CLASS_CCC20,
+ HB_MODIFIED_COMBINING_CLASS_CCC21,
+ HB_MODIFIED_COMBINING_CLASS_CCC22,
+ HB_MODIFIED_COMBINING_CLASS_CCC23,
+ HB_MODIFIED_COMBINING_CLASS_CCC24,
+ HB_MODIFIED_COMBINING_CLASS_CCC25,
+ HB_MODIFIED_COMBINING_CLASS_CCC26,
+
+ /* Arabic */
+ HB_MODIFIED_COMBINING_CLASS_CCC27,
+ HB_MODIFIED_COMBINING_CLASS_CCC28,
+ HB_MODIFIED_COMBINING_CLASS_CCC29,
+ HB_MODIFIED_COMBINING_CLASS_CCC30,
+ HB_MODIFIED_COMBINING_CLASS_CCC31,
+ HB_MODIFIED_COMBINING_CLASS_CCC32,
+ HB_MODIFIED_COMBINING_CLASS_CCC33,
+ HB_MODIFIED_COMBINING_CLASS_CCC34,
+ HB_MODIFIED_COMBINING_CLASS_CCC35,
+
+ /* Syriac */
+ HB_MODIFIED_COMBINING_CLASS_CCC36,
+
+ 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83,
+
+ /* Telugu */
+ HB_MODIFIED_COMBINING_CLASS_CCC84,
+ 85, 86, 87, 88, 89, 90,
+ HB_MODIFIED_COMBINING_CLASS_CCC91,
+ 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
+
+ /* Thai */
+ HB_MODIFIED_COMBINING_CLASS_CCC103,
+ 104, 105, 106,
+ HB_MODIFIED_COMBINING_CLASS_CCC107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+
+ /* Lao */
+ HB_MODIFIED_COMBINING_CLASS_CCC118,
+ 119, 120, 121,
+ HB_MODIFIED_COMBINING_CLASS_CCC122,
+ 123, 124, 125, 126, 127, 128,
+
+ /* Tibetan */
+ HB_MODIFIED_COMBINING_CLASS_CCC129,
+ HB_MODIFIED_COMBINING_CLASS_CCC130,
+ 131,
+ HB_MODIFIED_COMBINING_CLASS_CCC132,
+ 133, 134, 135, 136, 137, 138, 139,
+
+
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+
+ 200, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT */
+ 201,
+ 202, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW */
+ 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+ 214, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE */
+ 215,
+ 216, /* HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT */
+ 217,
+ 218, /* HB_UNICODE_COMBINING_CLASS_BELOW_LEFT */
+ 219,
+ 220, /* HB_UNICODE_COMBINING_CLASS_BELOW */
+ 221,
+ 222, /* HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT */
+ 223,
+ 224, /* HB_UNICODE_COMBINING_CLASS_LEFT */
+ 225,
+ 226, /* HB_UNICODE_COMBINING_CLASS_RIGHT */
+ 227,
+ 228, /* HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT */
+ 229,
+ 230, /* HB_UNICODE_COMBINING_CLASS_ABOVE */
+ 231,
+ 232, /* HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT */
+ 233, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW */
+ 234, /* HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE */
+ 235, 236, 237, 238, 239,
+ 240, /* HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT */
+ 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255, /* HB_UNICODE_COMBINING_CLASS_INVALID */
+};
diff --git a/src/hb-unicode.h b/src/hb-unicode.h
index b26168f..1c4e097 100644
--- a/src/hb-unicode.h
+++ b/src/hb-unicode.h
@@ -1,7 +1,7 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2011 Codethink Limited
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -40,11 +40,135 @@
HB_BEGIN_DECLS
+/* hb_unicode_general_category_t */
+
+/* Unicode Character Database property: General_Category (gc) */
+typedef enum
+{
+ HB_UNICODE_GENERAL_CATEGORY_CONTROL, /* Cc */
+ HB_UNICODE_GENERAL_CATEGORY_FORMAT, /* Cf */
+ HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, /* Cn */
+ HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, /* Co */
+ HB_UNICODE_GENERAL_CATEGORY_SURROGATE, /* Cs */
+ HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, /* Ll */
+ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, /* Lm */
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, /* Lo */
+ HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, /* Lt */
+ HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, /* Lu */
+ HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, /* Mc */
+ HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, /* Me */
+ HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, /* Mn */
+ HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, /* Nd */
+ HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, /* Nl */
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, /* No */
+ HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, /* Pc */
+ HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, /* Pd */
+ HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, /* Pe */
+ HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, /* Pf */
+ HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, /* Pi */
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, /* Po */
+ HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, /* Ps */
+ HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, /* Sc */
+ HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, /* Sk */
+ HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, /* Sm */
+ HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, /* So */
+ HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, /* Zl */
+ HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, /* Zp */
+ HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR /* Zs */
+} hb_unicode_general_category_t;
+
+/* hb_unicode_combining_class_t */
+
+/* Note: newer versions of Unicode may add new values. Clients should be ready to handle
+ * any value in the 0..254 range being returned from hb_unicode_combining_class().
+ */
+
+/* Unicode Character Database property: Canonical_Combining_Class (ccc) */
+typedef enum
+{
+ HB_UNICODE_COMBINING_CLASS_NOT_REORDERED = 0,
+ HB_UNICODE_COMBINING_CLASS_OVERLAY = 1,
+ HB_UNICODE_COMBINING_CLASS_NUKTA = 7,
+ HB_UNICODE_COMBINING_CLASS_KANA_VOICING = 8,
+ HB_UNICODE_COMBINING_CLASS_VIRAMA = 9,
+
+ /* Hebrew */
+ HB_UNICODE_COMBINING_CLASS_CCC10 = 10,
+ HB_UNICODE_COMBINING_CLASS_CCC11 = 11,
+ HB_UNICODE_COMBINING_CLASS_CCC12 = 12,
+ HB_UNICODE_COMBINING_CLASS_CCC13 = 13,
+ HB_UNICODE_COMBINING_CLASS_CCC14 = 14,
+ HB_UNICODE_COMBINING_CLASS_CCC15 = 15,
+ HB_UNICODE_COMBINING_CLASS_CCC16 = 16,
+ HB_UNICODE_COMBINING_CLASS_CCC17 = 17,
+ HB_UNICODE_COMBINING_CLASS_CCC18 = 18,
+ HB_UNICODE_COMBINING_CLASS_CCC19 = 19,
+ HB_UNICODE_COMBINING_CLASS_CCC20 = 20,
+ HB_UNICODE_COMBINING_CLASS_CCC21 = 21,
+ HB_UNICODE_COMBINING_CLASS_CCC22 = 22,
+ HB_UNICODE_COMBINING_CLASS_CCC23 = 23,
+ HB_UNICODE_COMBINING_CLASS_CCC24 = 24,
+ HB_UNICODE_COMBINING_CLASS_CCC25 = 25,
+ HB_UNICODE_COMBINING_CLASS_CCC26 = 26,
+
+ /* Arabic */
+ HB_UNICODE_COMBINING_CLASS_CCC27 = 27,
+ HB_UNICODE_COMBINING_CLASS_CCC28 = 28,
+ HB_UNICODE_COMBINING_CLASS_CCC29 = 29,
+ HB_UNICODE_COMBINING_CLASS_CCC30 = 30,
+ HB_UNICODE_COMBINING_CLASS_CCC31 = 31,
+ HB_UNICODE_COMBINING_CLASS_CCC32 = 32,
+ HB_UNICODE_COMBINING_CLASS_CCC33 = 33,
+ HB_UNICODE_COMBINING_CLASS_CCC34 = 34,
+ HB_UNICODE_COMBINING_CLASS_CCC35 = 35,
+
+ /* Syriac */
+ HB_UNICODE_COMBINING_CLASS_CCC36 = 36,
+
+ /* Telugu */
+ HB_UNICODE_COMBINING_CLASS_CCC84 = 84,
+ HB_UNICODE_COMBINING_CLASS_CCC91 = 91,
+
+ /* Thai */
+ HB_UNICODE_COMBINING_CLASS_CCC103 = 103,
+ HB_UNICODE_COMBINING_CLASS_CCC107 = 107,
+
+ /* Lao */
+ HB_UNICODE_COMBINING_CLASS_CCC118 = 118,
+ HB_UNICODE_COMBINING_CLASS_CCC122 = 122,
+
+ /* Tibetan */
+ HB_UNICODE_COMBINING_CLASS_CCC129 = 129,
+ HB_UNICODE_COMBINING_CLASS_CCC130 = 130,
+ HB_UNICODE_COMBINING_CLASS_CCC133 = 132,
+
+
+ HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT = 200,
+ HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW = 202,
+ HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE = 214,
+ HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT = 216,
+ HB_UNICODE_COMBINING_CLASS_BELOW_LEFT = 218,
+ HB_UNICODE_COMBINING_CLASS_BELOW = 220,
+ HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT = 222,
+ HB_UNICODE_COMBINING_CLASS_LEFT = 224,
+ HB_UNICODE_COMBINING_CLASS_RIGHT = 226,
+ HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT = 228,
+ HB_UNICODE_COMBINING_CLASS_ABOVE = 230,
+ HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT = 232,
+ HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW = 233,
+ HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE = 234,
+
+ HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT = 240,
+
+ HB_UNICODE_COMBINING_CLASS_INVALID = 255
+} hb_unicode_combining_class_t;
+
+
/*
* hb_unicode_funcs_t
*/
-typedef struct _hb_unicode_funcs_t hb_unicode_funcs_t;
+typedef struct hb_unicode_funcs_t hb_unicode_funcs_t;
/*
@@ -71,7 +195,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
- hb_bool_t replace);
+ hb_bool_t replace);
+
void *
hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
@@ -94,7 +219,7 @@ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs);
/* typedefs */
-typedef unsigned int (*hb_unicode_combining_class_func_t) (hb_unicode_funcs_t *ufuncs,
+typedef hb_unicode_combining_class_t (*hb_unicode_combining_class_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs,
@@ -121,47 +246,165 @@ typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *b,
void *user_data);
+/**
+ * hb_unicode_decompose_compatibility_func_t:
+ * @ufuncs: a Unicode function structure
+ * @u: codepoint to decompose
+ * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
+ * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
+ *
+ * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
+ * The complete length of the decomposition will be returned.
+ *
+ * If @u has no compatibility decomposition, zero should be returned.
+ *
+ * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
+ * compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations
+ * of this function type must ensure that they do not write past the provided array.
+ *
+ * Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available.
+ */
+typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed,
+ void *user_data);
+
+/* See Unicode 6.1 for details on the maximum decomposition length. */
+#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */
+
/* setters */
+/**
+ * hb_unicode_funcs_set_combining_class_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
- hb_unicode_combining_class_func_t combining_class_func,
+ hb_unicode_combining_class_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_unicode_funcs_set_eastasian_width_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
- hb_unicode_eastasian_width_func_t eastasian_width_func,
+ hb_unicode_eastasian_width_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_unicode_funcs_set_general_category_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
- hb_unicode_general_category_func_t general_category_func,
+ hb_unicode_general_category_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_unicode_funcs_set_mirroring_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
- hb_unicode_mirroring_func_t mirroring_func,
+ hb_unicode_mirroring_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_unicode_funcs_set_script_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
- hb_unicode_script_func_t script_func,
+ hb_unicode_script_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_unicode_funcs_set_compose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs,
- hb_unicode_compose_func_t compose_func,
+ hb_unicode_compose_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_unicode_funcs_set_decompose_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
void
hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs,
- hb_unicode_decompose_func_t decompose_func,
+ hb_unicode_decompose_func_t func,
void *user_data, hb_destroy_func_t destroy);
+/**
+ * hb_unicode_funcs_set_decompose_compatibility_func:
+ * @ufuncs: a Unicode function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified):
+ * @user_data:
+ * @destroy:
+ *
+ *
+ *
+ * Since: 1.0
+ **/
+void
+hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
+ hb_unicode_decompose_compatibility_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
/* accessors */
-unsigned int
+hb_unicode_combining_class_t
hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
@@ -192,6 +435,11 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *a,
hb_codepoint_t *b);
+unsigned int
+hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
+ hb_codepoint_t u,
+ hb_codepoint_t *decomposed);
+
HB_END_DECLS
#endif /* HB_UNICODE_H */
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index 9f84a3c..e7bcad2 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -1,5 +1,5 @@
/*
- * Copyright © 2011 Google, Inc.
+ * Copyright © 2011,2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -24,211 +24,703 @@
* Google Author(s): Behdad Esfahbod
*/
-#define _WIN32_WINNT 0x0500
-
-#include "hb-private.hh"
+#define HB_SHAPER uniscribe
+#include "hb-shaper-impl-private.hh"
#include <windows.h>
#include <usp10.h>
-
-typedef ULONG WIN_ULONG;
+#include <rpc.h>
#include "hb-uniscribe.h"
+#include "hb-open-file-private.hh"
#include "hb-ot-name-table.hh"
#include "hb-ot-tag.h"
-#include "hb-font-private.hh"
-#include "hb-buffer-private.hh"
-
-
#ifndef HB_DEBUG_UNISCRIBE
#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
#endif
-/*
-DWORD GetFontData(
- __in HDC hdc,
- __in DWORD dwTable,
- __in DWORD dwOffset,
- __out LPVOID lpvBuffer,
- __in DWORD cbData
+static inline uint16_t hb_uint16_swap (const uint16_t v)
+{ return (v >> 8) | (v << 8); }
+static inline uint32_t hb_uint32_swap (const uint32_t v)
+{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+
+
+typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
+ const WCHAR *pwcInChars,
+ int cInChars,
+ int cMaxItems,
+ const SCRIPT_CONTROL *psControl,
+ const SCRIPT_STATE *psState,
+ SCRIPT_ITEM *pItems,
+ OPENTYPE_TAG *pScriptTags,
+ int *pcItems
);
-*/
-static bool
-populate_log_font (LOGFONTW *lf,
- HDC hdc,
- hb_font_t *font)
+typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/(
+ HDC hdc,
+ SCRIPT_CACHE *psc,
+ SCRIPT_ANALYSIS *psa,
+ OPENTYPE_TAG tagScript,
+ OPENTYPE_TAG tagLangSys,
+ int *rcRangeChars,
+ TEXTRANGE_PROPERTIES **rpRangeProperties,
+ int cRanges,
+ const WCHAR *pwcChars,
+ int cChars,
+ int cMaxGlyphs,
+ WORD *pwLogClust,
+ SCRIPT_CHARPROP *pCharProps,
+ WORD *pwOutGlyphs,
+ SCRIPT_GLYPHPROP *pOutGlyphProps,
+ int *pcGlyphs
+);
+
+typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/(
+ HDC hdc,
+ SCRIPT_CACHE *psc,
+ SCRIPT_ANALYSIS *psa,
+ OPENTYPE_TAG tagScript,
+ OPENTYPE_TAG tagLangSys,
+ int *rcRangeChars,
+ TEXTRANGE_PROPERTIES **rpRangeProperties,
+ int cRanges,
+ const WCHAR *pwcChars,
+ WORD *pwLogClust,
+ SCRIPT_CHARPROP *pCharProps,
+ int cChars,
+ const WORD *pwGlyphs,
+ const SCRIPT_GLYPHPROP *pGlyphProps,
+ int cGlyphs,
+ int *piAdvance,
+ GOFFSET *pGoffset,
+ ABC *pABC
+);
+
+
+/* Fallback implementations. */
+
+static HRESULT WINAPI
+hb_ScriptItemizeOpenType(
+ const WCHAR *pwcInChars,
+ int cInChars,
+ int cMaxItems,
+ const SCRIPT_CONTROL *psControl,
+ const SCRIPT_STATE *psState,
+ SCRIPT_ITEM *pItems,
+ OPENTYPE_TAG *pScriptTags,
+ int *pcItems
+)
{
- memset (lf, 0, sizeof (*lf));
- int dpi = GetDeviceCaps (hdc, LOGPIXELSY);
- lf->lfHeight = -font->y_scale;
+{
+ return ScriptItemize (pwcInChars,
+ cInChars,
+ cMaxItems,
+ psControl,
+ psState,
+ pItems,
+ pcItems);
+}
+}
- hb_blob_t *blob = Sanitizer<name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e')));
- const name *name_table = Sanitizer<name>::lock_instance (blob);
- unsigned int len = name_table->get_name (3, 1, 0x409, 4,
- lf->lfFaceName,
- sizeof (lf->lfFaceName[0]) * LF_FACESIZE)
- / sizeof (lf->lfFaceName[0]);
- hb_blob_destroy (blob);
+static HRESULT WINAPI
+hb_ScriptShapeOpenType(
+ HDC hdc,
+ SCRIPT_CACHE *psc,
+ SCRIPT_ANALYSIS *psa,
+ OPENTYPE_TAG tagScript,
+ OPENTYPE_TAG tagLangSys,
+ int *rcRangeChars,
+ TEXTRANGE_PROPERTIES **rpRangeProperties,
+ int cRanges,
+ const WCHAR *pwcChars,
+ int cChars,
+ int cMaxGlyphs,
+ WORD *pwLogClust,
+ SCRIPT_CHARPROP *pCharProps,
+ WORD *pwOutGlyphs,
+ SCRIPT_GLYPHPROP *pOutGlyphProps,
+ int *pcGlyphs
+)
+{
+ SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps;
+ return ScriptShape (hdc,
+ psc,
+ pwcChars,
+ cChars,
+ cMaxGlyphs,
+ psa,
+ pwOutGlyphs,
+ pwLogClust,
+ psva,
+ pcGlyphs);
+}
- if (unlikely (!len)) {
- DEBUG_MSG (UNISCRIBE, NULL, "Didn't find English name table entry");
- return false;
- }
- if (unlikely (len >= LF_FACESIZE)) {
- DEBUG_MSG (UNISCRIBE, NULL, "Font name too long");
- return false;
+static HRESULT WINAPI
+hb_ScriptPlaceOpenType(
+ HDC hdc,
+ SCRIPT_CACHE *psc,
+ SCRIPT_ANALYSIS *psa,
+ OPENTYPE_TAG tagScript,
+ OPENTYPE_TAG tagLangSys,
+ int *rcRangeChars,
+ TEXTRANGE_PROPERTIES **rpRangeProperties,
+ int cRanges,
+ const WCHAR *pwcChars,
+ WORD *pwLogClust,
+ SCRIPT_CHARPROP *pCharProps,
+ int cChars,
+ const WORD *pwGlyphs,
+ const SCRIPT_GLYPHPROP *pGlyphProps,
+ int cGlyphs,
+ int *piAdvance,
+ GOFFSET *pGoffset,
+ ABC *pABC
+)
+{
+ SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps;
+ return ScriptPlace (hdc,
+ psc,
+ pwGlyphs,
+ cGlyphs,
+ psva,
+ psa,
+ piAdvance,
+ pGoffset,
+ pABC);
+}
+
+
+struct hb_uniscribe_shaper_funcs_t {
+ SIOT ScriptItemizeOpenType;
+ SSOT ScriptShapeOpenType;
+ SPOT ScriptPlaceOpenType;
+
+ inline void init (void)
+ {
+ HMODULE hinstLib;
+ this->ScriptItemizeOpenType = NULL;
+ this->ScriptShapeOpenType = NULL;
+ this->ScriptPlaceOpenType = NULL;
+
+ hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
+ if (hinstLib)
+ {
+ this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
+ this->ScriptShapeOpenType = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
+ this->ScriptPlaceOpenType = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
+ }
+ if (!this->ScriptItemizeOpenType ||
+ !this->ScriptShapeOpenType ||
+ !this->ScriptPlaceOpenType)
+ {
+ DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back.");
+ this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
+ this->ScriptShapeOpenType = hb_ScriptShapeOpenType;
+ this->ScriptPlaceOpenType = hb_ScriptPlaceOpenType;
+ }
}
+};
+static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;
- for (unsigned int i = 0; i < len; i++)
- lf->lfFaceName[i] = hb_be_uint16 (lf->lfFaceName[i]);
- lf->lfFaceName[len] = 0;
+static inline void
+free_uniscribe_funcs (void)
+{
+ free (uniscribe_funcs);
+}
- return true;
+static hb_uniscribe_shaper_funcs_t *
+hb_uniscribe_shaper_get_funcs (void)
+{
+retry:
+ hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
+
+ if (unlikely (!funcs))
+ {
+ funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
+ if (unlikely (!funcs))
+ return NULL;
+
+ funcs->init ();
+
+ if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
+ free (funcs);
+ goto retry;
+ }
+
+#ifdef HB_USE_ATEXIT
+ atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
+#endif
+ }
+
+ return funcs;
}
-static hb_user_data_key_t hb_uniscribe_data_key;
+struct active_feature_t {
+ OPENTYPE_FEATURE_RECORD rec;
+ unsigned int order;
+
+ static int cmp (const active_feature_t *a, const active_feature_t *b) {
+ return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
+ a->order < b->order ? -1 : a->order > b->order ? 1 :
+ a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
+ 0;
+ }
+ bool operator== (const active_feature_t *f) {
+ return cmp (this, f) == 0;
+ }
+};
+struct feature_event_t {
+ unsigned int index;
+ bool start;
+ active_feature_t feature;
-static struct hb_uniscribe_face_data_t {
+ static int cmp (const feature_event_t *a, const feature_event_t *b) {
+ return a->index < b->index ? -1 : a->index > b->index ? 1 :
+ a->start < b->start ? -1 : a->start > b->start ? 1 :
+ active_feature_t::cmp (&a->feature, &b->feature);
+ }
+};
+
+struct range_record_t {
+ TEXTRANGE_PROPERTIES props;
+ unsigned int index_first; /* == start */
+ unsigned int index_last; /* == end - 1 */
+};
+
+HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
+
+
+/*
+ * shaper face data
+ */
+
+struct hb_uniscribe_shaper_face_data_t {
HANDLE fh;
-} _hb_uniscribe_face_data_nil = {0};
+ hb_uniscribe_shaper_funcs_t *funcs;
+ wchar_t face_name[LF_FACESIZE];
+};
+/* face_name should point to a wchar_t[LF_FACESIZE] object. */
static void
-_hb_uniscribe_face_data_destroy (hb_uniscribe_face_data_t *data)
+_hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
{
- if (data->fh)
- RemoveFontMemResourceEx (data->fh);
- free (data);
+ /* We'll create a private name for the font from a UUID using a simple,
+ * somewhat base64-like encoding scheme */
+ const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
+ UUID id;
+ UuidCreate ((UUID*) &id);
+ ASSERT_STATIC (2 + 3 * (16/2) < LF_FACESIZE);
+ unsigned int name_str_len = 0;
+ face_name[name_str_len++] = 'F';
+ face_name[name_str_len++] = '_';
+ unsigned char *p = (unsigned char *) &id;
+ for (unsigned int i = 0; i < 16; i += 2)
+ {
+ /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
+ * using the bits in groups of 5,5,6 to select chars from enc.
+ * This will generate 24 characters; with the 'F_' prefix we already provided,
+ * the name will be 26 chars (plus the NUL terminator), so will always fit within
+ * face_name (LF_FACESIZE = 32). */
+ face_name[name_str_len++] = enc[p[i] >> 3];
+ face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
+ face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
+ }
+ face_name[name_str_len] = 0;
+ if (plen)
+ *plen = name_str_len;
}
-static hb_uniscribe_face_data_t *
-_hb_uniscribe_face_get_data (hb_face_t *face)
+/* Destroys blob. */
+static hb_blob_t *
+_hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
{
- hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
- if (likely (data)) return data;
+ /* Create a copy of the font data, with the 'name' table replaced by a
+ * table that names the font with our private F_* name created above.
+ * For simplicity, we just append a new 'name' table and update the
+ * sfnt directory; the original table is left in place, but unused.
+ *
+ * The new table will contain just 5 name IDs: family, style, unique,
+ * full, PS. All of them point to the same name data with our unique name.
+ */
+
+ blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
+
+ unsigned int length, new_length, name_str_len;
+ const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
- data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t));
+ _hb_generate_unique_face_name (new_name, &name_str_len);
+
+ static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
+
+ unsigned int name_table_length = OT::name::min_size +
+ ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
+ name_str_len * 2; /* for name data in UTF16BE form */
+ unsigned int name_table_offset = (length + 3) & ~3;
+
+ new_length = name_table_offset + ((name_table_length + 3) & ~3);
+ void *new_sfnt_data = calloc (1, new_length);
+ if (!new_sfnt_data)
+ {
+ hb_blob_destroy (blob);
+ return NULL;
+ }
+
+ memcpy(new_sfnt_data, orig_sfnt_data, length);
+
+ OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
+ name.format.set (0);
+ name.count.set (ARRAY_LENGTH (name_IDs));
+ name.stringOffset.set (name.get_size ());
+ for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
+ {
+ OT::NameRecord &record = name.nameRecord[i];
+ record.platformID.set (3);
+ record.encodingID.set (1);
+ record.languageID.set (0x0409u); /* English */
+ record.nameID.set (name_IDs[i]);
+ record.length.set (name_str_len * 2);
+ record.offset.set (0);
+ }
+
+ /* Copy string data from new_name, converting wchar_t to UTF16BE. */
+ unsigned char *p = &OT::StructAfter<unsigned char> (name);
+ for (unsigned int i = 0; i < name_str_len; i++)
+ {
+ *p++ = new_name[i] >> 8;
+ *p++ = new_name[i] & 0xff;
+ }
+
+ /* Adjust name table entry to point to new name table */
+ const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data);
+ unsigned int face_count = file.get_face_count ();
+ for (unsigned int face_index = 0; face_index < face_count; face_index++)
+ {
+ /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be
+ * toe-stepping. But we don't really care. */
+ const OT::OpenTypeFontFace &face = file.get_face (face_index);
+ unsigned int index;
+ if (face.find_table_index (HB_OT_TAG_name, &index))
+ {
+ OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
+ record.checkSum.set_for_data (&name, name_table_length);
+ record.offset.set (name_table_offset);
+ record.length.set (name_table_length);
+ }
+ else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
+ {
+ free (new_sfnt_data);
+ hb_blob_destroy (blob);
+ return NULL;
+ }
+ }
+
+ /* The checkSumAdjustment field in the 'head' table is now wrong,
+ * but that doesn't actually seem to cause any problems so we don't
+ * bother. */
+
+ hb_blob_destroy (blob);
+ return hb_blob_create ((const char *) new_sfnt_data, new_length,
+ HB_MEMORY_MODE_WRITABLE, NULL, free);
+}
+
+hb_uniscribe_shaper_face_data_t *
+_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
+{
+ hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
if (unlikely (!data))
- return &_hb_uniscribe_face_data_nil;
+ return NULL;
+ data->funcs = hb_uniscribe_shaper_get_funcs ();
+ if (unlikely (!data->funcs))
+ {
+ free (data);
+ return NULL;
+ }
hb_blob_t *blob = hb_face_reference_blob (face);
- unsigned int blob_length;
- const char *blob_data = hb_blob_get_data (blob, &blob_length);
- if (unlikely (!blob_length))
+ if (unlikely (!hb_blob_get_length (blob)))
DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
+ blob = _hb_rename_font (blob, data->face_name);
+ if (unlikely (!blob))
+ {
+ free (data);
+ return NULL;
+ }
+
DWORD num_fonts_installed;
- data->fh = AddFontMemResourceEx ((void *) blob_data, blob_length, 0, &num_fonts_installed);
- hb_blob_destroy (blob);
+ data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
+ hb_blob_get_length (blob),
+ 0, &num_fonts_installed);
if (unlikely (!data->fh))
- DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
-
-
- if (unlikely (!hb_face_set_user_data (face, &hb_uniscribe_data_key, data,
- (hb_destroy_func_t) _hb_uniscribe_face_data_destroy,
- false)))
{
- _hb_uniscribe_face_data_destroy (data);
- data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key);
- if (data)
- return data;
- else
- return &_hb_uniscribe_face_data_nil;
+ DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
+ free (data);
+ return NULL;
}
return data;
}
+void
+_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
+{
+ RemoveFontMemResourceEx (data->fh);
+ free (data);
+}
+
-static struct hb_uniscribe_font_data_t {
+/*
+ * shaper font data
+ */
+
+struct hb_uniscribe_shaper_font_data_t {
HDC hdc;
LOGFONTW log_font;
HFONT hfont;
SCRIPT_CACHE script_cache;
-} _hb_uniscribe_font_data_nil = {NULL, NULL, NULL};
+};
-static void
-_hb_uniscribe_font_data_destroy (hb_uniscribe_font_data_t *data)
+static bool
+populate_log_font (LOGFONTW *lf,
+ hb_font_t *font)
{
- if (data->hdc)
- ReleaseDC (NULL, data->hdc);
- if (data->hfont)
- DeleteObject (data->hfont);
- if (data->script_cache)
- ScriptFreeCache (&data->script_cache);
- free (data);
+ memset (lf, 0, sizeof (*lf));
+ lf->lfHeight = -font->y_scale;
+ lf->lfCharSet = DEFAULT_CHARSET;
+
+ hb_face_t *face = font->face;
+ hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+ memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
+
+ return true;
}
-static hb_uniscribe_font_data_t *
-_hb_uniscribe_font_get_data (hb_font_t *font)
+hb_uniscribe_shaper_font_data_t *
+_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
{
- hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
- if (likely (data)) return data;
+ if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
- data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t));
+ hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
if (unlikely (!data))
- return &_hb_uniscribe_font_data_nil;
+ return NULL;
data->hdc = GetDC (NULL);
- if (unlikely (!populate_log_font (&data->log_font, data->hdc, font)))
+ if (unlikely (!populate_log_font (&data->log_font, font))) {
DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
- else {
- data->hfont = CreateFontIndirectW (&data->log_font);
- if (unlikely (!data->hfont))
- DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
- if (!SelectObject (data->hdc, data->hfont))
- DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
+ _hb_uniscribe_shaper_font_data_destroy (data);
+ return NULL;
}
- if (unlikely (!hb_font_set_user_data (font, &hb_uniscribe_data_key, data,
- (hb_destroy_func_t) _hb_uniscribe_font_data_destroy,
- false)))
- {
- _hb_uniscribe_font_data_destroy (data);
- data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key);
- if (data)
- return data;
- else
- return &_hb_uniscribe_font_data_nil;
+ data->hfont = CreateFontIndirectW (&data->log_font);
+ if (unlikely (!data->hfont)) {
+ DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
+ _hb_uniscribe_shaper_font_data_destroy (data);
+ return NULL;
+ }
+
+ if (!SelectObject (data->hdc, data->hfont)) {
+ DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
+ _hb_uniscribe_shaper_font_data_destroy (data);
+ return NULL;
}
return data;
}
+void
+_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
+{
+ if (data->hdc)
+ ReleaseDC (NULL, data->hdc);
+ if (data->hfont)
+ DeleteObject (data->hfont);
+ if (data->script_cache)
+ ScriptFreeCache (&data->script_cache);
+ free (data);
+}
+
LOGFONTW *
hb_uniscribe_font_get_logfontw (hb_font_t *font)
{
- hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
- if (unlikely (!font_data))
- return NULL;
+ if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+ hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
return &font_data->log_font;
}
HFONT
hb_uniscribe_font_get_hfont (hb_font_t *font)
{
- hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
- if (unlikely (!font_data))
- return 0;
+ if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
+ hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
return font_data->hfont;
}
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_uniscribe_shaper_shape_plan_data_t {};
+
+hb_uniscribe_shaper_shape_plan_data_t *
+_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
+ const hb_feature_t *user_features HB_UNUSED,
+ unsigned int num_user_features HB_UNUSED)
+{
+ return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+
hb_bool_t
-_hb_uniscribe_shape (hb_font_t *font,
+_hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
- buffer->guess_properties ();
+ hb_face_t *face = font->face;
+ hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+ hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+ hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
+
+ /*
+ * Set up features.
+ */
+ hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records;
+ hb_auto_array_t<range_record_t> range_records;
+ if (num_features)
+ {
+ /* Sort features by start/end events. */
+ hb_auto_array_t<feature_event_t> feature_events;
+ for (unsigned int i = 0; i < num_features; i++)
+ {
+ active_feature_t feature;
+ feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
+ feature.rec.lParameter = features[i].value;
+ feature.order = i;
+
+ feature_event_t *event;
+
+ event = feature_events.push ();
+ if (unlikely (!event))
+ goto fail_features;
+ event->index = features[i].start;
+ event->start = true;
+ event->feature = feature;
+
+ event = feature_events.push ();
+ if (unlikely (!event))
+ goto fail_features;
+ event->index = features[i].end;
+ event->start = false;
+ event->feature = feature;
+ }
+ feature_events.qsort ();
+ /* Add a strategic final event. */
+ {
+ active_feature_t feature;
+ feature.rec.tagFeature = 0;
+ feature.rec.lParameter = 0;
+ feature.order = num_features + 1;
+
+ feature_event_t *event = feature_events.push ();
+ if (unlikely (!event))
+ goto fail_features;
+ event->index = 0; /* This value does magic. */
+ event->start = false;
+ event->feature = feature;
+ }
+
+ /* Scan events and save features for each range. */
+ hb_auto_array_t<active_feature_t> active_features;
+ unsigned int last_index = 0;
+ for (unsigned int i = 0; i < feature_events.len; i++)
+ {
+ feature_event_t *event = &feature_events[i];
+
+ if (event->index != last_index)
+ {
+ /* Save a snapshot of active features and the range. */
+ range_record_t *range = range_records.push ();
+ if (unlikely (!range))
+ goto fail_features;
+
+ unsigned int offset = feature_records.len;
+
+ active_features.qsort ();
+ for (unsigned int j = 0; j < active_features.len; j++)
+ {
+ if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
+ {
+ OPENTYPE_FEATURE_RECORD *feature = feature_records.push ();
+ if (unlikely (!feature))
+ goto fail_features;
+ *feature = active_features[j].rec;
+ }
+ else
+ {
+ /* Overrides value for existing feature. */
+ feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
+ }
+ }
+
+ /* Will convert to pointer after all is ready, since feature_records.array
+ * may move as we grow it. */
+ range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
+ range->props.cotfRecords = feature_records.len - offset;
+ range->index_first = last_index;
+ range->index_last = event->index - 1;
+
+ last_index = event->index;
+ }
+
+ if (event->start) {
+ active_feature_t *feature = active_features.push ();
+ if (unlikely (!feature))
+ goto fail_features;
+ *feature = event->feature;
+ } else {
+ active_feature_t *feature = active_features.find (&event->feature);
+ if (feature)
+ active_features.remove (feature - active_features.array);
+ }
+ }
+
+ if (!range_records.len) /* No active feature found. */
+ goto fail_features;
+
+ /* Fixup the pointers. */
+ for (unsigned int i = 0; i < range_records.len; i++)
+ {
+ range_record_t *range = &range_records[i];
+ range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
+ }
+ }
+ else
+ {
+ fail_features:
+ num_features = 0;
+ }
#define FAIL(...) \
HB_STMT_START { \
@@ -236,58 +728,66 @@ _hb_uniscribe_shape (hb_font_t *font,
return false; \
} HB_STMT_END;
- hb_uniscribe_face_data_t *face_data = _hb_uniscribe_face_get_data (font->face);
- if (unlikely (!face_data->fh))
- FAIL ("Couldn't get face data");
-
- hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font);
- if (unlikely (!font_data->hfont))
- FAIL ("Couldn't get font font");
-
- if (unlikely (!buffer->len))
- return true;
-
HRESULT hr;
retry:
unsigned int scratch_size;
- char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size);
-
- /* Allocate char buffers; they all fit */
+ hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
#define ALLOCATE_ARRAY(Type, name, len) \
Type *name = (Type *) scratch; \
- scratch += len * sizeof (name[0]); \
- scratch_size -= len * sizeof (name[0]);
+ { \
+ unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+ assert (_consumed <= scratch_size); \
+ scratch += _consumed; \
+ scratch_size -= _consumed; \
+ }
#define utf16_index() var1.u32
- WCHAR *pchars = (WCHAR *) scratch;
+ ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);
+
unsigned int chars_len = 0;
- for (unsigned int i = 0; i < buffer->len; i++) {
+ for (unsigned int i = 0; i < buffer->len; i++)
+ {
hb_codepoint_t c = buffer->info[i].codepoint;
buffer->info[i].utf16_index() = chars_len;
- if (likely (c < 0x10000))
+ if (likely (c <= 0xFFFFu))
pchars[chars_len++] = c;
- else if (unlikely (c >= 0x110000))
- pchars[chars_len++] = 0xFFFD;
+ else if (unlikely (c > 0x10FFFFu))
+ pchars[chars_len++] = 0xFFFDu;
else {
- pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
- pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
+ pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+ pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
}
}
- ALLOCATE_ARRAY (WCHAR, wchars, chars_len);
ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
- /* On Windows, we don't care about alignment...*/
- unsigned int glyphs_size = scratch_size / (sizeof (WORD) +
- sizeof (SCRIPT_GLYPHPROP) +
- sizeof (int) +
- sizeof (GOFFSET) +
- sizeof (uint32_t));
+ if (num_features)
+ {
+ /* Need log_clusters to assign features. */
+ chars_len = 0;
+ for (unsigned int i = 0; i < buffer->len; i++)
+ {
+ hb_codepoint_t c = buffer->info[i].codepoint;
+ unsigned int cluster = buffer->info[i].cluster;
+ log_clusters[chars_len++] = cluster;
+ if (hb_in_range (c, 0x10000u, 0x10FFFFu))
+ log_clusters[chars_len++] = cluster; /* Surrogates. */
+ }
+ }
+
+ /* The -2 in the following is to compensate for possible
+ * alignment needed after the WORD array. sizeof(WORD) == 2. */
+ unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
+ / (sizeof (WORD) +
+ sizeof (SCRIPT_GLYPHPROP) +
+ sizeof (int) +
+ sizeof (GOFFSET) +
+ sizeof (uint32_t));
ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
@@ -295,13 +795,22 @@ retry:
ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
+ /* Note:
+ * We can't touch the contents of glyph_props. Our fallback
+ * implementations of Shape and Place functions use that buffer
+ * by casting it to a different type. It works because they
+ * both agree about it, but if we want to access it here we
+ * need address that issue first.
+ */
+
+#undef ALLOCATE_ARRAY
-#define MAX_ITEMS 10
+#define MAX_ITEMS 256
SCRIPT_ITEM items[MAX_ITEMS + 1];
SCRIPT_CONTROL bidi_control = {0};
SCRIPT_STATE bidi_state = {0};
- WIN_ULONG script_tags[MAX_ITEMS];
+ ULONG script_tags[MAX_ITEMS];
int item_count;
/* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
@@ -309,96 +818,147 @@ retry:
*(uint32_t*)&bidi_control |= 1<<24;
bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
-// bidi_state.fOverrideDirection = 1;
-
- hr = ScriptItemizeOpenType (wchars,
- chars_len,
- MAX_ITEMS,
- &bidi_control,
- &bidi_state,
- items,
- script_tags,
- &item_count);
+ bidi_state.fOverrideDirection = 1;
+
+ hr = funcs->ScriptItemizeOpenType (pchars,
+ chars_len,
+ MAX_ITEMS,
+ &bidi_control,
+ &bidi_state,
+ items,
+ script_tags,
+ &item_count);
if (unlikely (FAILED (hr)))
FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
#undef MAX_ITEMS
- int *range_char_counts = NULL;
- TEXTRANGE_PROPERTIES **range_properties = NULL;
- int range_count = 0;
- if (num_features) {
- /* TODO setup ranges */
- }
-
- OPENTYPE_TAG language_tag = hb_ot_tag_from_language (buffer->props.language);
+ OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
+ hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties;
+ hb_auto_array_t<int> range_char_counts;
unsigned int glyphs_offset = 0;
unsigned int glyphs_len;
+ bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
for (unsigned int i = 0; i < item_count; i++)
{
- unsigned int chars_offset = items[i].iCharPos;
- unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
- OPENTYPE_TAG script_tag = script_tags[i]; /* XXX buffer->props.script */
-
- hr = ScriptShapeOpenType (font_data->hdc,
- &font_data->script_cache,
- &items[i].a,
- script_tag,
- language_tag,
- range_char_counts,
- range_properties,
- range_count,
- wchars + chars_offset,
- item_chars_len,
- glyphs_size - glyphs_offset,
- /* out */
- log_clusters + chars_offset,
- char_props + chars_offset,
- glyphs + glyphs_offset,
- glyph_props + glyphs_offset,
- (int *) &glyphs_len);
-
- for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
- log_clusters[j] += glyphs_offset;
-
- if (unlikely (items[i].a.fNoGlyphIndex))
- FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
- if (unlikely (hr == E_OUTOFMEMORY))
+ unsigned int chars_offset = items[i].iCharPos;
+ unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
+
+ if (num_features)
+ {
+ range_properties.shrink (0);
+ range_char_counts.shrink (0);
+
+ range_record_t *last_range = &range_records[0];
+
+ for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
{
- buffer->ensure (buffer->allocated * 2);
- if (buffer->in_error)
- FAIL ("Buffer resize failed");
- goto retry;
+ range_record_t *range = last_range;
+ while (log_clusters[k] < range->index_first)
+ range--;
+ while (log_clusters[k] > range->index_last)
+ range++;
+ if (!range_properties.len ||
+ &range->props != range_properties[range_properties.len - 1])
+ {
+ TEXTRANGE_PROPERTIES **props = range_properties.push ();
+ int *c = range_char_counts.push ();
+ if (unlikely (!props || !c))
+ {
+ range_properties.shrink (0);
+ range_char_counts.shrink (0);
+ break;
+ }
+ *props = &range->props;
+ *c = 1;
+ }
+ else
+ {
+ range_char_counts[range_char_counts.len - 1]++;
+ }
+
+ last_range = range;
}
- if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
+ }
+
+ /* Asking for glyphs in logical order circumvents at least
+ * one bug in Uniscribe. */
+ items[i].a.fLogicalOrder = true;
+
+ retry_shape:
+ hr = funcs->ScriptShapeOpenType (font_data->hdc,
+ &font_data->script_cache,
+ &items[i].a,
+ script_tags[i],
+ language_tag,
+ range_char_counts.array,
+ range_properties.array,
+ range_properties.len,
+ pchars + chars_offset,
+ item_chars_len,
+ glyphs_size - glyphs_offset,
+ /* out */
+ log_clusters + chars_offset,
+ char_props + chars_offset,
+ glyphs + glyphs_offset,
+ glyph_props + glyphs_offset,
+ (int *) &glyphs_len);
+
+ if (unlikely (items[i].a.fNoGlyphIndex))
+ FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
+ if (unlikely (hr == E_OUTOFMEMORY))
+ {
+ if (unlikely (!buffer->ensure (buffer->allocated * 2)))
+ FAIL ("Buffer resize failed");
+ goto retry;
+ }
+ if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
+ {
+ if (items[i].a.eScript == SCRIPT_UNDEFINED)
FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
- if (unlikely (FAILED (hr)))
- FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
-
- hr = ScriptPlaceOpenType (font_data->hdc,
- &font_data->script_cache,
- &items[i].a,
- script_tag,
- language_tag,
- range_char_counts,
- range_properties,
- range_count,
- wchars + chars_offset,
- log_clusters + chars_offset,
- char_props + chars_offset,
- item_chars_len,
- glyphs + glyphs_offset,
- glyph_props + glyphs_offset,
- glyphs_len,
- /* out */
- advances + glyphs_offset,
- offsets + glyphs_offset,
- NULL);
- if (unlikely (FAILED (hr)))
- FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
-
- glyphs_offset += glyphs_len;
+ items[i].a.eScript = SCRIPT_UNDEFINED;
+ goto retry_shape;
+ }
+ if (unlikely (FAILED (hr)))
+ {
+ FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
+ }
+
+ for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
+ log_clusters[j] += glyphs_offset;
+
+ hr = funcs->ScriptPlaceOpenType (font_data->hdc,
+ &font_data->script_cache,
+ &items[i].a,
+ script_tags[i],
+ language_tag,
+ range_char_counts.array,
+ range_properties.array,
+ range_properties.len,
+ pchars + chars_offset,
+ log_clusters + chars_offset,
+ char_props + chars_offset,
+ item_chars_len,
+ glyphs + glyphs_offset,
+ glyph_props + glyphs_offset,
+ glyphs_len,
+ /* out */
+ advances + glyphs_offset,
+ offsets + glyphs_offset,
+ NULL);
+ if (unlikely (FAILED (hr)))
+ FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
+
+ if (DEBUG_ENABLED (UNISCRIBE))
+ fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
+ i,
+ items[i].a.fRTL,
+ items[i].a.fLayoutRTL,
+ items[i].a.fLogicalOrder,
+ HB_UNTAG (hb_uint32_swap (script_tags[i])));
+
+ glyphs_offset += glyphs_len;
}
glyphs_len = glyphs_offset;
@@ -412,20 +972,13 @@ retry:
uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
*p = MIN (*p, buffer->info[i].cluster);
}
- if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) {
- for (unsigned int i = 1; i < glyphs_len; i++)
- if (!glyph_props[i].sva.fClusterStart)
- vis_clusters[i] = vis_clusters[i - 1];
- } else {
- for (int i = glyphs_len - 2; i >= 0; i--)
- if (!glyph_props[i].sva.fClusterStart)
- vis_clusters[i] = vis_clusters[i + 1];
- }
+ for (unsigned int i = 1; i < glyphs_len; i++)
+ if (vis_clusters[i] == -1)
+ vis_clusters[i] = vis_clusters[i - 1];
#undef utf16_index
- buffer->ensure (glyphs_len);
- if (buffer->in_error)
+ if (unlikely (!buffer->ensure (glyphs_len)))
FAIL ("Buffer in error");
#undef FAIL
@@ -454,10 +1007,13 @@ retry:
/* TODO vertical */
pos->x_advance = info->mask;
- pos->x_offset = info->var1.u32;
+ pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
pos->y_offset = info->var2.u32;
}
+ if (backward)
+ hb_buffer_reverse (buffer);
+
/* Wow, done! */
return true;
}
diff --git a/src/hb-uniscribe.h b/src/hb-uniscribe.h
index 216610e..001ab38 100644
--- a/src/hb-uniscribe.h
+++ b/src/hb-uniscribe.h
@@ -29,7 +29,6 @@
#include "hb.h"
-#define _WIN32_WINNT 0x0500
#include <windows.h>
HB_BEGIN_DECLS
diff --git a/src/hb-utf-private.hh b/src/hb-utf-private.hh
new file mode 100644
index 0000000..14d3c2e
--- /dev/null
+++ b/src/hb-utf-private.hh
@@ -0,0 +1,278 @@
+/*
+ * Copyright © 2011,2012,2014 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_UTF_PRIVATE_HH
+#define HB_UTF_PRIVATE_HH
+
+#include "hb-private.hh"
+
+
+struct hb_utf8_t
+{
+ typedef uint8_t codepoint_t;
+
+ static inline const uint8_t *
+ next (const uint8_t *text,
+ const uint8_t *end,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+ /* Written to only accept well-formed sequences.
+ * Based on ideas from ICU's U8_NEXT.
+ * Generates one "replacement" for each ill-formed byte. */
+
+ hb_codepoint_t c = *text++;
+
+ if (c > 0x7Fu)
+ {
+ if (hb_in_range (c, 0xC2u, 0xDFu)) /* Two-byte */
+ {
+ unsigned int t1;
+ if (likely (text < end &&
+ (t1 = text[0] - 0x80u) <= 0x3Fu))
+ {
+ c = ((c&0x1Fu)<<6) | t1;
+ text++;
+ }
+ else
+ goto error;
+ }
+ else if (hb_in_range (c, 0xE0u, 0xEFu)) /* Three-byte */
+ {
+ unsigned int t1, t2;
+ if (likely (1 < end - text &&
+ (t1 = text[0] - 0x80u) <= 0x3Fu &&
+ (t2 = text[1] - 0x80u) <= 0x3Fu))
+ {
+ c = ((c&0xFu)<<12) | (t1<<6) | t2;
+ if (unlikely (c < 0x0800u || hb_in_range (c, 0xD800u, 0xDFFFu)))
+ goto error;
+ text += 2;
+ }
+ else
+ goto error;
+ }
+ else if (hb_in_range (c, 0xF0u, 0xF4u)) /* Four-byte */
+ {
+ unsigned int t1, t2, t3;
+ if (likely (2 < end - text &&
+ (t1 = text[0] - 0x80u) <= 0x3Fu &&
+ (t2 = text[1] - 0x80u) <= 0x3Fu &&
+ (t3 = text[2] - 0x80u) <= 0x3Fu))
+ {
+ c = ((c&0x7u)<<18) | (t1<<12) | (t2<<6) | t3;
+ if (unlikely (!hb_in_range (c, 0x10000u, 0x10FFFFu)))
+ goto error;
+ text += 3;
+ }
+ else
+ goto error;
+ }
+ else
+ goto error;
+ }
+
+ *unicode = c;
+ return text;
+
+ error:
+ *unicode = replacement;
+ return text;
+ }
+
+ static inline const uint8_t *
+ prev (const uint8_t *text,
+ const uint8_t *start,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+ const uint8_t *end = text--;
+ while (start < text && (*text & 0xc0) == 0x80 && end - text < 4)
+ text--;
+
+ if (likely (next (text, end, unicode, replacement) == end))
+ return text;
+
+ *unicode = replacement;
+ return end - 1;
+ }
+
+ static inline unsigned int
+ strlen (const uint8_t *text)
+ {
+ return ::strlen ((const char *) text);
+ }
+};
+
+
+struct hb_utf16_t
+{
+ typedef uint16_t codepoint_t;
+
+ static inline const uint16_t *
+ next (const uint16_t *text,
+ const uint16_t *end,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+ hb_codepoint_t c = *text++;
+
+ if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+ {
+ *unicode = c;
+ return text;
+ }
+
+ if (likely (hb_in_range (c, 0xD800u, 0xDBFFu)))
+ {
+ /* High-surrogate in c */
+ hb_codepoint_t l;
+ if (text < end && ((l = *text), likely (hb_in_range (l, 0xDC00u, 0xDFFFu))))
+ {
+ /* Low-surrogate in l */
+ *unicode = (c << 10) + l - ((0xD800u << 10) - 0x10000u + 0xDC00u);
+ text++;
+ return text;
+ }
+ }
+
+ /* Lonely / out-of-order surrogate. */
+ *unicode = replacement;
+ return text;
+ }
+
+ static inline const uint16_t *
+ prev (const uint16_t *text,
+ const uint16_t *start,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+ const uint16_t *end = text--;
+ hb_codepoint_t c = *text;
+
+ if (likely (!hb_in_range (c, 0xD800u, 0xDFFFu)))
+ {
+ *unicode = c;
+ return text;
+ }
+
+ if (likely (start < text && hb_in_range (c, 0xDC00u, 0xDFFFu)))
+ text--;
+
+ if (likely (next (text, end, unicode, replacement) == end))
+ return text;
+
+ *unicode = replacement;
+ return end - 1;
+ }
+
+
+ static inline unsigned int
+ strlen (const uint16_t *text)
+ {
+ unsigned int l = 0;
+ while (*text++) l++;
+ return l;
+ }
+};
+
+
+template <bool validate=true>
+struct hb_utf32_t
+{
+ typedef uint32_t codepoint_t;
+
+ static inline const uint32_t *
+ next (const uint32_t *text,
+ const uint32_t *end HB_UNUSED,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+ hb_codepoint_t c = *text++;
+ if (validate && unlikely (c > 0x10FFFFu || hb_in_range (c, 0xD800u, 0xDFFFu)))
+ goto error;
+ *unicode = c;
+ return text;
+
+ error:
+ *unicode = replacement;
+ return text;
+ }
+
+ static inline const uint32_t *
+ prev (const uint32_t *text,
+ const uint32_t *start HB_UNUSED,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+ next (text - 1, text, unicode, replacement);
+ return text - 1;
+ }
+
+ static inline unsigned int
+ strlen (const uint32_t *text)
+ {
+ unsigned int l = 0;
+ while (*text++) l++;
+ return l;
+ }
+};
+
+
+struct hb_latin1_t
+{
+ typedef uint8_t codepoint_t;
+
+ static inline const uint8_t *
+ next (const uint8_t *text,
+ const uint8_t *end HB_UNUSED,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement HB_UNUSED)
+ {
+ *unicode = *text++;
+ return text;
+ }
+
+ static inline const uint8_t *
+ prev (const uint8_t *text,
+ const uint8_t *start HB_UNUSED,
+ hb_codepoint_t *unicode,
+ hb_codepoint_t replacement)
+ {
+ *unicode = *--text;
+ return text;
+ }
+
+ static inline unsigned int
+ strlen (const uint8_t *text)
+ {
+ unsigned int l = 0;
+ while (*text++) l++;
+ return l;
+ }
+};
+
+#endif /* HB_UTF_PRIVATE_HH */
diff --git a/src/hb-version.h.in b/src/hb-version.h.in
index 43634f9..2517160 100644
--- a/src/hb-version.h.in
+++ b/src/hb-version.h.in
@@ -42,8 +42,8 @@ HB_BEGIN_DECLS
#define HB_VERSION_STRING "@HB_VERSION@"
-#define HB_VERSION_CHECK(major,minor,micro) \
- ((major)*10000+(minor)*100+(micro) >= \
+#define HB_VERSION_ATLEAST(major,minor,micro) \
+ ((major)*10000+(minor)*100+(micro) <= \
HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO)
@@ -56,9 +56,9 @@ const char *
hb_version_string (void);
hb_bool_t
-hb_version_check (unsigned int major,
- unsigned int minor,
- unsigned int micro);
+hb_version_atleast (unsigned int major,
+ unsigned int minor,
+ unsigned int micro);
HB_END_DECLS
diff --git a/src/hb-warning.cc b/src/hb-warning.cc
index 4f1f65f..e0f88e2 100644
--- a/src/hb-warning.cc
+++ b/src/hb-warning.cc
@@ -53,14 +53,3 @@
#endif
-#include "hb-unicode-private.hh"
-
-#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL)
-#ifdef _MSC_VER
-#pragma message("Could not find any Unicode functions implementation, you have to provide your own")
-#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS")
-#else
-#warning "Could not find any Unicode functions implementation, you have to provide your own"
-#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS"
-#endif
-#endif
diff --git a/src/hb.h b/src/hb.h
index d36040e..c5a938a 100644
--- a/src/hb.h
+++ b/src/hb.h
@@ -31,9 +31,12 @@
#include "hb-blob.h"
#include "hb-buffer.h"
#include "hb-common.h"
+#include "hb-deprecated.h"
+#include "hb-face.h"
#include "hb-font.h"
#include "hb-set.h"
#include "hb-shape.h"
+#include "hb-shape-plan.h"
#include "hb-unicode.h"
#include "hb-version.h"
diff --git a/src/main.cc b/src/main.cc
index 07d3d69..f9708cc 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -36,6 +36,8 @@
#include <stdio.h>
+using namespace OT;
+
int
main (int argc, char **argv)
@@ -129,8 +131,11 @@ main (int argc, char **argv)
else
printf (" Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
(const char *)script.get_lang_sys_tag (n_langsys));
- if (langsys.get_required_feature_index () == Index::NOT_FOUND_INDEX)
+ if (!langsys.has_required_feature ())
printf (" No required feature\n");
+ else
+ printf (" Required feature index: %d\n",
+ langsys.get_required_feature_index ());
int num_features = langsys.get_feature_count ();
printf (" %d feature(s) found in language system\n", num_features);
@@ -145,11 +150,10 @@ main (int argc, char **argv)
printf (" %d feature(s) found in table\n", num_features);
for (int n_feature = 0; n_feature < num_features; n_feature++) {
const Feature &feature = g.get_feature (n_feature);
- printf (" Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features,
- (const char *)g.get_feature_tag(n_feature),
- feature.get_lookup_count());
-
int num_lookups = feature.get_lookup_count ();
+ printf (" Feature %2d of %2d: %c%c%c%c\n", n_feature, num_features,
+ HB_UNTAG(g.get_feature_tag(n_feature)));
+
printf (" %d lookup(s) found in feature\n", num_lookups);
for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
@@ -168,7 +172,7 @@ main (int argc, char **argv)
}
break;
- case GDEF::Tag:
+ case GDEF::tableTag:
{
const GDEF &gdef = *CastP<GDEF> (font_data + table.offset);
diff --git a/src/sample.py b/src/sample.py
new file mode 100755
index 0000000..f8d2216
--- /dev/null
+++ b/src/sample.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from __future__ import print_function
+import sys
+from gi.repository import HarfBuzz as hb
+from gi.repository import GLib
+
+# Python 2/3 compatibility
+try:
+ unicode
+except NameError:
+ unicode = str
+
+def tounicode(s, encoding='utf-8'):
+ if not isinstance(s, unicode):
+ return s.decode(encoding)
+ else:
+ return s
+
+fontdata = open (sys.argv[1], 'rb').read ()
+text = tounicode(sys.argv[2])
+# Need to create GLib.Bytes explicitly until this bug is fixed:
+# https://bugzilla.gnome.org/show_bug.cgi?id=729541
+blob = hb.glib_blob_create (GLib.Bytes.new (fontdata))
+face = hb.face_create (blob, 0)
+del blob
+font = hb.font_create (face)
+upem = hb.face_get_upem (face)
+del face
+hb.font_set_scale (font, upem, upem)
+#hb.ft_font_set_funcs (font)
+hb.ot_font_set_funcs (font)
+
+buf = hb.buffer_create ()
+hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
+hb.buffer_guess_segment_properties (buf)
+
+hb.shape (font, buf, [])
+del font
+
+infos = hb.buffer_get_glyph_infos (buf)
+positions = hb.buffer_get_glyph_positions (buf)
+
+for info,pos in zip(infos, positions):
+ gid = info.codepoint
+ cluster = info.cluster
+ x_advance = pos.x_advance
+ x_offset = pos.x_offset
+ y_offset = pos.y_offset
+
+ print("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset))
diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc
new file mode 100644
index 0000000..18c46e9
--- /dev/null
+++ b/src/test-buffer-serialize.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright © 2010,2011,2013 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+# define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ hb_blob_t *blob = NULL;
+
+ if (argc != 2) {
+ fprintf (stderr, "usage: %s font-file\n", argv[0]);
+ exit (1);
+ }
+
+ /* Create the blob */
+ {
+ const char *font_data;
+ unsigned int len;
+ hb_destroy_func_t destroy;
+ void *user_data;
+ hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+ GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+ font_data = g_mapped_file_get_contents (mf);
+ len = g_mapped_file_get_length (mf);
+ destroy = (hb_destroy_func_t) g_mapped_file_unref;
+ user_data = (void *) mf;
+ mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+ FILE *f = fopen (argv[1], "rb");
+ fseek (f, 0, SEEK_END);
+ len = ftell (f);
+ fseek (f, 0, SEEK_SET);
+ font_data = (const char *) malloc (len);
+ if (!font_data) len = 0;
+ len = fread ((char *) font_data, 1, len, f);
+ destroy = free;
+ user_data = (void *) font_data;
+ fclose (f);
+ mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+ blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+ }
+
+ hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+ hb_blob_destroy (blob);
+ blob = NULL;
+
+ unsigned int upem = hb_face_get_upem (face);
+ hb_font_t *font = hb_font_create (face);
+ hb_face_destroy (face);
+ hb_font_set_scale (font, upem, upem);
+#ifdef HAVE_FREETYPE
+ hb_ft_font_set_funcs (font);
+#endif
+
+ hb_buffer_t *buf;
+ buf = hb_buffer_create ();
+
+ bool ret = true;
+ char line[BUFSIZ], out[BUFSIZ];
+ while (fgets (line, sizeof(line), stdin) != 0)
+ {
+ hb_buffer_clear_contents (buf);
+
+ const char *p = line;
+ while (hb_buffer_deserialize_glyphs (buf,
+ p, -1, &p,
+ font,
+ HB_BUFFER_SERIALIZE_FORMAT_JSON))
+ ;
+ if (*p && *p != '\n')
+ ret = false;
+
+ hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf),
+ out, sizeof (out), NULL,
+ font, HB_BUFFER_SERIALIZE_FORMAT_JSON,
+ HB_BUFFER_SERIALIZE_FLAG_DEFAULT);
+ puts (out);
+ }
+
+ hb_buffer_destroy (buf);
+
+ hb_font_destroy (font);
+
+ return !ret;
+}
diff --git a/src/test-size-params.cc b/src/test-size-params.cc
new file mode 100644
index 0000000..35d9e3c
--- /dev/null
+++ b/src/test-size-params.cc
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2010,2011 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+# define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ hb_blob_t *blob = NULL;
+
+ if (argc != 2) {
+ fprintf (stderr, "usage: %s font-file\n", argv[0]);
+ exit (1);
+ }
+
+ /* Create the blob */
+ {
+ const char *font_data;
+ unsigned int len;
+ hb_destroy_func_t destroy;
+ void *user_data;
+ hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+ GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+ font_data = g_mapped_file_get_contents (mf);
+ len = g_mapped_file_get_length (mf);
+ destroy = (hb_destroy_func_t) g_mapped_file_unref;
+ user_data = (void *) mf;
+ mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+ FILE *f = fopen (argv[1], "rb");
+ fseek (f, 0, SEEK_END);
+ len = ftell (f);
+ fseek (f, 0, SEEK_SET);
+ font_data = (const char *) malloc (len);
+ if (!font_data) len = 0;
+ len = fread ((char *) font_data, 1, len, f);
+ destroy = free;
+ user_data = (void *) font_data;
+ fclose (f);
+ mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+ blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+ }
+
+ /* Create the face */
+ hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+ hb_blob_destroy (blob);
+ blob = NULL;
+
+ unsigned int p[5];
+ bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4);
+
+ printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.);
+
+ return !ret;
+}
diff --git a/src/test-would-substitute.cc b/src/test-would-substitute.cc
new file mode 100644
index 0000000..8ea87cd
--- /dev/null
+++ b/src/test-would-substitute.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2010,2011 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+#include "hb-ot.h"
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+# define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+int
+main (int argc, char **argv)
+{
+ hb_blob_t *blob = NULL;
+
+ if (argc != 4 && argc != 5) {
+ fprintf (stderr, "usage: %s font-file lookup-index first-glyph [second-glyph]\n", argv[0]);
+ exit (1);
+ }
+
+ /* Create the blob */
+ {
+ const char *font_data;
+ unsigned int len;
+ hb_destroy_func_t destroy;
+ void *user_data;
+ hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+ GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+ font_data = g_mapped_file_get_contents (mf);
+ len = g_mapped_file_get_length (mf);
+ destroy = (hb_destroy_func_t) g_mapped_file_unref;
+ user_data = (void *) mf;
+ mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+ FILE *f = fopen (argv[1], "rb");
+ fseek (f, 0, SEEK_END);
+ len = ftell (f);
+ fseek (f, 0, SEEK_SET);
+ font_data = (const char *) malloc (len);
+ if (!font_data) len = 0;
+ len = fread ((char *) font_data, 1, len, f);
+ destroy = free;
+ user_data = (void *) font_data;
+ fclose (f);
+ mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+ blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+ }
+
+ /* Create the face */
+ hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+ hb_blob_destroy (blob);
+ blob = NULL;
+
+ hb_font_t *font = hb_font_create (face);
+#ifdef HAVE_FREETYPE
+ hb_ft_font_set_funcs (font);
+#endif
+
+ unsigned int len = argc - 3;
+ hb_codepoint_t glyphs[2];
+ if (!hb_font_glyph_from_string (font, argv[3], -1, &glyphs[0]) ||
+ (argc > 4 &&
+ !hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1])))
+ return 2;
+ return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], NULL, 0), glyphs, len, false);
+}
diff --git a/src/test.cc b/src/test.cc
new file mode 100644
index 0000000..a8fe046
--- /dev/null
+++ b/src/test.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright © 2010,2011 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hb.h"
+
+#ifdef HAVE_GLIB
+# include <glib.h>
+# if !GLIB_CHECK_VERSION (2, 22, 0)
+# define g_mapped_file_unref g_mapped_file_free
+# endif
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef HAVE_FREETYPE
+#include "hb-ft.h"
+#endif
+
+int
+main (int argc, char **argv)
+{
+ hb_blob_t *blob = NULL;
+
+ if (argc != 2) {
+ fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
+ exit (1);
+ }
+
+ /* Create the blob */
+ {
+ const char *font_data;
+ unsigned int len;
+ hb_destroy_func_t destroy;
+ void *user_data;
+ hb_memory_mode_t mm;
+
+#ifdef HAVE_GLIB
+ GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL);
+ font_data = g_mapped_file_get_contents (mf);
+ len = g_mapped_file_get_length (mf);
+ destroy = (hb_destroy_func_t) g_mapped_file_unref;
+ user_data = (void *) mf;
+ mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE;
+#else
+ FILE *f = fopen (argv[1], "rb");
+ fseek (f, 0, SEEK_END);
+ len = ftell (f);
+ fseek (f, 0, SEEK_SET);
+ font_data = (const char *) malloc (len);
+ if (!font_data) len = 0;
+ len = fread ((char *) font_data, 1, len, f);
+ destroy = free;
+ user_data = (void *) font_data;
+ fclose (f);
+ mm = HB_MEMORY_MODE_WRITABLE;
+#endif
+
+ blob = hb_blob_create (font_data, len, mm, user_data, destroy);
+ }
+
+ printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
+
+ /* Create the face */
+ hb_face_t *face = hb_face_create (blob, 0 /* first face */);
+ hb_blob_destroy (blob);
+ blob = NULL;
+ unsigned int upem = hb_face_get_upem (face);
+
+ hb_font_t *font = hb_font_create (face);
+ hb_font_set_scale (font, upem, upem);
+
+#ifdef HAVE_FREETYPE
+ hb_ft_font_set_funcs (font);
+#endif
+
+ hb_buffer_t *buffer = hb_buffer_create ();
+
+ hb_buffer_add_utf8 (buffer, "\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb0\xe0\xa5\x8d\xe0\xa4\x95", -1, 0, -1);
+ hb_buffer_guess_segment_properties (buffer);
+
+ hb_shape (font, buffer, NULL, 0);
+
+ unsigned int count = hb_buffer_get_length (buffer);
+ hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, NULL);
+ hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, NULL);
+
+ for (unsigned int i = 0; i < count; i++)
+ {
+ hb_glyph_info_t *info = &infos[i];
+ hb_glyph_position_t *pos = &positions[i];
+
+ printf ("cluster %d glyph 0x%x at (%d,%d)+(%d,%d)\n",
+ info->cluster,
+ info->codepoint,
+ pos->x_offset,
+ pos->x_offset,
+ pos->x_advance,
+ pos->y_advance);
+
+ }
+
+ hb_buffer_destroy (buffer);
+ hb_font_destroy (font);
+ hb_face_destroy (face);
+
+ return 0;
+}
+
+