bug 449292 - part 1 - harfbuzz-ng code from upstream. r=jdaggett sr=roc

This commit is contained in:
Jonathan Kew 2010-06-11 20:14:37 +01:00
Родитель e3499cdeb7
Коммит d2c3a98fdb
58 изменённых файлов: 13733 добавлений и 0 удалений

0
gfx/harfbuzz/AUTHORS Normal file
Просмотреть файл

17
gfx/harfbuzz/COPYING Normal file
Просмотреть файл

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

45
gfx/harfbuzz/Makefile.am Normal file
Просмотреть файл

@ -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
gfx/harfbuzz/NEWS Normal file
Просмотреть файл

9
gfx/harfbuzz/README Normal file
Просмотреть файл

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

12
gfx/harfbuzz/TODO Normal file
Просмотреть файл

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

188
gfx/harfbuzz/autogen.sh Executable file
Просмотреть файл

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

59
gfx/harfbuzz/configure.ac Normal file
Просмотреть файл

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

184
gfx/harfbuzz/git.mk Normal file
Просмотреть файл

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

356
gfx/harfbuzz/src/hb-blob.c Normal file
Просмотреть файл

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

469
gfx/harfbuzz/src/hb-font.cc Normal file
Просмотреть файл

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

199
gfx/harfbuzz/src/hb-font.h Normal file
Просмотреть файл

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

240
gfx/harfbuzz/src/hb-ft.cc Normal file
Просмотреть файл

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

56
gfx/harfbuzz/src/hb-ft.h Normal file
Просмотреть файл

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

248
gfx/harfbuzz/src/hb-icu.c Normal file
Просмотреть файл

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

39
gfx/harfbuzz/src/hb-icu.h Normal file
Просмотреть файл

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

36
gfx/harfbuzz/src/hb-ot.h Normal file
Просмотреть файл

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

38
gfx/harfbuzz/src/hb.h Normal file
Просмотреть файл

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

190
gfx/harfbuzz/src/main.cc Normal file
Просмотреть файл

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