diff options
author | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-05 20:38:50 +0000 |
---|---|---|
committer | evan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-05 20:38:50 +0000 |
commit | 29c2daeafac577bd80c7b37891e3bbae7c542b5e (patch) | |
tree | 3ba8adb929982562db6c0b37c15c00ada32b41da | |
parent | 678a7d737ffd81978c981d692972695e4ad7f394 (diff) | |
download | chromium_src-29c2daeafac577bd80c7b37891e3bbae7c542b5e.zip chromium_src-29c2daeafac577bd80c7b37891e3bbae7c542b5e.tar.gz chromium_src-29c2daeafac577bd80c7b37891e3bbae7c542b5e.tar.bz2 |
harfbuzz: check in harfbuzz-ng, add gyp define to use it
This checks in harbuzz-ng b0d396aa88b3cdf8cea896bfeeba197656e1cdb1.
Setting use_harfbuzz_ng to 1 in gyp will cause us to build
harfbuzz-ng in place of harfbuzz. So far this currently fails to
compile due to all our other code relying on the old API.
BUG=68551
TEST=./build/gyp_chromium -Duse_harfbuzz_ng=1, verify build breaks
Review URL: http://codereview.chromium.org/6052008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70539 0039d316-1c4b-4281-b951-d872f2087c98
65 files changed, 14955 insertions, 40 deletions
diff --git a/build/common.gypi b/build/common.gypi index e741a29..f914684 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -323,6 +323,10 @@ # Use OpenSSL instead of NSS. Under development: see http://crbug.com/62803 'use_openssl%': 0, + # Use Harfbuzz-NG instead of Harfbuzz. + # Under development: http://crbug.com/68551 + 'use_harfbuzz_ng%': 0, + 'conditions': [ ['OS=="linux" or OS=="freebsd" or OS=="openbsd"', { # This will set gcc_version to XY if you are running gcc X.Y.*. diff --git a/third_party/harfbuzz-ng/COPYING b/third_party/harfbuzz-ng/COPYING new file mode 100644 index 0000000..3fb9e51 --- /dev/null +++ b/third_party/harfbuzz-ng/COPYING @@ -0,0 +1,29 @@ +HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. + +Copyright (C) 2010 Google, Inc. +Copyright (C) 2006 Behdad Esfahbod +Copyright (C) 2009 Keith Stribley +Copyright (C) 2009 Martin Hosken and SIL International +Copyright (C) 2007 Chris Wilson +Copyright (C) 2004,2007,2008,2009,2010 Red Hat, Inc. +Copyright (C) 1998-2004 David Turner and Werner Lemberg +For full copyright notices consult the individual files in the package. + + +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. diff --git a/third_party/harfbuzz-ng/README b/third_party/harfbuzz-ng/README new file mode 100644 index 0000000..06aad34 --- /dev/null +++ b/third_party/harfbuzz-ng/README @@ -0,0 +1,9 @@ +This is HarfBuzz, a text shaping library. + +Bug reports on these files should be sent to the HarfBuzz mailing list as +listed on http://harfbuzz.org/ + +For license information, see the file COPYING. + +Behdad Esfahbod +18 November 2010 diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium new file mode 100644 index 0000000..e656355 --- /dev/null +++ b/third_party/harfbuzz-ng/README.chromium @@ -0,0 +1,9 @@ +Name: HarfBuzz +URL: http://freedesktop.org/wiki/Software/HarfBuzz + +This is harfbuzz-ng, a new implementation of harfbuzz with a different +API from the old one. + +This code was taken from b0d396aa88b3cdf8cea896bfeeba197656e1cdb1 +(git://anongit.freedesktop.org/harfbuzz). I also deleted all +unneeded files from the root directory (but left src/ alone). diff --git a/third_party/harfbuzz-ng/harfbuzz.gyp b/third_party/harfbuzz-ng/harfbuzz.gyp new file mode 100644 index 0000000..08bbb14 --- /dev/null +++ b/third_party/harfbuzz-ng/harfbuzz.gyp @@ -0,0 +1,73 @@ +# Copyright (c) 2009 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'targets': [ + { + 'target_name': 'harfbuzz', + 'type': '<(library)', + 'sources': [ + 'src/hb-blob-private.h', + 'src/hb-blob.c', + 'src/hb-blob.h', + 'src/hb-buffer-private.hh', + 'src/hb-buffer.cc', + 'src/hb-buffer.h', + 'src/hb-common.c', + 'src/hb-common.h', + 'src/hb-font-private.h', + 'src/hb-font.cc', + 'src/hb-font.h', + 'src/hb-ft.c', + 'src/hb-icu.c', + 'src/hb-language.c', + 'src/hb-language.h', + 'src/hb-object-private.h', + 'src/hb-open-file-private.hh', + 'src/hb-open-type-private.hh', + 'src/hb-ot-head-private.hh', + 'src/hb-ot-layout-common-private.hh', + 'src/hb-ot-layout-gdef-private.hh', + 'src/hb-ot-layout-gpos-private.hh', + 'src/hb-ot-layout-gsub-private.hh', + 'src/hb-ot-layout-gsubgpos-private.hh', + 'src/hb-ot-layout-private.hh', + 'src/hb-ot-layout.cc', + 'src/hb-ot-map-private.hh', + 'src/hb-ot-map.cc', + 'src/hb-ot-shape-complex-arabic-table.h', + 'src/hb-ot-shape-complex-arabic.cc', + 'src/hb-ot-shape-complex-private.hh', + 'src/hb-ot-shape-private.hh', + 'src/hb-ot-shape.cc', + 'src/hb-ot-tag.c', + 'src/hb-private.h', + 'src/hb-shape.cc', + 'src/hb-shape.h', + 'src/hb-unicode-private.h', + 'src/hb-unicode.c', + 'src/hb-unicode.h', + 'src/hb.h', + ], + 'include_dirs': [ + 'src', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'src', + ], + }, + 'dependencies': [ + '../../build/linux/system.gyp:freetype2', + '../../third_party/icu/icu.gyp:icuuc', + ], + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/third_party/harfbuzz-ng/src/Makefile.am b/third_party/harfbuzz-ng/src/Makefile.am new file mode 100644 index 0000000..13107b9 --- /dev/null +++ b/third_party/harfbuzz-ng/src/Makefile.am @@ -0,0 +1,147 @@ +# Process this file with automake to produce Makefile.in + +NULL = +EXTRA_DIST = + +# 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-common.c \ + hb-font.cc \ + hb-font-private.h \ + 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-map.cc \ + hb-ot-map-private.hh \ + hb-ot-shape.cc \ + hb-ot-shape-complex-arabic.cc \ + hb-ot-shape-complex-arabic-table.h \ + hb-ot-shape-complex-private.hh \ + hb-ot-shape-private.hh \ + hb-ot-tag.c \ + $(NULL) +HBHEADERS += \ + hb-ot.h \ + hb-ot-layout.h \ + hb-ot-shape.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.c \ + $(NULL) +HBHEADERS += \ + hb-ft.h \ + $(NULL) +endif + +if HAVE_GRAPHITE +HBCFLAGS += $(GRAPHITE_CFLAGS) +HBLIBS += $(GRAPHITE_LIBS) +HBSOURCES += \ + hb-graphite.cc \ + $(NULL) +HBHEADERS += \ + hb-graphite.h \ + $(NULL) +endif + +CXXLINK = $(LINK) +libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) +libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) +libharfbuzz_la_LIBADD = $(HBLIBS) +pkginclude_HEADERS = $(HBHEADERS) + + +GENERATORS = \ + gen-arabic-joining-table.py \ + $(NULL) + +EXTRA_DIST += $(GENERATORS) + +noinst_PROGRAMS = main test + +main_SOURCES = main.cc +main_CPPFLAGS = $(HBCFLAGS) +main_LDADD = libharfbuzz.la $(HBLIBS) + +test_SOURCES = test.c +test_CPPFLAGS = $(HBCFLAGS) +test_LDADD = libharfbuzz.la $(HBLIBS) + +TESTS = \ + check-c-linkage-decls.sh \ + check-header-guards.sh \ + check-internal-symbols.sh \ + $(NULL) + +if HAVE_ICU +else +if HAVE_GRAPHITE +else +TESTS += check-libstdc++.sh +endif +endif + +-include $(top_srcdir)/git.mk diff --git a/third_party/harfbuzz-ng/src/check-c-linkage-decls.sh b/third_party/harfbuzz-ng/src/check-c-linkage-decls.sh new file mode 100755 index 0000000..711d089 --- /dev/null +++ b/third_party/harfbuzz-ng/src/check-c-linkage-decls.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +test -z "$srcdir" && srcdir=. +stat=0 + +cd "$srcdir" + +for x in hb-*.c hb-*.cc hb-*.h hb-*.hh ; do + if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then + echo "Ouch, file $x does not HB_BEGIN_DECLS / HB_END_DECLS" + stat=1 + fi +done + +exit $stat diff --git a/third_party/harfbuzz-ng/src/check-header-guards.sh b/third_party/harfbuzz-ng/src/check-header-guards.sh new file mode 100755 index 0000000..c966cd2 --- /dev/null +++ b/third_party/harfbuzz-ng/src/check-header-guards.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +test -z "$srcdir" && srcdir=. +stat=0 + +cd "$srcdir" + +for x in hb-*.h hb-*.hh ; do + tag=`echo "$x" | tr 'a-z.-' 'A-Z_'` + lines=`grep "\<$tag\>" "$x" | wc -l` + if test "x$lines" != x3; then + echo "Ouch, header file $x does not have correct preprocessor guards" + stat=1 + fi +done + +exit $stat diff --git a/third_party/harfbuzz-ng/src/check-internal-symbols.sh b/third_party/harfbuzz-ng/src/check-internal-symbols.sh new file mode 100755 index 0000000..124a7b0 --- /dev/null +++ b/third_party/harfbuzz-ng/src/check-internal-symbols.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +if which nm 2>/dev/null >/dev/null; then + : +else + echo "check-internal-symbols.sh: 'nm' 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 exposing internal symbols" + if nm $so | grep ' T ' | grep -v ' T _fini\>\| T _init\>\| T hb_'; then + echo "Ouch, internal symbols exposed" + stat=1 + fi +else + echo "check-internal-symbols.sh: libharfbuzz.so not found; skipping test" +fi + +exit $stat diff --git a/third_party/harfbuzz-ng/src/check-libstdc++.sh b/third_party/harfbuzz-ng/src/check-libstdc++.sh new file mode 100755 index 0000000..c0abcbe4 --- /dev/null +++ b/third_party/harfbuzz-ng/src/check-libstdc++.sh @@ -0,0 +1,27 @@ +#!/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=. +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 diff --git a/third_party/harfbuzz-ng/src/gen-arabic-joining-table.py b/third_party/harfbuzz-ng/src/gen-arabic-joining-table.py new file mode 100755 index 0000000..08e54db --- /dev/null +++ b/third_party/harfbuzz-ng/src/gen-arabic-joining-table.py @@ -0,0 +1,83 @@ +#!/usr/bin/python + +import sys + +header = sys.stdin.readline (), sys.stdin.readline () +while sys.stdin.readline ().find ('##################') < 0: + pass + + +print "/* == Start of generated table == */" +print "/*" +print " * The following table is generated by running:" +print " *" +print " * ./gen-arabic-joining-table.py < ArabicShaping.txt" +print " *" +print " * on the ArabicShaping.txt file with the header:" +print " *" +for line in header: + print " * %s" % (line.strip()) +print " */" + +print "static const uint8_t joining_table[] =" +print "{" + + +min_u = 0x110000 +max_u = 0 +num = 0 +last = -1 +block = '' +for line in sys.stdin: + + if line[0] == '#': + if line.find (" characters"): + block = line[2:].strip () + continue + + fields = [x.strip () for x in line.split (';')] + if len (fields) == 1: + continue + + u = int (fields[0], 16) + if u == 0x200C or u == 0x200D: + continue + if u < last: + raise Exception ("Input data character not sorted", u) + min_u = min (min_u, u) + max_u = max (max_u, u) + num += 1 + + if block: + print "\n /* %s */\n" % block + block = '' + + if last != -1: + last += 1 + while last < u: + print " JOINING_TYPE_X, /* %04X */" % last + last += 1 + else: + last = u + + if fields[3] in ["ALAPH", "DALATH RISH"]: + value = "JOINING_GROUP_" + fields[3].replace(' ', '_') + else: + value = "JOINING_TYPE_" + fields[2] + print " %s, /* %s */" % (value, '; '.join(fields)) + +print +print " JOINING_TYPE_X /* dummy */" +print "};" +print + +print "#define JOINING_TABLE_FIRST 0x%04x" % min_u +print "#define JOINING_TABLE_LAST 0x%04x" % max_u +print + +print "/* == End of generated table == */" + +occupancy = num * 100 / (max_u - min_u + 1) +# Maintain at least 40% occupancy in the table */ +if occupancy < 40: + raise Exception ("Table too sparse, please investigate: ", occupancy) diff --git a/third_party/harfbuzz-ng/src/hb-blob-private.h b/third_party/harfbuzz-ng/src/hb-blob-private.h new file mode 100644 index 0000000..92109ed --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-blob-private.h @@ -0,0 +1,59 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-blob.c b/third_party/harfbuzz-ng/src/hb-blob.c new file mode 100644 index 0000000..37e7787 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-blob.c @@ -0,0 +1,362 @@ +/* + * 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 */ + +#include <stdio.h> +#include <errno.h> + +HB_BEGIN_DECLS + + +#ifndef HB_DEBUG_BLOB +#define HB_DEBUG_BLOB (HB_DEBUG+0) +#endif + +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); + + (void) (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); + + (void) (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) { + (void) (HB_DEBUG_BLOB && + fprintf (stderr, "%p %s: failed to get pagesize: %s\n", blob, __FUNCTION__, strerror (errno))); + return FALSE; + } + (void) (HB_DEBUG_BLOB && + fprintf (stderr, "%p %s: pagesize is %lu\n", blob, __FUNCTION__, (unsigned long) pagesize)); + + mask = ~(pagesize-1); + addr = (const char *) (((uintptr_t) blob->data) & mask); + length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask) - addr; + (void) (HB_DEBUG_BLOB && + fprintf (stderr, "%p %s: calling mprotect on [%p..%p] (%lu bytes)\n", + blob, __FUNCTION__, + addr, addr+length, (unsigned long) length)); + if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) { + (void) (HB_DEBUG_BLOB && + fprintf (stderr, "%p %s: %s\n", blob, __FUNCTION__, strerror (errno))); + return FALSE; + } + + (void) (HB_DEBUG_BLOB && + fprintf (stderr, "%p %s: successfully made [%p..%p] (%lu bytes) writable\n", + blob, __FUNCTION__, + addr, addr+length, (unsigned long) length)); + return TRUE; +#else + return FALSE; +#endif +} + +static void +try_writable_inplace_locked (hb_blob_t *blob) +{ + (void) (HB_DEBUG_BLOB && + fprintf (stderr, "%p %s: making writable\n", blob, __FUNCTION__)); + + if (_try_make_writable_inplace_unix_locked (blob)) { + (void) (HB_DEBUG_BLOB && + fprintf (stderr, "%p %s: making writable -> succeeded\n", blob, __FUNCTION__)); + blob->mode = HB_MEMORY_MODE_WRITABLE; + } else { + (void) (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; + + (void) (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) { + (void) (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; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-blob.h b/third_party/harfbuzz-ng/src/hb-blob.h new file mode 100644 index 0000000..dbbfc90 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-blob.h @@ -0,0 +1,89 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-buffer-private.hh b/third_party/harfbuzz-ng/src/hb-buffer-private.hh new file mode 100644 index 0000000..a129165 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-buffer-private.hh @@ -0,0 +1,146 @@ +/* + * 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_HH +#define HB_BUFFER_PRIVATE_HH + +#include "hb-private.h" +#include "hb-buffer.h" +#include "hb-unicode-private.h" + +HB_BEGIN_DECLS + + +ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20); +ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)); + +typedef struct _hb_segment_properties_t { + hb_direction_t direction; + hb_script_t script; + hb_language_t language; +} hb_segment_properties_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_replace_glyphs_be16 (hb_buffer_t *buffer, + unsigned int num_in, + unsigned int num_out, + const uint16_t *glyph_data_be); + +HB_INTERNAL void +_hb_buffer_replace_glyph (hb_buffer_t *buffer, + hb_codepoint_t glyph_index); + +HB_INTERNAL void +_hb_buffer_next_glyph (hb_buffer_t *buffer); + + +HB_INTERNAL void +_hb_buffer_reset_masks (hb_buffer_t *buffer, + hb_mask_t mask); + +HB_INTERNAL void +_hb_buffer_add_masks (hb_buffer_t *buffer, + hb_mask_t mask); + +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; /* Unicode functions */ + hb_segment_properties_t props; /* Script, language, direction */ + + /* 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_glyph_info_t *info; + hb_glyph_info_t *out_info; + hb_glyph_position_t *pos; + + /* Other stuff */ + + unsigned int serial; + + + /* Methods */ + inline unsigned int next_serial (void) { return serial++; } + 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 replace_glyphs_be16 (unsigned int num_in, + unsigned int num_out, + const uint16_t *glyph_data_be) + { _hb_buffer_replace_glyphs_be16 (this, num_in, num_out, glyph_data_be); } + inline void replace_glyph (hb_codepoint_t glyph_index) + { _hb_buffer_replace_glyph (this, glyph_index); } + + inline void reset_masks (hb_mask_t mask) + { + for (unsigned int i = 0; i < len; i++) + info[i].mask = mask; + } + inline void add_masks (hb_mask_t mask) + { + for (unsigned int i = 0; i < len; i++) + info[i].mask |= mask; + } + 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_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc new file mode 100644 index 0000000..03e8e1a --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-buffer.cc @@ -0,0 +1,630 @@ +/* + * 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> + +HB_BEGIN_DECLS + + +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_glyph_position_t *new_pos; + hb_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_glyph_position_t *) realloc (buffer->pos, new_allocated * sizeof (buffer->pos[0])); + new_info = (hb_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_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 inline 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_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->props.direction = direction; +} + +hb_direction_t +hb_buffer_get_direction (hb_buffer_t *buffer) +{ + return buffer->props.direction; +} + +void +hb_buffer_set_script (hb_buffer_t *buffer, + hb_script_t script) +{ + buffer->props.script = script; +} + +hb_script_t +hb_buffer_get_script (hb_buffer_t *buffer) +{ + return buffer->props.script; +} + +void +hb_buffer_set_language (hb_buffer_t *buffer, + hb_language_t language) +{ + buffer->props.language = language; +} + +hb_language_t +hb_buffer_get_language (hb_buffer_t *buffer) +{ + return buffer->props.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->serial = 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_glyph_info_t *glyph; + + if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return; + + glyph = &buffer->info[buffer->len]; + + memset (glyph, 0, sizeof (*glyph)); + glyph->codepoint = codepoint; + glyph->mask = mask; + glyph->cluster = cluster; + + 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_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_glyph_info_t *tmp_string; + tmp_string = buffer->info; + buffer->info = buffer->out_info; + buffer->out_info = tmp_string; + buffer->pos = (hb_glyph_position_t *) buffer->out_info; + } + + tmp = buffer->len; + buffer->len = buffer->out_len; + buffer->out_len = tmp; + + buffer->i = 0; +} + +void +_hb_buffer_replace_glyphs_be16 (hb_buffer_t *buffer, + unsigned int num_in, + unsigned int num_out, + const uint16_t *glyph_data_be) +{ + 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; + } + + hb_glyph_info_t orig_info = buffer->info[buffer->i]; + + for (unsigned int i = 0; i < num_out; i++) + { + hb_glyph_info_t *info = &buffer->out_info[buffer->out_len + i]; + *info = orig_info; + info->codepoint = hb_be_uint16 (glyph_data_be[i]); + } + + buffer->i += num_in; + buffer->out_len += num_out; +} + +void +_hb_buffer_replace_glyph (hb_buffer_t *buffer, + hb_codepoint_t glyph_index) +{ + hb_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; + + 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_reset_masks (hb_buffer_t *buffer, + hb_mask_t mask) +{ + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->info[i].mask = mask; +} + +void +_hb_buffer_add_masks (hb_buffer_t *buffer, + hb_mask_t mask) +{ + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->info[i].mask |= mask; +} + +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; + value &= mask; + + if (!mask) + return; + + 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; + } + + /* XXX can't bsearch since .cluster may not be sorted. */ + /* 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_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_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 +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-buffer.h b/third_party/harfbuzz-ng/src/hb-buffer.h new file mode 100644 index 0000000..0185415 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-buffer.h @@ -0,0 +1,163 @@ +/* + * 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; + hb_var_int_t var1; + hb_var_int_t var2; +} 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; + hb_var_int_t var; +} 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-common.c b/third_party/harfbuzz-ng/src/hb-common.c new file mode 100644 index 0000000..74f8933 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-common.c @@ -0,0 +1,47 @@ +/* + * 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_BEGIN_DECLS + + +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); +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-common.h b/third_party/harfbuzz-ng/src/hb-common.h new file mode 100644 index 0000000..1dd02cb --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-common.h @@ -0,0 +1,106 @@ +/* + * 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 __cplusplus +# define HB_BEGIN_DECLS extern "C" { +# define HB_END_DECLS } +# else /* !__cplusplus */ +# define HB_BEGIN_DECLS +# define HB_END_DECLS +# endif /* !__cplusplus */ + +HB_BEGIN_DECLS + + +#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 + +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)) + + +typedef union _hb_var_int_t { + uint32_t u32; + int32_t i32; + uint16_t u16[2]; + int16_t i16[2]; + uint8_t u8[4]; + int8_t i8[4]; +} hb_var_int_t; + + +HB_END_DECLS + +#endif /* HB_COMMON_H */ diff --git a/third_party/harfbuzz-ng/src/hb-font-private.h b/third_party/harfbuzz-ng/src/hb-font-private.h new file mode 100644 index 0000000..b147bce --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-font-private.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" + +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_glyph_advance_func_t get_glyph_advance; + hb_font_get_glyph_extents_func_t get_glyph_extents; + hb_font_get_contour_point_func_t get_contour_point; + 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-font.cc b/third_party/harfbuzz-ng/src/hb-font.cc new file mode 100644 index 0000000..63631a9 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-font.cc @@ -0,0 +1,583 @@ +/* + * 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.h" +#include "hb-blob-private.h" +#include "hb-open-file-private.hh" + +#include "hb-ot-layout-private.hh" + +#include <string.h> + +HB_BEGIN_DECLS + + +/* + * 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 void +hb_font_get_glyph_advance_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_position_t *x_advance HB_UNUSED, + hb_position_t *y_advance HB_UNUSED) +{ } + +static void +hb_font_get_glyph_extents_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_extents_t *extents HB_UNUSED) +{ } + +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 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_glyph_advance_nil, + hb_font_get_glyph_extents_nil, + hb_font_get_contour_point_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; +} + +hb_bool_t +hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) +{ + return ffuncs->immutable; +} + + +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_glyph_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_advance_func_t glyph_advance_func) +{ + if (ffuncs->immutable) + return; + + ffuncs->v.get_glyph_advance = glyph_advance_func ? glyph_advance_func : hb_font_get_glyph_advance_nil; +} + +void +hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_extents_func_t glyph_extents_func) +{ + if (ffuncs->immutable) + return; + + ffuncs->v.get_glyph_extents = glyph_extents_func ? glyph_extents_func : hb_font_get_glyph_extents_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_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_font_get_glyph_func_t +hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs) +{ + return ffuncs->v.get_glyph; +} + +hb_font_get_glyph_advance_func_t +hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs) +{ + return ffuncs->v.get_glyph_advance; +} + +hb_font_get_glyph_extents_func_t +hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs) +{ + return ffuncs->v.get_glyph_extents; +} + +hb_font_get_contour_point_func_t +hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs) +{ + return ffuncs->v.get_contour_point; +} + +hb_font_get_kerning_func_t +hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs) +{ + return ffuncs->v.get_kerning; +} + + + +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); +} + +void +hb_font_get_glyph_advance (hb_font_t *font, hb_face_t *face, + hb_codepoint_t glyph, + hb_position_t *x_advance, hb_position_t *y_advance) +{ + *x_advance = *y_advance = 0; + return font->klass->v.get_glyph_advance (font, face, font->user_data, + glyph, x_advance, y_advance); +} + +void +hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face, + hb_codepoint_t glyph, hb_glyph_extents_t *extents) +{ + memset (extents, 0, sizeof (*extents)); + return font->klass->v.get_glyph_extents (font, face, font->user_data, + glyph, extents); +} + +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); +} + +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 = 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_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (Sanitizer<OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index); + + if (unlikely (!closure)) + return &_hb_face_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; +} + +unsigned int +hb_face_get_upem (hb_face_t *face) +{ + return (face->head_table ? face->head_table : &Null(head))->get_upem (); +} + + +/* + * 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_unset_funcs (hb_font_t *font, + hb_font_funcs_t **klass, + hb_destroy_func_t *destroy, + void **user_data) +{ + /* None of the input arguments can be NULL. */ + + *klass = font->klass; + *destroy = font->destroy; + *user_data = font->user_data; + + if (HB_OBJECT_IS_INERT (font)) + return; + + font->klass = NULL; + font->destroy = NULL; + font->user_data = NULL; +} + +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_get_scale (hb_font_t *font, + unsigned int *x_scale, + unsigned int *y_scale) +{ + if (x_scale) *x_scale = font->x_scale; + if (y_scale) *y_scale = font->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; +} + +void +hb_font_get_ppem (hb_font_t *font, + unsigned int *x_ppem, + unsigned int *y_ppem) +{ + if (x_ppem) *x_ppem = font->x_ppem; + if (y_ppem) *y_ppem = font->y_ppem; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-font.h b/third_party/harfbuzz-ng/src/hb-font.h new file mode 100644 index 0000000..f33e56f --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-font.h @@ -0,0 +1,270 @@ +/* + * 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); + +/* XXX + * + * I have two major concerns about this API as it is right now: + * + * - Jonathan Kew convinced me to make it return NULL if table not found (280af1bd), + * however, that is WRONG IMO. The API should not differentiate between a non-existing + * table vs a zero-length table vs a very short table. It only leads to implementations + * that check for non-NULL and assume that they've got a usable table going on... This + * actually happened with Firefox. + * + * - It has to be renamed to reference_table() since unlike any other _get_ API, a reference + * ownership transfer happens and the user is responsible to destroy the result. + */ +hb_blob_t * +hb_face_get_table (hb_face_t *face, + hb_tag_t tag); + +unsigned int +hb_face_get_upem (hb_face_t *face); + + +/* + * 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); + +hb_bool_t +hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); + +/* funcs */ + +typedef struct _hb_glyph_extents_t +{ + hb_position_t x_bearing; + hb_position_t y_bearing; + hb_position_t width; + hb_position_t height; +} hb_glyph_extents_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 void (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data, + hb_codepoint_t glyph, + hb_position_t *x_advance, hb_position_t *y_advance); +typedef void (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, hb_face_t *face, const void *user_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents); +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 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_glyph_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_advance_func_t glyph_advance_func); + +void +hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_extents_func_t glyph_extents_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_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_kerning_func_t kerning_func); + + +/* These never return NULL. Return fallback defaults instead. */ + +hb_font_get_glyph_func_t +hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs); + +hb_font_get_glyph_advance_func_t +hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs); + +hb_font_get_glyph_extents_func_t +hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs); + +hb_font_get_contour_point_func_t +hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs); + +hb_font_get_kerning_func_t +hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs); + + +hb_codepoint_t +hb_font_get_glyph (hb_font_t *font, hb_face_t *face, + hb_codepoint_t unicode, hb_codepoint_t variation_selector); + +void +hb_font_get_glyph_advance (hb_font_t *font, hb_face_t *face, + hb_codepoint_t glyph, + hb_position_t *x_advance, hb_position_t *y_advance); + +void +hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents); + +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); + +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); + +/* Returns what was set and unsets it, but doesn't destroy(user_data). + * This is useful for wrapping / chaining font_funcs_t's. + * + * The client is responsible for: + * + * - Take ownership of the reference on the returned klass, + * + * - Calling "destroy(user_data)" exactly once if returned destroy func + * is not NULL and the returned info is not needed anymore. + */ +void +hb_font_unset_funcs (hb_font_t *font, + hb_font_funcs_t **klass, + hb_destroy_func_t *destroy, + void **user_data); + + +/* + * We should add support for full matrices. + */ +void +hb_font_set_scale (hb_font_t *font, + unsigned int x_scale, + unsigned int y_scale); + +void +hb_font_get_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); + +void +hb_font_get_ppem (hb_font_t *font, + unsigned int *x_ppem, + unsigned int *y_ppem); + + +HB_END_DECLS + +#endif /* HB_FONT_H */ diff --git a/third_party/harfbuzz-ng/src/hb-ft.c b/third_party/harfbuzz-ng/src/hb-ft.c new file mode 100644 index 0000000..e696fe8 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ft.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009 Keith Stribley + * + * 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.h" + +#include FT_TRUETYPE_TABLES_H + +HB_BEGIN_DECLS + + +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 void +hb_ft_get_glyph_advance (hb_font_t *font HB_UNUSED, + hb_face_t *face HB_UNUSED, + const void *user_data, + hb_codepoint_t glyph, + hb_position_t *x_advance, + hb_position_t *y_advance) +{ + FT_Face ft_face = (FT_Face) user_data; + int load_flags = FT_LOAD_DEFAULT; + + /* TODO: load_flags, embolden, etc */ + + if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags))) + { + *x_advance = ft_face->glyph->advance.x; + *y_advance = ft_face->glyph->advance.y; + } +} + +static void +hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, + hb_face_t *face HB_UNUSED, + const void *user_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) +{ + FT_Face ft_face = (FT_Face) user_data; + int load_flags = FT_LOAD_DEFAULT; + + /* TODO: load_flags, embolden, etc */ + + if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags))) + { + /* XXX: A few negations should be in order here, not sure. */ + extents->x_bearing = ft_face->glyph->metrics.horiBearingX; + extents->y_bearing = ft_face->glyph->metrics.horiBearingY; + extents->width = ft_face->glyph->metrics.width; + extents->height = ft_face->glyph->metrics.height; + } +} + +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 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_glyph_advance, + hb_ft_get_glyph_extents, + hb_ft_get_contour_point, + 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; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ft.h b/third_party/harfbuzz-ng/src/hb-ft.h new file mode 100644 index 0000000..be5c854 --- /dev/null +++ b/third_party/harfbuzz-ng/src/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 + */ + +#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 */ diff --git a/third_party/harfbuzz-ng/src/hb-glib.c b/third_party/harfbuzz-ng/src/hb-glib.c new file mode 100644 index 0000000..c548fa6 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-glib.c @@ -0,0 +1,64 @@ +/* + * 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> + +HB_BEGIN_DECLS + + +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; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-glib.h b/third_party/harfbuzz-ng/src/hb-glib.h new file mode 100644 index 0000000..81ab15d --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-glib.h @@ -0,0 +1,41 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-graphite.cc b/third_party/harfbuzz-ng/src/hb-graphite.cc new file mode 100644 index 0000000..0a8d681 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-graphite.cc @@ -0,0 +1,310 @@ +/* + * 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.h" +#include "hb-graphite.h" +#include <map> + +HB_BEGIN_DECLS + + +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; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-graphite.h b/third_party/harfbuzz-ng/src/hb-graphite.h new file mode 100644 index 0000000..b5d1176 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-graphite.h @@ -0,0 +1,47 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-icu.c b/third_party/harfbuzz-ng/src/hb-icu.c new file mode 100644 index 0000000..601ef61 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-icu.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2009 Red Hat, Inc. + * Copyright (C) 2009 Keith Stribley + * + * 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> + +HB_BEGIN_DECLS + + +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_SCRIPT2(MEITEI_MAYEK, MEETEI_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 */ + + /* Unicode-6.0 additions */ + MATCH_SCRIPT (BATAK); /* Batk */ + MATCH_SCRIPT (BRAHMI); /* Brah */ + MATCH_SCRIPT2(MANDAEAN, MANDAIC); /* Mand */ + + } + 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; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-icu.h b/third_party/harfbuzz-ng/src/hb-icu.h new file mode 100644 index 0000000..cc17af8 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-icu.h @@ -0,0 +1,41 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-language.c b/third_party/harfbuzz-ng/src/hb-language.c new file mode 100644 index 0000000..2aabada --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-language.c @@ -0,0 +1,120 @@ +/* + * 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" + +HB_BEGIN_DECLS + + +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; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-language.h b/third_party/harfbuzz-ng/src/hb-language.h new file mode 100644 index 0000000..d3c91fb --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-language.h @@ -0,0 +1,46 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-object-private.h b/third_party/harfbuzz-ng/src/hb-object-private.h new file mode 100644 index 0000000..a5b5355 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-object-private.h @@ -0,0 +1,141 @@ +/* + * 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_OBJECT_PRIVATE_H +#define HB_OBJECT_PRIVATE_H + +#include "hb-private.h" + +HB_BEGIN_DECLS + + +/* 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) +{ + (void) (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 + + +HB_END_DECLS + +#endif /* HB_OBJECT_PRIVATE_H */ diff --git a/third_party/harfbuzz-ng/src/hb-open-file-private.hh b/third_party/harfbuzz-ng/src/hb-open-file-private.hh new file mode 100644 index 0000000..cfb60db --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-open-file-private.hh @@ -0,0 +1,258 @@ +/* + * 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" + +HB_BEGIN_DECLS + + +/* + * + * The OpenType Font File + * + */ + + +/* + * Organization of an OpenType Font + */ + +struct OpenTypeFontFile; +struct OffsetTable; +struct TTCHeader; + + +typedef struct TableRecord +{ + inline bool sanitize (hb_sanitize_context_t *c) { + 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 TableRecord& get_table (unsigned int i) const + { + if (unlikely (i >= numTables)) return Null(TableRecord); + return tables[i]; + } + inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const + { + Tag t; + t.set (tag); + unsigned int count = numTables; + for (unsigned int i = 0; i < count; i++) + { + if (t == tables[i].tag) + { + if (table_index) *table_index = i; + return true; + } + } + if (table_index) *table_index = Index::NOT_FOUND_INDEX; + return false; + } + inline const TableRecord& get_table_by_tag (hb_tag_t tag) const + { + unsigned int table_index; + find_table_index (tag, &table_index); + return get_table (table_index); + } + + public: + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) + && c->check_array (tables, TableRecord::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. */ + TableRecord tables[VAR]; /* TableRecord entries. numTables items */ + public: + DEFINE_SIZE_ARRAY (12, tables); +} OpenTypeFontFace; + + +/* + * TrueType Collections + */ + +struct TTCHeaderVersion1 +{ + friend struct TTCHeader; + + inline unsigned int get_face_count (void) const { return table.len; } + inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } + + inline bool sanitize (hb_sanitize_context_t *c) { + 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); +}; + + +HB_END_DECLS + +#endif /* HB_OPEN_FILE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-open-type-private.hh b/third_party/harfbuzz-ng/src/hb-open-type-private.hh new file mode 100644 index 0000000..8f3001b --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh @@ -0,0 +1,727 @@ +/* + * 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_TYPE_PRIVATE_HH +#define HB_OPEN_TYPE_PRIVATE_HH + +#include "hb-private.h" + +#include "hb-blob.h" + +HB_BEGIN_DECLS +HB_END_DECLS + + +/* + * 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 (void) { + 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> (void) { \ + return *CastP<Type> (_Null##Type); \ +} /* The following line really exists such that we end in a place needing semicolon */ \ +ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) + +/* 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) { + (void) (*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; + + (void) (HB_DEBUG_SANITIZE && + fprintf (stderr, "sanitize %p init [%p..%p] (%lu bytes)\n", + this->blob, this->start, this->end, + (unsigned long) (this->end - this->start))); + } + + inline void finish (void) + { + (void) (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; + + (void) (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 = record_size > 0 && len >= ((unsigned int) -1) / record_size; + + (void) (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++; + + (void) (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: + (void) (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) { + (void) (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) { + (void) (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 */ + (void) (HB_DEBUG_SANITIZE && + fprintf (stderr, "Sanitizer %p retry %s\n", blob, HB_FUNC)); + goto retry; + } + } + + (void) (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 void set (Type i) { hb_be_uint16_put (v,i); } + inline operator Type (void) const { return hb_be_uint16_get (v); } + inline bool operator == (const BEInt<Type, 2>& o) const { return hb_be_uint16_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 void set (Type i) { hb_be_uint32_put (v,i); } + inline operator Type (void) const { return hb_be_uint32_get (v); } + inline bool operator == (const BEInt<Type, 4>& o) const { return hb_be_uint32_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.set (i); } + inline operator Type(void) const { return v; } + inline bool operator == (const IntType<Type> &o) const { return v == o.v; } + inline bool operator != (const IntType<Type> &o) const { return v != o.v; } + inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; } + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + 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 (void) 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. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && array[0].sanitize (c)); + + 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 (void) 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. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && array[0].sanitize (c)); + + return true; + } + + USHORT len; + Type array[VAR]; + public: + DEFINE_SIZE_ARRAY (sizeof (USHORT), array); +}; + + +/* An array with sorted elements. Supports binary searching. */ +template <typename Type> +struct SortedArrayOf : ArrayOf<Type> { + + template <typename SearchType> + inline int search (const SearchType &x) const { + class Cmp { + public: static int cmp (const SearchType *a, const Type *b) { return b->cmp (*a); } + }; + const Type *p = (const Type *) bsearch (&x, this->array, this->len, sizeof (this->array[0]), (hb_compare_func_t) Cmp::cmp); + return p ? p - this->array : -1; + } +}; + + +HB_BEGIN_DECLS +HB_END_DECLS + +#endif /* HB_OPEN_TYPE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-head-private.hh b/third_party/harfbuzz-ng/src/hb-ot-head-private.hh new file mode 100644 index 0000000..3a4bbbf --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-head-private.hh @@ -0,0 +1,146 @@ +/* + * 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" + +HB_BEGIN_DECLS + + +/* + * 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 unsigned int get_upem (void) const { + unsigned int upem = unitsPerEm; + /* If no valid head table found, assume 1000, which matches typicaly Type1 usage. */ + return 16 <= upem && upem <= 16384 ? upem : 1000; + } + + 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); + } + + private: + 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: Last Resort font. If set, indicates that + * the glyphs encoded in the cmap subtables are simply + * generic symbolic representations of code point + * ranges and don’t truly represent support for those + * code points. If unset, indicates that the glyphs + * encoded in the cmap subtables represent proper + * support for those code points. + * Bit 15: Reserved, set to 0. */ + USHORT unitsPerEm; /* Valid range is from 16 to 16384. This value + * should be a power of 2 for fonts that have + * TrueType outlines. */ + LONGDATETIME created; /* Number of seconds since 12:00 midnight, + January 1, 1904. 64-bit integer */ + LONGDATETIME modified; /* Number of seconds since 12:00 midnight, + January 1, 1904. 64-bit integer */ + SHORT xMin; /* For all glyph bounding boxes. */ + SHORT yMin; /* For all glyph bounding boxes. */ + SHORT xMax; /* For all glyph bounding boxes. */ + SHORT yMax; /* For all glyph bounding boxes. */ + USHORT macStyle; /* Bit 0: Bold (if set to 1); + * Bit 1: Italic (if set to 1) + * Bit 2: Underline (if set to 1) + * Bit 3: Outline (if set to 1) + * Bit 4: Shadow (if set to 1) + * Bit 5: Condensed (if set to 1) + * Bit 6: Extended (if set to 1) + * Bits 7-15: Reserved (set to 0). */ + USHORT lowestRecPPEM; /* Smallest readable size in pixels. */ + SHORT fontDirectionHint; /* Deprecated (Set to 2). + * 0: Fully mixed directional glyphs; + * 1: Only strongly left to right; + * 2: Like 1 but also contains neutrals; + * -1: Only strongly right to left; + * -2: Like -1 but also contains neutrals. */ + SHORT indexToLocFormat; /* 0 for short offsets, 1 for long. */ + SHORT glyphDataFormat; /* 0 for current format. */ + public: + DEFINE_SIZE_STATIC (54); +}; + + +HB_END_DECLS + +#endif /* HB_OT_HEAD_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh new file mode 100644 index 0000000..9ff5ca9 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh @@ -0,0 +1,604 @@ +/* + * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google 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 + +HB_BEGIN_DECLS +HB_END_DECLS + + +/* + * + * OpenType Layout Common Table Formats + * + */ + + +/* + * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList + */ + +template <typename Type> +struct Record +{ + inline int cmp (hb_tag_t a) const { + return tag.cmp (a); + } + + 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 : SortedArrayOf<Record<Type> > { + inline const Tag& get_tag (unsigned int i) const + { + /* We cheat slightly and don't define separate Null objects + * for Record types. Instead, we return the correct Null(Tag) + * here. */ + 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 + { + int i = this->search (tag); + if (i != -1) { + if (index) *index = i; + return true; + } else { + 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 RangeRecord +{ + inline int cmp (hb_codepoint_t g) const { + hb_codepoint_t a = start, b = end; + return g < a ? -1 : g <= b ? 0 : +1 ; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this); + } + + GlyphID start; /* First GlyphID in the range */ + GlyphID end; /* Last GlyphID in the range */ + USHORT value; /* Value */ + public: + DEFINE_SIZE_STATIC (6); +}; +DEFINE_NULL_DATA (RangeRecord, "\000\001"); + + +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); + } + + 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; } + + /* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and + * higher 16-bit is mark-filtering-set if the lookup uses one. + * Not to be confused with glyph_props which is very similar. */ + inline uint32_t get_props (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 + { + int i = glyphArray.search (glyph_id); + if (i != -1) + 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 */ + SortedArrayOf<GlyphID> + glyphArray; /* Array of GlyphIDs--in numerical order */ + public: + DEFINE_SIZE_ARRAY (4, glyphArray); +}; + +struct CoverageFormat2 +{ + friend struct Coverage; + + private: + inline unsigned int get_coverage (hb_codepoint_t glyph_id) const + { + int i = rangeRecord.search (glyph_id); + if (i != -1) { + const RangeRecord &range = rangeRecord[i]; + return (unsigned int) range.value + (glyph_id - range.start); + } + return NOT_COVERED; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return rangeRecord.sanitize (c); + } + + private: + USHORT coverageFormat; /* Format identifier--format = 2 */ + SortedArrayOf<RangeRecord> + 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 unsigned int 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 ClassDefFormat2 +{ + friend struct ClassDef; + + private: + inline unsigned int get_class (hb_codepoint_t glyph_id) const + { + int i = rangeRecord.search (glyph_id); + if (i != -1) + return rangeRecord[i].value; + return 0; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return rangeRecord.sanitize (c); + } + + USHORT classFormat; /* Format identifier--format = 2 */ + SortedArrayOf<RangeRecord> + rangeRecord; /* Array of glyph ranges--ordered by + * Start GlyphID */ + public: + DEFINE_SIZE_ARRAY (4, rangeRecord); +}; + +struct ClassDef +{ + inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); } + + inline unsigned int get_class (hb_codepoint_t glyph_id) const + { + switch (u.format) { + 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 +{ + + inline hb_position_t get_x_delta (hb_ot_layout_context_t *c) const + { return get_delta (c->font->x_ppem, c->font->x_scale); } + + inline hb_position_t get_y_delta (hb_ot_layout_context_t *c) const + { return get_delta (c->font->y_ppem, c->font->y_scale); } + + inline int get_delta (unsigned int ppem, unsigned int scale) const + { + if (!ppem) return 0; + + int pixels = get_delta_pixels (ppem); + + if (!pixels) return 0; + + /* pixels is at most in the -8..7 range. So 64-bit arithmetic is + * not really necessary here. A simple cast to int may just work + * as well. But since this code is not reached that often and + * for the sake of correctness, we do a 64bit operation. */ + return pixels * (int64_t) scale / ppem; + } + + + inline int get_delta_pixels (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 (void) 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); +}; + + +HB_BEGIN_DECLS +HB_END_DECLS + +#endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-private.hh new file mode 100644 index 0000000..4172a7c --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-private.hh @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google 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.h" + +HB_BEGIN_DECLS + + +/* + * 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_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? c->scale_x (coordinate) : c->scale_y (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_direction_t direction, hb_codepoint_t glyph_id) const + { + hb_position_t x, y; + if (hb_font_get_contour_point (c->font, c->face, caretValuePoint, glyph_id, &x, &y)) + return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; + 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_direction_t direction, hb_codepoint_t glyph_id) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? + c->scale_x (coordinate) + (this+deviceTable).get_x_delta (c) : + c->scale_y (coordinate) + (this+deviceTable).get_y_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_direction_t direction, hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.get_caret_value (c, direction, glyph_id); + case 2: return u.format2.get_caret_value (c, direction, glyph_id); + case 3: return u.format3.get_caret_value (c, direction, 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_direction_t direction, + 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, direction, 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_direction_t direction, + 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, direction, 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 (void) const { return glyphClassDef != 0; } + inline unsigned int get_glyph_class (hb_codepoint_t glyph) const + { return (this+glyphClassDef).get_class (glyph); } + + inline bool has_mark_attachment_types (void) const { return markAttachClassDef != 0; } + inline unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const + { return (this+markAttachClassDef).get_class (glyph); } + + inline bool has_attach_points (void) const { return attachList != 0; } + inline unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const + { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); } + + inline bool has_lig_carets (void) const { return ligCaretList != 0; } + inline unsigned int get_lig_carets (hb_ot_layout_context_t *c, + hb_direction_t direction, + 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, direction, glyph_id, start_offset, caret_count, caret_array); } + + inline bool has_mark_sets (void) 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)); + } + + + /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing + * glyph class and other bits, and high 8-bit gthe mark attachment type (if any). + * Not to be confused with lookup_props which is very similar. */ + inline unsigned int get_glyph_props (hb_codepoint_t glyph) const + { + unsigned int klass = get_glyph_class (glyph); + + switch (klass) { + default: + case UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; + case BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH; + case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE; + case ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT; + case MarkGlyph: + klass = get_mark_attachment_type (glyph); + return HB_OT_LAYOUT_GLYPH_CLASS_MARK | (klass << 8); + } + } + + + 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); +}; + + +HB_END_DECLS + +#endif /* HB_OT_LAYOUT_GDEF_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-private.hh new file mode 100644 index 0000000..11bb286 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-private.hh @@ -0,0 +1,1588 @@ +/* + * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH +#define HB_OT_LAYOUT_GPOS_PRIVATE_HH + +#include "hb-ot-layout-gsubgpos-private.hh" + +HB_BEGIN_DECLS + + +/* buffer var allocations */ +#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */ +#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */ + + +/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */ + +typedef USHORT Value; + +typedef Value ValueRecord[VAR]; + +struct ValueFormat : USHORT +{ + enum + { + xPlacement = 0x0001, /* Includes horizontal adjustment for placement */ + yPlacement = 0x0002, /* Includes vertical adjustment for placement */ + xAdvance = 0x0004, /* Includes horizontal adjustment for advance */ + yAdvance = 0x0008, /* Includes vertical adjustment for advance */ + xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */ + yPlaDevice = 0x0020, /* Includes vertical Device table for placement */ + xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */ + yAdvDevice = 0x0080, /* Includes vertical Device table for advance */ + ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */ + reserved = 0xF000, /* For future use */ + + devices = 0x00F0 /* Mask for having any Device table */ + }; + +/* All fields are options. Only those available advance the value pointer. */ +#if 0 + SHORT xPlacement; /* Horizontal adjustment for + * placement--in design units */ + SHORT yPlacement; /* Vertical adjustment for + * placement--in design units */ + SHORT xAdvance; /* Horizontal adjustment for + * advance--in design units (only used + * for horizontal writing) */ + SHORT yAdvance; /* Vertical adjustment for advance--in + * design units (only used for vertical + * writing) */ + Offset xPlaDevice; /* Offset to Device table for + * horizontal placement--measured from + * beginning of PosTable (may be NULL) */ + Offset yPlaDevice; /* Offset to Device table for vertical + * placement--measured from beginning + * of PosTable (may be NULL) */ + Offset xAdvDevice; /* Offset to Device table for + * horizontal advance--measured from + * beginning of PosTable (may be NULL) */ + Offset yAdvDevice; /* Offset to Device table for vertical + * advance--measured from beginning of + * PosTable (may be NULL) */ +#endif + + inline unsigned int get_len (void) const + { return _hb_popcount32 ((unsigned int) *this); } + inline unsigned int get_size (void) const + { return get_len () * Value::static_size; } + + void apply_value (hb_ot_layout_context_t *layout, + const void *base, + const Value *values, + hb_glyph_position_t &glyph_pos) const + { + unsigned int x_ppem, y_ppem; + unsigned int format = *this; + + if (!format) return; + + /* design units -> fractional pixel */ + if (format & xPlacement) glyph_pos.x_offset += layout->scale_x (get_short (values++)); + if (format & yPlacement) glyph_pos.y_offset += layout->scale_y (get_short (values++)); + if (format & xAdvance) glyph_pos.x_advance += layout->scale_x (get_short (values++)); + if (format & yAdvance) glyph_pos.y_advance += layout->scale_y (get_short (values++)); + + if (!has_device ()) return; + + x_ppem = layout->font->x_ppem; + y_ppem = layout->font->y_ppem; + + if (!x_ppem && !y_ppem) return; + + /* pixel -> fractional pixel */ + if (format & xPlaDevice) { + if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (layout); else values++; + } + if (format & yPlaDevice) { + if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (layout); else values++; + } + if (format & xAdvDevice) { + if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (layout); else values++; + } + if (format & yAdvDevice) { + if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_delta (layout); else values++; + } + } + + private: + inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) { + unsigned int format = *this; + + if (format & xPlacement) values++; + if (format & yPlacement) values++; + if (format & xAdvance) values++; + if (format & yAdvance) values++; + + if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false; + if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false; + + return true; + } + + static inline OffsetTo<Device>& get_device (Value* value) + { return *CastP<OffsetTo<Device> > (value); } + static inline const OffsetTo<Device>& get_device (const Value* value) + { return *CastP<OffsetTo<Device> > (value); } + + static inline const SHORT& get_short (const Value* value) + { return *CastP<SHORT> (value); } + + public: + + inline bool has_device (void) const { + unsigned int format = *this; + return (format & devices) != 0; + } + + inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) { + TRACE_SANITIZE (); + return c->check_range (values, get_size ()) + && (!has_device () || sanitize_value_devices (c, base, values)); + } + + inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) { + TRACE_SANITIZE (); + unsigned int len = get_len (); + + if (!c->check_array (values, get_size (), count)) return false; + + if (!has_device ()) return true; + + for (unsigned int i = 0; i < count; i++) { + if (!sanitize_value_devices (c, base, values)) + return false; + values += len; + } + + return true; + } + + /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ + inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) { + TRACE_SANITIZE (); + + if (!has_device ()) return true; + + for (unsigned int i = 0; i < count; i++) { + if (!sanitize_value_devices (c, base, values)) + return false; + values += stride; + } + + return true; + } +}; + + +struct AnchorFormat1 +{ + friend struct Anchor; + + private: + inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED, + hb_position_t *x, hb_position_t *y) const + { + *x = layout->scale_x (xCoordinate); + *y = layout->scale_y (yCoordinate); + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + SHORT xCoordinate; /* Horizontal value--in design units */ + SHORT yCoordinate; /* Vertical value--in design units */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct AnchorFormat2 +{ + friend struct Anchor; + + private: + inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id, + hb_position_t *x, hb_position_t *y) const + { + unsigned int x_ppem = layout->font->x_ppem; + unsigned int y_ppem = layout->font->y_ppem; + hb_position_t cx, cy; + hb_bool_t ret = false; + + if (x_ppem || y_ppem) + ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy); + *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate); + *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate); + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this); + } + + private: + USHORT format; /* Format identifier--format = 2 */ + SHORT xCoordinate; /* Horizontal value--in design units */ + SHORT yCoordinate; /* Vertical value--in design units */ + USHORT anchorPoint; /* Index to glyph contour point */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct AnchorFormat3 +{ + friend struct Anchor; + + private: + inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED, + hb_position_t *x, hb_position_t *y) const + { + *x = layout->scale_x (xCoordinate); + *y = layout->scale_y (yCoordinate); + + /* pixel -> fractional pixel */ + if (layout->font->x_ppem) + *x += (this+xDeviceTable).get_x_delta (layout); + if (layout->font->y_ppem) + *y += (this+yDeviceTable).get_x_delta (layout); + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) + && xDeviceTable.sanitize (c, this) + && yDeviceTable.sanitize (c, this); + } + + private: + USHORT format; /* Format identifier--format = 3 */ + SHORT xCoordinate; /* Horizontal value--in design units */ + SHORT yCoordinate; /* Vertical value--in design units */ + OffsetTo<Device> + xDeviceTable; /* Offset to Device table for X + * coordinate-- from beginning of + * Anchor table (may be NULL) */ + OffsetTo<Device> + yDeviceTable; /* Offset to Device table for Y + * coordinate-- from beginning of + * Anchor table (may be NULL) */ + public: + DEFINE_SIZE_STATIC (10); +}; + +struct Anchor +{ + inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id, + hb_position_t *x, hb_position_t *y) const + { + *x = *y = 0; + switch (u.format) { + case 1: u.format1.get_anchor (layout, glyph_id, x, y); return; + case 2: u.format2.get_anchor (layout, glyph_id, x, y); return; + case 3: u.format3.get_anchor (layout, glyph_id, x, y); return; + default: return; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!u.format.sanitize (c)) return false; + switch (u.format) { + case 1: return u.format1.sanitize (c); + case 2: return u.format2.sanitize (c); + case 3: return u.format3.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT format; /* Format identifier */ + AnchorFormat1 format1; + AnchorFormat2 format2; + AnchorFormat3 format3; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + + +struct AnchorMatrix +{ + inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const { + if (unlikely (row >= rows || col >= cols)) return Null(Anchor); + return this+matrix[row * cols + col]; + } + + inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) { + TRACE_SANITIZE (); + if (!c->check_struct (this)) return false; + if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false; + unsigned int count = rows * cols; + if (!c->check_array (matrix, matrix[0].static_size, count)) return false; + for (unsigned int i = 0; i < count; i++) + if (!matrix[i].sanitize (c, this)) return false; + return true; + } + + USHORT rows; /* Number of rows */ + private: + OffsetTo<Anchor> + matrix[VAR]; /* Matrix of offsets to Anchor tables-- + * from beginning of AnchorMatrix table */ + public: + DEFINE_SIZE_ARRAY (2, matrix); +}; + + +struct MarkRecord +{ + friend struct MarkArray; + + inline bool sanitize (hb_sanitize_context_t *c, void *base) { + TRACE_SANITIZE (); + return c->check_struct (this) + && markAnchor.sanitize (c, base); + } + + private: + USHORT klass; /* Class defined for this mark */ + OffsetTo<Anchor> + markAnchor; /* Offset to Anchor table--from + * beginning of MarkArray table */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */ +{ + inline bool apply (hb_apply_context_t *c, + unsigned int mark_index, unsigned int glyph_index, + const AnchorMatrix &anchors, unsigned int class_count, + unsigned int glyph_pos) const + { + TRACE_APPLY (); + const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index); + unsigned int mark_class = record.klass; + + const Anchor& mark_anchor = this + record.markAnchor; + const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count); + + hb_position_t mark_x, mark_y, base_x, base_y; + + mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y); + glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y); + + hb_glyph_position_t &o = c->buffer->pos[c->buffer->i]; + o.x_offset = base_x - mark_x; + o.y_offset = base_y - mark_y; + o.attach_lookback() = c->buffer->i - glyph_pos; + + c->buffer->i++; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return ArrayOf<MarkRecord>::sanitize (c, this); + } +}; + + +/* Lookups */ + +struct SinglePosFormat1 +{ + friend struct SinglePos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) + return false; + + valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->i]); + + c->buffer->i++; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) + && coverage.sanitize (c, this) + && valueFormat.sanitize_value (c, this, values); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + OffsetTo<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat; /* Defines the types of data in the + * ValueRecord */ + ValueRecord values; /* Defines positioning + * value(s)--applied to all glyphs in + * the Coverage table */ + public: + DEFINE_SIZE_ARRAY (6, values); +}; + +struct SinglePosFormat2 +{ + friend struct SinglePos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) + return false; + + if (likely (index >= valueCount)) + return false; + + valueFormat.apply_value (c->layout, this, + &values[index * valueFormat.get_len ()], + c->buffer->pos[c->buffer->i]); + + c->buffer->i++; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) + && coverage.sanitize (c, this) + && valueFormat.sanitize_values (c, this, values, valueCount); + } + + private: + USHORT format; /* Format identifier--format = 2 */ + OffsetTo<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat; /* Defines the types of data in the + * ValueRecord */ + USHORT valueCount; /* Number of ValueRecords */ + ValueRecord values; /* Array of ValueRecords--positioning + * values applied to glyphs */ + public: + DEFINE_SIZE_ARRAY (8, values); +}; + +struct SinglePos +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + switch (u.format) { + case 1: return u.format1.apply (c); + case 2: return u.format2.apply (c); + default:return false; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!u.format.sanitize (c)) return false; + switch (u.format) { + case 1: return u.format1.sanitize (c); + case 2: return u.format2.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT format; /* Format identifier */ + SinglePosFormat1 format1; + SinglePosFormat2 format2; + } u; +}; + + +struct PairValueRecord +{ + friend struct PairSet; + + private: + GlyphID secondGlyph; /* GlyphID of second glyph in the + * pair--first glyph is listed in the + * Coverage table */ + ValueRecord values; /* Positioning data for the first glyph + * followed by for second glyph */ + public: + DEFINE_SIZE_ARRAY (2, values); +}; + +struct PairSet +{ + friend struct PairPosFormat1; + + inline bool apply (hb_apply_context_t *c, + const ValueFormat *valueFormats, + unsigned int pos) const + { + TRACE_APPLY (); + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = USHORT::static_size * (1 + len1 + len2); + + unsigned int count = len; + const PairValueRecord *record = CastP<PairValueRecord> (array); + for (unsigned int i = 0; i < count; i++) + { + if (c->buffer->info[pos].codepoint == record->secondGlyph) + { + valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->pos[c->buffer->i]); + valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->pos[pos]); + if (len2) + pos++; + c->buffer->i = pos; + return true; + } + record = &StructAtOffset<PairValueRecord> (record, record_size); + } + + return false; + } + + struct sanitize_closure_t { + void *base; + ValueFormat *valueFormats; + unsigned int len1; /* valueFormats[0].get_len() */ + unsigned int stride; /* 1 + len1 + len2 */ + }; + + inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) { + TRACE_SANITIZE (); + if (!(c->check_struct (this) + && c->check_array (array, USHORT::static_size * closure->stride, len))) return false; + + unsigned int count = len; + PairValueRecord *record = CastP<PairValueRecord> (array); + return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) + && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride); + } + + private: + USHORT len; /* Number of PairValueRecords */ + USHORT array[VAR]; /* Array of PairValueRecords--ordered + * by GlyphID of the second glyph */ + public: + DEFINE_SIZE_ARRAY (2, array); +}; + +struct PairPosFormat1 +{ + friend struct PairPos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); + if (unlikely (c->buffer->i + 2 > end)) + return false; + + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) + return false; + + unsigned int j = c->buffer->i + 1; + while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL)) + { + if (unlikely (j == end)) + return false; + j++; + } + + return (this+pairSet[index]).apply (c, &valueFormat1, j); + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + + unsigned int len1 = valueFormat1.get_len (); + unsigned int len2 = valueFormat2.get_len (); + PairSet::sanitize_closure_t closure = { + this, + &valueFormat1, + len1, + 1 + len1 + len2 + }; + + return c->check_struct (this) + && coverage.sanitize (c, this) + && pairSet.sanitize (c, this, &closure); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + OffsetTo<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat1; /* Defines the types of data in + * ValueRecord1--for the first glyph + * in the pair--may be zero (0) */ + ValueFormat valueFormat2; /* Defines the types of data in + * ValueRecord2--for the second glyph + * in the pair--may be zero (0) */ + OffsetArrayOf<PairSet> + pairSet; /* Array of PairSet tables + * ordered by Coverage Index */ + public: + DEFINE_SIZE_ARRAY (10, pairSet); +}; + +struct PairPosFormat2 +{ + friend struct PairPos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); + if (unlikely (c->buffer->i + 2 > end)) + return false; + + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (index == NOT_COVERED)) + return false; + + unsigned int j = c->buffer->i + 1; + while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL)) + { + if (unlikely (j == end)) + return false; + j++; + } + + unsigned int len1 = valueFormat1.get_len (); + unsigned int len2 = valueFormat2.get_len (); + unsigned int record_len = len1 + len2; + + unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint); + unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint); + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) + return false; + + const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; + valueFormat1.apply_value (c->layout, this, v, c->buffer->pos[c->buffer->i]); + valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->pos[j]); + + if (len2) + j++; + c->buffer->i = j; + + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!(c->check_struct (this) + && coverage.sanitize (c, this) + && classDef1.sanitize (c, this) + && classDef2.sanitize (c, this))) return false; + + unsigned int len1 = valueFormat1.get_len (); + unsigned int len2 = valueFormat2.get_len (); + unsigned int stride = len1 + len2; + unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); + unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; + return c->check_array (values, record_size, count) && + valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride); + } + + private: + USHORT format; /* Format identifier--format = 2 */ + OffsetTo<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ValueFormat valueFormat1; /* ValueRecord definition--for the + * first glyph of the pair--may be zero + * (0) */ + ValueFormat valueFormat2; /* ValueRecord definition--for the + * second glyph of the pair--may be + * zero (0) */ + OffsetTo<ClassDef> + classDef1; /* Offset to ClassDef table--from + * beginning of PairPos subtable--for + * the first glyph of the pair */ + OffsetTo<ClassDef> + classDef2; /* Offset to ClassDef table--from + * beginning of PairPos subtable--for + * the second glyph of the pair */ + USHORT class1Count; /* Number of classes in ClassDef1 + * table--includes Class0 */ + USHORT class2Count; /* Number of classes in ClassDef2 + * table--includes Class0 */ + ValueRecord values; /* Matrix of value pairs: + * class1-major, class2-minor, + * Each entry has value1 and value2 */ + public: + DEFINE_SIZE_ARRAY (16, values); +}; + +struct PairPos +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + switch (u.format) { + case 1: return u.format1.apply (c); + case 2: return u.format2.apply (c); + default:return false; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!u.format.sanitize (c)) return false; + switch (u.format) { + case 1: return u.format1.sanitize (c); + case 2: return u.format2.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT format; /* Format identifier */ + PairPosFormat1 format1; + PairPosFormat2 format2; + } u; +}; + + +struct EntryExitRecord +{ + friend struct CursivePosFormat1; + + inline bool sanitize (hb_sanitize_context_t *c, void *base) { + TRACE_SANITIZE (); + return entryAnchor.sanitize (c, base) + && exitAnchor.sanitize (c, base); + } + + private: + OffsetTo<Anchor> + entryAnchor; /* Offset to EntryAnchor table--from + * beginning of CursivePos + * subtable--may be NULL */ + OffsetTo<Anchor> + exitAnchor; /* Offset to ExitAnchor table--from + * beginning of CursivePos + * subtable--may be NULL */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct CursivePosFormat1 +{ + friend struct CursivePos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + + /* We don't handle mark glyphs here. */ + if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) + return false; + + unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); + if (unlikely (c->buffer->i + 2 > end)) + return false; + + const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)]; + if (!this_record.exitAnchor) + return false; + + unsigned int j = c->buffer->i + 1; + while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL)) + { + if (unlikely (j == end)) + return false; + j++; + } + + const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[j].codepoint)]; + if (!next_record.entryAnchor) + return false; + + unsigned int i = c->buffer->i; + + hb_position_t entry_x, entry_y, exit_x, exit_y; + (this+this_record.exitAnchor).get_anchor (c->layout, c->buffer->info[i].codepoint, &exit_x, &exit_y); + (this+next_record.entryAnchor).get_anchor (c->layout, c->buffer->info[j].codepoint, &entry_x, &entry_y); + + hb_direction_t direction = c->buffer->props.direction; + + /* Align the exit anchor of the left/top glyph with the entry anchor of the right/bottom glyph + * by adjusting advance of the left/top glyph. */ + if (HB_DIRECTION_IS_BACKWARD (direction)) + { + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) + c->buffer->pos[j].x_advance = c->buffer->pos[j].x_offset + entry_x - exit_x; + else + c->buffer->pos[j].y_advance = c->buffer->pos[j].y_offset + entry_y - exit_y; + } + else + { + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) + c->buffer->pos[i].x_advance = c->buffer->pos[i].x_offset + exit_x - entry_x; + else + c->buffer->pos[i].y_advance = c->buffer->pos[i].y_offset + exit_y - entry_y; + } + + if (c->lookup_props & LookupFlag::RightToLeft) + { + c->buffer->pos[i].cursive_chain() = j - i; + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) + c->buffer->pos[i].y_offset = entry_y - exit_y; + else + c->buffer->pos[i].x_offset = entry_x - exit_x; + } + else + { + c->buffer->pos[j].cursive_chain() = i - j; + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) + c->buffer->pos[j].y_offset = exit_y - entry_y; + else + c->buffer->pos[j].x_offset = exit_x - entry_x; + } + + c->buffer->i = j; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return coverage.sanitize (c, this) + && entryExitRecord.sanitize (c, this); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + OffsetTo<Coverage> + coverage; /* Offset to Coverage table--from + * beginning of subtable */ + ArrayOf<EntryExitRecord> + entryExitRecord; /* Array of EntryExit records--in + * Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (6, entryExitRecord); +}; + +struct CursivePos +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + switch (u.format) { + case 1: return u.format1.apply (c); + default:return false; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!u.format.sanitize (c)) return false; + switch (u.format) { + case 1: return u.format1.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT format; /* Format identifier */ + CursivePosFormat1 format1; + } u; +}; + + +typedef AnchorMatrix BaseArray; /* base-major-- + * in order of BaseCoverage Index--, + * mark-minor-- + * ordered by class--zero-based. */ + +struct MarkBasePosFormat1 +{ + friend struct MarkBasePos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (mark_index == NOT_COVERED)) + return false; + + /* now we search backwards for a non-mark glyph */ + unsigned int property; + unsigned int j = c->buffer->i; + do + { + if (unlikely (!j)) + return false; + j--; + } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property)); + + /* The following assertion is too strong, so we've disabled it. */ + if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) + {/*return false;*/} + + unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint); + if (base_index == NOT_COVERED) + return false; + + return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j); + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) + && markCoverage.sanitize (c, this) + && baseCoverage.sanitize (c, this) + && markArray.sanitize (c, this) + && baseArray.sanitize (c, this, (unsigned int) classCount); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + OffsetTo<Coverage> + markCoverage; /* Offset to MarkCoverage table--from + * beginning of MarkBasePos subtable */ + OffsetTo<Coverage> + baseCoverage; /* Offset to BaseCoverage table--from + * beginning of MarkBasePos subtable */ + USHORT classCount; /* Number of classes defined for marks */ + OffsetTo<MarkArray> + markArray; /* Offset to MarkArray table--from + * beginning of MarkBasePos subtable */ + OffsetTo<BaseArray> + baseArray; /* Offset to BaseArray table--from + * beginning of MarkBasePos subtable */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct MarkBasePos +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + switch (u.format) { + case 1: return u.format1.apply (c); + default:return false; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!u.format.sanitize (c)) return false; + switch (u.format) { + case 1: return u.format1.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT format; /* Format identifier */ + MarkBasePosFormat1 format1; + } u; +}; + + +typedef AnchorMatrix LigatureAttach; /* component-major-- + * in order of writing direction--, + * mark-minor-- + * ordered by class--zero-based. */ + +typedef OffsetListOf<LigatureAttach> LigatureArray; + /* Array of LigatureAttach + * tables ordered by + * LigatureCoverage Index */ + +struct MarkLigPosFormat1 +{ + friend struct MarkLigPos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (mark_index == NOT_COVERED)) + return false; + + /* now we search backwards for a non-mark glyph */ + unsigned int property; + unsigned int j = c->buffer->i; + do + { + if (unlikely (!j)) + return false; + j--; + } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property)); + + /* The following assertion is too strong, so we've disabled it. */ + if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) + {/*return false;*/} + + unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint); + if (lig_index == NOT_COVERED) + return false; + + const LigatureArray& lig_array = this+ligatureArray; + const LigatureAttach& lig_attach = lig_array[lig_index]; + + /* Find component to attach to */ + unsigned int comp_count = lig_attach.rows; + if (unlikely (!comp_count)) + return false; + unsigned int comp_index; + /* We must now check whether the ligature ID of the current mark glyph + * is identical to the ligature ID of the found ligature. If yes, we + * can directly use the component index. If not, we attach the mark + * glyph to the last component of the ligature. */ + if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->i].lig_id() && c->buffer->info[c->buffer->i].lig_comp()) + { + comp_index = c->buffer->info[c->buffer->i].lig_comp() - 1; + if (comp_index >= comp_count) + comp_index = comp_count - 1; + } + else + comp_index = comp_count - 1; + + return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j); + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) + && markCoverage.sanitize (c, this) + && ligatureCoverage.sanitize (c, this) + && markArray.sanitize (c, this) + && ligatureArray.sanitize (c, this, (unsigned int) classCount); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + OffsetTo<Coverage> + markCoverage; /* Offset to Mark Coverage table--from + * beginning of MarkLigPos subtable */ + OffsetTo<Coverage> + ligatureCoverage; /* Offset to Ligature Coverage + * table--from beginning of MarkLigPos + * subtable */ + USHORT classCount; /* Number of defined mark classes */ + OffsetTo<MarkArray> + markArray; /* Offset to MarkArray table--from + * beginning of MarkLigPos subtable */ + OffsetTo<LigatureArray> + ligatureArray; /* Offset to LigatureArray table--from + * beginning of MarkLigPos subtable */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct MarkLigPos +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + switch (u.format) { + case 1: return u.format1.apply (c); + default:return false; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!u.format.sanitize (c)) return false; + switch (u.format) { + case 1: return u.format1.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT format; /* Format identifier */ + MarkLigPosFormat1 format1; + } u; +}; + + +typedef AnchorMatrix Mark2Array; /* mark2-major-- + * in order of Mark2Coverage Index--, + * mark1-minor-- + * ordered by class--zero-based. */ + +struct MarkMarkPosFormat1 +{ + friend struct MarkMarkPos; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint); + if (likely (mark1_index == NOT_COVERED)) + return false; + + /* now we search backwards for a suitable mark glyph until a non-mark glyph */ + unsigned int property; + unsigned int j = c->buffer->i; + do + { + if (unlikely (!j)) + return false; + j--; + } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, &property)); + + if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) + return false; + + /* Two marks match only if they belong to the same base, or same component + * of the same ligature. That is, the component numbers must match, and + * if those are non-zero, the ligid number should also match. */ + if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->i].lig_comp()) || + (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->i].lig_id())) + return false; + + unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint); + if (mark2_index == NOT_COVERED) + return false; + + return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j); + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) + && mark1Coverage.sanitize (c, this) + && mark2Coverage.sanitize (c, this) + && mark1Array.sanitize (c, this) + && mark2Array.sanitize (c, this, (unsigned int) classCount); + } + + private: + USHORT format; /* Format identifier--format = 1 */ + OffsetTo<Coverage> + mark1Coverage; /* Offset to Combining Mark1 Coverage + * table--from beginning of MarkMarkPos + * subtable */ + OffsetTo<Coverage> + mark2Coverage; /* Offset to Combining Mark2 Coverage + * table--from beginning of MarkMarkPos + * subtable */ + USHORT classCount; /* Number of defined mark classes */ + OffsetTo<MarkArray> + mark1Array; /* Offset to Mark1Array table--from + * beginning of MarkMarkPos subtable */ + OffsetTo<Mark2Array> + mark2Array; /* Offset to Mark2Array table--from + * beginning of MarkMarkPos subtable */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct MarkMarkPos +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + switch (u.format) { + case 1: return u.format1.apply (c); + default:return false; + } + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (!u.format.sanitize (c)) return false; + switch (u.format) { + case 1: return u.format1.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT format; /* Format identifier */ + MarkMarkPosFormat1 format1; + } u; +}; + + +HB_BEGIN_DECLS +static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index); +HB_END_DECLS + +struct ContextPos : Context +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + return Context::apply (c, position_lookup); + } +}; + +struct ChainContextPos : ChainContext +{ + friend struct PosLookupSubTable; + + private: + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (); + return ChainContext::apply (c, position_lookup); + } +}; + + +struct ExtensionPos : Extension +{ + friend struct PosLookupSubTable; + + private: + inline const struct PosLookupSubTable& get_subtable (void) const + { + unsigned int offset = get_offset (); + if (unlikely (!offset)) return Null(PosLookupSubTable); + return StructAtOffset<PosLookupSubTable> (this, offset); + } + + inline bool apply (hb_apply_context_t *c) const; + + inline bool sanitize (hb_sanitize_context_t *c); +}; + + + +/* + * PosLookup + */ + + +struct PosLookupSubTable +{ + friend struct PosLookup; + + enum { + Single = 1, + Pair = 2, + Cursive = 3, + MarkBase = 4, + MarkLig = 5, + MarkMark = 6, + Context = 7, + ChainContext = 8, + Extension = 9 + }; + + inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const + { + TRACE_APPLY (); + switch (lookup_type) { + case Single: return u.single.apply (c); + case Pair: return u.pair.apply (c); + case Cursive: return u.cursive.apply (c); + case MarkBase: return u.markBase.apply (c); + case MarkLig: return u.markLig.apply (c); + case MarkMark: return u.markMark.apply (c); + case Context: return u.c.apply (c); + case ChainContext: return u.chainContext.apply (c); + case Extension: return u.extension.apply (c); + default:return false; + } + } + + inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { + TRACE_SANITIZE (); + switch (lookup_type) { + case Single: return u.single.sanitize (c); + case Pair: return u.pair.sanitize (c); + case Cursive: return u.cursive.sanitize (c); + case MarkBase: return u.markBase.sanitize (c); + case MarkLig: return u.markLig.sanitize (c); + case MarkMark: return u.markMark.sanitize (c); + case Context: return u.c.sanitize (c); + case ChainContext: return u.chainContext.sanitize (c); + case Extension: return u.extension.sanitize (c); + default:return true; + } + } + + private: + union { + USHORT sub_format; + SinglePos single; + PairPos pair; + CursivePos cursive; + MarkBasePos markBase; + MarkLigPos markLig; + MarkMarkPos markMark; + ContextPos c; + ChainContextPos chainContext; + ExtensionPos extension; + } u; + public: + DEFINE_SIZE_UNION (2, sub_format); +}; + + +struct PosLookup : Lookup +{ + inline const PosLookupSubTable& get_subtable (unsigned int i) const + { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; } + + inline bool apply_once (hb_ot_layout_context_t *layout, + hb_buffer_t *buffer, + hb_mask_t lookup_mask, + unsigned int context_length, + unsigned int nesting_level_left) const + { + unsigned int lookup_type = get_type (); + hb_apply_context_t c[1] = {{0}}; + + c->layout = layout; + c->buffer = buffer; + c->lookup_mask = lookup_mask; + c->context_length = context_length; + c->nesting_level_left = nesting_level_left; + c->lookup_props = get_props (); + + if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property)) + return false; + + for (unsigned int i = 0; i < get_subtable_count (); i++) + if (get_subtable (i).apply (c, lookup_type)) + return true; + + return false; + } + + inline bool apply_string (hb_ot_layout_context_t *layout, + hb_buffer_t *buffer, + hb_mask_t mask) const + { + bool ret = false; + + if (unlikely (!buffer->len)) + return false; + + 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->i++; + } + + return ret; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (unlikely (!Lookup::sanitize (c))) return false; + OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable); + return list.sanitize (c, this, get_type ()); + } +}; + +typedef OffsetListOf<PosLookup> PosLookupList; + +/* + * GPOS + */ + +struct GPOS : GSUBGPOS +{ + static const hb_tag_t Tag = HB_OT_TAG_GPOS; + + inline const PosLookup& get_lookup (unsigned int i) const + { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } + + inline bool position_lookup (hb_ot_layout_context_t *layout, + hb_buffer_t *buffer, + unsigned int lookup_index, + hb_mask_t mask) const + { return get_lookup (lookup_index).apply_string (layout, buffer, mask); } + + static inline void position_finish (hb_buffer_t *buffer); + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + if (unlikely (!GSUBGPOS::sanitize (c))) return false; + OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); + return list.sanitize (c, this); + } + public: + DEFINE_SIZE_STATIC (10); +}; + +void +GPOS::position_finish (hb_buffer_t *buffer) +{ + unsigned int i, j; + unsigned int len = hb_buffer_get_length (buffer); + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer); + hb_direction_t direction = buffer->props.direction; + + /* Handle cursive connections: + * First handle all chain-back connections, then handle all chain-forward connections. */ + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) + { + for (j = 0; j < len; j++) { + if (pos[j].cursive_chain() < 0) + pos[j].y_offset += pos[j + pos[j].cursive_chain()].y_offset; + } + 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; + } + } + else + { + for (j = 0; j < len; j++) { + if (pos[j].cursive_chain() < 0) + pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset; + } + for (i = len; i > 0; i--) { + j = i - 1; + if (pos[j].cursive_chain() > 0) + pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset; + } + } + + + /* Handle attachments */ + for (i = 0; i < len; i++) + if (pos[i].attach_lookback()) + { + unsigned int back = i - pos[i].attach_lookback(); + pos[i].x_offset += pos[back].x_offset; + pos[i].y_offset += pos[back].y_offset; + + if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + 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; + } + } +} + + +/* Out-of-class implementation for methods recursing */ + +inline bool ExtensionPos::apply (hb_apply_context_t *c) const +{ + TRACE_APPLY (); + return get_subtable ().apply (c, get_type ()); +} + +inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c) +{ + TRACE_SANITIZE (); + if (unlikely (!Extension::sanitize (c))) return false; + unsigned int offset = get_offset (); + if (unlikely (!offset)) return true; + return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()); +} + +static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) +{ + const GPOS &gpos = *(c->layout->face->ot_layout->gpos); + const PosLookup &l = gpos.get_lookup (lookup_index); + + if (unlikely (c->nesting_level_left == 0)) + return false; + + if (unlikely (c->context_length < 1)) + return false; + + return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1); +} + + +#undef attach_lookback +#undef cursive_chain + + +HB_END_DECLS + +#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-private.hh new file mode 100644 index 0000000..ae1c5f3 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-private.hh @@ -0,0 +1,931 @@ +/* + * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google 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" + +HB_BEGIN_DECLS + + +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->replace_glyph (glyph_id); + + 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->replace_glyph (glyph_id); + + 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; + + if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE) + c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH); + c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array); + + 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->replace_glyph (glyph_id); + + 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) 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 (count < 2 || c->buffer->i + count > end)) + return false; + + bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK); + bool found_non_mark = 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_props, &property)) + { + if (unlikely (j + count - i == end)) + return false; + j++; + } + + found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK); + + if (likely (c->buffer->info[j].codepoint != component[i])) + return false; + } + + if (first_was_mark && found_non_mark) + c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE); + + /* Allocate new ligature id */ + unsigned int lig_id = allocate_lig_id (c->buffer); + c->buffer->info[c->buffer->i].lig_comp() = 0; + c->buffer->info[c->buffer->i].lig_id() = lig_id; + + if (j == c->buffer->i + i) /* No input glyphs skipped */ + { + c->replace_glyphs_be16 (i, 1, (const uint16_t *) &ligGlyph); + } + else + { + c->replace_glyph (ligGlyph); + + /* 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_props, NULL)) + { + c->buffer->info[c->buffer->i].lig_comp() = i; + c->buffer->info[c->buffer->i].lig_id() = lig_id; + c->replace_glyph (c->buffer->info[c->buffer->i].codepoint); + } + + /* Skip the base glyph */ + c->buffer->i++; + } + } + + return true; + } + + inline uint16_t allocate_lig_id (hb_buffer_t *buffer) const { + uint16_t lig_id = buffer->next_serial (); + if (unlikely (!lig_id)) lig_id = buffer->next_serial (); /* in case of overflows */ + return lig_id; + } + + 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) 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)) + 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; + + 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); + } + + 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; +}; + + +HB_BEGIN_DECLS +static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index); +HB_END_DECLS + +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_props = get_props (); + + if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, &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); +} + + +HB_END_DECLS + +#endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh new file mode 100644 index 0000000..c2b2eea --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh @@ -0,0 +1,981 @@ +/* + * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google 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" + +HB_BEGIN_DECLS + + +/* buffer var allocations */ +#define lig_id() var2.u16[0] /* unique ligature id */ +#define lig_comp() var2.u16[1] /* component number in the ligature (0 = base) */ + + +#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); \ + + +HB_BEGIN_DECLS + +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_props; + unsigned int property; /* propety of first glyph */ + + + inline void replace_glyph (hb_codepoint_t glyph_index) const + { + clear_property (); + buffer->replace_glyph (glyph_index); + } + inline void replace_glyphs_be16 (unsigned int num_in, + unsigned int num_out, + const uint16_t *glyph_data_be) const + { + clear_property (); + buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be); + } + + inline void guess_glyph_class (unsigned int klass) + { + /* XXX if ! has gdef */ + buffer->info[buffer->i].props_cache() = klass; + } + + private: + inline void clear_property (void) const + { + /* XXX if has gdef */ + buffer->info[buffer->i].props_cache() = 0; + } +}; + + + +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_props, 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_props, 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_props, 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; +} + +HB_END_DECLS + + +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); +}; + + +HB_BEGIN_DECLS + +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 (count == 0 || 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, it will underflow after the first loop + * and we jump out of it. Not entirely disastrous. So we don't check + * for reverse lookup here. + */ + for (unsigned int i = 0; i < count; /* NOP */) + { + while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, 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; +} + +HB_END_DECLS + + +/* 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]; + 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); + } + + 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]; + 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); + } + + 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); +}; + + +HB_END_DECLS + +#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh new file mode 100644 index 0000000..b0088fb --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh @@ -0,0 +1,114 @@ +/* + * 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_HH +#define HB_OT_LAYOUT_PRIVATE_HH + +#include "hb-private.h" + +#include "hb-ot-layout.h" +#include "hb-ot-head-private.hh" + +#include "hb-font-private.h" +#include "hb-buffer-private.hh" + +HB_BEGIN_DECLS + + +/* buffer var allocations */ +#define props_cache() var1.u16[1] /* glyph_props cache */ + + +/* XXX cleanup */ +typedef enum { + HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0001, + HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 0x0002, + HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 0x0004, + HB_OT_LAYOUT_GLYPH_CLASS_MARK = 0x0008, + HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 0x0010 +} hb_ot_layout_glyph_class_t; + + +/* + * 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 hb_ot_layout_context_t +{ + hb_face_t *face; + hb_font_t *font; + + /* Convert from font-space to user-space */ + inline hb_position_t scale_x (int16_t v) { return scale (v, this->font->x_scale); } + inline hb_position_t scale_y (int16_t v) { return scale (v, this->font->y_scale); } + + private: + inline hb_position_t scale (int16_t v, unsigned int scale) { return v * (int64_t) scale / this->face->head_table->get_upem (); } +}; + + +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 unsigned int +_hb_ot_layout_get_glyph_property (hb_face_t *face, + hb_glyph_info_t *info); + +HB_INTERNAL hb_bool_t +_hb_ot_layout_check_glyph_property (hb_face_t *face, + hb_glyph_info_t *ginfo, + unsigned int lookup_props, + unsigned int *property_out); + +HB_INTERNAL hb_bool_t +_hb_ot_layout_skip_mark (hb_face_t *face, + hb_glyph_info_t *ginfo, + unsigned int lookup_props, + unsigned int *property_out); + + +HB_END_DECLS + +#endif /* HB_OT_LAYOUT_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc new file mode 100644 index 0000000..fc4b1d3 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc @@ -0,0 +1,485 @@ +/* + * 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_BEGIN_DECLS + + +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); +} + +static inline const GDEF& +_get_gdef (hb_face_t *face) +{ + return likely (face->ot_layout && face->ot_layout->gdef) ? *face->ot_layout->gdef : Null(GDEF); +} + +static inline const GSUB& +_get_gsub (hb_face_t *face) +{ + return likely (face->ot_layout && face->ot_layout->gsub) ? *face->ot_layout->gsub : Null(GSUB); +} + +static inline const GPOS& +_get_gpos (hb_face_t *face) +{ + return likely (face->ot_layout && face->ot_layout->gpos) ? *face->ot_layout->gpos : Null(GPOS); +} + + +/* + * GDEF + */ + +hb_bool_t +hb_ot_layout_has_glyph_classes (hb_face_t *face) +{ + return _get_gdef (face).has_glyph_classes (); +} + +unsigned int +_hb_ot_layout_get_glyph_property (hb_face_t *face, + hb_glyph_info_t *info) +{ + if (!info->props_cache()) + { + const GDEF &gdef = _get_gdef (face); + info->props_cache() = gdef.get_glyph_props (info->codepoint); + } + + return info->props_cache(); +} + +static hb_bool_t +_hb_ot_layout_match_properties (hb_face_t *face, + hb_codepoint_t codepoint, + unsigned int glyph_props, + unsigned int lookup_props) +{ + /* Not covered, if, for example, glyph class is ligature and + * lookup_props includes LookupFlags::IgnoreLigatures + */ + if (glyph_props & lookup_props & LookupFlag::IgnoreFlags) + return false; + + if (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK) + { + /* If using mark filtering sets, the high short of + * lookup_props has the set index. + */ + if (lookup_props & LookupFlag::UseMarkFilteringSet) + return _get_gdef (face).mark_set_covers (lookup_props >> 16, codepoint); + + /* The second byte of lookup_props has the meaning + * "ignore marks of attachment type different than + * the attachment type specified." + */ + if (lookup_props & LookupFlag::MarkAttachmentType && glyph_props & LookupFlag::MarkAttachmentType) + return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType); + } + + return true; +} + +hb_bool_t +_hb_ot_layout_check_glyph_property (hb_face_t *face, + hb_glyph_info_t *ginfo, + unsigned int lookup_props, + unsigned int *property_out) +{ + unsigned int property; + + property = _hb_ot_layout_get_glyph_property (face, ginfo); + (void) (property_out && (*property_out = property)); + + return _hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props); +} + +hb_bool_t +_hb_ot_layout_skip_mark (hb_face_t *face, + hb_glyph_info_t *ginfo, + unsigned int lookup_props, + unsigned int *property_out) +{ + unsigned int property; + + property = _hb_ot_layout_get_glyph_property (face, ginfo); + (void) (property_out && (*property_out = property)); + + /* If it's a mark, skip it we don't accept it. */ + if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) + return !_hb_ot_layout_match_properties (face, ginfo->codepoint, property, lookup_props); + + /* If not a mark, don't skip. */ + return false; +} + + + +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_ligature_carets (hb_font_t *font, + hb_face_t *face, + hb_direction_t direction, + 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, direction, 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 :(. + * including many versions of DejaVu Sans Mono! */ + 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_buffer_t *buffer) +{ + GPOS::position_finish (buffer); +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.h b/third_party/harfbuzz-ng/src/hb-ot-layout.h new file mode 100644 index 0000000..9619eb7 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.h @@ -0,0 +1,196 @@ +/* + * 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 + */ + +hb_bool_t +hb_ot_layout_has_glyph_classes (hb_face_t *face); + +/* 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_ligature_carets (hb_font_t *font, + hb_face_t *face, + hb_direction_t direction, + 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_buffer_t *buffer); + + +HB_END_DECLS + +#endif /* HB_OT_LAYOUT_H */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-map-private.hh b/third_party/harfbuzz-ng/src/hb-ot-map-private.hh new file mode 100644 index 0000000..0a1d9f6 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-map-private.hh @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2009,2010 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_MAP_PRIVATE_HH +#define HB_OT_MAP_PRIVATE_HH + +#include "hb-buffer-private.hh" + +#include "hb-ot-layout.h" + +HB_BEGIN_DECLS + + +#define MAX_FEATURES 100 /* FIXME */ +#define MAX_LOOKUPS 1000 /* FIXME */ + +static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS}; + +struct hb_ot_map_t { + + private: + + struct feature_info_t { + hb_tag_t tag; + unsigned int seq; /* sequence#, used for stable sorting only */ + unsigned int max_value; + bool global; /* whether the feature applies value to every glyph in the buffer */ + unsigned int default_value; /* for non-global features, what should the unset glyphs take */ + + static int cmp (const feature_info_t *a, const feature_info_t *b) + { return (a->tag != b->tag) ? (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); } + }; + + struct feature_map_t { + hb_tag_t tag; /* should be first for our bsearch to work */ + unsigned int index[2]; /* GSUB, GPOS */ + unsigned int shift; + hb_mask_t mask; + hb_mask_t _1_mask; /* mask for value=1, for quick access */ + + static int cmp (const feature_map_t *a, const feature_map_t *b) + { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; } + }; + + struct lookup_map_t { + unsigned int index; + hb_mask_t mask; + + static int cmp (const lookup_map_t *a, const lookup_map_t *b) + { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; } + }; + + HB_INTERNAL void add_lookups (hb_face_t *face, + unsigned int table_index, + unsigned int feature_index, + hb_mask_t mask); + + + public: + + hb_ot_map_t (void) : feature_count (0) {} + + void add_feature (hb_tag_t tag, unsigned int value, bool global) + { + feature_info_t *info = &feature_infos[feature_count++]; + info->tag = tag; + info->seq = feature_count; + info->max_value = value; + info->global = global; + info->default_value = global ? value : 0; + } + + inline void add_bool_feature (hb_tag_t tag, bool global = true) + { add_feature (tag, 1, global); } + + HB_INTERNAL void compile (hb_face_t *face, + const hb_segment_properties_t *props); + + inline hb_mask_t get_global_mask (void) const { return global_mask; } + + inline hb_mask_t get_mask (hb_tag_t tag, unsigned int *shift = NULL) const { + const feature_map_t *map = (const feature_map_t *) bsearch (&tag, feature_maps, feature_count, sizeof (feature_maps[0]), (hb_compare_func_t) feature_map_t::cmp); + if (shift) *shift = map ? map->shift : 0; + return map ? map->mask : 0; + } + + inline hb_mask_t get_1_mask (hb_tag_t tag) const { + const feature_map_t *map = (const feature_map_t *) bsearch (&tag, feature_maps, feature_count, sizeof (feature_maps[0]), (hb_compare_func_t) feature_map_t::cmp); + return map ? map->_1_mask : 0; + } + + inline void substitute (hb_face_t *face, hb_buffer_t *buffer) const { + for (unsigned int i = 0; i < lookup_count[0]; i++) + hb_ot_layout_substitute_lookup (face, buffer, lookup_maps[0][i].index, lookup_maps[0][i].mask); + } + + inline void position (hb_font_t *font, hb_face_t *face, hb_buffer_t *buffer) const { + for (unsigned int i = 0; i < lookup_count[1]; i++) + hb_ot_layout_position_lookup (font, face, buffer, lookup_maps[1][i].index, lookup_maps[1][i].mask); + } + + private: + + hb_mask_t global_mask; + + unsigned int feature_count; + feature_info_t feature_infos[MAX_FEATURES]; /* used before compile() only */ + feature_map_t feature_maps[MAX_FEATURES]; + + lookup_map_t lookup_maps[2][MAX_LOOKUPS]; /* GSUB/GPOS */ + unsigned int lookup_count[2]; +}; + + + +HB_END_DECLS + +#endif /* HB_OT_MAP_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-map.cc b/third_party/harfbuzz-ng/src/hb-ot-map.cc new file mode 100644 index 0000000..ca96ba9 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-map.cc @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2009,2010 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-map-private.hh" + +#include "hb-ot-shape-private.hh" + +HB_BEGIN_DECLS + + +void +hb_ot_map_t::add_lookups (hb_face_t *face, + unsigned int table_index, + unsigned int feature_index, + hb_mask_t mask) +{ + unsigned int i = MAX_LOOKUPS - lookup_count[table_index]; + lookup_map_t *lookups = lookup_maps[table_index] + lookup_count[table_index]; + + unsigned int *lookup_indices = (unsigned int *) lookups; + + hb_ot_layout_feature_get_lookup_indexes (face, + table_tags[table_index], + feature_index, + 0, &i, + lookup_indices); + + lookup_count[table_index] += i; + + while (i--) { + lookups[i].mask = mask; + lookups[i].index = lookup_indices[i]; + } +} + + +void +hb_ot_map_t::compile (hb_face_t *face, + const hb_segment_properties_t *props) +{ + global_mask = 1; + lookup_count[0] = lookup_count[1] = 0; + + if (!feature_count) + return; + + + /* Fetch script/language indices for GSUB/GPOS. We need these later to skip + * features not available in either table and not waste precious bits for them. */ + + const hb_tag_t *script_tags; + hb_tag_t language_tag; + + script_tags = hb_ot_tags_from_script (props->script); + language_tag = hb_ot_tag_from_language (props->language); + + unsigned int script_index[2], language_index[2]; + for (unsigned int table_index = 0; table_index < 2; table_index++) { + hb_tag_t table_tag = table_tags[table_index]; + hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index]); + hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]); + } + + + /* Sort features and merge duplicates */ + qsort (feature_infos, feature_count, sizeof (feature_infos[0]), (hb_compare_func_t) feature_info_t::cmp); + unsigned int j = 0; + for (unsigned int i = 1; i < feature_count; i++) + if (feature_infos[i].tag != feature_infos[j].tag) + feature_infos[++j] = feature_infos[i]; + else { + if (feature_infos[i].global) + feature_infos[j] = feature_infos[i]; + else { + feature_infos[j].global = false; + feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value); + /* Inherit default_value from j */ + } + } + feature_count = j + 1; + + + /* Allocate bits now */ + unsigned int next_bit = 1; + j = 0; + for (unsigned int i = 0; i < feature_count; i++) { + const feature_info_t *info = &feature_infos[i]; + + unsigned int bits_needed; + + if (info->global && info->max_value == 1) + /* Uses the global bit */ + bits_needed = 0; + else + bits_needed = _hb_bit_storage (info->max_value); + + if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t)) + continue; /* Feature disabled, or not enough bits. */ + + + bool found = false; + unsigned int feature_index[2]; + for (unsigned int table_index = 0; table_index < 2; table_index++) + found |= hb_ot_layout_language_find_feature (face, + table_tags[table_index], + script_index[table_index], + language_index[table_index], + info->tag, + &feature_index[table_index]); + if (!found) + continue; + + + feature_map_t *map = &feature_maps[j++]; + + map->tag = info->tag; + map->index[0] = feature_index[0]; + map->index[1] = feature_index[1]; + if (info->global && info->max_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) + global_mask |= (info->default_value << map->shift) & map->mask; + } + map->_1_mask = (1 << map->shift) & map->mask; + + } + feature_count = j; + + + for (unsigned int table_index = 0; table_index < 2; table_index++) { + hb_tag_t table_tag = table_tags[table_index]; + + /* Collect lookup indices for features */ + + unsigned int required_feature_index; + if (hb_ot_layout_language_get_required_feature_index (face, + table_tag, + script_index[table_index], + language_index[table_index], + &required_feature_index)) + add_lookups (face, table_index, required_feature_index, 1); + + for (unsigned i = 0; i < feature_count; i++) + add_lookups (face, table_index, feature_maps[i].index[table_index], feature_maps[i].mask); + + /* Sort lookups and merge duplicates */ + qsort (lookup_maps[table_index], lookup_count[table_index], sizeof (lookup_maps[table_index][0]), (hb_compare_func_t) lookup_map_t::cmp); + if (lookup_count[table_index]) + { + unsigned int j = 0; + for (unsigned int i = 1; i < lookup_count[table_index]; i++) + if (lookup_maps[table_index][i].index != lookup_maps[table_index][j].index) + lookup_maps[table_index][++j] = lookup_maps[table_index][i]; + else + lookup_maps[table_index][j].mask |= lookup_maps[table_index][i].mask; + j++; + lookup_count[table_index] = j; + } + } +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.h b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.h new file mode 100644 index 0000000..523fc84 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.h @@ -0,0 +1,674 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_H +#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_H + +#include "hb-private.h" + +HB_BEGIN_DECLS + +/* == Start of generated table == */ +/* + * The following table is generated by running: + * + * ./gen-arabic-joining-table.py < ArabicShaping.txt + * + * on the ArabicShaping.txt file with the header: + * + * # ArabicShaping-6.1.0.txt + * # Date: 2010-11-09, 12:10:00 PST [KW] + */ +static const uint8_t joining_table[] = +{ + + /* Arabic characters */ + + JOINING_TYPE_U, /* 0600; ARABIC NUMBER SIGN; U; No_Joining_Group */ + JOINING_TYPE_U, /* 0601; ARABIC SIGN SANAH; U; No_Joining_Group */ + JOINING_TYPE_U, /* 0602; ARABIC FOOTNOTE MARKER; U; No_Joining_Group */ + JOINING_TYPE_U, /* 0603; ARABIC SIGN SAFHA; U; No_Joining_Group */ + JOINING_TYPE_X, /* 0604 */ + JOINING_TYPE_X, /* 0605 */ + JOINING_TYPE_X, /* 0606 */ + JOINING_TYPE_X, /* 0607 */ + JOINING_TYPE_U, /* 0608; ARABIC RAY; U; No_Joining_Group */ + JOINING_TYPE_X, /* 0609 */ + JOINING_TYPE_X, /* 060A */ + JOINING_TYPE_U, /* 060B; AFGHANI SIGN; U; No_Joining_Group */ + JOINING_TYPE_X, /* 060C */ + JOINING_TYPE_X, /* 060D */ + JOINING_TYPE_X, /* 060E */ + JOINING_TYPE_X, /* 060F */ + JOINING_TYPE_X, /* 0610 */ + JOINING_TYPE_X, /* 0611 */ + JOINING_TYPE_X, /* 0612 */ + JOINING_TYPE_X, /* 0613 */ + JOINING_TYPE_X, /* 0614 */ + JOINING_TYPE_X, /* 0615 */ + JOINING_TYPE_X, /* 0616 */ + JOINING_TYPE_X, /* 0617 */ + JOINING_TYPE_X, /* 0618 */ + JOINING_TYPE_X, /* 0619 */ + JOINING_TYPE_X, /* 061A */ + JOINING_TYPE_X, /* 061B */ + JOINING_TYPE_X, /* 061C */ + JOINING_TYPE_X, /* 061D */ + JOINING_TYPE_X, /* 061E */ + JOINING_TYPE_X, /* 061F */ + JOINING_TYPE_D, /* 0620; YEH WITH RING; D; YEH */ + JOINING_TYPE_U, /* 0621; HAMZA; U; No_Joining_Group */ + JOINING_TYPE_R, /* 0622; MADDA ON ALEF; R; ALEF */ + JOINING_TYPE_R, /* 0623; HAMZA ON ALEF; R; ALEF */ + JOINING_TYPE_R, /* 0624; HAMZA ON WAW; R; WAW */ + JOINING_TYPE_R, /* 0625; HAMZA UNDER ALEF; R; ALEF */ + JOINING_TYPE_D, /* 0626; HAMZA ON YEH; D; YEH */ + JOINING_TYPE_R, /* 0627; ALEF; R; ALEF */ + JOINING_TYPE_D, /* 0628; BEH; D; BEH */ + JOINING_TYPE_R, /* 0629; TEH MARBUTA; R; TEH MARBUTA */ + JOINING_TYPE_D, /* 062A; TEH; D; BEH */ + JOINING_TYPE_D, /* 062B; THEH; D; BEH */ + JOINING_TYPE_D, /* 062C; JEEM; D; HAH */ + JOINING_TYPE_D, /* 062D; HAH; D; HAH */ + JOINING_TYPE_D, /* 062E; KHAH; D; HAH */ + JOINING_TYPE_R, /* 062F; DAL; R; DAL */ + JOINING_TYPE_R, /* 0630; THAL; R; DAL */ + JOINING_TYPE_R, /* 0631; REH; R; REH */ + JOINING_TYPE_R, /* 0632; ZAIN; R; REH */ + JOINING_TYPE_D, /* 0633; SEEN; D; SEEN */ + JOINING_TYPE_D, /* 0634; SHEEN; D; SEEN */ + JOINING_TYPE_D, /* 0635; SAD; D; SAD */ + JOINING_TYPE_D, /* 0636; DAD; D; SAD */ + JOINING_TYPE_D, /* 0637; TAH; D; TAH */ + JOINING_TYPE_D, /* 0638; ZAH; D; TAH */ + JOINING_TYPE_D, /* 0639; AIN; D; AIN */ + JOINING_TYPE_D, /* 063A; GHAIN; D; AIN */ + JOINING_TYPE_D, /* 063B; KEHEH WITH 2 DOTS ABOVE; D; GAF */ + JOINING_TYPE_D, /* 063C; KEHEH WITH 3 DOTS BELOW; D; GAF */ + JOINING_TYPE_D, /* 063D; FARSI YEH WITH INVERTED V; D; FARSI YEH */ + JOINING_TYPE_D, /* 063E; FARSI YEH WITH 2 DOTS ABOVE; D; FARSI YEH */ + JOINING_TYPE_D, /* 063F; FARSI YEH WITH 3 DOTS ABOVE; D; FARSI YEH */ + JOINING_TYPE_C, /* 0640; TATWEEL; C; No_Joining_Group */ + JOINING_TYPE_D, /* 0641; FEH; D; FEH */ + JOINING_TYPE_D, /* 0642; QAF; D; QAF */ + JOINING_TYPE_D, /* 0643; KAF; D; KAF */ + JOINING_TYPE_D, /* 0644; LAM; D; LAM */ + JOINING_TYPE_D, /* 0645; MEEM; D; MEEM */ + JOINING_TYPE_D, /* 0646; NOON; D; NOON */ + JOINING_TYPE_D, /* 0647; HEH; D; HEH */ + JOINING_TYPE_R, /* 0648; WAW; R; WAW */ + JOINING_TYPE_D, /* 0649; ALEF MAKSURA; D; YEH */ + JOINING_TYPE_D, /* 064A; YEH; D; YEH */ + JOINING_TYPE_X, /* 064B */ + JOINING_TYPE_X, /* 064C */ + JOINING_TYPE_X, /* 064D */ + JOINING_TYPE_X, /* 064E */ + JOINING_TYPE_X, /* 064F */ + JOINING_TYPE_X, /* 0650 */ + JOINING_TYPE_X, /* 0651 */ + JOINING_TYPE_X, /* 0652 */ + JOINING_TYPE_X, /* 0653 */ + JOINING_TYPE_X, /* 0654 */ + JOINING_TYPE_X, /* 0655 */ + JOINING_TYPE_X, /* 0656 */ + JOINING_TYPE_X, /* 0657 */ + JOINING_TYPE_X, /* 0658 */ + JOINING_TYPE_X, /* 0659 */ + JOINING_TYPE_X, /* 065A */ + JOINING_TYPE_X, /* 065B */ + JOINING_TYPE_X, /* 065C */ + JOINING_TYPE_X, /* 065D */ + JOINING_TYPE_X, /* 065E */ + JOINING_TYPE_X, /* 065F */ + JOINING_TYPE_X, /* 0660 */ + JOINING_TYPE_X, /* 0661 */ + JOINING_TYPE_X, /* 0662 */ + JOINING_TYPE_X, /* 0663 */ + JOINING_TYPE_X, /* 0664 */ + JOINING_TYPE_X, /* 0665 */ + JOINING_TYPE_X, /* 0666 */ + JOINING_TYPE_X, /* 0667 */ + JOINING_TYPE_X, /* 0668 */ + JOINING_TYPE_X, /* 0669 */ + JOINING_TYPE_X, /* 066A */ + JOINING_TYPE_X, /* 066B */ + JOINING_TYPE_X, /* 066C */ + JOINING_TYPE_X, /* 066D */ + JOINING_TYPE_D, /* 066E; DOTLESS BEH; D; BEH */ + JOINING_TYPE_D, /* 066F; DOTLESS QAF; D; QAF */ + JOINING_TYPE_X, /* 0670 */ + JOINING_TYPE_R, /* 0671; HAMZAT WASL ON ALEF; R; ALEF */ + JOINING_TYPE_R, /* 0672; WAVY HAMZA ON ALEF; R; ALEF */ + JOINING_TYPE_R, /* 0673; WAVY HAMZA UNDER ALEF; R; ALEF */ + JOINING_TYPE_U, /* 0674; HIGH HAMZA; U; No_Joining_Group */ + JOINING_TYPE_R, /* 0675; HIGH HAMZA ALEF; R; ALEF */ + JOINING_TYPE_R, /* 0676; HIGH HAMZA WAW; R; WAW */ + JOINING_TYPE_R, /* 0677; HIGH HAMZA WAW WITH DAMMA; R; WAW */ + JOINING_TYPE_D, /* 0678; HIGH HAMZA YEH; D; YEH */ + JOINING_TYPE_D, /* 0679; TEH WITH SMALL TAH; D; BEH */ + JOINING_TYPE_D, /* 067A; TEH WITH 2 DOTS VERTICAL ABOVE; D; BEH */ + JOINING_TYPE_D, /* 067B; BEH WITH 2 DOTS VERTICAL BELOW; D; BEH */ + JOINING_TYPE_D, /* 067C; TEH WITH RING; D; BEH */ + JOINING_TYPE_D, /* 067D; TEH WITH 3 DOTS ABOVE DOWNWARD; D; BEH */ + JOINING_TYPE_D, /* 067E; TEH WITH 3 DOTS BELOW; D; BEH */ + JOINING_TYPE_D, /* 067F; TEH WITH 4 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0680; BEH WITH 4 DOTS BELOW; D; BEH */ + JOINING_TYPE_D, /* 0681; HAMZA ON HAH; D; HAH */ + JOINING_TYPE_D, /* 0682; HAH WITH 2 DOTS VERTICAL ABOVE; D; HAH */ + JOINING_TYPE_D, /* 0683; HAH WITH MIDDLE 2 DOTS; D; HAH */ + JOINING_TYPE_D, /* 0684; HAH WITH MIDDLE 2 DOTS VERTICAL; D; HAH */ + JOINING_TYPE_D, /* 0685; HAH WITH 3 DOTS ABOVE; D; HAH */ + JOINING_TYPE_D, /* 0686; HAH WITH MIDDLE 3 DOTS DOWNWARD; D; HAH */ + JOINING_TYPE_D, /* 0687; HAH WITH MIDDLE 4 DOTS; D; HAH */ + JOINING_TYPE_R, /* 0688; DAL WITH SMALL TAH; R; DAL */ + JOINING_TYPE_R, /* 0689; DAL WITH RING; R; DAL */ + JOINING_TYPE_R, /* 068A; DAL WITH DOT BELOW; R; DAL */ + JOINING_TYPE_R, /* 068B; DAL WITH DOT BELOW AND SMALL TAH; R; DAL */ + JOINING_TYPE_R, /* 068C; DAL WITH 2 DOTS ABOVE; R; DAL */ + JOINING_TYPE_R, /* 068D; DAL WITH 2 DOTS BELOW; R; DAL */ + JOINING_TYPE_R, /* 068E; DAL WITH 3 DOTS ABOVE; R; DAL */ + JOINING_TYPE_R, /* 068F; DAL WITH 3 DOTS ABOVE DOWNWARD; R; DAL */ + JOINING_TYPE_R, /* 0690; DAL WITH 4 DOTS ABOVE; R; DAL */ + JOINING_TYPE_R, /* 0691; REH WITH SMALL TAH; R; REH */ + JOINING_TYPE_R, /* 0692; REH WITH SMALL V; R; REH */ + JOINING_TYPE_R, /* 0693; REH WITH RING; R; REH */ + JOINING_TYPE_R, /* 0694; REH WITH DOT BELOW; R; REH */ + JOINING_TYPE_R, /* 0695; REH WITH SMALL V BELOW; R; REH */ + JOINING_TYPE_R, /* 0696; REH WITH DOT BELOW AND DOT ABOVE; R; REH */ + JOINING_TYPE_R, /* 0697; REH WITH 2 DOTS ABOVE; R; REH */ + JOINING_TYPE_R, /* 0698; REH WITH 3 DOTS ABOVE; R; REH */ + JOINING_TYPE_R, /* 0699; REH WITH 4 DOTS ABOVE; R; REH */ + JOINING_TYPE_D, /* 069A; SEEN WITH DOT BELOW AND DOT ABOVE; D; SEEN */ + JOINING_TYPE_D, /* 069B; SEEN WITH 3 DOTS BELOW; D; SEEN */ + JOINING_TYPE_D, /* 069C; SEEN WITH 3 DOTS BELOW AND 3 DOTS ABOVE; D; SEEN */ + JOINING_TYPE_D, /* 069D; SAD WITH 2 DOTS BELOW; D; SAD */ + JOINING_TYPE_D, /* 069E; SAD WITH 3 DOTS ABOVE; D; SAD */ + JOINING_TYPE_D, /* 069F; TAH WITH 3 DOTS ABOVE; D; TAH */ + JOINING_TYPE_D, /* 06A0; AIN WITH 3 DOTS ABOVE; D; AIN */ + JOINING_TYPE_D, /* 06A1; DOTLESS FEH; D; FEH */ + JOINING_TYPE_D, /* 06A2; FEH WITH DOT MOVED BELOW; D; FEH */ + JOINING_TYPE_D, /* 06A3; FEH WITH DOT BELOW; D; FEH */ + JOINING_TYPE_D, /* 06A4; FEH WITH 3 DOTS ABOVE; D; FEH */ + JOINING_TYPE_D, /* 06A5; FEH WITH 3 DOTS BELOW; D; FEH */ + JOINING_TYPE_D, /* 06A6; FEH WITH 4 DOTS ABOVE; D; FEH */ + JOINING_TYPE_D, /* 06A7; QAF WITH DOT ABOVE; D; QAF */ + JOINING_TYPE_D, /* 06A8; QAF WITH 3 DOTS ABOVE; D; QAF */ + JOINING_TYPE_D, /* 06A9; KEHEH; D; GAF */ + JOINING_TYPE_D, /* 06AA; SWASH KAF; D; SWASH KAF */ + JOINING_TYPE_D, /* 06AB; KAF WITH RING; D; GAF */ + JOINING_TYPE_D, /* 06AC; KAF WITH DOT ABOVE; D; KAF */ + JOINING_TYPE_D, /* 06AD; KAF WITH 3 DOTS ABOVE; D; KAF */ + JOINING_TYPE_D, /* 06AE; KAF WITH 3 DOTS BELOW; D; KAF */ + JOINING_TYPE_D, /* 06AF; GAF; D; GAF */ + JOINING_TYPE_D, /* 06B0; GAF WITH RING; D; GAF */ + JOINING_TYPE_D, /* 06B1; GAF WITH 2 DOTS ABOVE; D; GAF */ + JOINING_TYPE_D, /* 06B2; GAF WITH 2 DOTS BELOW; D; GAF */ + JOINING_TYPE_D, /* 06B3; GAF WITH 2 DOTS VERTICAL BELOW; D; GAF */ + JOINING_TYPE_D, /* 06B4; GAF WITH 3 DOTS ABOVE; D; GAF */ + JOINING_TYPE_D, /* 06B5; LAM WITH SMALL V; D; LAM */ + JOINING_TYPE_D, /* 06B6; LAM WITH DOT ABOVE; D; LAM */ + JOINING_TYPE_D, /* 06B7; LAM WITH 3 DOTS ABOVE; D; LAM */ + JOINING_TYPE_D, /* 06B8; LAM WITH 3 DOTS BELOW; D; LAM */ + JOINING_TYPE_D, /* 06B9; NOON WITH DOT BELOW; D; NOON */ + JOINING_TYPE_D, /* 06BA; DOTLESS NOON; D; NOON */ + JOINING_TYPE_D, /* 06BB; DOTLESS NOON WITH SMALL TAH; D; NOON */ + JOINING_TYPE_D, /* 06BC; NOON WITH RING; D; NOON */ + JOINING_TYPE_D, /* 06BD; NYA; D; NYA */ + JOINING_TYPE_D, /* 06BE; KNOTTED HEH; D; KNOTTED HEH */ + JOINING_TYPE_D, /* 06BF; HAH WITH MIDDLE 3 DOTS DOWNWARD AND DOT ABOVE; D; HAH */ + JOINING_TYPE_R, /* 06C0; HAMZA ON HEH; R; TEH MARBUTA */ + JOINING_TYPE_D, /* 06C1; HEH GOAL; D; HEH GOAL */ + JOINING_TYPE_D, /* 06C2; HAMZA ON HEH GOAL; D; HEH GOAL */ + JOINING_TYPE_R, /* 06C3; TEH MARBUTA GOAL; R; TEH MARBUTA GOAL */ + JOINING_TYPE_R, /* 06C4; WAW WITH RING; R; WAW */ + JOINING_TYPE_R, /* 06C5; WAW WITH BAR; R; WAW */ + JOINING_TYPE_R, /* 06C6; WAW WITH SMALL V; R; WAW */ + JOINING_TYPE_R, /* 06C7; WAW WITH DAMMA; R; WAW */ + JOINING_TYPE_R, /* 06C8; WAW WITH ALEF ABOVE; R; WAW */ + JOINING_TYPE_R, /* 06C9; WAW WITH INVERTED SMALL V; R; WAW */ + JOINING_TYPE_R, /* 06CA; WAW WITH 2 DOTS ABOVE; R; WAW */ + JOINING_TYPE_R, /* 06CB; WAW WITH 3 DOTS ABOVE; R; WAW */ + JOINING_TYPE_D, /* 06CC; FARSI YEH; D; FARSI YEH */ + JOINING_TYPE_R, /* 06CD; YEH WITH TAIL; R; YEH WITH TAIL */ + JOINING_TYPE_D, /* 06CE; FARSI YEH WITH SMALL V; D; FARSI YEH */ + JOINING_TYPE_R, /* 06CF; WAW WITH DOT ABOVE; R; WAW */ + JOINING_TYPE_D, /* 06D0; YEH WITH 2 DOTS VERTICAL BELOW; D; YEH */ + JOINING_TYPE_D, /* 06D1; YEH WITH 3 DOTS BELOW; D; YEH */ + JOINING_TYPE_R, /* 06D2; YEH BARREE; R; YEH BARREE */ + JOINING_TYPE_R, /* 06D3; HAMZA ON YEH BARREE; R; YEH BARREE */ + JOINING_TYPE_X, /* 06D4 */ + JOINING_TYPE_R, /* 06D5; AE; R; TEH MARBUTA */ + JOINING_TYPE_X, /* 06D6 */ + JOINING_TYPE_X, /* 06D7 */ + JOINING_TYPE_X, /* 06D8 */ + JOINING_TYPE_X, /* 06D9 */ + JOINING_TYPE_X, /* 06DA */ + JOINING_TYPE_X, /* 06DB */ + JOINING_TYPE_X, /* 06DC */ + JOINING_TYPE_U, /* 06DD; ARABIC END OF AYAH; U; No_Joining_Group */ + JOINING_TYPE_X, /* 06DE */ + JOINING_TYPE_X, /* 06DF */ + JOINING_TYPE_X, /* 06E0 */ + JOINING_TYPE_X, /* 06E1 */ + JOINING_TYPE_X, /* 06E2 */ + JOINING_TYPE_X, /* 06E3 */ + JOINING_TYPE_X, /* 06E4 */ + JOINING_TYPE_X, /* 06E5 */ + JOINING_TYPE_X, /* 06E6 */ + JOINING_TYPE_X, /* 06E7 */ + JOINING_TYPE_X, /* 06E8 */ + JOINING_TYPE_X, /* 06E9 */ + JOINING_TYPE_X, /* 06EA */ + JOINING_TYPE_X, /* 06EB */ + JOINING_TYPE_X, /* 06EC */ + JOINING_TYPE_X, /* 06ED */ + JOINING_TYPE_R, /* 06EE; DAL WITH INVERTED V; R; DAL */ + JOINING_TYPE_R, /* 06EF; REH WITH INVERTED V; R; REH */ + JOINING_TYPE_X, /* 06F0 */ + JOINING_TYPE_X, /* 06F1 */ + JOINING_TYPE_X, /* 06F2 */ + JOINING_TYPE_X, /* 06F3 */ + JOINING_TYPE_X, /* 06F4 */ + JOINING_TYPE_X, /* 06F5 */ + JOINING_TYPE_X, /* 06F6 */ + JOINING_TYPE_X, /* 06F7 */ + JOINING_TYPE_X, /* 06F8 */ + JOINING_TYPE_X, /* 06F9 */ + JOINING_TYPE_D, /* 06FA; SEEN WITH DOT BELOW AND 3 DOTS ABOVE; D; SEEN */ + JOINING_TYPE_D, /* 06FB; DAD WITH DOT BELOW; D; SAD */ + JOINING_TYPE_D, /* 06FC; GHAIN WITH DOT BELOW; D; AIN */ + JOINING_TYPE_X, /* 06FD */ + JOINING_TYPE_X, /* 06FE */ + JOINING_TYPE_D, /* 06FF; HEH WITH INVERTED V; D; KNOTTED HEH */ + + /* Syriac characters */ + + JOINING_TYPE_X, /* 0700 */ + JOINING_TYPE_X, /* 0701 */ + JOINING_TYPE_X, /* 0702 */ + JOINING_TYPE_X, /* 0703 */ + JOINING_TYPE_X, /* 0704 */ + JOINING_TYPE_X, /* 0705 */ + JOINING_TYPE_X, /* 0706 */ + JOINING_TYPE_X, /* 0707 */ + JOINING_TYPE_X, /* 0708 */ + JOINING_TYPE_X, /* 0709 */ + JOINING_TYPE_X, /* 070A */ + JOINING_TYPE_X, /* 070B */ + JOINING_TYPE_X, /* 070C */ + JOINING_TYPE_X, /* 070D */ + JOINING_TYPE_X, /* 070E */ + JOINING_TYPE_X, /* 070F */ + JOINING_GROUP_ALAPH, /* 0710; ALAPH; R; ALAPH */ + JOINING_TYPE_X, /* 0711 */ + JOINING_TYPE_D, /* 0712; BETH; D; BETH */ + JOINING_TYPE_D, /* 0713; GAMAL; D; GAMAL */ + JOINING_TYPE_D, /* 0714; GAMAL GARSHUNI; D; GAMAL */ + JOINING_GROUP_DALATH_RISH, /* 0715; DALATH; R; DALATH RISH */ + JOINING_GROUP_DALATH_RISH, /* 0716; DOTLESS DALATH RISH; R; DALATH RISH */ + JOINING_TYPE_R, /* 0717; HE; R; HE */ + JOINING_TYPE_R, /* 0718; WAW; R; SYRIAC WAW */ + JOINING_TYPE_R, /* 0719; ZAIN; R; ZAIN */ + JOINING_TYPE_D, /* 071A; HETH; D; HETH */ + JOINING_TYPE_D, /* 071B; TETH; D; TETH */ + JOINING_TYPE_D, /* 071C; TETH GARSHUNI; D; TETH */ + JOINING_TYPE_D, /* 071D; YUDH; D; YUDH */ + JOINING_TYPE_R, /* 071E; YUDH HE; R; YUDH HE */ + JOINING_TYPE_D, /* 071F; KAPH; D; KAPH */ + JOINING_TYPE_D, /* 0720; LAMADH; D; LAMADH */ + JOINING_TYPE_D, /* 0721; MIM; D; MIM */ + JOINING_TYPE_D, /* 0722; NUN; D; NUN */ + JOINING_TYPE_D, /* 0723; SEMKATH; D; SEMKATH */ + JOINING_TYPE_D, /* 0724; FINAL SEMKATH; D; FINAL SEMKATH */ + JOINING_TYPE_D, /* 0725; E; D; E */ + JOINING_TYPE_D, /* 0726; PE; D; PE */ + JOINING_TYPE_D, /* 0727; REVERSED PE; D; REVERSED PE */ + JOINING_TYPE_R, /* 0728; SADHE; R; SADHE */ + JOINING_TYPE_D, /* 0729; QAPH; D; QAPH */ + JOINING_GROUP_DALATH_RISH, /* 072A; RISH; R; DALATH RISH */ + JOINING_TYPE_D, /* 072B; SHIN; D; SHIN */ + JOINING_TYPE_R, /* 072C; TAW; R; TAW */ + JOINING_TYPE_D, /* 072D; PERSIAN BHETH; D; BETH */ + JOINING_TYPE_D, /* 072E; PERSIAN GHAMAL; D; GAMAL */ + JOINING_GROUP_DALATH_RISH, /* 072F; PERSIAN DHALATH; R; DALATH RISH */ + JOINING_TYPE_X, /* 0730 */ + JOINING_TYPE_X, /* 0731 */ + JOINING_TYPE_X, /* 0732 */ + JOINING_TYPE_X, /* 0733 */ + JOINING_TYPE_X, /* 0734 */ + JOINING_TYPE_X, /* 0735 */ + JOINING_TYPE_X, /* 0736 */ + JOINING_TYPE_X, /* 0737 */ + JOINING_TYPE_X, /* 0738 */ + JOINING_TYPE_X, /* 0739 */ + JOINING_TYPE_X, /* 073A */ + JOINING_TYPE_X, /* 073B */ + JOINING_TYPE_X, /* 073C */ + JOINING_TYPE_X, /* 073D */ + JOINING_TYPE_X, /* 073E */ + JOINING_TYPE_X, /* 073F */ + JOINING_TYPE_X, /* 0740 */ + JOINING_TYPE_X, /* 0741 */ + JOINING_TYPE_X, /* 0742 */ + JOINING_TYPE_X, /* 0743 */ + JOINING_TYPE_X, /* 0744 */ + JOINING_TYPE_X, /* 0745 */ + JOINING_TYPE_X, /* 0746 */ + JOINING_TYPE_X, /* 0747 */ + JOINING_TYPE_X, /* 0748 */ + JOINING_TYPE_X, /* 0749 */ + JOINING_TYPE_X, /* 074A */ + JOINING_TYPE_X, /* 074B */ + JOINING_TYPE_X, /* 074C */ + JOINING_TYPE_R, /* 074D; SOGDIAN ZHAIN; R; ZHAIN */ + JOINING_TYPE_D, /* 074E; SOGDIAN KHAPH; D; KHAPH */ + JOINING_TYPE_D, /* 074F; SOGDIAN FE; D; FE */ + + /* Arabic supplement characters */ + + JOINING_TYPE_D, /* 0750; BEH WITH 3 DOTS HORIZONTALLY BELOW; D; BEH */ + JOINING_TYPE_D, /* 0751; BEH WITH DOT BELOW AND 3 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0752; BEH WITH 3 DOTS POINTING UPWARDS BELOW; D; BEH */ + JOINING_TYPE_D, /* 0753; BEH WITH 3 DOTS POINTING UPWARDS BELOW AND 2 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0754; BEH WITH 2 DOTS BELOW AND DOT ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0755; BEH WITH INVERTED SMALL V BELOW; D; BEH */ + JOINING_TYPE_D, /* 0756; BEH WITH SMALL V; D; BEH */ + JOINING_TYPE_D, /* 0757; HAH WITH 2 DOTS ABOVE; D; HAH */ + JOINING_TYPE_D, /* 0758; HAH WITH 3 DOTS POINTING UPWARDS BELOW; D; HAH */ + JOINING_TYPE_R, /* 0759; DAL WITH 2 DOTS VERTICALLY BELOW AND SMALL TAH; R; DAL */ + JOINING_TYPE_R, /* 075A; DAL WITH INVERTED SMALL V BELOW; R; DAL */ + JOINING_TYPE_R, /* 075B; REH WITH STROKE; R; REH */ + JOINING_TYPE_D, /* 075C; SEEN WITH 4 DOTS ABOVE; D; SEEN */ + JOINING_TYPE_D, /* 075D; AIN WITH 2 DOTS ABOVE; D; AIN */ + JOINING_TYPE_D, /* 075E; AIN WITH 3 DOTS POINTING DOWNWARDS ABOVE; D; AIN */ + JOINING_TYPE_D, /* 075F; AIN WITH 2 DOTS VERTICALLY ABOVE; D; AIN */ + JOINING_TYPE_D, /* 0760; FEH WITH 2 DOTS BELOW; D; FEH */ + JOINING_TYPE_D, /* 0761; FEH WITH 3 DOTS POINTING UPWARDS BELOW; D; FEH */ + JOINING_TYPE_D, /* 0762; KEHEH WITH DOT ABOVE; D; GAF */ + JOINING_TYPE_D, /* 0763; KEHEH WITH 3 DOTS ABOVE; D; GAF */ + JOINING_TYPE_D, /* 0764; KEHEH WITH 3 DOTS POINTING UPWARDS BELOW; D; GAF */ + JOINING_TYPE_D, /* 0765; MEEM WITH DOT ABOVE; D; MEEM */ + JOINING_TYPE_D, /* 0766; MEEM WITH DOT BELOW; D; MEEM */ + JOINING_TYPE_D, /* 0767; NOON WITH 2 DOTS BELOW; D; NOON */ + JOINING_TYPE_D, /* 0768; NOON WITH SMALL TAH; D; NOON */ + JOINING_TYPE_D, /* 0769; NOON WITH SMALL V; D; NOON */ + JOINING_TYPE_D, /* 076A; LAM WITH BAR; D; LAM */ + JOINING_TYPE_R, /* 076B; REH WITH 2 DOTS VERTICALLY ABOVE; R; REH */ + JOINING_TYPE_R, /* 076C; REH WITH HAMZA ABOVE; R; REH */ + JOINING_TYPE_D, /* 076D; SEEN WITH 2 DOTS VERTICALLY ABOVE; D; SEEN */ + JOINING_TYPE_D, /* 076E; HAH WITH SMALL TAH BELOW; D; HAH */ + JOINING_TYPE_D, /* 076F; HAH WITH SMALL TAH AND 2 DOTS; D; HAH */ + JOINING_TYPE_D, /* 0770; SEEN WITH SMALL TAH AND 2 DOTS; D; SEEN */ + JOINING_TYPE_R, /* 0771; REH WITH SMALL TAH AND 2 DOTS; R; REH */ + JOINING_TYPE_D, /* 0772; HAH WITH SMALL TAH ABOVE; D; HAH */ + JOINING_TYPE_R, /* 0773; ALEF WITH DIGIT TWO ABOVE; R; ALEF */ + JOINING_TYPE_R, /* 0774; ALEF WITH DIGIT THREE ABOVE; R; ALEF */ + JOINING_TYPE_D, /* 0775; FARSI YEH WITH DIGIT TWO ABOVE; D; FARSI YEH */ + JOINING_TYPE_D, /* 0776; FARSI YEH WITH DIGIT THREE ABOVE; D; FARSI YEH */ + JOINING_TYPE_D, /* 0777; YEH WITH DIGIT FOUR BELOW; D; YEH */ + JOINING_TYPE_R, /* 0778; WAW WITH DIGIT TWO ABOVE; R; WAW */ + JOINING_TYPE_R, /* 0779; WAW WITH DIGIT THREE ABOVE; R; WAW */ + JOINING_TYPE_D, /* 077A; YEH BARREE WITH DIGIT TWO ABOVE; D; BURUSHASKI YEH BARREE */ + JOINING_TYPE_D, /* 077B; YEH BARREE WITH DIGIT THREE ABOVE; D; BURUSHASKI YEH BARREE */ + JOINING_TYPE_D, /* 077C; HAH WITH DIGIT FOUR BELOW; D; HAH */ + JOINING_TYPE_D, /* 077D; SEEN WITH DIGIT FOUR ABOVE; D; SEEN */ + JOINING_TYPE_D, /* 077E; SEEN WITH INVERTED V; D; SEEN */ + JOINING_TYPE_D, /* 077F; KAF WITH 2 DOTS ABOVE; D; KAF */ + + /* N'Ko Characters */ + + JOINING_TYPE_X, /* 0780 */ + JOINING_TYPE_X, /* 0781 */ + JOINING_TYPE_X, /* 0782 */ + JOINING_TYPE_X, /* 0783 */ + JOINING_TYPE_X, /* 0784 */ + JOINING_TYPE_X, /* 0785 */ + JOINING_TYPE_X, /* 0786 */ + JOINING_TYPE_X, /* 0787 */ + JOINING_TYPE_X, /* 0788 */ + JOINING_TYPE_X, /* 0789 */ + JOINING_TYPE_X, /* 078A */ + JOINING_TYPE_X, /* 078B */ + JOINING_TYPE_X, /* 078C */ + JOINING_TYPE_X, /* 078D */ + JOINING_TYPE_X, /* 078E */ + JOINING_TYPE_X, /* 078F */ + JOINING_TYPE_X, /* 0790 */ + JOINING_TYPE_X, /* 0791 */ + JOINING_TYPE_X, /* 0792 */ + JOINING_TYPE_X, /* 0793 */ + JOINING_TYPE_X, /* 0794 */ + JOINING_TYPE_X, /* 0795 */ + JOINING_TYPE_X, /* 0796 */ + JOINING_TYPE_X, /* 0797 */ + JOINING_TYPE_X, /* 0798 */ + JOINING_TYPE_X, /* 0799 */ + JOINING_TYPE_X, /* 079A */ + JOINING_TYPE_X, /* 079B */ + JOINING_TYPE_X, /* 079C */ + JOINING_TYPE_X, /* 079D */ + JOINING_TYPE_X, /* 079E */ + JOINING_TYPE_X, /* 079F */ + JOINING_TYPE_X, /* 07A0 */ + JOINING_TYPE_X, /* 07A1 */ + JOINING_TYPE_X, /* 07A2 */ + JOINING_TYPE_X, /* 07A3 */ + JOINING_TYPE_X, /* 07A4 */ + JOINING_TYPE_X, /* 07A5 */ + JOINING_TYPE_X, /* 07A6 */ + JOINING_TYPE_X, /* 07A7 */ + JOINING_TYPE_X, /* 07A8 */ + JOINING_TYPE_X, /* 07A9 */ + JOINING_TYPE_X, /* 07AA */ + JOINING_TYPE_X, /* 07AB */ + JOINING_TYPE_X, /* 07AC */ + JOINING_TYPE_X, /* 07AD */ + JOINING_TYPE_X, /* 07AE */ + JOINING_TYPE_X, /* 07AF */ + JOINING_TYPE_X, /* 07B0 */ + JOINING_TYPE_X, /* 07B1 */ + JOINING_TYPE_X, /* 07B2 */ + JOINING_TYPE_X, /* 07B3 */ + JOINING_TYPE_X, /* 07B4 */ + JOINING_TYPE_X, /* 07B5 */ + JOINING_TYPE_X, /* 07B6 */ + JOINING_TYPE_X, /* 07B7 */ + JOINING_TYPE_X, /* 07B8 */ + JOINING_TYPE_X, /* 07B9 */ + JOINING_TYPE_X, /* 07BA */ + JOINING_TYPE_X, /* 07BB */ + JOINING_TYPE_X, /* 07BC */ + JOINING_TYPE_X, /* 07BD */ + JOINING_TYPE_X, /* 07BE */ + JOINING_TYPE_X, /* 07BF */ + JOINING_TYPE_X, /* 07C0 */ + JOINING_TYPE_X, /* 07C1 */ + JOINING_TYPE_X, /* 07C2 */ + JOINING_TYPE_X, /* 07C3 */ + JOINING_TYPE_X, /* 07C4 */ + JOINING_TYPE_X, /* 07C5 */ + JOINING_TYPE_X, /* 07C6 */ + JOINING_TYPE_X, /* 07C7 */ + JOINING_TYPE_X, /* 07C8 */ + JOINING_TYPE_X, /* 07C9 */ + JOINING_TYPE_D, /* 07CA; NKO A; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07CB; NKO EE; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07CC; NKO I; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07CD; NKO E; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07CE; NKO U; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07CF; NKO OO; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D0; NKO O; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D1; NKO DAGBASINNA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D2; NKO N; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D3; NKO BA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D4; NKO PA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D5; NKO TA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D6; NKO JA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D7; NKO CHA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D8; NKO DA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07D9; NKO RA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07DA; NKO RRA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07DB; NKO SA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07DC; NKO GBA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07DD; NKO FA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07DE; NKO KA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07DF; NKO LA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E0; NKO NA WOLOSO; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E1; NKO MA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E2; NKO NYA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E3; NKO NA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E4; NKO HA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E5; NKO WA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E6; NKO YA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E7; NKO NYA WOLOSO; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E8; NKO JONA JA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07E9; NKO JONA CHA; D; No_Joining_Group */ + JOINING_TYPE_D, /* 07EA; NKO JONA RA; D; No_Joining_Group */ + JOINING_TYPE_X, /* 07EB */ + JOINING_TYPE_X, /* 07EC */ + JOINING_TYPE_X, /* 07ED */ + JOINING_TYPE_X, /* 07EE */ + JOINING_TYPE_X, /* 07EF */ + JOINING_TYPE_X, /* 07F0 */ + JOINING_TYPE_X, /* 07F1 */ + JOINING_TYPE_X, /* 07F2 */ + JOINING_TYPE_X, /* 07F3 */ + JOINING_TYPE_X, /* 07F4 */ + JOINING_TYPE_X, /* 07F5 */ + JOINING_TYPE_X, /* 07F6 */ + JOINING_TYPE_X, /* 07F7 */ + JOINING_TYPE_X, /* 07F8 */ + JOINING_TYPE_X, /* 07F9 */ + JOINING_TYPE_C, /* 07FA; NKO LAJANYALAN; C; No_Joining_Group */ + + /* Mandaic Characters */ + + JOINING_TYPE_X, /* 07FB */ + JOINING_TYPE_X, /* 07FC */ + JOINING_TYPE_X, /* 07FD */ + JOINING_TYPE_X, /* 07FE */ + JOINING_TYPE_X, /* 07FF */ + JOINING_TYPE_X, /* 0800 */ + JOINING_TYPE_X, /* 0801 */ + JOINING_TYPE_X, /* 0802 */ + JOINING_TYPE_X, /* 0803 */ + JOINING_TYPE_X, /* 0804 */ + JOINING_TYPE_X, /* 0805 */ + JOINING_TYPE_X, /* 0806 */ + JOINING_TYPE_X, /* 0807 */ + JOINING_TYPE_X, /* 0808 */ + JOINING_TYPE_X, /* 0809 */ + JOINING_TYPE_X, /* 080A */ + JOINING_TYPE_X, /* 080B */ + JOINING_TYPE_X, /* 080C */ + JOINING_TYPE_X, /* 080D */ + JOINING_TYPE_X, /* 080E */ + JOINING_TYPE_X, /* 080F */ + JOINING_TYPE_X, /* 0810 */ + JOINING_TYPE_X, /* 0811 */ + JOINING_TYPE_X, /* 0812 */ + JOINING_TYPE_X, /* 0813 */ + JOINING_TYPE_X, /* 0814 */ + JOINING_TYPE_X, /* 0815 */ + JOINING_TYPE_X, /* 0816 */ + JOINING_TYPE_X, /* 0817 */ + JOINING_TYPE_X, /* 0818 */ + JOINING_TYPE_X, /* 0819 */ + JOINING_TYPE_X, /* 081A */ + JOINING_TYPE_X, /* 081B */ + JOINING_TYPE_X, /* 081C */ + JOINING_TYPE_X, /* 081D */ + JOINING_TYPE_X, /* 081E */ + JOINING_TYPE_X, /* 081F */ + JOINING_TYPE_X, /* 0820 */ + JOINING_TYPE_X, /* 0821 */ + JOINING_TYPE_X, /* 0822 */ + JOINING_TYPE_X, /* 0823 */ + JOINING_TYPE_X, /* 0824 */ + JOINING_TYPE_X, /* 0825 */ + JOINING_TYPE_X, /* 0826 */ + JOINING_TYPE_X, /* 0827 */ + JOINING_TYPE_X, /* 0828 */ + JOINING_TYPE_X, /* 0829 */ + JOINING_TYPE_X, /* 082A */ + JOINING_TYPE_X, /* 082B */ + JOINING_TYPE_X, /* 082C */ + JOINING_TYPE_X, /* 082D */ + JOINING_TYPE_X, /* 082E */ + JOINING_TYPE_X, /* 082F */ + JOINING_TYPE_X, /* 0830 */ + JOINING_TYPE_X, /* 0831 */ + JOINING_TYPE_X, /* 0832 */ + JOINING_TYPE_X, /* 0833 */ + JOINING_TYPE_X, /* 0834 */ + JOINING_TYPE_X, /* 0835 */ + JOINING_TYPE_X, /* 0836 */ + JOINING_TYPE_X, /* 0837 */ + JOINING_TYPE_X, /* 0838 */ + JOINING_TYPE_X, /* 0839 */ + JOINING_TYPE_X, /* 083A */ + JOINING_TYPE_X, /* 083B */ + JOINING_TYPE_X, /* 083C */ + JOINING_TYPE_X, /* 083D */ + JOINING_TYPE_X, /* 083E */ + JOINING_TYPE_X, /* 083F */ + JOINING_TYPE_R, /* 0840; MANDAIC HALQA; R; No_Joining_Group */ + JOINING_TYPE_D, /* 0841; MANDAIC AB; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0842; MANDAIC AG; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0843; MANDAIC AD; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0844; MANDAIC AH; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0845; MANDAIC USHENNA; D; No_Joining_Group */ + JOINING_TYPE_R, /* 0846; MANDAIC AZ; R; No_Joining_Group */ + JOINING_TYPE_D, /* 0847; MANDAIC IT; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0848; MANDAIC ATT; D; No_Joining_Group */ + JOINING_TYPE_R, /* 0849; MANDAIC AKSA; R; No_Joining_Group */ + JOINING_TYPE_D, /* 084A; MANDAIC AK; D; No_Joining_Group */ + JOINING_TYPE_D, /* 084B; MANDAIC AL; D; No_Joining_Group */ + JOINING_TYPE_D, /* 084C; MANDAIC AM; D; No_Joining_Group */ + JOINING_TYPE_D, /* 084D; MANDAIC AN; D; No_Joining_Group */ + JOINING_TYPE_D, /* 084E; MANDAIC AS; D; No_Joining_Group */ + JOINING_TYPE_R, /* 084F; MANDAIC IN; R; No_Joining_Group */ + JOINING_TYPE_D, /* 0850; MANDAIC AP; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0851; MANDAIC ASZ; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0852; MANDAIC AQ; D; No_Joining_Group */ + JOINING_TYPE_D, /* 0853; MANDAIC AR; D; No_Joining_Group */ + JOINING_TYPE_R, /* 0854; MANDAIC ASH; R; No_Joining_Group */ + JOINING_TYPE_D, /* 0855; MANDAIC AT; D; No_Joining_Group */ + JOINING_TYPE_U, /* 0856; MANDAIC DUSHENNA; U; No_Joining_Group */ + JOINING_TYPE_U, /* 0857; MANDAIC KAD; U; No_Joining_Group */ + JOINING_TYPE_U, /* 0858; MANDAIC AIN; U; No_Joining_Group */ + + JOINING_TYPE_X /* dummy */ +}; + +#define JOINING_TABLE_FIRST 0x0600 +#define JOINING_TABLE_LAST 0x0858 + +/* == End of generated table == */ + +HB_END_DECLS + +#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_H */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc new file mode 100644 index 0000000..77a9c82 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-shape-complex-private.hh" + +HB_BEGIN_DECLS + + +/* buffer var allocations */ +#define arabic_shaping_action() var2.u32 /* arabic shaping action */ + + +/* + * Bits used in the joining tables + */ +enum { + JOINING_TYPE_U = 0, + JOINING_TYPE_R = 1, + JOINING_TYPE_D = 2, + JOINING_TYPE_C = JOINING_TYPE_D, + JOINING_GROUP_ALAPH = 3, + JOINING_GROUP_DALATH_RISH = 4, + NUM_STATE_MACHINE_COLS = 5, + + /* We deliberately don't have a JOINING_TYPE_L since that's unused in Unicode. */ + + JOINING_TYPE_T = 6, + JOINING_TYPE_X = 7 /* means: use general-category to choose between U or T. */ +}; + +/* + * Joining types: + */ + +#include "hb-ot-shape-complex-arabic-table.h" + +static unsigned int get_joining_type (hb_codepoint_t u, hb_category_t gen_cat) +{ + /* TODO Macroize the magic bit operations */ + + if (likely (JOINING_TABLE_FIRST <= u && u <= JOINING_TABLE_LAST)) { + unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST]; + if (likely (j_type != JOINING_TYPE_X)) + return j_type; + } + + /* Mongolian joining data is not in ArabicJoining.txt yet */ + if (unlikely (0x1800 <= u && u <= 0x18AF)) + { + /* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */ + if (gen_cat == HB_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A) + return JOINING_TYPE_D; + } + + if (unlikely ((u & ~(0x200C^0x200D)) == 0x200C)) { + return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C; + } + + return ((1<<gen_cat) & ((1<<HB_CATEGORY_NON_SPACING_MARK)|(1<<HB_CATEGORY_ENCLOSING_MARK)|(1<<HB_CATEGORY_FORMAT))) ? + JOINING_TYPE_T : JOINING_TYPE_U; +} + + + +static const hb_tag_t arabic_syriac_features[] = +{ + HB_TAG('i','n','i','t'), + HB_TAG('m','e','d','i'), + HB_TAG('f','i','n','a'), + HB_TAG('i','s','o','l'), + /* Syriac */ + HB_TAG('m','e','d','2'), + HB_TAG('f','i','n','2'), + HB_TAG('f','i','n','3'), + HB_TAG_NONE +}; + + +/* Same order as the feature array */ +enum { + INIT, + MEDI, + FINA, + ISOL, + + /* Syriac */ + MED2, + FIN2, + FIN3, + + NONE, + + COMMON_NUM_FEATURES = 4, + SYRIAC_NUM_FEATURES = 7, + TOTAL_NUM_FEATURES = NONE +}; + +static const struct arabic_state_table_entry { + uint8_t prev_action; + uint8_t curr_action; + uint8_t next_state; + uint8_t padding; +} arabic_state_table[][NUM_STATE_MACHINE_COLS] = +{ + /* jt_U, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */ + + /* State 0: prev was U, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, }, + + /* State 1: prev was R or ISOL/ALAPH, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, }, + + /* State 2: prev was D/ISOL, willing to join. */ + { {NONE,NONE,0}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, }, + + /* State 3: prev was D/FINA, willing to join. */ + { {NONE,NONE,0}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, }, + + /* State 4: prev was FINA ALAPH, not willing to join. */ + { {NONE,NONE,0}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, }, + + /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */ + { {NONE,NONE,0}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, }, + + /* State 6: prev was DALATH/RISH, not willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, } +}; + + + +void +_hb_ot_shape_complex_collect_features_arabic (hb_ot_shape_plan_t *plan, const hb_segment_properties_t *props) +{ + unsigned int num_features = props->script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES; + for (unsigned int i = 0; i < num_features; i++) + plan->map.add_bool_feature (arabic_syriac_features[i], false); +} + +void +_hb_ot_shape_complex_setup_masks_arabic (hb_ot_shape_context_t *c) +{ + unsigned int count = c->buffer->len; + unsigned int prev = 0, state = 0; + + for (unsigned int i = 0; i < count; i++) + { + unsigned int this_type = get_joining_type (c->buffer->info[i].codepoint, (hb_category_t) c->buffer->info[i].general_category()); + + if (unlikely (this_type == JOINING_TYPE_T)) { + c->buffer->info[i].arabic_shaping_action() = NONE; + continue; + } + + const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; + + if (entry->prev_action != NONE) + c->buffer->info[prev].arabic_shaping_action() = entry->prev_action; + + c->buffer->info[i].arabic_shaping_action() = entry->curr_action; + + prev = i; + state = entry->next_state; + } + + hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0}; + unsigned int num_masks = c->buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES; + for (unsigned int i = 0; i < num_masks; i++) + mask_array[i] = c->plan->map.get_1_mask (arabic_syriac_features[i]); + + for (unsigned int i = 0; i < count; i++) + c->buffer->info[i].mask |= mask_array[c->buffer->info[i].arabic_shaping_action()]; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh new file mode 100644 index 0000000..fed167d --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH +#define HB_OT_SHAPE_COMPLEX_PRIVATE_HH + +#include "hb-private.h" + +#include "hb-ot-shape-private.hh" + +HB_BEGIN_DECLS + + +static inline hb_ot_complex_shaper_t +hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) +{ + switch ((int) props->script) { + case HB_SCRIPT_ARABIC: + case HB_SCRIPT_NKO: + case HB_SCRIPT_SYRIAC: + case HB_SCRIPT_MANDAIC: + case HB_SCRIPT_MONGOLIAN: + return hb_ot_complex_shaper_arabic; + + default: + return hb_ot_complex_shaper_none; + } +} + + + +/* + * collect_features() + * + * Called during shape_plan(). + * + * Shapers should use plan->map to add their features. + */ + +HB_INTERNAL void _hb_ot_shape_complex_collect_features_arabic (hb_ot_shape_plan_t *plan, const hb_segment_properties_t *props); + +static inline void +hb_ot_shape_complex_collect_features (hb_ot_shape_plan_t *plan, + const hb_segment_properties_t *props) +{ + switch (plan->shaper) { + case hb_ot_complex_shaper_arabic: _hb_ot_shape_complex_collect_features_arabic (plan, props); return; + case hb_ot_complex_shaper_none: default: return; + } +} + + +/* setup_masks() + * + * Called during shape_execute(). + * + * Shapers should use c->plan.map to get feature masks and set on buffer. + */ + +HB_INTERNAL void _hb_ot_shape_complex_setup_masks_arabic (hb_ot_shape_context_t *c); + +static inline void +hb_ot_shape_complex_setup_masks (hb_ot_shape_context_t *c) +{ + switch (c->plan->shaper) { + case hb_ot_complex_shaper_arabic: _hb_ot_shape_complex_setup_masks_arabic (c); return; + case hb_ot_complex_shaper_none: default: return; + } +} + + +HB_END_DECLS + +#endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh new file mode 100644 index 0000000..deaec97 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_PRIVATE_HH +#define HB_OT_SHAPE_PRIVATE_HH + +#include "hb-private.h" + +#include "hb-ot-shape.h" + +#include "hb-ot-map-private.hh" + +HB_BEGIN_DECLS + + +/* buffer var allocations */ +#define general_category() var1.u8[0] /* unicode general_category (hb_category_t) */ +#define combining_class() var1.u8[1] /* unicode combining_class (uint8_t) */ + + +enum hb_ot_complex_shaper_t { + hb_ot_complex_shaper_none, + hb_ot_complex_shaper_arabic +}; + + +struct hb_ot_shape_plan_t +{ + hb_ot_map_t map; + hb_ot_complex_shaper_t shaper; +}; + + +struct hb_ot_shape_context_t +{ + /* Input to hb_ot_shape_execute() */ + hb_ot_shape_plan_t *plan; + hb_font_t *font; + hb_face_t *face; + hb_buffer_t *buffer; + const hb_feature_t *user_features; + unsigned int num_user_features; + + /* Transient stuff */ + hb_direction_t target_direction; + hb_bool_t applied_substitute_complex; + hb_bool_t applied_position_complex; +}; + + +HB_END_DECLS + +#endif /* HB_OT_SHAPE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape.cc b/third_party/harfbuzz-ng/src/hb-ot-shape.cc new file mode 100644 index 0000000..92c3925 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape.cc @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2009,2010 Red Hat, Inc. + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-shape-private.hh" +#include "hb-ot-shape-complex-private.hh" + +HB_BEGIN_DECLS + + +/* 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') +}; + +static void +hb_ot_shape_collect_features (hb_ot_shape_plan_t *plan, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features) +{ + switch (props->direction) { + case HB_DIRECTION_LTR: + plan->map.add_bool_feature (HB_TAG ('l','t','r','a')); + plan->map.add_bool_feature (HB_TAG ('l','t','r','m')); + break; + case HB_DIRECTION_RTL: + plan->map.add_bool_feature (HB_TAG ('r','t','l','a')); + plan->map.add_bool_feature (HB_TAG ('r','t','l','m'), false); + break; + case HB_DIRECTION_TTB: + case HB_DIRECTION_BTT: + default: + break; + } + + for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++) + plan->map.add_bool_feature (default_features[i]); + + hb_ot_shape_complex_collect_features (plan, props); + + for (unsigned int i = 0; i < num_user_features; i++) { + const hb_feature_t *feature = &user_features[i]; + plan->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1)); + } +} + + +static void +hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) +{ + hb_mask_t global_mask = c->plan->map.get_global_mask (); + c->buffer->reset_masks (global_mask); + + hb_ot_shape_complex_setup_masks (c); /* BUFFER: Clobbers var2 */ + + for (unsigned int i = 0; i < c->num_user_features; i++) + { + const hb_feature_t *feature = &c->user_features[i]; + if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { + unsigned int shift; + hb_mask_t mask = c->plan->map.get_mask (feature->tag, &shift); + c->buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); + } + } +} + + +static void +hb_ot_substitute_complex (hb_ot_shape_context_t *c) +{ + if (!hb_ot_layout_has_substitution (c->face)) + return; + + c->plan->map.substitute (c->face, c->buffer); + + c->applied_substitute_complex = TRUE; + return; +} + +static void +hb_ot_position_complex (hb_ot_shape_context_t *c) +{ + + if (!hb_ot_layout_has_positioning (c->face)) + return; + + c->plan->map.position (c->font, c->face, c->buffer); + + hb_ot_layout_position_finish (c->buffer); + + c->applied_position_complex = TRUE; + return; +} + + +/* 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_set_unicode_props (hb_ot_shape_context_t *c) +{ + hb_unicode_get_general_category_func_t get_general_category = c->buffer->unicode->v.get_general_category; + hb_unicode_get_combining_class_func_t get_combining_class = c->buffer->unicode->v.get_combining_class; + hb_glyph_info_t *info = c->buffer->info; + + unsigned int count = c->buffer->len; + for (unsigned int i = 1; i < count; i++) { + info[i].general_category() = get_general_category (info[i].codepoint); + info[i].combining_class() = get_combining_class (info[i].codepoint); + } +} + +static void +hb_form_clusters (hb_ot_shape_context_t *c) +{ + unsigned int count = c->buffer->len; + for (unsigned int i = 1; i < count; i++) + if (c->buffer->info[i].general_category() == HB_CATEGORY_NON_SPACING_MARK) + c->buffer->info[i].cluster = c->buffer->info[i - 1].cluster; +} + +static void +hb_ensure_native_direction (hb_ot_shape_context_t *c) +{ + hb_direction_t direction = c->buffer->props.direction; + + /* TODO vertical */ + if (HB_DIRECTION_IS_HORIZONTAL (direction) && + direction != _hb_script_get_horizontal_direction (c->buffer->props.script)) + { + hb_buffer_reverse_clusters (c->buffer); + c->buffer->props.direction = HB_DIRECTION_REVERSE (c->buffer->props.direction); + } +} + +static void +hb_reset_glyph_infos (hb_ot_shape_context_t *c) +{ + unsigned int count = c->buffer->len; + for (unsigned int i = 0; i < count; i++) + c->buffer->info[i].var1.u32 = c->buffer->info[i].var2.u32 = 0; +} + + +/* Substitute */ + +static void +hb_mirror_chars (hb_ot_shape_context_t *c) +{ + hb_unicode_get_mirroring_func_t get_mirroring = c->buffer->unicode->v.get_mirroring; + + if (HB_DIRECTION_IS_FORWARD (c->target_direction)) + return; + + hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m')); + + unsigned int count = c->buffer->len; + for (unsigned int i = 0; i < count; i++) { + hb_codepoint_t codepoint = get_mirroring (c->buffer->info[i].codepoint); + if (likely (codepoint == c->buffer->info[i].codepoint)) + c->buffer->info[i].mask |= rtlm_mask; /* XXX this should be moved to before setting user-feature masks */ + else + c->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->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, buffer->info[buffer->i + 1].codepoint)); + buffer->i++; + } else { + buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0)); + } + } + if (likely (buffer->i < buffer->len)) + buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0)); + buffer->swap (); +} + +static void +hb_substitute_default (hb_ot_shape_context_t *c) +{ + hb_map_glyphs (c->font, c->face, c->buffer); +} + +static void +hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) +{ + /* TODO Arabic */ +} + + +/* Position */ + +static void +hb_position_default (hb_ot_shape_context_t *c) +{ + hb_buffer_clear_positions (c->buffer); + + unsigned int count = c->buffer->len; + for (unsigned int i = 0; i < count; i++) { + hb_font_get_glyph_advance (c->font, c->face, c->buffer->info[i].codepoint, + &c->buffer->pos[i].x_advance, + &c->buffer->pos[i].y_advance); + } +} + +static void +hb_position_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) +{ + /* TODO Mark pos */ +} + +static void +hb_truetype_kern (hb_ot_shape_context_t *c) +{ + /* TODO Check for kern=0 */ + unsigned int count = c->buffer->len; + for (unsigned int i = 1; i < count; i++) { + hb_position_t kern, kern1, kern2; + kern = hb_font_get_kerning (c->font, c->face, c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint); + kern1 = kern >> 1; + kern2 = kern - kern1; + c->buffer->pos[i - 1].x_advance += kern1; + c->buffer->pos[i].x_advance += kern2; + c->buffer->pos[i].x_offset += kern2; + } +} + +static void +hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) +{ + hb_truetype_kern (c); +} + + +/* Do it! */ + +static void +hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) +{ + /* Save the original direction, we use it later. */ + c->target_direction = c->buffer->props.direction; + + hb_reset_glyph_infos (c); /* BUFFER: Clear buffer var1 and var2 */ + + hb_set_unicode_props (c); /* BUFFER: Set general_category and combining_class in var1 */ + + hb_ensure_native_direction (c); + + hb_form_clusters (c); + + hb_ot_shape_setup_masks (c); /* BUFFER: Clobbers var2 */ + + /* SUBSTITUTE */ + { + /* Mirroring needs to see the original direction */ + hb_mirror_chars (c); + + hb_substitute_default (c); + + hb_ot_substitute_complex (c); + + if (!c->applied_substitute_complex) + hb_substitute_complex_fallback (c); + } + + /* POSITION */ + { + hb_position_default (c); + + hb_ot_position_complex (c); + + hb_bool_t position_fallback = !c->applied_position_complex; + if (position_fallback) + hb_position_complex_fallback (c); + + if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) + hb_buffer_reverse (c->buffer); + + if (position_fallback) + hb_position_complex_fallback_visual (c); + } + + c->buffer->props.direction = c->target_direction; +} + +void +hb_ot_shape_plan_internal (hb_ot_shape_plan_t *plan, + hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features) +{ + plan->shaper = hb_ot_shape_complex_categorize (props); + + hb_ot_shape_collect_features (plan, props, user_features, num_user_features); + + plan->map.compile (face, props); +} + +void +hb_ot_shape_execute (hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_face_t *face, + hb_buffer_t *buffer, + const hb_feature_t *user_features, + unsigned int num_user_features) +{ + hb_ot_shape_context_t c = {plan, font, face, buffer, user_features, num_user_features}; + hb_ot_shape_execute_internal (&c); +} + +void +hb_ot_shape (hb_font_t *font, + hb_face_t *face, + hb_buffer_t *buffer, + const hb_feature_t *user_features, + unsigned int num_user_features) +{ + hb_ot_shape_plan_t plan; + + hb_ot_shape_plan_internal (&plan, face, &buffer->props, user_features, num_user_features); + hb_ot_shape_execute (&plan, font, face, buffer, user_features, num_user_features); +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape.h b/third_party/harfbuzz-ng/src/hb-ot-shape.h new file mode 100644 index 0000000..c90e0fe --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape.h @@ -0,0 +1,46 @@ +/* + * 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, + const hb_feature_t *user_features, + unsigned int num_user_features); + + +HB_END_DECLS + +#endif /* HB_OT_SHAPE_H */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-tag.c b/third_party/harfbuzz-ng/src/hb-ot-tag.c new file mode 100644 index 0000000..f3e0f1f --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-tag.c @@ -0,0 +1,703 @@ +/* + * 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> + +HB_BEGIN_DECLS + + +/* + * 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('a','v','s','t')}, /* HB_SCRIPT_AVESTAN */ + {HB_TAG('b','a','m','u')}, /* HB_SCRIPT_BAMUM */ + {HB_TAG('e','g','y','p')}, /* HB_SCRIPT_EGYPTIAN_HIEROGLYPHS */ + {HB_TAG('a','r','m','i')}, /* HB_SCRIPT_IMPERIAL_ARAMAIC */ + {HB_TAG('p','h','l','i')}, /* HB_SCRIPT_INSCRIPTIONAL_PAHLAVI */ + {HB_TAG('p','r','t','i')}, /* HB_SCRIPT_INSCRIPTIONAL_PARTHIAN */ + {HB_TAG('j','a','v','a')}, /* HB_SCRIPT_JAVANESE */ + {HB_TAG('k','t','h','i')}, /* HB_SCRIPT_KAITHI */ + {HB_TAG('l','i','s','u')}, /* HB_SCRIPT_LISU */ + {HB_TAG('m','y','e','i')}, /* HB_SCRIPT_MEETEI_MAYEK */ + {HB_TAG('s','a','r','b')}, /* HB_SCRIPT_OLD_SOUTH_ARABIAN */ + {HB_TAG('o','r','k','h')}, /* HB_SCRIPT_OLD_TURKIC */ + {HB_TAG('s','a','m','r')}, /* HB_SCRIPT_SAMARITAN */ + {HB_TAG('l','a','n','a')}, /* HB_SCRIPT_TAI_THAM */ + {HB_TAG('t','a','v','t')}, /* HB_SCRIPT_TAI_VIET */ + + /* Unicode-6.0 additions */ + {HB_TAG('b','a','t','k')}, /* HB_SCRIPT_BATAK */ + {HB_TAG('b','r','a','h')}, /* HB_SCRIPT_BRAHMI */ + {HB_TAG('m','a','n','d')} /* HB_SCRIPT_MANDAIC */ +}; + +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 char *a, + const char *b) +{ + 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; +#define IS_LETTER(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) +#define TO_UPPER(c) (((c) >= 'a' && (c) <= 'z') ? (c) + 'A' - 'a' : (c)) + for (i = 0; i < 4 && IS_LETTER (lang_str[i]); i++) + tag[i] = TO_UPPER (lang_str[i]); + for (; i < 4; i++) + 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), + (hb_compare_func_t) 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)->language) == 0) + lang_tag++; + + /* go back, find which one matches completely */ + while (lang_tag >= ot_languages && + lang_compare_first_component (lang_str, lang_tag->language) == 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); +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-tag.h b/third_party/harfbuzz-ng/src/hb-ot-tag.h new file mode 100644 index 0000000..1eec69f --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-tag.h @@ -0,0 +1,54 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-ot.h b/third_party/harfbuzz-ng/src/hb-ot.h new file mode 100644 index 0000000..268711d --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_H +#define HB_OT_H + +#include "hb.h" + +#include "hb-ot-layout.h" +#include "hb-ot-shape.h" +#include "hb-ot-tag.h" + +HB_BEGIN_DECLS +HB_END_DECLS + +#endif /* HB_OT_H */ diff --git a/third_party/harfbuzz-ng/src/hb-private.h b/third_party/harfbuzz-ng/src/hb-private.h new file mode 100644 index 0000000..96b9464 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-private.h @@ -0,0 +1,270 @@ +/* + * 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> + +HB_BEGIN_DECLS + + +/* 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 +} + +/* Type of bsearch() / qsort() compare function */ +typedef int (*hb_compare_func_t) (const void *, const void *); + + +/* 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) +{ + (void) ((depth < max_depth) && fprintf (stderr, "%s(%p) %-*d-> %s\n", what, obj, depth, depth, function)); + return TRUE; +} + + +#include "hb-object-private.h" + + +HB_END_DECLS + +#endif /* HB_PRIVATE_H */ diff --git a/third_party/harfbuzz-ng/src/hb-shape.cc b/third_party/harfbuzz-ng/src/hb-shape.cc new file mode 100644 index 0000000..a73977b --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-shape.cc @@ -0,0 +1,65 @@ +/* + * 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 + +HB_BEGIN_DECLS + + +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); +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-shape.h b/third_party/harfbuzz-ng/src/hb-shape.h new file mode 100644 index 0000000..48f1a55 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-shape.h @@ -0,0 +1,54 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-unicode-private.h b/third_party/harfbuzz-ng/src/hb-unicode-private.h new file mode 100644 index 0000000..419404b --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-unicode-private.h @@ -0,0 +1,64 @@ +/* + * 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 */ diff --git a/third_party/harfbuzz-ng/src/hb-unicode.c b/third_party/harfbuzz-ng/src/hb-unicode.c new file mode 100644 index 0000000..2ab308b --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-unicode.c @@ -0,0 +1,364 @@ +/* + * 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_BEGIN_DECLS + + +/* + * 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; +} + +hb_bool_t +hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs) +{ + return ufuncs->immutable; +} + + +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_unicode_get_mirroring_func_t +hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs) +{ + return ufuncs->v.get_mirroring; +} + +hb_unicode_get_general_category_func_t +hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs) +{ + return ufuncs->v.get_general_category; +} + +hb_unicode_get_script_func_t +hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs) +{ + return ufuncs->v.get_script; +} + +hb_unicode_get_combining_class_func_t +hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs) +{ + return ufuncs->v.get_combining_class; +} + +hb_unicode_get_eastasian_width_func_t +hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs) +{ + return ufuncs->v.get_eastasian_width; +} + + + +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 */ + + /* Unicode-6.0 additions */ + LTR, /* Batk */ + LTR, /* Brah */ + RTL /* Mand */ +}; +#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]; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-unicode.h b/third_party/harfbuzz-ng/src/hb-unicode.h new file mode 100644 index 0000000..43b04ca --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-unicode.h @@ -0,0 +1,294 @@ +/* + * 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, /* Cc */ + HB_CATEGORY_FORMAT, /* Cf */ + HB_CATEGORY_UNASSIGNED, /* Cn */ + HB_CATEGORY_PRIVATE_USE, /* Co */ + HB_CATEGORY_SURROGATE, /* Cs */ + HB_CATEGORY_LOWERCASE_LETTER, /* Ll */ + HB_CATEGORY_MODIFIER_LETTER, /* Lm */ + HB_CATEGORY_OTHER_LETTER, /* Lo */ + HB_CATEGORY_TITLECASE_LETTER, /* Lt */ + HB_CATEGORY_UPPERCASE_LETTER, /* Lu */ + HB_CATEGORY_COMBINING_MARK, /* Mc */ + HB_CATEGORY_ENCLOSING_MARK, /* Me */ + HB_CATEGORY_NON_SPACING_MARK, /* Mn */ + HB_CATEGORY_DECIMAL_NUMBER, /* Nd */ + HB_CATEGORY_LETTER_NUMBER, /* Nl */ + HB_CATEGORY_OTHER_NUMBER, /* No */ + HB_CATEGORY_CONNECT_PUNCTUATION, /* Pc */ + HB_CATEGORY_DASH_PUNCTUATION, /* Pd */ + HB_CATEGORY_CLOSE_PUNCTUATION, /* Pe */ + HB_CATEGORY_FINAL_PUNCTUATION, /* Pf */ + HB_CATEGORY_INITIAL_PUNCTUATION, /* Pi */ + HB_CATEGORY_OTHER_PUNCTUATION, /* Po */ + HB_CATEGORY_OPEN_PUNCTUATION, /* Ps */ + HB_CATEGORY_CURRENCY_SYMBOL, /* Sc */ + HB_CATEGORY_MODIFIER_SYMBOL, /* Sk */ + HB_CATEGORY_MATH_SYMBOL, /* Sm */ + HB_CATEGORY_OTHER_SYMBOL, /* So */ + HB_CATEGORY_LINE_SEPARATOR, /* Zl */ + HB_CATEGORY_PARAGRAPH_SEPARATOR, /* Zp */ + HB_CATEGORY_SPACE_SEPARATOR /* Zs */ +} 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_MEETEI_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 */ + + /* Unicode-6.0 additions */ + HB_SCRIPT_BATAK, /* Batk */ + HB_SCRIPT_BRAHMI, /* Brah */ + HB_SCRIPT_MANDAIC /* Mand */ +} 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); + +hb_bool_t +hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs); + +/* + * funcs + */ + + +/* typedefs */ + +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); + + +/* setters */ + +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); + + +/* getters */ + +/* These never return NULL. Return fallback defaults instead. */ + +hb_unicode_get_mirroring_func_t +hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs); + +hb_unicode_get_general_category_func_t +hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs); + +hb_unicode_get_script_func_t +hb_unicode_funcs_get_script_func (hb_unicode_funcs_t *ufuncs); + +hb_unicode_get_combining_class_func_t +hb_unicode_funcs_get_combining_class_func (hb_unicode_funcs_t *ufuncs); + +hb_unicode_get_eastasian_width_func_t +hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs); + + +/* accessors */ + +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 */ diff --git a/third_party/harfbuzz-ng/src/hb.h b/third_party/harfbuzz-ng/src/hb.h new file mode 100644 index 0000000..691adee --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb.h @@ -0,0 +1,41 @@ +/* + * 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" + +HB_BEGIN_DECLS +HB_END_DECLS + +#endif /* HB_H */ diff --git a/third_party/harfbuzz-ng/src/main.cc b/third_party/harfbuzz-ng/src/main.cc new file mode 100644 index 0000000..8126dae --- /dev/null +++ b/third_party/harfbuzz-ng/src/main.cc @@ -0,0 +1,196 @@ +/* + * 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> + +HB_BEGIN_DECLS + + +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, props 0x%04X\n", n_lookup, num_lookups, + lookup.get_type(), lookup.get_props()); + } + + } + 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; +} + + +HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/test.c b/third_party/harfbuzz-ng/src/test.c new file mode 100644 index 0000000..836dd4c --- /dev/null +++ b/third_party/harfbuzz-ng/src/test.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "hb.h" + +#ifdef HAVE_GLIB +#include <glib.h> +#endif +#include <stdlib.h> +#include <stdio.h> + +HB_BEGIN_DECLS + + +int +main (int argc, char **argv) +{ + hb_blob_t *blob = NULL; + hb_face_t *face = NULL; + + if (argc != 2) { + fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]); + exit (1); + } + + /* Create the blob */ + { + const char *font_data; + unsigned int len; + hb_destroy_func_t destroy; + void *user_data; + +#ifdef HAVE_GLIB + GMappedFile *mf = g_mapped_file_new (argv[1], FALSE, NULL); + font_data = g_mapped_file_get_contents (mf); + len = g_mapped_file_get_length (mf); + destroy = (hb_destroy_func_t) g_mapped_file_unref; + user_data = (void *) mf; +#else + FILE *f = fopen (argv[1], "rb"); + fseek (f, 0, SEEK_END); + len = ftell (f); + fseek (f, 0, SEEK_SET); + font_data = (const char *) malloc (len); + if (!font_data) len = 0; + len = fread ((char *) font_data, 1, len, f); + destroy = free; + user_data = (void *) font_data; + fclose (f); +#endif + + blob = hb_blob_create (font_data, len, + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, + destroy, user_data); + } + + /* Create the face */ + face = hb_face_create_for_data (blob, 0 /* first face */); + + /* So, what now? */ + + hb_face_destroy (face); + hb_blob_destroy (blob); + + return 0; +} diff --git a/third_party/harfbuzz/harfbuzz.gyp b/third_party/harfbuzz/harfbuzz.gyp index 308b170..64535be 100644 --- a/third_party/harfbuzz/harfbuzz.gyp +++ b/third_party/harfbuzz/harfbuzz.gyp @@ -3,47 +3,66 @@ # found in the LICENSE file. { - 'targets': [ - { - 'target_name': 'harfbuzz', - 'type': '<(library)', - 'sources': [ - 'contrib/harfbuzz-freetype.c', - 'contrib/harfbuzz-unicode.c', - 'contrib/harfbuzz-unicode-tables.c', - 'src/harfbuzz-buffer.c', - 'src/harfbuzz-stream.c', - 'src/harfbuzz-dump.c', - 'src/harfbuzz-gdef.c', - 'src/harfbuzz-gpos.c', - 'src/harfbuzz-gsub.c', - 'src/harfbuzz-impl.c', - 'src/harfbuzz-open.c', - 'src/harfbuzz-shaper.cpp', - 'src/harfbuzz-tibetan.c', - 'src/harfbuzz-khmer.c', - 'src/harfbuzz-indic.cpp', - 'src/harfbuzz-hebrew.c', - 'src/harfbuzz-arabic.c', - 'src/harfbuzz-hangul.c', - 'src/harfbuzz-myanmar.c', - 'src/harfbuzz-thai.c', + 'conditions': [ + ['use_harfbuzz_ng==0', { + 'targets': [ + { + 'target_name': 'harfbuzz', + 'type': '<(library)', + 'sources': [ + 'contrib/harfbuzz-freetype.c', + 'contrib/harfbuzz-unicode.c', + 'contrib/harfbuzz-unicode-tables.c', + 'src/harfbuzz-buffer.c', + 'src/harfbuzz-stream.c', + 'src/harfbuzz-dump.c', + 'src/harfbuzz-gdef.c', + 'src/harfbuzz-gpos.c', + 'src/harfbuzz-gsub.c', + 'src/harfbuzz-impl.c', + 'src/harfbuzz-open.c', + 'src/harfbuzz-shaper.cpp', + 'src/harfbuzz-tibetan.c', + 'src/harfbuzz-khmer.c', + 'src/harfbuzz-indic.cpp', + 'src/harfbuzz-hebrew.c', + 'src/harfbuzz-arabic.c', + 'src/harfbuzz-hangul.c', + 'src/harfbuzz-myanmar.c', + 'src/harfbuzz-thai.c', + ], + 'include_dirs': [ + 'contrib', + 'src', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + 'contrib', + 'src', + ], + }, + 'dependencies': [ + '../../build/linux/system.gyp:freetype2', + ], + }, ], - 'include_dirs': [ - 'contrib', - 'src', - ], - 'direct_dependent_settings': { - 'include_dirs': [ - 'contrib', - 'src', - ], - }, - 'dependencies': [ - '../../build/linux/system.gyp:freetype2', - ], - }, - ], + }, { # else, use new harfbuzz + 'targets': [ + { + # Make the 'harfbuzz' target just shim through to the harfbuzz-ng + # one. + 'target_name': 'harfbuzz', + 'type': 'settings', + 'dependencies': [ + '../harfbuzz-ng/harfbuzz.gyp:harfbuzz' + ], + 'export_dependent_settings': [ + '../harfbuzz-ng/harfbuzz.gyp:harfbuzz' + ], + } + ] + }] + ] } # Local Variables: |