import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,372 @@
# Process this file with automake to produce Makefile.in
SUBDIRS =
DIST_SUBDIRS =
BUILT_SOURCES =
EXTRA_DIST =
CLEANFILES =
DISTCLEANFILES =
MAINTAINERCLEANFILES =
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
# The following warning options are useful for debugging: -Wpadded
#AM_CXXFLAGS =
# Convenience targets:
lib: $(BUILT_SOURCES) libharfbuzz.la
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
lib_LTLIBRARIES = libharfbuzz.la
include Makefile.sources
HBCFLAGS =
HBLIBS =
HBNONPCLIBS =
HBDEPS =
HBSOURCES = $(HB_BASE_sources)
HBHEADERS = $(HB_BASE_headers)
HBNODISTHEADERS = $(HB_NODIST_headers)
if HAVE_OT
HBSOURCES += $(HB_OT_sources)
HBHEADERS += $(HB_OT_headers)
endif
if HAVE_FALLBACK
HBSOURCES += $(HB_FALLBACK_sources)
endif
if HAVE_PTHREAD
HBCFLAGS += $(PTHREAD_CFLAGS)
HBNONPCLIBS += $(PTHREAD_LIBS)
endif
if HAVE_GLIB
HBCFLAGS += $(GLIB_CFLAGS)
HBLIBS += $(GLIB_LIBS)
HBDEPS += $(GLIB_DEPS)
HBSOURCES += $(HB_GLIB_sources)
HBHEADERS += $(HB_GLIB_headers)
endif
if HAVE_FREETYPE
HBCFLAGS += $(FREETYPE_CFLAGS)
HBLIBS += $(FREETYPE_LIBS)
# XXX
# The following creates a recursive dependency on FreeType if FreeType is
# built with HarfBuzz support enabled. Newer pkg-config handles that just
# fine but pkg-config 0.26 as shipped in Ubuntu 14.04 crashes. Remove
# in a year or two, or otherwise work around it...
#HBDEPS += $(FREETYPE_DEPS)
HBSOURCES += $(HB_FT_sources)
HBHEADERS += $(HB_FT_headers)
endif
if HAVE_GRAPHITE2
HBCFLAGS += $(GRAPHITE2_CFLAGS)
HBLIBS += $(GRAPHITE2_LIBS)
HBDEPS += $(GRAPHITE2_DEPS)
HBSOURCES += $(HB_GRAPHITE2_sources)
HBHEADERS += $(HB_GRAPHITE2_headers)
endif
if HAVE_UNISCRIBE
HBCFLAGS += $(UNISCRIBE_CFLAGS)
HBNONPCLIBS += $(UNISCRIBE_LIBS)
HBSOURCES += $(HB_UNISCRIBE_sources)
HBHEADERS += $(HB_UNISCRIBE_headers)
endif
if HAVE_DIRECTWRITE
HBCFLAGS += $(DIRECTWRITE_CXXFLAGS)
HBNONPCLIBS += $(DIRECTWRITE_LIBS)
HBSOURCES += $(HB_DIRECTWRITE_sources)
HBHEADERS += $(HB_DIRECTWRITE_headers)
endif
if HAVE_CORETEXT
HBCFLAGS += $(CORETEXT_CFLAGS)
HBNONPCLIBS += $(CORETEXT_LIBS)
HBSOURCES += $(HB_CORETEXT_sources)
HBHEADERS += $(HB_CORETEXT_headers)
endif
if HAVE_UCDN
SUBDIRS += hb-ucdn
HBCFLAGS += -I$(srcdir)/hb-ucdn
HBLIBS += hb-ucdn/libhb-ucdn.la
HBSOURCES += $(HB_UCDN_sources)
endif
DIST_SUBDIRS += hb-ucdn
# Put the library together
HBLIBS += $(HBNONPCLIBS)
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)
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) $(export_symbols) -no-undefined
libharfbuzz_la_LIBADD = $(HBLIBS)
EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
pkginclude_HEADERS = $(HBHEADERS)
nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = harfbuzz.pc
EXTRA_DIST += harfbuzz.pc.in
FUZZING_CPPFLAGS= \
-DHB_NDEBUG \
-DHB_MAX_NESTING_LEVEL=3 \
-DHB_SANITIZE_MAX_EDITS=3 \
-DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
-DHB_BUFFER_MAX_LEN_MIN=8 \
-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
$(NULL)
EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
CLEANFILES += libharfbuzz-fuzzing.la
if HAVE_ICU
if HAVE_ICU_BUILTIN
HBCFLAGS += $(ICU_CFLAGS)
HBLIBS += $(ICU_LIBS)
HBSOURCES += $(HB_ICU_sources)
HBHEADERS += $(HB_ICU_headers)
else
lib_LTLIBRARIES += libharfbuzz-icu.la
libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
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_headers)
pkgconfig_DATA += harfbuzz-icu.pc
endif
endif
EXTRA_DIST += harfbuzz-icu.pc.in
if HAVE_GOBJECT
lib_LTLIBRARIES += libharfbuzz-gobject.la
libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_sources)
nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_ENUM_sources)
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_headers)
nodist_pkginclude_HEADERS += $(HB_GOBJECT_ENUM_headers)
pkgconfig_DATA += harfbuzz-gobject.pc
BUILT_SOURCES += \
$(HB_GOBJECT_ENUM_sources) \
$(HB_GOBJECT_ENUM_headers) \
$(NULL)
DISTCLEANFILES += \
$(HB_GOBJECT_ENUM_sources) \
$(HB_GOBJECT_ENUM_headers) \
$(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@%libs_private%@$(HBNONPCLIBS)@g' \
-e 's@%requires_private%@$(HBDEPS)@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-0.dll; \
) >"$@"
@ ! grep -q hb_ERROR "$@" \
|| ($(RM) "$@"; false)
GENERATORS = \
gen-arabic-table.py \
gen-indic-table.py \
gen-use-table.py \
$(NULL)
EXTRA_DIST += $(GENERATORS)
unicode-tables: arabic-table indic-table use-table
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)
indic-table: gen-indic-table.py IndicSyllabicCategory-7.0.0.txt IndicMatraCategory-7.0.0.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
|| ($(RM) hb-ot-shape-complex-indic-table.cc; false)
use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-use-table.cc \
|| ($(RM) hb-ot-shape-complex-use-table.cc; false)
built-sources: $(BUILT_SOURCES)
.PHONY: unicode-tables arabic-table indic-table use-table built-sources
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-use-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-use-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 \
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)
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-includes.sh \
check-libstdc++.sh \
check-static-inits.sh \
check-symbols.sh \
$(NULL)
check_PROGRAMS = \
test-ot-tag \
$(NULL)
test_ot_tag_SOURCES = hb-ot-tag.cc
test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
HBSOURCES="$(HBSOURCES)" \
HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \
$(NULL)
if HAVE_INTROSPECTION
-include $(INTROSPECTION_MAKEFILE)
INTROSPECTION_GIRS = HarfBuzz-0.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 \
-DHB_EXTERN= \
$(NULL)
HarfBuzz_0_0_gir_LIBS = \
libharfbuzz.la \
libharfbuzz-gobject.la \
$(NULL)
HarfBuzz_0_0_gir_FILES = \
$(HBHEADERS) \
$(HBNODISTHEADERS) \
$(HBSOURCES) \
$(HB_GOBJECT_ENUM_sources) \
$(HB_GOBJECT_ENUM_headers) \
$(HB_GOBJECT_sources) \
$(HB_GOBJECT_STRUCTS_headers) \
$(NULL)
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

View file

@ -0,0 +1,28 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
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 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
exit $stat

View file

@ -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

View file

@ -0,0 +1,24 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
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
test -f "$srcdir/$x" && x="$srcdir/$x"
echo "$x" | grep -q '[^h]$' && continue;
xx=`echo "$x" | sed 's@.*/@@'`
tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`
lines=`grep -w "$tag" "$x" | wc -l | sed 's/[ ]*//g'`
if test "x$lines" != x3; then
echo "Ouch, header file $x does not have correct preprocessor guards"
stat=1
fi
done
exit $stat

View file

@ -0,0 +1,44 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
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"' |
grep -v '"hb[.]h"' |
grep -v 'hb-common[.]h:' |
grep -v 'hb[.]h:' |
grep . >&2 && stat=1
echo 'Checking that source files #include "hb-*private.hh" first (or none)'
for x in $HBSOURCES; do
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:' |
grep . >&2 && stat=1
echo 'Checking that there is no #include <hb.*.h>'
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

View file

@ -0,0 +1,34 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
if which ldd 2>/dev/null >/dev/null; then
:
else
echo "check-libstdc++.sh: 'ldd' not found; skipping test"
exit 77
fi
tested=false
for suffix in so dylib; do
so=.libs/libharfbuzz.$suffix
if ! test -f "$so"; then continue; fi
echo "Checking that we are not linking to libstdc++ or libc++"
if ldd $so | grep 'libstdc[+][+]\|libc[+][+]'; then
echo "Ouch, linked to libstdc++ or libc++"
stat=1
fi
tested=true
done
if ! $tested; then
echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"
exit 77
fi
exit $stat

View file

@ -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

View file

@ -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\>\| ___gcov_flush\>\| llvm_\| _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

View file

@ -0,0 +1,269 @@
#!/usr/bin/python
import sys
import os.path
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 ()], [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:
j = line.find ('#')
if j >= 0:
line = line[:j]
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):
values = {}
for line in f:
if line[0] == '#':
continue
fields = [x.strip () for x in line.split (';')]
if len (fields) == 1:
continue
u = int (fields[0], 16)
if fields[3] in ["ALAPH", "DALATH RISH"]:
value = "JOINING_GROUP_" + fields[3].replace(' ', '_')
else:
value = "JOINING_TYPE_" + fields[2]
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
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 "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
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):
shapes = {}
ligatures = {}
names = {}
for line in f:
fields = [x.strip () for x in line.split (';')]
if fields[5][0:1] != '<':
continue
items = fields[5].split (' ')
shape, items = items[0][1:-1], tuple (int (x, 16) for x in items[1:])
if not shape in ['initial', 'medial', 'isolated', 'final']:
continue
c = int (fields[0], 16)
if len (items) != 1:
# We only care about lam-alef ligatures
if len (items) != 2 or items[0] != 0x0644 or items[1] not in [0x0622, 0x0623, 0x0625, 0x0627]:
continue
# Save ligature
names[c] = fields[1]
if items not in ligatures:
ligatures[items] = {}
ligatures[items][shape] = c
pass
else:
# Save shape
if items[0] not in names:
names[items[0]] = fields[1]
else:
names[items[0]] = os.path.commonprefix ([names[items[0]], fields[1]]).strip ()
if items[0] not in shapes:
shapes[items[0]] = {}
shapes[items[0]][shape] = c
print
print "static const uint16_t shaping_table[][4] ="
print "{"
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 0
for shape in ['initial', 'medial', 'final', 'isolated']]
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%04Xu" % min_u
print "#define SHAPING_TABLE_LAST 0x%04Xu" % max_u
print
ligas = {}
for pair in ligatures.keys ():
for shape in ligatures[pair]:
c = ligatures[pair][shape]
if shape == 'isolated':
liga = (shapes[pair[0]]['initial'], shapes[pair[1]]['final'])
elif shape == 'final':
liga = (shapes[pair[0]]['medial'], shapes[pair[1]]['final'])
else:
raise Exception ("Unexpected shape", shape)
if liga[0] not in ligas:
ligas[liga[0]] = []
ligas[liga[0]].append ((liga[1], c))
max_i = max (len (ligas[l]) for l in ligas)
print
print "static const struct ligature_set_t {"
print " uint16_t first;"
print " struct ligature_pairs_t {"
print " uint16_t second;"
print " uint16_t ligature;"
print " } ligatures[%d];" % max_i
print "} ligature_table[] ="
print "{"
keys = ligas.keys ()
keys.sort ()
for first in keys:
print " { 0x%04Xu, {" % (first)
for liga in ligas[first]:
print " { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]])
print " }},"
print "};"
print
print "/* == Start of generated table == */"
print "/*"
print " * The following table is generated by running:"
print " *"
print " * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt"
print " *"
print " * on files with these headers:"
print " *"
for h in headers:
for l in h:
print " * %s" % (l.strip())
print " */"
print
print "#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
print "#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH"
print
read_blocks (files[2])
print_joining_table (files[0])
print_shaping_table (files[1])
print
print "#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */"
print
print "/* == End of generated table == */"

View file

@ -0,0 +1,260 @@
#!/usr/bin/python
import sys
if len (sys.argv) != 4:
print >>sys.stderr, "usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt"
sys.exit (1)
ALLOWED_SINGLES = [0x00A0, 0x25CC]
ALLOWED_BLOCKS = [
'Basic Latin',
'Latin-1 Supplement',
'Devanagari',
'Bengali',
'Gurmukhi',
'Gujarati',
'Oriya',
'Tamil',
'Telugu',
'Kannada',
'Malayalam',
'Sinhala',
'Myanmar',
'Khmer',
'Vedic Extensions',
'General Punctuation',
'Superscripts and Subscripts',
'Devanagari Extended',
'Myanmar Extended-B',
'Myanmar Extended-A',
]
files = [file (x) for x in sys.argv[1:]]
headers = [[f.readline () for i in range (2)] for f in files]
data = [{} for f in files]
values = [{} for f in files]
for i, f in enumerate (files):
for line in f:
j = line.find ('#')
if j >= 0:
line = line[:j]
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):
data[i][u] = t
values[i][t] = values[i].get (t, 0) + end - start + 1
# Merge data into one dict:
defaults = ('Other', 'Not_Applicable', 'No_Block')
for i,v in enumerate (defaults):
values[i][v] = values[i].get (v, 0) + 1
combined = {}
for i,d in enumerate (data):
for u,v in d.items ():
if i == 2 and not u in combined:
continue
if not u in combined:
combined[u] = list (defaults)
combined[u][i] = v
combined = {k:v for k,v in combined.items() if k in ALLOWED_SINGLES or v[2] in ALLOWED_BLOCKS}
data = combined
del combined
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 ALLOWED_SINGLES:
singles[u] = data[u]
del data[u]
print "/* == Start of generated table == */"
print "/*"
print " * The following table is generated by running:"
print " *"
print " * ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt"
print " *"
print " * on files with these headers:"
print " *"
for h in headers:
for l in h:
print " * %s" % (l.strip())
print " */"
print
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',
"Consonant_Prefixed": 'CPrf',
"Other": 'x',
},{
"Not_Applicable": 'x',
}]
all_shorts = [{},{}]
# Add some of the values, to make them more readable, and to avoid duplicates
for i in range (2):
for v,s in short[i].items ():
all_shorts[i][s] = v
what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
what_short = ["ISC", "IMC"]
for i in range (2):
print
vv = values[i].keys ()
vv.sort ()
for v in vv:
v_no_and = v.replace ('_And_', '_')
if v in short[i]:
s = short[i][v]
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, 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 (), \
' '* ((48-1 - len (what[i]) - 1 - len (v)) / 8), \
values[i][v], v)
print
print "#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)"
print
print
total = 0
used = 0
last_block = None
def print_block (block, start, end, data):
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
print " /* %04X */" % u,
if u in data:
num += 1
d = data.get (u, defaults)
sys.stdout.write ("%9s" % ("_(%s,%s)," % (short[0][d[0]], short[1][d[1]])))
total += end - start + 1
used += num
if block:
last_block = block
uu = data.keys ()
uu.sort ()
last = -100000
num = 0
offset = 0
starts = []
ends = []
print "static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {"
for u in uu:
if u <= last:
continue
block = data[u][2]
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 <= 1+16*3:
print_block (None, last+1, start-1, data)
last = start-1
else:
if last >= 0:
ends.append (last + 1)
offset += ends[-1] - starts[-1]
print
print
print "#define indic_offset_0x%04xu %d" % (start, offset)
starts.append (start)
print_block (block, start, end, data)
last = end
ends.append (last + 1)
offset += ends[-1] - starts[-1]
print
print
occupancy = used * 100. / total
page_bits = 12
print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
print
print "INDIC_TABLE_ELEMENT_TYPE"
print "hb_indic_get_categories (hb_codepoint_t u)"
print "{"
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
print "#undef _"
for i in range (2):
print
vv = values[i].keys ()
vv.sort ()
for v in vv:
print "#undef %s_%s" % \
(what_short[i], short[i][v])
print
print "/* == End of generated table == */"
# Maintain at least 30% occupancy in the table */
if occupancy < 30:
raise Exception ("Table too sparse, please investigate: ", occupancy)

View file

@ -0,0 +1,477 @@
#!/usr/bin/python
import sys
if len (sys.argv) != 5:
print >>sys.stderr, "usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.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 j,f in enumerate(files) if j != 2]
headers.append (["UnicodeData.txt does not have a header."])
data = [{} for f in files]
values = [{} for f in files]
for i, f in enumerate (files):
for line in f:
j = line.find ('#')
if j >= 0:
line = line[:j]
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 if i != 2 else 2]
for u in range (start, end + 1):
data[i][u] = t
values[i][t] = values[i].get (t, 0) + end - start + 1
defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
# TODO Characters that are not in Unicode Indic files, but used in USE
data[0][0x034F] = defaults[0]
data[0][0x2060] = defaults[0]
for u in range (0xFE00, 0xFE0F + 1):
data[0][u] = defaults[0]
# Merge data into one dict:
for i,v in enumerate (defaults):
values[i][v] = values[i].get (v, 0) + 1
combined = {}
for i,d in enumerate (data):
for u,v in d.items ():
if i >= 2 and not u in combined:
continue
if not u in combined:
combined[u] = list (defaults)
combined[u][i] = v
combined = {k:v for k,v in combined.items() if v[3] not in BLACKLISTED_BLOCKS}
data = combined
del combined
num = len (data)
property_names = [
# General_Category
'Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', 'Mc',
'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf', 'Pi', 'Po',
'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',
# Indic_Syllabic_Category
'Other',
'Bindu',
'Visarga',
'Avagraha',
'Nukta',
'Virama',
'Pure_Killer',
'Invisible_Stacker',
'Vowel_Independent',
'Vowel_Dependent',
'Vowel',
'Consonant_Placeholder',
'Consonant',
'Consonant_Dead',
'Consonant_With_Stacker',
'Consonant_Prefixed',
'Consonant_Preceding_Repha',
'Consonant_Succeeding_Repha',
'Consonant_Subjoined',
'Consonant_Medial',
'Consonant_Final',
'Consonant_Head_Letter',
'Modifying_Letter',
'Tone_Letter',
'Tone_Mark',
'Gemination_Mark',
'Cantillation_Mark',
'Register_Shifter',
'Syllable_Modifier',
'Consonant_Killer',
'Non_Joiner',
'Joiner',
'Number_Joiner',
'Number',
'Brahmi_Joining_Number',
# Indic_Positional_Category
'Not_Applicable',
'Right',
'Left',
'Visual_Order_Left',
'Left_And_Right',
'Top',
'Bottom',
'Top_And_Bottom',
'Top_And_Right',
'Top_And_Left',
'Top_And_Left_And_Right',
'Bottom_And_Right',
'Top_And_Bottom_And_Right',
'Overstruck',
]
class PropertyValue(object):
def __init__(self, name_):
self.name = name_
def __str__(self):
return self.name
def __eq__(self, other):
return self.name == (other if isinstance(other, basestring) else other.name)
def __ne__(self, other):
return not (self == other)
property_values = {}
for name in property_names:
value = PropertyValue(name)
assert value not in property_values
assert value not in globals()
property_values[name] = value
globals().update(property_values)
def is_BASE(U, UISC, UGC):
return (UISC in [Number, Consonant, Consonant_Head_Letter,
#SPEC-DRAFT Consonant_Placeholder,
Tone_Letter,
Vowel_Independent #SPEC-DRAFT
] or
(UGC == Lo and UISC in [Avagraha, Bindu, Consonant_Final, Consonant_Medial,
Consonant_Subjoined, Vowel, Vowel_Dependent]))
def is_BASE_IND(U, UISC, UGC):
#SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
return (UISC in [Consonant_Dead, Modifying_Letter] or
(UGC == Po and not U in [0x104E, 0x2022]) or
False # SPEC-DRAFT-OUTDATED! U == 0x002D
)
def is_BASE_NUM(U, UISC, UGC):
return UISC == Brahmi_Joining_Number
def is_BASE_OTHER(U, UISC, UGC):
if UISC == Consonant_Placeholder: return True #SPEC-DRAFT
#SPEC-DRAFT return U in [0x00A0, 0x00D7, 0x2015, 0x2022, 0x25CC, 0x25FB, 0x25FC, 0x25FD, 0x25FE]
return U in [0x2015, 0x2022, 0x25FB, 0x25FC, 0x25FD, 0x25FE]
def is_CGJ(U, UISC, UGC):
return U == 0x034F
def is_CONS_FINAL(U, UISC, UGC):
return ((UISC == Consonant_Final and UGC != Lo) or
UISC == Consonant_Succeeding_Repha)
def is_CONS_FINAL_MOD(U, UISC, UGC):
#SPEC-DRAFT return UISC in [Consonant_Final_Modifier, Syllable_Modifier]
return UISC == Syllable_Modifier
def is_CONS_MED(U, UISC, UGC):
return UISC == Consonant_Medial and UGC != Lo
def is_CONS_MOD(U, UISC, UGC):
return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
def is_CONS_SUB(U, UISC, UGC):
#SPEC-DRAFT return UISC == Consonant_Subjoined
return UISC == Consonant_Subjoined and UGC != Lo
def is_HALANT(U, UISC, UGC):
return UISC in [Virama, Invisible_Stacker]
def is_HALANT_NUM(U, UISC, UGC):
return UISC == Number_Joiner
def is_ZWNJ(U, UISC, UGC):
return UISC == Non_Joiner
def is_ZWJ(U, UISC, UGC):
return UISC == Joiner
def is_Word_Joiner(U, UISC, UGC):
return U == 0x2060
def is_OTHER(U, UISC, UGC):
#SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters
return (UISC == Other
and not is_SYM_MOD(U, UISC, UGC)
and not is_CGJ(U, UISC, UGC)
and not is_Word_Joiner(U, UISC, UGC)
and not is_VARIATION_SELECTOR(U, UISC, UGC)
)
def is_Reserved(U, UISC, UGC):
return UGC == 'Cn'
def is_REPHA(U, UISC, UGC):
#return UISC == Consonant_Preceding_Repha
#SPEC-OUTDATED hack to categorize Consonant_With_Stacker and Consonant_Prefixed
return UISC in [Consonant_Preceding_Repha, Consonant_With_Stacker, Consonant_Prefixed]
def is_SYM(U, UISC, UGC):
if U == 0x25CC: return False #SPEC-DRAFT
#SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter
return UGC in [So, Sc]
def is_SYM_MOD(U, UISC, UGC):
return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
def is_VARIATION_SELECTOR(U, UISC, UGC):
return 0xFE00 <= U <= 0xFE0F
def is_VOWEL(U, UISC, UGC):
return (UISC == Pure_Killer or
(UGC != Lo and UISC in [Vowel, Vowel_Dependent]))
def is_VOWEL_MOD(U, UISC, UGC):
return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
(UGC != Lo and UISC == Bindu))
use_mapping = {
'B': is_BASE,
'IND': is_BASE_IND,
'N': is_BASE_NUM,
'GB': is_BASE_OTHER,
'CGJ': is_CGJ,
'F': is_CONS_FINAL,
'FM': is_CONS_FINAL_MOD,
'M': is_CONS_MED,
'CM': is_CONS_MOD,
'SUB': is_CONS_SUB,
'H': is_HALANT,
'HN': is_HALANT_NUM,
'ZWNJ': is_ZWNJ,
'ZWJ': is_ZWJ,
'WJ': is_Word_Joiner,
'O': is_OTHER,
'Rsv': is_Reserved,
'R': is_REPHA,
'S': is_SYM,
'SM': is_SYM_MOD,
'VS': is_VARIATION_SELECTOR,
'V': is_VOWEL,
'VM': is_VOWEL_MOD,
}
use_positions = {
'F': {
'Abv': [Top],
'Blw': [Bottom],
'Pst': [Right],
},
'M': {
'Abv': [Top],
'Blw': [Bottom],
'Pst': [Right],
'Pre': [Left],
},
'CM': {
'Abv': [Top],
'Blw': [Bottom],
},
'V': {
'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right],
'Blw': [Bottom, Overstruck, Bottom_And_Right],
'Pst': [Right],
'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
},
'VM': {
'Abv': [Top],
'Blw': [Bottom, Overstruck],
'Pst': [Right],
'Pre': [Left],
},
'SM': {
'Abv': [Top],
'Blw': [Bottom],
},
'H': None,
'B': None,
'FM': None,
'SUB': None,
}
def map_to_use(data):
out = {}
items = use_mapping.items()
for U,(UISC,UIPC,UGC,UBlock) in data.items():
# Resolve Indic_Syllabic_Category
# TODO: These don't have UISC assigned in Unicode 8.0, but
# have UIPC
if U == 0x17DD: UISC = Vowel_Dependent
if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
# TODO: U+1CED should only be allowed after some of
# the nasalization marks, maybe only for U+1CE9..U+1CF1.
if U == 0x1CED: UISC = Tone_Mark
evals = [(k, v(U,UISC,UGC)) for k,v in items]
values = [k for k,v in evals if v]
assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
USE = values[0]
# Resolve Indic_Positional_Category
# TODO: Not in Unicode 8.0 yet, but in spec.
if U == 0x1B6C: UIPC = Bottom
# TODO: These should die, but have UIPC in Unicode 8.0
if U in [0x953, 0x954]: UIPC = Not_Applicable
# TODO: In USE's override list but not in Unicode 8.0
if U == 0x103C: UIPC = Left
# TODO: These are not in USE's override list that we have, nor are they in Unicode 8.0
if 0xA926 <= U <= 0xA92A: UIPC = Top
if U == 0x111CA: UIPC = Bottom
if U == 0x11300: UIPC = Top
if U == 0x1133C: UIPC = Bottom
if U == 0x1171E: UIPC = Left # Correct?!
if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
assert (UIPC in [Not_Applicable, Visual_Order_Left] or
USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
pos_mapping = use_positions.get(USE, None)
if pos_mapping:
values = [k for k,v in pos_mapping.items() if v and UIPC in v]
assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, values)
USE = USE + values[0]
out[U] = (USE, UBlock)
return out
defaults = ('O', 'No_Block')
data = map_to_use(data)
# Remove the outliers
singles = {}
for u in [0x034F, 0x25CC, 0x1107F]:
singles[u] = data[u]
del data[u]
print "/* == Start of generated table == */"
print "/*"
print " * The following table is generated by running:"
print " *"
print " * ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt"
print " *"
print " * on files with these headers:"
print " *"
for h in headers:
for l in h:
print " * %s" % (l.strip())
print " */"
print
print '#include "hb-ot-shape-complex-use-private.hh"'
print
total = 0
used = 0
last_block = None
def print_block (block, start, end, data):
global total, used, last_block
if block and block != last_block:
print
print
print " /* %s */" % block
if start % 16:
print ' ' * (20 + (start % 16 * 6)),
num = 0
assert start % 8 == 0
assert (end+1) % 8 == 0
for u in range (start, end+1):
if u % 16 == 0:
print
print " /* %04X */" % u,
if u in data:
num += 1
d = data.get (u, defaults)
sys.stdout.write ("%6s," % d[0])
total += end - start + 1
used += num
if block:
last_block = block
uu = data.keys ()
uu.sort ()
last = -100000
num = 0
offset = 0
starts = []
ends = []
for k,v in sorted(use_mapping.items()):
if k in use_positions and use_positions[k]: continue
print "#define %s USE_%s /* %s */" % (k, k, v.__name__[3:])
for k,v in sorted(use_positions.items()):
if not v: continue
for suf in v.keys():
tag = k + suf
print "#define %s USE_%s" % (tag, tag)
print ""
print "static const USE_TABLE_ELEMENT_TYPE use_table[] = {"
for u in uu:
if u <= last:
continue
block = data[u][1]
start = u//8*8
end = start+1
while end in uu and block == data[end][1]:
end += 1
end = (end-1)//8*8 + 7
if start != last + 1:
if start - last <= 1+16*3:
print_block (None, last+1, start-1, data)
last = start-1
else:
if last >= 0:
ends.append (last + 1)
offset += ends[-1] - starts[-1]
print
print
print "#define use_offset_0x%04xu %d" % (start, offset)
starts.append (start)
print_block (block, start, end, data)
last = end
ends.append (last + 1)
offset += ends[-1] - starts[-1]
print
print
occupancy = used * 100. / total
page_bits = 12
print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
print
print "USE_TABLE_ELEMENT_TYPE"
print "hb_use_get_categories (hb_codepoint_t u)"
print "{"
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 = "use_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return use_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;" % (u, d[0])
print " break;"
print ""
print " default:"
print " break;"
print " }"
print " return USE_O;"
print "}"
print
for k in sorted(use_mapping.keys()):
if k in use_positions and use_positions[k]: continue
print "#undef %s" % k
for k,v in sorted(use_positions.items()):
if not v: continue
for suf in v.keys():
tag = k + suf
print "#undef %s" % tag
print
print "/* == End of generated table == */"
# Maintain at least 50% occupancy in the table */
if occupancy < 50:
raise Exception ("Table too sparse, please investigate: ", occupancy)

View file

@ -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

View file

@ -0,0 +1,13 @@
prefix=/usr/local
exec_prefix=/usr/local
libdir=/usr/local/lib
includedir=/usr/local/include
Name: harfbuzz
Description: HarfBuzz text shaping library ICU integration
Version: 1.4.1
Requires: harfbuzz
Requires.private: icu-uc
Libs: -L${libdir} -lharfbuzz-icu
Cflags: -I${includedir}/harfbuzz

View file

@ -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

View file

@ -0,0 +1,13 @@
prefix=/usr/local
exec_prefix=/usr/local
libdir=/usr/local/lib
includedir=/usr/local/include
Name: harfbuzz
Description: HarfBuzz text shaping library
Version: 1.4.1
Libs: -L${libdir} -lharfbuzz
Libs.private:
Requires.private: glib-2.0 >= 2.19.1
Cflags: -I${includedir}/harfbuzz

View file

@ -0,0 +1,13 @@
prefix=%prefix%
exec_prefix=%exec_prefix%
libdir=%libdir%
includedir=%includedir%
Name: harfbuzz
Description: HarfBuzz text shaping library
Version: %VERSION%
Libs: -L${libdir} -lharfbuzz
Libs.private: %libs_private%
Requires.private: %requires_private%
Cflags: -I${includedir}/harfbuzz

View file

@ -0,0 +1,189 @@
/*
* Copyright © 2007 Chris Wilson
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_ATOMIC_PRIVATE_HH
#define HB_ATOMIC_PRIVATE_HH
#include "hb-private.hh"
/* atomic_int */
/* We need external help for these */
#if defined(hb_atomic_int_impl_add) \
&& defined(hb_atomic_ptr_impl_get) \
&& defined(hb_atomic_ptr_impl_cmpexch)
/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#include <windows.h>
/* 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
}
typedef LONG hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
#define hb_atomic_ptr_impl_get(P) (_HBMemoryBarrier (), (void *) *(P))
#define hb_atomic_ptr_impl_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_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
#define hb_atomic_ptr_impl_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_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
#else
#if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
#endif
#endif
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
typedef int hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add (&(AI), (V))
#define hb_atomic_ptr_impl_get(P) (void *) (__sync_synchronize (), *(P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
#include <atomic.h>
#include <mbarrier.h>
typedef unsigned int hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
#define hb_atomic_ptr_impl_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P))
#define hb_atomic_ptr_impl_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) && defined(_AIX) && defined(__IBMCPP__)
#include <builtins.h>
static inline int hb_fetch_and_add(volatile int* AI, unsigned int V) {
__lwsync();
int result = __fetch_and_add(AI, V);
__isync();
return result;
}
static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) {
__sync();
int result = __compare_and_swaplp (P, &O, N);
__sync();
return result;
}
typedef int hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) hb_fetch_and_add (&(AI), (V))
#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
#elif !defined(HB_NO_MT)
#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
typedef volatile int hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V))
#define hb_atomic_ptr_impl_get(P) ((void *) *(P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
#else /* HB_NO_MT */
typedef int hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V))
#define hb_atomic_ptr_impl_get(P) ((void *) *(P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
#endif
#define HB_ATOMIC_INT_INIT(V) {HB_ATOMIC_INT_IMPL_INIT(V)}
struct hb_atomic_int_t
{
hb_atomic_int_impl_t v;
inline void set_unsafe (int v_) { v = v_; }
inline int get_unsafe (void) const { return v; }
inline int inc (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), 1); }
inline int dec (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), -1); }
};
#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P)
#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N))
#endif /* HB_ATOMIC_PRIVATE_HH */

478
gfx/harfbuzz/src/hb-blob.cc Normal file
View file

@ -0,0 +1,478 @@
/*
* 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
*/
/* 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-object-private.hh"
#ifdef HAVE_SYS_MMAN_H
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /* HAVE_UNISTD_H */
#include <sys/mman.h>
#endif /* HAVE_SYS_MMAN_H */
#include <stdio.h>
#include <errno.h>
#ifndef HB_DEBUG_BLOB
#define HB_DEBUG_BLOB (HB_DEBUG+0)
#endif
struct hb_blob_t {
hb_object_header_t header;
ASSERT_POD ();
bool immutable;
const char *data;
unsigned int length;
hb_memory_mode_t mode;
void *user_data;
hb_destroy_func_t destroy;
};
static bool _try_writable (hb_blob_t *blob);
static void
_hb_blob_destroy_user_data (hb_blob_t *blob)
{
if (blob->destroy) {
blob->destroy (blob->user_data);
blob->user_data = NULL;
blob->destroy = NULL;
}
}
/**
* 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: 0.9.2
**/
hb_blob_t *
hb_blob_create (const char *data,
unsigned int length,
hb_memory_mode_t mode,
void *user_data,
hb_destroy_func_t destroy)
{
hb_blob_t *blob;
if (!length ||
length >= 1u << 31 ||
!(blob = hb_object_create<hb_blob_t> ())) {
if (destroy)
destroy (user_data);
return hb_blob_get_empty ();
}
blob->data = data;
blob->length = length;
blob->mode = mode;
blob->user_data = user_data;
blob->destroy = destroy;
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
blob->mode = HB_MEMORY_MODE_READONLY;
if (!_try_writable (blob)) {
hb_blob_destroy (blob);
return hb_blob_get_empty ();
}
}
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: 0.9.2
**/
hb_blob_t *
hb_blob_create_sub_blob (hb_blob_t *parent,
unsigned int offset,
unsigned int length)
{
hb_blob_t *blob;
if (!length || offset >= parent->length)
return hb_blob_get_empty ();
hb_blob_make_immutable (parent);
blob = hb_blob_create (parent->data + offset,
MIN (length, parent->length - offset),
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: 0.9.2
**/
hb_blob_t *
hb_blob_get_empty (void)
{
static const hb_blob_t _hb_blob_nil = {
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
NULL, /* data */
0, /* length */
HB_MEMORY_MODE_READONLY, /* mode */
NULL, /* user_data */
NULL /* destroy */
};
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: 0.9.2
**/
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: 0.9.2
**/
void
hb_blob_destroy (hb_blob_t *blob)
{
if (!hb_object_destroy (blob)) return;
_hb_blob_destroy_user_data (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: 0.9.2
**/
hb_bool_t
hb_blob_set_user_data (hb_blob_t *blob,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
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: 0.9.2
**/
void *
hb_blob_get_user_data (hb_blob_t *blob,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (blob, key);
}
/**
* hb_blob_make_immutable:
* @blob: a blob.
*
*
*
* Since: 0.9.2
**/
void
hb_blob_make_immutable (hb_blob_t *blob)
{
if (hb_object_is_inert (blob))
return;
blob->immutable = true;
}
/**
* hb_blob_is_immutable:
* @blob: a blob.
*
*
*
* Return value: TODO
*
* Since: 0.9.2
**/
hb_bool_t
hb_blob_is_immutable (hb_blob_t *blob)
{
return blob->immutable;
}
/**
* hb_blob_get_length:
* @blob: a blob.
*
*
*
* Return value: the length of blob data in bytes.
*
* Since: 0.9.2
**/
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: 0.9.2
**/
const char *
hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
{
if (length)
*length = blob->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: 0.9.2
**/
char *
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
{
if (!_try_writable (blob)) {
if (length)
*length = 0;
return NULL;
}
if (length)
*length = blob->length;
return const_cast<char *> (blob->data);
}
static hb_bool_t
_try_make_writable_inplace_unix (hb_blob_t *blob)
{
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
uintptr_t pagesize = -1, mask, length;
const char *addr;
#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE)
pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE);
#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
pagesize = (uintptr_t) sysconf (_SC_PAGESIZE);
#elif defined(HAVE_GETPAGESIZE)
pagesize = (uintptr_t) getpagesize ();
#endif
if ((uintptr_t) -1L == pagesize) {
DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno));
return false;
}
DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize);
mask = ~(pagesize-1);
addr = (const char *) (((uintptr_t) blob->data) & mask);
length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask) - addr;
DEBUG_MSG_FUNC (BLOB, blob,
"calling mprotect on [%p..%p] (%lu bytes)",
addr, addr+length, (unsigned long) length);
if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno));
return false;
}
blob->mode = HB_MEMORY_MODE_WRITABLE;
DEBUG_MSG_FUNC (BLOB, blob,
"successfully made [%p..%p] (%lu bytes) writable\n",
addr, addr+length, (unsigned long) length);
return true;
#else
return false;
#endif
}
static bool
_try_writable_inplace (hb_blob_t *blob)
{
DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n");
if (_try_make_writable_inplace_unix (blob))
return true;
DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n");
/* Failed to make writable inplace, mark that */
blob->mode = HB_MEMORY_MODE_READONLY;
return false;
}
static bool
_try_writable (hb_blob_t *blob)
{
if (blob->immutable)
return false;
if (blob->mode == HB_MEMORY_MODE_WRITABLE)
return true;
if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob))
return true;
if (blob->mode == HB_MEMORY_MODE_WRITABLE)
return true;
DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data);
char *new_data;
new_data = (char *) malloc (blob->length);
if (unlikely (!new_data))
return false;
DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data);
memcpy (new_data, blob->data, blob->length);
_hb_blob_destroy_user_data (blob);
blob->mode = HB_MEMORY_MODE_WRITABLE;
blob->data = new_data;
blob->user_data = new_data;
blob->destroy = free;
return true;
}

126
gfx/harfbuzz/src/hb-blob.h Normal file
View file

@ -0,0 +1,126 @@
/*
* 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_BLOB_H
#define HB_BLOB_H
#include "hb-common.h"
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,
HB_MEMORY_MODE_WRITABLE,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE
} hb_memory_mode_t;
typedef struct hb_blob_t hb_blob_t;
HB_EXTERN hb_blob_t *
hb_blob_create (const char *data,
unsigned int length,
hb_memory_mode_t mode,
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_EXTERN hb_blob_t *
hb_blob_create_sub_blob (hb_blob_t *parent,
unsigned int offset,
unsigned int length);
HB_EXTERN hb_blob_t *
hb_blob_get_empty (void);
HB_EXTERN hb_blob_t *
hb_blob_reference (hb_blob_t *blob);
HB_EXTERN void
hb_blob_destroy (hb_blob_t *blob);
HB_EXTERN hb_bool_t
hb_blob_set_user_data (hb_blob_t *blob,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_blob_get_user_data (hb_blob_t *blob,
hb_user_data_key_t *key);
HB_EXTERN void
hb_blob_make_immutable (hb_blob_t *blob);
HB_EXTERN hb_bool_t
hb_blob_is_immutable (hb_blob_t *blob);
HB_EXTERN unsigned int
hb_blob_get_length (hb_blob_t *blob);
HB_EXTERN const char *
hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
HB_EXTERN char *
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
HB_END_DECLS
#endif /* HB_BLOB_H */

View file

@ -0,0 +1,643 @@
#line 1 "hb-buffer-deserialize-json.rl"
/*
* 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"
#line 36 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u,
9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u,
120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u,
9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
};
static const char _deserialize_json_key_spans[] = {
0, 115, 26, 7, 2, 1, 50, 49,
10, 117, 117, 117, 1, 50, 49, 10,
117, 117, 1, 1, 50, 49, 117, 117,
2, 1, 50, 49, 10, 117, 117, 1,
50, 49, 10, 117, 117, 1, 50, 49,
58, 89, 117, 117, 85, 115, 0
};
static const short _deserialize_json_index_offsets[] = {
0, 0, 116, 143, 151, 154, 156, 207,
257, 268, 386, 504, 622, 624, 675, 725,
736, 854, 972, 974, 976, 1027, 1077, 1195,
1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666,
1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069,
2119, 2178, 2268, 2386, 2504, 2590, 2706
};
static const char _deserialize_json_indicies[] = {
0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 3, 3, 3,
3, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 3, 1, 4, 1,
5, 1, 6, 7, 1, 1, 8, 1,
9, 10, 1, 11, 1, 11, 11, 11,
11, 11, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 11, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 12, 1,
12, 12, 12, 12, 12, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 12,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 13, 1, 1, 14,
15, 15, 15, 15, 15, 15, 15, 15,
15, 1, 16, 17, 17, 17, 17, 17,
17, 17, 17, 17, 1, 18, 18, 18,
18, 18, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 18, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
19, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 20, 1, 21, 21, 21, 21, 21,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 21, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 3, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 22,
1, 18, 18, 18, 18, 18, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
18, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 19, 1, 1, 1,
17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 20, 1, 23,
1, 23, 23, 23, 23, 23, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
23, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 24, 1, 24, 24, 24, 24,
24, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 24, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
25, 1, 1, 26, 27, 27, 27, 27,
27, 27, 27, 27, 27, 1, 28, 29,
29, 29, 29, 29, 29, 29, 29, 29,
1, 30, 30, 30, 30, 30, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
30, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 31, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 32, 1, 30,
30, 30, 30, 30, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 30, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 31, 1, 1, 1, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 32, 1, 33, 1, 34,
1, 34, 34, 34, 34, 34, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
34, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 35, 1, 35, 35, 35, 35,
35, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 35, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 36, 37, 37, 37, 37,
37, 37, 37, 37, 37, 1, 38, 38,
38, 38, 38, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 38, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 39, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 40, 1, 38, 38, 38, 38,
38, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 38, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 39,
1, 1, 1, 41, 41, 41, 41, 41,
41, 41, 41, 41, 41, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
40, 1, 42, 43, 1, 44, 1, 44,
44, 44, 44, 44, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 44, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
45, 1, 45, 45, 45, 45, 45, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 45, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 46, 1,
1, 47, 48, 48, 48, 48, 48, 48,
48, 48, 48, 1, 49, 50, 50, 50,
50, 50, 50, 50, 50, 50, 1, 51,
51, 51, 51, 51, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 51, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 52, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 53, 1, 51, 51, 51,
51, 51, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 51, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
52, 1, 1, 1, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 53, 1, 54, 1, 54, 54, 54,
54, 54, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 54, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 55, 1,
55, 55, 55, 55, 55, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 55,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 56, 1, 1, 57,
58, 58, 58, 58, 58, 58, 58, 58,
58, 1, 59, 60, 60, 60, 60, 60,
60, 60, 60, 60, 1, 61, 61, 61,
61, 61, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 61, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
62, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 63, 1, 61, 61, 61, 61, 61,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 61, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 62, 1,
1, 1, 60, 60, 60, 60, 60, 60,
60, 60, 60, 60, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 63,
1, 64, 1, 64, 64, 64, 64, 64,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 64, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 65, 1, 65, 65,
65, 65, 65, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 65, 1, 66,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 67, 68, 68,
68, 68, 68, 68, 68, 68, 68, 1,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 1, 1, 1, 1, 1, 1,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 1, 70, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 71, 71,
1, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 1, 1, 1, 1, 1,
1, 1, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 1, 1, 1, 1,
71, 1, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 1, 72, 72, 72,
72, 72, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 72, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
73, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 74, 1, 72, 72, 72, 72, 72,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 72, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 73, 1,
1, 1, 75, 75, 75, 75, 75, 75,
75, 75, 75, 75, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 74,
1, 76, 76, 76, 76, 76, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
76, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 77, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 78, 1, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 0
};
static const char _deserialize_json_trans_targs[] = {
1, 0, 2, 2, 3, 4, 18, 24,
37, 5, 12, 6, 7, 8, 9, 11,
9, 11, 10, 2, 44, 10, 44, 13,
14, 15, 16, 17, 16, 17, 10, 2,
44, 19, 20, 21, 22, 23, 10, 2,
44, 23, 25, 31, 26, 27, 28, 29,
30, 29, 30, 10, 2, 44, 32, 33,
34, 35, 36, 35, 36, 10, 2, 44,
38, 39, 40, 42, 43, 41, 10, 41,
10, 2, 44, 43, 44, 45, 46
};
static const char _deserialize_json_trans_actions[] = {
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 2, 2,
0, 0, 3, 3, 4, 0, 5, 0,
0, 2, 2, 2, 0, 0, 6, 6,
7, 0, 0, 0, 2, 2, 8, 8,
9, 0, 0, 0, 0, 0, 2, 2,
2, 0, 0, 10, 10, 11, 0, 0,
2, 2, 2, 0, 0, 12, 12, 13,
0, 0, 0, 2, 2, 2, 14, 0,
15, 15, 16, 0, 0, 0, 0
};
static const int deserialize_json_start = 1;
static const int deserialize_json_first_final = 44;
static const int deserialize_json_error = 0;
static const int deserialize_json_en_main = 1;
#line 97 "hb-buffer-deserialize-json.rl"
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};
#line 466 "hb-buffer-deserialize-json.hh"
{
cs = deserialize_json_start;
}
#line 471 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
_keys = _deserialize_json_trans_keys + (cs<<1);
_inds = _deserialize_json_indicies + _deserialize_json_index_offsets[cs];
_slen = _deserialize_json_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
(*p) <= _keys[1] ?
(*p) - _keys[0] : _slen ];
cs = _deserialize_json_trans_targs[_trans];
if ( _deserialize_json_trans_actions[_trans] == 0 )
goto _again;
switch ( _deserialize_json_trans_actions[_trans] ) {
case 1:
#line 38 "hb-buffer-deserialize-json.rl"
{
memset (&info, 0, sizeof (info));
memset (&pos , 0, sizeof (pos ));
}
break;
case 5:
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 2:
#line 51 "hb-buffer-deserialize-json.rl"
{
tok = p;
}
break;
case 14:
#line 55 "hb-buffer-deserialize-json.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 15:
#line 62 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
break;
case 8:
#line 63 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 10:
#line 64 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
case 12:
#line 65 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
case 3:
#line 66 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
case 6:
#line 67 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
break;
case 16:
#line 62 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 63 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 64 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 13:
#line 65 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 4:
#line 66 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 7:
#line 67 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 624 "hb-buffer-deserialize-json.hh"
}
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
_out: {}
}
#line 125 "hb-buffer-deserialize-json.rl"
*end_ptr = p;
return p == pe && *(p-1) != ']';
}
#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */

View file

@ -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 */

View file

@ -0,0 +1,571 @@
#line 1 "hb-buffer-deserialize-text.rl"
/*
* 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"
#line 36 "hb-buffer-deserialize-text.hh"
static const unsigned char _deserialize_text_trans_keys[] = {
0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u,
9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 9u, 124u, 9u, 124u, 0
};
static const char _deserialize_text_key_spans[] = {
0, 114, 13, 10, 13, 10, 10, 13,
10, 1, 13, 10, 14, 116, 116, 0,
114, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116
};
static const short _deserialize_text_index_offsets[] = {
0, 0, 115, 129, 140, 154, 165, 176,
190, 201, 203, 217, 228, 243, 360, 477,
478, 593, 710, 827, 944, 1061, 1178, 1295,
1412, 1529, 1646
};
static const char _deserialize_text_indicies[] = {
0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 1, 1, 1, 1, 1, 1,
1, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 1, 5, 1, 1, 6,
7, 7, 7, 7, 7, 7, 7, 7,
7, 1, 8, 9, 9, 9, 9, 9,
9, 9, 9, 9, 1, 10, 1, 1,
11, 12, 12, 12, 12, 12, 12, 12,
12, 12, 1, 13, 14, 14, 14, 14,
14, 14, 14, 14, 14, 1, 15, 16,
16, 16, 16, 16, 16, 16, 16, 16,
1, 17, 1, 1, 18, 19, 19, 19,
19, 19, 19, 19, 19, 19, 1, 20,
21, 21, 21, 21, 21, 21, 21, 21,
21, 1, 22, 1, 23, 1, 1, 24,
25, 25, 25, 25, 25, 25, 25, 25,
25, 1, 26, 27, 27, 27, 27, 27,
27, 27, 27, 27, 1, 22, 1, 1,
1, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 1, 28, 28, 28, 28,
28, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 28, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 29, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
30, 1, 1, 31, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
32, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 33,
1, 34, 34, 34, 34, 34, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
34, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 35, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 36, 1, 1, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 3,
3, 3, 3, 3, 3, 3, 3, 3,
1, 1, 1, 1, 1, 1, 1, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 1, 1, 1, 1, 1, 1, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 1, 28, 28, 28, 28, 28, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 28, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 29, 1, 1, 1,
1, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 1, 1, 1, 30, 1,
1, 31, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 32, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 33, 1, 38,
38, 38, 38, 38, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 38, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 39, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 40, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 41, 1, 42, 42, 42, 42,
42, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 42, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
43, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 44,
1, 42, 42, 42, 42, 42, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
42, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 43, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 44, 1, 38, 38,
38, 38, 38, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 38, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 39, 1, 1, 1, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 40, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 41, 1, 45, 45, 45, 45, 45,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 45, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 46, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 47, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 48,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 49, 1,
50, 50, 50, 50, 50, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 50,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 51, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 52, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 53, 1, 50, 50, 50,
50, 50, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 50, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 51,
1, 1, 1, 1, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 52, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
53, 1, 45, 45, 45, 45, 45, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 45, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 46, 1, 1, 1,
1, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 1, 1, 1, 1, 1,
1, 47, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 48, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 49, 1, 28,
28, 28, 28, 28, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 28, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 29, 1, 55, 55, 1, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
1, 1, 1, 30, 1, 1, 31, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 1, 1, 32, 1, 55, 1, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 1, 33, 1, 0
};
static const char _deserialize_text_trans_targs[] = {
1, 0, 13, 17, 26, 3, 18, 21,
18, 21, 5, 19, 20, 19, 20, 22,
25, 8, 9, 12, 9, 12, 10, 11,
23, 24, 23, 24, 14, 2, 6, 7,
15, 16, 14, 15, 16, 17, 14, 4,
15, 16, 14, 15, 16, 14, 2, 7,
15, 16, 14, 2, 15, 16, 25, 26
};
static const char _deserialize_text_trans_actions[] = {
0, 0, 1, 1, 1, 2, 2, 2,
0, 0, 2, 2, 2, 0, 0, 2,
2, 2, 2, 2, 0, 0, 3, 2,
2, 2, 0, 0, 4, 5, 5, 5,
4, 4, 0, 0, 0, 0, 6, 7,
6, 6, 8, 8, 8, 9, 10, 10,
9, 9, 11, 12, 11, 11, 0, 0
};
static const char _deserialize_text_eof_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 4, 0, 0,
0, 4, 6, 8, 8, 6, 9, 11,
11, 9, 4
};
static const int deserialize_text_start = 1;
static const int deserialize_text_first_final = 13;
static const int deserialize_text_error = 0;
static const int deserialize_text_en_main = 1;
#line 91 "hb-buffer-deserialize-text.rl"
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};
#line 343 "hb-buffer-deserialize-text.hh"
{
cs = deserialize_text_start;
}
#line 348 "hb-buffer-deserialize-text.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
_keys = _deserialize_text_trans_keys + (cs<<1);
_inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs];
_slen = _deserialize_text_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
(*p) <= _keys[1] ?
(*p) - _keys[0] : _slen ];
cs = _deserialize_text_trans_targs[_trans];
if ( _deserialize_text_trans_actions[_trans] == 0 )
goto _again;
switch ( _deserialize_text_trans_actions[_trans] ) {
case 2:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 5:
#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 10:
#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 3:
#line 63 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
case 12:
#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
case 7:
#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
case 1:
#line 38 "hb-buffer-deserialize-text.rl"
{
memset (&info, 0, sizeof (info));
memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 4:
#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 6:
#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 8:
#line 66 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 480 "hb-buffer-deserialize-text.hh"
}
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
switch ( _deserialize_text_eof_actions[cs] ) {
case 4:
#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 6:
#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 8:
#line 66 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 557 "hb-buffer-deserialize-text.hh"
}
}
_out: {}
}
#line 119 "hb-buffer-deserialize-text.rl"
*end_ptr = p;
return p == pe && *(p-1) != ']';
}
#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */

View file

@ -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 */

View file

@ -0,0 +1,296 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Owen Taylor, Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_PRIVATE_HH
#define HB_BUFFER_PRIVATE_HH
#include "hb-private.hh"
#include "hb-object-private.hh"
#include "hb-unicode-private.hh"
#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
#endif
#ifndef HB_BUFFER_MAX_LEN_MIN
#define HB_BUFFER_MAX_LEN_MIN 8192
#endif
#ifndef HB_BUFFER_MAX_LEN_DEFAULT
#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
#endif
ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
/* Reserved for complex shapers' internal use. */
HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX2 = 0x04000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX3 = 0x08000000u,
};
HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
/*
* 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_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
/* 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 */
bool have_positions; /* Whether we have positions */
unsigned int idx; /* Cursor into ->info and ->pos arrays */
unsigned int len; /* Length of ->info and ->pos arrays */
unsigned int out_len; /* Length of ->out array if have_output */
unsigned int allocated; /* Length of allocated arrays */
hb_glyph_info_t *info;
hb_glyph_info_t *out_info;
hb_glyph_position_t *pos;
inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
inline bool has_separate_output (void) const { return info != out_info; }
unsigned int serial;
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
static const unsigned int CONTEXT_LENGTH = 5;
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
/* Debugging API */
hb_buffer_message_func_t message_func;
void *message_data;
hb_destroy_func_t message_destroy;
/* Internal debugging. */
/* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
#ifndef HB_NDEBUG
uint8_t allocated_var_bits;
#endif
inline void allocate_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (0 == (allocated_var_bits & bits));
allocated_var_bits |= bits;
#endif
}
inline void deallocate_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
allocated_var_bits &= ~bits;
#endif
}
inline void assert_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
#endif
}
inline void deallocate_var_all (void)
{
#ifndef HB_NDEBUG
allocated_var_bits = 0;
#endif
}
/* 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 add (hb_codepoint_t codepoint,
unsigned int cluster);
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
HB_INTERNAL void reverse (void);
HB_INTERNAL void reverse_clusters (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 (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. */
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++; }
inline void reset_masks (hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask = mask;
}
inline void add_masks (hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask |= mask;
}
HB_INTERNAL void set_masks (hb_mask_t value,
hb_mask_t mask,
unsigned int cluster_start,
unsigned int cluster_end);
HB_INTERNAL void merge_clusters (unsigned int start,
unsigned int end)
{
if (end - start < 2)
return;
merge_clusters_impl (start, end);
}
HB_INTERNAL void merge_clusters_impl (unsigned int start,
unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start,
unsigned int end);
/* Merge clusters for deleting current glyph, and skip it. */
HB_INTERNAL void delete_glyph (void);
/* Internal methods */
HB_INTERNAL bool enlarge (unsigned int size);
inline bool ensure (unsigned int 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);
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; }
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
inline bool messaging (void) { return unlikely (message_func); }
inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{
if (!messaging ())
return true;
va_list ap;
va_start (ap, fmt);
bool ret = message_impl (font, fmt, ap);
va_end (ap);
return ret;
}
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
};
#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
sizeof (b->info[0].var))
#define HB_BUFFER_ALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var ())
#define HB_BUFFER_DEALLOCATE_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var ())
#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
#endif /* HB_BUFFER_PRIVATE_HH */

View file

@ -0,0 +1,454 @@
/*
* 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:
*
* Returns a list of supported buffer serialization formats.
*
* Return value: (transfer none):
* A string array of buffer serialization formats. Should not be freed.
*
* Since: 0.9.7
**/
const char **
hb_buffer_serialize_list_formats (void)
{
return serialize_formats;
}
/**
* hb_buffer_serialize_format_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
* @len: length of @str, or -1 if string is %NULL terminated
*
* Parses a string into an #hb_buffer_serialize_format_t. Does not check if
* @str is a valid buffer serialization format, use
* hb_buffer_serialize_list_formats() to get the list of supported formats.
*
* Return value:
* The parsed #hb_buffer_serialize_format_t.
*
* Since: 0.9.7
**/
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: an #hb_buffer_serialize_format_t to convert.
*
* Converts @format to the string corresponding it, or %NULL if it is not a valid
* #hb_buffer_serialize_format_t.
*
* Return value: (transfer none):
* A %NULL terminated string corresponding to @format. Should not be freed.
*
* Since: 0.9.7
**/
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 = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
NULL : 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);
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
{
hb_glyph_extents_t extents;
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
extents.x_bearing, extents.y_bearing));
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
extents.width, extents.height));
}
*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 = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
NULL : 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));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
{
hb_glyph_extents_t extents;
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
}
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;
}
/**
* hb_buffer_serialize_glyphs:
* @buffer: an #hb_buffer_t buffer.
* @start: the first item in @buffer to serialize.
* @end: the last item in @buffer to serialize.
* @buf: (out) (array length=buf_size) (element-type uint8_t): output string to
* write serialized buffer into.
* @buf_size: the size of @buf.
* @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf.
* @font: (allow-none): the #hb_font_t used to shape this buffer, needed to
* read glyph names and extents. If %NULL, and empty font will be used.
* @format: the #hb_buffer_serialize_format_t to use for formatting the output.
* @flags: the #hb_buffer_serialize_flags_t that control what glyph properties
* to serialize.
*
* Serializes @buffer into a textual representation of its glyph content,
* useful for showing the contents of the buffer, for example during debugging.
* There are currently two supported serialization formats:
*
* ## text
* A human-readable, plain text format.
* The serialized glyphs will look something like:
*
* ```
* [uni0651=0@518,0+0|uni0628=0+1897]
* ```
* - The serialized glyphs are delimited with `[` and `]`.
* - Glyphs are separated with `|`
* - Each glyph starts with glyph name, or glyph index if
* #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. Then,
* - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, `=` then #hb_glyph_info_t.cluster.
* - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format:
* - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then,
* - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then,
* - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the
* #hb_glyph_extents_t in the format
* `&lt;x_bearing,y_bearing,width,height&gt;`
*
* ## json
* TODO.
*
* Return value:
* The number of serialized items.
*
* Since: 0.9.7
**/
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,
hb_font_t *font,
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 (!buffer->have_positions)
flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
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: an #hb_buffer_t buffer.
* @buf: (array length=buf_len):
* @buf_len:
* @end_ptr: (out):
* @font:
* @format:
*
*
*
* Return value:
*
* Since: 0.9.7
**/
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;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,472 @@
/*
* Copyright © 1998-2004 David Turner and Werner Lemberg
* Copyright © 2004,2007,2009 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Owen Taylor, Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_BUFFER_H
#define HB_BUFFER_H
#include "hb-common.h"
#include "hb-unicode.h"
#include "hb-font.h"
HB_BEGIN_DECLS
/**
* hb_glyph_info_t:
* @codepoint: either a Unicode code point (before shaping) or a glyph index
* (after shaping).
* @mask:
* @cluster: the index of the character in the original text that corresponds
* to this #hb_glyph_info_t, or whatever the client passes to
* hb_buffer_add(). More than one #hb_glyph_info_t can have the same
* @cluster value, if they resulted from the same character (e.g. one
* to many glyph substitution), and when more than one character gets
* merged in the same glyph (e.g. many to one glyph substitution) the
* #hb_glyph_info_t will have the smallest cluster value of them.
* By default some characters are merged into the same cluster
* (e.g. combining marks have the same cluster as their bases)
* even if they are separate glyphs, hb_buffer_set_cluster_level()
* allow selecting more fine-grained cluster handling.
*
* The #hb_glyph_info_t is the structure that holds information about the
* glyphs and their relation to input text.
*
*/
typedef struct hb_glyph_info_t {
hb_codepoint_t codepoint;
hb_mask_t mask;
uint32_t cluster;
/*< private >*/
hb_var_int_t var1;
hb_var_int_t var2;
} hb_glyph_info_t;
/**
* hb_glyph_position_t:
* @x_advance: how much the line advances after drawing this glyph when setting
* text in horizontal direction.
* @y_advance: how much the line advances after drawing this glyph when setting
* text in vertical direction.
* @x_offset: how much the glyph moves on the X-axis before drawing it, this
* should not affect how much the line advances.
* @y_offset: how much the glyph moves on the Y-axis before drawing it, this
* should not affect how much the line advances.
*
* The #hb_glyph_position_t is the structure that holds the positions of the
* glyph in both horizontal and vertical directions. All positions in
* #hb_glyph_position_t are relative to the current point.
*
*/
typedef struct hb_glyph_position_t {
hb_position_t x_advance;
hb_position_t y_advance;
hb_position_t x_offset;
hb_position_t y_offset;
/*< private >*/
hb_var_int_t var;
} hb_glyph_position_t;
/**
* hb_segment_properties_t:
* @direction: the #hb_direction_t of the buffer, see hb_buffer_set_direction().
* @script: the #hb_script_t of the buffer, see hb_buffer_set_script().
* @language: the #hb_language_t of the buffer, see hb_buffer_set_language().
*
* The structure that holds various text properties of an #hb_buffer_t. Can be
* set and retrieved using hb_buffer_set_segment_properties() and
* hb_buffer_get_segment_properties(), respectively.
*/
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_EXTERN hb_bool_t
hb_segment_properties_equal (const hb_segment_properties_t *a,
const hb_segment_properties_t *b);
HB_EXTERN unsigned int
hb_segment_properties_hash (const hb_segment_properties_t *p);
/**
* hb_buffer_t:
*
* The main structure holding the input text and its properties before shaping,
* and output glyphs and their information after shaping.
*/
typedef struct hb_buffer_t hb_buffer_t;
HB_EXTERN hb_buffer_t *
hb_buffer_create (void);
HB_EXTERN hb_buffer_t *
hb_buffer_get_empty (void);
HB_EXTERN hb_buffer_t *
hb_buffer_reference (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_destroy (hb_buffer_t *buffer);
HB_EXTERN hb_bool_t
hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key);
/**
* hb_buffer_content_type_t:
* @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
* @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping).
* @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping).
*/
typedef enum {
HB_BUFFER_CONTENT_TYPE_INVALID = 0,
HB_BUFFER_CONTENT_TYPE_UNICODE,
HB_BUFFER_CONTENT_TYPE_GLYPHS
} hb_buffer_content_type_t;
HB_EXTERN void
hb_buffer_set_content_type (hb_buffer_t *buffer,
hb_buffer_content_type_t content_type);
HB_EXTERN hb_buffer_content_type_t
hb_buffer_get_content_type (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode_funcs);
HB_EXTERN hb_unicode_funcs_t *
hb_buffer_get_unicode_funcs (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction);
HB_EXTERN hb_direction_t
hb_buffer_get_direction (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_script (hb_buffer_t *buffer,
hb_script_t script);
HB_EXTERN hb_script_t
hb_buffer_get_script (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_language (hb_buffer_t *buffer,
hb_language_t language);
HB_EXTERN hb_language_t
hb_buffer_get_language (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
const hb_segment_properties_t *props);
HB_EXTERN void
hb_buffer_get_segment_properties (hb_buffer_t *buffer,
hb_segment_properties_t *props);
HB_EXTERN void
hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
/**
* hb_buffer_flags_t:
* @HB_BUFFER_FLAG_DEFAULT: the default buffer flag.
* @HB_BUFFER_FLAG_BOT: flag indicating that special handling of the beginning
* of text paragraph can be applied to this buffer. Should usually
* be set, unless you are passing to the buffer only part
* of the text without the full context.
* @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
* paragraph can be applied to this buffer, similar to
* @HB_BUFFER_FLAG_EOT.
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
* flag indication that character with Default_Ignorable
* Unicode property should use the corresponding glyph
* from the font, instead of hiding them (currently done
* by replacing them with the space glyph and zeroing the
* advance width.)
*
* Since: 0.9.20
*/
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;
HB_EXTERN void
hb_buffer_set_flags (hb_buffer_t *buffer,
hb_buffer_flags_t flags);
HB_EXTERN hb_buffer_flags_t
hb_buffer_get_flags (hb_buffer_t *buffer);
/*
* Since: 0.9.42
*/
typedef enum {
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0,
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1,
HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES
} hb_buffer_cluster_level_t;
HB_EXTERN void
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
hb_buffer_cluster_level_t cluster_level);
HB_EXTERN hb_buffer_cluster_level_t
hb_buffer_get_cluster_level (hb_buffer_t *buffer);
/**
* HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT:
*
* The default code point for replacing invalid characters in a given encoding.
* Set to U+FFFD REPLACEMENT CHARACTER.
*
* Since: 0.9.31
*/
#define HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT 0xFFFDu
HB_EXTERN void
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement);
HB_EXTERN hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_clear_contents (hb_buffer_t *buffer);
HB_EXTERN hb_bool_t
hb_buffer_pre_allocate (hb_buffer_t *buffer,
unsigned int size);
HB_EXTERN hb_bool_t
hb_buffer_allocation_successful (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_reverse (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_reverse_range (hb_buffer_t *buffer,
unsigned int start, unsigned int end);
HB_EXTERN void
hb_buffer_reverse_clusters (hb_buffer_t *buffer);
/* Filling the buffer in */
HB_EXTERN void
hb_buffer_add (hb_buffer_t *buffer,
hb_codepoint_t codepoint,
unsigned int cluster);
HB_EXTERN void
hb_buffer_add_utf8 (hb_buffer_t *buffer,
const char *text,
int text_length,
unsigned int item_offset,
int item_length);
HB_EXTERN void
hb_buffer_add_utf16 (hb_buffer_t *buffer,
const uint16_t *text,
int text_length,
unsigned int item_offset,
int item_length);
HB_EXTERN void
hb_buffer_add_utf32 (hb_buffer_t *buffer,
const uint32_t *text,
int text_length,
unsigned int item_offset,
int item_length);
HB_EXTERN void
hb_buffer_add_latin1 (hb_buffer_t *buffer,
const uint8_t *text,
int text_length,
unsigned int item_offset,
int item_length);
HB_EXTERN 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_EXTERN hb_bool_t
hb_buffer_set_length (hb_buffer_t *buffer,
unsigned int length);
HB_EXTERN unsigned int
hb_buffer_get_length (hb_buffer_t *buffer);
/* Getting glyphs out of the buffer */
HB_EXTERN hb_glyph_info_t *
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
unsigned int *length);
HB_EXTERN hb_glyph_position_t *
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
unsigned int *length);
HB_EXTERN void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
/*
* Serialize
*/
/**
* hb_buffer_serialize_flags_t:
* @HB_BUFFER_SERIALIZE_FLAG_DEFAULT: serialize glyph names, clusters and positions.
* @HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS: do not serialize glyph cluster.
* @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
* @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
*
* Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
*
* Since: 0.9.20
*/
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_FLAG_GLYPH_EXTENTS = 0x00000008u
} hb_buffer_serialize_flags_t;
/**
* hb_buffer_serialize_format_t:
* @HB_BUFFER_SERIALIZE_FORMAT_TEXT: a human-readable, plain text format.
* @HB_BUFFER_SERIALIZE_FORMAT_JSON: a machine-readable JSON format.
* @HB_BUFFER_SERIALIZE_FORMAT_INVALID: invalid format.
*
* The buffer serialization and de-serialization format used in
* hb_buffer_serialize_glyphs() and hb_buffer_deserialize_glyphs().
*
* Since: 0.9.2
*/
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;
HB_EXTERN hb_buffer_serialize_format_t
hb_buffer_serialize_format_from_string (const char *str, int len);
HB_EXTERN const char *
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format);
HB_EXTERN const char **
hb_buffer_serialize_list_formats (void);
HB_EXTERN 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,
hb_font_t *font,
hb_buffer_serialize_format_t format,
hb_buffer_serialize_flags_t flags);
HB_EXTERN hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
int buf_len,
const char **end_ptr,
hb_font_t *font,
hb_buffer_serialize_format_t format);
/*
* Debugging.
*/
typedef hb_bool_t (*hb_buffer_message_func_t) (hb_buffer_t *buffer,
hb_font_t *font,
const char *message,
void *user_data);
HB_EXTERN void
hb_buffer_set_message_func (hb_buffer_t *buffer,
hb_buffer_message_func_t func,
void *user_data, hb_destroy_func_t destroy);
HB_END_DECLS
#endif /* HB_BUFFER_H */

View file

@ -0,0 +1,74 @@
/*
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_CACHE_PRIVATE_HH
#define HB_CACHE_PRIVATE_HH
#include "hb-private.hh"
/* Implements a lock-free cache for int->int functions. */
template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
struct hb_cache_t
{
ASSERT_STATIC (key_bits >= cache_bits);
ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int));
inline void clear (void)
{
memset (values, 255, sizeof (values));
}
inline bool get (unsigned int key, unsigned int *value)
{
unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = values[k];
if ((v >> value_bits) != (key >> cache_bits))
return false;
*value = v & ((1u<<value_bits)-1);
return true;
}
inline bool set (unsigned int key, unsigned int value)
{
if (unlikely ((key >> key_bits) || (value >> value_bits)))
return false; /* Overflows */
unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
values[k] = v;
return true;
}
private:
unsigned int values[1u<<cache_bits];
};
typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
#endif /* HB_CACHE_PRIVATE_HH */

View file

@ -0,0 +1,607 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#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: 0.9.2
**/
hb_tag_t
hb_tag_from_string (const char *str, int len)
{
char tag[4];
unsigned int i;
if (!str || !len || !*str)
return HB_TAG_NONE;
if (len < 0 || len > 4)
len = 4;
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: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
*
*
*
* Since: 0.9.5
**/
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 */
const char direction_strings[][4] = {
"ltr",
"rtl",
"ttb",
"btt"
};
/**
* hb_direction_from_string:
* @str: (array length=len) (element-type uint8_t):
* @len:
*
*
*
* Return value:
*
* Since: 0.9.2
**/
hb_direction_t
hb_direction_from_string (const char *str, int len)
{
if (unlikely (!str || !len || !*str))
return HB_DIRECTION_INVALID;
/* Lets match loosely: just match the first letter, such that
* all of "ltr", "left-to-right", etc work!
*/
char c = TOLOWER (str[0]);
for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
if (c == direction_strings[i][0])
return (hb_direction_t) (HB_DIRECTION_LTR + i);
return HB_DIRECTION_INVALID;
}
/**
* hb_direction_to_string:
* @direction:
*
*
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
const char *
hb_direction_to_string (hb_direction_t direction)
{
if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
< ARRAY_LENGTH (direction_strings)))
return direction_strings[direction - HB_DIRECTION_LTR];
return "invalid";
}
/* hb_language_t */
struct hb_language_impl_t {
const char s[1];
};
static const char canon_map[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
'-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
};
static bool
lang_equal (hb_language_t v1,
const void *v2)
{
const unsigned char *p1 = (const unsigned char *) v1;
const unsigned char *p2 = (const unsigned char *) v2;
while (*p1 && *p1 == canon_map[*p2])
p1++, p2++;
return *p1 == canon_map[*p2];
}
#if 0
static unsigned int
lang_hash (const void *key)
{
const unsigned char *p = key;
unsigned int h = 0;
while (canon_map[*p])
{
h = (h << 5) - h + canon_map[*p];
p++;
}
return h;
}
#endif
struct hb_language_item_t {
struct hb_language_item_t *next;
hb_language_t lang;
inline bool operator == (const char *s) const {
return lang_equal (lang, s);
}
inline hb_language_item_t & operator = (const char *s) {
lang = (hb_language_t) strdup (s);
for (unsigned char *p = (unsigned char *) lang; *p; p++)
*p = canon_map[*p];
return *this;
}
void finish (void) { free ((void *) lang); }
};
/* Thread-safe lock-free language list */
static hb_language_item_t *langs;
#ifdef HB_USE_ATEXIT
static
void free_langs (void)
{
while (langs) {
hb_language_item_t *next = langs->next;
langs->finish ();
free (langs);
langs = next;
}
}
#endif
static hb_language_item_t *
lang_find_or_insert (const char *key)
{
retry:
hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
if (*lang == key)
return lang;
/* Not found; allocate one. */
hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
if (unlikely (!lang))
return NULL;
lang->next = first_lang;
*lang = key;
if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
lang->finish ();
free (lang);
goto retry;
}
#ifdef HB_USE_ATEXIT
if (!first_lang)
atexit (free_langs); /* First person registers atexit() callback. */
#endif
return lang;
}
/**
* hb_language_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing
* ISO 639 language code
* @len: length of the @str, or -1 if it is %NULL-terminated.
*
* Converts @str representing an ISO 639 language code to the corresponding
* #hb_language_t.
*
* Return value: (transfer none):
* The #hb_language_t corresponding to the ISO 639 language code.
*
* Since: 0.9.2
**/
hb_language_t
hb_language_from_string (const char *str, int len)
{
if (!str || !len || !*str)
return HB_LANGUAGE_INVALID;
hb_language_item_t *item = NULL;
if (len >= 0)
{
/* NUL-terminate it. */
char strbuf[64];
len = MIN (len, (int) sizeof (strbuf) - 1);
memcpy (strbuf, str, len);
strbuf[len] = '\0';
item = lang_find_or_insert (strbuf);
}
else
item = lang_find_or_insert (str);
return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
}
/**
* hb_language_to_string:
* @language: an #hb_language_t to convert.
*
* See hb_language_from_string().
*
* Return value: (transfer none):
* A %NULL-terminated string representing the @language. Must not be freed by
* the caller.
*
* Since: 0.9.2
**/
const char *
hb_language_to_string (hb_language_t language)
{
/* This is actually NULL-safe! */
return language->s;
}
/**
* hb_language_get_default:
*
*
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
hb_language_t
hb_language_get_default (void)
{
static hb_language_t default_language = HB_LANGUAGE_INVALID;
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;
}
/* hb_script_t */
/**
* hb_script_from_iso15924_tag:
* @tag: an #hb_tag_t representing an ISO 15924 tag.
*
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
*
* Return value:
* An #hb_script_t corresponding to the ISO 15924 tag.
*
* Since: 0.9.2
**/
hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag)
{
if (unlikely (tag == HB_TAG_NONE))
return HB_SCRIPT_INVALID;
/* Be lenient, adjust case (one capital letter followed by three small letters) */
tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
switch (tag) {
/* These graduated from the 'Q' private-area codes, but
* the old code is still aliased by Unicode, and the Qaai
* one in use by ICU. */
case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
/* Script variants from http://unicode.org/iso15924/ */
case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
}
/* If it looks right, just use the tag as a script */
if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
return (hb_script_t) tag;
/* Otherwise, return unknown */
return HB_SCRIPT_UNKNOWN;
}
/**
* hb_script_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing an
* ISO 15924 tag.
* @len: length of the @str, or -1 if it is %NULL-terminated.
*
* Converts a string @str representing an ISO 15924 script tag to a
* corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
* hb_script_from_iso15924_tag().
*
* Return value:
* An #hb_script_t corresponding to the ISO 15924 tag.
*
* Since: 0.9.2
**/
hb_script_t
hb_script_from_string (const char *str, int len)
{
return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
}
/**
* hb_script_to_iso15924_tag:
* @script: an #hb_script_ to convert.
*
* See hb_script_from_iso15924_tag().
*
* Return value:
* An #hb_tag_t representing an ISO 15924 script tag.
*
* Since: 0.9.2
**/
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: 0.9.2
**/
hb_direction_t
hb_script_get_horizontal_direction (hb_script_t script)
{
/* http://goo.gl/x9ilM */
switch ((hb_tag_t) script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_ARABIC:
case HB_SCRIPT_HEBREW:
/* Unicode-3.0 additions */
case HB_SCRIPT_SYRIAC:
case HB_SCRIPT_THAANA:
/* Unicode-4.0 additions */
case HB_SCRIPT_CYPRIOT:
/* Unicode-4.1 additions */
case HB_SCRIPT_KHAROSHTHI:
/* Unicode-5.0 additions */
case HB_SCRIPT_PHOENICIAN:
case HB_SCRIPT_NKO:
/* Unicode-5.1 additions */
case HB_SCRIPT_LYDIAN:
/* Unicode-5.2 additions */
case HB_SCRIPT_AVESTAN:
case HB_SCRIPT_IMPERIAL_ARAMAIC:
case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
case HB_SCRIPT_OLD_SOUTH_ARABIAN:
case HB_SCRIPT_OLD_TURKIC:
case HB_SCRIPT_SAMARITAN:
/* Unicode-6.0 additions */
case HB_SCRIPT_MANDAIC:
/* Unicode-6.1 additions */
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:
/* Unicode-8.0 additions */
case HB_SCRIPT_OLD_HUNGARIAN:
/* Unicode-9.0 additions */
case HB_SCRIPT_ADLAM:
return HB_DIRECTION_RTL;
}
return HB_DIRECTION_LTR;
}
/* hb_user_data_array_t */
bool
hb_user_data_array_t::set (hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
if (!key)
return false;
if (replace) {
if (!data && !destroy) {
items.remove (key, lock);
return true;
}
}
hb_user_data_item_t item = {key, data, destroy};
bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
return ret;
}
void *
hb_user_data_array_t::get (hb_user_data_key_t *key)
{
hb_user_data_item_t item = {NULL, NULL, NULL};
return items.find (key, &item, lock) ? item.data : NULL;
}
/* 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: 0.9.2
**/
void
hb_version (unsigned int *major,
unsigned int *minor,
unsigned int *micro)
{
*major = HB_VERSION_MAJOR;
*minor = HB_VERSION_MINOR;
*micro = HB_VERSION_MICRO;
}
/**
* hb_version_string:
*
* Returns library version as a string with three components.
*
* Return value: library version string.
*
* Since: 0.9.2
**/
const char *
hb_version_string (void)
{
return HB_VERSION_STRING;
}
/**
* hb_version_atleast:
* @major:
* @minor:
* @micro:
*
*
*
* Return value:
*
* Since: 0.9.30
**/
hb_bool_t
hb_version_atleast (unsigned int major,
unsigned int minor,
unsigned int micro)
{
return HB_VERSION_ATLEAST (major, minor, micro);
}

View file

@ -0,0 +1,367 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_H_IN
#error "Include <hb.h> instead."
#endif
#ifndef HB_COMMON_H
#define HB_COMMON_H
#ifndef HB_BEGIN_DECLS
# ifdef __cplusplus
# define HB_BEGIN_DECLS extern "C" {
# define HB_END_DECLS }
# else /* !__cplusplus */
# define HB_BEGIN_DECLS
# define HB_END_DECLS
# endif /* !__cplusplus */
#endif
#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
HB_BEGIN_DECLS
typedef int hb_bool_t;
typedef uint32_t hb_codepoint_t;
typedef int32_t hb_position_t;
typedef uint32_t hb_mask_t;
typedef union _hb_var_int_t {
uint32_t u32;
int32_t i32;
uint16_t u16[2];
int16_t i16[2];
uint8_t u8[4];
int8_t i8[4];
} hb_var_int_t;
/* hb_tag_t */
typedef uint32_t hb_tag_t;
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
#define HB_TAG_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_EXTERN hb_tag_t
hb_tag_from_string (const char *str, int len);
/* buf should have 4 bytes. */
HB_EXTERN void
hb_tag_to_string (hb_tag_t tag, char *buf);
/**
* hb_direction_t:
* @HB_DIRECTION_INVALID: Initial, unset direction.
* @HB_DIRECTION_LTR: Text is set horizontally from left to right.
* @HB_DIRECTION_RTL: Text is set horizontally from right to left.
* @HB_DIRECTION_TTB: Text is set vertically from top to bottom.
* @HB_DIRECTION_BTT: Text is set vertically from bottom to top.
*/
typedef enum {
HB_DIRECTION_INVALID = 0,
HB_DIRECTION_LTR = 4,
HB_DIRECTION_RTL,
HB_DIRECTION_TTB,
HB_DIRECTION_BTT
} hb_direction_t;
/* len=-1 means str is NUL-terminated */
HB_EXTERN hb_direction_t
hb_direction_from_string (const char *str, int len);
HB_EXTERN 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_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
/* hb_language_t */
typedef const struct hb_language_impl_t *hb_language_t;
HB_EXTERN hb_language_t
hb_language_from_string (const char *str, int len);
HB_EXTERN const char *
hb_language_to_string (hb_language_t language);
#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
HB_EXTERN hb_language_t
hb_language_get_default (void);
/* hb_script_t */
/* http://unicode.org/iso15924/ */
/* http://goo.gl/x9ilM */
/* Unicode Character Database property: Script (sc) */
typedef enum
{
/*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'),
/*
* Since: 0.9.30
*/
/*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'),
/*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'),
/*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'),
/*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'),
/*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'),
/*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'),
/*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'),
/*
* Since 1.3.0
*/
/*9.0*/ HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'),
/*9.0*/ HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'),
/*9.0*/ HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'),
/*9.0*/ HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'),
/*9.0*/ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'),
/*9.0*/ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','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;
/* Script functions */
HB_EXTERN hb_script_t
hb_script_from_iso15924_tag (hb_tag_t tag);
HB_EXTERN hb_script_t
hb_script_from_string (const char *str, int len);
HB_EXTERN hb_tag_t
hb_script_to_iso15924_tag (hb_script_t script);
HB_EXTERN hb_direction_t
hb_script_get_horizontal_direction (hb_script_t script);
/* User data */
typedef struct hb_user_data_key_t {
/*< private >*/
char unused;
} hb_user_data_key_t;
typedef void (*hb_destroy_func_t) (void *user_data);
HB_END_DECLS
#endif /* HB_COMMON_H */

File diff suppressed because it is too large Load diff

View file

@ -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_EXTERN hb_face_t *
hb_coretext_face_create (CGFontRef cg_font);
HB_EXTERN CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face);
HB_EXTERN CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font);
HB_END_DECLS
#endif /* HB_CORETEXT_H */

View file

@ -0,0 +1,61 @@
/*
* 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_H_IN
#error "Include <hb.h> instead."
#endif
#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_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS
#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT
#define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_BUFFER_SERIALIZE_FLAG_DEFAULT
typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data);
HB_EXTERN void
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
#endif
HB_END_DECLS
#endif /* HB_DEPRECATED_H */

View file

@ -0,0 +1,934 @@
/*
* Copyright © 2015-2016 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#define HB_SHAPER directwrite
#include "hb-shaper-impl-private.hh"
#include <DWrite_1.h>
#include "hb-directwrite.h"
#ifndef HB_DEBUG_DIRECTWRITE
#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
#endif
HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
/*
* DirectWrite font stream helpers
*/
// This is a font loader which provides only one font (unlike its original design).
// For a better implementation which was also source of this
// and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
class DWriteFontFileLoader : public IDWriteFontFileLoader
{
private:
IDWriteFontFileStream *mFontFileStream;
public:
DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream) {
mFontFileStream = fontFileStream;
}
// IUnknown interface
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD_(ULONG, AddRef)() { return 1; }
IFACEMETHOD_(ULONG, Release)() { return 1; }
// IDWriteFontFileLoader methods
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
UINT32 fontFileReferenceKeySize,
OUT IDWriteFontFileStream** fontFileStream)
{
*fontFileStream = mFontFileStream;
return S_OK;
}
};
class DWriteFontFileStream : public IDWriteFontFileStream
{
private:
uint8_t *mData;
uint32_t mSize;
public:
DWriteFontFileStream(uint8_t *aData, uint32_t aSize)
{
mData = aData;
mSize = aSize;
}
// IUnknown interface
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD_(ULONG, AddRef)() { return 1; }
IFACEMETHOD_(ULONG, Release)() { return 1; }
// IDWriteFontFileStream methods
virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
OUT void** fragmentContext)
{
// We are required to do bounds checking.
if (fileOffset + fragmentSize > mSize) {
return E_FAIL;
}
// truncate the 64 bit fileOffset to size_t sized index into mData
size_t index = static_cast<size_t> (fileOffset);
// We should be alive for the duration of this.
*fragmentStart = &mData[index];
*fragmentContext = nullptr;
return S_OK;
}
virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext) { }
virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize)
{
*fileSize = mSize;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime)
{
return E_NOTIMPL;
}
};
/*
* shaper face data
*/
struct hb_directwrite_shaper_face_data_t {
IDWriteFactory *dwriteFactory;
IDWriteFontFile *fontFile;
IDWriteFontFileStream *fontFileStream;
IDWriteFontFileLoader *fontFileLoader;
IDWriteFontFace *fontFace;
hb_blob_t *faceBlob;
};
hb_directwrite_shaper_face_data_t *
_hb_directwrite_shaper_face_data_create(hb_face_t *face)
{
hb_directwrite_shaper_face_data_t *data =
(hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
if (unlikely (!data))
return NULL;
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
DWriteCreateFactory (
DWRITE_FACTORY_TYPE_SHARED,
__uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory
);
HRESULT hr;
hb_blob_t *blob = hb_face_reference_blob (face);
IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
(uint8_t*) hb_blob_get_data (blob, NULL), hb_blob_get_length (blob));
IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
dwriteFactory->RegisterFontFileLoader (fontFileLoader);
IDWriteFontFile *fontFile;
uint64_t fontFileKey = 0;
hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
fontFileLoader, &fontFile);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
return false; \
} HB_STMT_END;
if (FAILED (hr)) {
FAIL ("Failed to load font file from data!");
return false;
}
BOOL isSupported;
DWRITE_FONT_FILE_TYPE fileType;
DWRITE_FONT_FACE_TYPE faceType;
UINT32 numberOfFaces;
hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
if (FAILED (hr) || !isSupported) {
FAIL ("Font file is not supported.");
return false;
}
#undef FAIL
IDWriteFontFace *fontFace;
dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
data->dwriteFactory = dwriteFactory;
data->fontFile = fontFile;
data->fontFileStream = fontFileStream;
data->fontFileLoader = fontFileLoader;
data->fontFace = fontFace;
data->faceBlob = blob;
return data;
}
void
_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
{
if (data->fontFace)
data->fontFace->Release ();
if (data->fontFile)
data->fontFile->Release ();
if (data->dwriteFactory) {
if (data->fontFileLoader)
data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
data->dwriteFactory->Release ();
}
if (data->fontFileLoader)
delete data->fontFileLoader;
if (data->fontFileStream)
delete data->fontFileStream;
if (data->faceBlob)
hb_blob_destroy (data->faceBlob);
if (data)
free (data);
}
/*
* shaper font data
*/
struct hb_directwrite_shaper_font_data_t {
};
hb_directwrite_shaper_font_data_t *
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
{
if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
hb_directwrite_shaper_font_data_t *data =
(hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
if (unlikely (!data))
return NULL;
return data;
}
void
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
{
free (data);
}
/*
* shaper shape_plan data
*/
struct hb_directwrite_shaper_shape_plan_data_t {};
hb_directwrite_shaper_shape_plan_data_t *
_hb_directwrite_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,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
{
}
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
// but now is relicensed to MIT for HarfBuzz use
class TextAnalysis
: public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
{
public:
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD_(ULONG, AddRef)() { return 1; }
IFACEMETHOD_(ULONG, Release)() { return 1; }
// A single contiguous run of characters containing the same analysis
// results.
struct Run
{
uint32_t mTextStart; // starting text position of this run
uint32_t mTextLength; // number of contiguous code units covered
uint32_t mGlyphStart; // starting glyph in the glyphs array
uint32_t mGlyphCount; // number of glyphs associated with this run of
// text
DWRITE_SCRIPT_ANALYSIS mScript;
uint8_t mBidiLevel;
bool mIsSideways;
inline bool ContainsTextPosition(uint32_t aTextPosition) const
{
return aTextPosition >= mTextStart
&& aTextPosition < mTextStart + mTextLength;
}
Run *nextRun;
};
public:
TextAnalysis(const wchar_t* text,
uint32_t textLength,
const wchar_t* localeName,
DWRITE_READING_DIRECTION readingDirection)
: mText(text)
, mTextLength(textLength)
, mLocaleName(localeName)
, mReadingDirection(readingDirection)
, mCurrentRun(NULL) { };
~TextAnalysis() {
// delete runs, except mRunHead which is part of the TextAnalysis object
for (Run *run = mRunHead.nextRun; run;) {
Run *origRun = run;
run = run->nextRun;
free (origRun);
}
}
STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
Run **runHead) {
// Analyzes the text using the script analyzer and returns
// the result as a series of runs.
HRESULT hr = S_OK;
// Initially start out with one result that covers the entire range.
// This result will be subdivided by the analysis processes.
mRunHead.mTextStart = 0;
mRunHead.mTextLength = mTextLength;
mRunHead.mBidiLevel =
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
mRunHead.nextRun = NULL;
mCurrentRun = &mRunHead;
// Call each of the analyzers in sequence, recording their results.
if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this))) {
*runHead = &mRunHead;
}
return hr;
}
// IDWriteTextAnalysisSource implementation
IFACEMETHODIMP GetTextAtPosition(uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition >= mTextLength) {
// No text at this position, valid query though.
*textString = NULL;
*textLength = 0;
}
else {
*textString = mText + textPosition;
*textLength = mTextLength - textPosition;
}
return S_OK;
}
IFACEMETHODIMP GetTextBeforePosition(uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition == 0 || textPosition > mTextLength) {
// Either there is no text before here (== 0), or this
// is an invalid position. The query is considered valid thouh.
*textString = NULL;
*textLength = 0;
}
else {
*textString = mText;
*textLength = textPosition;
}
return S_OK;
}
IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
GetParagraphReadingDirection() { return mReadingDirection; }
IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
uint32_t* textLength,
wchar_t const** localeName)
{
return S_OK;
}
IFACEMETHODIMP
GetNumberSubstitution(uint32_t textPosition,
OUT uint32_t* textLength,
OUT IDWriteNumberSubstitution** numberSubstitution)
{
// We do not support number substitution.
*numberSubstitution = NULL;
*textLength = mTextLength - textPosition;
return S_OK;
}
// IDWriteTextAnalysisSink implementation
IFACEMETHODIMP
SetScriptAnalysis(uint32_t textPosition,
uint32_t textLength,
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
{
SetCurrentRun(textPosition);
SplitCurrentRun(textPosition);
while (textLength > 0)
{
Run *run = FetchNextRun(&textLength);
run->mScript = *scriptAnalysis;
}
return S_OK;
}
IFACEMETHODIMP
SetLineBreakpoints(uint32_t textPosition,
uint32_t textLength,
const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
IFACEMETHODIMP SetBidiLevel(uint32_t textPosition,
uint32_t textLength,
uint8_t explicitLevel,
uint8_t resolvedLevel) { return S_OK; }
IFACEMETHODIMP
SetNumberSubstitution(uint32_t textPosition,
uint32_t textLength,
IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
protected:
Run *FetchNextRun(IN OUT uint32_t* textLength)
{
// Used by the sink setters, this returns a reference to the next run.
// Position and length are adjusted to now point after the current run
// being returned.
Run *origRun = mCurrentRun;
// Split the tail if needed (the length remaining is less than the
// current run's size).
if (*textLength < mCurrentRun->mTextLength)
{
SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
}
else
{
// Just advance the current run.
mCurrentRun = mCurrentRun->nextRun;
}
*textLength -= origRun->mTextLength;
// Return a reference to the run that was just current.
return origRun;
}
void SetCurrentRun(uint32_t textPosition)
{
// Move the current run to the given position.
// Since the analyzers generally return results in a forward manner,
// this will usually just return early. If not, find the
// corresponding run for the text position.
if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
{
return;
}
for (Run *run = &mRunHead; run; run = run->nextRun) {
if (run->ContainsTextPosition (textPosition))
{
mCurrentRun = run;
return;
}
}
//NS_NOTREACHED("We should always be able to find the text position in one \
// of our runs");
}
void SplitCurrentRun(uint32_t splitPosition)
{
if (!mCurrentRun)
{
//NS_ASSERTION(false, "SplitCurrentRun called without current run.");
// Shouldn't be calling this when no current run is set!
return;
}
// Split the current run.
if (splitPosition <= mCurrentRun->mTextStart)
{
// No need to split, already the start of a run
// or before it. Usually the first.
return;
}
Run *newRun = (Run*) malloc (sizeof (Run));
*newRun = *mCurrentRun;
// Insert the new run in our linked list.
newRun->nextRun = mCurrentRun->nextRun;
mCurrentRun->nextRun = newRun;
// Adjust runs' text positions and lengths.
uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
newRun->mTextStart += splitPoint;
newRun->mTextLength -= splitPoint;
mCurrentRun->mTextLength = splitPoint;
mCurrentRun = newRun;
}
protected:
// Input
// (weak references are fine here, since this class is a transient
// stack-based helper that doesn't need to copy data)
uint32_t mTextLength;
const wchar_t* mText;
const wchar_t* mLocaleName;
DWRITE_READING_DIRECTION mReadingDirection;
// Current processing state.
Run *mCurrentRun;
// Output is a list of runs starting here
Run mRunHead;
};
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); }
/*
* shaper
*/
static hb_bool_t
_hb_directwrite_shape_full(hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float lineWidth)
{
hb_face_t *face = font->face;
hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
IDWriteFontFace *fontFace = face_data->fontFace;
IDWriteTextAnalyzer* analyzer;
dwriteFactory->CreateTextAnalyzer(&analyzer);
unsigned int scratch_size;
hb_buffer_t::scratch_buffer_t *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; \
}
#define utf16_index() var1.u32
ALLOCATE_ARRAY(wchar_t, textString, buffer->len * 2);
unsigned int chars_len = 0;
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 <= 0xFFFFu))
textString[chars_len++] = c;
else if (unlikely(c > 0x10FFFFu))
textString[chars_len++] = 0xFFFDu;
else {
textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
}
}
ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
// 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. */
}
}
// TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ?
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
/*
* There's an internal 16-bit limit on some things inside the analyzer,
* but we never attempt to shape a word longer than 64K characters
* in a single gfxShapedWord, so we cannot exceed that limit.
*/
uint32_t textLength = buffer->len;
TextAnalysis analysis(textString, textLength, NULL, readingDirection);
TextAnalysis::Run *runHead;
HRESULT hr;
hr = analysis.GenerateResults(analyzer, &runHead);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
return false; \
} HB_STMT_END;
if (FAILED (hr))
{
FAIL ("Analyzer failed to generate results.");
return false;
}
uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
uint32_t glyphCount;
bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
const wchar_t localeName[20] = {0};
if (buffer->props.language != NULL)
{
mbstowcs ((wchar_t*) localeName,
hb_language_to_string (buffer->props.language), 20);
}
DWRITE_TYPOGRAPHIC_FEATURES singleFeatures;
singleFeatures.featureCount = num_features;
if (num_features)
{
DWRITE_FONT_FEATURE* dwfeatureArray = (DWRITE_FONT_FEATURE*)
malloc (sizeof (DWRITE_FONT_FEATURE) * num_features);
for (unsigned int i = 0; i < num_features; ++i)
{
dwfeatureArray[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
hb_uint32_swap (features[i].tag);
dwfeatureArray[i].parameter = features[i].value;
}
singleFeatures.features = dwfeatureArray;
}
const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures =
(const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures;
const uint32_t featureRangeLengths[] = { textLength };
uint16_t* clusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
malloc (textLength * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
retry_getglyphs:
uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
hr = analyzer->GetGlyphs (textString, textLength, fontFace, FALSE,
isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
glyphProperties, &glyphCount);
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
{
free (glyphIndices);
free (glyphProperties);
maxGlyphCount *= 2;
goto retry_getglyphs;
}
if (FAILED (hr))
{
FAIL ("Analyzer failed to get glyphs.");
return false;
}
float* glyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
DWRITE_GLYPH_OFFSET* glyphOffsets = (DWRITE_GLYPH_OFFSET*)
malloc(maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
/* 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(DWRITE_SHAPING_GLYPH_PROPERTIES) +
sizeof(int) +
sizeof(DWRITE_GLYPH_OFFSET) +
sizeof(uint32_t));
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
#undef ALLOCATE_ARRAY
int fontEmSize = font->face->get_upem();
if (fontEmSize < 0)
fontEmSize = -fontEmSize;
if (fontEmSize < 0)
fontEmSize = -fontEmSize;
double x_mult = (double) font->x_scale / fontEmSize;
double y_mult = (double) font->y_scale / fontEmSize;
hr = analyzer->GetGlyphPlacements (textString,
clusterMap, textProperties, textLength, glyphIndices,
glyphProperties, glyphCount, fontFace, fontEmSize,
FALSE, isRightToLeft, &runHead->mScript, localeName,
&dwFeatures, featureRangeLengths, 1,
glyphAdvances, glyphOffsets);
if (FAILED (hr))
{
FAIL ("Analyzer failed to get glyph placements.");
return false;
}
IDWriteTextAnalyzer1* analyzer1;
analyzer->QueryInterface (&analyzer1);
if (analyzer1 && lineWidth)
{
DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
(DWRITE_JUSTIFICATION_OPPORTUNITY*)
malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize,
runHead->mScript, textLength, glyphCount, textString, clusterMap,
glyphProperties, justificationOpportunities);
if (FAILED (hr))
{
FAIL ("Analyzer failed to get justification opportunities.");
return false;
}
float* justifiedGlyphAdvances =
(float*) malloc (maxGlyphCount * sizeof (float));
DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
if (FAILED (hr))
{
FAIL("Analyzer failed to get justified glyph advances.");
return false;
}
DWRITE_SCRIPT_PROPERTIES scriptProperties;
hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
if (FAILED (hr))
{
FAIL("Analyzer failed to get script properties.");
return false;
}
uint32_t justificationCharacter = scriptProperties.justificationCharacter;
// if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
if (justificationCharacter != 32)
{
uint16_t* modifiedClusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
retry_getjustifiedglyphs:
uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
uint32_t actualGlyphsCount;
hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
modifiedGlyphAdvances, modifiedGlyphOffsets);
if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
{
maxGlyphCount = actualGlyphsCount;
free (modifiedGlyphIndices);
free (modifiedGlyphAdvances);
free (modifiedGlyphOffsets);
maxGlyphCount = actualGlyphsCount;
goto retry_getjustifiedglyphs;
}
if (FAILED (hr))
{
FAIL ("Analyzer failed to get justified glyphs.");
return false;
}
free (clusterMap);
free (glyphIndices);
free (glyphAdvances);
free (glyphOffsets);
glyphCount = actualGlyphsCount;
clusterMap = modifiedClusterMap;
glyphIndices = modifiedGlyphIndices;
glyphAdvances = modifiedGlyphAdvances;
glyphOffsets = modifiedGlyphOffsets;
free (justifiedGlyphAdvances);
free (justifiedGlyphOffsets);
}
else
{
free (glyphAdvances);
free (glyphOffsets);
glyphAdvances = justifiedGlyphAdvances;
glyphOffsets = justifiedGlyphOffsets;
}
free (justificationOpportunities);
}
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
/* Calculate visual-clusters. That's what we ship. */
for (unsigned int i = 0; i < glyphCount; i++)
vis_clusters[i] = -1;
for (unsigned int i = 0; i < buffer->len; i++)
{
uint32_t *p =
&vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
*p = MIN (*p, buffer->info[i].cluster);
}
for (unsigned int i = 1; i < glyphCount; i++)
if (vis_clusters[i] == -1)
vis_clusters[i] = vis_clusters[i - 1];
#undef utf16_index
if (unlikely (!buffer->ensure (glyphCount)))
FAIL ("Buffer in error");
#undef FAIL
/* Set glyph infos */
buffer->len = 0;
for (unsigned int i = 0; i < glyphCount; i++)
{
hb_glyph_info_t *info = &buffer->info[buffer->len++];
info->codepoint = glyphIndices[i];
info->cluster = vis_clusters[i];
/* The rest is crap. Let's store position info there for now. */
info->mask = glyphAdvances[i];
info->var1.i32 = glyphOffsets[i].advanceOffset;
info->var2.i32 = glyphOffsets[i].ascenderOffset;
}
/* Set glyph positions */
buffer->clear_positions ();
for (unsigned int i = 0; i < glyphCount; i++)
{
hb_glyph_info_t *info = &buffer->info[i];
hb_glyph_position_t *pos = &buffer->pos[i];
/* TODO vertical */
pos->x_advance = x_mult * (int32_t) info->mask;
pos->x_offset =
x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
pos->y_offset = y_mult * info->var2.i32;
}
if (isRightToLeft)
hb_buffer_reverse (buffer);
free (clusterMap);
free (glyphIndices);
free (textProperties);
free (glyphProperties);
free (glyphAdvances);
free (glyphOffsets);
if (num_features)
free (singleFeatures.features);
/* Wow, done! */
return true;
}
hb_bool_t
_hb_directwrite_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_directwrite_shape_full(shape_plan, font, buffer,
features, num_features, 0);
}
/*
* Public [experimental] API
*/
hb_bool_t
hb_shape_dwrite_experimental_width(hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float width)
{
static char *shapers = "directwrite";
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
&buffer->props, features, num_features, &shapers);
hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
features, num_features, width);
if (res)
buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS;
return res;
}

View file

@ -0,0 +1,38 @@
/*
* Copyright © 2015 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_DIRECTWRITE_H
#define HB_DIRECTWRITE_H
#include "hb.h"
HB_BEGIN_DECLS
HB_EXTERN hb_bool_t
hb_shape_dwrite_experimental_width(hb_font_t *font, hb_buffer_t *buffer,
const hb_feature_t *features, unsigned int num_features, float width);
HB_END_DECLS
#endif /* HB_DIRECTWRITE_H */

View file

@ -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 */

479
gfx/harfbuzz/src/hb-face.cc Normal file
View file

@ -0,0 +1,479 @@
/*
* 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 <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: 0.9.2
**/
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 *) calloc (1, 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: 0.9.2
**/
hb_face_t *
hb_face_create (hb_blob_t *blob,
unsigned int index)
{
hb_face_t *face;
if (unlikely (!blob))
blob = hb_blob_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: 0.9.2
**/
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: 0.9.2
**/
hb_face_t *
hb_face_reference (hb_face_t *face)
{
return hb_object_reference (face);
}
/**
* hb_face_destroy: (skip)
* @face: a face.
*
*
*
* Since: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.2
**/
unsigned int
hb_face_get_index (hb_face_t *face)
{
return face->index;
}
/**
* hb_face_set_upem:
* @face: a face.
* @upem:
*
*
*
* Since: 0.9.2
**/
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: 0.9.2
**/
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: 0.9.7
**/
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: 0.9.7
**/
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);
}

117
gfx/harfbuzz/src/hb-face.h Normal file
View file

@ -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_EXTERN 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_EXTERN 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_EXTERN hb_face_t *
hb_face_get_empty (void);
HB_EXTERN hb_face_t *
hb_face_reference (hb_face_t *face);
HB_EXTERN void
hb_face_destroy (hb_face_t *face);
HB_EXTERN 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);
HB_EXTERN void *
hb_face_get_user_data (hb_face_t *face,
hb_user_data_key_t *key);
HB_EXTERN void
hb_face_make_immutable (hb_face_t *face);
HB_EXTERN hb_bool_t
hb_face_is_immutable (hb_face_t *face);
HB_EXTERN hb_blob_t *
hb_face_reference_table (hb_face_t *face,
hb_tag_t tag);
HB_EXTERN hb_blob_t *
hb_face_reference_blob (hb_face_t *face);
HB_EXTERN void
hb_face_set_index (hb_face_t *face,
unsigned int index);
HB_EXTERN unsigned int
hb_face_get_index (hb_face_t *face);
HB_EXTERN void
hb_face_set_upem (hb_face_t *face,
unsigned int upem);
HB_EXTERN unsigned int
hb_face_get_upem (hb_face_t *face);
HB_EXTERN void
hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count);
HB_EXTERN unsigned int
hb_face_get_glyph_count (hb_face_t *face);
HB_END_DECLS
#endif /* HB_FACE_H */

View file

@ -0,0 +1,143 @@
/*
* 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
*/
#define HB_SHAPER fallback
#include "hb-shaper-impl-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,
const int *coords HB_UNUSED,
unsigned int num_coords 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_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)
{
/* TODO
*
* - Apply fallback kern.
* - Handle Variation Selectors?
* - Apply normalization?
*
* This will make the fallback shaper into a dumb "TrueType"
* shaper which many people unfortunately still request.
*/
hb_codepoint_t space;
bool has_space = (bool) font->get_nominal_glyph (' ', &space);
buffer->clear_positions ();
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_nominal_glyph (info[i].codepoint, &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 (direction))
hb_buffer_reverse (buffer);
return true;
}

View file

@ -0,0 +1,553 @@
/*
* 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_FONT_PRIVATE_HH
#define HB_FONT_PRIVATE_HH
#include "hb-private.hh"
#include "hb-object-private.hh"
#include "hb-face-private.hh"
#include "hb-shaper-private.hh"
/*
* hb_font_funcs_t
*/
#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \
HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
/* ^--- Add new callbacks here */
struct hb_font_funcs_t {
hb_object_header_t header;
ASSERT_POD ();
hb_bool_t immutable;
struct {
#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} user_data;
struct {
#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} destroy;
/* Don't access these directly. Call font->get_*() instead. */
union get_t {
struct get_funcs_t {
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name;
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
} f;
void (*array[VAR]) (void);
} get;
};
/*
* hb_font_t
*/
struct hb_font_t {
hb_object_header_t header;
ASSERT_POD ();
hb_bool_t immutable;
hb_font_t *parent;
hb_face_t *face;
int x_scale;
int y_scale;
unsigned int x_ppem;
unsigned int y_ppem;
/* Font variation coordinates. */
unsigned int num_coords;
int *coords;
hb_font_funcs_t *klass;
void *user_data;
hb_destroy_func_t destroy;
struct hb_shaper_data_t shaper_data;
/* Convert from font-space to user-space */
inline int dir_scale (hb_direction_t direction)
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
{ return em_scale (v, dir_scale (direction)); }
/* 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 (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 (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) {
return parent_scale_x_distance (v);
}
inline hb_position_t parent_scale_y_position (hb_position_t v) {
return parent_scale_y_distance (v);
}
inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
*x = parent_scale_x_distance (*x);
*y = parent_scale_y_distance (*y);
}
inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
*x = parent_scale_x_position (*x);
*y = parent_scale_y_position (*y);
}
/* Public getters */
HB_INTERNAL bool has_func (unsigned int i);
/* has_* ... */
#define HB_FONT_FUNC_IMPLEMENT(name) \
bool \
has_##name##_func (void) \
{ \
hb_font_funcs_t *funcs = this->klass; \
unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
return has_func (i); \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_h_extents (this, user_data,
extents,
klass->user_data.font_h_extents);
}
inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_v_extents (this, user_data,
extents,
klass->user_data.font_v_extents);
}
inline bool has_glyph (hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
return get_nominal_glyph (unicode, &glyph);
}
inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
hb_codepoint_t *glyph)
{
*glyph = 0;
return klass->get.f.nominal_glyph (this, user_data,
unicode, glyph,
klass->user_data.nominal_glyph);
}
inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
{
*glyph = 0;
return klass->get.f.variation_glyph (this, user_data,
unicode, variation_selector, glyph,
klass->user_data.variation_glyph);
}
inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
{
return klass->get.f.glyph_h_advance (this, user_data,
glyph,
klass->user_data.glyph_h_advance);
}
inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
{
return klass->get.f.glyph_v_advance (this, user_data,
glyph,
klass->user_data.glyph_v_advance);
}
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.f.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.f.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.f.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.f.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.f.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.f.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.f.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.f.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_h_extents_with_fallback (hb_font_extents_t *extents)
{
if (!get_font_h_extents (extents))
{
extents->ascender = y_scale * .8;
extents->descender = extents->ascender - y_scale;
extents->line_gap = 0;
}
}
inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
{
if (!get_font_v_extents (extents))
{
extents->ascender = x_scale / 2;
extents->descender = extents->ascender - x_scale;
extents->line_gap = 0;
}
}
inline void get_extents_for_direction (hb_direction_t direction,
hb_font_extents_t *extents)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
get_h_extents_with_fallback (extents);
else
get_v_extents_with_fallback (extents);
}
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);
}
}
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 cache this somehow?! */
hb_font_extents_t extents;
get_h_extents_with_fallback (&extents);
*y = extents.ascender;
}
inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
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;
}
}
inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
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 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)))
get_glyph_h_origin_with_fallback (glyph, x, y);
else
get_glyph_v_origin_with_fallback (glyph, x, y);
}
inline void add_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
}
inline void add_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
}
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_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
}
inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin_with_fallback (glyph, &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_nominal_glyph (unichar, glyph))
return true;
}
return false;
}
inline hb_position_t em_scale (int16_t v, int scale)
{
int upem = face->get_upem ();
int64_t scaled = v * (int64_t) scale;
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
return (hb_position_t) (scaled / upem);
}
inline hb_position_t em_scalef (float v, int scale)
{
return (hb_position_t) (v * 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 */

1698
gfx/harfbuzz/src/hb-font.cc Normal file

File diff suppressed because it is too large Load diff

614
gfx/harfbuzz/src/hb-font.h Normal file
View file

@ -0,0 +1,614 @@
/*
* 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_FONT_H
#define HB_FONT_H
#include "hb-common.h"
#include "hb-face.h"
HB_BEGIN_DECLS
typedef struct hb_font_t hb_font_t;
/*
* hb_font_funcs_t
*/
typedef struct hb_font_funcs_t hb_font_funcs_t;
HB_EXTERN hb_font_funcs_t *
hb_font_funcs_create (void);
HB_EXTERN hb_font_funcs_t *
hb_font_funcs_get_empty (void);
HB_EXTERN hb_font_funcs_t *
hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
HB_EXTERN void
hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
HB_EXTERN hb_bool_t
hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
hb_user_data_key_t *key);
HB_EXTERN void
hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
HB_EXTERN hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs);
/* font and glyph extents */
/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */
typedef struct hb_font_extents_t
{
hb_position_t ascender; /* typographic ascender. */
hb_position_t descender; /* typographic descender. */
hb_position_t line_gap; /* suggested line spacing gap. */
/*< private >*/
hb_position_t reserved9;
hb_position_t reserved8;
hb_position_t reserved7;
hb_position_t reserved6;
hb_position_t reserved5;
hb_position_t reserved4;
hb_position_t reserved3;
hb_position_t reserved2;
hb_position_t reserved1;
} hb_font_extents_t;
/* Note that height is negative in coordinate systems that grow up. */
typedef struct hb_glyph_extents_t
{
hb_position_t x_bearing; /* left side of glyph from origin. */
hb_position_t y_bearing; /* top side of glyph from origin. */
hb_position_t width; /* distance from left to right side. */
hb_position_t height; /* distance from top to bottom side. */
} hb_glyph_extents_t;
/* func types */
typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
hb_font_extents_t *metrics,
void *user_data);
typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data);
typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph,
void *user_data);
typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
void *user_data);
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y,
void *user_data);
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data);
typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph, unsigned int point_index,
hb_position_t *x, hb_position_t *y,
void *user_data);
typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data);
typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data,
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data);
/* func setters */
/**
* hb_font_funcs_set_font_h_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.1.2
**/
HB_EXTERN void
hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs,
hb_font_get_font_h_extents_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_font_v_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.1.2
**/
HB_EXTERN void
hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
hb_font_get_font_v_extents_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_nominal_glyph_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.2.3
**/
HB_EXTERN void
hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_nominal_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_variation_glyph_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 1.2.3
**/
HB_EXTERN void
hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_variation_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: 0.9.2
**/
HB_EXTERN 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: 0.9.2
**/
HB_EXTERN 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: 0.9.2
**/
HB_EXTERN 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: 0.9.2
**/
HB_EXTERN 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: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_extents_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN 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: 0.9.2
**/
HB_EXTERN 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: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
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: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_from_name_func_t func,
void *user_data, hb_destroy_func_t destroy);
/* func dispatch */
HB_EXTERN hb_bool_t
hb_font_get_h_extents (hb_font_t *font,
hb_font_extents_t *extents);
HB_EXTERN hb_bool_t
hb_font_get_v_extents (hb_font_t *font,
hb_font_extents_t *extents);
HB_EXTERN hb_bool_t
hb_font_get_nominal_glyph (hb_font_t *font,
hb_codepoint_t unicode,
hb_codepoint_t *glyph);
HB_EXTERN hb_bool_t
hb_font_get_variation_glyph (hb_font_t *font,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_advance (hb_font_t *font,
hb_codepoint_t glyph);
HB_EXTERN hb_position_t
hb_font_get_glyph_v_advance (hb_font_t *font,
hb_codepoint_t glyph);
HB_EXTERN 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);
HB_EXTERN 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);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
HB_EXTERN hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents);
HB_EXTERN 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);
HB_EXTERN hb_bool_t
hb_font_get_glyph_name (hb_font_t *font,
hb_codepoint_t glyph,
char *name, unsigned int size);
HB_EXTERN 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);
/* high-level funcs, with fallback */
/* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
* otherwise callse hb_font_get_variation_glyph(). */
HB_EXTERN hb_bool_t
hb_font_get_glyph (hb_font_t *font,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph);
HB_EXTERN void
hb_font_get_extents_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_font_extents_t *extents);
HB_EXTERN 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);
HB_EXTERN 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);
HB_EXTERN 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_EXTERN 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_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
hb_glyph_extents_t *extents);
HB_EXTERN 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);
/* Generates gidDDD if glyph has no name. */
HB_EXTERN 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_EXTERN 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
*/
/* Fonts are very light-weight objects */
HB_EXTERN hb_font_t *
hb_font_create (hb_face_t *face);
HB_EXTERN hb_font_t *
hb_font_create_sub_font (hb_font_t *parent);
HB_EXTERN hb_font_t *
hb_font_get_empty (void);
HB_EXTERN hb_font_t *
hb_font_reference (hb_font_t *font);
HB_EXTERN void
hb_font_destroy (hb_font_t *font);
HB_EXTERN hb_bool_t
hb_font_set_user_data (hb_font_t *font,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_font_get_user_data (hb_font_t *font,
hb_user_data_key_t *key);
HB_EXTERN void
hb_font_make_immutable (hb_font_t *font);
HB_EXTERN hb_bool_t
hb_font_is_immutable (hb_font_t *font);
HB_EXTERN void
hb_font_set_parent (hb_font_t *font,
hb_font_t *parent);
HB_EXTERN hb_font_t *
hb_font_get_parent (hb_font_t *font);
HB_EXTERN hb_face_t *
hb_font_get_face (hb_font_t *font);
HB_EXTERN void
hb_font_set_funcs (hb_font_t *font,
hb_font_funcs_t *klass,
void *font_data,
hb_destroy_func_t destroy);
/* Be *very* careful with this function! */
HB_EXTERN void
hb_font_set_funcs_data (hb_font_t *font,
void *font_data,
hb_destroy_func_t destroy);
HB_EXTERN void
hb_font_set_scale (hb_font_t *font,
int x_scale,
int y_scale);
HB_EXTERN void
hb_font_get_scale (hb_font_t *font,
int *x_scale,
int *y_scale);
/*
* A zero value means "no hinting in that direction"
*/
HB_EXTERN void
hb_font_set_ppem (hb_font_t *font,
unsigned int x_ppem,
unsigned int y_ppem);
HB_EXTERN void
hb_font_get_ppem (hb_font_t *font,
unsigned int *x_ppem,
unsigned int *y_ppem);
HB_EXTERN void
hb_font_set_var_coords_normalized (hb_font_t *font,
int *coords, /* XXX 2.14 normalized */
unsigned int coords_length);
HB_END_DECLS
#endif /* HB_FONT_H */

744
gfx/harfbuzz/src/hb-ft.cc Normal file
View file

@ -0,0 +1,744 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2009 Keith Stribley
* Copyright © 2015 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb-ft.h"
#include "hb-font-private.hh"
#include "hb-cache-private.hh" // Maybe use in the future?
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_TRUETYPE_TABLES_H
#ifndef HB_DEBUG_FT
#define HB_DEBUG_FT (HB_DEBUG+0)
#endif
/* TODO:
*
* In general, this file does a fine job of what it's supposed to do.
* There are, however, things that need more work:
*
* - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
* Have not investigated.
*
* - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
* would work fine. However, we also abuse this API for performing in font-space,
* but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
* for that, such that no rounding etc happens. As such, we don't set ppem, and
* pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale
* ourselves, like we do in uniscribe, etc.
*
* - We don't handle / allow for emboldening / obliqueing.
*
* - In the future, we should add constructors to create fonts in font space?
*
* - FT_Load_Glyph() is exteremely costly. Do something about it?
*/
struct hb_ft_font_t
{
FT_Face ft_face;
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
};
static hb_ft_font_t *
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
if (unlikely (!ft_font))
return NULL;
ft_font->ft_face = ft_face;
ft_font->symbol = symbol;
ft_font->unref = unref;
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
return ft_font;
}
static void
_hb_ft_face_destroy (FT_Face ft_face)
{
FT_Done_Face (ft_face);
}
static void
_hb_ft_font_destroy (hb_ft_font_t *ft_font)
{
if (ft_font->unref)
_hb_ft_face_destroy (ft_font->ft_face);
free (ft_font);
}
/**
* hb_ft_font_set_load_flags:
* @font:
* @load_flags:
*
*
*
* Since: 1.0.5
**/
void
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
{
if (font->immutable)
return;
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
return;
hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
ft_font->load_flags = load_flags;
}
/**
* hb_ft_font_get_load_flags:
* @font:
*
*
*
* Return value:
* Since: 1.0.5
**/
int
hb_ft_font_get_load_flags (hb_font_t *font)
{
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
return 0;
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
return ft_font->load_flags;
}
FT_Face
hb_ft_font_get_face (hb_font_t *font)
{
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
return NULL;
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
return ft_font->ft_face;
}
static hb_bool_t
hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
if (unlikely (!g))
{
if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
{
/* For symbol-encoded OpenType fonts, we duplicate the
* U+F000..F0FF range at U+0000..U+00FF. That's what
* Windows seems to do, and that's hinted about at:
* http://www.microsoft.com/typography/otspec/recom.htm
* under "Non-Standard (Symbol) Fonts". */
g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
if (!g)
return false;
}
else
return false;
}
*glyph = g;
return true;
}
static hb_bool_t
hb_ft_get_variation_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_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
if (unlikely (!g))
return false;
*glyph = g;
return true;
}
static hb_position_t
hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
return 0;
if (font->x_scale < 0)
v = -v;
return (v + (1<<9)) >> 10;
}
static hb_position_t
hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
return 0;
if (font->y_scale < 0)
v = -v;
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
* have a Y growing upward. Hence the extra negation. */
return (-v + (1<<9)) >> 10;
}
static hb_bool_t
hb_ft_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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
* have a Y growing upward. Hence the extra negation. */
*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,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Vector kerningv;
FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
return 0;
return kerningv.x;
}
static hb_bool_t
hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
extents->width = ft_face->glyph->metrics.width;
extents->height = -ft_face->glyph->metrics.height;
if (font->x_scale < 0)
{
extents->x_bearing = -extents->x_bearing;
extents->width = -extents->width;
}
if (font->y_scale < 0)
{
extents->y_bearing = -extents->y_bearing;
extents->height = -extents->height;
}
return true;
}
static hb_bool_t
hb_ft_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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
return false;
if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
return false;
*x = ft_face->glyph->outline.points[point_index].x;
*y = ft_face->glyph->outline.points[point_index].y;
return true;
}
static hb_bool_t
hb_ft_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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
if (ret && (size && !*name))
ret = false;
return ret;
}
static hb_bool_t
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,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
if (len < 0)
*glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
else {
/* Make a nul-terminated version. */
char buf[128];
len = MIN (len, (int) sizeof (buf) - 1);
strncpy (buf, name, len);
buf[len] = '\0';
*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;
}
static hb_bool_t
hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Face ft_face = ft_font->ft_face;
metrics->ascender = ft_face->size->metrics.ascender;
metrics->descender = ft_face->size->metrics.descender;
metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
if (font->y_scale < 0)
{
metrics->ascender = -metrics->ascender;
metrics->descender = -metrics->descender;
metrics->line_gap = -metrics->line_gap;
}
return true;
}
static hb_font_funcs_t *static_ft_funcs = NULL;
#ifdef HB_USE_ATEXIT
static
void free_static_ft_funcs (void)
{
hb_font_funcs_destroy (static_ft_funcs);
}
#endif
static void
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
{
retry:
hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
if (unlikely (!funcs))
{
funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
hb_font_funcs_make_immutable (funcs);
if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
hb_font_funcs_destroy (funcs);
goto retry;
}
#ifdef HB_USE_ATEXIT
atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
#endif
};
bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
hb_font_set_funcs (font,
funcs,
_hb_ft_font_create (ft_face, symbol, unref),
(hb_destroy_func_t) _hb_ft_font_destroy);
}
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
FT_Face ft_face = (FT_Face) user_data;
FT_Byte *buffer;
FT_ULong length = 0;
FT_Error error;
/* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
if (error)
return NULL;
buffer = (FT_Byte *) malloc (length);
if (buffer == NULL)
return NULL;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
if (error)
return NULL;
return hb_blob_create ((const char *) buffer, length,
HB_MEMORY_MODE_WRITABLE,
buffer, free);
}
/**
* hb_ft_face_create:
* @ft_face: (destroy destroy) (scope notified):
* @destroy:
*
*
*
* Return value: (transfer full):
* Since: 0.9.2
**/
hb_face_t *
hb_ft_face_create (FT_Face ft_face,
hb_destroy_func_t destroy)
{
hb_face_t *face;
if (ft_face->stream->read == NULL) {
hb_blob_t *blob;
blob = hb_blob_create ((const char *) ft_face->stream->base,
(unsigned int) ft_face->stream->size,
HB_MEMORY_MODE_READONLY,
ft_face, destroy);
face = hb_face_create (blob, ft_face->face_index);
hb_blob_destroy (blob);
} else {
face = hb_face_create_for_tables (reference_table, ft_face, destroy);
}
hb_face_set_index (face, ft_face->face_index);
hb_face_set_upem (face, ft_face->units_per_EM);
return face;
}
/**
* hb_ft_face_create_referenced:
* @ft_face:
*
*
*
* Return value: (transfer full):
* Since: 0.9.38
**/
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) _hb_ft_face_destroy);
}
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: 0.9.2
**/
hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face)
{
if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
{
if (ft_face->generic.finalizer)
ft_face->generic.finalizer (ft_face);
ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
}
return hb_face_reference ((hb_face_t *) ft_face->generic.data);
}
/**
* hb_ft_font_create:
* @ft_face: (destroy destroy) (scope notified):
* @destroy:
*
*
*
* Return value: (transfer full):
* Since: 0.9.2
**/
hb_font_t *
hb_ft_font_create (FT_Face ft_face,
hb_destroy_func_t destroy)
{
hb_font_t *font;
hb_face_t *face;
face = hb_ft_face_create (ft_face, destroy);
font = hb_font_create (face);
hb_face_destroy (face);
_hb_ft_font_set_funcs (font, ft_face, false);
hb_font_set_scale (font,
(int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
(int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<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
#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
FT_MM_Var *mm_var = NULL;
if (!FT_Get_MM_Var (ft_face, &mm_var))
{
FT_Fixed coords[mm_var->num_axis];
int hbCoords[mm_var->num_axis];
if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, coords))
{
for (int i = 0; i < mm_var->num_axis; ++i)
hbCoords[i] = coords[i] >> 2;
hb_font_set_var_coords_normalized (font, hbCoords, mm_var->num_axis);
}
}
free (mm_var);
#endif
return font;
}
/**
* hb_ft_font_create_referenced:
* @ft_face:
*
*
*
* Return value: (transfer full):
* Since: 0.9.38
**/
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) _hb_ft_face_destroy);
}
/* 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)
{
retry:
FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
if (unlikely (!library))
{
/* Not found; allocate one. */
if (FT_Init_FreeType (&library))
return NULL;
if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
FT_Done_FreeType (library);
goto retry;
}
#ifdef HB_USE_ATEXIT
atexit (free_ft_library); /* First person registers atexit() callback. */
#endif
}
return library;
}
static void
_release_blob (FT_Face ft_face)
{
hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
}
void
hb_ft_font_set_funcs (hb_font_t *font)
{
hb_blob_t *blob = hb_face_reference_blob (font->face);
unsigned int blob_length;
const char *blob_data = hb_blob_get_data (blob, &blob_length);
if (unlikely (!blob_length))
DEBUG_MSG (FT, font, "Font face has empty blob");
FT_Face ft_face = NULL;
FT_Error err = FT_New_Memory_Face (get_ft_library (),
(const FT_Byte *) blob_data,
blob_length,
hb_face_get_index (font->face),
&ft_face);
if (unlikely (err)) {
hb_blob_destroy (blob);
DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
return;
}
if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
FT_Set_Char_Size (ft_face,
abs (font->x_scale), abs (font->y_scale),
0, 0);
#if 0
font->x_ppem * 72 * 64 / font->x_scale,
font->y_ppem * 72 * 64 / font->y_scale);
#endif
if (font->x_scale < 0 || font->y_scale < 0)
{
FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
0, font->y_scale < 0 ? -1 : +1};
FT_Set_Transform (ft_face, &matrix, NULL);
}
ft_face->generic.data = blob;
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
_hb_ft_font_set_funcs (font, ft_face, true);
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
}

126
gfx/harfbuzz/src/hb-ft.h Normal file
View file

@ -0,0 +1,126 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2015 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_FT_H
#define HB_FT_H
#include "hb.h"
#include <ft2build.h>
#include FT_FREETYPE_H
HB_BEGIN_DECLS
/*
* 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_EXTERN 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_EXTERN 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_EXTERN 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_EXTERN 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_EXTERN hb_font_t *
hb_ft_font_create_referenced (FT_Face ft_face);
HB_EXTERN FT_Face
hb_ft_font_get_face (hb_font_t *font);
HB_EXTERN void
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
HB_EXTERN int
hb_ft_font_get_load_flags (hb_font_t *font);
/* Makes an hb_font_t use FreeType internally to implement font functions. */
HB_EXTERN void
hb_ft_font_set_funcs (hb_font_t *font);
HB_END_DECLS
#endif /* HB_FT_H */

402
gfx/harfbuzz/src/hb-glib.cc Normal file
View file

@ -0,0 +1,402 @@
/*
* 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
*/
#include "hb-private.hh"
#include "hb-glib.h"
#include "hb-unicode-private.hh"
#if !GLIB_CHECK_VERSION(2,29,14)
static const hb_script_t
glib_script_to_script[] =
{
HB_SCRIPT_COMMON,
HB_SCRIPT_INHERITED,
HB_SCRIPT_ARABIC,
HB_SCRIPT_ARMENIAN,
HB_SCRIPT_BENGALI,
HB_SCRIPT_BOPOMOFO,
HB_SCRIPT_CHEROKEE,
HB_SCRIPT_COPTIC,
HB_SCRIPT_CYRILLIC,
HB_SCRIPT_DESERET,
HB_SCRIPT_DEVANAGARI,
HB_SCRIPT_ETHIOPIC,
HB_SCRIPT_GEORGIAN,
HB_SCRIPT_GOTHIC,
HB_SCRIPT_GREEK,
HB_SCRIPT_GUJARATI,
HB_SCRIPT_GURMUKHI,
HB_SCRIPT_HAN,
HB_SCRIPT_HANGUL,
HB_SCRIPT_HEBREW,
HB_SCRIPT_HIRAGANA,
HB_SCRIPT_KANNADA,
HB_SCRIPT_KATAKANA,
HB_SCRIPT_KHMER,
HB_SCRIPT_LAO,
HB_SCRIPT_LATIN,
HB_SCRIPT_MALAYALAM,
HB_SCRIPT_MONGOLIAN,
HB_SCRIPT_MYANMAR,
HB_SCRIPT_OGHAM,
HB_SCRIPT_OLD_ITALIC,
HB_SCRIPT_ORIYA,
HB_SCRIPT_RUNIC,
HB_SCRIPT_SINHALA,
HB_SCRIPT_SYRIAC,
HB_SCRIPT_TAMIL,
HB_SCRIPT_TELUGU,
HB_SCRIPT_THAANA,
HB_SCRIPT_THAI,
HB_SCRIPT_TIBETAN,
HB_SCRIPT_CANADIAN_SYLLABICS,
HB_SCRIPT_YI,
HB_SCRIPT_TAGALOG,
HB_SCRIPT_HANUNOO,
HB_SCRIPT_BUHID,
HB_SCRIPT_TAGBANWA,
/* Unicode-4.0 additions */
HB_SCRIPT_BRAILLE,
HB_SCRIPT_CYPRIOT,
HB_SCRIPT_LIMBU,
HB_SCRIPT_OSMANYA,
HB_SCRIPT_SHAVIAN,
HB_SCRIPT_LINEAR_B,
HB_SCRIPT_TAI_LE,
HB_SCRIPT_UGARITIC,
/* Unicode-4.1 additions */
HB_SCRIPT_NEW_TAI_LUE,
HB_SCRIPT_BUGINESE,
HB_SCRIPT_GLAGOLITIC,
HB_SCRIPT_TIFINAGH,
HB_SCRIPT_SYLOTI_NAGRI,
HB_SCRIPT_OLD_PERSIAN,
HB_SCRIPT_KHAROSHTHI,
/* Unicode-5.0 additions */
HB_SCRIPT_UNKNOWN,
HB_SCRIPT_BALINESE,
HB_SCRIPT_CUNEIFORM,
HB_SCRIPT_PHOENICIAN,
HB_SCRIPT_PHAGS_PA,
HB_SCRIPT_NKO,
/* Unicode-5.1 additions */
HB_SCRIPT_KAYAH_LI,
HB_SCRIPT_LEPCHA,
HB_SCRIPT_REJANG,
HB_SCRIPT_SUNDANESE,
HB_SCRIPT_SAURASHTRA,
HB_SCRIPT_CHAM,
HB_SCRIPT_OL_CHIKI,
HB_SCRIPT_VAI,
HB_SCRIPT_CARIAN,
HB_SCRIPT_LYCIAN,
HB_SCRIPT_LYDIAN,
/* Unicode-5.2 additions */
HB_SCRIPT_AVESTAN,
HB_SCRIPT_BAMUM,
HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
HB_SCRIPT_IMPERIAL_ARAMAIC,
HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
HB_SCRIPT_JAVANESE,
HB_SCRIPT_KAITHI,
HB_SCRIPT_TAI_THAM,
HB_SCRIPT_LISU,
HB_SCRIPT_MEETEI_MAYEK,
HB_SCRIPT_OLD_SOUTH_ARABIAN,
HB_SCRIPT_OLD_TURKIC,
HB_SCRIPT_SAMARITAN,
HB_SCRIPT_TAI_VIET,
/* Unicode-6.0 additions */
HB_SCRIPT_BATAK,
HB_SCRIPT_BRAHMI,
HB_SCRIPT_MANDAIC,
/* Unicode-6.1 additions */
HB_SCRIPT_CHAKMA,
HB_SCRIPT_MEROITIC_CURSIVE,
HB_SCRIPT_MEROITIC_HIEROGLYPHS,
HB_SCRIPT_MIAO,
HB_SCRIPT_SHARADA,
HB_SCRIPT_SORA_SOMPENG,
HB_SCRIPT_TAKRI
};
#endif
hb_script_t
hb_glib_script_to_script (GUnicodeScript script)
{
#if GLIB_CHECK_VERSION(2,29,14)
return (hb_script_t) g_unicode_script_to_iso15924 (script);
#else
if (likely ((unsigned int) script < ARRAY_LENGTH (glib_script_to_script)))
return glib_script_to_script[script];
if (unlikely (script == G_UNICODE_SCRIPT_INVALID_CODE))
return HB_SCRIPT_INVALID;
return HB_SCRIPT_UNKNOWN;
#endif
}
GUnicodeScript
hb_glib_script_from_script (hb_script_t script)
{
#if GLIB_CHECK_VERSION(2,29,14)
return g_unicode_script_from_iso15924 (script);
#else
unsigned int count = ARRAY_LENGTH (glib_script_to_script);
for (unsigned int i = 0; i < count; i++)
if (glib_script_to_script[i] == script)
return (GUnicodeScript) i;
if (unlikely (script == HB_SCRIPT_INVALID))
return G_UNICODE_SCRIPT_INVALID_CODE;
return G_UNICODE_SCRIPT_UNKNOWN;
#endif
}
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 (hb_unicode_combining_class_t) g_unichar_combining_class (unicode);
}
static unsigned int
hb_glib_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
return g_unichar_iswide (unicode) ? 2 : 1;
}
static hb_unicode_general_category_t
hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
/* hb_unicode_general_category_t and GUnicodeType are identical */
return (hb_unicode_general_category_t) g_unichar_type (unicode);
}
static hb_codepoint_t
hb_glib_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
g_unichar_get_mirror_char (unicode, &unicode);
return unicode;
}
static hb_script_t
hb_glib_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
return hb_glib_script_to_script (g_unichar_get_script (unicode));
}
static hb_bool_t
hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab,
void *user_data HB_UNUSED)
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_compose (a, b, ab);
#endif
/* We don't ifdef-out the fallback code such that compiler always
* sees it and makes sure it's compilable. */
gchar utf8[12];
gchar *normalized;
int len;
hb_bool_t ret;
len = g_unichar_to_utf8 (a, utf8);
len += g_unichar_to_utf8 (b, utf8 + len);
normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC);
len = g_utf8_strlen (normalized, -1);
if (unlikely (!len))
return false;
if (len == 1) {
*ab = g_utf8_get_char (normalized);
ret = true;
} else {
ret = false;
}
g_free (normalized);
return ret;
}
static hb_bool_t
hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b,
void *user_data HB_UNUSED)
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_decompose (ab, a, b);
#endif
/* We don't ifdef-out the fallback code such that compiler always
* sees it and makes sure it's compilable. */
gchar utf8[6];
gchar *normalized;
int len;
hb_bool_t ret;
len = g_unichar_to_utf8 (ab, utf8);
normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD);
len = g_utf8_strlen (normalized, -1);
if (unlikely (!len))
return false;
if (len == 1) {
*a = g_utf8_get_char (normalized);
*b = 0;
ret = *a != ab;
} else if (len == 2) {
*a = g_utf8_get_char (normalized);
*b = g_utf8_get_char (g_utf8_next_char (normalized));
/* Here's the ugly part: if ab decomposes to a single character and
* that character decomposes again, we have to detect that and undo
* the second part :-(. */
gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC);
hb_codepoint_t c = g_utf8_get_char (recomposed);
if (c != ab && c != *a) {
*a = c;
*b = 0;
}
g_free (recomposed);
ret = true;
} else {
/* If decomposed to more than two characters, take the last one,
* and recompose the rest to get the first component. */
gchar *end = g_utf8_offset_to_pointer (normalized, len - 1);
gchar *recomposed;
*b = g_utf8_get_char (end);
recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC);
/* We expect that recomposed has exactly one character now. */
*a = g_utf8_get_char (recomposed);
g_free (recomposed);
ret = true;
}
g_free (normalized);
return ret;
}
static unsigned int
hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t u,
hb_codepoint_t *decomposed,
void *user_data HB_UNUSED)
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_fully_decompose (u, true, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN);
#endif
/* If the user doesn't have GLib >= 2.29.12 we have to perform
* a round trip to UTF-8 and the associated memory management dance. */
gchar utf8[6];
gchar *utf8_decomposed, *c;
gsize utf8_len, utf8_decomposed_len, i;
/* Convert @u to UTF-8 and normalise it in NFKD mode. This performs the compatibility decomposition. */
utf8_len = g_unichar_to_utf8 (u, utf8);
utf8_decomposed = g_utf8_normalize (utf8, utf8_len, G_NORMALIZE_NFKD);
utf8_decomposed_len = g_utf8_strlen (utf8_decomposed, -1);
assert (utf8_decomposed_len <= HB_UNICODE_MAX_DECOMPOSITION_LEN);
for (i = 0, c = utf8_decomposed; i < utf8_decomposed_len; i++, c = g_utf8_next_char (c))
*decomposed++ = g_utf8_get_char (c);
g_free (utf8_decomposed);
return utf8_decomposed_len;
}
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);
}
#if GLIB_CHECK_VERSION(2,31,10)
/**
* hb_glib_blob_create:
*
* Since: 0.9.38
**/
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);
}
#endif

View file

@ -0,0 +1,56 @@
/*
* 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_GLIB_H
#define HB_GLIB_H
#include "hb.h"
#include <glib.h>
HB_BEGIN_DECLS
HB_EXTERN hb_script_t
hb_glib_script_to_script (GUnicodeScript script);
HB_EXTERN GUnicodeScript
hb_glib_script_from_script (hb_script_t script);
HB_EXTERN hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void);
#if GLIB_CHECK_VERSION(2,31,10)
HB_EXTERN hb_blob_t *
hb_glib_blob_create (GBytes *gbytes);
#endif
HB_END_DECLS
#endif /* HB_GLIB_H */

View file

@ -0,0 +1,73 @@
/*** BEGIN file-header ***/
/*
* 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-private.hh"
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>
#if !GLIB_CHECK_VERSION(2,29,16)
#undef __GNUC__
#undef __GNUC_MINOR__
#define __GNUC__ 2
#define __GNUC_MINOR__ 6
#endif
#include "hb-gobject.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
{
static gsize type_id = 0;
if (g_once_init_enter (&type_id))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&type_id, id);
}
return type_id;
}
/*** END value-tail ***/

View file

@ -0,0 +1,55 @@
/*** BEGIN file-header ***/
/*
* 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_GOBJECT_H_IN
#error "Include <hb-gobject.h> instead."
#endif
#ifndef HB_GOBJECT_ENUMS_H
#define HB_GOBJECT_ENUMS_H
#include "hb.h"
#include <glib-object.h>
HB_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN value-header ***/
HB_EXTERN 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 ***/

View file

@ -0,0 +1,83 @@
/*
* 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-private.hh"
/* g++ didn't like older gtype.h gcc-only code path. */
#include <glib.h>
#if !GLIB_CHECK_VERSION(2,29,16)
#undef __GNUC__
#undef __GNUC_MINOR__
#define __GNUC__ 2
#define __GNUC_MINOR__ 6
#endif
#include "hb-gobject.h"
#define HB_DEFINE_BOXED_TYPE(name,copy_func,free_func) \
GType \
hb_gobject_##name##_get_type (void) \
{ \
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_id; \
}
#define HB_DEFINE_OBJECT_TYPE(name) \
HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy);
#define HB_DEFINE_VALUE_TYPE(name) \
static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
{ \
hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
if (unlikely (!c)) return NULL; \
*c = *l; \
return c; \
} \
static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy);
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)
HB_DEFINE_VALUE_TYPE (feature)
HB_DEFINE_VALUE_TYPE (glyph_info)
HB_DEFINE_VALUE_TYPE (glyph_position)
HB_DEFINE_VALUE_TYPE (segment_properties)
HB_DEFINE_VALUE_TYPE (user_data_key)
HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)

View file

@ -0,0 +1,117 @@
/*
* 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 */
/**
* hb_gobject_blob_get_type:
*
* Since: 0.9.2
**/
HB_EXTERN GType hb_gobject_blob_get_type (void);
#define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
/**
* hb_gobject_buffer_get_type:
*
* Since: 0.9.2
**/
HB_EXTERN GType hb_gobject_buffer_get_type (void);
#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
/**
* hb_gobject_face_get_type:
*
* Since: 0.9.2
**/
HB_EXTERN GType hb_gobject_face_get_type (void);
#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
/**
* hb_gobject_font_get_type:
*
* Since: 0.9.2
**/
HB_EXTERN GType hb_gobject_font_get_type (void);
#define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
/**
* hb_gobject_font_funcs_get_type:
*
* Since: 0.9.2
**/
HB_EXTERN GType hb_gobject_font_funcs_get_type (void);
#define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
HB_EXTERN GType hb_gobject_set_get_type (void);
#define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
HB_EXTERN GType hb_gobject_shape_plan_get_type (void);
#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
/**
* hb_gobject_unicode_funcs_get_type:
*
* Since: 0.9.2
**/
HB_EXTERN GType hb_gobject_unicode_funcs_get_type (void);
#define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
/* Value types */
HB_EXTERN GType hb_gobject_feature_get_type (void);
#define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ())
HB_EXTERN GType hb_gobject_glyph_info_get_type (void);
#define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ())
HB_EXTERN GType hb_gobject_glyph_position_get_type (void);
#define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ())
HB_EXTERN GType hb_gobject_segment_properties_get_type (void);
#define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
HB_EXTERN GType hb_gobject_user_data_key_get_type (void);
#define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
HB_END_DECLS
#endif /* HB_GOBJECT_H */

View file

@ -0,0 +1,40 @@
/*
* 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
#define HB_GOBJECT_H
#define HB_GOBJECT_H_IN
#include "hb.h"
#include "hb-gobject-enums.h"
#include "hb-gobject-structs.h"
HB_BEGIN_DECLS
HB_END_DECLS
#undef HB_GOBJECT_H_IN
#endif /* HB_GOBJECT_H */

View file

@ -0,0 +1,427 @@
/*
* Copyright © 2011 Martin Hosken
* Copyright © 2011 SIL International
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#define HB_SHAPER graphite2
#define hb_graphite2_shaper_font_data_t gr_font
#include "hb-shaper-impl-private.hh"
#include "hb-graphite2.h"
#include <graphite2/Segment.h>
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
/*
* shaper face data
*/
typedef struct hb_graphite2_tablelist_t {
struct hb_graphite2_tablelist_t *next;
hb_blob_t *blob;
unsigned int tag;
} hb_graphite2_tablelist_t;
struct hb_graphite2_shaper_face_data_t {
hb_face_t *face;
gr_face *grface;
hb_graphite2_tablelist_t *tlist;
};
static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
{
hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
hb_graphite2_tablelist_t *tlist = face_data->tlist;
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))
{
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->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;
}
unsigned int tlen;
const char *d = hb_blob_get_data (blob, &tlen);
*len = tlen;
return d;
}
hb_graphite2_shaper_face_data_t *
_hb_graphite2_shaper_face_data_create (hb_face_t *face)
{
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;
}
void
_hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data)
{
hb_graphite2_tablelist_t *tlist = data->tlist;
while (tlist)
{
hb_graphite2_tablelist_t *old = tlist;
hb_blob_destroy (tlist->blob);
tlist = tlist->next;
free (old);
}
gr_face_destroy (data->grface);
free (data);
}
/*
* Since: 0.9.10
*/
gr_face *
hb_graphite2_face_get_gr_face (hb_face_t *face)
{
if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL;
return HB_SHAPER_DATA_GET (face)->grface;
}
/*
* shaper font data
*/
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;
hb_face_t *face = font->face;
hb_graphite2_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
return gr_make_font_with_advance_fn (font->x_scale, font, &hb_graphite2_get_advance, face_data->grface);
}
void
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data)
{
gr_font_destroy (data);
}
/*
* Since: 0.9.10
*/
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);
}
/*
* shaper shape_plan data
*/
struct hb_graphite2_shaper_shape_plan_data_t {};
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,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shaper_shape_plan_data_t *data HB_UNUSED)
{
}
/*
* shaper
*/
struct hb_graphite2_cluster_t {
unsigned int base_char;
unsigned int num_chars;
unsigned int base_glyph;
unsigned int num_glyphs;
unsigned int cluster;
float advance;
};
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 = lang ? strchr (lang, '-') : NULL;
int lang_len = lang_end ? lang_end - lang : -1;
gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
for (unsigned int i = 0; i < num_features; i++)
{
const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
if (fref)
gr_fref_set_feature_value (fref, features[i].value, feats);
}
gr_segment *seg = NULL;
const gr_slot *is;
unsigned int ci = 0, ic = 0;
float curradvx = 0., curradvy = 0.;
unsigned int scratch_size;
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
uint32_t *chars = (uint32_t *) scratch;
for (unsigned int i = 0; i < buffer->len; ++i)
chars[i] = buffer->info[i].codepoint;
/* TODO ensure_native_direction. */
hb_tag_t script_tag[2];
hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]);
seg = gr_make_seg (grfont, grface,
script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1],
feats,
gr_utf32, chars, buffer->len,
2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
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);
buffer->len = 0;
return true;
}
buffer->ensure (glyph_count);
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);
#undef ALLOCATE_ARRAY
memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
hb_codepoint_t *pg = gids;
clusters[0].cluster = buffer->info[0].cluster;
float curradv = HB_DIRECTION_IS_BACKWARD(buffer->props.direction) ? gr_slot_origin_X(gr_seg_first_slot(seg)) : 0.;
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
{
curradv = gr_slot_origin_X(gr_seg_first_slot(seg));
clusters[0].advance = gr_seg_advance_X(seg) - curradv;
}
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);
unsigned int after = gr_slot_after (is);
*pg = gr_slot_gid (is);
pg++;
while (clusters[ci].base_char > before && ci)
{
clusters[ci-1].num_chars += clusters[ci].num_chars;
clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
clusters[ci-1].advance += clusters[ci].advance;
ci--;
}
if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
{
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;
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
{
ci++;
clusters[ci].advance = curradv - gr_slot_origin_X(is);
} else {
clusters[ci].advance = gr_slot_origin_X(is) - curradv;
ci++;
}
curradv = gr_slot_origin_X(is);
}
clusters[ci].num_glyphs++;
if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
}
if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
clusters[ci].advance = gr_seg_advance_X(seg) - curradv;
ci++;
for (unsigned int i = 0; i < ci; ++i)
{
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;
info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance
}
}
buffer->len = glyph_count;
float yscale = font->y_scale / font->x_scale;
/* Positioning. */
if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
{
int currclus = -1;
const hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
curradvx = 0;
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
{
pPos->x_offset = gr_slot_origin_X (is) - curradvx;
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
if (info->cluster != currclus) {
pPos->x_advance = info->var1.i32;
curradvx += pPos->x_advance;
currclus = info->cluster;
} else
pPos->x_advance = 0.;
pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
curradvy += pPos->y_advance;
}
}
else
{
int currclus = -1;
const hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
curradvx = gr_seg_advance_X(seg);
for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
{
if (info->cluster != currclus)
{
pPos->x_advance = info->var1.i32;
if (currclus != -1) curradvx -= info[-1].var1.i32;
currclus = info->cluster;
} else
pPos->x_advance = 0.;
pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
curradvy -= pPos->y_advance;
pPos->x_offset = gr_slot_origin_X (is) - curradvx + pPos->x_advance;
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
}
hb_buffer_reverse_clusters (buffer);
}
if (feats) gr_featureval_destroy (feats);
gr_seg_destroy (seg);
return true;
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (C) 2011 Martin Hosken
* Copyright (C) 2011 SIL International
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_GRAPHITE2_H
#define HB_GRAPHITE2_H
#include "hb.h"
#include <graphite2/Font.h>
HB_BEGIN_DECLS
#define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
HB_EXTERN gr_face *
hb_graphite2_face_get_gr_face (hb_face_t *face);
HB_EXTERN gr_font *
hb_graphite2_font_get_gr_font (hb_font_t *font);
HB_END_DECLS
#endif /* HB_GRAPHITE2_H */

371
gfx/harfbuzz/src/hb-icu.cc Normal file
View file

@ -0,0 +1,371 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2009 Keith Stribley
* Copyright © 2011 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb-private.hh"
#include "hb-icu.h"
#include "hb-unicode-private.hh"
#include <unicode/uchar.h>
#include <unicode/unorm.h>
#include <unicode/ustring.h>
#include <unicode/utf16.h>
#include <unicode/uversion.h>
hb_script_t
hb_icu_script_to_script (UScriptCode script)
{
if (unlikely (script == USCRIPT_INVALID_CODE))
return HB_SCRIPT_INVALID;
return hb_script_from_string (uscript_getShortName (script), -1);
}
UScriptCode
hb_icu_script_from_script (hb_script_t script)
{
if (unlikely (script == HB_SCRIPT_INVALID))
return USCRIPT_INVALID_CODE;
for (unsigned int i = 0; i < USCRIPT_CODE_LIMIT; i++)
if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script))
return (UScriptCode) i;
return USCRIPT_UNKNOWN;
}
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 (hb_unicode_combining_class_t) u_getCombiningClass (unicode);
}
static unsigned int
hb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH))
{
case U_EA_WIDE:
case U_EA_FULLWIDTH:
return 2;
case U_EA_NEUTRAL:
case U_EA_AMBIGUOUS:
case U_EA_HALFWIDTH:
case U_EA_NARROW:
return 1;
}
return 1;
}
static hb_unicode_general_category_t
hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
{
case U_UNASSIGNED: return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
case U_UPPERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
case U_LOWERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
case U_TITLECASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
case U_MODIFIER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
case U_OTHER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
case U_NON_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
case U_ENCLOSING_MARK: return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
case U_COMBINING_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK;
case U_DECIMAL_DIGIT_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
case U_LETTER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
case U_OTHER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
case U_SPACE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
case U_LINE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
case U_PARAGRAPH_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
case U_CONTROL_CHAR: return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
case U_FORMAT_CHAR: return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
case U_PRIVATE_USE_CHAR: return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
case U_SURROGATE: return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
case U_DASH_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
case U_START_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
case U_END_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
case U_CONNECTOR_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
case U_OTHER_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
case U_MATH_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
case U_CURRENCY_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
case U_MODIFIER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
case U_OTHER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
case U_INITIAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
case U_FINAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
}
return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
}
static hb_codepoint_t
hb_icu_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
return u_charMirror(unicode);
}
static hb_script_t
hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
UErrorCode status = U_ZERO_ERROR;
UScriptCode scriptCode = uscript_getScript(unicode, &status);
if (unlikely (U_FAILURE (status)))
return HB_SCRIPT_UNKNOWN;
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,
hb_codepoint_t b,
hb_codepoint_t *ab,
void *user_data HB_UNUSED)
{
#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];
unsigned int len;
hb_bool_t ret, err;
UErrorCode icu_err;
len = 0;
err = false;
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err);
if (err) return false;
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err);
if (err) return false;
icu_err = U_ZERO_ERROR;
len = unorm_normalize (utf16, len, UNORM_NFC, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
if (U_FAILURE (icu_err))
return false;
if (u_countChar32 (normalized, len) == 1) {
U16_GET_UNSAFE (normalized, 0, *ab);
ret = true;
} else {
ret = false;
}
return ret;
}
static hb_bool_t
hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b,
void *user_data HB_UNUSED)
{
#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;
/* This function is a monster! Maybe it wasn't a good idea adding a
* pairwise decompose API... */
/* Watchout for the dragons. Err, watchout for macros changing len. */
len = 0;
err = false;
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err);
if (err) return false;
icu_err = U_ZERO_ERROR;
len = unorm_normalize (utf16, len, UNORM_NFD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err);
if (U_FAILURE (icu_err))
return false;
len = u_countChar32 (normalized, len);
if (len == 1) {
U16_GET_UNSAFE (normalized, 0, *a);
*b = 0;
ret = *a != ab;
} else if (len == 2) {
len =0;
U16_NEXT_UNSAFE (normalized, len, *a);
U16_NEXT_UNSAFE (normalized, len, *b);
/* Here's the ugly part: if ab decomposes to a single character and
* that character decomposes again, we have to detect that and undo
* the second part :-(. */
UChar recomposed[20];
icu_err = U_ZERO_ERROR;
unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
if (U_FAILURE (icu_err))
return false;
hb_codepoint_t c;
U16_GET_UNSAFE (recomposed, 0, c);
if (c != *a && c != ab) {
*a = c;
*b = 0;
}
ret = true;
} 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); /* 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;
}
return ret;
}
static unsigned int
hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t u,
hb_codepoint_t *decomposed,
void *user_data HB_UNUSED)
{
UChar utf16[2], normalized[2 * HB_UNICODE_MAX_DECOMPOSITION_LEN + 1];
unsigned int len;
int32_t utf32_len;
hb_bool_t err;
UErrorCode icu_err;
/* Copy @u into a UTF-16 array to be passed to ICU. */
len = 0;
err = false;
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), u, err);
if (err)
return 0;
/* Normalise the codepoint using NFKD mode. */
icu_err = U_ZERO_ERROR;
len = 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;
}
hb_unicode_funcs_t *
hb_icu_get_unicode_funcs (void)
{
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);
}

52
gfx/harfbuzz/src/hb-icu.h Normal file
View file

@ -0,0 +1,52 @@
/*
* 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_ICU_H
#define HB_ICU_H
#include "hb.h"
#include <unicode/uscript.h>
HB_BEGIN_DECLS
HB_EXTERN hb_script_t
hb_icu_script_to_script (UScriptCode script);
HB_EXTERN UScriptCode
hb_icu_script_from_script (hb_script_t script);
HB_EXTERN hb_unicode_funcs_t *
hb_icu_get_unicode_funcs (void);
HB_END_DECLS
#endif /* HB_ICU_H */

View file

@ -0,0 +1,141 @@
/*
* Copyright © 2007 Chris Wilson
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MUTEX_PRIVATE_HH
#define HB_MUTEX_PRIVATE_HH
#include "hb-private.hh"
/* mutex */
/* We need external help for these */
#if defined(HB_MUTEX_IMPL_INIT) \
&& defined(hb_mutex_impl_init) \
&& defined(hb_mutex_impl_lock) \
&& defined(hb_mutex_impl_unlock) \
&& defined(hb_mutex_impl_finish)
/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#include <windows.h>
typedef CRITICAL_SECTION hb_mutex_impl_t;
#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)
#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
#include <pthread.h>
typedef pthread_mutex_t hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER
#define hb_mutex_impl_init(M) pthread_mutex_init (M, NULL)
#define hb_mutex_impl_lock(M) pthread_mutex_lock (M)
#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M)
#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
# include <sched.h>
# define HB_SCHED_YIELD() sched_yield ()
#else
# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
#endif
/* This actually is not a totally awful implementation. */
typedef volatile int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) *(M) = 0
#define hb_mutex_impl_lock(M) HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END
#define hb_mutex_impl_unlock(M) __sync_lock_release (M)
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
#elif !defined(HB_NO_MT)
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
# include <sched.h>
# define HB_SCHED_YIELD() sched_yield ()
#else
# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
#endif
#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
typedef volatile int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) *(M) = 0
#define hb_mutex_impl_lock(M) HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END
#define hb_mutex_impl_unlock(M) (*(M))--;
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
#else /* HB_NO_MT */
typedef int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) HB_STMT_START {} HB_STMT_END
#define hb_mutex_impl_lock(M) HB_STMT_START {} HB_STMT_END
#define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
#endif
#define HB_MUTEX_INIT {HB_MUTEX_IMPL_INIT}
struct hb_mutex_t
{
/* TODO Add tracing. */
hb_mutex_impl_t m;
inline void init (void) { hb_mutex_impl_init (&m); }
inline void lock (void) { hb_mutex_impl_lock (&m); }
inline void unlock (void) { hb_mutex_impl_unlock (&m); }
inline void finish (void) { hb_mutex_impl_finish (&m); }
};
#endif /* HB_MUTEX_PRIVATE_HH */

View file

@ -0,0 +1,202 @@
/*
* Copyright © 2007 Chris Wilson
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OBJECT_PRIVATE_HH
#define HB_OBJECT_PRIVATE_HH
#include "hb-private.hh"
#include "hb-atomic-private.hh"
#include "hb-mutex-private.hh"
/* Debug */
#ifndef HB_DEBUG_OBJECT
#define HB_DEBUG_OBJECT (HB_DEBUG+0)
#endif
/* reference_count */
#define HB_REFERENCE_COUNT_INERT_VALUE -1
#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT(HB_REFERENCE_COUNT_INERT_VALUE)}
struct hb_reference_count_t
{
hb_atomic_int_t ref_count;
inline void init (int v) { ref_count.set_unsafe (v); }
inline int get_unsafe (void) const { return ref_count.get_unsafe (); }
inline int inc (void) { return ref_count.inc (); }
inline int dec (void) { return ref_count.dec (); }
inline void finish (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); }
inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; }
inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; }
};
/* user_data */
#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT}
struct hb_user_data_array_t
{
struct hb_user_data_item_t {
hb_user_data_key_t *key;
void *data;
hb_destroy_func_t destroy;
inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; }
inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; }
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) { 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_INTERNAL void *get (hb_user_data_key_t *key);
inline void finish (void) { items.finish (lock); lock.finish (); }
};
/* object_header */
struct hb_object_header_t
{
hb_reference_count_t ref_count;
hb_user_data_array_t user_data;
#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_USER_DATA_ARRAY_INIT}
private:
ASSERT_POD ();
};
/* object */
template <typename Type>
static inline void hb_object_trace (const Type *obj, const char *function)
{
DEBUG_MSG (OBJECT, (void *) obj,
"%s refcount=%d",
function,
obj ? obj->header.ref_count.get_unsafe () : 0);
}
template <typename Type>
static inline Type *hb_object_create (void)
{
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.ref_count.is_inert ());
}
template <typename Type>
static inline bool hb_object_is_valid (const Type *obj)
{
return likely (obj->header.ref_count.is_valid ());
}
template <typename Type>
static inline Type *hb_object_reference (Type *obj)
{
hb_object_trace (obj, HB_FUNC);
if (unlikely (!obj || hb_object_is_inert (obj)))
return obj;
assert (hb_object_is_valid (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);
if (unlikely (!obj || hb_object_is_inert (obj)))
return false;
assert (hb_object_is_valid (obj));
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,
hb_user_data_key_t *key,
void * data,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
if (unlikely (!obj || hb_object_is_inert (obj)))
return false;
assert (hb_object_is_valid (obj));
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)
{
if (unlikely (!obj || hb_object_is_inert (obj)))
return NULL;
assert (hb_object_is_valid (obj));
return obj->header.user_data.get (key);
}
#endif /* HB_OBJECT_PRIVATE_HH */

View file

@ -0,0 +1,268 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OPEN_FILE_PRIVATE_HH
#define HB_OPEN_FILE_PRIVATE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
*
* The OpenType Font File
*
*/
/*
* Organization of an OpenType Font
*/
struct OpenTypeFontFile;
struct OffsetTable;
struct TTCHeader;
typedef struct TableRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
Tag tag; /* 4-byte identifier. */
CheckSum checkSum; /* CheckSum for this table. */
ULONG offset; /* Offset from beginning of TrueType font
* file. */
ULONG length; /* Length of this table. */
public:
DEFINE_SIZE_STATIC (16);
} OpenTypeTable;
typedef struct OffsetTable
{
friend struct OpenTypeFontFile;
inline unsigned int get_table_count (void) const
{ return numTables; }
inline const TableRecord& get_table (unsigned int i) const
{
if (unlikely (i >= numTables)) return Null(TableRecord);
return tables[i];
}
inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
{
Tag t;
t.set (tag);
unsigned int count = numTables;
for (unsigned int i = 0; i < count; i++)
{
if (t == tables[i].tag)
{
if (table_index) *table_index = i;
return true;
}
}
if (table_index) *table_index = Index::NOT_FOUND_INDEX;
return false;
}
inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
{
unsigned int table_index;
find_table_index (tag, &table_index);
return get_table (table_index);
}
public:
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
}
protected:
Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
USHORT numTables; /* Number of tables. */
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);
} OpenTypeFontFace;
/*
* TrueType Collections
*/
struct TTCHeaderVersion1
{
friend struct TTCHeader;
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) const
{
TRACE_SANITIZE (this);
return_trace (table.sanitize (c, this));
}
protected:
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
DEFINE_SIZE_ARRAY (12, table);
};
struct TTCHeader
{
friend struct OpenTypeFontFile;
private:
inline unsigned int get_face_count (void) const
{
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
case 1: return u.version1.get_face_count ();
default:return 0;
}
}
inline const OpenTypeFontFace& get_face (unsigned int i) const
{
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
case 1: return u.version1.get_face (i);
default:return Null(OpenTypeFontFace);
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
case 1: return_trace (u.version1.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
struct {
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<>version; /* Version of the TTC Header (1.0 or 2.0),
* 0x00010000u or 0x00020000u */
} header;
TTCHeaderVersion1 version1;
} u;
};
/*
* OpenType Font File
*/
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 */
static const hb_tag_t TrueTag = HB_TAG ('t','r','u','e'); /* Obsolete Apple TrueType */
static const hb_tag_t Typ1Tag = HB_TAG ('t','y','p','1'); /* Obsolete Apple Type1 font in SFNT container */
inline hb_tag_t get_tag (void) const { return u.tag; }
inline unsigned int get_face_count (void) const
{
switch (u.tag) {
case CFFTag: /* All the non-collection tags */
case TrueTag:
case Typ1Tag:
case TrueTypeTag: return 1;
case TTCTag: return u.ttcHeader.get_face_count ();
default: return 0;
}
}
inline const OpenTypeFontFace& get_face (unsigned int i) const
{
switch (u.tag) {
/* Note: for non-collection SFNT data we ignore index. This is because
* Apple dfont container is a container of SFNT's. So each SFNT is a
* non-TTC, but the index is more than zero. */
case CFFTag: /* All the non-collection tags */
case TrueTag:
case Typ1Tag:
case TrueTypeTag: return u.fontFace;
case TTCTag: return u.ttcHeader.get_face (i);
default: return Null(OpenTypeFontFace);
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!u.tag.sanitize (c))) return_trace (false);
switch (u.tag) {
case CFFTag: /* All the non-collection tags */
case TrueTag:
case Typ1Tag:
case TrueTypeTag: return_trace (u.fontFace.sanitize (c));
case TTCTag: return_trace (u.ttcHeader.sanitize (c));
default: return_trace (true);
}
}
protected:
union {
Tag tag; /* 4-byte identifier. */
OpenTypeFontFace fontFace;
TTCHeader ttcHeader;
} u;
public:
DEFINE_SIZE_UNION (4, tag);
};
} /* namespace OT */
#endif /* HB_OPEN_FILE_PRIVATE_HH */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,384 @@
/*
* Copyright © 2016 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Seigo Nonaka
*/
#ifndef HB_OT_CBDT_TABLE_HH
#define HB_OT_CBDT_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
struct SmallGlyphMetrics
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
inline void get_extents (hb_glyph_extents_t *extents) const
{
extents->x_bearing = bearingX;
extents->y_bearing = bearingY;
extents->width = width;
extents->height = -height;
}
BYTE height;
BYTE width;
CHAR bearingX;
CHAR bearingY;
BYTE advance;
DEFINE_SIZE_STATIC(5);
};
struct BigGlyphMetrics : SmallGlyphMetrics
{
CHAR vertBearingX;
CHAR vertBearingY;
BYTE vertAdvance;
DEFINE_SIZE_STATIC(8);
};
struct SBitLineMetrics
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
CHAR ascender;
CHAR decender;
BYTE widthMax;
CHAR caretSlopeNumerator;
CHAR caretSlopeDenominator;
CHAR caretOffset;
CHAR minOriginSB;
CHAR minAdvanceSB;
CHAR maxBeforeBL;
CHAR minAfterBL;
CHAR padding1;
CHAR padding2;
DEFINE_SIZE_STATIC(12);
};
/*
* Index Subtables.
*/
struct IndexSubtableHeader
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
USHORT indexFormat;
USHORT imageFormat;
ULONG imageDataOffset;
DEFINE_SIZE_STATIC(8);
};
template <typename OffsetType>
struct IndexSubtableFormat1Or3
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
c->check_array (offsetArrayZ, offsetArrayZ[0].static_size, glyph_count + 1));
}
bool get_image_data (unsigned int idx,
unsigned int *offset,
unsigned int *length) const
{
if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
return false;
*offset = header.imageDataOffset + offsetArrayZ[idx];
*length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
return true;
}
IndexSubtableHeader header;
Offset<OffsetType> offsetArrayZ[VAR];
DEFINE_SIZE_ARRAY(8, offsetArrayZ);
};
struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<ULONG> {};
struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<USHORT> {};
struct IndexSubtable
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
{
TRACE_SANITIZE (this);
if (!u.header.sanitize (c)) return_trace (false);
switch (u.header.indexFormat) {
case 1: return_trace (u.format1.sanitize (c, glyph_count));
case 3: return_trace (u.format3.sanitize (c, glyph_count));
default:return_trace (true);
}
}
inline bool get_extents (hb_glyph_extents_t *extents) const
{
switch (u.header.indexFormat) {
case 2: case 5: /* TODO */
case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
default:return (false);
}
}
bool get_image_data (unsigned int idx,
unsigned int *offset,
unsigned int *length,
unsigned int *format) const
{
*format = u.header.imageFormat;
switch (u.header.indexFormat) {
case 1: return u.format1.get_image_data (idx, offset, length);
case 3: return u.format3.get_image_data (idx, offset, length);
default: return false;
}
}
protected:
union {
IndexSubtableHeader header;
IndexSubtableFormat1 format1;
IndexSubtableFormat3 format3;
/* TODO: Format 2, 4, 5. */
} u;
public:
DEFINE_SIZE_UNION (8, header);
};
struct IndexSubtableRecord
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
firstGlyphIndex <= lastGlyphIndex &&
offsetToSubtable.sanitize (c, this, lastGlyphIndex - firstGlyphIndex + 1));
}
inline bool get_extents (hb_glyph_extents_t *extents) const
{
return (this+offsetToSubtable).get_extents (extents);
}
bool get_image_data (unsigned int gid,
unsigned int *offset,
unsigned int *length,
unsigned int *format) const
{
if (gid < firstGlyphIndex || gid > lastGlyphIndex)
{
return false;
}
return (this+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
offset, length, format);
}
USHORT firstGlyphIndex;
USHORT lastGlyphIndex;
OffsetTo<IndexSubtable, ULONG> offsetToSubtable;
DEFINE_SIZE_STATIC(8);
};
struct IndexSubtableArray
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_array (&indexSubtablesZ, indexSubtablesZ[0].static_size, count)))
return_trace (false);
for (unsigned int i = 0; i < count; i++)
if (unlikely (!indexSubtablesZ[i].sanitize (c, this)))
return_trace (false);
return_trace (true);
}
public:
const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
{
for (unsigned int i = 0; i < numTables; ++i)
{
unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) {
return &indexSubtablesZ[i];
}
}
return NULL;
}
protected:
IndexSubtableRecord indexSubtablesZ[VAR];
public:
DEFINE_SIZE_ARRAY(0, indexSubtablesZ);
};
struct BitmapSizeTable
{
friend struct CBLC;
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
c->check_range (&(base+indexSubtableArrayOffset), indexTablesSize) &&
horizontal.sanitize (c) &&
vertical.sanitize (c));
}
const IndexSubtableRecord *find_table (hb_codepoint_t glyph, const void *base) const
{
return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
}
protected:
OffsetTo<IndexSubtableArray, ULONG> indexSubtableArrayOffset;
ULONG indexTablesSize;
ULONG numberOfIndexSubtables;
ULONG colorRef;
SBitLineMetrics horizontal;
SBitLineMetrics vertical;
USHORT startGlyphIndex;
USHORT endGlyphIndex;
BYTE ppemX;
BYTE ppemY;
BYTE bitDepth;
CHAR flags;
public:
DEFINE_SIZE_STATIC(48);
};
/*
* Glyph Bitmap Data Formats.
*/
struct GlyphBitmapDataFormat17
{
SmallGlyphMetrics glyphMetrics;
ULONG dataLen;
BYTE dataZ[VAR];
DEFINE_SIZE_ARRAY(9, dataZ);
};
/*
* CBLC -- Color Bitmap Location Table
*/
#define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
struct CBLC
{
static const hb_tag_t tableTag = HB_OT_TAG_CBLC;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
likely (version.major == 2 || version.major == 3) &&
sizeTables.sanitize (c, this));
}
public:
const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
unsigned int *x_ppem, unsigned int *y_ppem) const
{
/* TODO: Make it possible to select strike. */
unsigned int count = sizeTables.len;
for (uint32_t i = 0; i < count; ++i)
{
unsigned int startGlyphIndex = sizeTables.array[i].startGlyphIndex;
unsigned int endGlyphIndex = sizeTables.array[i].endGlyphIndex;
if (startGlyphIndex <= glyph && glyph <= endGlyphIndex)
{
*x_ppem = sizeTables[i].ppemX;
*y_ppem = sizeTables[i].ppemY;
return sizeTables[i].find_table (glyph, this);
}
}
return NULL;
}
protected:
FixedVersion<>version;
ArrayOf<BitmapSizeTable, ULONG> sizeTables;
public:
DEFINE_SIZE_ARRAY(8, sizeTables);
};
/*
* CBDT -- Color Bitmap Data Table
*/
#define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')
struct CBDT
{
static const hb_tag_t tableTag = HB_OT_TAG_CBDT;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
likely (version.major == 2 || version.major == 3));
}
protected:
FixedVersion<>version;
BYTE dataZ[VAR];
public:
DEFINE_SIZE_ARRAY(4, dataZ);
};
} /* namespace OT */
#endif /* HB_OT_CBDT_TABLE_HH */

View file

@ -0,0 +1,535 @@
/*
* 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 (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
{
struct accelerator_t
{
inline void init (const CmapSubtableFormat4 *subtable)
{
segCount = subtable->segCountX2 / 2;
endCount = subtable->values;
startCount = endCount + segCount + 1;
idDelta = startCount + segCount;
idRangeOffset = idDelta + segCount;
glyphIdArray = idRangeOffset + segCount;
glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2;
}
static inline bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph)
{
const accelerator_t *thiz = (const accelerator_t *) obj;
/* Custom two-array bsearch. */
int min = 0, max = (int) thiz->segCount - 1;
const USHORT *startCount = thiz->startCount;
const USHORT *endCount = thiz->endCount;
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 = thiz->idRangeOffset[i];
if (rangeOffset == 0)
gid = codepoint + thiz->idDelta[i];
else
{
/* Somebody has been smoking... */
unsigned int index = rangeOffset / 2 + (codepoint - thiz->startCount[i]) + i - thiz->segCount;
if (unlikely (index >= thiz->glyphIdArrayLength))
return false;
gid = thiz->glyphIdArray[index];
if (unlikely (!gid))
return false;
gid += thiz->idDelta[i];
}
*glyph = gid & 0xFFFFu;
return true;
}
const USHORT *endCount;
const USHORT *startCount;
const USHORT *idDelta;
const USHORT *idRangeOffset;
const USHORT *glyphIdArray;
unsigned int segCount;
unsigned int glyphIdArrayLength;
};
inline bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const
{
accelerator_t accel;
accel.init (this);
return accel.get_glyph_func (&accel, codepoint, glyph);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (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 (false);
}
return_trace (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 (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 (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 (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 (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 (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 (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 (c->check_struct (this) &&
record.sanitize (c, this));
}
protected:
USHORT format; /* Format number is set to 14. */
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 bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 0: return_trace (u.format0 .sanitize (c));
case 4: return_trace (u.format4 .sanitize (c));
case 6: return_trace (u.format6 .sanitize (c));
case 10: return_trace (u.format10.sanitize (c));
case 12: return_trace (u.format12.sanitize (c));
case 13: return_trace (u.format13.sanitize (c));
case 14: return_trace (u.format14.sanitize (c));
default:return_trace (true);
}
}
public:
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 (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 (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 */

View file

@ -0,0 +1,662 @@
/*
* 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-cbdt-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-os2-table.hh"
//#include "hb-ot-post-table.hh"
struct hb_ot_face_metrics_accelerator_t
{
unsigned int num_metrics;
unsigned int num_advances;
unsigned int default_advance;
unsigned short ascender;
unsigned short descender;
unsigned short line_gap;
bool has_font_extents;
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,
hb_tag_t os2_tag,
unsigned int default_advance = 0)
{
this->default_advance = default_advance ? default_advance : face->get_upem ();
bool got_font_extents = false;
if (os2_tag)
{
hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
#define USE_TYPO_METRICS (1u<<7)
if (0 != (os2->fsSelection & USE_TYPO_METRICS))
{
this->ascender = os2->sTypoAscender;
this->descender = os2->sTypoDescender;
this->line_gap = os2->sTypoLineGap;
got_font_extents = (this->ascender | this->descender) != 0;
}
hb_blob_destroy (os2_blob);
}
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;
if (!got_font_extents)
{
this->ascender = _hea->ascender;
this->descender = _hea->descender;
this->line_gap = _hea->lineGap;
got_font_extents = (this->ascender | this->descender) != 0;
}
hb_blob_destroy (_hea_blob);
this->has_font_extents = got_font_extents;
this->blob = OT::Sanitizer<OT::_mtx>::sanitize (face->reference_table (_mtx_tag));
/* Cap num_metrics() and num_advances() based on table length. */
unsigned int len = hb_blob_get_length (this->blob);
if (unlikely (this->num_advances * 4 > len))
this->num_advances = len / 4;
this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;
/* We MUST set num_metrics to zero if num_advances is zero.
* Our get_advance() depends on that. */
if (unlikely (!this->num_advances))
{
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 default advance. 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_glyf_accelerator_t
{
bool short_offset;
unsigned int num_glyphs;
const OT::loca *loca;
const OT::glyf *glyf;
hb_blob_t *loca_blob;
hb_blob_t *glyf_blob;
unsigned int glyf_len;
inline void init (hb_face_t *face)
{
hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
{
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
hb_blob_destroy (head_blob);
return;
}
this->short_offset = 0 == head->indexToLocFormat;
hb_blob_destroy (head_blob);
this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);
this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
this->glyf_len = hb_blob_get_length (this->glyf_blob);
}
inline void fini (void)
{
hb_blob_destroy (this->loca_blob);
hb_blob_destroy (this->glyf_blob);
}
inline bool get_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const
{
if (unlikely (glyph >= this->num_glyphs))
return false;
unsigned int start_offset, end_offset;
if (this->short_offset)
{
start_offset = 2 * this->loca->u.shortsZ[glyph];
end_offset = 2 * this->loca->u.shortsZ[glyph + 1];
}
else
{
start_offset = this->loca->u.longsZ[glyph];
end_offset = this->loca->u.longsZ[glyph + 1];
}
if (start_offset > end_offset || end_offset > this->glyf_len)
return false;
if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
return true; /* Empty glyph; zero extents. */
const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);
extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;
return true;
}
};
struct hb_ot_face_cbdt_accelerator_t
{
hb_blob_t *cblc_blob;
hb_blob_t *cbdt_blob;
const OT::CBLC *cblc;
const OT::CBDT *cbdt;
unsigned int cbdt_len;
float upem;
inline void init (hb_face_t *face)
{
upem = face->get_upem();
cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
cbdt_len = hb_blob_get_length (cbdt_blob);
if (hb_blob_get_length (cblc_blob) == 0) {
cblc = NULL;
cbdt = NULL;
return; /* Not a bitmap font. */
}
cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
}
inline void fini (void)
{
hb_blob_destroy (this->cblc_blob);
hb_blob_destroy (this->cbdt_blob);
}
inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */
if (cblc == NULL)
return false; // Not a color bitmap font.
const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
if (subtable_record == NULL)
return false;
if (subtable_record->get_extents (extents))
return true;
unsigned int image_offset = 0, image_length = 0, image_format = 0;
if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
return false;
{
/* TODO Move the following into CBDT struct when adding more formats. */
if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
return false;
switch (image_format)
{
case 17: {
if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
return false;
const OT::GlyphBitmapDataFormat17& glyphFormat17 =
OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
glyphFormat17.glyphMetrics.get_extents (extents);
}
break;
default:
// TODO: Support other image formats.
return false;
}
}
/* Convert to the font units. */
extents->x_bearing *= upem / (float) x_ppem;
extents->y_bearing *= upem / (float) y_ppem;
extents->width *= upem / (float) x_ppem;
extents->height *= upem / (float) y_ppem;
return true;
}
};
typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph);
template <typename Type>
static inline bool get_glyph_from (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph)
{
const Type *typed_obj = (const Type *) obj;
return typed_obj->get_glyph (codepoint, glyph);
}
template <typename Type>
static inline bool get_glyph_from_symbol (const void *obj,
hb_codepoint_t codepoint,
hb_codepoint_t *glyph)
{
const Type *typed_obj = (const Type *) obj;
if (likely (typed_obj->get_glyph (codepoint, glyph)))
return true;
if (codepoint <= 0x00FFu)
{
/* For symbol-encoded OpenType fonts, we duplicate the
* U+F000..F0FF range at U+0000..U+00FF. That's what
* Windows seems to do, and that's hinted about at:
* http://www.microsoft.com/typography/otspec/recom.htm
* under "Non-Standard (Symbol) Fonts". */
return typed_obj->get_glyph (0xF000u + codepoint, glyph);
}
return false;
}
struct hb_ot_face_cmap_accelerator_t
{
hb_cmap_get_glyph_func_t get_glyph_func;
const void *get_glyph_data;
OT::CmapSubtableFormat4::accelerator_t format4_accel;
const OT::CmapSubtableFormat14 *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::CmapSubtableFormat14 *subtable_uvs = NULL;
bool symbol = false;
/* 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);
if (!subtable)
{
subtable = cmap->find_subtable (3, 0);
if (subtable) symbol = true;
}
/* Meh. */
if (!subtable) subtable = &OT::Null(OT::CmapSubtable);
/* UVS subtable. */
if (!subtable_uvs)
{
const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
if (st && st->u.format == 14)
subtable_uvs = &st->u.format14;
}
/* Meh. */
if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
this->uvs_table = subtable_uvs;
this->get_glyph_data = subtable;
if (unlikely (symbol))
this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
else
switch (subtable->u.format) {
/* Accelerate format 4 and format 12. */
default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>; break;
case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>; break;
case 4:
{
this->format4_accel.init (&subtable->u.format4);
this->get_glyph_data = &this->format4_accel;
this->get_glyph_func = this->format4_accel.get_glyph_func;
}
break;
}
}
inline void fini (void)
{
hb_blob_destroy (this->blob);
}
inline bool get_nominal_glyph (hb_codepoint_t unicode,
hb_codepoint_t *glyph) const
{
return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
}
inline bool get_variation_glyph (hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t *glyph) const
{
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 get_nominal_glyph (unicode, glyph);
}
};
template <typename T>
struct hb_lazy_loader_t
{
inline void init (hb_face_t *face_)
{
face = face_;
instance = NULL;
}
inline void fini (void)
{
if (instance && instance != &OT::Null(T))
{
instance->fini();
free (instance);
}
}
inline const T* operator-> (void) const
{
retry:
T *p = (T *) hb_atomic_ptr_get (&instance);
if (unlikely (!p))
{
p = (T *) calloc (1, sizeof (T));
if (unlikely (!p))
return &OT::Null(T);
p->init (face);
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), NULL, p)))
{
p->fini ();
goto retry;
}
}
return p;
}
private:
hb_face_t *face;
T *instance;
};
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;
hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
};
static hb_ot_font_t *
_hb_ot_font_create (hb_face_t *face)
{
hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));
if (unlikely (!ot_font))
return NULL;
ot_font->cmap.init (face);
ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_os2);
ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_TAG_NONE,
ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
ot_font->glyf.init (face);
ot_font->cbdt.init (face);
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 ();
ot_font->glyf.fini ();
ot_font->cbdt.fini ();
free (ot_font);
}
static hb_bool_t
hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
return ot_font->cmap.get_nominal_glyph (unicode, glyph);
}
static hb_bool_t
hb_ot_get_variation_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_variation_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 (-(int) ot_font->v_metrics.get_advance (glyph));
}
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)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
bool ret = ot_font->glyf->get_extents (glyph, extents);
if (!ret)
ret = ot_font->cbdt->get_extents (glyph, extents);
extents->x_bearing = font->em_scale_x (extents->x_bearing);
extents->y_bearing = font->em_scale_y (extents->y_bearing);
extents->width = font->em_scale_x (extents->width);
extents->height = font->em_scale_y (extents->height);
return ret;
}
static hb_bool_t
hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
return ot_font->h_metrics.has_font_extents;
}
static hb_bool_t
hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
return ot_font->v_metrics.has_font_extents;
}
static hb_font_funcs_t *static_ot_funcs = NULL;
#ifdef HB_USE_ATEXIT
static
void free_static_ot_funcs (void)
{
hb_font_funcs_destroy (static_ot_funcs);
}
#endif
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
retry:
hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
if (unlikely (!funcs))
{
funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
//hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
//hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
//hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
//hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
//hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
hb_font_funcs_make_immutable (funcs);
if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
hb_font_funcs_destroy (funcs);
goto retry;
}
#ifdef HB_USE_ATEXIT
atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
#endif
};
return funcs;
}
/**
* hb_ot_font_set_funcs:
*
* Since: 0.9.28
**/
void
hb_ot_font_set_funcs (hb_font_t *font)
{
hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
if (unlikely (!ot_font))
return;
hb_font_set_funcs (font,
_hb_ot_get_font_funcs (),
ot_font,
(hb_destroy_func_t) _hb_ot_font_destroy);
}

View file

@ -0,0 +1,45 @@
/*
* Copyright © 2014 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod, Roozbeh Pournader
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_FONT_H
#define HB_OT_FONT_H
#include "hb.h"
HB_BEGIN_DECLS
HB_EXTERN void
hb_ot_font_set_funcs (hb_font_t *font);
HB_END_DECLS
#endif /* HB_OT_FONT_H */

View file

@ -0,0 +1,104 @@
/*
* Copyright © 2015 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_GLYF_TABLE_HH
#define HB_OT_GLYF_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* loca -- Index to Location
*/
#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
struct loca
{
static const hb_tag_t tableTag = HB_OT_TAG_loca;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (true);
}
public:
union {
USHORT shortsZ[VAR]; /* Location offset divided by 2. */
ULONG longsZ[VAR]; /* Location offset. */
} u;
DEFINE_SIZE_ARRAY (0, u.longsZ);
};
/*
* glyf -- TrueType Glyph Data
*/
#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
struct glyf
{
static const hb_tag_t tableTag = HB_OT_TAG_glyf;
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 (true);
}
public:
BYTE dataX[VAR]; /* Glyphs data. */
DEFINE_SIZE_ARRAY (0, dataX);
};
struct glyfGlyphHeader
{
SHORT numberOfContours; /* If the number of contours is
* greater than or equal to zero,
* this is a simple glyph; if negative,
* this is a composite glyph. */
FWORD xMin; /* Minimum x for coordinate data. */
FWORD yMin; /* Minimum y for coordinate data. */
FWORD xMax; /* Maximum x for coordinate data. */
FWORD yMax; /* Maximum y for coordinate data. */
DEFINE_SIZE_STATIC (10);
};
} /* namespace OT */
#endif /* HB_OT_GLYF_TABLE_HH */

View file

@ -0,0 +1,154 @@
/*
* Copyright © 2010 Red Hat, Inc.
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_HEAD_TABLE_HH
#define HB_OT_HEAD_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* head -- Font Header
*/
#define HB_OT_TAG_head HB_TAG('h','e','a','d')
struct head
{
static const hb_tag_t tableTag = HB_OT_TAG_head;
inline unsigned int get_upem (void) const
{
unsigned int upem = unitsPerEm;
/* 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) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
version.major == 1 &&
magicNumber == 0x5F0F3CF5u);
}
protected:
FixedVersion<>version; /* Version of the head table--currently
* 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
* 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;
* Bit 3: Force ppem to integer values for all
* internal scaler math; may use fractional
* ppem sizes if this bit is clear;
* Bit 4: Instructions may alter advance width
* (the advance widths might not scale linearly);
* Bits 5-10: These should be set according to
* Apple's specification. However, they are not
* implemented in OpenType.
* Bit 5: This bit should be set in fonts that are
* intended to e laid out vertically, and in
* which the glyphs have been drawn such that an
* x-coordinate of 0 corresponds to the desired
* vertical baseline.
* Bit 6: This bit must be set to zero.
* Bit 7: This bit should be set if the font
* requires layout for correct linguistic
* rendering (e.g. Arabic fonts).
* Bit 8: This bit should be set for a GX font
* which has one or more metamorphosis effects
* designated as happening by default.
* Bit 9: This bit should be set if the font
* contains any strong right-to-left glyphs.
* Bit 10: This bit should be set if the font
* contains Indic-style rearrangement effects.
* Bit 11: Font data is 'lossless,' as a result
* of having been compressed and decompressed
* with the Agfa MicroType Express engine.
* Bit 12: Font converted (produce compatible metrics)
* Bit 13: Font optimized for ClearType™.
* Note, fonts that rely on embedded bitmaps (EBDT)
* for rendering should not be considered optimized
* for ClearType, and therefore should keep this bit
* cleared.
* Bit 14: Last Resort font. If set, indicates that
* the glyphs encoded in the cmap subtables are simply
* generic symbolic representations of code point
* ranges and don’t truly represent support for those
* code points. If unset, indicates that the glyphs
* encoded in the cmap subtables represent proper
* support for those code points.
* Bit 15: Reserved, set to 0. */
USHORT unitsPerEm; /* Valid range is from 16 to 16384. This value
* should be a power of 2 for fonts that have
* TrueType outlines. */
LONGDATETIME created; /* Number of seconds since 12:00 midnight,
January 1, 1904. 64-bit integer */
LONGDATETIME modified; /* Number of seconds since 12:00 midnight,
January 1, 1904. 64-bit integer */
SHORT xMin; /* For all glyph bounding boxes. */
SHORT yMin; /* For all glyph bounding boxes. */
SHORT xMax; /* For all glyph bounding boxes. */
SHORT yMax; /* For all glyph bounding boxes. */
USHORT macStyle; /* Bit 0: Bold (if set to 1);
* Bit 1: Italic (if set to 1)
* Bit 2: Underline (if set to 1)
* Bit 3: Outline (if set to 1)
* Bit 4: Shadow (if set to 1)
* Bit 5: Condensed (if set to 1)
* Bit 6: Extended (if set to 1)
* Bits 7-15: Reserved (set to 0). */
USHORT lowestRecPPEM; /* Smallest readable size in pixels. */
SHORT fontDirectionHint; /* Deprecated (Set to 2).
* 0: Fully mixed directional glyphs;
* 1: Only strongly left to right;
* 2: Like 1 but also contains neutrals;
* -1: Only strongly right to left;
* -2: Like -1 but also contains neutrals. */
public:
SHORT indexToLocFormat; /* 0 for short offsets, 1 for long. */
SHORT glyphDataFormat; /* 0 for current format. */
DEFINE_SIZE_STATIC (54);
};
} /* namespace OT */
#endif /* HB_OT_HEAD_TABLE_HH */

View file

@ -0,0 +1,103 @@
/*
* 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_HHEA_TABLE_HH
#define HB_OT_HHEA_TABLE_HH
#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 _hea
{
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) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && likely (version.major == 1));
}
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)) 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 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. */
SHORT metricDataFormat; /* 0 for current format. */
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 */

View file

@ -0,0 +1,104 @@
/*
* 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_HMTX_TABLE_HH
#define HB_OT_HMTX_TABLE_HH
#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 LongMetric
{
UFWORD advance; /* Advance width/height. */
FWORD lsb; /* Leading (left/top) side bearing. */
public:
DEFINE_SIZE_STATIC (4);
};
struct _mtx
{
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) const
{
TRACE_SANITIZE (this);
/* We don't check for anything specific here. The users of the
* struct do all the hard work... */
return_trace (true);
}
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
* monospaced, only one entry need
* be in the array, but that entry is
* required. The last entry applies to
* all subsequent glyphs. */
FWORD leadingBearingX[VAR]; /* Here the advance is assumed
* 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 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 side bearing
* values for each glyph. */
public:
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 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,459 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_LAYOUT_GDEF_TABLE_HH
#define HB_OT_LAYOUT_GDEF_TABLE_HH
#include "hb-ot-layout-common-private.hh"
#include "hb-font-private.hh"
namespace OT {
/*
* Attachment List Table
*/
typedef ArrayOf<USHORT> AttachPoint; /* Array of contour point indices--in
* increasing numerical order */
struct AttachList
{
inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (point_count)
*point_count = 0;
return 0;
}
const AttachPoint &points = this+attachPoint[index];
if (point_count) {
const USHORT *array = points.sub_array (start_offset, point_count);
unsigned int count = *point_count;
for (unsigned int i = 0; i < count; i++)
point_array[i] = array[i];
}
return points.len;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
}
protected:
OffsetTo<Coverage>
coverage; /* Offset to Coverage table -- from
* beginning of AttachList table */
OffsetArrayOf<AttachPoint>
attachPoint; /* Array of AttachPoint tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, attachPoint);
};
/*
* Ligature Caret Table
*/
struct CaretValueFormat1
{
friend struct CaretValue;
private:
inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
USHORT caretValueFormat; /* Format identifier--format = 1 */
SHORT coordinate; /* X or Y value, in design units */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat2
{
friend struct CaretValue;
private:
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 (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) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
USHORT caretValueFormat; /* Format identifier--format = 2 */
USHORT caretValuePoint; /* Contour point index on glyph */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat3
{
friend struct CaretValue;
inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, const VariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
}
protected:
USHORT caretValueFormat; /* Format identifier--format = 3 */
SHORT coordinate; /* X or Y value, in design units */
OffsetTo<Device>
deviceTable; /* Offset to Device table for X or Y
* value--from beginning of CaretValue
* table */
public:
DEFINE_SIZE_STATIC (6);
};
struct CaretValue
{
inline hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
case 2: return u.format2.get_caret_value (font, direction, glyph_id);
case 3: return u.format3.get_caret_value (font, direction, var_store);
default:return 0;
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (u.format3.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
USHORT format; /* Format identifier */
CaretValueFormat1 format1;
CaretValueFormat2 format2;
CaretValueFormat3 format3;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct LigGlyph
{
inline unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
if (caret_count) {
const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count);
unsigned int count = *caret_count;
for (unsigned int i = 0; i < count; i++)
caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
}
return carets.len;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (carets.sanitize (c, this));
}
protected:
OffsetArrayOf<CaretValue>
carets; /* Offset array of CaretValue tables
* --from beginning of LigGlyph table
* --in increasing coordinate order */
public:
DEFINE_SIZE_ARRAY (2, carets);
};
struct LigCaretList
{
inline unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (caret_count)
*caret_count = 0;
return 0;
}
const LigGlyph &lig_glyph = this+ligGlyph[index];
return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
}
protected:
OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of LigCaretList table */
OffsetArrayOf<LigGlyph>
ligGlyph; /* Array of LigGlyph tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, ligGlyph);
};
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) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this));
}
protected:
USHORT format; /* Format identifier--format = 1 */
ArrayOf<OffsetTo<Coverage, ULONG> >
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
DEFINE_SIZE_ARRAY (4, coverage);
};
struct MarkGlyphSets
{
inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{
switch (u.format) {
case 1: return u.format1.covers (set_index, glyph_id);
default:return false;
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
USHORT format; /* Format identifier */
MarkGlyphSetsFormat1 format1;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
/*
* GDEF -- The Glyph Definition Table
*/
struct GDEF
{
static const hb_tag_t tableTag = HB_OT_TAG_GDEF;
enum GlyphClasses {
UnclassifiedGlyph = 0,
BaseGlyph = 1,
LigatureGlyph = 2,
MarkGlyph = 3,
ComponentGlyph = 4
};
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
{ return (this+markAttachClassDef).get_class (glyph); }
inline bool has_attach_points (void) const { return attachList != 0; }
inline unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{ return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
inline bool has_lig_carets (void) const { return ligCaretList != 0; }
inline unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{ return (this+ligCaretList).get_lig_carets (font,
direction, glyph_id, get_var_store(),
start_offset, caret_count, caret_array); }
inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
inline bool has_var_store (void) const { return version.to_int () >= 0x00010003u && varStore != 0; }
inline const VariationStore &get_var_store (void) const
{ return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
glyphClassDef.sanitize (c, this) &&
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
inline unsigned int get_glyph_props (hb_codepoint_t glyph) const
{
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: 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_PROPS_MARK | (klass << 8);
}
}
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
* 0x00010003u */
OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
* GDEF header (may be Null) */
OffsetTo<AttachList>
attachList; /* Offset to list of glyphs with
* attachment points--from beginning
* of GDEF header (may be Null) */
OffsetTo<LigCaretList>
ligCaretList; /* Offset to list of positioning points
* for ligature carets--from beginning
* of GDEF header (may be Null) */
OffsetTo<ClassDef>
markAttachClassDef; /* Offset to class definition table for
* mark attachment type--from beginning
* of GDEF header (may be Null) */
OffsetTo<MarkGlyphSets>
markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
OffsetTo<VariationStore, ULONG>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010003. */
public:
DEFINE_SIZE_MIN (12);
};
} /* namespace OT */
#endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,234 @@
/*
* 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 (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 (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 (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 (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 */

View file

@ -0,0 +1,722 @@
/*
* Copyright © 2016 Igalia S.L.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Igalia Author(s): Frédéric Wang
*/
#ifndef HB_OT_LAYOUT_MATH_TABLE_HH
#define HB_OT_LAYOUT_MATH_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-ot-layout-common-private.hh"
#include "hb-ot-math.h"
namespace OT {
struct MathValueRecord
{
inline hb_position_t get_x_value (hb_font_t *font, const void *base) const
{ return font->em_scale_x (value) + (base+deviceTable).get_x_delta (font); }
inline hb_position_t get_y_value (hb_font_t *font, const void *base) const
{ return font->em_scale_y (value) + (base+deviceTable).get_y_delta (font); }
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && deviceTable.sanitize (c, base));
}
protected:
SHORT value; /* The X or Y value in design units */
OffsetTo<Device> deviceTable; /* Offset to the device table - from the
* beginning of parent table. May be NULL.
* Suggested format for device table is 1. */
public:
DEFINE_SIZE_STATIC (4);
};
struct MathConstants
{
inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
unsigned int count = ARRAY_LENGTH (mathValueRecords);
for (unsigned int i = 0; i < count; i++)
if (!mathValueRecords[i].sanitize (c, this))
return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && sanitize_math_value_records(c));
}
inline hb_position_t get_value (hb_ot_math_constant_t constant,
hb_font_t *font) const
{
switch (constant) {
case HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN:
case HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN:
return percentScaleDown[constant - HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN];
case HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT:
case HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT:
return font->em_scale_y (minHeight[constant - HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT]);
case HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE:
case HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE:
case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP:
case HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT:
return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_x_value(font, this);
case HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT:
case HB_OT_MATH_CONSTANT_AXIS_HEIGHT:
case HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT:
case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP:
case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP:
case HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN:
case HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN:
case HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN:
case HB_OT_MATH_CONSTANT_MATH_LEADING:
case HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER:
case HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER:
case HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN:
case HB_OT_MATH_CONSTANT_STACK_GAP_MIN:
case HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP:
case HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN:
case HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP:
case HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN:
case HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN:
case HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX:
case HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP:
case HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED:
case HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER:
case HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS:
case HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP:
case HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN:
case HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN:
return mathValueRecords[constant - HB_OT_MATH_CONSTANT_MATH_LEADING].get_y_value(font, this);
case HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT:
return radicalDegreeBottomRaisePercent;
default:
return 0;
}
}
protected:
SHORT percentScaleDown[2];
USHORT minHeight[2];
MathValueRecord mathValueRecords[51];
SHORT radicalDegreeBottomRaisePercent;
public:
DEFINE_SIZE_STATIC (214);
};
struct MathItalicsCorrectionInfo
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) &&
italicsCorrection.sanitize (c, this));
}
inline hb_position_t get_value (hb_codepoint_t glyph,
hb_font_t *font) const
{
unsigned int index = (this+coverage).get_coverage (glyph);
return italicsCorrection[index].get_x_value (font, this);
}
protected:
OffsetTo<Coverage> coverage; /* Offset to Coverage table -
* from the beginning of
* MathItalicsCorrectionInfo
* table. */
ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
* defining italics correction
* values for each
* covered glyph. */
public:
DEFINE_SIZE_ARRAY (4, italicsCorrection);
};
struct MathTopAccentAttachment
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
topAccentCoverage.sanitize (c, this) &&
topAccentAttachment.sanitize (c, this));
}
inline hb_position_t get_value (hb_codepoint_t glyph,
hb_font_t *font) const
{
unsigned int index = (this+topAccentCoverage).get_coverage (glyph);
if (index == NOT_COVERED)
return font->get_glyph_h_advance (glyph) / 2;
return topAccentAttachment[index].get_x_value(font, this);
}
protected:
OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table -
* from the beginning of
* MathTopAccentAttachment
* table. */
ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
* defining top accent
* attachment points for each
* covered glyph. */
public:
DEFINE_SIZE_ARRAY (2 + 2, topAccentAttachment);
};
struct MathKern
{
inline bool sanitize_math_value_records (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
unsigned int count = 2 * heightCount + 1;
for (unsigned int i = 0; i < count; i++)
if (!mathValueRecords[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
c->check_array (mathValueRecords,
mathValueRecords[0].static_size,
2 * heightCount + 1) &&
sanitize_math_value_records (c));
}
inline hb_position_t get_value (hb_position_t correction_height, hb_font_t *font) const
{
const MathValueRecord* correctionHeight = mathValueRecords;
const MathValueRecord* kernValue = mathValueRecords + heightCount;
int sign = font->y_scale < 0 ? -1 : +1;
/* The description of the MathKern table is a ambiguous, but interpreting
* "between the two heights found at those indexes" for 0 < i < len as
*
* correctionHeight[i-1] < correction_height <= correctionHeight[i]
*
* makes the result consistent with the limit cases and we can just use the
* binary search algorithm of std::upper_bound:
*/
unsigned int i = 0;
unsigned int count = heightCount;
while (count > 0)
{
unsigned int half = count / 2;
hb_position_t height = correctionHeight[i + half].get_y_value(font, this);
if (sign * height < sign * correction_height)
{
i += half + 1;
count -= half + 1;
} else
count = half;
}
return kernValue[i].get_x_value(font, this);
}
protected:
USHORT heightCount;
MathValueRecord mathValueRecords[VAR]; /* Array of correction heights at
* which the kern value changes.
* Sorted by the height value in
* design units (heightCount entries),
* Followed by:
* Array of kern values corresponding
* to heights. (heightCount+1 entries).
*/
public:
DEFINE_SIZE_ARRAY (2, mathValueRecords);
};
struct MathKernInfoRecord
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
unsigned int count = ARRAY_LENGTH (mathKern);
for (unsigned int i = 0; i < count; i++)
if (unlikely (!mathKern[i].sanitize (c, base)))
return_trace (false);
return_trace (true);
}
inline hb_position_t get_kerning (hb_ot_math_kern_t kern,
hb_position_t correction_height,
hb_font_t *font,
const void *base) const
{
unsigned int idx = kern;
if (unlikely (idx >= ARRAY_LENGTH (mathKern))) return 0;
return (base+mathKern[idx]).get_value (correction_height, font);
}
protected:
/* Offset to MathKern table for each corner -
* from the beginning of MathKernInfo table. May be NULL. */
OffsetTo<MathKern> mathKern[4];
public:
DEFINE_SIZE_STATIC (8);
};
struct MathKernInfo
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
mathKernCoverage.sanitize (c, this) &&
mathKernInfoRecords.sanitize (c, this));
}
inline hb_position_t get_kerning (hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
hb_position_t correction_height,
hb_font_t *font) const
{
unsigned int index = (this+mathKernCoverage).get_coverage (glyph);
return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this);
}
protected:
OffsetTo<Coverage> mathKernCoverage; /* Offset to Coverage table -
* from the beginning of the
* MathKernInfo table. */
ArrayOf<MathKernInfoRecord> mathKernInfoRecords; /* Array of
* MathKernInfoRecords,
* per-glyph information for
* mathematical positioning
* of subscripts and
* superscripts. */
public:
DEFINE_SIZE_ARRAY (4, mathKernInfoRecords);
};
struct MathGlyphInfo
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
mathItalicsCorrectionInfo.sanitize (c, this) &&
mathTopAccentAttachment.sanitize (c, this) &&
extendedShapeCoverage.sanitize (c, this) &&
mathKernInfo.sanitize(c, this));
}
inline hb_position_t
get_italics_correction (hb_codepoint_t glyph, hb_font_t *font) const
{ return (this+mathItalicsCorrectionInfo).get_value (glyph, font); }
inline hb_position_t
get_top_accent_attachment (hb_codepoint_t glyph, hb_font_t *font) const
{ return (this+mathTopAccentAttachment).get_value (glyph, font); }
inline bool is_extended_shape (hb_codepoint_t glyph) const
{ return (this+extendedShapeCoverage).get_coverage (glyph) != NOT_COVERED; }
inline hb_position_t get_kerning (hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
hb_position_t correction_height,
hb_font_t *font) const
{ return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); }
protected:
/* Offset to MathItalicsCorrectionInfo table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
/* Offset to MathTopAccentAttachment table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
/* Offset to coverage table for Extended Shape glyphs -
* from the beginning of MathGlyphInfo table. When the left or right glyph of
* a box is an extended shape variant, the (ink) box (and not the default
* position defined by values in MathConstants table) should be used for
* vertical positioning purposes. May be NULL.. */
OffsetTo<Coverage> extendedShapeCoverage;
/* Offset to MathKernInfo table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathKernInfo> mathKernInfo;
public:
DEFINE_SIZE_STATIC (8);
};
struct MathGlyphVariantRecord
{
friend struct MathGlyphConstruction;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
GlyphID variantGlyph; /* Glyph ID for the variant. */
USHORT advanceMeasurement; /* Advance width/height, in design units, of the
* variant, in the direction of requested
* glyph extension. */
public:
DEFINE_SIZE_STATIC (4);
};
struct PartFlags : USHORT
{
enum Flags {
Extender = 0x0001u, /* If set, the part can be skipped or repeated. */
Defined = 0x0001u, /* All defined flags. */
};
public:
DEFINE_SIZE_STATIC (2);
};
struct MathGlyphPartRecord
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
inline void extract (hb_ot_math_glyph_part_t &out,
int scale,
hb_font_t *font) const
{
out.glyph = glyph;
out.start_connector_length = font->em_scale (startConnectorLength, scale);
out.end_connector_length = font->em_scale (endConnectorLength, scale);
out.full_advance = font->em_scale (fullAdvance, scale);
ASSERT_STATIC ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER ==
(unsigned int) PartFlags::Extender);
out.flags = (hb_ot_math_glyph_part_flags_t)
(unsigned int)
(partFlags & PartFlags::Defined);
}
protected:
GlyphID glyph; /* Glyph ID for the part. */
USHORT startConnectorLength; /* Advance width/ height of the straight bar
* connector material, in design units, is at
* the beginning of the glyph, in the
* direction of the extension. */
USHORT endConnectorLength; /* Advance width/ height of the straight bar
* connector material, in design units, is at
* the end of the glyph, in the direction of
* the extension. */
USHORT fullAdvance; /* Full advance width/height for this part,
* in the direction of the extension.
* In design units. */
PartFlags partFlags; /* Part qualifiers. */
public:
DEFINE_SIZE_STATIC (10);
};
struct MathGlyphAssembly
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
italicsCorrection.sanitize(c, this) &&
partRecords.sanitize(c));
}
inline unsigned int get_parts (hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *parts_count, /* IN/OUT */
hb_ot_math_glyph_part_t *parts /* OUT */,
hb_position_t *italics_correction /* OUT */) const
{
if (parts_count)
{
int scale = font->dir_scale (direction);
const MathGlyphPartRecord *arr =
partRecords.sub_array (start_offset, parts_count);
unsigned int count = *parts_count;
for (unsigned int i = 0; i < count; i++)
arr[i].extract (parts[i], scale, font);
}
if (italics_correction)
*italics_correction = italicsCorrection.get_x_value (font, this);
return partRecords.len;
}
protected:
MathValueRecord italicsCorrection; /* Italics correction of this
* MathGlyphAssembly. Should not
* depend on the assembly size. */
ArrayOf<MathGlyphPartRecord> partRecords; /* Array of part records, from
* left to right and bottom to
* top. */
public:
DEFINE_SIZE_ARRAY (6, partRecords);
};
struct MathGlyphConstruction
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
glyphAssembly.sanitize(c, this) &&
mathGlyphVariantRecord.sanitize(c));
}
inline const MathGlyphAssembly &get_assembly (void) const
{ return this+glyphAssembly; }
inline unsigned int get_variants (hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *variants_count, /* IN/OUT */
hb_ot_math_glyph_variant_t *variants /* OUT */) const
{
if (variants_count)
{
int scale = font->dir_scale (direction);
const MathGlyphVariantRecord *arr =
mathGlyphVariantRecord.sub_array (start_offset, variants_count);
unsigned int count = *variants_count;
for (unsigned int i = 0; i < count; i++)
{
variants[i].glyph = arr[i].variantGlyph;
variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale);
}
}
return mathGlyphVariantRecord.len;
}
protected:
/* Offset to MathGlyphAssembly table for this shape - from the beginning of
MathGlyphConstruction table. May be NULL. */
OffsetTo<MathGlyphAssembly> glyphAssembly;
/* MathGlyphVariantRecords for alternative variants of the glyphs. */
ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
public:
DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
};
struct MathVariants
{
inline bool sanitize_offsets (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
unsigned int count = vertGlyphCount + horizGlyphCount;
for (unsigned int i = 0; i < count; i++)
if (!glyphConstruction[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
vertGlyphCoverage.sanitize (c, this) &&
horizGlyphCoverage.sanitize (c, this) &&
c->check_array (glyphConstruction,
glyphConstruction[0].static_size,
vertGlyphCount + horizGlyphCount) &&
sanitize_offsets (c));
}
inline hb_position_t get_min_connector_overlap (hb_direction_t direction,
hb_font_t *font) const
{ return font->em_scale_dir (minConnectorOverlap, direction); }
inline unsigned int get_glyph_variants (hb_codepoint_t glyph,
hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *variants_count, /* IN/OUT */
hb_ot_math_glyph_variant_t *variants /* OUT */) const
{ return get_glyph_construction (glyph, direction, font)
.get_variants (direction, font, start_offset, variants_count, variants); }
inline unsigned int get_glyph_parts (hb_codepoint_t glyph,
hb_direction_t direction,
hb_font_t *font,
unsigned int start_offset,
unsigned int *parts_count, /* IN/OUT */
hb_ot_math_glyph_part_t *parts /* OUT */,
hb_position_t *italics_correction /* OUT */) const
{ return get_glyph_construction (glyph, direction, font)
.get_assembly ()
.get_parts (direction, font,
start_offset, parts_count, parts,
italics_correction); }
private:
inline const MathGlyphConstruction &
get_glyph_construction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_font_t *font) const
{
bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
: horizGlyphCoverage;
unsigned int index = (this+coverage).get_coverage (glyph);
if (unlikely (index >= count)) return Null(MathGlyphConstruction);
if (!vertical)
index += vertGlyphCount;
return this+glyphConstruction[index];
}
protected:
USHORT minConnectorOverlap; /* Minimum overlap of connecting
* glyphs during glyph construction,
* in design units. */
OffsetTo<Coverage> vertGlyphCoverage; /* Offset to Coverage table -
* from the beginning of MathVariants
* table. */
OffsetTo<Coverage> horizGlyphCoverage; /* Offset to Coverage table -
* from the beginning of MathVariants
* table. */
USHORT vertGlyphCount; /* Number of glyphs for which
* information is provided for
* vertically growing variants. */
USHORT horizGlyphCount; /* Number of glyphs for which
* information is provided for
* horizontally growing variants. */
/* Array of offsets to MathGlyphConstruction tables - from the beginning of
the MathVariants table, for shapes growing in vertical/horizontal
direction. */
OffsetTo<MathGlyphConstruction> glyphConstruction[VAR];
public:
DEFINE_SIZE_ARRAY (10, glyphConstruction);
};
/*
* MATH -- The MATH Table
*/
struct MATH
{
static const hb_tag_t tableTag = HB_OT_TAG_MATH;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
mathConstants.sanitize (c, this) &&
mathGlyphInfo.sanitize (c, this) &&
mathVariants.sanitize (c, this));
}
inline hb_position_t get_constant (hb_ot_math_constant_t constant,
hb_font_t *font) const
{ return (this+mathConstants).get_value (constant, font); }
inline const MathGlyphInfo &get_math_glyph_info (void) const
{ return this+mathGlyphInfo; }
inline const MathVariants &get_math_variants (void) const
{ return this+mathVariants; }
protected:
FixedVersion<>version; /* Version of the MATH table
* initially set to 0x00010000u */
OffsetTo<MathConstants> mathConstants;/* MathConstants table */
OffsetTo<MathGlyphInfo> mathGlyphInfo;/* MathGlyphInfo table */
OffsetTo<MathVariants> mathVariants; /* MathVariants table */
public:
DEFINE_SIZE_STATIC (10);
};
} /* mathspace OT */
#endif /* HB_OT_LAYOUT_MATH_TABLE_HH */

View file

@ -0,0 +1,621 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_LAYOUT_PRIVATE_HH
#define HB_OT_LAYOUT_PRIVATE_HH
#include "hb-private.hh"
#include "hb-font-private.hh"
#include "hb-buffer-private.hh"
#include "hb-set-private.hh"
/* Private API corresponding to hb-ot-layout.h: */
HB_INTERNAL hb_bool_t
hb_ot_layout_table_find_feature (hb_face_t *face,
hb_tag_t table_tag,
hb_tag_t feature_tag,
unsigned int *feature_index);
/*
* GDEF
*/
enum hb_ot_layout_glyph_props_flags_t
{
/* 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_OT_LAYOUT_GLYPH_PROPS_PRESERVE = HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED |
HB_OT_LAYOUT_GLYPH_PROPS_LIGATED |
HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED
};
HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t);
/*
* GSUB/GPOS
*/
HB_INTERNAL hb_bool_t
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 before all the position_lookup's are done. */
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, to finish advances. */
HB_INTERNAL void
hb_ot_layout_position_finish_advances (hb_font_t *font,
hb_buffer_t *buffer);
/* Should be called after hb_ot_layout_position_finish_advances, to finish offsets. */
HB_INTERNAL void
hb_ot_layout_position_finish_offsets (hb_font_t *font,
hb_buffer_t *buffer);
/*
* hb_ot_layout_t
*/
namespace OT {
struct GDEF;
struct GSUB;
struct GPOS;
struct MATH;
}
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;
hb_blob_t *math_blob;
const struct OT::GDEF *gdef;
const struct OT::GSUB *gsub;
const struct OT::GPOS *gpos;
const struct OT::MATH *math;
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;
};
HB_INTERNAL hb_ot_layout_t *
_hb_ot_layout_create (hb_face_t *face);
HB_INTERNAL void
_hb_ot_layout_destroy (hb_ot_layout_t *layout);
#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot)
/*
* Buffer var routines.
*/
/* buffer var allocations, used during the entire shaping process */
#define unicode_props() var2.u16[0]
/* 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 */
/* loop over syllables */
#define foreach_syllable(buffer, start, end) \
for (unsigned int \
_count = buffer->len, \
start = 0, end = _count ? _next_syllable (buffer, 0) : 0; \
start < _count; \
start = end, end = _next_syllable (buffer, start))
static inline unsigned int
_next_syllable (hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
unsigned int syllable = info[start].syllable();
while (++start < count && syllable == info[start].syllable())
;
return start;
}
/* unicode_props */
/* Design:
* unicode_props() is a two-byte number. The low byte includes:
* - General_Category: 5 bits.
* - A bit each for:
* * Is it Default_Ignorable(); we have a modified Default_Ignorable().
* * Whether it's one of the three Mongolian Free Variation Selectors.
* * One free bit right now.
*
* The high-byte has different meanings, switched by the Gen-Cat:
* - For Mn,Mc,Me: the modified Combining_Class.
* - For Cf: whether it's ZWJ, ZWNJ, or something else.
* - For Ws: index of which space character this is, if space fallback
* is needed, ie. we don't set this by default, only if asked to.
*/
enum hb_unicode_props_flags_t {
UPROPS_MASK_GEN_CAT = 0x001Fu,
UPROPS_MASK_IGNORABLE = 0x0020u,
UPROPS_MASK_FVS = 0x0040u, /* MONGOLIAN FREE VARIATION SELECTOR 1..3 */
/* If GEN_CAT=FORMAT, top byte masks: */
UPROPS_MASK_Cf_ZWJ = 0x0100u,
UPROPS_MASK_Cf_ZWNJ = 0x0200u
};
HB_MARK_AS_FLAG_T (hb_unicode_props_flags_t);
static inline void
_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
{
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int u = info->codepoint;
unsigned int gen_cat = (unsigned int) unicode->general_category (u);
unsigned int props = gen_cat;
if (u >= 0x80)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII;
if (unlikely (unicode->is_default_ignorable (u)))
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES;
props |= UPROPS_MASK_IGNORABLE;
if (u == 0x200Cu) props |= UPROPS_MASK_Cf_ZWNJ;
if (u == 0x200Du) props |= UPROPS_MASK_Cf_ZWJ;
/* Mongolian Free Variation Selectors need to be remembered
* because although we need to hide them like default-ignorables,
* they need to non-ignorable during shaping. This is similar to
* what we do for joiners in Indic-like shapers, but since the
* FVSes are GC=Mn, we have use a separate bit to remember them.
* Fixes:
* https://github.com/behdad/harfbuzz/issues/234
*/
if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_FVS;
}
else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
{
/* The above check is just an optimization to let in only things we need further
* processing on. */
/* Only Mn and Mc can have non-zero ccc:
* http://www.unicode.org/policies/stability_policy.html#Property_Value
* """
* Canonical_Combining_Class, General_Category
* All characters other than those with General_Category property values
* Spacing_Mark (Mc) and Nonspacing_Mark (Mn) have the Canonical_Combining_Class
* property value 0.
* 1.1.5+
* """
*
* Also, all Mn's that are Default_Ignorable, have ccc=0, hence
* the "else if".
*/
props |= unicode->modified_combining_class (info->codepoint)<<8;
/* Recategorize emoji skin-tone modifiers as Unicode mark, so they
* behave correctly in non-native directionality. They originally
* are MODIFIER_SYMBOL. Fixes:
* https://github.com/behdad/harfbuzz/issues/169
*/
if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
{
props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
}
}
}
info->unicode_props() = props;
}
static inline void
_hb_glyph_info_set_general_category (hb_glyph_info_t *info,
hb_unicode_general_category_t gen_cat)
{
/* Clears top-byte. */
info->unicode_props() = (unsigned int) gen_cat | (info->unicode_props() & (0xFF & ~UPROPS_MASK_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_props() & UPROPS_MASK_GEN_CAT);
}
static inline bool
_hb_glyph_info_is_unicode_mark (const hb_glyph_info_t *info)
{
return HB_UNICODE_GENERAL_CATEGORY_IS_MARK (info->unicode_props() & UPROPS_MASK_GEN_CAT);
}
static inline void
_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info,
unsigned int modified_class)
{
if (unlikely (!_hb_glyph_info_is_unicode_mark (info)))
return;
info->unicode_props() = (modified_class<<8) | (info->unicode_props() & 0xFF);
}
static inline unsigned int
_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_mark (info) ? info->unicode_props()>>8 : 0;
}
static inline bool
_hb_glyph_info_is_unicode_space (const hb_glyph_info_t *info)
{
return _hb_glyph_info_get_general_category (info) ==
HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
}
static inline void
_hb_glyph_info_set_unicode_space_fallback_type (hb_glyph_info_t *info, hb_unicode_funcs_t::space_t s)
{
if (unlikely (!_hb_glyph_info_is_unicode_space (info)))
return;
info->unicode_props() = (((unsigned int) s)<<8) | (info->unicode_props() & 0xFF);
}
static inline hb_unicode_funcs_t::space_t
_hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_space (info) ?
(hb_unicode_funcs_t::space_t) (info->unicode_props()>>8) :
hb_unicode_funcs_t::NOT_SPACE;
}
static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
static inline hb_bool_t
_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info)
{
return (info->unicode_props() & UPROPS_MASK_IGNORABLE) &&
!_hb_glyph_info_ligated (info);
}
static inline hb_bool_t
_hb_glyph_info_is_default_ignorable_and_not_fvs (const hb_glyph_info_t *info)
{
return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_FVS))
== UPROPS_MASK_IGNORABLE) &&
!_hb_glyph_info_ligated (info);
}
static inline bool
_hb_glyph_info_is_unicode_format (const hb_glyph_info_t *info)
{
return _hb_glyph_info_get_general_category (info) ==
HB_UNICODE_GENERAL_CATEGORY_FORMAT;
}
static inline hb_bool_t
_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWNJ);
}
static inline hb_bool_t
_hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & UPROPS_MASK_Cf_ZWJ);
}
static inline hb_bool_t
_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_unicode_format (info) && (info->unicode_props() & (UPROPS_MASK_Cf_ZWNJ|UPROPS_MASK_Cf_ZWJ));
}
static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
if (!_hb_glyph_info_is_unicode_format (info))
return;
info->unicode_props() ^= UPROPS_MASK_Cf_ZWNJ | UPROPS_MASK_Cf_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);
}
static inline void
_hb_glyph_info_clear_substituted (hb_glyph_info_t *info)
{
info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
}
/* Allocation / deallocation. */
static inline void
_hb_buffer_allocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ALLOCATE_VAR (buffer, unicode_props);
}
static inline void
_hb_buffer_deallocate_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_DEALLOCATE_VAR (buffer, unicode_props);
}
static inline void
_hb_buffer_assert_unicode_vars (hb_buffer_t *buffer)
{
HB_BUFFER_ASSERT_VAR (buffer, unicode_props);
}
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 */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,321 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_LAYOUT_H
#define HB_OT_LAYOUT_H
#include "hb.h"
#include "hb-ot-tag.h"
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
*/
HB_EXTERN 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_EXTERN hb_ot_layout_glyph_class_t
hb_ot_layout_get_glyph_class (hb_face_t *face,
hb_codepoint_t glyph);
HB_EXTERN 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 */
HB_EXTERN unsigned int
hb_ot_layout_get_attach_points (hb_face_t *face,
hb_codepoint_t glyph,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */);
/* Ligature caret positions */
HB_EXTERN unsigned int
hb_ot_layout_get_ligature_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */);
/*
* GSUB/GPOS feature query and enumeration interface
*/
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_FEATURE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX 0xFFFFu
#define HB_OT_LAYOUT_NO_VARIATIONS_INDEX 0xFFFFFFFFu
HB_EXTERN unsigned int
hb_ot_layout_table_get_script_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *script_count /* IN/OUT */,
hb_tag_t *script_tags /* OUT */);
HB_EXTERN 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);
/* Like find_script, but takes zero-terminated array of scripts to test */
HB_EXTERN hb_bool_t
hb_ot_layout_table_choose_script (hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *script_tags,
unsigned int *script_index,
hb_tag_t *chosen_script);
HB_EXTERN unsigned int
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */);
HB_EXTERN unsigned int
hb_ot_layout_script_get_language_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int start_offset,
unsigned int *language_count /* IN/OUT */,
hb_tag_t *language_tags /* OUT */);
HB_EXTERN hb_bool_t
hb_ot_layout_script_find_language (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
hb_tag_t language_tag,
unsigned int *language_index);
HB_EXTERN hb_bool_t
hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int *feature_index);
HB_EXTERN 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);
HB_EXTERN unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
unsigned int *feature_indexes /* OUT */);
HB_EXTERN unsigned int
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
unsigned int start_offset,
unsigned int *feature_count /* IN/OUT */,
hb_tag_t *feature_tags /* OUT */);
HB_EXTERN hb_bool_t
hb_ot_layout_language_find_feature (hb_face_t *face,
hb_tag_t table_tag,
unsigned int script_index,
unsigned int language_index,
hb_tag_t feature_tag,
unsigned int *feature_index);
HB_EXTERN unsigned int
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 */);
HB_EXTERN unsigned int
hb_ot_layout_table_get_lookup_count (hb_face_t *face,
hb_tag_t table_tag);
HB_EXTERN 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 */);
HB_EXTERN void
hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
hb_set_t *glyphs_before, /* OUT. May be NULL */
hb_set_t *glyphs_input, /* OUT. May be NULL */
hb_set_t *glyphs_after, /* OUT. May be NULL */
hb_set_t *glyphs_output /* OUT. May be NULL */);
#ifdef HB_NOT_IMPLEMENTED
typedef struct
{
const hb_codepoint_t *before,
unsigned int before_length,
const hb_codepoint_t *input,
unsigned int input_length,
const hb_codepoint_t *after,
unsigned int after_length,
} hb_ot_layout_glyph_sequence_t;
typedef hb_bool_t
(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font,
hb_tag_t table_tag,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
void *user_data);
HB_EXTERN void
Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face,
hb_tag_t table_tag,
unsigned int lookup_index,
hb_ot_layout_glyph_sequence_func_t callback,
void *user_data);
#endif
/* Variations support */
HB_EXTERN hb_bool_t
hb_ot_layout_table_find_feature_variations (hb_face_t *face,
hb_tag_t table_tag,
const int *coords,
unsigned int num_coords,
unsigned int *variations_index /* out */);
HB_EXTERN unsigned int
hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
hb_tag_t table_tag,
unsigned int feature_index,
unsigned int variations_index,
unsigned int start_offset,
unsigned int *lookup_count /* IN/OUT */,
unsigned int *lookup_indexes /* OUT */);
/*
* GSUB
*/
HB_EXTERN hb_bool_t
hb_ot_layout_has_substitution (hb_face_t *face);
HB_EXTERN 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);
HB_EXTERN void
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_EXTERN hb_bool_t
Xhb_ot_layout_lookup_substitute (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
unsigned int out_size,
hb_codepoint_t *glyphs_out, /* OUT */
unsigned int *clusters_out, /* OUT */
unsigned int *out_length /* OUT */);
#endif
/*
* GPOS
*/
HB_EXTERN hb_bool_t
hb_ot_layout_has_positioning (hb_face_t *face);
#ifdef HB_NOT_IMPLEMENTED
/* Note: You better have GDEF when using this API, or marks won't do much. */
HB_EXTERN hb_bool_t
Xhb_ot_layout_lookup_position (hb_font_t *font,
unsigned int lookup_index,
const hb_ot_layout_glyph_sequence_t *sequence,
hb_glyph_position_t *positions /* IN / OUT */);
#endif
/* Optical 'size' feature info. Returns true if found.
* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
HB_EXTERN hb_bool_t
hb_ot_layout_get_size_params (hb_face_t *face,
unsigned int *design_size, /* OUT. May be NULL */
unsigned int *subfamily_id, /* OUT. May be NULL */
unsigned int *subfamily_name_id, /* OUT. May be NULL */
unsigned int *range_start, /* OUT. May be NULL */
unsigned int *range_end /* OUT. May be NULL */);
HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */

View file

@ -0,0 +1,239 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2010,2011,2012,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_MAP_PRIVATE_HH
#define HB_OT_MAP_PRIVATE_HH
#include "hb-buffer-private.hh"
struct hb_ot_shape_plan_t;
static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
struct hb_ot_map_t
{
friend struct hb_ot_map_builder_t;
public:
struct feature_map_t {
hb_tag_t tag; /* should be first for our bsearch to work */
unsigned int index[2]; /* GSUB/GPOS */
unsigned int stage[2]; /* GSUB/GPOS */
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 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 struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
struct stage_map_t {
unsigned int last_lookup; /* Cumulative */
pause_func_t pause_func;
};
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_mask_t global_mask;
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<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
};
enum hb_ot_map_feature_flags_t {
F_NONE = 0x0000u,
F_GLOBAL = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
F_HAS_FALLBACK = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
F_MANUAL_ZWJ = 0x0004u, /* Don't skip over ZWJ when matching. */
F_GLOBAL_SEARCH = 0x0008u /* If feature not found in LangSys, look for it in global feature list and pick one. */
};
HB_MARK_AS_FLAG_T (hb_ot_map_feature_flags_t);
/* Macro version for where const is desired. */
#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
struct hb_ot_map_builder_t
{
public:
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,
hb_ot_map_feature_flags_t flags);
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::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_ot_map_t &m,
const int *coords,
unsigned int num_coords);
inline void finish (void) {
feature_infos.finish ();
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
stages[table_index].finish ();
}
}
private:
HB_INTERNAL void add_lookups (hb_ot_map_t &m,
hb_face_t *face,
unsigned int table_index,
unsigned int feature_index,
unsigned int variations_index,
hb_mask_t mask,
bool auto_zwj);
struct feature_info_t {
hb_tag_t tag;
unsigned int seq; /* sequence#, used for stable sorting only */
unsigned int max_value;
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 */
static int cmp (const feature_info_t *a, const feature_info_t *b)
{ return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) :
(a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); }
};
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);
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, 32> feature_infos;
hb_prealloced_array_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */
};
#endif /* HB_OT_MAP_PRIVATE_HH */

View file

@ -0,0 +1,328 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2010,2011,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-map-private.hh"
#include "hb-ot-layout-private.hh"
void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
{
for (unsigned int i = 0; i < lookups[table_index].len; i++)
hb_set_add (lookups_out, lookups[table_index][i].index);
}
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] = (bool) hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
}
}
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->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_builder_t::add_lookups (hb_ot_map_t &m,
hb_face_t *face,
unsigned int table_index,
unsigned int feature_index,
unsigned int variations_index,
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_with_variations_get_lookups (face,
table_tags[table_index],
feature_index,
variations_index,
offset, &len,
lookup_indices);
for (unsigned int i = 0; i < len; i++)
{
if (lookup_indices[i] >= table_lookup_count)
continue;
hb_ot_map_t::lookup_map_t *lookup = m.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));
}
void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
{
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_ot_map_t &m,
const int *coords,
unsigned int num_coords)
{
m.global_mask = 1;
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};
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.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].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].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]);
}
feature_infos.shrink (j + 1);
}
/* Allocate bits now */
unsigned int next_bit = 1;
for (unsigned int i = 0; i < feature_infos.len; i++)
{
const feature_info_t *info = &feature_infos[i];
unsigned int bits_needed;
if ((info->flags & F_GLOBAL) && info->max_value == 1)
/* Uses the global bit */
bits_needed = 0;
else
/* Limit to 8 bits per feature. */
bits_needed = MIN(8u, _hb_bit_storage (info->max_value));
if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
continue; /* Feature disabled, or not enough bits. */
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 |= 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 && (info->flags & F_GLOBAL_SEARCH))
{
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
found |= hb_ot_layout_table_find_feature (face,
table_tags[table_index],
info->tag,
&feature_index[table_index]);
}
}
if (!found && !(info->flags & F_HAS_FALLBACK))
continue;
hb_ot_map_t::feature_map_t *map = m.features.push ();
if (unlikely (!map))
break;
map->tag = info->tag;
map->index[0] = feature_index[0];
map->index[1] = feature_index[1];
map->stage[0] = info->stage[0];
map->stage[1] = info->stage[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;
} else {
map->shift = next_bit;
map->mask = (1u << (next_bit + bits_needed)) - (1u << next_bit);
next_bit += bits_needed;
m.global_mask |= (info->default_value << map->shift) & map->mask;
}
map->_1_mask = (1u << map->shift) & map->mask;
map->needs_fallback = !found;
}
feature_infos.shrink (0); /* Done with these */
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 variations_index;
hb_ot_layout_table_find_feature_variations (face,
table_tags[table_index],
coords,
num_coords,
&variations_index);
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)
add_lookups (m, face, table_index,
required_feature_index[table_index],
variations_index,
1 /* mask */,
true /* auto_zwj */);
for (unsigned i = 0; i < m.features.len; i++)
if (m.features[i].stage[table_index] == stage)
add_lookups (m, face, table_index,
m.features[i].index[table_index],
variations_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].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 (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;
}
stage_index++;
}
}
}
}

View file

@ -0,0 +1,272 @@
/*
* Copyright © 2016 Igalia S.L.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Igalia Author(s): Frédéric Wang
*/
#include "hb-open-type-private.hh"
#include "hb-ot-layout-math-table.hh"
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
static inline const OT::MATH&
_get_math (hb_face_t *face)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::MATH);
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
retry:
const OT::MATH *math = (const OT::MATH *) hb_atomic_ptr_get (&layout->math);
if (unlikely (!math))
{
hb_blob_t *blob = OT::Sanitizer<OT::MATH>::sanitize (face->reference_table (HB_OT_TAG_MATH));
math = OT::Sanitizer<OT::MATH>::lock_instance (blob);
if (!hb_atomic_ptr_cmpexch (&layout->math, NULL, math))
{
hb_blob_destroy (blob);
goto retry;
}
layout->math_blob = blob;
}
return *math;
}
/*
* OT::MATH
*/
/**
* hb_ot_math_has_data:
* @face: #hb_face_t to test
*
* This function allows to verify the presence of an OpenType MATH table on the
* face. If so, such a table will be loaded into memory and sanitized. You can
* then safely call other functions for math layout and shaping.
*
* Return value: #TRUE if face has a MATH table and #FALSE otherwise
*
* Since: 1.3.3
**/
hb_bool_t
hb_ot_math_has_data (hb_face_t *face)
{
return &_get_math (face) != &OT::Null(OT::MATH);
}
/**
* hb_ot_math_get_constant:
* @font: #hb_font_t from which to retrieve the value
* @constant: #hb_ot_math_constant_t the constant to retrieve
*
* This function returns the requested math constants as a #hb_position_t.
* If the request constant is HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN,
* HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or
* HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN then the return value is
* actually an integer between 0 and 100 representing that percentage.
*
* Return value: the requested constant or 0
*
* Since: 1.3.3
**/
hb_position_t
hb_ot_math_get_constant (hb_font_t *font,
hb_ot_math_constant_t constant)
{
const OT::MATH &math = _get_math (font->face);
return math.get_constant(constant, font);
}
/**
* hb_ot_math_get_glyph_italics_correction:
* @font: #hb_font_t from which to retrieve the value
* @glyph: glyph index from which to retrieve the value
*
* Return value: the italics correction of the glyph or 0
*
* Since: 1.3.3
**/
hb_position_t
hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
hb_codepoint_t glyph)
{
const OT::MATH &math = _get_math (font->face);
return math.get_math_glyph_info().get_italics_correction (glyph, font);
}
/**
* hb_ot_math_get_glyph_top_accent_attachment:
* @font: #hb_font_t from which to retrieve the value
* @glyph: glyph index from which to retrieve the value
*
* Return value: the top accent attachment of the glyph or 0
*
* Since: 1.3.3
**/
hb_position_t
hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
hb_codepoint_t glyph)
{
const OT::MATH &math = _get_math (font->face);
return math.get_math_glyph_info().get_top_accent_attachment (glyph, font);
}
/**
* hb_ot_math_is_glyph_extended_shape:
* @font: a #hb_font_t to test
* @glyph: a glyph index to test
*
* Return value: #TRUE if the glyph is an extended shape and #FALSE otherwise
*
* Since: 1.3.3
**/
hb_bool_t
hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
hb_codepoint_t glyph)
{
const OT::MATH &math = _get_math (face);
return math.get_math_glyph_info().is_extended_shape (glyph);
}
/**
* hb_ot_math_get_glyph_kerning:
* @font: #hb_font_t from which to retrieve the value
* @glyph: glyph index from which to retrieve the value
* @kern: the #hb_ot_math_kern_t from which to retrieve the value
* @correction_height: the correction height to use to determine the kerning.
*
* This function tries to retrieve the MathKern table for the specified font,
* glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the
* MathKern table to find one value that is greater or equal to specified
* correction_height. If one is found the corresponding value from the list of
* kerns is returned and otherwise the last kern value is returned.
*
* Return value: requested kerning or 0
*
* Since: 1.3.3
**/
hb_position_t
hb_ot_math_get_glyph_kerning (hb_font_t *font,
hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
hb_position_t correction_height)
{
const OT::MATH &math = _get_math (font->face);
return math.get_math_glyph_info().get_kerning (glyph, kern, correction_height, font);
}
/**
* hb_ot_math_get_glyph_variants:
* @font: #hb_font_t from which to retrieve the values
* @glyph: index of the glyph to stretch
* @direction: direction of the stretching
* @start_offset: offset of the first variant to retrieve
* @variants_count: maximum number of variants to retrieve after start_offset
* (IN) and actual number of variants retrieved (OUT)
* @variants: array of size at least @variants_count to store the result
*
* This function tries to retrieve the MathGlyphConstruction for the specified
* font, glyph and direction. Note that only the value of
* #HB_DIRECTION_IS_HORIZONTAL is considered. It provides the corresponding list
* of size variants as an array of hb_ot_math_glyph_variant_t structs.
*
* Return value: the total number of size variants available or 0
*
* Since: 1.3.3
**/
unsigned int
hb_ot_math_get_glyph_variants (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
unsigned int start_offset,
unsigned int *variants_count, /* IN/OUT */
hb_ot_math_glyph_variant_t *variants /* OUT */)
{
const OT::MATH &math = _get_math (font->face);
return math.get_math_variants().get_glyph_variants (glyph, direction, font,
start_offset,
variants_count,
variants);
}
/**
* hb_ot_math_get_min_connector_overlap:
* @font: #hb_font_t from which to retrieve the value
* @direction: direction of the stretching
*
* This function tries to retrieve the MathVariants table for the specified
* font and returns the minimum overlap of connecting glyphs to draw a glyph
* assembly in the specified direction. Note that only the value of
* #HB_DIRECTION_IS_HORIZONTAL is considered.
*
* Return value: requested min connector overlap or 0
*
* Since: 1.3.3
**/
hb_position_t
hb_ot_math_get_min_connector_overlap (hb_font_t *font,
hb_direction_t direction)
{
const OT::MATH &math = _get_math (font->face);
return math.get_math_variants().get_min_connector_overlap (direction, font);
}
/**
* hb_ot_math_get_glyph_assembly:
* @font: #hb_font_t from which to retrieve the values
* @glyph: index of the glyph to stretch
* @direction: direction of the stretching
* @start_offset: offset of the first glyph part to retrieve
* @parts_count: maximum number of glyph parts to retrieve after start_offset
* (IN) and actual number of parts retrieved (OUT)
* @parts: array of size at least @parts_count to store the result
* @italics_correction: italic correction of the glyph assembly
*
* This function tries to retrieve the GlyphAssembly for the specified font,
* glyph and direction. Note that only the value of #HB_DIRECTION_IS_HORIZONTAL
* is considered. It provides the information necessary to draw the glyph
* assembly as an array of #hb_ot_math_glyph_part_t.
*
* Return value: the total number of parts in the glyph assembly
*
* Since: 1.3.3
**/
unsigned int
hb_ot_math_get_glyph_assembly (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
unsigned int start_offset,
unsigned int *parts_count, /* IN/OUT */
hb_ot_math_glyph_part_t *parts, /* OUT */
hb_position_t *italics_correction /* OUT */)
{
const OT::MATH &math = _get_math (font->face);
return math.get_math_variants().get_glyph_parts (glyph, direction, font,
start_offset,
parts_count,
parts,
italics_correction);
}

View file

@ -0,0 +1,209 @@
/*
* Copyright © 2016 Igalia S.L.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Igalia Author(s): Frédéric Wang
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_MATH_H
#define HB_OT_MATH_H
#include "hb.h"
HB_BEGIN_DECLS
/*
* MATH
*/
#define HB_OT_TAG_MATH HB_TAG('M','A','T','H')
/* Use with hb_buffer_set_script() for math shaping. */
#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h')
/* Types */
/**
* hb_ot_math_constant_t:
*
* Since: 1.3.3
*/
typedef enum {
HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN = 0,
HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN = 1,
HB_OT_MATH_CONSTANT_DELIMITED_SUB_FORMULA_MIN_HEIGHT = 2,
HB_OT_MATH_CONSTANT_DISPLAY_OPERATOR_MIN_HEIGHT = 3,
HB_OT_MATH_CONSTANT_MATH_LEADING = 4,
HB_OT_MATH_CONSTANT_AXIS_HEIGHT = 5,
HB_OT_MATH_CONSTANT_ACCENT_BASE_HEIGHT = 6,
HB_OT_MATH_CONSTANT_FLATTENED_ACCENT_BASE_HEIGHT = 7,
HB_OT_MATH_CONSTANT_SUBSCRIPT_SHIFT_DOWN = 8,
HB_OT_MATH_CONSTANT_SUBSCRIPT_TOP_MAX = 9,
HB_OT_MATH_CONSTANT_SUBSCRIPT_BASELINE_DROP_MIN = 10,
HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP = 11,
HB_OT_MATH_CONSTANT_SUPERSCRIPT_SHIFT_UP_CRAMPED = 12,
HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MIN = 13,
HB_OT_MATH_CONSTANT_SUPERSCRIPT_BASELINE_DROP_MAX = 14,
HB_OT_MATH_CONSTANT_SUB_SUPERSCRIPT_GAP_MIN = 15,
HB_OT_MATH_CONSTANT_SUPERSCRIPT_BOTTOM_MAX_WITH_SUBSCRIPT = 16,
HB_OT_MATH_CONSTANT_SPACE_AFTER_SCRIPT = 17,
HB_OT_MATH_CONSTANT_UPPER_LIMIT_GAP_MIN = 18,
HB_OT_MATH_CONSTANT_UPPER_LIMIT_BASELINE_RISE_MIN = 19,
HB_OT_MATH_CONSTANT_LOWER_LIMIT_GAP_MIN = 20,
HB_OT_MATH_CONSTANT_LOWER_LIMIT_BASELINE_DROP_MIN = 21,
HB_OT_MATH_CONSTANT_STACK_TOP_SHIFT_UP = 22,
HB_OT_MATH_CONSTANT_STACK_TOP_DISPLAY_STYLE_SHIFT_UP = 23,
HB_OT_MATH_CONSTANT_STACK_BOTTOM_SHIFT_DOWN = 24,
HB_OT_MATH_CONSTANT_STACK_BOTTOM_DISPLAY_STYLE_SHIFT_DOWN = 25,
HB_OT_MATH_CONSTANT_STACK_GAP_MIN = 26,
HB_OT_MATH_CONSTANT_STACK_DISPLAY_STYLE_GAP_MIN = 27,
HB_OT_MATH_CONSTANT_STRETCH_STACK_TOP_SHIFT_UP = 28,
HB_OT_MATH_CONSTANT_STRETCH_STACK_BOTTOM_SHIFT_DOWN = 29,
HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_ABOVE_MIN = 30,
HB_OT_MATH_CONSTANT_STRETCH_STACK_GAP_BELOW_MIN = 31,
HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_SHIFT_UP = 32,
HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_DISPLAY_STYLE_SHIFT_UP = 33,
HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_SHIFT_DOWN = 34,
HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_DISPLAY_STYLE_SHIFT_DOWN = 35,
HB_OT_MATH_CONSTANT_FRACTION_NUMERATOR_GAP_MIN = 36,
HB_OT_MATH_CONSTANT_FRACTION_NUM_DISPLAY_STYLE_GAP_MIN = 37,
HB_OT_MATH_CONSTANT_FRACTION_RULE_THICKNESS = 38,
HB_OT_MATH_CONSTANT_FRACTION_DENOMINATOR_GAP_MIN = 39,
HB_OT_MATH_CONSTANT_FRACTION_DENOM_DISPLAY_STYLE_GAP_MIN = 40,
HB_OT_MATH_CONSTANT_SKEWED_FRACTION_HORIZONTAL_GAP = 41,
HB_OT_MATH_CONSTANT_SKEWED_FRACTION_VERTICAL_GAP = 42,
HB_OT_MATH_CONSTANT_OVERBAR_VERTICAL_GAP = 43,
HB_OT_MATH_CONSTANT_OVERBAR_RULE_THICKNESS = 44,
HB_OT_MATH_CONSTANT_OVERBAR_EXTRA_ASCENDER = 45,
HB_OT_MATH_CONSTANT_UNDERBAR_VERTICAL_GAP = 46,
HB_OT_MATH_CONSTANT_UNDERBAR_RULE_THICKNESS = 47,
HB_OT_MATH_CONSTANT_UNDERBAR_EXTRA_DESCENDER = 48,
HB_OT_MATH_CONSTANT_RADICAL_VERTICAL_GAP = 49,
HB_OT_MATH_CONSTANT_RADICAL_DISPLAY_STYLE_VERTICAL_GAP = 50,
HB_OT_MATH_CONSTANT_RADICAL_RULE_THICKNESS = 51,
HB_OT_MATH_CONSTANT_RADICAL_EXTRA_ASCENDER = 52,
HB_OT_MATH_CONSTANT_RADICAL_KERN_BEFORE_DEGREE = 53,
HB_OT_MATH_CONSTANT_RADICAL_KERN_AFTER_DEGREE = 54,
HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT = 55
} hb_ot_math_constant_t;
/**
* hb_ot_math_kern_t:
*
* Since: 1.3.3
*/
typedef enum {
HB_OT_MATH_KERN_TOP_RIGHT = 0,
HB_OT_MATH_KERN_TOP_LEFT = 1,
HB_OT_MATH_KERN_BOTTOM_RIGHT = 2,
HB_OT_MATH_KERN_BOTTOM_LEFT = 3
} hb_ot_math_kern_t;
/**
* hb_ot_math_glyph_variant_t:
*
* Since: 1.3.3
*/
typedef struct hb_ot_math_glyph_variant_t {
hb_codepoint_t glyph;
hb_position_t advance;
} hb_ot_math_glyph_variant_t;
/**
* hb_ot_math_glyph_part_flags_t:
*
* Since: 1.3.3
*/
typedef enum { /*< flags >*/
HB_MATH_GLYPH_PART_FLAG_EXTENDER = 0x00000001u /* Extender glyph */
} hb_ot_math_glyph_part_flags_t;
/**
* hb_ot_math_glyph_part_t:
*
* Since: 1.3.3
*/
typedef struct hb_ot_math_glyph_part_t {
hb_codepoint_t glyph;
hb_position_t start_connector_length;
hb_position_t end_connector_length;
hb_position_t full_advance;
hb_ot_math_glyph_part_flags_t flags;
} hb_ot_math_glyph_part_t;
/* Methods */
HB_EXTERN hb_bool_t
hb_ot_math_has_data (hb_face_t *face);
HB_EXTERN hb_position_t
hb_ot_math_get_constant (hb_font_t *font,
hb_ot_math_constant_t constant);
HB_EXTERN hb_position_t
hb_ot_math_get_glyph_italics_correction (hb_font_t *font,
hb_codepoint_t glyph);
HB_EXTERN hb_position_t
hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font,
hb_codepoint_t glyph);
HB_EXTERN hb_bool_t
hb_ot_math_is_glyph_extended_shape (hb_face_t *face,
hb_codepoint_t glyph);
HB_EXTERN hb_position_t
hb_ot_math_get_glyph_kerning (hb_font_t *font,
hb_codepoint_t glyph,
hb_ot_math_kern_t kern,
hb_position_t correction_height);
HB_EXTERN unsigned int
hb_ot_math_get_glyph_variants (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
unsigned int start_offset,
unsigned int *variants_count, /* IN/OUT */
hb_ot_math_glyph_variant_t *variants /* OUT */);
HB_EXTERN hb_position_t
hb_ot_math_get_min_connector_overlap (hb_font_t *font,
hb_direction_t direction);
HB_EXTERN unsigned int
hb_ot_math_get_glyph_assembly (hb_font_t *font,
hb_codepoint_t glyph,
hb_direction_t direction,
unsigned int start_offset,
unsigned int *parts_count, /* IN/OUT */
hb_ot_math_glyph_part_t *parts, /* OUT */
hb_position_t *italics_correction /* OUT */);
HB_END_DECLS
#endif /* HB_OT_MATH_H */

View file

@ -0,0 +1,72 @@
/*
* 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_MAXP_TABLE_HH
#define HB_OT_MAXP_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* maxp -- The Maximum Profile Table
*/
#define HB_OT_TAG_maxp HB_TAG('m','a','x','p')
struct maxp
{
static const hb_tag_t tableTag = HB_OT_TAG_maxp;
inline unsigned int get_num_glyphs (void) const
{
return numGlyphs;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
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. */
protected:
FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0),
* 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 */

View file

@ -0,0 +1,136 @@
/*
* 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_NAME_TABLE_HH
#define HB_OT_NAME_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* name -- The Naming Table
*/
#define HB_OT_TAG_name HB_TAG('n','a','m','e')
struct NameRecord
{
static int cmp (const NameRecord *a, const NameRecord *b)
{
int ret;
ret = b->platformID.cmp (a->platformID);
if (ret) return ret;
ret = b->encodingID.cmp (a->encodingID);
if (ret) return ret;
ret = b->languageID.cmp (a->languageID);
if (ret) return ret;
ret = b->nameID.cmp (a->nameID);
if (ret) return ret;
return 0;
}
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 (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
}
USHORT platformID; /* Platform ID. */
USHORT encodingID; /* Platform-specific encoding ID. */
USHORT languageID; /* Language ID. */
USHORT nameID; /* Name ID. */
USHORT length; /* String length (in bytes). */
USHORT offset; /* String offset from start of storage area (in bytes). */
public:
DEFINE_SIZE_STATIC (12);
};
struct name
{
static const hb_tag_t tableTag = HB_OT_TAG_name;
inline unsigned int get_name (unsigned int platform_id,
unsigned int encoding_id,
unsigned int language_id,
unsigned int name_id,
void *buffer,
unsigned int buffer_length) const
{
NameRecord key;
key.platformID.set (platform_id);
key.encodingID.set (encoding_id);
key.languageID.set (language_id);
key.nameID.set (name_id);
NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), (hb_compare_func_t) NameRecord::cmp);
if (!match)
return 0;
unsigned int length = MIN (buffer_length, (unsigned int) match->length);
memcpy (buffer, (char *) this + stringOffset + match->offset, length);
return length;
}
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++)
if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false);
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
likely (format == 0 || format == 1) &&
c->check_array (nameRecord, nameRecord[0].static_size, count) &&
sanitize_records (c));
}
/* We only implement format 0 for now. */
USHORT format; /* Format selector (=0/1). */
USHORT count; /* Number of name records. */
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 */

View file

@ -0,0 +1,105 @@
/*
* 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_OS2_TABLE_HH
#define HB_OT_OS2_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* OS/2 and Windows Metrics
* http://www.microsoft.com/typography/otspec/os2.htm
*/
#define HB_OT_TAG_os2 HB_TAG('O','S','/','2')
struct os2
{
static const hb_tag_t tableTag = HB_OT_TAG_os2;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
USHORT version;
/* Version 0 */
SHORT xAvgCharWidth;
USHORT usWeightClass;
USHORT usWidthClass;
USHORT fsType;
SHORT ySubscriptXSize;
SHORT ySubscriptYSize;
SHORT ySubscriptXOffset;
SHORT ySubscriptYOffset;
SHORT ySuperscriptXSize;
SHORT ySuperscriptYSize;
SHORT ySuperscriptXOffset;
SHORT ySuperscriptYOffset;
SHORT yStrikeoutSize;
SHORT yStrikeoutPosition;
SHORT sFamilyClass;
BYTE panose[10];
ULONG ulUnicodeRange[4];
Tag achVendID;
USHORT fsSelection;
USHORT usFirstCharIndex;
USHORT usLastCharIndex;
SHORT sTypoAscender;
SHORT sTypoDescender;
SHORT sTypoLineGap;
USHORT usWinAscent;
USHORT usWinDescent;
/* Version 1 */
//ULONG ulCodePageRange1;
//ULONG ulCodePageRange2;
/* Version 2 */
//SHORT sxHeight;
//SHORT sCapHeight;
//USHORT usDefaultChar;
//USHORT usBreakChar;
//USHORT usMaxContext;
/* Version 5 */
//USHORT usLowerOpticalPointSize;
//USHORT usUpperOpticalPointSize;
public:
DEFINE_SIZE_STATIC (78);
};
} /* namespace OT */
#endif /* HB_OT_OS2_TABLE_HH */

View file

@ -0,0 +1,119 @@
/*
* Copyright © 2016 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_POST_TABLE_HH
#define HB_OT_POST_TABLE_HH
#include "hb-open-type-private.hh"
namespace OT {
/*
* post -- PostScript
*/
#define HB_OT_TAG_post HB_TAG('p','o','s','t')
struct postV2Tail
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (numberOfGlyphs.sanitize (c) &&
c->check_array (glyphNameIndex, sizeof (USHORT), numberOfGlyphs));
}
USHORT numberOfGlyphs; /* Number of glyphs (this should be the
* same as numGlyphs in 'maxp' table). */
USHORT glyphNameIndex[VAR]; /* This is not an offset, but is the
* ordinal number of the glyph in 'post'
* string tables. */
BYTE namesX[VAR]; /* Glyph names with length bytes [variable]
* (a Pascal string). */
DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX);
};
struct post
{
static const hb_tag_t tableTag = HB_OT_TAG_post;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
if (version.to_int () == 0x00020000)
{
const postV2Tail &v2 = StructAfter<postV2Tail>(*this);
return_trace (v2.sanitize (c));
}
return_trace (true);
}
public:
FixedVersion<>version; /* 0x00010000 for version 1.0
* 0x00020000 for version 2.0
* 0x00025000 for version 2.5 (deprecated)
* 0x00030000 for version 3.0 */
Fixed italicAngle; /* Italic angle in counter-clockwise degrees
* from the vertical. Zero for upright text,
* negative for text that leans to the right
* (forward). */
FWORD underlinePosition; /* This is the suggested distance of the top
* of the underline from the baseline
* (negative values indicate below baseline).
* The PostScript definition of this FontInfo
* dictionary key (the y coordinate of the
* center of the stroke) is not used for
* historical reasons. The value of the
* PostScript key may be calculated by
* subtracting half the underlineThickness
* from the value of this field. */
FWORD underlineThickness; /* Suggested values for the underline
thickness. */
ULONG isFixedPitch; /* Set to 0 if the font is proportionally
* spaced, non-zero if the font is not
* proportionally spaced (i.e. monospaced). */
ULONG minMemType42; /* Minimum memory usage when an OpenType font
* is downloaded. */
ULONG maxMemType42; /* Maximum memory usage when an OpenType font
* is downloaded. */
ULONG minMemType1; /* Minimum memory usage when an OpenType font
* is downloaded as a Type 1 font. */
ULONG maxMemType1; /* Maximum memory usage when an OpenType font
* is downloaded as a Type 1 font. */
/*postV2Tail v2[VAR];*/
DEFINE_SIZE_STATIC (32);
};
} /* namespace OT */
#endif /* HB_OT_POST_TABLE_HH */

View file

@ -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 or something equally good!
* May not be good-enough for presidential candidate interviews, but good-enough for us... */
hb_stable_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_stable_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 */

View file

@ -0,0 +1,50 @@
/*
* Copyright © 2015 Mozilla Foundation.
* Copyright © 2015 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Mozilla Author(s): Jonathan Kew
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
#define HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH
#include "hb-private.hh"
#include "hb-ot-shape-complex-private.hh"
struct arabic_shape_plan_t;
HB_INTERNAL void *
data_create_arabic (const hb_ot_shape_plan_t *plan);
HB_INTERNAL void
data_destroy_arabic (void *data);
HB_INTERNAL void
setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
hb_buffer_t *buffer,
hb_script_t script);
#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_PRIVATE_HH */

View file

@ -0,0 +1,395 @@
/* == Start of generated table == */
/*
* The following table is generated by running:
*
* ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
*
* on files with these headers:
*
* # ArabicShaping-9.0.0.txt
* # Date: 2016-02-24, 22:25:00 GMT [RP]
* # Blocks-9.0.0.txt
* # Date: 2016-02-05, 23:48:00 GMT [KW]
* UnicodeData.txt does not have a header.
*/
#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH
#define X JOINING_TYPE_X
#define R JOINING_TYPE_R
#define T JOINING_TYPE_T
#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[] =
{
#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,D,D,X,D,D,D,R,D,D,D,D,X,X,
/* 08C0 */ 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,
/* 08E0 */ X,X,U,
#define joining_offset_0x1806u 739
/* 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,T,T,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 904
/* General Punctuation */
/* 2000 */ U,C,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 2020 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 2040 */ 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,
/* 2060 */ X,X,X,X,X,X,U,U,U,U,
#define joining_offset_0xa840u 998
/* 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 1050
/* 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 1098
/* 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,
#define joining_offset_0x1e900u 1146
/* Adlam */
/* 1E900 */ 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,
/* 1E920 */ 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,
/* 1E940 */ D,D,D,D,
}; /* Table items: 1214; occupancy: 54% */
static unsigned int
joining_type (hb_codepoint_t u)
{
switch (u >> 12)
{
case 0x0u:
if (hb_in_range (u, 0x0600u, 0x08E2u)) 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, 0x2069u)) return joining_table[u - 0x200Cu + joining_offset_0x200cu];
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;
case 0x1Eu:
if (hb_in_range (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u];
break;
default:
break;
}
return X;
}
#undef X
#undef R
#undef T
#undef U
#undef A
#undef DR
#undef L
#undef C
#undef D
static const uint16_t shaping_table[][4] =
{
{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 0x0621u
#define SHAPING_TABLE_LAST 0x06D3u
static const struct ligature_set_t {
uint16_t first;
struct ligature_pairs_t {
uint16_t second;
uint16_t ligature;
} ligatures[4];
} ligature_table[] =
{
{ 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 */
}},
{ 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 */
}},
};
#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */
/* == End of generated table == */

View file

@ -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_ZERO (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_ZERO (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 */

View file

@ -0,0 +1,624 @@
/*
* 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-arabic-private.hh"
#include "hb-ot-shape-private.hh"
#ifndef HB_DEBUG_ARABIC
#define HB_DEBUG_ARABIC (HB_DEBUG+0)
#endif
/* buffer var allocations */
#define arabic_shaping_action() complex_var_u8_0() /* arabic shaping action */
#define HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH HB_BUFFER_SCRATCH_FLAG_COMPLEX0
/* See:
* https://github.com/behdad/harfbuzz/commit/6e6f82b6f3dde0fc6c3c7d991d9ec6cfff57823d#commitcomment-14248516 */
#define HB_ARABIC_GENERAL_CATEGORY_IS_WORD(gen_cat) \
(FLAG_SAFE (gen_cat) & \
(FLAG (HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE) | \
/*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) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL)))
/*
* Joining types:
*/
/*
* Bits used in the joining tables
*/
enum hb_arabic_joining_type_t {
JOINING_TYPE_U = 0,
JOINING_TYPE_L = 1,
JOINING_TYPE_R = 2,
JOINING_TYPE_D = 3,
JOINING_TYPE_C = JOINING_TYPE_D,
JOINING_GROUP_ALAPH = 4,
JOINING_GROUP_DALATH_RISH = 5,
NUM_STATE_MACHINE_COLS = 6,
JOINING_TYPE_T = 7,
JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */
};
#include "hb-ot-shape-complex-arabic-table.hh"
static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat)
{
unsigned int j_type = joining_type(u);
if (likely (j_type != JOINING_TYPE_X))
return j_type;
return (FLAG_SAFE(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;
}
#define FEATURE_IS_SYRIAC(tag) hb_in_range<unsigned char> ((unsigned char) (tag), '2', '3')
static const hb_tag_t arabic_features[] =
{
HB_TAG('i','s','o','l'),
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 arabic_action_t {
ISOL,
FINA,
FIN2,
FIN3,
MEDI,
MED2,
INIT,
NONE,
ARABIC_NUM_FEATURES = NONE,
/* We abuse the same byte for other things... */
STCH_FIXED,
STCH_REPEATING,
};
static const struct arabic_state_table_entry {
uint8_t prev_action;
uint8_t curr_action;
uint16_t next_state;
} arabic_state_table[][NUM_STATE_MACHINE_COLS] =
{
/* 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,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,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,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 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}, {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}, {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,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);
static void
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
static void
record_stch (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)
{
hb_ot_map_builder_t *map = &plan->map;
/* We apply features according to the Arabic spec, with pauses
* in between most.
*
* The pause between init/medi/... and rlig is required. See eg:
* https://bugzilla.mozilla.org/show_bug.cgi?id=644184
*
* 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_gsub_pause (nuke_joiners);
map->add_global_bool_feature (HB_TAG('s','t','c','h'));
map->add_gsub_pause (record_stch);
map->add_global_bool_feature (HB_TAG('c','c','m','p'));
map->add_global_bool_feature (HB_TAG('l','o','c','l'));
map->add_gsub_pause (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);
}
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'));
/* 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_gsub_pause (NULL);
//map->add_global_bool_feature (HB_TAG('c','s','w','h'));
map->add_global_bool_feature (HB_TAG('m','s','e','t'));
}
#include "hb-ot-shape-complex-arabic-fallback.hh"
struct arabic_shape_plan_t
{
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];
arabic_fallback_plan_t *fallback_plan;
unsigned int do_fallback : 1;
unsigned int has_stch : 1;
};
void *
data_create_arabic (const hb_ot_shape_plan_t *plan)
{
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;
arabic_plan->has_stch = !!plan->map.get_1_mask (HB_TAG ('s','t','c','h'));
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]));
}
return arabic_plan;
}
void
data_destroy_arabic (void *data)
{
arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data;
arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
free (data);
}
static void
arabic_joining (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
unsigned int prev = (unsigned int) -1, state = 0;
/* 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 (info[i].codepoint, _hb_glyph_info_get_general_category (&info[i]));
if (unlikely (this_type == JOINING_TYPE_T)) {
info[i].arabic_shaping_action() = NONE;
continue;
}
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;
info[i].arabic_shaping_action() = entry->curr_action;
prev = i;
state = entry->next_state;
}
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;
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();
}
void
setup_masks_arabic_plan (const arabic_shape_plan_t *arabic_plan,
hb_buffer_t *buffer,
hb_script_t script)
{
HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action);
arabic_joining (buffer);
if (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()];
}
static void
setup_masks_arabic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font HB_UNUSED)
{
const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data;
setup_masks_arabic_plan (arabic_plan, buffer, plan->props.script);
}
static void
nuke_joiners (const hb_ot_shape_plan_t *plan HB_UNUSED,
hb_font_t *font HB_UNUSED,
hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (_hb_glyph_info_is_zwj (&info[i]))
_hb_glyph_info_flip_joiners (&info[i]);
}
static void
arabic_fallback_shape (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
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);
}
/*
* Stretch feature: "stch".
* See example here:
* https://www.microsoft.com/typography/OpenTypeDev/syriac/intro.htm
* We implement this in a generic way, such that the Arabic subtending
* marks can use it as well.
*/
static void
record_stch (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->has_stch)
return;
/* 'stch' feature was just applied. Look for anything that multiplied,
* and record it for stch treatment later. Note that rtlm, frac, etc
* are applied before stch, but we assume that they didn't result in
* anything multiplying into 5 pieces, so it's safe-ish... */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
if (unlikely (_hb_glyph_info_multiplied (&info[i])))
{
unsigned int comp = _hb_glyph_info_get_lig_comp (&info[i]);
info[i].arabic_shaping_action() = comp % 2 ? STCH_REPEATING : STCH_FIXED;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH;
}
}
static void
apply_stch (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_ARABIC_HAS_STCH)))
return;
/* The Arabic shaper currently always processes in RTL mode, so we should
* stretch / position the stretched pieces to the left / preceding glyphs. */
/* We do a two pass implementation:
* First pass calculates the exact number of extra glyphs we need,
* We then enlarge buffer to have that much room,
* Second pass applies the stretch, copying things to the end of buffer.
*/
int sign = font->x_scale < 0 ? -1 : +1;
unsigned int extra_glyphs_needed = 0; // Set during MEASURE, used during CUT
typedef enum { MEASURE, CUT } step_t;
for (step_t step = MEASURE; step <= CUT; step = (step_t) (step + 1))
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
unsigned int new_len = count + extra_glyphs_needed; // write head during CUT
unsigned int j = new_len;
for (unsigned int i = count; i; i--)
{
if (!hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
{
if (step == CUT)
{
--j;
info[j] = info[i - 1];
pos[j] = pos[i - 1];
}
continue;
}
/* Yay, justification! */
hb_position_t w_total = 0; // Total to be filled
hb_position_t w_fixed = 0; // Sum of fixed tiles
hb_position_t w_repeating = 0; // Sum of repeating tiles
int n_fixed = 0;
int n_repeating = 0;
unsigned int end = i;
while (i &&
hb_in_range<unsigned> (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING))
{
i--;
hb_position_t width = font->get_glyph_h_advance (info[i].codepoint);
if (info[i].arabic_shaping_action() == STCH_FIXED)
{
w_fixed += width;
n_fixed++;
}
else
{
w_repeating += width;
n_repeating++;
}
}
unsigned int start = i;
unsigned int context = i;
while (context &&
!hb_in_range<unsigned> (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) &&
(_hb_glyph_info_is_default_ignorable (&info[context - 1]) ||
HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1]))))
{
context--;
w_total += pos[context].x_advance;
}
i++; // Don't touch i again.
DEBUG_MSG (ARABIC, NULL, "%s stretch at (%d,%d,%d)",
step == MEASURE ? "measuring" : "cutting", context, start, end);
DEBUG_MSG (ARABIC, NULL, "rest of word: count=%d width %d", start - context, w_total);
DEBUG_MSG (ARABIC, NULL, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
DEBUG_MSG (ARABIC, NULL, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
/* Number of additional times to repeat each repeating tile. */
int n_copies = 0;
hb_position_t w_remaining = w_total - w_fixed;
if (sign * w_remaining > sign * w_repeating && sign * w_repeating > 0)
n_copies = (sign * w_remaining) / (sign * w_repeating) - 1;
/* See if we can improve the fit by adding an extra repeat and squeezing them together a bit. */
hb_position_t extra_repeat_overlap = 0;
hb_position_t shortfall = sign * w_remaining - sign * w_repeating * (n_copies + 1);
if (shortfall > 0)
{
++n_copies;
hb_position_t excess = (n_copies + 1) * sign * w_repeating - sign * w_remaining;
if (excess > 0)
extra_repeat_overlap = excess / (n_copies * n_repeating);
}
if (step == MEASURE)
{
extra_glyphs_needed += n_copies * n_repeating;
DEBUG_MSG (ARABIC, NULL, "will add extra %d copies of repeating tiles", n_copies);
}
else
{
hb_position_t x_offset = 0;
for (unsigned int k = end; k > start; k--)
{
hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
unsigned int repeat = 1;
if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
repeat += n_copies;
DEBUG_MSG (ARABIC, NULL, "appending %d copies of glyph %d; j=%d",
repeat, info[k - 1].codepoint, j);
for (unsigned int n = 0; n < repeat; n++)
{
x_offset -= width;
if (n > 0)
x_offset += extra_repeat_overlap;
pos[k - 1].x_offset = x_offset;
/* Append copy. */
--j;
info[j] = info[k - 1];
pos[j] = pos[k - 1];
}
}
}
}
if (step == MEASURE)
{
if (unlikely (!buffer->ensure (count + extra_glyphs_needed)))
break;
}
else
{
assert (j == 0);
buffer->len = new_len;
}
}
}
static void
postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
apply_stch (plan, buffer, font);
HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action);
}
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 */
postprocess_glyphs_arabic,
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_arabic,
NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};

View file

@ -0,0 +1,46 @@
/*
* 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"
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 */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};

View file

@ -0,0 +1,425 @@
/*
* 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 && !buffer->in_error;)
{
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))
{
buffer->merge_out_clusters (start, end + 1);
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;
}
}
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;
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
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;
if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
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_destroy_hangul,
preprocess_text_hangul,
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
NULL, /* decompose */
NULL, /* compose */
setup_masks_hangul,
NULL, /* disable_otl */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};

View file

@ -0,0 +1,186 @@
/*
* 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 = (bool) 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;
}
static bool
disable_otl_hebrew (const hb_ot_shape_plan_t *plan)
{
/* For Hebrew shaper, use fallback if GPOS does not have 'hebr'
* script. This matches Uniscribe better, and makes fonts like
* Arial that have GSUB/GPOS/GDEF but no data for Hebrew work.
* See:
* https://github.com/behdad/harfbuzz/issues/347#issuecomment-267838368
*/
return plan->map.chosen_script[1] != HB_TAG ('h','e','b','r');
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
{
"hebrew",
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
NULL, /* postprocess_glyphs */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
compose_hebrew,
NULL, /* setup_masks */
disable_otl_hebrew,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,129 @@
/*
* 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"
%%{
machine indic_syllable_machine;
alphtype unsigned char;
write data;
}%%
%%{
# Same order as enum indic_category_t. Not sure how to avoid duplication.
X = 0;
C = 1;
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;
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?;
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 => { 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 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].indic_category();
}%%
p = 0;
pe = eof = buffer->len;
unsigned int last = 0;
unsigned int syllable_serial = 1;
%%{
write exec;
}%%
}
#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */

View file

@ -0,0 +1,189 @@
/*
* Copyright © 2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH
#define HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH
#include "hb-private.hh"
#include "hb-ot-shape-complex-private.hh"
#include "hb-ot-shape-private.hh" /* XXX Remove */
#define INDIC_TABLE_ELEMENT_TYPE uint16_t
/* Cateories used in the OpenType spec:
* https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx
*/
/* Note: This enum is duplicated in the -machine.rl source file.
* Not sure how to avoid duplication. */
enum indic_category_t {
OT_X = 0,
OT_C = 1,
OT_V = 2,
OT_N = 3,
OT_H = 4,
OT_ZWNJ = 5,
OT_ZWJ = 6,
OT_M = 7,
OT_SM = 8,
OT_VD = 9,
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). */
};
#define MEDIAL_FLAGS (FLAG (OT_CM))
/* Note:
*
* We treat Vowels and placeholders as if they were consonants. This is safe because Vowels
* cannot happen in a consonant syllable. The plus side however is, we can call the
* consonant syllable logic from the vowel syllable function and get it all right! */
#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_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_AFTER_SUB,
POS_BEFORE_POST,
POS_POST_C,
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_Symbol,
INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM,
INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER = OT_PLACEHOLDER, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK = OT_A,
INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C,
INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER = OT_M, /* U+17CD only. */
INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_PLACEHOLDER,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA = OT_Repha,
INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED = OT_X, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_CM,
INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA = OT_N,
INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER = OT_Repha, /* TODO */
INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK = OT_SM,
INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER = OT_Coeng,
INDIC_SYLLABIC_CATEGORY_JOINER = OT_ZWJ,
INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_NON_JOINER = OT_ZWNJ,
INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N,
INDIC_SYLLABIC_CATEGORY_NUMBER = OT_PLACEHOLDER,
INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER = OT_PLACEHOLDER, /* Don't care. */
INDIC_SYLLABIC_CATEGORY_PURE_KILLER = OT_M, /* Is like a vowel matra. */
INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS,
INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER = OT_M, /* Misc Khmer signs. */
INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X,
INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N,
INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H,
INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM,
INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V,
INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M,
INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V
};
/* Categories used in IndicSMatraCategory.txt from UCD */
enum indic_matra_category_t {
INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_END,
INDIC_MATRA_CATEGORY_LEFT = POS_PRE_C,
INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_C,
INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_C,
INDIC_MATRA_CATEGORY_RIGHT = POS_POST_C,
/* These should resolve to the position of the last part of the split sequence. */
INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM,
INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_TOP,
INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT,
INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN,
INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M
};
#define INDIC_COMBINE_CATEGORIES(S,M) \
( \
ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \
( S | \
( \
( \
S == INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL || \
S == INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK || \
S == INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER || \
S == INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA || \
S == INDIC_SYLLABIC_CATEGORY_VIRAMA || \
S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT || \
false \
? M : INDIC_MATRA_CATEGORY_NOT_APPLICABLE \
) << 8 \
) \
) \
)
HB_INTERNAL INDIC_TABLE_ELEMENT_TYPE
hb_indic_get_categories (hb_codepoint_t u);
#endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */

View file

@ -0,0 +1,484 @@
/* == Start of generated table == */
/*
* The following table is generated by running:
*
* ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
*
* on files with these headers:
*
* # IndicSyllabicCategory-9.0.0.txt
* # Date: 2016-05-21, 02:46:00 GMT [RP]
* # IndicPositionalCategory-9.0.0.txt
* # Date: 2016-02-25, 00:48:00 GMT [RP]
* # Blocks-9.0.0.txt
* # Date: 2016-02-05, 23:48:00 GMT [KW]
*/
#include "hb-ot-shape-complex-indic-private.hh"
#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 15 chars; Avagraha */
#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 67 chars; Bindu */
#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */
#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 53 chars; Cantillation_Mark */
#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 1907 chars; Consonant */
#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 10 chars; Consonant_Dead */
#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 62 chars; Consonant_Final */
#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */
#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */
#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 22 chars; Consonant_Medial */
#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 16 chars; Consonant_Placeholder */
#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 1 chars; Consonant_Preceding_Repha */
#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 2 chars; Consonant_Prefixed */
#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 90 chars; Consonant_Subjoined */
#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */
#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 4 chars; Consonant_With_Stacker */
#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_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */
#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 24 chars; Nukta */
#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 459 chars; Number */
#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */
#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 16 chars; Pure_Killer */
#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */
#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 22 chars; Syllable_Modifier */
#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */
#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */
#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 24 chars; Virama */
#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 31 chars; Visarga */
#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */
#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 602 chars; Vowel_Dependent */
#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 431 chars; Vowel_Independent */
#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 300 chars; Bottom */
#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_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 /* 10 chars; Overstruck */
#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 258 chars; Right */
#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 342 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 /* 6 chars; Top_And_Left */
#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */
#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */
#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */
#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)
static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {
#define indic_offset_0x0028u 0
/* Basic Latin */
/* 0028 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x), _(x,x), _(x,x),
/* 0030 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0038 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x00b0u 24
/* Latin-1 Supplement */
/* 00B0 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 00B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 00C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 00C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 00D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CP,x),
#define indic_offset_0x0900u 64
/* Devanagari */
/* 0900 */ _(Bi,T), _(Bi,T), _(Bi,T), _(Vs,R), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,B), _(A,x), _(M,R), _(M,L),
/* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T),
/* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R),
/* 0950 */ _(x,x), _(Ca,T), _(Ca,B), _(x,T), _(x,T), _(M,T), _(M,B), _(M,B),
/* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0968 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0970 */ _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0978 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* Bengali */
/* 0980 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
/* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
/* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
/* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
/* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x),
/* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 09D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x),
/* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 09E8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 09F0 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 09F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Gurmukhi */
/* 0A00 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
/* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x),
/* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(x,x), _(M,R), _(M,L),
/* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T),
/* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x),
/* 0A50 */ _(x,x), _(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), _(Nd,x), _(Nd,x),
/* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0A70 */ _(Bi,T), _(GM,T), _(CP,x), _(CP,x), _(x,x), _(CM,B), _(x,x), _(x,x),
/* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Gujarati */
/* 0A80 */ _(x,x), _(Bi,T), _(Bi,T), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x),
/* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,L),
/* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T),
/* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x),
/* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0AE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0AF8 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Oriya */
/* 0B00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x),
/* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
/* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L),
/* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x),
/* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(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), _(Nd,x), _(Nd,x),
/* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0B70 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Tamil */
/* 0B80 */ _(x,x), _(x,x), _(Bi,T), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x),
/* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x),
/* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x),
/* 0BA0 */ _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x),
/* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x),
/* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R),
/* 0BC0 */ _(M,T), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L),
/* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x),
/* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0BE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0BF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Telugu */
/* 0C00 */ _(Bi,T), _(Bi,R), _(Bi,R), _(Vs,R), _(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), _(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), _(C,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 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x),
/* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x),
/* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x),
/* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T),
/* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR),
/* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
/* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x),
/* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0CF0 */ _(x,x),_(CWS,x),_(CWS,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* Malayalam */
/* 0D00 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(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),
/* 0D20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0D38 */ _(C,x), _(C,x), _(C,x), _(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),_(CPR,x), _(x,x),
/* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(M,R),
/* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x),
/* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0D68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0D78 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x),
/* Sinhala */
/* 0D80 */ _(x,x), _(x,x), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x),
/* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DB0 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0DB8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x),
/* 0DC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
/* 0DC8 */ _(x,x), _(x,x), _(V,T), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R),
/* 0DD0 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(x,x), _(M,B), _(x,x),
/* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR),_(M,TLR), _(M,LR), _(M,R),
/* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0DE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x1000u 1336
/* Myanmar */
/* 1000 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1008 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1010 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B),
/* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,T), _(TM,B),
/* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B), _(C,x),
/* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(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,B), _(CM,B),
/* 1060 */ _(CM,B), _(C,x), _(M,R), _(TM,R), _(TM,R), _(C,x), _(C,x), _(M,R),
/* 1068 */ _(M,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(C,x), _(C,x),
/* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x),
/* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1080 */ _(C,x), _(C,x), _(CM,B), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,R),
/* 1088 */ _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,R), _(TM,B), _(C,x), _(TM,R),
/* 1090 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 1098 */ _(Nd,x), _(Nd,x), _(TM,R), _(TM,R), _(M,R), _(M,T), _(x,x), _(x,x),
#define indic_offset_0x1780u 1496
/* Khmer */
/* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1788 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1790 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 1798 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 17A0 */ _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x),
/* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T),
/* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR),
/* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,T), _(Vs,R),
/* 17C8 */ _(M,R), _(RS,T), _(RS,T), _(SM,T),_(CSR,T), _(CK,T), _(SM,T), _(SM,T),
/* 17D0 */ _(SM,T), _(PK,T), _(IS,x), _(SM,T), _(x,x), _(x,x), _(x,x), _(x,x),
/* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(SM,T), _(x,x), _(x,x),
/* 17E0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 17E8 */ _(Nd,x), _(Nd,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x1cd0u 1608
/* Vedic Extensions */
/* 1CD0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(x,x), _(Ca,O), _(Ca,B), _(Ca,B), _(Ca,B),
/* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B),
/* 1CE0 */ _(Ca,T), _(Ca,R), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O),
/* 1CE8 */ _(x,O), _(x,x), _(x,x), _(x,x), _(x,x), _(x,B), _(x,x), _(x,x),
/* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(Ca,T), _(x,x), _(x,x), _(x,x),
/* 1CF8 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x2008u 1656
/* General Punctuation */
/* 2008 */ _(x,x), _(x,x), _(x,x), _(x,x),_(ZWNJ,x),_(ZWJ,x), _(x,x), _(x,x),
/* 2010 */ _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(CP,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0x2070u 1672
/* Superscripts and Subscripts */
/* 2070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(SM,x), _(x,x), _(x,x), _(x,x),
/* 2078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 2080 */ _(x,x), _(x,x), _(SM,x), _(SM,x), _(SM,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0xa8e0u 1696
/* Devanagari Extended */
/* A8E0 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
/* A8E8 */ _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T), _(Ca,T),
/* A8F0 */ _(Ca,T), _(Ca,T), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
#define indic_offset_0xa9e0u 1720
/* Myanmar Extended-B */
/* A9E0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), _(x,x), _(C,x),
/* A9E8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* A9F0 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* A9F8 */ _(Nd,x), _(Nd,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x),
#define indic_offset_0xaa60u 1752
/* Myanmar Extended-A */
/* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(CP,x), _(CP,x), _(CP,x), _(x,x),
/* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,R), _(TM,T), _(TM,R), _(C,x), _(C,x),
}; /* Table items: 1784; occupancy: 69% */
INDIC_TABLE_ELEMENT_TYPE
hb_indic_get_categories (hb_codepoint_t u)
{
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, 0x00B0u, 0x00D7u)) return indic_table[u - 0x00B0u + indic_offset_0x00b0u];
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, 0x1780u, 0x17EFu)) return indic_table[u - 0x1780u + indic_offset_0x1780u];
if (hb_in_range (u, 0x1CD0u, 0x1CFFu)) 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 (hb_in_range (u, 0x2070u, 0x2087u)) return indic_table[u - 0x2070u + indic_offset_0x2070u];
if (unlikely (u == 0x25CCu)) return _(CP,x);
break;
case 0xAu:
if (hb_in_range (u, 0xA8E0u, 0xA8F7u)) return indic_table[u - 0xA8E0u + indic_offset_0xa8e0u];
if (hb_in_range (u, 0xA9E0u, 0xA9FFu)) return indic_table[u - 0xA9E0u + indic_offset_0xa9e0u];
if (hb_in_range (u, 0xAA60u, 0xAA7Fu)) return indic_table[u - 0xAA60u + indic_offset_0xaa60u];
break;
default:
break;
}
return _(x,x);
}
#undef _
#undef ISC_A
#undef ISC_Bi
#undef ISC_BJN
#undef ISC_Ca
#undef ISC_C
#undef ISC_CD
#undef ISC_CF
#undef ISC_CHL
#undef ISC_CK
#undef ISC_CM
#undef ISC_CP
#undef ISC_CPR
#undef ISC_CPrf
#undef ISC_CS
#undef ISC_CSR
#undef ISC_CWS
#undef ISC_GM
#undef ISC_IS
#undef ISC_ZWJ
#undef ISC_ML
#undef ISC_ZWNJ
#undef ISC_N
#undef ISC_Nd
#undef ISC_NJ
#undef ISC_x
#undef ISC_PK
#undef ISC_RS
#undef ISC_SM
#undef ISC_TL
#undef ISC_TM
#undef ISC_V
#undef ISC_Vs
#undef ISC_Vo
#undef ISC_M
#undef ISC_VI
#undef IMC_B
#undef IMC_BR
#undef IMC_L
#undef IMC_LR
#undef IMC_x
#undef IMC_O
#undef IMC_R
#undef IMC_T
#undef IMC_TB
#undef IMC_TBR
#undef IMC_TL
#undef IMC_TLR
#undef IMC_TR
#undef IMC_VOL
/* == End of generated table == */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,400 @@
#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
/*
* Copyright © 2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH
#include "hb-private.hh"
#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 31u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 5u, 29u, 5u, 8u,
5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
3u, 30u, 3u, 29u, 1u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u,
3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 8u, 8u, 0
};
static const char _myanmar_syllable_machine_key_spans[] = {
31, 28, 25, 4, 25, 23, 21, 21,
27, 27, 27, 27, 16, 27, 27, 27,
27, 27, 27, 27, 27, 27, 25, 4,
25, 23, 21, 21, 27, 27, 27, 27,
28, 27, 30, 27, 27, 27, 27, 27,
27, 27, 27, 27, 1
};
static const short _myanmar_syllable_machine_index_offsets[] = {
0, 32, 61, 87, 92, 118, 142, 164,
186, 214, 242, 270, 298, 315, 343, 371,
399, 427, 455, 483, 511, 539, 567, 593,
598, 624, 648, 670, 692, 720, 748, 776,
804, 833, 861, 892, 920, 948, 976, 1004,
1032, 1060, 1088, 1116, 1144
};
static const char _myanmar_syllable_machine_indicies[] = {
1, 1, 2, 3, 4, 4, 0, 5,
0, 6, 1, 0, 0, 0, 0, 7,
0, 8, 1, 0, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 0,
21, 22, 23, 23, 20, 24, 20, 25,
20, 20, 20, 20, 20, 20, 20, 26,
20, 20, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 20, 23, 23, 20,
24, 20, 20, 20, 20, 20, 20, 20,
20, 20, 37, 20, 20, 20, 20, 20,
20, 31, 20, 20, 20, 35, 20, 23,
23, 20, 24, 20, 23, 23, 20, 24,
20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20,
31, 20, 20, 20, 35, 20, 38, 20,
23, 23, 20, 24, 20, 31, 20, 20,
20, 20, 20, 20, 20, 39, 20, 20,
20, 20, 20, 20, 31, 20, 23, 23,
20, 24, 20, 20, 20, 20, 20, 20,
20, 20, 20, 39, 20, 20, 20, 20,
20, 20, 31, 20, 23, 23, 20, 24,
20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20,
31, 20, 21, 20, 23, 23, 20, 24,
20, 25, 20, 20, 20, 20, 20, 20,
20, 40, 20, 20, 40, 20, 20, 20,
31, 41, 20, 20, 35, 20, 21, 20,
23, 23, 20, 24, 20, 25, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 31, 20, 20, 20,
35, 20, 21, 20, 23, 23, 20, 24,
20, 25, 20, 20, 20, 20, 20, 20,
20, 40, 20, 20, 20, 20, 20, 20,
31, 41, 20, 20, 35, 20, 21, 20,
23, 23, 20, 24, 20, 25, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 31, 41, 20, 20,
35, 20, 1, 1, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 1, 20, 21, 20, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20,
20, 20, 26, 20, 20, 27, 28, 29,
30, 31, 32, 33, 34, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 34, 20,
20, 20, 20, 20, 20, 31, 32, 33,
34, 35, 20, 21, 20, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 31, 32, 33, 34, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 31, 32, 33,
20, 35, 20, 21, 20, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20,
20, 31, 20, 33, 20, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 34, 20,
20, 27, 20, 29, 20, 31, 32, 33,
34, 35, 20, 21, 20, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20,
20, 20, 34, 20, 20, 27, 20, 20,
20, 31, 32, 33, 34, 35, 20, 21,
20, 23, 23, 20, 24, 20, 25, 20,
20, 20, 20, 20, 20, 20, 34, 20,
20, 27, 28, 29, 20, 31, 32, 33,
34, 35, 20, 21, 22, 23, 23, 20,
24, 20, 25, 20, 20, 20, 20, 20,
20, 20, 26, 20, 20, 27, 28, 29,
30, 31, 32, 33, 34, 35, 20, 3,
3, 42, 5, 42, 42, 42, 42, 42,
42, 42, 42, 42, 43, 42, 42, 42,
42, 42, 42, 13, 42, 42, 42, 17,
42, 3, 3, 42, 5, 42, 3, 3,
42, 5, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 13, 42, 42, 42, 17, 42,
44, 42, 3, 3, 42, 5, 42, 13,
42, 42, 42, 42, 42, 42, 42, 45,
42, 42, 42, 42, 42, 42, 13, 42,
3, 3, 42, 5, 42, 42, 42, 42,
42, 42, 42, 42, 42, 45, 42, 42,
42, 42, 42, 42, 13, 42, 3, 3,
42, 5, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 13, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 46, 42, 42, 46, 42,
42, 42, 13, 47, 42, 42, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 13, 42,
42, 42, 17, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 46, 42, 42, 42, 42,
42, 42, 13, 47, 42, 42, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 13, 47,
42, 42, 17, 42, 21, 22, 23, 23,
20, 24, 20, 25, 20, 20, 20, 20,
20, 20, 20, 48, 20, 20, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36,
20, 21, 49, 23, 23, 20, 24, 20,
25, 20, 20, 20, 20, 20, 20, 20,
26, 20, 20, 27, 28, 29, 30, 31,
32, 33, 34, 35, 20, 1, 1, 2,
3, 3, 3, 42, 5, 42, 6, 1,
42, 42, 42, 42, 1, 42, 8, 1,
42, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 8, 42, 42, 9, 10,
11, 12, 13, 14, 15, 16, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 16,
42, 42, 42, 42, 42, 42, 13, 14,
15, 16, 17, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 13, 14, 15, 16, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 13, 14,
15, 42, 17, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 42, 42, 42, 42, 42,
42, 42, 13, 42, 15, 42, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 16,
42, 42, 9, 42, 11, 42, 13, 14,
15, 16, 17, 42, 2, 42, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 16, 42, 42, 9, 42,
42, 42, 13, 14, 15, 16, 17, 42,
2, 42, 3, 3, 42, 5, 42, 6,
42, 42, 42, 42, 42, 42, 42, 16,
42, 42, 9, 10, 11, 42, 13, 14,
15, 16, 17, 42, 2, 3, 3, 3,
42, 5, 42, 6, 42, 42, 42, 42,
42, 42, 42, 8, 42, 42, 9, 10,
11, 12, 13, 14, 15, 16, 17, 42,
51, 50, 0
};
static const char _myanmar_syllable_machine_trans_targs[] = {
0, 1, 22, 0, 0, 23, 29, 32,
35, 36, 40, 41, 42, 25, 38, 39,
37, 28, 43, 44, 0, 2, 12, 0,
3, 9, 13, 14, 18, 19, 20, 5,
16, 17, 15, 8, 21, 4, 6, 7,
10, 11, 0, 24, 26, 27, 30, 31,
33, 34, 0, 0
};
static const char _myanmar_syllable_machine_trans_actions[] = {
3, 0, 0, 4, 5, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 6, 0, 0, 7,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 8, 0, 0, 0, 0, 0,
0, 0, 9, 10
};
static const char _myanmar_syllable_machine_to_state_actions[] = {
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0
};
static const char _myanmar_syllable_machine_from_state_actions[] = {
2, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0
};
static const short _myanmar_syllable_machine_eof_trans[] = {
0, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 43, 43,
43, 43, 43, 43, 43, 43, 43, 43,
21, 21, 43, 43, 43, 43, 43, 43,
43, 43, 43, 43, 51
};
static const int myanmar_syllable_machine_start = 0;
static const int myanmar_syllable_machine_first_final = 0;
static const int myanmar_syllable_machine_error = -1;
static const int myanmar_syllable_machine_en_main = 0;
#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
#define found_syllable(syllable_type) \
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \
for (unsigned int i = last; i < p+1; i++) \
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;
#line 289 "hb-ot-shape-complex-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
te = 0;
act = 0;
}
#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
p = 0;
pe = eof = buffer->len;
unsigned int last = 0;
unsigned int syllable_serial = 1;
#line 306 "hb-ot-shape-complex-myanmar-machine.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
_resume:
switch ( _myanmar_syllable_machine_from_state_actions[cs] ) {
case 2:
#line 1 "NONE"
{ts = p;}
break;
#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
_inds = _myanmar_syllable_machine_indicies + _myanmar_syllable_machine_index_offsets[cs];
_slen = _myanmar_syllable_machine_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].myanmar_category()) &&
( info[p].myanmar_category()) <= _keys[1] ?
( info[p].myanmar_category()) - _keys[0] : _slen ];
_eof_trans:
cs = _myanmar_syllable_machine_trans_targs[_trans];
if ( _myanmar_syllable_machine_trans_actions[_trans] == 0 )
goto _again;
switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
case 7:
#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (consonant_syllable); }}
break;
case 5:
#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (non_myanmar_cluster); }}
break;
case 10:
#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (punctuation_cluster); }}
break;
case 4:
#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (broken_cluster); }}
break;
case 3:
#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (non_myanmar_cluster); }}
break;
case 6:
#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p;p--;{ found_syllable (consonant_syllable); }}
break;
case 8:
#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
case 9:
#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
break;
#line 370 "hb-ot-shape-complex-myanmar-machine.hh"
}
_again:
switch ( _myanmar_syllable_machine_to_state_actions[cs] ) {
case 1:
#line 1 "NONE"
{ts = 0;}
break;
#line 379 "hb-ot-shape-complex-myanmar-machine.hh"
}
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
if ( _myanmar_syllable_machine_eof_trans[cs] > 0 ) {
_trans = _myanmar_syllable_machine_eof_trans[cs] - 1;
goto _eof_trans;
}
}
}
#line 123 "hb-ot-shape-complex-myanmar-machine.rl"
}
#undef found_syllable
#endif /* HB_OT_SHAPE_COMPLEX_MYANMAR_MACHINE_HH */

View file

@ -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 */

Some files were not shown because too many files have changed in this diff Show more