зеркало из https://github.com/mozilla/gecko-dev.git
bug 449292 - part 1 - harfbuzz-ng code from upstream. r=jdaggett sr=roc
This commit is contained in:
Родитель
e3499cdeb7
Коммит
d2c3a98fdb
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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 */
|
|
@ -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 rule_set.apply (c, lookup_context);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE ();
|
||||
return coverage.sanitize (c, this)
|
||||
&& backtrackClassDef.sanitize (c, this)
|
||||
&& inputClassDef.sanitize (c, this)
|
||||
&& lookaheadClassDef.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>
|
||||
backtrackClassDef; /* Offset to glyph ClassDef table
|
||||
* containing backtrack sequence
|
||||
* data--from beginning of table */
|
||||
OffsetTo<ClassDef>
|
||||
inputClassDef; /* Offset to glyph ClassDef
|
||||
* table containing input sequence
|
||||
* data--from beginning of table */
|
||||
OffsetTo<ClassDef>
|
||||
lookaheadClassDef; /* Offset to glyph ClassDef table
|
||||
* containing lookahead sequence
|
||||
* data--from beginning of table */
|
||||
OffsetArrayOf<ChainRuleSet>
|
||||
ruleSet; /* Array of ChainRuleSet tables
|
||||
* ordered by class */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (12, ruleSet);
|
||||
};
|
||||
|
||||
struct ChainContextFormat3
|
||||
{
|
||||
friend struct ChainContext;
|
||||
|
||||
private:
|
||||
|
||||
inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
|
||||
{
|
||||
TRACE_APPLY ();
|
||||
const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
|
||||
unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->i].codepoint);
|
||||
if (likely (index == NOT_COVERED))
|
||||
return false;
|
||||
|
||||
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
struct ChainContextLookupContext lookup_context = {
|
||||
{match_coverage, apply_func},
|
||||
{this, this, this}
|
||||
};
|
||||
return chain_context_lookup (c,
|
||||
backtrack.len, (const USHORT *) backtrack.array,
|
||||
input.len, (const USHORT *) input.array + 1,
|
||||
lookahead.len, (const USHORT *) lookahead.array,
|
||||
lookup.len, lookup.array,
|
||||
lookup_context);
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE ();
|
||||
if (!backtrack.sanitize (c, this)) return false;
|
||||
OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
|
||||
if (!input.sanitize (c, this)) return false;
|
||||
OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
|
||||
if (!lookahead.sanitize (c, this)) return false;
|
||||
ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
|
||||
return lookup.sanitize (c);
|
||||
}
|
||||
|
||||
private:
|
||||
USHORT format; /* Format identifier--format = 3 */
|
||||
OffsetArrayOf<Coverage>
|
||||
backtrack; /* Array of coverage tables
|
||||
* in backtracking sequence, in glyph
|
||||
* sequence order */
|
||||
OffsetArrayOf<Coverage>
|
||||
inputX ; /* Array of coverage
|
||||
* tables in input sequence, in glyph
|
||||
* sequence order */
|
||||
OffsetArrayOf<Coverage>
|
||||
lookaheadX; /* Array of coverage tables
|
||||
* in lookahead sequence, in glyph
|
||||
* sequence order */
|
||||
ArrayOf<LookupRecord>
|
||||
lookupX; /* Array of LookupRecords--in
|
||||
* design order) */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (10);
|
||||
};
|
||||
|
||||
struct ChainContext
|
||||
{
|
||||
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 */
|
||||
ChainContextFormat1 format1;
|
||||
ChainContextFormat2 format2;
|
||||
ChainContextFormat3 format3;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
struct ExtensionFormat1
|
||||
{
|
||||
friend struct Extension;
|
||||
|
||||
protected:
|
||||
inline unsigned int get_type (void) const { return extensionLookupType; }
|
||||
inline unsigned int get_offset (void) const { return extensionOffset; }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE ();
|
||||
return c->check_struct (this);
|
||||
}
|
||||
|
||||
private:
|
||||
USHORT format; /* Format identifier. Set to 1. */
|
||||
USHORT extensionLookupType; /* Lookup type of subtable referenced
|
||||
* by ExtensionOffset (i.e. the
|
||||
* extension subtable). */
|
||||
ULONG extensionOffset; /* Offset to the extension subtable,
|
||||
* of lookup type subtable. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct Extension
|
||||
{
|
||||
inline unsigned int get_type (void) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.get_type ();
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
inline unsigned int get_offset (void) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.get_offset ();
|
||||
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);
|
||||
default:return true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
USHORT format; /* Format identifier */
|
||||
ExtensionFormat1 format1;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* GSUB/GPOS Common
|
||||
*/
|
||||
|
||||
struct GSUBGPOS
|
||||
{
|
||||
static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
|
||||
static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
|
||||
|
||||
inline unsigned int get_script_count (void) const
|
||||
{ return (this+scriptList).len; }
|
||||
inline const Tag& get_script_tag (unsigned int i) const
|
||||
{ return (this+scriptList).get_tag (i); }
|
||||
inline unsigned int get_script_tags (unsigned int start_offset,
|
||||
unsigned int *script_count /* IN/OUT */,
|
||||
hb_tag_t *script_tags /* OUT */) const
|
||||
{ return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
|
||||
inline const Script& get_script (unsigned int i) const
|
||||
{ return (this+scriptList)[i]; }
|
||||
inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
|
||||
{ return (this+scriptList).find_index (tag, index); }
|
||||
|
||||
inline unsigned int get_feature_count (void) const
|
||||
{ return (this+featureList).len; }
|
||||
inline const Tag& get_feature_tag (unsigned int i) const
|
||||
{ return (this+featureList).get_tag (i); }
|
||||
inline unsigned int get_feature_tags (unsigned int start_offset,
|
||||
unsigned int *feature_count /* IN/OUT */,
|
||||
hb_tag_t *feature_tags /* OUT */) const
|
||||
{ return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
|
||||
inline const Feature& get_feature (unsigned int i) const
|
||||
{ return (this+featureList)[i]; }
|
||||
inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
|
||||
{ return (this+featureList).find_index (tag, index); }
|
||||
|
||||
inline unsigned int get_lookup_count (void) const
|
||||
{ return (this+lookupList).len; }
|
||||
inline const Lookup& get_lookup (unsigned int i) const
|
||||
{ return (this+lookupList)[i]; }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) {
|
||||
TRACE_SANITIZE ();
|
||||
return version.sanitize (c) && likely (version.major == 1)
|
||||
&& scriptList.sanitize (c, this)
|
||||
&& featureList.sanitize (c, this)
|
||||
&& lookupList.sanitize (c, this);
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion version; /* Version of the GSUB/GPOS table--initially set
|
||||
* to 0x00010000 */
|
||||
OffsetTo<ScriptList>
|
||||
scriptList; /* ScriptList table */
|
||||
OffsetTo<FeatureList>
|
||||
featureList; /* FeatureList table */
|
||||
OffsetTo<LookupList>
|
||||
lookupList; /* LookupList table */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (10);
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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_PRIVATE_H
|
||||
#define HB_OT_LAYOUT_PRIVATE_H
|
||||
|
||||
#include "hb-private.h"
|
||||
|
||||
#include "hb-ot-layout.h"
|
||||
|
||||
#include "hb-font-private.hh"
|
||||
#include "hb-buffer-private.hh"
|
||||
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
typedef unsigned int hb_ot_layout_class_t;
|
||||
|
||||
/*
|
||||
* hb_ot_layout_t
|
||||
*/
|
||||
|
||||
struct hb_ot_layout_t
|
||||
{
|
||||
hb_blob_t *gdef_blob;
|
||||
hb_blob_t *gsub_blob;
|
||||
hb_blob_t *gpos_blob;
|
||||
|
||||
const struct GDEF *gdef;
|
||||
const struct GSUB *gsub;
|
||||
const struct GPOS *gpos;
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned char *klasses;
|
||||
unsigned int len;
|
||||
} new_gdef;
|
||||
};
|
||||
|
||||
struct hb_ot_layout_context_t
|
||||
{
|
||||
hb_face_t *face;
|
||||
hb_font_t *font;
|
||||
|
||||
union info_t
|
||||
{
|
||||
struct gpos_t
|
||||
{
|
||||
unsigned int last; /* the last valid glyph--used with cursive positioning */
|
||||
hb_position_t anchor_x; /* the coordinates of the anchor point */
|
||||
hb_position_t anchor_y; /* of the last valid glyph */
|
||||
} gpos;
|
||||
} info;
|
||||
|
||||
/* Convert from font-space to user-space */
|
||||
/* XXX div-by-zero / speed up */
|
||||
inline hb_position_t scale_x (int16_t v) { return (int64_t) this->font->x_scale * v / this->face->head_table->unitsPerEm; }
|
||||
inline hb_position_t scale_y (int16_t v) { return (int64_t) this->font->y_scale * v / this->face->head_table->unitsPerEm; }
|
||||
};
|
||||
|
||||
|
||||
HB_INTERNAL hb_ot_layout_t *
|
||||
_hb_ot_layout_new (hb_face_t *face);
|
||||
|
||||
HB_INTERNAL void
|
||||
_hb_ot_layout_free (hb_ot_layout_t *layout);
|
||||
|
||||
|
||||
/*
|
||||
* GDEF
|
||||
*/
|
||||
|
||||
HB_INTERNAL hb_bool_t
|
||||
_hb_ot_layout_has_new_glyph_classes (hb_face_t *face);
|
||||
|
||||
HB_INTERNAL void
|
||||
_hb_ot_layout_set_glyph_property (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int property);
|
||||
|
||||
HB_INTERNAL void
|
||||
_hb_ot_layout_set_glyph_class (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
hb_ot_layout_glyph_class_t klass);
|
||||
|
||||
HB_INTERNAL hb_bool_t
|
||||
_hb_ot_layout_check_glyph_property (hb_face_t *face,
|
||||
hb_internal_glyph_info_t *ginfo,
|
||||
unsigned int lookup_flags,
|
||||
unsigned int *property);
|
||||
|
||||
HB_INTERNAL hb_bool_t
|
||||
_hb_ot_layout_skip_mark (hb_face_t *face,
|
||||
hb_internal_glyph_info_t *ginfo,
|
||||
unsigned int lookup_flags,
|
||||
unsigned int *property);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_OT_LAYOUT_PRIVATE_H */
|
|
@ -0,0 +1,646 @@
|
|||
/*
|
||||
* Copyright (C) 1998-2004 David Turner and Werner Lemberg
|
||||
* Copyright (C) 2006 Behdad Esfahbod
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define HB_OT_LAYOUT_CC
|
||||
|
||||
#include "hb-ot-layout-private.hh"
|
||||
|
||||
#include "hb-ot-layout-gdef-private.hh"
|
||||
#include "hb-ot-layout-gsub-private.hh"
|
||||
#include "hb-ot-layout-gpos-private.hh"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
hb_ot_layout_t *
|
||||
_hb_ot_layout_new (hb_face_t *face)
|
||||
{
|
||||
/* Remove this object altogether */
|
||||
hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
|
||||
|
||||
layout->gdef_blob = Sanitizer<GDEF>::sanitize (hb_face_get_table (face, HB_OT_TAG_GDEF));
|
||||
layout->gdef = Sanitizer<GDEF>::lock_instance (layout->gdef_blob);
|
||||
|
||||
layout->gsub_blob = Sanitizer<GSUB>::sanitize (hb_face_get_table (face, HB_OT_TAG_GSUB));
|
||||
layout->gsub = Sanitizer<GSUB>::lock_instance (layout->gsub_blob);
|
||||
|
||||
layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_get_table (face, HB_OT_TAG_GPOS));
|
||||
layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_ot_layout_free (hb_ot_layout_t *layout)
|
||||
{
|
||||
hb_blob_unlock (layout->gdef_blob);
|
||||
hb_blob_unlock (layout->gsub_blob);
|
||||
hb_blob_unlock (layout->gpos_blob);
|
||||
|
||||
hb_blob_destroy (layout->gdef_blob);
|
||||
hb_blob_destroy (layout->gsub_blob);
|
||||
hb_blob_destroy (layout->gpos_blob);
|
||||
|
||||
free (layout->new_gdef.klasses);
|
||||
}
|
||||
|
||||
static const GDEF&
|
||||
_get_gdef (hb_face_t *face)
|
||||
{
|
||||
return likely (face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF);
|
||||
}
|
||||
|
||||
static const GSUB&
|
||||
_get_gsub (hb_face_t *face)
|
||||
{
|
||||
return likely (face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB);
|
||||
}
|
||||
|
||||
static const GPOS&
|
||||
_get_gpos (hb_face_t *face)
|
||||
{
|
||||
return likely (face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GDEF
|
||||
*/
|
||||
|
||||
/* TODO the public class_t is a mess */
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_has_glyph_classes (hb_face_t *face)
|
||||
{
|
||||
return _get_gdef (face).has_glyph_classes ();
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
_hb_ot_layout_has_new_glyph_classes (hb_face_t *face)
|
||||
{
|
||||
return face->ot_layout->new_gdef.len > 0;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
_hb_ot_layout_get_glyph_property (hb_face_t *face,
|
||||
hb_codepoint_t glyph)
|
||||
{
|
||||
hb_ot_layout_class_t klass;
|
||||
const GDEF &gdef = _get_gdef (face);
|
||||
|
||||
klass = gdef.get_glyph_class (glyph);
|
||||
|
||||
if (!klass && glyph < face->ot_layout->new_gdef.len)
|
||||
klass = face->ot_layout->new_gdef.klasses[glyph];
|
||||
|
||||
switch (klass) {
|
||||
default:
|
||||
case GDEF::UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
|
||||
case GDEF::BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
|
||||
case GDEF::LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
|
||||
case GDEF::ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT;
|
||||
case GDEF::MarkGlyph:
|
||||
klass = gdef.get_mark_attachment_type (glyph);
|
||||
return HB_OT_LAYOUT_GLYPH_CLASS_MARK + (klass << 8);
|
||||
}
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
_hb_ot_layout_check_glyph_property (hb_face_t *face,
|
||||
hb_internal_glyph_info_t *ginfo,
|
||||
unsigned int lookup_flags,
|
||||
unsigned int *property_out)
|
||||
{
|
||||
unsigned int property;
|
||||
|
||||
if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
|
||||
ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
|
||||
property = ginfo->gproperty;
|
||||
if (property_out)
|
||||
*property_out = property;
|
||||
|
||||
/* Not covered, if, for example, glyph class is ligature and
|
||||
* lookup_flags includes LookupFlags::IgnoreLigatures
|
||||
*/
|
||||
if (property & lookup_flags & LookupFlag::IgnoreFlags)
|
||||
return false;
|
||||
|
||||
if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
|
||||
{
|
||||
/* If using mark filtering sets, the high short of
|
||||
* lookup_flags has the set index.
|
||||
*/
|
||||
if (lookup_flags & LookupFlag::UseMarkFilteringSet)
|
||||
return _get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
|
||||
|
||||
/* The second byte of lookup_flags has the meaning
|
||||
* "ignore marks of attachment type different than
|
||||
* the attachment type specified."
|
||||
*/
|
||||
if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
|
||||
return (lookup_flags & LookupFlag::MarkAttachmentType) == (property & LookupFlag::MarkAttachmentType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
_hb_ot_layout_skip_mark (hb_face_t *face,
|
||||
hb_internal_glyph_info_t *ginfo,
|
||||
unsigned int lookup_flags,
|
||||
unsigned int *property_out)
|
||||
{
|
||||
unsigned int property;
|
||||
|
||||
if (ginfo->gproperty == HB_BUFFER_GLYPH_PROPERTIES_UNKNOWN)
|
||||
ginfo->gproperty = _hb_ot_layout_get_glyph_property (face, ginfo->codepoint);
|
||||
property = ginfo->gproperty;
|
||||
if (property_out)
|
||||
*property_out = property;
|
||||
|
||||
if (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
|
||||
{
|
||||
/* Skip mark if lookup_flags includes LookupFlags::IgnoreMarks */
|
||||
if (lookup_flags & LookupFlag::IgnoreMarks)
|
||||
return true;
|
||||
|
||||
/* If using mark filtering sets, the high short of lookup_flags has the set index. */
|
||||
if (lookup_flags & LookupFlag::UseMarkFilteringSet)
|
||||
return !_get_gdef (face).mark_set_covers (lookup_flags >> 16, ginfo->codepoint);
|
||||
|
||||
/* The second byte of lookup_flags has the meaning "ignore marks of attachment type
|
||||
* different than the attachment type specified." */
|
||||
if (lookup_flags & LookupFlag::MarkAttachmentType && property & LookupFlag::MarkAttachmentType)
|
||||
return (lookup_flags & LookupFlag::MarkAttachmentType) != (property & LookupFlag::MarkAttachmentType);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_ot_layout_set_glyph_class (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
hb_ot_layout_glyph_class_t klass)
|
||||
{
|
||||
if (HB_OBJECT_IS_INERT (face))
|
||||
return;
|
||||
|
||||
/* TODO optimize this? similar to old harfbuzz code for example */
|
||||
|
||||
hb_ot_layout_t *layout = face->ot_layout;
|
||||
hb_ot_layout_class_t gdef_klass;
|
||||
unsigned int len = layout->new_gdef.len;
|
||||
|
||||
if (unlikely (glyph > 65535))
|
||||
return;
|
||||
|
||||
/* XXX this is not threadsafe */
|
||||
if (glyph >= len) {
|
||||
unsigned int new_len;
|
||||
unsigned char *new_klasses;
|
||||
|
||||
new_len = len == 0 ? 120 : 2 * len;
|
||||
while (new_len <= glyph)
|
||||
new_len *= 2;
|
||||
|
||||
if (new_len > 65536)
|
||||
new_len = 65536;
|
||||
new_klasses = (unsigned char *) realloc (layout->new_gdef.klasses, new_len * sizeof (unsigned char));
|
||||
|
||||
if (unlikely (!new_klasses))
|
||||
return;
|
||||
|
||||
memset (new_klasses + len, 0, new_len - len);
|
||||
|
||||
layout->new_gdef.klasses = new_klasses;
|
||||
layout->new_gdef.len = new_len;
|
||||
}
|
||||
|
||||
switch (klass) {
|
||||
default:
|
||||
case HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: gdef_klass = GDEF::UnclassifiedGlyph; break;
|
||||
case HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: gdef_klass = GDEF::BaseGlyph; break;
|
||||
case HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: gdef_klass = GDEF::LigatureGlyph; break;
|
||||
case HB_OT_LAYOUT_GLYPH_CLASS_MARK: gdef_klass = GDEF::MarkGlyph; break;
|
||||
case HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: gdef_klass = GDEF::ComponentGlyph; break;
|
||||
}
|
||||
|
||||
layout->new_gdef.klasses[glyph] = gdef_klass;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_ot_layout_set_glyph_property (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int property)
|
||||
{ _hb_ot_layout_set_glyph_class (face, glyph, (hb_ot_layout_glyph_class_t) (property & 0xff)); }
|
||||
|
||||
|
||||
hb_ot_layout_glyph_class_t
|
||||
hb_ot_layout_get_glyph_class (hb_face_t *face,
|
||||
hb_codepoint_t glyph)
|
||||
{
|
||||
return (hb_ot_layout_glyph_class_t) (_hb_ot_layout_get_glyph_property (face, glyph) & 0xff);
|
||||
}
|
||||
|
||||
void
|
||||
hb_ot_layout_set_glyph_class (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
hb_ot_layout_glyph_class_t klass)
|
||||
{
|
||||
_hb_ot_layout_set_glyph_class (face, glyph, klass);
|
||||
}
|
||||
|
||||
void
|
||||
hb_ot_layout_build_glyph_classes (hb_face_t *face,
|
||||
hb_codepoint_t *glyphs,
|
||||
unsigned char *klasses,
|
||||
uint16_t count)
|
||||
{
|
||||
if (HB_OBJECT_IS_INERT (face))
|
||||
return;
|
||||
|
||||
hb_ot_layout_t *layout = face->ot_layout;
|
||||
|
||||
if (unlikely (!count || !glyphs || !klasses))
|
||||
return;
|
||||
|
||||
if (layout->new_gdef.len == 0) {
|
||||
layout->new_gdef.klasses = (unsigned char *) calloc (count, sizeof (unsigned char));
|
||||
layout->new_gdef.len = count;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
_hb_ot_layout_set_glyph_class (face, glyphs[i], (hb_ot_layout_glyph_class_t) klasses[i]);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_get_attach_points (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *point_count /* IN/OUT */,
|
||||
unsigned int *point_array /* OUT */)
|
||||
{
|
||||
return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_get_lig_carets (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
int *caret_array /* OUT */)
|
||||
{
|
||||
hb_ot_layout_context_t c;
|
||||
c.font = font;
|
||||
c.face = face;
|
||||
return _get_gdef (face).get_lig_carets (&c, glyph, start_offset, caret_count, caret_array);
|
||||
}
|
||||
|
||||
/*
|
||||
* GSUB/GPOS
|
||||
*/
|
||||
|
||||
static const GSUBGPOS&
|
||||
get_gsubgpos_table (hb_face_t *face,
|
||||
hb_tag_t table_tag)
|
||||
{
|
||||
switch (table_tag) {
|
||||
case HB_OT_TAG_GSUB: return _get_gsub (face);
|
||||
case HB_OT_TAG_GPOS: return _get_gpos (face);
|
||||
default: return Null(GSUBGPOS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_table_get_script_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int start_offset,
|
||||
unsigned int *script_count /* IN/OUT */,
|
||||
hb_tag_t *script_tags /* OUT */)
|
||||
{
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
|
||||
return g.get_script_tags (start_offset, script_count, script_tags);
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_table_find_script (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
hb_tag_t script_tag,
|
||||
unsigned int *script_index)
|
||||
{
|
||||
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
|
||||
if (g.find_script_index (script_tag, script_index))
|
||||
return TRUE;
|
||||
|
||||
/* try finding 'DFLT' */
|
||||
if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
|
||||
return FALSE;
|
||||
|
||||
/* try with 'dflt'; MS site has had typos and many fonts use it now :( */
|
||||
if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
|
||||
return FALSE;
|
||||
|
||||
if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_table_choose_script (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
const hb_tag_t *script_tags,
|
||||
unsigned int *script_index)
|
||||
{
|
||||
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
|
||||
while (*script_tags)
|
||||
{
|
||||
if (g.find_script_index (*script_tags, script_index))
|
||||
return TRUE;
|
||||
script_tags++;
|
||||
}
|
||||
|
||||
/* try finding 'DFLT' */
|
||||
if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
|
||||
return FALSE;
|
||||
|
||||
/* try with 'dflt'; MS site has had typos and many fonts use it now :( */
|
||||
if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
|
||||
return FALSE;
|
||||
|
||||
if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count /* IN/OUT */,
|
||||
hb_tag_t *feature_tags /* OUT */)
|
||||
{
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
|
||||
return g.get_feature_tags (start_offset, feature_count, feature_tags);
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_script_get_language_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *language_count /* IN/OUT */,
|
||||
hb_tag_t *language_tags /* OUT */)
|
||||
{
|
||||
const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
||||
|
||||
return s.get_lang_sys_tags (start_offset, language_count, language_tags);
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_script_find_language (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
hb_tag_t language_tag,
|
||||
unsigned int *language_index)
|
||||
{
|
||||
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
|
||||
const Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
|
||||
|
||||
if (s.find_lang_sys_index (language_tag, language_index))
|
||||
return TRUE;
|
||||
|
||||
/* try with 'dflt'; MS site has had typos and many fonts use it now :( */
|
||||
if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
|
||||
return FALSE;
|
||||
|
||||
if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
unsigned int *feature_index)
|
||||
{
|
||||
const LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
|
||||
|
||||
if (feature_index) *feature_index = l.get_required_feature_index ();
|
||||
|
||||
return l.has_required_feature ();
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count /* IN/OUT */,
|
||||
unsigned int *feature_indexes /* OUT */)
|
||||
{
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
||||
|
||||
return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count /* IN/OUT */,
|
||||
hb_tag_t *feature_tags /* OUT */)
|
||||
{
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
||||
|
||||
ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
|
||||
unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
|
||||
|
||||
if (feature_tags) {
|
||||
unsigned int count = *feature_count;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_language_find_feature (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
hb_tag_t feature_tag,
|
||||
unsigned int *feature_index)
|
||||
{
|
||||
ASSERT_STATIC (Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
const LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
||||
|
||||
unsigned int num_features = l.get_feature_count ();
|
||||
for (unsigned int i = 0; i < num_features; i++) {
|
||||
unsigned int f_index = l.get_feature_index (i);
|
||||
|
||||
if (feature_tag == g.get_feature_tag (f_index)) {
|
||||
if (feature_index) *feature_index = f_index;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int feature_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *lookup_count /* IN/OUT */,
|
||||
unsigned int *lookup_indexes /* OUT */)
|
||||
{
|
||||
const GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
const Feature &f = g.get_feature (feature_index);
|
||||
|
||||
return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GSUB
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_has_substitution (hb_face_t *face)
|
||||
{
|
||||
return &_get_gsub (face) != &Null(GSUB);
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_substitute_lookup (hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int lookup_index,
|
||||
hb_mask_t mask)
|
||||
{
|
||||
hb_ot_layout_context_t c;
|
||||
c.font = NULL;
|
||||
c.face = face;
|
||||
return _get_gsub (face).substitute_lookup (&c, buffer, lookup_index, mask);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GPOS
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_has_positioning (hb_face_t *face)
|
||||
{
|
||||
return &_get_gpos (face) != &Null(GPOS);
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_position_lookup (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int lookup_index,
|
||||
hb_mask_t mask)
|
||||
{
|
||||
hb_ot_layout_context_t c;
|
||||
c.font = font;
|
||||
c.face = face;
|
||||
return _get_gpos (face).position_lookup (&c, buffer, lookup_index, mask);
|
||||
}
|
||||
|
||||
void
|
||||
hb_ot_layout_position_finish (hb_font_t *font HB_UNUSED,
|
||||
hb_face_t *face HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
unsigned int i, j;
|
||||
unsigned int len = hb_buffer_get_length (buffer);
|
||||
hb_internal_glyph_position_t *pos = (hb_internal_glyph_position_t *) hb_buffer_get_glyph_positions (buffer);
|
||||
|
||||
/* TODO: Vertical */
|
||||
|
||||
/* Handle cursive connections */
|
||||
/* First handle all left-to-right connections */
|
||||
for (j = 0; j < len; j++) {
|
||||
if (pos[j].cursive_chain > 0)
|
||||
{
|
||||
pos[j].y_offset += pos[j - pos[j].cursive_chain].y_offset;
|
||||
pos[j].cursive_chain = 0;
|
||||
}
|
||||
}
|
||||
/* Then handle all right-to-left connections */
|
||||
for (i = len; i > 0; i--) {
|
||||
j = i - 1;
|
||||
if (pos[j].cursive_chain < 0)
|
||||
{
|
||||
pos[j].y_offset += pos[j - pos[j].cursive_chain].y_offset;
|
||||
pos[j].cursive_chain = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle attachments */
|
||||
for (i = 0; i < len; i++)
|
||||
if (pos[i].back)
|
||||
{
|
||||
unsigned int back = i - pos[i].back;
|
||||
pos[i].back = 0;
|
||||
pos[i].x_offset += pos[back].x_offset;
|
||||
pos[i].y_offset += pos[back].y_offset;
|
||||
|
||||
if (buffer->direction == HB_DIRECTION_RTL)
|
||||
for (j = back + 1; j < i + 1; j++) {
|
||||
pos[i].x_offset += pos[j].x_advance;
|
||||
pos[i].y_offset += pos[j].y_advance;
|
||||
}
|
||||
else
|
||||
for (j = back; j < i; j++) {
|
||||
pos[i].x_offset -= pos[j].x_advance;
|
||||
pos[i].y_offset -= pos[j].y_advance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* 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_H
|
||||
#define HB_OT_LAYOUT_H
|
||||
|
||||
#include "hb-common.h"
|
||||
#include "hb-buffer.h"
|
||||
#include "hb-font.h"
|
||||
|
||||
#include "hb-ot-tag.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
#define HB_OT_TAG_GDEF HB_TAG('G','D','E','F')
|
||||
#define HB_OT_TAG_GSUB HB_TAG('G','S','U','B')
|
||||
#define HB_OT_TAG_GPOS HB_TAG('G','P','O','S')
|
||||
|
||||
/*
|
||||
* GDEF
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0000,
|
||||
HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 0x0002,
|
||||
HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 0x0004,
|
||||
HB_OT_LAYOUT_GLYPH_CLASS_MARK = 0x0008,
|
||||
HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 0x0010
|
||||
} hb_ot_layout_glyph_class_t;
|
||||
|
||||
/* XXX These should eventually be removed as we move synthesized glyph
|
||||
* classes in harfbuzz. */
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_has_glyph_classes (hb_face_t *face);
|
||||
|
||||
hb_ot_layout_glyph_class_t
|
||||
hb_ot_layout_get_glyph_class (hb_face_t *face,
|
||||
hb_codepoint_t glyph);
|
||||
|
||||
void
|
||||
hb_ot_layout_set_glyph_class (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
hb_ot_layout_glyph_class_t klass);
|
||||
|
||||
void
|
||||
hb_ot_layout_build_glyph_classes (hb_face_t *face,
|
||||
hb_codepoint_t *glyphs,
|
||||
unsigned char *klasses,
|
||||
uint16_t count);
|
||||
|
||||
/* Not that useful. Provides list of attach points for a glyph that a
|
||||
* client may want to cache */
|
||||
unsigned int
|
||||
hb_ot_layout_get_attach_points (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *point_count /* IN/OUT */,
|
||||
unsigned int *point_array /* OUT */);
|
||||
|
||||
/* Ligature caret positions */
|
||||
unsigned int
|
||||
hb_ot_layout_get_lig_carets (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
int *caret_array /* OUT */);
|
||||
|
||||
|
||||
/*
|
||||
* GSUB/GPOS feature query and enumeration interface
|
||||
*/
|
||||
|
||||
#define HB_OT_LAYOUT_NO_SCRIPT_INDEX ((unsigned int) 0xFFFF)
|
||||
#define HB_OT_LAYOUT_NO_FEATURE_INDEX ((unsigned int) 0xFFFF)
|
||||
#define HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX ((unsigned int) 0xFFFF)
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_table_get_script_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int start_offset,
|
||||
unsigned int *script_count /* IN/OUT */,
|
||||
hb_tag_t *script_tags /* OUT */);
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_table_find_script (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
hb_tag_t script_tag,
|
||||
unsigned int *script_index);
|
||||
|
||||
/* Like find_script, but takes zero-terminated array of scripts to test */
|
||||
hb_bool_t
|
||||
hb_ot_layout_table_choose_script (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
const hb_tag_t *script_tags,
|
||||
unsigned int *script_index);
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count /* IN/OUT */,
|
||||
hb_tag_t *feature_tags /* OUT */);
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_script_get_language_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *language_count /* IN/OUT */,
|
||||
hb_tag_t *language_tags /* OUT */);
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_script_find_language (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
hb_tag_t language_tag,
|
||||
unsigned int *language_index);
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_language_get_required_feature_index (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
unsigned int *feature_index);
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count /* IN/OUT */,
|
||||
unsigned int *feature_indexes /* OUT */);
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count /* IN/OUT */,
|
||||
hb_tag_t *feature_tags /* OUT */);
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_language_find_feature (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
hb_tag_t feature_tag,
|
||||
unsigned int *feature_index);
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int feature_index,
|
||||
unsigned int start_offset,
|
||||
unsigned int *lookup_count /* IN/OUT */,
|
||||
unsigned int *lookup_indexes /* OUT */);
|
||||
|
||||
|
||||
/*
|
||||
* GSUB
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_has_substitution (hb_face_t *face);
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_substitute_lookup (hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int lookup_index,
|
||||
hb_mask_t mask);
|
||||
|
||||
/*
|
||||
* GPOS
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_has_positioning (hb_face_t *face);
|
||||
|
||||
hb_bool_t
|
||||
hb_ot_layout_position_lookup (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int lookup_index,
|
||||
hb_mask_t mask);
|
||||
|
||||
/* Should be called after all the position_lookup's are done */
|
||||
void
|
||||
hb_ot_layout_position_finish (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_OT_LAYOUT_H */
|
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-ot-shape.h"
|
||||
|
||||
#include "hb-buffer-private.hh"
|
||||
|
||||
#include "hb-open-type-private.hh"
|
||||
|
||||
#include "hb-ot-layout.h"
|
||||
|
||||
/* XXX vertical */
|
||||
hb_tag_t default_features[] = {
|
||||
HB_TAG('c','a','l','t'),
|
||||
HB_TAG('c','c','m','p'),
|
||||
HB_TAG('c','l','i','g'),
|
||||
HB_TAG('c','s','w','h'),
|
||||
HB_TAG('c','u','r','s'),
|
||||
HB_TAG('k','e','r','n'),
|
||||
HB_TAG('l','i','g','a'),
|
||||
HB_TAG('l','o','c','l'),
|
||||
HB_TAG('m','a','r','k'),
|
||||
HB_TAG('m','k','m','k'),
|
||||
HB_TAG('r','l','i','g')
|
||||
};
|
||||
|
||||
enum {
|
||||
MASK_ALWAYS_ON = 1 << 0,
|
||||
MASK_RTLM = 1 << 1
|
||||
};
|
||||
#define MASK_BITS_USED 2
|
||||
|
||||
struct lookup_map {
|
||||
unsigned int index;
|
||||
hb_mask_t mask;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
add_feature (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int feature_index,
|
||||
hb_mask_t mask,
|
||||
lookup_map *lookups,
|
||||
unsigned int *num_lookups,
|
||||
unsigned int room_lookups)
|
||||
{
|
||||
unsigned int i = room_lookups - *num_lookups;
|
||||
lookups += *num_lookups;
|
||||
|
||||
unsigned int *lookup_indices = (unsigned int *) lookups;
|
||||
|
||||
hb_ot_layout_feature_get_lookup_indexes (face, table_tag, feature_index, 0,
|
||||
&i,
|
||||
lookup_indices);
|
||||
|
||||
*num_lookups += i;
|
||||
|
||||
while (i--) {
|
||||
lookups[i].mask = mask;
|
||||
lookups[i].index = lookup_indices[i];
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cmp_lookups (const void *p1, const void *p2)
|
||||
{
|
||||
const lookup_map *a = (const lookup_map *) p1;
|
||||
const lookup_map *b = (const lookup_map *) p2;
|
||||
|
||||
return a->index - b->index;
|
||||
}
|
||||
|
||||
|
||||
#define MAX_FEATURES 100
|
||||
|
||||
struct hb_mask_allocator_t {
|
||||
|
||||
struct feature_info_t {
|
||||
hb_tag_t tag;
|
||||
unsigned int value;
|
||||
unsigned int seq;
|
||||
bool global;
|
||||
|
||||
static int
|
||||
cmp (const void *p1, const void *p2)
|
||||
{
|
||||
const feature_info_t *a = (const feature_info_t *) p1;
|
||||
const feature_info_t *b = (const feature_info_t *) p2;
|
||||
|
||||
if (a->tag != b->tag)
|
||||
return a->tag < b->tag ? -1 : 1;
|
||||
|
||||
return a->seq < b->seq ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct feature_map_t {
|
||||
hb_tag_t tag; /* should be first */
|
||||
unsigned int index;
|
||||
unsigned int shift;
|
||||
hb_mask_t mask;
|
||||
|
||||
static int
|
||||
cmp (const void *p1, const void *p2)
|
||||
{
|
||||
const feature_map_t *a = (const feature_map_t *) p1;
|
||||
const feature_map_t *b = (const feature_map_t *) p2;
|
||||
|
||||
return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
hb_mask_allocator_t (void) : count (0) {}
|
||||
|
||||
void add_feature (hb_tag_t tag,
|
||||
unsigned int value,
|
||||
bool global)
|
||||
{
|
||||
feature_info_t *info = &infos[count++];
|
||||
info->tag = tag;
|
||||
info->value = value;
|
||||
info->seq = count;
|
||||
info->global = global;
|
||||
}
|
||||
|
||||
void compile (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index)
|
||||
{
|
||||
global_mask = 0;
|
||||
next_bit = MASK_BITS_USED;
|
||||
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
qsort (infos, count, sizeof (infos[0]), feature_info_t::cmp);
|
||||
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (infos[i].tag != infos[j].tag)
|
||||
infos[++j] = infos[i];
|
||||
else {
|
||||
if (infos[i].global)
|
||||
infos[j] = infos[i];
|
||||
else {
|
||||
infos[j].global = infos[j].global && (infos[j].value == infos[i].value);
|
||||
infos[j].value = MAX (infos[j].value, infos[i].value);
|
||||
}
|
||||
}
|
||||
count = j + 1;
|
||||
|
||||
/* Allocate bits now */
|
||||
j = 0;
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
const feature_info_t *info = &infos[i];
|
||||
|
||||
unsigned int bits_needed;
|
||||
|
||||
if (info->global && info->value == 1)
|
||||
/* Uses the global bit */
|
||||
bits_needed = 0;
|
||||
else
|
||||
bits_needed = _hb_bit_storage (info->value);
|
||||
|
||||
if (!info->value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
|
||||
continue; /* Feature disabled, or not enough bits. */
|
||||
|
||||
unsigned int feature_index;
|
||||
if (!hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index,
|
||||
info->tag, &feature_index))
|
||||
continue;
|
||||
|
||||
feature_map_t *map = &maps[j++];
|
||||
|
||||
map->tag = info->tag;
|
||||
map->index = feature_index;
|
||||
if (info->global && info->value == 1) {
|
||||
/* Uses the global bit */
|
||||
map->shift = 0;
|
||||
map->mask = 1;
|
||||
} else {
|
||||
map->shift = next_bit;
|
||||
map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
|
||||
next_bit += bits_needed;
|
||||
}
|
||||
|
||||
if (info->global && map->mask != 1)
|
||||
global_mask |= map->mask;
|
||||
}
|
||||
count = j;
|
||||
}
|
||||
|
||||
hb_mask_t get_global_mask (void) { return global_mask; }
|
||||
const feature_map_t *find_feature (hb_tag_t tag) const {
|
||||
static const feature_map_t off_map = { HB_TAG_NONE, Index::NOT_FOUND_INDEX, 0, 0 };
|
||||
const feature_map_t *map = (const feature_map_t *) bsearch (&tag, maps, count, sizeof (maps[0]), feature_map_t::cmp);
|
||||
return map ? map : &off_map;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
unsigned int count;
|
||||
feature_info_t infos[MAX_FEATURES];
|
||||
feature_map_t maps[MAX_FEATURES];
|
||||
|
||||
hb_mask_t global_mask;
|
||||
unsigned int next_bit;
|
||||
};
|
||||
|
||||
static void
|
||||
setup_lookups (hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features,
|
||||
unsigned int num_features,
|
||||
hb_tag_t table_tag,
|
||||
lookup_map *lookups,
|
||||
unsigned int *num_lookups,
|
||||
hb_direction_t original_direction)
|
||||
{
|
||||
unsigned int i, j, script_index, language_index, feature_index, room_lookups;
|
||||
|
||||
room_lookups = *num_lookups;
|
||||
*num_lookups = 0;
|
||||
|
||||
hb_ot_layout_table_choose_script (face, table_tag,
|
||||
hb_ot_tags_from_script (buffer->script),
|
||||
&script_index);
|
||||
hb_ot_layout_script_find_language (face, table_tag, script_index,
|
||||
hb_ot_tag_from_language (buffer->language),
|
||||
&language_index);
|
||||
|
||||
if (hb_ot_layout_language_get_required_feature_index (face, table_tag, script_index, language_index,
|
||||
&feature_index))
|
||||
add_feature (face, table_tag, feature_index, 1, lookups, num_lookups, room_lookups);
|
||||
|
||||
|
||||
hb_mask_allocator_t allocator;
|
||||
|
||||
switch (original_direction) {
|
||||
case HB_DIRECTION_LTR:
|
||||
allocator.add_feature (HB_TAG ('l','t','r','a'), 1, true);
|
||||
allocator.add_feature (HB_TAG ('l','t','r','m'), 1, true);
|
||||
break;
|
||||
case HB_DIRECTION_RTL:
|
||||
allocator.add_feature (HB_TAG ('r','t','l','a'), 1, true);
|
||||
//allocator.add_feature (HB_TAG ('r','t','l','m'), false);
|
||||
allocator.add_feature (HB_TAG ('r','t','l','m'), 1, true);
|
||||
break;
|
||||
case HB_DIRECTION_TTB:
|
||||
case HB_DIRECTION_BTT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH (default_features); i++)
|
||||
allocator.add_feature (default_features[i], 1, true);
|
||||
|
||||
/* XXX complex-shaper features go here */
|
||||
|
||||
for (unsigned int i = 0; i < num_features; i++) {
|
||||
const hb_feature_t *feature = &features[i];
|
||||
allocator.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1));
|
||||
}
|
||||
|
||||
|
||||
/* Compile features */
|
||||
allocator.compile (face, table_tag, script_index, language_index);
|
||||
|
||||
|
||||
/* Gather lookup indices for features and set buffer masks at the same time */
|
||||
|
||||
const hb_mask_allocator_t::feature_map_t *map;
|
||||
|
||||
hb_mask_t global_mask = allocator.get_global_mask ();
|
||||
if (global_mask)
|
||||
buffer->set_masks (global_mask, global_mask, 0, (unsigned int) -1);
|
||||
|
||||
switch (original_direction) {
|
||||
case HB_DIRECTION_LTR:
|
||||
map = allocator.find_feature (HB_TAG ('l','t','r','a'));
|
||||
add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
|
||||
map = allocator.find_feature (HB_TAG ('l','t','r','m'));
|
||||
add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
|
||||
break;
|
||||
case HB_DIRECTION_RTL:
|
||||
map = allocator.find_feature (HB_TAG ('r','t','l','a'));
|
||||
add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
|
||||
//map = allocator.find_feature (HB_TAG ('r','t','l','m'));
|
||||
add_feature (face, table_tag, map->index, MASK_RTLM, lookups, num_lookups, room_lookups);
|
||||
break;
|
||||
case HB_DIRECTION_TTB:
|
||||
case HB_DIRECTION_BTT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH (default_features); i++)
|
||||
{
|
||||
map = allocator.find_feature (default_features[i]);
|
||||
add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_features; i++)
|
||||
{
|
||||
hb_feature_t *feature = &features[i];
|
||||
map = allocator.find_feature (feature->tag);
|
||||
add_feature (face, table_tag, map->index, map->mask, lookups, num_lookups, room_lookups);
|
||||
if (!(feature->start == 0 && feature->end == (unsigned int)-1))
|
||||
buffer->set_masks (features[i].value << map->shift, map->mask, feature->start, feature->end);
|
||||
}
|
||||
|
||||
|
||||
/* Sort lookups and merge duplicates */
|
||||
|
||||
qsort (lookups, *num_lookups, sizeof (lookups[0]), cmp_lookups);
|
||||
|
||||
if (*num_lookups)
|
||||
{
|
||||
for (i = 1, j = 0; i < *num_lookups; i++)
|
||||
if (lookups[i].index != lookups[j].index)
|
||||
lookups[++j] = lookups[i];
|
||||
else
|
||||
lookups[j].mask |= lookups[i].mask;
|
||||
j++;
|
||||
*num_lookups = j;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
hb_ot_substitute_complex (hb_font_t *font HB_UNUSED,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features,
|
||||
unsigned int num_features,
|
||||
hb_direction_t original_direction)
|
||||
{
|
||||
lookup_map lookups[1000]; /* FIXME */
|
||||
unsigned int num_lookups = ARRAY_LENGTH (lookups);
|
||||
unsigned int i;
|
||||
|
||||
if (!hb_ot_layout_has_substitution (face))
|
||||
return FALSE;
|
||||
|
||||
setup_lookups (face, buffer, features, num_features,
|
||||
HB_OT_TAG_GSUB,
|
||||
lookups, &num_lookups,
|
||||
original_direction);
|
||||
|
||||
for (i = 0; i < num_lookups; i++)
|
||||
hb_ot_layout_substitute_lookup (face, buffer, lookups[i].index, lookups[i].mask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ot_position_complex (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features,
|
||||
unsigned int num_features,
|
||||
hb_direction_t original_direction)
|
||||
{
|
||||
lookup_map lookups[1000];
|
||||
unsigned int num_lookups = ARRAY_LENGTH (lookups);
|
||||
unsigned int i;
|
||||
|
||||
if (!hb_ot_layout_has_positioning (face))
|
||||
return FALSE;
|
||||
|
||||
setup_lookups (face, buffer, features, num_features,
|
||||
HB_OT_TAG_GPOS,
|
||||
lookups, &num_lookups,
|
||||
original_direction);
|
||||
|
||||
for (i = 0; i < num_lookups; i++)
|
||||
hb_ot_layout_position_lookup (font, face, buffer, lookups[i].index, lookups[i].mask);
|
||||
|
||||
hb_ot_layout_position_finish (font, face, buffer);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Main shaper */
|
||||
|
||||
/* Prepare */
|
||||
|
||||
static inline hb_bool_t
|
||||
is_variation_selector (hb_codepoint_t unicode)
|
||||
{
|
||||
return unlikely ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */
|
||||
(unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SELECTOR-1..16 */
|
||||
(unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SELECTOR-17..256 */
|
||||
}
|
||||
|
||||
static void
|
||||
hb_form_clusters (hb_buffer_t *buffer)
|
||||
{
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
if (buffer->unicode->v.get_general_category (buffer->info[i].codepoint) == HB_CATEGORY_NON_SPACING_MARK)
|
||||
buffer->info[i].cluster = buffer->info[i - 1].cluster;
|
||||
}
|
||||
|
||||
static hb_direction_t
|
||||
hb_ensure_native_direction (hb_buffer_t *buffer)
|
||||
{
|
||||
hb_direction_t original_direction = buffer->direction;
|
||||
|
||||
/* TODO vertical */
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (original_direction) &&
|
||||
original_direction != _hb_script_get_horizontal_direction (buffer->script))
|
||||
{
|
||||
hb_buffer_reverse_clusters (buffer);
|
||||
buffer->direction = HB_DIRECTION_REVERSE (buffer->direction);
|
||||
}
|
||||
|
||||
return original_direction;
|
||||
}
|
||||
|
||||
|
||||
/* Substitute */
|
||||
|
||||
static void
|
||||
hb_mirror_chars (hb_buffer_t *buffer)
|
||||
{
|
||||
hb_unicode_get_mirroring_func_t get_mirroring = buffer->unicode->v.get_mirroring;
|
||||
|
||||
if (HB_DIRECTION_IS_FORWARD (buffer->direction))
|
||||
return;
|
||||
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
hb_codepoint_t codepoint = get_mirroring (buffer->info[i].codepoint);
|
||||
if (likely (codepoint == buffer->info[i].codepoint))
|
||||
buffer->info[i].mask |= MASK_RTLM;
|
||||
else
|
||||
buffer->info[i].codepoint = codepoint;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hb_map_glyphs (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
if (unlikely (!buffer->len))
|
||||
return;
|
||||
|
||||
buffer->clear_output ();
|
||||
unsigned int count = buffer->len - 1;
|
||||
for (buffer->i = 0; buffer->i < count;) {
|
||||
if (unlikely (is_variation_selector (buffer->info[buffer->i + 1].codepoint))) {
|
||||
buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, buffer->info[buffer->i + 1].codepoint));
|
||||
buffer->i++;
|
||||
} else {
|
||||
buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
|
||||
}
|
||||
}
|
||||
if (likely (buffer->i < buffer->len))
|
||||
buffer->add_output_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0));
|
||||
buffer->swap ();
|
||||
}
|
||||
|
||||
static void
|
||||
hb_substitute_default (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features HB_UNUSED,
|
||||
unsigned int num_features HB_UNUSED)
|
||||
{
|
||||
hb_map_glyphs (font, face, buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
hb_substitute_complex_fallback (hb_font_t *font HB_UNUSED,
|
||||
hb_face_t *face HB_UNUSED,
|
||||
hb_buffer_t *buffer HB_UNUSED,
|
||||
hb_feature_t *features HB_UNUSED,
|
||||
unsigned int num_features HB_UNUSED)
|
||||
{
|
||||
/* TODO Arabic */
|
||||
}
|
||||
|
||||
|
||||
/* Position */
|
||||
|
||||
static void
|
||||
hb_position_default (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features HB_UNUSED,
|
||||
unsigned int num_features HB_UNUSED)
|
||||
{
|
||||
hb_buffer_clear_positions (buffer);
|
||||
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
hb_glyph_metrics_t metrics;
|
||||
hb_font_get_glyph_metrics (font, face, buffer->info[i].codepoint, &metrics);
|
||||
buffer->pos[i].x_advance = metrics.x_advance;
|
||||
buffer->pos[i].y_advance = metrics.y_advance;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hb_position_complex_fallback (hb_font_t *font HB_UNUSED,
|
||||
hb_face_t *face HB_UNUSED,
|
||||
hb_buffer_t *buffer HB_UNUSED,
|
||||
hb_feature_t *features HB_UNUSED,
|
||||
unsigned int num_features HB_UNUSED)
|
||||
{
|
||||
/* TODO Mark pos */
|
||||
}
|
||||
|
||||
static void
|
||||
hb_truetype_kern (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features HB_UNUSED,
|
||||
unsigned int num_features HB_UNUSED)
|
||||
{
|
||||
/* TODO Check for kern=0 */
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 1; i < count; i++) {
|
||||
hb_position_t kern, kern1, kern2;
|
||||
kern = hb_font_get_kerning (font, face, buffer->info[i - 1].codepoint, buffer->info[i].codepoint);
|
||||
kern1 = kern >> 1;
|
||||
kern2 = kern - kern1;
|
||||
buffer->pos[i - 1].x_advance += kern1;
|
||||
buffer->pos[i].x_advance += kern2;
|
||||
buffer->pos[i].x_offset += kern2;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hb_position_complex_fallback_visual (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
hb_truetype_kern (font, face, buffer, features, num_features);
|
||||
}
|
||||
|
||||
|
||||
/* Do it! */
|
||||
|
||||
void
|
||||
hb_ot_shape (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
hb_direction_t original_direction;
|
||||
hb_bool_t substitute_fallback, position_fallback;
|
||||
|
||||
hb_form_clusters (buffer);
|
||||
|
||||
/* SUBSTITUTE */
|
||||
{
|
||||
|
||||
buffer->clear_masks ();
|
||||
|
||||
/* Mirroring needs to see the original direction */
|
||||
hb_mirror_chars (buffer);
|
||||
|
||||
original_direction = hb_ensure_native_direction (buffer);
|
||||
|
||||
hb_substitute_default (font, face, buffer, features, num_features);
|
||||
|
||||
substitute_fallback = !hb_ot_substitute_complex (font, face, buffer, features, num_features, original_direction);
|
||||
|
||||
if (substitute_fallback)
|
||||
hb_substitute_complex_fallback (font, face, buffer, features, num_features);
|
||||
|
||||
}
|
||||
|
||||
/* POSITION */
|
||||
{
|
||||
|
||||
buffer->clear_masks ();
|
||||
|
||||
hb_position_default (font, face, buffer, features, num_features);
|
||||
|
||||
position_fallback = !hb_ot_position_complex (font, face, buffer, features, num_features, original_direction);
|
||||
|
||||
if (position_fallback)
|
||||
hb_position_complex_fallback (font, face, buffer, features, num_features);
|
||||
|
||||
if (HB_DIRECTION_IS_BACKWARD (buffer->direction))
|
||||
hb_buffer_reverse (buffer);
|
||||
|
||||
if (position_fallback)
|
||||
hb_position_complex_fallback_visual (font, face, buffer, features, num_features);
|
||||
}
|
||||
|
||||
buffer->direction = original_direction;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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_SHAPE_H
|
||||
#define HB_OT_SHAPE_H
|
||||
|
||||
#include "hb-shape.h"
|
||||
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
void
|
||||
hb_ot_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_OT_SHAPE_PRIVATE_H */
|
|
@ -0,0 +1,696 @@
|
|||
/*
|
||||
* 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-ot.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
* Complete list at:
|
||||
* http://www.microsoft.com/typography/otspec/scripttags.htm
|
||||
*/
|
||||
static const hb_tag_t ot_scripts[][3] = {
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_COMMON */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_INHERITED */
|
||||
{HB_TAG('a','r','a','b')}, /* HB_SCRIPT_ARABIC */
|
||||
{HB_TAG('a','r','m','n')}, /* HB_SCRIPT_ARMENIAN */
|
||||
{HB_TAG('b','n','g','2'), HB_TAG('b','e','n','g')}, /* HB_SCRIPT_BENGALI */
|
||||
{HB_TAG('b','o','p','o')}, /* HB_SCRIPT_BOPOMOFO */
|
||||
{HB_TAG('c','h','e','r')}, /* HB_SCRIPT_CHEROKEE */
|
||||
{HB_TAG('c','o','p','t')}, /* HB_SCRIPT_COPTIC */
|
||||
{HB_TAG('c','y','r','l')}, /* HB_SCRIPT_CYRILLIC */
|
||||
{HB_TAG('d','s','r','t')}, /* HB_SCRIPT_DESERET */
|
||||
{HB_TAG('d','e','v','2'), HB_TAG('d','e','v','a')}, /* HB_SCRIPT_DEVANAGARI */
|
||||
{HB_TAG('e','t','h','i')}, /* HB_SCRIPT_ETHIOPIC */
|
||||
{HB_TAG('g','e','o','r')}, /* HB_SCRIPT_GEORGIAN */
|
||||
{HB_TAG('g','o','t','h')}, /* HB_SCRIPT_GOTHIC */
|
||||
{HB_TAG('g','r','e','k')}, /* HB_SCRIPT_GREEK */
|
||||
{HB_TAG('g','j','r','2'), HB_TAG('g','u','j','r')}, /* HB_SCRIPT_GUJARATI */
|
||||
{HB_TAG('g','u','r','2'), HB_TAG('g','u','r','u')}, /* HB_SCRIPT_GURMUKHI */
|
||||
{HB_TAG('h','a','n','i')}, /* HB_SCRIPT_HAN */
|
||||
{HB_TAG('h','a','n','g')}, /* HB_SCRIPT_HANGUL */
|
||||
{HB_TAG('h','e','b','r')}, /* HB_SCRIPT_HEBREW */
|
||||
{HB_TAG('k','a','n','a')}, /* HB_SCRIPT_HIRAGANA */
|
||||
{HB_TAG('k','n','d','2'), HB_TAG('k','n','d','a')}, /* HB_SCRIPT_KANNADA */
|
||||
{HB_TAG('k','a','n','a')}, /* HB_SCRIPT_KATAKANA */
|
||||
{HB_TAG('k','h','m','r')}, /* HB_SCRIPT_KHMER */
|
||||
{HB_TAG('l','a','o',' ')}, /* HB_SCRIPT_LAO */
|
||||
{HB_TAG('l','a','t','n')}, /* HB_SCRIPT_LATIN */
|
||||
{HB_TAG('m','l','m','2'), HB_TAG('m','l','y','m')}, /* HB_SCRIPT_MALAYALAM */
|
||||
{HB_TAG('m','o','n','g')}, /* HB_SCRIPT_MONGOLIAN */
|
||||
{HB_TAG('m','y','m','r')}, /* HB_SCRIPT_MYANMAR */
|
||||
{HB_TAG('o','g','a','m')}, /* HB_SCRIPT_OGHAM */
|
||||
{HB_TAG('i','t','a','l')}, /* HB_SCRIPT_OLD_ITALIC */
|
||||
{HB_TAG('o','r','y','2'), HB_TAG('o','r','y','a')}, /* HB_SCRIPT_ORIYA */
|
||||
{HB_TAG('r','u','n','r')}, /* HB_SCRIPT_RUNIC */
|
||||
{HB_TAG('s','i','n','h')}, /* HB_SCRIPT_SINHALA */
|
||||
{HB_TAG('s','y','r','c')}, /* HB_SCRIPT_SYRIAC */
|
||||
{HB_TAG('t','m','l','2'), HB_TAG('t','a','m','l')}, /* HB_SCRIPT_TAMIL */
|
||||
{HB_TAG('t','e','l','2'), HB_TAG('t','e','l','u')}, /* HB_SCRIPT_TELUGU */
|
||||
{HB_TAG('t','h','a','a')}, /* HB_SCRIPT_THAANA */
|
||||
{HB_TAG('t','h','a','i')}, /* HB_SCRIPT_THAI */
|
||||
{HB_TAG('t','i','b','t')}, /* HB_SCRIPT_TIBETAN */
|
||||
{HB_TAG('c','a','n','s')}, /* HB_SCRIPT_CANADIAN_ABORIGINAL */
|
||||
{HB_TAG('y','i',' ',' ')}, /* HB_SCRIPT_YI */
|
||||
{HB_TAG('t','g','l','g')}, /* HB_SCRIPT_TAGALOG */
|
||||
{HB_TAG('h','a','n','o')}, /* HB_SCRIPT_HANUNOO */
|
||||
{HB_TAG('b','u','h','d')}, /* HB_SCRIPT_BUHID */
|
||||
{HB_TAG('t','a','g','b')}, /* HB_SCRIPT_TAGBANWA */
|
||||
|
||||
/* Unicode-4.0 additions */
|
||||
{HB_TAG('b','r','a','i')}, /* HB_SCRIPT_BRAILLE */
|
||||
{HB_TAG('c','p','r','t')}, /* HB_SCRIPT_CYPRIOT */
|
||||
{HB_TAG('l','i','m','b')}, /* HB_SCRIPT_LIMBU */
|
||||
{HB_TAG('o','s','m','a')}, /* HB_SCRIPT_OSMANYA */
|
||||
{HB_TAG('s','h','a','w')}, /* HB_SCRIPT_SHAVIAN */
|
||||
{HB_TAG('l','i','n','b')}, /* HB_SCRIPT_LINEAR_B */
|
||||
{HB_TAG('t','a','l','e')}, /* HB_SCRIPT_TAI_LE */
|
||||
{HB_TAG('u','g','a','r')}, /* HB_SCRIPT_UGARITIC */
|
||||
|
||||
/* Unicode-4.1 additions */
|
||||
{HB_TAG('t','a','l','u')}, /* HB_SCRIPT_NEW_TAI_LUE */
|
||||
{HB_TAG('b','u','g','i')}, /* HB_SCRIPT_BUGINESE */
|
||||
{HB_TAG('g','l','a','g')}, /* HB_SCRIPT_GLAGOLITIC */
|
||||
{HB_TAG('t','f','n','g')}, /* HB_SCRIPT_TIFINAGH */
|
||||
{HB_TAG('s','y','l','o')}, /* HB_SCRIPT_SYLOTI_NAGRI */
|
||||
{HB_TAG('x','p','e','o')}, /* HB_SCRIPT_OLD_PERSIAN */
|
||||
{HB_TAG('k','h','a','r')}, /* HB_SCRIPT_KHAROSHTHI */
|
||||
|
||||
/* Unicode-5.0 additions */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_UNKNOWN */
|
||||
{HB_TAG('b','a','l','i')}, /* HB_SCRIPT_BALINESE */
|
||||
{HB_TAG('x','s','u','x')}, /* HB_SCRIPT_CUNEIFORM */
|
||||
{HB_TAG('p','h','n','x')}, /* HB_SCRIPT_PHOENICIAN */
|
||||
{HB_TAG('p','h','a','g')}, /* HB_SCRIPT_PHAGS_PA */
|
||||
{HB_TAG('n','k','o',' ')}, /* HB_SCRIPT_NKO */
|
||||
|
||||
/* Unicode-5.1 additions */
|
||||
{HB_TAG('k','a','l','i')}, /* HB_SCRIPT_KAYAH_LI */
|
||||
{HB_TAG('l','e','p','c')}, /* HB_SCRIPT_LEPCHA */
|
||||
{HB_TAG('r','j','n','g')}, /* HB_SCRIPT_REJANG */
|
||||
{HB_TAG('s','u','n','d')}, /* HB_SCRIPT_SUNDANESE */
|
||||
{HB_TAG('s','a','u','r')}, /* HB_SCRIPT_SAURASHTRA */
|
||||
{HB_TAG('c','h','a','m')}, /* HB_SCRIPT_CHAM */
|
||||
{HB_TAG('o','l','c','k')}, /* HB_SCRIPT_OL_CHIKI */
|
||||
{HB_TAG('v','a','i',' ')}, /* HB_SCRIPT_VAI */
|
||||
{HB_TAG('c','a','r','i')}, /* HB_SCRIPT_CARIAN */
|
||||
{HB_TAG('l','y','c','i')}, /* HB_SCRIPT_LYCIAN */
|
||||
{HB_TAG('l','y','d','i')}, /* HB_SCRIPT_LYDIAN */
|
||||
|
||||
/* Unicode-5.2 additions */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_AVESTAN */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_BAMUM */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_EGYPTIAN_HIEROGLYPHS */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_IMPERIAL_ARAMAIC */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_INSCRIPTIONAL_PAHLAVI */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_INSCRIPTIONAL_PARTHIAN */
|
||||
{HB_TAG('j','a','v','a')}, /* HB_SCRIPT_JAVANESE */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_KAITHI */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_LISU */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_MEITEI_MAYEK */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_OLD_SOUTH_ARABIAN */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_OLD_TURKIC */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_SAMARITAN */
|
||||
{HB_TAG('D','F','L','T')}, /* HB_SCRIPT_TAI_THAM */
|
||||
{HB_TAG('D','F','L','T')} /* HB_SCRIPT_TAI_VIET */
|
||||
};
|
||||
|
||||
const hb_tag_t *
|
||||
hb_ot_tags_from_script (hb_script_t script)
|
||||
{
|
||||
static const hb_tag_t def_tag[] = {HB_OT_TAG_DEFAULT_SCRIPT, HB_TAG_NONE};
|
||||
|
||||
if (unlikely ((unsigned int) script >= ARRAY_LENGTH (ot_scripts)))
|
||||
return def_tag;
|
||||
|
||||
return ot_scripts[script];
|
||||
}
|
||||
|
||||
hb_script_t
|
||||
hb_ot_tag_to_script (hb_tag_t tag)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH (ot_scripts); i++) {
|
||||
const hb_tag_t *p;
|
||||
for (p = ot_scripts[i]; *p; p++)
|
||||
if (tag == *p)
|
||||
return i;
|
||||
}
|
||||
|
||||
return HB_SCRIPT_UNKNOWN;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char language[6];
|
||||
hb_tag_t tag;
|
||||
} LangTag;
|
||||
|
||||
/*
|
||||
* Complete list at:
|
||||
* http://www.microsoft.com/typography/otspec/languagetags.htm
|
||||
*
|
||||
* Generated by intersecting the OpenType language tag list from
|
||||
* Draft OpenType 1.5 spec, with with the ISO 639-3 codes from
|
||||
* 2008/08/04, matching on name, and finally adjusted manually.
|
||||
*
|
||||
* Many items still missing. Those are commented out at the end.
|
||||
* Keep sorted for bsearch.
|
||||
*/
|
||||
static const LangTag ot_languages[] = {
|
||||
{"aa", HB_TAG('A','F','R',' ')}, /* Afar */
|
||||
{"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */
|
||||
{"abq", HB_TAG('A','B','A',' ')}, /* Abaza */
|
||||
{"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */
|
||||
{"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */
|
||||
{"aiw", HB_TAG('A','R','I',' ')}, /* Aari */
|
||||
{"am", HB_TAG('A','M','H',' ')}, /* Amharic */
|
||||
{"ar", HB_TAG('A','R','A',' ')}, /* Arabic */
|
||||
{"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */
|
||||
{"as", HB_TAG('A','S','M',' ')}, /* Assamese */
|
||||
{"av", HB_TAG('A','V','R',' ')}, /* Avaric */
|
||||
{"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */
|
||||
{"ay", HB_TAG('A','Y','M',' ')}, /* Aymara */
|
||||
{"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani */
|
||||
{"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */
|
||||
{"bal", HB_TAG('B','L','I',' ')}, /* Baluchi */
|
||||
{"bcq", HB_TAG('B','C','H',' ')}, /* Bench */
|
||||
{"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */
|
||||
{"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */
|
||||
{"bft", HB_TAG('B','L','T',' ')}, /* Balti */
|
||||
{"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */
|
||||
{"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */
|
||||
{"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */
|
||||
{"bik", HB_TAG('B','I','K',' ')}, /* Bikol */
|
||||
{"bin", HB_TAG('E','D','O',' ')}, /* Bini */
|
||||
{"bm", HB_TAG('B','M','B',' ')}, /* Bambara */
|
||||
{"bn", HB_TAG('B','E','N',' ')}, /* Bengali */
|
||||
{"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */
|
||||
{"br", HB_TAG('B','R','E',' ')}, /* Breton */
|
||||
{"brh", HB_TAG('B','R','H',' ')}, /* Brahui */
|
||||
{"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */
|
||||
{"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) */
|
||||
{"ca", HB_TAG('C','A','T',' ')}, /* Catalan */
|
||||
{"ce", HB_TAG('C','H','E',' ')}, /* Chechen */
|
||||
{"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */
|
||||
{"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */
|
||||
{"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */
|
||||
{"cop", HB_TAG('C','O','P',' ')}, /* Coptic */
|
||||
{"cr", HB_TAG('C','R','E',' ')}, /* Cree */
|
||||
{"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */
|
||||
{"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */
|
||||
{"crx", HB_TAG('C','R','R',' ')}, /* Carrier */
|
||||
{"cs", HB_TAG('C','S','Y',' ')}, /* Czech */
|
||||
{"cu", HB_TAG('C','S','L',' ')}, /* Church Slavic */
|
||||
{"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */
|
||||
{"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */
|
||||
{"cy", HB_TAG('W','E','L',' ')}, /* Welsh */
|
||||
{"da", HB_TAG('D','A','N',' ')}, /* Danish */
|
||||
{"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) */
|
||||
{"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */
|
||||
{"de", HB_TAG('D','E','U',' ')}, /* German */
|
||||
{"din", HB_TAG('D','N','K',' ')}, /* Dinka */
|
||||
{"dng", HB_TAG('D','U','N',' ')}, /* Dungan */
|
||||
{"doi", HB_TAG('D','G','R',' ')}, /* Dogri */
|
||||
{"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */
|
||||
{"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi */
|
||||
{"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */
|
||||
{"ee", HB_TAG('E','W','E',' ')}, /* Ewe */
|
||||
{"efi", HB_TAG('E','F','I',' ')}, /* Efik */
|
||||
{"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) */
|
||||
{"en", HB_TAG('E','N','G',' ')}, /* English */
|
||||
{"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */
|
||||
{"eot", HB_TAG('B','T','I',' ')}, /* Beti (Côte d'Ivoire) */
|
||||
{"es", HB_TAG('E','S','P',' ')}, /* Spanish */
|
||||
{"et", HB_TAG('E','T','I',' ')}, /* Estonian */
|
||||
{"eu", HB_TAG('E','U','Q',' ')}, /* Basque */
|
||||
{"eve", HB_TAG('E','V','N',' ')}, /* Even */
|
||||
{"evn", HB_TAG('E','V','K',' ')}, /* Evenki */
|
||||
{"fa", HB_TAG('F','A','R',' ')}, /* Persian */
|
||||
{"ff", HB_TAG('F','U','L',' ')}, /* Fulah */
|
||||
{"fi", HB_TAG('F','I','N',' ')}, /* Finnish */
|
||||
{"fil", HB_TAG('P','I','L',' ')}, /* Filipino */
|
||||
{"fj", HB_TAG('F','J','I',' ')}, /* Fijian */
|
||||
{"fo", HB_TAG('F','O','S',' ')}, /* Faroese */
|
||||
{"fon", HB_TAG('F','O','N',' ')}, /* Fon */
|
||||
{"fr", HB_TAG('F','R','A',' ')}, /* French */
|
||||
{"fur", HB_TAG('F','R','L',' ')}, /* Friulian */
|
||||
{"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian */
|
||||
{"ga", HB_TAG('I','R','I',' ')}, /* Irish */
|
||||
{"gaa", HB_TAG('G','A','D',' ')}, /* Ga */
|
||||
{"gag", HB_TAG('G','A','G',' ')}, /* Gagauz */
|
||||
{"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */
|
||||
{"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
|
||||
{"gl", HB_TAG('G','A','L',' ')}, /* Galician */
|
||||
{"gld", HB_TAG('N','A','N',' ')}, /* Nanai */
|
||||
{"gn", HB_TAG('G','U','A',' ')}, /* Guarani */
|
||||
{"gon", HB_TAG('G','O','N',' ')}, /* Gondi */
|
||||
{"grt", HB_TAG('G','R','O',' ')}, /* Garo */
|
||||
{"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */
|
||||
{"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */
|
||||
{"gv", HB_TAG('M','N','X',' ')}, /* Manx Gaelic */
|
||||
{"ha", HB_TAG('H','A','U',' ')}, /* Hausa */
|
||||
{"har", HB_TAG('H','R','I',' ')}, /* Harari */
|
||||
{"he", HB_TAG('I','W','R',' ')}, /* Hebrew */
|
||||
{"hi", HB_TAG('H','I','N',' ')}, /* Hindi */
|
||||
{"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */
|
||||
{"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */
|
||||
{"hr", HB_TAG('H','R','V',' ')}, /* Croatian */
|
||||
{"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */
|
||||
{"ht", HB_TAG('H','A','I',' ')}, /* Haitian */
|
||||
{"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */
|
||||
{"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */
|
||||
{"id", HB_TAG('I','N','D',' ')}, /* Indonesian */
|
||||
{"ig", HB_TAG('I','B','O',' ')}, /* Igbo */
|
||||
{"igb", HB_TAG('E','B','I',' ')}, /* Ebira */
|
||||
{"inh", HB_TAG('I','N','G',' ')}, /* Ingush */
|
||||
{"is", HB_TAG('I','S','L',' ')}, /* Icelandic */
|
||||
{"it", HB_TAG('I','T','A',' ')}, /* Italian */
|
||||
{"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut */
|
||||
{"ja", HB_TAG('J','A','N',' ')}, /* Japanese */
|
||||
{"jv", HB_TAG('J','A','V',' ')}, /* Javanese */
|
||||
{"ka", HB_TAG('K','A','T',' ')}, /* Georgian */
|
||||
{"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
|
||||
{"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */
|
||||
{"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */
|
||||
{"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */
|
||||
{"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */
|
||||
{"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */
|
||||
{"kha", HB_TAG('K','S','I',' ')}, /* Khasi */
|
||||
{"khw", HB_TAG('K','H','W',' ')}, /* Khowar */
|
||||
{"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu */
|
||||
{"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */
|
||||
{"kl", HB_TAG('G','R','N',' ')}, /* Kalaallisut */
|
||||
{"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin */
|
||||
{"km", HB_TAG('K','H','M',' ')}, /* Central Khmer */
|
||||
{"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */
|
||||
{"kn", HB_TAG('K','A','N',' ')}, /* Kannada */
|
||||
{"ko", HB_TAG('K','O','R',' ')}, /* Korean */
|
||||
{"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */
|
||||
{"kok", HB_TAG('K','O','K',' ')}, /* Konkani */
|
||||
{"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle */
|
||||
{"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */
|
||||
{"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */
|
||||
{"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */
|
||||
{"kr", HB_TAG('K','N','R',' ')}, /* Kanuri */
|
||||
{"kri", HB_TAG('K','R','I',' ')}, /* Krio */
|
||||
{"krl", HB_TAG('K','R','L',' ')}, /* Karelian */
|
||||
{"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */
|
||||
{"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */
|
||||
{"ku", HB_TAG('K','U','R',' ')}, /* Kurdish */
|
||||
{"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */
|
||||
{"kvd", HB_TAG('K','U','I',' ')}, /* Kui (Indonesia) */
|
||||
{"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */
|
||||
{"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz */
|
||||
{"la", HB_TAG('L','A','T',' ')}, /* Latin */
|
||||
{"lad", HB_TAG('J','U','D',' ')}, /* Ladino */
|
||||
{"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */
|
||||
{"lbe", HB_TAG('L','A','K',' ')}, /* Lak */
|
||||
{"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */
|
||||
{"lif", HB_TAG('L','M','B',' ')}, /* Limbu */
|
||||
{"lld", HB_TAG('L','A','D',' ')}, /* Ladin */
|
||||
{"ln", HB_TAG('L','I','N',' ')}, /* Lingala */
|
||||
{"lo", HB_TAG('L','A','O',' ')}, /* Lao */
|
||||
{"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */
|
||||
{"luo", HB_TAG('L','U','O',' ')}, /* Luo (Kenya and Tanzania) */
|
||||
{"luw", HB_TAG('L','U','O',' ')}, /* Luo (Cameroon) */
|
||||
{"lv", HB_TAG('L','V','I',' ')}, /* Latvian */
|
||||
{"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */
|
||||
{"mai", HB_TAG('M','T','H',' ')}, /* Maithili */
|
||||
{"mdc", HB_TAG('M','L','E',' ')}, /* Male (Papua New Guinea) */
|
||||
{"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */
|
||||
{"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */
|
||||
{"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */
|
||||
{"mg", HB_TAG('M','L','G',' ')}, /* Malagasy */
|
||||
{"mi", HB_TAG('M','R','I',' ')}, /* Maori */
|
||||
{"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */
|
||||
{"ml", HB_TAG('M','L','R',' ')}, /* Malayalam */
|
||||
{"mn", HB_TAG('M','N','G',' ')}, /* Mongolian */
|
||||
{"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */
|
||||
{"mni", HB_TAG('M','N','I',' ')}, /* Manipuri */
|
||||
{"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */
|
||||
{"mns", HB_TAG('M','A','N',' ')}, /* Mansi */
|
||||
{"mnw", HB_TAG('M','O','N',' ')}, /* Mon */
|
||||
{"mo", HB_TAG('M','O','L',' ')}, /* Moldavian */
|
||||
{"moh", HB_TAG('M','O','H',' ')}, /* Mohawk */
|
||||
{"mpe", HB_TAG('M','A','J',' ')}, /* Majang */
|
||||
{"mr", HB_TAG('M','A','R',' ')}, /* Marathi */
|
||||
{"ms", HB_TAG('M','L','Y',' ')}, /* Malay */
|
||||
{"mt", HB_TAG('M','T','S',' ')}, /* Maltese */
|
||||
{"mwr", HB_TAG('M','A','W',' ')}, /* Marwari */
|
||||
{"my", HB_TAG('B','R','M',' ')}, /* Burmese */
|
||||
{"mym", HB_TAG('M','E','N',' ')}, /* Me'en */
|
||||
{"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */
|
||||
{"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål */
|
||||
{"nco", HB_TAG('S','I','B',' ')}, /* Sibe */
|
||||
{"ne", HB_TAG('N','E','P',' ')}, /* Nepali */
|
||||
{"new", HB_TAG('N','E','W',' ')}, /* Newari */
|
||||
{"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */
|
||||
{"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */
|
||||
{"niu", HB_TAG('N','I','U',' ')}, /* Niuean */
|
||||
{"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */
|
||||
{"nl", HB_TAG('N','L','D',' ')}, /* Dutch */
|
||||
{"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk */
|
||||
{"no", HB_TAG('N','O','R',' ')}, /* Norwegian (deprecated) */
|
||||
{"nog", HB_TAG('N','O','G',' ')}, /* Nogai */
|
||||
{"nqo", HB_TAG('N','K','O',' ')}, /* N'Ko */
|
||||
{"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */
|
||||
{"ny", HB_TAG('C','H','I',' ')}, /* Nyanja */
|
||||
{"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
|
||||
{"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa */
|
||||
{"om", HB_TAG('O','R','O',' ')}, /* Oromo */
|
||||
{"or", HB_TAG('O','R','I',' ')}, /* Oriya */
|
||||
{"os", HB_TAG('O','S','S',' ')}, /* Ossetian */
|
||||
{"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */
|
||||
{"pi", HB_TAG('P','A','L',' ')}, /* Pali */
|
||||
{"pl", HB_TAG('P','L','K',' ')}, /* Polish */
|
||||
{"plp", HB_TAG('P','A','P',' ')}, /* Palpa */
|
||||
{"prs", HB_TAG('D','R','I',' ')}, /* Dari */
|
||||
{"ps", HB_TAG('P','A','S',' ')}, /* Pushto */
|
||||
{"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */
|
||||
{"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani */
|
||||
{"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */
|
||||
{"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */
|
||||
{"ro", HB_TAG('R','O','M',' ')}, /* Romanian */
|
||||
{"rom", HB_TAG('R','O','Y',' ')}, /* Romany */
|
||||
{"ru", HB_TAG('R','U','S',' ')}, /* Russian */
|
||||
{"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */
|
||||
{"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */
|
||||
{"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */
|
||||
{"sat", HB_TAG('S','A','T',' ')}, /* Santali */
|
||||
{"sck", HB_TAG('S','A','D',' ')}, /* Sadri */
|
||||
{"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */
|
||||
{"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */
|
||||
{"seh", HB_TAG('S','N','A',' ')}, /* Sena */
|
||||
{"sel", HB_TAG('S','E','L',' ')}, /* Selkup */
|
||||
{"sg", HB_TAG('S','G','O',' ')}, /* Sango */
|
||||
{"shn", HB_TAG('S','H','N',' ')}, /* Shan */
|
||||
{"si", HB_TAG('S','N','H',' ')}, /* Sinhala */
|
||||
{"sid", HB_TAG('S','I','D',' ')}, /* Sidamo */
|
||||
{"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */
|
||||
{"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */
|
||||
{"skr", HB_TAG('S','R','K',' ')}, /* Seraiki */
|
||||
{"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */
|
||||
{"sm", HB_TAG('S','M','O',' ')}, /* Samoan */
|
||||
{"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */
|
||||
{"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */
|
||||
{"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */
|
||||
{"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */
|
||||
{"snk", HB_TAG('S','N','K',' ')}, /* Soninke */
|
||||
{"so", HB_TAG('S','M','L',' ')}, /* Somali */
|
||||
{"sq", HB_TAG('S','Q','I',' ')}, /* Albanian */
|
||||
{"sr", HB_TAG('S','R','B',' ')}, /* Serbian */
|
||||
{"srr", HB_TAG('S','R','R',' ')}, /* Serer */
|
||||
{"suq", HB_TAG('S','U','R',' ')}, /* Suri */
|
||||
{"sv", HB_TAG('S','V','E',' ')}, /* Swedish */
|
||||
{"sva", HB_TAG('S','V','A',' ')}, /* Svan */
|
||||
{"sw", HB_TAG('S','W','K',' ')}, /* Swahili */
|
||||
{"swb", HB_TAG('C','M','R',' ')}, /* Comorian */
|
||||
{"syr", HB_TAG('S','Y','R',' ')}, /* Syriac */
|
||||
{"ta", HB_TAG('T','A','M',' ')}, /* Tamil */
|
||||
{"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */
|
||||
{"te", HB_TAG('T','E','L',' ')}, /* Telugu */
|
||||
{"tg", HB_TAG('T','A','J',' ')}, /* Tajik */
|
||||
{"th", HB_TAG('T','H','A',' ')}, /* Thai */
|
||||
{"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */
|
||||
{"tig", HB_TAG('T','G','R',' ')}, /* Tigre */
|
||||
{"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */
|
||||
{"tn", HB_TAG('T','N','A',' ')}, /* Tswana */
|
||||
{"tnz", HB_TAG('T','N','G',' ')}, /* Tonga (Thailand) */
|
||||
{"to", HB_TAG('T','N','G',' ')}, /* Tonga (Tonga Islands) */
|
||||
{"tog", HB_TAG('T','N','G',' ')}, /* Tonga (Nyasa) */
|
||||
{"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */
|
||||
{"tr", HB_TAG('T','R','K',' ')}, /* Turkish */
|
||||
{"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */
|
||||
{"tt", HB_TAG('T','A','T',' ')}, /* Tatar */
|
||||
{"tw", HB_TAG('T','W','I',' ')}, /* Twi */
|
||||
{"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */
|
||||
{"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */
|
||||
{"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */
|
||||
{"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */
|
||||
{"unr", HB_TAG('M','U','N',' ')}, /* Mundari */
|
||||
{"ur", HB_TAG('U','R','D',' ')}, /* Urdu */
|
||||
{"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek */
|
||||
{"ve", HB_TAG('V','E','N',' ')}, /* Venda */
|
||||
{"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */
|
||||
{"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */
|
||||
{"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */
|
||||
{"wo", HB_TAG('W','L','F',' ')}, /* Wolof */
|
||||
{"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */
|
||||
{"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */
|
||||
{"xom", HB_TAG('K','M','O',' ')}, /* Komo (Sudan) */
|
||||
{"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */
|
||||
{"yi", HB_TAG('J','I','I',' ')}, /* Yiddish */
|
||||
{"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */
|
||||
{"yso", HB_TAG('N','I','S',' ')}, /* Nisi (China) */
|
||||
{"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */
|
||||
{"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */
|
||||
{"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */
|
||||
{"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */
|
||||
{"zh-tw", HB_TAG('Z','H','T',' ')}, /* Chinese (Taiwan) */
|
||||
{"zne", HB_TAG('Z','N','D',' ')}, /* Zande */
|
||||
{"zu", HB_TAG('Z','U','L',' ')} /* Zulu */
|
||||
|
||||
/* I couldn't find the language id for these */
|
||||
|
||||
/*{"??", HB_TAG('A','G','W',' ')},*/ /* Agaw */
|
||||
/*{"??", HB_TAG('A','L','S',' ')},*/ /* Alsatian */
|
||||
/*{"??", HB_TAG('A','L','T',' ')},*/ /* Altai */
|
||||
/*{"??", HB_TAG('A','R','K',' ')},*/ /* Arakanese */
|
||||
/*{"??", HB_TAG('A','T','H',' ')},*/ /* Athapaskan */
|
||||
/*{"??", HB_TAG('B','A','G',' ')},*/ /* Baghelkhandi */
|
||||
/*{"??", HB_TAG('B','A','L',' ')},*/ /* Balkar */
|
||||
/*{"??", HB_TAG('B','A','U',' ')},*/ /* Baule */
|
||||
/*{"??", HB_TAG('B','B','R',' ')},*/ /* Berber */
|
||||
/*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */
|
||||
/*{"??", HB_TAG('B','E','L',' ')},*/ /* Belarussian */
|
||||
/*{"??", HB_TAG('B','I','L',' ')},*/ /* Bilen */
|
||||
/*{"??", HB_TAG('B','K','F',' ')},*/ /* Blackfoot */
|
||||
/*{"??", HB_TAG('B','L','N',' ')},*/ /* Balante */
|
||||
/*{"??", HB_TAG('B','M','L',' ')},*/ /* Bamileke */
|
||||
/*{"??", HB_TAG('B','R','I',' ')},*/ /* Braj Bhasha */
|
||||
/*{"??", HB_TAG('C','H','G',' ')},*/ /* Chaha Gurage */
|
||||
/*{"??", HB_TAG('C','H','H',' ')},*/ /* Chattisgarhi */
|
||||
/*{"??", HB_TAG('C','H','K',' ')},*/ /* Chukchi */
|
||||
/*{"??", HB_TAG('D','J','R',' ')},*/ /* Djerma */
|
||||
/*{"??", HB_TAG('D','N','G',' ')},*/ /* Dangme */
|
||||
/*{"??", HB_TAG('E','C','R',' ')},*/ /* Eastern Cree */
|
||||
/*{"??", HB_TAG('F','A','N',' ')},*/ /* French Antillean */
|
||||
/*{"??", HB_TAG('F','L','E',' ')},*/ /* Flemish */
|
||||
/*{"??", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */
|
||||
/*{"??", HB_TAG('F','T','A',' ')},*/ /* Futa */
|
||||
/*{"??", HB_TAG('G','A','R',' ')},*/ /* Garshuni */
|
||||
/*{"??", HB_TAG('G','E','Z',' ')},*/ /* Ge'ez */
|
||||
/*{"??", HB_TAG('H','A','L',' ')},*/ /* Halam */
|
||||
/*{"??", HB_TAG('H','A','R',' ')},*/ /* Harauti */
|
||||
/*{"??", HB_TAG('H','A','W',' ')},*/ /* Hawaiin */
|
||||
/*{"??", HB_TAG('H','B','N',' ')},*/ /* Hammer-Banna */
|
||||
/*{"??", HB_TAG('H','M','A',' ')},*/ /* High Mari */
|
||||
/*{"??", HB_TAG('H','N','D',' ')},*/ /* Hindko */
|
||||
/*{"??", HB_TAG('I','J','O',' ')},*/ /* Ijo */
|
||||
/*{"??", HB_TAG('I','L','O',' ')},*/ /* Ilokano */
|
||||
/*{"??", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */
|
||||
/*{"??", HB_TAG('J','U','L',' ')},*/ /* Jula */
|
||||
/*{"??", HB_TAG('K','A','R',' ')},*/ /* Karachay */
|
||||
/*{"??", HB_TAG('K','E','B',' ')},*/ /* Kebena */
|
||||
/*{"??", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */
|
||||
/*{"??", HB_TAG('K','H','A',' ')},*/ /* Khakass */
|
||||
/*{"??", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */
|
||||
/*{"??", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */
|
||||
/*{"??", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */
|
||||
/*{"??", HB_TAG('K','I','S',' ')},*/ /* Kisii */
|
||||
/*{"??", HB_TAG('K','K','N',' ')},*/ /* Kokni */
|
||||
/*{"??", HB_TAG('K','M','S',' ')},*/ /* Komso */
|
||||
/*{"??", HB_TAG('K','O','D',' ')},*/ /* Kodagu */
|
||||
/*{"??", HB_TAG('K','O','H',' ')},*/ /* Korean Old Hangul */
|
||||
/*{"??", HB_TAG('K','O','N',' ')},*/ /* Kikongo */
|
||||
/*{"??", HB_TAG('K','R','K',' ')},*/ /* Karakalpak */
|
||||
/*{"??", HB_TAG('K','R','N',' ')},*/ /* Karen */
|
||||
/*{"??", HB_TAG('K','U','L',' ')},*/ /* Kulvi */
|
||||
/*{"??", HB_TAG('L','A','H',' ')},*/ /* Lahuli */
|
||||
/*{"??", HB_TAG('L','A','M',' ')},*/ /* Lambani */
|
||||
/*{"??", HB_TAG('L','C','R',' ')},*/ /* L-Cree */
|
||||
/*{"??", HB_TAG('L','E','Z',' ')},*/ /* Lezgi */
|
||||
/*{"??", HB_TAG('L','M','A',' ')},*/ /* Low Mari */
|
||||
/*{"??", HB_TAG('L','U','B',' ')},*/ /* Luba */
|
||||
/*{"??", HB_TAG('L','U','G',' ')},*/ /* Luganda */
|
||||
/*{"??", HB_TAG('L','U','H',' ')},*/ /* Luhya */
|
||||
/*{"??", HB_TAG('M','A','K',' ')},*/ /* Makua */
|
||||
/*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */
|
||||
/*{"??", HB_TAG('M','B','N',' ')},*/ /* Mbundu */
|
||||
/*{"??", HB_TAG('M','I','Z',' ')},*/ /* Mizo */
|
||||
/*{"??", HB_TAG('M','L','N',' ')},*/ /* Malinke */
|
||||
/*{"??", HB_TAG('M','N','K',' ')},*/ /* Maninka */
|
||||
/*{"??", HB_TAG('M','O','R',' ')},*/ /* Moroccan */
|
||||
/*{"??", HB_TAG('N','A','G',' ')},*/ /* Naga-Assamese */
|
||||
/*{"??", HB_TAG('N','C','R',' ')},*/ /* N-Cree */
|
||||
/*{"??", HB_TAG('N','D','B',' ')},*/ /* Ndebele */
|
||||
/*{"??", HB_TAG('N','G','R',' ')},*/ /* Nagari */
|
||||
/*{"??", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */
|
||||
/*{"??", HB_TAG('N','K','L',' ')},*/ /* Nkole */
|
||||
/*{"??", HB_TAG('N','T','A',' ')},*/ /* Northern Tai */
|
||||
/*{"??", HB_TAG('O','C','R',' ')},*/ /* Oji-Cree */
|
||||
/*{"??", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */
|
||||
/*{"??", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */
|
||||
/*{"??", HB_TAG('P','L','G',' ')},*/ /* Palaung */
|
||||
/*{"??", HB_TAG('Q','I','N',' ')},*/ /* Chin */
|
||||
/*{"??", HB_TAG('R','B','U',' ')},*/ /* Russian Buriat */
|
||||
/*{"??", HB_TAG('R','C','R',' ')},*/ /* R-Cree */
|
||||
/*{"??", HB_TAG('R','M','S',' ')},*/ /* Rhaeto-Romanic */
|
||||
/*{"??", HB_TAG('R','U','A',' ')},*/ /* Ruanda */
|
||||
/*{"??", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */
|
||||
/*{"??", HB_TAG('S','E','K',' ')},*/ /* Sekota */
|
||||
/*{"??", HB_TAG('S','I','G',' ')},*/ /* Silte Gurage */
|
||||
/*{"??", HB_TAG('S','L','A',' ')},*/ /* Slavey */
|
||||
/*{"??", HB_TAG('S','O','G',' ')},*/ /* Sodo Gurage */
|
||||
/*{"??", HB_TAG('S','O','T',' ')},*/ /* Sotho */
|
||||
/*{"??", HB_TAG('S','W','A',' ')},*/ /* Swadaya Aramaic */
|
||||
/*{"??", HB_TAG('S','W','Z',' ')},*/ /* Swazi */
|
||||
/*{"??", HB_TAG('S','X','T',' ')},*/ /* Sutu */
|
||||
/*{"??", HB_TAG('T','A','B',' ')},*/ /* Tabasaran */
|
||||
/*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */
|
||||
/*{"??", HB_TAG('T','G','N',' ')},*/ /* Tongan */
|
||||
/*{"??", HB_TAG('T','M','N',' ')},*/ /* Temne */
|
||||
/*{"??", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */
|
||||
/*{"??", HB_TAG('T','O','D',' ')},*/ /* Todo */
|
||||
/*{"??", HB_TAG('T','U','A',' ')},*/ /* Turoyo Aramaic */
|
||||
/*{"??", HB_TAG('T','U','V',' ')},*/ /* Tuvin */
|
||||
/*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */
|
||||
/*{"??", HB_TAG('X','B','D',' ')},*/ /* Tai Lue */
|
||||
/*{"??", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */
|
||||
/*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */
|
||||
/*{"??", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */
|
||||
/*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */
|
||||
};
|
||||
|
||||
static int
|
||||
lang_compare_first_component (const void *pa,
|
||||
const void *pb)
|
||||
{
|
||||
const char *a = pa, *b = pb;
|
||||
unsigned int da, db;
|
||||
const char *p;
|
||||
|
||||
p = strstr (a, "-");
|
||||
da = p ? (unsigned int) (p - a) : strlen (a);
|
||||
|
||||
p = strstr (b, "-");
|
||||
db = p ? (unsigned int) (p - b) : strlen (b);
|
||||
|
||||
return strncmp (a, b, MAX (da, db));
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
lang_matches (const char *lang_str, const char *spec)
|
||||
{
|
||||
unsigned int len = strlen (spec);
|
||||
|
||||
return lang_str && strncmp (lang_str, spec, len) == 0 &&
|
||||
(lang_str[len] == '\0' || lang_str[len] == '-');
|
||||
}
|
||||
|
||||
hb_tag_t
|
||||
hb_ot_tag_from_language (hb_language_t language)
|
||||
{
|
||||
const char *lang_str;
|
||||
LangTag *lang_tag;
|
||||
|
||||
if (language == NULL)
|
||||
return HB_OT_TAG_DEFAULT_LANGUAGE;
|
||||
|
||||
lang_str = hb_language_to_string (language);
|
||||
|
||||
if (0 == strcmp (lang_str, "x-hbot")) {
|
||||
char tag[4];
|
||||
int i;
|
||||
lang_str += 6;
|
||||
i = 0;
|
||||
#define IS_LETTER(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
|
||||
#define TO_UPPER(c) (((c) >= 'a' && (c) <= 'z') ? (c) + 'A' - 'a' : (c))
|
||||
while (i < 4 && IS_LETTER (lang_str[i])) {
|
||||
tag[i] = TO_UPPER (lang_str[i]);
|
||||
}
|
||||
while (i < 4)
|
||||
tag[i] = ' ';
|
||||
return HB_TAG_STR (tag);
|
||||
}
|
||||
|
||||
/* find a language matching in the first component */
|
||||
lang_tag = bsearch (lang_str, ot_languages,
|
||||
ARRAY_LENGTH (ot_languages), sizeof (LangTag),
|
||||
lang_compare_first_component);
|
||||
|
||||
/* we now need to find the best language matching */
|
||||
if (lang_tag)
|
||||
{
|
||||
hb_bool_t found = FALSE;
|
||||
|
||||
/* go to the final one matching in the first component */
|
||||
while (lang_tag + 1 < ot_languages + ARRAY_LENGTH (ot_languages) &&
|
||||
lang_compare_first_component (lang_str, lang_tag + 1) == 0)
|
||||
lang_tag++;
|
||||
|
||||
/* go back, find which one matches completely */
|
||||
while (lang_tag >= ot_languages &&
|
||||
lang_compare_first_component (lang_str, lang_tag) == 0)
|
||||
{
|
||||
if (lang_matches (lang_str, lang_tag->language)) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
lang_tag--;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
lang_tag = NULL;
|
||||
}
|
||||
|
||||
if (lang_tag)
|
||||
return lang_tag->tag;
|
||||
|
||||
return HB_OT_TAG_DEFAULT_LANGUAGE;
|
||||
}
|
||||
|
||||
hb_language_t
|
||||
hb_ot_tag_to_language (hb_tag_t tag)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char buf[11] = "x-hbot";
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH (ot_languages); i++)
|
||||
if (ot_languages[i].tag == tag)
|
||||
return hb_language_from_string (ot_languages[i].language);
|
||||
|
||||
buf[6] = tag >> 24;
|
||||
buf[7] = (tag >> 16) & 0xFF;
|
||||
buf[8] = (tag >> 8) & 0xFF;
|
||||
buf[9] = tag & 0xFF;
|
||||
buf[10] = '\0';
|
||||
return hb_language_from_string ((char *) buf);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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_OT_TAG_H
|
||||
#define HB_OT_TAG_H
|
||||
|
||||
#include "hb-common.h"
|
||||
#include "hb-language.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
|
||||
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
|
||||
|
||||
const hb_tag_t *
|
||||
hb_ot_tags_from_script (hb_script_t script);
|
||||
|
||||
hb_script_t
|
||||
hb_ot_tag_to_script (hb_tag_t tag);
|
||||
|
||||
hb_tag_t
|
||||
hb_ot_tag_from_language (hb_language_t language);
|
||||
|
||||
hb_language_t
|
||||
hb_ot_tag_to_language (hb_tag_t tag);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_OT_TAG_H */
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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_OT_H
|
||||
#define HB_OT_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include "hb-ot-layout.h"
|
||||
#include "hb-ot-shape.h"
|
||||
#include "hb-ot-tag.h"
|
||||
|
||||
#endif /* HB_OT_H */
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* 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_PRIVATE_H
|
||||
#define HB_PRIVATE_H
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "hb-common.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* We only use these two for debug output. However, the debug code is
|
||||
* always seen by the compiler (and optimized out in non-debug builds.
|
||||
* If including these becomes a problem, we can start thinking about
|
||||
* someway around that. */
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
/* Essentials */
|
||||
|
||||
#ifndef NULL
|
||||
# define NULL ((void *) 0)
|
||||
#endif
|
||||
|
||||
#undef FALSE
|
||||
#define FALSE 0
|
||||
|
||||
#undef TRUE
|
||||
#define TRUE 1
|
||||
|
||||
|
||||
/* Basics */
|
||||
|
||||
#undef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#undef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#undef ARRAY_LENGTH
|
||||
#define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
|
||||
|
||||
#define HB_STMT_START do
|
||||
#define HB_STMT_END while (0)
|
||||
|
||||
#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
|
||||
#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
|
||||
#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
|
||||
|
||||
|
||||
/* Misc */
|
||||
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
|
||||
#define _HB_BOOLEAN_EXPR(expr) ((expr) ? 1 : 0)
|
||||
#define likely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 1))
|
||||
#define unlikely(expr) (__builtin_expect (_HB_BOOLEAN_EXPR(expr), 0))
|
||||
#else
|
||||
#define likely(expr) (expr)
|
||||
#define unlikely(expr) (expr)
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
#undef __attribute__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#define HB_PURE_FUNC __attribute__((pure))
|
||||
#define HB_CONST_FUNC __attribute__((const))
|
||||
#else
|
||||
#define HB_PURE_FUNC
|
||||
#define HB_CONST_FUNC
|
||||
#endif
|
||||
#if __GNUC__ >= 4
|
||||
#define HB_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define HB_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef HB_INTERNAL
|
||||
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
|
||||
#endif
|
||||
|
||||
|
||||
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#undef inline
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
#undef inline
|
||||
#define inline __inline__
|
||||
#endif
|
||||
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#define HB_FUNC __PRETTY_FUNCTION__
|
||||
#elif defined(_MSC_VER)
|
||||
#define HB_FUNC __FUNCSIG__
|
||||
#else
|
||||
#define HB_FUNC __func__
|
||||
#endif
|
||||
|
||||
|
||||
/* Return the number of 1 bits in mask. */
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
_hb_popcount32 (uint32_t mask)
|
||||
{
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
return __builtin_popcount (mask);
|
||||
#else
|
||||
/* "HACKMEM 169" */
|
||||
register uint32_t y;
|
||||
y = (mask >> 1) &033333333333;
|
||||
y = mask - y - ((y >>1) & 033333333333);
|
||||
return (((y + (y >> 3)) & 030707070707) % 077);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns the number of bits needed to store number */
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
_hb_bit_storage (unsigned int number)
|
||||
{
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
|
||||
return likely (number) ? (sizeof (unsigned int) * 8 - __builtin_clz (number)) : 0;
|
||||
#else
|
||||
register unsigned int n_bits = 0;
|
||||
while (number) {
|
||||
n_bits++;
|
||||
number >>= 1;
|
||||
}
|
||||
return n_bits;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Returns the number of zero bits in the least significant side of number */
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
_hb_ctz (unsigned int number)
|
||||
{
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
|
||||
return likely (number) ? __builtin_ctz (number) : 0;
|
||||
#else
|
||||
register unsigned int n_bits = 0;
|
||||
if (unlikely (!number)) return 0;
|
||||
while (!(number & 1)) {
|
||||
n_bits++;
|
||||
number >>= 1;
|
||||
}
|
||||
return n_bits;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We need external help for these */
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef int hb_atomic_int_t;
|
||||
#define hb_atomic_int_fetch_and_add(AI, V) g_atomic_int_exchange_and_add (&(AI), V)
|
||||
#define hb_atomic_int_get(AI) g_atomic_int_get (&(AI))
|
||||
#define hb_atomic_int_set(AI, V) g_atomic_int_set (&(AI), V)
|
||||
|
||||
typedef GStaticMutex hb_mutex_t;
|
||||
#define HB_MUTEX_INIT G_STATIC_MUTEX_INIT
|
||||
#define hb_mutex_init(M) g_static_mutex_init (&M)
|
||||
#define hb_mutex_lock(M) g_static_mutex_lock (&M)
|
||||
#define hb_mutex_trylock(M) g_static_mutex_trylock (&M)
|
||||
#define hb_mutex_unlock(M) g_static_mutex_unlock (&M)
|
||||
|
||||
#else
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma message(__LOC__"Could not find any system to define platform macros, library will NOT be thread-safe")
|
||||
#else
|
||||
#warning "Could not find any system to define platform macros, library will NOT be thread-safe"
|
||||
#endif
|
||||
|
||||
typedef int hb_atomic_int_t;
|
||||
#define hb_atomic_int_fetch_and_add(AI, V) ((AI) += (V), (AI) - (V))
|
||||
#define hb_atomic_int_get(AI) (AI)
|
||||
#define hb_atomic_int_set(AI, V) HB_STMT_START { (AI) = (V); } HB_STMT_END
|
||||
|
||||
typedef int hb_mutex_t;
|
||||
#define HB_MUTEX_INIT 0
|
||||
#define hb_mutex_init(M) HB_STMT_START { (M) = 0; } HB_STMT_END
|
||||
#define hb_mutex_lock(M) HB_STMT_START { (M) = 1; } HB_STMT_END
|
||||
#define hb_mutex_trylock(M) ((M) = 1, 1)
|
||||
#define hb_mutex_unlock(M) HB_STMT_START { (M) = 0; } HB_STMT_END
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Big-endian handling */
|
||||
|
||||
#define hb_be_uint16(v) ((uint16_t) ((((const uint8_t *)&(v))[0] << 8) + (((const uint8_t *)&(v))[1])))
|
||||
|
||||
#define hb_be_uint16_put(v,V) HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END
|
||||
#define hb_be_uint16_get(v) (uint16_t) ((v[0] << 8) + v[1])
|
||||
#define hb_be_uint16_cmp(a,b) (a[0] == b[0] && a[1] == b[1])
|
||||
|
||||
#define hb_be_uint32_put(v,V) HB_STMT_START { v[0] = (V>>24); v[1] = (V>>16); v[2] = (V>>8); v[3] = (V); } HB_STMT_END
|
||||
#define hb_be_uint32_get(v) (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3])
|
||||
#define hb_be_uint32_cmp(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3])
|
||||
|
||||
|
||||
/* Debug */
|
||||
|
||||
#ifndef HB_DEBUG
|
||||
#define HB_DEBUG 0
|
||||
#endif
|
||||
|
||||
static inline hb_bool_t /* always returns TRUE */
|
||||
_hb_trace (const char *what,
|
||||
const char *function,
|
||||
const void *obj,
|
||||
unsigned int depth,
|
||||
unsigned int max_depth)
|
||||
{
|
||||
if (depth < max_depth)
|
||||
fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, depth, depth, function);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#include "hb-object-private.h"
|
||||
|
||||
#endif /* HB_PRIVATE_H */
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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-shape.h"
|
||||
|
||||
#include "hb-buffer-private.hh"
|
||||
|
||||
#include "hb-ot-shape.h"
|
||||
|
||||
#ifdef HAVE_GRAPHITE
|
||||
#include "hb-graphite.h"
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
hb_shape (hb_font_t *font,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
#if 0 && defined(HAVE_GRAPHITE)
|
||||
hb_blob_t *silf_blob;
|
||||
silf_blob = hb_face_get_table (face, HB_GRAPHITE_TAG_Silf);
|
||||
if (hb_blob_get_length(silf_blob))
|
||||
{
|
||||
hb_graphite_shape(font, face, buffer, features, num_features);
|
||||
hb_blob_destroy(silf_blob);
|
||||
return;
|
||||
}
|
||||
hb_blob_destroy(silf_blob);
|
||||
#endif
|
||||
|
||||
hb_ot_shape (font, face, buffer, features, num_features);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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_SHAPE_H
|
||||
#define HB_SHAPE_H
|
||||
|
||||
#include "hb-common.h"
|
||||
#include "hb-buffer.h"
|
||||
#include "hb-font.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
typedef struct _hb_feature_t {
|
||||
hb_tag_t tag;
|
||||
uint32_t value;
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
} hb_feature_t;
|
||||
|
||||
void
|
||||
hb_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_SHAPE_H */
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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_UNICODE_PRIVATE_H
|
||||
#define HB_UNICODE_PRIVATE_H
|
||||
|
||||
#include "hb-private.h"
|
||||
|
||||
#include "hb-unicode.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* hb_unicode_funcs_t
|
||||
*/
|
||||
|
||||
struct _hb_unicode_funcs_t {
|
||||
hb_reference_count_t ref_count;
|
||||
|
||||
hb_bool_t immutable;
|
||||
|
||||
struct {
|
||||
hb_unicode_get_general_category_func_t get_general_category;
|
||||
hb_unicode_get_combining_class_func_t get_combining_class;
|
||||
hb_unicode_get_mirroring_func_t get_mirroring;
|
||||
hb_unicode_get_script_func_t get_script;
|
||||
hb_unicode_get_eastasian_width_func_t get_eastasian_width;
|
||||
} v;
|
||||
};
|
||||
|
||||
extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_nil;
|
||||
|
||||
|
||||
HB_INTERNAL hb_direction_t
|
||||
_hb_script_get_horizontal_direction (hb_script_t script);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_UNICODE_PRIVATE_H */
|
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* 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-unicode-private.h"
|
||||
|
||||
/*
|
||||
* hb_unicode_funcs_t
|
||||
*/
|
||||
|
||||
static hb_codepoint_t hb_unicode_get_mirroring_nil (hb_codepoint_t unicode) { return unicode; }
|
||||
static hb_category_t hb_unicode_get_general_category_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_CATEGORY_OTHER_LETTER; }
|
||||
static hb_script_t hb_unicode_get_script_nil (hb_codepoint_t unicode HB_UNUSED) { return HB_SCRIPT_UNKNOWN; }
|
||||
static unsigned int hb_unicode_get_combining_class_nil (hb_codepoint_t unicode HB_UNUSED) { return 0; }
|
||||
static unsigned int hb_unicode_get_eastasian_width_nil (hb_codepoint_t unicode HB_UNUSED) { return 1; }
|
||||
|
||||
hb_unicode_funcs_t _hb_unicode_funcs_nil = {
|
||||
HB_REFERENCE_COUNT_INVALID, /* ref_count */
|
||||
TRUE, /* immutable */
|
||||
{
|
||||
hb_unicode_get_general_category_nil,
|
||||
hb_unicode_get_combining_class_nil,
|
||||
hb_unicode_get_mirroring_nil,
|
||||
hb_unicode_get_script_nil,
|
||||
hb_unicode_get_eastasian_width_nil
|
||||
}
|
||||
};
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_unicode_funcs_create (void)
|
||||
{
|
||||
hb_unicode_funcs_t *ufuncs;
|
||||
|
||||
if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
|
||||
return &_hb_unicode_funcs_nil;
|
||||
|
||||
ufuncs->v = _hb_unicode_funcs_nil.v;
|
||||
|
||||
return ufuncs;
|
||||
}
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs)
|
||||
{
|
||||
HB_OBJECT_DO_REFERENCE (ufuncs);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_unicode_funcs_get_reference_count (hb_unicode_funcs_t *ufuncs)
|
||||
{
|
||||
HB_OBJECT_DO_GET_REFERENCE_COUNT (ufuncs);
|
||||
}
|
||||
|
||||
void
|
||||
hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs)
|
||||
{
|
||||
HB_OBJECT_DO_DESTROY (ufuncs);
|
||||
|
||||
free (ufuncs);
|
||||
}
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_unicode_funcs_copy (hb_unicode_funcs_t *other_ufuncs)
|
||||
{
|
||||
hb_unicode_funcs_t *ufuncs;
|
||||
|
||||
if (!HB_OBJECT_DO_CREATE (hb_unicode_funcs_t, ufuncs))
|
||||
return &_hb_unicode_funcs_nil;
|
||||
|
||||
ufuncs->v = other_ufuncs->v;
|
||||
|
||||
return ufuncs;
|
||||
}
|
||||
|
||||
void
|
||||
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs)
|
||||
{
|
||||
if (HB_OBJECT_IS_INERT (ufuncs))
|
||||
return;
|
||||
|
||||
ufuncs->immutable = TRUE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_mirroring_func_t mirroring_func)
|
||||
{
|
||||
if (ufuncs->immutable)
|
||||
return;
|
||||
|
||||
ufuncs->v.get_mirroring = mirroring_func ? mirroring_func : hb_unicode_get_mirroring_nil;
|
||||
}
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_general_category_func_t general_category_func)
|
||||
{
|
||||
if (ufuncs->immutable)
|
||||
return;
|
||||
|
||||
ufuncs->v.get_general_category = general_category_func ? general_category_func : hb_unicode_get_general_category_nil;
|
||||
}
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_script_func_t script_func)
|
||||
{
|
||||
if (ufuncs->immutable)
|
||||
return;
|
||||
|
||||
ufuncs->v.get_script = script_func ? script_func : hb_unicode_get_script_nil;
|
||||
}
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_combining_class_func_t combining_class_func)
|
||||
{
|
||||
if (ufuncs->immutable)
|
||||
return;
|
||||
|
||||
ufuncs->v.get_combining_class = combining_class_func ? combining_class_func : hb_unicode_get_combining_class_nil;
|
||||
}
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_eastasian_width_func_t eastasian_width_func)
|
||||
{
|
||||
if (ufuncs->immutable)
|
||||
return;
|
||||
|
||||
ufuncs->v.get_eastasian_width = eastasian_width_func ? eastasian_width_func : hb_unicode_get_eastasian_width_nil;
|
||||
}
|
||||
|
||||
|
||||
hb_codepoint_t
|
||||
hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode)
|
||||
{
|
||||
return ufuncs->v.get_mirroring (unicode);
|
||||
}
|
||||
|
||||
hb_category_t
|
||||
hb_unicode_get_general_category (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode)
|
||||
{
|
||||
return ufuncs->v.get_general_category (unicode);
|
||||
}
|
||||
|
||||
hb_script_t
|
||||
hb_unicode_get_script (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode)
|
||||
{
|
||||
return ufuncs->v.get_script (unicode);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_unicode_get_combining_class (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode)
|
||||
{
|
||||
return ufuncs->v.get_combining_class (unicode);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hb_unicode_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode)
|
||||
{
|
||||
return ufuncs->v.get_eastasian_width (unicode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define LTR HB_DIRECTION_LTR
|
||||
#define RTL HB_DIRECTION_RTL
|
||||
const hb_direction_t horiz_dir[] =
|
||||
{
|
||||
LTR, /* Zyyy */
|
||||
LTR, /* Qaai */
|
||||
RTL, /* Arab */
|
||||
LTR, /* Armn */
|
||||
LTR, /* Beng */
|
||||
LTR, /* Bopo */
|
||||
LTR, /* Cher */
|
||||
LTR, /* Qaac */
|
||||
LTR, /* Cyrl (Cyrs) */
|
||||
LTR, /* Dsrt */
|
||||
LTR, /* Deva */
|
||||
LTR, /* Ethi */
|
||||
LTR, /* Geor (Geon, Geoa) */
|
||||
LTR, /* Goth */
|
||||
LTR, /* Grek */
|
||||
LTR, /* Gujr */
|
||||
LTR, /* Guru */
|
||||
LTR, /* Hani */
|
||||
LTR, /* Hang */
|
||||
RTL, /* Hebr */
|
||||
LTR, /* Hira */
|
||||
LTR, /* Knda */
|
||||
LTR, /* Kana */
|
||||
LTR, /* Khmr */
|
||||
LTR, /* Laoo */
|
||||
LTR, /* Latn (Latf, Latg) */
|
||||
LTR, /* Mlym */
|
||||
LTR, /* Mong */
|
||||
LTR, /* Mymr */
|
||||
LTR, /* Ogam */
|
||||
LTR, /* Ital */
|
||||
LTR, /* Orya */
|
||||
LTR, /* Runr */
|
||||
LTR, /* Sinh */
|
||||
RTL, /* Syrc (Syrj, Syrn, Syre) */
|
||||
LTR, /* Taml */
|
||||
LTR, /* Telu */
|
||||
RTL, /* Thaa */
|
||||
LTR, /* Thai */
|
||||
LTR, /* Tibt */
|
||||
LTR, /* Cans */
|
||||
LTR, /* Yiii */
|
||||
LTR, /* Tglg */
|
||||
LTR, /* Hano */
|
||||
LTR, /* Buhd */
|
||||
LTR, /* Tagb */
|
||||
|
||||
/* Unicode-4.0 additions */
|
||||
LTR, /* Brai */
|
||||
RTL, /* Cprt */
|
||||
LTR, /* Limb */
|
||||
LTR, /* Osma */
|
||||
LTR, /* Shaw */
|
||||
LTR, /* Linb */
|
||||
LTR, /* Tale */
|
||||
LTR, /* Ugar */
|
||||
|
||||
/* Unicode-4.1 additions */
|
||||
LTR, /* Talu */
|
||||
LTR, /* Bugi */
|
||||
LTR, /* Glag */
|
||||
LTR, /* Tfng */
|
||||
LTR, /* Sylo */
|
||||
LTR, /* Xpeo */
|
||||
LTR, /* Khar */
|
||||
|
||||
/* Unicode-5.0 additions */
|
||||
LTR, /* Zzzz */
|
||||
LTR, /* Bali */
|
||||
LTR, /* Xsux */
|
||||
RTL, /* Phnx */
|
||||
LTR, /* Phag */
|
||||
RTL, /* Nkoo */
|
||||
|
||||
/* Unicode-5.1 additions */
|
||||
LTR, /* Kali */
|
||||
LTR, /* Lepc */
|
||||
LTR, /* Rjng */
|
||||
LTR, /* Sund */
|
||||
LTR, /* Saur */
|
||||
LTR, /* Cham */
|
||||
LTR, /* Olck */
|
||||
LTR, /* Vaii */
|
||||
LTR, /* Cari */
|
||||
LTR, /* Lyci */
|
||||
LTR, /* Lydi */
|
||||
|
||||
/* Unicode-5.2 additions */
|
||||
RTL, /* Avst */
|
||||
LTR, /* Bamu */
|
||||
LTR, /* Egyp */
|
||||
RTL, /* Armi */
|
||||
RTL, /* Phli */
|
||||
RTL, /* Prti */
|
||||
LTR, /* Java */
|
||||
LTR, /* Kthi */
|
||||
LTR, /* Lisu */
|
||||
LTR, /* Mtei */
|
||||
RTL, /* Sarb */
|
||||
RTL, /* Orkh */
|
||||
RTL, /* Samr */
|
||||
LTR, /* Lana */
|
||||
LTR /* Tavt */
|
||||
};
|
||||
#undef LTR
|
||||
#undef RTL
|
||||
|
||||
hb_direction_t
|
||||
_hb_script_get_horizontal_direction (hb_script_t script)
|
||||
{
|
||||
if (unlikely ((unsigned int) script >= ARRAY_LENGTH (horiz_dir)))
|
||||
return HB_DIRECTION_LTR;
|
||||
|
||||
return horiz_dir[script];
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* 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_UNICODE_H
|
||||
#define HB_UNICODE_H
|
||||
|
||||
#include "hb-common.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
/* Unicode General Category property */
|
||||
typedef enum
|
||||
{
|
||||
HB_CATEGORY_CONTROL,
|
||||
HB_CATEGORY_FORMAT,
|
||||
HB_CATEGORY_UNASSIGNED,
|
||||
HB_CATEGORY_PRIVATE_USE,
|
||||
HB_CATEGORY_SURROGATE,
|
||||
HB_CATEGORY_LOWERCASE_LETTER,
|
||||
HB_CATEGORY_MODIFIER_LETTER,
|
||||
HB_CATEGORY_OTHER_LETTER,
|
||||
HB_CATEGORY_TITLECASE_LETTER,
|
||||
HB_CATEGORY_UPPERCASE_LETTER,
|
||||
HB_CATEGORY_COMBINING_MARK,
|
||||
HB_CATEGORY_ENCLOSING_MARK,
|
||||
HB_CATEGORY_NON_SPACING_MARK,
|
||||
HB_CATEGORY_DECIMAL_NUMBER,
|
||||
HB_CATEGORY_LETTER_NUMBER,
|
||||
HB_CATEGORY_OTHER_NUMBER,
|
||||
HB_CATEGORY_CONNECT_PUNCTUATION,
|
||||
HB_CATEGORY_DASH_PUNCTUATION,
|
||||
HB_CATEGORY_CLOSE_PUNCTUATION,
|
||||
HB_CATEGORY_FINAL_PUNCTUATION,
|
||||
HB_CATEGORY_INITIAL_PUNCTUATION,
|
||||
HB_CATEGORY_OTHER_PUNCTUATION,
|
||||
HB_CATEGORY_OPEN_PUNCTUATION,
|
||||
HB_CATEGORY_CURRENCY_SYMBOL,
|
||||
HB_CATEGORY_MODIFIER_SYMBOL,
|
||||
HB_CATEGORY_MATH_SYMBOL,
|
||||
HB_CATEGORY_OTHER_SYMBOL,
|
||||
HB_CATEGORY_LINE_SEPARATOR,
|
||||
HB_CATEGORY_PARAGRAPH_SEPARATOR,
|
||||
HB_CATEGORY_SPACE_SEPARATOR
|
||||
} hb_category_t;
|
||||
|
||||
/* Unicode Script property */
|
||||
typedef enum
|
||||
{ /* ISO 15924 code */
|
||||
HB_SCRIPT_INVALID_CODE = -1,
|
||||
HB_SCRIPT_COMMON = 0, /* Zyyy */
|
||||
HB_SCRIPT_INHERITED, /* Qaai */
|
||||
HB_SCRIPT_ARABIC, /* Arab */
|
||||
HB_SCRIPT_ARMENIAN, /* Armn */
|
||||
HB_SCRIPT_BENGALI, /* Beng */
|
||||
HB_SCRIPT_BOPOMOFO, /* Bopo */
|
||||
HB_SCRIPT_CHEROKEE, /* Cher */
|
||||
HB_SCRIPT_COPTIC, /* Qaac */
|
||||
HB_SCRIPT_CYRILLIC, /* Cyrl (Cyrs) */
|
||||
HB_SCRIPT_DESERET, /* Dsrt */
|
||||
HB_SCRIPT_DEVANAGARI, /* Deva */
|
||||
HB_SCRIPT_ETHIOPIC, /* Ethi */
|
||||
HB_SCRIPT_GEORGIAN, /* Geor (Geon, Geoa) */
|
||||
HB_SCRIPT_GOTHIC, /* Goth */
|
||||
HB_SCRIPT_GREEK, /* Grek */
|
||||
HB_SCRIPT_GUJARATI, /* Gujr */
|
||||
HB_SCRIPT_GURMUKHI, /* Guru */
|
||||
HB_SCRIPT_HAN, /* Hani */
|
||||
HB_SCRIPT_HANGUL, /* Hang */
|
||||
HB_SCRIPT_HEBREW, /* Hebr */
|
||||
HB_SCRIPT_HIRAGANA, /* Hira */
|
||||
HB_SCRIPT_KANNADA, /* Knda */
|
||||
HB_SCRIPT_KATAKANA, /* Kana */
|
||||
HB_SCRIPT_KHMER, /* Khmr */
|
||||
HB_SCRIPT_LAO, /* Laoo */
|
||||
HB_SCRIPT_LATIN, /* Latn (Latf, Latg) */
|
||||
HB_SCRIPT_MALAYALAM, /* Mlym */
|
||||
HB_SCRIPT_MONGOLIAN, /* Mong */
|
||||
HB_SCRIPT_MYANMAR, /* Mymr */
|
||||
HB_SCRIPT_OGHAM, /* Ogam */
|
||||
HB_SCRIPT_OLD_ITALIC, /* Ital */
|
||||
HB_SCRIPT_ORIYA, /* Orya */
|
||||
HB_SCRIPT_RUNIC, /* Runr */
|
||||
HB_SCRIPT_SINHALA, /* Sinh */
|
||||
HB_SCRIPT_SYRIAC, /* Syrc (Syrj, Syrn, Syre) */
|
||||
HB_SCRIPT_TAMIL, /* Taml */
|
||||
HB_SCRIPT_TELUGU, /* Telu */
|
||||
HB_SCRIPT_THAANA, /* Thaa */
|
||||
HB_SCRIPT_THAI, /* Thai */
|
||||
HB_SCRIPT_TIBETAN, /* Tibt */
|
||||
HB_SCRIPT_CANADIAN_ABORIGINAL, /* Cans */
|
||||
HB_SCRIPT_YI, /* Yiii */
|
||||
HB_SCRIPT_TAGALOG, /* Tglg */
|
||||
HB_SCRIPT_HANUNOO, /* Hano */
|
||||
HB_SCRIPT_BUHID, /* Buhd */
|
||||
HB_SCRIPT_TAGBANWA, /* Tagb */
|
||||
|
||||
/* Unicode-4.0 additions */
|
||||
HB_SCRIPT_BRAILLE, /* Brai */
|
||||
HB_SCRIPT_CYPRIOT, /* Cprt */
|
||||
HB_SCRIPT_LIMBU, /* Limb */
|
||||
HB_SCRIPT_OSMANYA, /* Osma */
|
||||
HB_SCRIPT_SHAVIAN, /* Shaw */
|
||||
HB_SCRIPT_LINEAR_B, /* Linb */
|
||||
HB_SCRIPT_TAI_LE, /* Tale */
|
||||
HB_SCRIPT_UGARITIC, /* Ugar */
|
||||
|
||||
/* Unicode-4.1 additions */
|
||||
HB_SCRIPT_NEW_TAI_LUE, /* Talu */
|
||||
HB_SCRIPT_BUGINESE, /* Bugi */
|
||||
HB_SCRIPT_GLAGOLITIC, /* Glag */
|
||||
HB_SCRIPT_TIFINAGH, /* Tfng */
|
||||
HB_SCRIPT_SYLOTI_NAGRI, /* Sylo */
|
||||
HB_SCRIPT_OLD_PERSIAN, /* Xpeo */
|
||||
HB_SCRIPT_KHAROSHTHI, /* Khar */
|
||||
|
||||
/* Unicode-5.0 additions */
|
||||
HB_SCRIPT_UNKNOWN, /* Zzzz */
|
||||
HB_SCRIPT_BALINESE, /* Bali */
|
||||
HB_SCRIPT_CUNEIFORM, /* Xsux */
|
||||
HB_SCRIPT_PHOENICIAN, /* Phnx */
|
||||
HB_SCRIPT_PHAGS_PA, /* Phag */
|
||||
HB_SCRIPT_NKO, /* Nkoo */
|
||||
|
||||
/* Unicode-5.1 additions */
|
||||
HB_SCRIPT_KAYAH_LI, /* Kali */
|
||||
HB_SCRIPT_LEPCHA, /* Lepc */
|
||||
HB_SCRIPT_REJANG, /* Rjng */
|
||||
HB_SCRIPT_SUNDANESE, /* Sund */
|
||||
HB_SCRIPT_SAURASHTRA, /* Saur */
|
||||
HB_SCRIPT_CHAM, /* Cham */
|
||||
HB_SCRIPT_OL_CHIKI, /* Olck */
|
||||
HB_SCRIPT_VAI, /* Vaii */
|
||||
HB_SCRIPT_CARIAN, /* Cari */
|
||||
HB_SCRIPT_LYCIAN, /* Lyci */
|
||||
HB_SCRIPT_LYDIAN, /* Lydi */
|
||||
|
||||
/* Unicode-5.2 additions */
|
||||
HB_SCRIPT_AVESTAN, /* Avst */
|
||||
HB_SCRIPT_BAMUM, /* Bamu */
|
||||
HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, /* Egyp */
|
||||
HB_SCRIPT_IMPERIAL_ARAMAIC, /* Armi */
|
||||
HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, /* Phli */
|
||||
HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, /* Prti */
|
||||
HB_SCRIPT_JAVANESE, /* Java */
|
||||
HB_SCRIPT_KAITHI, /* Kthi */
|
||||
HB_SCRIPT_LISU, /* Lisu */
|
||||
HB_SCRIPT_MEITEI_MAYEK, /* Mtei */
|
||||
HB_SCRIPT_OLD_SOUTH_ARABIAN, /* Sarb */
|
||||
HB_SCRIPT_OLD_TURKIC, /* Orkh */
|
||||
HB_SCRIPT_SAMARITAN, /* Samr */
|
||||
HB_SCRIPT_TAI_THAM, /* Lana */
|
||||
HB_SCRIPT_TAI_VIET /* Tavt */
|
||||
} hb_script_t;
|
||||
|
||||
|
||||
/*
|
||||
* hb_unicode_funcs_t
|
||||
*/
|
||||
|
||||
typedef struct _hb_unicode_funcs_t hb_unicode_funcs_t;
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_unicode_funcs_create (void);
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs);
|
||||
|
||||
unsigned int
|
||||
hb_unicode_funcs_get_reference_count (hb_unicode_funcs_t *ufuncs);
|
||||
|
||||
void
|
||||
hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs);
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_unicode_funcs_copy (hb_unicode_funcs_t *ufuncs);
|
||||
|
||||
void
|
||||
hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs);
|
||||
|
||||
|
||||
/* funcs */
|
||||
|
||||
typedef hb_codepoint_t (*hb_unicode_get_mirroring_func_t) (hb_codepoint_t unicode);
|
||||
typedef hb_category_t (*hb_unicode_get_general_category_func_t) (hb_codepoint_t unicode);
|
||||
typedef hb_script_t (*hb_unicode_get_script_func_t) (hb_codepoint_t unicode);
|
||||
typedef unsigned int (*hb_unicode_get_combining_class_func_t) (hb_codepoint_t unicode);
|
||||
typedef unsigned int (*hb_unicode_get_eastasian_width_func_t) (hb_codepoint_t unicode);
|
||||
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_mirroring_func_t mirroring_func);
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_general_category_func_t general_category_func);
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_script_func_t script_func);
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_combining_class_func_t combining_class_func);
|
||||
|
||||
void
|
||||
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_get_eastasian_width_func_t eastasian_width_func);
|
||||
|
||||
|
||||
hb_codepoint_t
|
||||
hb_unicode_get_mirroring (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode);
|
||||
|
||||
hb_category_t
|
||||
hb_unicode_get_general_category (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode);
|
||||
|
||||
hb_script_t
|
||||
hb_unicode_get_script (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode);
|
||||
|
||||
unsigned int
|
||||
hb_unicode_get_combining_class (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode);
|
||||
|
||||
unsigned int
|
||||
hb_unicode_get_eastasian_width (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_UNICODE_H */
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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_H
|
||||
#define HB_H
|
||||
|
||||
#include "hb-blob.h"
|
||||
#include "hb-buffer.h"
|
||||
#include "hb-common.h"
|
||||
#include "hb-font.h"
|
||||
#include "hb-language.h"
|
||||
#include "hb-shape.h"
|
||||
#include "hb-unicode.h"
|
||||
|
||||
#endif /* HB_H */
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define HB_OT_LAYOUT_CC
|
||||
#include "hb-open-file-private.hh"
|
||||
#include "hb-ot-layout-gdef-private.hh"
|
||||
#include "hb-ot-layout-gsubgpos-private.hh"
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
const char *font_data = NULL;
|
||||
int len = 0;
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
GMappedFile *mf = g_mapped_file_new (argv[1], FALSE, NULL);
|
||||
font_data = g_mapped_file_get_contents (mf);
|
||||
len = g_mapped_file_get_length (mf);
|
||||
#else
|
||||
FILE *f = fopen (argv[1], "rb");
|
||||
fseek (f, 0, SEEK_END);
|
||||
len = ftell (f);
|
||||
fseek (f, 0, SEEK_SET);
|
||||
font_data = (const char *) malloc (len);
|
||||
len = fread ((char *) font_data, 1, len, f);
|
||||
#endif
|
||||
|
||||
printf ("Opened font file %s: %d bytes long\n", argv[1], len);
|
||||
|
||||
const OpenTypeFontFile &ot = *CastP<OpenTypeFontFile> (font_data);
|
||||
|
||||
switch (ot.get_tag ()) {
|
||||
case OpenTypeFontFile::TrueTypeTag:
|
||||
printf ("OpenType font with TrueType outlines\n");
|
||||
break;
|
||||
case OpenTypeFontFile::CFFTag:
|
||||
printf ("OpenType font with CFF (Type1) outlines\n");
|
||||
break;
|
||||
case OpenTypeFontFile::TTCTag:
|
||||
printf ("TrueType Collection of OpenType fonts\n");
|
||||
break;
|
||||
case OpenTypeFontFile::TrueTag:
|
||||
printf ("Obsolete Apple TrueType font\n");
|
||||
break;
|
||||
case OpenTypeFontFile::Typ1Tag:
|
||||
printf ("Obsolete Apple Type1 font in SFNT container\n");
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown font format\n");
|
||||
break;
|
||||
}
|
||||
|
||||
int num_fonts = ot.get_face_count ();
|
||||
printf ("%d font(s) found in file\n", num_fonts);
|
||||
for (int n_font = 0; n_font < num_fonts; n_font++) {
|
||||
const OpenTypeFontFace &font = ot.get_face (n_font);
|
||||
printf ("Font %d of %d:\n", n_font, num_fonts);
|
||||
|
||||
int num_tables = font.get_table_count ();
|
||||
printf (" %d table(s) found in font\n", num_tables);
|
||||
for (int n_table = 0; n_table < num_tables; n_table++) {
|
||||
const OpenTypeTable &table = font.get_table (n_table);
|
||||
printf (" Table %2d of %2d: %.4s (0x%08x+0x%08x)\n", n_table, num_tables,
|
||||
(const char *)table.tag,
|
||||
(unsigned int) table.offset,
|
||||
(unsigned int) table.length);
|
||||
|
||||
switch (table.tag) {
|
||||
|
||||
case GSUBGPOS::GSUBTag:
|
||||
case GSUBGPOS::GPOSTag:
|
||||
{
|
||||
|
||||
const GSUBGPOS &g = *CastP<GSUBGPOS> (font_data + table.offset);
|
||||
|
||||
int num_scripts = g.get_script_count ();
|
||||
printf (" %d script(s) found in table\n", num_scripts);
|
||||
for (int n_script = 0; n_script < num_scripts; n_script++) {
|
||||
const Script &script = g.get_script (n_script);
|
||||
printf (" Script %2d of %2d: %.4s\n", n_script, num_scripts,
|
||||
(const char *)g.get_script_tag(n_script));
|
||||
|
||||
if (!script.has_default_lang_sys())
|
||||
printf (" No default language system\n");
|
||||
int num_langsys = script.get_lang_sys_count ();
|
||||
printf (" %d language system(s) found in script\n", num_langsys);
|
||||
for (int n_langsys = script.has_default_lang_sys() ? -1 : 0; n_langsys < num_langsys; n_langsys++) {
|
||||
const LangSys &langsys = n_langsys == -1
|
||||
? script.get_default_lang_sys ()
|
||||
: script.get_lang_sys (n_langsys);
|
||||
printf (n_langsys == -1
|
||||
? " Default Language System\n"
|
||||
: " Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
|
||||
(const char *)script.get_lang_sys_tag (n_langsys));
|
||||
if (langsys.get_required_feature_index () == Index::NOT_FOUND_INDEX)
|
||||
printf (" No required feature\n");
|
||||
|
||||
int num_features = langsys.get_feature_count ();
|
||||
printf (" %d feature(s) found in language system\n", num_features);
|
||||
for (int n_feature = 0; n_feature < num_features; n_feature++) {
|
||||
printf (" Feature index %2d of %2d: %d\n", n_feature, num_features,
|
||||
langsys.get_feature_index (n_feature));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int num_features = g.get_feature_count ();
|
||||
printf (" %d feature(s) found in table\n", num_features);
|
||||
for (int n_feature = 0; n_feature < num_features; n_feature++) {
|
||||
const Feature &feature = g.get_feature (n_feature);
|
||||
printf (" Feature %2d of %2d: %.4s; %d lookup(s)\n", n_feature, num_features,
|
||||
(const char *)g.get_feature_tag(n_feature),
|
||||
feature.get_lookup_count());
|
||||
|
||||
int num_lookups = feature.get_lookup_count ();
|
||||
printf (" %d lookup(s) found in feature\n", num_lookups);
|
||||
for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
|
||||
printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups,
|
||||
feature.get_lookup_index (n_lookup));
|
||||
}
|
||||
}
|
||||
|
||||
int num_lookups = g.get_lookup_count ();
|
||||
printf (" %d lookup(s) found in table\n", num_lookups);
|
||||
for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) {
|
||||
const Lookup &lookup = g.get_lookup (n_lookup);
|
||||
printf (" Lookup %2d of %2d: type %d, flags 0x%04X\n", n_lookup, num_lookups,
|
||||
lookup.get_type(), lookup.get_flag());
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case GDEF::Tag:
|
||||
{
|
||||
|
||||
const GDEF &gdef = *CastP<GDEF> (font_data + table.offset);
|
||||
|
||||
printf (" Has %sglyph classes\n",
|
||||
gdef.has_glyph_classes () ? "" : "no ");
|
||||
printf (" Has %smark attachment types\n",
|
||||
gdef.has_mark_attachment_types () ? "" : "no ");
|
||||
printf (" Has %sattach points\n",
|
||||
gdef.has_attach_points () ? "" : "no ");
|
||||
printf (" Has %slig carets\n",
|
||||
gdef.has_lig_carets () ? "" : "no ");
|
||||
printf (" Has %smark sets\n",
|
||||
gdef.has_mark_sets () ? "" : "no ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Загрузка…
Ссылка в новой задаче