new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/COPYING
@@ -0,0 +1,17 @@
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in
+all copies of this software.
+
+IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
+
+THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/Makefile.am
@@ -0,0 +1,45 @@
+SUBDIRS = src
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = harfbuzz.pc
+
+EXTRA_DIST = \
+ autogen.sh
+
+MAINTAINERCLEANFILES = \
+ $(srcdir)/INSTALL \
+ $(srcdir)/aclocal.m4 \
+ $(srcdir)/autoscan.log \
+ $(srcdir)/compile \
+ $(srcdir)/config.guess \
+ $(srcdir)/config.h.in \
+ $(srcdir)/config.sub \
+ $(srcdir)/configure.scan \
+ $(srcdir)/depcomp \
+ $(srcdir)/install-sh \
+ $(srcdir)/ltmain.sh \
+ $(srcdir)/missing \
+ $(srcdir)/mkinstalldirs \
+ $(srcdir)/ChangeLog \
+ `find "$(srcdir)" -type f -name Makefile.in -print`
+
+CHANGELOG_RANGE =
+
+ChangeLog: $(srcdir)/ChangeLog
+$(srcdir)/ChangeLog:
+ $(AM_V_GEN) if test -d "$(srcdir)/.git"; then \
+ (GIT_DIR=$(top_srcdir)/.git ./missing --run \
+ git log $(CHANGELOG_RANGE) --stat) | fmt --split-only > $@.tmp \
+ && mv -f $@.tmp $@ \
+ || ($(RM) $@.tmp; \
+ echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
+ (test -f $@ || echo git-log is required to generate this file >> $@)); \
+ else \
+ test -f $@ || \
+ (echo A git checkout and git-log is required to generate ChangeLog >&2 && \
+ echo A git checkout and git-log is required to generate this file >> $@); \
+ fi
+.PHONY: $(srcdir)/ChangeLog
+
+
+-include $(top_srcdir)/git.mk
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/README
@@ -0,0 +1,9 @@
+This is HarfBuzz, an OpenType Layout engine.
+
+Bug reports on these files should be sent to the HarfBuzz mailing list as
+listed on http://freedesktop.org/wiki/Software/harfbuzz
+
+For license information, see the file COPYING.
+
+Behdad Esfahbod
+May 24, 2009
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/TODO
@@ -0,0 +1,12 @@
+
+- kern/GPOS interaction
+
+- Use size_t in sanitize?
+- Buffer error handling?
+- Better define HB_INTERNAL
+- Future-proof metrics struct
+
+hb-ot:
+- Rename hb_internal_glyph_info_t to hb_ot_glyph_info_t
+- Add query API for aalt-like features
+- HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH vs LookupType::... mess
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/autogen.sh
@@ -0,0 +1,188 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+set -e
+
+ARGV0=$0
+
+# Allow invocation from a separate build directory; in that case, we change
+# to the source directory to run the auto*, then change back before running configure
+srcdir=`dirname $ARGV0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+PACKAGE=harfbuzz
+
+LIBTOOLIZE_FLAGS="--copy --force --automake"
+ACLOCAL_FLAGS=""
+AUTOHEADER=${AUTOHEADER-autoheader}
+GTKDOCIZE_FLAGS="--copy"
+GTKDOCIZE=${GTKDOCIZE-gtkdocize}
+AUTOMAKE_FLAGS="--add-missing --gnu -Wall"
+AUTOCONF=${AUTOCONF-autoconf}
+
+CONFIGURE_AC=
+test -f configure.ac && CONFIGURE_AC=configure.ac
+
+if test "X$CONFIGURE_AC" = X; then
+ echo "$ARGV0: ERROR: No $srcdir/configure.in or $srcdir/configure.ac found."
+ exit 1
+fi
+
+extract_version() {
+ grep "^ *$1" "$CONFIGURE_AC" | sed 's/.*(\[*\([^])]*\)]*).*/\1/'
+}
+
+autoconf_min_vers=`extract_version AC_PREREQ`
+automake_min_vers=`extract_version AM_INIT_AUTOMAKE`
+libtoolize_min_vers=`extract_version AC_PROG_LIBTOOL`
+aclocal_min_vers=$automake_min_vers
+
+
+# Not all echo versions allow -n, so we check what is possible. This test is
+# based on the one in autoconf.
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ;;
+ *c*,* ) ECHO_N=-n ;;
+ *) ECHO_N= ;;
+esac
+
+
+# some terminal codes ...
+boldface="`tput bold 2>/dev/null || true`"
+normal="`tput sgr0 2>/dev/null || true`"
+printbold() {
+ echo $ECHO_N "$boldface"
+ echo "$@"
+ echo $ECHO_N "$normal"
+}
+printerr() {
+ echo "$@" >&2
+}
+
+
+# Usage:
+# compare_versions MIN_VERSION ACTUAL_VERSION
+# returns true if ACTUAL_VERSION >= MIN_VERSION
+compare_versions() {
+ ch_min_version=$1
+ ch_actual_version=$2
+ ch_status=0
+ IFS="${IFS= }"; ch_save_IFS="$IFS"; IFS="."
+ set $ch_actual_version
+ for ch_min in $ch_min_version; do
+ ch_cur=`echo $1 | sed 's/[^0-9].*$//'`; shift # remove letter suffixes
+ if [ -z "$ch_min" ]; then break; fi
+ if [ -z "$ch_cur" ]; then ch_status=1; break; fi
+ if [ $ch_cur -gt $ch_min ]; then break; fi
+ if [ $ch_cur -lt $ch_min ]; then ch_status=1; break; fi
+ done
+ IFS="$ch_save_IFS"
+ return $ch_status
+}
+
+# Usage:
+# version_check PACKAGE VARIABLE CHECKPROGS MIN_VERSION SOURCE
+# checks to see if the package is available
+version_check() {
+ vc_package=$1
+ vc_variable=$2
+ vc_checkprogs=$3
+ vc_min_version=$4
+ vc_source=$5
+ vc_status=1
+
+ vc_checkprog=`eval echo "\\$$vc_variable"`
+ if [ -n "$vc_checkprog" ]; then
+ printbold "using $vc_checkprog for $vc_package"
+ return 0
+ fi
+
+ printbold "checking for $vc_package >= $vc_min_version..."
+ for vc_checkprog in $vc_checkprogs; do
+ echo $ECHO_N " testing $vc_checkprog... "
+ if $vc_checkprog --version < /dev/null > /dev/null 2>&1; then
+ vc_actual_version=`$vc_checkprog --version | head -n 1 | \
+ sed 's/^.*[ ]\([0-9.]*[a-z]*\).*$/\1/'`
+ if compare_versions $vc_min_version $vc_actual_version; then
+ echo "found $vc_actual_version"
+ # set variable
+ eval "$vc_variable=$vc_checkprog"
+ vc_status=0
+ break
+ else
+ echo "too old (found version $vc_actual_version)"
+ fi
+ else
+ echo "not found."
+ fi
+ done
+ if [ "$vc_status" != 0 ]; then
+ printerr "***Error***: You must have $vc_package >= $vc_min_version installed"
+ printerr " to build $PROJECT. Download the appropriate package for"
+ printerr " from your distribution or get the source tarball at"
+ printerr " $vc_source"
+ printerr
+ fi
+ return $vc_status
+}
+
+
+version_check autoconf AUTOCONF $AUTOCONF $autoconf_min_vers \
+ "http://ftp.gnu.org/pub/gnu/autoconf/autoconf-${autoconf_min_vers}.tar.gz" || DIE=1
+
+#
+# Hunt for an appropriate version of automake and aclocal; we can't
+# assume that 'automake' is necessarily the most recent installed version
+#
+# We check automake first to allow it to be a newer version than we know about.
+#
+version_check automake AUTOMAKE "$AUTOMAKE automake automake-1.10 automake-1.9 automake-1.8 automake-1.7" $automake_min_vers \
+ "http://ftp.gnu.org/pub/gnu/automake/automake-${automake_min_vers}.tar.gz" || DIE=1
+ACLOCAL=`echo $AUTOMAKE | sed s/automake/aclocal/`
+
+
+version_check libtool LIBTOOLIZE "$LIBTOOLIZE glibtoolize libtoolize" $libtoolize_min_vers \
+ "http://ftp.gnu.org/pub/gnu/libtool/libtool-${libtool_min_vers}.tar.gz" || DIE=1
+
+if test -n "$DIE"; then
+ exit 1
+fi
+
+
+if test -z "$*"; then
+ echo "$ARGV0: Note: \`./configure' will be run with no arguments."
+ echo " If you wish to pass any to it, please specify them on the"
+ echo " \`$0' command line."
+ echo
+fi
+
+do_cmd() {
+ echo "$ARGV0: running \`$@'"
+ $@
+}
+
+do_cmd $LIBTOOLIZE $LIBTOOLIZE_FLAGS
+
+do_cmd $ACLOCAL $ACLOCAL_FLAGS
+
+do_cmd $AUTOHEADER
+
+touch ChangeLog
+
+# We don't call gtkdocize right now. When we do, we should then modify
+# the generated gtk-doc.make and move it to build/Makefile.am.gtk-doc.
+# See that file for details.
+#do_cmd $GTKDOCIZE $GTKDOCIZE_FLAGS
+
+do_cmd $AUTOMAKE $AUTOMAKE_FLAGS
+
+do_cmd $AUTOCONF
+
+cd "$ORIGDIR" || exit 1
+
+rm -f config.cache
+
+do_cmd $srcdir/configure \
+ ${1+"$@"} && echo "Now type \`make' to compile $PROJECT." || exit 1
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/configure.ac
@@ -0,0 +1,59 @@
+AC_PREREQ(2.59)
+AC_INIT(harfbuzz, 0.1, [http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz])
+AC_CONFIG_SRCDIR([harfbuzz.pc.in])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([1.9.6 gnu dist-bzip2 no-dist-gzip -Wall no-define])
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
+AC_LIBTOOL_WIN32_DLL
+AC_PROG_LIBTOOL dnl ([1.4]) Don't remove!
+
+AC_PROG_CC
+AC_PROG_CXX
+
+AC_C_FLEXIBLE_ARRAY_MEMBER
+
+AC_CHECK_FUNCS(mprotect sysconf getpagesize)
+AC_CHECK_HEADERS(unistd.h sys/mman.h)
+
+# Make sure we don't link to libstdc++
+if test "x$GCC" = "xyes"; then
+ CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
+fi
+
+dnl ==========================================================================
+
+PKG_CHECK_MODULES(GLIB, glib-2.0, have_glib=true, have_glib=false)
+if $have_glib; then
+ AC_DEFINE(HAVE_GLIB, 1, [Have glib2 library])
+fi
+AM_CONDITIONAL(HAVE_GLIB, $have_glib)
+
+PKG_CHECK_MODULES(ICU, icu, have_icu=true, have_icu=false)
+if $have_icu; then
+ AC_DEFINE(HAVE_ICU, 1, [Have ICU library])
+fi
+AM_CONDITIONAL(HAVE_ICU, $have_icu)
+
+PKG_CHECK_MODULES(FREETYPE, freetype2, have_freetype=true, have_freetype=false)
+if $have_freetype; then
+ AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
+ _save_libs="$LIBS"
+ _save_cflags="$CFLAGS"
+ LIBS="$LIBS $FREETYPE_LIBS"
+ CFLAGS="$CFLAGS $FREETYPE_CFLAGS"
+ AC_CHECK_FUNCS(FT_Face_GetCharVariantIndex)
+ LIBS="$_save_libs"
+ CFLAGS="$_save_cflags"
+fi
+AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
+
+dnl ==========================================================================
+
+AC_CONFIG_FILES([
+harfbuzz.pc
+Makefile
+src/Makefile
+])
+
+AC_OUTPUT
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/git.mk
@@ -0,0 +1,184 @@
+# git.mk
+#
+# Copyright 2009, Red Hat, Inc.
+# Written by Behdad Esfahbod
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.
+#
+# The canonical source for this file is pango/git.mk, or whereever the
+# header of pango/git.mk suggests in the future.
+#
+# To use in your project, import this file in your git repo's toplevel,
+# then do "make -f git.mk". This modifies all Makefile.am files in
+# your project to include git.mk.
+#
+# This enables automatic .gitignore generation. If you need to ignore
+# more files, add them to the GITIGNOREFILES variable in your Makefile.am.
+# But think twice before doing that. If a file has to be in .gitignore,
+# chances are very high that it's a generated file and should be in one
+# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES.
+#
+# The only case that you need to manually add a file to GITIGNOREFILES is
+# when remove files in one of mostlyclean-local, clean-local, distclean-local,
+# or maintainer-clean-local.
+#
+# Note that for files like editor backup, etc, there are better places to
+# ignore them. See "man gitignore".
+#
+# If "make maintainer-clean" removes the files but they are not recognized
+# by this script (that is, if "git status" shows untracked files still), send
+# me the output of "git status" as well as your Makefile.am and Makefile for
+# the directories involved.
+#
+# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
+# pango/Makefile.am.
+#
+# Don't EXTRA_DIST this file. It is supposed to only live in git clones,
+# not tarballs. It serves no useful purpose in tarballs and clutters the
+# build dir.
+#
+# This file knows how to handle autoconf, automake, libtool, gtk-doc,
+# gnome-doc-utils, intltool.
+#
+#
+# KNOWN ISSUES:
+#
+# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the
+# submodule doesn't find us. If you have configure.{in,ac} files in
+# subdirs, add a proxy git.mk file in those dirs that simply does:
+# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste.
+# And add those files to git. See vte/gnome-pty-helper/git.mk for
+# example.
+#
+
+git-all: git-mk-install
+
+git-mk-install:
+ @echo Installing git makefile
+ @any_failed=; find $(top_srcdir) -name Makefile.am | while read x; do \
+ if grep 'include .*/git.mk' $$x >/dev/null; then \
+ echo $$x already includes git.mk; \
+ else \
+ failed=; \
+ echo "Updating $$x"; \
+ { cat $$x; \
+ echo ''; \
+ echo '-include $$(top_srcdir)/git.mk'; \
+ } > $$x.tmp || failed=1; \
+ if test x$$failed = x; then \
+ mv $$x.tmp $$x || failed=1; \
+ fi; \
+ if test x$$failed = x; then : else \
+ echo Failed updating $$x; >&2 \
+ any_failed=1; \
+ fi; \
+ fi; done; test -z "$$any_failed"
+
+.PHONY: git-all git-mk-install
+
+
+### .gitignore generation
+
+$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
+ $(AM_V_GEN) \
+ { \
+ if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
+ for x in \
+ $(DOC_MODULE)-decl-list.txt \
+ $(DOC_MODULE)-decl.txt \
+ tmpl/$(DOC_MODULE)-unused.sgml \
+ "tmpl/*.bak" \
+ xml html \
+ ; do echo /$$x; done; \
+ fi; \
+ if test "x$(DOC_MODULE)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
+ for x in \
+ $(_DOC_C_DOCS) \
+ $(_DOC_LC_DOCS) \
+ $(_DOC_OMF_ALL) \
+ $(_DOC_DSK_ALL) \
+ $(_DOC_HTML_ALL) \
+ $(_DOC_POFILES) \
+ "*/.xml2po.mo" \
+ "*/*.omf.out" \
+ ; do echo /$$x; done; \
+ fi; \
+ if test -f $(srcdir)/po/Makefile.in.in; then \
+ for x in \
+ po/Makefile.in.in \
+ po/Makefile.in \
+ po/Makefile \
+ po/POTFILES \
+ po/stamp-it \
+ po/.intltool-merge-cache \
+ "po/*.gmo" \
+ "po/*.mo" \
+ po/$(GETTEXT_PACKAGE).pot \
+ intltool-extract.in \
+ intltool-merge.in \
+ intltool-update.in \
+ ; do echo /$$x; done; \
+ fi; \
+ if test -f $(srcdir)/configure; then \
+ for x in \
+ autom4te.cache \
+ configure \
+ config.h \
+ stamp-h1 \
+ libtool \
+ config.lt \
+ ; do echo /$$x; done; \
+ fi; \
+ for x in \
+ .gitignore \
+ $(GITIGNOREFILES) \
+ $(CLEANFILES) \
+ $(PROGRAMS) \
+ $(check_PROGRAMS) \
+ $(EXTRA_PROGRAMS) \
+ $(LTLIBRARIES) \
+ so_locations \
+ .libs _libs \
+ $(MOSTLYCLEANFILES) \
+ "*.$(OBJEXT)" \
+ "*.lo" \
+ $(DISTCLEANFILES) \
+ $(am__CONFIG_DISTCLEAN_FILES) \
+ $(CONFIG_CLEAN_FILES) \
+ TAGS ID GTAGS GRTAGS GSYMS GPATH tags \
+ "*.tab.c" \
+ $(MAINTAINERCLEANFILES) \
+ $(BUILT_SOURCES) \
+ $(DEPDIR) \
+ Makefile \
+ Makefile.in \
+ "*.orig" \
+ "*.rej" \
+ "*.bak" \
+ "*~" \
+ ".*.sw[nop]" \
+ ; do echo /$$x; done; \
+ } | \
+ sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
+ sed 's@/[.]/@/@g' | \
+ LC_ALL=C sort | uniq > $@.tmp && \
+ mv $@.tmp $@;
+
+all: $(srcdir)/.gitignore gitignore-recurse-maybe
+gitignore-recurse-maybe:
+ @if test "x$(SUBDIRS)" = "x$(DIST_SUBDIRS)"; then :; else \
+ $(MAKE) $(AM_MAKEFLAGS) gitignore-recurse; \
+ fi;
+gitignore-recurse:
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || echo "Skipping $$subdir"); \
+ done
+gitignore: $(srcdir)/.gitignore gitignore-recurse
+
+maintainer-clean: gitignore-clean
+gitignore-clean:
+ -rm -f $(srcdir)/.gitignore
+
+.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/harfbuzz.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: harfbuzz
+Description: Text shaping library
+Version: @VERSION@
+
+Libs: -L${libdir} -lharfbuzz
+Cflags: -I${includedir}/harfbuzz
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/Makefile.am
@@ -0,0 +1,111 @@
+# Process this file with automake to produce Makefile.in
+
+NULL =
+
+# The following warning options are useful for debugging: -Wpadded -Wcast-align
+#AM_CXXFLAGS =
+
+lib_LTLIBRARIES = libharfbuzz.la
+
+HBCFLAGS =
+HBLIBS =
+HBSOURCES = \
+ hb-blob.c \
+ hb-blob-private.h \
+ hb-buffer.cc \
+ hb-buffer-private.hh \
+ hb-font.cc \
+ hb-font-private.hh \
+ hb-object-private.h \
+ hb-open-file-private.hh \
+ hb-open-type-private.hh \
+ hb-language.c \
+ hb-ot-head-private.hh \
+ hb-private.h \
+ hb-shape.cc \
+ hb-unicode.c \
+ hb-unicode-private.h \
+ $(NULL)
+HBHEADERS = \
+ hb.h \
+ hb-blob.h \
+ hb-buffer.h \
+ hb-common.h \
+ hb-font.h \
+ hb-language.h \
+ hb-shape.h \
+ hb-unicode.h \
+ $(NULL)
+
+HBSOURCES += \
+ hb-ot-layout.cc \
+ hb-ot-layout-common-private.hh \
+ hb-ot-layout-gdef-private.hh \
+ hb-ot-layout-gpos-private.hh \
+ hb-ot-layout-gsubgpos-private.hh \
+ hb-ot-layout-gsub-private.hh \
+ hb-ot-layout-private.hh \
+ hb-ot-shape.cc \
+ hb-ot-shape-private.hh \
+ hb-ot-tag.c \
+ $(NULL)
+HBHEADERS += \
+ hb-ot.h \
+ hb-ot-layout.h \
+ hb-ot-tag.h \
+ $(NULL)
+
+if HAVE_GLIB
+HBCFLAGS += $(GLIB_CFLAGS)
+HBLIBS += $(GLIB_LIBS)
+HBSOURCES += \
+ hb-glib.c \
+ $(NULL)
+HBHEADERS += \
+ hb-glib.h \
+ $(NULL)
+endif
+
+if HAVE_ICU
+HBCFLAGS += $(ICU_CFLAGS)
+HBLIBS += $(ICU_LIBS)
+HBSOURCES += \
+ hb-icu.c \
+ $(NULL)
+HBHEADERS += \
+ hb-icu.h \
+ $(NULL)
+endif
+
+if HAVE_FREETYPE
+HBCFLAGS += $(FREETYPE_CFLAGS)
+HBLIBS += $(FREETYPE_LIBS)
+HBSOURCES += \
+ hb-ft.cc \
+ $(NULL)
+HBHEADERS += \
+ hb-ft.h \
+ $(NULL)
+endif
+
+CXXLINK = $(LINK)
+libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
+libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
+libharfbuzz_la_LIBADD = $(HBLIBS)
+pkginclude_HEADERS = $(HBHEADERS)
+
+noinst_PROGRAMS = main
+
+main_SOURCES = main.cc
+main_CPPFLAGS = $(HBCFLAGS)
+main_LDADD = libharfbuzz.la $(HBLIBS)
+
+TESTS = \
+ check-internal-symbols.sh
+
+if HAVE_ICU
+else
+TESTS += check-libstdc++.sh
+endif
+
+-include $(top_srcdir)/git.mk
new file mode 100755
--- /dev/null
+++ b/gfx/harfbuzz/src/check-libstdc++.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+if which ldd 2>/dev/null >/dev/null; then
+ :
+else
+ echo "check-libstdc++.sh: 'ldd' not found; skipping test"
+ exit 0
+fi
+
+test -z "$srcdir" && srcdir=.
+test -z "$MAKE" && MAKE=make
+stat=0
+
+so=.libs/libharfbuzz.so
+if test -f "$so"; then
+ echo "Checking that we are not linking to libstdc++"
+ if ldd $so | grep 'libstdc[+][+]'; then
+ echo "Ouch, linked to libstdc++"
+ stat=1
+ fi
+else
+ echo "check-libstdc++.sh: libharfbuzz.so not found; skipping test"
+fi
+
+exit $stat
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-blob-private.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 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_BLOB_PRIVATE_H
+#define HB_BLOB_PRIVATE_H
+
+#include "hb-private.h"
+
+#include "hb-blob.h"
+
+HB_BEGIN_DECLS
+
+struct _hb_blob_t {
+ hb_reference_count_t ref_count;
+
+ unsigned int length;
+
+ hb_mutex_t lock;
+ /* the rest are protected by lock */
+
+ unsigned int lock_count;
+ hb_memory_mode_t mode;
+
+ const char *data;
+
+ hb_destroy_func_t destroy;
+ void *user_data;
+};
+
+extern HB_INTERNAL hb_blob_t _hb_blob_nil;
+
+HB_END_DECLS
+
+#endif /* HB_BLOB_PRIVATE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-blob.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 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
+ */
+
+#include "hb-private.h"
+
+#include "hb-blob-private.h"
+
+#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 */
+
+#ifndef HB_DEBUG_BLOB
+#define HB_DEBUG_BLOB HB_DEBUG+0
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+hb_blob_t _hb_blob_nil = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+
+ 0, /* length */
+
+ HB_MUTEX_INIT, /* lock */
+
+ 0, /* lock_count */
+ HB_MEMORY_MODE_READONLY, /* mode */
+
+ NULL, /* data */
+
+ NULL, /* destroy */
+ NULL /* user_data */
+};
+
+static void
+_hb_blob_destroy_user_data (hb_blob_t *blob)
+{
+ if (blob->destroy) {
+ blob->destroy (blob->user_data);
+ blob->destroy = NULL;
+ blob->user_data = NULL;
+ }
+}
+
+static void
+_hb_blob_unlock_and_destroy (hb_blob_t *blob)
+{
+ hb_blob_unlock (blob);
+ hb_blob_destroy (blob);
+}
+
+hb_blob_t *
+hb_blob_create (const char *data,
+ unsigned int length,
+ hb_memory_mode_t mode,
+ hb_destroy_func_t destroy,
+ void *user_data)
+{
+ hb_blob_t *blob;
+
+ if (!length || !HB_OBJECT_DO_CREATE (hb_blob_t, blob)) {
+ if (destroy)
+ destroy (user_data);
+ return &_hb_blob_nil;
+ }
+
+ hb_mutex_init (blob->lock);
+ blob->lock_count = 0;
+
+ blob->data = data;
+ blob->length = length;
+ blob->mode = mode;
+
+ blob->destroy = destroy;
+ blob->user_data = user_data;
+
+ if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
+ blob->mode = HB_MEMORY_MODE_READONLY;
+ if (!hb_blob_try_writable (blob)) {
+ hb_blob_destroy (blob);
+ return &_hb_blob_nil;
+ }
+ }
+
+ return blob;
+}
+
+hb_blob_t *
+hb_blob_create_sub_blob (hb_blob_t *parent,
+ unsigned int offset,
+ unsigned int length)
+{
+ hb_blob_t *blob;
+ const char *pdata;
+
+ if (!length || offset >= parent->length || !HB_OBJECT_DO_CREATE (hb_blob_t, blob))
+ return &_hb_blob_nil;
+
+ pdata = hb_blob_lock (parent);
+
+ blob->data = pdata + offset;
+ blob->length = MIN (length, parent->length - offset);
+
+ hb_mutex_lock (parent->lock);
+ blob->mode = parent->mode;
+ hb_mutex_unlock (parent->lock);
+
+ blob->destroy = (hb_destroy_func_t) _hb_blob_unlock_and_destroy;
+ blob->user_data = hb_blob_reference (parent);
+
+ return blob;
+}
+
+hb_blob_t *
+hb_blob_create_empty (void)
+{
+ return &_hb_blob_nil;
+}
+
+hb_blob_t *
+hb_blob_reference (hb_blob_t *blob)
+{
+ HB_OBJECT_DO_REFERENCE (blob);
+}
+
+unsigned int
+hb_blob_get_reference_count (hb_blob_t *blob)
+{
+ HB_OBJECT_DO_GET_REFERENCE_COUNT (blob);
+}
+
+void
+hb_blob_destroy (hb_blob_t *blob)
+{
+ HB_OBJECT_DO_DESTROY (blob);
+
+ _hb_blob_destroy_user_data (blob);
+
+ free (blob);
+}
+
+unsigned int
+hb_blob_get_length (hb_blob_t *blob)
+{
+ return blob->length;
+}
+
+const char *
+hb_blob_lock (hb_blob_t *blob)
+{
+ if (HB_OBJECT_IS_INERT (blob))
+ return NULL;
+
+ hb_mutex_lock (blob->lock);
+
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
+ blob->lock_count, blob->data);
+
+ blob->lock_count++;
+
+ hb_mutex_unlock (blob->lock);
+
+ return blob->data;
+}
+
+void
+hb_blob_unlock (hb_blob_t *blob)
+{
+ if (HB_OBJECT_IS_INERT (blob))
+ return;
+
+ hb_mutex_lock (blob->lock);
+
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
+ blob->lock_count, blob->data);
+
+ assert (blob->lock_count > 0);
+ blob->lock_count--;
+
+ hb_mutex_unlock (blob->lock);
+}
+
+hb_bool_t
+hb_blob_is_writable (hb_blob_t *blob)
+{
+ hb_memory_mode_t mode;
+
+ if (HB_OBJECT_IS_INERT (blob))
+ return FALSE;
+
+ hb_mutex_lock (blob->lock);
+
+ mode = blob->mode;
+
+ hb_mutex_unlock (blob->lock);
+
+ return mode == HB_MEMORY_MODE_WRITABLE;
+}
+
+
+static hb_bool_t
+_try_make_writable_inplace_unix_locked (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) {
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: failed to get pagesize: %s\n", blob, __FUNCTION__, strerror (errno));
+ return FALSE;
+ }
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: pagesize is %u\n", blob, __FUNCTION__, 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;
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: calling mprotect on [%p..%p] (%d bytes)\n",
+ blob, __FUNCTION__,
+ addr, addr+length, length);
+ if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: %s\n", blob, __FUNCTION__, strerror (errno));
+ return FALSE;
+ }
+
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: successfully made [%p..%p] (%d bytes) writable\n",
+ blob, __FUNCTION__,
+ addr, addr+length, length);
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+static void
+_try_writable_inplace_locked (hb_blob_t *blob)
+{
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: making writable\n", blob, __FUNCTION__);
+
+ if (_try_make_writable_inplace_unix_locked (blob)) {
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: making writable -> succeeded\n", blob, __FUNCTION__);
+ blob->mode = HB_MEMORY_MODE_WRITABLE;
+ } else {
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: making writable -> FAILED\n", blob, __FUNCTION__);
+ /* Failed to make writable inplace, mark that */
+ blob->mode = HB_MEMORY_MODE_READONLY;
+ }
+}
+
+hb_bool_t
+hb_blob_try_writable_inplace (hb_blob_t *blob)
+{
+ hb_memory_mode_t mode;
+
+ if (HB_OBJECT_IS_INERT (blob))
+ return FALSE;
+
+ hb_mutex_lock (blob->lock);
+
+ if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
+ _try_writable_inplace_locked (blob);
+
+ mode = blob->mode;
+
+ hb_mutex_unlock (blob->lock);
+
+ return mode == HB_MEMORY_MODE_WRITABLE;
+}
+
+hb_bool_t
+hb_blob_try_writable (hb_blob_t *blob)
+{
+ hb_memory_mode_t mode;
+
+ if (HB_OBJECT_IS_INERT (blob))
+ return FALSE;
+
+ hb_mutex_lock (blob->lock);
+
+ if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE)
+ _try_writable_inplace_locked (blob);
+
+ if (blob->mode == HB_MEMORY_MODE_READONLY)
+ {
+ char *new_data;
+
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s (%d) -> %p\n", blob, __FUNCTION__,
+ blob->lock_count, blob->data);
+
+ if (blob->lock_count)
+ goto done;
+
+ new_data = malloc (blob->length);
+ if (new_data) {
+ if (HB_DEBUG_BLOB)
+ fprintf (stderr, "%p %s: dupped successfully -> %p\n", blob, __FUNCTION__, 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->destroy = free;
+ blob->user_data = new_data;
+ }
+ }
+
+done:
+ mode = blob->mode;
+
+ hb_mutex_unlock (blob->lock);
+
+ return mode == HB_MEMORY_MODE_WRITABLE;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-blob.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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_BLOB_H
+#define HB_BLOB_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+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_blob_t *
+hb_blob_create (const char *data,
+ unsigned int length,
+ hb_memory_mode_t mode,
+ hb_destroy_func_t destroy,
+ void *user_data);
+
+hb_blob_t *
+hb_blob_create_sub_blob (hb_blob_t *parent,
+ unsigned int offset,
+ unsigned int length);
+
+hb_blob_t *
+hb_blob_create_empty (void);
+
+hb_blob_t *
+hb_blob_reference (hb_blob_t *blob);
+
+unsigned int
+hb_blob_get_reference_count (hb_blob_t *blob);
+
+void
+hb_blob_destroy (hb_blob_t *blob);
+
+unsigned int
+hb_blob_get_length (hb_blob_t *blob);
+
+const char *
+hb_blob_lock (hb_blob_t *blob);
+
+void
+hb_blob_unlock (hb_blob_t *blob);
+
+hb_bool_t
+hb_blob_is_writable (hb_blob_t *blob);
+
+hb_bool_t
+hb_blob_try_writable_inplace (hb_blob_t *blob);
+
+hb_bool_t
+hb_blob_try_writable (hb_blob_t *blob);
+
+HB_END_DECLS
+
+#endif /* HB_BLOB_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-buffer-private.hh
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2004,2007,2009,2010 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): Owen Taylor, Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_PRIVATE_H
+#define HB_BUFFER_PRIVATE_H
+
+#include "hb-private.h"
+#include "hb-buffer.h"
+#include "hb-unicode-private.h"
+
+HB_BEGIN_DECLS
+
+#define HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN 0xFFFF
+
+
+typedef struct _hb_internal_glyph_info_t {
+ hb_codepoint_t codepoint;
+ hb_mask_t mask;
+ uint32_t cluster;
+ uint16_t component;
+ uint16_t lig_id;
+ uint32_t gproperty;
+} hb_internal_glyph_info_t;
+
+typedef struct _hb_internal_glyph_position_t {
+ hb_position_t x_advance;
+ hb_position_t y_advance;
+ hb_position_t x_offset;
+ hb_position_t y_offset;
+ uint32_t back : 16; /* number of glyphs to go back
+ for drawing current glyph */
+ int32_t cursive_chain : 16; /* character to which this connects,
+ may be positive or negative */
+} hb_internal_glyph_position_t;
+
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_internal_glyph_info_t));
+ASSERT_STATIC (sizeof (hb_glyph_position_t) == sizeof (hb_internal_glyph_position_t));
+ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
+
+
+HB_INTERNAL void
+_hb_buffer_swap (hb_buffer_t *buffer);
+
+HB_INTERNAL void
+_hb_buffer_clear_output (hb_buffer_t *buffer);
+
+HB_INTERNAL void
+_hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
+ unsigned int num_in,
+ unsigned int num_out,
+ const hb_codepoint_t *glyph_data,
+ unsigned short component,
+ unsigned short ligID);
+
+HB_INTERNAL void
+_hb_buffer_add_output_glyphs_be16 (hb_buffer_t *buffer,
+ unsigned int num_in,
+ unsigned int num_out,
+ const uint16_t *glyph_data_be,
+ unsigned short component,
+ unsigned short ligID);
+
+HB_INTERNAL void
+_hb_buffer_add_output_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t glyph_index,
+ unsigned short component,
+ unsigned short ligID);
+
+HB_INTERNAL void
+_hb_buffer_next_glyph (hb_buffer_t *buffer);
+
+
+HB_INTERNAL void
+_hb_buffer_clear_masks (hb_buffer_t *buffer);
+
+HB_INTERNAL void
+_hb_buffer_set_masks (hb_buffer_t *buffer,
+ hb_mask_t value,
+ hb_mask_t mask,
+ unsigned int cluster_start,
+ unsigned int cluster_end);
+
+
+struct _hb_buffer_t {
+ hb_reference_count_t ref_count;
+
+ /* Information about how the text in the buffer should be treated */
+ hb_unicode_funcs_t *unicode;
+ hb_direction_t direction;
+ hb_script_t script;
+ hb_language_t language;
+
+ /* Buffer contents */
+
+ unsigned int allocated; /* Length of allocated arrays */
+
+ hb_bool_t have_output; /* Whether we have an output buffer going on */
+ hb_bool_t have_positions; /* Whether we have positions */
+ hb_bool_t in_error; /* Allocation failed */
+
+ unsigned int i; /* Cursor into ->info and ->pos arrays */
+ unsigned int len; /* Length of ->info and ->pos arrays */
+ unsigned int out_len; /* Length of ->out array */
+
+ hb_internal_glyph_info_t *info;
+ hb_internal_glyph_info_t *out_info;
+ hb_internal_glyph_position_t *pos;
+
+ /* Other stuff */
+
+ unsigned int max_lig_id;
+
+
+ /* Methods */
+ inline unsigned int allocate_lig_id (void) { return max_lig_id++; }
+ inline void swap (void) { _hb_buffer_swap (this); }
+ inline void clear_output (void) { _hb_buffer_clear_output (this); }
+ inline void next_glyph (void) { _hb_buffer_next_glyph (this); }
+ inline void add_output_glyphs (unsigned int num_in,
+ unsigned int num_out,
+ const hb_codepoint_t *glyph_data,
+ unsigned short component,
+ unsigned short ligID)
+ { _hb_buffer_add_output_glyphs (this, num_in, num_out, glyph_data, component, ligID); }
+ inline void add_output_glyphs_be16 (unsigned int num_in,
+ unsigned int num_out,
+ const uint16_t *glyph_data_be,
+ unsigned short component,
+ unsigned short ligID)
+ { _hb_buffer_add_output_glyphs_be16 (this, num_in, num_out, glyph_data_be, component, ligID); }
+ inline void add_output_glyph (hb_codepoint_t glyph_index,
+ unsigned short component = 0xFFFF,
+ unsigned short ligID = 0xFFFF)
+ { _hb_buffer_add_output_glyph (this, glyph_index, component, ligID); }
+ inline void replace_glyph (hb_codepoint_t glyph_index) { add_output_glyph (glyph_index); }
+
+ inline void clear_masks (void) { _hb_buffer_clear_masks (this); }
+ inline void set_masks (hb_mask_t value,
+ hb_mask_t mask,
+ unsigned int cluster_start,
+ unsigned int cluster_end)
+ { _hb_buffer_set_masks (this, value, mask, cluster_start, cluster_end); }
+
+};
+
+
+HB_END_DECLS
+
+#endif /* HB_BUFFER_PRIVATE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-buffer.cc
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2004,2007,2009,2010 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): Owen Taylor, Behdad Esfahbod
+ */
+
+#include "hb-buffer-private.hh"
+
+#include <string.h>
+
+
+static hb_buffer_t _hb_buffer_nil = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+
+ &_hb_unicode_funcs_nil /* unicode */
+};
+
+/* Here is how the buffer works internally:
+ *
+ * There are two info pointers: info and out_info. They always have
+ * the same allocated size, but different lengths.
+ *
+ * As an optimization, both info and out_info may point to the
+ * same piece of memory, which is owned by info. This remains the
+ * case as long as out_len doesn't exceed len at any time.
+ * In that case, swap() is no-op and the glyph operations operate
+ * mostly in-place.
+ *
+ * As soon as out_info gets longer than info, out_info is moved over
+ * to an alternate buffer (which we reuse the pos buffer for!), and its
+ * current contents (out_len entries) are copied to the new place.
+ * This should all remain transparent to the user. swap() then
+ * switches info and out_info.
+ */
+
+
+static hb_bool_t
+_hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size)
+{
+ if (unlikely (buffer->in_error))
+ return FALSE;
+
+ unsigned int new_allocated = buffer->allocated;
+ hb_internal_glyph_position_t *new_pos;
+ hb_internal_glyph_info_t *new_info;
+ bool separate_out;
+
+ separate_out = buffer->out_info != buffer->info;
+
+ while (size > new_allocated)
+ new_allocated += (new_allocated >> 1) + 8;
+
+ new_pos = (hb_internal_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof (buffer->pos[0]));
+ new_info = (hb_internal_glyph_info_t *) realloc (buffer->info, new_allocated * sizeof (buffer->info[0]));
+
+ if (unlikely (!new_pos || !new_info))
+ buffer->in_error = TRUE;
+
+ if (likely (new_pos))
+ buffer->pos = new_pos;
+
+ if (likely (new_info))
+ buffer->info = new_info;
+
+ buffer->out_info = separate_out ? (hb_internal_glyph_info_t *) buffer->pos : buffer->info;
+ if (likely (!buffer->in_error))
+ buffer->allocated = new_allocated;
+
+ return likely (!buffer->in_error);
+}
+
+static inline hb_bool_t
+_hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
+{
+ return likely (size <= buffer->allocated) ? TRUE : _hb_buffer_enlarge (buffer, size);
+}
+
+static hb_bool_t
+_hb_buffer_ensure_separate (hb_buffer_t *buffer, unsigned int size)
+{
+ if (unlikely (!_hb_buffer_ensure (buffer, size))) return FALSE;
+
+ if (buffer->out_info == buffer->info)
+ {
+ assert (buffer->have_output);
+
+ buffer->out_info = (hb_internal_glyph_info_t *) buffer->pos;
+ memcpy (buffer->out_info, buffer->info, buffer->out_len * sizeof (buffer->out_info[0]));
+ }
+
+ return TRUE;
+}
+
+
+/* Public API */
+
+hb_buffer_t *
+hb_buffer_create (unsigned int pre_alloc_size)
+{
+ hb_buffer_t *buffer;
+
+ if (!HB_OBJECT_DO_CREATE (hb_buffer_t, buffer))
+ return &_hb_buffer_nil;
+
+ if (pre_alloc_size)
+ _hb_buffer_ensure (buffer, pre_alloc_size);
+
+ buffer->unicode = &_hb_unicode_funcs_nil;
+
+ return buffer;
+}
+
+hb_buffer_t *
+hb_buffer_reference (hb_buffer_t *buffer)
+{
+ HB_OBJECT_DO_REFERENCE (buffer);
+}
+
+unsigned int
+hb_buffer_get_reference_count (hb_buffer_t *buffer)
+{
+ HB_OBJECT_DO_GET_REFERENCE_COUNT (buffer);
+}
+
+void
+hb_buffer_destroy (hb_buffer_t *buffer)
+{
+ HB_OBJECT_DO_DESTROY (buffer);
+
+ hb_unicode_funcs_destroy (buffer->unicode);
+
+ free (buffer->info);
+ free (buffer->pos);
+
+ free (buffer);
+}
+
+
+void
+hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
+ hb_unicode_funcs_t *unicode)
+{
+ if (!unicode)
+ unicode = &_hb_unicode_funcs_nil;
+
+ hb_unicode_funcs_reference (unicode);
+ hb_unicode_funcs_destroy (buffer->unicode);
+ buffer->unicode = unicode;
+}
+
+hb_unicode_funcs_t *
+hb_buffer_get_unicode_funcs (hb_buffer_t *buffer)
+{
+ return buffer->unicode;
+}
+
+void
+hb_buffer_set_direction (hb_buffer_t *buffer,
+ hb_direction_t direction)
+
+{
+ buffer->direction = direction;
+}
+
+hb_direction_t
+hb_buffer_get_direction (hb_buffer_t *buffer)
+{
+ return buffer->direction;
+}
+
+void
+hb_buffer_set_script (hb_buffer_t *buffer,
+ hb_script_t script)
+{
+ buffer->script = script;
+}
+
+hb_script_t
+hb_buffer_get_script (hb_buffer_t *buffer)
+{
+ return buffer->script;
+}
+
+void
+hb_buffer_set_language (hb_buffer_t *buffer,
+ hb_language_t language)
+{
+ buffer->language = language;
+}
+
+hb_language_t
+hb_buffer_get_language (hb_buffer_t *buffer)
+{
+ return buffer->language;
+}
+
+
+void
+hb_buffer_clear (hb_buffer_t *buffer)
+{
+ buffer->have_output = FALSE;
+ buffer->have_positions = FALSE;
+ buffer->in_error = FALSE;
+ buffer->len = 0;
+ buffer->out_len = 0;
+ buffer->i = 0;
+ buffer->out_info = buffer->info;
+ buffer->max_lig_id = 0;
+}
+
+hb_bool_t
+hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size)
+{
+ return _hb_buffer_ensure (buffer, size);
+}
+
+void
+hb_buffer_add_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t codepoint,
+ hb_mask_t mask,
+ unsigned int cluster)
+{
+ hb_internal_glyph_info_t *glyph;
+
+ if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return;
+
+ glyph = &buffer->info[buffer->len];
+ glyph->codepoint = codepoint;
+ glyph->mask = mask;
+ glyph->cluster = cluster;
+ glyph->component = 0;
+ glyph->lig_id = 0;
+ glyph->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
+
+ buffer->len++;
+}
+
+void
+hb_buffer_clear_positions (hb_buffer_t *buffer)
+{
+ _hb_buffer_clear_output (buffer);
+ buffer->have_output = FALSE;
+ buffer->have_positions = TRUE;
+
+ if (unlikely (!buffer->pos))
+ {
+ buffer->pos = (hb_internal_glyph_position_t *) calloc (buffer->allocated, sizeof (buffer->pos[0]));
+ return;
+ }
+
+ memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len);
+}
+
+/* HarfBuzz-Internal API */
+
+void
+_hb_buffer_clear_output (hb_buffer_t *buffer)
+{
+ buffer->have_output = TRUE;
+ buffer->have_positions = FALSE;
+ buffer->out_len = 0;
+ buffer->out_info = buffer->info;
+}
+
+void
+_hb_buffer_swap (hb_buffer_t *buffer)
+{
+ unsigned int tmp;
+
+ assert (buffer->have_output);
+
+ if (unlikely (buffer->in_error)) return;
+
+ if (buffer->out_info != buffer->info)
+ {
+ hb_internal_glyph_info_t *tmp_string;
+ tmp_string = buffer->info;
+ buffer->info = buffer->out_info;
+ buffer->out_info = tmp_string;
+ buffer->pos = (hb_internal_glyph_position_t *) buffer->out_info;
+ }
+
+ tmp = buffer->len;
+ buffer->len = buffer->out_len;
+ buffer->out_len = tmp;
+
+ buffer->i = 0;
+}
+
+/* The following function copies `num_out' elements from `glyph_data'
+ to `buffer->out_info', advancing the in array pointer in the structure
+ by `num_in' elements, and the out array pointer by `num_out' elements.
+ Finally, it sets the `length' field of `out' equal to
+ `pos' of the `out' structure.
+
+ If `component' is 0xFFFF, the component value from buffer->i
+ will copied `num_out' times, otherwise `component' itself will
+ be used to fill the `component' fields.
+
+ If `lig_id' is 0xFFFF, the lig_id value from buffer->i
+ will copied `num_out' times, otherwise `lig_id' itself will
+ be used to fill the `lig_id' fields.
+
+ The mask for all replacement glyphs are taken
+ from the glyph at position `buffer->i'.
+
+ The cluster value for the glyph at position buffer->i is used
+ for all replacement glyphs */
+
+void
+_hb_buffer_add_output_glyphs (hb_buffer_t *buffer,
+ unsigned int num_in,
+ unsigned int num_out,
+ const hb_codepoint_t *glyph_data,
+ unsigned short component,
+ unsigned short lig_id)
+{
+ unsigned int i;
+ unsigned int mask;
+ unsigned int cluster;
+
+ if (buffer->out_info != buffer->info ||
+ buffer->out_len + num_out > buffer->i + num_in)
+ {
+ if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
+ return;
+ }
+
+ mask = buffer->info[buffer->i].mask;
+ cluster = buffer->info[buffer->i].cluster;
+ if (component == 0xFFFF)
+ component = buffer->info[buffer->i].component;
+ if (lig_id == 0xFFFF)
+ lig_id = buffer->info[buffer->i].lig_id;
+
+ for (i = 0; i < num_out; i++)
+ {
+ hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
+ info->codepoint = glyph_data[i];
+ info->mask = mask;
+ info->cluster = cluster;
+ info->component = component;
+ info->lig_id = lig_id;
+ info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
+ }
+
+ buffer->i += num_in;
+ buffer->out_len += num_out;
+}
+
+void
+_hb_buffer_add_output_glyphs_be16 (hb_buffer_t *buffer,
+ unsigned int num_in,
+ unsigned int num_out,
+ const uint16_t *glyph_data_be,
+ unsigned short component,
+ unsigned short lig_id)
+{
+ unsigned int i;
+ unsigned int mask;
+ unsigned int cluster;
+
+ if (buffer->out_info != buffer->info ||
+ buffer->out_len + num_out > buffer->i + num_in)
+ {
+ if (unlikely (!_hb_buffer_ensure_separate (buffer, buffer->out_len + num_out)))
+ return;
+ }
+
+ mask = buffer->info[buffer->i].mask;
+ cluster = buffer->info[buffer->i].cluster;
+ if (component == 0xFFFF)
+ component = buffer->info[buffer->i].component;
+ if (lig_id == 0xFFFF)
+ lig_id = buffer->info[buffer->i].lig_id;
+
+ for (i = 0; i < num_out; i++)
+ {
+ hb_internal_glyph_info_t *info = &buffer->out_info[buffer->out_len + i];
+ info->codepoint = hb_be_uint16 (glyph_data_be[i]);
+ info->mask = mask;
+ info->cluster = cluster;
+ info->component = component;
+ info->lig_id = lig_id;
+ info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
+ }
+
+ buffer->i += num_in;
+ buffer->out_len += num_out;
+}
+
+void
+_hb_buffer_add_output_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t glyph_index,
+ unsigned short component,
+ unsigned short lig_id)
+{
+ hb_internal_glyph_info_t *info;
+
+ if (buffer->out_info != buffer->info)
+ {
+ if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
+ buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
+ }
+ else if (buffer->out_len != buffer->i)
+ buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
+
+ info = &buffer->out_info[buffer->out_len];
+ info->codepoint = glyph_index;
+ if (component != 0xFFFF)
+ info->component = component;
+ if (lig_id != 0xFFFF)
+ info->lig_id = lig_id;
+ info->gproperty = HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN;
+
+ buffer->i++;
+ buffer->out_len++;
+}
+
+void
+_hb_buffer_next_glyph (hb_buffer_t *buffer)
+{
+ if (buffer->have_output)
+ {
+ if (buffer->out_info != buffer->info)
+ {
+ if (unlikely (!_hb_buffer_ensure (buffer, buffer->out_len + 1))) return;
+ buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
+ }
+ else if (buffer->out_len != buffer->i)
+ buffer->out_info[buffer->out_len] = buffer->info[buffer->i];
+
+ buffer->out_len++;
+ }
+
+ buffer->i++;
+}
+
+void
+_hb_buffer_clear_masks (hb_buffer_t *buffer)
+{
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ buffer->info[i].mask = 1;
+}
+
+void
+_hb_buffer_set_masks (hb_buffer_t *buffer,
+ hb_mask_t value,
+ hb_mask_t mask,
+ unsigned int cluster_start,
+ unsigned int cluster_end)
+{
+ hb_mask_t not_mask = ~mask;
+
+ if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
+ unsigned int count = buffer->len;
+ for (unsigned int i = 0; i < count; i++)
+ buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
+ return;
+ }
+
+ /* Binary search to find the start position and go from there. */
+ unsigned int min = 0, max = buffer->len;
+ while (min < max)
+ {
+ unsigned int mid = min + ((max - min) / 2);
+ if (buffer->info[mid].cluster < cluster_start)
+ min = mid + 1;
+ else
+ max = mid;
+ }
+ unsigned int count = buffer->len;
+ for (unsigned int i = min; i < count && buffer->info[i].cluster < cluster_end; i++)
+ buffer->info[i].mask = (buffer->info[i].mask & not_mask) | value;
+}
+
+
+/* Public API again */
+
+unsigned int
+hb_buffer_get_length (hb_buffer_t *buffer)
+{
+ return buffer->len;
+}
+
+/* Return value valid as long as buffer not modified */
+hb_glyph_info_t *
+hb_buffer_get_glyph_infos (hb_buffer_t *buffer)
+{
+ return (hb_glyph_info_t *) buffer->info;
+}
+
+/* Return value valid as long as buffer not modified */
+hb_glyph_position_t *
+hb_buffer_get_glyph_positions (hb_buffer_t *buffer)
+{
+ if (!buffer->have_positions)
+ hb_buffer_clear_positions (buffer);
+
+ return (hb_glyph_position_t *) buffer->pos;
+}
+
+
+static void
+reverse_range (hb_buffer_t *buffer,
+ unsigned int start,
+ unsigned int end)
+{
+ unsigned int i, j;
+
+ for (i = start, j = end - 1; i < j; i++, j--) {
+ hb_internal_glyph_info_t t;
+
+ t = buffer->info[i];
+ buffer->info[i] = buffer->info[j];
+ buffer->info[j] = t;
+ }
+
+ if (buffer->pos) {
+ for (i = 0, j = end - 1; i < j; i++, j--) {
+ hb_internal_glyph_position_t t;
+
+ t = buffer->pos[i];
+ buffer->pos[i] = buffer->pos[j];
+ buffer->pos[j] = t;
+ }
+ }
+}
+
+void
+hb_buffer_reverse (hb_buffer_t *buffer)
+{
+ if (unlikely (!buffer->len))
+ return;
+
+ reverse_range (buffer, 0, buffer->len);
+}
+
+void
+hb_buffer_reverse_clusters (hb_buffer_t *buffer)
+{
+ unsigned int i, start, count, last_cluster;
+
+ if (unlikely (!buffer->len))
+ return;
+
+ hb_buffer_reverse (buffer);
+
+ count = buffer->len;
+ start = 0;
+ last_cluster = buffer->info[0].cluster;
+ for (i = 1; i < count; i++) {
+ if (last_cluster != buffer->info[i].cluster) {
+ reverse_range (buffer, start, i);
+ start = i;
+ last_cluster = buffer->info[i].cluster;
+ }
+ }
+ reverse_range (buffer, start, i);
+}
+
+
+#define ADD_UTF(T) \
+ HB_STMT_START { \
+ const T *next = (const T *) text + item_offset; \
+ const T *end = next + item_length; \
+ while (next < end) { \
+ hb_codepoint_t u; \
+ const T *old_next = next; \
+ next = UTF_NEXT (next, end, u); \
+ hb_buffer_add_glyph (buffer, u, 1, old_next - (const T *) text); \
+ } \
+ } HB_STMT_END
+
+
+#define UTF8_COMPUTE(Char, Mask, Len) \
+ if (Char < 128) { Len = 1; Mask = 0x7f; } \
+ else if ((Char & 0xe0) == 0xc0) { Len = 2; Mask = 0x1f; } \
+ else if ((Char & 0xf0) == 0xe0) { Len = 3; Mask = 0x0f; } \
+ else if ((Char & 0xf8) == 0xf0) { Len = 4; Mask = 0x07; } \
+ else Len = 0;
+
+static inline const uint8_t *
+hb_utf8_next (const uint8_t *text,
+ const uint8_t *end,
+ hb_codepoint_t *unicode)
+{
+ uint8_t c = *text;
+ unsigned int mask, len;
+
+ /* TODO check for overlong sequences? also: optimize? */
+
+ UTF8_COMPUTE (c, mask, len);
+ if (unlikely (!len || (unsigned int) (end - text) < len)) {
+ *unicode = -1;
+ return text + 1;
+ } else {
+ hb_codepoint_t result;
+ unsigned int i;
+ result = c & mask;
+ for (i = 1; i < len; i++)
+ {
+ if (unlikely ((text[i] & 0xc0) != 0x80))
+ {
+ *unicode = -1;
+ return text + 1;
+ }
+ result <<= 6;
+ result |= (text[i] & 0x3f);
+ }
+ *unicode = result;
+ return text + len;
+ }
+}
+
+void
+hb_buffer_add_utf8 (hb_buffer_t *buffer,
+ const char *text,
+ unsigned int text_length HB_UNUSED,
+ unsigned int item_offset,
+ unsigned int item_length)
+{
+#define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U))
+ ADD_UTF (uint8_t);
+#undef UTF_NEXT
+}
+
+static inline const uint16_t *
+hb_utf16_next (const uint16_t *text,
+ const uint16_t *end,
+ hb_codepoint_t *unicode)
+{
+ uint16_t c = *text++;
+
+ if (unlikely (c >= 0xd800 && c < 0xdc00)) {
+ /* high surrogate */
+ uint16_t l;
+ if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) {
+ /* low surrogate */
+ *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000);
+ text++;
+ } else
+ *unicode = -1;
+ } else
+ *unicode = c;
+
+ return text;
+}
+
+void
+hb_buffer_add_utf16 (hb_buffer_t *buffer,
+ const uint16_t *text,
+ unsigned int text_length HB_UNUSED,
+ unsigned int item_offset,
+ unsigned int item_length)
+{
+#define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U))
+ ADD_UTF (uint16_t);
+#undef UTF_NEXT
+}
+
+void
+hb_buffer_add_utf32 (hb_buffer_t *buffer,
+ const uint32_t *text,
+ unsigned int text_length HB_UNUSED,
+ unsigned int item_offset,
+ unsigned int item_length)
+{
+#define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1)
+ ADD_UTF (uint32_t);
+#undef UTF_NEXT
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-buffer.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 1998-2004 David Turner and Werner Lemberg
+ * Copyright (C) 2004,2007,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): Owen Taylor, Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_H
+#define HB_BUFFER_H
+
+#include "hb-common.h"
+#include "hb-unicode.h"
+#include "hb-language.h"
+
+HB_BEGIN_DECLS
+
+typedef struct _hb_buffer_t hb_buffer_t;
+
+typedef struct _hb_glyph_info_t {
+ hb_codepoint_t codepoint;
+ hb_mask_t mask;
+ uint32_t cluster;
+ uint32_t internal1;
+ uint32_t internal2;
+} hb_glyph_info_t;
+
+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;
+ uint32_t internal;
+} hb_glyph_position_t;
+
+
+hb_buffer_t *
+hb_buffer_create (unsigned int pre_alloc_size);
+
+hb_buffer_t *
+hb_buffer_reference (hb_buffer_t *buffer);
+
+unsigned int
+hb_buffer_get_reference_count (hb_buffer_t *buffer);
+
+void
+hb_buffer_destroy (hb_buffer_t *buffer);
+
+
+void
+hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
+ hb_unicode_funcs_t *unicode_funcs);
+
+hb_unicode_funcs_t *
+hb_buffer_get_unicode_funcs (hb_buffer_t *buffer);
+
+void
+hb_buffer_set_direction (hb_buffer_t *buffer,
+ hb_direction_t direction);
+
+hb_direction_t
+hb_buffer_get_direction (hb_buffer_t *buffer);
+
+void
+hb_buffer_set_script (hb_buffer_t *buffer,
+ hb_script_t script);
+
+hb_script_t
+hb_buffer_get_script (hb_buffer_t *buffer);
+
+void
+hb_buffer_set_language (hb_buffer_t *buffer,
+ hb_language_t language);
+
+hb_language_t
+hb_buffer_get_language (hb_buffer_t *buffer);
+
+
+void
+hb_buffer_clear (hb_buffer_t *buffer);
+
+void
+hb_buffer_clear_positions (hb_buffer_t *buffer);
+
+hb_bool_t
+hb_buffer_ensure (hb_buffer_t *buffer,
+ unsigned int size);
+
+void
+hb_buffer_reverse (hb_buffer_t *buffer);
+
+void
+hb_buffer_reverse_clusters (hb_buffer_t *buffer);
+
+
+/* Filling the buffer in */
+
+void
+hb_buffer_add_glyph (hb_buffer_t *buffer,
+ hb_codepoint_t codepoint,
+ hb_mask_t mask,
+ unsigned int cluster);
+
+void
+hb_buffer_add_utf8 (hb_buffer_t *buffer,
+ const char *text,
+ unsigned int text_length,
+ unsigned int item_offset,
+ unsigned int item_length);
+
+void
+hb_buffer_add_utf16 (hb_buffer_t *buffer,
+ const uint16_t *text,
+ unsigned int text_length,
+ unsigned int item_offset,
+ unsigned int item_length);
+
+void
+hb_buffer_add_utf32 (hb_buffer_t *buffer,
+ const uint32_t *text,
+ unsigned int text_length,
+ unsigned int item_offset,
+ unsigned int item_length);
+
+
+/* Getting glyphs out of the buffer */
+
+/* Return value valid as long as buffer not modified */
+unsigned int
+hb_buffer_get_length (hb_buffer_t *buffer);
+
+/* Return value valid as long as buffer not modified */
+hb_glyph_info_t *
+hb_buffer_get_glyph_infos (hb_buffer_t *buffer);
+
+/* Return value valid as long as buffer not modified */
+hb_glyph_position_t *
+hb_buffer_get_glyph_positions (hb_buffer_t *buffer);
+
+
+HB_END_DECLS
+
+#endif /* HB_BUFFER_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-common.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 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
+ */
+
+#include "hb-private.h"
+
+hb_tag_t
+hb_tag_from_string (const char *s)
+{
+ char tag[4];
+ unsigned int i;
+
+ for (i = 0; i < 4 && s[i]; i++)
+ tag[i] = s[i];
+ for (; i < 4; i++)
+ tag[i] = ' ';
+
+ return HB_TAG_STR (tag);
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-common.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 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_COMMON_H
+#define HB_COMMON_H
+
+#ifdef _MSC_VER
+#define _HB__STR2__(x) #x
+#define _HB__STR1__(x) _HB__STR2__(x)
+#define _HB__LOC__ __FILE__ "("_HB__STR1__(__LINE__)") : Warning Msg: "
+#pragma message(_HB__LOC__"Not using stdint.h; integer types may have wrong size")
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+#ifndef __cplusplus
+#define inline __inline
+#endif
+#else
+#include <stdint.h>
+#endif
+
+# ifdef __cplusplus
+# define HB_BEGIN_DECLS extern "C" {
+# define HB_END_DECLS }
+# else /* !__cplusplus */
+# define HB_BEGIN_DECLS
+# define HB_END_DECLS
+# endif /* !__cplusplus */
+
+typedef int hb_bool_t;
+
+typedef uint32_t hb_tag_t;
+#define HB_TAG(a,b,c,d) ((hb_tag_t)(((uint8_t)a<<24)|((uint8_t)b<<16)|((uint8_t)c<<8)|(uint8_t)d))
+#define HB_TAG_STR(s) (HB_TAG(((const char *) s)[0], \
+ ((const char *) s)[1], \
+ ((const char *) s)[2], \
+ ((const char *) s)[3]))
+#define HB_TAG_NONE HB_TAG(0,0,0,0)
+
+hb_tag_t hb_tag_from_string (const char *s);
+
+
+typedef uint32_t hb_codepoint_t;
+typedef int32_t hb_position_t;
+typedef uint32_t hb_mask_t;
+
+typedef void (*hb_destroy_func_t) (void *user_data);
+
+typedef enum _hb_direction_t {
+ HB_DIRECTION_LTR,
+ HB_DIRECTION_RTL,
+ HB_DIRECTION_TTB,
+ HB_DIRECTION_BTT
+} hb_direction_t;
+
+#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 0)
+#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 2)
+#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 0)
+#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 1)
+#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1))
+
+
+#endif /* HB_COMMON_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-font-private.hh
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 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_FONT_PRIVATE_H
+#define HB_FONT_PRIVATE_H
+
+#include "hb-private.h"
+
+#include "hb-font.h"
+
+#include "hb-ot-head-private.hh"
+
+HB_BEGIN_DECLS
+
+/*
+ * hb_font_funcs_t
+ */
+
+struct _hb_font_funcs_t {
+ hb_reference_count_t ref_count;
+
+ hb_bool_t immutable;
+
+ struct {
+ hb_font_get_glyph_func_t get_glyph;
+ hb_font_get_contour_point_func_t get_contour_point;
+ hb_font_get_glyph_metrics_func_t get_glyph_metrics;
+ hb_font_get_kerning_func_t get_kerning;
+ } v;
+};
+
+extern HB_INTERNAL hb_font_funcs_t _hb_font_funcs_nil;
+
+
+/*
+ * hb_face_t
+ */
+
+struct _hb_face_t {
+ hb_reference_count_t ref_count;
+
+ hb_get_table_func_t get_table;
+ hb_destroy_func_t destroy;
+ void *user_data;
+
+ hb_blob_t *head_blob;
+ const struct head *head_table;
+
+ struct hb_ot_layout_t *ot_layout;
+};
+
+
+/*
+ * hb_font_t
+ */
+
+struct _hb_font_t {
+ hb_reference_count_t ref_count;
+
+ unsigned int x_scale;
+ unsigned int y_scale;
+
+ unsigned int x_ppem;
+ unsigned int y_ppem;
+
+ hb_font_funcs_t *klass;
+ hb_destroy_func_t destroy;
+ void *user_data;
+};
+
+
+HB_END_DECLS
+
+#endif /* HB_FONT_PRIVATE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-font.cc
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 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
+ */
+
+#include "hb-private.h"
+
+#include "hb-font-private.hh"
+#include "hb-blob-private.h"
+#include "hb-open-file-private.hh"
+
+#include "hb-ot-layout-private.hh"
+
+#include <string.h>
+
+
+/*
+ * hb_font_funcs_t
+ */
+
+static hb_codepoint_t
+hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data HB_UNUSED,
+ hb_codepoint_t unicode HB_UNUSED,
+ hb_codepoint_t variation_selector HB_UNUSED)
+{ return 0; }
+
+static hb_bool_t
+hb_font_get_contour_point_nil (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data HB_UNUSED,
+ unsigned int point_index HB_UNUSED,
+ hb_codepoint_t glyph HB_UNUSED,
+ hb_position_t *x HB_UNUSED,
+ hb_position_t *y HB_UNUSED)
+{ return false; }
+
+static void
+hb_font_get_glyph_metrics_nil (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data HB_UNUSED,
+ hb_codepoint_t glyph HB_UNUSED,
+ hb_glyph_metrics_t *metrics HB_UNUSED)
+{ }
+
+static hb_position_t
+hb_font_get_kerning_nil (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data HB_UNUSED,
+ hb_codepoint_t first_glyph HB_UNUSED,
+ hb_codepoint_t second_glyph HB_UNUSED)
+{ return 0; }
+
+hb_font_funcs_t _hb_font_funcs_nil = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+ TRUE, /* immutable */
+ {
+ hb_font_get_glyph_nil,
+ hb_font_get_contour_point_nil,
+ hb_font_get_glyph_metrics_nil,
+ hb_font_get_kerning_nil
+ }
+};
+
+hb_font_funcs_t *
+hb_font_funcs_create (void)
+{
+ hb_font_funcs_t *ffuncs;
+
+ if (!HB_OBJECT_DO_CREATE (hb_font_funcs_t, ffuncs))
+ return &_hb_font_funcs_nil;
+
+ ffuncs->v = _hb_font_funcs_nil.v;
+
+ return ffuncs;
+}
+
+hb_font_funcs_t *
+hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
+{
+ HB_OBJECT_DO_REFERENCE (ffuncs);
+}
+
+unsigned int
+hb_font_funcs_get_reference_count (hb_font_funcs_t *ffuncs)
+{
+ HB_OBJECT_DO_GET_REFERENCE_COUNT (ffuncs);
+}
+
+void
+hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
+{
+ HB_OBJECT_DO_DESTROY (ffuncs);
+
+ free (ffuncs);
+}
+
+hb_font_funcs_t *
+hb_font_funcs_copy (hb_font_funcs_t *other_ffuncs)
+{
+ hb_font_funcs_t *ffuncs;
+
+ if (!HB_OBJECT_DO_CREATE (hb_font_funcs_t, ffuncs))
+ return &_hb_font_funcs_nil;
+
+ ffuncs->v = other_ffuncs->v;
+
+ return ffuncs;
+}
+
+void
+hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
+{
+ if (HB_OBJECT_IS_INERT (ffuncs))
+ return;
+
+ ffuncs->immutable = TRUE;
+}
+
+
+void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_func_t glyph_func)
+{
+ if (ffuncs->immutable)
+ return;
+
+ ffuncs->v.get_glyph = glyph_func ? glyph_func : hb_font_get_glyph_nil;
+}
+
+void
+hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_contour_point_func_t contour_point_func)
+{
+ if (ffuncs->immutable)
+ return;
+
+ ffuncs->v.get_contour_point = contour_point_func ? contour_point_func : hb_font_get_contour_point_nil;
+}
+
+void
+hb_font_funcs_set_glyph_metrics_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_metrics_func_t glyph_metrics_func)
+{
+ if (ffuncs->immutable)
+ return;
+
+ ffuncs->v.get_glyph_metrics = glyph_metrics_func ? glyph_metrics_func : hb_font_get_glyph_metrics_nil;
+}
+
+void
+hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_kerning_func_t kerning_func)
+{
+ if (ffuncs->immutable)
+ return;
+
+ ffuncs->v.get_kerning = kerning_func ? kerning_func : hb_font_get_kerning_nil;
+}
+
+
+hb_codepoint_t
+hb_font_get_glyph (hb_font_t *font, hb_face_t *face,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector)
+{
+ return font->klass->v.get_glyph (font, face, font->user_data,
+ unicode, variation_selector);
+}
+
+hb_bool_t
+hb_font_get_contour_point (hb_font_t *font, hb_face_t *face,
+ unsigned int point_index,
+ hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y)
+{
+ *x = 0; *y = 0;
+ return font->klass->v.get_contour_point (font, face, font->user_data,
+ point_index,
+ glyph, x, y);
+}
+
+void
+hb_font_get_glyph_metrics (hb_font_t *font, hb_face_t *face,
+ hb_codepoint_t glyph, hb_glyph_metrics_t *metrics)
+{
+ memset (metrics, 0, sizeof (*metrics));
+ return font->klass->v.get_glyph_metrics (font, face, font->user_data,
+ glyph, metrics);
+}
+
+hb_position_t
+hb_font_get_kerning (hb_font_t *font, hb_face_t *face,
+ hb_codepoint_t first_glyph, hb_codepoint_t second_glyph)
+{
+ return font->klass->v.get_kerning (font, face, font->user_data,
+ first_glyph, second_glyph);
+}
+
+
+/*
+ * hb_face_t
+ */
+
+static hb_face_t _hb_face_nil = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+
+ NULL, /* get_table */
+ NULL, /* destroy */
+ NULL, /* user_data */
+
+ NULL, /* head_blob */
+ NULL, /* head_table */
+
+ NULL /* ot_layout */
+};
+
+
+hb_face_t *
+hb_face_create_for_tables (hb_get_table_func_t get_table,
+ hb_destroy_func_t destroy,
+ void *user_data)
+{
+ hb_face_t *face;
+
+ if (!HB_OBJECT_DO_CREATE (hb_face_t, face)) {
+ if (destroy)
+ destroy (user_data);
+ return &_hb_face_nil;
+ }
+
+ face->get_table = get_table;
+ face->destroy = destroy;
+ face->user_data = user_data;
+
+ face->ot_layout = _hb_ot_layout_new (face);
+
+ face->head_blob = Sanitizer<head>::sanitize (hb_face_get_table (face, HB_OT_TAG_head));
+ face->head_table = Sanitizer<head>::lock_instance (face->head_blob);
+
+ return face;
+}
+
+
+typedef struct _hb_face_for_data_closure_t {
+ hb_blob_t *blob;
+ unsigned int index;
+} hb_face_for_data_closure_t;
+
+static hb_face_for_data_closure_t *
+_hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
+{
+ hb_face_for_data_closure_t *closure;
+
+ closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t));
+ if (unlikely (!closure))
+ return NULL;
+
+ closure->blob = hb_blob_reference (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_get_table (hb_tag_t tag, void *user_data)
+{
+ hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data;
+
+ const OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob);
+ const OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
+
+ const OpenTypeTable &table = ot_face.get_table_by_tag (tag);
+
+ hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
+
+ hb_blob_unlock (data->blob);
+
+ return blob;
+}
+
+hb_face_t *
+hb_face_create_for_data (hb_blob_t *blob,
+ unsigned int index)
+{
+ hb_blob_reference (blob);
+ hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (blob), index);
+ hb_blob_destroy (blob);
+
+ if (unlikely (!closure))
+ return &_hb_face_nil;
+
+ return hb_face_create_for_tables (_hb_face_for_data_get_table,
+ (hb_destroy_func_t) _hb_face_for_data_closure_destroy,
+ closure);
+}
+
+
+hb_face_t *
+hb_face_reference (hb_face_t *face)
+{
+ HB_OBJECT_DO_REFERENCE (face);
+}
+
+unsigned int
+hb_face_get_reference_count (hb_face_t *face)
+{
+ HB_OBJECT_DO_GET_REFERENCE_COUNT (face);
+}
+
+void
+hb_face_destroy (hb_face_t *face)
+{
+ HB_OBJECT_DO_DESTROY (face);
+
+ _hb_ot_layout_free (face->ot_layout);
+
+ hb_blob_unlock (face->head_blob);
+ hb_blob_destroy (face->head_blob);
+
+ if (face->destroy)
+ face->destroy (face->user_data);
+
+ free (face);
+}
+
+hb_blob_t *
+hb_face_get_table (hb_face_t *face,
+ hb_tag_t tag)
+{
+ hb_blob_t *blob;
+
+ if (unlikely (!face || !face->get_table))
+ return &_hb_blob_nil;
+
+ blob = face->get_table (tag, face->user_data);
+
+ return blob;
+}
+
+
+/*
+ * hb_font_t
+ */
+
+static hb_font_t _hb_font_nil = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+
+ 0, /* x_scale */
+ 0, /* y_scale */
+
+ 0, /* x_ppem */
+ 0, /* y_ppem */
+
+ NULL, /* klass */
+ NULL, /* destroy */
+ NULL /* user_data */
+};
+
+hb_font_t *
+hb_font_create (void)
+{
+ hb_font_t *font;
+
+ if (!HB_OBJECT_DO_CREATE (hb_font_t, font))
+ return &_hb_font_nil;
+
+ font->klass = &_hb_font_funcs_nil;
+
+ return font;
+}
+
+hb_font_t *
+hb_font_reference (hb_font_t *font)
+{
+ HB_OBJECT_DO_REFERENCE (font);
+}
+
+unsigned int
+hb_font_get_reference_count (hb_font_t *font)
+{
+ HB_OBJECT_DO_GET_REFERENCE_COUNT (font);
+}
+
+void
+hb_font_destroy (hb_font_t *font)
+{
+ HB_OBJECT_DO_DESTROY (font);
+
+ hb_font_funcs_destroy (font->klass);
+ if (font->destroy)
+ font->destroy (font->user_data);
+
+ free (font);
+}
+
+void
+hb_font_set_funcs (hb_font_t *font,
+ hb_font_funcs_t *klass,
+ hb_destroy_func_t destroy,
+ void *user_data)
+{
+ if (HB_OBJECT_IS_INERT (font))
+ return;
+
+ if (font->destroy)
+ font->destroy (font->user_data);
+
+ if (!klass)
+ klass = &_hb_font_funcs_nil;
+
+ hb_font_funcs_reference (klass);
+ hb_font_funcs_destroy (font->klass);
+ font->klass = klass;
+ font->destroy = destroy;
+ font->user_data = user_data;
+}
+
+void
+hb_font_set_scale (hb_font_t *font,
+ unsigned int x_scale,
+ unsigned int y_scale)
+{
+ if (HB_OBJECT_IS_INERT (font))
+ return;
+
+ font->x_scale = x_scale;
+ font->y_scale = y_scale;
+}
+
+void
+hb_font_set_ppem (hb_font_t *font,
+ unsigned int x_ppem,
+ unsigned int y_ppem)
+{
+ if (HB_OBJECT_IS_INERT (font))
+ return;
+
+ font->x_ppem = x_ppem;
+ font->y_ppem = y_ppem;
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-font.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 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_FONT_H
+#define HB_FONT_H
+
+#include "hb-common.h"
+#include "hb-blob.h"
+
+HB_BEGIN_DECLS
+
+typedef struct _hb_face_t hb_face_t;
+typedef struct _hb_font_t hb_font_t;
+
+/*
+ * hb_face_t
+ */
+
+hb_face_t *
+hb_face_create_for_data (hb_blob_t *blob,
+ unsigned int index);
+
+typedef hb_blob_t * (*hb_get_table_func_t) (hb_tag_t tag, void *user_data);
+
+/* calls destroy() when not needing user_data anymore */
+hb_face_t *
+hb_face_create_for_tables (hb_get_table_func_t get_table,
+ hb_destroy_func_t destroy,
+ void *user_data);
+
+hb_face_t *
+hb_face_reference (hb_face_t *face);
+
+unsigned int
+hb_face_get_reference_count (hb_face_t *face);
+
+void
+hb_face_destroy (hb_face_t *face);
+
+/* Returns NULL if not found */
+hb_blob_t *
+hb_face_get_table (hb_face_t *face,
+ hb_tag_t tag);
+
+
+/*
+ * hb_font_funcs_t
+ */
+
+typedef struct _hb_font_funcs_t hb_font_funcs_t;
+
+hb_font_funcs_t *
+hb_font_funcs_create (void);
+
+hb_font_funcs_t *
+hb_font_funcs_reference (hb_font_funcs_t *ffuncs);
+
+unsigned int
+hb_font_funcs_get_reference_count (hb_font_funcs_t *ffuncs);
+
+void
+hb_font_funcs_destroy (hb_font_funcs_t *ffuncs);
+
+hb_font_funcs_t *
+hb_font_funcs_copy (hb_font_funcs_t *ffuncs);
+
+void
+hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs);
+
+
+/* funcs */
+
+typedef struct _hb_glyph_metrics_t
+{
+ hb_position_t x_advance;
+ hb_position_t y_advance;
+ hb_position_t x_offset;
+ hb_position_t y_offset;
+ hb_position_t width;
+ hb_position_t height;
+} hb_glyph_metrics_t;
+
+typedef hb_codepoint_t (*hb_font_get_glyph_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector);
+typedef hb_bool_t (*hb_font_get_contour_point_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
+ unsigned int point_index,
+ hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y);
+typedef void (*hb_font_get_glyph_metrics_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
+ hb_codepoint_t glyph, hb_glyph_metrics_t *metrics);
+typedef hb_position_t (*hb_font_get_kerning_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data,
+ hb_codepoint_t first_glyph, hb_codepoint_t second_glyph);
+
+
+void
+hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_func_t glyph_func);
+
+void
+hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_contour_point_func_t contour_point_func);
+
+void
+hb_font_funcs_set_glyph_metrics_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_metrics_func_t glyph_metrics_func);
+
+void
+hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_kerning_func_t kerning_func);
+
+
+hb_codepoint_t
+hb_font_get_glyph (hb_font_t *font, hb_face_t *face,
+ hb_codepoint_t unicode, hb_codepoint_t variation_selector);
+
+hb_bool_t
+hb_font_get_contour_point (hb_font_t *font, hb_face_t *face,
+ unsigned int point_index,
+ hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y);
+
+void
+hb_font_get_glyph_metrics (hb_font_t *font, hb_face_t *face,
+ hb_codepoint_t glyph, hb_glyph_metrics_t *metrics);
+
+hb_position_t
+hb_font_get_kerning (hb_font_t *font, hb_face_t *face,
+ hb_codepoint_t first_glyph, hb_codepoint_t second_glyph);
+
+
+/*
+ * hb_font_t
+ */
+
+/* Fonts are very light-weight objects */
+
+hb_font_t *
+hb_font_create (void);
+
+hb_font_t *
+hb_font_reference (hb_font_t *font);
+
+unsigned int
+hb_font_get_reference_count (hb_font_t *font);
+
+void
+hb_font_destroy (hb_font_t *font);
+
+void
+hb_font_set_funcs (hb_font_t *font,
+ hb_font_funcs_t *klass,
+ hb_destroy_func_t destroy,
+ void *user_data);
+
+hb_font_funcs_t *
+hb_font_get_funcs (hb_font_t *font);
+
+
+/*
+ * We should add support for full matrices.
+ */
+void
+hb_font_set_scale (hb_font_t *font,
+ unsigned int x_scale,
+ unsigned int y_scale);
+
+/*
+ * A zero value means "no hinting in that direction"
+ */
+void
+hb_font_set_ppem (hb_font_t *font,
+ unsigned int x_ppem,
+ unsigned int y_ppem);
+
+
+HB_END_DECLS
+
+#endif /* HB_FONT_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ft.cc
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Keith Stribley <devel@thanlwinsoft.org>
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE 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
+ */
+
+#include "hb-private.h"
+
+#include "hb-ft.h"
+
+#include "hb-font-private.hh"
+
+#include FT_TRUETYPE_TABLES_H
+
+static hb_codepoint_t
+hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector)
+{
+ FT_Face ft_face = (FT_Face) user_data;
+
+#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX
+ if (unlikely (variation_selector)) {
+ hb_codepoint_t glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector);
+ if (glyph)
+ return glyph;
+ }
+#endif
+
+ return FT_Get_Char_Index (ft_face, unicode);
+}
+
+static hb_bool_t
+hb_ft_get_contour_point (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data,
+ unsigned int point_index,
+ hb_codepoint_t glyph,
+ hb_position_t *x,
+ hb_position_t *y)
+{
+ FT_Face ft_face = (FT_Face) user_data;
+ int load_flags = FT_LOAD_DEFAULT;
+
+ /* TODO: load_flags, embolden, etc */
+
+ if (unlikely (FT_Load_Glyph (ft_face, glyph, 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 void
+hb_ft_get_glyph_metrics (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data,
+ hb_codepoint_t glyph,
+ hb_glyph_metrics_t *metrics)
+{
+ FT_Face ft_face = (FT_Face) user_data;
+ int load_flags = FT_LOAD_DEFAULT;
+
+ /* TODO: load_flags, embolden, etc */
+
+ metrics->x_advance = metrics->y_advance = 0;
+ metrics->x_offset = metrics->y_offset = 0;
+ metrics->width = metrics->height = 0;
+ if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags)))
+ {
+ /* TODO: A few negations should be in order here, not sure. */
+ metrics->x_advance = ft_face->glyph->advance.x;
+ metrics->y_advance = ft_face->glyph->advance.y;
+ metrics->x_offset = ft_face->glyph->metrics.horiBearingX;
+ metrics->y_offset = ft_face->glyph->metrics.horiBearingY;
+ metrics->width = ft_face->glyph->metrics.width;
+ metrics->height = ft_face->glyph->metrics.height;
+ }
+}
+
+static hb_position_t
+hb_ft_get_kerning (hb_font_t *font HB_UNUSED,
+ hb_face_t *face HB_UNUSED,
+ const void *user_data,
+ hb_codepoint_t first_glyph,
+ hb_codepoint_t second_glyph)
+{
+ FT_Face ft_face = (FT_Face) user_data;
+ FT_Vector kerning;
+
+ /* TODO: Kern type? */
+ if (FT_Get_Kerning (ft_face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &kerning))
+ return 0;
+
+ return kerning.x;
+}
+
+static hb_font_funcs_t ft_ffuncs = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+ TRUE, /* immutable */
+ {
+ hb_ft_get_glyph,
+ hb_ft_get_contour_point,
+ hb_ft_get_glyph_metrics,
+ hb_ft_get_kerning
+ }
+};
+
+hb_font_funcs_t *
+hb_ft_get_font_funcs (void)
+{
+ return &ft_ffuncs;
+}
+
+
+static hb_blob_t *
+_get_table (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;
+
+ if (unlikely (tag == HB_TAG_NONE))
+ return NULL;
+
+ error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
+ if (error)
+ return NULL;
+
+ /* TODO Use FT_Memory? */
+ 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,
+ free, buffer);
+}
+
+
+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,
+ /* TODO: Check FT_FACE_FLAG_EXTERNAL_STREAM? */
+ HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
+ destroy, ft_face);
+ face = hb_face_create_for_data (blob, ft_face->face_index);
+ hb_blob_destroy (blob);
+ } else {
+ face = hb_face_create_for_tables (_get_table, destroy, ft_face);
+ }
+
+ return face;
+}
+
+static void
+hb_ft_face_finalize (FT_Face ft_face)
+{
+ hb_face_destroy ((hb_face_t *) ft_face->generic.data);
+}
+
+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_font_t *
+hb_ft_font_create (FT_Face ft_face,
+ hb_destroy_func_t destroy)
+{
+ hb_font_t *font;
+
+ font = hb_font_create ();
+ hb_font_set_funcs (font,
+ hb_ft_get_font_funcs (),
+ destroy, ft_face);
+ hb_font_set_scale (font,
+ ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16,
+ ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16);
+ hb_font_set_ppem (font,
+ ft_face->size->metrics.x_ppem,
+ ft_face->size->metrics.y_ppem);
+
+ return font;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ft.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 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_FT_H
+#define HB_FT_H
+
+#include "hb.h"
+
+#include "hb-font.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+HB_BEGIN_DECLS
+
+hb_font_funcs_t *
+hb_ft_get_font_funcs (void);
+
+hb_face_t *
+hb_ft_face_create (FT_Face ft_face,
+ hb_destroy_func_t destroy);
+
+/* Note: This function is not thread-safe */
+hb_face_t *
+hb_ft_face_create_cached (FT_Face ft_face);
+
+hb_font_t *
+hb_ft_font_create (FT_Face ft_face,
+ hb_destroy_func_t destroy);
+
+HB_END_DECLS
+
+#endif /* HB_FT_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-glib.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 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
+ */
+
+#include "hb-private.h"
+
+#include "hb-glib.h"
+
+#include "hb-unicode-private.h"
+
+#include <glib.h>
+
+static hb_codepoint_t hb_glib_get_mirroring (hb_codepoint_t unicode) { g_unichar_get_mirror_char (unicode, &unicode); return unicode; }
+static hb_category_t hb_glib_get_general_category (hb_codepoint_t unicode) { return g_unichar_type (unicode); }
+static hb_script_t hb_glib_get_script (hb_codepoint_t unicode) { return g_unichar_get_script (unicode); }
+static unsigned int hb_glib_get_combining_class (hb_codepoint_t unicode) { return g_unichar_combining_class (unicode); }
+static unsigned int hb_glib_get_eastasian_width (hb_codepoint_t unicode) { return g_unichar_iswide (unicode); }
+
+
+static hb_unicode_funcs_t glib_ufuncs = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+ TRUE, /* immutable */
+ {
+ hb_glib_get_general_category,
+ hb_glib_get_combining_class,
+ hb_glib_get_mirroring,
+ hb_glib_get_script,
+ hb_glib_get_eastasian_width
+ }
+};
+
+hb_unicode_funcs_t *
+hb_glib_get_unicode_funcs (void)
+{
+ return &glib_ufuncs;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-glib.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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_GLIB_H
+#define HB_GLIB_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+hb_unicode_funcs_t *
+hb_glib_get_unicode_funcs (void);
+
+HB_END_DECLS
+
+#endif /* HB_GLIB_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-graphite.cc
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2009, Martin Hosken
+ * Copyright (C) 2009, 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.
+ */
+
+#include <graphite/GrClient.h>
+#include <graphite/ITextSource.h>
+#include <graphite/GrData.h>
+#include <graphite/GrConstants.h>
+#include <graphite/Segment.h>
+#include "hb-buffer-private.hh"
+#include "hb-font-private.hh"
+#include "hb-graphite.h"
+#include <map>
+
+namespace TtfUtil
+{
+extern int FontAscent(const void *pOS2);
+extern int FontDescent(const void *pOS2);
+extern int DesignUnits(const void *pHead);
+extern bool FontOs2Style(const void *pOS2, bool &fBold, bool &fItalic);
+}
+
+typedef struct _featureSetting {
+ unsigned int id;
+ int value;
+} featureSetting;
+
+class HbGrBufferTextSrc : public gr::ITextSource
+{
+public:
+ HbGrBufferTextSrc(hb_buffer_t *buff, hb_feature_t *feats, unsigned int num_features)
+ {
+ hb_feature_t *aFeat = feats;
+ featureSetting *aNewFeat;
+
+ buffer = hb_buffer_reference(buff);
+ features = new featureSetting[num_features];
+ nFeatures = num_features;
+ aNewFeat = features;
+ for (unsigned int i = 0; i < num_features; i++, aFeat++, aNewFeat++)
+ {
+ aNewFeat->id = aFeat->tag;
+ aNewFeat->value = aFeat->value;
+ }
+ };
+ ~HbGrBufferTextSrc() { hb_buffer_destroy(buffer); delete[] features; };
+ virtual gr::UtfType utfEncodingForm() { return gr::kutf32; };
+ virtual size_t getLength() { return buffer->len; };
+ virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf32 * prgchBuffer)
+ {
+ assert(cch <= buffer->len);
+ if (cch > buffer->len)
+ return 0;
+ for (unsigned int i = ichMin; i < ichMin + cch; i++)
+ prgchBuffer[i - ichMin] = buffer->info[i].codepoint;
+ return (cch - ichMin);
+ };
+ virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf16 * prgchBuffer) { return 0 ;};
+ virtual size_t fetch(gr::toffset ichMin, size_t cch, gr::utf8 * prgchBuffer) { return 0; };
+ virtual bool getRightToLeft(gr::toffset ich)
+ { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL; };
+ virtual unsigned int getDirectionDepth(gr::toffset ich)
+ { return hb_buffer_get_direction(buffer) == HB_DIRECTION_RTL ? 1 : 0; };
+ virtual float getVerticalOffset(gr::toffset ich) { return 0; };
+ virtual gr::isocode getLanguage(gr::toffset ich)
+ {
+ gr::isocode aLang;
+ char *p = (char *)(buffer->language);
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ if (p != NULL)
+ aLang.rgch[i] = *p;
+ else
+ aLang.rgch[i] = 0;
+ if (p && *p)
+ p++;
+ }
+ return aLang;
+ }
+
+ virtual std::pair<gr::toffset, gr::toffset> propertyRange(gr::toffset ich)
+ { return std::pair<gr::toffset, gr::toffset>(0, buffer->len); };
+ virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset)
+ {
+ featureSetting *aFeat = features;
+ for (unsigned int i = 0; i < nFeatures; i++, aFeat++, prgfset++)
+ {
+ prgfset->id = aFeat->id;
+ prgfset->value = aFeat->value;
+ }
+ return nFeatures;
+ }
+ virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2) {return true; };
+
+private:
+ hb_buffer_t *buffer;
+ featureSetting *features;
+ unsigned int nFeatures;
+};
+
+class HbGrFont : public gr::Font
+{
+public:
+ HbGrFont(hb_font_t *font, hb_face_t *face) : gr::Font()
+ { m_font = hb_font_reference(font); m_face = hb_face_reference(face); initfont(); };
+ ~HbGrFont()
+ {
+ std::map<hb_tag_t,hb_blob_t *>::iterator p = m_blobs.begin();
+ while (p != m_blobs.end())
+ { hb_blob_destroy((p++)->second); }
+ hb_font_destroy(m_font);
+ hb_face_destroy(m_face);
+ };
+ HbGrFont (const HbGrFont &font) : gr::Font(font)
+ {
+ *this = font;
+ m_blobs = std::map<hb_tag_t, hb_blob_t *>(font.m_blobs);
+ std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.begin();
+ while (p != m_blobs.end()) { hb_blob_reference((*p++).second); }
+ hb_font_reference(m_font);
+ hb_face_reference(m_face);
+ };
+ virtual HbGrFont *copyThis() { return new HbGrFont(*this); };
+ virtual bool bold() { return m_bold; };
+ virtual bool italic() { return m_italic; };
+ virtual float ascent() { float asc; getFontMetrics(&asc, NULL, NULL); return asc; };
+ virtual float descent() { float desc; getFontMetrics(NULL, &desc, NULL); return desc; };
+ virtual float height()
+ { float asc, desc; getFontMetrics(&asc, &desc, NULL); return (asc + desc); };
+ virtual unsigned int getDPIx() { return m_font->x_ppem; };
+ virtual unsigned int getDPIy() { return m_font->y_ppem; };
+ virtual const void *getTable(gr::fontTableId32 tableID, size_t *pcbsize)
+ {
+ hb_blob_t *blob;
+ std::map<hb_tag_t,hb_blob_t *>::iterator p=m_blobs.find((hb_tag_t)tableID);
+ if (p == m_blobs.end())
+ {
+ blob = hb_face_get_table(m_face, (hb_tag_t)tableID);
+ m_blobs[(hb_tag_t)tableID] = blob;
+ }
+ else
+ { blob = p->second; }
+
+ const char *res = hb_blob_lock(blob);
+ if (pcbsize)
+ *pcbsize = hb_blob_get_length(blob);
+ hb_blob_unlock(blob);
+ return (const void *)res;
+ }
+
+ virtual void getFontMetrics(float *pAscent, float *pDescent, float *pEmSquare)
+ {
+ if (pAscent) *pAscent = 1. * m_ascent * m_font->y_ppem / m_emsquare;
+ if (pDescent) *pDescent = 1. * m_descent * m_font->y_ppem / m_emsquare;
+ if (pEmSquare) *pEmSquare = m_font->x_scale;
+ }
+ virtual void getGlyphPoint(gr::gid16 glyphID, unsigned int pointNum, gr::Point &pointReturn)
+ {
+ hb_position_t x, y;
+ hb_font_get_contour_point(m_font, m_face, pointNum, glyphID, &x, &y);
+ pointReturn.x = (float)x;
+ pointReturn.y = (float)y;
+ }
+
+ virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect &boundingBox, gr::Point &advances)
+ {
+ hb_glyph_metrics_t metrics;
+ hb_font_get_glyph_metrics(m_font, m_face, glyphID, &metrics);
+ boundingBox.top = (metrics.y_offset + metrics.height);
+ boundingBox.bottom = metrics.y_offset;
+ boundingBox.left = metrics.x_offset;
+ boundingBox.right = (metrics.x_offset + metrics.width);
+ advances.x = metrics.x_advance;
+ advances.y = metrics.y_advance;
+// fprintf (stderr, "%d: (%d, %d, %d, %d)+(%d, %d)\n", glyphID, metrics.x_offset, metrics.y_offset, metrics.width, metrics.height, metrics.x_advance, metrics.y_advance);
+ }
+
+private:
+ HB_INTERNAL void initfont();
+
+ hb_font_t *m_font;
+ hb_face_t *m_face;
+ float m_ascent;
+ float m_descent;
+ float m_emsquare;
+ bool m_bold;
+ bool m_italic;
+ std::map<hb_tag_t, hb_blob_t *> m_blobs;
+};
+
+void HbGrFont::initfont()
+{
+ const void *pOS2 = getTable(gr::kttiOs2, NULL);
+ const void *pHead = getTable(gr::kttiHead, NULL);
+ TtfUtil::FontOs2Style(pOS2, m_bold, m_italic);
+ m_ascent = static_cast<float>(TtfUtil::FontAscent(pOS2));
+ m_descent = static_cast<float>(TtfUtil::FontDescent(pOS2));
+ m_emsquare = static_cast<float>(TtfUtil::DesignUnits(pHead));
+}
+
+void
+hb_graphite_shape (hb_font_t *font,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ hb_feature_t *features,
+ unsigned int num_features)
+{
+ /* create text source */
+ HbGrBufferTextSrc textSrc(buffer, features, num_features);
+
+ /* create grfont */
+ HbGrFont grfont(font, face);
+
+ /* create segment */
+ int *firsts;
+ bool *flags;
+ int numChars;
+ int numGlyphs;
+ gr::LayoutEnvironment layout;
+ std::pair<gr::GlyphIterator, gr::GlyphIterator>glyph_range;
+ gr::GlyphIterator iGlyph;
+ hb_codepoint_t *glyph_infos, *pGlyph;
+ hb_glyph_position_t *pPosition;
+ int cGlyph = 0;
+ int cChar = 0;
+
+ layout.setStartOfLine(0);
+ layout.setEndOfLine(0);
+ layout.setDumbFallback(true);
+ layout.setJustifier(NULL);
+ layout.setRightToLeft(false);
+
+ gr::RangeSegment pSegment(&grfont, &textSrc, &layout, (gr::toffset)0,
+ static_cast<gr::toffset>(buffer->len), (gr::Segment *)NULL);
+
+ /* fill in buffer from segment */
+ _hb_buffer_clear_output(buffer);
+ pSegment.getUniscribeClusters(NULL, 0, &numChars, NULL, 0, &numGlyphs);
+ firsts = new int[numChars];
+ flags = new bool[numGlyphs];
+ glyph_infos = new hb_codepoint_t[numGlyphs];
+ hb_buffer_ensure(buffer, numGlyphs);
+ pSegment.getUniscribeClusters(firsts, numChars, NULL, flags, numGlyphs, NULL);
+ glyph_range = pSegment.glyphs();
+ for (pGlyph = glyph_infos, iGlyph = glyph_range.first; iGlyph != glyph_range.second;
+ iGlyph++, pGlyph++)
+ { *pGlyph = iGlyph->glyphID(); }
+
+ while (cGlyph < numGlyphs)
+ {
+ if (flags[cGlyph])
+ {
+ int oldcChar = cChar++;
+ int oldcGlyph = cGlyph++;
+ while (cChar < numChars && firsts[cChar] == firsts[oldcChar]) cChar++;
+ while (cGlyph < numGlyphs && !flags[cGlyph]) cGlyph++;
+ _hb_buffer_add_output_glyphs(buffer, cChar - oldcChar, cGlyph - oldcGlyph,
+ glyph_infos + oldcGlyph, 0xFFFF, 0xFFFF);
+ }
+ else
+ { cGlyph++; } /* This should never happen */
+ }
+
+ float curradvx = 0., curradvy = 0.;
+ for (pPosition = hb_buffer_get_glyph_positions(buffer), iGlyph = glyph_range.first;
+ iGlyph != glyph_range.second; pPosition++, iGlyph++)
+ {
+ pPosition->x_offset = iGlyph->origin() - curradvx;
+ pPosition->y_offset = iGlyph->yOffset() - curradvy;
+ pPosition->x_advance = pPosition->x_offset + iGlyph->advanceWidth();
+ pPosition->y_advance = pPosition->y_offset + iGlyph->advanceHeight();
+ if (pPosition->x_advance < 0 && iGlyph->logicalIndex() != iGlyph->attachedClusterBase()->logicalIndex())
+ pPosition->x_advance = 0;
+ curradvx += pPosition->x_advance;
+ curradvy += pPosition->y_advance;
+// fprintf(stderr, "%d@(%f, %f)+(%f, %f)\n", iGlyph->glyphID(), iGlyph->origin(), iGlyph->yOffset(), iGlyph->advanceWidth(), iGlyph->advanceHeight());
+ }
+
+ delete[] glyph_infos;
+ delete[] firsts;
+ delete[] flags;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-graphite.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2009, Martin Hosken
+ * Copyright (C) 2009, 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.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_GRAPHITE_H
+#define HB_GRAPHITE_H
+
+#include "hb-shape.h"
+
+
+HB_BEGIN_DECLS
+
+#define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f')
+
+void hb_graphite_shape (hb_font_t *font,
+ hb_face_t *face,
+ hb_buffer_t *buffer,
+ hb_feature_t *features,
+ unsigned int num_features);
+
+HB_END_DECLS
+
+#endif /* HB_GRAPHITE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-icu.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Copyright (C) 2009 Keith Stribley <devel@thanlwinsoft.org>
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE 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
+ */
+
+#include "hb-private.h"
+
+#include "hb-icu.h"
+
+#include "hb-unicode-private.h"
+
+#include <unicode/uversion.h>
+#include <unicode/uchar.h>
+#include <unicode/uscript.h>
+
+static hb_codepoint_t hb_icu_get_mirroring (hb_codepoint_t unicode) { return u_charMirror(unicode); }
+static unsigned int hb_icu_get_combining_class (hb_codepoint_t unicode) { return u_getCombiningClass (unicode); }
+
+static unsigned int
+hb_icu_get_eastasian_width (hb_codepoint_t unicode)
+{
+ 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_category_t
+hb_icu_get_general_category (hb_codepoint_t unicode)
+{
+ switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
+ {
+ case U_UNASSIGNED: return HB_CATEGORY_UNASSIGNED;
+
+ case U_UPPERCASE_LETTER: return HB_CATEGORY_UPPERCASE_LETTER; /* Lu */
+ case U_LOWERCASE_LETTER: return HB_CATEGORY_LOWERCASE_LETTER; /* Ll */
+ case U_TITLECASE_LETTER: return HB_CATEGORY_TITLECASE_LETTER; /* Lt */
+ case U_MODIFIER_LETTER: return HB_CATEGORY_MODIFIER_LETTER; /* Lm */
+ case U_OTHER_LETTER: return HB_CATEGORY_OTHER_LETTER; /* Lo */
+
+ case U_NON_SPACING_MARK: return HB_CATEGORY_NON_SPACING_MARK; /* Mn */
+ case U_ENCLOSING_MARK: return HB_CATEGORY_ENCLOSING_MARK; /* Me */
+ case U_COMBINING_SPACING_MARK: return HB_CATEGORY_COMBINING_MARK; /* Mc */
+
+ case U_DECIMAL_DIGIT_NUMBER: return HB_CATEGORY_DECIMAL_NUMBER; /* Nd */
+ case U_LETTER_NUMBER: return HB_CATEGORY_LETTER_NUMBER; /* Nl */
+ case U_OTHER_NUMBER: return HB_CATEGORY_OTHER_NUMBER; /* No */
+
+ case U_SPACE_SEPARATOR: return HB_CATEGORY_SPACE_SEPARATOR; /* Zs */
+ case U_LINE_SEPARATOR: return HB_CATEGORY_LINE_SEPARATOR; /* Zl */
+ case U_PARAGRAPH_SEPARATOR: return HB_CATEGORY_PARAGRAPH_SEPARATOR; /* Zp */
+
+ case U_CONTROL_CHAR: return HB_CATEGORY_CONTROL; /* Cc */
+ case U_FORMAT_CHAR: return HB_CATEGORY_FORMAT; /* Cf */
+ case U_PRIVATE_USE_CHAR: return HB_CATEGORY_PRIVATE_USE; /* Co */
+ case U_SURROGATE: return HB_CATEGORY_SURROGATE; /* Cs */
+
+
+ case U_DASH_PUNCTUATION: return HB_CATEGORY_DASH_PUNCTUATION; /* Pd */
+ case U_START_PUNCTUATION: return HB_CATEGORY_OPEN_PUNCTUATION; /* Ps */
+ case U_END_PUNCTUATION: return HB_CATEGORY_CLOSE_PUNCTUATION; /* Pe */
+ case U_CONNECTOR_PUNCTUATION: return HB_CATEGORY_CONNECT_PUNCTUATION; /* Pc */
+ case U_OTHER_PUNCTUATION: return HB_CATEGORY_OTHER_PUNCTUATION; /* Po */
+
+ case U_MATH_SYMBOL: return HB_CATEGORY_MATH_SYMBOL; /* Sm */
+ case U_CURRENCY_SYMBOL: return HB_CATEGORY_CURRENCY_SYMBOL; /* Sc */
+ case U_MODIFIER_SYMBOL: return HB_CATEGORY_MODIFIER_SYMBOL; /* Sk */
+ case U_OTHER_SYMBOL: return HB_CATEGORY_OTHER_SYMBOL; /* So */
+
+ case U_INITIAL_PUNCTUATION: return HB_CATEGORY_INITIAL_PUNCTUATION; /* Pi */
+ case U_FINAL_PUNCTUATION: return HB_CATEGORY_FINAL_PUNCTUATION; /* Pf */
+ }
+
+ return HB_CATEGORY_UNASSIGNED;
+}
+
+static hb_script_t
+hb_icu_get_script (hb_codepoint_t unicode)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UScriptCode scriptCode = uscript_getScript(unicode, &status);
+ switch ((int) scriptCode)
+ {
+#define CHECK_ICU_VERSION(major, minor) \
+ U_ICU_VERSION_MAJOR_NUM > (major) || (U_ICU_VERSION_MAJOR_NUM == (major) && U_ICU_VERSION_MINOR_NUM >= (minor))
+#define MATCH_SCRIPT(C) case USCRIPT_##C: return HB_SCRIPT_##C
+#define MATCH_SCRIPT2(C1, C2) case USCRIPT_##C1: return HB_SCRIPT_##C2
+ MATCH_SCRIPT (INVALID_CODE);
+ MATCH_SCRIPT (COMMON); /* Zyyy */
+ MATCH_SCRIPT (INHERITED); /* Qaai */
+ MATCH_SCRIPT (ARABIC); /* Arab */
+ MATCH_SCRIPT (ARMENIAN); /* Armn */
+ MATCH_SCRIPT (BENGALI); /* Beng */
+ MATCH_SCRIPT (BOPOMOFO); /* Bopo */
+ MATCH_SCRIPT (CHEROKEE); /* Cher */
+ MATCH_SCRIPT (COPTIC); /* Qaac */
+ MATCH_SCRIPT (CYRILLIC); /* Cyrl (Cyrs) */
+ MATCH_SCRIPT (DESERET); /* Dsrt */
+ MATCH_SCRIPT (DEVANAGARI); /* Deva */
+ MATCH_SCRIPT (ETHIOPIC); /* Ethi */
+ MATCH_SCRIPT (GEORGIAN); /* Geor (Geon); Geoa) */
+ MATCH_SCRIPT (GOTHIC); /* Goth */
+ MATCH_SCRIPT (GREEK); /* Grek */
+ MATCH_SCRIPT (GUJARATI); /* Gujr */
+ MATCH_SCRIPT (GURMUKHI); /* Guru */
+ MATCH_SCRIPT (HAN); /* Hani */
+ MATCH_SCRIPT (HANGUL); /* Hang */
+ MATCH_SCRIPT (HEBREW); /* Hebr */
+ MATCH_SCRIPT (HIRAGANA); /* Hira */
+ MATCH_SCRIPT (KANNADA); /* Knda */
+ MATCH_SCRIPT (KATAKANA); /* Kana */
+ MATCH_SCRIPT (KHMER); /* Khmr */
+ MATCH_SCRIPT (LAO); /* Laoo */
+ MATCH_SCRIPT (LATIN); /* Latn (Latf); Latg) */
+ MATCH_SCRIPT (MALAYALAM); /* Mlym */
+ MATCH_SCRIPT (MONGOLIAN); /* Mong */
+ MATCH_SCRIPT (MYANMAR); /* Mymr */
+ MATCH_SCRIPT (OGHAM); /* Ogam */
+ MATCH_SCRIPT (OLD_ITALIC); /* Ital */
+ MATCH_SCRIPT (ORIYA); /* Orya */
+ MATCH_SCRIPT (RUNIC); /* Runr */
+ MATCH_SCRIPT (SINHALA); /* Sinh */
+ MATCH_SCRIPT (SYRIAC); /* Syrc (Syrj, Syrn); Syre) */
+ MATCH_SCRIPT (TAMIL); /* Taml */
+ MATCH_SCRIPT (TELUGU); /* Telu */
+ MATCH_SCRIPT (THAANA); /* Thaa */
+ MATCH_SCRIPT (THAI); /* Thai */
+ MATCH_SCRIPT (TIBETAN); /* Tibt */
+ MATCH_SCRIPT (CANADIAN_ABORIGINAL);/* Cans */
+ MATCH_SCRIPT (YI); /* Yiii */
+ MATCH_SCRIPT (TAGALOG); /* Tglg */
+ MATCH_SCRIPT (HANUNOO); /* Hano */
+ MATCH_SCRIPT (BUHID); /* Buhd */
+ MATCH_SCRIPT (TAGBANWA); /* Tagb */
+
+ /* Unicode-4.0 additions */
+ MATCH_SCRIPT (BRAILLE); /* Brai */
+ MATCH_SCRIPT (CYPRIOT); /* Cprt */
+ MATCH_SCRIPT (LIMBU); /* Limb */
+ MATCH_SCRIPT (OSMANYA); /* Osma */
+ MATCH_SCRIPT (SHAVIAN); /* Shaw */
+ MATCH_SCRIPT (LINEAR_B); /* Linb */
+ MATCH_SCRIPT (TAI_LE); /* Tale */
+ MATCH_SCRIPT (UGARITIC); /* Ugar */
+
+ /* Unicode-4.1 additions */
+ MATCH_SCRIPT (NEW_TAI_LUE); /* Talu */
+ MATCH_SCRIPT (BUGINESE); /* Bugi */
+ MATCH_SCRIPT (GLAGOLITIC); /* Glag */
+ MATCH_SCRIPT (TIFINAGH); /* Tfng */
+ MATCH_SCRIPT (SYLOTI_NAGRI); /* Sylo */
+ MATCH_SCRIPT (OLD_PERSIAN); /* Xpeo */
+ MATCH_SCRIPT (KHAROSHTHI); /* Khar */
+
+ /* Unicode-5.0 additions */
+ MATCH_SCRIPT (UNKNOWN); /* Zzzz */
+ MATCH_SCRIPT (BALINESE); /* Bali */
+ MATCH_SCRIPT (CUNEIFORM); /* Xsux */
+ MATCH_SCRIPT (PHOENICIAN); /* Phnx */
+ MATCH_SCRIPT (PHAGS_PA); /* Phag */
+ MATCH_SCRIPT (NKO); /* Nkoo */
+
+ /* Unicode-5.1 additions */
+ MATCH_SCRIPT (KAYAH_LI); /* Kali */
+ MATCH_SCRIPT (LEPCHA); /* Lepc */
+ MATCH_SCRIPT (REJANG); /* Rjng */
+ MATCH_SCRIPT (SUNDANESE); /* Sund */
+ MATCH_SCRIPT (SAURASHTRA); /* Saur */
+ MATCH_SCRIPT (CHAM); /* Cham */
+ MATCH_SCRIPT (OL_CHIKI); /* Olck */
+ MATCH_SCRIPT (VAI); /* Vaii */
+ MATCH_SCRIPT (CARIAN); /* Cari */
+ MATCH_SCRIPT (LYCIAN); /* Lyci */
+ MATCH_SCRIPT (LYDIAN); /* Lydi */
+
+ /* Unicode-5.2 additions */
+ MATCH_SCRIPT (AVESTAN); /* Avst */
+#if CHECK_ICU_VERSION (4, 4)
+ MATCH_SCRIPT (BAMUM); /* Bamu */
+#endif
+ MATCH_SCRIPT (EGYPTIAN_HIEROGLYPHS); /* Egyp */
+ MATCH_SCRIPT (IMPERIAL_ARAMAIC); /* Armi */
+ MATCH_SCRIPT (INSCRIPTIONAL_PAHLAVI); /* Phli */
+ MATCH_SCRIPT (INSCRIPTIONAL_PARTHIAN); /* Prti */
+ MATCH_SCRIPT (JAVANESE); /* Java */
+ MATCH_SCRIPT (KAITHI); /* Kthi */
+ MATCH_SCRIPT2(LANNA, TAI_THAM); /* Lana */
+#if CHECK_ICU_VERSION (4, 4)
+ MATCH_SCRIPT (LISU); /* Lisu */
+#endif
+ MATCH_SCRIPT (MEITEI_MAYEK); /* Mtei */
+#if CHECK_ICU_VERSION (4, 4)
+ MATCH_SCRIPT (OLD_SOUTH_ARABIAN); /* Sarb */
+#endif
+ MATCH_SCRIPT2(ORKHON, OLD_TURKIC); /* Orkh */
+ MATCH_SCRIPT (SAMARITAN); /* Samr */
+ MATCH_SCRIPT (TAI_VIET); /* Tavt */
+ }
+ return HB_SCRIPT_UNKNOWN;
+}
+
+static hb_unicode_funcs_t icu_ufuncs = {
+ HB_REFERENCE_COUNT_INVALID, /* ref_count */
+ TRUE, /* immutable */
+ {
+ hb_icu_get_general_category,
+ hb_icu_get_combining_class,
+ hb_icu_get_mirroring,
+ hb_icu_get_script,
+ hb_icu_get_eastasian_width
+ }
+};
+
+hb_unicode_funcs_t *
+hb_icu_get_unicode_funcs (void)
+{
+ return &icu_ufuncs;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-icu.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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_ICU_H
+#define HB_ICU_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+hb_unicode_funcs_t *
+hb_icu_get_unicode_funcs (void);
+
+HB_END_DECLS
+
+#endif /* HB_ICU_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-language.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 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
+ */
+
+#include "hb-private.h"
+
+#include "hb-language.h"
+
+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 hb_bool_t
+lang_equal (const void *v1,
+ const void *v2)
+{
+ const unsigned char *p1 = v1;
+ const unsigned char *p2 = v2;
+
+ while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2])
+ {
+ p1++, p2++;
+ }
+
+ return (canon_map[*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
+
+
+hb_language_t
+hb_language_from_string (const char *str)
+{
+ static unsigned int num_langs;
+ static unsigned int num_alloced;
+ static const char **langs;
+ unsigned int i;
+ unsigned char *p;
+
+ /* TODO Use a hash table or something */
+
+ if (!str)
+ return NULL;
+
+ for (i = 0; i < num_langs; i++)
+ if (lang_equal (str, langs[i]))
+ return langs[i];
+
+ if (unlikely (num_langs == num_alloced)) {
+ unsigned int new_alloced = 2 * (8 + num_alloced);
+ const char **new_langs = realloc (langs, new_alloced * sizeof (langs[0]));
+ if (!new_langs)
+ return NULL;
+ num_alloced = new_alloced;
+ langs = new_langs;
+ }
+
+ langs[i] = strdup (str);
+ for (p = (unsigned char *) langs[i]; *p; p++)
+ *p = canon_map[*p];
+
+ num_langs++;
+
+ return (hb_language_t) langs[i];
+}
+
+const char *
+hb_language_to_string (hb_language_t language)
+{
+ return (const char *) language;
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-language.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 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_LANGUAGE_H
+#define HB_LANGUAGE_H
+
+#include "hb-common.h"
+
+HB_BEGIN_DECLS
+
+typedef const void *hb_language_t;
+
+hb_language_t
+hb_language_from_string (const char *str);
+
+const char *
+hb_language_to_string (hb_language_t language);
+
+HB_END_DECLS
+
+#endif /* HB_LANGUAGE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-object-private.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2007 Chris Wilson
+ * Copyright (C) 2009,2010 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.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ * Red Hat Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_REFCOUNT_PRIVATE_H
+#define HB_REFCOUNT_PRIVATE_H
+
+#include "hb-private.h"
+
+
+
+/* Encapsulate operations on the object's reference count */
+typedef struct {
+ hb_atomic_int_t ref_count;
+} hb_reference_count_t;
+
+#define hb_reference_count_inc(RC) hb_atomic_int_fetch_and_add ((RC).ref_count, 1)
+#define hb_reference_count_dec(RC) hb_atomic_int_fetch_and_add ((RC).ref_count, -1)
+
+#define HB_REFERENCE_COUNT_INIT(RC, VALUE) ((RC).ref_count = (VALUE))
+
+#define HB_REFERENCE_COUNT_GET_VALUE(RC) hb_atomic_int_get ((RC).ref_count)
+#define HB_REFERENCE_COUNT_SET_VALUE(RC, VALUE) hb_atomic_int_set ((RC).ref_count, (VALUE))
+
+#define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1)
+#define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE}
+
+#define HB_REFERENCE_COUNT_IS_INVALID(RC) (HB_REFERENCE_COUNT_GET_VALUE (RC) == HB_REFERENCE_COUNT_INVALID_VALUE)
+
+#define HB_REFERENCE_COUNT_HAS_REFERENCE(RC) (HB_REFERENCE_COUNT_GET_VALUE (RC) > 0)
+
+
+
+/* Debug */
+
+#ifndef HB_DEBUG_OBJECT
+#define HB_DEBUG_OBJECT HB_DEBUG+0
+#endif
+
+static inline void
+_hb_trace_object (const void *obj,
+ hb_reference_count_t *ref_count,
+ const char *function)
+{
+ if (HB_DEBUG_OBJECT)
+ fprintf (stderr, "OBJECT(%p) refcount=%d %s\n",
+ obj,
+ HB_REFERENCE_COUNT_GET_VALUE (*ref_count),
+ function);
+}
+
+#define TRACE_OBJECT(obj) _hb_trace_object (obj, &obj->ref_count, __FUNCTION__)
+
+
+
+/* Object allocation and lifecycle manamgement macros */
+
+#define HB_OBJECT_IS_INERT(obj) \
+ (unlikely (HB_REFERENCE_COUNT_IS_INVALID ((obj)->ref_count)))
+
+#define HB_OBJECT_DO_INIT_EXPR(obj) \
+ HB_REFERENCE_COUNT_INIT (obj->ref_count, 1)
+
+#define HB_OBJECT_DO_INIT(obj) \
+ HB_STMT_START { \
+ HB_OBJECT_DO_INIT_EXPR (obj); \
+ } HB_STMT_END
+
+#define HB_OBJECT_DO_CREATE(Type, obj) \
+ likely (( \
+ (void) ( \
+ ((obj) = (Type *) calloc (1, sizeof (Type))) && \
+ ( \
+ HB_OBJECT_DO_INIT_EXPR (obj), \
+ TRACE_OBJECT (obj), \
+ TRUE \
+ ) \
+ ), \
+ (obj) \
+ ))
+
+#define HB_OBJECT_DO_REFERENCE(obj) \
+ HB_STMT_START { \
+ int old_count; \
+ if (unlikely (!(obj) || HB_OBJECT_IS_INERT (obj))) \
+ return obj; \
+ TRACE_OBJECT (obj); \
+ old_count = hb_reference_count_inc (obj->ref_count); \
+ assert (old_count > 0); \
+ return obj; \
+ } HB_STMT_END
+
+#define HB_OBJECT_DO_GET_REFERENCE_COUNT(obj) \
+ HB_STMT_START { \
+ if (unlikely (!(obj) || HB_OBJECT_IS_INERT (obj))) \
+ return 0; \
+ return HB_REFERENCE_COUNT_GET_VALUE (obj->ref_count); \
+ } HB_STMT_END
+
+#define HB_OBJECT_DO_DESTROY(obj) \
+ HB_STMT_START { \
+ int old_count; \
+ if (unlikely (!(obj) || HB_OBJECT_IS_INERT (obj))) \
+ return; \
+ TRACE_OBJECT (obj); \
+ old_count = hb_reference_count_dec (obj->ref_count); \
+ assert (old_count > 0); \
+ if (old_count != 1) \
+ return; \
+ } HB_STMT_END
+
+
+
+#endif /* HB_REFCOUNT_PRIVATE_H */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-open-file-private.hh
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 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_OPEN_FILE_PRIVATE_HH
+#define HB_OPEN_FILE_PRIVATE_HH
+
+#include "hb-open-type-private.hh"
+
+
+/*
+ *
+ * The OpenType Font File
+ *
+ */
+
+
+/*
+ * Organization of an OpenType Font
+ */
+
+struct OpenTypeFontFile;
+struct OffsetTable;
+struct TTCHeader;
+
+
+typedef struct TableDirectory
+{
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return 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 TableDirectory& get_table (unsigned int i) const
+ {
+ if (unlikely (i >= numTables)) return Null(TableDirectory);
+ return tableDir[i];
+ }
+ inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
+ {
+ Tag t;
+ t.set (tag);
+ /* TODO: bsearch (need to sort in sanitize) */
+ unsigned int count = numTables;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (t == tableDir[i].tag)
+ {
+ if (table_index) *table_index = i;
+ return true;
+ }
+ }
+ if (table_index) *table_index = Index::NOT_FOUND_INDEX;
+ return false;
+ }
+ inline const TableDirectory& 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) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && c->check_array (tableDir, TableDirectory::static_size, numTables);
+ }
+
+ private:
+ Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
+ USHORT numTables; /* Number of tables. */
+ USHORT searchRange; /* (Maximum power of 2 <= numTables) x 16 */
+ USHORT entrySelector; /* Log2(maximum power of 2 <= numTables). */
+ USHORT rangeShift; /* NumTables x 16-searchRange. */
+ TableDirectory tableDir[VAR]; /* TableDirectory entries. numTables items */
+ public:
+ DEFINE_SIZE_ARRAY (12, tableDir);
+} 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) {
+ TRACE_SANITIZE ();
+ return table.sanitize (c, this);
+ }
+
+ private:
+ Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
+ FixedVersion version; /* Version of the TTC Header (1.0),
+ * 0x00010000 */
+ LongOffsetLongArrayOf<OffsetTable>
+ 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) {
+ 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) {
+ 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) {
+ TRACE_SANITIZE ();
+ if (unlikely (!u.header.version.sanitize (c))) return false;
+ switch (u.header.version) {
+ case 2: /* version 2 is compatible with version 1 */
+ case 1: return u.version1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ struct {
+ Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
+ FixedVersion version; /* Version of the TTC Header (1.0 or 2.0),
+ * 0x00010000 or 0x00020000 */
+ } header;
+ TTCHeaderVersion1 version1;
+ } u;
+};
+
+
+/*
+ * OpenType Font File
+ */
+
+struct OpenTypeFontFile
+{
+ 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) {
+ TRACE_SANITIZE ();
+ if (unlikely (!u.tag.sanitize (c))) return false;
+ switch (u.tag) {
+ case CFFTag: /* All the non-collection tags */
+ case TrueTag:
+ case Typ1Tag:
+ case TrueTypeTag: return u.fontFace.sanitize (c);
+ case TTCTag: return u.ttcHeader.sanitize (c);
+ default: return true;
+ }
+ }
+
+ private:
+ union {
+ Tag tag; /* 4-byte identifier. */
+ OpenTypeFontFace fontFace;
+ TTCHeader ttcHeader;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (4, tag);
+};
+
+
+#endif /* HB_OPEN_FILE_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-open-type-private.hh
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010 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_OPEN_TYPES_PRIVATE_HH
+#define HB_OPEN_TYPES_PRIVATE_HH
+
+#include "hb-private.h"
+
+#include "hb-blob.h"
+
+
+
+/*
+ * Casts
+ */
+
+/* Cast to struct T, reference to reference */
+template<typename Type, typename TObject>
+inline const Type& CastR(const TObject &X)
+{ return reinterpret_cast<const Type&> (X); }
+template<typename Type, typename TObject>
+inline Type& CastR(TObject &X)
+{ return reinterpret_cast<Type&> (X); }
+
+/* Cast to struct T, pointer to pointer */
+template<typename Type, typename TObject>
+inline const Type* CastP(const TObject *X)
+{ return reinterpret_cast<const Type*> (X); }
+template<typename Type, typename TObject>
+inline Type* CastP(TObject *X)
+{ return reinterpret_cast<Type*> (X); }
+
+/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
+ * location pointed to by P plus Ofs bytes. */
+template<typename Type>
+inline const Type& StructAtOffset(const void *P, unsigned int offset)
+{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
+template<typename Type>
+inline Type& StructAtOffset(void *P, unsigned int offset)
+{ return * reinterpret_cast<Type*> ((char *) P + offset); }
+
+/* StructAfter<T>(X) returns the struct T& that is placed after X.
+ * Works with X of variable size also. X must implement get_size() */
+template<typename Type, typename TObject>
+inline const Type& StructAfter(const TObject &X)
+{ return StructAtOffset<Type>(&X, X.get_size()); }
+template<typename Type, typename TObject>
+inline Type& StructAfter(TObject &X)
+{ return StructAtOffset<Type>(&X, X.get_size()); }
+
+
+
+/*
+ * Size checking
+ */
+
+/* Check _assertion in a method environment */
+#define _DEFINE_SIZE_ASSERTION(_assertion) \
+ inline void _size_assertion (void) const \
+ { ASSERT_STATIC (_assertion); }
+/* Check that _code compiles in a method environment */
+#define _DEFINE_COMPILES_ASSERTION(_code) \
+ inline void _compiles_assertion (void) const \
+ { _code; }
+
+
+#define DEFINE_SIZE_STATIC(size) \
+ _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size)); \
+ static const unsigned int static_size = (size); \
+ static const unsigned int min_size = (size)
+
+/* Size signifying variable-sized array */
+#define VAR 1
+
+#define DEFINE_SIZE_UNION(size, _member) \
+ _DEFINE_SIZE_ASSERTION (this->u._member.static_size == (size)); \
+ static const unsigned int min_size = (size)
+
+#define DEFINE_SIZE_MIN(size) \
+ _DEFINE_SIZE_ASSERTION (sizeof (*this) >= (size)); \
+ static const unsigned int min_size = (size)
+
+#define DEFINE_SIZE_ARRAY(size, array) \
+ _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
+ _DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
+ static const unsigned int min_size = (size)
+
+#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
+ _DEFINE_SIZE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
+ _DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
+ static const unsigned int min_size = (size)
+
+
+
+/*
+ * Null objects
+ */
+
+/* Global nul-content Null pool. Enlarge as necessary. */
+static const void *_NullPool[64 / sizeof (void *)];
+
+/* Generic nul-content Null objects. */
+template <typename Type>
+static inline const Type& Null () {
+ ASSERT_STATIC (Type::min_size <= sizeof (_NullPool));
+ return *CastP<Type> (_NullPool);
+}
+
+/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
+#define DEFINE_NULL_DATA(Type, data) \
+static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \
+template <> \
+inline const Type& Null<Type> () { \
+ return *CastP<Type> (_Null##Type); \
+} /* The following line really exists such that we end in a place needing semicolon */ \
+ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type))
+
+/* Accessor macro. */
+#define Null(Type) Null<Type>()
+
+
+/*
+ * Trace
+ */
+
+
+template <int max_depth>
+struct hb_trace_t {
+ explicit hb_trace_t (unsigned int *pdepth, const char *what, const char *function, const void *obj) : pdepth(pdepth) {
+ if (*pdepth < max_depth)
+ fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, *pdepth, *pdepth, function);
+ if (max_depth) ++*pdepth;
+ }
+ ~hb_trace_t (void) { if (max_depth) --*pdepth; }
+
+ private:
+ unsigned int *pdepth;
+};
+template <> /* Optimize when tracing is disabled */
+struct hb_trace_t<0> {
+ explicit hb_trace_t (unsigned int *pdepth HB_UNUSED, const char *what HB_UNUSED, const char *function HB_UNUSED, const void *obj HB_UNUSED) {}
+};
+
+
+
+/*
+ * Sanitize
+ */
+
+#ifndef HB_DEBUG_SANITIZE
+#define HB_DEBUG_SANITIZE HB_DEBUG+0
+#endif
+
+
+#define TRACE_SANITIZE() \
+ hb_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", HB_FUNC, this); \
+
+
+struct hb_sanitize_context_t
+{
+ inline void init (hb_blob_t *blob)
+ {
+ this->blob = hb_blob_reference (blob);
+ this->start = hb_blob_lock (blob);
+ this->end = this->start + hb_blob_get_length (blob);
+ this->writable = hb_blob_is_writable (blob);
+ this->edit_count = 0;
+ this->debug_depth = 0;
+
+ if (HB_DEBUG_SANITIZE)
+ fprintf (stderr, "sanitize %p init [%p..%p] (%u bytes)\n",
+ this->blob, this->start, this->end, this->end - this->start);
+ }
+
+ inline void finish (void)
+ {
+ if (HB_DEBUG_SANITIZE)
+ fprintf (stderr, "sanitize %p fini [%p..%p] %u edit requests\n",
+ this->blob, this->start, this->end, this->edit_count);
+
+ hb_blob_unlock (this->blob);
+ hb_blob_destroy (this->blob);
+ this->blob = NULL;
+ this->start = this->end = NULL;
+ }
+
+ inline bool check_range (const void *base, unsigned int len) const
+ {
+ const char *p = (const char *) base;
+ bool ret = this->start <= p &&
+ p <= this->end &&
+ (unsigned int) (this->end - p) >= len;
+
+ if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE) \
+ fprintf (stderr, "SANITIZE(%p) %-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
+ p,
+ this->debug_depth, this->debug_depth,
+ p, p + len, len,
+ this->start, this->end,
+ ret ? "pass" : "FAIL");
+
+ return likely (ret);
+ }
+
+ inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
+ {
+ const char *p = (const char *) base;
+ bool overflows = len >= ((unsigned int) -1) / record_size;
+
+ if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
+ fprintf (stderr, "SANITIZE(%p) %-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s\n", \
+ p,
+ this->debug_depth, this->debug_depth,
+ p, p + (record_size * len), record_size, len, (unsigned long) record_size * len,
+ this->start, this->end,
+ !overflows ? "does not overflow" : "OVERFLOWS FAIL");
+
+ return likely (!overflows && this->check_range (base, record_size * len));
+ }
+
+ template <typename Type>
+ inline bool check_struct (const Type *obj) const
+ {
+ return likely (this->check_range (obj, obj->min_size));
+ }
+
+ inline bool can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED)
+ {
+ const char *p = (const char *) base;
+ this->edit_count++;
+
+ if (HB_DEBUG_SANITIZE && (int) this->debug_depth < (int) HB_DEBUG_SANITIZE)
+ fprintf (stderr, "SANITIZE(%p) %-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s\n", \
+ p,
+ this->debug_depth, this->debug_depth,
+ this->edit_count,
+ p, p + len, len,
+ this->start, this->end,
+ this->writable ? "granted" : "REJECTED");
+
+ return this->writable;
+ }
+
+ unsigned int debug_depth;
+ const char *start, *end;
+ bool writable;
+ unsigned int edit_count;
+ hb_blob_t *blob;
+};
+
+
+
+/* Template to sanitize an object. */
+template <typename Type>
+struct Sanitizer
+{
+ static hb_blob_t *sanitize (hb_blob_t *blob) {
+ hb_sanitize_context_t c[1] = {{0}};
+ bool sane;
+
+ /* TODO is_sane() stuff */
+
+ if (!blob)
+ return hb_blob_create_empty ();
+
+ retry:
+ if (HB_DEBUG_SANITIZE)
+ fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC);
+
+ c->init (blob);
+
+ if (unlikely (!c->start)) {
+ c->finish ();
+ return blob;
+ }
+
+ Type *t = CastP<Type> (const_cast<char *> (c->start));
+
+ sane = t->sanitize (c);
+ if (sane) {
+ if (c->edit_count) {
+ if (HB_DEBUG_SANITIZE)
+ fprintf (stderr, "Sanitizer %p passed first round with %d edits; doing a second round %s\n",
+ blob, c->edit_count, HB_FUNC);
+
+ /* sanitize again to ensure no toe-stepping */
+ c->edit_count = 0;
+ sane = t->sanitize (c);
+ if (c->edit_count) {
+ if (HB_DEBUG_SANITIZE)
+ fprintf (stderr, "Sanitizer %p requested %d edits in second round; FAILLING %s\n",
+ blob, c->edit_count, HB_FUNC);
+ sane = false;
+ }
+ }
+ c->finish ();
+ } else {
+ unsigned int edit_count = c->edit_count;
+ c->finish ();
+ if (edit_count && !hb_blob_is_writable (blob) && hb_blob_try_writable (blob)) {
+ /* ok, we made it writable by relocating. try again */
+ if (HB_DEBUG_SANITIZE)
+ fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC);
+ goto retry;
+ }
+ }
+
+ if (HB_DEBUG_SANITIZE)
+ fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC);
+ if (sane)
+ return blob;
+ else {
+ hb_blob_destroy (blob);
+ return hb_blob_create_empty ();
+ }
+ }
+
+ static const Type* lock_instance (hb_blob_t *blob) {
+ const char *base = hb_blob_lock (blob);
+ return unlikely (!base) ? &Null(Type) : CastP<Type> (base);
+ }
+};
+
+
+
+
+/*
+ *
+ * The OpenType Font File: Data Types
+ */
+
+
+/* "The following data types are used in the OpenType font file.
+ * All OpenType fonts use Motorola-style byte ordering (Big Endian):" */
+
+/*
+ * Int types
+ */
+
+
+template <typename Type, int Bytes> class BEInt;
+
+/* LONGTERMTODO: On machines allowing unaligned access, we can make the
+ * following tighter by using byteswap instructions on ints directly. */
+template <typename Type>
+class BEInt<Type, 2>
+{
+ public:
+ inline class BEInt<Type,2>& operator = (Type i) { hb_be_uint16_put (v,i); return *this; }
+ inline operator Type () const { return hb_be_uint16_get (v); }
+ inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_cmp (v, o.v); }
+ inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
+ private: uint8_t v[2];
+};
+template <typename Type>
+class BEInt<Type, 4>
+{
+ public:
+ inline class BEInt<Type,4>& operator = (Type i) { hb_be_uint32_put (v,i); return *this; }
+ inline operator Type () const { return hb_be_uint32_get (v); }
+ inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_cmp (v, o.v); }
+ inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
+ private: uint8_t v[4];
+};
+
+/* Integer types in big-endian order and no alignment requirement */
+template <typename Type>
+struct IntType
+{
+ inline void set (Type i) { v = i; }
+ inline operator Type(void) const { return v; }
+ inline bool operator == (const IntType<Type> &o) const { return v == o.v; }
+ inline bool operator != (const IntType<Type> &o) const { return v != o.v; }
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return likely (c->check_struct (this));
+ }
+ protected:
+ BEInt<Type, sizeof (Type)> v;
+ public:
+ DEFINE_SIZE_STATIC (sizeof (Type));
+};
+
+typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */
+typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */
+typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */
+typedef IntType<int32_t> LONG; /* 32-bit signed integer. */
+
+/* Date represented in number of seconds since 12:00 midnight, January 1,
+ * 1904. The value is represented as a signed 64-bit integer. */
+struct LONGDATETIME
+{
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return likely (c->check_struct (this));
+ }
+ private:
+ LONG major;
+ ULONG minor;
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+/* Array of four uint8s (length = 32 bits) used to identify a script, language
+ * system, feature, or baseline */
+struct Tag : ULONG
+{
+ /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
+ inline operator const char* (void) const { return reinterpret_cast<const char *> (&this->v); }
+ inline operator char* (void) { return reinterpret_cast<char *> (&this->v); }
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+DEFINE_NULL_DATA (Tag, " ");
+
+/* Glyph index number, same as uint16 (length = 16 bits) */
+typedef USHORT GlyphID;
+
+/* Script/language-system/feature index */
+struct Index : USHORT {
+ static const unsigned int NOT_FOUND_INDEX = 0xFFFF;
+};
+DEFINE_NULL_DATA (Index, "\xff\xff");
+
+/* Offset to a table, same as uint16 (length = 16 bits), Null offset = 0x0000 */
+typedef USHORT Offset;
+
+/* LongOffset to a table, same as uint32 (length = 32 bits), Null offset = 0x00000000 */
+typedef ULONG LongOffset;
+
+
+/* CheckSum */
+struct CheckSum : ULONG
+{
+ static uint32_t CalcTableChecksum (ULONG *Table, uint32_t Length)
+ {
+ uint32_t Sum = 0L;
+ ULONG *EndPtr = Table+((Length+3) & ~3) / ULONG::static_size;
+
+ while (Table < EndPtr)
+ Sum += *Table++;
+ return Sum;
+ }
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+
+/*
+ * Version Numbers
+ */
+
+struct FixedVersion
+{
+ inline operator uint32_t (void) const { return (major << 16) + minor; }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ USHORT major;
+ USHORT minor;
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+
+
+/*
+ * Template subclasses of Offset and LongOffset that do the dereferencing.
+ * Use: (base+offset)
+ */
+
+template <typename OffsetType, typename Type>
+struct GenericOffsetTo : OffsetType
+{
+ inline const Type& operator () (const void *base) const
+ {
+ unsigned int offset = *this;
+ if (unlikely (!offset)) return Null(Type);
+ return StructAtOffset<Type> (base, offset);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ TRACE_SANITIZE ();
+ if (unlikely (!c->check_struct (this))) return false;
+ unsigned int offset = *this;
+ if (unlikely (!offset)) return true;
+ Type &obj = StructAtOffset<Type> (base, offset);
+ return likely (obj.sanitize (c)) || neuter (c);
+ }
+ template <typename T>
+ inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
+ TRACE_SANITIZE ();
+ if (unlikely (!c->check_struct (this))) return false;
+ unsigned int offset = *this;
+ if (unlikely (!offset)) return true;
+ Type &obj = StructAtOffset<Type> (base, offset);
+ return likely (obj.sanitize (c, user_data)) || neuter (c);
+ }
+
+ private:
+ /* Set the offset to Null */
+ inline bool neuter (hb_sanitize_context_t *c) {
+ if (c->can_edit (this, this->static_size)) {
+ this->set (0); /* 0 is Null offset */
+ return true;
+ }
+ return false;
+ }
+};
+template <typename Base, typename OffsetType, typename Type>
+inline const Type& operator + (const Base &base, GenericOffsetTo<OffsetType, Type> offset) { return offset (base); }
+
+template <typename Type>
+struct OffsetTo : GenericOffsetTo<Offset, Type> {};
+
+template <typename Type>
+struct LongOffsetTo : GenericOffsetTo<LongOffset, Type> {};
+
+
+/*
+ * Array Types
+ */
+
+template <typename LenType, typename Type>
+struct GenericArrayOf
+{
+ const Type *sub_array (unsigned int start_offset, unsigned int *pcount /* IN/OUT */) const
+ {
+ unsigned int count = len;
+ if (unlikely (start_offset > count))
+ count = 0;
+ else
+ count -= start_offset;
+ count = MIN (count, *pcount);
+ *pcount = count;
+ return array + start_offset;
+ }
+
+ inline const Type& operator [] (unsigned int i) const
+ {
+ if (unlikely (i >= len)) return Null(Type);
+ return array[i];
+ }
+ inline unsigned int get_size () const
+ { return len.static_size + len * Type::static_size; }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (unlikely (!sanitize_shallow (c))) return false;
+ /* Note: for structs that do not reference other structs,
+ * we do not need to call their sanitize() as we already did
+ * a bound check on the aggregate array size, hence the return.
+ */
+ return true;
+ /* We do keep this code though to make sure the structs pointed
+ * to do have a simple sanitize(), ie. they do not reference
+ * other structs. */
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ if (array[i].sanitize (c))
+ return false;
+ return true;
+ }
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ TRACE_SANITIZE ();
+ if (unlikely (!sanitize_shallow (c))) return false;
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!array[i].sanitize (c, base)))
+ return false;
+ return true;
+ }
+ template <typename T>
+ inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
+ TRACE_SANITIZE ();
+ if (unlikely (!sanitize_shallow (c))) return false;
+ unsigned int count = len;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!array[i].sanitize (c, base, user_data)))
+ return false;
+ return true;
+ }
+
+ private:
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && c->check_array (this, Type::static_size, len);
+ }
+
+ public:
+ LenType len;
+ Type array[VAR];
+ public:
+ DEFINE_SIZE_ARRAY (sizeof (LenType), array);
+};
+
+/* An array with a USHORT number of elements. */
+template <typename Type>
+struct ArrayOf : GenericArrayOf<USHORT, Type> {};
+
+/* An array with a ULONG number of elements. */
+template <typename Type>
+struct LongArrayOf : GenericArrayOf<ULONG, Type> {};
+
+/* Array of Offset's */
+template <typename Type>
+struct OffsetArrayOf : ArrayOf<OffsetTo<Type> > {};
+
+/* Array of LongOffset's */
+template <typename Type>
+struct LongOffsetArrayOf : ArrayOf<LongOffsetTo<Type> > {};
+
+/* LongArray of LongOffset's */
+template <typename Type>
+struct LongOffsetLongArrayOf : LongArrayOf<LongOffsetTo<Type> > {};
+
+/* Array of offsets relative to the beginning of the array itself. */
+template <typename Type>
+struct OffsetListOf : OffsetArrayOf<Type>
+{
+ inline const Type& operator [] (unsigned int i) const
+ {
+ if (unlikely (i >= this->len)) return Null(Type);
+ return this+this->array[i];
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return OffsetArrayOf<Type>::sanitize (c, this);
+ }
+ template <typename T>
+ inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
+ TRACE_SANITIZE ();
+ return OffsetArrayOf<Type>::sanitize (c, this, user_data);
+ }
+};
+
+
+/* An array with a USHORT number of elements,
+ * starting at second element. */
+template <typename Type>
+struct HeadlessArrayOf
+{
+ inline const Type& operator [] (unsigned int i) const
+ {
+ if (unlikely (i >= len || !i)) return Null(Type);
+ return array[i-1];
+ }
+ inline unsigned int get_size () const
+ { return len.static_size + (len ? len - 1 : 0) * Type::static_size; }
+
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+ return c->check_struct (this)
+ && c->check_array (this, Type::static_size, len);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (unlikely (!sanitize_shallow (c))) return false;
+ /* Note: for structs that do not reference other structs,
+ * we do not need to call their sanitize() as we already did
+ * a bound check on the aggregate array size, hence the return.
+ */
+ return true;
+ /* We do keep this code though to make sure the structs pointed
+ * to do have a simple sanitize(), ie. they do not reference
+ * other structs. */
+ unsigned int count = len ? len - 1 : 0;
+ Type *a = array;
+ for (unsigned int i = 0; i < count; i++)
+ if (unlikely (!a[i].sanitize (c)))
+ return false;
+ return true;
+ }
+
+ USHORT len;
+ Type array[VAR];
+ public:
+ DEFINE_SIZE_ARRAY (sizeof (USHORT), array);
+};
+
+
+#endif /* HB_OPEN_TYPE_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-head-private.hh
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 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_HEAD_PRIVATE_HH
+#define HB_OT_HEAD_PRIVATE_HH
+
+#include "hb-open-type-private.hh"
+
+/*
+ * head
+ */
+
+#define HB_OT_TAG_head HB_TAG('h','e','a','d')
+
+struct head
+{
+ static const hb_tag_t Tag = HB_OT_TAG_head;
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ /* Shall we check for magicNumber here? Who cares? */
+ return c->check_struct (this) && likely (version.major == 1);
+ }
+
+ FixedVersion version; /* Version of the head table--currently
+ * 0x00010000 for version 1.0. */
+ FixedVersion fontRevision; /* Set by font manufacturer. */
+ ULONG checkSumAdjustment; /* To compute: set it to 0, sum the
+ * entire font as ULONG, then store
+ * 0xB1B0AFBA - sum. */
+ ULONG magicNumber; /* Set to 0x5F0F3CF5. */
+ 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: Reserved, set to 0
+ * 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. */
+ SHORT indexToLocFormat; /* 0 for short offsets, 1 for long. */
+ SHORT glyphDataFormat; /* 0 for current format. */
+ public:
+ DEFINE_SIZE_STATIC (54);
+};
+
+
+#endif /* HB_OT_HEAD_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh
@@ -0,0 +1,627 @@
+/*
+ * Copyright (C) 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_LAYOUT_COMMON_PRIVATE_HH
+#define HB_OT_LAYOUT_COMMON_PRIVATE_HH
+
+#include "hb-ot-layout-private.hh"
+
+#include "hb-open-type-private.hh"
+
+
+#define NO_CONTEXT ((unsigned int) 0x110000)
+#define NOT_COVERED ((unsigned int) 0x110000)
+#define MAX_NESTING_LEVEL 8
+
+
+/*
+ *
+ * OpenType Layout Common Table Formats
+ *
+ */
+
+
+/*
+ * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList
+ */
+
+template <typename Type>
+struct Record
+{
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && offset.sanitize (c, base);
+ }
+
+ Tag tag; /* 4-byte Tag identifier */
+ OffsetTo<Type>
+ offset; /* Offset from beginning of object holding
+ * the Record */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+template <typename Type>
+struct RecordArrayOf : ArrayOf<Record<Type> > {
+ inline const Tag& get_tag (unsigned int i) const
+ {
+ if (unlikely (i >= this->len)) return Null(Tag);
+ return (*this)[i].tag;
+ }
+ inline unsigned int get_tags (unsigned int start_offset,
+ unsigned int *record_count /* IN/OUT */,
+ hb_tag_t *record_tags /* OUT */) const
+ {
+ if (record_count) {
+ const Record<Type> *array = this->sub_array (start_offset, record_count);
+ unsigned int count = *record_count;
+ for (unsigned int i = 0; i < count; i++)
+ record_tags[i] = array[i].tag;
+ }
+ return this->len;
+ }
+ inline bool find_index (hb_tag_t tag, unsigned int *index) const
+ {
+ Tag t;
+ t.set (tag);
+ /* TODO: bsearch (need to sort in sanitize) */
+ const Record<Type> *a = this->array;
+ unsigned int count = this->len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (t == a[i].tag)
+ {
+ if (index) *index = i;
+ return true;
+ }
+ }
+ if (index) *index = Index::NOT_FOUND_INDEX;
+ return false;
+ }
+};
+
+template <typename Type>
+struct RecordListOf : RecordArrayOf<Type>
+{
+ inline const Type& operator [] (unsigned int i) const
+ { return this+RecordArrayOf<Type>::operator [](i).offset; }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return RecordArrayOf<Type>::sanitize (c, this);
+ }
+};
+
+
+struct IndexArray : ArrayOf<Index>
+{
+ inline unsigned int get_indexes (unsigned int start_offset,
+ unsigned int *_count /* IN/OUT */,
+ unsigned int *_indexes /* OUT */) const
+ {
+ if (_count) {
+ const USHORT *array = this->sub_array (start_offset, _count);
+ unsigned int count = *_count;
+ for (unsigned int i = 0; i < count; i++)
+ _indexes[i] = array[i];
+ }
+ return this->len;
+ }
+};
+
+
+struct Script;
+struct LangSys;
+struct Feature;
+
+
+struct LangSys
+{
+ inline unsigned int get_feature_count (void) const
+ { return featureIndex.len; }
+ inline hb_tag_t get_feature_index (unsigned int i) const
+ { return featureIndex[i]; }
+ inline unsigned int get_feature_indexes (unsigned int start_offset,
+ unsigned int *feature_count /* IN/OUT */,
+ unsigned int *feature_indexes /* OUT */) const
+ { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
+
+ inline bool has_required_feature (void) const { return reqFeatureIndex != 0xffff; }
+ inline unsigned int get_required_feature_index (void) const
+ {
+ if (reqFeatureIndex == 0xffff)
+ return Index::NOT_FOUND_INDEX;
+ return reqFeatureIndex;;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && featureIndex.sanitize (c);
+ }
+
+ Offset lookupOrder; /* = Null (reserved for an offset to a
+ * reordering table) */
+ USHORT reqFeatureIndex;/* Index of a feature required for this
+ * language system--if no required features
+ * = 0xFFFF */
+ IndexArray featureIndex; /* Array of indices into the FeatureList */
+ public:
+ DEFINE_SIZE_ARRAY (6, featureIndex);
+};
+DEFINE_NULL_DATA (LangSys, "\0\0\xFF\xFF");
+
+
+struct Script
+{
+ 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 LangSys& 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 LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return defaultLangSys.sanitize (c, this)
+ && langSys.sanitize (c, this);
+ }
+
+ private:
+ OffsetTo<LangSys>
+ defaultLangSys; /* Offset to DefaultLangSys table--from
+ * beginning of Script table--may be Null */
+ RecordArrayOf<LangSys>
+ langSys; /* Array of LangSysRecords--listed
+ * alphabetically by LangSysTag */
+ public:
+ DEFINE_SIZE_ARRAY (4, langSys);
+};
+
+typedef RecordListOf<Script> ScriptList;
+
+
+struct Feature
+{
+ inline unsigned int get_lookup_count (void) const
+ { return lookupIndex.len; }
+ inline hb_tag_t get_lookup_index (unsigned int i) const
+ { return lookupIndex[i]; }
+ inline unsigned int get_lookup_indexes (unsigned int start_index,
+ unsigned int *lookup_count /* IN/OUT */,
+ unsigned int *lookup_tags /* OUT */) const
+ { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && lookupIndex.sanitize (c);
+ }
+
+ /* LONGTERMTODO: implement get_feature_parameters() */
+ /* LONGTERMTODO: implement FeatureSize and other special features? */
+ Offset featureParams; /* Offset to Feature Parameters table (if one
+ * has been defined for the feature), relative
+ * to the beginning of the Feature Table; = Null
+ * if not required */
+ IndexArray lookupIndex; /* Array of LookupList indices */
+ public:
+ DEFINE_SIZE_ARRAY (4, lookupIndex);
+};
+
+typedef RecordListOf<Feature> FeatureList;
+
+
+struct LookupFlag : USHORT
+{
+ enum {
+ RightToLeft = 0x0001u,
+ IgnoreBaseGlyphs = 0x0002u,
+ IgnoreLigatures = 0x0004u,
+ IgnoreMarks = 0x0008u,
+ IgnoreFlags = 0x000Eu,
+ UseMarkFilteringSet = 0x0010u,
+ Reserved = 0x00E0u,
+ MarkAttachmentType = 0xFF00u
+ };
+ public:
+ DEFINE_SIZE_STATIC (2);
+};
+
+struct Lookup
+{
+ inline unsigned int get_subtable_count (void) const { return subTable.len; }
+
+ inline unsigned int get_type (void) const { return lookupType; }
+ inline unsigned int get_flag (void) const
+ {
+ unsigned int flag = lookupFlag;
+ if (unlikely (flag & LookupFlag::UseMarkFilteringSet))
+ {
+ const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+ flag += (markFilteringSet << 16);
+ }
+ return flag;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ /* Real sanitize of the subtables is done by GSUB/GPOS/... */
+ if (!(c->check_struct (this)
+ && subTable.sanitize (c))) return false;
+ if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet))
+ {
+ USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+ if (!markFilteringSet.sanitize (c)) return false;
+ }
+ return true;
+ }
+
+ USHORT lookupType; /* Different enumerations for GSUB and GPOS */
+ USHORT lookupFlag; /* Lookup qualifiers */
+ ArrayOf<Offset>
+ subTable; /* Array of SubTables */
+ USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets
+ * structure. This field is only present if bit
+ * UseMarkFilteringSet of lookup flags is set. */
+ public:
+ DEFINE_SIZE_ARRAY2 (6, subTable, markFilteringSetX);
+};
+
+typedef OffsetListOf<Lookup> LookupList;
+
+
+/*
+ * Coverage Table
+ */
+
+struct CoverageFormat1
+{
+ friend struct Coverage;
+
+ private:
+ inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
+ {
+ if (unlikely (glyph_id > 0xFFFF))
+ return NOT_COVERED;
+ GlyphID gid;
+ gid.set (glyph_id);
+ /* TODO: bsearch (need to sort in sanitize) */
+ unsigned int num_glyphs = glyphArray.len;
+ for (unsigned int i = 0; i < num_glyphs; i++)
+ if (gid == glyphArray[i])
+ return i;
+ return NOT_COVERED;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return glyphArray.sanitize (c);
+ }
+
+ private:
+ USHORT coverageFormat; /* Format identifier--format = 1 */
+ ArrayOf<GlyphID>
+ glyphArray; /* Array of GlyphIDs--in numerical order */
+ public:
+ DEFINE_SIZE_ARRAY (4, glyphArray);
+};
+
+struct CoverageRangeRecord
+{
+ friend struct CoverageFormat2;
+
+ private:
+ inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
+ {
+ if (glyph_id >= start && glyph_id <= end)
+ return (unsigned int) startCoverageIndex + (glyph_id - start);
+ return NOT_COVERED;
+ }
+
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ private:
+ GlyphID start; /* First GlyphID in the range */
+ GlyphID end; /* Last GlyphID in the range */
+ USHORT startCoverageIndex; /* Coverage Index of first GlyphID in
+ * range */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+DEFINE_NULL_DATA (CoverageRangeRecord, "\000\001");
+
+struct CoverageFormat2
+{
+ friend struct Coverage;
+
+ private:
+ inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
+ {
+ /* TODO: bsearch (need to sort in sanitize) */
+ unsigned int count = rangeRecord.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ unsigned int coverage = rangeRecord[i].get_coverage (glyph_id);
+ if (coverage != NOT_COVERED)
+ return coverage;
+ }
+ return NOT_COVERED;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return rangeRecord.sanitize (c);
+ }
+
+ private:
+ USHORT coverageFormat; /* Format identifier--format = 2 */
+ ArrayOf<CoverageRangeRecord>
+ rangeRecord; /* Array of glyph ranges--ordered by
+ * Start GlyphID. rangeCount entries
+ * long */
+ public:
+ DEFINE_SIZE_ARRAY (4, rangeRecord);
+};
+
+struct Coverage
+{
+ inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); }
+
+ inline unsigned int get_coverage (hb_codepoint_t glyph_id) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.get_coverage(glyph_id);
+ case 2: return u.format2.get_coverage(glyph_id);
+ default:return NOT_COVERED;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ CoverageFormat1 format1;
+ CoverageFormat2 format2;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * Class Definition Table
+ */
+
+struct ClassDefFormat1
+{
+ friend struct ClassDef;
+
+ private:
+ inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
+ {
+ if ((unsigned int) (glyph_id - startGlyph) < classValue.len)
+ return classValue[glyph_id - startGlyph];
+ return 0;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && classValue.sanitize (c);
+ }
+
+ USHORT classFormat; /* Format identifier--format = 1 */
+ GlyphID startGlyph; /* First GlyphID of the classValueArray */
+ ArrayOf<USHORT>
+ classValue; /* Array of Class Values--one per GlyphID */
+ public:
+ DEFINE_SIZE_ARRAY (6, classValue);
+};
+
+struct ClassRangeRecord
+{
+ friend struct ClassDefFormat2;
+
+ private:
+ inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
+ {
+ if (glyph_id >= start && glyph_id <= end)
+ return classValue;
+ return 0;
+ }
+
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ private:
+ GlyphID start; /* First GlyphID in the range */
+ GlyphID end; /* Last GlyphID in the range */
+ USHORT classValue; /* Applied to all glyphs in the range */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+DEFINE_NULL_DATA (ClassRangeRecord, "\000\001");
+
+struct ClassDefFormat2
+{
+ friend struct ClassDef;
+
+ private:
+ inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
+ {
+ /* TODO: bsearch (need to sort in sanitize) */
+ unsigned int count = rangeRecord.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ int classValue = rangeRecord[i].get_class (glyph_id);
+ if (classValue > 0)
+ return classValue;
+ }
+ return 0;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return rangeRecord.sanitize (c);
+ }
+
+ USHORT classFormat; /* Format identifier--format = 2 */
+ ArrayOf<ClassRangeRecord>
+ rangeRecord; /* Array of glyph ranges--ordered by
+ * Start GlyphID */
+ public:
+ DEFINE_SIZE_ARRAY (4, rangeRecord);
+};
+
+struct ClassDef
+{
+ inline hb_ot_layout_class_t operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); }
+
+ inline hb_ot_layout_class_t get_class (hb_codepoint_t glyph_id) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.get_class(glyph_id);
+ case 2: return u.format2.get_class(glyph_id);
+ default:return 0;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ ClassDefFormat1 format1;
+ ClassDefFormat2 format2;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * Device Tables
+ */
+
+struct Device
+{
+ /* XXX speed up */
+
+ inline hb_position_t get_x_delta (hb_ot_layout_context_t *c) const
+ { return c->font->x_ppem ? get_delta (c->font->x_ppem) * (uint64_t) c->font->x_scale / c->font->x_ppem : 0; }
+
+ inline hb_position_t get_y_delta (hb_ot_layout_context_t *c) const
+ { return c->font->y_ppem ? get_delta (c->font->y_ppem) * (uint64_t) c->font->y_scale / c->font->y_ppem : 0; }
+
+ inline int get_delta (unsigned int ppem_size) const
+ {
+ unsigned int f = deltaFormat;
+ if (unlikely (f < 1 || f > 3))
+ return 0;
+
+ if (ppem_size < startSize || ppem_size > endSize)
+ return 0;
+
+ unsigned int s = ppem_size - startSize;
+
+ unsigned int byte = deltaValue[s >> (4 - f)];
+ unsigned int bits = (byte >> (16 - (((s & ((1 << (4 - f)) - 1)) + 1) << f)));
+ unsigned int mask = (0xFFFF >> (16 - (1 << f)));
+
+ int delta = bits & mask;
+
+ if ((unsigned int) delta >= ((mask + 1) >> 1))
+ delta -= mask + 1;
+
+ return delta;
+ }
+
+ inline unsigned int get_size () const
+ {
+ unsigned int f = deltaFormat;
+ if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
+ return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && c->check_range (this, this->get_size ());
+ }
+
+ private:
+ USHORT startSize; /* Smallest size to correct--in ppem */
+ USHORT endSize; /* Largest size to correct--in ppem */
+ USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3
+ * 1 Signed 2-bit value, 8 values per uint16
+ * 2 Signed 4-bit value, 4 values per uint16
+ * 3 Signed 8-bit value, 2 values per uint16
+ */
+ USHORT deltaValue[VAR]; /* Array of compressed data */
+ public:
+ DEFINE_SIZE_ARRAY (6, deltaValue);
+};
+
+
+#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-private.hh
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 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_LAYOUT_GDEF_PRIVATE_HH
+#define HB_OT_LAYOUT_GDEF_PRIVATE_HH
+
+#include "hb-ot-layout-common-private.hh"
+
+#include "hb-font-private.hh"
+
+
+/*
+ * 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) (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) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && attachPoint.sanitize (c, this);
+ }
+
+ private:
+ 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 int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id HB_UNUSED) const
+ {
+ /* TODO vertical */
+ return c->scale_x (coordinate);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ private:
+ 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 int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id) const
+ {
+ /* TODO vertical */
+ hb_position_t x, y;
+ if (hb_font_get_contour_point (c->font, c->face, caretValuePoint, glyph_id, &x, &y))
+ return x;
+ else
+ return 0;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ private:
+ USHORT caretValueFormat; /* Format identifier--format = 2 */
+ USHORT caretValuePoint; /* Contour point index on glyph */
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+struct CaretValueFormat3
+{
+ friend struct CaretValue;
+
+ inline int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id HB_UNUSED) const
+ {
+ /* TODO vertical */
+ return c->scale_x (coordinate) + ((this+deviceTable).get_x_delta (c));
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && deviceTable.sanitize (c, this);
+ }
+
+ private:
+ 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 int get_caret_value (hb_ot_layout_context_t *c, hb_codepoint_t glyph_id) const
+ {
+ switch (u.format) {
+ case 1: return u.format1.get_caret_value (c, glyph_id);
+ case 2: return u.format2.get_caret_value (c, glyph_id);
+ case 3: return u.format3.get_caret_value (c, glyph_id);
+ default:return 0;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ case 3: return u.format3.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ 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_ot_layout_context_t *c,
+ hb_codepoint_t glyph_id,
+ unsigned int start_offset,
+ unsigned int *caret_count /* IN/OUT */,
+ int *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 (c, glyph_id);
+ }
+
+ return carets.len;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return carets.sanitize (c, this);
+ }
+
+ private:
+ 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_ot_layout_context_t *c,
+ hb_codepoint_t glyph_id,
+ unsigned int start_offset,
+ unsigned int *caret_count /* IN/OUT */,
+ int *caret_array /* OUT */) const
+ {
+ unsigned int index = (this+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 (c, glyph_id, start_offset, caret_count, caret_array);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && ligGlyph.sanitize (c, this);
+ }
+
+ private:
+ 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) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ LongOffsetArrayOf<Coverage>
+ 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) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ MarkGlyphSetsFormat1 format1;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * GDEF
+ */
+
+struct GDEF
+{
+ static const hb_tag_t Tag = HB_OT_TAG_GDEF;
+
+ enum {
+ UnclassifiedGlyph = 0,
+ BaseGlyph = 1,
+ LigatureGlyph = 2,
+ MarkGlyph = 3,
+ ComponentGlyph = 4
+ };
+
+ inline bool has_glyph_classes () const { return glyphClassDef != 0; }
+ inline hb_ot_layout_class_t get_glyph_class (hb_codepoint_t glyph) const
+ { return (this+glyphClassDef).get_class (glyph); }
+
+ inline bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
+ inline hb_ot_layout_class_t get_mark_attachment_type (hb_codepoint_t glyph) const
+ { return (this+markAttachClassDef).get_class (glyph); }
+
+ inline bool has_attach_points () 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 () const { return ligCaretList != 0; }
+ inline unsigned int get_lig_carets (hb_ot_layout_context_t *c,
+ hb_codepoint_t glyph_id,
+ unsigned int start_offset,
+ unsigned int *caret_count /* IN/OUT */,
+ int *caret_array /* OUT */) const
+ { return (this+ligCaretList).get_lig_carets (c, glyph_id, start_offset, caret_count, caret_array); }
+
+ inline bool has_mark_sets () const { return version >= 0x00010002 && markGlyphSetsDef[0] != 0; }
+ inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+ { return version >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return version.sanitize (c) && likely (version.major == 1)
+ && glyphClassDef.sanitize (c, this)
+ && attachList.sanitize (c, this)
+ && ligCaretList.sanitize (c, this)
+ && markAttachClassDef.sanitize (c, this)
+ && (version < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this));
+ }
+
+ private:
+ FixedVersion version; /* Version of the GDEF table--currently
+ * 0x00010002 */
+ 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[VAR]; /* Offset to the table of mark set
+ * definitions--from beginning of GDEF
+ * header (may be NULL). Introduced
+ * in version 00010002. */
+ public:
+ DEFINE_SIZE_ARRAY (12, markGlyphSetsDef);
+};
+
+
+#endif /* HB_OT_LAYOUT_GDEF_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-private.hh
@@ -0,0 +1,1630 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010 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_LAYOUT_GPOS_PRIVATE_HH
+#define HB_OT_LAYOUT_GPOS_PRIVATE_HH
+
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+
+#define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
+
+/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
+
+typedef USHORT Value;
+
+typedef Value ValueRecord[VAR];
+
+struct ValueFormat : USHORT
+{
+ enum
+ {
+ xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
+ yPlacement = 0x0002, /* Includes vertical adjustment for placement */
+ xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
+ yAdvance = 0x0008, /* Includes vertical adjustment for advance */
+ xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
+ yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
+ xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
+ yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
+ ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
+ reserved = 0xF000, /* For future use */
+
+ devices = 0x00F0 /* Mask for having any Device table */
+ };
+
+/* All fields are options. Only those available advance the value pointer. */
+#if 0
+ SHORT xPlacement; /* Horizontal adjustment for
+ * placement--in design units */
+ SHORT yPlacement; /* Vertical adjustment for
+ * placement--in design units */
+ SHORT xAdvance; /* Horizontal adjustment for
+ * advance--in design units (only used
+ * for horizontal writing) */
+ SHORT yAdvance; /* Vertical adjustment for advance--in
+ * design units (only used for vertical
+ * writing) */
+ Offset xPlaDevice; /* Offset to Device table for
+ * horizontal placement--measured from
+ * beginning of PosTable (may be NULL) */
+ Offset yPlaDevice; /* Offset to Device table for vertical
+ * placement--measured from beginning
+ * of PosTable (may be NULL) */
+ Offset xAdvDevice; /* Offset to Device table for
+ * horizontal advance--measured from
+ * beginning of PosTable (may be NULL) */
+ Offset yAdvDevice; /* Offset to Device table for vertical
+ * advance--measured from beginning of
+ * PosTable (may be NULL) */
+#endif
+
+ inline unsigned int get_len () const
+ { return _hb_popcount32 ((unsigned int) *this); }
+ inline unsigned int get_size () const
+ { return get_len () * Value::static_size; }
+
+ void apply_value (hb_ot_layout_context_t *layout,
+ const void *base,
+ const Value *values,
+ hb_internal_glyph_position_t &glyph_pos) const
+ {
+ unsigned int x_ppem, y_ppem;
+ unsigned int format = *this;
+
+ if (!format) return;
+
+ /* design units -> fractional pixel */
+ if (format & xPlacement) glyph_pos.x_offset += layout->scale_x (get_short (values++));
+ if (format & yPlacement) glyph_pos.y_offset += layout->scale_y (get_short (values++));
+ if (format & xAdvance) glyph_pos.x_advance += layout->scale_x (get_short (values++));
+ if (format & yAdvance) glyph_pos.y_advance += layout->scale_y (get_short (values++));
+
+ if (!has_device ()) return;
+
+ x_ppem = layout->font->x_ppem;
+ y_ppem = layout->font->y_ppem;
+
+ if (!x_ppem && !y_ppem) return;
+
+ /* pixel -> fractional pixel */
+ if (format & xPlaDevice) {
+ if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (layout); else values++;
+ }
+ if (format & yPlaDevice) {
+ if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (layout); else values++;
+ }
+ if (format & xAdvDevice) {
+ if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (layout); else values++;
+ }
+ if (format & yAdvDevice) {
+ if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_delta (layout); else values++;
+ }
+ }
+
+ private:
+ inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
+ unsigned int format = *this;
+
+ if (format & xPlacement) values++;
+ if (format & yPlacement) values++;
+ if (format & xAdvance) values++;
+ if (format & yAdvance) values++;
+
+ if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+ if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
+ if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+ if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
+
+ return true;
+ }
+
+ static inline OffsetTo<Device>& get_device (Value* value)
+ { return *CastP<OffsetTo<Device> > (value); }
+ static inline const OffsetTo<Device>& get_device (const Value* value)
+ { return *CastP<OffsetTo<Device> > (value); }
+
+ static inline const SHORT& get_short (const Value* value)
+ { return *CastP<SHORT> (value); }
+
+ public:
+
+ inline bool has_device () const {
+ unsigned int format = *this;
+ return (format & devices) != 0;
+ }
+
+ inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
+ TRACE_SANITIZE ();
+ return c->check_range (values, get_size ())
+ && (!has_device () || sanitize_value_devices (c, base, values));
+ }
+
+ inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
+ TRACE_SANITIZE ();
+ unsigned int len = get_len ();
+
+ if (!c->check_array (values, get_size (), count)) return false;
+
+ if (!has_device ()) return true;
+
+ for (unsigned int i = 0; i < count; i++) {
+ if (!sanitize_value_devices (c, base, values))
+ return false;
+ values += len;
+ }
+
+ return true;
+ }
+
+ /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
+ inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
+ TRACE_SANITIZE ();
+
+ if (!has_device ()) return true;
+
+ for (unsigned int i = 0; i < count; i++) {
+ if (!sanitize_value_devices (c, base, values))
+ return false;
+ values += stride;
+ }
+
+ return true;
+ }
+};
+
+
+struct AnchorFormat1
+{
+ friend struct Anchor;
+
+ private:
+ inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
+ hb_position_t *x, hb_position_t *y) const
+ {
+ *x = layout->scale_x (xCoordinate);
+ *y = layout->scale_y (yCoordinate);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ SHORT xCoordinate; /* Horizontal value--in design units */
+ SHORT yCoordinate; /* Vertical value--in design units */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct AnchorFormat2
+{
+ friend struct Anchor;
+
+ private:
+ inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
+ hb_position_t *x, hb_position_t *y) const
+ {
+ unsigned int x_ppem = layout->font->x_ppem;
+ unsigned int y_ppem = layout->font->y_ppem;
+ hb_position_t cx, cy;
+ hb_bool_t ret;
+
+ if (x_ppem || y_ppem)
+ ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
+ *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate);
+ *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 2 */
+ SHORT xCoordinate; /* Horizontal value--in design units */
+ SHORT yCoordinate; /* Vertical value--in design units */
+ USHORT anchorPoint; /* Index to glyph contour point */
+ public:
+ DEFINE_SIZE_STATIC (8);
+};
+
+struct AnchorFormat3
+{
+ friend struct Anchor;
+
+ private:
+ inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
+ hb_position_t *x, hb_position_t *y) const
+ {
+ *x = layout->scale_x (xCoordinate);
+ *y = layout->scale_y (yCoordinate);
+
+ /* pixel -> fractional pixel */
+ if (layout->font->x_ppem)
+ *x += (this+xDeviceTable).get_x_delta (layout);
+ if (layout->font->y_ppem)
+ *y += (this+yDeviceTable).get_x_delta (layout);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && xDeviceTable.sanitize (c, this)
+ && yDeviceTable.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 3 */
+ SHORT xCoordinate; /* Horizontal value--in design units */
+ SHORT yCoordinate; /* Vertical value--in design units */
+ OffsetTo<Device>
+ xDeviceTable; /* Offset to Device table for X
+ * coordinate-- from beginning of
+ * Anchor table (may be NULL) */
+ OffsetTo<Device>
+ yDeviceTable; /* Offset to Device table for Y
+ * coordinate-- from beginning of
+ * Anchor table (may be NULL) */
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+struct Anchor
+{
+ inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
+ hb_position_t *x, hb_position_t *y) const
+ {
+ *x = *y = 0;
+ switch (u.format) {
+ case 1: u.format1.get_anchor (layout, glyph_id, x, y); return;
+ case 2: u.format2.get_anchor (layout, glyph_id, x, y); return;
+ case 3: u.format3.get_anchor (layout, glyph_id, x, y); return;
+ default: return;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ case 3: return u.format3.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ AnchorFormat1 format1;
+ AnchorFormat2 format2;
+ AnchorFormat3 format3;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, format);
+};
+
+
+struct AnchorMatrix
+{
+ inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
+ if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
+ return this+matrix[row * cols + col];
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
+ TRACE_SANITIZE ();
+ if (!c->check_struct (this)) return false;
+ if (unlikely (cols >= ((unsigned int) -1) / rows)) return false;
+ unsigned int count = rows * cols;
+ if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
+ for (unsigned int i = 0; i < count; i++)
+ if (!matrix[i].sanitize (c, this)) return false;
+ return true;
+ }
+
+ USHORT rows; /* Number of rows */
+ private:
+ OffsetTo<Anchor>
+ matrix[VAR]; /* Matrix of offsets to Anchor tables--
+ * from beginning of AnchorMatrix table */
+ public:
+ DEFINE_SIZE_ARRAY (2, matrix);
+};
+
+
+struct MarkRecord
+{
+ friend struct MarkArray;
+
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && markAnchor.sanitize (c, base);
+ }
+
+ private:
+ USHORT klass; /* Class defined for this mark */
+ OffsetTo<Anchor>
+ markAnchor; /* Offset to Anchor table--from
+ * beginning of MarkArray table */
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
+{
+ inline bool apply (hb_apply_context_t *c,
+ unsigned int mark_index, unsigned int glyph_index,
+ const AnchorMatrix &anchors, unsigned int class_count,
+ unsigned int glyph_pos) const
+ {
+ TRACE_APPLY ();
+ const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
+ unsigned int mark_class = record.klass;
+
+ const Anchor& mark_anchor = this + record.markAnchor;
+ const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
+
+ hb_position_t mark_x, mark_y, base_x, base_y;
+
+ mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
+ glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+
+ hb_internal_glyph_position_t &o = c->buffer->pos[c->buffer->i];
+ o.x_advance = 0;
+ o.y_advance = 0;
+ o.x_offset = base_x - mark_x;
+ o.y_offset = base_y - mark_y;
+ o.back = c->buffer->i - glyph_pos;
+
+ c->buffer->i++;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return ArrayOf<MarkRecord>::sanitize (c, this);
+ }
+};
+
+
+/* Lookups */
+
+struct SinglePosFormat1
+{
+ friend struct SinglePos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->i]);
+
+ c->buffer->i++;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && valueFormat.sanitize_value (c, this, values);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat; /* Defines the types of data in the
+ * ValueRecord */
+ ValueRecord values; /* Defines positioning
+ * value(s)--applied to all glyphs in
+ * the Coverage table */
+ public:
+ DEFINE_SIZE_ARRAY (6, values);
+};
+
+struct SinglePosFormat2
+{
+ friend struct SinglePos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ if (likely (index >= valueCount))
+ return false;
+
+ valueFormat.apply_value (c->layout, this,
+ &values[index * valueFormat.get_len ()],
+ c->buffer->pos[c->buffer->i]);
+
+ c->buffer->i++;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && valueFormat.sanitize_values (c, this, values, valueCount);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 2 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat; /* Defines the types of data in the
+ * ValueRecord */
+ USHORT valueCount; /* Number of ValueRecords */
+ ValueRecord values; /* Array of ValueRecords--positioning
+ * values applied to glyphs */
+ public:
+ DEFINE_SIZE_ARRAY (8, values);
+};
+
+struct SinglePos
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ case 2: return u.format2.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ SinglePosFormat1 format1;
+ SinglePosFormat2 format2;
+ } u;
+};
+
+
+struct PairValueRecord
+{
+ friend struct PairSet;
+
+ private:
+ GlyphID secondGlyph; /* GlyphID of second glyph in the
+ * pair--first glyph is listed in the
+ * Coverage table */
+ ValueRecord values; /* Positioning data for the first glyph
+ * followed by for second glyph */
+ public:
+ DEFINE_SIZE_ARRAY (2, values);
+};
+
+struct PairSet
+{
+ friend struct PairPosFormat1;
+
+ inline bool apply (hb_apply_context_t *c,
+ const ValueFormat *valueFormats,
+ unsigned int pos) const
+ {
+ TRACE_APPLY ();
+ unsigned int len1 = valueFormats[0].get_len ();
+ unsigned int len2 = valueFormats[1].get_len ();
+ unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
+
+ unsigned int count = len;
+ const PairValueRecord *record = CastP<PairValueRecord> (array);
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (c->buffer->info[pos].codepoint == record->secondGlyph)
+ {
+ valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->pos[c->buffer->i]);
+ valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->pos[pos]);
+ if (len2)
+ pos++;
+ c->buffer->i = pos;
+ return true;
+ }
+ record = &StructAtOffset<PairValueRecord> (record, record_size);
+ }
+
+ return false;
+ }
+
+ struct sanitize_closure_t {
+ void *base;
+ ValueFormat *valueFormats;
+ unsigned int len1; /* valueFormats[0].get_len() */
+ unsigned int stride; /* 1 + len1 + len2 */
+ };
+
+ inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
+ TRACE_SANITIZE ();
+ if (!(c->check_struct (this)
+ && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
+
+ unsigned int count = len;
+ PairValueRecord *record = CastP<PairValueRecord> (array);
+ return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
+ && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
+ }
+
+ private:
+ USHORT len; /* Number of PairValueRecords */
+ USHORT array[VAR]; /* Array of PairValueRecords--ordered
+ * by GlyphID of the second glyph */
+ public:
+ DEFINE_SIZE_ARRAY (2, array);
+};
+
+struct PairPosFormat1
+{
+ friend struct PairPos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
+ if (unlikely (c->buffer->i + 2 > end))
+ return false;
+
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ unsigned int j = c->buffer->i + 1;
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+ {
+ if (unlikely (j == end))
+ return false;
+ j++;
+ }
+
+ return (this+pairSet[index]).apply (c, &valueFormat1, j);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ PairSet::sanitize_closure_t closure = {
+ this,
+ &valueFormat1,
+ len1,
+ 1 + len1 + len2
+ };
+
+ return c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && pairSet.sanitize (c, this, &closure);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat1; /* Defines the types of data in
+ * ValueRecord1--for the first glyph
+ * in the pair--may be zero (0) */
+ ValueFormat valueFormat2; /* Defines the types of data in
+ * ValueRecord2--for the second glyph
+ * in the pair--may be zero (0) */
+ OffsetArrayOf<PairSet>
+ pairSet; /* Array of PairSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (10, pairSet);
+};
+
+struct PairPosFormat2
+{
+ friend struct PairPos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
+ if (unlikely (c->buffer->i + 2 > end))
+ return false;
+
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ unsigned int j = c->buffer->i + 1;
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+ {
+ if (unlikely (j == end))
+ return false;
+ j++;
+ }
+
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ unsigned int record_len = len1 + len2;
+
+ unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint);
+ unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
+ if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
+ return false;
+
+ const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
+ valueFormat1.apply_value (c->layout, this, v, c->buffer->pos[c->buffer->i]);
+ valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->pos[j]);
+
+ if (len2)
+ j++;
+ c->buffer->i = j;
+
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!(c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && classDef1.sanitize (c, this)
+ && classDef2.sanitize (c, this))) return false;
+
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ unsigned int stride = len1 + len2;
+ unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
+ unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
+ return c->check_array (values, record_size, count) &&
+ valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+ valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 2 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ValueFormat valueFormat1; /* ValueRecord definition--for the
+ * first glyph of the pair--may be zero
+ * (0) */
+ ValueFormat valueFormat2; /* ValueRecord definition--for the
+ * second glyph of the pair--may be
+ * zero (0) */
+ OffsetTo<ClassDef>
+ classDef1; /* Offset to ClassDef table--from
+ * beginning of PairPos subtable--for
+ * the first glyph of the pair */
+ OffsetTo<ClassDef>
+ classDef2; /* Offset to ClassDef table--from
+ * beginning of PairPos subtable--for
+ * the second glyph of the pair */
+ USHORT class1Count; /* Number of classes in ClassDef1
+ * table--includes Class0 */
+ USHORT class2Count; /* Number of classes in ClassDef2
+ * table--includes Class0 */
+ ValueRecord values; /* Matrix of value pairs:
+ * class1-major, class2-minor,
+ * Each entry has value1 and value2 */
+ public:
+ DEFINE_SIZE_ARRAY (16, values);
+};
+
+struct PairPos
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ case 2: return u.format2.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ PairPosFormat1 format1;
+ PairPosFormat2 format2;
+ } u;
+};
+
+
+struct EntryExitRecord
+{
+ friend struct CursivePosFormat1;
+
+ inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ TRACE_SANITIZE ();
+ return entryAnchor.sanitize (c, base)
+ && exitAnchor.sanitize (c, base);
+ }
+
+ private:
+ OffsetTo<Anchor>
+ entryAnchor; /* Offset to EntryAnchor table--from
+ * beginning of CursivePos
+ * subtable--may be NULL */
+ OffsetTo<Anchor>
+ exitAnchor; /* Offset to ExitAnchor table--from
+ * beginning of CursivePos
+ * subtable--may be NULL */
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+struct CursivePosFormat1
+{
+ friend struct CursivePos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ /* Now comes the messiest part of the whole OpenType
+ specification. At first glance, cursive connections seem easy
+ to understand, but there are pitfalls! The reason is that
+ the specs don't mention how to compute the advance values
+ resp. glyph offsets. I was told it would be an omission, to
+ be fixed in the next OpenType version... Again many thanks to
+ Andrei Burago <andreib@microsoft.com> for clarifications.
+
+ Consider the following example:
+
+ | xadv1 |
+ +---------+
+ | |
+ +-----+--+ 1 |
+ | | .| |
+ | 0+--+------+
+ | 2 |
+ | |
+ 0+--------+
+ | xadv2 |
+
+ glyph1: advance width = 12
+ anchor point = (3,1)
+
+ glyph2: advance width = 11
+ anchor point = (9,4)
+
+ LSB is 1 for both glyphs (so the boxes drawn above are glyph
+ bboxes). Writing direction is R2L; `0' denotes the glyph's
+ coordinate origin.
+
+ Now the surprising part: The advance width of the *left* glyph
+ (resp. of the *bottom* glyph) will be modified, no matter
+ whether the writing direction is L2R or R2L (resp. T2B or
+ B2T)! This assymetry is caused by the fact that the glyph's
+ coordinate origin is always the lower left corner for all
+ writing directions.
+
+ Continuing the above example, we can compute the new
+ (horizontal) advance width of glyph2 as
+
+ 9 - 3 = 6 ,
+
+ and the new vertical offset of glyph2 as
+
+ 1 - 4 = -3 .
+
+
+ Vertical writing direction is far more complicated:
+
+ a) Assuming that we recompute the advance height of the lower glyph:
+
+ --
+ +---------+
+ -- | |
+ +-----+--+ 1 | yadv1
+ | | .| |
+ yadv2 | 0+--+------+ -- BSB1 --
+ | 2 | -- -- y_offset
+ | |
+ BSB2 -- 0+--------+ --
+ -- --
+
+ glyph1: advance height = 6
+ anchor point = (3,1)
+
+ glyph2: advance height = 7
+ anchor point = (9,4)
+
+ TSB is 1 for both glyphs; writing direction is T2B.
+
+
+ BSB1 = yadv1 - (TSB1 + ymax1)
+ BSB2 = yadv2 - (TSB2 + ymax2)
+ y_offset = y2 - y1
+
+ vertical advance width of glyph2
+ = y_offset + BSB2 - BSB1
+ = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
+ = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
+ = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
+
+
+ b) Assuming that we recompute the advance height of the upper glyph:
+
+ -- --
+ +---------+ -- TSB1
+ -- -- | |
+ TSB2 -- +-----+--+ 1 | yadv1 ymax1
+ | | .| |
+ yadv2 | 0+--+------+ -- --
+ ymax2 | 2 | -- y_offset
+ | |
+ -- 0+--------+ --
+ --
+
+ glyph1: advance height = 6
+ anchor point = (3,1)
+
+ glyph2: advance height = 7
+ anchor point = (9,4)
+
+ TSB is 1 for both glyphs; writing direction is T2B.
+
+ y_offset = y2 - y1
+
+ vertical advance width of glyph2
+ = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
+ = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
+
+
+ Comparing a) with b) shows that b) is easier to compute. I'll wait
+ for a reply from Andrei to see what should really be implemented...
+
+ Since horizontal advance widths or vertical advance heights
+ can be used alone but not together, no ambiguity occurs. */
+
+ struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &c->layout->info.gpos;
+ hb_codepoint_t last_pos = gpi->last;
+ gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
+
+ /* We don't handle mark glyphs here. */
+ if (c->property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
+ return false;
+
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const EntryExitRecord &record = entryExitRecord[index];
+
+ if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
+ goto end;
+
+ hb_position_t entry_x, entry_y;
+ (this+record.entryAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &entry_x, &entry_y);
+
+ /* TODO vertical */
+
+ if (c->buffer->direction == HB_DIRECTION_RTL)
+ {
+ /* advance is absolute, not relative */
+ c->buffer->pos[c->buffer->i].x_advance = entry_x - gpi->anchor_x;
+ }
+ else
+ {
+ /* advance is absolute, not relative */
+ c->buffer->pos[last_pos].x_advance = gpi->anchor_x - entry_x;
+ }
+
+ if (c->lookup_flag & LookupFlag::RightToLeft)
+ {
+ c->buffer->pos[last_pos].cursive_chain = last_pos - c->buffer->i;
+ c->buffer->pos[last_pos].y_offset = entry_y - gpi->anchor_y;
+ }
+ else
+ {
+ c->buffer->pos[c->buffer->i].cursive_chain = c->buffer->i - last_pos;
+ c->buffer->pos[c->buffer->i].y_offset = gpi->anchor_y - entry_y;
+ }
+
+ end:
+ if (record.exitAnchor)
+ {
+ gpi->last = c->buffer->i;
+ (this+record.exitAnchor).get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &gpi->anchor_x, &gpi->anchor_y);
+ }
+
+ c->buffer->i++;
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && entryExitRecord.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of subtable */
+ ArrayOf<EntryExitRecord>
+ entryExitRecord; /* Array of EntryExit records--in
+ * Coverage Index order */
+ public:
+ DEFINE_SIZE_ARRAY (6, entryExitRecord);
+};
+
+struct CursivePos
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ CursivePosFormat1 format1;
+ } u;
+};
+
+
+typedef AnchorMatrix BaseArray; /* base-major--
+ * in order of BaseCoverage Index--,
+ * mark-minor--
+ * ordered by class--zero-based. */
+
+struct MarkBasePosFormat1
+{
+ friend struct MarkBasePos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (mark_index == NOT_COVERED))
+ return false;
+
+ /* now we search backwards for a non-mark glyph */
+ unsigned int property;
+ unsigned int j = c->buffer->i;
+ do
+ {
+ if (unlikely (!j))
+ return false;
+ j--;
+ } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
+
+ /* The following assertion is too strong, so we've disabled it. */
+ if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
+ return false;
+
+ unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
+ if (base_index == NOT_COVERED)
+ return false;
+
+ return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && markCoverage.sanitize (c, this)
+ && baseCoverage.sanitize (c, this)
+ && markArray.sanitize (c, this)
+ && baseArray.sanitize (c, this, (unsigned int) classCount);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ markCoverage; /* Offset to MarkCoverage table--from
+ * beginning of MarkBasePos subtable */
+ OffsetTo<Coverage>
+ baseCoverage; /* Offset to BaseCoverage table--from
+ * beginning of MarkBasePos subtable */
+ USHORT classCount; /* Number of classes defined for marks */
+ OffsetTo<MarkArray>
+ markArray; /* Offset to MarkArray table--from
+ * beginning of MarkBasePos subtable */
+ OffsetTo<BaseArray>
+ baseArray; /* Offset to BaseArray table--from
+ * beginning of MarkBasePos subtable */
+ public:
+ DEFINE_SIZE_STATIC (12);
+};
+
+struct MarkBasePos
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ MarkBasePosFormat1 format1;
+ } u;
+};
+
+
+typedef AnchorMatrix LigatureAttach; /* component-major--
+ * in order of writing direction--,
+ * mark-minor--
+ * ordered by class--zero-based. */
+
+typedef OffsetListOf<LigatureAttach> LigatureArray;
+ /* Array of LigatureAttach
+ * tables ordered by
+ * LigatureCoverage Index */
+
+struct MarkLigPosFormat1
+{
+ friend struct MarkLigPos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (mark_index == NOT_COVERED))
+ return false;
+
+ /* now we search backwards for a non-mark glyph */
+ unsigned int property;
+ unsigned int j = c->buffer->i;
+ do
+ {
+ if (unlikely (!j))
+ return false;
+ j--;
+ } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
+
+ /* The following assertion is too strong, so we've disabled it. */
+ if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
+ return false;
+
+ unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
+ if (lig_index == NOT_COVERED)
+ return false;
+
+ const LigatureArray& lig_array = this+ligatureArray;
+ const LigatureAttach& lig_attach = lig_array[lig_index];
+
+ /* Find component to attach to */
+ unsigned int comp_count = lig_attach.rows;
+ if (unlikely (!comp_count))
+ return false;
+ unsigned int comp_index;
+ /* We must now check whether the ligature ID of the current mark glyph
+ * is identical to the ligature ID of the found ligature. If yes, we
+ * can directly use the component index. If not, we attach the mark
+ * glyph to the last component of the ligature. */
+ if (c->buffer->info[j].lig_id && c->buffer->info[j].lig_id == c->buffer->info[c->buffer->i].lig_id && c->buffer->info[c->buffer->i].component)
+ {
+ comp_index = c->buffer->info[c->buffer->i].component - 1;
+ if (comp_index >= comp_count)
+ comp_index = comp_count - 1;
+ }
+ else
+ comp_index = comp_count - 1;
+
+ return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && markCoverage.sanitize (c, this)
+ && ligatureCoverage.sanitize (c, this)
+ && markArray.sanitize (c, this)
+ && ligatureArray.sanitize (c, this, (unsigned int) classCount);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ markCoverage; /* Offset to Mark Coverage table--from
+ * beginning of MarkLigPos subtable */
+ OffsetTo<Coverage>
+ ligatureCoverage; /* Offset to Ligature Coverage
+ * table--from beginning of MarkLigPos
+ * subtable */
+ USHORT classCount; /* Number of defined mark classes */
+ OffsetTo<MarkArray>
+ markArray; /* Offset to MarkArray table--from
+ * beginning of MarkLigPos subtable */
+ OffsetTo<LigatureArray>
+ ligatureArray; /* Offset to LigatureArray table--from
+ * beginning of MarkLigPos subtable */
+ public:
+ DEFINE_SIZE_STATIC (12);
+};
+
+struct MarkLigPos
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ MarkLigPosFormat1 format1;
+ } u;
+};
+
+
+typedef AnchorMatrix Mark2Array; /* mark2-major--
+ * in order of Mark2Coverage Index--,
+ * mark1-minor--
+ * ordered by class--zero-based. */
+
+struct MarkMarkPosFormat1
+{
+ friend struct MarkMarkPos;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (mark1_index == NOT_COVERED))
+ return false;
+
+ /* now we search backwards for a suitable mark glyph until a non-mark glyph */
+ unsigned int property;
+ unsigned int j = c->buffer->i;
+ do
+ {
+ if (unlikely (!j))
+ return false;
+ j--;
+ } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property));
+
+ if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
+ return false;
+
+ /* Two marks match only if they belong to the same base, or same component
+ * of the same ligature. That is, the component numbers must match, and
+ * if those are non-zero, the ligid number should also match. */
+ if ((c->buffer->info[j].component != c->buffer->info[c->buffer->i].component) ||
+ (c->buffer->info[j].component && c->buffer->info[j].lig_id != c->buffer->info[c->buffer->i].lig_id))
+ return false;
+
+ unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
+ if (mark2_index == NOT_COVERED)
+ return false;
+
+ return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this)
+ && mark1Coverage.sanitize (c, this)
+ && mark2Coverage.sanitize (c, this)
+ && mark1Array.sanitize (c, this)
+ && mark2Array.sanitize (c, this, (unsigned int) classCount);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ mark1Coverage; /* Offset to Combining Mark1 Coverage
+ * table--from beginning of MarkMarkPos
+ * subtable */
+ OffsetTo<Coverage>
+ mark2Coverage; /* Offset to Combining Mark2 Coverage
+ * table--from beginning of MarkMarkPos
+ * subtable */
+ USHORT classCount; /* Number of defined mark classes */
+ OffsetTo<MarkArray>
+ mark1Array; /* Offset to Mark1Array table--from
+ * beginning of MarkMarkPos subtable */
+ OffsetTo<Mark2Array>
+ mark2Array; /* Offset to Mark2Array table--from
+ * beginning of MarkMarkPos subtable */
+ public:
+ DEFINE_SIZE_STATIC (12);
+};
+
+struct MarkMarkPos
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ MarkMarkPosFormat1 format1;
+ } u;
+};
+
+
+static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
+
+struct ContextPos : Context
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ return Context::apply (c, position_lookup);
+ }
+};
+
+struct ChainContextPos : ChainContext
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ return ChainContext::apply (c, position_lookup);
+ }
+};
+
+
+struct ExtensionPos : Extension
+{
+ friend struct PosLookupSubTable;
+
+ private:
+ inline const struct PosLookupSubTable& get_subtable (void) const
+ {
+ unsigned int offset = get_offset ();
+ if (unlikely (!offset)) return Null(PosLookupSubTable);
+ return StructAtOffset<PosLookupSubTable> (this, offset);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const;
+
+ inline bool sanitize (hb_sanitize_context_t *c);
+};
+
+
+
+/*
+ * PosLookup
+ */
+
+
+struct PosLookupSubTable
+{
+ friend struct PosLookup;
+
+ enum {
+ Single = 1,
+ Pair = 2,
+ Cursive = 3,
+ MarkBase = 4,
+ MarkLig = 5,
+ MarkMark = 6,
+ Context = 7,
+ ChainContext = 8,
+ Extension = 9
+ };
+
+ inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
+ {
+ TRACE_APPLY ();
+ switch (lookup_type) {
+ case Single: return u.single.apply (c);
+ case Pair: return u.pair.apply (c);
+ case Cursive: return u.cursive.apply (c);
+ case MarkBase: return u.markBase.apply (c);
+ case MarkLig: return u.markLig.apply (c);
+ case MarkMark: return u.markMark.apply (c);
+ case Context: return u.c.apply (c);
+ case ChainContext: return u.chainContext.apply (c);
+ case Extension: return u.extension.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
+ TRACE_SANITIZE ();
+ switch (lookup_type) {
+ case Single: return u.single.sanitize (c);
+ case Pair: return u.pair.sanitize (c);
+ case Cursive: return u.cursive.sanitize (c);
+ case MarkBase: return u.markBase.sanitize (c);
+ case MarkLig: return u.markLig.sanitize (c);
+ case MarkMark: return u.markMark.sanitize (c);
+ case Context: return u.c.sanitize (c);
+ case ChainContext: return u.chainContext.sanitize (c);
+ case Extension: return u.extension.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT sub_format;
+ SinglePos single;
+ PairPos pair;
+ CursivePos cursive;
+ MarkBasePos markBase;
+ MarkLigPos markLig;
+ MarkMarkPos markMark;
+ ContextPos c;
+ ChainContextPos chainContext;
+ ExtensionPos extension;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, sub_format);
+};
+
+
+struct PosLookup : Lookup
+{
+ inline const PosLookupSubTable& get_subtable (unsigned int i) const
+ { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
+
+ inline bool apply_once (hb_ot_layout_context_t *layout,
+ hb_buffer_t *buffer,
+ hb_mask_t lookup_mask,
+ unsigned int context_length,
+ unsigned int nesting_level_left) const
+ {
+ unsigned int lookup_type = get_type ();
+ hb_apply_context_t c[1] = {{0}};
+
+ c->layout = layout;
+ c->buffer = buffer;
+ c->lookup_mask = lookup_mask;
+ c->context_length = context_length;
+ c->nesting_level_left = nesting_level_left;
+ c->lookup_flag = get_flag ();
+
+ if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, &c->property))
+ return false;
+
+ for (unsigned int i = 0; i < get_subtable_count (); i++)
+ if (get_subtable (i).apply (c, lookup_type))
+ return true;
+
+ return false;
+ }
+
+ inline bool apply_string (hb_ot_layout_context_t *layout,
+ hb_buffer_t *buffer,
+ hb_mask_t mask) const
+ {
+ bool ret = false;
+
+ if (unlikely (!buffer->len))
+ return false;
+
+ layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
+
+ buffer->i = 0;
+ while (buffer->i < buffer->len)
+ {
+ bool done;
+ if (buffer->info[buffer->i].mask & mask)
+ {
+ done = apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL);
+ ret |= done;
+ }
+ else
+ {
+ done = false;
+ /* Contrary to properties defined in GDEF, user-defined properties
+ will always stop a possible cursive positioning. */
+ layout->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
+ }
+
+ if (!done)
+ buffer->i++;
+ }
+
+ return ret;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (unlikely (!Lookup::sanitize (c))) return false;
+ OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
+ return list.sanitize (c, this, get_type ());
+ }
+};
+
+typedef OffsetListOf<PosLookup> PosLookupList;
+
+/*
+ * GPOS
+ */
+
+struct GPOS : GSUBGPOS
+{
+ static const hb_tag_t Tag = HB_OT_TAG_GPOS;
+
+ inline const PosLookup& get_lookup (unsigned int i) const
+ { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
+
+ inline bool position_lookup (hb_ot_layout_context_t *layout,
+ hb_buffer_t *buffer,
+ unsigned int lookup_index,
+ hb_mask_t mask) const
+ { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (unlikely (!GSUBGPOS::sanitize (c))) return false;
+ OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
+ return list.sanitize (c, this);
+ }
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+
+/* Out-of-class implementation for methods recursing */
+
+inline bool ExtensionPos::apply (hb_apply_context_t *c) const
+{
+ TRACE_APPLY ();
+ return get_subtable ().apply (c, get_type ());
+}
+
+inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
+{
+ TRACE_SANITIZE ();
+ if (unlikely (!Extension::sanitize (c))) return false;
+ unsigned int offset = get_offset ();
+ if (unlikely (!offset)) return true;
+ return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
+}
+
+static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+{
+ const GPOS &gpos = *(c->layout->face->ot_layout->gpos);
+ const PosLookup &l = gpos.get_lookup (lookup_index);
+
+ if (unlikely (c->nesting_level_left == 0))
+ return false;
+
+ if (unlikely (c->context_length < 1))
+ return false;
+
+ return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
+}
+
+
+#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-private.hh
@@ -0,0 +1,939 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010 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_LAYOUT_GSUB_PRIVATE_HH
+#define HB_OT_LAYOUT_GSUB_PRIVATE_HH
+
+#include "hb-ot-layout-gsubgpos-private.hh"
+
+
+struct SingleSubstFormat1
+{
+ friend struct SingleSubst;
+
+ private:
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
+ unsigned int index = (this+coverage) (glyph_id);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ glyph_id += deltaGlyphID;
+ c->buffer->replace_glyph (glyph_id);
+
+ /* We inherit the old glyph class to the substituted glyph */
+ if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
+ _hb_ot_layout_set_glyph_property (c->layout->face, glyph_id, c->property);
+
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && deltaGlyphID.sanitize (c);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ SHORT deltaGlyphID; /* Add to original GlyphID to get
+ * substitute GlyphID */
+ public:
+ DEFINE_SIZE_STATIC (6);
+};
+
+struct SingleSubstFormat2
+{
+ friend struct SingleSubst;
+
+ private:
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
+ unsigned int index = (this+coverage) (glyph_id);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ if (unlikely (index >= substitute.len))
+ return false;
+
+ glyph_id = substitute[index];
+ c->buffer->replace_glyph (glyph_id);
+
+ /* We inherit the old glyph class to the substituted glyph */
+ if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
+ _hb_ot_layout_set_glyph_property (c->layout->face, glyph_id, c->property);
+
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && substitute.sanitize (c);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 2 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ ArrayOf<GlyphID>
+ substitute; /* Array of substitute
+ * GlyphIDs--ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (6, substitute);
+};
+
+struct SingleSubst
+{
+ friend struct SubstLookupSubTable;
+
+ private:
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ case 2: return u.format2.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ SingleSubstFormat1 format1;
+ SingleSubstFormat2 format2;
+ } u;
+};
+
+
+struct Sequence
+{
+ friend struct MultipleSubstFormat1;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ if (unlikely (!substitute.len))
+ return false;
+
+ c->buffer->add_output_glyphs_be16 (1,
+ substitute.len, (const uint16_t *) substitute.array,
+ 0xFFFF, 0xFFFF);
+
+ /* This is a guess only ... */
+ if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
+ {
+ unsigned int property = c->property;
+ if (property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
+ property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
+
+ unsigned int count = substitute.len;
+ for (unsigned int n = 0; n < count; n++)
+ _hb_ot_layout_set_glyph_property (c->layout->face, substitute[n], property);
+ }
+
+ return true;
+ }
+
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return substitute.sanitize (c);
+ }
+
+ private:
+ ArrayOf<GlyphID>
+ substitute; /* String of GlyphIDs to substitute */
+ public:
+ DEFINE_SIZE_ARRAY (2, substitute);
+};
+
+struct MultipleSubstFormat1
+{
+ friend struct MultipleSubst;
+
+ private:
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ return (this+sequence[index]).apply (c);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && sequence.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ OffsetArrayOf<Sequence>
+ sequence; /* Array of Sequence tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (6, sequence);
+};
+
+struct MultipleSubst
+{
+ friend struct SubstLookupSubTable;
+
+ private:
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ MultipleSubstFormat1 format1;
+ } u;
+};
+
+
+typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
+ * arbitrary order */
+
+struct AlternateSubstFormat1
+{
+ friend struct AlternateSubst;
+
+ private:
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
+ hb_mask_t glyph_mask = c->buffer->info[c->buffer->i].mask;
+ hb_mask_t lookup_mask = c->lookup_mask;
+
+ unsigned int index = (this+coverage) (glyph_id);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const AlternateSet &alt_set = this+alternateSet[index];
+
+ if (unlikely (!alt_set.len))
+ return false;
+
+ /* Note: This breaks badly if two features enabled this lookup together. */
+ unsigned int shift = _hb_ctz (lookup_mask);
+ unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+ if (unlikely (alt_index > alt_set.len || alt_index == 0))
+ return false;
+
+ glyph_id = alt_set[alt_index - 1];
+
+ c->buffer->replace_glyph (glyph_id);
+
+ /* We inherit the old glyph class to the substituted glyph */
+ if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
+ _hb_ot_layout_set_glyph_property (c->layout->face, glyph_id, c->property);
+
+ return true;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && alternateSet.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ OffsetArrayOf<AlternateSet>
+ alternateSet; /* Array of AlternateSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (6, alternateSet);
+};
+
+struct AlternateSubst
+{
+ friend struct SubstLookupSubTable;
+
+ private:
+
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ AlternateSubstFormat1 format1;
+ } u;
+};
+
+
+struct Ligature
+{
+ friend struct LigatureSet;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, bool is_mark) const
+ {
+ TRACE_APPLY ();
+ unsigned int i, j;
+ unsigned int count = component.len;
+ unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
+ if (unlikely (c->buffer->i + count > end))
+ return false;
+
+ for (i = 1, j = c->buffer->i + 1; i < count; i++, j++)
+ {
+ unsigned int property;
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, &property))
+ {
+ if (unlikely (j + count - i == end))
+ return false;
+ j++;
+ }
+
+ if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
+ is_mark = false;
+
+ if (likely (c->buffer->info[j].codepoint != component[i]))
+ return false;
+ }
+ /* This is just a guess ... */
+ if (_hb_ot_layout_has_new_glyph_classes (c->layout->face))
+ _hb_ot_layout_set_glyph_class (c->layout->face, ligGlyph,
+ is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK
+ : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
+
+ if (j == c->buffer->i + i) /* No input glyphs skipped */
+ /* We don't use a new ligature ID if there are no skipped
+ glyphs and the ligature already has an ID. */
+ c->buffer->add_output_glyphs_be16 (i,
+ 1, (const uint16_t *) &ligGlyph,
+ 0,
+ c->buffer->info[c->buffer->i].lig_id && !c->buffer->info[c->buffer->i].component ?
+ 0xFFFF : c->buffer->allocate_lig_id ());
+ else
+ {
+ unsigned int lig_id = c->buffer->allocate_lig_id ();
+ c->buffer->add_output_glyph (ligGlyph, 0xFFFF, lig_id);
+
+ /* Now we must do a second loop to copy the skipped glyphs to
+ `out' and assign component values to it. We start with the
+ glyph after the first component. Glyphs between component
+ i and i+1 belong to component i. Together with the lig_id
+ value it is later possible to check whether a specific
+ component value really belongs to a given ligature. */
+
+ for ( i = 1; i < count; i++ )
+ {
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, NULL))
+ c->buffer->add_output_glyph (c->buffer->info[c->buffer->i].codepoint, i, lig_id);
+
+ (c->buffer->i)++;
+ }
+ }
+
+ return true;
+ }
+
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return ligGlyph.sanitize (c)
+ && component.sanitize (c);
+ }
+
+ private:
+ GlyphID ligGlyph; /* GlyphID of ligature to substitute */
+ HeadlessArrayOf<GlyphID>
+ component; /* Array of component GlyphIDs--start
+ * with the second component--ordered
+ * in writing direction */
+ public:
+ DEFINE_SIZE_ARRAY (4, component);
+};
+
+struct LigatureSet
+{
+ friend struct LigatureSubstFormat1;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, bool is_mark) const
+ {
+ TRACE_APPLY ();
+ unsigned int num_ligs = ligature.len;
+ for (unsigned int i = 0; i < num_ligs; i++)
+ {
+ const Ligature &lig = this+ligature[i];
+ if (lig.apply (c, is_mark))
+ return true;
+ }
+
+ return false;
+ }
+
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return ligature.sanitize (c, this);
+ }
+
+ private:
+ OffsetArrayOf<Ligature>
+ ligature; /* Array LigatureSet tables
+ * ordered by preference */
+ public:
+ DEFINE_SIZE_ARRAY (2, ligature);
+};
+
+struct LigatureSubstFormat1
+{
+ friend struct LigatureSubst;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint;
+
+ bool first_is_mark = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
+
+ unsigned int index = (this+coverage) (glyph_id);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const LigatureSet &lig_set = this+ligatureSet[index];
+ return lig_set.apply (c, first_is_mark);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && ligatureSet.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of Substitution table */
+ OffsetArrayOf<LigatureSet>
+ ligatureSet; /* Array LigatureSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (6, ligatureSet);
+};
+
+struct LigatureSubst
+{
+ friend struct SubstLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ LigatureSubstFormat1 format1;
+ } u;
+};
+
+
+
+static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
+
+struct ContextSubst : Context
+{
+ friend struct SubstLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ return Context::apply (c, substitute_lookup);
+ }
+};
+
+struct ChainContextSubst : ChainContext
+{
+ friend struct SubstLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ return ChainContext::apply (c, substitute_lookup);
+ }
+};
+
+
+struct ExtensionSubst : Extension
+{
+ friend struct SubstLookupSubTable;
+ friend struct SubstLookup;
+
+ private:
+ inline const struct SubstLookupSubTable& get_subtable (void) const
+ {
+ unsigned int offset = get_offset ();
+ if (unlikely (!offset)) return Null(SubstLookupSubTable);
+ return StructAtOffset<SubstLookupSubTable> (this, offset);
+ }
+
+ inline bool apply (hb_apply_context_t *c) const;
+
+ inline bool sanitize (hb_sanitize_context_t *c);
+
+ inline bool is_reverse (void) const;
+};
+
+
+struct ReverseChainSingleSubstFormat1
+{
+ friend struct ReverseChainSingleSubst;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ if (unlikely (c->context_length != NO_CONTEXT))
+ return false; /* No chaining to this type */
+
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+
+ if (match_backtrack (c,
+ backtrack.len, (USHORT *) backtrack.array,
+ match_coverage, this) &&
+ match_lookahead (c,
+ lookahead.len, (USHORT *) lookahead.array,
+ match_coverage, this,
+ 1))
+ {
+ c->buffer->info[c->buffer->i].codepoint = substitute[index];
+ c->buffer->i--; /* Reverse! */
+ return true;
+ }
+
+ return false;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!(coverage.sanitize (c, this)
+ && backtrack.sanitize (c, this)))
+ return false;
+ OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ if (!lookahead.sanitize (c, this))
+ return false;
+ ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+ return substitute.sanitize (c);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of table */
+ OffsetArrayOf<Coverage>
+ backtrack; /* Array of coverage tables
+ * in backtracking sequence, in glyph
+ * sequence order */
+ OffsetArrayOf<Coverage>
+ lookaheadX; /* Array of coverage tables
+ * in lookahead sequence, in glyph
+ * sequence order */
+ ArrayOf<GlyphID>
+ substituteX; /* Array of substitute
+ * GlyphIDs--ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_MIN (10);
+};
+
+struct ReverseChainSingleSubst
+{
+ friend struct SubstLookupSubTable;
+
+ private:
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ ReverseChainSingleSubstFormat1 format1;
+ } u;
+};
+
+
+
+/*
+ * SubstLookup
+ */
+
+struct SubstLookupSubTable
+{
+ friend struct SubstLookup;
+
+ enum {
+ Single = 1,
+ Multiple = 2,
+ Alternate = 3,
+ Ligature = 4,
+ Context = 5,
+ ChainContext = 6,
+ Extension = 7,
+ ReverseChainSingle = 8
+ };
+
+ inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
+ {
+ TRACE_APPLY ();
+ switch (lookup_type) {
+ case Single: return u.single.apply (c);
+ case Multiple: return u.multiple.apply (c);
+ case Alternate: return u.alternate.apply (c);
+ case Ligature: return u.ligature.apply (c);
+ case Context: return u.c.apply (c);
+ case ChainContext: return u.chainContext.apply (c);
+ case Extension: return u.extension.apply (c);
+ case ReverseChainSingle: return u.reverseChainContextSingle.apply (c);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
+ TRACE_SANITIZE ();
+ switch (lookup_type) {
+ case Single: return u.single.sanitize (c);
+ case Multiple: return u.multiple.sanitize (c);
+ case Alternate: return u.alternate.sanitize (c);
+ case Ligature: return u.ligature.sanitize (c);
+ case Context: return u.c.sanitize (c);
+ case ChainContext: return u.chainContext.sanitize (c);
+ case Extension: return u.extension.sanitize (c);
+ case ReverseChainSingle: return u.reverseChainContextSingle.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT sub_format;
+ SingleSubst single;
+ MultipleSubst multiple;
+ AlternateSubst alternate;
+ LigatureSubst ligature;
+ ContextSubst c;
+ ChainContextSubst chainContext;
+ ExtensionSubst extension;
+ ReverseChainSingleSubst reverseChainContextSingle;
+ } u;
+ public:
+ DEFINE_SIZE_UNION (2, sub_format);
+};
+
+
+struct SubstLookup : Lookup
+{
+ inline const SubstLookupSubTable& get_subtable (unsigned int i) const
+ { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
+
+ inline static bool lookup_type_is_reverse (unsigned int lookup_type)
+ { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
+
+ inline bool is_reverse (void) const
+ {
+ unsigned int type = get_type ();
+ if (unlikely (type == SubstLookupSubTable::Extension))
+ return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
+ return lookup_type_is_reverse (type);
+ }
+
+
+ inline bool apply_once (hb_ot_layout_context_t *layout,
+ hb_buffer_t *buffer,
+ hb_mask_t lookup_mask,
+ unsigned int context_length,
+ unsigned int nesting_level_left) const
+ {
+ unsigned int lookup_type = get_type ();
+ hb_apply_context_t c[1] = {{0}};
+
+ c->layout = layout;
+ c->buffer = buffer;
+ c->lookup_mask = lookup_mask;
+ c->context_length = context_length;
+ c->nesting_level_left = nesting_level_left;
+ c->lookup_flag = get_flag ();
+
+ if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, &c->property))
+ return false;
+
+ if (unlikely (lookup_type == SubstLookupSubTable::Extension))
+ {
+ /* The spec says all subtables should have the same type.
+ * This is specially important if one has a reverse type!
+ *
+ * This is rather slow to do this here for every glyph,
+ * but it's easiest, and who uses extension lookups anyway?!*/
+ unsigned int count = get_subtable_count ();
+ unsigned int type = get_subtable(0).u.extension.get_type ();
+ for (unsigned int i = 1; i < count; i++)
+ if (get_subtable(i).u.extension.get_type () != type)
+ return false;
+ }
+
+ unsigned int count = get_subtable_count ();
+ for (unsigned int i = 0; i < count; i++)
+ if (get_subtable (i).apply (c, lookup_type))
+ return true;
+
+ return false;
+ }
+
+ inline bool apply_string (hb_ot_layout_context_t *layout,
+ hb_buffer_t *buffer,
+ hb_mask_t mask) const
+ {
+ bool ret = false;
+
+ if (unlikely (!buffer->len))
+ return false;
+
+ if (likely (!is_reverse ()))
+ {
+ /* in/out forward substitution */
+ buffer->clear_output ();
+ buffer->i = 0;
+ while (buffer->i < buffer->len)
+ {
+ if ((buffer->info[buffer->i].mask & mask) &&
+ apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
+ ret = true;
+ else
+ buffer->next_glyph ();
+
+ }
+ if (ret)
+ buffer->swap ();
+ }
+ else
+ {
+ /* in-place backward substitution */
+ buffer->i = buffer->len - 1;
+ do
+ {
+ if ((buffer->info[buffer->i].mask & mask) &&
+ apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
+ ret = true;
+ else
+ buffer->i--;
+
+ }
+ while ((int) buffer->i >= 0);
+ }
+
+ return ret;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (unlikely (!Lookup::sanitize (c))) return false;
+ OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
+ return list.sanitize (c, this, get_type ());
+ }
+};
+
+typedef OffsetListOf<SubstLookup> SubstLookupList;
+
+/*
+ * GSUB
+ */
+
+struct GSUB : GSUBGPOS
+{
+ static const hb_tag_t Tag = HB_OT_TAG_GSUB;
+
+ inline const SubstLookup& get_lookup (unsigned int i) const
+ { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
+
+ inline bool substitute_lookup (hb_ot_layout_context_t *layout,
+ hb_buffer_t *buffer,
+ unsigned int lookup_index,
+ hb_mask_t mask) const
+ { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (unlikely (!GSUBGPOS::sanitize (c))) return false;
+ OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
+ return list.sanitize (c, this);
+ }
+ public:
+ DEFINE_SIZE_STATIC (10);
+};
+
+
+/* Out-of-class implementation for methods recursing */
+
+inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
+{
+ TRACE_APPLY ();
+ return get_subtable ().apply (c, get_type ());
+}
+
+inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
+{
+ TRACE_SANITIZE ();
+ if (unlikely (!Extension::sanitize (c))) return false;
+ unsigned int offset = get_offset ();
+ if (unlikely (!offset)) return true;
+ return StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ());
+}
+
+inline bool ExtensionSubst::is_reverse (void) const
+{
+ unsigned int type = get_type ();
+ if (unlikely (type == SubstLookupSubTable::Extension))
+ return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
+ return SubstLookup::lookup_type_is_reverse (type);
+}
+
+static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
+{
+ const GSUB &gsub = *(c->layout->face->ot_layout->gsub);
+ const SubstLookup &l = gsub.get_lookup (lookup_index);
+
+ if (unlikely (c->nesting_level_left == 0))
+ return false;
+
+ if (unlikely (c->context_length < 1))
+ return false;
+
+ return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
+}
+
+
+#endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */
new file mode 100644
--- /dev/null
+++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh
@@ -0,0 +1,942 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010 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_LAYOUT_GSUBGPOS_PRIVATE_HH
+#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
+
+#include "hb-buffer-private.hh"
+#include "hb-ot-layout-gdef-private.hh"
+
+
+#ifndef HB_DEBUG_APPLY
+#define HB_DEBUG_APPLY HB_DEBUG+0
+#endif
+
+#define TRACE_APPLY() \
+ hb_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", HB_FUNC, this); \
+
+
+struct hb_apply_context_t
+{
+ unsigned int debug_depth;
+ hb_ot_layout_context_t *layout;
+ hb_buffer_t *buffer;
+ hb_mask_t lookup_mask;
+ unsigned int context_length;
+ unsigned int nesting_level_left;
+ unsigned int lookup_flag;
+ unsigned int property; /* propety of first glyph (TODO remove) */
+};
+
+
+
+typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
+typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+
+struct ContextFuncs
+{
+ match_func_t match;
+ apply_lookup_func_t apply;
+};
+
+
+static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
+{
+ return glyph_id == value;
+}
+
+static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+{
+ const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+ return class_def.get_class (glyph_id) == value;
+}
+
+static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
+{
+ const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
+ return (data+coverage) (glyph_id) != NOT_COVERED;
+}
+
+
+static inline bool match_input (hb_apply_context_t *c,
+ unsigned int count, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int *context_length_out)
+{
+ unsigned int i, j;
+ unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
+ if (unlikely (c->buffer->i + count > end))
+ return false;
+
+ for (i = 1, j = c->buffer->i + 1; i < count; i++, j++)
+ {
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+ {
+ if (unlikely (j + count - i == end))
+ return false;
+ j++;
+ }
+
+ if (likely (!match_func (c->buffer->info[j].codepoint, input[i - 1], match_data)))
+ return false;
+ }
+
+ *context_length_out = j - c->buffer->i;
+
+ return true;
+}
+
+static inline bool match_backtrack (hb_apply_context_t *c,
+ unsigned int count,
+ const USHORT backtrack[],
+ match_func_t match_func,
+ const void *match_data)
+{
+ if (unlikely (c->buffer->out_len < count))
+ return false;
+
+ for (unsigned int i = 0, j = c->buffer->out_len - 1; i < count; i++, j--)
+ {
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->out_info[j], c->lookup_flag, NULL))
+ {
+ if (unlikely (j + 1 == count - i))
+ return false;
+ j--;
+ }
+
+ if (likely (!match_func (c->buffer->out_info[j].codepoint, backtrack[i], match_data)))
+ return false;
+ }
+
+ return true;
+}
+
+static inline bool match_lookahead (hb_apply_context_t *c,
+ unsigned int count,
+ const USHORT lookahead[],
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int offset)
+{
+ unsigned int i, j;
+ unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
+ if (unlikely (c->buffer->i + offset + count > end))
+ return false;
+
+ for (i = 0, j = c->buffer->i + offset; i < count; i++, j++)
+ {
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_flag, NULL))
+ {
+ if (unlikely (j + count - i == end))
+ return false;
+ j++;
+ }
+
+ if (likely (!match_func (c->buffer->info[j].codepoint, lookahead[i], match_data)))
+ return false;
+ }
+
+ return true;
+}
+
+
+struct LookupRecord
+{
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return c->check_struct (this);
+ }
+
+ USHORT sequenceIndex; /* Index into current glyph
+ * sequence--first glyph = 0 */
+ USHORT lookupListIndex; /* Lookup to apply to that
+ * position--zero--based */
+ public:
+ DEFINE_SIZE_STATIC (4);
+};
+
+static inline bool apply_lookup (hb_apply_context_t *c,
+ unsigned int count, /* Including the first glyph */
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
+ apply_lookup_func_t apply_func)
+{
+ unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
+ if (unlikely (c->buffer->i + count > end))
+ return false;
+
+ /* TODO We don't support lookupRecord arrays that are not increasing:
+ * Should be easy for in_place ones at least. */
+
+ /* Note: If sublookup is reverse, i will underflow after the first loop
+ * and we jump out of it. Not entirely disastrous. So we don't check
+ * for reverse lookup here.
+ */
+ for (unsigned int i = 0; i < count; /* NOP */)
+ {
+ while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_flag, NULL))
+ {
+ if (unlikely (c->buffer->i == end))
+ return true;
+ /* No lookup applied for this index */
+ c->buffer->next_glyph ();
+ }
+
+ if (lookupCount && i == lookupRecord->sequenceIndex)
+ {
+ unsigned int old_pos = c->buffer->i;
+
+ /* Apply a lookup */
+ bool done = apply_func (c, lookupRecord->lookupListIndex);
+
+ lookupRecord++;
+ lookupCount--;
+ /* Err, this is wrong if the lookup jumped over some glyphs */
+ i += c->buffer->i - old_pos;
+ if (unlikely (c->buffer->i == end))
+ return true;
+
+ if (!done)
+ goto not_applied;
+ }
+ else
+ {
+ not_applied:
+ /* No lookup applied for this index */
+ c->buffer->next_glyph ();
+ i++;
+ }
+ }
+
+ return true;
+}
+
+
+/* Contextual lookups */
+
+struct ContextLookupContext
+{
+ ContextFuncs funcs;
+ const void *match_data;
+};
+
+static inline bool context_lookup (hb_apply_context_t *c,
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[],
+ ContextLookupContext &lookup_context)
+{
+ hb_apply_context_t new_context = *c;
+ return match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match, lookup_context.match_data,
+ &new_context.context_length)
+ && apply_lookup (&new_context,
+ inputCount,
+ lookupCount, lookupRecord,
+ lookup_context.funcs.apply);
+}
+
+struct Rule
+{
+ friend struct RuleSet;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const
+ {
+ TRACE_APPLY ();
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
+ return context_lookup (c,
+ inputCount, input,
+ lookupCount, lookupRecord,
+ lookup_context);
+ }
+
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return inputCount.sanitize (c)
+ && lookupCount.sanitize (c)
+ && c->check_range (input,
+ input[0].static_size * inputCount
+ + lookupRecordX[0].static_size * lookupCount);
+ }
+
+ private:
+ USHORT inputCount; /* Total number of glyphs in input
+ * glyph sequence--includes the first
+ * glyph */
+ USHORT lookupCount; /* Number of LookupRecords */
+ USHORT input[VAR]; /* Array of match inputs--start with
+ * second glyph */
+ LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
+ * design order */
+ public:
+ DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
+};
+
+struct RuleSet
+{
+ inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const
+ {
+ TRACE_APPLY ();
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ {
+ if ((this+rule[i]).apply (c, lookup_context))
+ return true;
+ }
+
+ return false;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return rule.sanitize (c, this);
+ }
+
+ private:
+ OffsetArrayOf<Rule>
+ rule; /* Array of Rule tables
+ * ordered by preference */
+ public:
+ DEFINE_SIZE_ARRAY (2, rule);
+};
+
+
+struct ContextFormat1
+{
+ friend struct Context;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ {
+ TRACE_APPLY ();
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const RuleSet &rule_set = this+ruleSet[index];
+ struct ContextLookupContext lookup_context = {
+ {match_glyph, apply_func},
+ NULL
+ };
+ return rule_set.apply (c, lookup_context);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && ruleSet.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of table */
+ OffsetArrayOf<RuleSet>
+ ruleSet; /* Array of RuleSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (6, ruleSet);
+};
+
+
+struct ContextFormat2
+{
+ friend struct Context;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ {
+ TRACE_APPLY ();
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const ClassDef &class_def = this+classDef;
+ index = class_def (c->buffer->info[c->buffer->i].codepoint);
+ const RuleSet &rule_set = this+ruleSet[index];
+ /* LONGTERMTODO: Old code fetches glyph classes at most once and caches
+ * them across subrule lookups. Not sure it's worth it.
+ */
+ struct ContextLookupContext lookup_context = {
+ {match_class, apply_func},
+ &class_def
+ };
+ return rule_set.apply (c, lookup_context);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && classDef.sanitize (c, this)
+ && ruleSet.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 2 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of table */
+ OffsetTo<ClassDef>
+ classDef; /* Offset to glyph ClassDef table--from
+ * beginning of table */
+ OffsetArrayOf<RuleSet>
+ ruleSet; /* Array of RuleSet tables
+ * ordered by class */
+ public:
+ DEFINE_SIZE_ARRAY (8, ruleSet);
+};
+
+
+struct ContextFormat3
+{
+ friend struct Context;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ {
+ TRACE_APPLY ();
+ unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
+ struct ContextLookupContext lookup_context = {
+ {match_coverage, apply_func},
+ this
+ };
+ return context_lookup (c,
+ glyphCount, (const USHORT *) (coverage + 1),
+ lookupCount, lookupRecord,
+ lookup_context);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!c->check_struct (this)) return false;
+ unsigned int count = glyphCount;
+ if (!c->check_array (coverage, coverage[0].static_size, count)) return false;
+ for (unsigned int i = 0; i < count; i++)
+ if (!coverage[i].sanitize (c, this)) return false;
+ LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
+ return c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 3 */
+ USHORT glyphCount; /* Number of glyphs in the input glyph
+ * sequence */
+ USHORT lookupCount; /* Number of LookupRecords */
+ OffsetTo<Coverage>
+ coverage[VAR]; /* Array of offsets to Coverage
+ * table in glyph sequence order */
+ LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
+ * design order */
+ public:
+ DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
+};
+
+struct Context
+{
+ protected:
+ inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ {
+ TRACE_APPLY ();
+ switch (u.format) {
+ case 1: return u.format1.apply (c, apply_func);
+ case 2: return u.format2.apply (c, apply_func);
+ case 3: return u.format3.apply (c, apply_func);
+ default:return false;
+ }
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!u.format.sanitize (c)) return false;
+ switch (u.format) {
+ case 1: return u.format1.sanitize (c);
+ case 2: return u.format2.sanitize (c);
+ case 3: return u.format3.sanitize (c);
+ default:return true;
+ }
+ }
+
+ private:
+ union {
+ USHORT format; /* Format identifier */
+ ContextFormat1 format1;
+ ContextFormat2 format2;
+ ContextFormat3 format3;
+ } u;
+};
+
+
+/* Chaining Contextual lookups */
+
+struct ChainContextLookupContext
+{
+ ContextFuncs funcs;
+ const void *match_data[3];
+};
+
+static inline bool chain_context_lookup (hb_apply_context_t *c,
+ unsigned int backtrackCount,
+ const USHORT backtrack[],
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const USHORT input[], /* Array of input values--start with second glyph */
+ unsigned int lookaheadCount,
+ const USHORT lookahead[],
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[],
+ ChainContextLookupContext &lookup_context)
+{
+ /* First guess */
+ if (unlikely (c->buffer->out_len < backtrackCount ||
+ c->buffer->i + inputCount + lookaheadCount > c->buffer->len ||
+ inputCount + lookaheadCount > c->context_length))
+ return false;
+
+ hb_apply_context_t new_context = *c;
+ return match_backtrack (c,
+ backtrackCount, backtrack,
+ lookup_context.funcs.match, lookup_context.match_data[0])
+ && match_input (c,
+ inputCount, input,
+ lookup_context.funcs.match, lookup_context.match_data[1],
+ &new_context.context_length)
+ && match_lookahead (c,
+ lookaheadCount, lookahead,
+ lookup_context.funcs.match, lookup_context.match_data[2],
+ new_context.context_length)
+ && apply_lookup (&new_context,
+ inputCount,
+ lookupCount, lookupRecord,
+ lookup_context.funcs.apply);
+}
+
+struct ChainRule
+{
+ friend struct ChainRuleSet;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const
+ {
+ TRACE_APPLY ();
+ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ return chain_context_lookup (c,
+ backtrack.len, backtrack.array,
+ input.len, input.array,
+ lookahead.len, lookahead.array,
+ lookup.len, lookup.array,
+ lookup_context);
+ return false;
+ }
+
+ public:
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ if (!backtrack.sanitize (c)) return false;
+ HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ if (!input.sanitize (c)) return false;
+ ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ if (!lookahead.sanitize (c)) return false;
+ ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ return lookup.sanitize (c);
+ }
+
+ private:
+ ArrayOf<USHORT>
+ backtrack; /* Array of backtracking values
+ * (to be matched before the input
+ * sequence) */
+ HeadlessArrayOf<USHORT>
+ inputX; /* Array of input values (start with
+ * second glyph) */
+ ArrayOf<USHORT>
+ lookaheadX; /* Array of lookahead values's (to be
+ * matched after the input sequence) */
+ ArrayOf<LookupRecord>
+ lookupX; /* Array of LookupRecords--in
+ * design order) */
+ public:
+ DEFINE_SIZE_MIN (8);
+};
+
+struct ChainRuleSet
+{
+ inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const
+ {
+ TRACE_APPLY ();
+ unsigned int num_rules = rule.len;
+ for (unsigned int i = 0; i < num_rules; i++)
+ {
+ if ((this+rule[i]).apply (c, lookup_context))
+ return true;
+ }
+
+ return false;
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return rule.sanitize (c, this);
+ }
+
+ private:
+ OffsetArrayOf<ChainRule>
+ rule; /* Array of ChainRule tables
+ * ordered by preference */
+ public:
+ DEFINE_SIZE_ARRAY (2, rule);
+};
+
+struct ChainContextFormat1
+{
+ friend struct ChainContext;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ {
+ TRACE_APPLY ();
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const ChainRuleSet &rule_set = this+ruleSet[index];
+ struct ChainContextLookupContext lookup_context = {
+ {match_glyph, apply_func},
+ {NULL, NULL, NULL}
+ };
+ return rule_set.apply (c, lookup_context);
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) {
+ TRACE_SANITIZE ();
+ return coverage.sanitize (c, this)
+ && ruleSet.sanitize (c, this);
+ }
+
+ private:
+ USHORT format; /* Format identifier--format = 1 */
+ OffsetTo<Coverage>
+ coverage; /* Offset to Coverage table--from
+ * beginning of table */
+ OffsetArrayOf<ChainRuleSet>
+ ruleSet; /* Array of ChainRuleSet tables
+ * ordered by Coverage Index */
+ public:
+ DEFINE_SIZE_ARRAY (6, ruleSet);
+};
+
+struct ChainContextFormat2
+{
+ friend struct ChainContext;
+
+ private:
+ inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
+ {
+ TRACE_APPLY ();
+ unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
+ if (likely (index == NOT_COVERED))
+ return false;
+
+ const ClassDef &backtrack_class_def = this+backtrackClassDef;
+ const ClassDef &input_class_def = this+inputClassDef;
+ const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+ index = input_class_def (c->buffer->info[c->buffer->i].codepoint);
+ const ChainRuleSet &rule_set = this+ruleSet[index];
+ /* LONGTERMTODO: Old code fetches glyph classes at most once and caches
+ * them across subrule lookups. Not sure it's worth it.
+ */
+ struct ChainContextLookupContext lookup_context = {
+ {match_class, apply_func},
+ {&backtrack_class_def,
+ &input_class_def,
+ &lookahead_class_def}
+ };
+ return r