diff options
author | bashi@google.com <bashi@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-30 11:34:19 +0000 |
---|---|---|
committer | bashi@google.com <bashi@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-30 11:34:19 +0000 |
commit | 681d5ae61568fa5e5149027edad6a616bbfd081d (patch) | |
tree | 6d1824f16ecb26faf30740d1030e2c27aea9d497 | |
parent | fb70ecf10de0dbc5065b677dc9235633afcbef38 (diff) | |
download | chromium_src-681d5ae61568fa5e5149027edad6a616bbfd081d.zip chromium_src-681d5ae61568fa5e5149027edad6a616bbfd081d.tar.gz chromium_src-681d5ae61568fa5e5149027edad6a616bbfd081d.tar.bz2 |
Update harfbuzz-ng to 1a5a91dc0d8bf4b72a2f22dc6300b06ad7000b79.
Preparing for using HarfBuzz-ng as a secondary text shaper on mac.
CoreText doesn't support OpenType features so we need additional
text shaper to support -webkit-font-feature-settings property.
I don't think this version is ready for transition on Linux because I
could see considerable performance regressions when I run cycler tests.
BUG=68551
TEST=None. This CL doesn't change build process for now.
Review URL: https://chromiumcodereview.appspot.com/9223010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119661 0039d316-1c4b-4281-b951-d872f2087c98
92 files changed, 11670 insertions, 5053 deletions
diff --git a/third_party/harfbuzz-ng/COPYING b/third_party/harfbuzz-ng/COPYING index 3fb9e51..4bb77a0 100644 --- a/third_party/harfbuzz-ng/COPYING +++ b/third_party/harfbuzz-ng/COPYING @@ -1,12 +1,14 @@ 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 +Copyright © 2011 Codethink Limited +Copyright © 2010,2011 Google, Inc. +Copyright © 2006 Behdad Esfahbod +Copyright © 2009 Keith Stribley +Copyright © 2009 Martin Hosken and SIL International +Copyright © 2007 Chris Wilson +Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc. +Copyright © 1998-2004 David Turner and Werner Lemberg + For full copyright notices consult the individual files in the package. diff --git a/third_party/harfbuzz-ng/README b/third_party/harfbuzz-ng/README index 06aad34..74e739d 100644 --- a/third_party/harfbuzz-ng/README +++ b/third_party/harfbuzz-ng/README @@ -1,9 +1,7 @@ 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 bug reports, mailing list, and other information please visit: -For license information, see the file COPYING. + http://harfbuzz.org/ -Behdad Esfahbod -18 November 2010 +For license information, see the file COPYING. diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium index ca393d0..9930732 100644 --- a/third_party/harfbuzz-ng/README.chromium +++ b/third_party/harfbuzz-ng/README.chromium @@ -1,7 +1,10 @@ Name: harfbuzz-ng +Short Name: harfbuzz-ng URL: http://freedesktop.org/wiki/Software/HarfBuzz Version: unknown -Revision: b0d396aa88b3cdf8cea896bfeeba197656e1cdb1 +Date: 20120127 +Revision: 1a5a91dc0d8bf4b72a2f22dc6300b06ad7000b79 +Security Critical: yes Description: This is harfbuzz-ng, a new implementation of harfbuzz with a different diff --git a/third_party/harfbuzz-ng/harfbuzz.gyp b/third_party/harfbuzz-ng/harfbuzz.gyp index c1ea3e4..ea8e48d 100644 --- a/third_party/harfbuzz-ng/harfbuzz.gyp +++ b/third_party/harfbuzz-ng/harfbuzz.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2009 The Chromium Authors. All rights reserved. +# Copyright (c) 2012 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. @@ -8,51 +8,79 @@ ], 'targets': [ { - 'target_name': 'harfbuzz', + 'target_name': 'harfbuzz-ng', 'type': 'static_library', + 'defines': [ + 'HAVE_OT', + 'HAVE_ICU', + ], 'sources': [ - 'src/hb-blob-private.h', - 'src/hb-blob.c', + 'src/hb-blob.cc', 'src/hb-blob.h', 'src/hb-buffer-private.hh', 'src/hb-buffer.cc', 'src/hb-buffer.h', - 'src/hb-common.c', + 'src/hb-common.cc', 'src/hb-common.h', - 'src/hb-font-private.h', + 'src/hb-fallback-shape-private.hh', + 'src/hb-fallback-shape.cc', + 'src/hb-font-private.hh', '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-glib.cc', + 'src/hb-glib.h', + 'src/hb-gobject-enums.cc', + 'src/hb-gobject-structs.cc', + 'src/hb-gobject.h', + 'src/hb-icu.cc', + 'src/hb-icu.h', + 'src/hb-mutex-private.hh', + 'src/hb-object-private.hh', 'src/hb-open-file-private.hh', 'src/hb-open-type-private.hh', - 'src/hb-ot-head-private.hh', + 'src/hb-ot-head-table.hh', + 'src/hb-ot-hhea-table.hh', + 'src/hb-ot-hmtx-table.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-gdef-table.hh', + 'src/hb-ot-layout-gpos-table.hh', + 'src/hb-ot-layout-gsub-table.hh', 'src/hb-ot-layout-gsubgpos-private.hh', 'src/hb-ot-layout-private.hh', 'src/hb-ot-layout.cc', + 'src/hb-ot-layout.h', 'src/hb-ot-map-private.hh', 'src/hb-ot-map.cc', - 'src/hb-ot-shape-complex-arabic-table.h', + 'src/hb-ot-maxp-table.hh', + 'src/hb-ot-name-table.hh', + 'src/hb-ot-shape-complex-arabic-table.hh', 'src/hb-ot-shape-complex-arabic.cc', + 'src/hb-ot-shape-complex-indic-machine.hh', + 'src/hb-ot-shape-complex-indic-table.hh', + 'src/hb-ot-shape-complex-indic.cc', + 'src/hb-ot-shape-complex-misc.cc', 'src/hb-ot-shape-complex-private.hh', + 'src/hb-ot-shape-normalize.cc', 'src/hb-ot-shape-private.hh', 'src/hb-ot-shape.cc', - 'src/hb-ot-tag.c', - 'src/hb-private.h', + 'src/hb-ot-shape.h', + 'src/hb-ot-tag.cc', + 'src/hb-ot-tag.h', + 'src/hb-ot.h', + 'src/hb-private.hh', 'src/hb-shape.cc', 'src/hb-shape.h', - 'src/hb-unicode-private.h', - 'src/hb-unicode.c', + 'src/hb-tt-font.cc', + 'src/hb-unicode-private.hh', + 'src/hb-unicode.cc', 'src/hb-unicode.h', + 'src/hb-version.h', 'src/hb.h', ], + 'sources/': [ + ['exclude', 'src/hb-glib\\.(cc|h)$'], + ['exclude', 'src/hb-gobject.*\\.(cc|h)$'], + ], 'include_dirs': [ 'src', ], @@ -62,9 +90,22 @@ ], }, 'dependencies': [ - '../../build/linux/system.gyp:freetype2', '../../third_party/icu/icu.gyp:icuuc', ], + 'conditions': [ + ['use_glib == 1', { + 'defines': [ + 'HAVE_GLIB', + ], + 'sources/': [ + ['include', 'src/hb-glib\\.(cc|h)$'], + ['include', 'src/hb-gobject.*\\.(cc|h)$'], + ], + 'dependencies': [ + '../../base/base.gyp:base', + ], + }], + ], }, ], } diff --git a/third_party/harfbuzz-ng/src/Makefile.am b/third_party/harfbuzz-ng/src/Makefile.am deleted file mode 100644 index 13107b9..0000000 --- a/third_party/harfbuzz-ng/src/Makefile.am +++ /dev/null @@ -1,147 +0,0 @@ -# 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 deleted file mode 100755 index 711d089..0000000 --- a/third_party/harfbuzz-ng/src/check-c-linkage-decls.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/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 deleted file mode 100755 index c966cd2..0000000 --- a/third_party/harfbuzz-ng/src/check-header-guards.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/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 deleted file mode 100755 index 124a7b0..0000000 --- a/third_party/harfbuzz-ng/src/check-internal-symbols.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/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 deleted file mode 100755 index c0abcbe4..0000000 --- a/third_party/harfbuzz-ng/src/check-libstdc++.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/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 deleted file mode 100755 index 08e54db..0000000 --- a/third_party/harfbuzz-ng/src/gen-arabic-joining-table.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/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.c b/third_party/harfbuzz-ng/src/hb-blob.c deleted file mode 100644 index 37e7787..0000000 --- a/third_party/harfbuzz-ng/src/hb-blob.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * 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.cc b/third_party/harfbuzz-ng/src/hb-blob.cc new file mode 100644 index 0000000..b2b1d9c --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-blob.cc @@ -0,0 +1,324 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-blob.h" +#include "hb-object-private.hh" + +#ifdef HAVE_SYS_MMAN_H +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* HAVE_UNISTD_H */ +#include <sys/mman.h> +#endif /* HAVE_SYS_MMAN_H */ + +#include <stdio.h> +#include <errno.h> + + + +#ifndef HB_DEBUG_BLOB +#define HB_DEBUG_BLOB (HB_DEBUG+0) +#endif + + +struct _hb_blob_t { + hb_object_header_t header; + + bool immutable; + + const char *data; + unsigned int length; + hb_memory_mode_t mode; + + void *user_data; + hb_destroy_func_t destroy; +}; + +static hb_blob_t _hb_blob_nil = { + HB_OBJECT_HEADER_STATIC, + + TRUE, /* immutable */ + + NULL, /* data */ + 0, /* length */ + HB_MEMORY_MODE_READONLY, /* mode */ + + NULL, /* user_data */ + NULL /* destroy */ +}; + + +static bool _try_writable (hb_blob_t *blob); + +static void +_hb_blob_destroy_user_data (hb_blob_t *blob) +{ + if (blob->destroy) { + blob->destroy (blob->user_data); + blob->user_data = NULL; + blob->destroy = NULL; + } +} + +hb_blob_t * +hb_blob_create (const char *data, + unsigned int length, + hb_memory_mode_t mode, + void *user_data, + hb_destroy_func_t destroy) +{ + hb_blob_t *blob; + + if (!length || !(blob = hb_object_create<hb_blob_t> ())) { + if (destroy) + destroy (user_data); + return &_hb_blob_nil; + } + + blob->data = data; + blob->length = length; + blob->mode = mode; + + blob->user_data = user_data; + blob->destroy = destroy; + + if (blob->mode == HB_MEMORY_MODE_DUPLICATE) { + blob->mode = HB_MEMORY_MODE_READONLY; + if (!_try_writable (blob)) { + hb_blob_destroy (blob); + return &_hb_blob_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; + + if (!length || offset >= parent->length) + return &_hb_blob_nil; + + hb_blob_make_immutable (parent); + + blob = hb_blob_create (parent->data + offset, + MIN (length, parent->length - offset), + parent->mode, + hb_blob_reference (parent), + (hb_destroy_func_t) hb_blob_destroy); + + return blob; +} + +hb_blob_t * +hb_blob_get_empty (void) +{ + return &_hb_blob_nil; +} + +hb_blob_t * +hb_blob_reference (hb_blob_t *blob) +{ + return hb_object_reference (blob); +} + +void +hb_blob_destroy (hb_blob_t *blob) +{ + if (!hb_object_destroy (blob)) return; + + _hb_blob_destroy_user_data (blob); + + free (blob); +} + +hb_bool_t +hb_blob_set_user_data (hb_blob_t *blob, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (blob, key, data, destroy, replace); +} + +void * +hb_blob_get_user_data (hb_blob_t *blob, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (blob, key); +} + + +void +hb_blob_make_immutable (hb_blob_t *blob) +{ + if (hb_object_is_inert (blob)) + return; + + blob->immutable = TRUE; +} + +hb_bool_t +hb_blob_is_immutable (hb_blob_t *blob) +{ + return blob->immutable; +} + + +unsigned int +hb_blob_get_length (hb_blob_t *blob) +{ + return blob->length; +} + +const char * +hb_blob_get_data (hb_blob_t *blob, unsigned int *length) +{ + if (length) + *length = blob->length; + + return blob->data; +} + +char * +hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) +{ + if (!_try_writable (blob)) { + if (length) + *length = 0; + + return NULL; + } + + if (length) + *length = blob->length; + + return const_cast<char *> (blob->data); +} + + +static hb_bool_t +_try_make_writable_inplace_unix (hb_blob_t *blob) +{ +#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) + uintptr_t pagesize = -1, mask, length; + const char *addr; + +#if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) + pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE); +#elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) + pagesize = (uintptr_t) sysconf (_SC_PAGESIZE); +#elif defined(HAVE_GETPAGESIZE) + pagesize = (uintptr_t) getpagesize (); +#endif + + if ((uintptr_t) -1L == pagesize) { + DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno)); + return FALSE; + } + DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize); + + mask = ~(pagesize-1); + addr = (const char *) (((uintptr_t) blob->data) & mask); + length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask) - addr; + DEBUG_MSG_FUNC (BLOB, blob, + "calling mprotect on [%p..%p] (%lu bytes)", + addr, addr+length, (unsigned long) length); + if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) { + DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno)); + return FALSE; + } + + blob->mode = HB_MEMORY_MODE_WRITABLE; + + DEBUG_MSG_FUNC (BLOB, blob, + "successfully made [%p..%p] (%lu bytes) writable\n", + addr, addr+length, (unsigned long) length); + return TRUE; +#else + return FALSE; +#endif +} + +static bool +_try_writable_inplace (hb_blob_t *blob) +{ + DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n"); + + if (_try_make_writable_inplace_unix (blob)) + return TRUE; + + DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n"); + + /* Failed to make writable inplace, mark that */ + blob->mode = HB_MEMORY_MODE_READONLY; + return FALSE; +} + +static bool +_try_writable (hb_blob_t *blob) +{ + if (blob->immutable) + return FALSE; + + if (blob->mode == HB_MEMORY_MODE_WRITABLE) + return TRUE; + + if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob)) + return TRUE; + + if (blob->mode == HB_MEMORY_MODE_WRITABLE) + return TRUE; + + + DEBUG_MSG_FUNC (BLOB, blob, "currect data is -> %p\n", blob->data); + + char *new_data; + + new_data = (char *) malloc (blob->length); + if (unlikely (!new_data)) + return FALSE; + + DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data); + + memcpy (new_data, blob->data, blob->length); + _hb_blob_destroy_user_data (blob); + blob->mode = HB_MEMORY_MODE_WRITABLE; + blob->data = new_data; + blob->user_data = new_data; + blob->destroy = free; + + return TRUE; +} + + diff --git a/third_party/harfbuzz-ng/src/hb-blob.h b/third_party/harfbuzz-ng/src/hb-blob.h index dbbfc90..50c9ae3 100644 --- a/third_party/harfbuzz-ng/src/hb-blob.h +++ b/third_party/harfbuzz-ng/src/hb-blob.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -45,8 +45,8 @@ 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); + void *user_data, + hb_destroy_func_t destroy); hb_blob_t * hb_blob_create_sub_blob (hb_blob_t *parent, @@ -54,34 +54,42 @@ hb_blob_create_sub_blob (hb_blob_t *parent, unsigned int length); hb_blob_t * -hb_blob_create_empty (void); +hb_blob_get_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); +hb_bool_t +hb_blob_set_user_data (hb_blob_t *blob, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_blob_get_user_data (hb_blob_t *blob, + hb_user_data_key_t *key); -const char * -hb_blob_lock (hb_blob_t *blob); void -hb_blob_unlock (hb_blob_t *blob); +hb_blob_make_immutable (hb_blob_t *blob); hb_bool_t -hb_blob_is_writable (hb_blob_t *blob); +hb_blob_is_immutable (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); +unsigned int +hb_blob_get_length (hb_blob_t *blob); + +const char * +hb_blob_get_data (hb_blob_t *blob, unsigned int *length); + +char * +hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-buffer-private.hh b/third_party/harfbuzz-ng/src/hb-buffer-private.hh index a129165..4292222 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer-private.hh +++ b/third_party/harfbuzz-ng/src/hb-buffer-private.hh @@ -1,8 +1,9 @@ /* - * Copyright (C) 1998-2004 David Turner and Werner Lemberg - * Copyright (C) 2004,2007,2009,2010 Red Hat, Inc. + * Copyright © 1998-2004 David Turner and Werner Lemberg + * Copyright © 2004,2007,2009,2010 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * - * This is part of HarfBuzz, a text shaping library. + * 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 @@ -23,16 +24,17 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Owen Taylor, Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_BUFFER_PRIVATE_HH #define HB_BUFFER_PRIVATE_HH -#include "hb-private.h" +#include "hb-private.hh" #include "hb-buffer.h" -#include "hb-unicode-private.h" +#include "hb-object-private.hh" +#include "hb-unicode-private.hh" -HB_BEGIN_DECLS ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20); @@ -45,44 +47,8 @@ typedef struct _hb_segment_properties_t { } 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; + hb_object_header_t header; /* Information about how the text in the buffer should be treated */ @@ -91,56 +57,100 @@ struct _hb_buffer_t { /* 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 */ + bool in_error; /* Allocation failed */ + bool have_output; /* Whether we have an output buffer going on */ + bool have_positions; /* Whether we have positions */ - unsigned int i; /* Cursor into ->info and ->pos arrays */ + unsigned int idx; /* Cursor into ->info and ->pos arrays */ unsigned int len; /* Length of ->info and ->pos arrays */ - unsigned int out_len; /* Length of ->out array */ + unsigned int out_len; /* Length of ->out array if have_output */ + unsigned int allocated; /* Length of allocated arrays */ hb_glyph_info_t *info; hb_glyph_info_t *out_info; hb_glyph_position_t *pos; - /* Other stuff */ - unsigned int serial; + uint8_t allocated_var_bytes[8]; + const char *allocated_var_owner[8]; /* Methods */ + + HB_INTERNAL void reset (void); + + inline unsigned int backtrack_len (void) const + { return have_output? out_len : idx; } 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, + + HB_INTERNAL void allocate_var (unsigned int byte_i, unsigned int count, const char *owner); + HB_INTERNAL void deallocate_var (unsigned int byte_i, unsigned int count, const char *owner); + HB_INTERNAL void deallocate_var_all (void); + + HB_INTERNAL void add (hb_codepoint_t codepoint, + hb_mask_t mask, + unsigned int cluster); + + HB_INTERNAL void reverse_range (unsigned int start, unsigned int end); + HB_INTERNAL void reverse (void); + HB_INTERNAL void reverse_clusters (void); + HB_INTERNAL void guess_properties (void); + + HB_INTERNAL void swap_buffers (void); + HB_INTERNAL void clear_output (void); + HB_INTERNAL void clear_positions (void); + HB_INTERNAL void replace_glyphs_be16 (unsigned int num_in, + unsigned int num_out, + const uint16_t *glyph_data_be); + HB_INTERNAL void replace_glyphs (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); } + const uint16_t *glyph_data); + HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index); + /* Makes a copy of the glyph at idx to output and replace glyph_index */ + HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index); + /* Copies glyph at idx to output but doesn't advance idx */ + HB_INTERNAL void copy_glyph (void); + /* Copies glyph at idx to output and advance idx. + * If there's no output, just advance idx. */ + HB_INTERNAL void next_glyph (void); + /* Advance idx without copying to output. */ + inline void skip_glyph (void) { idx++; } inline void reset_masks (hb_mask_t mask) { - for (unsigned int i = 0; i < len; i++) - info[i].mask = mask; + for (unsigned int j = 0; j < len; j++) + info[j].mask = mask; } inline void add_masks (hb_mask_t mask) { - for (unsigned int i = 0; i < len; i++) - info[i].mask |= mask; + for (unsigned int j = 0; j < len; j++) + info[j].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_INTERNAL void set_masks (hb_mask_t value, + hb_mask_t mask, + unsigned int cluster_start, + unsigned int cluster_end); + /* Internal methods */ + HB_INTERNAL bool enlarge (unsigned int size); + + inline bool ensure (unsigned int size) + { return likely (size <= allocated) ? TRUE : enlarge (size); } + + HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out); + + HB_INTERNAL void *get_scratch_buffer (unsigned int *size); }; -HB_END_DECLS +#define HB_BUFFER_XALLOCATE_VAR(b, func, var, owner) \ + b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \ + sizeof (b->info[0].var), owner) +#define HB_BUFFER_ALLOCATE_VAR(b, var) \ + HB_BUFFER_XALLOCATE_VAR (b, allocate_var, var (), #var) +#define HB_BUFFER_DEALLOCATE_VAR(b, var) \ + HB_BUFFER_XALLOCATE_VAR (b, deallocate_var, var (), #var) + + #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 index 03e8e1a..e8bdfb1 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer.cc +++ b/third_party/harfbuzz-ng/src/hb-buffer.cc @@ -1,8 +1,9 @@ /* - * Copyright (C) 1998-2004 David Turner and Werner Lemberg - * Copyright (C) 2004,2007,2009,2010 Red Hat, Inc. + * Copyright © 1998-2004 David Turner and Werner Lemberg + * Copyright © 2004,2007,2009,2010 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * - * This is part of HarfBuzz, a text shaping library. + * 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 @@ -23,19 +24,33 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Owen Taylor, Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #include "hb-buffer-private.hh" #include <string.h> -HB_BEGIN_DECLS + + +#ifndef HB_DEBUG_BUFFER +#define HB_DEBUG_BUFFER (HB_DEBUG+0) +#endif static hb_buffer_t _hb_buffer_nil = { - HB_REFERENCE_COUNT_INVALID, /* ref_count */ + HB_OBJECT_HEADER_STATIC, - &_hb_unicode_funcs_nil /* unicode */ + &_hb_unicode_funcs_default, + { + HB_DIRECTION_INVALID, + HB_SCRIPT_INVALID, + NULL, + }, + + TRUE, /* in_error */ + TRUE, /* have_output */ + TRUE /* have_positions */ }; /* Here is how the buffer works internally: @@ -45,392 +60,630 @@ static hb_buffer_t _hb_buffer_nil = { * * 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 + * case as long as out_len doesn't exceed i at any time. + * In that case, swap_buffers() 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 + * This should all remain transparent to the user. swap_buffers() then * switches info and out_info. */ -static hb_bool_t -_hb_buffer_enlarge (hb_buffer_t *buffer, unsigned int size) + +/* Internal API */ + +bool +hb_buffer_t::enlarge (unsigned int size) { - if (unlikely (buffer->in_error)) + if (unlikely (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; + unsigned int new_allocated = allocated; + hb_glyph_position_t *new_pos = NULL; + hb_glyph_info_t *new_info = NULL; + bool separate_out = out_info != info; - separate_out = buffer->out_info != buffer->info; + if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0])))) + goto done; while (size > new_allocated) - new_allocated += (new_allocated >> 1) + 8; + new_allocated += (new_allocated >> 1) + 32; + + ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0])); + if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0])))) + goto done; - 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])); + new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0])); + new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0])); +done: if (unlikely (!new_pos || !new_info)) - buffer->in_error = TRUE; + in_error = TRUE; if (likely (new_pos)) - buffer->pos = new_pos; + pos = new_pos; if (likely (new_info)) - buffer->info = new_info; + 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; + out_info = separate_out ? (hb_glyph_info_t *) pos : info; + if (likely (!in_error)) + allocated = new_allocated; - return likely (!buffer->in_error); + return likely (!in_error); } -static inline hb_bool_t -_hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size) +bool +hb_buffer_t::make_room_for (unsigned int num_in, + unsigned int num_out) { - 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 (unlikely (!ensure (out_len + num_out))) return FALSE; - if (buffer->out_info == buffer->info) + if (out_info == info && + out_len + num_out > idx + num_in) { - assert (buffer->have_output); + assert (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])); + out_info = (hb_glyph_info_t *) pos; + memcpy (out_info, info, out_len * sizeof (out_info[0])); } return TRUE; } +void * +hb_buffer_t::get_scratch_buffer (unsigned int *size) +{ + have_output = FALSE; + have_positions = FALSE; + out_len = 0; + *size = allocated * sizeof (pos[0]); + return pos; +} -/* Public API */ -hb_buffer_t * -hb_buffer_create (unsigned int pre_alloc_size) +/* HarfBuzz-Internal API */ + +void +hb_buffer_t::reset (void) { - hb_buffer_t *buffer; + if (unlikely (hb_object_is_inert (this))) + return; - if (!HB_OBJECT_DO_CREATE (hb_buffer_t, buffer)) - return &_hb_buffer_nil; + hb_unicode_funcs_destroy (unicode); + unicode = _hb_buffer_nil.unicode; - if (pre_alloc_size) - _hb_buffer_ensure (buffer, pre_alloc_size); + props = _hb_buffer_nil.props; - buffer->unicode = &_hb_unicode_funcs_nil; + in_error = FALSE; + have_output = FALSE; + have_positions = FALSE; - return buffer; -} + idx = 0; + len = 0; + out_len = 0; -hb_buffer_t * -hb_buffer_reference (hb_buffer_t *buffer) -{ - HB_OBJECT_DO_REFERENCE (buffer); -} + serial = 0; + memset (allocated_var_bytes, 0, sizeof allocated_var_bytes); + memset (allocated_var_owner, 0, sizeof allocated_var_owner); -unsigned int -hb_buffer_get_reference_count (hb_buffer_t *buffer) -{ - HB_OBJECT_DO_GET_REFERENCE_COUNT (buffer); + out_info = info; } void -hb_buffer_destroy (hb_buffer_t *buffer) +hb_buffer_t::add (hb_codepoint_t codepoint, + hb_mask_t mask, + unsigned int cluster) { - HB_OBJECT_DO_DESTROY (buffer); + hb_glyph_info_t *glyph; - hb_unicode_funcs_destroy (buffer->unicode); + if (unlikely (!ensure (len + 1))) return; - free (buffer->info); - free (buffer->pos); + glyph = &info[len]; - free (buffer); -} + memset (glyph, 0, sizeof (*glyph)); + glyph->codepoint = codepoint; + glyph->mask = mask; + glyph->cluster = cluster; + len++; +} void -hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, - hb_unicode_funcs_t *unicode) +hb_buffer_t::clear_output (void) { - if (!unicode) - unicode = &_hb_unicode_funcs_nil; + if (unlikely (hb_object_is_inert (this))) + return; - hb_unicode_funcs_reference (unicode); - hb_unicode_funcs_destroy (buffer->unicode); - buffer->unicode = unicode; + have_output = TRUE; + have_positions = FALSE; + + out_len = 0; + out_info = info; } -hb_unicode_funcs_t * -hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) +void +hb_buffer_t::clear_positions (void) { - return buffer->unicode; + if (unlikely (hb_object_is_inert (this))) + return; + + have_output = FALSE; + have_positions = TRUE; + + memset (pos, 0, sizeof (pos[0]) * len); } void -hb_buffer_set_direction (hb_buffer_t *buffer, - hb_direction_t direction) - +hb_buffer_t::swap_buffers (void) { - buffer->props.direction = direction; + if (unlikely (in_error)) return; + + assert (have_output); + + if (out_info != info) + { + hb_glyph_info_t *tmp_string; + tmp_string = info; + info = out_info; + out_info = tmp_string; + pos = (hb_glyph_position_t *) out_info; + } + + unsigned int tmp; + tmp = len; + len = out_len; + out_len = tmp; + + idx = 0; } -hb_direction_t -hb_buffer_get_direction (hb_buffer_t *buffer) +void +hb_buffer_t::replace_glyphs_be16 (unsigned int num_in, + unsigned int num_out, + const uint16_t *glyph_data_be) { - return buffer->props.direction; + if (!make_room_for (num_in, num_out)) return; + + hb_glyph_info_t orig_info = info[idx]; + for (unsigned int i = 1; i < num_in; i++) + { + hb_glyph_info_t *inf = &info[idx + i]; + orig_info.cluster = MIN (orig_info.cluster, inf->cluster); + } + + hb_glyph_info_t *pinfo = &out_info[out_len]; + for (unsigned int i = 0; i < num_out; i++) + { + *pinfo = orig_info; + pinfo->codepoint = hb_be_uint16 (glyph_data_be[i]); + pinfo++; + } + + idx += num_in; + out_len += num_out; } void -hb_buffer_set_script (hb_buffer_t *buffer, - hb_script_t script) +hb_buffer_t::replace_glyphs (unsigned int num_in, + unsigned int num_out, + const uint16_t *glyph_data) { - buffer->props.script = script; + if (!make_room_for (num_in, num_out)) return; + + hb_glyph_info_t orig_info = info[idx]; + for (unsigned int i = 1; i < num_in; i++) + { + hb_glyph_info_t *inf = &info[idx + i]; + orig_info.cluster = MIN (orig_info.cluster, inf->cluster); + } + + hb_glyph_info_t *pinfo = &out_info[out_len]; + for (unsigned int i = 0; i < num_out; i++) + { + *pinfo = orig_info; + pinfo->codepoint = glyph_data[i]; + pinfo++; + } + + idx += num_in; + out_len += num_out; } -hb_script_t -hb_buffer_get_script (hb_buffer_t *buffer) +void +hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) { - return buffer->props.script; + if (!make_room_for (0, 1)) return; + + out_info[out_len] = info[idx]; + out_info[out_len].codepoint = glyph_index; + + out_len++; } void -hb_buffer_set_language (hb_buffer_t *buffer, - hb_language_t language) +hb_buffer_t::copy_glyph (void) { - buffer->props.language = language; + if (!make_room_for (0, 1)) return; + + out_info[out_len] = info[idx]; + + out_len++; } -hb_language_t -hb_buffer_get_language (hb_buffer_t *buffer) +void +hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index) { - return buffer->props.language; -} + if (!make_room_for (1, 1)) return; + out_info[out_len] = info[idx]; + out_info[out_len].codepoint = glyph_index; + + idx++; + out_len++; +} void -hb_buffer_clear (hb_buffer_t *buffer) +hb_buffer_t::next_glyph (void) { - 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; + if (have_output) + { + if (out_info != info) + { + if (unlikely (!ensure (out_len + 1))) return; + out_info[out_len] = info[idx]; + } + else if (out_len != idx) + out_info[out_len] = info[idx]; + + out_len++; + } + + idx++; } -hb_bool_t -hb_buffer_ensure (hb_buffer_t *buffer, unsigned int size) +void +hb_buffer_t::set_masks (hb_mask_t value, + hb_mask_t mask, + unsigned int cluster_start, + unsigned int cluster_end) { - return _hb_buffer_ensure (buffer, size); + hb_mask_t not_mask = ~mask; + value &= mask; + + if (!mask) + return; + + if (cluster_start == 0 && cluster_end == (unsigned int)-1) { + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + info[i].mask = (info[i].mask & not_mask) | value; + return; + } + + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) + info[i].mask = (info[i].mask & not_mask) | value; } void -hb_buffer_add_glyph (hb_buffer_t *buffer, - hb_codepoint_t codepoint, - hb_mask_t mask, - unsigned int cluster) +hb_buffer_t::reverse_range (unsigned int start, + unsigned int end) { - hb_glyph_info_t *glyph; + unsigned int i, j; - if (unlikely (!_hb_buffer_ensure (buffer, buffer->len + 1))) return; + if (start == end - 1) + return; - glyph = &buffer->info[buffer->len]; + for (i = start, j = end - 1; i < j; i++, j--) { + hb_glyph_info_t t; - memset (glyph, 0, sizeof (*glyph)); - glyph->codepoint = codepoint; - glyph->mask = mask; - glyph->cluster = cluster; + t = info[i]; + info[i] = info[j]; + info[j] = t; + } + + if (pos) { + for (i = start, j = end - 1; i < j; i++, j--) { + hb_glyph_position_t t; - buffer->len++; + t = pos[i]; + pos[i] = pos[j]; + pos[j] = t; + } + } } void -hb_buffer_clear_positions (hb_buffer_t *buffer) +hb_buffer_t::reverse (void) { - _hb_buffer_clear_output (buffer); - buffer->have_output = FALSE; - buffer->have_positions = TRUE; + if (unlikely (!len)) + return; - if (unlikely (!buffer->pos)) - { - buffer->pos = (hb_glyph_position_t *) calloc (buffer->allocated, sizeof (buffer->pos[0])); + reverse_range (0, len); +} + +void +hb_buffer_t::reverse_clusters (void) +{ + unsigned int i, start, count, last_cluster; + + if (unlikely (!len)) return; + + reverse (); + + count = len; + start = 0; + last_cluster = info[0].cluster; + for (i = 1; i < count; i++) { + if (last_cluster != info[i].cluster) { + reverse_range (start, i); + start = i; + last_cluster = info[i].cluster; + } + } + reverse_range (start, i); +} + +void +hb_buffer_t::guess_properties (void) +{ + /* If script is set to INVALID, guess from buffer contents */ + if (props.script == HB_SCRIPT_INVALID) { + for (unsigned int i = 0; i < len; i++) { + hb_script_t script = hb_unicode_script (unicode, info[i].codepoint); + if (likely (script != HB_SCRIPT_COMMON && + script != HB_SCRIPT_INHERITED && + script != HB_SCRIPT_UNKNOWN)) { + props.script = script; + break; + } + } } - memset (buffer->pos, 0, sizeof (buffer->pos[0]) * buffer->len); + /* If direction is set to INVALID, guess from script */ + if (props.direction == HB_DIRECTION_INVALID) { + props.direction = hb_script_get_horizontal_direction (props.script); + } + + /* If language is not set, use default language from locale */ + if (props.language == HB_LANGUAGE_INVALID) { + /* TODO get_default_for_script? using $LANGUAGE */ + props.language = hb_language_get_default (); + } } -/* HarfBuzz-Internal API */ -void -_hb_buffer_clear_output (hb_buffer_t *buffer) +static inline void +dump_var_allocation (const hb_buffer_t *buffer) { - buffer->have_output = TRUE; - buffer->have_positions = FALSE; - buffer->out_len = 0; - buffer->out_info = buffer->info; + char buf[80]; + for (unsigned int i = 0; i < 8; i++) + buf[i] = '0' + buffer->allocated_var_bytes[7 - i]; + buf[8] = '\0'; + DEBUG_MSG (BUFFER, buffer, + "Current var allocation: %s", + buf); } -void -_hb_buffer_swap (hb_buffer_t *buffer) +void hb_buffer_t::allocate_var (unsigned int byte_i, unsigned int count, const char *owner) { - unsigned int tmp; + assert (byte_i < 8 && byte_i + count <= 8); - assert (buffer->have_output); + if (DEBUG (BUFFER)) + dump_var_allocation (this); + DEBUG_MSG (BUFFER, this, + "Allocating var bytes %d..%d for %s", + byte_i, byte_i + count - 1, owner); - if (unlikely (buffer->in_error)) return; + for (unsigned int i = byte_i; i < byte_i + count; i++) { + assert (!allocated_var_bytes[i]); + allocated_var_bytes[i]++; + allocated_var_owner[i] = owner; + } +} - 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; +void hb_buffer_t::deallocate_var (unsigned int byte_i, unsigned int count, const char *owner) +{ + if (DEBUG (BUFFER)) + dump_var_allocation (this); + + DEBUG_MSG (BUFFER, this, + "Deallocating var bytes %d..%d for %s", + byte_i, byte_i + count - 1, owner); + + assert (byte_i < 8 && byte_i + count <= 8); + for (unsigned int i = byte_i; i < byte_i + count; i++) { + assert (allocated_var_bytes[i]); + assert (0 == strcmp (allocated_var_owner[i], owner)); + allocated_var_bytes[i]--; } +} + +void hb_buffer_t::deallocate_var_all (void) +{ + memset (allocated_var_bytes, 0, sizeof (allocated_var_bytes)); + memset (allocated_var_owner, 0, sizeof (allocated_var_owner)); +} + +/* Public API */ - tmp = buffer->len; - buffer->len = buffer->out_len; - buffer->out_len = tmp; +hb_buffer_t * +hb_buffer_create () +{ + hb_buffer_t *buffer; - buffer->i = 0; + if (!(buffer = hb_object_create<hb_buffer_t> ())) + return &_hb_buffer_nil; + + buffer->reset (); + + return buffer; +} + +hb_buffer_t * +hb_buffer_get_empty (void) +{ + return &_hb_buffer_nil; +} + +hb_buffer_t * +hb_buffer_reference (hb_buffer_t *buffer) +{ + return hb_object_reference (buffer); } 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_buffer_destroy (hb_buffer_t *buffer) { - 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; - } + if (!hb_object_destroy (buffer)) return; - hb_glyph_info_t orig_info = buffer->info[buffer->i]; + hb_unicode_funcs_destroy (buffer->unicode); - 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]); - } + free (buffer->info); + free (buffer->pos); + + free (buffer); +} - buffer->i += num_in; - buffer->out_len += num_out; +hb_bool_t +hb_buffer_set_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (buffer, key, data, destroy, replace); } +void * +hb_buffer_get_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (buffer, key); +} + + void -_hb_buffer_replace_glyph (hb_buffer_t *buffer, - hb_codepoint_t glyph_index) +hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, + hb_unicode_funcs_t *unicode) { - hb_glyph_info_t *info; + if (unlikely (hb_object_is_inert (buffer))) + return; - 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]; + if (!unicode) + unicode = _hb_buffer_nil.unicode; - info = &buffer->out_info[buffer->out_len]; - info->codepoint = glyph_index; + hb_unicode_funcs_reference (unicode); + hb_unicode_funcs_destroy (buffer->unicode); + buffer->unicode = unicode; +} - buffer->i++; - buffer->out_len++; +hb_unicode_funcs_t * +hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) +{ + return buffer->unicode; } void -_hb_buffer_next_glyph (hb_buffer_t *buffer) +hb_buffer_set_direction (hb_buffer_t *buffer, + hb_direction_t direction) + { - 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]; + if (unlikely (hb_object_is_inert (buffer))) + return; - buffer->out_len++; - } + buffer->props.direction = direction; +} - buffer->i++; +hb_direction_t +hb_buffer_get_direction (hb_buffer_t *buffer) +{ + return buffer->props.direction; } void -_hb_buffer_reset_masks (hb_buffer_t *buffer, - hb_mask_t mask) +hb_buffer_set_script (hb_buffer_t *buffer, + hb_script_t script) { - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - buffer->info[i].mask = mask; + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->props.script = script; +} + +hb_script_t +hb_buffer_get_script (hb_buffer_t *buffer) +{ + return buffer->props.script; } void -_hb_buffer_add_masks (hb_buffer_t *buffer, - hb_mask_t mask) +hb_buffer_set_language (hb_buffer_t *buffer, + hb_language_t language) { - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - buffer->info[i].mask |= mask; + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->props.language = language; +} + +hb_language_t +hb_buffer_get_language (hb_buffer_t *buffer) +{ + return buffer->props.language; } + 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_buffer_reset (hb_buffer_t *buffer) { - hb_mask_t not_mask = ~mask; - value &= mask; + buffer->reset (); +} - if (!mask) - return; +hb_bool_t +hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) +{ + return buffer->ensure (size); +} - 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; - } +hb_bool_t +hb_buffer_allocation_successful (hb_buffer_t *buffer) +{ + return !buffer->in_error; +} - /* 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; +void +hb_buffer_add (hb_buffer_t *buffer, + hb_codepoint_t codepoint, + hb_mask_t mask, + unsigned int cluster) +{ + buffer->add (codepoint, mask, cluster); } +hb_bool_t +hb_buffer_set_length (hb_buffer_t *buffer, + unsigned int length) +{ + if (!buffer->ensure (length)) + return FALSE; + + /* Wipe the new space */ + if (length > buffer->len) { + memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); + if (buffer->have_positions) + memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); + } -/* Public API again */ + buffer->len = length; + return TRUE; +} unsigned int hb_buffer_get_length (hb_buffer_t *buffer) @@ -440,90 +693,67 @@ 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) +hb_buffer_get_glyph_infos (hb_buffer_t *buffer, + unsigned int *length) { + if (length) + *length = buffer->len; + 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) +hb_buffer_get_glyph_positions (hb_buffer_t *buffer, + unsigned int *length) { 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; - } + buffer->clear_positions (); - if (buffer->pos) { - for (i = 0, j = end - 1; i < j; i++, j--) { - hb_glyph_position_t t; + if (length) + *length = buffer->len; - t = buffer->pos[i]; - buffer->pos[i] = buffer->pos[j]; - buffer->pos[j] = t; - } - } + return (hb_glyph_position_t *) buffer->pos; } void hb_buffer_reverse (hb_buffer_t *buffer) { - if (unlikely (!buffer->len)) - return; - - reverse_range (buffer, 0, buffer->len); + buffer->reverse (); } 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); + buffer->reverse_clusters (); } +void +hb_buffer_guess_properties (hb_buffer_t *buffer) +{ + buffer->guess_properties (); +} #define ADD_UTF(T) \ HB_STMT_START { \ + if (text_length == -1) { \ + text_length = 0; \ + const T *p = (const T *) text; \ + while (*p) { \ + text_length++; \ + p++; \ + } \ + } \ + if (item_length == -1) \ + item_length = text_length - item_offset; \ + buffer->ensure (buffer->len + item_length * sizeof (T) / 4); \ 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_buffer_add (buffer, u, 1, old_next - (const T *) text); \ } \ } HB_STMT_END @@ -543,7 +773,7 @@ hb_utf8_next (const uint8_t *text, uint8_t c = *text; unsigned int mask, len; - /* TODO check for overlong sequences? also: optimize? */ + /* TODO check for overlong sequences? */ UTF8_COMPUTE (c, mask, len); if (unlikely (!len || (unsigned int) (end - text) < len)) { @@ -571,9 +801,9 @@ hb_utf8_next (const uint8_t *text, void hb_buffer_add_utf8 (hb_buffer_t *buffer, const char *text, - unsigned int text_length HB_UNUSED, + int text_length, unsigned int item_offset, - unsigned int item_length) + int item_length) { #define UTF_NEXT(S, E, U) hb_utf8_next (S, E, &(U)) ADD_UTF (uint8_t); @@ -590,7 +820,7 @@ hb_utf16_next (const uint16_t *text, if (unlikely (c >= 0xd800 && c < 0xdc00)) { /* high surrogate */ uint16_t l; - if (text < end && ((l = *text), unlikely (l >= 0xdc00 && l < 0xe000))) { + if (text < end && ((l = *text), likely (l >= 0xdc00 && l < 0xe000))) { /* low surrogate */ *unicode = ((hb_codepoint_t) ((c) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000); text++; @@ -605,9 +835,9 @@ hb_utf16_next (const uint16_t *text, void hb_buffer_add_utf16 (hb_buffer_t *buffer, const uint16_t *text, - unsigned int text_length HB_UNUSED, + int text_length, unsigned int item_offset, - unsigned int item_length) + int item_length) { #define UTF_NEXT(S, E, U) hb_utf16_next (S, E, &(U)) ADD_UTF (uint16_t); @@ -617,9 +847,9 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer, void hb_buffer_add_utf32 (hb_buffer_t *buffer, const uint32_t *text, - unsigned int text_length HB_UNUSED, + int text_length, unsigned int item_offset, - unsigned int item_length) + int item_length) { #define UTF_NEXT(S, E, U) ((U) = *(S), (S)+1) ADD_UTF (uint32_t); @@ -627,4 +857,3 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer, } -HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-buffer.h b/third_party/harfbuzz-ng/src/hb-buffer.h index 0185415..9582ebe 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer.h +++ b/third_party/harfbuzz-ng/src/hb-buffer.h @@ -1,8 +1,9 @@ /* - * Copyright (C) 1998-2004 David Turner and Werner Lemberg - * Copyright (C) 2004,2007,2009 Red Hat, Inc. + * Copyright © 1998-2004 David Turner and Werner Lemberg + * Copyright © 2004,2007,2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * - * This is part of HarfBuzz, a text shaping library. + * 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 @@ -23,6 +24,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Owen Taylor, Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_BUFFER_H @@ -30,7 +32,6 @@ #include "hb-common.h" #include "hb-unicode.h" -#include "hb-language.h" HB_BEGIN_DECLS @@ -41,6 +42,8 @@ typedef struct _hb_glyph_info_t { hb_codepoint_t codepoint; hb_mask_t mask; uint32_t cluster; + + /*< private >*/ hb_var_int_t var1; hb_var_int_t var2; } hb_glyph_info_t; @@ -50,22 +53,35 @@ typedef struct _hb_glyph_position_t { hb_position_t y_advance; hb_position_t x_offset; hb_position_t y_offset; + + /*< private >*/ hb_var_int_t var; } hb_glyph_position_t; hb_buffer_t * -hb_buffer_create (unsigned int pre_alloc_size); +hb_buffer_create (void); hb_buffer_t * -hb_buffer_reference (hb_buffer_t *buffer); +hb_buffer_get_empty (void); -unsigned int -hb_buffer_get_reference_count (hb_buffer_t *buffer); +hb_buffer_t * +hb_buffer_reference (hb_buffer_t *buffer); void hb_buffer_destroy (hb_buffer_t *buffer); +hb_bool_t +hb_buffer_set_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + +void * +hb_buffer_get_user_data (hb_buffer_t *buffer, + hb_user_data_key_t *key); + void hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, @@ -96,15 +112,20 @@ hb_language_t hb_buffer_get_language (hb_buffer_t *buffer); +/* Resets the buffer. Afterwards it's as if it was just created, + * except that it has a larger buffer allocated perhaps... */ void -hb_buffer_clear (hb_buffer_t *buffer); +hb_buffer_reset (hb_buffer_t *buffer); + +/* Returns FALSE if allocation failed */ +hb_bool_t +hb_buffer_pre_allocate (hb_buffer_t *buffer, + unsigned int size); -void -hb_buffer_clear_positions (hb_buffer_t *buffer); +/* Returns FALSE if allocation has failed before */ hb_bool_t -hb_buffer_ensure (hb_buffer_t *buffer, - unsigned int size); +hb_buffer_allocation_successful (hb_buffer_t *buffer); void hb_buffer_reverse (hb_buffer_t *buffer); @@ -112,50 +133,60 @@ hb_buffer_reverse (hb_buffer_t *buffer); void hb_buffer_reverse_clusters (hb_buffer_t *buffer); +void +hb_buffer_guess_properties (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); +hb_buffer_add (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, + int text_length, unsigned int item_offset, - unsigned int item_length); + int item_length); void hb_buffer_add_utf16 (hb_buffer_t *buffer, const uint16_t *text, - unsigned int text_length, + int text_length, unsigned int item_offset, - unsigned int item_length); + int item_length); void hb_buffer_add_utf32 (hb_buffer_t *buffer, const uint32_t *text, - unsigned int text_length, + int text_length, unsigned int item_offset, - unsigned int item_length); + int item_length); -/* Getting glyphs out of the buffer */ +/* Clears any new items added at the end */ +hb_bool_t +hb_buffer_set_length (hb_buffer_t *buffer, + unsigned int length); /* Return value valid as long as buffer not modified */ unsigned int hb_buffer_get_length (hb_buffer_t *buffer); +/* Getting glyphs out of the buffer */ + /* Return value valid as long as buffer not modified */ hb_glyph_info_t * -hb_buffer_get_glyph_infos (hb_buffer_t *buffer); +hb_buffer_get_glyph_infos (hb_buffer_t *buffer, + unsigned int *length); /* Return value valid as long as buffer not modified */ hb_glyph_position_t * -hb_buffer_get_glyph_positions (hb_buffer_t *buffer); +hb_buffer_get_glyph_positions (hb_buffer_t *buffer, + unsigned int *length); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-common.cc b/third_party/harfbuzz-ng/src/hb-common.cc new file mode 100644 index 0000000..6093289 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-common.cc @@ -0,0 +1,372 @@ +/* + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-version.h" + +#include "hb-mutex-private.hh" +#include "hb-object-private.hh" + +#include <locale.h> + + + +/* hb_tag_t */ + +hb_tag_t +hb_tag_from_string (const char *s, int len) +{ + char tag[4]; + unsigned int i; + + if (!s || !len || !*s) + return HB_TAG_NONE; + + if (len < 0 || len > 4) + len = 4; + for (i = 0; i < (unsigned) len && s[i]; i++) + tag[i] = s[i]; + for (; i < 4; i++) + tag[i] = ' '; + + return HB_TAG_CHAR4 (tag); +} + + +/* hb_direction_t */ + +const char direction_strings[][4] = { + "ltr", + "rtl", + "ttb", + "btt" +}; + +hb_direction_t +hb_direction_from_string (const char *str, int len) +{ + if (unlikely (!str || !len || !*str)) + return HB_DIRECTION_INVALID; + + /* Lets match loosely: just match the first letter, such that + * all of "ltr", "left-to-right", etc work! + */ + char c = TOLOWER (str[0]); + for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++) + if (c == direction_strings[i][0]) + return (hb_direction_t) i; + + return HB_DIRECTION_INVALID; +} + +const char * +hb_direction_to_string (hb_direction_t direction) +{ + if (likely ((unsigned int) direction < ARRAY_LENGTH (direction_strings))) + return direction_strings[direction]; + + return "invalid"; +} + + +/* hb_language_t */ + +struct _hb_language_t { + const char s[1]; +}; + +static const char canon_map[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, + '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-', + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 +}; + +static hb_bool_t +lang_equal (const void *v1, + const void *v2) +{ + const unsigned char *p1 = (const unsigned char *) v1; + const unsigned char *p2 = (const unsigned char *) 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 + + +struct hb_language_item_t { + + hb_language_t lang; + + inline bool operator == (const char *s) const { + return lang_equal (lang, s); + } + + inline hb_language_item_t & operator = (const char *s) { + lang = (hb_language_t) strdup (s); + for (unsigned char *p = (unsigned char *) lang; *p; p++) + *p = canon_map[*p]; + + return *this; + } + + void finish (void) { free (lang); } +}; + +static struct hb_static_lang_set_t : hb_lockable_set_t<hb_language_item_t, hb_static_mutex_t> { + ~hb_static_lang_set_t (void) { this->finish (lock); } + hb_static_mutex_t lock; +} langs; + +hb_language_t +hb_language_from_string (const char *str, int len) +{ + if (!str || !len || !*str) + return HB_LANGUAGE_INVALID; + + char strbuf[32]; + if (len >= 0) { + len = MIN (len, (int) sizeof (strbuf) - 1); + str = (char *) memcpy (strbuf, str, len); + strbuf[len] = '\0'; + } + + hb_language_item_t *item = langs.find_or_insert (str, langs.lock); + + return likely (item) ? item->lang : HB_LANGUAGE_INVALID; +} + +const char * +hb_language_to_string (hb_language_t language) +{ + /* This is actually NULL-safe! */ + return language->s; +} + +hb_language_t +hb_language_get_default (void) +{ + static hb_language_t default_language; + + if (!default_language) { + /* This block is not quite threadsafe, but is not as bad as + * it looks since it's idempotent. As long as pointer ops + * are atomic, we are safe. */ + + /* I hear that setlocale() doesn't honor env vars on Windows, + * but for now we ignore that. */ + + default_language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1); + } + + return default_language; +} + + +/* hb_script_t */ + +hb_script_t +hb_script_from_iso15924_tag (hb_tag_t tag) +{ + if (unlikely (tag == HB_TAG_NONE)) + return HB_SCRIPT_INVALID; + + /* Be lenient, adjust case (one capital letter followed by three small letters) */ + tag = (tag & 0xDFDFDFDF) | 0x00202020; + + switch (tag) { + + /* These graduated from the 'Q' private-area codes, but + * the old code is still aliased by Unicode, and the Qaai + * one in use by ICU. */ + case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED; + case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC; + + /* Script variants from http://unicode.org/iso15924/ */ + case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC; + case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN; + case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN; + case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC; + case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC; + case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC; + } + + /* If it looks right, just use the tag as a script */ + if (((uint32_t) tag & 0xE0E0E0E0) == 0x40606060) + return (hb_script_t) tag; + + /* Otherwise, return unknown */ + return HB_SCRIPT_UNKNOWN; +} + +hb_script_t +hb_script_from_string (const char *s, int len) +{ + return hb_script_from_iso15924_tag (hb_tag_from_string (s, len)); +} + +hb_tag_t +hb_script_to_iso15924_tag (hb_script_t script) +{ + return (hb_tag_t) script; +} + +hb_direction_t +hb_script_get_horizontal_direction (hb_script_t script) +{ + switch ((hb_tag_t) script) + { + case HB_SCRIPT_ARABIC: + case HB_SCRIPT_HEBREW: + case HB_SCRIPT_SYRIAC: + case HB_SCRIPT_THAANA: + + /* Unicode-4.0 additions */ + case HB_SCRIPT_CYPRIOT: + + /* Unicode-5.0 additions */ + case HB_SCRIPT_PHOENICIAN: + case HB_SCRIPT_NKO: + + /* Unicode-5.2 additions */ + case HB_SCRIPT_AVESTAN: + case HB_SCRIPT_IMPERIAL_ARAMAIC: + case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: + case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: + case HB_SCRIPT_OLD_SOUTH_ARABIAN: + case HB_SCRIPT_OLD_TURKIC: + case HB_SCRIPT_SAMARITAN: + + /* Unicode-6.0 additions */ + case HB_SCRIPT_MANDAIC: + + return HB_DIRECTION_RTL; + } + + return HB_DIRECTION_LTR; +} + + +/* hb_user_data_array_t */ + + +/* NOTE: Currently we use a global lock for user_data access + * threadsafety. If one day we add a mutex to any object, we + * should switch to using that insted for these too. + */ + +static hb_static_mutex_t user_data_lock; + +bool +hb_user_data_array_t::set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + if (!key) + return false; + + if (replace) { + if (!data && !destroy) { + items.remove (key, user_data_lock); + return true; + } + } + hb_user_data_item_t item = {key, data, destroy}; + bool ret = !!items.replace_or_insert (item, user_data_lock, replace); + + return ret; +} + +void * +hb_user_data_array_t::get (hb_user_data_key_t *key) +{ + hb_user_data_item_t item = {NULL }; + + return items.find (key, &item, user_data_lock) ? item.data : NULL; +} + +void +hb_user_data_array_t::finish (void) +{ + items.finish (user_data_lock); +} + + +/* hb_version */ + +void +hb_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro) +{ + *major = HB_VERSION_MAJOR; + *minor = HB_VERSION_MINOR; + *micro = HB_VERSION_MICRO; +} + +const char * +hb_version_string (void) +{ + return HB_VERSION_STRING; +} + +hb_bool_t +hb_version_check (unsigned int major, + unsigned int minor, + unsigned int micro) +{ + return HB_VERSION_CHECK (major, minor, micro); +} + + diff --git a/third_party/harfbuzz-ng/src/hb-common.h b/third_party/harfbuzz-ng/src/hb-common.h index 1dd02cb..b7fef32 100644 --- a/third_party/harfbuzz-ng/src/hb-common.h +++ b/third_party/harfbuzz-ng/src/hb-common.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,6 +23,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_COMMON_H @@ -37,53 +39,77 @@ HB_BEGIN_DECLS +#if !defined (HB_DONT_DEFINE_STDINT) -#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 +#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ + defined (_sgi) || defined (__sun) || defined (sun) || \ + defined (__digital__) || defined (__HP_cc) +# include <inttypes.h> +#elif defined (_AIX) +# include <sys/inttypes.h> +/* VS 2010 (_MSC_VER 1600) has stdint.h */ +#elif defined (_MSC_VER) && _MSC_VER < 1600 +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; #else -#include <stdint.h> +# 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) +#endif -hb_tag_t hb_tag_from_string (const char *s); +typedef int hb_bool_t; 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 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; + -typedef enum _hb_direction_t { - HB_DIRECTION_LTR, +/* hb_tag_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_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag)) + +#define HB_TAG_NONE HB_TAG(0,0,0,0) + +/* len=-1 means s is NUL-terminated */ +hb_tag_t hb_tag_from_string (const char *s, int len); + + +/* hb_direction_t */ + +typedef enum { + HB_DIRECTION_INVALID = -1, + HB_DIRECTION_LTR = 0, HB_DIRECTION_RTL, HB_DIRECTION_TTB, HB_DIRECTION_BTT } hb_direction_t; +/* len=-1 means s is NUL-terminated */ +hb_direction_t +hb_direction_from_string (const char *str, int len); + +const char * +hb_direction_to_string (hb_direction_t direction); + #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) @@ -91,14 +117,204 @@ typedef enum _hb_direction_t { #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_language_t */ + +typedef struct _hb_language_t *hb_language_t; + +/* len=-1 means s is NUL-terminated */ +hb_language_t +hb_language_from_string (const char *str, int len); + +const char * +hb_language_to_string (hb_language_t language); + +#define HB_LANGUAGE_INVALID ((hb_language_t) NULL) + +hb_language_t +hb_language_get_default (void); + + +/* hb_unicode_general_category_t */ + +typedef enum +{ + HB_UNICODE_GENERAL_CATEGORY_CONTROL, /* Cc */ + HB_UNICODE_GENERAL_CATEGORY_FORMAT, /* Cf */ + HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, /* Cn */ + HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, /* Co */ + HB_UNICODE_GENERAL_CATEGORY_SURROGATE, /* Cs */ + HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, /* Ll */ + HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, /* Lm */ + HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, /* Lo */ + HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, /* Lt */ + HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, /* Lu */ + HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, /* Mc */ + HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, /* Me */ + HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, /* Mn */ + HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, /* Nd */ + HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, /* Nl */ + HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, /* No */ + HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, /* Pc */ + HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, /* Pd */ + HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, /* Pe */ + HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, /* Pf */ + HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, /* Pi */ + HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, /* Po */ + HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, /* Ps */ + HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, /* Sc */ + HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, /* Sk */ + HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, /* Sm */ + HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, /* So */ + HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, /* Zl */ + HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, /* Zp */ + HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR /* Zs */ +} hb_unicode_general_category_t; + + +/* hb_script_t */ + +/* http://unicode.org/iso15924/ */ +typedef enum +{ + HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), + HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), + HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), + HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), + HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), + HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), + HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), + HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), + HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), + HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), + HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), + HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), + HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), + HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), + HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), + HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), + HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), + HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), + HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), + HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), + HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), + HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), + HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), + HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), + HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), + HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), + HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), + HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), + HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), + HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), + HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), + HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), + HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), + HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), + HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), + HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), + HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), + HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), + HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), + HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), + HB_SCRIPT_CANADIAN_ABORIGINAL = HB_TAG ('C','a','n','s'), + HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), + HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), + HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), + HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), + HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), + + /* Unicode-4.0 additions */ + HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), + HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), + HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), + HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), + HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), + HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), + HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), + HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), + + /* Unicode-4.1 additions */ + HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), + HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), + HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), + HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), + HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), + HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), + HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), + + /* Unicode-5.0 additions */ + HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), + HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), + HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), + HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), + HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), + HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), + + /* Unicode-5.1 additions */ + HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), + HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), + HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), + HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), + HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), + HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), + HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), + HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), + HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), + HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), + HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), + + /* Unicode-5.2 additions */ + HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), + HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), + HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), + HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), + HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), + HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), + HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), + HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), + HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), + HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), + HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), + HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), + HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), + + /* Unicode-6.0 additions */ + HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), + HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), + HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), + + /* No script set */ + HB_SCRIPT_INVALID = HB_TAG_NONE +} hb_script_t; + + +/* Script functions */ + +hb_script_t +hb_script_from_iso15924_tag (hb_tag_t tag); + +/* suger for tag_from_string() then script_from_iso15924_tag */ +/* len=-1 means s is NUL-terminated */ +hb_script_t +hb_script_from_string (const char *s, int len); + +hb_tag_t +hb_script_to_iso15924_tag (hb_script_t script); + +hb_direction_t +hb_script_get_horizontal_direction (hb_script_t script); + + +/* User data */ + +typedef struct _hb_user_data_key_t { + /*< private >*/ + char unused; +} hb_user_data_key_t; + +typedef void (*hb_destroy_func_t) (void *user_data); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-language.h b/third_party/harfbuzz-ng/src/hb-fallback-shape-private.hh index d3c91fb..d0beb16 100644 --- a/third_party/harfbuzz-ng/src/hb-language.h +++ b/third_party/harfbuzz-ng/src/hb-fallback-shape-private.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -21,26 +21,28 @@ * 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_LANGUAGE_H -#define HB_LANGUAGE_H +#ifndef HB_FALLBACK_SHAPE_PRIVATE_HH +#define HB_FALLBACK_SHAPE_PRIVATE_HH -#include "hb-common.h" +#include "hb-private.hh" -HB_BEGIN_DECLS +#include "hb-shape.h" -typedef const void *hb_language_t; +HB_BEGIN_DECLS -hb_language_t -hb_language_from_string (const char *str); -const char * -hb_language_to_string (hb_language_t language); +HB_INTERNAL hb_bool_t +hb_fallback_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options); HB_END_DECLS -#endif /* HB_LANGUAGE_H */ +#endif /* HB_FALLBACK_SHAPE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-fallback-shape.cc b/third_party/harfbuzz-ng/src/hb-fallback-shape.cc new file mode 100644 index 0000000..2fd527f --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-fallback-shape.cc @@ -0,0 +1,62 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-fallback-shape-private.hh" + +#include "hb-buffer-private.hh" + +hb_bool_t +hb_fallback_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options) +{ + buffer->guess_properties (); + + unsigned int count = buffer->len; + + for (unsigned int i = 0; i < count; i++) + hb_font_get_glyph (font, buffer->info[i].codepoint, 0, &buffer->info[i].codepoint); + + buffer->clear_positions (); + + for (unsigned int i = 0; i < count; i++) { + hb_font_get_glyph_advance_for_direction (font, buffer->info[i].codepoint, + buffer->props.direction, + &buffer->pos[i].x_advance, + &buffer->pos[i].y_advance); + hb_font_subtract_glyph_origin_for_direction (font, buffer->info[i].codepoint, + buffer->props.direction, + &buffer->pos[i].x_offset, + &buffer->pos[i].y_offset); + } + + if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) + hb_buffer_reverse (buffer); + + return TRUE; +} diff --git a/third_party/harfbuzz-ng/src/hb-font-private.h b/third_party/harfbuzz-ng/src/hb-font-private.h deleted file mode 100644 index b147bce..0000000 --- a/third_party/harfbuzz-ng/src/hb-font-private.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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-private.hh b/third_party/harfbuzz-ng/src/hb-font-private.hh new file mode 100644 index 0000000..d896e72 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-font-private.hh @@ -0,0 +1,163 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_FONT_PRIVATE_HH +#define HB_FONT_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-font.h" +#include "hb-object-private.hh" + + + +/* + * hb_font_funcs_t + */ + +#define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \ + HB_FONT_FUNC_IMPLEMENT (glyph) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \ + HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \ + HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \ + HB_FONT_FUNC_IMPLEMENT (glyph_extents) \ + HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ + /* ^--- Add new callbacks here */ + +struct _hb_font_funcs_t { + hb_object_header_t header; + + hb_bool_t immutable; + + /* Don't access these directly. Call hb_font_get_*() instead. */ + + struct { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name; + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } get; + + struct { +#define HB_FONT_FUNC_IMPLEMENT(name) void *name; + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } user_data; + + struct { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name; + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } destroy; +}; + + +/* + * hb_face_t + */ + +struct _hb_face_t { + hb_object_header_t header; + + hb_bool_t immutable; + + hb_reference_table_func_t reference_table; + void *user_data; + hb_destroy_func_t destroy; + + struct hb_ot_layout_t *ot_layout; + + unsigned int index; + unsigned int upem; +}; + + +/* + * hb_font_t + */ + +struct _hb_font_t { + hb_object_header_t header; + + hb_bool_t immutable; + + hb_font_t *parent; + hb_face_t *face; + + int x_scale; + int y_scale; + + unsigned int x_ppem; + unsigned int y_ppem; + + hb_font_funcs_t *klass; + void *user_data; + hb_destroy_func_t destroy; + + + /* Convert from font-space to user-space */ + inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); } + inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); } + + /* Convert from parent-font user-space to our user-space */ + inline hb_position_t parent_scale_x_distance (hb_position_t v) { + if (unlikely (parent && parent->x_scale != x_scale)) + return v * (int64_t) this->x_scale / this->parent->x_scale; + return v; + } + inline hb_position_t parent_scale_y_distance (hb_position_t v) { + if (unlikely (parent && parent->y_scale != y_scale)) + return v * (int64_t) this->y_scale / this->parent->y_scale; + return v; + } + inline hb_position_t parent_scale_x_position (hb_position_t v) { + return parent_scale_x_distance (v); + } + inline hb_position_t parent_scale_y_position (hb_position_t v) { + return parent_scale_y_distance (v); + } + + inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) { + *x = parent_scale_x_distance (*x); + *y = parent_scale_y_distance (*y); + } + inline void parent_scale_position (hb_position_t *x, hb_position_t *y) { + *x = parent_scale_x_position (*x); + *y = parent_scale_y_position (*y); + } + + + private: + inline hb_position_t em_scale (int16_t v, int scale) { return v * (int64_t) scale / hb_face_get_upem (this->face); } +}; + + + +#endif /* HB_FONT_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-font.cc b/third_party/harfbuzz-ng/src/hb-font.cc index 63631a9..d549455 100644 --- a/third_party/harfbuzz-ng/src/hb-font.cc +++ b/third_party/harfbuzz-ng/src/hb-font.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,128 +24,248 @@ * 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-private.hh" #include "hb-ot-layout-private.hh" +#include "hb-font-private.hh" +#include "hb-blob.h" +#include "hb-open-file-private.hh" +#include "hb-ot-head-table.hh" + #include <string.h> -HB_BEGIN_DECLS /* * hb_font_funcs_t */ -static hb_codepoint_t +static hb_bool_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; } + void *font_data HB_UNUSED, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph); -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) -{ } + *glyph = 0; + return FALSE; +} -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_position_t +hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph)); + + return font->x_scale; +} + +static hb_position_t +hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph)); + + return font->y_scale; +} + +static hb_bool_t +hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent, + glyph, + x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return FALSE; +} 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; } +hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent, + glyph, + x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return FALSE; +} + +static hb_position_t +hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph)); + + return 0; +} 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_v_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph)); + + return 0; +} + +static hb_bool_t +hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_extents (font->parent, + glyph, + extents); + if (ret) { + font->parent_scale_position (&extents->x_bearing, &extents->y_bearing); + font->parent_scale_distance (&extents->width, &extents->height); + } + return ret; + } + + memset (extents, 0, sizeof (*extents)); + return FALSE; +} + +static hb_bool_t +hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent, + glyph, point_index, + x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return FALSE; +} + + +static hb_font_funcs_t _hb_font_funcs_nil = { + HB_OBJECT_HEADER_STATIC, + + 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 +#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT } }; + hb_font_funcs_t * hb_font_funcs_create (void) { hb_font_funcs_t *ffuncs; - if (!HB_OBJECT_DO_CREATE (hb_font_funcs_t, ffuncs)) + if (!(ffuncs = hb_object_create<hb_font_funcs_t> ())) return &_hb_font_funcs_nil; - ffuncs->v = _hb_font_funcs_nil.v; + ffuncs->get = _hb_font_funcs_nil.get; return ffuncs; } hb_font_funcs_t * -hb_font_funcs_reference (hb_font_funcs_t *ffuncs) +hb_font_funcs_get_empty (void) { - HB_OBJECT_DO_REFERENCE (ffuncs); + return &_hb_font_funcs_nil; } -unsigned int -hb_font_funcs_get_reference_count (hb_font_funcs_t *ffuncs) +hb_font_funcs_t * +hb_font_funcs_reference (hb_font_funcs_t *ffuncs) { - HB_OBJECT_DO_GET_REFERENCE_COUNT (ffuncs); + return hb_object_reference (ffuncs); } void hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) { - HB_OBJECT_DO_DESTROY (ffuncs); + if (!hb_object_destroy (ffuncs)) return; + +#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \ + ffuncs->destroy.name (ffuncs->user_data.name); + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT free (ffuncs); } -hb_font_funcs_t * -hb_font_funcs_copy (hb_font_funcs_t *other_ffuncs) +hb_bool_t +hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) { - hb_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 hb_object_set_user_data (ffuncs, key, data, destroy, replace); +} - return ffuncs; +void * +hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (ffuncs, key); } + void hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) { - if (HB_OBJECT_IS_INERT (ffuncs)) + if (hb_object_is_inert (ffuncs)) return; ffuncs->immutable = TRUE; @@ -158,133 +278,253 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) } -void -hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_func_t glyph_func) -{ - if (ffuncs->immutable) - return; +#define HB_FONT_FUNC_IMPLEMENT(name) \ + \ +void \ +hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ + hb_font_get_##name##_func_t func, \ + void *user_data, \ + hb_destroy_func_t destroy) \ +{ \ + if (ffuncs->immutable) { \ + if (destroy) \ + destroy (user_data); \ + return; \ + } \ + \ + if (ffuncs->destroy.name) \ + ffuncs->destroy.name (ffuncs->user_data.name); \ + \ + if (func) { \ + ffuncs->get.name = func; \ + ffuncs->user_data.name = user_data; \ + ffuncs->destroy.name = destroy; \ + } else { \ + ffuncs->get.name = hb_font_get_##name##_nil; \ + ffuncs->user_data.name = NULL; \ + ffuncs->destroy.name = NULL; \ + } \ +} + +HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT - 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) +hb_bool_t +hb_font_get_glyph (hb_font_t *font, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph) { - if (ffuncs->immutable) - return; - - ffuncs->v.get_glyph_advance = glyph_advance_func ? glyph_advance_func : hb_font_get_glyph_advance_nil; + *glyph = 0; + return font->klass->get.glyph (font, font->user_data, + unicode, variation_selector, glyph, + font->klass->user_data.glyph); } -void -hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_extents_func_t glyph_extents_func) +hb_position_t +hb_font_get_glyph_h_advance (hb_font_t *font, + hb_codepoint_t glyph) { - if (ffuncs->immutable) - return; - - ffuncs->v.get_glyph_extents = glyph_extents_func ? glyph_extents_func : hb_font_get_glyph_extents_nil; + return font->klass->get.glyph_h_advance (font, font->user_data, + glyph, + font->klass->user_data.glyph_h_advance); } -void -hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs, - hb_font_get_contour_point_func_t contour_point_func) +hb_position_t +hb_font_get_glyph_v_advance (hb_font_t *font, + hb_codepoint_t glyph) { - if (ffuncs->immutable) - return; - - ffuncs->v.get_contour_point = contour_point_func ? contour_point_func : hb_font_get_contour_point_nil; + return font->klass->get.glyph_v_advance (font, font->user_data, + glyph, + font->klass->user_data.glyph_v_advance); } -void -hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs, - hb_font_get_kerning_func_t kerning_func) +hb_bool_t +hb_font_get_glyph_h_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { - if (ffuncs->immutable) - return; - - ffuncs->v.get_kerning = kerning_func ? kerning_func : hb_font_get_kerning_nil; + *x = *y = 0; + return font->klass->get.glyph_h_origin (font, font->user_data, + glyph, x, y, + font->klass->user_data.glyph_h_origin); } - -hb_font_get_glyph_func_t -hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs) +hb_bool_t +hb_font_get_glyph_v_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { - return ffuncs->v.get_glyph; + *x = *y = 0; + return font->klass->get.glyph_v_origin (font, font->user_data, + glyph, x, y, + font->klass->user_data.glyph_v_origin); } -hb_font_get_glyph_advance_func_t -hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs) +hb_position_t +hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) { - return ffuncs->v.get_glyph_advance; + return font->klass->get.glyph_h_kerning (font, font->user_data, + left_glyph, right_glyph, + font->klass->user_data.glyph_h_kerning); } -hb_font_get_glyph_extents_func_t -hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs) +hb_position_t +hb_font_get_glyph_v_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) { - return ffuncs->v.get_glyph_extents; + return font->klass->get.glyph_v_kerning (font, font->user_data, + left_glyph, right_glyph, + font->klass->user_data.glyph_v_kerning); } -hb_font_get_contour_point_func_t -hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs) +hb_bool_t +hb_font_get_glyph_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents) { - return ffuncs->v.get_contour_point; + memset (extents, 0, sizeof (*extents)); + return font->klass->get.glyph_extents (font, font->user_data, + glyph, + extents, + font->klass->user_data.glyph_extents); } -hb_font_get_kerning_func_t -hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs) +hb_bool_t +hb_font_get_glyph_contour_point (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y) { - return ffuncs->v.get_kerning; + *x = *y = 0; + return font->klass->get.glyph_contour_point (font, font->user_data, + glyph, point_index, + x, y, + font->klass->user_data.glyph_contour_point); } +/* A bit higher-level, and with fallback */ + +void +hb_font_get_glyph_advance_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { + *x = hb_font_get_glyph_h_advance (font, glyph); + *y = 0; + } else { + *x = 0; + *y = hb_font_get_glyph_v_advance (font, glyph); + } +} -hb_codepoint_t -hb_font_get_glyph (hb_font_t *font, hb_face_t *face, - hb_codepoint_t unicode, hb_codepoint_t variation_selector) +static void +guess_v_origin_minus_h_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y) { - return font->klass->v.get_glyph (font, face, font->user_data, - unicode, variation_selector); + *x = hb_font_get_glyph_h_advance (font, glyph) / 2; + + /* TODO use font_metics.ascent */ + *y = font->y_scale; } + 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) +hb_font_get_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { + hb_bool_t ret = hb_font_get_glyph_h_origin (font, glyph, x, y); + if (!ret && (ret = hb_font_get_glyph_v_origin (font, glyph, x, y))) { + hb_position_t dx, dy; + guess_v_origin_minus_h_origin (font, glyph, &dx, &dy); + *x -= dx; *y -= dy; + } + } else { + hb_bool_t ret = hb_font_get_glyph_v_origin (font, glyph, x, y); + if (!ret && (ret = hb_font_get_glyph_h_origin (font, glyph, x, y))) { + hb_position_t dx, dy; + guess_v_origin_minus_h_origin (font, glyph, &dx, &dy); + *x += dx; *y += dy; + } + } +} + +void +hb_font_add_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { - *x_advance = *y_advance = 0; - return font->klass->v.get_glyph_advance (font, face, font->user_data, - glyph, x_advance, y_advance); + hb_position_t origin_x, origin_y; + + hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y); + + *x += origin_x; + *y += origin_y; } void -hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face, - hb_codepoint_t glyph, hb_glyph_extents_t *extents) +hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { - memset (extents, 0, sizeof (*extents)); - return font->klass->v.get_glyph_extents (font, face, font->user_data, - glyph, extents); + hb_position_t origin_x, origin_y; + + hb_font_get_glyph_origin_for_direction (font, glyph, direction, &origin_x, &origin_y); + + *x -= origin_x; + *y -= origin_y; +} + +void +hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) +{ + if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) { + *x = hb_font_get_glyph_h_kerning (font, first_glyph, second_glyph); + *y = 0; + } else { + *x = 0; + *y = hb_font_get_glyph_v_kerning (font, first_glyph, second_glyph); + } } 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_font_get_glyph_extents_for_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_glyph_extents_t *extents) { - *x = 0; *y = 0; - return font->klass->v.get_contour_point (font, face, font->user_data, - point_index, - glyph, x, y); + hb_bool_t ret = hb_font_get_glyph_extents (font, glyph, extents); + + if (ret) + hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, &extents->x_bearing, &extents->y_bearing); + + return ret; } -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_bool_t +hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y) { - return font->klass->v.get_kerning (font, face, font->user_data, - first_glyph, second_glyph); + hb_bool_t ret = hb_font_get_glyph_contour_point (font, glyph, point_index, x, y); + + if (ret) + hb_font_subtract_glyph_origin_for_direction (font, glyph, direction, x, y); + + return ret; } @@ -293,40 +533,41 @@ hb_font_get_kerning (hb_font_t *font, hb_face_t *face, */ static hb_face_t _hb_face_nil = { - HB_REFERENCE_COUNT_INVALID, /* ref_count */ + HB_OBJECT_HEADER_STATIC, - NULL, /* get_table */ - NULL, /* destroy */ + TRUE, /* immutable */ + + NULL, /* reference_table */ NULL, /* user_data */ + NULL, /* destroy */ - NULL, /* head_blob */ - NULL, /* head_table */ + NULL, /* ot_layout */ - NULL /* ot_layout */ + 0, /* index */ + 1000 /* upem */ }; 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_create_for_tables (hb_reference_table_func_t reference_table, + void *user_data, + hb_destroy_func_t destroy) { hb_face_t *face; - if (!HB_OBJECT_DO_CREATE (hb_face_t, face)) { + if (!reference_table || !(face = hb_object_create<hb_face_t> ())) { if (destroy) destroy (user_data); return &_hb_face_nil; } - face->get_table = get_table; - face->destroy = destroy; + face->reference_table = reference_table; face->user_data = user_data; + face->destroy = destroy; - face->ot_layout = _hb_ot_layout_new (face); + face->ot_layout = _hb_ot_layout_create (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); + face->upem = 0; return face; } @@ -360,10 +601,13 @@ _hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure) } static hb_blob_t * -_hb_face_for_data_get_table (hb_tag_t tag, void *user_data) +_hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) user_data; + if (tag == HB_TAG_NONE) + return hb_blob_reference (data->blob); + const OpenTypeFontFile &ot_file = *Sanitizer<OpenTypeFontFile>::lock_instance (data->blob); const OpenTypeFontFace &ot_face = ot_file.get_face (data->index); @@ -371,47 +615,51 @@ _hb_face_for_data_get_table (hb_tag_t tag, void *user_data) 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_create (hb_blob_t *blob, + unsigned int index) { + hb_face_t *face; + + if (unlikely (!blob || !hb_blob_get_length (blob))) + return &_hb_face_nil; + 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); -} + face = hb_face_create_for_tables (_hb_face_for_data_reference_table, + closure, + (hb_destroy_func_t) _hb_face_for_data_closure_destroy); + + hb_face_set_index (face, index); + return face; +} hb_face_t * -hb_face_reference (hb_face_t *face) +hb_face_get_empty (void) { - HB_OBJECT_DO_REFERENCE (face); + return &_hb_face_nil; } -unsigned int -hb_face_get_reference_count (hb_face_t *face) + +hb_face_t * +hb_face_reference (hb_face_t *face) { - HB_OBJECT_DO_GET_REFERENCE_COUNT (face); + return hb_object_reference (face); } void hb_face_destroy (hb_face_t *face) { - HB_OBJECT_DO_DESTROY (face); - - _hb_ot_layout_free (face->ot_layout); + if (!hb_object_destroy (face)) return; - hb_blob_unlock (face->head_blob); - hb_blob_destroy (face->head_blob); + _hb_ot_layout_destroy (face->ot_layout); if (face->destroy) face->destroy (face->user_data); @@ -419,24 +667,97 @@ hb_face_destroy (hb_face_t *face) free (face); } +hb_bool_t +hb_face_set_user_data (hb_face_t *face, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (face, key, data, destroy, replace); +} + +void * +hb_face_get_user_data (hb_face_t *face, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (face, key); +} + +void +hb_face_make_immutable (hb_face_t *face) +{ + if (hb_object_is_inert (face)) + return; + + face->immutable = true; +} + +hb_bool_t +hb_face_is_immutable (hb_face_t *face) +{ + return face->immutable; +} + + hb_blob_t * -hb_face_get_table (hb_face_t *face, - hb_tag_t tag) +hb_face_reference_table (hb_face_t *face, + hb_tag_t tag) { hb_blob_t *blob; - if (unlikely (!face || !face->get_table)) - return &_hb_blob_nil; + if (unlikely (!face || !face->reference_table)) + return hb_blob_get_empty (); - blob = face->get_table (tag, face->user_data); + blob = face->reference_table (face, tag, face->user_data); + if (unlikely (!blob)) + return hb_blob_get_empty (); return blob; } +hb_blob_t * +hb_face_reference_blob (hb_face_t *face) +{ + return hb_face_reference_table (face, HB_TAG_NONE); +} + +void +hb_face_set_index (hb_face_t *face, + unsigned int index) +{ + if (hb_object_is_inert (face)) + return; + + face->index = 0; +} + +unsigned int +hb_face_get_index (hb_face_t *face) +{ + return face->index; +} + +void +hb_face_set_upem (hb_face_t *face, + unsigned int upem) +{ + if (hb_object_is_inert (face)) + return; + + face->upem = upem; +} + unsigned int hb_face_get_upem (hb_face_t *face) { - return (face->head_table ? face->head_table : &Null(head))->get_upem (); + if (unlikely (!face->upem)) { + hb_blob_t *head_blob = Sanitizer<head>::sanitize (hb_face_reference_table (face, HB_OT_TAG_head)); + const head *head_table = Sanitizer<head>::lock_instance (head_blob); + face->upem = head_table->get_upem (); + hb_blob_destroy (head_blob); + } + return face->upem; } @@ -445,7 +766,12 @@ hb_face_get_upem (hb_face_t *face) */ static hb_font_t _hb_font_nil = { - HB_REFERENCE_COUNT_INVALID, /* ref_count */ + HB_OBJECT_HEADER_STATIC, + + TRUE, /* immutable */ + + NULL, /* parent */ + &_hb_face_nil, 0, /* x_scale */ 0, /* y_scale */ @@ -453,41 +779,73 @@ static hb_font_t _hb_font_nil = { 0, /* x_ppem */ 0, /* y_ppem */ - NULL, /* klass */ - NULL, /* destroy */ - NULL /* user_data */ + &_hb_font_funcs_nil, /* klass */ + NULL, /* user_data */ + NULL /* destroy */ }; hb_font_t * -hb_font_create (void) +hb_font_create (hb_face_t *face) { hb_font_t *font; - if (!HB_OBJECT_DO_CREATE (hb_font_t, font)) + if (unlikely (!face)) + face = &_hb_face_nil; + if (unlikely (hb_object_is_inert (face))) + return &_hb_font_nil; + if (!(font = hb_object_create<hb_font_t> ())) return &_hb_font_nil; + hb_face_make_immutable (face); + font->face = hb_face_reference (face); font->klass = &_hb_font_funcs_nil; return font; } hb_font_t * -hb_font_reference (hb_font_t *font) +hb_font_create_sub_font (hb_font_t *parent) { - HB_OBJECT_DO_REFERENCE (font); + if (unlikely (!parent)) + return &_hb_font_nil; + + hb_font_t *font = hb_font_create (parent->face); + + if (unlikely (hb_object_is_inert (font))) + return font; + + hb_font_make_immutable (parent); + font->parent = hb_font_reference (parent); + + font->x_scale = parent->x_scale; + font->y_scale = parent->y_scale; + font->x_ppem = parent->x_ppem; + font->y_ppem = parent->y_ppem; + + font->klass = &_hb_font_funcs_nil; + + return font; } -unsigned int -hb_font_get_reference_count (hb_font_t *font) +hb_font_t * +hb_font_get_empty (void) { - HB_OBJECT_DO_GET_REFERENCE_COUNT (font); + return &_hb_font_nil; +} + +hb_font_t * +hb_font_reference (hb_font_t *font) +{ + return hb_object_reference (font); } void hb_font_destroy (hb_font_t *font) { - HB_OBJECT_DO_DESTROY (font); + if (!hb_object_destroy (font)) return; + hb_font_destroy (font->parent); + hb_face_destroy (font->face); hb_font_funcs_destroy (font->klass); if (font->destroy) font->destroy (font->user_data); @@ -495,14 +853,62 @@ hb_font_destroy (hb_font_t *font) free (font); } +hb_bool_t +hb_font_set_user_data (hb_font_t *font, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (font, key, data, destroy, replace); +} + +void * +hb_font_get_user_data (hb_font_t *font, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (font, key); +} + +void +hb_font_make_immutable (hb_font_t *font) +{ + if (hb_object_is_inert (font)) + return; + + font->immutable = true; +} + +hb_bool_t +hb_font_is_immutable (hb_font_t *font) +{ + return font->immutable; +} + +hb_font_t * +hb_font_get_parent (hb_font_t *font) +{ + return font->parent; +} + +hb_face_t * +hb_font_get_face (hb_font_t *font) +{ + return font->face; +} + + void hb_font_set_funcs (hb_font_t *font, hb_font_funcs_t *klass, - hb_destroy_func_t destroy, - void *user_data) + void *user_data, + hb_destroy_func_t destroy) { - if (HB_OBJECT_IS_INERT (font)) + if (font->immutable) { + if (destroy) + destroy (user_data); return; + } if (font->destroy) font->destroy (font->user_data); @@ -513,36 +919,36 @@ hb_font_set_funcs (hb_font_t *font, hb_font_funcs_reference (klass); hb_font_funcs_destroy (font->klass); font->klass = klass; - font->destroy = destroy; font->user_data = user_data; + font->destroy = destroy; } void -hb_font_unset_funcs (hb_font_t *font, - hb_font_funcs_t **klass, - hb_destroy_func_t *destroy, - void **user_data) +hb_font_set_funcs_data (hb_font_t *font, + void *user_data, + hb_destroy_func_t destroy) { - /* 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)) + /* Destroy user_data? */ + if (font->immutable) { + if (destroy) + destroy (user_data); return; + } + + if (font->destroy) + font->destroy (font->user_data); - font->klass = NULL; - font->destroy = NULL; - font->user_data = NULL; + font->user_data = user_data; + font->destroy = destroy; } + void hb_font_set_scale (hb_font_t *font, - unsigned int x_scale, - unsigned int y_scale) + int x_scale, + int y_scale) { - if (HB_OBJECT_IS_INERT (font)) + if (font->immutable) return; font->x_scale = x_scale; @@ -551,8 +957,8 @@ hb_font_set_scale (hb_font_t *font, void hb_font_get_scale (hb_font_t *font, - unsigned int *x_scale, - unsigned int *y_scale) + int *x_scale, + int *y_scale) { if (x_scale) *x_scale = font->x_scale; if (y_scale) *y_scale = font->y_scale; @@ -563,7 +969,7 @@ hb_font_set_ppem (hb_font_t *font, unsigned int x_ppem, unsigned int y_ppem) { - if (HB_OBJECT_IS_INERT (font)) + if (font->immutable) return; font->x_ppem = x_ppem; @@ -580,4 +986,3 @@ hb_font_get_ppem (hb_font_t *font, } -HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-font.h b/third_party/harfbuzz-ng/src/hb-font.h index f33e56f..8a9dda5 100644 --- a/third_party/harfbuzz-ng/src/hb-font.h +++ b/third_party/harfbuzz-ng/src/hb-font.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -41,42 +41,62 @@ typedef struct _hb_font_t hb_font_t; */ hb_face_t * -hb_face_create_for_data (hb_blob_t *blob, - unsigned int index); +hb_face_create (hb_blob_t *blob, + unsigned int index); -typedef hb_blob_t * (*hb_get_table_func_t) (hb_tag_t tag, void *user_data); +typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data); /* calls destroy() when not needing user_data anymore */ hb_face_t * -hb_face_create_for_tables (hb_get_table_func_t get_table, - hb_destroy_func_t destroy, - void *user_data); +hb_face_create_for_tables (hb_reference_table_func_t reference_table, + void *user_data, + hb_destroy_func_t destroy); hb_face_t * -hb_face_reference (hb_face_t *face); +hb_face_get_empty (void); -unsigned int -hb_face_get_reference_count (hb_face_t *face); +hb_face_t * +hb_face_reference (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_bool_t +hb_face_set_user_data (hb_face_t *face, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_face_get_user_data (hb_face_t *face, + hb_user_data_key_t *key); + +void +hb_face_make_immutable (hb_face_t *face); + +hb_bool_t +hb_face_is_immutable (hb_face_t *face); + + +hb_blob_t * +hb_face_reference_table (hb_face_t *face, + hb_tag_t tag); + hb_blob_t * -hb_face_get_table (hb_face_t *face, - hb_tag_t tag); +hb_face_reference_blob (hb_face_t *face); + +void +hb_face_set_index (hb_face_t *face, + unsigned int index); + +unsigned int +hb_face_get_index (hb_face_t *face); + +void +hb_face_set_upem (hb_face_t *face, + unsigned int upem); unsigned int hb_face_get_upem (hb_face_t *face); @@ -92,16 +112,26 @@ hb_font_funcs_t * hb_font_funcs_create (void); hb_font_funcs_t * -hb_font_funcs_reference (hb_font_funcs_t *ffuncs); +hb_font_funcs_get_empty (void); -unsigned int -hb_font_funcs_get_reference_count (hb_font_funcs_t *ffuncs); +hb_font_funcs_t * +hb_font_funcs_reference (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); +hb_bool_t +hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key); + void hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs); @@ -113,88 +143,176 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); 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_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); + +/* func types */ + +typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data); +typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + void *user_data); +typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t; +typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t; + +typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y, + void *user_data); +typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t; +typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t; + +typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + void *user_data); +typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; +typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t; + + +typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data); +typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y, + void *user_data); + + +/* func setters */ + void hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_func_t glyph_func); + hb_font_get_glyph_func_t glyph_func, + void *user_data, hb_destroy_func_t destroy); void -hb_font_funcs_set_glyph_advance_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_advance_func_t glyph_advance_func); +hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_advance_func_t func, + void *user_data, hb_destroy_func_t destroy); +void +hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_advance_func_t func, + void *user_data, hb_destroy_func_t destroy); void -hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_extents_func_t glyph_extents_func); +hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); +void +hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_origin_func_t func, + void *user_data, hb_destroy_func_t destroy); void -hb_font_funcs_set_contour_point_func (hb_font_funcs_t *ffuncs, - hb_font_get_contour_point_func_t contour_point_func); +hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); +void +hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_v_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); void -hb_font_funcs_set_kerning_func (hb_font_funcs_t *ffuncs, - hb_font_get_kerning_func_t kerning_func); +hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_extents_func_t func, + void *user_data, hb_destroy_func_t destroy); +void +hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_contour_point_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/* func dispatch */ -/* These never return NULL. Return fallback defaults instead. */ +hb_bool_t +hb_font_get_glyph (hb_font_t *font, + hb_codepoint_t unicode, hb_codepoint_t variation_selector, + hb_codepoint_t *glyph); -hb_font_get_glyph_func_t -hb_font_funcs_get_glyph_func (hb_font_funcs_t *ffuncs); +hb_position_t +hb_font_get_glyph_h_advance (hb_font_t *font, + hb_codepoint_t glyph); +hb_position_t +hb_font_get_glyph_v_advance (hb_font_t *font, + hb_codepoint_t glyph); -hb_font_get_glyph_advance_func_t -hb_font_funcs_get_glyph_advance_func (hb_font_funcs_t *ffuncs); +hb_bool_t +hb_font_get_glyph_h_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y); +hb_bool_t +hb_font_get_glyph_v_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, hb_position_t *y); -hb_font_get_glyph_extents_func_t -hb_font_funcs_get_glyph_extents_func (hb_font_funcs_t *ffuncs); +hb_position_t +hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); +hb_position_t +hb_font_get_glyph_v_kerning (hb_font_t *font, + hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); -hb_font_get_contour_point_func_t -hb_font_funcs_get_contour_point_func (hb_font_funcs_t *ffuncs); +hb_bool_t +hb_font_get_glyph_extents (hb_font_t *font, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents); -hb_font_get_kerning_func_t -hb_font_funcs_get_kerning_func (hb_font_funcs_t *ffuncs); +hb_bool_t +hb_font_get_glyph_contour_point (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_position_t *x, hb_position_t *y); -hb_codepoint_t -hb_font_get_glyph (hb_font_t *font, hb_face_t *face, - hb_codepoint_t unicode, hb_codepoint_t variation_selector); +/* high-level funcs, with fallback */ 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); +hb_font_get_glyph_advance_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +void +hb_font_get_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +void +hb_font_add_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); +void +hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); void -hb_font_get_glyph_extents (hb_font_t *font, hb_face_t *face, - hb_codepoint_t glyph, - hb_glyph_extents_t *extents); +hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); hb_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_font_get_glyph_extents_for_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_glyph_extents_t *extents); -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_bool_t +hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, + hb_codepoint_t glyph, unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); /* @@ -204,52 +322,67 @@ hb_font_get_kerning (hb_font_t *font, hb_face_t *face, /* Fonts are very light-weight objects */ hb_font_t * -hb_font_create (void); +hb_font_create (hb_face_t *face); hb_font_t * -hb_font_reference (hb_font_t *font); +hb_font_create_sub_font (hb_font_t *parent); -unsigned int -hb_font_get_reference_count (hb_font_t *font); +hb_font_t * +hb_font_get_empty (void); + +hb_font_t * +hb_font_reference (hb_font_t *font); void hb_font_destroy (hb_font_t *font); +hb_bool_t +hb_font_set_user_data (hb_font_t *font, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_font_get_user_data (hb_font_t *font, + hb_user_data_key_t *key); + +void +hb_font_make_immutable (hb_font_t *font); + +hb_bool_t +hb_font_is_immutable (hb_font_t *font); + +hb_font_t * +hb_font_get_parent (hb_font_t *font); + +hb_face_t * +hb_font_get_face (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); + void *font_data, + hb_destroy_func_t destroy); -/* 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. - */ +/* Be *very* careful with this function! */ void -hb_font_unset_funcs (hb_font_t *font, - hb_font_funcs_t **klass, - hb_destroy_func_t *destroy, - void **user_data); +hb_font_set_funcs_data (hb_font_t *font, + void *font_data, + hb_destroy_func_t destroy); -/* - * We should add support for full matrices. - */ void hb_font_set_scale (hb_font_t *font, - unsigned int x_scale, - unsigned int y_scale); + int x_scale, + int y_scale); void hb_font_get_scale (hb_font_t *font, - unsigned int *x_scale, - unsigned int *y_scale); + int *x_scale, + int *y_scale); /* * A zero value means "no hinting in that direction" diff --git a/third_party/harfbuzz-ng/src/hb-ft.c b/third_party/harfbuzz-ng/src/hb-ft.c deleted file mode 100644 index e696fe8..0000000 --- a/third_party/harfbuzz-ng/src/hb-ft.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * 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.cc b/third_party/harfbuzz-ng/src/hb-ft.cc new file mode 100644 index 0000000..23c2cc0 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ft.cc @@ -0,0 +1,439 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 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.hh" + +#include "hb-ft.h" + +#include "hb-font-private.hh" + +#include FT_ADVANCES_H +#include FT_TRUETYPE_TABLES_H + + + +#ifndef HB_DEBUG_FT +#define HB_DEBUG_FT (HB_DEBUG+0) +#endif + + +/* TODO: + * + * In general, this file does a fine job of what it's supposed to do. + * There are, however, things that need more work: + * + * - We don't handle any load_flags. That definitely has API implications. :( + * I believe hb_ft_font_create() should take load_flags input. + * In particular, FT_Get_Advance() without the NO_HINTING flag seems to be + * buggy. + * + * - We don't handle / allow for emboldening / obliqueing. + * + * - Rounding, etc? + * + * - In the future, we should add constructors to create fonts in font space. + * + * - I believe transforms are not correctly implemented. FreeType does not + * provide any API to get to the transform/delta set on the face. :( + * + * - Always use FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH? + */ + + +static hb_bool_t +hb_ft_get_glyph (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) + +{ + FT_Face ft_face = (FT_Face) font_data; + +#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX + if (unlikely (variation_selector)) { + *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector); + if (*glyph) + return TRUE; + } +#endif + + *glyph = FT_Get_Char_Index (ft_face, unicode); + return *glyph != 0; +} + +static hb_position_t +hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + FT_Fixed v; + + if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) + return 0; + + return v >> 10; +} + +static hb_position_t +hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT; + FT_Fixed v; + + if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) + return 0; + + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates + * have a Y growing upward. Hence the extra negation. */ + return -v >> 10; +} + +static hb_bool_t +hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_position_t *x HB_UNUSED, + hb_position_t *y HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* We always work in the horizontal coordinates. */ + return TRUE; +} + +static hb_bool_t +hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT; + + if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + return FALSE; + + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates + * have a Y growing upward. Hence the extra negation. */ + *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; + *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); + + return TRUE; +} + +static hb_position_t +hb_ft_get_glyph_h_kerning (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + FT_Vector kerningv; + + if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerningv)) + return 0; + + return kerningv.x; +} + +static hb_position_t +hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph HB_UNUSED, + hb_codepoint_t bottom_glyph HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* FreeType API doesn't support vertical kerning */ + return 0; +} + +static hb_bool_t +hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT; + + if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + return FALSE; + + extents->x_bearing = ft_face->glyph->metrics.horiBearingX; + extents->y_bearing = ft_face->glyph->metrics.horiBearingY; + extents->width = ft_face->glyph->metrics.width; + extents->height = ft_face->glyph->metrics.height; + return TRUE; +} + +static hb_bool_t +hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT; + + 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_font_funcs_t ft_ffuncs = { + HB_OBJECT_HEADER_STATIC, + + TRUE, /* immutable */ + + { + hb_ft_get_glyph, + hb_ft_get_glyph_h_advance, + hb_ft_get_glyph_v_advance, + hb_ft_get_glyph_h_origin, + hb_ft_get_glyph_v_origin, + hb_ft_get_glyph_h_kerning, + hb_ft_get_glyph_v_kerning, + hb_ft_get_glyph_extents, + hb_ft_get_glyph_contour_point, + } +}; + +static hb_font_funcs_t * +_hb_ft_get_font_funcs (void) +{ + return &ft_ffuncs; +} + + +static hb_blob_t * +reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + FT_Face ft_face = (FT_Face) user_data; + FT_Byte *buffer; + FT_ULong length = 0; + FT_Error error; + + /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); + if (error) + return NULL; + + buffer = (FT_Byte *) malloc (length); + if (buffer == NULL) + return NULL; + + error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length); + if (error) + return NULL; + + return hb_blob_create ((const char *) buffer, length, + HB_MEMORY_MODE_WRITABLE, + buffer, free); +} + + +hb_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: We assume that it's mmap()'ed, but FreeType code + * suggests that there are cases we reach here but font is + * not mmapped. For example, when mmap() fails. No idea + * how to deal with it better here. */ + HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, + ft_face, destroy); + face = hb_face_create (blob, ft_face->face_index); + hb_blob_destroy (blob); + } else { + face = hb_face_create_for_tables (reference_table, ft_face, destroy); + } + + hb_face_set_index (face, ft_face->face_index); + hb_face_set_upem (face, ft_face->units_per_EM); + + return face; +} + +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); +} + +static void +_do_nothing (void) +{ +} + + +hb_font_t * +hb_ft_font_create (FT_Face ft_face, + hb_destroy_func_t destroy) +{ + hb_font_t *font; + hb_face_t *face; + + face = hb_ft_face_create (ft_face, destroy); + font = hb_font_create (face); + hb_face_destroy (face); + hb_font_set_funcs (font, + _hb_ft_get_font_funcs (), + ft_face, (hb_destroy_func_t) _do_nothing); + 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; +} + + + + +static FT_Library ft_library; +static hb_bool_t ft_library_initialized; +static struct ft_library_destructor { + ~ft_library_destructor (void) { + if (ft_library) + FT_Done_FreeType (ft_library); + } +} static_ft_library_destructor; + +static FT_Library +_get_ft_library (void) +{ + if (unlikely (!ft_library_initialized)) { + FT_Init_FreeType (&ft_library); + ft_library_initialized = TRUE; + } + + return ft_library; +} + +static void +_release_blob (FT_Face ft_face) +{ + hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); +} + +void +hb_ft_font_set_funcs (hb_font_t *font) +{ + hb_blob_t *blob = hb_face_reference_blob (font->face); + unsigned int blob_length; + const char *blob_data = hb_blob_get_data (blob, &blob_length); + if (unlikely (!blob_length)) + DEBUG_MSG (FT, font, "Font face has empty blob"); + + FT_Face ft_face = NULL; + FT_Error err = FT_New_Memory_Face (_get_ft_library (), + (const FT_Byte *) blob_data, + blob_length, + hb_face_get_index (font->face), + &ft_face); + + if (unlikely (err)) { + hb_blob_destroy (blob); + DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed"); + return; + } + + FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); + + FT_Set_Char_Size (ft_face, + font->x_scale, font->y_scale, + font->x_ppem * 72 * 64 / font->x_scale, + font->y_ppem * 72 * 64 / font->y_scale); + + ft_face->generic.data = blob; + ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; + + hb_font_set_funcs (font, + _hb_ft_get_font_funcs (), + ft_face, + (hb_destroy_func_t) FT_Done_Face); +} + +FT_Face +hb_ft_font_get_face (hb_font_t *font) +{ + if (font->destroy == (hb_destroy_func_t) FT_Done_Face || + font->destroy == (hb_destroy_func_t) _do_nothing) + return (FT_Face) font->user_data; + + return NULL; +} diff --git a/third_party/harfbuzz-ng/src/hb-ft.h b/third_party/harfbuzz-ng/src/hb-ft.h index be5c854..c1772ac 100644 --- a/third_party/harfbuzz-ng/src/hb-ft.h +++ b/third_party/harfbuzz-ng/src/hb-ft.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -36,15 +36,12 @@ HB_BEGIN_DECLS - -hb_font_funcs_t * -hb_ft_get_font_funcs (void); +/* Note: FreeType is not thread-safe. Hence, these functions are not either. */ 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); @@ -53,6 +50,15 @@ hb_ft_font_create (FT_Face ft_face, hb_destroy_func_t destroy); + +/* Makes an hb_font_t use FreeType internally to implement font functions. */ +void +hb_ft_font_set_funcs (hb_font_t *font); + +FT_Face +hb_ft_font_get_face (hb_font_t *font); + + 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 deleted file mode 100644 index c548fa6..0000000 --- a/third_party/harfbuzz-ng/src/hb-glib.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.cc b/third_party/harfbuzz-ng/src/hb-glib.cc new file mode 100644 index 0000000..f990988 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-glib.cc @@ -0,0 +1,349 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-glib.h" + +#include "hb-unicode-private.hh" + + +#if !GLIB_CHECK_VERSION(2,29,14) +static const hb_script_t +glib_script_to_script[] = +{ + HB_SCRIPT_COMMON, + HB_SCRIPT_INHERITED, + HB_SCRIPT_ARABIC, + HB_SCRIPT_ARMENIAN, + HB_SCRIPT_BENGALI, + HB_SCRIPT_BOPOMOFO, + HB_SCRIPT_CHEROKEE, + HB_SCRIPT_COPTIC, + HB_SCRIPT_CYRILLIC, + HB_SCRIPT_DESERET, + HB_SCRIPT_DEVANAGARI, + HB_SCRIPT_ETHIOPIC, + HB_SCRIPT_GEORGIAN, + HB_SCRIPT_GOTHIC, + HB_SCRIPT_GREEK, + HB_SCRIPT_GUJARATI, + HB_SCRIPT_GURMUKHI, + HB_SCRIPT_HAN, + HB_SCRIPT_HANGUL, + HB_SCRIPT_HEBREW, + HB_SCRIPT_HIRAGANA, + HB_SCRIPT_KANNADA, + HB_SCRIPT_KATAKANA, + HB_SCRIPT_KHMER, + HB_SCRIPT_LAO, + HB_SCRIPT_LATIN, + HB_SCRIPT_MALAYALAM, + HB_SCRIPT_MONGOLIAN, + HB_SCRIPT_MYANMAR, + HB_SCRIPT_OGHAM, + HB_SCRIPT_OLD_ITALIC, + HB_SCRIPT_ORIYA, + HB_SCRIPT_RUNIC, + HB_SCRIPT_SINHALA, + HB_SCRIPT_SYRIAC, + HB_SCRIPT_TAMIL, + HB_SCRIPT_TELUGU, + HB_SCRIPT_THAANA, + HB_SCRIPT_THAI, + HB_SCRIPT_TIBETAN, + HB_SCRIPT_CANADIAN_ABORIGINAL, + HB_SCRIPT_YI, + HB_SCRIPT_TAGALOG, + HB_SCRIPT_HANUNOO, + HB_SCRIPT_BUHID, + HB_SCRIPT_TAGBANWA, + + /* Unicode-4.0 additions */ + HB_SCRIPT_BRAILLE, + HB_SCRIPT_CYPRIOT, + HB_SCRIPT_LIMBU, + HB_SCRIPT_OSMANYA, + HB_SCRIPT_SHAVIAN, + HB_SCRIPT_LINEAR_B, + HB_SCRIPT_TAI_LE, + HB_SCRIPT_UGARITIC, + + /* Unicode-4.1 additions */ + HB_SCRIPT_NEW_TAI_LUE, + HB_SCRIPT_BUGINESE, + HB_SCRIPT_GLAGOLITIC, + HB_SCRIPT_TIFINAGH, + HB_SCRIPT_SYLOTI_NAGRI, + HB_SCRIPT_OLD_PERSIAN, + HB_SCRIPT_KHAROSHTHI, + + /* Unicode-5.0 additions */ + HB_SCRIPT_UNKNOWN, + HB_SCRIPT_BALINESE, + HB_SCRIPT_CUNEIFORM, + HB_SCRIPT_PHOENICIAN, + HB_SCRIPT_PHAGS_PA, + HB_SCRIPT_NKO, + + /* Unicode-5.1 additions */ + HB_SCRIPT_KAYAH_LI, + HB_SCRIPT_LEPCHA, + HB_SCRIPT_REJANG, + HB_SCRIPT_SUNDANESE, + HB_SCRIPT_SAURASHTRA, + HB_SCRIPT_CHAM, + HB_SCRIPT_OL_CHIKI, + HB_SCRIPT_VAI, + HB_SCRIPT_CARIAN, + HB_SCRIPT_LYCIAN, + HB_SCRIPT_LYDIAN, + + /* Unicode-5.2 additions */ + HB_SCRIPT_AVESTAN, + HB_SCRIPT_BAMUM, + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, + HB_SCRIPT_IMPERIAL_ARAMAIC, + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, + HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, + HB_SCRIPT_JAVANESE, + HB_SCRIPT_KAITHI, + HB_SCRIPT_TAI_THAM, + HB_SCRIPT_LISU, + HB_SCRIPT_MEETEI_MAYEK, + HB_SCRIPT_OLD_SOUTH_ARABIAN, + HB_SCRIPT_OLD_TURKIC, + HB_SCRIPT_SAMARITAN, + HB_SCRIPT_TAI_VIET, + + /* Unicode-6.0 additions */ + HB_SCRIPT_BATAK, + HB_SCRIPT_BRAHMI, + HB_SCRIPT_MANDAIC +}; +#endif + +hb_script_t +hb_glib_script_to_script (GUnicodeScript script) +{ +#if GLIB_CHECK_VERSION(2,29,14) + return (hb_script_t) g_unicode_script_to_iso15924 (script); +#else + if (likely ((unsigned int) script < ARRAY_LENGTH (glib_script_to_script))) + return glib_script_to_script[script]; + + if (unlikely (script == G_UNICODE_SCRIPT_INVALID_CODE)) + return HB_SCRIPT_INVALID; + + return HB_SCRIPT_UNKNOWN; +#endif +} + +GUnicodeScript +hb_glib_script_from_script (hb_script_t script) +{ +#if GLIB_CHECK_VERSION(2,29,14) + return g_unicode_script_from_iso15924 (script); +#else + unsigned int count = ARRAY_LENGTH (glib_script_to_script); + for (unsigned int i = 0; i < count; i++) + if (glib_script_to_script[i] == script) + return (GUnicodeScript) i; + + if (unlikely (script == HB_SCRIPT_INVALID)) + return G_UNICODE_SCRIPT_INVALID_CODE; + + return G_UNICODE_SCRIPT_UNKNOWN; +#endif +} + + +static unsigned int +hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) + +{ + return g_unichar_combining_class (unicode); +} + +static unsigned int +hb_glib_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + return g_unichar_iswide (unicode) ? 2 : 1; +} + +static hb_unicode_general_category_t +hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) + +{ + /* hb_unicode_general_category_t and GUnicodeType are identical */ + return (hb_unicode_general_category_t) g_unichar_type (unicode); +} + +static hb_codepoint_t +hb_glib_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + g_unichar_get_mirror_char (unicode, &unicode); + return unicode; +} + +static hb_script_t +hb_glib_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + return hb_glib_script_to_script (g_unichar_get_script (unicode)); +} + +static hb_bool_t +hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab, + void *user_data HB_UNUSED) +{ +#if GLIB_CHECK_VERSION(2,29,12) + return g_unichar_compose (a, b, ab); +#endif + + /* We don't ifdef-out the fallback code such that compiler always + * sees it and makes sure it's compilable. */ + + if (!a || !b) + return FALSE; + + gchar utf8[12]; + gchar *normalized; + gint len; + hb_bool_t ret; + + len = g_unichar_to_utf8 (a, utf8); + len += g_unichar_to_utf8 (b, utf8 + len); + normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC); + len = g_utf8_strlen (normalized, -1); + if (unlikely (!len)) + return FALSE; + + if (len == 1) { + *ab = g_utf8_get_char (normalized); + ret = TRUE; + } else { + ret = FALSE; + } + + g_free (normalized); + return ret; +} + +static hb_bool_t +hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b, + void *user_data HB_UNUSED) +{ +#if GLIB_CHECK_VERSION(2,29,12) + return g_unichar_decompose (ab, a, b); +#endif + + /* We don't ifdef-out the fallback code such that compiler always + * sees it and makes sure it's compilable. */ + + gchar utf8[6]; + gchar *normalized; + gint len; + hb_bool_t ret; + + len = g_unichar_to_utf8 (ab, utf8); + normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD); + len = g_utf8_strlen (normalized, -1); + if (unlikely (!len)) + return FALSE; + + if (len == 1) { + *a = g_utf8_get_char (normalized); + *b = 0; + ret = *a != ab; + } else if (len == 2) { + *a = g_utf8_get_char (normalized); + *b = g_utf8_get_char (g_utf8_next_char (normalized)); + /* Here's the ugly part: if ab decomposes to a single character and + * that character decomposes again, we have to detect that and undo + * the second part :-(. */ + gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC); + hb_codepoint_t c = g_utf8_get_char (recomposed); + if (c != ab && c != *a) { + *a = c; + *b = 0; + } + g_free (recomposed); + ret = TRUE; + } else { + /* If decomposed to more than two characters, take the last one, + * and recompose the rest to get the first component. */ + gchar *end = g_utf8_offset_to_pointer (normalized, len - 1); + gchar *recomposed; + *b = g_utf8_get_char (end); + recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC); + /* We expect that recomposed has exactly one character now. */ + *a = g_utf8_get_char (recomposed); + g_free (recomposed); + ret = TRUE; + } + + g_free (normalized); + return ret; +} + + +extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_glib; +hb_unicode_funcs_t _hb_glib_unicode_funcs = { + HB_OBJECT_HEADER_STATIC, + + NULL, /* parent */ + TRUE, /* immutable */ + { +#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name, + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + } +}; + +hb_unicode_funcs_t * +hb_glib_get_unicode_funcs (void) +{ + return &_hb_glib_unicode_funcs; +} + diff --git a/third_party/harfbuzz-ng/src/hb-glib.h b/third_party/harfbuzz-ng/src/hb-glib.h index 81ab15d..3bc3ebf 100644 --- a/third_party/harfbuzz-ng/src/hb-glib.h +++ b/third_party/harfbuzz-ng/src/hb-glib.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,16 +23,25 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_GLIB_H #define HB_GLIB_H #include "hb.h" +#include <glib.h> HB_BEGIN_DECLS +hb_script_t +hb_glib_script_to_script (GUnicodeScript script); + +GUnicodeScript +hb_glib_script_from_script (hb_script_t script); + + hb_unicode_funcs_t * hb_glib_get_unicode_funcs (void); diff --git a/third_party/harfbuzz-ng/src/hb-gobject-enums.cc b/third_party/harfbuzz-ng/src/hb-gobject-enums.cc new file mode 100644 index 0000000..9d16c85 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-gobject-enums.cc @@ -0,0 +1,259 @@ + +/* Generated data (by glib-mkenums) */ + +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +/* g++ didn't like older gtype.h gcc-only code path. */ +#include <glib.h> +#if !GLIB_CHECK_VERSION(2,29,16) +#undef __GNUC__ +#undef __GNUC_MINOR__ +#define __GNUC__ 2 +#define __GNUC_MINOR__ 6 +#endif + +#include "hb-gobject.h" + +/* enumerations from "hb-blob.h" */ +inline static /* TODO(behdad) disable these for now until we fix them... */ +GType +hb_memory_mode_t_hb_memory_mode_t_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GEnumValue values[] = { + { HB_MEMORY_MODE_DUPLICATE, "HB_MEMORY_MODE_DUPLICATE", "duplicate" }, + { HB_MEMORY_MODE_READONLY, "HB_MEMORY_MODE_READONLY", "readonly" }, + { HB_MEMORY_MODE_WRITABLE, "HB_MEMORY_MODE_WRITABLE", "writable" }, + { HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, "HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE", "readonly-may-make-writable" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_enum_register_static (g_intern_static_string ("hb_memory_mode_t"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/* enumerations from "hb-common.h" */ +inline static /* TODO(behdad) disable these for now until we fix them... */ +GType +hb_direction_t_hb_direction_t_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GEnumValue values[] = { + { HB_DIRECTION_INVALID, "HB_DIRECTION_INVALID", "invalid" }, + { HB_DIRECTION_LTR, "HB_DIRECTION_LTR", "ltr" }, + { HB_DIRECTION_RTL, "HB_DIRECTION_RTL", "rtl" }, + { HB_DIRECTION_TTB, "HB_DIRECTION_TTB", "ttb" }, + { HB_DIRECTION_BTT, "HB_DIRECTION_BTT", "btt" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_enum_register_static (g_intern_static_string ("hb_direction_t"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +inline static /* TODO(behdad) disable these for now until we fix them... */ +GType +hb_unicode_general_category_t_hb_unicode_general_category_t_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GEnumValue values[] = { + { HB_UNICODE_GENERAL_CATEGORY_CONTROL, "HB_UNICODE_GENERAL_CATEGORY_CONTROL", "control" }, + { HB_UNICODE_GENERAL_CATEGORY_FORMAT, "HB_UNICODE_GENERAL_CATEGORY_FORMAT", "format" }, + { HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED, "HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED", "unassigned" }, + { HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE, "HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE", "private-use" }, + { HB_UNICODE_GENERAL_CATEGORY_SURROGATE, "HB_UNICODE_GENERAL_CATEGORY_SURROGATE", "surrogate" }, + { HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER", "lowercase-letter" }, + { HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER, "HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER", "modifier-letter" }, + { HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER, "HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER", "other-letter" }, + { HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER", "titlecase-letter" }, + { HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER, "HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER", "uppercase-letter" }, + { HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK, "HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK", "spacing-mark" }, + { HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK, "HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK", "enclosing-mark" }, + { HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK, "HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK", "non-spacing-mark" }, + { HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER", "decimal-number" }, + { HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER", "letter-number" }, + { HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER, "HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER", "other-number" }, + { HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION", "connect-punctuation" }, + { HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION", "dash-punctuation" }, + { HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION", "close-punctuation" }, + { HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION", "final-punctuation" }, + { HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION", "initial-punctuation" }, + { HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION", "other-punctuation" }, + { HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION, "HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION", "open-punctuation" }, + { HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL", "currency-symbol" }, + { HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL", "modifier-symbol" }, + { HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL", "math-symbol" }, + { HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL, "HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL", "other-symbol" }, + { HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR", "line-separator" }, + { HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR", "paragraph-separator" }, + { HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR, "HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR", "space-separator" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_enum_register_static (g_intern_static_string ("hb_unicode_general_category_t"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +inline static /* TODO(behdad) disable these for now until we fix them... */ +GType +hb_script_t_hb_script_t_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GEnumValue values[] = { + { HB_SCRIPT_COMMON, "HB_SCRIPT_COMMON", "common" }, + { HB_SCRIPT_INHERITED, "HB_SCRIPT_INHERITED", "inherited" }, + { HB_SCRIPT_ARABIC, "HB_SCRIPT_ARABIC", "arabic" }, + { HB_SCRIPT_ARMENIAN, "HB_SCRIPT_ARMENIAN", "armenian" }, + { HB_SCRIPT_BENGALI, "HB_SCRIPT_BENGALI", "bengali" }, + { HB_SCRIPT_BOPOMOFO, "HB_SCRIPT_BOPOMOFO", "bopomofo" }, + { HB_SCRIPT_CHEROKEE, "HB_SCRIPT_CHEROKEE", "cherokee" }, + { HB_SCRIPT_COPTIC, "HB_SCRIPT_COPTIC", "coptic" }, + { HB_SCRIPT_CYRILLIC, "HB_SCRIPT_CYRILLIC", "cyrillic" }, + { HB_SCRIPT_DESERET, "HB_SCRIPT_DESERET", "deseret" }, + { HB_SCRIPT_DEVANAGARI, "HB_SCRIPT_DEVANAGARI", "devanagari" }, + { HB_SCRIPT_ETHIOPIC, "HB_SCRIPT_ETHIOPIC", "ethiopic" }, + { HB_SCRIPT_GEORGIAN, "HB_SCRIPT_GEORGIAN", "georgian" }, + { HB_SCRIPT_GOTHIC, "HB_SCRIPT_GOTHIC", "gothic" }, + { HB_SCRIPT_GREEK, "HB_SCRIPT_GREEK", "greek" }, + { HB_SCRIPT_GUJARATI, "HB_SCRIPT_GUJARATI", "gujarati" }, + { HB_SCRIPT_GURMUKHI, "HB_SCRIPT_GURMUKHI", "gurmukhi" }, + { HB_SCRIPT_HAN, "HB_SCRIPT_HAN", "han" }, + { HB_SCRIPT_HANGUL, "HB_SCRIPT_HANGUL", "hangul" }, + { HB_SCRIPT_HEBREW, "HB_SCRIPT_HEBREW", "hebrew" }, + { HB_SCRIPT_HIRAGANA, "HB_SCRIPT_HIRAGANA", "hiragana" }, + { HB_SCRIPT_KANNADA, "HB_SCRIPT_KANNADA", "kannada" }, + { HB_SCRIPT_KATAKANA, "HB_SCRIPT_KATAKANA", "katakana" }, + { HB_SCRIPT_KHMER, "HB_SCRIPT_KHMER", "khmer" }, + { HB_SCRIPT_LAO, "HB_SCRIPT_LAO", "lao" }, + { HB_SCRIPT_LATIN, "HB_SCRIPT_LATIN", "latin" }, + { HB_SCRIPT_MALAYALAM, "HB_SCRIPT_MALAYALAM", "malayalam" }, + { HB_SCRIPT_MONGOLIAN, "HB_SCRIPT_MONGOLIAN", "mongolian" }, + { HB_SCRIPT_MYANMAR, "HB_SCRIPT_MYANMAR", "myanmar" }, + { HB_SCRIPT_OGHAM, "HB_SCRIPT_OGHAM", "ogham" }, + { HB_SCRIPT_OLD_ITALIC, "HB_SCRIPT_OLD_ITALIC", "old-italic" }, + { HB_SCRIPT_ORIYA, "HB_SCRIPT_ORIYA", "oriya" }, + { HB_SCRIPT_RUNIC, "HB_SCRIPT_RUNIC", "runic" }, + { HB_SCRIPT_SINHALA, "HB_SCRIPT_SINHALA", "sinhala" }, + { HB_SCRIPT_SYRIAC, "HB_SCRIPT_SYRIAC", "syriac" }, + { HB_SCRIPT_TAMIL, "HB_SCRIPT_TAMIL", "tamil" }, + { HB_SCRIPT_TELUGU, "HB_SCRIPT_TELUGU", "telugu" }, + { HB_SCRIPT_THAANA, "HB_SCRIPT_THAANA", "thaana" }, + { HB_SCRIPT_THAI, "HB_SCRIPT_THAI", "thai" }, + { HB_SCRIPT_TIBETAN, "HB_SCRIPT_TIBETAN", "tibetan" }, + { HB_SCRIPT_CANADIAN_ABORIGINAL, "HB_SCRIPT_CANADIAN_ABORIGINAL", "canadian-aboriginal" }, + { HB_SCRIPT_YI, "HB_SCRIPT_YI", "yi" }, + { HB_SCRIPT_TAGALOG, "HB_SCRIPT_TAGALOG", "tagalog" }, + { HB_SCRIPT_HANUNOO, "HB_SCRIPT_HANUNOO", "hanunoo" }, + { HB_SCRIPT_BUHID, "HB_SCRIPT_BUHID", "buhid" }, + { HB_SCRIPT_TAGBANWA, "HB_SCRIPT_TAGBANWA", "tagbanwa" }, + { HB_SCRIPT_BRAILLE, "HB_SCRIPT_BRAILLE", "braille" }, + { HB_SCRIPT_CYPRIOT, "HB_SCRIPT_CYPRIOT", "cypriot" }, + { HB_SCRIPT_LIMBU, "HB_SCRIPT_LIMBU", "limbu" }, + { HB_SCRIPT_OSMANYA, "HB_SCRIPT_OSMANYA", "osmanya" }, + { HB_SCRIPT_SHAVIAN, "HB_SCRIPT_SHAVIAN", "shavian" }, + { HB_SCRIPT_LINEAR_B, "HB_SCRIPT_LINEAR_B", "linear-b" }, + { HB_SCRIPT_TAI_LE, "HB_SCRIPT_TAI_LE", "tai-le" }, + { HB_SCRIPT_UGARITIC, "HB_SCRIPT_UGARITIC", "ugaritic" }, + { HB_SCRIPT_NEW_TAI_LUE, "HB_SCRIPT_NEW_TAI_LUE", "new-tai-lue" }, + { HB_SCRIPT_BUGINESE, "HB_SCRIPT_BUGINESE", "buginese" }, + { HB_SCRIPT_GLAGOLITIC, "HB_SCRIPT_GLAGOLITIC", "glagolitic" }, + { HB_SCRIPT_TIFINAGH, "HB_SCRIPT_TIFINAGH", "tifinagh" }, + { HB_SCRIPT_SYLOTI_NAGRI, "HB_SCRIPT_SYLOTI_NAGRI", "syloti-nagri" }, + { HB_SCRIPT_OLD_PERSIAN, "HB_SCRIPT_OLD_PERSIAN", "old-persian" }, + { HB_SCRIPT_KHAROSHTHI, "HB_SCRIPT_KHAROSHTHI", "kharoshthi" }, + { HB_SCRIPT_UNKNOWN, "HB_SCRIPT_UNKNOWN", "unknown" }, + { HB_SCRIPT_BALINESE, "HB_SCRIPT_BALINESE", "balinese" }, + { HB_SCRIPT_CUNEIFORM, "HB_SCRIPT_CUNEIFORM", "cuneiform" }, + { HB_SCRIPT_PHOENICIAN, "HB_SCRIPT_PHOENICIAN", "phoenician" }, + { HB_SCRIPT_PHAGS_PA, "HB_SCRIPT_PHAGS_PA", "phags-pa" }, + { HB_SCRIPT_NKO, "HB_SCRIPT_NKO", "nko" }, + { HB_SCRIPT_KAYAH_LI, "HB_SCRIPT_KAYAH_LI", "kayah-li" }, + { HB_SCRIPT_LEPCHA, "HB_SCRIPT_LEPCHA", "lepcha" }, + { HB_SCRIPT_REJANG, "HB_SCRIPT_REJANG", "rejang" }, + { HB_SCRIPT_SUNDANESE, "HB_SCRIPT_SUNDANESE", "sundanese" }, + { HB_SCRIPT_SAURASHTRA, "HB_SCRIPT_SAURASHTRA", "saurashtra" }, + { HB_SCRIPT_CHAM, "HB_SCRIPT_CHAM", "cham" }, + { HB_SCRIPT_OL_CHIKI, "HB_SCRIPT_OL_CHIKI", "ol-chiki" }, + { HB_SCRIPT_VAI, "HB_SCRIPT_VAI", "vai" }, + { HB_SCRIPT_CARIAN, "HB_SCRIPT_CARIAN", "carian" }, + { HB_SCRIPT_LYCIAN, "HB_SCRIPT_LYCIAN", "lycian" }, + { HB_SCRIPT_LYDIAN, "HB_SCRIPT_LYDIAN", "lydian" }, + { HB_SCRIPT_AVESTAN, "HB_SCRIPT_AVESTAN", "avestan" }, + { HB_SCRIPT_BAMUM, "HB_SCRIPT_BAMUM", "bamum" }, + { HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, "HB_SCRIPT_EGYPTIAN_HIEROGLYPHS", "egyptian-hieroglyphs" }, + { HB_SCRIPT_IMPERIAL_ARAMAIC, "HB_SCRIPT_IMPERIAL_ARAMAIC", "imperial-aramaic" }, + { HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, "HB_SCRIPT_INSCRIPTIONAL_PAHLAVI", "inscriptional-pahlavi" }, + { HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, "HB_SCRIPT_INSCRIPTIONAL_PARTHIAN", "inscriptional-parthian" }, + { HB_SCRIPT_JAVANESE, "HB_SCRIPT_JAVANESE", "javanese" }, + { HB_SCRIPT_KAITHI, "HB_SCRIPT_KAITHI", "kaithi" }, + { HB_SCRIPT_LISU, "HB_SCRIPT_LISU", "lisu" }, + { HB_SCRIPT_MEETEI_MAYEK, "HB_SCRIPT_MEETEI_MAYEK", "meetei-mayek" }, + { HB_SCRIPT_OLD_SOUTH_ARABIAN, "HB_SCRIPT_OLD_SOUTH_ARABIAN", "old-south-arabian" }, + { HB_SCRIPT_OLD_TURKIC, "HB_SCRIPT_OLD_TURKIC", "old-turkic" }, + { HB_SCRIPT_SAMARITAN, "HB_SCRIPT_SAMARITAN", "samaritan" }, + { HB_SCRIPT_TAI_THAM, "HB_SCRIPT_TAI_THAM", "tai-tham" }, + { HB_SCRIPT_TAI_VIET, "HB_SCRIPT_TAI_VIET", "tai-viet" }, + { HB_SCRIPT_BATAK, "HB_SCRIPT_BATAK", "batak" }, + { HB_SCRIPT_BRAHMI, "HB_SCRIPT_BRAHMI", "brahmi" }, + { HB_SCRIPT_MANDAIC, "HB_SCRIPT_MANDAIC", "mandaic" }, + { HB_SCRIPT_INVALID, "HB_SCRIPT_INVALID", "invalid" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_enum_register_static (g_intern_static_string ("hb_script_t"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + + +/* Generated data ends here */ + diff --git a/third_party/harfbuzz-ng/src/hb-gobject-enums.cc.tmpl b/third_party/harfbuzz-ng/src/hb-gobject-enums.cc.tmpl new file mode 100644 index 0000000..05abd89 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-gobject-enums.cc.tmpl @@ -0,0 +1,74 @@ +/*** BEGIN file-header ***/ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +/* g++ didn't like older gtype.h gcc-only code path. */ +#include <glib.h> +#if !GLIB_CHECK_VERSION(2,29,16) +#undef __GNUC__ +#undef __GNUC_MINOR__ +#define __GNUC__ 2 +#define __GNUC_MINOR__ 6 +#endif + +#include "hb-gobject.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +inline static /* TODO(behdad) disable these for now until we fix them... */ +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/*** END value-tail ***/ diff --git a/third_party/harfbuzz-ng/src/hb-gobject-structs.cc b/third_party/harfbuzz-ng/src/hb-gobject-structs.cc new file mode 100644 index 0000000..cec4854 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-gobject-structs.cc @@ -0,0 +1,63 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +/* g++ didn't like older gtype.h gcc-only code path. */ +#include <glib.h> +#if !GLIB_CHECK_VERSION(2,29,16) +#undef __GNUC__ +#undef __GNUC_MINOR__ +#define __GNUC__ 2 +#define __GNUC_MINOR__ 6 +#endif + +#include "hb-gobject.h" + +#define _HB_DEFINE_BOXED_TYPE(Name,underscore_name,copy_func,free_func) \ +GType \ +underscore_name##_get_type (void) \ +{ \ + static volatile gsize type = 0; \ + if (g_once_init_enter (&type)) { \ + GType t = g_boxed_type_register_static (g_intern_static_string (#Name), \ + (GBoxedCopyFunc) copy_func, \ + (GBoxedFreeFunc) free_func); \ + g_once_init_leave (&type, t); \ + } \ + return type; \ +} + +#define HB_DEFINE_BOXED_TYPE(name) \ + _HB_DEFINE_BOXED_TYPE (hb_##name, hb_gobject_##name, hb_##name##_reference, hb_##name##_destroy); + +HB_DEFINE_BOXED_TYPE (buffer) +HB_DEFINE_BOXED_TYPE (blob) +HB_DEFINE_BOXED_TYPE (face) +HB_DEFINE_BOXED_TYPE (font) +HB_DEFINE_BOXED_TYPE (font_funcs) +HB_DEFINE_BOXED_TYPE (unicode_funcs) + diff --git a/third_party/harfbuzz-ng/src/hb-unicode-private.h b/third_party/harfbuzz-ng/src/hb-gobject.h index 419404b..25fc941 100644 --- a/third_party/harfbuzz-ng/src/hb-unicode-private.h +++ b/third_party/harfbuzz-ng/src/hb-gobject.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -21,44 +21,48 @@ * 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_UNICODE_PRIVATE_H -#define HB_UNICODE_PRIVATE_H +#ifndef HB_GOBJECT_H +#define HB_GOBJECT_H -#include "hb-private.h" - -#include "hb-unicode.h" +#include "hb.h" +#include <glib-object.h> HB_BEGIN_DECLS -/* - * hb_unicode_funcs_t - */ +/* Objects */ + +#define HB_GOBJECT_TYPE_BLOB hb_gobject_blob_get_type () +GType +hb_gobject_blob_get_type (void); + +#define HB_GOBJECT_TYPE_BUFFER hb_gobject_buffer_get_type () +GType +hb_gobject_buffer_get_type (void); -struct _hb_unicode_funcs_t { - hb_reference_count_t ref_count; +#define HB_GOBJECT_TYPE_FACE hb_gobject_face_get_type () +GType +hb_gobject_face_get_type (void); - hb_bool_t immutable; +#define HB_GOBJECT_TYPE_FONT hb_gobject_font_get_type () +GType +hb_gobject_font_get_type (void); - 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; -}; +#define HB_GOBJECT_TYPE_FONT_FUNCS hb_gobject_font_funcs_get_type () +GType +hb_gobject_font_funcs_get_type (void); -extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_nil; +#define HB_GOBJECT_TYPE_UNICODE_FUNCS hb_gobject_unicode_funcs_get_type () +GType +hb_gobject_unicode_funcs_get_type (void); -HB_INTERNAL hb_direction_t -_hb_script_get_horizontal_direction (hb_script_t script); +/* Enums */ HB_END_DECLS -#endif /* HB_UNICODE_PRIVATE_H */ +#endif /* HB_GOBJECT_H */ diff --git a/third_party/harfbuzz-ng/src/hb-graphite.cc b/third_party/harfbuzz-ng/src/hb-graphite.cc deleted file mode 100644 index 0a8d681..0000000 --- a/third_party/harfbuzz-ng/src/hb-graphite.cc +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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-graphite2.cc b/third_party/harfbuzz-ng/src/hb-graphite2.cc new file mode 100644 index 0000000..0675759 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-graphite2.cc @@ -0,0 +1,348 @@ +/* + * Copyright © 2011 Martin Hosken + * Copyright © 2011 SIL International + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-graphite2.h" + +#include "hb-buffer-private.hh" +#include "hb-font-private.hh" +#include "hb-ot-tag.h" + +#include <graphite2/Font.h> +#include <graphite2/Segment.h> + + +struct hb_gr_cluster_t { + unsigned int base_char; + unsigned int num_chars; + unsigned int base_glyph; + unsigned int num_glyphs; +}; + + +typedef struct hb_gr_tablelist_t { + hb_blob_t *blob; + struct hb_gr_tablelist_t *next; + unsigned int tag; +} hb_gr_tablelist_t; + +static struct hb_gr_face_data_t { + hb_face_t *face; + gr_face *grface; + hb_gr_tablelist_t *tlist; +} _hb_gr_face_data_nil = {NULL, NULL}; + +static struct hb_gr_font_data_t { + gr_font *grfont; + gr_face *grface; +} _hb_gr_font_data_nil = {NULL, NULL}; + + +static const void *hb_gr_get_table (const void *data, unsigned int tag, size_t *len) +{ + hb_gr_tablelist_t *pl = NULL, *p; + hb_gr_face_data_t *face = (hb_gr_face_data_t *) data; + hb_gr_tablelist_t *tlist = face->tlist; + + for (p = tlist; p; p = p->next) + if (p->tag == tag ) { + unsigned int tlen; + const char *d = hb_blob_get_data (p->blob, &tlen); + *len = tlen; + return d; + } else + pl = p; + + if (!face->face) + return NULL; + hb_blob_t *blob = hb_face_reference_table (face->face, tag); + + if (!pl || pl->blob) + { + p = (hb_gr_tablelist_t *) malloc (sizeof (hb_gr_tablelist_t)); + if (!p) { + hb_blob_destroy (blob); + return NULL; + } + p->next = NULL; + if (pl) + pl->next = p; + else + face->tlist = p; + pl = p; + } + pl->blob = blob; + pl->tag = tag; + + unsigned int tlen; + const char *d = hb_blob_get_data (blob, &tlen); + *len = tlen; + return d; +} + +static float hb_gr_get_advance (const void *hb_font, unsigned short gid) +{ + return hb_font_get_glyph_h_advance ((hb_font_t *) hb_font, gid); +} + +static void _hb_gr_face_data_destroy (void *data) +{ + hb_gr_face_data_t *f = (hb_gr_face_data_t *) data; + hb_gr_tablelist_t *tlist = f->tlist; + while (tlist) + { + hb_gr_tablelist_t *old = tlist; + hb_blob_destroy (tlist->blob); + tlist = tlist->next; + free (old); + } + gr_face_destroy (f->grface); +} + +static void _hb_gr_font_data_destroy (void *data) +{ + hb_gr_font_data_t *f = (hb_gr_font_data_t *) data; + + gr_font_destroy (f->grfont); +} + +static hb_user_data_key_t hb_gr_data_key; + +static hb_gr_face_data_t * +_hb_gr_face_get_data (hb_face_t *face) +{ + hb_gr_face_data_t *data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key); + if (likely (data)) return data; + + data = (hb_gr_face_data_t *) calloc (1, sizeof (hb_gr_face_data_t)); + if (unlikely (!data)) + return &_hb_gr_face_data_nil; + + + hb_blob_t *silf_blob = hb_face_reference_table (face, HB_GRAPHITE_TAG_Silf); + if (!hb_blob_get_length (silf_blob)) + { + hb_blob_destroy (silf_blob); + return &_hb_gr_face_data_nil; + } + + data->face = face; + data->grface = gr_make_face (data, &hb_gr_get_table, gr_face_default); + + + if (unlikely (!hb_face_set_user_data (face, &hb_gr_data_key, data, + (hb_destroy_func_t) _hb_gr_face_data_destroy, + FALSE))) + { + _hb_gr_face_data_destroy (data); + data = (hb_gr_face_data_t *) hb_face_get_user_data (face, &hb_gr_data_key); + if (data) + return data; + else + return &_hb_gr_face_data_nil; + } + + return data; +} + +static hb_gr_font_data_t * +_hb_gr_font_get_data (hb_font_t *font) +{ + hb_gr_font_data_t *data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key); + if (likely (data)) return data; + + data = (hb_gr_font_data_t *) calloc (1, sizeof (hb_gr_font_data_t)); + if (unlikely (!data)) + return &_hb_gr_font_data_nil; + + + hb_blob_t *silf_blob = hb_face_reference_table (font->face, HB_GRAPHITE_TAG_Silf); + if (!hb_blob_get_length (silf_blob)) + { + hb_blob_destroy (silf_blob); + return &_hb_gr_font_data_nil; + } + + data->grface = _hb_gr_face_get_data (font->face)->grface; + int scale; + hb_font_get_scale (font, &scale, NULL); + data->grfont = gr_make_font_with_advance_fn (scale, font, &hb_gr_get_advance, data->grface); + + + if (unlikely (!hb_font_set_user_data (font, &hb_gr_data_key, data, + (hb_destroy_func_t) _hb_gr_font_data_destroy, + FALSE))) + { + _hb_gr_font_data_destroy (data); + data = (hb_gr_font_data_t *) hb_font_get_user_data (font, &hb_gr_data_key); + if (data) + return data; + else + return &_hb_gr_font_data_nil; + } + + return data; +} + + +hb_bool_t +hb_graphite_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options) +{ + + buffer->guess_properties (); + + hb_gr_font_data_t *data = _hb_gr_font_get_data (font); + if (!data->grface) return FALSE; + + unsigned int charlen; + hb_glyph_info_t *bufferi = hb_buffer_get_glyph_infos (buffer, &charlen); + + int success = 0; + + if (!charlen) return TRUE; + + const char *lang = hb_language_to_string (hb_buffer_get_language (buffer)); + const char *lang_end = strchr (lang, '-'); + int lang_len = lang_end ? lang_end - lang : -1; + gr_feature_val *feats = gr_face_featureval_for_lang (data->grface, lang ? hb_tag_from_string (lang, lang_len) : 0); + + while (num_features--) + { + const gr_feature_ref *fref = gr_face_find_fref (data->grface, features->tag); + if (fref) + gr_fref_set_feature_value (fref, features->value, feats); + features++; + } + + unsigned short *gids = NULL; + hb_gr_cluster_t *clusters = NULL; + gr_segment *seg = NULL; + uint32_t *text = NULL; + unsigned short *pg; + const gr_slot *is; + unsigned int ci = 0, ic = 0; + float curradvx = 0., curradvy = 0.; + unsigned int glyphlen = 0; + unsigned int *p; + + text = (uint32_t *) malloc ((charlen + 1) * sizeof (uint32_t)); + if (!text) goto dieout; + + p = text; + for (unsigned int i = 0; i < charlen; ++i) + *p++ = bufferi++->codepoint; + *p = 0; + + hb_tag_t script_tag[2]; + hb_ot_tags_from_script (hb_buffer_get_script (buffer), &script_tag[0], &script_tag[1]); + + seg = gr_make_seg (data->grfont, data->grface, + script_tag[1] == HB_TAG_NONE ? script_tag[0] : script_tag[1], + feats, + gr_utf32, text, charlen, + 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0)); + if (!seg) goto dieout; + + glyphlen = gr_seg_n_slots (seg); + clusters = (hb_gr_cluster_t *) calloc (charlen, sizeof (hb_gr_cluster_t)); + if (!glyphlen || !clusters) goto dieout; + + gids = (uint16_t *) malloc (glyphlen * sizeof (uint16_t)); + if (!gids) goto dieout; + + pg = gids; + for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++) + { + unsigned int before = gr_slot_before (is); + unsigned int after = gr_slot_after (is); + *pg = gr_slot_gid (is); + pg++; + while (clusters[ci].base_char > before && ci) + { + clusters[ci-1].num_chars += clusters[ci].num_chars; + clusters[ci-1].num_glyphs += clusters[ci].num_glyphs; + ci--; + } + + if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars) + { + hb_gr_cluster_t *c = clusters + ci + 1; + c->base_char = clusters[ci].base_char + clusters[ci].num_chars; + c->num_chars = before - c->base_char; + c->base_glyph = ic; + c->num_glyphs = 0; + ci++; + } + clusters[ci].num_glyphs++; + + if (clusters[ci].base_char + clusters[ci].num_chars < after + 1) + clusters[ci].num_chars = after + 1 - clusters[ci].base_char; + } + ci++; + + buffer->clear_output (); + for (unsigned int i = 0; i < ci; ++i) + buffer->replace_glyphs (clusters[i].num_chars, clusters[i].num_glyphs, gids + clusters[i].base_glyph); + buffer->swap_buffers (); + + hb_glyph_position_t *pPos; + for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg); + is; pPos++, is = gr_slot_next_in_segment (is)) + { + pPos->x_offset = gr_slot_origin_X(is) - curradvx; + pPos->y_offset = gr_slot_origin_Y(is) - curradvy; + pPos->x_advance = gr_slot_advance_X(is, data->grface, data->grfont); + pPos->y_advance = gr_slot_advance_Y(is, data->grface, data->grfont); +// if (pPos->x_advance < 0 && gr_slot_attached_to(is)) +// pPos->x_advance = 0; + curradvx += pPos->x_advance; + curradvy += pPos->y_advance; + } + pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx; + + /* TODO(behdad): + * This shaper is badly broken with RTL text. It returns glyphs + * in the logical order! + */ +// if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction)) +// hb_buffer_reverse (buffer); + + success = 1; + +dieout: + if (gids) free (gids); + if (clusters) free (clusters); + if (seg) gr_seg_destroy (seg); + if (text) free (text); + return success; +} diff --git a/third_party/harfbuzz-ng/src/hb-graphite.h b/third_party/harfbuzz-ng/src/hb-graphite2.h index b5d1176..68bd019 100644 --- a/third_party/harfbuzz-ng/src/hb-graphite.h +++ b/third_party/harfbuzz-ng/src/hb-graphite2.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009, Martin Hosken - * Copyright (C) 2009, SIL International + * Copyright (C) 2011 Martin Hosken + * Copyright (C) 2011 SIL International * * This is part of HarfBuzz, a text shaping library. * @@ -21,13 +21,12 @@ * 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 +#ifndef HB_GRAPHITE2_H +#define HB_GRAPHITE2_H +#include "hb-common.h" #include "hb-shape.h" HB_BEGIN_DECLS @@ -35,13 +34,13 @@ 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_bool_t +hb_graphite_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options); HB_END_DECLS -#endif /* HB_GRAPHITE_H */ +#endif /* HB_GRAPHITE2_H */ diff --git a/third_party/harfbuzz-ng/src/hb-icu.c b/third_party/harfbuzz-ng/src/hb-icu.c deleted file mode 100644 index 601ef61..0000000 --- a/third_party/harfbuzz-ng/src/hb-icu.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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.cc b/third_party/harfbuzz-ng/src/hb-icu.cc new file mode 100644 index 0000000..5cd0143 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-icu.cc @@ -0,0 +1,291 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2009 Keith Stribley + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-icu.h" + +#include "hb-unicode-private.hh" + +#include <unicode/uversion.h> +#include <unicode/uchar.h> +#include <unicode/unorm.h> +#include <unicode/ustring.h> + + + +hb_script_t +hb_icu_script_to_script (UScriptCode script) +{ + if (unlikely (script == USCRIPT_INVALID_CODE)) + return HB_SCRIPT_INVALID; + + return hb_script_from_string (uscript_getShortName (script), -1); +} + +UScriptCode +hb_icu_script_from_script (hb_script_t script) +{ + if (unlikely (script == HB_SCRIPT_INVALID)) + return USCRIPT_INVALID_CODE; + + for (unsigned int i = 0; i < USCRIPT_CODE_LIMIT; i++) + if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script)) + return (UScriptCode) i; + + return USCRIPT_UNKNOWN; +} + + +static unsigned int +hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) + +{ + return u_getCombiningClass (unicode); +} + +static unsigned int +hb_icu_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + switch (u_getIntPropertyValue(unicode, UCHAR_EAST_ASIAN_WIDTH)) + { + case U_EA_WIDE: + case U_EA_FULLWIDTH: + return 2; + case U_EA_NEUTRAL: + case U_EA_AMBIGUOUS: + case U_EA_HALFWIDTH: + case U_EA_NARROW: + return 1; + } + return 1; +} + +static hb_unicode_general_category_t +hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY)) + { + case U_UNASSIGNED: return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED; + + case U_UPPERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER; + case U_LOWERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER; + case U_TITLECASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER; + case U_MODIFIER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER; + case U_OTHER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER; + + case U_NON_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK; + case U_ENCLOSING_MARK: return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK; + case U_COMBINING_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK; + + case U_DECIMAL_DIGIT_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER; + case U_LETTER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER; + case U_OTHER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER; + + case U_SPACE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR; + case U_LINE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR; + case U_PARAGRAPH_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR; + + case U_CONTROL_CHAR: return HB_UNICODE_GENERAL_CATEGORY_CONTROL; + case U_FORMAT_CHAR: return HB_UNICODE_GENERAL_CATEGORY_FORMAT; + case U_PRIVATE_USE_CHAR: return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE; + case U_SURROGATE: return HB_UNICODE_GENERAL_CATEGORY_SURROGATE; + + + case U_DASH_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION; + case U_START_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION; + case U_END_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION; + case U_CONNECTOR_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION; + case U_OTHER_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION; + + case U_MATH_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL; + case U_CURRENCY_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL; + case U_MODIFIER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL; + case U_OTHER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL; + + case U_INITIAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION; + case U_FINAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION; + } + + return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED; +} + +static hb_codepoint_t +hb_icu_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + return u_charMirror(unicode); +} + +static hb_script_t +hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + UErrorCode status = U_ZERO_ERROR; + UScriptCode scriptCode = uscript_getScript(unicode, &status); + + if (unlikely (U_FAILURE (status))) + return HB_SCRIPT_UNKNOWN; + + return hb_icu_script_to_script (scriptCode); +} + +static hb_bool_t +hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab, + void *user_data HB_UNUSED) +{ + if (!a || !b) + return FALSE; + + UChar utf16[4], normalized[5]; + int len; + hb_bool_t ret, err; + UErrorCode icu_err; + + len = 0; + err = FALSE; + U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err); + if (err) return FALSE; + U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err); + if (err) return FALSE; + + icu_err = U_ZERO_ERROR; + len = unorm_normalize (utf16, len, UNORM_NFC, 0, normalized, ARRAY_LENGTH (normalized), &icu_err); + if (U_FAILURE (icu_err)) + return FALSE; + if (u_countChar32 (normalized, len) == 1) { + U16_GET_UNSAFE (normalized, 0, *ab); + ret = TRUE; + } else { + ret = FALSE; + } + + return ret; +} + +static hb_bool_t +hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b, + void *user_data HB_UNUSED) +{ + UChar utf16[2], normalized[20]; + int len; + hb_bool_t ret, err; + UErrorCode icu_err; + + /* This function is a monster! Maybe it wasn't a good idea adding a + * pairwise decompose API... */ + /* Watchout for the dragons. Err, watchout for macros changing len. */ + + len = 0; + err = FALSE; + U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err); + if (err) return FALSE; + + icu_err = U_ZERO_ERROR; + len = unorm_normalize (utf16, len, UNORM_NFD, 0, normalized, ARRAY_LENGTH (normalized), &icu_err); + if (U_FAILURE (icu_err)) + return FALSE; + + len = u_countChar32 (normalized, len); + + if (len == 1) { + U16_GET_UNSAFE (normalized, 0, *a); + *b = 0; + ret = *a != ab; + } else if (len == 2) { + len =0; + U16_NEXT_UNSAFE (normalized, len, *a); + U16_NEXT_UNSAFE (normalized, len, *b); + + /* Here's the ugly part: if ab decomposes to a single character and + * that character decomposes again, we have to detect that and undo + * the second part :-(. */ + UChar recomposed[20]; + icu_err = U_ZERO_ERROR; + unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err); + if (U_FAILURE (icu_err)) + return FALSE; + hb_codepoint_t c; + U16_GET_UNSAFE (recomposed, 0, c); + if (c != *a && c != ab) { + *a = c; + *b = 0; + } + ret = TRUE; + } else { + /* If decomposed to more than two characters, take the last one, + * and recompose the rest to get the first component. */ + U16_PREV_UNSAFE (normalized, len, *b); + UChar recomposed[20]; + icu_err = U_ZERO_ERROR; + len = unorm_normalize (normalized, len, UNORM_NFC, 0, recomposed, ARRAY_LENGTH (recomposed), &icu_err); + if (U_FAILURE (icu_err)) + return FALSE; + /* We expect that recomposed has exactly one character now. */ + U16_GET_UNSAFE (recomposed, 0, *a); + ret = TRUE; + } + + return ret; +} + +extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_icu; +hb_unicode_funcs_t _hb_icu_unicode_funcs = { + HB_OBJECT_HEADER_STATIC, + + NULL, /* parent */ + TRUE, /* immutable */ + { +#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_icu_unicode_##name, + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + } +}; + +hb_unicode_funcs_t * +hb_icu_get_unicode_funcs (void) +{ + return &_hb_icu_unicode_funcs; +} + + diff --git a/third_party/harfbuzz-ng/src/hb-icu.h b/third_party/harfbuzz-ng/src/hb-icu.h index cc17af8..ecabec2 100644 --- a/third_party/harfbuzz-ng/src/hb-icu.h +++ b/third_party/harfbuzz-ng/src/hb-icu.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,16 +23,26 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_ICU_H #define HB_ICU_H #include "hb.h" +#include <unicode/uscript.h> + HB_BEGIN_DECLS +hb_script_t +hb_icu_script_to_script (UScriptCode script); + +UScriptCode +hb_icu_script_from_script (hb_script_t script); + + hb_unicode_funcs_t * hb_icu_get_unicode_funcs (void); diff --git a/third_party/harfbuzz-ng/src/hb-language.c b/third_party/harfbuzz-ng/src/hb-language.c deleted file mode 100644 index 2aabada..0000000 --- a/third_party/harfbuzz-ng/src/hb-language.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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-mutex-private.hh b/third_party/harfbuzz-ng/src/hb-mutex-private.hh new file mode 100644 index 0000000..9855a565 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-mutex-private.hh @@ -0,0 +1,110 @@ +/* + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_MUTEX_PRIVATE_HH +#define HB_MUTEX_PRIVATE_HH + +#include "hb-private.hh" + + + +/* mutex */ + +/* We need external help for these */ + +#ifdef HAVE_GLIB + +#include <glib.h> + +typedef GStaticMutex hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT G_STATIC_MUTEX_INIT +#define hb_mutex_impl_init(M) g_static_mutex_init (M) +#define hb_mutex_impl_lock(M) g_static_mutex_lock (M) +#define hb_mutex_impl_unlock(M) g_static_mutex_unlock (M) +#define hb_mutex_impl_free(M) g_static_mutex_free (M) + + +#elif defined(_MSC_VER) || defined(__MINGW32__) + +#include <windows.h> + +typedef CRITICAL_SECTION hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 } +#define hb_mutex_impl_init(M) InitializeCriticalSection (M) +#define hb_mutex_impl_lock(M) EnterCriticalSection (M) +#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M) +#define hb_mutex_impl_free(M) DeleteCriticalSection (M) + + +#else + +#warning "Could not find any system to define platform macros, library will NOT be thread-safe" + +typedef volatile int hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT 0 +#define hb_mutex_impl_init(M) ((void) (*(M) = 0)) +#define hb_mutex_impl_lock(M) ((void) (*(M) = 1)) +#define hb_mutex_impl_unlock(M) ((void) (*(M) = 0)) +#define hb_mutex_impl_free(M) ((void) (*(M) = 2)) + + +#endif + + +struct hb_mutex_t +{ + hb_mutex_impl_t m; + + inline void init (void) { hb_mutex_impl_init (&m); } + inline void lock (void) { hb_mutex_impl_lock (&m); } + inline void unlock (void) { hb_mutex_impl_unlock (&m); } + inline void free (void) { hb_mutex_impl_free (&m); } +}; + +#define HB_MUTEX_INIT {HB_MUTEX_IMPL_INIT} +#define hb_mutex_init(M) (M)->init () +#define hb_mutex_lock(M) (M)->lock () +#define hb_mutex_unlock(M) (M)->unlock () +#define hb_mutex_free(M) (M)->free () + + +struct hb_static_mutex_t : hb_mutex_t +{ + hb_static_mutex_t (void) { this->init (); } + ~hb_static_mutex_t (void) { this->free (); } + + private: + NO_COPY (hb_static_mutex_t); +}; + + + +#endif /* HB_MUTEX_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-object-private.h b/third_party/harfbuzz-ng/src/hb-object-private.h deleted file mode 100644 index a5b5355..0000000 --- a/third_party/harfbuzz-ng/src/hb-object-private.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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-object-private.hh b/third_party/harfbuzz-ng/src/hb-object-private.hh new file mode 100644 index 0000000..2e4a385 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-object-private.hh @@ -0,0 +1,267 @@ +/* + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OBJECT_PRIVATE_HH +#define HB_OBJECT_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-mutex-private.hh" + + + +/* Debug */ + +#ifndef HB_DEBUG_OBJECT +#define HB_DEBUG_OBJECT (HB_DEBUG+0) +#endif + + +/* atomic_int */ + +/* We need external help for these */ + +#ifdef HAVE_GLIB + +#include <glib.h> + +typedef volatile int hb_atomic_int_t; +#if GLIB_CHECK_VERSION(2,29,5) +#define hb_atomic_int_add(AI, V) g_atomic_int_add (&(AI), V) +#else +#define hb_atomic_int_add(AI, V) g_atomic_int_exchange_and_add (&(AI), V) +#endif +#define hb_atomic_int_get(AI) g_atomic_int_get (&(AI)) +#define hb_atomic_int_set(AI, V) g_atomic_int_set (&(AI), V) + + +#elif defined(_MSC_VER) && _MSC_VER >= 1600 + +#include <intrin.h> + +typedef long hb_atomic_int_t; +#define hb_atomic_int_add(AI, V) _InterlockedExchangeAdd (&(AI), V) +#define hb_atomic_int_get(AI) (_ReadBarrier (), (AI)) +#define hb_atomic_int_set(AI, V) ((void) _InterlockedExchange (&(AI), (V))) + + +#else + +#ifdef _MSC_VER +#pragma message("Could not find any system to define atomic_int macros, library will NOT be thread-safe") +#else +#warning "Could not find any system to define atomic_int macros, library will NOT be thread-safe" +#endif + +typedef volatile int hb_atomic_int_t; +#define hb_atomic_int_add(AI, V) ((AI) += (V), (AI) - (V)) +#define hb_atomic_int_get(AI) (AI) +#define hb_atomic_int_set(AI, V) ((void) ((AI) = (V))) + + +#endif + + + + +/* reference_count */ + +typedef struct { + hb_atomic_int_t ref_count; + +#define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1) +#define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE} + + inline void init (int v) { ref_count = v; /* non-atomic is fine */ } + inline int inc (void) { return hb_atomic_int_add (ref_count, 1); } + inline int dec (void) { return hb_atomic_int_add (ref_count, -1); } + inline void set (int v) { hb_atomic_int_set (ref_count, v); } + + inline int get (void) const { return hb_atomic_int_get (ref_count); } + inline bool is_invalid (void) const { return get () == HB_REFERENCE_COUNT_INVALID_VALUE; } + +} hb_reference_count_t; + + +/* user_data */ + +struct hb_user_data_array_t { + + struct hb_user_data_item_t { + hb_user_data_key_t *key; + void *data; + hb_destroy_func_t destroy; + + inline bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } + inline bool operator == (hb_user_data_item_t &other) const { return key == other.key; } + + void finish (void) { if (destroy) destroy (data); } + }; + + hb_lockable_set_t<hb_user_data_item_t, hb_static_mutex_t> items; + + HB_INTERNAL bool set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + HB_INTERNAL void *get (hb_user_data_key_t *key); + + HB_INTERNAL void finish (void); +}; + + +/* object_header */ + +typedef struct _hb_object_header_t hb_object_header_t; + +struct _hb_object_header_t { + hb_reference_count_t ref_count; + hb_user_data_array_t user_data; + +#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID} + + static inline void *create (unsigned int size) { + hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size); + + if (likely (obj)) + obj->init (); + + return obj; + } + + inline void init (void) { + ref_count.init (1); + } + + inline bool is_inert (void) const { + return unlikely (ref_count.is_invalid ()); + } + + inline void reference (void) { + if (unlikely (!this || this->is_inert ())) + return; + ref_count.inc (); + } + + inline bool destroy (void) { + if (unlikely (!this || this->is_inert ())) + return false; + if (ref_count.dec () != 1) + return false; + + ref_count.init (HB_REFERENCE_COUNT_INVALID_VALUE); + + user_data.finish (); + + return true; + } + + inline bool set_user_data (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy_func, + hb_bool_t replace) { + if (unlikely (!this || this->is_inert ())) + return false; + + return user_data.set (key, data, destroy_func, replace); + } + + inline void *get_user_data (hb_user_data_key_t *key) { + return user_data.get (key); + } + + inline void trace (const char *function) const { + DEBUG_MSG (OBJECT, (void *) this, + "refcount=%d %s", + this ? ref_count.get () : 0, + function); + } + +}; + + + + +/* object */ + +template <typename Type> +static inline void hb_object_trace (const Type *obj, const char *function) +{ + obj->header.trace (function); +} +template <typename Type> +static inline Type *hb_object_create (void) +{ + Type *obj = (Type *) hb_object_header_t::create (sizeof (Type)); + hb_object_trace (obj, HB_FUNC); + return obj; +} +template <typename Type> +static inline bool hb_object_is_inert (const Type *obj) +{ + return unlikely (obj->header.is_inert ()); +} +template <typename Type> +static inline Type *hb_object_reference (Type *obj) +{ + hb_object_trace (obj, HB_FUNC); + obj->header.reference (); + return obj; +} +template <typename Type> +static inline bool hb_object_destroy (Type *obj) +{ + hb_object_trace (obj, HB_FUNC); + return obj->header.destroy (); +} +template <typename Type> +static inline bool hb_object_set_user_data (Type *obj, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return obj->header.set_user_data (key, data, destroy, replace); +} + +template <typename Type> +static inline void *hb_object_get_user_data (Type *obj, + hb_user_data_key_t *key) +{ + return obj->header.get_user_data (key); +} + + + + + +#endif /* HB_OBJECT_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-open-file-private.hh b/third_party/harfbuzz-ng/src/hb-open-file-private.hh index cfb60db..62e1f17 100644 --- a/third_party/harfbuzz-ng/src/hb-open-file-private.hh +++ b/third_party/harfbuzz-ng/src/hb-open-file-private.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright © 2007,2008,2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -29,7 +29,6 @@ #include "hb-open-type-private.hh" -HB_BEGIN_DECLS /* @@ -152,7 +151,7 @@ struct TTCHeader inline unsigned int get_face_count (void) const { - switch (u.header.version) { + switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ case 1: return u.version1.get_face_count (); default:return 0; @@ -160,7 +159,7 @@ struct TTCHeader } inline const OpenTypeFontFace& get_face (unsigned int i) const { - switch (u.header.version) { + switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ case 1: return u.version1.get_face (i); default:return Null(OpenTypeFontFace); @@ -170,7 +169,7 @@ struct TTCHeader inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); if (unlikely (!u.header.version.sanitize (c))) return false; - switch (u.header.version) { + switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ case 1: return u.version1.sanitize (c); default:return true; @@ -253,6 +252,5 @@ struct OpenTypeFontFile }; -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 index 8f3001b..8143b28 100644 --- a/third_party/harfbuzz-ng/src/hb-open-type-private.hh +++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -27,12 +27,10 @@ #ifndef HB_OPEN_TYPE_PRIVATE_HH #define HB_OPEN_TYPE_PRIVATE_HH -#include "hb-private.h" +#include "hb-private.hh" #include "hb-blob.h" -HB_BEGIN_DECLS -HB_END_DECLS /* @@ -144,29 +142,6 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) #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 @@ -178,33 +153,36 @@ struct hb_trace_t<0> { #define TRACE_SANITIZE() \ - hb_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", HB_FUNC, this); \ + hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, NULL, HB_FUNC); struct hb_sanitize_context_t { - inline void init (hb_blob_t *blob) + inline void init (hb_blob_t *b) + { + this->blob = hb_blob_reference (b); + this->writable = false; + } + + inline void setup (void) { - 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->start = hb_blob_get_data (this->blob, NULL); + this->end = this->start + hb_blob_get_length (this->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))); + DEBUG_MSG (SANITIZE, this->blob, + "init [%p..%p] (%lu bytes)", + 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)); + DEBUG_MSG (SANITIZE, this->blob, + "fini [%p..%p] %u edit requests", + 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; @@ -217,13 +195,12 @@ struct hb_sanitize_context_t 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")); + DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, + "%-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s", + this->debug_depth, this->debug_depth, + p, p + len, len, + this->start, this->end, + ret ? "pass" : "FAIL"); return likely (ret); } @@ -231,15 +208,14 @@ struct hb_sanitize_context_t 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; + bool overflows = _hb_unsigned_int_mul_overflows (len, 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")); + DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, + "%-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s", + 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)); } @@ -255,14 +231,13 @@ struct hb_sanitize_context_t 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")); + DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, + "%-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", + this->debug_depth, this->debug_depth, + this->edit_count, + p, p + len, len, + this->start, this->end, + this->writable ? "granted" : "REJECTED"); return this->writable; } @@ -286,14 +261,12 @@ struct Sanitizer /* TODO is_sane() stuff */ - if (!blob) - return hb_blob_create_empty (); + c->init (blob); retry: - (void) (HB_DEBUG_SANITIZE && - fprintf (stderr, "Sanitizer %p start %s\n", blob, HB_FUNC)); + DEBUG_MSG_FUNC (SANITIZE, blob, "start"); - c->init (blob); + c->setup (); if (unlikely (!c->start)) { c->finish (); @@ -305,44 +278,45 @@ struct Sanitizer 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)); + DEBUG_MSG_FUNC (SANITIZE, blob, "passed first round with %d edits; going for second round", c->edit_count); /* 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)); + DEBUG_MSG_FUNC (SANITIZE, blob, "requested %d edits in second round; FAILLING", c->edit_count); 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; + if (edit_count && !c->writable) { + c->start = hb_blob_get_data_writable (blob, NULL); + c->end = c->start + hb_blob_get_length (blob); + + if (c->start) { + c->writable = true; + /* ok, we made it writable by relocating. try again */ + DEBUG_MSG_FUNC (SANITIZE, blob, "retry"); + goto retry; + } } } - (void) (HB_DEBUG_SANITIZE && - fprintf (stderr, "Sanitizer %p %s %s\n", blob, sane ? "passed" : "FAILED", HB_FUNC)); + c->finish (); + + DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED"); if (sane) return blob; else { hb_blob_destroy (blob); - return hb_blob_create_empty (); + return hb_blob_get_empty (); } } static const Type* lock_instance (hb_blob_t *blob) { - const char *base = hb_blob_lock (blob); + hb_blob_make_immutable (blob); + const char *base = hb_blob_get_data (blob, NULL); return unlikely (!base) ? &Null(Type) : CastP<Type> (base); } }; @@ -364,27 +338,27 @@ struct Sanitizer */ -template <typename Type, int Bytes> class BEInt; +template <typename Type, int Bytes> struct 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> +struct 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 hb_be_uint16_eq (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> +struct 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 hb_be_uint32_eq (v, o.v); } inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); } private: uint8_t v[4]; }; @@ -408,11 +382,22 @@ struct IntType DEFINE_SIZE_STATIC (sizeof (Type)); }; +/* Typedef these to avoid clash with windows.h */ +#define USHORT HB_USHORT +#define SHORT HB_SHORT +#define ULONG HB_ULONG +#define LONG HB_LONG 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. */ +/* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ +typedef SHORT FWORD; + +/* 16-bit unsigned integer (USHORT) that describes a quantity in FUnits. */ +typedef USHORT UFWORD; + /* 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 @@ -479,7 +464,7 @@ struct CheckSum : ULONG struct FixedVersion { - inline operator uint32_t (void) const { return (major << 16) + minor; } + inline uint32_t to_int (void) const { return (major << 16) + minor; } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); @@ -712,8 +697,8 @@ 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); } + struct Cmp { + 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; @@ -721,7 +706,5 @@ struct SortedArrayOf : ArrayOf<Type> { }; -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-table.hh index 3a4bbbf..a4d8d5f 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-head-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Red Hat, Inc. + * Copyright © 2010 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,16 +24,15 @@ * Red Hat Author(s): Behdad Esfahbod */ -#ifndef HB_OT_HEAD_PRIVATE_HH -#define HB_OT_HEAD_PRIVATE_HH +#ifndef HB_OT_HEAD_TABLE_HH +#define HB_OT_HEAD_TABLE_HH #include "hb-open-type-private.hh" -HB_BEGIN_DECLS /* - * head + * head -- Font Header */ #define HB_OT_TAG_head HB_TAG('h','e','a','d') @@ -50,7 +49,6 @@ struct head inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - /* Shall we check for magicNumber here? Who cares? */ return c->check_struct (this) && likely (version.major == 1); } @@ -141,6 +139,5 @@ struct head }; -HB_END_DECLS -#endif /* HB_OT_HEAD_PRIVATE_HH */ +#endif /* HB_OT_HEAD_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh new file mode 100644 index 0000000..34bf494 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh @@ -0,0 +1,92 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_HHEA_TABLE_HH +#define HB_OT_HHEA_TABLE_HH + +#include "hb-open-type-private.hh" + + + +/* + * hhea -- The Horizontal Header Table + */ + +#define HB_OT_TAG_hhea HB_TAG('h','h','e','a') + + +struct hhea +{ + static const hb_tag_t Tag = HB_OT_TAG_hhea; + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) && likely (version.major == 1); + } + + private: + FixedVersion version; /* 0x00010000 for version 1.0. */ + FWORD ascender; /* Typographic ascent. <a + * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html"> + * (Distance from baseline of highest + * ascender)</a> */ + FWORD descender; /* Typographic descent. <a + * href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html"> + * (Distance from baseline of lowest + * descender)</a> */ + FWORD lineGap; /* Typographic line gap. Negative + * LineGap values are treated as zero + * in Windows 3.1, System 6, and + * System 7. */ + UFWORD advanceWidthMax; /* Maximum advance width value in + * 'hmtx' table. */ + FWORD minLeftSideBearing; /* Minimum left sidebearing value in + * 'hmtx' table. */ + FWORD minRightSideBearing; /* Minimum right sidebearing value; + * calculated as Min(aw - lsb - + * (xMax - xMin)). */ + FWORD xMaxExtent; /* Max(lsb + (xMax - xMin)). */ + SHORT caretSlopeRise; /* Used to calculate the slope of the + * cursor (rise/run); 1 for vertical. */ + SHORT caretSlopeRun; /* 0 for vertical. */ + SHORT caretOffset; /* The amount by which a slanted + * highlight on a glyph needs + * to be shifted to produce the + * best appearance. Set to 0 for + * non--slanted fonts */ + SHORT reserved1; /* set to 0 */ + SHORT reserved2; /* set to 0 */ + SHORT reserved3; /* set to 0 */ + SHORT reserved4; /* set to 0 */ + SHORT metricDataFormat; /* 0 for current format. */ + USHORT numberOfHMetrics; /* Number of hMetric entries in 'hmtx' + * table */ + public: + DEFINE_SIZE_STATIC (36); +}; + + +#endif /* HB_OT_HHEA_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh new file mode 100644 index 0000000..b58799c --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh @@ -0,0 +1,86 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_HMTX_TABLE_HH +#define HB_OT_HMTX_TABLE_HH + +#include "hb-open-type-private.hh" + + + +/* + * hmtx -- The Horizontal Metrics Table + */ + +#define HB_OT_TAG_hmtx HB_TAG('h','m','t','x') + + +struct LongHorMetric +{ + USHORT advanceWidth; + SHORT lsb; + public: + DEFINE_SIZE_STATIC (4); +}; + +struct hmtx +{ + static const hb_tag_t Tag = HB_OT_TAG_hmtx; + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + /* We don't check for anything specific here. The users of the + * struct do all the hard work... */ + return true; + } + + private: + LongHorMetric longHorMetric[VAR]; /* Paired advance width and left side + * bearing values for each glyph. The + * value numOfHMetrics comes from + * the 'hhea' table. If the font is + * monospaced, only one entry need + * be in the array, but that entry is + * required. The last entry applies to + * all subsequent glyphs. */ + SHORT leftSideBearingX[VAR]; /* Here the advanceWidth is assumed + * to be the same as the advanceWidth + * for the last entry above. The + * number of entries in this array is + * derived from numGlyphs (from 'maxp' + * table) minus numberOfHMetrics. This + * generally is used with a run of + * monospaced glyphs (e.g., Kanji + * fonts or Courier fonts). Only one + * run is allowed and it must be at + * the end. This allows a monospaced + * font to vary the left side bearing + * values for each glyph. */ + public: + DEFINE_SIZE_ARRAY2 (0, longHorMetric, leftSideBearingX); +}; + +#endif /* HB_OT_HMTX_TABLE_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 index 9ff5ca9..5d19e08 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh @@ -1,6 +1,6 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -38,8 +38,6 @@ #define NOT_COVERED ((unsigned int) 0x110000) #define MAX_NESTING_LEVEL 8 -HB_BEGIN_DECLS -HB_END_DECLS /* @@ -89,10 +87,10 @@ struct RecordArrayOf : SortedArrayOf<Record<Type> > { hb_tag_t *record_tags /* OUT */) const { if (record_count) { - const Record<Type> *array = this->sub_array (start_offset, record_count); + const Record<Type> *arr = 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; + record_tags[i] = arr[i].tag; } return this->len; } @@ -150,10 +148,10 @@ struct IndexArray : ArrayOf<Index> unsigned int *_indexes /* OUT */) const { if (_count) { - const USHORT *array = this->sub_array (start_offset, _count); + const USHORT *arr = this->sub_array (start_offset, _count); unsigned int count = *_count; for (unsigned int i = 0; i < count; i++) - _indexes[i] = array[i]; + _indexes[i] = arr[i]; } return this->len; } @@ -526,13 +524,13 @@ struct ClassDef 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_x_delta (hb_font_t *font) const + { return get_delta (font->x_ppem, 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 hb_position_t get_y_delta (hb_font_t *font) const + { return get_delta (font->y_ppem, font->y_scale); } - inline int get_delta (unsigned int ppem, unsigned int scale) const + inline int get_delta (unsigned int ppem, int scale) const { if (!ppem) return 0; @@ -540,10 +538,6 @@ struct Device 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; } @@ -598,7 +592,5 @@ struct Device }; -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-table.hh index 4172a7c..ee9c508 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh @@ -1,6 +1,6 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -26,14 +26,13 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_GDEF_PRIVATE_HH -#define HB_OT_LAYOUT_GDEF_PRIVATE_HH +#ifndef HB_OT_LAYOUT_GDEF_TABLE_HH +#define HB_OT_LAYOUT_GDEF_TABLE_HH #include "hb-ot-layout-common-private.hh" -#include "hb-font-private.h" +#include "hb-font-private.hh" -HB_BEGIN_DECLS /* @@ -96,9 +95,9 @@ 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 + inline hb_position_t get_caret_value (hb_font_t *font, 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); + return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -118,10 +117,10 @@ 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 + inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const { hb_position_t x, y; - if (hb_font_get_contour_point (c->font, c->face, caretValuePoint, glyph_id, &x, &y)) + if (hb_font_get_glyph_contour_point_for_origin (font, glyph_id, caretValuePoint, direction, &x, &y)) return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; else return 0; @@ -143,11 +142,11 @@ 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 + inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) 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); + font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font) : + font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -169,12 +168,12 @@ struct CaretValueFormat3 struct CaretValue { - inline int get_caret_value (hb_ot_layout_context_t *c, hb_direction_t direction, hb_codepoint_t glyph_id) const + inline hb_position_t get_caret_value (hb_font_t *font, 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); + case 1: return u.format1.get_caret_value (font, direction, glyph_id); + case 2: return u.format2.get_caret_value (font, direction, glyph_id); + case 3: return u.format3.get_caret_value (font, direction, glyph_id); default:return 0; } } @@ -203,18 +202,18 @@ struct CaretValue struct LigGlyph { - inline unsigned int get_lig_carets (hb_ot_layout_context_t *c, + inline unsigned int get_lig_carets (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id, unsigned int start_offset, unsigned int *caret_count /* IN/OUT */, - int *caret_array /* OUT */) const + hb_position_t *caret_array /* OUT */) const { if (caret_count) { const OffsetTo<CaretValue> *array = carets.sub_array (start_offset, caret_count); unsigned int count = *caret_count; for (unsigned int i = 0; i < count; i++) - caret_array[i] = (this+array[i]).get_caret_value (c, direction, glyph_id); + caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id); } return carets.len; @@ -236,12 +235,12 @@ struct LigGlyph struct LigCaretList { - inline unsigned int get_lig_carets (hb_ot_layout_context_t *c, + inline unsigned int get_lig_carets (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id, unsigned int start_offset, unsigned int *caret_count /* IN/OUT */, - int *caret_array /* OUT */) const + hb_position_t *caret_array /* OUT */) const { unsigned int index = (this+coverage) (glyph_id); if (index == NOT_COVERED) @@ -251,7 +250,7 @@ struct LigCaretList 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); + return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -321,7 +320,7 @@ struct MarkGlyphSets /* - * GDEF + * GDEF -- The Glyph Definition Table */ struct GDEF @@ -352,17 +351,17 @@ struct GDEF { 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, + inline unsigned int get_lig_carets (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id, unsigned int start_offset, unsigned int *caret_count /* IN/OUT */, - int *caret_array /* OUT */) const - { return (this+ligCaretList).get_lig_carets (c, direction, glyph_id, start_offset, caret_count, caret_array); } + hb_position_t *caret_array /* OUT */) const + { return (this+ligCaretList).get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); } - inline bool has_mark_sets (void) const { return version >= 0x00010002 && markGlyphSetsDef[0] != 0; } + inline bool has_mark_sets (void) const { return version.to_int () >= 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); } + { return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); @@ -371,7 +370,7 @@ struct GDEF && attachList.sanitize (c, this) && ligCaretList.sanitize (c, this) && markAttachClassDef.sanitize (c, this) - && (version < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this)); + && (version.to_int () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this)); } @@ -424,6 +423,5 @@ struct GDEF }; -HB_END_DECLS -#endif /* HB_OT_LAYOUT_GDEF_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_GDEF_TABLE_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-table.hh index 11bb286..412850b 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh @@ -1,6 +1,6 @@ /* - * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -26,15 +26,14 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH -#define HB_OT_LAYOUT_GPOS_PRIVATE_HH +#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH +#define HB_OT_LAYOUT_GPOS_TABLE_HH #include "hb-ot-layout-gsubgpos-private.hh" -HB_BEGIN_DECLS -/* buffer var allocations */ +/* buffer **position** 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 */ @@ -94,41 +93,48 @@ struct ValueFormat : USHORT 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 + void apply_value (hb_font_t *font, + hb_direction_t direction, + const void *base, + const Value *values, + hb_glyph_position_t &glyph_pos) const { unsigned int x_ppem, y_ppem; unsigned int format = *this; + hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction); 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 (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++)); + if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++)); + if (format & xAdvance) { + if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++; + } + /* y_advance values grow downward but font-space grows upward, hence negation */ + if (format & yAdvance) { + if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++; + } if (!has_device ()) return; - x_ppem = layout->font->x_ppem; - y_ppem = layout->font->y_ppem; + x_ppem = font->x_ppem; + y_ppem = 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 (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++; } if (format & yPlaDevice) { - if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (layout); else values++; + if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++; } if (format & xAdvDevice) { - if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (layout); else values++; + if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++; } if (format & yAdvDevice) { - if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_delta (layout); else values++; + /* y_advance values grow downward but font-space grows upward, hence negation */ + if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++; } } @@ -209,11 +215,11 @@ struct AnchorFormat1 friend struct Anchor; private: - inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED, + inline void get_anchor (hb_font_t *font, 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); + *x = font->em_scale_x (xCoordinate); + *y = font->em_scale_y (yCoordinate); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -234,18 +240,18 @@ struct AnchorFormat2 friend struct Anchor; private: - inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id, + inline void get_anchor (hb_font_t *font, 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; + unsigned int x_ppem = font->x_ppem; + unsigned int y_ppem = 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); + ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); + *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate); + *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -267,17 +273,16 @@ struct AnchorFormat3 friend struct Anchor; private: - inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED, + inline void get_anchor (hb_font_t *font, 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); + *x = font->em_scale_x (xCoordinate); + *y = font->em_scale_y (yCoordinate); + + if (font->x_ppem) + *x += (this+xDeviceTable).get_x_delta (font); + if (font->y_ppem) + *y += (this+yDeviceTable).get_x_delta (font); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -305,15 +310,15 @@ struct AnchorFormat3 struct Anchor { - inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id, + inline void get_anchor (hb_font_t *font, 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; + case 1: u.format1.get_anchor (font, glyph_id, x, y); return; + case 2: u.format2.get_anchor (font, glyph_id, x, y); return; + case 3: u.format3.get_anchor (font, glyph_id, x, y); return; + default: return; } } @@ -403,15 +408,15 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde 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); + mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->idx].codepoint, &mark_x, &mark_y); + glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y); - hb_glyph_position_t &o = c->buffer->pos[c->buffer->i]; + hb_glyph_position_t &o = c->buffer->pos[c->buffer->idx]; o.x_offset = base_x - mark_x; o.y_offset = base_y - mark_y; - o.attach_lookback() = c->buffer->i - glyph_pos; + o.attach_lookback() = c->buffer->idx - glyph_pos; - c->buffer->i++; + c->buffer->idx++; return true; } @@ -432,13 +437,14 @@ struct SinglePosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; - valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->i]); + valueFormat.apply_value (c->font, c->direction, this, + values, c->buffer->pos[c->buffer->idx]); - c->buffer->i++; + c->buffer->idx++; return true; } @@ -471,18 +477,18 @@ struct SinglePosFormat2 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; if (likely (index >= valueCount)) return false; - valueFormat.apply_value (c->layout, this, + valueFormat.apply_value (c->font, c->direction, this, &values[index * valueFormat.get_len ()], - c->buffer->pos[c->buffer->i]); + c->buffer->pos[c->buffer->idx]); - c->buffer->i++; + c->buffer->idx++; return true; } @@ -574,11 +580,13 @@ struct PairSet { 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]); + valueFormats[0].apply_value (c->font, c->direction, this, + &record->values[0], c->buffer->pos[c->buffer->idx]); + valueFormats[1].apply_value (c->font, c->direction, this, + &record->values[len1], c->buffer->pos[pos]); if (len2) pos++; - c->buffer->i = pos; + c->buffer->idx = pos; return true; } record = &StructAtOffset<PairValueRecord> (record, record_size); @@ -621,23 +629,18 @@ struct PairPosFormat1 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)) + hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); + if (skippy_iter.has_no_chance ()) return false; - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].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++; - } + if (!skippy_iter.next ()) + return false; - return (this+pairSet[index]).apply (c, &valueFormat1, j); + return (this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -683,38 +686,35 @@ struct PairPosFormat2 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)) + hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); + if (skippy_iter.has_no_chance ()) return false; - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].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++; - } + if (!skippy_iter.next ()) + return false; 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); + unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->idx].codepoint); + unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].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]); + valueFormat1.apply_value (c->font, c->direction, this, + v, c->buffer->pos[c->buffer->idx]); + valueFormat2.apply_value (c->font, c->direction, this, + v + len1, c->buffer->pos[skippy_iter.idx]); + c->buffer->idx = skippy_iter.idx; if (len2) - j++; - c->buffer->i = j; + c->buffer->idx++; return true; } @@ -836,69 +836,82 @@ struct CursivePosFormat1 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)) + hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); + if (skippy_iter.has_no_chance ()) return false; - const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)]; + const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->idx].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++; - } + if (!skippy_iter.next ()) + return false; - const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[j].codepoint)]; + const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)]; if (!next_record.entryAnchor) return false; - unsigned int i = c->buffer->i; + unsigned int i = c->buffer->idx; + unsigned int j = skippy_iter.idx; 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; + (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y); + (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y); + + hb_glyph_position_t *pos = c->buffer->pos; + + hb_position_t d; + /* Main-direction adjustment */ + switch (c->direction) { + case HB_DIRECTION_LTR: + pos[i].x_advance = exit_x + pos[i].x_offset; + + d = entry_x + pos[j].x_offset; + pos[j].x_advance -= d; + pos[j].x_offset -= d; + break; + case HB_DIRECTION_RTL: + d = exit_x + pos[i].x_offset; + pos[i].x_advance -= d; + pos[i].x_offset -= d; + + pos[j].x_advance = entry_x + pos[j].x_offset; + break; + case HB_DIRECTION_TTB: + pos[i].y_advance = exit_y + pos[i].y_offset; + + d = entry_y + pos[j].y_offset; + pos[j].y_advance -= d; + pos[j].y_offset -= d; + break; + case HB_DIRECTION_BTT: + d = exit_y + pos[i].y_offset; + pos[i].y_advance -= d; + pos[i].y_offset -= d; + + pos[j].y_advance = entry_y; + break; + case HB_DIRECTION_INVALID: + default: + break; } - 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; + /* Cross-direction adjustment */ + if (c->lookup_props & LookupFlag::RightToLeft) { + pos[i].cursive_chain() = j - i; + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) + 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; + pos[i].x_offset = entry_x - exit_x; + } else { + pos[j].cursive_chain() = i - j; + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) + pos[j].y_offset = exit_y - entry_y; else - c->buffer->pos[j].x_offset = exit_x - entry_x; + pos[j].x_offset = exit_x - entry_x; } - c->buffer->i = j; + c->buffer->idx = j; return true; } @@ -964,29 +977,25 @@ struct MarkBasePosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].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)); + hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); + if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) + return false; /* 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); + unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint); if (base_index == NOT_COVERED) return false; - return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j); + return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -1066,24 +1075,21 @@ struct MarkLigPosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].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)); + hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); + if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) + return false; /* The following assertion is too strong, so we've disabled it. */ if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) {/*return false;*/} + unsigned int j = skippy_iter.idx; unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint); if (lig_index == NOT_COVERED) return false; @@ -1100,9 +1106,9 @@ struct MarkLigPosFormat1 * 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()) + if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->idx].lig_id() && c->buffer->info[c->buffer->idx].lig_comp()) { - comp_index = c->buffer->info[c->buffer->i].lig_comp() - 1; + comp_index = c->buffer->info[c->buffer->idx].lig_comp() - 1; if (comp_index >= comp_count) comp_index = comp_count - 1; } @@ -1185,28 +1191,26 @@ struct MarkMarkPosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->idx].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)); + hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); + if (!skippy_iter.prev (&property)) + return false; if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return false; + unsigned int j = skippy_iter.idx; + /* 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())) + if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->idx].lig_comp()) || + (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->idx].lig_id())) return false; unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint); @@ -1277,9 +1281,7 @@ struct MarkMarkPos }; -HB_BEGIN_DECLS static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index); -HB_END_DECLS struct ContextPos : Context { @@ -1402,7 +1404,7 @@ 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, + inline bool apply_once (hb_font_t *font, hb_buffer_t *buffer, hb_mask_t lookup_mask, unsigned int context_length, @@ -1411,14 +1413,16 @@ struct PosLookup : Lookup unsigned int lookup_type = get_type (); hb_apply_context_t c[1] = {{0}}; - c->layout = layout; + c->font = font; + c->face = font->face; c->buffer = buffer; + c->direction = buffer->props.direction; 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)) + if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property)) return false; for (unsigned int i = 0; i < get_subtable_count (); i++) @@ -1428,7 +1432,7 @@ struct PosLookup : Lookup return false; } - inline bool apply_string (hb_ot_layout_context_t *layout, + inline bool apply_string (hb_font_t *font, hb_buffer_t *buffer, hb_mask_t mask) const { @@ -1437,14 +1441,14 @@ struct PosLookup : Lookup if (unlikely (!buffer->len)) return false; - buffer->i = 0; - while (buffer->i < buffer->len) + buffer->idx = 0; + while (buffer->idx < buffer->len) { - if ((buffer->info[buffer->i].mask & mask) && - apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) + if ((buffer->info[buffer->idx].mask & mask) && + apply_once (font, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) ret = true; else - buffer->i++; + buffer->idx++; } return ret; @@ -1461,7 +1465,7 @@ struct PosLookup : Lookup typedef OffsetListOf<PosLookup> PosLookupList; /* - * GPOS + * GPOS -- The Glyph Positioning Table */ struct GPOS : GSUBGPOS @@ -1471,12 +1475,13 @@ struct GPOS : GSUBGPOS 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, + inline bool position_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, hb_mask_t mask) const - { return get_lookup (lookup_index).apply_string (layout, buffer, mask); } + { return get_lookup (lookup_index).apply_string (font, buffer, mask); } + static inline void position_start (hb_buffer_t *buffer); static inline void position_finish (hb_buffer_t *buffer); inline bool sanitize (hb_sanitize_context_t *c) { @@ -1489,61 +1494,79 @@ struct GPOS : GSUBGPOS DEFINE_SIZE_STATIC (10); }; -void -GPOS::position_finish (hb_buffer_t *buffer) + +static void +fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) { - 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; + unsigned int j = pos[i].cursive_chain(); + if (likely (!j)) + return; - /* 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; + j += i; + + pos[i].cursive_chain() = 0; + + fix_cursive_minor_offset (pos, j, direction); + + if (HB_DIRECTION_IS_HORIZONTAL (direction)) + pos[i].y_offset += pos[j].y_offset; + else + pos[i].x_offset += pos[j].x_offset; +} + +static void +fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction) +{ + if (likely (!(pos[i].attach_lookback()))) + return; + + unsigned int j = i - pos[i].attach_lookback(); + + pos[i].x_advance = 0; + pos[i].y_advance = 0; + pos[i].x_offset += pos[j].x_offset; + pos[i].y_offset += pos[j].y_offset; + + if (HB_DIRECTION_IS_FORWARD (direction)) + for (unsigned int k = j; k < i; k++) { + pos[i].x_offset -= pos[k].x_advance; + pos[i].y_offset -= pos[k].y_advance; } - } 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; + for (unsigned int k = j + 1; k < i + 1; k++) { + pos[i].x_offset += pos[k].x_advance; + pos[i].y_offset += pos[k].y_advance; } - } +} + +void +GPOS::position_start (hb_buffer_t *buffer) +{ + buffer->clear_positions (); + + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0; +} + +void +GPOS::position_finish (hb_buffer_t *buffer) +{ + unsigned int len; + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len); + hb_direction_t direction = buffer->props.direction; + /* Handle cursive connections */ + for (unsigned int i = 0; i < len; i++) + fix_cursive_minor_offset (pos, i, direction); /* 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; - } - } + for (unsigned int i = 0; i < len; i++) + fix_mark_attachment (pos, i, direction); + + HB_BUFFER_DEALLOCATE_VAR (buffer, lig_comp); + HB_BUFFER_DEALLOCATE_VAR (buffer, lig_id); + HB_BUFFER_DEALLOCATE_VAR (buffer, props_cache); } @@ -1566,7 +1589,7 @@ inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c) static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) { - const GPOS &gpos = *(c->layout->face->ot_layout->gpos); + const GPOS &gpos = *(c->face->ot_layout->gpos); const PosLookup &l = gpos.get_lookup (lookup_index); if (unlikely (c->nesting_level_left == 0)) @@ -1575,7 +1598,7 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i 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); + return l.apply_once (c->font, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1); } @@ -1583,6 +1606,5 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i #undef cursive_chain -HB_END_DECLS -#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_GPOS_TABLE_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-table.hh index ae1c5f3..f7ec3cc 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh @@ -1,6 +1,6 @@ /* - * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -26,12 +26,11 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_LAYOUT_GSUB_PRIVATE_HH -#define HB_OT_LAYOUT_GSUB_PRIVATE_HH +#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH +#define HB_OT_LAYOUT_GSUB_TABLE_HH #include "hb-ot-layout-gsubgpos-private.hh" -HB_BEGIN_DECLS struct SingleSubstFormat1 @@ -43,12 +42,14 @@ struct SingleSubstFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint; + hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; unsigned int index = (this+coverage) (glyph_id); if (likely (index == NOT_COVERED)) return false; - glyph_id += deltaGlyphID; + /* According to the Adobe Annotated OpenType Suite, result is always + * limited to 16bit. */ + glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF; c->replace_glyph (glyph_id); return true; @@ -80,7 +81,7 @@ struct SingleSubstFormat2 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint; + hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; unsigned int index = (this+coverage) (glyph_id); if (likely (index == NOT_COVERED)) return false; @@ -188,7 +189,7 @@ struct MultipleSubstFormat1 { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; @@ -257,8 +258,8 @@ struct AlternateSubstFormat1 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_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; + hb_mask_t glyph_mask = c->buffer->info[c->buffer->idx].mask; hb_mask_t lookup_mask = c->lookup_mask; unsigned int index = (this+coverage) (glyph_id); @@ -342,28 +343,27 @@ struct Ligature 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)) + if (unlikely (count < 2)) + return false; + + hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); + if (skippy_iter.has_no_chance ()) 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++) + for (unsigned int i = 1; i < count; i++) { 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++; - } + + if (!skippy_iter.next (&property)) + return false; found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK); - if (likely (c->buffer->info[j].codepoint != component[i])) + if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return false; } @@ -372,12 +372,12 @@ struct 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; + c->buffer->info[c->buffer->idx].lig_comp() = 0; + c->buffer->info[c->buffer->idx].lig_id() = lig_id; - if (j == c->buffer->i + i) /* No input glyphs skipped */ + if (skippy_iter.idx < c->buffer->idx + count) /* No input glyphs skipped */ { - c->replace_glyphs_be16 (i, 1, (const uint16_t *) &ligGlyph); + c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph); } else { @@ -390,29 +390,23 @@ struct Ligature value it is later possible to check whether a specific component value really belongs to a given ligature. */ - for (i = 1; i < count; i++) + for (unsigned int i = 1; i < count; i++) { - while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, NULL)) + while (c->should_mark_skip_current_glyph ()) { - 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); + c->buffer->info[c->buffer->idx].lig_comp() = i; + c->buffer->info[c->buffer->idx].lig_id() = lig_id; + c->replace_glyph (c->buffer->info[c->buffer->idx].codepoint); } /* Skip the base glyph */ - c->buffer->i++; + c->buffer->idx++; } } 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 (); @@ -471,7 +465,7 @@ struct LigatureSubstFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - hb_codepoint_t glyph_id = c->buffer->info[c->buffer->i].codepoint; + hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; unsigned int index = (this+coverage) (glyph_id); if (likely (index == NOT_COVERED)) @@ -530,9 +524,7 @@ struct LigatureSubst }; -HB_BEGIN_DECLS static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index); -HB_END_DECLS struct ContextSubst : Context { @@ -591,7 +583,7 @@ struct ReverseChainSingleSubstFormat1 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); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; @@ -606,8 +598,8 @@ struct ReverseChainSingleSubstFormat1 match_coverage, this, 1)) { - c->buffer->info[c->buffer->i].codepoint = substitute[index]; - c->buffer->i--; /* Reverse! */ + c->buffer->info[c->buffer->idx].codepoint = substitute[index]; + c->buffer->idx--; /* Reverse! */ return true; } @@ -762,7 +754,7 @@ struct SubstLookup : Lookup } - inline bool apply_once (hb_ot_layout_context_t *layout, + inline bool apply_once (hb_face_t *face, hb_buffer_t *buffer, hb_mask_t lookup_mask, unsigned int context_length, @@ -771,14 +763,15 @@ struct SubstLookup : Lookup unsigned int lookup_type = get_type (); hb_apply_context_t c[1] = {{0}}; - c->layout = layout; + c->face = face; c->buffer = buffer; + c->direction = buffer->props.direction; 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)) + if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property)) return false; if (unlikely (lookup_type == SubstLookupSubTable::Extension)) @@ -803,7 +796,7 @@ struct SubstLookup : Lookup return false; } - inline bool apply_string (hb_ot_layout_context_t *layout, + inline bool apply_string (hb_face_t *face, hb_buffer_t *buffer, hb_mask_t mask) const { @@ -816,33 +809,33 @@ struct SubstLookup : Lookup { /* in/out forward substitution */ buffer->clear_output (); - buffer->i = 0; - while (buffer->i < buffer->len) + buffer->idx = 0; + while (buffer->idx < buffer->len) { - if ((buffer->info[buffer->i].mask & mask) && - apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) + if ((buffer->info[buffer->idx].mask & mask) && + apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) ret = true; else buffer->next_glyph (); } if (ret) - buffer->swap (); + buffer->swap_buffers (); } else { /* in-place backward substitution */ - buffer->i = buffer->len - 1; + buffer->idx = buffer->len - 1; do { - if ((buffer->info[buffer->i].mask & mask) && - apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) + if ((buffer->info[buffer->idx].mask & mask) && + apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) ret = true; else - buffer->i--; + buffer->idx--; } - while ((int) buffer->i >= 0); + while ((int) buffer->idx >= 0); } return ret; @@ -859,7 +852,7 @@ struct SubstLookup : Lookup typedef OffsetListOf<SubstLookup> SubstLookupList; /* - * GSUB + * GSUB -- The Glyph Substitution Table */ struct GSUB : GSUBGPOS @@ -869,11 +862,14 @@ struct GSUB : GSUBGPOS 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, + inline bool substitute_lookup (hb_face_t *face, hb_buffer_t *buffer, unsigned int lookup_index, hb_mask_t mask) const - { return get_lookup (lookup_index).apply_string (layout, buffer, mask); } + { return get_lookup (lookup_index).apply_string (face, buffer, mask); } + + static inline void substitute_start (hb_buffer_t *buffer); + static inline void substitute_finish (hb_buffer_t *buffer); inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); @@ -886,6 +882,24 @@ struct GSUB : GSUBGPOS }; +void +GSUB::substitute_start (hb_buffer_t *buffer) +{ + HB_BUFFER_ALLOCATE_VAR (buffer, props_cache); + HB_BUFFER_ALLOCATE_VAR (buffer, lig_id); + HB_BUFFER_ALLOCATE_VAR (buffer, lig_comp); + + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + buffer->info[i].props_cache() = buffer->info[i].lig_id() = buffer->info[i].lig_comp() = 0; +} + +void +GSUB::substitute_finish (hb_buffer_t *buffer) +{ +} + + /* Out-of-class implementation for methods recursing */ inline bool ExtensionSubst::apply (hb_apply_context_t *c) const @@ -913,7 +927,7 @@ inline bool ExtensionSubst::is_reverse (void) const static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) { - const GSUB &gsub = *(c->layout->face->ot_layout->gsub); + const GSUB &gsub = *(c->face->ot_layout->gsub); const SubstLookup &l = gsub.get_lookup (lookup_index); if (unlikely (c->nesting_level_left == 0)) @@ -922,10 +936,9 @@ static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup 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); + return l.apply_once (c->face, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1); } -HB_END_DECLS -#endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */ +#endif /* HB_OT_LAYOUT_GSUB_TABLE_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 index c2b2eea..13386c2 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh @@ -1,6 +1,6 @@ /* - * Copyright (C) 2007,2008,2009,2010 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -30,14 +30,19 @@ #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH #include "hb-buffer-private.hh" -#include "hb-ot-layout-gdef-private.hh" - -HB_BEGIN_DECLS +#include "hb-ot-layout-gdef-table.hh" /* 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) */ +#define lig_id() var2.u8[2] /* unique ligature id */ +#define lig_comp() var2.u8[3] /* component number in the ligature (0 = base) */ + +static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) { + uint8_t lig_id = buffer->next_serial (); + if (unlikely (!lig_id)) lig_id = buffer->next_serial (); /* in case of overflow */ + return lig_id; +} + #ifndef HB_DEBUG_APPLY @@ -45,22 +50,107 @@ HB_BEGIN_DECLS #endif #define TRACE_APPLY() \ - hb_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", HB_FUNC, this); \ + hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, NULL, HB_FUNC); -HB_BEGIN_DECLS struct hb_apply_context_t { unsigned int debug_depth; - hb_ot_layout_context_t *layout; + hb_font_t *font; + hb_face_t *face; hb_buffer_t *buffer; + hb_direction_t direction; 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 */ + struct mark_skipping_forward_iterator_t + { + inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_, + unsigned int start_index_, + unsigned int num_items_) + { + c = c_; + idx = start_index_; + num_items = num_items_; + end = MIN (c->buffer->len, c->buffer->idx + c->context_length); + } + inline bool has_no_chance (void) const + { + return unlikely (num_items && idx + num_items >= end); + } + inline bool next (unsigned int *property_out, + unsigned int lookup_props) + { + assert (num_items > 0); + do + { + if (has_no_chance ()) + return false; + idx++; + } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out)); + num_items--; + return true; + } + inline bool next (unsigned int *property_out = NULL) + { + return next (property_out, c->lookup_props); + } + + unsigned int idx; + private: + hb_apply_context_t *c; + unsigned int num_items; + unsigned int end; + }; + + struct mark_skipping_backward_iterator_t + { + inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_, + unsigned int start_index_, + unsigned int num_items_) + { + c = c_; + idx = start_index_; + num_items = num_items_; + } + inline bool has_no_chance (void) const + { + return unlikely (idx < num_items); + } + inline bool prev (unsigned int *property_out, + unsigned int lookup_props) + { + assert (num_items > 0); + do + { + if (has_no_chance ()) + return false; + idx--; + } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out)); + num_items--; + return true; + } + inline bool prev (unsigned int *property_out = NULL) + { + return prev (property_out, c->lookup_props); + } + + unsigned int idx; + private: + hb_apply_context_t *c; + unsigned int num_items; + }; + + inline bool should_mark_skip_current_glyph (void) const + { + return _hb_ot_layout_skip_mark (face, &buffer->info[buffer->idx], lookup_props, NULL); + } + + inline void replace_glyph (hb_codepoint_t glyph_index) const { @@ -78,14 +168,14 @@ struct hb_apply_context_t inline void guess_glyph_class (unsigned int klass) { /* XXX if ! has gdef */ - buffer->info[buffer->i].props_cache() = klass; + buffer->info[buffer->idx].props_cache() = klass; } private: inline void clear_property (void) const { /* XXX if has gdef */ - buffer->info[buffer->i].props_cache() = 0; + buffer->info[buffer->idx].props_cache() = 0; } }; @@ -126,25 +216,20 @@ static inline bool match_input (hb_apply_context_t *c, 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)) + hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); + if (skippy_iter.has_no_chance ()) return false; - for (i = 1, j = c->buffer->i + 1; i < count; i++, j++) + for (unsigned int i = 1; i < count; i++) { - 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 (!skippy_iter.next ()) + return false; - if (likely (!match_func (c->buffer->info[j].codepoint, input[i - 1], match_data))) + if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return false; } - *context_length_out = j - c->buffer->i; + *context_length_out = skippy_iter.idx - c->buffer->idx + 1; return true; } @@ -155,19 +240,16 @@ static inline bool match_backtrack (hb_apply_context_t *c, match_func_t match_func, const void *match_data) { - if (unlikely (c->buffer->out_len < count)) + hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count); + if (skippy_iter.has_no_chance ()) return false; - for (unsigned int i = 0, j = c->buffer->out_len - 1; i < count; i++, j--) + for (unsigned int i = 0; i < count; i++) { - 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 (!skippy_iter.prev ()) + return false; - if (likely (!match_func (c->buffer->out_info[j].codepoint, backtrack[i], match_data))) + if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data))) return false; } @@ -181,28 +263,22 @@ static inline bool match_lookahead (hb_apply_context_t *c, 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)) + hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count); + if (skippy_iter.has_no_chance ()) return false; - for (i = 0, j = c->buffer->i + offset; i < count; i++, j++) + for (unsigned int i = 0; i < count; i++) { - 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 (!skippy_iter.next ()) + return false; - if (likely (!match_func (c->buffer->info[j].codepoint, lookahead[i], match_data))) + if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data))) return false; } return true; } -HB_END_DECLS struct LookupRecord @@ -221,7 +297,6 @@ struct LookupRecord }; -HB_BEGIN_DECLS static inline bool apply_lookup (hb_apply_context_t *c, unsigned int count, /* Including the first glyph */ @@ -229,8 +304,8 @@ static inline bool apply_lookup (hb_apply_context_t *c, 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)) + unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length); + if (unlikely (count == 0 || c->buffer->idx + count > end)) return false; /* TODO We don't support lookupRecord arrays that are not increasing: @@ -242,17 +317,19 @@ static inline bool apply_lookup (hb_apply_context_t *c, */ 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->idx == end)) + return true; + while (c->should_mark_skip_current_glyph ()) { - if (unlikely (c->buffer->i == end)) - return true; /* No lookup applied for this index */ c->buffer->next_glyph (); + if (unlikely (c->buffer->idx == end)) + return true; } if (lookupCount && i == lookupRecord->sequenceIndex) { - unsigned int old_pos = c->buffer->i; + unsigned int old_pos = c->buffer->idx; /* Apply a lookup */ bool done = apply_func (c, lookupRecord->lookupListIndex); @@ -260,8 +337,8 @@ static inline bool apply_lookup (hb_apply_context_t *c, 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)) + i += c->buffer->idx - old_pos; + if (unlikely (c->buffer->idx == end)) return true; if (!done) @@ -279,7 +356,6 @@ static inline bool apply_lookup (hb_apply_context_t *c, return true; } -HB_END_DECLS /* Contextual lookups */ @@ -383,7 +459,7 @@ struct ContextFormat1 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); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; @@ -422,12 +498,12 @@ struct ContextFormat2 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); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; const ClassDef &class_def = this+classDef; - index = class_def (c->buffer->info[c->buffer->i].codepoint); + index = class_def (c->buffer->info[c->buffer->idx].codepoint); const RuleSet &rule_set = this+ruleSet[index]; struct ContextLookupContext lookup_context = { {match_class, apply_func}, @@ -467,7 +543,7 @@ struct ContextFormat3 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); + unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; @@ -562,8 +638,8 @@ static inline bool chain_context_lookup (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) { /* First guess */ - if (unlikely (c->buffer->out_len < backtrackCount || - c->buffer->i + inputCount + lookaheadCount > c->buffer->len || + if (unlikely (c->buffer->backtrack_len () < backtrackCount || + c->buffer->idx + inputCount + lookaheadCount > c->buffer->len || inputCount + lookaheadCount > c->context_length)) return false; @@ -670,7 +746,7 @@ struct ChainContextFormat1 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); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; @@ -708,7 +784,7 @@ struct ChainContextFormat2 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); + unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; @@ -716,7 +792,7 @@ struct ChainContextFormat2 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); + index = input_class_def (c->buffer->info[c->buffer->idx].codepoint); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextLookupContext lookup_context = { {match_class, apply_func}, @@ -771,7 +847,7 @@ struct ChainContextFormat3 TRACE_APPLY (); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); - unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->i].codepoint); + unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->idx].codepoint); if (likely (index == NOT_COVERED)) return false; @@ -976,6 +1052,5 @@ struct GSUBGPOS }; -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 index b0088fb..bf7e43b 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright © 2007,2008,2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -27,21 +27,22 @@ #ifndef HB_OT_LAYOUT_PRIVATE_HH #define HB_OT_LAYOUT_PRIVATE_HH -#include "hb-private.h" +#include "hb-private.hh" #include "hb-ot-layout.h" -#include "hb-ot-head-private.hh" -#include "hb-font-private.h" +#include "hb-font-private.hh" #include "hb-buffer-private.hh" -HB_BEGIN_DECLS +/* + * GDEF + */ + /* buffer var allocations */ #define props_cache() var1.u16[1] /* glyph_props cache */ - /* XXX cleanup */ typedef enum { HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0001, @@ -52,6 +53,24 @@ typedef enum { } hb_ot_layout_glyph_class_t; +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_ot_layout_t */ @@ -67,48 +86,13 @@ struct hb_ot_layout_t 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_ot_layout_create (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_ot_layout_destroy (hb_ot_layout_t *layout); -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 index fc4b1d3..f3e0713 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc @@ -1,7 +1,7 @@ /* - * Copyright (C) 1998-2004 David Turner and Werner Lemberg - * Copyright (C) 2006 Behdad Esfahbod - * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright © 1998-2004 David Turner and Werner Lemberg + * Copyright © 2006 Behdad Esfahbod + * Copyright © 2007,2008,2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -26,46 +26,40 @@ * 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 "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gsub-table.hh" +#include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-maxp-table.hh" #include <stdlib.h> #include <string.h> -HB_BEGIN_DECLS hb_ot_layout_t * -_hb_ot_layout_new (hb_face_t *face) +_hb_ot_layout_create (hb_face_t *face) { - /* Remove this object altogether */ + /* TODO 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_blob = Sanitizer<GDEF>::sanitize (hb_face_reference_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_blob = Sanitizer<GSUB>::sanitize (hb_face_reference_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_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_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_ot_layout_destroy (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); @@ -78,13 +72,11 @@ _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) { @@ -193,17 +185,13 @@ hb_ot_layout_get_attach_points (hb_face_t *face, 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); + return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); } /* @@ -263,27 +251,48 @@ 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 *script_index, + hb_tag_t *chosen_script) { 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)) + if (g.find_script_index (*script_tags, script_index)) { + if (chosen_script) + *chosen_script = *script_tags; return TRUE; + } script_tags++; } /* try finding 'DFLT' */ - if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) + if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) { + if (chosen_script) + *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT; 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)) + if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) { + if (chosen_script) + *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE; + return FALSE; + } + + /* try with 'latn'; some old fonts put their features there even though + they're really trying to support Thai, for example :( */ +#define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n') + if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) { + if (chosen_script) + *chosen_script = HB_OT_TAG_LATIN_SCRIPT; return FALSE; + } if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX; + if (chosen_script) + *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX; return FALSE; } @@ -439,16 +448,25 @@ hb_ot_layout_has_substitution (hb_face_t *face) return &_get_gsub (face) != &Null(GSUB); } +void +hb_ot_layout_substitute_start (hb_buffer_t *buffer) +{ + GSUB::substitute_start (buffer); +} + 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); + return _get_gsub (face).substitute_lookup (face, buffer, lookup_index, mask); +} + +void +hb_ot_layout_substitute_finish (hb_buffer_t *buffer HB_UNUSED) +{ + GSUB::substitute_finish (buffer); } @@ -462,17 +480,19 @@ hb_ot_layout_has_positioning (hb_face_t *face) return &_get_gpos (face) != &Null(GPOS); } +void +hb_ot_layout_position_start (hb_buffer_t *buffer) +{ + GPOS::position_start (buffer); +} + 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); + return _get_gpos (font->face).position_lookup (font, buffer, lookup_index, mask); } void @@ -482,4 +502,3 @@ hb_ot_layout_position_finish (hb_buffer_t *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 index 9619eb7..447e35d 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout.h +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright © 2007,2008,2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -59,12 +59,11 @@ hb_ot_layout_get_attach_points (hb_face_t *face, /* 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 */); + hb_position_t *caret_array /* OUT */); /* @@ -93,7 +92,8 @@ 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 *script_index, + hb_tag_t *chosen_script); unsigned int hb_ot_layout_table_get_feature_tags (hb_face_t *face, @@ -166,12 +166,20 @@ hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, hb_bool_t hb_ot_layout_has_substitution (hb_face_t *face); +/* Should be called before all the substitute_lookup's are done. */ +void +hb_ot_layout_substitute_start (hb_buffer_t *buffer); + hb_bool_t hb_ot_layout_substitute_lookup (hb_face_t *face, hb_buffer_t *buffer, unsigned int lookup_index, hb_mask_t mask); +/* Should be called after all the substitute_lookup's are done */ +void +hb_ot_layout_substitute_finish (hb_buffer_t *buffer); + /* * GPOS */ @@ -179,9 +187,12 @@ hb_ot_layout_substitute_lookup (hb_face_t *face, hb_bool_t hb_ot_layout_has_positioning (hb_face_t *face); +/* Should be called before all the position_lookup's are done. Resets positions to zero. */ +void +hb_ot_layout_position_start (hb_buffer_t *buffer); + 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); diff --git a/third_party/harfbuzz-ng/src/hb-ot-map-private.hh b/third_party/harfbuzz-ng/src/hb-ot-map-private.hh index 0a1d9f6..710cc0a 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-map-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-map-private.hh @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009,2010 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2010,2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -33,32 +33,56 @@ #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 { +struct hb_ot_map_t +{ + friend struct hb_ot_map_builder_t; - private: + public: - 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 */ + hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); } - 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); } - }; + typedef void (*gsub_pause_func_t) (const hb_ot_map_t *map, hb_face_t *face, hb_buffer_t *buffer, void *user_data); + typedef void (*gpos_pause_func_t) (const hb_ot_map_t *map, hb_font_t *font, hb_buffer_t *buffer, void *user_data); + + 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 = features.bsearch (&tag); + 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 = features.bsearch (&tag); + return map ? map->_1_mask : 0; + } + + inline hb_tag_t get_chosen_script (unsigned int table_index) const + { return chosen_script[table_index]; } + + inline void substitute (hb_face_t *face, hb_buffer_t *buffer) const + { apply (0, (hb_ot_map_t::apply_lookup_func_t) hb_ot_layout_substitute_lookup, face, buffer); } + inline void position (hb_font_t *font, hb_buffer_t *buffer) const + { apply (1, (hb_ot_map_t::apply_lookup_func_t) hb_ot_layout_position_lookup, font, buffer); } + + inline void finish (void) { + features.finish (); + lookups[0].finish (); + lookups[1].finish (); + pauses[0].finish (); + pauses[1].finish (); + } + + private: struct feature_map_t { hb_tag_t tag; /* should be first for our bsearch to work */ - unsigned int index[2]; /* GSUB, GPOS */ + unsigned int index[2]; /* GSUB/GPOS */ + unsigned int stage[2]; /* GSUB/GPOS */ unsigned int shift; hb_mask_t mask; hb_mask_t _1_mask; /* mask for value=1, for quick access */ @@ -75,69 +99,93 @@ struct hb_ot_map_t { { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; } }; + typedef void (*pause_func_t) (const hb_ot_map_t *map, void *face_or_font, hb_buffer_t *buffer, void *user_data); + typedef struct { + pause_func_t func; + void *user_data; + } pause_callback_t; + + struct pause_map_t { + unsigned int num_lookups; /* Cumulative */ + pause_callback_t callback; + }; + + typedef hb_bool_t (*apply_lookup_func_t) (void *face_or_font, + hb_buffer_t *buffer, + unsigned int lookup_index, + hb_mask_t mask); + HB_INTERNAL void add_lookups (hb_face_t *face, unsigned int table_index, unsigned int feature_index, hb_mask_t mask); + HB_INTERNAL void apply (unsigned int table_index, + hb_ot_map_t::apply_lookup_func_t apply_lookup_func, + void *face_or_font, + hb_buffer_t *buffer) const; + hb_mask_t global_mask; + + hb_tag_t chosen_script[2]; + hb_prealloced_array_t<feature_map_t, 8> features; + hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */ + hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */ +}; + + +struct hb_ot_map_builder_t +{ public: - hb_ot_map_t (void) : feature_count (0) {} + hb_ot_map_builder_t (void) { memset (this, 0, sizeof (*this)); } - 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; - } + HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global); 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 void add_gsub_pause (hb_ot_map_t::gsub_pause_func_t pause_func, void *user_data) + { add_pause (0, (hb_ot_map_t::pause_func_t) pause_func, user_data); } + inline void add_gpos_pause (hb_ot_map_t::gpos_pause_func_t pause_func, void *user_data) + { add_pause (1, (hb_ot_map_t::pause_func_t) pause_func, user_data); } - 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; - } + HB_INTERNAL void compile (hb_face_t *face, + const hb_segment_properties_t *props, + struct hb_ot_map_t &m); - 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 finish (void) { + feature_infos.finish (); + pauses[0].finish (); + pauses[1].finish (); } - 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); - } + private: - 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); - } + 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 */ + unsigned int stage[2]; /* GSUB/GPOS */ - private: + 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); } + }; - hb_mask_t global_mask; + struct pause_info_t { + unsigned int stage; + hb_ot_map_t::pause_callback_t callback; + }; - unsigned int feature_count; - feature_info_t feature_infos[MAX_FEATURES]; /* used before compile() only */ - feature_map_t feature_maps[MAX_FEATURES]; + HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data); - lookup_map_t lookup_maps[2][MAX_LOOKUPS]; /* GSUB/GPOS */ - unsigned int lookup_count[2]; + unsigned int current_stage[2]; /* GSUB/GPOS */ + hb_prealloced_array_t<feature_info_t,16> feature_infos; + hb_prealloced_array_t<pause_info_t, 1> pauses[2]; /* GSUB/GPOS */ }; -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 index ca96ba9..a54e306 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-map.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-map.cc @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009,2010 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2010,2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -30,7 +30,6 @@ #include "hb-ot-shape-private.hh" -HB_BEGIN_DECLS void @@ -39,76 +38,133 @@ hb_ot_map_t::add_lookups (hb_face_t *face, 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[32]; + unsigned int offset, len; + + offset = 0; + do { + len = ARRAY_LENGTH (lookup_indices); + hb_ot_layout_feature_get_lookup_indexes (face, + table_tags[table_index], + feature_index, + offset, &len, + lookup_indices); + + for (unsigned int i = 0; i < len; i++) { + hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push (); + if (unlikely (!lookup)) + return; + lookup->mask = mask; + lookup->index = lookup_indices[i]; + } + + offset += len; + } while (len == ARRAY_LENGTH (lookup_indices)); +} - 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); +void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global) +{ + feature_info_t *info = feature_infos.push(); + if (unlikely (!info)) return; + info->tag = tag; + info->seq = feature_infos.len; + info->max_value = value; + info->global = global; + info->default_value = global ? value : 0; + info->stage[0] = current_stage[0]; + info->stage[1] = current_stage[1]; +} + +void hb_ot_map_t::apply (unsigned int table_index, + hb_ot_map_t::apply_lookup_func_t apply_lookup_func, + void *face_or_font, + hb_buffer_t *buffer) const +{ + unsigned int i = 0; - lookup_count[table_index] += i; + for (unsigned int pause_index = 0; pause_index < pauses[table_index].len; pause_index++) { + const pause_map_t *pause = &pauses[table_index][pause_index]; + for (; i < pause->num_lookups; i++) + apply_lookup_func (face_or_font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); - while (i--) { - lookups[i].mask = mask; - lookups[i].index = lookup_indices[i]; + pause->callback.func (this, face_or_font, buffer, pause->callback.user_data); } + + for (; i < lookups[table_index].len; i++) + apply_lookup_func (face_or_font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); } +void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data) +{ + if (pause_func) { + pause_info_t *p = pauses[table_index].push (); + if (likely (p)) { + p->stage = current_stage[table_index]; + p->callback.func = pause_func; + p->callback.user_data = user_data; + } + } + + current_stage[table_index]++; +} + void -hb_ot_map_t::compile (hb_face_t *face, - const hb_segment_properties_t *props) +hb_ot_map_builder_t::compile (hb_face_t *face, + const hb_segment_properties_t *props, + hb_ot_map_t &m) { - global_mask = 1; - lookup_count[0] = lookup_count[1] = 0; + m.global_mask = 1; - if (!feature_count) + if (!feature_infos.len) 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 script_tags[3] = {HB_TAG_NONE}; hb_tag_t language_tag; - script_tags = hb_ot_tags_from_script (props->script); + hb_ot_tags_from_script (props->script, &script_tags[0], &script_tags[1]); 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_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &m.chosen_script[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]; + { + feature_infos.sort (); + unsigned int j = 0; + for (unsigned int i = 1; i < feature_infos.len; i++) + if (feature_infos[i].tag != feature_infos[j].tag) + feature_infos[++j] = feature_infos[i]; else { - feature_infos[j].global = false; - feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value); + if (feature_infos[i].global) { + feature_infos[j].global = true; + feature_infos[j].max_value = feature_infos[i].max_value; + feature_infos[j].default_value = feature_infos[i].default_value; + } else { + feature_infos[j].global = false; + feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value); + } + feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]); + feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]); /* Inherit default_value from j */ } - } - feature_count = j + 1; + feature_infos.shrink (j + 1); + } /* Allocate bits now */ unsigned int next_bit = 1; - j = 0; - for (unsigned int i = 0; i < feature_count; i++) { + for (unsigned int i = 0; i < feature_infos.len; i++) { const feature_info_t *info = &feature_infos[i]; unsigned int bits_needed; @@ -136,11 +192,15 @@ hb_ot_map_t::compile (hb_face_t *face, continue; - feature_map_t *map = &feature_maps[j++]; + hb_ot_map_t::feature_map_t *map = m.features.push (); + if (unlikely (!map)) + break; map->tag = info->tag; map->index[0] = feature_index[0]; map->index[1] = feature_index[1]; + map->stage[0] = info->stage[0]; + map->stage[1] = info->stage[1]; if (info->global && info->max_value == 1) { /* Uses the global bit */ map->shift = 0; @@ -150,13 +210,16 @@ hb_ot_map_t::compile (hb_face_t *face, 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; + m.global_mask |= (info->default_value << map->shift) & map->mask; } map->_1_mask = (1 << map->shift) & map->mask; } - feature_count = j; + feature_infos.shrink (0); /* Done with these */ + + add_gsub_pause (NULL, NULL); + add_gpos_pause (NULL, NULL); for (unsigned int table_index = 0; table_index < 2; table_index++) { hb_tag_t table_tag = table_tags[table_index]; @@ -169,26 +232,43 @@ hb_ot_map_t::compile (hb_face_t *face, 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); + m.add_lookups (face, table_index, required_feature_index, 1); - /* 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 pause_index = 0; + unsigned int last_num_lookups = 0; + for (unsigned stage = 0; stage < current_stage[table_index]; stage++) { - 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; + for (unsigned i = 0; i < m.features.len; i++) + if (m.features[i].stage[table_index] == stage) + m.add_lookups (face, table_index, m.features[i].index[table_index], m.features[i].mask); + + /* Sort lookups and merge duplicates */ + if (last_num_lookups < m.lookups[table_index].len) + { + m.lookups[table_index].sort (last_num_lookups, m.lookups[table_index].len); + + unsigned int j = last_num_lookups; + for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++) + if (m.lookups[table_index][i].index != m.lookups[table_index][j].index) + m.lookups[table_index][++j] = m.lookups[table_index][i]; + else + m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask; + m.lookups[table_index].shrink (j + 1); + } + + last_num_lookups = m.lookups[table_index].len; + + if (pause_index < pauses[table_index].len && pauses[table_index][pause_index].stage == stage) { + hb_ot_map_t::pause_map_t *pause_map = m.pauses[table_index].push (); + if (likely (pause_map)) { + pause_map->num_lookups = last_num_lookups; + pause_map->callback = pauses[table_index][pause_index].callback; + } + + pause_index++; + } } } } -HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh new file mode 100644 index 0000000..c3ac1c2 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh @@ -0,0 +1,66 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_MAXP_TABLE_HH +#define HB_OT_MAXP_TABLE_HH + +#include "hb-open-type-private.hh" + + + +/* + * maxp -- The Maximum Profile Table + */ + +#define HB_OT_TAG_maxp HB_TAG('m','a','x','p') + +struct maxp +{ + static const hb_tag_t Tag = HB_OT_TAG_maxp; + + inline unsigned int get_num_glyphs (void) const { + return numGlyphs; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) && + likely (version.major == 1 || + (version.major == 0 && version.minor == 0x5000)); + } + + /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */ + private: + FixedVersion version; /* Version of the maxp table (0.5 or 1.0), + * 0x00005000 or 0x00010000. */ + USHORT numGlyphs; /* The number of glyphs in the font. */ + public: + DEFINE_SIZE_STATIC (6); +}; + + + +#endif /* HB_OT_MAXP_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-name-table.hh b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh new file mode 100644 index 0000000..0e9f7a4 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh @@ -0,0 +1,129 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_NAME_TABLE_HH +#define HB_OT_NAME_TABLE_HH + +#include "hb-open-type-private.hh" + + + +/* + * name -- The Naming Table + */ + +#define HB_OT_TAG_name HB_TAG('n','a','m','e') + + +struct NameRecord +{ + static int cmp (const NameRecord *a, const NameRecord *b) + { + int ret; + ret = b->platformID.cmp (a->platformID); + if (ret) return ret; + ret = b->encodingID.cmp (a->encodingID); + if (ret) return ret; + ret = b->languageID.cmp (a->languageID); + if (ret) return ret; + ret = b->nameID.cmp (a->nameID); + if (ret) return ret; + return 0; + } + + inline bool sanitize (hb_sanitize_context_t *c, void *base) { + TRACE_SANITIZE (); + /* We can check from base all the way up to the end of string... */ + return c->check_struct (this) && + c->check_range ((char *) base, (unsigned int) length + offset); + } + + USHORT platformID; /* Platform ID. */ + USHORT encodingID; /* Platform-specific encoding ID. */ + USHORT languageID; /* Language ID. */ + USHORT nameID; /* Name ID. */ + USHORT length; /* String length (in bytes). */ + USHORT offset; /* String offset from start of storage area (in bytes). */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct name +{ + static const hb_tag_t Tag = HB_OT_TAG_name; + + inline unsigned int get_name (unsigned int platform_id, + unsigned int encoding_id, + unsigned int language_id, + unsigned int name_id, + void *buffer, + unsigned int buffer_length) const + { + NameRecord key; + key.platformID.set (platform_id); + key.encodingID.set (encoding_id); + key.languageID.set (language_id); + key.nameID.set (name_id); + NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), (hb_compare_func_t) NameRecord::cmp); + + if (!match) + return 0; + + unsigned int length = MIN (buffer_length, (unsigned int) match->length); + memcpy (buffer, (char *) this + stringOffset + match->offset, length); + return length; + } + + inline bool sanitize_records (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + char *string_pool = (char *) this + stringOffset; + unsigned int _count = count; + for (unsigned int i = 0; i < _count; i++) + if (!nameRecord[i].sanitize (c, string_pool)) return false; + return true; + } + + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (); + return c->check_struct (this) && + likely (format == 0 || format == 1) && + c->check_array (nameRecord, nameRecord[0].static_size, count) && + sanitize_records (c); + } + + /* We only implement format 0 for now. */ + private: + USHORT format; /* Format selector (=0/1). */ + USHORT count; /* Number of name records. */ + Offset stringOffset; /* Offset to start of string storage (from start of table). */ + NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */ + public: + DEFINE_SIZE_ARRAY (6, nameRecord); +}; + + + +#endif /* HB_OT_NAME_TABLE_HH */ 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.hh index 523fc84..5aa8716 100644 --- 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.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,34 +24,33 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_H -#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_H +#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH +#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH -#include "hb-private.h" +#include "hb-private.hh" -HB_BEGIN_DECLS /* == Start of generated table == */ /* * The following table is generated by running: * - * ./gen-arabic-joining-table.py < ArabicShaping.txt + * ./gen-arabic-table.py ArabicShaping.txt * - * on the ArabicShaping.txt file with the header: + * on files with these headers: * * # ArabicShaping-6.1.0.txt - * # Date: 2010-11-09, 12:10:00 PST [KW] + * # Date: 2011-04-15, 23:16:00 GMT [KW] */ static const uint8_t joining_table[] = { - /* Arabic characters */ + /* 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_U, /* 0604; ARABIC SIGN SAMVAT; U; No_Joining_Group */ JOINING_TYPE_X, /* 0605 */ JOINING_TYPE_X, /* 0606 */ JOINING_TYPE_X, /* 0607 */ @@ -79,36 +78,36 @@ static const uint8_t joining_table[] = JOINING_TYPE_X, /* 061D */ JOINING_TYPE_X, /* 061E */ JOINING_TYPE_X, /* 061F */ - JOINING_TYPE_D, /* 0620; YEH WITH RING; D; YEH */ + JOINING_TYPE_D, /* 0620; DOTLESS YEH WITH SEPARATE RING BELOW; 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, /* 0622; ALEF WITH MADDA ABOVE; R; ALEF */ + JOINING_TYPE_R, /* 0623; ALEF WITH HAMZA ABOVE; R; ALEF */ + JOINING_TYPE_R, /* 0624; WAW WITH HAMZA ABOVE; R; WAW */ + JOINING_TYPE_R, /* 0625; ALEF WITH HAMZA BELOW; R; ALEF */ + JOINING_TYPE_D, /* 0626; DOTLESS YEH WITH HAMZA ABOVE; 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, /* 062A; DOTLESS BEH WITH 2 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 062B; DOTLESS BEH WITH 3 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 062C; HAH WITH DOT BELOW; D; HAH */ JOINING_TYPE_D, /* 062D; HAH; D; HAH */ - JOINING_TYPE_D, /* 062E; KHAH; D; HAH */ + JOINING_TYPE_D, /* 062E; HAH WITH DOT ABOVE; D; HAH */ JOINING_TYPE_R, /* 062F; DAL; R; DAL */ - JOINING_TYPE_R, /* 0630; THAL; R; DAL */ + JOINING_TYPE_R, /* 0630; DAL WITH DOT ABOVE; R; DAL */ JOINING_TYPE_R, /* 0631; REH; R; REH */ - JOINING_TYPE_R, /* 0632; ZAIN; R; REH */ + JOINING_TYPE_R, /* 0632; REH WITH DOT ABOVE; R; REH */ JOINING_TYPE_D, /* 0633; SEEN; D; SEEN */ - JOINING_TYPE_D, /* 0634; SHEEN; D; SEEN */ + JOINING_TYPE_D, /* 0634; SEEN WITH 3 DOTS ABOVE; D; SEEN */ JOINING_TYPE_D, /* 0635; SAD; D; SAD */ - JOINING_TYPE_D, /* 0636; DAD; D; SAD */ + JOINING_TYPE_D, /* 0636; SAD WITH DOT ABOVE; D; SAD */ JOINING_TYPE_D, /* 0637; TAH; D; TAH */ - JOINING_TYPE_D, /* 0638; ZAH; D; TAH */ + JOINING_TYPE_D, /* 0638; TAH WITH DOT ABOVE; D; TAH */ JOINING_TYPE_D, /* 0639; AIN; D; AIN */ - JOINING_TYPE_D, /* 063A; GHAIN; D; AIN */ + JOINING_TYPE_D, /* 063A; AIN WITH DOT ABOVE; 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, /* 063D; FARSI YEH WITH INVERTED V ABOVE; 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 */ @@ -120,7 +119,7 @@ static const uint8_t joining_table[] = 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, /* 0649; DOTLESS YEH; D; YEH */ JOINING_TYPE_D, /* 064A; YEH; D; YEH */ JOINING_TYPE_X, /* 064B */ JOINING_TYPE_X, /* 064C */ @@ -160,44 +159,44 @@ static const uint8_t joining_table[] = 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_R, /* 0671; ALEF WITH WASLA ABOVE; R; ALEF */ + JOINING_TYPE_R, /* 0672; ALEF WITH WAVY HAMZA ABOVE; R; ALEF */ + JOINING_TYPE_R, /* 0673; ALEF WITH WAVY HAMZA BELOW; 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_R, /* 0677; HIGH HAMZA WAW WITH DAMMA ABOVE; R; WAW */ + JOINING_TYPE_D, /* 0678; HIGH HAMZA DOTLESS YEH; D; YEH */ + JOINING_TYPE_D, /* 0679; DOTLESS BEH WITH TAH ABOVE; D; BEH */ + JOINING_TYPE_D, /* 067A; DOTLESS BEH WITH VERTICAL 2 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 067B; DOTLESS BEH WITH VERTICAL 2 DOTS BELOW; D; BEH */ + JOINING_TYPE_D, /* 067C; DOTLESS BEH WITH ATTACHED RING BELOW AND 2 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 067D; DOTLESS BEH WITH INVERTED 3 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 067E; DOTLESS BEH WITH 3 DOTS BELOW; D; BEH */ + JOINING_TYPE_D, /* 067F; DOTLESS BEH WITH 4 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0680; DOTLESS BEH WITH 4 DOTS BELOW; D; BEH */ + JOINING_TYPE_D, /* 0681; HAH WITH HAMZA ABOVE; D; HAH */ + JOINING_TYPE_D, /* 0682; HAH WITH VERTICAL 2 DOTS ABOVE; D; HAH */ + JOINING_TYPE_D, /* 0683; HAH WITH 2 DOTS BELOW; D; HAH */ + JOINING_TYPE_D, /* 0684; HAH WITH VERTICAL 2 DOTS BELOW; 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_D, /* 0686; HAH WITH 3 DOTS BELOW; D; HAH */ + JOINING_TYPE_D, /* 0687; HAH WITH 4 DOTS BELOW; D; HAH */ + JOINING_TYPE_R, /* 0688; DAL WITH TAH ABOVE; R; DAL */ + JOINING_TYPE_R, /* 0689; DAL WITH ATTACHED RING BELOW; 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, /* 068B; DAL WITH DOT BELOW AND TAH ABOVE; 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, /* 068F; DAL WITH INVERTED 3 DOTS ABOVE; 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, /* 0691; REH WITH TAH ABOVE; R; REH */ + JOINING_TYPE_R, /* 0692; REH WITH V ABOVE; R; REH */ + JOINING_TYPE_R, /* 0693; REH WITH ATTACHED RING BELOW; 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, /* 0695; REH WITH V BELOW; R; REH */ + JOINING_TYPE_R, /* 0696; REH WITH DOT BELOW AND DOT WITHIN; 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 */ @@ -209,58 +208,58 @@ static const uint8_t joining_table[] = 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, /* 06A2; DOTLESS FEH WITH DOT 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, /* 06A4; DOTLESS FEH WITH 3 DOTS ABOVE; D; FEH */ + JOINING_TYPE_D, /* 06A5; DOTLESS FEH WITH 3 DOTS BELOW; D; FEH */ + JOINING_TYPE_D, /* 06A6; DOTLESS FEH WITH 4 DOTS ABOVE; D; FEH */ + JOINING_TYPE_D, /* 06A7; DOTLESS QAF WITH DOT ABOVE; D; QAF */ + JOINING_TYPE_D, /* 06A8; DOTLESS 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, /* 06AB; KEHEH WITH ATTACHED RING BELOW; 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, /* 06B0; GAF WITH ATTACHED RING BELOW; 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, /* 06B3; GAF WITH VERTICAL 2 DOTS 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, /* 06B5; LAM WITH V ABOVE; 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, /* 06BB; DOTLESS NOON WITH TAH ABOVE; D; NOON */ + JOINING_TYPE_D, /* 06BC; NOON WITH ATTACHED RING BELOW; 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, /* 06BF; HAH WITH 3 DOTS BELOW AND DOT ABOVE; D; HAH */ + JOINING_TYPE_R, /* 06C0; DOTLESS TEH MARBUTA WITH HAMZA ABOVE; 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_D, /* 06C2; HEH GOAL WITH HAMZA ABOVE; 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, /* 06C4; WAW WITH ATTACHED RING WITHIN; 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, /* 06C6; WAW WITH V ABOVE; R; WAW */ + JOINING_TYPE_R, /* 06C7; WAW WITH DAMMA ABOVE; 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, /* 06C9; WAW WITH INVERTED V ABOVE; 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_D, /* 06CE; FARSI YEH WITH V ABOVE; 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_D, /* 06D0; DOTLESS YEH WITH VERTICAL 2 DOTS BELOW; D; YEH */ + JOINING_TYPE_D, /* 06D1; DOTLESS 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_R, /* 06D3; YEH BARREE WITH HAMZA ABOVE; R; YEH BARREE */ JOINING_TYPE_X, /* 06D4 */ - JOINING_TYPE_R, /* 06D5; AE; R; TEH MARBUTA */ + JOINING_TYPE_R, /* 06D5; DOTLESS TEH MARBUTA; R; TEH MARBUTA */ JOINING_TYPE_X, /* 06D6 */ JOINING_TYPE_X, /* 06D7 */ JOINING_TYPE_X, /* 06D8 */ @@ -285,8 +284,8 @@ static const uint8_t joining_table[] = 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_R, /* 06EE; DAL WITH INVERTED V ABOVE; R; DAL */ + JOINING_TYPE_R, /* 06EF; REH WITH INVERTED V ABOVE; R; REH */ JOINING_TYPE_X, /* 06F0 */ JOINING_TYPE_X, /* 06F1 */ JOINING_TYPE_X, /* 06F2 */ @@ -298,13 +297,13 @@ static const uint8_t joining_table[] = 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_D, /* 06FB; SAD WITH DOT BELOW AND DOT ABOVE; D; SAD */ + JOINING_TYPE_D, /* 06FC; AIN WITH DOT BELOW AND DOT ABOVE; D; AIN */ JOINING_TYPE_X, /* 06FD */ JOINING_TYPE_X, /* 06FE */ - JOINING_TYPE_D, /* 06FF; HEH WITH INVERTED V; D; KNOTTED HEH */ + JOINING_TYPE_D, /* 06FF; KNOTTED HEH WITH INVERTED V ABOVE; D; KNOTTED HEH */ - /* Syriac characters */ + /* Syriac Characters */ JOINING_TYPE_X, /* 0700 */ JOINING_TYPE_X, /* 0701 */ @@ -387,55 +386,55 @@ static const uint8_t joining_table[] = JOINING_TYPE_D, /* 074E; SOGDIAN KHAPH; D; KHAPH */ JOINING_TYPE_D, /* 074F; SOGDIAN FE; D; FE */ - /* Arabic supplement characters */ + /* 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, /* 0750; DOTLESS BEH WITH HORIZONTAL 3 DOTS BELOW; D; BEH */ + JOINING_TYPE_D, /* 0751; BEH WITH 3 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0752; DOTLESS BEH WITH INVERTED 3 DOTS BELOW; D; BEH */ + JOINING_TYPE_D, /* 0753; DOTLESS BEH WITH INVERTED 3 DOTS BELOW AND 2 DOTS ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0754; DOTLESS BEH WITH 2 DOTS BELOW AND DOT ABOVE; D; BEH */ + JOINING_TYPE_D, /* 0755; DOTLESS BEH WITH INVERTED V BELOW; D; BEH */ + JOINING_TYPE_D, /* 0756; DOTLESS BEH WITH V ABOVE; 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, /* 0758; HAH WITH INVERTED 3 DOTS BELOW; D; HAH */ + JOINING_TYPE_R, /* 0759; DAL WITH VERTICAL 2 DOTS BELOW AND TAH ABOVE; R; DAL */ + JOINING_TYPE_R, /* 075A; DAL WITH INVERTED V BELOW; R; DAL */ + JOINING_TYPE_R, /* 075B; REH WITH BAR; 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, /* 075E; AIN WITH INVERTED 3 DOTS ABOVE; D; AIN */ + JOINING_TYPE_D, /* 075F; AIN WITH VERTICAL 2 DOTS ABOVE; D; AIN */ + JOINING_TYPE_D, /* 0760; DOTLESS FEH WITH 2 DOTS BELOW; D; FEH */ + JOINING_TYPE_D, /* 0761; DOTLESS FEH WITH INVERTED 3 DOTS 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, /* 0764; KEHEH WITH INVERTED 3 DOTS 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, /* 0768; NOON WITH TAH ABOVE; D; NOON */ + JOINING_TYPE_D, /* 0769; NOON WITH V ABOVE; 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, /* 076B; REH WITH VERTICAL 2 DOTS 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_D, /* 076D; SEEN WITH VERTICAL 2 DOTS ABOVE; D; SEEN */ + JOINING_TYPE_D, /* 076E; HAH WITH TAH BELOW; D; HAH */ + JOINING_TYPE_D, /* 076F; HAH WITH TAH AND 2 DOTS BELOW; D; HAH */ + JOINING_TYPE_D, /* 0770; SEEN WITH 2 DOTS AND TAH ABOVE; D; SEEN */ + JOINING_TYPE_R, /* 0771; REH WITH 2 DOTS AND TAH ABOVE; R; REH */ + JOINING_TYPE_D, /* 0772; HAH WITH 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_D, /* 0777; DOTLESS 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, /* 077A; BURUSHASKI YEH BARREE WITH DIGIT TWO ABOVE; D; BURUSHASKI YEH BARREE */ + JOINING_TYPE_D, /* 077B; BURUSHASKI 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, /* 077E; SEEN WITH INVERTED V ABOVE; D; SEEN */ JOINING_TYPE_D, /* 077F; KAF WITH 2 DOTS ABOVE; D; KAF */ /* N'Ko Characters */ @@ -661,14 +660,99 @@ static const uint8_t joining_table[] = JOINING_TYPE_U, /* 0857; MANDAIC KAD; U; No_Joining_Group */ JOINING_TYPE_U, /* 0858; MANDAIC AIN; U; No_Joining_Group */ - JOINING_TYPE_X /* dummy */ + /* Arabic Extended-A Characters */ + + JOINING_TYPE_X, /* 0859 */ + JOINING_TYPE_X, /* 085A */ + JOINING_TYPE_X, /* 085B */ + JOINING_TYPE_X, /* 085C */ + JOINING_TYPE_X, /* 085D */ + JOINING_TYPE_X, /* 085E */ + JOINING_TYPE_X, /* 085F */ + JOINING_TYPE_X, /* 0860 */ + JOINING_TYPE_X, /* 0861 */ + JOINING_TYPE_X, /* 0862 */ + JOINING_TYPE_X, /* 0863 */ + JOINING_TYPE_X, /* 0864 */ + JOINING_TYPE_X, /* 0865 */ + JOINING_TYPE_X, /* 0866 */ + JOINING_TYPE_X, /* 0867 */ + JOINING_TYPE_X, /* 0868 */ + JOINING_TYPE_X, /* 0869 */ + JOINING_TYPE_X, /* 086A */ + JOINING_TYPE_X, /* 086B */ + JOINING_TYPE_X, /* 086C */ + JOINING_TYPE_X, /* 086D */ + JOINING_TYPE_X, /* 086E */ + JOINING_TYPE_X, /* 086F */ + JOINING_TYPE_X, /* 0870 */ + JOINING_TYPE_X, /* 0871 */ + JOINING_TYPE_X, /* 0872 */ + JOINING_TYPE_X, /* 0873 */ + JOINING_TYPE_X, /* 0874 */ + JOINING_TYPE_X, /* 0875 */ + JOINING_TYPE_X, /* 0876 */ + JOINING_TYPE_X, /* 0877 */ + JOINING_TYPE_X, /* 0878 */ + JOINING_TYPE_X, /* 0879 */ + JOINING_TYPE_X, /* 087A */ + JOINING_TYPE_X, /* 087B */ + JOINING_TYPE_X, /* 087C */ + JOINING_TYPE_X, /* 087D */ + JOINING_TYPE_X, /* 087E */ + JOINING_TYPE_X, /* 087F */ + JOINING_TYPE_X, /* 0880 */ + JOINING_TYPE_X, /* 0881 */ + JOINING_TYPE_X, /* 0882 */ + JOINING_TYPE_X, /* 0883 */ + JOINING_TYPE_X, /* 0884 */ + JOINING_TYPE_X, /* 0885 */ + JOINING_TYPE_X, /* 0886 */ + JOINING_TYPE_X, /* 0887 */ + JOINING_TYPE_X, /* 0888 */ + JOINING_TYPE_X, /* 0889 */ + JOINING_TYPE_X, /* 088A */ + JOINING_TYPE_X, /* 088B */ + JOINING_TYPE_X, /* 088C */ + JOINING_TYPE_X, /* 088D */ + JOINING_TYPE_X, /* 088E */ + JOINING_TYPE_X, /* 088F */ + JOINING_TYPE_X, /* 0890 */ + JOINING_TYPE_X, /* 0891 */ + JOINING_TYPE_X, /* 0892 */ + JOINING_TYPE_X, /* 0893 */ + JOINING_TYPE_X, /* 0894 */ + JOINING_TYPE_X, /* 0895 */ + JOINING_TYPE_X, /* 0896 */ + JOINING_TYPE_X, /* 0897 */ + JOINING_TYPE_X, /* 0898 */ + JOINING_TYPE_X, /* 0899 */ + JOINING_TYPE_X, /* 089A */ + JOINING_TYPE_X, /* 089B */ + JOINING_TYPE_X, /* 089C */ + JOINING_TYPE_X, /* 089D */ + JOINING_TYPE_X, /* 089E */ + JOINING_TYPE_X, /* 089F */ + JOINING_TYPE_D, /* 08A0; DOTLESS BEH WITH V BELOW; D; BEH */ + JOINING_TYPE_X, /* 08A1 */ + JOINING_TYPE_D, /* 08A2; HAH WITH DOT BELOW AND 2 DOTS ABOVE; D; HAH */ + JOINING_TYPE_D, /* 08A3; TAH WITH 2 DOTS ABOVE; D; TAH */ + JOINING_TYPE_D, /* 08A4; DOTLESS FEH WITH DOT BELOW AND 3 DOTS ABOVE; D; FEH */ + JOINING_TYPE_D, /* 08A5; QAF WITH DOT BELOW; D; QAF */ + JOINING_TYPE_D, /* 08A6; LAM WITH DOUBLE BAR; D; LAM */ + JOINING_TYPE_D, /* 08A7; MEEM WITH 3 DOTS ABOVE; D; MEEM */ + JOINING_TYPE_D, /* 08A8; YEH WITH HAMZA ABOVE; D; YEH */ + JOINING_TYPE_D, /* 08A9; YEH WITH DOT ABOVE; D; YEH */ + JOINING_TYPE_R, /* 08AA; REH WITH LOOP; R; REH */ + JOINING_TYPE_R, /* 08AB; WAW WITH DOT WITHIN; R; WAW */ + JOINING_TYPE_R, /* 08AC; ROHINGYA YEH; R; ROHINGYA YEH */ + }; #define JOINING_TABLE_FIRST 0x0600 -#define JOINING_TABLE_LAST 0x0858 +#define JOINING_TABLE_LAST 0x08AC /* == End of generated table == */ -HB_END_DECLS -#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_H */ +#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */ 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 index 77a9c82..2b863ef 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google, Inc. + * Copyright © 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -26,11 +26,10 @@ #include "hb-ot-shape-complex-private.hh" -HB_BEGIN_DECLS /* buffer var allocations */ -#define arabic_shaping_action() var2.u32 /* arabic shaping action */ +#define arabic_shaping_action() complex_var_temporary_u16() /* arabic shaping action */ /* @@ -55,31 +54,31 @@ enum { * Joining types: */ -#include "hb-ot-shape-complex-arabic-table.h" +#include "hb-ot-shape-complex-arabic-table.hh" -static unsigned int get_joining_type (hb_codepoint_t u, hb_category_t gen_cat) +static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat) { /* TODO Macroize the magic bit operations */ - if (likely (JOINING_TABLE_FIRST <= u && u <= JOINING_TABLE_LAST)) { + if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, 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)) + if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF))) { /* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */ - if (gen_cat == HB_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A) + if (gen_cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A) return JOINING_TYPE_D; } - if (unlikely ((u & ~(0x200C^0x200D)) == 0x200C)) { + if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) { 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))) ? + return (FLAG(gen_cat) & (FLAG(HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG(HB_UNICODE_GENERAL_CATEGORY_FORMAT))) ? JOINING_TYPE_T : JOINING_TYPE_U; } @@ -121,8 +120,7 @@ enum { static const struct arabic_state_table_entry { uint8_t prev_action; uint8_t curr_action; - uint8_t next_state; - uint8_t padding; + uint16_t next_state; } arabic_state_table[][NUM_STATE_MACHINE_COLS] = { /* jt_U, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */ @@ -152,47 +150,82 @@ static const struct arabic_state_table_entry { void -_hb_ot_shape_complex_collect_features_arabic (hb_ot_shape_plan_t *plan, const hb_segment_properties_t *props) +_hb_ot_shape_complex_collect_features_arabic (hb_ot_map_builder_t *map, const hb_segment_properties_t *props) { + /* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together, + * then rlig and calt each in their own stage. This makes IranNastaliq's ALLAH + * ligature work correctly. It's unfortunate though... + * + * This also makes Arial Bold in Windows7 work. See: + * https://bugzilla.mozilla.org/show_bug.cgi?id=644184 + * + * TODO: Add test cases for these two. + */ + + map->add_bool_feature (HB_TAG('c','c','m','p')); + map->add_bool_feature (HB_TAG('l','o','c','l')); + + map->add_gsub_pause (NULL, NULL); + 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); + map->add_bool_feature (arabic_syriac_features[i], false); + + map->add_gsub_pause (NULL, NULL); + + map->add_bool_feature (HB_TAG('r','l','i','g')); + map->add_gsub_pause (NULL, NULL); + + map->add_bool_feature (HB_TAG('c','a','l','t')); + map->add_gsub_pause (NULL, NULL); + + /* ArabicOT spec enables 'cswh' for Arabic where as for basic shaper it's disabled by default. */ + map->add_bool_feature (HB_TAG('c','s','w','h')); +} + +bool +_hb_ot_shape_complex_prefer_decomposed_arabic (void) +{ + return FALSE; } void -_hb_ot_shape_complex_setup_masks_arabic (hb_ot_shape_context_t *c) +_hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map, hb_buffer_t *buffer) { - unsigned int count = c->buffer->len; + unsigned int count = buffer->len; unsigned int prev = 0, state = 0; + HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action); + 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()); + unsigned int this_type = get_joining_type (buffer->info[i].codepoint, (hb_unicode_general_category_t) buffer->info[i].general_category()); if (unlikely (this_type == JOINING_TYPE_T)) { - c->buffer->info[i].arabic_shaping_action() = NONE; + 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; + buffer->info[prev].arabic_shaping_action() = entry->prev_action; - c->buffer->info[i].arabic_shaping_action() = entry->curr_action; + 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; + unsigned int num_masks = 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]); + mask_array[i] = 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()]; + buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()]; + + HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); } -HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh new file mode 100644 index 0000000..5c42355 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh @@ -0,0 +1,304 @@ + +#line 1 "hb-ot-shape-complex-indic-machine.rl" +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH +#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH + +#include "hb-private.hh" + +HB_BEGIN_DECLS + + +#line 38 "hb-ot-shape-complex-indic-machine.hh.tmp" +static const unsigned char _indic_syllable_machine_trans_keys[] = { + 0u, 0u, 5u, 5u, 1u, 2u, 1u, 2u, 5u, 5u, 1u, 5u, 5u, 5u, 1u, 2u, + 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, + 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, + 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, + 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, + 0u, 12u, 0 +}; + +static const char _indic_syllable_machine_key_spans[] = { + 0, 1, 2, 2, 1, 5, 1, 2, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13 +}; + +static const short _indic_syllable_machine_index_offsets[] = { + 0, 0, 2, 5, 8, 10, 16, 18, + 21, 35, 49, 63, 77, 91, 105, 119, + 133, 147, 161, 175, 189, 203, 217, 231, + 245, 259, 273, 287, 301, 315, 329, 343, + 357, 371, 385, 399, 413, 427, 441, 455, + 469 +}; + +static const char _indic_syllable_machine_indicies[] = { + 0, 1, 2, 2, 1, 3, 3, + 1, 4, 1, 2, 2, 1, 1, 0, + 1, 5, 1, 6, 6, 1, 7, 6, + 8, 9, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 1, 11, 12, 13, 14, + 1, 1, 1, 1, 1, 1, 1, 1, + 15, 1, 16, 17, 18, 19, 20, 21, + 22, 22, 23, 24, 25, 26, 27, 1, + 16, 17, 18, 19, 20, 28, 22, 22, + 23, 24, 25, 26, 27, 1, 29, 30, + 31, 32, 33, 1, 34, 35, 36, 37, + 38, 1, 39, 1, 29, 30, 31, 32, + 1, 1, 34, 35, 36, 37, 38, 1, + 39, 1, 29, 30, 31, 32, 1, 1, + 1, 1, 36, 37, 38, 1, 39, 1, + 29, 30, 31, 32, 40, 2, 1, 1, + 36, 37, 38, 1, 39, 1, 29, 30, + 31, 32, 1, 2, 1, 1, 36, 37, + 38, 1, 39, 1, 29, 30, 31, 32, + 1, 1, 1, 1, 1, 1, 38, 1, + 39, 1, 29, 30, 31, 32, 1, 1, + 1, 1, 1, 1, 41, 1, 39, 1, + 29, 30, 31, 32, 1, 1, 1, 1, + 1, 1, 1, 1, 39, 1, 42, 43, + 44, 45, 46, 4, 47, 47, 48, 49, + 50, 1, 51, 1, 42, 43, 44, 45, + 1, 4, 47, 47, 48, 49, 50, 1, + 51, 1, 42, 43, 44, 45, 1, 1, + 1, 1, 48, 49, 50, 1, 51, 1, + 42, 43, 44, 45, 52, 3, 1, 1, + 48, 49, 50, 1, 51, 1, 42, 43, + 44, 45, 1, 3, 1, 1, 48, 49, + 50, 1, 51, 1, 42, 43, 44, 45, + 1, 1, 1, 1, 1, 1, 50, 1, + 51, 1, 42, 43, 44, 45, 1, 1, + 1, 1, 1, 1, 53, 1, 51, 1, + 42, 43, 44, 45, 1, 1, 1, 1, + 1, 1, 1, 1, 51, 1, 16, 17, + 18, 19, 1, 21, 22, 22, 23, 24, + 25, 26, 27, 1, 16, 6, 6, 19, + 1, 1, 54, 54, 1, 24, 25, 1, + 27, 1, 16, 6, 6, 19, 1, 1, + 1, 1, 1, 24, 25, 1, 27, 1, + 16, 17, 18, 19, 1, 1, 1, 1, + 1, 1, 25, 1, 27, 1, 16, 17, + 18, 19, 1, 1, 1, 1, 1, 1, + 55, 1, 27, 1, 16, 17, 18, 19, + 1, 1, 1, 1, 1, 1, 1, 1, + 27, 1, 16, 17, 18, 19, 56, 57, + 1, 1, 23, 24, 25, 1, 27, 1, + 16, 17, 18, 19, 1, 57, 1, 1, + 23, 24, 25, 1, 27, 1, 16, 17, + 18, 19, 1, 1, 1, 1, 23, 24, + 25, 1, 27, 1, 16, 17, 18, 19, + 1, 58, 1, 1, 23, 24, 25, 1, + 27, 1, 16, 17, 18, 19, 1, 1, + 59, 59, 1, 24, 25, 1, 27, 1, + 16, 17, 18, 19, 1, 1, 1, 1, + 1, 24, 25, 1, 27, 1, 16, 6, + 6, 9, 1, 1, 54, 54, 1, 24, + 25, 1, 10, 1, 0 +}; + +static const char _indic_syllable_machine_trans_targs[] = { + 2, 0, 14, 22, 3, 7, 10, 9, + 11, 12, 20, 9, 10, 11, 12, 20, + 9, 10, 11, 12, 28, 29, 6, 34, + 31, 32, 37, 20, 40, 9, 10, 11, + 12, 13, 1, 5, 15, 17, 18, 20, + 16, 19, 9, 10, 11, 12, 21, 4, + 23, 25, 26, 20, 24, 27, 30, 33, + 35, 36, 38, 39 +}; + +static const char _indic_syllable_machine_trans_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 3, 3, 3, + 3, 0, 0, 0, 0, 0, 0, 3, + 0, 0, 4, 4, 4, 4, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +static const char _indic_syllable_machine_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 4, 4, 4, 4, + 4, 4, 4, 4, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2 +}; + +static const int indic_syllable_machine_start = 8; +static const int indic_syllable_machine_first_final = 8; +static const int indic_syllable_machine_error = 0; + +static const int indic_syllable_machine_en_main = 8; + + +#line 38 "hb-ot-shape-complex-indic-machine.rl" + + + +#line 83 "hb-ot-shape-complex-indic-machine.rl" + + + +static void +set_cluster (hb_buffer_t *buffer, + unsigned int start, unsigned int end) +{ + unsigned int cluster = buffer->info[start].cluster; + + for (unsigned int i = start + 1; i < end; i++) + cluster = MIN (cluster, buffer->info[i].cluster); + for (unsigned int i = start; i < end; i++) + buffer->info[i].cluster = cluster; +} + +static void +find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array) +{ + unsigned int p, pe, eof; + int cs; + +#line 194 "hb-ot-shape-complex-indic-machine.hh.tmp" + { + cs = indic_syllable_machine_start; + } + +#line 106 "hb-ot-shape-complex-indic-machine.rl" + + + p = 0; + pe = eof = buffer->len; + + unsigned int last = 0; + +#line 207 "hb-ot-shape-complex-indic-machine.hh.tmp" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _indic_syllable_machine_trans_keys + (cs<<1); + _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs]; + + _slen = _indic_syllable_machine_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=( buffer->info[p].indic_category()) && + ( buffer->info[p].indic_category()) <= _keys[1] ? + ( buffer->info[p].indic_category()) - _keys[0] : _slen ]; + + cs = _indic_syllable_machine_trans_targs[_trans]; + + if ( _indic_syllable_machine_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _indic_syllable_machine_trans_actions[_trans] ) { + case 2: +#line 62 "hb-ot-shape-complex-indic-machine.rl" + { found_consonant_syllable (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; + case 3: +#line 63 "hb-ot-shape-complex-indic-machine.rl" + { found_vowel_syllable (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; + case 4: +#line 64 "hb-ot-shape-complex-indic-machine.rl" + { found_standalone_cluster (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; + case 1: +#line 65 "hb-ot-shape-complex-indic-machine.rl" + { found_non_indic (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; +#line 256 "hb-ot-shape-complex-indic-machine.hh.tmp" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _indic_syllable_machine_eof_actions[cs] ) { + case 2: +#line 62 "hb-ot-shape-complex-indic-machine.rl" + { found_consonant_syllable (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; + case 3: +#line 63 "hb-ot-shape-complex-indic-machine.rl" + { found_vowel_syllable (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; + case 4: +#line 64 "hb-ot-shape-complex-indic-machine.rl" + { found_standalone_cluster (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; + case 1: +#line 65 "hb-ot-shape-complex-indic-machine.rl" + { found_non_indic (map, buffer, mask_array, last, p); } +#line 67 "hb-ot-shape-complex-indic-machine.rl" + { set_cluster (buffer, p, last); last = p; } + break; +#line 292 "hb-ot-shape-complex-indic-machine.hh.tmp" + } + } + + _out: {} + } + +#line 114 "hb-ot-shape-complex-indic-machine.rl" + +} + +HB_END_DECLS + +#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.rl b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.rl new file mode 100644 index 0000000..53dc20d --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.rl @@ -0,0 +1,119 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH +#define HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH + +#include "hb-private.hh" + +HB_BEGIN_DECLS + +%%{ + machine indic_syllable_machine; + alphtype unsigned char; + write data; +}%% + +%%{ + +# Same order as enum indic_category_t. Not sure how to avoid duplication. +X = 0; +C = 1; +Ra = 2; +V = 3; +N = 4; +H = 5; +ZWNJ = 6; +ZWJ = 7; +M = 8; +SM = 9; +VD = 10; +A = 11; +NBSP = 12; + +c = C | Ra; +z = ZWJ|ZWNJ; +matra_group = M N? H?; +syllable_tail = SM? (VD VD?)?; + +action found_consonant_syllable { found_consonant_syllable (map, buffer, mask_array, last, p); } +action found_vowel_syllable { found_vowel_syllable (map, buffer, mask_array, last, p); } +action found_standalone_cluster { found_standalone_cluster (map, buffer, mask_array, last, p); } +action found_non_indic { found_non_indic (map, buffer, mask_array, last, p); } + +action next_syllable { set_cluster (buffer, p, last); last = p; } + +consonant_syllable = (c.N? (z.H|H.z?))* c.N? A? (H.z? | matra_group*)? syllable_tail %(found_consonant_syllable); +vowel_syllable = (Ra H)? V N? (z.H.c | ZWJ.c)? matra_group* syllable_tail %(found_vowel_syllable); +standalone_cluster = (Ra H)? NBSP N? (z? H c)? matra_group* syllable_tail %(found_standalone_cluster); +non_indic = X %(found_non_indic); + +syllable = + consonant_syllable + | vowel_syllable + | standalone_cluster + | non_indic + ; + +main := (syllable %(next_syllable))**; + +}%% + + +static void +set_cluster (hb_buffer_t *buffer, + unsigned int start, unsigned int end) +{ + unsigned int cluster = buffer->info[start].cluster; + + for (unsigned int i = start + 1; i < end; i++) + cluster = MIN (cluster, buffer->info[i].cluster); + for (unsigned int i = start; i < end; i++) + buffer->info[i].cluster = cluster; +} + +static void +find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array) +{ + unsigned int p, pe, eof; + int cs; + %%{ + write init; + getkey buffer->info[p].indic_category(); + }%% + + p = 0; + pe = eof = buffer->len; + + unsigned int last = 0; + %%{ + write exec; + }%% +} + +HB_END_DECLS + +#endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.hh new file mode 100644 index 0000000..5077e8a --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.hh @@ -0,0 +1,830 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH +#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH + +#include "hb-private.hh" + + +/* == Start of generated table == */ +/* + * The following table is generated by running: + * + * ./gen-indic-table.py IndicSyllabicCategory.txt IndicMatraCategory.txt Blocks.txt + * + * on files with these headers: + * + * # IndicSyllabicCategory-6.0.0.txt + * # Date: 2010-05-25, 11:45:00 PDT [KW] + * # IndicMatraCategory-6.0.0.txt + * # Date: 2010-07-14, 15:03:00 PDT [KW] + * # Blocks-6.0.0.txt + * # Date: 2010-06-04, 11:12:00 PDT [KW] + */ + + +#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 9 chars; Avagraha */ +#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 31 chars; Bindu */ +#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 116 chars; Consonant */ +#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 2 chars; Consonant_Dead */ +#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 16 chars; Consonant_Final */ +#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 1 chars; Consonant_Head_Letter */ +#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 12 chars; Consonant_Medial */ +#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 4 chars; Consonant_Placeholder */ +#define ISC_CR INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA /* 5 chars; Consonant_Repha */ +#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 9 chars; Consonant_Subjoined */ +#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */ +#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 11 chars; Nukta */ +#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */ +#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 1 chars; Register_Shifter */ +#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 3 chars; Tone_Letter */ +#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 16 chars; Tone_Mark */ +#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 29 chars; Virama */ +#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 19 chars; Visarga */ +#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 5 chars; Vowel */ +#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 161 chars; Vowel_Dependent */ +#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 53 chars; Vowel_Independent */ + +#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 60 chars; Bottom */ +#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */ +#define IMC_I INDIC_MATRA_CATEGORY_INVISIBLE /* 4 chars; Invisible */ +#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 25 chars; Left */ +#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 8 chars; Left_And_Right */ +#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */ +#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 2 chars; Overstruck */ +#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 70 chars; Right */ +#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 74 chars; Top */ +#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 5 chars; Top_And_Bottom */ +#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */ +#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 4 chars; Top_And_Left */ +#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 2 chars; Top_And_Left_And_Right */ +#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 7 chars; Top_And_Right */ +#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 5 chars; Visual_Order_Left */ + +#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M) + + +static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = { + + +#define indic_offset_0x0900 0 + + + /* Devanagari (0900..097F) */ + + /* 0900 */ _(Bi,x), _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 0908 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 0910 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0920 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0928 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0938 */ _(C,x), _(C,x), _(M,T), _(M,R), _(N,x), _(A,x), _(M,R), _(M,L), + /* 0940 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), + /* 0948 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(M,L), _(M,R), + /* 0950 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(M,B), + /* 0958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0960 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0970 */ _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 0978 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + + /* Bengali (0980..09FF) */ + + /* 0980 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0988 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x), + /* 0990 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 09A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 09A8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 09B0 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), + /* 09B8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L), + /* 09C0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L), + /* 09C8 */ _(M,L), _(x,x), _(x,x), _(M,LR), _(M,LR), _(V,B), _(CD,x), _(x,x), + /* 09D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), + /* 09D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), + /* 09E0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 09E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 09F0 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 09F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Gurmukhi (0A00..0A7F) */ + + /* 0A00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0A08 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x), + /* 0A10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0A18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0A28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0A30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), + /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(x,x), _(M,R), _(M,L), + /* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), + /* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x), + /* 0A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), + /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0A68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0A70 */ _(Bi,x), _(x,x), _(CP,x), _(CP,x), _(x,x), _(CM,x), _(x,x), _(x,x), + /* 0A78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Gujarati (0A80..0AFF) */ + + /* 0A80 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0A88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), + /* 0A90 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0A98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0AA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0AA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0AB0 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), + /* 0AB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,L), + /* 0AC0 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(x,x), _(M,T), + /* 0AC8 */ _(M,T), _(M,TR), _(x,x), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), + /* 0AD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0AD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0AE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0AE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0AF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0AF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Oriya (0B00..0B7F) */ + + /* 0B00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(VI,x), + /* 0B10 */ _(VI,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0B28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0B30 */ _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), + /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T), + /* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L), + /* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x), + /* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,TR), + /* 0B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), + /* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0B70 */ _(x,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Tamil (0B80..0BFF) */ + + /* 0B80 */ _(x,x), _(x,x), _(Bi,x), _(ML,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0B88 */ _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(x,x), _(VI,x), _(VI,x), + /* 0B90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(x,x), _(x,x), + /* 0B98 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), _(C,x), + /* 0BA0 */ _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), + /* 0BA8 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), + /* 0BB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0BB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), + /* 0BC0 */ _(M,T), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(M,L), _(M,L), + /* 0BC8 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(x,x), _(x,x), + /* 0BD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), + /* 0BD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0BE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0BE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0BF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Telugu (0C00..0C7F) */ + + /* 0C00 */ _(x,x), _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0C08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), + /* 0C10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0C28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), + /* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(A,x), _(M,T), _(M,T), + /* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T), + /* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x), + /* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x), + /* 0C58 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0C68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0C78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Kannada (0C80..0CFF) */ + + /* 0C80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), + /* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0CA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0CA8 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0CB0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), + /* 0CB8 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,x), _(A,x), _(M,R), _(M,T), + /* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR), + /* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x), + /* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), + /* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x), + /* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0CF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Malayalam (0D00..0D7F) */ + + /* 0D00 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), + /* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0D20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0D28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0D38 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(A,x), _(M,R), _(M,R), + /* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L), + /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T), _(CR,x), _(x,x), + /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), + /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0D68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0D70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0D78 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), _(CD,x), + + /* Sinhala (0D80..0DFF) */ + + /* 0D80 */ _(x,x), _(x,x), _(Bi,x), _(Vs,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), + /* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0DA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0DA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0DB0 */ _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0DB8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), + /* 0DC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), + /* 0DC8 */ _(x,x), _(x,x), _(V,T), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), + /* 0DD0 */ _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), _(x,x), _(M,B), _(x,x), + /* 0DD8 */ _(M,R), _(M,L), _(M,TL), _(M,L), _(M,LR), _(M,LR), _(M,LR), _(M,R), + /* 0DE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0DE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0DF0 */ _(x,x), _(x,x), _(M,R), _(M,R), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0DF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Thai (0E00..0E7F) */ + + /* 0E00 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0E08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0E10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0E18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0E20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0E28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), + /* 0E30 */ _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T), _(M,T), + /* 0E38 */ _(M,B), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0E40 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL), _(M,R), _(x,x), _(M,T), + /* 0E48 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(Bi,x), _(V,T), _(x,x), + /* 0E50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0E58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0E60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0E68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0E70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0E78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Lao (0E80..0EFF) */ + + /* 0E80 */ _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(C,x), + /* 0E88 */ _(C,x), _(x,x), _(C,x), _(x,x), _(x,x), _(C,x), _(x,x), _(x,x), + /* 0E90 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0E98 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0EA0 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), _(C,x), + /* 0EA8 */ _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(x,x), + /* 0EB0 */ _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T), _(M,T), + /* 0EB8 */ _(M,B), _(M,B), _(x,x), _(M,T), _(CM,x), _(CM,x), _(x,x), _(x,x), + /* 0EC0 */_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL),_(M,VOL), _(x,x), _(x,x), _(x,x), + /* 0EC8 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(Bi,x), _(x,x), _(x,x), + /* 0ED0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0ED8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(x,x), + /* 0EE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0EE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0EF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0EF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Tibetan (0F00..0FFF) */ + + /* 0F00 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F10 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F18 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F20 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F28 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F30 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0F40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0F48 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0F50 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0F58 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0F60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 0F68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), + /* 0F70 */ _(x,x), _(M,B), _(M,T), _(M,TB), _(M,B), _(M,B), _(M,TB), _(M,TB), + /* 0F78 */ _(M,TB), _(M,TB), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(Vs,x), + /* 0F80 */ _(M,T), _(M,TB), _(Bi,x), _(Bi,x), _(V,B), _(A,x), _(x,x), _(x,x), + /* 0F88 */_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x),_(CHL,x), _(CS,x), _(CS,x), _(CS,x), + /* 0F90 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), + /* 0F98 */ _(x,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), + /* 0FA0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), + /* 0FA8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), + /* 0FB0 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), + /* 0FB8 */ _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x), + /* 0FC0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0FC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0FD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0FD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0FE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0FE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0FF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0FF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Myanmar (1000..109F) */ + + /* 1000 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1008 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1010 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), + /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,x), _(TM,x), + /* 1038 */ _(Vs,x), _(V,I), _(V,T), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(C,x), + /* 1040 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1048 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), + /* 1058 */ _(M,B), _(M,B), _(C,x), _(C,x), _(C,x), _(C,x), _(CM,x), _(CM,x), + /* 1060 */ _(CM,x), _(C,x), _(M,R), _(TM,x), _(TM,x), _(C,x), _(C,x), _(M,R), + /* 1068 */ _(M,R), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(C,x), + /* 1070 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(C,x), _(C,x), _(C,x), + /* 1078 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1080 */ _(C,x), _(C,x), _(CM,x), _(M,R), _(M,L), _(M,T), _(M,T), _(TM,x), + /* 1088 */ _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(TM,x), _(C,x), _(TM,x), + /* 1090 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1098 */ _(x,x), _(x,x), _(TM,x), _(TM,x), _(M,R), _(M,T), _(x,x), _(x,x), + +#define indic_offset_0x1700 1952 + + + /* Tagalog (1700..171F) */ + + /* 1700 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1708 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), + /* 1710 */ _(C,x), _(C,x), _(M,T), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x), + /* 1718 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Hanunoo (1720..173F) */ + + /* 1720 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1728 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1730 */ _(C,x), _(C,x), _(M,T), _(M,B), _(V,B), _(x,x), _(x,x), _(x,x), + /* 1738 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Buhid (1740..175F) */ + + /* 1740 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1748 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1750 */ _(C,x), _(C,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1758 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Tagbanwa (1760..177F) */ + + /* 1760 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1768 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), + /* 1770 */ _(C,x), _(x,x), _(M,T), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1778 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Khmer (1780..17FF) */ + + /* 1780 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1788 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1790 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1798 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 17A0 */ _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 17A8 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 17B0 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(x,x), _(M,R), _(M,T), + /* 17B8 */ _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,TL),_(M,TLR), + /* 17C0 */ _(M,LR), _(M,L), _(M,L), _(M,L), _(M,LR), _(M,LR), _(Bi,x), _(Vs,x), + /* 17C8 */ _(M,R), _(RS,x), _(RS,x), _(x,x), _(CR,x), _(x,x), _(x,x), _(x,x), + /* 17D0 */ _(x,x), _(V,T), _(V,I), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 17D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(A,x), _(x,x), _(x,x), _(x,x), + /* 17E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 17E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 17F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 17F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0x1900 2208 + + + /* Limbu (1900..194F) */ + + /* 1900 */ _(CP,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1908 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), + /* 1920 */ _(M,T), _(M,T), _(M,B), _(M,R), _(M,R), _(M,TR), _(M,TR), _(M,T), + /* 1928 */ _(M,T), _(CS,x), _(CS,x), _(CS,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1930 */ _(CF,x), _(CF,x), _(Bi,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), + /* 1938 */ _(CF,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1940 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1948 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Tai Le (1950..197F) */ + + /* 1950 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1958 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1960 */ _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), + /* 1968 */ _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(x,x), _(x,x), + /* 1970 */ _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(TL,x), _(x,x), _(x,x), _(x,x), + /* 1978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* New Tai Lue (1980..19DF) */ + + /* 1980 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1988 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 19A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 19A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 19B0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,L), _(M,L), _(M,L), + /* 19B8 */ _(M,R), _(M,R), _(M,L), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), + /* 19C0 */ _(M,R), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), + /* 19C8 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 19D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 19D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* FILLER (19E0..19FF) */ + + /* 19E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 19E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 19F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 19F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Buginese (1A00..1A1F) */ + + /* 1A00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1A08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), + /* 1A18 */ _(M,B), _(M,L), _(M,R), _(M,L), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Tai Tham (1A20..1AAF) */ + + /* 1A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1A38 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1A40 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1A48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), + /* 1A50 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(CM,x), _(CM,x), _(CF,x), + /* 1A58 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x), + /* 1A60 */ _(V,I), _(M,R), _(M,T), _(M,R), _(M,R), _(M,T), _(M,T), _(M,T), + /* 1A68 */ _(M,T), _(M,B), _(M,B), _(M,T), _(M,B), _(M,R), _(M,L), _(M,L), + /* 1A70 */ _(M,L), _(M,L), _(M,L), _(M,T), _(M,T), _(TM,x), _(TM,x), _(TM,x), + /* 1A78 */ _(TM,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1A80 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1A88 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1A90 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1A98 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1AA0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1AA8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0x1b00 2640 + + + /* Balinese (1B00..1B7F) */ + + /* 1B00 */ _(Bi,x), _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), + /* 1B08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 1B10 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1B18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1B20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1B28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1B30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,T), _(M,T), + /* 1B38 */ _(M,B), _(M,B), _(M,B), _(M,BR), _(M,TB),_(M,TBR), _(M,L), _(M,L), + /* 1B40 */ _(M,LR), _(M,LR), _(M,T), _(M,TR), _(V,R), _(C,x), _(C,x), _(C,x), + /* 1B48 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1B60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1B68 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1B70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1B78 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Sundanese (1B80..1BBF) */ + + /* 1B80 */ _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 1B88 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1B90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1B98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1BA0 */ _(C,x), _(CS,x), _(CS,x), _(CS,x), _(M,T), _(M,B), _(M,L), _(M,R), + /* 1BA8 */ _(M,T), _(M,T), _(V,R), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), + /* 1BB0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1BB8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Batak (1BC0..1BFF) */ + + /* 1BC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1BC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1BD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1BD8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1BE0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(N,x), _(M,x), + /* 1BE8 */ _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), _(M,x), + /* 1BF0 */ _(CF,x), _(CF,x), _(V,R), _(V,R), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1BF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Lepcha (1C00..1C4F) */ + + /* 1C00 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1C08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1C10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1C18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 1C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CS,x), _(CS,x), _(M,R), _(M,L), + /* 1C28 */ _(M,L), _(M,TL), _(M,R), _(M,R), _(M,B), _(CF,x), _(CF,x), _(CF,x), + /* 1C30 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(Bi,x), _(Bi,x), _(x,x), _(N,x), + /* 1C38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1C40 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1C48 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), + +#define indic_offset_0xa800 2976 + + + /* Syloti Nagri (A800..A82F) */ + + /* A800 */ _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(V,T), _(C,x), + /* A808 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A810 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A818 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A820 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,R), _(M,B), _(M,T), _(M,R), + /* A828 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* FILLER (A830..A83F) */ + + /* A830 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A838 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Phags-pa (A840..A87F) */ + + /* A840 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A848 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A850 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A858 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(Vo,x), + /* A860 */ _(Vo,x), _(Vo,x), _(C,x), _(C,x), _(C,x), _(C,x), _(Vo,x), _(CS,x), + /* A868 */ _(CS,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A870 */ _(C,x), _(CS,x), _(C,x), _(Bi,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A878 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Saurashtra (A880..A8DF) */ + + /* A880 */ _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* A888 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* A890 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A898 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A8A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A8A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A8B0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(M,R), _(M,R), _(M,R), + /* A8B8 */ _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), _(M,R), + /* A8C0 */ _(M,R), _(M,R), _(M,R), _(M,R), _(V,B), _(x,x), _(x,x), _(x,x), + /* A8C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A8D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A8D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* FILLER (A8E0..A8FF) */ + + /* A8E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A8E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A8F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A8F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Kayah Li (A900..A92F) */ + + /* A900 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A908 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A910 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A918 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A920 */ _(C,x), _(C,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), _(Vo,x), + /* A928 */ _(Vo,x), _(Vo,x), _(Vo,x), _(TM,x), _(TM,x), _(TM,x), _(x,x), _(x,x), + + /* Rejang (A930..A95F) */ + + /* A930 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A938 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A940 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,B), + /* A948 */ _(M,B), _(M,B), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), _(CF,x), + /* A950 */ _(CF,x), _(CF,x), _(CF,x), _(V,R), _(x,x), _(x,x), _(x,x), _(x,x), + /* A958 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* FILLER (A960..A97F) */ + + /* A960 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A968 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A970 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A978 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Javanese (A980..A9DF) */ + + /* A980 */ _(Bi,x), _(Bi,x), _(CR,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* A988 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), + /* A990 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A998 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A9A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A9A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* A9B0 */ _(C,x), _(C,x), _(C,x), _(N,x), _(M,R), _(M,R), _(M,T), _(M,T), + /* A9B8 */ _(M,B), _(M,B), _(M,L), _(M,L), _(M,T), _(CS,x), _(CM,x), _(CM,x), + /* A9C0 */ _(V,BR), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A9C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A9D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A9D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* FILLER (A9E0..A9FF) */ + + /* A9E0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A9E8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A9F0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* A9F8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Cham (AA00..AA5F) */ + + /* AA00 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), + /* AA08 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA28 */ _(C,x), _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,T), _(M,L), + /* AA30 */ _(M,L), _(M,T), _(M,B), _(CM,x), _(CM,x), _(CM,x), _(CM,x), _(x,x), + /* AA38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* AA40 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), + /* AA48 */ _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(x,x), _(x,x), + /* AA50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* AA58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Myanmar Extended-A (AA60..AA7F) */ + + /* AA60 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA68 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Tai Viet (AA80..AADF) */ + + /* AA80 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA88 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AA98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AAA0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AAA8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AAB0 */ _(M,T), _(M,R), _(M,T), _(M,T), _(M,B),_(M,VOL),_(M,VOL), _(M,T), + /* AAB8 */ _(M,T),_(M,VOL), _(M,R),_(M,VOL),_(M,VOL), _(M,R), _(M,T), _(TM,x), + /* AAC0 */ _(TL,x), _(TM,x), _(TL,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* AAC8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* AAD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* AAD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0xabc0 3712 + + + /* Meetei Mayek (ABC0..ABFF) */ + + /* ABC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* ABC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* ABD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* ABD8 */ _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), + /* ABE0 */ _(CF,x), _(CF,x), _(CF,x), _(M,R), _(M,R), _(M,T), _(M,R), _(M,R), + /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(V,B), _(x,x), _(x,x), + /* ABF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* ABF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0x10a00 3776 + + + /* Kharoshthi (10A00..10A5F) */ + + /* 10A00 */ _(C,x), _(M,O), _(M,B), _(M,B), _(x,x), _(M,T), _(M,O), _(x,x), + /* 10A08 */ _(x,x), _(x,x), _(x,x), _(x,x), _(M,B), _(x,x), _(Bi,x), _(Vs,x), + /* 10A10 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), + /* 10A18 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 10A20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 10A28 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 10A30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 10A38 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(V,I), + /* 10A40 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 10A48 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 10A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 10A58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0x11000 3872 + + + /* Brahmi (11000..1107F) */ + + /* 11000 */ _(Bi,x), _(Bi,x), _(Vs,x), _(x,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 11008 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 11010 */ _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11018 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11020 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11028 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11030 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11038 */ _(M,T), _(M,T), _(M,T), _(M,T), _(M,B), _(M,B), _(M,B), _(M,B), + /* 11040 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), + /* 11048 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11050 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11058 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11060 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11068 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11070 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11078 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + + /* Kaithi (11080..110CF) */ + + /* 11080 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 11088 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), + /* 11090 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11098 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 110A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 110A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 110B0 */ _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), _(M,T), _(M,T), _(M,R), + /* 110B8 */ _(M,R), _(V,B), _(N,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 110C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 110C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_total 4080 + +}; + +static INDIC_TABLE_ELEMENT_TYPE +get_indic_categories (hb_codepoint_t u) +{ + if (0x0900 <= u && u <= 0x10A0) return indic_table[u - 0x0900 + indic_offset_0x0900]; + if (0x1700 <= u && u <= 0x1800) return indic_table[u - 0x1700 + indic_offset_0x1700]; + if (0x1900 <= u && u <= 0x1AB0) return indic_table[u - 0x1900 + indic_offset_0x1900]; + if (0x1B00 <= u && u <= 0x1C50) return indic_table[u - 0x1B00 + indic_offset_0x1b00]; + if (0xA800 <= u && u <= 0xAAE0) return indic_table[u - 0xA800 + indic_offset_0xa800]; + if (0xABC0 <= u && u <= 0xAC00) return indic_table[u - 0xABC0 + indic_offset_0xabc0]; + if (0x10A00 <= u && u <= 0x10A60) return indic_table[u - 0x10A00 + indic_offset_0x10a00]; + if (0x11000 <= u && u <= 0x110D0) return indic_table[u - 0x11000 + indic_offset_0x11000]; + if (unlikely (u == 0x00A0)) return _(CP,x); + if (unlikely (u == 0x25CC)) return _(CP,x); + return _(x,x); +} + +#undef _ + +#undef ISC_A +#undef ISC_Bi +#undef ISC_C +#undef ISC_CD +#undef ISC_CF +#undef ISC_CHL +#undef ISC_CM +#undef ISC_CP +#undef ISC_CR +#undef ISC_CS +#undef ISC_ML +#undef ISC_N +#undef ISC_x +#undef ISC_RS +#undef ISC_TL +#undef ISC_TM +#undef ISC_V +#undef ISC_Vs +#undef ISC_Vo +#undef ISC_M +#undef ISC_VI + +#undef IMC_B +#undef IMC_BR +#undef IMC_I +#undef IMC_L +#undef IMC_LR +#undef IMC_x +#undef IMC_O +#undef IMC_R +#undef IMC_T +#undef IMC_TB +#undef IMC_TBR +#undef IMC_TL +#undef IMC_TLR +#undef IMC_TR +#undef IMC_VOL + + +/* == End of generated table == */ + + +#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc new file mode 100644 index 0000000..9f50ef2 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc @@ -0,0 +1,765 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-shape-complex-private.hh" + + + +/* buffer var allocations */ +#define indic_category() complex_var_persistent_u8_0() /* indic_category_t */ +#define indic_position() complex_var_persistent_u8_1() /* indic_matra_category_t */ + +#define INDIC_TABLE_ELEMENT_TYPE uint8_t + +/* Cateories used in the OpenType spec: + * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx + */ +/* Note: This enum is duplicated in the -machine.rl source file. + * Not sure how to avoid duplication. */ +enum indic_category_t { + OT_X = 0, + OT_C, + OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */ + OT_V, + OT_N, + OT_H, + OT_ZWNJ, + OT_ZWJ, + OT_M, + OT_SM, + OT_VD, + OT_A, + OT_NBSP +}; + +/* Visual positions in a syllable from left to right. */ +enum indic_position_t { + POS_PRE, + POS_BASE, + POS_ABOVE, + POS_BELOW, + POS_POST +}; + +/* Categories used in IndicSyllabicCategory.txt from UCD */ +/* The assignments are guesswork */ +enum indic_syllabic_category_t { + INDIC_SYLLABIC_CATEGORY_OTHER = OT_X, + + INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_X, + INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM, + INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP, + INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_C, + INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X, + INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N, + INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_X, + INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X, + INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_X, + INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H, + INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM, + INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V, + INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M, + INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V +}; + +/* Categories used in IndicSMatraCategory.txt from UCD */ +enum indic_matra_category_t { + INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_BASE, + + INDIC_MATRA_CATEGORY_LEFT = POS_PRE, + INDIC_MATRA_CATEGORY_TOP = POS_ABOVE, + INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW, + INDIC_MATRA_CATEGORY_RIGHT = POS_POST, + + /* We don't really care much about these since we decompose them + * in the generic pre-shaping layer. They will only be used if + * the font does not cover the decomposition. In which case, we + * define these as aliases to the place we want the split-matra + * glyph to show up. Quite arbitrary. */ + INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_BOTTOM, + INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_LEFT, + INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM, + INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_BOTTOM, + INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_LEFT, + INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_LEFT, + INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, + + INDIC_MATRA_CATEGORY_INVISIBLE = INDIC_MATRA_CATEGORY_NOT_APPLICABLE, + INDIC_MATRA_CATEGORY_OVERSTRUCK = INDIC_MATRA_CATEGORY_NOT_APPLICABLE, + INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = INDIC_MATRA_CATEGORY_NOT_APPLICABLE +}; + +/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation + * because gcc fails to optimize the latter and fills the table in at runtime. */ +#define INDIC_COMBINE_CATEGORIES(S,M) \ + (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \ + ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \ + ((M << 4) | S)) + +#include "hb-ot-shape-complex-indic-table.hh" + +/* XXX + * This is a hack for now. We should: + * 1. Move this data into the main Indic table, + * and/or + * 2. Probe font lookups to determine consonant positions. + */ +static const struct consonant_position_t { + hb_codepoint_t u; + indic_position_t position; +} consonant_positions[] = { + {0x0930, POS_BELOW}, + {0x09AC, POS_BELOW}, + {0x09AF, POS_POST}, + {0x09B0, POS_BELOW}, + {0x09F0, POS_BELOW}, + {0x0A2F, POS_POST}, + {0x0A30, POS_BELOW}, + {0x0A35, POS_BELOW}, + {0x0A39, POS_BELOW}, + {0x0AB0, POS_BELOW}, + {0x0B24, POS_BELOW}, + {0x0B28, POS_BELOW}, + {0x0B2C, POS_BELOW}, + {0x0B2D, POS_BELOW}, + {0x0B2E, POS_BELOW}, + {0x0B2F, POS_POST}, + {0x0B30, POS_BELOW}, + {0x0B32, POS_BELOW}, + {0x0B33, POS_BELOW}, + {0x0B5F, POS_POST}, + {0x0B71, POS_BELOW}, + {0x0C15, POS_BELOW}, + {0x0C16, POS_BELOW}, + {0x0C17, POS_BELOW}, + {0x0C18, POS_BELOW}, + {0x0C19, POS_BELOW}, + {0x0C1A, POS_BELOW}, + {0x0C1B, POS_BELOW}, + {0x0C1C, POS_BELOW}, + {0x0C1D, POS_BELOW}, + {0x0C1E, POS_BELOW}, + {0x0C1F, POS_BELOW}, + {0x0C20, POS_BELOW}, + {0x0C21, POS_BELOW}, + {0x0C22, POS_BELOW}, + {0x0C23, POS_BELOW}, + {0x0C24, POS_BELOW}, + {0x0C25, POS_BELOW}, + {0x0C26, POS_BELOW}, + {0x0C27, POS_BELOW}, + {0x0C28, POS_BELOW}, + {0x0C2A, POS_BELOW}, + {0x0C2B, POS_BELOW}, + {0x0C2C, POS_BELOW}, + {0x0C2D, POS_BELOW}, + {0x0C2E, POS_BELOW}, + {0x0C2F, POS_BELOW}, + {0x0C30, POS_BELOW}, + {0x0C32, POS_BELOW}, + {0x0C33, POS_BELOW}, + {0x0C35, POS_BELOW}, + {0x0C36, POS_BELOW}, + {0x0C37, POS_BELOW}, + {0x0C38, POS_BELOW}, + {0x0C39, POS_BELOW}, + {0x0C95, POS_BELOW}, + {0x0C96, POS_BELOW}, + {0x0C97, POS_BELOW}, + {0x0C98, POS_BELOW}, + {0x0C99, POS_BELOW}, + {0x0C9A, POS_BELOW}, + {0x0C9B, POS_BELOW}, + {0x0C9C, POS_BELOW}, + {0x0C9D, POS_BELOW}, + {0x0C9E, POS_BELOW}, + {0x0C9F, POS_BELOW}, + {0x0CA0, POS_BELOW}, + {0x0CA1, POS_BELOW}, + {0x0CA2, POS_BELOW}, + {0x0CA3, POS_BELOW}, + {0x0CA4, POS_BELOW}, + {0x0CA5, POS_BELOW}, + {0x0CA6, POS_BELOW}, + {0x0CA7, POS_BELOW}, + {0x0CA8, POS_BELOW}, + {0x0CAA, POS_BELOW}, + {0x0CAB, POS_BELOW}, + {0x0CAC, POS_BELOW}, + {0x0CAD, POS_BELOW}, + {0x0CAE, POS_BELOW}, + {0x0CAF, POS_BELOW}, + {0x0CB0, POS_BELOW}, + {0x0CB2, POS_BELOW}, + {0x0CB3, POS_BELOW}, + {0x0CB5, POS_BELOW}, + {0x0CB6, POS_BELOW}, + {0x0CB7, POS_BELOW}, + {0x0CB8, POS_BELOW}, + {0x0CB9, POS_BELOW}, + {0x0CDE, POS_BELOW}, + {0x0D2F, POS_POST}, + {0x0D30, POS_POST}, + {0x0D32, POS_BELOW}, + {0x0D35, POS_POST}, +}; + +/* XXX + * This is a hack for now. We should move this data into the main Indic table. + */ +static const hb_codepoint_t ra_chars[] = { + 0x0930, /* Devanagari */ + 0x09B0, /* Bengali */ + 0x09F0, /* Bengali */ +//0x09F1, /* Bengali */ +//0x0A30, /* Gurmukhi */ + 0x0AB0, /* Gujarati */ + 0x0B30, /* Oriya */ +//0x0BB0, /* Tamil */ +//0x0C30, /* Telugu */ + 0x0CB0, /* Kannada */ +//0x0D30, /* Malayalam */ +}; + +static int +compare_codepoint (const void *pa, const void *pb) +{ + hb_codepoint_t a = * (hb_codepoint_t *) pa; + hb_codepoint_t b = * (hb_codepoint_t *) pb; + + return a < b ? -1 : a == b ? 0 : +1; +} + +static indic_position_t +consonant_position (hb_codepoint_t u) +{ + consonant_position_t *record; + + record = (consonant_position_t *) bsearch (&u, consonant_positions, + ARRAY_LENGTH (consonant_positions), + sizeof (consonant_positions[0]), + compare_codepoint); + + return record ? record->position : POS_BASE; +} + +static bool +is_ra (hb_codepoint_t u) +{ + return !!bsearch (&u, ra_chars, + ARRAY_LENGTH (ra_chars), + sizeof (ra_chars[0]), + compare_codepoint); +} + +static bool +is_joiner (const hb_glyph_info_t &info) +{ + return !!(FLAG (info.indic_category()) & (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ))); +} + +static bool +is_consonant (const hb_glyph_info_t &info) +{ + return !!(FLAG (info.indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra))); +} + +static const struct { + hb_tag_t tag; + hb_bool_t is_global; +} indic_basic_features[] = +{ + {HB_TAG('n','u','k','t'), true}, + {HB_TAG('a','k','h','n'), false}, + {HB_TAG('r','p','h','f'), false}, + {HB_TAG('r','k','r','f'), false}, + {HB_TAG('p','r','e','f'), false}, + {HB_TAG('b','l','w','f'), false}, + {HB_TAG('h','a','l','f'), false}, + {HB_TAG('v','a','t','u'), true}, + {HB_TAG('p','s','t','f'), false}, + {HB_TAG('c','j','c','t'), false}, +}; + +/* Same order as the indic_basic_features array */ +enum { + _NUKT, + AKHN, + RPHF, + RKRF, + PREF, + BLWF, + HALF, + _VATU, + PSTF, + CJCT +}; + +static const hb_tag_t indic_other_features[] = +{ + HB_TAG('p','r','e','s'), + HB_TAG('a','b','v','s'), + HB_TAG('b','l','w','s'), + HB_TAG('p','s','t','s'), + HB_TAG('h','a','l','n'), + + HB_TAG('d','i','s','t'), + HB_TAG('a','b','v','m'), + HB_TAG('b','l','w','m'), +}; + + +static void +initial_reordering (const hb_ot_map_t *map, + hb_face_t *face, + hb_buffer_t *buffer, + void *user_data HB_UNUSED); +static void +final_reordering (const hb_ot_map_t *map, + hb_face_t *face, + hb_buffer_t *buffer, + void *user_data HB_UNUSED); + +void +_hb_ot_shape_complex_collect_features_indic (hb_ot_map_builder_t *map, const hb_segment_properties_t *props) +{ + map->add_bool_feature (HB_TAG('l','o','c','l')); + /* The Indic specs do not require ccmp, but we apply it here since if + * there is a use of it, it's typically at the beginning. */ + map->add_bool_feature (HB_TAG('c','c','m','p')); + + map->add_gsub_pause (initial_reordering, NULL); + + for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) + map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global); + + map->add_gsub_pause (final_reordering, NULL); + + for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++) + map->add_bool_feature (indic_other_features[i], true); +} + + +bool +_hb_ot_shape_complex_prefer_decomposed_indic (void) +{ + /* We want split matras decomposed by the common shaping logic. */ + return TRUE; +} + + +void +_hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map, hb_buffer_t *buffer) +{ + HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); + HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); + + /* We cannot setup masks here. We save information about characters + * and setup masks later on in a pause-callback. */ + + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + { + unsigned int type = get_indic_categories (buffer->info[i].codepoint); + + buffer->info[i].indic_category() = type & 0x0F; + buffer->info[i].indic_position() = type >> 4; + + if (buffer->info[i].indic_category() == OT_C) { + buffer->info[i].indic_position() = consonant_position (buffer->info[i].codepoint); + if (is_ra (buffer->info[i].codepoint)) + buffer->info[i].indic_category() = OT_Ra; + } else if (buffer->info[i].codepoint == 0x200C) + buffer->info[i].indic_category() = OT_ZWNJ; + else if (buffer->info[i].codepoint == 0x200D) + buffer->info[i].indic_category() = OT_ZWJ; + } +} + +static int +compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) +{ + int a = pa->indic_position(); + int b = pb->indic_position(); + + return a < b ? -1 : a == b ? 0 : +1; +} + +static void +found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, + unsigned int start, unsigned int end) +{ + unsigned int i; + hb_glyph_info_t *info = buffer->info; + + /* Comments from: + * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ + + /* 1. Find base consonant: + * + * The shaping engine finds the base consonant of the syllable, using the + * following algorithm: starting from the end of the syllable, move backwards + * until a consonant is found that does not have a below-base or post-base + * form (post-base forms have to follow below-base forms), or that is not a + * pre-base reordering Ra, or arrive at the first consonant. The consonant + * stopped at will be the base. + * + * o If the syllable starts with Ra + Halant (in a script that has Reph) + * and has more than one consonant, Ra is excluded from candidates for + * base consonants. + */ + + unsigned int base = end; + + /* -> starting from the end of the syllable, move backwards */ + i = end; + unsigned int limit = start; + if (info[start].indic_category() == OT_Ra && start + 2 <= end) { + limit += 2; + base = start; + }; + do { + i--; + /* -> until a consonant is found */ + if (is_consonant (info[i])) + { + /* -> that does not have a below-base or post-base form + * (post-base forms have to follow below-base forms), */ + if (info[i].indic_position() != POS_BELOW && + info[i].indic_position() != POS_POST) + { + base = i; + break; + } + + /* -> or that is not a pre-base reordering Ra, + * + * TODO + */ + + /* -> o If the syllable starts with Ra + Halant (in a script that has Reph) + * and has more than one consonant, Ra is excluded from candidates for + * base consonants. + * + * IMPLEMENTATION NOTES: + * + * We do this by adjusting limit accordingly before entering the loop. + */ + + /* -> or arrive at the first consonant. The consonant stopped at will + * be the base. */ + base = i; + } + else + if (is_joiner (info[i])) + break; + } while (i > limit); + if (base < start) + base = start; /* Just in case... */ + + + /* 2. Decompose and reorder Matras: + * + * Each matra and any syllable modifier sign in the cluster are moved to the + * appropriate position relative to the consonant(s) in the cluster. The + * shaping engine decomposes two- or three-part matras into their constituent + * parts before any repositioning. Matra characters are classified by which + * consonant in a conjunct they have affinity for and are reordered to the + * following positions: + * + * o Before first half form in the syllable + * o After subjoined consonants + * o After post-form consonant + * o After main consonant (for above marks) + * + * IMPLEMENTATION NOTES: + * + * The normalize() routine has already decomposed matras for us, so we don't + * need to worry about that. + */ + + + /* 3. Reorder marks to canonical order: + * + * Adjacent nukta and halant or nukta and vedic sign are always repositioned + * if necessary, so that the nukta is first. + * + * IMPLEMENTATION NOTES: + * + * We don't need to do this: the normalize() routine already did this for us. + */ + + + /* Reorder characters */ + + for (i = start; i < base; i++) + info[i].indic_position() = POS_PRE; + info[base].indic_position() = POS_BASE; + + + /* Handle beginning Ra */ + if (start + 3 <= end && + info[start].indic_category() == OT_Ra && + info[start + 1].indic_category() == OT_H && + !is_joiner (info[start + 2])) + { + info[start].indic_position() = POS_POST; + info[start].mask = mask_array[RPHF]; + } + + /* For old-style Indic script tags, move the first post-base Halant after + * last consonant. */ + if ((map->get_chosen_script (0) & 0x000000FF) != '2') { + /* We should only do this for Indic scripts which have a version two I guess. */ + for (i = base + 1; i < end; i++) + if (info[i].indic_category() == OT_H) { + unsigned int j; + for (j = end - 1; j > i; j--) + if ((FLAG (info[j].indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra)))) + break; + if (j > i) { + /* Move Halant to after last consonant. */ + hb_glyph_info_t t = info[i]; + memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0])); + info[j] = t; + } + break; + } + } + + /* Attach ZWJ, ZWNJ, nukta, and halant to previous char to move with them. */ + for (i = start + 1; i < end; i++) + if ((FLAG (info[i].indic_category()) & + (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H)))) + info[i].indic_position() = info[i - 1].indic_position(); + + /* We do bubble-sort, skip malicious clusters attempts */ + if (end - start > 20) + return; + + /* Sit tight, rock 'n roll! */ + hb_bubble_sort (info + start, end - start, compare_indic_order); + + /* Setup masks now */ + + { + hb_mask_t mask; + + /* Pre-base */ + mask = mask_array[HALF] | mask_array[AKHN] | mask_array[CJCT]; + for (i = start; i < base; i++) + info[i].mask |= mask; + /* Base */ + mask = mask_array[AKHN] | mask_array[CJCT]; + info[base].mask |= mask; + /* Post-base */ + mask = mask_array[BLWF] | mask_array[PSTF] | mask_array[CJCT]; + for (i = base + 1; i < end; i++) + info[i].mask |= mask; + } + + /* Apply ZWJ/ZWNJ effects */ + for (i = start + 1; i < end; i++) + if (is_joiner (info[i])) { + bool non_joiner = info[i].indic_category() == OT_ZWNJ; + unsigned int j = i; + + do { + j--; + + /* Reading the Unicode and OpenType specs, I think the following line + * is correct, but this is not what the test suite expects currently. + * The test suite has been drinking, not me... But disable while + * investigating. + */ + //info[j].mask &= !mask_array[CJCT]; + if (non_joiner) + info[j].mask &= !mask_array[HALF]; + + } while (j > start && !is_consonant (info[j])); + } +} + + +static void +found_vowel_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, + unsigned int start, unsigned int end) +{ + /* TODO + * Not clear to me how this should work. Do the matras move to before the + * independent vowel? No idea. + */ +} + +static void +found_standalone_cluster (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, + unsigned int start, unsigned int end) +{ + /* TODO + * Easiest thing to do here is to convert the NBSP to consonant and + * call found_consonant_syllable. + */ +} + +static void +found_non_indic (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, + unsigned int start, unsigned int end) +{ + /* Nothing to do right now. If we ever switch to using the output + * buffer in the reordering process, we'd need to next_glyph() here. */ +} + +#include "hb-ot-shape-complex-indic-machine.hh" + +static void +remove_joiners (hb_buffer_t *buffer) +{ + /* For now we remove joiners. However, Uniscbire seems to keep them + * and output a zero-width space glyph for them. It is not clear to + * me how that is supposed to interact with GSUB. */ + + buffer->clear_output (); + unsigned int count = buffer->len; + for (buffer->idx = 0; buffer->idx < count;) + if (unlikely (is_joiner (buffer->info[buffer->idx]))) + buffer->skip_glyph (); + else + buffer->next_glyph (); + + buffer->swap_buffers (); +} + +static void +initial_reordering (const hb_ot_map_t *map, + hb_face_t *face, + hb_buffer_t *buffer, + void *user_data HB_UNUSED) +{ + hb_mask_t mask_array[ARRAY_LENGTH (indic_basic_features)] = {0}; + unsigned int num_masks = ARRAY_LENGTH (indic_basic_features); + for (unsigned int i = 0; i < num_masks; i++) + mask_array[i] = map->get_1_mask (indic_basic_features[i].tag); + + find_syllables (map, buffer, mask_array); + + remove_joiners (buffer); +} + +static void +final_reordering (const hb_ot_map_t *map, + hb_face_t *face, + hb_buffer_t *buffer, + void *user_data HB_UNUSED) +{ + /* 4. Final reordering: + * + * After the localized forms and basic shaping forms GSUB features have been + * applied (see below), the shaping engine performs some final glyph + * reordering before applying all the remaining font features to the entire + * cluster. + * + * o Reorder matras: + * + * If a pre-base matra character had been reordered before applying basic + * features, the glyph can be moved closer to the main consonant based on + * whether half-forms had been formed. Actual position for the matra is + * defined as “after last standalone halant glyph, after initial matra + * position and before the main consonant”. If ZWJ or ZWNJ follow this + * halant, position is moved after it. + * + * o Reorder reph: + * + * Reph’s original position is always at the beginning of the syllable, + * (i.e. it is not reordered at the character reordering stage). However, + * it will be reordered according to the basic-forms shaping results. + * Possible positions for reph, depending on the script, are; after main, + * before post-base consonant forms, and after post-base consonant forms. + * + * 1. If reph should be positioned after post-base consonant forms, + * proceed to step 5. + * + * 2. If the reph repositioning class is not after post-base: target + * position is after the first explicit halant glyph between the + * first post-reph consonant and last main consonant. If ZWJ or ZWNJ + * are following this halant, position is moved after it. If such + * position is found, this is the target position. Otherwise, + * proceed to the next step. + * + * Note: in old-implementation fonts, where classifications were + * fixed in shaping engine, there was no case where reph position + * will be found on this step. + * + * 3. If reph should be repositioned after the main consonant: from the + * first consonant not ligated with main, or find the first + * consonant that is not a potential pre-base reordering Ra. + * + * + * 4. If reph should be positioned before post-base consonant, find + * first post-base classified consonant not ligated with main. If no + * consonant is found, the target position should be before the + * first matra, syllable modifier sign or vedic sign. + * + * 5. If no consonant is found in steps 3 or 4, move reph to a position + * immediately before the first post-base matra, syllable modifier + * sign or vedic sign that has a reordering class after the intended + * reph position. For example, if the reordering position for reph + * is post-main, it will skip above-base matras that also have a + * post-main position. + * + * 6. Otherwise, reorder reph to the end of the syllable. + * + * o Reorder pre-base reordering consonants: + * + * If a pre-base reordering consonant is found, reorder it according to + * the following rules: + * + * 1. Only reorder a glyph produced by substitution during application + * of the feature. (Note that a font may shape a Ra consonant with + * the feature generally but block it in certain contexts.) + * + * 2. Try to find a target position the same way as for pre-base matra. + * If it is found, reorder pre-base consonant glyph. + * + * 3. If position is not found, reorder immediately before main + * consonant. + */ + + /* TODO */ + + + + HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); + HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); +} + + + diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc new file mode 100644 index 0000000..230704f --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc @@ -0,0 +1,55 @@ +/* + * Copyright © 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" + + +/* TODO Add kana, hangul, and other small sahpers here */ + +/* When adding trivial shapers, eg. kana, hangul, etc, we can either + * add a full shaper enum value for them, or switch on the script in + * the default complex shaper. The former is faster, so I think that's + * what we would do, and hence the default complex shaper shall remain + * empty. + */ + +void +_hb_ot_shape_complex_collect_features_default (hb_ot_map_builder_t *map, const hb_segment_properties_t *props) +{ +} + +bool +_hb_ot_shape_complex_prefer_decomposed_default (void) +{ + return FALSE; +} + +void +_hb_ot_shape_complex_setup_masks_default (hb_ot_map_t *map, hb_buffer_t *buffer) +{ +} + + 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 index fed167d..8b775fb 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google, Inc. + * Copyright © 2010,2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -27,26 +27,114 @@ #ifndef HB_OT_SHAPE_COMPLEX_PRIVATE_HH #define HB_OT_SHAPE_COMPLEX_PRIVATE_HH -#include "hb-private.h" +#include "hb-private.hh" -#include "hb-ot-shape-private.hh" +#include "hb-ot-map-private.hh" -HB_BEGIN_DECLS +/* buffer var allocations, used during the entire shaping process */ +#define general_category() var1.u8[0] /* unicode general_category (hb_unicode_general_category_t) */ +#define combining_class() var1.u8[1] /* unicode combining_class (uint8_t) */ + +/* buffer var allocations, used by complex shapers */ +#define complex_var_persistent_u8_0() var2.u8[0] +#define complex_var_persistent_u8_1() var2.u8[1] +#define complex_var_persistent_u16() var2.u16[0] +#define complex_var_temporary_u8_0() var2.u8[2] +#define complex_var_temporary_u8_1() var2.u8[3] +#define complex_var_temporary_u16() var2.u16[1] + + +#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \ + HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \ + HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \ + HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ + /* ^--- Add new shapers here */ + +enum hb_ot_complex_shaper_t { +#define HB_COMPLEX_SHAPER_IMPLEMENT(name) hb_ot_complex_shaper_##name, + HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS + /* Just here to avoid enum trailing comma: */ + hb_ot_complex_shaper_generic = hb_ot_complex_shaper_default +#undef HB_COMPLEX_SHAPER_IMPLEMENT +}; + static inline hb_ot_complex_shaper_t hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) { - switch ((int) props->script) { + switch ((int) props->script) + { + default: + return hb_ot_complex_shaper_default; + case HB_SCRIPT_ARABIC: - case HB_SCRIPT_NKO: - case HB_SCRIPT_SYRIAC: case HB_SCRIPT_MANDAIC: case HB_SCRIPT_MONGOLIAN: + case HB_SCRIPT_NKO: + case HB_SCRIPT_SYRIAC: return hb_ot_complex_shaper_arabic; - default: - return hb_ot_complex_shaper_none; +#if 0 + /* Note: + * + * These disabled scripts are listed in ucd/IndicSyllabicCategory.txt, but according + * to Martin Hosken do not require complex shaping. + * + * TODO We currently keep data for these scripts in our indic table. Need to fix the + * generator to not do that. + */ + + /* Simple? */ + case HB_SCRIPT_BATAK: + case HB_SCRIPT_BRAHMI: + case HB_SCRIPT_HANUNOO: + case HB_SCRIPT_MEETEI_MAYEK: + case HB_SCRIPT_SAURASHTRA: + + /* Simple */ + case HB_SCRIPT_KAYAH_LI: + case HB_SCRIPT_LAO: + case HB_SCRIPT_LIMBU: + case HB_SCRIPT_PHAGS_PA: + case HB_SCRIPT_SYLOTI_NAGRI: + case HB_SCRIPT_TAGALOG: + case HB_SCRIPT_TAGBANWA: + case HB_SCRIPT_TAI_LE: + case HB_SCRIPT_TAI_VIET: + case HB_SCRIPT_THAI: + case HB_SCRIPT_TIBETAN: + + /* May need Indic treatment in the future? */ + case HB_SCRIPT_MYANMAR: +#endif + + case HB_SCRIPT_BALINESE: + case HB_SCRIPT_BENGALI: + case HB_SCRIPT_BUGINESE: + case HB_SCRIPT_BUHID: + case HB_SCRIPT_CHAM: + case HB_SCRIPT_DEVANAGARI: + case HB_SCRIPT_GUJARATI: + case HB_SCRIPT_GURMUKHI: + case HB_SCRIPT_JAVANESE: + case HB_SCRIPT_KAITHI: + case HB_SCRIPT_KANNADA: + case HB_SCRIPT_KHAROSHTHI: + case HB_SCRIPT_KHMER: + case HB_SCRIPT_LEPCHA: + case HB_SCRIPT_MALAYALAM: + case HB_SCRIPT_NEW_TAI_LUE: + case HB_SCRIPT_ORIYA: + case HB_SCRIPT_REJANG: + case HB_SCRIPT_SINHALA: + case HB_SCRIPT_SUNDANESE: + case HB_SCRIPT_TAI_THAM: + case HB_SCRIPT_TAMIL: + case HB_SCRIPT_TELUGU: + return hb_ot_complex_shaper_indic; + + /* ^--- Add new shapers here */ } } @@ -57,18 +145,53 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) * * Called during shape_plan(). * - * Shapers should use plan->map to add their features. + * Shapers should use map to add their features and callbacks. */ -HB_INTERNAL void _hb_ot_shape_complex_collect_features_arabic (hb_ot_shape_plan_t *plan, const hb_segment_properties_t *props); +typedef void hb_ot_shape_complex_collect_features_func_t (hb_ot_map_builder_t *map, const hb_segment_properties_t *props); +#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ + HB_INTERNAL hb_ot_shape_complex_collect_features_func_t _hb_ot_shape_complex_collect_features_##name; + HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS +#undef HB_COMPLEX_SHAPER_IMPLEMENT static inline void -hb_ot_shape_complex_collect_features (hb_ot_shape_plan_t *plan, +hb_ot_shape_complex_collect_features (hb_ot_complex_shaper_t shaper, + hb_ot_map_builder_t *map, 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; + switch (shaper) { + default: +#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ + case hb_ot_complex_shaper_##name: _hb_ot_shape_complex_collect_features_##name (map, props); return; + HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS +#undef HB_COMPLEX_SHAPER_IMPLEMENT + } +} + + +/* + * prefer_decomposed() + * + * Called during shape_execute(). + * + * Shapers should return TRUE if it prefers decomposed (NFD) input rather than precomposed (NFC). + */ + +typedef bool hb_ot_shape_complex_prefer_decomposed_func_t (void); +#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ + HB_INTERNAL hb_ot_shape_complex_prefer_decomposed_func_t _hb_ot_shape_complex_prefer_decomposed_##name; + HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS +#undef HB_COMPLEX_SHAPER_IMPLEMENT + +static inline bool +hb_ot_shape_complex_prefer_decomposed (hb_ot_complex_shaper_t shaper) +{ + switch (shaper) { + default: +#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ + case hb_ot_complex_shaper_##name: return _hb_ot_shape_complex_prefer_decomposed_##name (); + HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS +#undef HB_COMPLEX_SHAPER_IMPLEMENT } } @@ -77,21 +200,29 @@ hb_ot_shape_complex_collect_features (hb_ot_shape_plan_t *plan, * * Called during shape_execute(). * - * Shapers should use c->plan.map to get feature masks and set on buffer. + * Shapers should use 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); +typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer_t *buffer); +#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ + HB_INTERNAL hb_ot_shape_complex_setup_masks_func_t _hb_ot_shape_complex_setup_masks_##name; + HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS +#undef HB_COMPLEX_SHAPER_IMPLEMENT static inline void -hb_ot_shape_complex_setup_masks (hb_ot_shape_context_t *c) +hb_ot_shape_complex_setup_masks (hb_ot_complex_shaper_t shaper, + hb_ot_map_t *map, + hb_buffer_t *buffer) { - 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; + switch (shaper) { + default: +#define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ + case hb_ot_complex_shaper_##name: _hb_ot_shape_complex_setup_masks_##name (map, buffer); return; + HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS +#undef HB_COMPLEX_SHAPER_IMPLEMENT } } -HB_END_DECLS #endif /* HB_OT_SHAPE_COMPLEX_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc new file mode 100644 index 0000000..eb9f32a --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc @@ -0,0 +1,286 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-shape-private.hh" +#include "hb-ot-shape-complex-private.hh" + + +/* + * HIGHLEVEL DESIGN: + * + * This file exports one main function: _hb_ot_shape_normalize(). + * + * This function closely reflects the Unicode Normalization Algorithm, + * yet it's different. The shaper an either prefer decomposed (NFD) or + * composed (NFC). + * + * In general what happens is that: each grapheme is decomposed in a chain + * of 1:2 decompositions, marks reordered, and then recomposed if desired, + * so far it's like Unicode Normalization. However, the decomposition and + * recomposition only happens if the font supports the resulting characters. + * + * The goals are: + * + * - Try to render all canonically equivalent strings similarly. To really + * achieve this we have to always do the full decomposition and then + * selectively recompose from there. It's kinda too expensive though, so + * we skip some cases. For example, if composed is desired, we simply + * don't touch 1-character clusters that are supported by the font, even + * though their NFC may be different. + * + * - When a font has a precomposed character for a sequence but the 'ccmp' + * feature in the font is not adequate, use the precomposed character + * which typically has better mark positioning. + * + * - When a font does not support a combining mark, but supports it precomposed + * with previous base. This needs the itemizer to have this knowledge too. + * We need ot provide assistance to the itemizer. + * + * - When a font does not support a character but supports its decomposition, + * well, use the decomposition. + * + * - The Indic shaper requests decomposed output. This will handle splitting + * matra for the Indic shaper. + */ + +static void +output_glyph (hb_ot_shape_context_t *c, + hb_codepoint_t glyph) +{ + hb_buffer_t *buffer = c->buffer; + + buffer->output_glyph (glyph); + hb_glyph_info_set_unicode_props (&buffer->out_info[buffer->out_len - 1], buffer->unicode); +} + +static bool +decompose (hb_ot_shape_context_t *c, + bool shortest, + hb_codepoint_t ab) +{ + hb_codepoint_t a, b, glyph; + + if (!hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) || + (b && !hb_font_get_glyph (c->font, b, 0, &glyph))) + return FALSE; + + bool has_a = hb_font_get_glyph (c->font, a, 0, &glyph); + if (shortest && has_a) { + /* Output a and b */ + output_glyph (c, a); + if (b) + output_glyph (c, b); + return TRUE; + } + + if (decompose (c, shortest, a)) { + if (b) + output_glyph (c, b); + return TRUE; + } + + if (has_a) { + output_glyph (c, a); + if (b) + output_glyph (c, b); + return TRUE; + } + + return FALSE; +} + +static void +decompose_current_glyph (hb_ot_shape_context_t *c, + bool shortest) +{ + if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint)) + c->buffer->skip_glyph (); + else + c->buffer->next_glyph (); +} + +static void +decompose_single_char_cluster (hb_ot_shape_context_t *c, + bool will_recompose) +{ + hb_codepoint_t glyph; + + /* If recomposing and font supports this, we're good to go */ + if (will_recompose && hb_font_get_glyph (c->font, c->buffer->info[c->buffer->idx].codepoint, 0, &glyph)) { + c->buffer->next_glyph (); + return; + } + + decompose_current_glyph (c, will_recompose); +} + +static void +decompose_multi_char_cluster (hb_ot_shape_context_t *c, + unsigned int end) +{ + /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ + for (unsigned int i = c->buffer->idx; i < end; i++) + if (unlikely (is_variation_selector (c->buffer->info[i].codepoint))) { + while (c->buffer->idx < end) + c->buffer->next_glyph (); + return; + } + + while (c->buffer->idx < end) + decompose_current_glyph (c, FALSE); +} + +static int +compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) +{ + unsigned int a = pa->combining_class(); + unsigned int b = pb->combining_class(); + + return a < b ? -1 : a == b ? 0 : +1; +} + +void +_hb_ot_shape_normalize (hb_ot_shape_context_t *c) +{ + hb_buffer_t *buffer = c->buffer; + bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper); + bool has_multichar_clusters = FALSE; + unsigned int count; + + /* We do a fairly straightforward yet custom normalization process in three + * separate rounds: decompose, reorder, recompose (if desired). Currently + * this makes two buffer swaps. We can make it faster by moving the last + * two rounds into the inner loop for the first round, but it's more readable + * this way. */ + + + /* First round, decompose */ + + buffer->clear_output (); + count = buffer->len; + for (buffer->idx = 0; buffer->idx < count;) + { + unsigned int end; + for (end = buffer->idx + 1; end < count; end++) + if (buffer->info[buffer->idx].cluster != buffer->info[end].cluster) + break; + + if (buffer->idx + 1 == end) + decompose_single_char_cluster (c, recompose); + else { + decompose_multi_char_cluster (c, end); + has_multichar_clusters = TRUE; + } + } + buffer->swap_buffers (); + + + /* Technically speaking, two characters with ccc=0 may combine. But all + * those cases are in languages that the indic module handles (which expects + * decomposed), or in Hangul jamo, which again, we want decomposed anyway. + * So we don't bother combining across cluster boundaries. This is a huge + * performance saver if the compose() callback is slow. + * + * TODO: Am I right about Hangul? If I am, we should add a Hangul module + * that requests decomposed. If for Hangul we end up wanting composed, we + * can do that in the Hangul module. + */ + + if (!has_multichar_clusters) + return; /* Done! */ + + + /* Second round, reorder (inplace) */ + + count = buffer->len; + for (unsigned int i = 0; i < count; i++) + { + if (buffer->info[i].combining_class() == 0) + continue; + + unsigned int end; + for (end = i + 1; end < count; end++) + if (buffer->info[end].combining_class() == 0) + break; + + /* We are going to do a bubble-sort. Only do this if the + * sequence is short. Doing it on long sequences can result + * in an O(n^2) DoS. */ + if (end - i > 10) { + i = end; + continue; + } + + hb_bubble_sort (buffer->info + i, end - i, compare_combining_class); + + i = end; + } + + + if (!recompose) + return; + + /* Third round, recompose */ + + /* As noted in the comment earlier, we don't try to combine + * ccc=0 chars with their previous Starter. */ + + buffer->clear_output (); + count = buffer->len; + unsigned int starter = 0; + buffer->next_glyph (); + while (buffer->idx < count) + { + if (buffer->info[buffer->idx].combining_class() == 0) { + starter = buffer->out_len; + buffer->next_glyph (); + continue; + } + + hb_codepoint_t composed, glyph; + if ((buffer->out_info[buffer->out_len - 1].combining_class() >= + buffer->info[buffer->idx].combining_class()) || + !hb_unicode_compose (c->buffer->unicode, + buffer->out_info[starter].codepoint, + buffer->info[buffer->idx].codepoint, + &composed) || + !hb_font_get_glyph (c->font, composed, 0, &glyph)) + { + /* Blocked, or doesn't compose. */ + buffer->next_glyph (); + continue; + } + + /* Composes. Modify starter and carry on. */ + buffer->out_info[starter].codepoint = composed; + hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode); + + buffer->skip_glyph (); + } + buffer->swap_buffers (); + +} + diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh index deaec97..c49c2b0 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Google, Inc. + * Copyright © 2010 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -27,30 +27,49 @@ #ifndef HB_OT_SHAPE_PRIVATE_HH #define HB_OT_SHAPE_PRIVATE_HH -#include "hb-private.h" +#include "hb-private.hh" #include "hb-ot-shape.h" #include "hb-ot-map-private.hh" +#include "hb-ot-shape-complex-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; +struct hb_ot_shape_plan_t +{ + friend struct hb_ot_shape_planner_t; -enum hb_ot_complex_shaper_t { - hb_ot_complex_shaper_none, - hb_ot_complex_shaper_arabic -}; + hb_ot_map_t map; + hb_ot_complex_shaper_t shaper; + hb_ot_shape_plan_t (void) : map () {} + ~hb_ot_shape_plan_t (void) { map.finish (); } -struct hb_ot_shape_plan_t + private: + NO_COPY (hb_ot_shape_plan_t); +}; + +struct hb_ot_shape_planner_t { - hb_ot_map_t map; + hb_ot_map_builder_t map; hb_ot_complex_shaper_t shaper; + + hb_ot_shape_planner_t (void) : map () {} + ~hb_ot_shape_planner_t (void) { map.finish (); } + + inline void compile (hb_face_t *face, + const hb_segment_properties_t *props, + struct hb_ot_shape_plan_t &plan) + { + plan.shaper = shaper; + map.compile (face, props, plan.map); + } + + private: + NO_COPY (hb_ot_shape_planner_t); }; @@ -71,6 +90,40 @@ struct hb_ot_shape_context_t }; -HB_END_DECLS +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 inline unsigned int +_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode) +{ + int c = hb_unicode_combining_class (ufuncs, unicode); + + /* Modify the combining-class to suit Arabic better. See: + * http://unicode.org/faq/normalization.html#8 + * http://unicode.org/faq/normalization.html#9 + */ + if (unlikely (hb_in_range<int> (c, 27, 33))) + c = c == 33 ? 27 : c + 1; + + return c; +} + +static inline void +hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode) +{ + info->general_category() = hb_unicode_general_category (unicode, info->codepoint); + info->combining_class() = _hb_unicode_modified_combining_class (unicode, info->codepoint); +} + +HB_INTERNAL void _hb_set_unicode_props (hb_buffer_t *buffer); + +HB_INTERNAL void _hb_ot_shape_normalize (hb_ot_shape_context_t *c); + #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 index 92c3925..4275afc 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape.cc @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009,2010 Red Hat, Inc. - * Copyright (C) 2010 Google, Inc. + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2010,2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -29,53 +29,81 @@ #include "hb-ot-shape-private.hh" #include "hb-ot-shape-complex-private.hh" -HB_BEGIN_DECLS +#include "hb-font-private.hh" -/* XXX vertical */ -hb_tag_t default_features[] = { - HB_TAG('c','a','l','t'), + +hb_tag_t common_features[] = { HB_TAG('c','c','m','p'), + HB_TAG('l','o','c','l'), + HB_TAG('m','a','r','k'), + HB_TAG('m','k','m','k'), + HB_TAG('r','l','i','g'), +}; + +hb_tag_t horizontal_features[] = { + HB_TAG('c','a','l','t'), 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') +}; + +/* Note: + * Technically speaking, vrt2 and vert are mutually exclusive. + * According to the spec, valt and vpal are also mutually exclusive. + * But we apply them all for now. + */ +hb_tag_t vertical_features[] = { + HB_TAG('v','a','l','t'), + HB_TAG('v','e','r','t'), + HB_TAG('v','k','r','n'), + HB_TAG('v','p','a','l'), + HB_TAG('v','r','t','2'), }; static void -hb_ot_shape_collect_features (hb_ot_shape_plan_t *plan, +hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, const hb_segment_properties_t *props, - const hb_feature_t *user_features, - unsigned int num_user_features) + 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')); + planner->map.add_bool_feature (HB_TAG ('l','t','r','a')); + planner->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); + planner->map.add_bool_feature (HB_TAG ('r','t','l','a')); + planner->map.add_bool_feature (HB_TAG ('r','t','l','m'), false); break; case HB_DIRECTION_TTB: case HB_DIRECTION_BTT: + case HB_DIRECTION_INVALID: default: break; } - for (unsigned int i = 0; i < ARRAY_LENGTH (default_features); i++) - plan->map.add_bool_feature (default_features[i]); +#define ADD_FEATURES(array) \ + HB_STMT_START { \ + for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \ + planner->map.add_bool_feature (array[i]); \ + } HB_STMT_END + + hb_ot_shape_complex_collect_features (planner->shaper, &planner->map, props); + + ADD_FEATURES (common_features); + + if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) + ADD_FEATURES (horizontal_features); + else + ADD_FEATURES (vertical_features); - hb_ot_shape_complex_collect_features (plan, props); +#undef ADD_FEATURES 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)); + planner->map.add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1)); } } @@ -86,7 +114,7 @@ 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 */ + hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer); for (unsigned int i = 0; i < c->num_user_features; i++) { @@ -100,98 +128,54 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) } -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) +void +_hb_set_unicode_props (hb_buffer_t *buffer) { - 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); - } + unsigned int count = buffer->len; + for (unsigned int i = 1; i < count; i++) + hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); } static void -hb_form_clusters (hb_ot_shape_context_t *c) +hb_form_clusters (hb_buffer_t *buffer) { - unsigned int count = c->buffer->len; + unsigned int count = 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; + if (FLAG (buffer->info[i].general_category()) & + (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))) + buffer->info[i].cluster = buffer->info[i - 1].cluster; } static void -hb_ensure_native_direction (hb_ot_shape_context_t *c) +hb_ensure_native_direction (hb_buffer_t *buffer) { - 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_direction_t direction = buffer->props.direction; + + /* TODO vertical: + * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType + * Ogham fonts are supposed to be implemented BTT or not. Need to research that + * first. */ + if ((HB_DIRECTION_IS_HORIZONTAL (direction) && direction != hb_script_get_horizontal_direction (buffer->props.script)) || + (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) { - hb_buffer_reverse_clusters (c->buffer); - c->buffer->props.direction = HB_DIRECTION_REVERSE (c->buffer->props.direction); + hb_buffer_reverse_clusters (buffer); + buffer->props.direction = HB_DIRECTION_REVERSE (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; + hb_unicode_funcs_t *unicode = c->buffer->unicode; if (HB_DIRECTION_IS_FORWARD (c->target_direction)) return; @@ -200,7 +184,7 @@ hb_mirror_chars (hb_ot_shape_context_t *c) 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); + hb_codepoint_t codepoint = hb_unicode_mirroring (unicode, 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 @@ -210,31 +194,54 @@ hb_mirror_chars (hb_ot_shape_context_t *c) static void hb_map_glyphs (hb_font_t *font, - hb_face_t *face, hb_buffer_t *buffer) { + hb_codepoint_t glyph; + 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++; + for (buffer->idx = 0; buffer->idx < count;) { + if (unlikely (is_variation_selector (buffer->info[buffer->idx + 1].codepoint))) { + hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, buffer->info[buffer->idx + 1].codepoint, &glyph); + buffer->replace_glyph (glyph); + buffer->skip_glyph (); } else { - buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0)); + hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph); + buffer->replace_glyph (glyph); } } - if (likely (buffer->i < buffer->len)) - buffer->replace_glyph (hb_font_get_glyph (font, face, buffer->info[buffer->i].codepoint, 0)); - buffer->swap (); + if (likely (buffer->idx < buffer->len)) { + hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph); + buffer->replace_glyph (glyph); + } + buffer->swap_buffers (); } static void hb_substitute_default (hb_ot_shape_context_t *c) { - hb_map_glyphs (c->font, c->face, c->buffer); + hb_ot_layout_substitute_start (c->buffer); + + hb_mirror_chars (c); + + hb_map_glyphs (c->font, c->buffer); +} + +static void +hb_ot_substitute_complex (hb_ot_shape_context_t *c) +{ + if (hb_ot_layout_has_substitution (c->face)) { + c->plan->map.substitute (c->face, c->buffer); + c->applied_substitute_complex = TRUE; + } + + hb_ot_layout_substitute_finish (c->buffer); + + return; } static void @@ -249,14 +256,52 @@ hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) static void hb_position_default (hb_ot_shape_context_t *c) { - hb_buffer_clear_positions (c->buffer); + hb_ot_layout_position_start (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); + hb_font_get_glyph_advance_for_direction (c->font, c->buffer->info[i].codepoint, + c->buffer->props.direction, + &c->buffer->pos[i].x_advance, + &c->buffer->pos[i].y_advance); + hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint, + c->buffer->props.direction, + &c->buffer->pos[i].x_offset, + &c->buffer->pos[i].y_offset); + } +} + +static void +hb_ot_position_complex (hb_ot_shape_context_t *c) +{ + + if (hb_ot_layout_has_positioning (c->face)) + { + /* Change glyph origin to what GPOS expects, apply GPOS, change it back. */ + + unsigned int count = c->buffer->len; + for (unsigned int i = 0; i < count; i++) { + hb_font_add_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint, + HB_DIRECTION_LTR, + &c->buffer->pos[i].x_offset, + &c->buffer->pos[i].y_offset); + } + + c->plan->map.position (c->font, c->buffer); + + for (unsigned int i = 0; i < count; i++) { + hb_font_subtract_glyph_origin_for_direction (c->font, c->buffer->info[i].codepoint, + HB_DIRECTION_LTR, + &c->buffer->pos[i].x_offset, + &c->buffer->pos[i].y_offset); + } + + c->applied_position_complex = TRUE; } + + hb_ot_layout_position_finish (c->buffer); + + return; } static void @@ -271,13 +316,23 @@ 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; + hb_position_t x_kern, y_kern, kern1, kern2; + hb_font_get_glyph_kerning_for_direction (c->font, + c->buffer->info[i - 1].codepoint, c->buffer->info[i].codepoint, + c->buffer->props.direction, + &x_kern, &y_kern); + + kern1 = x_kern >> 1; + kern2 = x_kern - kern1; c->buffer->pos[i - 1].x_advance += kern1; c->buffer->pos[i].x_advance += kern2; c->buffer->pos[i].x_offset += kern2; + + kern1 = y_kern >> 1; + kern2 = y_kern - kern1; + c->buffer->pos[i - 1].y_advance += kern1; + c->buffer->pos[i].y_advance += kern2; + c->buffer->pos[i].y_offset += kern2; } } @@ -293,24 +348,26 @@ hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) static void hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) { + c->buffer->deallocate_var_all (); + /* 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_BUFFER_ALLOCATE_VAR (c->buffer, general_category); + HB_BUFFER_ALLOCATE_VAR (c->buffer, combining_class); - hb_set_unicode_props (c); /* BUFFER: Set general_category and combining_class in var1 */ + _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class */ - hb_ensure_native_direction (c); + hb_form_clusters (c->buffer); - hb_form_clusters (c); + hb_ensure_native_direction (c->buffer); - hb_ot_shape_setup_masks (c); /* BUFFER: Clobbers var2 */ + _hb_ot_shape_normalize (c); + + hb_ot_shape_setup_masks (c); /* SUBSTITUTE */ { - /* Mirroring needs to see the original direction */ - hb_mirror_chars (c); - hb_substitute_default (c); hb_ot_substitute_complex (c); @@ -336,47 +393,56 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) hb_position_complex_fallback_visual (c); } + HB_BUFFER_DEALLOCATE_VAR (c->buffer, combining_class); + HB_BUFFER_DEALLOCATE_VAR (c->buffer, general_category); + c->buffer->props.direction = c->target_direction; + + c->buffer->deallocate_var_all (); } -void +static 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_planner_t planner; - hb_ot_shape_collect_features (plan, props, user_features, num_user_features); + planner.shaper = hb_ot_shape_complex_categorize (props); - plan->map.compile (face, props); + hb_ot_shape_collect_features (&planner, props, user_features, num_user_features); + + planner.compile (face, props, *plan); } -void +static 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_context_t c = {plan, font, 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_bool_t +hb_ot_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options) { 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); + buffer->guess_properties (); + + hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features); + hb_ot_shape_execute (&plan, font, buffer, features, num_features); + + return TRUE; } -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 index c90e0fe..1897e84 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape.h +++ b/third_party/harfbuzz-ng/src/hb-ot-shape.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Red Hat, Inc. + * Copyright © 2010 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -27,18 +27,19 @@ #ifndef HB_OT_SHAPE_H #define HB_OT_SHAPE_H +#include "hb-common.h" #include "hb-shape.h" HB_BEGIN_DECLS -void +hb_bool_t 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); + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-tag.c b/third_party/harfbuzz-ng/src/hb-ot-tag.cc index f3e0f1f..ac60e96 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-tag.c +++ b/third_party/harfbuzz-ng/src/hb-ot-tag.cc @@ -1,5 +1,6 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,157 +23,135 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ -#include "hb-private.h" +#include "hb-private.hh" #include "hb-ot.h" #include <string.h> -HB_BEGIN_DECLS +/* hb_script_t */ + +static hb_tag_t +hb_ot_old_tag_from_script (hb_script_t script) +{ + switch ((hb_tag_t) script) { + case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT; + + /* KATAKANA and HIRAGANA both map to 'kana' */ + case HB_SCRIPT_HIRAGANA: return HB_TAG('k','a','n','a'); + + /* Spaces at the end are preserved, unlike ISO 15924 */ + case HB_SCRIPT_LAO: return HB_TAG('l','a','o',' '); + case HB_SCRIPT_YI: return HB_TAG('y','i',' ',' '); + /* Unicode-5.0 additions */ + case HB_SCRIPT_NKO: return HB_TAG('n','k','o',' '); + /* Unicode-5.1 additions */ + case HB_SCRIPT_VAI: return HB_TAG('v','a','i',' '); + /* Unicode-5.2 additions */ + /* Unicode-6.0 additions */ + } + + /* Else, just change first char to lowercase and return */ + return ((hb_tag_t) script) | 0x20000000; +} + +static hb_script_t +hb_ot_old_tag_to_script (hb_tag_t tag) +{ + if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT)) + return HB_SCRIPT_INVALID; + + /* This side of the conversion is fully algorithmic. */ + + /* Any spaces at the end of the tag are replaced by repeating the last + * letter. Eg 'nko ' -> 'Nkoo' */ + if (unlikely ((tag & 0x0000FF00) == 0x00002000)) + tag |= (tag >> 8) & 0x0000FF00; /* Copy second letter to third */ + if (unlikely ((tag & 0x000000FF) == 0x00000020)) + tag |= (tag >> 8) & 0x000000FF; /* Copy third letter to fourth */ + + /* Change first char to uppercase and return */ + return (hb_script_t) (tag & ~0x20000000); +} + +static hb_tag_t +hb_ot_new_tag_from_script (hb_script_t script) +{ + switch ((hb_tag_t) script) { + case HB_SCRIPT_BENGALI: return HB_TAG('b','n','g','2'); + case HB_SCRIPT_DEVANAGARI: return HB_TAG('d','e','v','2'); + case HB_SCRIPT_GUJARATI: return HB_TAG('g','j','r','2'); + case HB_SCRIPT_GURMUKHI: return HB_TAG('g','u','r','2'); + case HB_SCRIPT_KANNADA: return HB_TAG('k','n','d','2'); + case HB_SCRIPT_MALAYALAM: return HB_TAG('m','l','m','2'); + case HB_SCRIPT_ORIYA: return HB_TAG('o','r','y','2'); + case HB_SCRIPT_TAMIL: return HB_TAG('t','m','l','2'); + case HB_SCRIPT_TELUGU: return HB_TAG('t','e','l','2'); + } + + return HB_OT_TAG_DEFAULT_SCRIPT; +} + +static hb_script_t +hb_ot_new_tag_to_script (hb_tag_t tag) +{ + switch (tag) { + case HB_TAG('b','n','g','2'): return HB_SCRIPT_BENGALI; + case HB_TAG('d','e','v','2'): return HB_SCRIPT_DEVANAGARI; + case HB_TAG('g','j','r','2'): return HB_SCRIPT_GUJARATI; + case HB_TAG('g','u','r','2'): return HB_SCRIPT_GURMUKHI; + case HB_TAG('k','n','d','2'): return HB_SCRIPT_KANNADA; + case HB_TAG('m','l','m','2'): return HB_SCRIPT_MALAYALAM; + case HB_TAG('o','r','y','2'): return HB_SCRIPT_ORIYA; + case HB_TAG('t','m','l','2'): return HB_SCRIPT_TAMIL; + case HB_TAG('t','e','l','2'): return HB_SCRIPT_TELUGU; + } + + return HB_SCRIPT_UNKNOWN; +} + /* * Complete list at: - * http://www.microsoft.com/typography/otspec/scripttags.htm + * https://www.microsoft.com/typography/otspec/scripttags.htm + * https://www.microsoft.com/typography/otspec160/scripttagsProposed.htm + * + * Most of the script tags are the same as the ISO 15924 tag but lowercased. + * So we just do that, and handle the exceptional cases in a switch. */ -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) +void +hb_ot_tags_from_script (hb_script_t script, + hb_tag_t *script_tag_1, + hb_tag_t *script_tag_2) { - static const hb_tag_t def_tag[] = {HB_OT_TAG_DEFAULT_SCRIPT, HB_TAG_NONE}; + hb_tag_t new_tag; - if (unlikely ((unsigned int) script >= ARRAY_LENGTH (ot_scripts))) - return def_tag; + *script_tag_2 = HB_OT_TAG_DEFAULT_SCRIPT; + *script_tag_1 = hb_ot_old_tag_from_script (script); - return ot_scripts[script]; + new_tag = hb_ot_new_tag_from_script (script); + if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) { + *script_tag_2 = *script_tag_1; + *script_tag_1 = new_tag; + } } hb_script_t hb_ot_tag_to_script (hb_tag_t tag) { - int i; + if (unlikely ((tag & 0x000000FF) == '2')) + return hb_ot_new_tag_to_script (tag); - 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; + return hb_ot_old_tag_to_script (tag); } + +/* hb_language_t */ + typedef struct { char language[6]; hb_tag_t tag; @@ -189,6 +168,7 @@ typedef struct { * 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 */ @@ -475,11 +455,6 @@ static const LangTag ot_languages[] = { {"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 */ @@ -595,6 +570,14 @@ static const LangTag ot_languages[] = { /*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ }; +static const LangTag ot_languages_zh[] = { + {"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) */ +}; + static int lang_compare_first_component (const char *a, const char *b) @@ -602,10 +585,10 @@ lang_compare_first_component (const char *a, unsigned int da, db; const char *p; - p = strstr (a, "-"); + p = strchr (a, '-'); da = p ? (unsigned int) (p - a) : strlen (a); - p = strstr (b, "-"); + p = strchr (b, '-'); db = p ? (unsigned int) (p - b) : strlen (b); return strncmp (a, b, MAX (da, db)); @@ -616,67 +599,65 @@ lang_matches (const char *lang_str, const char *spec) { unsigned int len = strlen (spec); - return lang_str && strncmp (lang_str, spec, len) == 0 && + return 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; + const char *lang_str, *s; + const LangTag *lang_tag; - if (language == NULL) + if (language == HB_LANGUAGE_INVALID) return HB_OT_TAG_DEFAULT_LANGUAGE; lang_str = hb_language_to_string (language); - if (0 == strcmp (lang_str, "x-hbot")) { + s = strstr (lang_str, "x-hbot"); + if (s) { 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); + s += 6; + for (i = 0; i < 4 && ISALPHA (s[i]); i++) + tag[i] = TOUPPER (s[i]); + if (i) { + for (; i < 4; i++) + tag[i] = ' '; + return HB_TAG_CHAR4 (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 */ + /* Find a language matching in the first component */ + lang_tag = (LangTag *) bsearch (lang_str, ot_languages, + ARRAY_LENGTH (ot_languages), sizeof (LangTag), + (hb_compare_func_t) lang_compare_first_component); if (lang_tag) - { - hb_bool_t found = FALSE; + return lang_tag->tag; - /* 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++; + /* Otherwise, check the Chinese ones */ + if (0 == lang_compare_first_component (lang_str, "zh")) + { + unsigned int i; - /* go back, find which one matches completely */ - while (lang_tag >= ot_languages && - lang_compare_first_component (lang_str, lang_tag->language) == 0) + for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++) { - if (lang_matches (lang_str, lang_tag->language)) { - found = TRUE; - break; - } - - lang_tag--; + lang_tag = &ot_languages_zh[i]; + if (lang_matches (lang_tag->language, lang_str)) + return lang_tag->tag; } - if (!found) - lang_tag = NULL; + /* Otherwise just return 'ZHS ' */ + return HB_TAG('Z','H','S',' '); } - if (lang_tag) - return lang_tag->tag; + s = strchr (lang_str, '-'); + if (!s) + s = lang_str + strlen (lang_str); + if (s - lang_str == 3) { + /* Assume it's ISO-639-3 and upper-case and use it. */ + return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000; + } return HB_OT_TAG_DEFAULT_LANGUAGE; } @@ -685,19 +666,45 @@ hb_language_t hb_ot_tag_to_language (hb_tag_t tag) { unsigned int i; - unsigned char buf[11] = "x-hbot"; + + if (tag == HB_OT_TAG_DEFAULT_LANGUAGE) + return NULL; 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); + return hb_language_from_string (ot_languages[i].language, -1); + + /* If tag starts with ZH, it's Chinese */ + if ((tag & 0xFFFF0000) == 0x5A480000) { + switch (tag) { + case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1); /* Hong Kong */ + default: { + /* Encode the tag... */ + unsigned char buf[14] = "zh-x-hbot"; + buf[9] = tag >> 24; + buf[10] = (tag >> 16) & 0xFF; + buf[11] = (tag >> 8) & 0xFF; + buf[12] = tag & 0xFF; + if (buf[12] == 0x20) + buf[12] = '\0'; + buf[13] = '\0'; + return hb_language_from_string ((char *) buf, -1); + } + } + } + + /* Else return a custom language in the form of "x-hbotABCD" */ + { + unsigned char buf[11] = "x-hbot"; + buf[6] = tag >> 24; + buf[7] = (tag >> 16) & 0xFF; + buf[8] = (tag >> 8) & 0xFF; + buf[9] = tag & 0xFF; + if (buf[9] == 0x20) + buf[9] = '\0'; + buf[10] = '\0'; + return hb_language_from_string ((char *) buf, -1); + } } -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 index 1eec69f..427a069 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-tag.h +++ b/third_party/harfbuzz-ng/src/hb-ot-tag.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -28,7 +28,6 @@ #define HB_OT_TAG_H #include "hb-common.h" -#include "hb-language.h" HB_BEGIN_DECLS @@ -36,8 +35,10 @@ 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); +void +hb_ot_tags_from_script (hb_script_t script, + hb_tag_t *script_tag_1, + hb_tag_t *script_tag_2); hb_script_t hb_ot_tag_to_script (hb_tag_t tag); diff --git a/third_party/harfbuzz-ng/src/hb-ot.h b/third_party/harfbuzz-ng/src/hb-ot.h index 268711d..fd6dd58 100644 --- a/third_party/harfbuzz-ng/src/hb-ot.h +++ b/third_party/harfbuzz-ng/src/hb-ot.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * diff --git a/third_party/harfbuzz-ng/src/hb-private.h b/third_party/harfbuzz-ng/src/hb-private.h deleted file mode 100644 index 96b9464..0000000 --- a/third_party/harfbuzz-ng/src/hb-private.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * 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-private.hh b/third_party/harfbuzz-ng/src/hb-private.hh new file mode 100644 index 0000000..c757e2dc --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-private.hh @@ -0,0 +1,632 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_PRIVATE_HH +#define HB_PRIVATE_HH + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "hb-common.h" + +#include <stdlib.h> +#include <stddef.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> +#include <stdarg.h> + + + +/* Essentials */ + +#ifndef NULL +# define NULL ((void *) 0) +#endif + +#undef FALSE +#define FALSE 0 + +#undef TRUE +#define TRUE 1 + + +/* Basics */ + + +#undef MIN +template <typename Type> static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; } + +#undef MAX +template <typename Type> static inline Type MAX (const Type &a, const Type &b) { return 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)) + +#define ASSERT_STATIC_EXPR(_cond) ((void) sizeof (char[(_cond) ? 1 : -1])) +#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1])) + + +/* Lets assert int types. Saves trouble down the road. */ + +ASSERT_STATIC (sizeof (int8_t) == 1); +ASSERT_STATIC (sizeof (uint8_t) == 1); +ASSERT_STATIC (sizeof (int16_t) == 2); +ASSERT_STATIC (sizeof (uint16_t) == 2); +ASSERT_STATIC (sizeof (int32_t) == 4); +ASSERT_STATIC (sizeof (uint32_t) == 4); +ASSERT_STATIC (sizeof (int64_t) == 8); +ASSERT_STATIC (sizeof (uint64_t) == 8); + +ASSERT_STATIC (sizeof (hb_codepoint_t) == 4); +ASSERT_STATIC (sizeof (hb_position_t) == 4); +ASSERT_STATIC (sizeof (hb_mask_t) == 4); +ASSERT_STATIC (sizeof (hb_var_int_t) == 4); + +/* 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)) +#define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) +#else +#define HB_PURE_FUNC +#define HB_CONST_FUNC +#define HB_PRINTF_FUNC(format_idx, arg_idx) +#endif +#if __GNUC__ >= 4 +#define HB_UNUSED __attribute__((unused)) +#else +#define HB_UNUSED +#endif + +#ifndef HB_INTERNAL +# ifndef __MINGW32__ +# define HB_INTERNAL __attribute__((__visibility__("hidden"))) +# else +# define HB_INTERNAL +# endif +#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 +} + +static inline bool +_hb_unsigned_int_mul_overflows (unsigned int count, unsigned int size) +{ + return (size > 0) && (count >= ((unsigned int) -1) / size); +} + + +/* Type of bsearch() / qsort() compare function */ +typedef int (*hb_compare_func_t) (const void *, const void *); + + + + +/* arrays and maps */ + + +template <typename Type, unsigned int StaticSize> +struct hb_prealloced_array_t { + + unsigned int len; + unsigned int allocated; + Type *array; + Type static_array[StaticSize]; + + hb_prealloced_array_t (void) { memset (this, 0, sizeof (*this)); } + + inline Type& operator [] (unsigned int i) { return array[i]; } + inline const Type& operator [] (unsigned int i) const { return array[i]; } + + inline Type *push (void) + { + if (!array) { + array = static_array; + allocated = ARRAY_LENGTH (static_array); + } + if (likely (len < allocated)) + return &array[len++]; + + /* Need to reallocate */ + unsigned int new_allocated = allocated + (allocated >> 1) + 8; + Type *new_array = NULL; + + if (array == static_array) { + new_array = (Type *) calloc (new_allocated, sizeof (Type)); + if (new_array) + memcpy (new_array, array, len * sizeof (Type)); + } else { + bool overflows = (new_allocated < allocated) || _hb_unsigned_int_mul_overflows (new_allocated, sizeof (Type)); + if (likely (!overflows)) { + new_array = (Type *) realloc (array, new_allocated * sizeof (Type)); + } + } + + if (unlikely (!new_array)) + return NULL; + + array = new_array; + allocated = new_allocated; + return &array[len++]; + } + + inline void pop (void) + { + len--; + /* TODO: shrink array if needed */ + } + + inline void shrink (unsigned int l) + { + if (l < len) + len = l; + /* TODO: shrink array if needed */ + } + + template <typename T> + inline Type *find (T v) { + for (unsigned int i = 0; i < len; i++) + if (array[i] == v) + return &array[i]; + return NULL; + } + template <typename T> + inline const Type *find (T v) const { + for (unsigned int i = 0; i < len; i++) + if (array[i] == v) + return &array[i]; + return NULL; + } + + inline void sort (void) + { + qsort (array, len, sizeof (Type), (hb_compare_func_t) Type::cmp); + } + + inline void sort (unsigned int start, unsigned int end) + { + qsort (array + start, end - start, sizeof (Type), (hb_compare_func_t) Type::cmp); + } + + template <typename T> + inline Type *bsearch (T *key) + { + return (Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp); + } + template <typename T> + inline const Type *bsearch (T *key) const + { + return (const Type *) ::bsearch (key, array, len, sizeof (Type), (hb_compare_func_t) Type::cmp); + } + + inline void finish (void) + { + if (array != static_array) + free (array); + array = NULL; + allocated = len = 0; + } +}; + +template <typename Type> +struct hb_array_t : hb_prealloced_array_t<Type, 2> {}; + + +template <typename item_t, typename lock_t> +struct hb_lockable_set_t +{ + hb_array_t <item_t> items; + + template <typename T> + inline item_t *replace_or_insert (T v, lock_t &l, bool replace) + { + l.lock (); + item_t *item = items.find (v); + if (item) { + if (replace) { + item_t old = *item; + *item = v; + l.unlock (); + old.finish (); + } + else { + item = NULL; + l.unlock (); + } + } else { + item = items.push (); + if (likely (item)) + *item = v; + l.unlock (); + } + return item; + } + + template <typename T> + inline void remove (T v, lock_t &l) + { + l.lock (); + item_t *item = items.find (v); + if (item) { + item_t old = *item; + *item = items[items.len - 1]; + items.pop (); + l.unlock (); + old.finish (); + } else { + l.unlock (); + } + } + + template <typename T> + inline bool find (T v, item_t *i, lock_t &l) + { + l.lock (); + item_t *item = items.find (v); + if (item) + *i = *item; + l.unlock (); + return !!item; + } + + template <typename T> + inline item_t *find_or_insert (T v, lock_t &l) + { + l.lock (); + item_t *item = items.find (v); + if (!item) { + item = items.push (); + if (likely (item)) + *item = v; + } + l.unlock (); + return item; + } + + inline void finish (lock_t &l) + { + l.lock (); + while (items.len) { + item_t old = items[items.len - 1]; + items.pop (); + l.unlock (); + old.finish (); + l.lock (); + } + items.finish (); + l.unlock (); + } + +}; + + + + +/* Big-endian handling */ + +static inline uint16_t hb_be_uint16 (const uint16_t v) +{ + const uint8_t *V = (const uint8_t *) &v; + return (uint16_t) (V[0] << 8) + 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_eq(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_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]) + + +/* ASCII tag/character handling */ + +static inline unsigned char ISALPHA (unsigned char c) +{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } +static inline unsigned char ISALNUM (unsigned char c) +{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } +static inline unsigned char TOUPPER (unsigned char c) +{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } +static inline unsigned char TOLOWER (unsigned char c) +{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } + +#define HB_TAG_CHAR4(s) (HB_TAG(((const char *) s)[0], \ + ((const char *) s)[1], \ + ((const char *) s)[2], \ + ((const char *) s)[3])) + + +/* C++ helpers */ + +/* Makes class uncopyable. Use in private: section. */ +#define NO_COPY(T) \ + T (const T &o); \ + T &operator = (const T &o) + + +/* Debug */ + + +#ifndef HB_DEBUG +#define HB_DEBUG 0 +#endif + +static inline bool +_hb_debug (unsigned int level, + unsigned int max_level) +{ + return level < max_level; +} + +#define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT)) +#define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0)) + +template <int max_level> inline bool /* always returns TRUE */ +_hb_debug_msg (const char *what, + const void *obj, + const char *func, + bool indented, + int level, + const char *message, + ...) HB_PRINTF_FUNC(6, 7); +template <int max_level> inline bool /* always returns TRUE */ +_hb_debug_msg (const char *what, + const void *obj, + const char *func, + bool indented, + int level, + const char *message, + ...) +{ + va_list ap; + va_start (ap, message); + + (void) (_hb_debug (level, max_level) && + fprintf (stderr, "%s", what) && + (obj && fprintf (stderr, "(%p)", obj), TRUE) && + fprintf (stderr, ": ") && + (func && fprintf (stderr, "%s: ", func), TRUE) && + (indented && fprintf (stderr, "%-*d-> ", level + 1, level), TRUE) && + vfprintf (stderr, message, ap) && + fprintf (stderr, "\n")); + + va_end (ap); + + return TRUE; +} +template <> inline bool /* always returns TRUE */ +_hb_debug_msg<0> (const char *what, + const void *obj, + const char *func, + bool indented, + int level, + const char *message, + ...) HB_PRINTF_FUNC(6, 7); +template <> inline bool /* always returns TRUE */ +_hb_debug_msg<0> (const char *what, + const void *obj, + const char *func, + bool indented, + int level, + const char *message, + ...) +{ + return TRUE; +} + +#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, FALSE, (LEVEL), __VA_ARGS__) +#define DEBUG_MSG(WHAT, OBJ, ...) DEBUG_MSG_LEVEL (WHAT, OBJ, 0, __VA_ARGS__) +#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, FALSE, 0, __VA_ARGS__) + + +/* + * Trace + */ + +template <int max_level> +struct hb_auto_trace_t { + explicit inline hb_auto_trace_t (unsigned int *plevel_, + const char *what, + const void *obj, + const char *func, + const char *message) : plevel(plevel_) + { + if (max_level) ++*plevel; + /* TODO support variadic args here */ + _hb_debug_msg<max_level> (what, obj, func, TRUE, *plevel, "%s", message); + } + ~hb_auto_trace_t (void) { if (max_level) --*plevel; } + + private: + unsigned int *plevel; +}; +template <> /* Optimize when tracing is disabled */ +struct hb_auto_trace_t<0> { + explicit inline hb_auto_trace_t (unsigned int *plevel_, + const char *what, + const void *obj, + const char *func, + const char *message) {} +}; + + +/* Misc */ + + +/* Pre-mature optimization: + * Checks for lo <= u <= hi but with an optimization if lo and hi + * are only different in a contiguous set of lower-most bits. + */ +template <typename T> inline bool +hb_in_range (T u, T lo, T hi) +{ + if ( ((lo^hi) & lo) == 0 && + ((lo^hi) & hi) == (lo^hi) && + ((lo^hi) & ((lo^hi) + 1)) == 0 ) + return (u & ~(lo^hi)) == lo; + else + return lo <= u && u <= hi; +} + + +/* Useful for set-operations on small enums. + * For example, for testing "x ∈ {x1, x2, x3}" use: + * (FLAG(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3))) + */ +#define FLAG(x) (1<<(x)) + + +template <typename T> inline void +hb_bubble_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) +{ + if (unlikely (!len)) + return; + + unsigned int k = len - 1; + do { + unsigned int new_k = 0; + + for (unsigned int j = 0; j < k; j++) + if (compar (&array[j], &array[j+1]) > 0) { + T t; + t = array[j]; + array[j] = array[j + 1]; + array[j + 1] = t; + + new_k = j; + } + k = new_k; + } while (k); +} + + + + +#endif /* HB_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-shape.cc b/third_party/harfbuzz-ng/src/hb-shape.cc index a73977b..9357f81 100644 --- a/third_party/harfbuzz-ng/src/hb-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-shape.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,42 +24,132 @@ * Red Hat Author(s): Behdad Esfahbod */ -#include "hb-private.h" +#include "hb-private.hh" #include "hb-shape.h" #include "hb-buffer-private.hh" -#include "hb-ot-shape.h" - #ifdef HAVE_GRAPHITE -#include "hb-graphite.h" +#include "hb-graphite2.h" +#endif +#ifdef HAVE_UNISCRIBE +# include "hb-uniscribe.h" +#endif +#ifdef HAVE_OT +# include "hb-ot-shape.h" #endif +#include "hb-fallback-shape-private.hh" -HB_BEGIN_DECLS +typedef hb_bool_t (*hb_shape_func_t) (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options); +#define HB_SHAPER_IMPLEMENT(name) {#name, hb_##name##_shape} +static struct hb_shaper_pair_t { + char name[16]; + hb_shape_func_t func; +} shapers[] = { + /* v--- Add new shapers in the right place here */ +#ifdef HAVE_GRAPHITE + HB_SHAPER_IMPLEMENT (graphite), +#endif +#ifdef HAVE_UNISCRIBE + HB_SHAPER_IMPLEMENT (uniscribe), +#endif +#ifdef HAVE_OT + HB_SHAPER_IMPLEMENT (ot), +#endif + HB_SHAPER_IMPLEMENT (fallback) /* should be last */ +}; +#undef HB_SHAPER_IMPLEMENT -void -hb_shape (hb_font_t *font, - hb_face_t *face, - hb_buffer_t *buffer, - hb_feature_t *features, - unsigned int num_features) +static struct static_shaper_list_t { -#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)) + static_shaper_list_t (void) { - hb_graphite_shape(font, face, buffer, features, num_features); - hb_blob_destroy(silf_blob); - return; + char *env = getenv ("HB_SHAPER_LIST"); + if (env && *env) + { + /* Reorder shaper list to prefer requested shaper list. */ + unsigned int i = 0; + char *end, *p = env; + for (;;) { + end = strchr (p, ','); + if (!end) + end = p + strlen (p); + + for (unsigned int j = i; j < ARRAY_LENGTH (shapers); j++) + if (end - p == (int) strlen (shapers[j].name) && + 0 == strncmp (shapers[j].name, p, end - p)) + { + /* Reorder this shaper to position i */ + struct hb_shaper_pair_t t = shapers[j]; + memmove (&shapers[i + 1], &shapers[i], sizeof (shapers[i]) * (j - i)); + shapers[i] = t; + i++; + } + + if (!*end) + break; + else + p = end + 1; + } + } + + ASSERT_STATIC ((ARRAY_LENGTH (shapers) + 1) * sizeof (*shaper_list) <= sizeof (shaper_list)); + unsigned int i; + for (i = 0; i < ARRAY_LENGTH (shapers); i++) + shaper_list[i] = shapers[i].name; + shaper_list[i] = NULL; } - hb_blob_destroy(silf_blob); -#endif - hb_ot_shape (font, face, buffer, features, num_features); + const char *shaper_list[ARRAY_LENGTH (shapers) + 1]; +} static_shaper_list; + +const char ** +hb_shape_list_shapers (void) +{ + return static_shaper_list.shaper_list; } +hb_bool_t +hb_shape_full (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options, + const char * const *shaper_list) +{ + if (likely (!shaper_list)) { + for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++) + if (likely (shapers[i].func (font, buffer, + features, num_features, + shaper_options))) + return TRUE; + } else { + while (*shaper_list) { + for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++) + if (0 == strcmp (*shaper_list, shapers[i].name)) { + if (likely (shapers[i].func (font, buffer, + features, num_features, + shaper_options))) + return TRUE; + break; + } + shaper_list++; + } + } + return FALSE; +} -HB_END_DECLS +void +hb_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) +{ + hb_shape_full (font, buffer, features, num_features, NULL, NULL); +} diff --git a/third_party/harfbuzz-ng/src/hb-shape.h b/third_party/harfbuzz-ng/src/hb-shape.h index 48f1a55..685b11d 100644 --- a/third_party/harfbuzz-ng/src/hb-shape.h +++ b/third_party/harfbuzz-ng/src/hb-shape.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -41,12 +41,23 @@ typedef struct _hb_feature_t { 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_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features); + +hb_bool_t +hb_shape_full (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options, + const char * const *shaper_list); + +const char ** +hb_shape_list_shapers (void); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-tt-font.cc b/third_party/harfbuzz-ng/src/hb-tt-font.cc new file mode 100644 index 0000000..ccd86e1 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-tt-font.cc @@ -0,0 +1,242 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-open-type-private.hh" + +#include "hb-ot-hhea-table.hh" +#include "hb-ot-hmtx-table.hh" + +#include "hb-font-private.hh" +#include "hb-blob.h" + +#include <string.h> + + + +#if 0 +struct hb_tt_font_t +{ + const struct hhea *hhea; + hb_blob_t *hhea_blob; +}; + + +static hb_tt_font_t * +_hb_tt_font_create (hb_font_t *font) +{ + /* TODO Remove this object altogether */ + hb_tt_font_t *tt = (hb_tt_font_t *) calloc (1, sizeof (hb_tt_font_t)); + + tt->hhea_blob = Sanitizer<hhea>::sanitize (hb_face_reference_table (font->face, HB_OT_TAG_hhea)); + tt->hhea = Sanitizer<hhea>::lock_instance (tt->hhea_blob); + + return tt; +} + +static void +_hb_tt_font_destroy (hb_tt_font_t *tt) +{ + hb_blob_destroy (tt->hhea_blob); + + free (tt); +} + +static inline const hhea& +_get_hhea (hb_face_t *face) +{ +// return likely (face->tt && face->tt->hhea) ? *face->tt->hhea : Null(hhea); +} + + +/* + * hb_tt_font_funcs_t + */ + +static hb_bool_t +hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return hb_font_get_glyph (font->parent, unicode, variation_selector, glyph); + + *glyph = 0; + return FALSE; +} + +static hb_position_t +hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_x_distance (hb_font_get_glyph_h_advance (font->parent, glyph)); + + return font->x_scale; +} + +static hb_position_t +hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_y_distance (hb_font_get_glyph_v_advance (font->parent, glyph)); + + return font->y_scale; +} + +static hb_bool_t +hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent, + glyph, + x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return FALSE; +} + +static hb_bool_t +hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent, + glyph, + x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return FALSE; +} + +static hb_position_t +hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_x_distance (hb_font_get_glyph_h_kerning (font->parent, left_glyph, right_glyph)); + + return 0; +} + +static hb_position_t +hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return font->parent_scale_y_distance (hb_font_get_glyph_v_kerning (font->parent, top_glyph, bottom_glyph)); + + return 0; +} + +static hb_bool_t +hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_extents (font->parent, + glyph, + extents); + if (ret) { + font->parent_scale_position (&extents->x_bearing, &extents->y_bearing); + font->parent_scale_distance (&extents->width, &extents->height); + } + return ret; + } + + memset (extents, 0, sizeof (*extents)); + return FALSE; +} + +static hb_bool_t +hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) +{ + if (font->parent) { + hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent, + glyph, point_index, + x, y); + if (ret) + font->parent_scale_position (x, y); + return ret; + } + + *x = *y = 0; + return FALSE; +} + + +static hb_font_funcs_t _hb_font_funcs_nil = { + HB_OBJECT_HEADER_STATIC, + + TRUE, /* immutable */ + + { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } +}; +#endif + diff --git a/third_party/harfbuzz-ng/src/hb-unicode-private.hh b/third_party/harfbuzz-ng/src/hb-unicode-private.hh new file mode 100644 index 0000000..2ad8a49 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-unicode-private.hh @@ -0,0 +1,107 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Codethink Limited + * Copyright © 2010,2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Codethink Author(s): Ryan Lortie + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_UNICODE_PRIVATE_HH +#define HB_UNICODE_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-unicode.h" +#include "hb-object-private.hh" + + + +/* + * hb_unicode_funcs_t + */ + +#define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS \ + HB_UNICODE_FUNC_IMPLEMENT (combining_class) \ + HB_UNICODE_FUNC_IMPLEMENT (eastasian_width) \ + HB_UNICODE_FUNC_IMPLEMENT (general_category) \ + HB_UNICODE_FUNC_IMPLEMENT (mirroring) \ + HB_UNICODE_FUNC_IMPLEMENT (script) \ + HB_UNICODE_FUNC_IMPLEMENT (compose) \ + HB_UNICODE_FUNC_IMPLEMENT (decompose) \ + /* ^--- Add new callbacks here */ + +/* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */ +#define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \ + HB_UNICODE_FUNC_IMPLEMENT (unsigned int, combining_class) \ + HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \ + HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \ + HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \ + HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \ + /* ^--- Add new simple callbacks here */ + +struct _hb_unicode_funcs_t { + hb_object_header_t header; + + hb_unicode_funcs_t *parent; + + bool immutable; + + /* Don't access these directly. Call hb_unicode_*() instead. */ + + struct { +#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_func_t name; + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + } func; + + struct { +#define HB_UNICODE_FUNC_IMPLEMENT(name) void *name; + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + } user_data; + + struct { +#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_destroy_func_t name; + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + } destroy; +}; + + +#ifdef HAVE_GLIB +extern HB_INTERNAL hb_unicode_funcs_t _hb_glib_unicode_funcs; +#define _hb_unicode_funcs_default _hb_glib_unicode_funcs +#elif defined(HAVE_ICU) +extern HB_INTERNAL hb_unicode_funcs_t _hb_icu_unicode_funcs; +#define _hb_unicode_funcs_default _hb_icu_unicode_funcs +#else +extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_nil; +#define _hb_unicode_funcs_default _hb_unicode_funcs_nil +#endif + + + + +#endif /* HB_UNICODE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-unicode.c b/third_party/harfbuzz-ng/src/hb-unicode.c deleted file mode 100644 index 2ab308b..0000000 --- a/third_party/harfbuzz-ng/src/hb-unicode.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * 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.cc b/third_party/harfbuzz-ng/src/hb-unicode.cc new file mode 100644 index 0000000..4b285c5 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-unicode.cc @@ -0,0 +1,273 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Codethink Limited + * Copyright © 2010,2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Codethink Author(s): Ryan Lortie + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-private.hh" + +#include "hb-unicode-private.hh" + + + +/* + * hb_unicode_funcs_t + */ + +static unsigned int +hb_unicode_combining_class_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, + void *user_data HB_UNUSED) +{ + return 0; +} + +static unsigned int +hb_unicode_eastasian_width_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, + void *user_data HB_UNUSED) +{ + return 1; +} + +static hb_unicode_general_category_t +hb_unicode_general_category_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, + void *user_data HB_UNUSED) +{ + return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER; +} + +static hb_codepoint_t +hb_unicode_mirroring_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, + void *user_data HB_UNUSED) +{ + return unicode; +} + +static hb_script_t +hb_unicode_script_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, + void *user_data HB_UNUSED) +{ + return HB_SCRIPT_UNKNOWN; +} + +static hb_bool_t +hb_unicode_compose_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t a HB_UNUSED, + hb_codepoint_t b HB_UNUSED, + hb_codepoint_t *ab HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* TODO handle Hangul jamo here? */ + return FALSE; +} + +static hb_bool_t +hb_unicode_decompose_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t ab HB_UNUSED, + hb_codepoint_t *a HB_UNUSED, + hb_codepoint_t *b HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* TODO handle Hangul jamo here? */ + return FALSE; +} + + +hb_unicode_funcs_t _hb_unicode_funcs_nil = { + HB_OBJECT_HEADER_STATIC, + + NULL, /* parent */ + TRUE, /* immutable */ + { +#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_unicode_##name##_nil, + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + } +}; + + +hb_unicode_funcs_t * +hb_unicode_funcs_get_default (void) +{ + return &_hb_unicode_funcs_default; +} + +hb_unicode_funcs_t * +hb_unicode_funcs_create (hb_unicode_funcs_t *parent) +{ + hb_unicode_funcs_t *ufuncs; + + if (!(ufuncs = hb_object_create<hb_unicode_funcs_t> ())) + return &_hb_unicode_funcs_nil; + + if (!parent) + parent = &_hb_unicode_funcs_nil; + + hb_unicode_funcs_make_immutable (parent); + ufuncs->parent = hb_unicode_funcs_reference (parent); + + ufuncs->func = parent->func; + + /* We can safely copy user_data from parent since we hold a reference + * onto it and it's immutable. We should not copy the destroy notifiers + * though. */ + ufuncs->user_data = parent->user_data; + + return ufuncs; +} + +hb_unicode_funcs_t * +hb_unicode_funcs_get_empty (void) +{ + return &_hb_unicode_funcs_nil; +} + +hb_unicode_funcs_t * +hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs) +{ + return hb_object_reference (ufuncs); +} + +void +hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs) +{ + if (!hb_object_destroy (ufuncs)) return; + +#define HB_UNICODE_FUNC_IMPLEMENT(name) \ + if (ufuncs->destroy.name) ufuncs->destroy.name (ufuncs->user_data.name); + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + + hb_unicode_funcs_destroy (ufuncs->parent); + + free (ufuncs); +} + +hb_bool_t +hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (ufuncs, key, data, destroy, replace); +} + +void * +hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (ufuncs, key); +} + + +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; +} + +hb_unicode_funcs_t * +hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs) +{ + return ufuncs->parent ? ufuncs->parent : &_hb_unicode_funcs_nil; +} + + +#define HB_UNICODE_FUNC_IMPLEMENT(name) \ + \ +void \ +hb_unicode_funcs_set_##name##_func (hb_unicode_funcs_t *ufuncs, \ + hb_unicode_##name##_func_t func, \ + void *user_data, \ + hb_destroy_func_t destroy) \ +{ \ + if (ufuncs->immutable) \ + return; \ + \ + if (ufuncs->destroy.name) \ + ufuncs->destroy.name (ufuncs->user_data.name); \ + \ + if (func) { \ + ufuncs->func.name = func; \ + ufuncs->user_data.name = user_data; \ + ufuncs->destroy.name = destroy; \ + } else { \ + ufuncs->func.name = ufuncs->parent->func.name; \ + ufuncs->user_data.name = ufuncs->parent->user_data.name; \ + ufuncs->destroy.name = NULL; \ + } \ +} + + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_UNICODE_FUNC_IMPLEMENT + + +#define HB_UNICODE_FUNC_IMPLEMENT(return_type, name) \ + \ +return_type \ +hb_unicode_##name (hb_unicode_funcs_t *ufuncs, \ + hb_codepoint_t unicode) \ +{ \ + return ufuncs->func.name (ufuncs, unicode, ufuncs->user_data.name); \ +} + HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE +#undef HB_UNICODE_FUNC_IMPLEMENT + +hb_bool_t +hb_unicode_compose (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab) +{ + *ab = 0; + return ufuncs->func.compose (ufuncs, a, b, ab, ufuncs->user_data.compose); +} + +hb_bool_t +hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b) +{ + *a = ab; *b = 0; + return ufuncs->func.decompose (ufuncs, ab, a, b, ufuncs->user_data.decompose); +} + diff --git a/third_party/harfbuzz-ng/src/hb-unicode.h b/third_party/harfbuzz-ng/src/hb-unicode.h index 43b04ca..13886df 100644 --- a/third_party/harfbuzz-ng/src/hb-unicode.h +++ b/third_party/harfbuzz-ng/src/hb-unicode.h @@ -1,5 +1,7 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2011 Codethink Limited + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,6 +24,8 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Codethink Author(s): Ryan Lortie + * Google Author(s): Behdad Esfahbod */ #ifndef HB_UNICODE_H @@ -32,176 +36,44 @@ 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; + +/* + * just give me the best implementation you've got there. + */ +hb_unicode_funcs_t * +hb_unicode_funcs_get_default (void); + + hb_unicode_funcs_t * -hb_unicode_funcs_create (void); +hb_unicode_funcs_create (hb_unicode_funcs_t *parent); hb_unicode_funcs_t * -hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs); +hb_unicode_funcs_get_empty (void); -unsigned int -hb_unicode_funcs_get_reference_count (hb_unicode_funcs_t *ufuncs); +hb_unicode_funcs_t * +hb_unicode_funcs_reference (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); +hb_bool_t +hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +void * +hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs, + hb_user_data_key_t *key); + void hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs); @@ -209,85 +81,113 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs); hb_bool_t hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs); +hb_unicode_funcs_t * +hb_unicode_funcs_get_parent (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); - +typedef unsigned int (*hb_unicode_combining_class_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode, + void *user_data); +typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode, + void *user_data); +typedef hb_unicode_general_category_t (*hb_unicode_general_category_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode, + void *user_data); +typedef hb_codepoint_t (*hb_unicode_mirroring_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode, + void *user_data); +typedef hb_script_t (*hb_unicode_script_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode, + void *user_data); + +typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab, + void *user_data); +typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b, + void *user_data); /* setters */ void -hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_get_mirroring_func_t mirroring_func); +hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_combining_class_func_t combining_class_func, + void *user_data, hb_destroy_func_t destroy); void -hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_get_general_category_func_t general_category_func); +hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_eastasian_width_func_t eastasian_width_func, + void *user_data, hb_destroy_func_t destroy); void -hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_get_script_func_t script_func); +hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_general_category_func_t general_category_func, + void *user_data, hb_destroy_func_t destroy); void -hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs, - hb_unicode_get_combining_class_func_t combining_class_func); +hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_mirroring_func_t mirroring_func, + void *user_data, hb_destroy_func_t destroy); 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_funcs_set_script_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_script_func_t script_func, + void *user_data, hb_destroy_func_t destroy); -hb_unicode_get_mirroring_func_t -hb_unicode_funcs_get_mirroring_func (hb_unicode_funcs_t *ufuncs); +void +hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_compose_func_t compose_func, + void *user_data, hb_destroy_func_t destroy); -hb_unicode_get_general_category_func_t -hb_unicode_funcs_get_general_category_func (hb_unicode_funcs_t *ufuncs); +void +hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs, + hb_unicode_decompose_func_t decompose_func, + void *user_data, hb_destroy_func_t destroy); -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); +/* accessors */ -hb_unicode_get_eastasian_width_func_t -hb_unicode_funcs_get_eastasian_width_func (hb_unicode_funcs_t *ufuncs); +unsigned int +hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode); +unsigned int +hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode); -/* accessors */ +hb_unicode_general_category_t +hb_unicode_general_category (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode); 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_unicode_mirroring (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_unicode_script (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode); +hb_bool_t +hb_unicode_compose (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab); +hb_bool_t +hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-uniscribe.cc b/third_party/harfbuzz-ng/src/hb-uniscribe.cc new file mode 100644 index 0000000..ce86074 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-uniscribe.cc @@ -0,0 +1,463 @@ +/* + * Copyright © 2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#define _WIN32_WINNT 0x0500 + +#include "hb-private.hh" + +#include <windows.h> +#include <usp10.h> + +typedef ULONG WIN_ULONG; + +#include "hb-uniscribe.h" + +#include "hb-ot-name-table.hh" +#include "hb-ot-tag.h" + +#include "hb-font-private.hh" +#include "hb-buffer-private.hh" + + + +#ifndef HB_DEBUG_UNISCRIBE +#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) +#endif + + +/* +DWORD GetFontData( + __in HDC hdc, + __in DWORD dwTable, + __in DWORD dwOffset, + __out LPVOID lpvBuffer, + __in DWORD cbData +); +*/ + +static bool +populate_log_font (LOGFONTW *lf, + HDC hdc, + hb_font_t *font) +{ + memset (lf, 0, sizeof (*lf)); + int dpi = GetDeviceCaps (hdc, LOGPIXELSY); + lf->lfHeight = -font->y_scale; + + hb_blob_t *blob = Sanitizer<name>::sanitize (hb_face_reference_table (font->face, HB_TAG ('n','a','m','e'))); + const name *name_table = Sanitizer<name>::lock_instance (blob); + unsigned int len = name_table->get_name (3, 1, 0x409, 4, + lf->lfFaceName, + sizeof (lf->lfFaceName[0]) * LF_FACESIZE) + / sizeof (lf->lfFaceName[0]); + hb_blob_destroy (blob); + + if (unlikely (!len)) { + DEBUG_MSG (UNISCRIBE, NULL, "Didn't find English name table entry"); + return FALSE; + } + if (unlikely (len >= LF_FACESIZE)) { + DEBUG_MSG (UNISCRIBE, NULL, "Font name too long"); + return FALSE; + } + + for (unsigned int i = 0; i < len; i++) + lf->lfFaceName[i] = hb_be_uint16 (lf->lfFaceName[i]); + lf->lfFaceName[len] = 0; + + return TRUE; +} + + +static hb_user_data_key_t hb_uniscribe_data_key; + + +static struct hb_uniscribe_face_data_t { + HANDLE fh; +} _hb_uniscribe_face_data_nil = {0}; + +static void +_hb_uniscribe_face_data_destroy (hb_uniscribe_face_data_t *data) +{ + if (data->fh) + RemoveFontMemResourceEx (data->fh); + free (data); +} + +static hb_uniscribe_face_data_t * +_hb_uniscribe_face_get_data (hb_face_t *face) +{ + hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key); + if (likely (data)) return data; + + data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t)); + if (unlikely (!data)) + return &_hb_uniscribe_face_data_nil; + + + hb_blob_t *blob = hb_face_reference_blob (face); + unsigned int blob_length; + const char *blob_data = hb_blob_get_data (blob, &blob_length); + if (unlikely (!blob_length)) + DEBUG_MSG (UNISCRIBE, face, "Face has empty blob"); + + DWORD num_fonts_installed; + data->fh = AddFontMemResourceEx ((void *) blob_data, blob_length, 0, &num_fonts_installed); + hb_blob_destroy (blob); + if (unlikely (!data->fh)) + DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed"); + + + if (unlikely (!hb_face_set_user_data (face, &hb_uniscribe_data_key, data, + (hb_destroy_func_t) _hb_uniscribe_face_data_destroy, + FALSE))) + { + _hb_uniscribe_face_data_destroy (data); + data = (hb_uniscribe_face_data_t *) hb_face_get_user_data (face, &hb_uniscribe_data_key); + if (data) + return data; + else + return &_hb_uniscribe_face_data_nil; + } + + return data; +} + + +static struct hb_uniscribe_font_data_t { + HDC hdc; + LOGFONTW log_font; + HFONT hfont; + SCRIPT_CACHE script_cache; +} _hb_uniscribe_font_data_nil = {NULL, NULL, NULL}; + +static void +_hb_uniscribe_font_data_destroy (hb_uniscribe_font_data_t *data) +{ + if (data->hdc) + ReleaseDC (NULL, data->hdc); + if (data->hfont) + DeleteObject (data->hfont); + if (data->script_cache) + ScriptFreeCache (&data->script_cache); + free (data); +} + +static hb_uniscribe_font_data_t * +_hb_uniscribe_font_get_data (hb_font_t *font) +{ + hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key); + if (likely (data)) return data; + + data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t)); + if (unlikely (!data)) + return &_hb_uniscribe_font_data_nil; + + data->hdc = GetDC (NULL); + + if (unlikely (!populate_log_font (&data->log_font, data->hdc, font))) + DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed"); + else { + data->hfont = CreateFontIndirectW (&data->log_font); + if (unlikely (!data->hfont)) + DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed"); + if (!SelectObject (data->hdc, data->hfont)) + DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed"); + } + + if (unlikely (!hb_font_set_user_data (font, &hb_uniscribe_data_key, data, + (hb_destroy_func_t) _hb_uniscribe_font_data_destroy, + FALSE))) + { + _hb_uniscribe_font_data_destroy (data); + data = (hb_uniscribe_font_data_t *) hb_font_get_user_data (font, &hb_uniscribe_data_key); + if (data) + return data; + else + return &_hb_uniscribe_font_data_nil; + } + + return data; +} + +LOGFONTW * +hb_uniscribe_font_get_logfontw (hb_font_t *font) +{ + hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font); + if (unlikely (!font_data)) + return NULL; + return &font_data->log_font; +} + +HFONT +hb_uniscribe_font_get_hfont (hb_font_t *font) +{ + hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font); + if (unlikely (!font_data)) + return 0; + return font_data->hfont; +} + + +hb_bool_t +hb_uniscribe_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options) +{ + buffer->guess_properties (); + +#define FAIL(...) \ + HB_STMT_START { \ + DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \ + return FALSE; \ + } HB_STMT_END; + + hb_uniscribe_face_data_t *face_data = _hb_uniscribe_face_get_data (font->face); + if (unlikely (!face_data->fh)) + FAIL ("Couldn't get face data"); + + hb_uniscribe_font_data_t *font_data = _hb_uniscribe_font_get_data (font); + if (unlikely (!font_data->hfont)) + FAIL ("Couldn't get font font"); + + if (unlikely (!buffer->len)) + return TRUE; + + HRESULT hr; + +retry: + + unsigned int scratch_size; + char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); + + /* Allocate char buffers; they all fit */ + +#define ALLOCATE_ARRAY(Type, name, len) \ + Type *name = (Type *) scratch; \ + scratch += len * sizeof (name[0]); \ + scratch_size -= len * sizeof (name[0]); + +#define utf16_index() var1.u32 + + WCHAR *pchars = (WCHAR *) scratch; + unsigned int chars_len = 0; + for (unsigned int i = 0; i < buffer->len; i++) { + hb_codepoint_t c = buffer->info[i].codepoint; + buffer->info[i].utf16_index() = chars_len; + if (likely (c < 0x10000)) + pchars[chars_len++] = c; + else if (unlikely (c >= 0x110000)) + pchars[chars_len++] = 0xFFFD; + else { + pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10); + pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1)); + } + } + + ALLOCATE_ARRAY (WCHAR, wchars, chars_len); + ALLOCATE_ARRAY (WORD, log_clusters, chars_len); + ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len); + + /* On Windows, we don't care about alignment...*/ + unsigned int glyphs_size = scratch_size / (sizeof (WORD) + + sizeof (SCRIPT_GLYPHPROP) + + sizeof (int) + + sizeof (GOFFSET) + + sizeof (uint32_t)); + + ALLOCATE_ARRAY (WORD, glyphs, glyphs_size); + ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size); + ALLOCATE_ARRAY (int, advances, glyphs_size); + ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size); + ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size); + + +#define MAX_ITEMS 10 + + SCRIPT_ITEM items[MAX_ITEMS + 1]; + SCRIPT_CONTROL bidi_control = {0}; + SCRIPT_STATE bidi_state = {0}; + WIN_ULONG script_tags[MAX_ITEMS]; + int item_count; + + /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */ + //bidi_control.fMergeNeutralItems = TRUE; + *(uint32_t*)&bidi_control |= 1<<24; + + bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; +// bidi_state.fOverrideDirection = 1; + + hr = ScriptItemizeOpenType (wchars, + chars_len, + MAX_ITEMS, + &bidi_control, + &bidi_state, + items, + script_tags, + &item_count); + if (unlikely (FAILED (hr))) + FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr); + +#undef MAX_ITEMS + + int *range_char_counts = NULL; + TEXTRANGE_PROPERTIES **range_properties = NULL; + int range_count = 0; + if (num_features) { + /* TODO setup ranges */ + } + + OPENTYPE_TAG language_tag = hb_ot_tag_from_language (buffer->props.language); + + unsigned int glyphs_offset = 0; + unsigned int glyphs_len; + for (unsigned int i = 0; i < item_count; i++) + { + unsigned int chars_offset = items[i].iCharPos; + unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset; + OPENTYPE_TAG script_tag = script_tags[i]; /* XXX buffer->props.script */ + + hr = ScriptShapeOpenType (font_data->hdc, + &font_data->script_cache, + &items[i].a, + script_tag, + language_tag, + range_char_counts, + range_properties, + range_count, + wchars + chars_offset, + item_chars_len, + glyphs_size - glyphs_offset, + /* out */ + log_clusters + chars_offset, + char_props + chars_offset, + glyphs + glyphs_offset, + glyph_props + glyphs_offset, + (int *) &glyphs_len); + + if (unlikely (items[i].a.fNoGlyphIndex)) + FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); + if (unlikely (hr == E_OUTOFMEMORY)) + { + buffer->ensure (buffer->allocated * 2); + if (buffer->in_error) + FAIL ("Buffer resize failed"); + goto retry; + } + if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT)) + FAIL ("ScriptShapeOpenType() failed: Font doesn't support script"); + if (unlikely (FAILED (hr))) + FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr); + + hr = ScriptPlaceOpenType (font_data->hdc, + &font_data->script_cache, + &items[i].a, + script_tag, + language_tag, + range_char_counts, + range_properties, + range_count, + wchars + chars_offset, + log_clusters + chars_offset, + char_props + chars_offset, + item_chars_len, + glyphs + glyphs_offset, + glyph_props + glyphs_offset, + glyphs_len, + /* out */ + advances + glyphs_offset, + offsets + glyphs_offset, + NULL); + if (unlikely (FAILED (hr))) + FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr); + + glyphs_offset += glyphs_len; + } + glyphs_len = glyphs_offset; + + /* Ok, we've got everything we need, now compose output buffer, + * very, *very*, carefully! */ + + /* Calculate visual-clusters. That's what we ship. */ + for (unsigned int i = 0; i < glyphs_len; i++) + vis_clusters[i] = -1; + for (unsigned int i = 0; i < buffer->len; i++) { + uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]]; + *p = MIN (*p, buffer->info[i].cluster); + } + if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { + for (unsigned int i = 1; i < glyphs_len; i++) + if (!glyph_props[i].sva.fClusterStart) + vis_clusters[i] = vis_clusters[i - 1]; + } else { + for (int i = glyphs_len - 2; i >= 0; i--) + if (!glyph_props[i].sva.fClusterStart) + vis_clusters[i] = vis_clusters[i + 1]; + } + +#undef utf16_index + + buffer->ensure (glyphs_len); + if (buffer->in_error) + FAIL ("Buffer in error"); + +#undef FAIL + + /* Set glyph infos */ + buffer->len = 0; + for (unsigned int i = 0; i < glyphs_len; i++) + { + hb_glyph_info_t *info = &buffer->info[buffer->len++]; + + info->codepoint = glyphs[i]; + info->cluster = vis_clusters[i]; + + /* The rest is crap. Let's store position info there for now. */ + info->mask = advances[i]; + info->var1.u32 = offsets[i].du; + info->var2.u32 = offsets[i].dv; + } + + /* Set glyph positions */ + buffer->clear_positions (); + for (unsigned int i = 0; i < glyphs_len; i++) + { + hb_glyph_info_t *info = &buffer->info[i]; + hb_glyph_position_t *pos = &buffer->pos[i]; + + /* TODO vertical */ + pos->x_advance = info->mask; + pos->x_offset = info->var1.u32; + pos->y_offset = info->var2.u32; + } + + /* Wow, done! */ + return TRUE; +} + + diff --git a/third_party/harfbuzz-ng/src/hb-blob-private.h b/third_party/harfbuzz-ng/src/hb-uniscribe.h index 92109ed..dbcacd7 100644 --- a/third_party/harfbuzz-ng/src/hb-blob-private.h +++ b/third_party/harfbuzz-ng/src/hb-uniscribe.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -21,39 +21,35 @@ * 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_BLOB_PRIVATE_H -#define HB_BLOB_PRIVATE_H +#ifndef HB_UNISCRIBE_H +#define HB_UNISCRIBE_H -#include "hb-private.h" +#include "hb-common.h" +#include "hb-shape.h" -#include "hb-blob.h" +#define _WIN32_WINNT 0x0500 +#include <windows.h> HB_BEGIN_DECLS -struct _hb_blob_t { - hb_reference_count_t ref_count; +hb_bool_t +hb_uniscribe_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shaper_options); - unsigned int length; +LOGFONTW * +hb_uniscribe_font_get_logfontw (hb_font_t *font); - 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; +HFONT +hb_uniscribe_font_get_hfont (hb_font_t *font); HB_END_DECLS -#endif /* HB_BLOB_PRIVATE_H */ +#endif /* HB_UNISCRIBE_H */ diff --git a/third_party/harfbuzz-ng/src/hb-common.c b/third_party/harfbuzz-ng/src/hb-version.h index 74f8933..c1e3cab 100644 --- a/third_party/harfbuzz-ng/src/hb-common.c +++ b/third_party/harfbuzz-ng/src/hb-version.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Red Hat, Inc. + * Copyright © 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -21,27 +21,42 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ -#include "hb-private.h" +#ifndef HB_VERSION_H +#define HB_VERSION_H + +#include "hb-common.h" HB_BEGIN_DECLS -hb_tag_t -hb_tag_from_string (const char *s) -{ - char tag[4]; - unsigned int i; +#define HB_VERSION_MAJOR 0 +#define HB_VERSION_MINOR 7 +#define HB_VERSION_MICRO 0 + +#define HB_VERSION_STRING "0.7.0" + +#define HB_VERSION_CHECK(major,minor,micro) \ + ((major)*10000+(minor)*100+(micro) >= \ + HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO) - for (i = 0; i < 4 && s[i]; i++) - tag[i] = s[i]; - for (; i < 4; i++) - tag[i] = ' '; - return HB_TAG_STR (tag); -} +void +hb_version (unsigned int *major, + unsigned int *minor, + unsigned int *micro); + +const char * +hb_version_string (void); + +hb_bool_t +hb_version_check (unsigned int major, + unsigned int minor, + unsigned int micro); HB_END_DECLS + +#endif /* HB_VERSION_H */ diff --git a/third_party/harfbuzz-ng/src/hb.h b/third_party/harfbuzz-ng/src/hb.h index 691adee..0a2ebd9 100644 --- a/third_party/harfbuzz-ng/src/hb.h +++ b/third_party/harfbuzz-ng/src/hb.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Red Hat, Inc. + * Copyright © 2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -31,9 +31,9 @@ #include "hb-buffer.h" #include "hb-common.h" #include "hb-font.h" -#include "hb-language.h" #include "hb-shape.h" #include "hb-unicode.h" +#include "hb-version.h" HB_BEGIN_DECLS HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/main.cc b/third_party/harfbuzz-ng/src/main.cc index 8126dae..442b1b9 100644 --- a/third_party/harfbuzz-ng/src/main.cc +++ b/third_party/harfbuzz-ng/src/main.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007,2008,2009 Red Hat, Inc. + * Copyright © 2007,2008,2009 Red Hat, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,9 +24,9 @@ * Red Hat Author(s): Behdad Esfahbod */ -#define HB_OT_LAYOUT_CC +#include "hb-mutex-private.hh" #include "hb-open-file-private.hh" -#include "hb-ot-layout-gdef-private.hh" +#include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsubgpos-private.hh" #ifdef HAVE_GLIB @@ -35,7 +35,6 @@ #include <stdlib.h> #include <stdio.h> -HB_BEGIN_DECLS int @@ -193,4 +192,3 @@ main (int argc, char **argv) } -HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/test.c b/third_party/harfbuzz-ng/src/test.c deleted file mode 100644 index 836dd4c..0000000 --- a/third_party/harfbuzz-ng/src/test.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 eb6cc53..7100d73e 100644 --- a/third_party/harfbuzz/harfbuzz.gyp +++ b/third_party/harfbuzz/harfbuzz.gyp @@ -71,10 +71,10 @@ 'target_name': 'harfbuzz', 'type': 'none', 'dependencies': [ - '../harfbuzz-ng/harfbuzz.gyp:harfbuzz' + '../harfbuzz-ng/harfbuzz.gyp:harfbuzz-ng' ], 'export_dependent_settings': [ - '../harfbuzz-ng/harfbuzz.gyp:harfbuzz' + '../harfbuzz-ng/harfbuzz.gyp:harfbuzz-ng' ], } ] |