From e73c66cc0af9b81ea1690b8e497e25d4c0b3b12c Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 30 Apr 2013 13:02:25 +0100 Subject: [PATCH] bug 863248 - update harfbuzz to version 0.9.16 from upstream. r=jdaggett --- gfx/harfbuzz/src/Makefile.am | 19 +- gfx/harfbuzz/src/check-symbols.sh | 50 ++ gfx/harfbuzz/src/hb-atomic-private.hh | 12 +- gfx/harfbuzz/src/hb-blob.cc | 2 +- gfx/harfbuzz/src/hb-blob.h | 26 + .../src/hb-buffer-deserialize-json.hh | 643 ++++++++++++++++++ .../src/hb-buffer-deserialize-json.rl | 132 ++++ .../src/hb-buffer-deserialize-text.hh | 571 ++++++++++++++++ .../src/hb-buffer-deserialize-text.rl | 126 ++++ gfx/harfbuzz/src/hb-buffer-private.hh | 3 +- gfx/harfbuzz/src/hb-buffer-serialize.cc | 336 +++++++++ gfx/harfbuzz/src/hb-buffer.cc | 241 +------ gfx/harfbuzz/src/hb-buffer.h | 6 +- gfx/harfbuzz/src/hb-fallback-shape.cc | 1 - gfx/harfbuzz/src/hb-ft.cc | 13 +- gfx/harfbuzz/src/hb-graphite2.cc | 2 +- gfx/harfbuzz/src/hb-open-type-private.hh | 45 +- .../src/hb-ot-layout-common-private.hh | 3 +- gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh | 134 ++-- gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh | 180 +++-- .../src/hb-ot-layout-gsubgpos-private.hh | 420 ++++++++---- gfx/harfbuzz/src/hb-ot-layout-private.hh | 68 +- gfx/harfbuzz/src/hb-ot-layout.cc | 16 +- gfx/harfbuzz/src/hb-ot-map-private.hh | 43 +- gfx/harfbuzz/src/hb-ot-map.cc | 59 +- .../hb-ot-shape-complex-arabic-fallback.hh | 6 +- .../src/hb-ot-shape-complex-arabic.cc | 58 +- .../src/hb-ot-shape-complex-default.cc | 8 +- .../src/hb-ot-shape-complex-indic-machine.hh | 2 +- .../src/hb-ot-shape-complex-indic-machine.rl | 2 +- gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc | 116 ++-- .../hb-ot-shape-complex-myanmar-machine.hh | 2 +- .../hb-ot-shape-complex-myanmar-machine.rl | 2 +- .../src/hb-ot-shape-complex-myanmar.cc | 44 +- .../src/hb-ot-shape-complex-private.hh | 14 + .../src/hb-ot-shape-complex-sea-machine.hh | 2 +- .../src/hb-ot-shape-complex-sea-machine.rl | 2 +- gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc | 43 +- .../src/hb-ot-shape-fallback-private.hh | 5 + gfx/harfbuzz/src/hb-ot-shape-fallback.cc | 46 ++ .../src/hb-ot-shape-normalize-private.hh | 1 - gfx/harfbuzz/src/hb-ot-shape-normalize.cc | 15 +- gfx/harfbuzz/src/hb-ot-shape-private.hh | 37 - gfx/harfbuzz/src/hb-ot-shape.cc | 62 +- gfx/harfbuzz/src/hb-private.hh | 27 +- gfx/harfbuzz/src/hb-set-private.hh | 105 +-- gfx/harfbuzz/src/hb-set.cc | 1 - gfx/harfbuzz/src/hb-shape-plan.cc | 8 +- gfx/harfbuzz/src/hb-shape.cc | 15 +- gfx/harfbuzz/src/hb-unicode-private.hh | 10 +- gfx/harfbuzz/src/hb-version.h | 4 +- gfx/harfbuzz/src/test-buffer-serialize.cc | 126 ++++ gfx/harfbuzz/src/test.cc | 1 + layout/reftests/font-features/reftest.list | 4 +- 54 files changed, 2988 insertions(+), 931 deletions(-) create mode 100755 gfx/harfbuzz/src/check-symbols.sh create mode 100644 gfx/harfbuzz/src/hb-buffer-deserialize-json.hh create mode 100644 gfx/harfbuzz/src/hb-buffer-deserialize-json.rl create mode 100644 gfx/harfbuzz/src/hb-buffer-deserialize-text.hh create mode 100644 gfx/harfbuzz/src/hb-buffer-deserialize-text.rl create mode 100644 gfx/harfbuzz/src/hb-buffer-serialize.cc create mode 100644 gfx/harfbuzz/src/test-buffer-serialize.cc diff --git a/gfx/harfbuzz/src/Makefile.am b/gfx/harfbuzz/src/Makefile.am index 3b0444e046c..342a3fb388c 100644 --- a/gfx/harfbuzz/src/Makefile.am +++ b/gfx/harfbuzz/src/Makefile.am @@ -20,7 +20,10 @@ HBLIBS = HBSOURCES = \ hb-atomic-private.hh \ hb-blob.cc \ + hb-buffer-deserialize-json.hh \ + hb-buffer-deserialize-text.hh \ hb-buffer-private.hh \ + hb-buffer-serialize.cc \ hb-buffer.cc \ hb-cache-private.hh \ hb-common.cc \ @@ -257,11 +260,15 @@ arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt .PHONY: unicode-tables arabic-table indic-table BUILT_SOURCES += \ + hb-buffer-deserialize-json.hh \ + hb-buffer-deserialize-text.hh \ hb-ot-shape-complex-indic-machine.hh \ hb-ot-shape-complex-myanmar-machine.hh \ hb-ot-shape-complex-sea-machine.hh \ $(NULL) EXTRA_DIST += \ + hb-buffer-deserialize-json.rl \ + hb-buffer-deserialize-text.rl \ hb-ot-shape-complex-indic-machine.rl \ hb-ot-shape-complex-myanmar-machine.rl \ hb-ot-shape-complex-sea-machine.rl \ @@ -270,7 +277,13 @@ EXTRA_DIST += \ $(AM_V_GEN)$(top_srcdir)/missing --run ragel -e -F1 -o "$@.tmp" "$<" && \ mv "$@.tmp" "$@" || ( $(RM) "$@.tmp" && false ) -noinst_PROGRAMS = main test test-would-substitute test-size-params +noinst_PROGRAMS = \ + main \ + test \ + test-buffer-serialize \ + test-size-params \ + test-would-substitute \ + $(NULL) bin_PROGRAMS = main_SOURCES = main.cc @@ -289,6 +302,10 @@ test_size_params_SOURCES = test-size-params.cc test_size_params_CPPFLAGS = $(HBCFLAGS) test_size_params_LDADD = libharfbuzz.la $(HBLIBS) +test_buffer_serialize_SOURCES = test-buffer-serialize.cc +test_buffer_serialize_CPPFLAGS = $(HBCFLAGS) +test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS) + dist_check_SCRIPTS = \ check-c-linkage-decls.sh \ check-header-guards.sh \ diff --git a/gfx/harfbuzz/src/check-symbols.sh b/gfx/harfbuzz/src/check-symbols.sh new file mode 100755 index 00000000000..73bfc9e9bfc --- /dev/null +++ b/gfx/harfbuzz/src/check-symbols.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +test -z "$srcdir" && srcdir=. +test -z "$MAKE" && MAKE=make +stat=0 + +if which nm 2>/dev/null >/dev/null; then + : +else + echo "check-symbols.sh: 'nm' not found; skipping test" + exit 77 +fi + +defs="harfbuzz.def" +$MAKE $defs > /dev/null +tested=false +for def in $defs; do + lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'` + so=.libs/lib${lib}.so + + EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>' | cut -d' ' -f3`" + + if test -f "$so"; then + + echo "Checking that $so has the same symbol list as $def" + { + echo EXPORTS + echo "$EXPORTED_SYMBOLS" + # cheat: copy the last line from the def file! + tail -n1 "$def" + } | diff "$def" - >&2 || stat=1 + + echo "Checking that we are not exposing internal symbols" + if echo "$EXPORTED_SYMBOLS" | grep -v 'hb_'; then + echo "Ouch, internal symbols exposed" + stat=1 + fi + + tested=true + fi +done +if ! $tested; then + echo "check-exported-symbols.sh: libharfbuzz shared library not found; skipping test" + exit 77 +fi + +exit $stat diff --git a/gfx/harfbuzz/src/hb-atomic-private.hh b/gfx/harfbuzz/src/hb-atomic-private.hh index bb10fe1d577..9cc3bc5587c 100644 --- a/gfx/harfbuzz/src/hb-atomic-private.hh +++ b/gfx/harfbuzz/src/hb-atomic-private.hh @@ -47,22 +47,18 @@ #define WIN32_LEAN_AND_MEAN #include -/* mingw32 does not have MemoryBarrier. - * MemoryBarrier may be defined as a macro or a function. - * Just make a failsafe version for ourselves. */ -#ifdef MemoryBarrier -#define HBMemoryBarrier MemoryBarrier -#else -static inline void HBMemoryBarrier (void) { +#if defined(__MINGW32__) && !defined(MemoryBarrier) +static inline void _HBMemoryBarrier (void) { long dummy = 0; InterlockedExchange (&dummy, 1); } +# define MemoryBarrier _HBMemoryBarrier #endif typedef LONG hb_atomic_int_t; #define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) -#define hb_atomic_ptr_get(P) (HBMemoryBarrier (), (void *) *(P)) +#define hb_atomic_ptr_get(P) (MemoryBarrier (), (void *) *(P)) #define hb_atomic_ptr_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O)) diff --git a/gfx/harfbuzz/src/hb-blob.cc b/gfx/harfbuzz/src/hb-blob.cc index 3ca50fbb187..dfd134b7762 100644 --- a/gfx/harfbuzz/src/hb-blob.cc +++ b/gfx/harfbuzz/src/hb-blob.cc @@ -123,7 +123,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent, blob = hb_blob_create (parent->data + offset, MIN (length, parent->length - offset), - parent->mode, + HB_MEMORY_MODE_READONLY, hb_blob_reference (parent), (hb_destroy_func_t) hb_blob_destroy); diff --git a/gfx/harfbuzz/src/hb-blob.h b/gfx/harfbuzz/src/hb-blob.h index 1a93baa46dc..d3d0f41b11c 100644 --- a/gfx/harfbuzz/src/hb-blob.h +++ b/gfx/harfbuzz/src/hb-blob.h @@ -36,6 +36,26 @@ HB_BEGIN_DECLS +/* + * Note re various memory-modes: + * + * - In no case shall the HarfBuzz client modify memory + * that is passed to HarfBuzz in a blob. If there is + * any such possibility, MODE_DUPLICATE should be used + * such that HarfBuzz makes a copy immediately, + * + * - Use MODE_READONLY otherse, unless you really really + * really know what you are doing, + * + * - MODE_WRITABLE is appropriate if you relaly made a + * copy of data solely for the purpose of passing to + * HarfBuzz and doing that just once (no reuse!), + * + * - If the font is mmap()ed, it's ok to use + * READONLY_MAY_MAKE_WRITABLE, however, there were + * design problems with that mode, so HarfBuzz do not + * really use it anymore. If not sure, use MODE_READONLY. + */ typedef enum { HB_MEMORY_MODE_DUPLICATE, HB_MEMORY_MODE_READONLY, @@ -52,6 +72,12 @@ hb_blob_create (const char *data, void *user_data, hb_destroy_func_t destroy); +/* Always creates with MEMORY_MODE_READONLY. + * Even if the parent blob is writable, we don't + * want the user of the sub-blob to be able to + * modify the parent data as that data may be + * shared among multiple sub-blobs. + */ hb_blob_t * hb_blob_create_sub_blob (hb_blob_t *parent, unsigned int offset, diff --git a/gfx/harfbuzz/src/hb-buffer-deserialize-json.hh b/gfx/harfbuzz/src/hb-buffer-deserialize-json.hh new file mode 100644 index 00000000000..dead700db82 --- /dev/null +++ b/gfx/harfbuzz/src/hb-buffer-deserialize-json.hh @@ -0,0 +1,643 @@ + +#line 1 "../../src/hb-buffer-deserialize-json.rl" +/* + * Copyright © 2013 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_BUFFER_DESERIALIZE_JSON_HH +#define HB_BUFFER_DESERIALIZE_JSON_HH + +#include "hb-private.hh" + + +#line 36 "hb-buffer-deserialize-json.hh.tmp" +static const unsigned char _deserialize_json_trans_keys[] = { + 0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, + 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, + 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, + 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, + 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, + 65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0 +}; + +static const char _deserialize_json_key_spans[] = { + 0, 115, 26, 7, 2, 1, 50, 49, + 10, 117, 117, 117, 1, 50, 49, 10, + 117, 117, 1, 1, 50, 49, 117, 117, + 2, 1, 50, 49, 10, 117, 117, 1, + 50, 49, 10, 117, 117, 1, 50, 49, + 58, 89, 117, 117, 85, 115, 0 +}; + +static const short _deserialize_json_index_offsets[] = { + 0, 0, 116, 143, 151, 154, 156, 207, + 257, 268, 386, 504, 622, 624, 675, 725, + 736, 854, 972, 974, 976, 1027, 1077, 1195, + 1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666, + 1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069, + 2119, 2178, 2268, 2386, 2504, 2590, 2706 +}; + +static const char _deserialize_json_indicies[] = { + 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 1, 3, 3, 3, + 3, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 1, 4, 1, + 5, 1, 6, 7, 1, 1, 8, 1, + 9, 10, 1, 11, 1, 11, 11, 11, + 11, 11, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 11, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 12, 1, + 12, 12, 12, 12, 12, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 12, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 13, 1, 1, 14, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 1, 16, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 1, 18, 18, 18, + 18, 18, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 18, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 19, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 20, 1, 21, 21, 21, 21, 21, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 21, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 22, + 1, 18, 18, 18, 18, 18, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 18, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 19, 1, 1, 1, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 20, 1, 23, + 1, 23, 23, 23, 23, 23, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 23, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 24, 1, 24, 24, 24, 24, + 24, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 24, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 25, 1, 1, 26, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 1, 28, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 1, 30, 30, 30, 30, 30, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 30, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 31, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 32, 1, 30, + 30, 30, 30, 30, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 30, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 31, 1, 1, 1, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 32, 1, 33, 1, 34, + 1, 34, 34, 34, 34, 34, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 34, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 35, 1, 35, 35, 35, 35, + 35, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 35, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 36, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 1, 38, 38, + 38, 38, 38, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 38, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 39, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 40, 1, 38, 38, 38, 38, + 38, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 38, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 39, + 1, 1, 1, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 40, 1, 42, 43, 1, 44, 1, 44, + 44, 44, 44, 44, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 44, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 45, 1, 45, 45, 45, 45, 45, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 46, 1, + 1, 47, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 1, 49, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 1, 51, + 51, 51, 51, 51, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 51, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 52, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 51, 51, 51, + 51, 51, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 51, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 52, 1, 1, 1, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 53, 1, 54, 1, 54, 54, 54, + 54, 54, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 54, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 55, 1, + 55, 55, 55, 55, 55, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 55, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 56, 1, 1, 57, + 58, 58, 58, 58, 58, 58, 58, 58, + 58, 1, 59, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 1, 61, 61, 61, + 61, 61, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 61, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 62, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 63, 1, 61, 61, 61, 61, 61, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 61, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 62, 1, + 1, 1, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 63, + 1, 64, 1, 64, 64, 64, 64, 64, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 64, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 65, 1, 65, 65, + 65, 65, 65, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 65, 1, 66, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 67, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 1, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 1, 1, 1, 1, 1, 1, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 1, 70, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 71, 71, + 1, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 1, 1, 1, 1, 1, + 1, 1, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 1, 1, 1, 1, + 71, 1, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 1, 72, 72, 72, + 72, 72, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 72, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 73, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 74, 1, 72, 72, 72, 72, 72, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 72, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 73, 1, + 1, 1, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 74, + 1, 76, 76, 76, 76, 76, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 76, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 77, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 78, 1, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 0 +}; + +static const char _deserialize_json_trans_targs[] = { + 1, 0, 2, 2, 3, 4, 18, 24, + 37, 5, 12, 6, 7, 8, 9, 11, + 9, 11, 10, 2, 44, 10, 44, 13, + 14, 15, 16, 17, 16, 17, 10, 2, + 44, 19, 20, 21, 22, 23, 10, 2, + 44, 23, 25, 31, 26, 27, 28, 29, + 30, 29, 30, 10, 2, 44, 32, 33, + 34, 35, 36, 35, 36, 10, 2, 44, + 38, 39, 40, 42, 43, 41, 10, 41, + 10, 2, 44, 43, 44, 45, 46 +}; + +static const char _deserialize_json_trans_actions[] = { + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 2, + 0, 0, 3, 3, 4, 0, 5, 0, + 0, 2, 2, 2, 0, 0, 6, 6, + 7, 0, 0, 0, 2, 2, 8, 8, + 9, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 10, 10, 11, 0, 0, + 2, 2, 2, 0, 0, 12, 12, 13, + 0, 0, 0, 2, 2, 2, 14, 0, + 15, 15, 16, 0, 0, 0, 0 +}; + +static const int deserialize_json_start = 1; +static const int deserialize_json_first_final = 44; +static const int deserialize_json_error = 0; + +static const int deserialize_json_en_main = 1; + + +#line 97 "../../src/hb-buffer-deserialize-json.rl" + + +static hb_bool_t +_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, NULL); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? ',' : '[')) + { + *end_ptr = ++p; + } + + const char *tok = NULL; + int cs; + hb_glyph_info_t info; + hb_glyph_position_t pos; + +#line 466 "hb-buffer-deserialize-json.hh.tmp" + { + cs = deserialize_json_start; + } + +#line 471 "hb-buffer-deserialize-json.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 = _deserialize_json_trans_keys + (cs<<1); + _inds = _deserialize_json_indicies + _deserialize_json_index_offsets[cs]; + + _slen = _deserialize_json_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_json_trans_targs[_trans]; + + if ( _deserialize_json_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_json_trans_actions[_trans] ) { + case 1: +#line 38 "../../src/hb-buffer-deserialize-json.rl" + { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); +} + break; + case 5: +#line 43 "../../src/hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 2: +#line 51 "../../src/hb-buffer-deserialize-json.rl" + { + tok = p; +} + break; + case 14: +#line 55 "../../src/hb-buffer-deserialize-json.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 15: +#line 62 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.codepoint)) return false; } + break; + case 8: +#line 63 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 10: +#line 64 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 12: +#line 65 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 3: +#line 66 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 6: +#line 67 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } + break; + case 16: +#line 62 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.codepoint)) return false; } +#line 43 "../../src/hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 63 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "../../src/hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 64 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } +#line 43 "../../src/hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 65 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "../../src/hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 4: +#line 66 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "../../src/hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 7: +#line 67 "../../src/hb-buffer-deserialize-json.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "../../src/hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 624 "hb-buffer-deserialize-json.hh.tmp" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 125 "../../src/hb-buffer-deserialize-json.rl" + + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; +} + +#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */ diff --git a/gfx/harfbuzz/src/hb-buffer-deserialize-json.rl b/gfx/harfbuzz/src/hb-buffer-deserialize-json.rl new file mode 100644 index 00000000000..7351b2ab47c --- /dev/null +++ b/gfx/harfbuzz/src/hb-buffer-deserialize-json.rl @@ -0,0 +1,132 @@ +/* + * Copyright © 2013 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_BUFFER_DESERIALIZE_JSON_HH +#define HB_BUFFER_DESERIALIZE_JSON_HH + +#include "hb-private.hh" + +%%{ + +machine deserialize_json; +alphtype unsigned char; +write data; + +action clear_item { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); +} + +action add_item { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + +action tok { + tok = p; +} + +action parse_glyph { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + +action parse_gid { if (!parse_uint (tok, p, &info.codepoint)) return false; } +action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; } +action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; } +action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; } +action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; } +action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; } + +unum = '0' | [1-9] digit*; +num = '-'? unum; + +comma = space* ',' space*; +colon = space* ':' space*; + +glyph_id = unum; +glyph_name = alpha (alnum|'_'|'.'|'-')*; + +glyph_string = '"' (glyph_name >tok %parse_glyph) '"'; +glyph_number = (glyph_id >tok %parse_gid); + +glyph = "\"g\"" colon (glyph_string | glyph_number); +cluster = "\"cl\"" colon (unum >tok %parse_cluster); +xoffset = "\"dx\"" colon (num >tok %parse_x_offset); +yoffset = "\"dy\"" colon (num >tok %parse_y_offset); +xadvance= "\"ax\"" colon (num >tok %parse_x_advance); +yadvance= "\"ay\"" colon (num >tok %parse_y_advance); + +element = glyph | cluster | xoffset | yoffset | xadvance | yadvance; +item = + ( '{' space* element (comma element)* space* '}') + >clear_item + @add_item + ; + +main := space* item (comma item)* space* (','|']')?; + +}%% + +static hb_bool_t +_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, NULL); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? ',' : '[')) + { + *end_ptr = ++p; + } + + const char *tok = NULL; + int cs; + hb_glyph_info_t info; + hb_glyph_position_t pos; + %%{ + write init; + write exec; + }%% + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; +} + +#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */ diff --git a/gfx/harfbuzz/src/hb-buffer-deserialize-text.hh b/gfx/harfbuzz/src/hb-buffer-deserialize-text.hh new file mode 100644 index 00000000000..a38efe3a415 --- /dev/null +++ b/gfx/harfbuzz/src/hb-buffer-deserialize-text.hh @@ -0,0 +1,571 @@ + +#line 1 "../../src/hb-buffer-deserialize-text.rl" +/* + * Copyright © 2013 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_BUFFER_DESERIALIZE_TEXT_HH +#define HB_BUFFER_DESERIALIZE_TEXT_HH + +#include "hb-private.hh" + + +#line 36 "hb-buffer-deserialize-text.hh.tmp" +static const unsigned char _deserialize_text_trans_keys[] = { + 0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, + 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, + 9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 0 +}; + +static const char _deserialize_text_key_spans[] = { + 0, 114, 13, 10, 13, 10, 10, 13, + 10, 1, 13, 10, 14, 116, 116, 0, + 114, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116 +}; + +static const short _deserialize_text_index_offsets[] = { + 0, 0, 115, 129, 140, 154, 165, 176, + 190, 201, 203, 217, 228, 243, 360, 477, + 478, 593, 710, 827, 944, 1061, 1178, 1295, + 1412, 1529, 1646 +}; + +static const char _deserialize_text_indicies[] = { + 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 1, 1, 1, 1, 1, 1, + 1, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 1, 1, 1, 1, 1, + 1, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 1, 5, 1, 1, 6, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 1, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 1, 10, 1, 1, + 11, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 1, 13, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 1, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 1, 17, 1, 1, 18, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 20, + 21, 21, 21, 21, 21, 21, 21, 21, + 21, 1, 22, 1, 23, 1, 1, 24, + 25, 25, 25, 25, 25, 25, 25, 25, + 25, 1, 26, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 1, 22, 1, 1, + 1, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 1, 28, 28, 28, 28, + 28, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 28, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 29, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 30, 1, 1, 31, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 32, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 33, + 1, 34, 34, 34, 34, 34, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 34, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 35, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 36, 1, 1, 0, + 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 1, 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 1, 28, 28, 28, 28, 28, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 28, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 29, 1, 1, 1, + 1, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 1, 1, 1, 30, 1, + 1, 31, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 32, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 33, 1, 38, + 38, 38, 38, 38, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 38, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 39, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 40, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 41, 1, 42, 42, 42, 42, + 42, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 42, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 43, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 44, + 1, 42, 42, 42, 42, 42, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 42, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 43, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 44, 1, 38, 38, + 38, 38, 38, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 38, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 39, 1, 1, 1, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 40, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 41, 1, 45, 45, 45, 45, 45, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 45, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 46, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 47, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 48, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 49, 1, + 50, 50, 50, 50, 50, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 50, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 51, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 52, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 50, 50, 50, + 50, 50, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 51, + 1, 1, 1, 1, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 52, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 53, 1, 45, 45, 45, 45, 45, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 46, 1, 1, 1, + 1, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 1, 1, 1, 1, 1, + 1, 47, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 48, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 49, 1, 28, + 28, 28, 28, 28, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 28, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 29, 1, 55, 55, 1, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 1, 1, 1, 30, 1, 1, 31, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 1, 1, 32, 1, 55, 1, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 1, 33, 1, 0 +}; + +static const char _deserialize_text_trans_targs[] = { + 1, 0, 13, 17, 26, 3, 18, 21, + 18, 21, 5, 19, 20, 19, 20, 22, + 25, 8, 9, 12, 9, 12, 10, 11, + 23, 24, 23, 24, 14, 2, 6, 7, + 15, 16, 14, 15, 16, 17, 14, 4, + 15, 16, 14, 15, 16, 14, 2, 7, + 15, 16, 14, 2, 15, 16, 25, 26 +}; + +static const char _deserialize_text_trans_actions[] = { + 0, 0, 1, 1, 1, 2, 2, 2, + 0, 0, 2, 2, 2, 0, 0, 2, + 2, 2, 2, 2, 0, 0, 3, 2, + 2, 2, 0, 0, 4, 5, 5, 5, + 4, 4, 0, 0, 0, 0, 6, 7, + 6, 6, 8, 8, 8, 9, 10, 10, + 9, 9, 11, 12, 11, 11, 0, 0 +}; + +static const char _deserialize_text_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, + 0, 4, 6, 8, 8, 6, 9, 11, + 11, 9, 4 +}; + +static const int deserialize_text_start = 1; +static const int deserialize_text_first_final = 13; +static const int deserialize_text_error = 0; + +static const int deserialize_text_en_main = 1; + + +#line 91 "../../src/hb-buffer-deserialize-text.rl" + + +static hb_bool_t +_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, NULL); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? '|' : '[')) + { + *end_ptr = ++p; + } + + const char *eof = pe, *tok = NULL; + int cs; + hb_glyph_info_t info; + hb_glyph_position_t pos; + +#line 343 "hb-buffer-deserialize-text.hh.tmp" + { + cs = deserialize_text_start; + } + +#line 348 "hb-buffer-deserialize-text.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 = _deserialize_text_trans_keys + (cs<<1); + _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs]; + + _slen = _deserialize_text_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_trans_targs[_trans]; + + if ( _deserialize_text_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_trans_actions[_trans] ) { + case 2: +#line 51 "../../src/hb-buffer-deserialize-text.rl" + { + tok = p; +} + break; + case 5: +#line 55 "../../src/hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 10: +#line 62 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 3: +#line 63 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 12: +#line 64 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 7: +#line 65 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 1: +#line 38 "../../src/hb-buffer-deserialize-text.rl" + { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); +} +#line 51 "../../src/hb-buffer-deserialize-text.rl" + { + tok = p; +} + break; + case 4: +#line 55 "../../src/hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 62 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 64 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 6: +#line 65 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 66 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 480 "hb-buffer-deserialize-text.hh.tmp" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_eof_actions[cs] ) { + case 4: +#line 55 "../../src/hb-buffer-deserialize-text.rl" + { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 62 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 64 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 6: +#line 65 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 66 "../../src/hb-buffer-deserialize-text.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "../../src/hb-buffer-deserialize-text.rl" + { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 557 "hb-buffer-deserialize-text.hh.tmp" + } + } + + _out: {} + } + +#line 119 "../../src/hb-buffer-deserialize-text.rl" + + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ diff --git a/gfx/harfbuzz/src/hb-buffer-deserialize-text.rl b/gfx/harfbuzz/src/hb-buffer-deserialize-text.rl new file mode 100644 index 00000000000..8856580fbe3 --- /dev/null +++ b/gfx/harfbuzz/src/hb-buffer-deserialize-text.rl @@ -0,0 +1,126 @@ +/* + * Copyright © 2013 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_BUFFER_DESERIALIZE_TEXT_HH +#define HB_BUFFER_DESERIALIZE_TEXT_HH + +#include "hb-private.hh" + +%%{ + +machine deserialize_text; +alphtype unsigned char; +write data; + +action clear_item { + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); +} + +action add_item { + buffer->add_info (info); + if (buffer->in_error) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + +action tok { + tok = p; +} + +action parse_glyph { + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + +action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; } +action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; } +action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; } +action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; } +action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; } + +unum = '0' | [1-9] digit*; +num = '-'? unum; + +glyph_id = unum; +glyph_name = alpha (alnum|'_'|'.'|'-')*; + +glyph = (glyph_id | glyph_name) >tok %parse_glyph; +cluster = '=' (unum >tok %parse_cluster); +offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset ); +advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?; +item = + ( + glyph + cluster? + offsets? + advances? + ) + >clear_item + %add_item + ; + +main := space* item (space* '|' space* item)* space* ('|'|']')?; + +}%% + +static hb_bool_t +_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, NULL); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? '|' : '[')) + { + *end_ptr = ++p; + } + + const char *eof = pe, *tok = NULL; + int cs; + hb_glyph_info_t info; + hb_glyph_position_t pos; + %%{ + write init; + write exec; + }%% + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ diff --git a/gfx/harfbuzz/src/hb-buffer-private.hh b/gfx/harfbuzz/src/hb-buffer-private.hh index 13cf4bb0e9b..387ebd9a84c 100644 --- a/gfx/harfbuzz/src/hb-buffer-private.hh +++ b/gfx/harfbuzz/src/hb-buffer-private.hh @@ -110,6 +110,7 @@ struct hb_buffer_t { HB_INTERNAL void add (hb_codepoint_t codepoint, unsigned int cluster); + HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info); HB_INTERNAL void reverse_range (unsigned int start, unsigned int end); HB_INTERNAL void reverse (void); @@ -128,7 +129,7 @@ struct hb_buffer_t { 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); - HB_INTERNAL void output_info (hb_glyph_info_t &glyph_info); + HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info); /* 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. diff --git a/gfx/harfbuzz/src/hb-buffer-serialize.cc b/gfx/harfbuzz/src/hb-buffer-serialize.cc new file mode 100644 index 00000000000..dc47ba73e08 --- /dev/null +++ b/gfx/harfbuzz/src/hb-buffer-serialize.cc @@ -0,0 +1,336 @@ +/* + * Copyright © 2012,2013 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-buffer-private.hh" + + +static const char *serialize_formats[] = { + "text", + "json", + NULL +}; + +const char ** +hb_buffer_serialize_list_formats (void) +{ + return serialize_formats; +} + +hb_buffer_serialize_format_t +hb_buffer_serialize_format_from_string (const char *str, int len) +{ + /* Upper-case it. */ + return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020); +} + +const char * +hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) +{ + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; + case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL; + } +} + +static unsigned int +_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + /* In the following code, we know b is large enough that no overflow can happen. */ + +#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END + + if (i) + *p++ = ','; + + *p++ = '{'; + + APPEND ("\"g\":"); + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) + { + char g[128]; + hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); + *p++ = '"'; + for (char *q = g; *q; q++) { + if (*q == '"') + *p++ = '\\'; + *p++ = *q; + } + *p++ = '"'; + } + else + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster); + } + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + { + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", + pos[i].x_offset, pos[i].y_offset); + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", + pos[i].x_advance, pos[i].y_advance); + } + + *p++ = '}'; + + if (buf_size > (p - b)) + { + unsigned int l = p - b; + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + } + + return end - start; +} + +static unsigned int +_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + /* In the following code, we know b is large enough that no overflow can happen. */ + + if (i) + *p++ = '|'; + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) + { + hb_font_glyph_to_string (font, info[i].codepoint, p, 128); + p += strlen (p); + } + else + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster); + } + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + { + if (pos[i].x_offset || pos[i].y_offset) + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset); + + *p++ = '+'; + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance); + if (pos->y_advance) + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance); + } + + if (buf_size > (p - b)) + { + unsigned int l = p - b; + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + } + + return end - start; +} + +/* Returns number of items, starting at start, that were serialized. */ +unsigned int +hb_buffer_serialize_glyphs (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, /* May be NULL */ + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) +{ + assert (start <= end && end <= buffer->len); + + unsigned int sconsumed; + if (!buf_consumed) + buf_consumed = &sconsumed; + *buf_consumed = 0; + + assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || + buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + + if (unlikely (start == end)) + return 0; + + if (!font) + font = hb_font_get_empty (); + + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + return _hb_buffer_serialize_glyphs_text (buffer, start, end, + buf, buf_size, buf_consumed, + font, flags); + + case HB_BUFFER_SERIALIZE_FORMAT_JSON: + return _hb_buffer_serialize_glyphs_json (buffer, start, end, + buf, buf_size, buf_consumed, + font, flags); + + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: + return 0; + + } +} + + +static hb_bool_t +parse_uint (const char *pp, const char *end, uint32_t *pv) +{ + char buf[32]; + unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); + strncpy (buf, pp, len); + buf[len] = '\0'; + + char *p = buf; + char *pend = p; + uint32_t v; + + errno = 0; + v = strtol (p, &pend, 10); + if (errno || p == pend || pend - p != end - pp) + return false; + + *pv = v; + return true; +} + +static hb_bool_t +parse_int (const char *pp, const char *end, int32_t *pv) +{ + char buf[32]; + unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); + strncpy (buf, pp, len); + buf[len] = '\0'; + + char *p = buf; + char *pend = p; + int32_t v; + + errno = 0; + v = strtol (p, &pend, 10); + if (errno || p == pend || pend - p != end - pp) + return false; + + *pv = v; + return true; +} + +#include "hb-buffer-deserialize-json.hh" +#include "hb-buffer-deserialize-text.hh" + +hb_bool_t +hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, + const char *buf, + int buf_len, /* -1 means nul-terminated */ + const char **end_ptr, /* May be NULL */ + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format) +{ + const char *end; + if (!end_ptr) + end_ptr = &end; + *end_ptr = buf; + + assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || + buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + + if (buf_len == -1) + buf_len = strlen (buf); + + if (!buf_len) + { + *end_ptr = buf; + return false; + } + + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); + + if (!font) + font = hb_font_get_empty (); + + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + return _hb_buffer_deserialize_glyphs_text (buffer, + buf, buf_len, end_ptr, + font); + + case HB_BUFFER_SERIALIZE_FORMAT_JSON: + return _hb_buffer_deserialize_glyphs_json (buffer, + buf, buf_len, end_ptr, + font); + + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: + return false; + + } +} diff --git a/gfx/harfbuzz/src/hb-buffer.cc b/gfx/harfbuzz/src/hb-buffer.cc index c7860e9bc30..4e26250c963 100644 --- a/gfx/harfbuzz/src/hb-buffer.cc +++ b/gfx/harfbuzz/src/hb-buffer.cc @@ -214,6 +214,17 @@ hb_buffer_t::add (hb_codepoint_t codepoint, len++; } +void +hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info) +{ + if (unlikely (!ensure (len + 1))) return; + + info[len] = glyph_info; + + len++; +} + + void hb_buffer_t::remove_output (void) { @@ -315,7 +326,7 @@ hb_buffer_t::output_glyph (hb_codepoint_t glyph_index) } void -hb_buffer_t::output_info (hb_glyph_info_t &glyph_info) +hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info) { if (unlikely (!make_room_for (0, 1))) return; @@ -1064,231 +1075,3 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer) } normalize_glyphs_cluster (buffer, start, end, backward); } - - -/* - * Serialize - */ - -static const char *serialize_formats[] = { - "text", - "json", - NULL -}; - -const char ** -hb_buffer_serialize_list_formats (void) -{ - return serialize_formats; -} - -hb_buffer_serialize_format_t -hb_buffer_serialize_format_from_string (const char *str, int len) -{ - /* Upper-case it. */ - return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020); -} - -const char * -hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) -{ - switch (format) - { - case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; - case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; - default: - case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL; - } -} - -static unsigned int -_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, - hb_buffer_serialize_flags_t flags) -{ - hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); - hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); - - *buf_consumed = 0; - for (unsigned int i = start; i < end; i++) - { - char b[1024]; - char *p = b; - - /* In the following code, we know b is large enough that no overflow can happen. */ - -#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END - - if (i) - *p++ = ','; - - *p++ = '{'; - - APPEND ("\"g\":"); - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) - { - char g[128]; - hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); - *p++ = '"'; - for (char *q = g; *q; q++) { - if (*q == '"') - *p++ = '\\'; - *p++ = *q; - } - *p++ = '"'; - } - else - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); - - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster); - } - - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) - { - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", - pos[i].x_offset, pos[i].y_offset); - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", - pos[i].x_advance, pos[i].y_advance); - } - - *p++ = '}'; - - if (buf_size > (p - b)) - { - unsigned int l = p - b; - memcpy (buf, b, l); - buf += l; - buf_size -= l; - *buf_consumed += l; - *buf = '\0'; - } else - return i - start; - } - - return end - start; -} - -static unsigned int -_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, - hb_buffer_serialize_flags_t flags) -{ - hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); - hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); - hb_direction_t direction = hb_buffer_get_direction (buffer); - - *buf_consumed = 0; - for (unsigned int i = start; i < end; i++) - { - char b[1024]; - char *p = b; - - /* In the following code, we know b is large enough that no overflow can happen. */ - - if (i) - *p++ = '|'; - - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) - { - hb_font_glyph_to_string (font, info[i].codepoint, p, 128); - p += strlen (p); - } - else - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); - - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster); - } - - if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) - { - if (pos[i].x_offset || pos[i].y_offset) - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset); - - *p++ = '+'; - if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos[i].x_advance) - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance); - if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance) - p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance); - } - - if (buf_size > (p - b)) - { - unsigned int l = p - b; - memcpy (buf, b, l); - buf += l; - buf_size -= l; - *buf_consumed += l; - *buf = '\0'; - } else - return i - start; - } - - return end - start; -} - -/* Returns number of items, starting at start, that were serialized. */ -unsigned int -hb_buffer_serialize_glyphs (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, /* May be NULL */ - hb_buffer_serialize_format_t format, - hb_buffer_serialize_flags_t flags) -{ - assert (start <= end && end <= buffer->len); - - *buf_consumed = 0; - - assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || - buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); - - if (unlikely (start == end)) - return 0; - - if (!font) - font = hb_font_get_empty (); - - switch (format) - { - case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_serialize_glyphs_text (buffer, start, end, - buf, buf_size, buf_consumed, - font, flags); - - case HB_BUFFER_SERIALIZE_FORMAT_JSON: - return _hb_buffer_serialize_glyphs_json (buffer, start, end, - buf, buf_size, buf_consumed, - font, flags); - - default: - case HB_BUFFER_SERIALIZE_FORMAT_INVALID: - return 0; - - } -} - -hb_bool_t -hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, - const char *buf, - unsigned int buf_len, - unsigned int *buf_consumed, - hb_font_t *font, /* May be NULL */ - hb_buffer_serialize_format_t format) -{ - return false; -} diff --git a/gfx/harfbuzz/src/hb-buffer.h b/gfx/harfbuzz/src/hb-buffer.h index 5386e360add..55a40457193 100644 --- a/gfx/harfbuzz/src/hb-buffer.h +++ b/gfx/harfbuzz/src/hb-buffer.h @@ -304,7 +304,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, unsigned int end, char *buf, unsigned int buf_size, - unsigned int *buf_consumed, + unsigned int *buf_consumed, /* May be NULL */ hb_font_t *font, /* May be NULL */ hb_buffer_serialize_format_t format, hb_buffer_serialize_flags_t flags); @@ -312,8 +312,8 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, const char *buf, - unsigned int buf_len, - unsigned int *buf_consumed, + int buf_len, /* -1 means nul-terminated */ + const char **end_ptr, /* May be NULL */ hb_font_t *font, /* May be NULL */ hb_buffer_serialize_format_t format); diff --git a/gfx/harfbuzz/src/hb-fallback-shape.cc b/gfx/harfbuzz/src/hb-fallback-shape.cc index bdc8a80c4bd..1a1fcfbda1e 100644 --- a/gfx/harfbuzz/src/hb-fallback-shape.cc +++ b/gfx/harfbuzz/src/hb-fallback-shape.cc @@ -98,7 +98,6 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, hb_codepoint_t space; font->get_glyph (' ', 0, &space); - buffer->guess_segment_properties (); buffer->clear_positions (); unsigned int count = buffer->len; diff --git a/gfx/harfbuzz/src/hb-ft.cc b/gfx/harfbuzz/src/hb-ft.cc index 1e87c1cb324..978230cd655 100644 --- a/gfx/harfbuzz/src/hb-ft.cc +++ b/gfx/harfbuzz/src/hb-ft.cc @@ -53,14 +53,7 @@ * * - 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? + * - In the future, we should add constructors to create fonts in font space? * * - FT_Load_Glyph() is exteremely costly. Do something about it? */ @@ -242,8 +235,8 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, FT_Face ft_face = (FT_Face) font_data; hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); - if (!ret || (size && !*name)) - snprintf (name, size, "gid%u", glyph); + if (ret && (size && !*name)) + ret = false; return ret; } diff --git a/gfx/harfbuzz/src/hb-graphite2.cc b/gfx/harfbuzz/src/hb-graphite2.cc index 16ef9a4dabe..cce860694cc 100644 --- a/gfx/harfbuzz/src/hb-graphite2.cc +++ b/gfx/harfbuzz/src/hb-graphite2.cc @@ -226,7 +226,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan, gr_font *grfont = HB_SHAPER_DATA_GET (font); const char *lang = hb_language_to_string (hb_buffer_get_language (buffer)); - const char *lang_end = strchr (lang, '-'); + const char *lang_end = lang ? strchr (lang, '-') : NULL; int lang_len = lang_end ? lang_end - lang : -1; gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0); diff --git a/gfx/harfbuzz/src/hb-open-type-private.hh b/gfx/harfbuzz/src/hb-open-type-private.hh index 90f28364019..6a8b98be684 100644 --- a/gfx/harfbuzz/src/hb-open-type-private.hh +++ b/gfx/harfbuzz/src/hb-open-type-private.hh @@ -171,6 +171,10 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) (&c->debug_depth, c->get_name (), this, HB_FUNC, \ ""); +/* This limits sanitizing time on really broken fonts. */ +#ifndef HB_SANITIZE_MAX_EDITS +#define HB_SANITIZE_MAX_EDITS 100 +#endif struct hb_sanitize_context_t { @@ -178,7 +182,7 @@ struct hb_sanitize_context_t static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE; typedef bool return_t; template - inline return_t process (const T &obj) { return obj.sanitize (this); } + inline return_t dispatch (const T &obj) { return obj.sanitize (this); } static return_t default_return_value (void) { return true; } bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; } @@ -247,6 +251,9 @@ struct hb_sanitize_context_t inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) { + if (this->edit_count >= HB_SANITIZE_MAX_EDITS) + return false; + const char *p = (const char *) base; this->edit_count++; @@ -404,7 +411,7 @@ struct hb_serialize_context_t template inline Type *allocate_size (unsigned int size) { - if (unlikely (this->ran_out_of_room || this->end - this->head < size)) { + if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) { this->ran_out_of_room = true; return NULL; } @@ -684,11 +691,6 @@ struct GenericOffsetTo : OffsetType if (unlikely (!offset)) return Null(Type); return StructAtOffset (base, offset); } - inline Type& operator () (void *base) - { - unsigned int offset = *this; - return StructAtOffset (base, offset); - } inline Type& serialize (hb_serialize_context_t *c, void *base) { @@ -947,21 +949,22 @@ template struct SortedArrayOf : ArrayOf { template - inline int search (const SearchType &x) const { - unsigned int count = this->len; - /* Linear search is *much* faster for small counts. */ - if (likely (count < 32)) { - for (unsigned int i = 0; i < count; i++) - if (this->array[i].cmp (x) == 0) - return i; - return -1; - } else { - 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; + inline int search (const SearchType &x) const + { + /* Hand-coded bsearch here since this is in the hot inner loop. */ + int min = 0, max = (int) this->len - 1; + while (min <= max) + { + int mid = (min + max) / 2; + int c = this->array[mid].cmp (x); + if (c < 0) + max = mid - 1; + else if (c > 0) + min = mid + 1; + else + return mid; } + return -1; } }; diff --git a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh index e6018db1243..d139b56ab86 100644 --- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh @@ -129,8 +129,7 @@ struct RecordListOf : RecordArrayOf struct RangeRecord { inline int cmp (hb_codepoint_t g) const { - hb_codepoint_t a = start, b = end; - return g < a ? -1 : g <= b ? 0 : +1 ; + return g < start ? -1 : g <= end ? 0 : +1 ; } inline bool sanitize (hb_sanitize_context_t *c) { diff --git a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh index 59d818e8317..b2b5e9ab02e 100644 --- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh @@ -519,12 +519,12 @@ struct SinglePosFormat2 struct SinglePos { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - case 2: return TRACE_RETURN (c->process (u.format2)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + case 2: return TRACE_RETURN (c->dispatch (u.format2)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -596,6 +596,7 @@ struct PairSet unsigned int count = len; for (unsigned int i = 0; i < count; i++) { + /* TODO bsearch */ if (c->buffer->info[pos].codepoint == record->secondGlyph) { valueFormats[0].apply_value (c->font, c->direction, this, @@ -809,12 +810,12 @@ struct PairPosFormat2 struct PairPos { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - case 2: return TRACE_RETURN (c->process (u.format2)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + case 2: return TRACE_RETURN (c->dispatch (u.format2)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -878,7 +879,7 @@ struct CursivePosFormat1 TRACE_APPLY (this); /* We don't handle mark glyphs here. */ - if (c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false); + if (c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false); hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); @@ -975,11 +976,11 @@ struct CursivePosFormat1 struct CursivePos { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -1028,17 +1029,17 @@ struct MarkBasePosFormat1 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); /* now we search backwards for a non-mark glyph */ - unsigned int property; hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); + skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); do { - if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false); + if (!skippy_iter.prev ()) return TRACE_RETURN (false); /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */ if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break; skippy_iter.reject (); } while (1); /* The following assertion is too strong, so we've disabled it. */ - if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/} + if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/} unsigned int base_index = (this+baseCoverage).get_coverage (c->buffer->info[skippy_iter.idx].codepoint); if (base_index == NOT_COVERED) return TRACE_RETURN (false); @@ -1074,11 +1075,11 @@ struct MarkBasePosFormat1 struct MarkBasePos { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -1132,12 +1133,12 @@ struct MarkLigPosFormat1 if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); /* now we search backwards for a non-mark glyph */ - unsigned int property; hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false); + skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); + if (!skippy_iter.prev ()) return TRACE_RETURN (false); /* The following assertion is too strong, so we've disabled it. */ - if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/} + if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/} unsigned int j = skippy_iter.idx; unsigned int lig_index = (this+ligatureCoverage).get_coverage (c->buffer->info[j].codepoint); @@ -1195,11 +1196,11 @@ struct MarkLigPosFormat1 struct MarkLigPos { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -1248,11 +1249,11 @@ struct MarkMarkPosFormat1 if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false); /* now we search backwards for a suitable mark glyph until a non-mark glyph */ - unsigned int property; hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (!skippy_iter.prev (&property, c->lookup_props & ~LookupFlag::IgnoreFlags)) return TRACE_RETURN (false); + skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); + if (!skippy_iter.prev ()) return TRACE_RETURN (false); - if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) return TRACE_RETURN (false); + if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) { return TRACE_RETURN (false); } unsigned int j = skippy_iter.idx; @@ -1314,11 +1315,11 @@ struct MarkMarkPosFormat1 struct MarkMarkPos { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -1373,19 +1374,19 @@ struct PosLookupSubTable }; template - inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const + inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (lookup_type) { - case Single: return TRACE_RETURN (u.single.process (c)); - case Pair: return TRACE_RETURN (u.pair.process (c)); - case Cursive: return TRACE_RETURN (u.cursive.process (c)); - case MarkBase: return TRACE_RETURN (u.markBase.process (c)); - case MarkLig: return TRACE_RETURN (u.markLig.process (c)); - case MarkMark: return TRACE_RETURN (u.markMark.process (c)); - case Context: return TRACE_RETURN (u.context.process (c)); - case ChainContext: return TRACE_RETURN (u.chainContext.process (c)); - case Extension: return TRACE_RETURN (u.extension.process (c)); + case Single: return TRACE_RETURN (u.single.dispatch (c)); + case Pair: return TRACE_RETURN (u.pair.dispatch (c)); + case Cursive: return TRACE_RETURN (u.cursive.dispatch (c)); + case MarkBase: return TRACE_RETURN (u.markBase.dispatch (c)); + case MarkLig: return TRACE_RETURN (u.markLig.dispatch (c)); + case MarkMark: return TRACE_RETURN (u.markMark.dispatch (c)); + case Context: return TRACE_RETURN (u.context.dispatch (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c)); + case Extension: return TRACE_RETURN (u.extension.dispatch (c)); default: return TRACE_RETURN (c->default_return_value ()); } } @@ -1433,27 +1434,11 @@ struct PosLookup : Lookup inline const PosLookupSubTable& get_subtable (unsigned int i) const { return this+CastR > (subTable)[i]; } - template - inline typename context_t::return_t process (context_t *c) const - { - TRACE_PROCESS (this); - unsigned int lookup_type = get_type (); - unsigned int count = get_subtable_count (); - for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable (i).process (c, lookup_type); - if (c->stop_sublookup_iteration (r)) - return TRACE_RETURN (r); - } - return TRACE_RETURN (c->default_return_value ()); - } - template - static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index); - inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); c->set_recurse_func (NULL); - return TRACE_RETURN (process (c)); + return TRACE_RETURN (dispatch (c)); } template @@ -1463,7 +1448,7 @@ struct PosLookup : Lookup const Coverage *last = NULL; unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - const Coverage *coverage = &get_subtable (i).process (&c, get_type ()); + const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ()); if (coverage != last) { coverage->add_coverage (glyphs); last = coverage; @@ -1474,9 +1459,9 @@ struct PosLookup : Lookup inline bool apply_once (hb_apply_context_t *c) const { TRACE_APPLY (this); - if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property)) + if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props)) return TRACE_RETURN (false); - return TRACE_RETURN (process (c)); + return TRACE_RETURN (dispatch (c)); } static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); @@ -1495,8 +1480,8 @@ struct PosLookup : Lookup while (c->buffer->idx < c->buffer->len) { - if ((c->buffer->cur().mask & c->lookup_mask) && - digest->may_have (c->buffer->cur().codepoint) && + if (digest->may_have (c->buffer->cur().codepoint) && + (c->buffer->cur().mask & c->lookup_mask) && apply_once (c)) ret = true; else @@ -1506,6 +1491,23 @@ struct PosLookup : Lookup return ret; } + template + static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); + + template + inline typename context_t::return_t dispatch (context_t *c) const + { + TRACE_DISPATCH (this); + unsigned int lookup_type = get_type (); + unsigned int count = get_subtable_count (); + for (unsigned int i = 0; i < count; i++) { + typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type); + if (c->stop_sublookup_iteration (r)) + return TRACE_RETURN (r); + } + return TRACE_RETURN (c->default_return_value ()); + } + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); @@ -1617,11 +1619,11 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) /* Out-of-class implementation for methods recursing */ template -inline typename context_t::return_t PosLookup::process_recurse_func (context_t *c, unsigned int lookup_index) +inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); const PosLookup &l = gpos.get_lookup (lookup_index); - return l.process (c); + return l.dispatch (c); } inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) @@ -1629,11 +1631,9 @@ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int l const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); const PosLookup &l = gpos.get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; - unsigned int saved_property = c->property; c->set_lookup (l); bool ret = l.apply_once (c); c->lookup_props = saved_lookup_props; - c->property = saved_property; return ret; } diff --git a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh index 2642acbbb5c..5247c682305 100644 --- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh @@ -192,17 +192,6 @@ struct SingleSubstFormat2 struct SingleSubst { - template - inline typename context_t::return_t process (context_t *c) const - { - TRACE_PROCESS (this); - switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - case 2: return TRACE_RETURN (c->process (u.format2)); - default:return TRACE_RETURN (c->default_return_value ()); - } - } - inline bool serialize (hb_serialize_context_t *c, Supplier &glyphs, Supplier &substitutes, @@ -230,6 +219,17 @@ struct SingleSubst } } + template + inline typename context_t::return_t dispatch (context_t *c) const + { + TRACE_DISPATCH (this); + switch (u.format) { + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + case 2: return TRACE_RETURN (c->dispatch (u.format2)); + default:return TRACE_RETURN (c->default_return_value ()); + } + } + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); @@ -272,7 +272,8 @@ struct Sequence TRACE_APPLY (this); if (unlikely (!substitute.len)) return TRACE_RETURN (false); - unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; + unsigned int klass = c->buffer->cur().glyph_props() & + HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; unsigned int count = substitute.len; for (unsigned int i = 0; i < count; i++) { set_lig_props_for_component (c->buffer->cur(), i); @@ -384,16 +385,6 @@ struct MultipleSubstFormat1 struct MultipleSubst { - template - inline typename context_t::return_t process (context_t *c) const - { - TRACE_PROCESS (this); - switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); - } - } - inline bool serialize (hb_serialize_context_t *c, Supplier &glyphs, Supplier &substitute_len_list, @@ -410,6 +401,16 @@ struct MultipleSubst } } + template + inline typename context_t::return_t dispatch (context_t *c) const + { + TRACE_DISPATCH (this); + switch (u.format) { + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); + } + } + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); @@ -535,16 +536,6 @@ struct AlternateSubstFormat1 struct AlternateSubst { - template - inline typename context_t::return_t process (context_t *c) const - { - TRACE_PROCESS (this); - switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); - } - } - inline bool serialize (hb_serialize_context_t *c, Supplier &glyphs, Supplier &alternate_len_list, @@ -561,6 +552,16 @@ struct AlternateSubst } } + template + inline typename context_t::return_t dispatch (context_t *c) const + { + TRACE_DISPATCH (this); + switch (u.format) { + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); + } + } + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); @@ -637,9 +638,9 @@ struct Ligature ligate_input (c, count, &component[1], - ligGlyph, match_glyph, NULL, + ligGlyph, is_mark_ligature, total_component_count); @@ -840,16 +841,6 @@ struct LigatureSubstFormat1 struct LigatureSubst { - template - inline typename context_t::return_t process (context_t *c) const - { - TRACE_PROCESS (this); - switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); - } - } - inline bool serialize (hb_serialize_context_t *c, Supplier &first_glyphs, Supplier &ligature_per_first_glyph_count_list, @@ -869,6 +860,16 @@ struct LigatureSubst } } + template + inline typename context_t::return_t dispatch (context_t *c) const + { + TRACE_DISPATCH (this); + switch (u.format) { + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); + } + } + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); @@ -1022,11 +1023,11 @@ struct ReverseChainSingleSubstFormat1 struct ReverseChainSingleSubst { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -1069,18 +1070,18 @@ struct SubstLookupSubTable }; template - inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const + inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (lookup_type) { - case Single: return TRACE_RETURN (u.single.process (c)); - case Multiple: return TRACE_RETURN (u.multiple.process (c)); - case Alternate: return TRACE_RETURN (u.alternate.process (c)); - case Ligature: return TRACE_RETURN (u.ligature.process (c)); - case Context: return TRACE_RETURN (u.context.process (c)); - case ChainContext: return TRACE_RETURN (u.chainContext.process (c)); - case Extension: return TRACE_RETURN (u.extension.process (c)); - case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.process (c)); + case Single: return TRACE_RETURN (u.single.dispatch (c)); + case Multiple: return TRACE_RETURN (u.multiple.dispatch (c)); + case Alternate: return TRACE_RETURN (u.alternate.dispatch (c)); + case Ligature: return TRACE_RETURN (u.ligature.dispatch (c)); + case Context: return TRACE_RETURN (u.context.dispatch (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c)); + case Extension: return TRACE_RETURN (u.extension.dispatch (c)); + case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c)); default: return TRACE_RETURN (c->default_return_value ()); } } @@ -1137,34 +1138,18 @@ struct SubstLookup : Lookup return lookup_type_is_reverse (type); } - template - inline typename context_t::return_t process (context_t *c) const - { - TRACE_PROCESS (this); - unsigned int lookup_type = get_type (); - unsigned int count = get_subtable_count (); - for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable (i).process (c, lookup_type); - if (c->stop_sublookup_iteration (r)) - return TRACE_RETURN (r); - } - return TRACE_RETURN (c->default_return_value ()); - } - template - static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index); - inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); - c->set_recurse_func (process_recurse_func); - return TRACE_RETURN (process (c)); + c->set_recurse_func (dispatch_recurse_func); + return TRACE_RETURN (dispatch (c)); } inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); - c->set_recurse_func (process_recurse_func); - return TRACE_RETURN (process (c)); + c->set_recurse_func (dispatch_recurse_func); + return TRACE_RETURN (dispatch (c)); } template @@ -1174,7 +1159,7 @@ struct SubstLookup : Lookup const Coverage *last = NULL; unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - const Coverage *coverage = &get_subtable (i).process (&c, get_type ()); + const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ()); if (coverage != last) { coverage->add_coverage (glyphs); last = coverage; @@ -1187,15 +1172,15 @@ struct SubstLookup : Lookup TRACE_WOULD_APPLY (this); if (unlikely (!c->len)) return TRACE_RETURN (false); if (!digest->may_have (c->glyphs[0])) return TRACE_RETURN (false); - return TRACE_RETURN (process (c)); + return TRACE_RETURN (dispatch (c)); } inline bool apply_once (hb_apply_context_t *c) const { TRACE_APPLY (this); - if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property)) + if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props)) return TRACE_RETURN (false); - return TRACE_RETURN (process (c)); + return TRACE_RETURN (dispatch (c)); } static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); @@ -1217,8 +1202,8 @@ struct SubstLookup : Lookup while (c->buffer->idx < c->buffer->len) { - if ((c->buffer->cur().mask & c->lookup_mask) && - digest->may_have (c->buffer->cur().codepoint) && + if (digest->may_have (c->buffer->cur().codepoint) && + (c->buffer->cur().mask & c->lookup_mask) && apply_once (c)) ret = true; else @@ -1234,8 +1219,8 @@ struct SubstLookup : Lookup c->buffer->idx = c->buffer->len - 1; do { - if ((c->buffer->cur().mask & c->lookup_mask) && - digest->may_have (c->buffer->cur().codepoint) && + if (digest->may_have (c->buffer->cur().codepoint) && + (c->buffer->cur().mask & c->lookup_mask) && apply_once (c)) ret = true; else @@ -1304,6 +1289,23 @@ struct SubstLookup : Lookup ligatures_list, component_count_list, component_list)); } + template + static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); + + template + inline typename context_t::return_t dispatch (context_t *c) const + { + TRACE_DISPATCH (this); + unsigned int lookup_type = get_type (); + unsigned int count = get_subtable_count (); + for (unsigned int i = 0; i < count; i++) { + typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type); + if (c->stop_sublookup_iteration (r)) + return TRACE_RETURN (r); + } + return TRACE_RETURN (c->default_return_value ()); + } + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (this); @@ -1315,9 +1317,7 @@ struct SubstLookup : Lookup { /* The spec says all subtables of an Extension lookup should * have the same type. This is specially important if one has - * a reverse type! - * - * We just check that they are all either forward, or reverse. */ + * a reverse type! */ unsigned int type = get_subtable (0).u.extension.get_type (); unsigned int count = get_subtable_count (); for (unsigned int i = 1; i < count; i++) @@ -1387,11 +1387,11 @@ inline bool ExtensionSubst::is_reverse (void) const } template -inline typename context_t::return_t SubstLookup::process_recurse_func (context_t *c, unsigned int lookup_index) +inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); const SubstLookup &l = gsub.get_lookup (lookup_index); - return l.process (c); + return l.dispatch (c); } inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) @@ -1399,11 +1399,9 @@ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); const SubstLookup &l = gsub.get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; - unsigned int saved_property = c->property; c->set_lookup (l); bool ret = l.apply_once (c); c->lookup_props = saved_lookup_props; - c->property = saved_property; return ret; } diff --git a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh index cb0eaa5f714..f46b3782ec7 100644 --- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh @@ -38,7 +38,7 @@ namespace OT { -#define TRACE_PROCESS(this) \ +#define TRACE_DISPATCH(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ ""); @@ -60,7 +60,7 @@ struct hb_closure_context_t typedef hb_void_t return_t; typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); template - inline return_t process (const T &obj) { obj.closure (this); return HB_VOID; } + inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } return_t recurse (unsigned int lookup_index) @@ -109,7 +109,7 @@ struct hb_would_apply_context_t static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY; typedef bool return_t; template - inline return_t process (const T &obj) { return obj.would_apply (this); } + inline return_t dispatch (const T &obj) { return obj.would_apply (this); } static return_t default_return_value (void) { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } @@ -148,7 +148,7 @@ struct hb_collect_glyphs_context_t typedef hb_void_t return_t; typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); template - inline return_t process (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } + inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } return_t recurse (unsigned int lookup_index) @@ -214,7 +214,7 @@ struct hb_get_coverage_context_t static const unsigned int max_debug_depth = 0; typedef const Coverage &return_t; template - inline return_t process (const T &obj) { return obj.get_coverage (); } + inline return_t dispatch (const T &obj) { return obj.get_coverage (); } static return_t default_return_value (void) { return Null(Coverage); } hb_get_coverage_context_t (void) : @@ -241,7 +241,7 @@ struct hb_apply_context_t typedef bool return_t; typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index); template - inline return_t process (const T &obj) { return obj.apply (this); } + inline return_t dispatch (const T &obj) { return obj.apply (this); } static return_t default_return_value (void) { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } return_t recurse (unsigned int lookup_index) @@ -255,83 +255,189 @@ struct hb_apply_context_t return ret; } + unsigned int table_index; /* GSUB/GPOS */ hb_font_t *font; hb_face_t *face; hb_buffer_t *buffer; hb_direction_t direction; hb_mask_t lookup_mask; + bool auto_zwj; recurse_func_t recurse_func; unsigned int nesting_level_left; unsigned int lookup_props; - unsigned int property; /* propety of first glyph */ const GDEF &gdef; bool has_glyph_classes; unsigned int debug_depth; - hb_apply_context_t (hb_font_t *font_, + hb_apply_context_t (unsigned int table_index_, + hb_font_t *font_, hb_buffer_t *buffer_, - hb_mask_t lookup_mask_) : + hb_mask_t lookup_mask_, + bool auto_zwj_) : + table_index (table_index_), font (font_), face (font->face), buffer (buffer_), direction (buffer_->props.direction), lookup_mask (lookup_mask_), + auto_zwj (auto_zwj_), recurse_func (NULL), nesting_level_left (MAX_NESTING_LEVEL), - lookup_props (0), property (0), + lookup_props (0), gdef (*hb_ot_layout_from_face (face)->gdef), has_glyph_classes (gdef.has_glyph_classes ()), debug_depth (0) {} - void set_recurse_func (recurse_func_t func) { recurse_func = func; } - void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } - void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } + inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } + inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } + inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } + + struct matcher_t + { + inline matcher_t (void) : + lookup_props (0), + ignore_zwnj (false), + ignore_zwj (false), + mask (-1), +#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */ + syllable arg1(0), +#undef arg1 + match_func (NULL), + match_data (NULL) {}; + + typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); + + inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } + inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } + inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } + inline void set_mask (hb_mask_t mask_) { mask = mask_; } + inline void set_syllable (uint8_t syllable_) { syllable = syllable_; } + inline void set_match_func (match_func_t match_func_, + const void *match_data_) + { match_func = match_func_; match_data = match_data_; } + + enum may_match_t { + MATCH_NO, + MATCH_YES, + MATCH_MAYBE + }; + + inline may_match_t may_match (const hb_glyph_info_t &info, + const USHORT *glyph_data) const + { + if (!(info.mask & mask) || + (syllable && syllable != info.syllable ())) + return MATCH_NO; + + if (match_func) + return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; + + return MATCH_MAYBE; + } + + enum may_skip_t { + SKIP_NO, + SKIP_YES, + SKIP_MAYBE + }; + + inline may_skip_t + may_skip (const hb_apply_context_t *c, + const hb_glyph_info_t &info) const + { + unsigned int property; + + property = info.glyph_props(); + + if (!c->match_properties (info.codepoint, property, lookup_props)) + return SKIP_YES; + + if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && + (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && + (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && + !is_a_ligature (info))) + return SKIP_MAYBE; + + return SKIP_NO; + } + + protected: + unsigned int lookup_props; + bool ignore_zwnj; + bool ignore_zwj; + hb_mask_t mask; + uint8_t syllable; + match_func_t match_func; + const void *match_data; + }; struct skipping_forward_iterator_t { inline skipping_forward_iterator_t (hb_apply_context_t *c_, unsigned int start_index_, unsigned int num_items_, - bool context_match = false) + bool context_match = false) : + idx (start_index_), + c (c_), + match_glyph_data (NULL), + num_items (num_items_), + end (c->buffer->len) { - c = c_; - idx = start_index_; - num_items = num_items_; - mask = context_match ? -1 : c->lookup_mask; - syllable = context_match ? 0 : c->buffer->cur().syllable (); - end = c->buffer->len; + matcher.set_lookup_props (c->lookup_props); + /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ + matcher.set_ignore_zwnj (context_match || c->table_index == 1); + /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ + matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); + if (!context_match) + matcher.set_mask (c->lookup_mask); + matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } - inline bool has_no_chance (void) const + inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } + inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } + inline void set_match_func (matcher_t::match_func_t match_func, + const void *match_data, + const USHORT glyph_data[]) { - return unlikely (num_items && idx + num_items >= end); + matcher.set_match_func (match_func, match_data); + match_glyph_data = glyph_data; } - inline void reject (void) - { - num_items++; - } - inline bool next (unsigned int *property_out, - unsigned int lookup_props) + + inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); } + inline void reject (void) { num_items++; match_glyph_data--; } + inline bool next (void) { assert (num_items > 0); - do + while (!has_no_chance ()) { - if (has_no_chance ()) - return false; idx++; - } while (c->should_skip (&c->buffer->info[idx], lookup_props, property_out)); - num_items--; - return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ()); - } - inline bool next (unsigned int *property_out = NULL) - { - return next (property_out, c->lookup_props); + const hb_glyph_info_t &info = c->buffer->info[idx]; + + matcher_t::may_skip_t skip = matcher.may_skip (c, info); + if (unlikely (skip == matcher_t::SKIP_YES)) + continue; + + matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); + if (match == matcher_t::MATCH_YES || + (match == matcher_t::MATCH_MAYBE && + skip == matcher_t::SKIP_NO)) + { + num_items--; + match_glyph_data++; + return true; + } + + if (skip == matcher_t::SKIP_NO) + return false; + } + return false; } unsigned int idx; protected: hb_apply_context_t *c; + matcher_t matcher; + const USHORT *match_glyph_data; + unsigned int num_items; - hb_mask_t mask; - uint8_t syllable; unsigned int end; }; @@ -340,47 +446,69 @@ struct hb_apply_context_t inline skipping_backward_iterator_t (hb_apply_context_t *c_, unsigned int start_index_, unsigned int num_items_, - hb_mask_t mask_ = 0, - bool match_syllable_ = true) + bool context_match = false) : + idx (start_index_), + c (c_), + match_glyph_data (NULL), + num_items (num_items_) { - c = c_; - idx = start_index_; - num_items = num_items_; - mask = mask_ ? mask_ : c->lookup_mask; - syllable = match_syllable_ ? c->buffer->cur().syllable () : 0; + matcher.set_lookup_props (c->lookup_props); + /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ + matcher.set_ignore_zwnj (context_match || c->table_index == 1); + /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ + matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); + if (!context_match) + matcher.set_mask (c->lookup_mask); + matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } - inline bool has_no_chance (void) const + inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } + inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } + inline void set_match_func (matcher_t::match_func_t match_func, + const void *match_data, + const USHORT glyph_data[]) { - return unlikely (idx < num_items); + matcher.set_match_func (match_func, match_data); + match_glyph_data = glyph_data; } - inline void reject (void) - { - num_items++; - } - inline bool prev (unsigned int *property_out, - unsigned int lookup_props) + + inline bool has_no_chance (void) const { return unlikely (idx < num_items); } + inline void reject (void) { num_items++; } + inline bool prev (void) { assert (num_items > 0); - do + while (!has_no_chance ()) { - if (has_no_chance ()) - return false; idx--; - } while (c->should_skip (&c->buffer->out_info[idx], lookup_props, property_out)); - num_items--; - return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ()); - } - inline bool prev (unsigned int *property_out = NULL) - { - return prev (property_out, c->lookup_props); + const hb_glyph_info_t &info = c->buffer->out_info[idx]; + + matcher_t::may_skip_t skip = matcher.may_skip (c, info); + + if (unlikely (skip == matcher_t::SKIP_YES)) + continue; + + matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); + if (match == matcher_t::MATCH_YES || + (match == matcher_t::MATCH_MAYBE && + skip == matcher_t::SKIP_NO)) + { + num_items--; + match_glyph_data++; + return true; + } + + if (skip == matcher_t::SKIP_NO) + return false; + } + return false; } unsigned int idx; protected: hb_apply_context_t *c; + matcher_t matcher; + const USHORT *match_glyph_data; + unsigned int num_items; - hb_mask_t mask; - uint8_t syllable; }; inline bool @@ -423,37 +551,15 @@ struct hb_apply_context_t inline bool check_glyph_property (hb_glyph_info_t *info, - unsigned int lookup_props, - unsigned int *property_out) const + unsigned int lookup_props) const { unsigned int property; property = info->glyph_props(); - *property_out = property; return match_properties (info->codepoint, property, lookup_props); } - inline bool - should_skip (hb_glyph_info_t *info, - unsigned int lookup_props, - unsigned int *property_out) const - { - unsigned int property; - - property = info->glyph_props(); - if (property_out) - *property_out = property; - - return !match_properties (info->codepoint, property, lookup_props); - } - - - inline bool should_skip_current_glyph (void) const - { - return should_skip (&buffer->cur(), lookup_props, NULL); - } - inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const { if (likely (has_glyph_classes)) @@ -598,6 +704,7 @@ static inline bool match_input (hb_apply_context_t *c, TRACE_APPLY (NULL); hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); + skippy_iter.set_match_func (match_func, match_data, input); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); /* @@ -618,7 +725,7 @@ static inline bool match_input (hb_apply_context_t *c, * ligate with a conjunct...) */ - bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK); + bool is_mark_ligature = !!(c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); unsigned int total_component_count = 0; total_component_count += get_lig_num_comps (c->buffer->cur()); @@ -628,11 +735,7 @@ static inline bool match_input (hb_apply_context_t *c, for (unsigned int i = 1; i < count; i++) { - unsigned int property; - - if (!skippy_iter.next (&property)) return TRACE_RETURN (false); - - if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return TRACE_RETURN (false); + if (!skippy_iter.next ()) return TRACE_RETURN (false); unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]); unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]); @@ -651,7 +754,7 @@ static inline bool match_input (hb_apply_context_t *c, return TRACE_RETURN (false); } - is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK); + is_mark_ligature = is_mark_ligature && (c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK); total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]); } @@ -668,13 +771,17 @@ static inline bool match_input (hb_apply_context_t *c, } static inline void ligate_input (hb_apply_context_t *c, unsigned int count, /* Including the first glyph (not matched) */ - const USHORT input[] HB_UNUSED, /* Array of input values--start with second glyph */ + const USHORT input[], /* Array of input values--start with second glyph */ + match_func_t match_func, + const void *match_data, hb_codepoint_t lig_glyph, - match_func_t match_func HB_UNUSED, - const void *match_data HB_UNUSED, bool is_mark_ligature, unsigned int total_component_count) { + hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); + skippy_iter.set_match_func (match_func, match_data, input); + if (skippy_iter.has_no_chance ()) return; + /* * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave * the ligature to keep its old ligature id. This will allow it to attach to @@ -715,7 +822,9 @@ static inline void ligate_input (hb_apply_context_t *c, for (unsigned int i = 1; i < count; i++) { - while (c->should_skip_current_glyph ()) + if (!skippy_iter.next ()) return; + + while (c->buffer->idx < skippy_iter.idx) { if (!is_mark_ligature) { unsigned int new_lig_comp = components_so_far - last_num_components + @@ -755,18 +864,13 @@ static inline bool match_backtrack (hb_apply_context_t *c, TRACE_APPLY (NULL); hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); - if (skippy_iter.has_no_chance ()) - return TRACE_RETURN (false); + skippy_iter.set_match_func (match_func, match_data, backtrack); + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); for (unsigned int i = 0; i < count; i++) - { if (!skippy_iter.prev ()) return TRACE_RETURN (false); - if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data))) - return TRACE_RETURN (false); - } - return TRACE_RETURN (true); } @@ -780,18 +884,13 @@ static inline bool match_lookahead (hb_apply_context_t *c, TRACE_APPLY (NULL); hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); - if (skippy_iter.has_no_chance ()) - return TRACE_RETURN (false); + skippy_iter.set_match_func (match_func, match_data, lookahead); + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); for (unsigned int i = 0; i < count; i++) - { if (!skippy_iter.next ()) return TRACE_RETURN (false); - if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data))) - return TRACE_RETURN (false); - } - return TRACE_RETURN (true); } @@ -824,6 +923,9 @@ static inline void recurse_lookups (context_t *c, static inline bool apply_lookup (hb_apply_context_t *c, unsigned int count, /* Including the first glyph */ + const USHORT input[], /* Array of input values--start with second glyph */ + match_func_t match_func, + const void *match_data, unsigned int lookupCount, const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) { @@ -840,17 +942,46 @@ static inline bool apply_lookup (hb_apply_context_t *c, * and we jump out of it. Not entirely disastrous. So we don't check * for reverse lookup here. */ - for (unsigned int i = 0; i < count; /* NOP */) + + hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); + skippy_iter.set_match_func (match_func, match_data, input); + uint8_t syllable = c->buffer->cur().syllable(); + + unsigned int i = 0; + if (lookupCount && 0 == lookupRecord->sequenceIndex) { - if (unlikely (c->buffer->idx == end)) - return TRACE_RETURN (true); - while (c->should_skip_current_glyph ()) + unsigned int old_pos = c->buffer->idx; + + /* Apply a lookup */ + bool done = c->recurse (lookupRecord->lookupListIndex); + + lookupRecord++; + lookupCount--; + /* Err, this is wrong if the lookup jumped over some glyphs */ + i += c->buffer->idx - old_pos; + + if (!done) + goto not_applied; + else { - /* No lookup applied for this index */ - c->buffer->next_glyph (); - if (unlikely (c->buffer->idx == end)) - return TRACE_RETURN (true); + /* Reinitialize iterator. */ + hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i); + tmp.set_syllable (syllable); + skippy_iter = tmp; } + } + else + { + not_applied: + /* No lookup applied for this index */ + c->buffer->next_glyph (); + i++; + } + while (i < count) + { + if (!skippy_iter.next ()) return TRACE_RETURN (true); + while (c->buffer->idx < skippy_iter.idx) + c->buffer->next_glyph (); if (lookupCount && i == lookupRecord->sequenceIndex) { @@ -863,15 +994,20 @@ static inline bool apply_lookup (hb_apply_context_t *c, lookupCount--; /* Err, this is wrong if the lookup jumped over some glyphs */ i += c->buffer->idx - old_pos; - if (unlikely (c->buffer->idx == end)) - return TRACE_RETURN (true); if (!done) - goto not_applied; + goto not_applied2; + else + { + /* Reinitialize iterator. */ + hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i); + tmp.set_syllable (syllable); + skippy_iter = tmp; + } } else { - not_applied: + not_applied2: /* No lookup applied for this index */ c->buffer->next_glyph (); i++; @@ -953,7 +1089,8 @@ static inline bool context_apply_lookup (hb_apply_context_t *c, inputCount, input, lookup_context.funcs.match, lookup_context.match_data) && apply_lookup (c, - inputCount, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data, lookupCount, lookupRecord); } @@ -1348,13 +1485,13 @@ struct ContextFormat3 struct Context { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - case 2: return TRACE_RETURN (c->process (u.format2)); - case 3: return TRACE_RETURN (c->process (u.format3)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + case 2: return TRACE_RETURN (c->dispatch (u.format2)); + case 3: return TRACE_RETURN (c->dispatch (u.format3)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -1489,7 +1626,8 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c, lookup_context.funcs.match, lookup_context.match_data[2], lookahead_offset) && apply_lookup (c, - inputCount, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data[1], lookupCount, lookupRecord); } @@ -1963,13 +2101,13 @@ struct ChainContextFormat3 struct ChainContext { template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - TRACE_PROCESS (this); + TRACE_DISPATCH (this); switch (u.format) { - case 1: return TRACE_RETURN (c->process (u.format1)); - case 2: return TRACE_RETURN (c->process (u.format2)); - case 3: return TRACE_RETURN (c->process (u.format3)); + case 1: return TRACE_RETURN (c->dispatch (u.format1)); + case 2: return TRACE_RETURN (c->dispatch (u.format2)); + case 3: return TRACE_RETURN (c->dispatch (u.format3)); default:return TRACE_RETURN (c->default_return_value ()); } } @@ -2043,9 +2181,9 @@ struct Extension } template - inline typename context_t::return_t process (context_t *c) const + inline typename context_t::return_t dispatch (context_t *c) const { - return get_subtable ().process (c, get_type ()); + return get_subtable ().dispatch (c, get_type ()); } inline bool sanitize_self (hb_sanitize_context_t *c) { diff --git a/gfx/harfbuzz/src/hb-ot-layout-private.hh b/gfx/harfbuzz/src/hb-ot-layout-private.hh index b550fa880b8..4866c419125 100644 --- a/gfx/harfbuzz/src/hb-ot-layout-private.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-private.hh @@ -43,6 +43,58 @@ #define syllable() var1.u8[2] /* GSUB/GPOS shaping boundaries */ #define lig_props() var1.u8[3] /* GSUB/GPOS ligature tracking */ +/* buffer var allocations, used during the entire shaping process */ +#define unicode_props0() var2.u8[0] +#define unicode_props1() var2.u8[1] + + +inline void +_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode) +{ + info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) | + (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0) | + (info->codepoint == 0x200C ? 0x40 : 0) | + (info->codepoint == 0x200D ? 0x20 : 0); + info->unicode_props1() = unicode->modified_combining_class (info->codepoint); +} + +inline hb_unicode_general_category_t +_hb_glyph_info_get_general_category (const hb_glyph_info_t *info) +{ + return (hb_unicode_general_category_t) (info->unicode_props0() & 0x1F); +} + +inline void +_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class) +{ + info->unicode_props1() = modified_class; +} + +inline unsigned int +_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) +{ + return info->unicode_props1(); +} + +inline hb_bool_t +_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info) +{ + return !!(info->unicode_props0() & 0x80); +} + +inline hb_bool_t +_hb_glyph_info_is_zwnj (const hb_glyph_info_t *info) +{ + return !!(info->unicode_props0() & 0x40); +} + +inline hb_bool_t +_hb_glyph_info_is_zwj (const hb_glyph_info_t *info) +{ + return !!(info->unicode_props0() & 0x20); +} + + #define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot) /* @@ -50,11 +102,11 @@ */ typedef enum { - HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED = 0x0001, - HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x0002, - HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE = 0x0004, - HB_OT_LAYOUT_GLYPH_PROPS_MARK = 0x0008, - HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT = 0x0010 + HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED = 1 << HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED, + HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 1 << HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH, + HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE = 1 << HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE, + HB_OT_LAYOUT_GLYPH_PROPS_MARK = 1 << HB_OT_LAYOUT_GLYPH_CLASS_MARK, + HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT = 1 << HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT } hb_ot_layout_glyph_class_mask_t; @@ -154,7 +206,8 @@ HB_INTERNAL hb_bool_t hb_ot_layout_substitute_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask); + hb_mask_t mask, + hb_bool_t auto_zwj); /* Should be called after all the substitute_lookup's are done */ HB_INTERNAL void @@ -171,7 +224,8 @@ HB_INTERNAL hb_bool_t hb_ot_layout_position_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask); + hb_mask_t mask, + hb_bool_t auto_zwj); /* Should be called after all the position_lookup's are done */ HB_INTERNAL void diff --git a/gfx/harfbuzz/src/hb-ot-layout.cc b/gfx/harfbuzz/src/hb-ot-layout.cc index 291ff9a95ec..c80ca7d7f70 100644 --- a/gfx/harfbuzz/src/hb-ot-layout.cc +++ b/gfx/harfbuzz/src/hb-ot-layout.cc @@ -70,9 +70,15 @@ _hb_ot_layout_create (hb_face_t *face) } for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) + { + layout->gsub_digests[i].init (); layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]); + } for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) + { + layout->gpos_digests[i].init (); layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]); + } return layout; } @@ -666,11 +672,12 @@ hb_bool_t hb_ot_layout_substitute_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask) + hb_mask_t mask, + hb_bool_t auto_zwj) { if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false; - OT::hb_apply_context_t c (font, buffer, mask); + OT::hb_apply_context_t c (0, font, buffer, mask, auto_zwj); const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index); @@ -715,11 +722,12 @@ hb_bool_t hb_ot_layout_position_lookup (hb_font_t *font, hb_buffer_t *buffer, unsigned int lookup_index, - hb_mask_t mask) + hb_mask_t mask, + hb_bool_t auto_zwj) { if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false; - OT::hb_apply_context_t c (font, buffer, mask); + OT::hb_apply_context_t c (1, font, buffer, mask, auto_zwj); const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index); diff --git a/gfx/harfbuzz/src/hb-ot-map-private.hh b/gfx/harfbuzz/src/hb-ot-map-private.hh index b140207aa97..a679fb5990e 100644 --- a/gfx/harfbuzz/src/hb-ot-map-private.hh +++ b/gfx/harfbuzz/src/hb-ot-map-private.hh @@ -49,14 +49,16 @@ struct hb_ot_map_t unsigned int shift; hb_mask_t mask; hb_mask_t _1_mask; /* mask for value=1, for quick access */ - hb_bool_t needs_fallback; + unsigned int needs_fallback : 1; + unsigned int auto_zwj : 1; static int cmp (const feature_map_t *a, const feature_map_t *b) { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; } }; struct lookup_map_t { - unsigned int index; + unsigned short index; + unsigned short auto_zwj : 1; hb_mask_t mask; static int cmp (const lookup_map_t *a, const lookup_map_t *b) @@ -136,7 +138,8 @@ struct hb_ot_map_t HB_INTERNAL void add_lookups (hb_face_t *face, unsigned int table_index, unsigned int feature_index, - hb_mask_t mask); + hb_mask_t mask, + bool auto_zwj); hb_mask_t global_mask; @@ -145,6 +148,30 @@ struct hb_ot_map_t hb_prealloced_array_t pauses[2]; /* GSUB/GPOS */ }; +enum hb_ot_map_feature_flags_t { + F_NONE = 0x0000, + F_GLOBAL = 0x0001, + F_HAS_FALLBACK = 0x0002, + F_MANUAL_ZWJ = 0x0004 +}; +/* Macro version for where const is desired. */ +#define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r))) +inline hb_ot_map_feature_flags_t +operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r) +{ return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); } +inline hb_ot_map_feature_flags_t +operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r) +{ return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); } +inline hb_ot_map_feature_flags_t +operator ~ (hb_ot_map_feature_flags_t r) +{ return hb_ot_map_feature_flags_t (~(unsigned int) r); } +inline hb_ot_map_feature_flags_t& +operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r) +{ l = l | r; return l; } +inline hb_ot_map_feature_flags_t& +operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r) +{ l = l & r; return l; } + struct hb_ot_map_builder_t { @@ -153,10 +180,11 @@ struct hb_ot_map_builder_t HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_, const hb_segment_properties_t *props_); - HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback = false); + HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, + hb_ot_map_feature_flags_t flags); - inline void add_bool_feature (hb_tag_t tag, bool global = true, bool has_fallback = false) - { add_feature (tag, 1, global, has_fallback); } + inline void add_global_bool_feature (hb_tag_t tag) + { add_feature (tag, 1, F_GLOBAL); } inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func) { add_pause (0, pause_func); } @@ -177,8 +205,7 @@ struct hb_ot_map_builder_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 */ - bool has_fallback; /* whether to allocate bits even if feature not found */ + hb_ot_map_feature_flags_t flags; unsigned int default_value; /* for non-global features, what should the unset glyphs take */ unsigned int stage[2]; /* GSUB/GPOS */ diff --git a/gfx/harfbuzz/src/hb-ot-map.cc b/gfx/harfbuzz/src/hb-ot-map.cc index 62f7904b2f9..85e6e16375a 100644 --- a/gfx/harfbuzz/src/hb-ot-map.cc +++ b/gfx/harfbuzz/src/hb-ot-map.cc @@ -33,7 +33,8 @@ void hb_ot_map_t::add_lookups (hb_face_t *face, unsigned int table_index, unsigned int feature_index, - hb_mask_t mask) + hb_mask_t mask, + bool auto_zwj) { unsigned int lookup_indices[32]; unsigned int offset, len; @@ -53,6 +54,7 @@ hb_ot_map_t::add_lookups (hb_face_t *face, return; lookup->mask = mask; lookup->index = lookup_indices[i]; + lookup->auto_zwj = auto_zwj; } offset += len; @@ -84,16 +86,16 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_, } } -void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback) +void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, + hb_ot_map_feature_flags_t flags) { 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->has_fallback = has_fallback; - info->default_value = global ? value : 0; + info->flags = flags; + info->default_value = (flags & F_GLOBAL) ? value : 0; info->stage[0] = current_stage[0]; info->stage[1] = current_stage[1]; } @@ -108,7 +110,10 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h 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++) - hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_substitute_lookup (font, buffer, + lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_zwj); buffer->clear_output (); @@ -117,7 +122,9 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h } for (; i < lookups[table_index].len; i++) - hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_substitute_lookup (font, buffer, lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_zwj); } void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const @@ -128,14 +135,18 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_ 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++) - hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_zwj); if (pause->callback) pause->callback (plan, font, buffer); } for (; i < lookups[table_index].len; i++) - hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); + hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, + lookups[table_index][i].mask, + lookups[table_index][i].auto_zwj); } void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const @@ -176,18 +187,18 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) if (feature_infos[i].tag != feature_infos[j].tag) feature_infos[++j] = feature_infos[i]; else { - if (feature_infos[i].global) { - feature_infos[j].global = true; + if (feature_infos[i].flags & F_GLOBAL) { + feature_infos[j].flags |= F_GLOBAL; 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].flags &= ~F_GLOBAL; feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value); + /* Inherit default_value from j */ } - feature_infos[j].has_fallback = feature_infos[j].has_fallback || feature_infos[i].has_fallback; + feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK); 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_infos.shrink (j + 1); } @@ -200,7 +211,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) unsigned int bits_needed; - if (info->global && info->max_value == 1) + if ((info->flags & F_GLOBAL) && info->max_value == 1) /* Uses the global bit */ bits_needed = 0; else @@ -219,7 +230,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) language_index[table_index], info->tag, &feature_index[table_index]); - if (!found && !info->has_fallback) + if (!found && !(info->flags & F_HAS_FALLBACK)) continue; @@ -232,7 +243,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) 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) { + map->auto_zwj = !(info->flags & F_MANUAL_ZWJ); + if ((info->flags & F_GLOBAL) && info->max_value == 1) { /* Uses the global bit */ map->shift = 0; map->mask = 1; @@ -240,8 +252,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) map->shift = next_bit; map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit); next_bit += bits_needed; - if (info->global) - m.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; map->needs_fallback = !found; @@ -264,7 +275,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) script_index[table_index], language_index[table_index], &required_feature_index)) - m.add_lookups (face, table_index, required_feature_index, 1); + m.add_lookups (face, table_index, required_feature_index, 1, true); unsigned int pause_index = 0; unsigned int last_num_lookups = 0; @@ -272,7 +283,10 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) { 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); + m.add_lookups (face, table_index, + m.features[i].index[table_index], + m.features[i].mask, + m.features[i].auto_zwj); /* Sort lookups and merge duplicates */ if (last_num_lookups < m.lookups[table_index].len) @@ -284,7 +298,10 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m) 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][j].auto_zwj &= m.lookups[table_index][i].auto_zwj; + } m.lookups[table_index].shrink (j + 1); } diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh index 4fcd0a2fd94..996e40e8dd8 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh @@ -212,7 +212,9 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, if (unlikely (!fallback_plan)) return const_cast (&arabic_fallback_plan_nil); - for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) { + for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) + { + fallback_plan->digest_array[i].init (); fallback_plan->mask_array[i] = plan->map.get_1_mask (arabic_fallback_features[i]); if (fallback_plan->mask_array[i]) { fallback_plan->lookup_array[i] = arabic_fallback_synthesize_lookup (plan, font, i); @@ -244,7 +246,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan, { for (unsigned int i = 0; i < ARABIC_NUM_FALLBACK_FEATURES; i++) if (fallback_plan->lookup_array[i]) { - OT::hb_apply_context_t c (font, buffer, fallback_plan->mask_array[i]); + OT::hb_apply_context_t c (0, font, buffer, fallback_plan->mask_array[i], true/*auto_zwj*/); fallback_plan->lookup_array[i]->apply_string (&c, &fallback_plan->digest_array[i]); } } diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc index 3374cfc9a3d..2f069d05f61 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-arabic.cc @@ -37,17 +37,16 @@ */ enum { JOINING_TYPE_U = 0, - JOINING_TYPE_R = 1, - JOINING_TYPE_D = 2, + JOINING_TYPE_L = 1, + JOINING_TYPE_R = 2, + JOINING_TYPE_D = 3, JOINING_TYPE_C = JOINING_TYPE_D, - JOINING_GROUP_ALAPH = 3, - JOINING_GROUP_DALATH_RISH = 4, - NUM_STATE_MACHINE_COLS = 5, + JOINING_GROUP_ALAPH = 4, + JOINING_GROUP_DALATH_RISH = 5, + NUM_STATE_MACHINE_COLS = 6, - /* We deliberately don't have a JOINING_TYPE_L since that's unused in Unicode. */ - - JOINING_TYPE_T = 6, - JOINING_TYPE_X = 7 /* means: use general-category to choose between U or T. */ + JOINING_TYPE_T = 7, + JOINING_TYPE_X = 8 /* means: use general-category to choose between U or T. */ }; /* @@ -81,8 +80,7 @@ static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_categ if (unlikely (hb_in_range (u, 0xA840, 0xA872))) { if (unlikely (u == 0xA872)) - /* XXX Looks like this should be TYPE_L, but we don't support that yet! */ - return JOINING_TYPE_R; + return JOINING_TYPE_L; return JOINING_TYPE_D; } @@ -133,28 +131,28 @@ static const struct arabic_state_table_entry { uint16_t next_state; } arabic_state_table[][NUM_STATE_MACHINE_COLS] = { - /* jt_U, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */ + /* jt_U, jt_L, jt_R, jt_D, jg_ALAPH, jg_DALATH_RISH */ /* State 0: prev was U, not willing to join. */ - { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, }, + { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,6}, }, /* State 1: prev was R or ISOL/ALAPH, not willing to join. */ - { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, }, + { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN2,5}, {NONE,ISOL,6}, }, - /* State 2: prev was D/ISOL, willing to join. */ - { {NONE,NONE,0}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, }, + /* State 2: prev was D/L in ISOL form, willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {INIT,FINA,1}, {INIT,FINA,3}, {INIT,FINA,4}, {INIT,FINA,6}, }, - /* State 3: prev was D/FINA, willing to join. */ - { {NONE,NONE,0}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, }, + /* State 3: prev was D in FINA form, willing to join. */ + { {NONE,NONE,0}, {NONE,ISOL,2}, {MEDI,FINA,1}, {MEDI,FINA,3}, {MEDI,FINA,4}, {MEDI,FINA,6}, }, /* State 4: prev was FINA ALAPH, not willing to join. */ - { {NONE,NONE,0}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, }, + { {NONE,NONE,0}, {NONE,ISOL,2}, {MED2,ISOL,1}, {MED2,ISOL,2}, {MED2,FIN2,5}, {MED2,ISOL,6}, }, /* State 5: prev was FIN2/FIN3 ALAPH, not willing to join. */ - { {NONE,NONE,0}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, }, + { {NONE,NONE,0}, {NONE,ISOL,2}, {ISOL,ISOL,1}, {ISOL,ISOL,2}, {ISOL,FIN2,5}, {ISOL,ISOL,6}, }, /* State 6: prev was DALATH/RISH, not willing to join. */ - { {NONE,NONE,0}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, } + { {NONE,NONE,0}, {NONE,ISOL,2}, {NONE,ISOL,1}, {NONE,ISOL,2}, {NONE,FIN3,5}, {NONE,ISOL,6}, } }; @@ -178,25 +176,25 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) * 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_global_bool_feature (HB_TAG('c','c','m','p')); + map->add_global_bool_feature (HB_TAG('l','o','c','l')); map->add_gsub_pause (NULL); for (unsigned int i = 0; i < ARABIC_NUM_FEATURES; i++) - map->add_bool_feature (arabic_features[i], false, i < 4); /* The first four features have fallback. */ + map->add_feature (arabic_features[i], 1, i < 4 ? F_HAS_FALLBACK : F_NONE); /* The first four features have fallback. */ map->add_gsub_pause (NULL); - map->add_bool_feature (HB_TAG('r','l','i','g'), true, true); + map->add_feature (HB_TAG('r','l','i','g'), 1, F_GLOBAL|F_HAS_FALLBACK); map->add_gsub_pause (arabic_fallback_shape); - map->add_bool_feature (HB_TAG('c','a','l','t')); + map->add_global_bool_feature (HB_TAG('c','a','l','t')); map->add_gsub_pause (NULL); - map->add_bool_feature (HB_TAG('c','s','w','h')); - map->add_bool_feature (HB_TAG('d','l','i','g')); - map->add_bool_feature (HB_TAG('m','s','e','t')); + map->add_global_bool_feature (HB_TAG('c','s','w','h')); + map->add_global_bool_feature (HB_TAG('d','l','i','g')); + map->add_global_bool_feature (HB_TAG('m','s','e','t')); } #include "hb-ot-shape-complex-arabic-fallback.hh" @@ -354,6 +352,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = NULL, /* decompose */ NULL, /* compose */ setup_masks_arabic, - HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE, + HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF, true, /* fallback_position */ }; diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc index d406f8c9d8c..ca092b5e9bc 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-default.cc @@ -68,18 +68,12 @@ collect_features_default (hb_ot_shape_planner_t *plan) } for (; script_features && *script_features; script_features++) - plan->map.add_bool_feature (*script_features); + plan->map.add_global_bool_feature (*script_features); } static hb_ot_shape_normalization_mode_t normalization_preference_default (const hb_segment_properties_t *props) { - switch ((hb_tag_t) props->script) - { - /* Unicode-1.1 additions */ - case HB_SCRIPT_HANGUL: - return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL; - } return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; } diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh index ed40b968bcb..c251160880c 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.hh @@ -1265,7 +1265,7 @@ static const int indic_syllable_machine_en_main = 170; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl index 11115c9cda4..f9f07d801d9 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic-machine.rl @@ -103,7 +103,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; %%{ diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc index 45b5825c51c..eb1e0be9def 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-indic.cc @@ -329,7 +329,7 @@ static const indic_config_t indic_configs[] = struct feature_list_t { hb_tag_t tag; - hb_bool_t is_global; + hb_ot_map_feature_flags_t flags; }; static const feature_list_t @@ -339,32 +339,32 @@ indic_features[] = * Basic features. * These features are applied in order, one at a time, after initial_reordering. */ - {HB_TAG('n','u','k','t'), true}, - {HB_TAG('a','k','h','n'), true}, - {HB_TAG('r','p','h','f'), false}, - {HB_TAG('r','k','r','f'), true}, - {HB_TAG('p','r','e','f'), false}, - {HB_TAG('b','l','w','f'), false}, - {HB_TAG('h','a','l','f'), false}, - {HB_TAG('a','b','v','f'), false}, - {HB_TAG('p','s','t','f'), false}, - {HB_TAG('c','f','a','r'), false}, - {HB_TAG('v','a','t','u'), true}, - {HB_TAG('c','j','c','t'), true}, + {HB_TAG('n','u','k','t'), F_GLOBAL}, + {HB_TAG('a','k','h','n'), F_GLOBAL}, + {HB_TAG('r','p','h','f'), F_NONE}, + {HB_TAG('r','k','r','f'), F_GLOBAL}, + {HB_TAG('p','r','e','f'), F_NONE}, + {HB_TAG('b','l','w','f'), F_NONE}, + {HB_TAG('h','a','l','f'), F_NONE}, + {HB_TAG('a','b','v','f'), F_NONE}, + {HB_TAG('p','s','t','f'), F_NONE}, + {HB_TAG('c','f','a','r'), F_NONE}, + {HB_TAG('v','a','t','u'), F_GLOBAL}, + {HB_TAG('c','j','c','t'), F_GLOBAL}, /* * Other features. * These features are applied all at once, after final_reordering. */ - {HB_TAG('i','n','i','t'), false}, - {HB_TAG('p','r','e','s'), true}, - {HB_TAG('a','b','v','s'), true}, - {HB_TAG('b','l','w','s'), true}, - {HB_TAG('p','s','t','s'), true}, - {HB_TAG('h','a','l','n'), true}, + {HB_TAG('i','n','i','t'), F_NONE}, + {HB_TAG('p','r','e','s'), F_GLOBAL}, + {HB_TAG('a','b','v','s'), F_GLOBAL}, + {HB_TAG('b','l','w','s'), F_GLOBAL}, + {HB_TAG('p','s','t','s'), F_GLOBAL}, + {HB_TAG('h','a','l','n'), F_GLOBAL}, /* Positioning features, though we don't care about the types. */ - {HB_TAG('d','i','s','t'), true}, - {HB_TAG('a','b','v','m'), true}, - {HB_TAG('b','l','w','m'), true}, + {HB_TAG('d','i','s','t'), F_GLOBAL}, + {HB_TAG('a','b','v','m'), F_GLOBAL}, + {HB_TAG('b','l','w','m'), F_GLOBAL}, }; /* @@ -419,21 +419,21 @@ collect_features_indic (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); - map->add_bool_feature (HB_TAG('l','o','c','l')); + map->add_global_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_global_bool_feature (HB_TAG('c','c','m','p')); unsigned int i = 0; map->add_gsub_pause (initial_reordering); for (; i < INDIC_BASIC_FEATURES; i++) { - map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); + map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); map->add_gsub_pause (NULL); } map->add_gsub_pause (final_reordering); for (; i < INDIC_NUM_FEATURES; i++) { - map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global); + map->add_feature (indic_features[i].tag, 1, indic_features[i].flags | F_MANUAL_ZWJ); } } @@ -442,9 +442,9 @@ override_features_indic (hb_ot_shape_planner_t *plan) { /* Uniscribe does not apply 'kern'. */ if (hb_options ().uniscribe_bug_compatible) - plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); + plan->map.add_feature (HB_TAG('k','e','r','n'), 0, F_GLOBAL); - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); + plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); } @@ -457,10 +457,10 @@ struct would_substitute_feature_t &lookups, &count); } - inline bool would_substitute (hb_codepoint_t *glyphs, - unsigned int glyphs_count, - bool zero_context, - hb_face_t *face) const + inline bool would_substitute (const hb_codepoint_t *glyphs, + unsigned int glyphs_count, + bool zero_context, + hb_face_t *face) const { for (unsigned int i = 0; i < count; i++) if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) @@ -532,7 +532,8 @@ data_create_indic (const hb_ot_shape_plan_t *plan) indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) - indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag); + indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? + 0 : plan->map.get_1_mask (indic_features[i].tag); return indic_plan; } @@ -545,13 +546,30 @@ data_destroy_indic (void *data) static indic_position_t consonant_position_from_face (const indic_shape_plan_t *indic_plan, - hb_codepoint_t *glyphs, unsigned int glyphs_len, - hb_face_t *face) + const hb_codepoint_t glyphs[2], + hb_face_t *face) { + /* For old-spec, the order of glyphs is Consonant,Virama, + * whereas for new-spec, it's Virama,Consonant. However, + * some broken fonts (like Free Sans) simply copied lookups + * from old-spec to new-spec without modification. + * And oddly enough, Uniscribe seems to respect those lookups. + * Eg. in the sequence U+0924,U+094D,U+0930, Uniscribe finds + * base at 0. The font however, only has lookups matching + * 930,94D in 'blwf', not the expected 94D,930 (with new-spec + * table). As such, we simply match both sequences. Seems + * to work. */ bool zero_context = indic_plan->is_old_spec ? false : true; - if (indic_plan->pref.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; - if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_BELOW_C; - if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, zero_context, face)) return POS_POST_C; + hb_codepoint_t glyphs_r[2] = {glyphs[1], glyphs[0]}; + if (indic_plan->pref.would_substitute (glyphs , 2, zero_context, face) || + indic_plan->pref.would_substitute (glyphs_r, 2, zero_context, face)) + return POS_POST_C; + if (indic_plan->blwf.would_substitute (glyphs , 2, zero_context, face) || + indic_plan->blwf.would_substitute (glyphs_r, 2, zero_context, face)) + return POS_BELOW_C; + if (indic_plan->pstf.would_substitute (glyphs , 2, zero_context, face) || + indic_plan->pstf.would_substitute (glyphs_r, 2, zero_context, face)) + return POS_POST_C; return POS_BASE_C; } @@ -609,16 +627,15 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan, { const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; - unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1; hb_codepoint_t glyphs[2]; - if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos])) + if (indic_plan->get_virama_glyph (font, &glyphs[0])) { hb_face_t *face = font->face; unsigned int count = buffer->len; for (unsigned int i = 0; i < count; i++) if (buffer->info[i].indic_position() == POS_BASE_C) { - glyphs[consonant_pos] = buffer->info[i].codepoint; - buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face); + glyphs[1] = buffer->info[i].codepoint; + buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, face); } } } @@ -716,7 +733,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * * IMPLEMENTATION NOTES: * - * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped + * Our pre-base reordering Ra's are marked POS_POST_C, so will be skipped * by the logic above already. */ @@ -1002,8 +1019,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, do { j--; - /* A ZWJ disables CJCT, however, it's mere presence is enough - * to disable ligation. No explicit action needed. */ + /* ZWJ/ZWNJ should disable CJCT. They do that by simply + * being there, since we don't skip them for the CJCT + * feature (ie. F_MANUAL_ZWJ) */ /* A ZWNJ disables HALF. */ if (non_joiner) @@ -1304,7 +1322,8 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) new_reph_pos++; - if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { + if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) + { /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) new_reph_pos++; @@ -1356,7 +1375,8 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos])) new_reph_pos++; - if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) { + if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) + { /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */ if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1])) new_reph_pos++; @@ -1455,9 +1475,11 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, } if (new_pos > start && is_halant_or_coeng (info[new_pos - 1])) + { /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ if (new_pos < end && is_joiner (info[new_pos])) new_pos++; + } { unsigned int old_pos = i; diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh index 38b6040d142..797bfc5bea0 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.hh @@ -280,7 +280,7 @@ static const int myanmar_syllable_machine_en_main = 0; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.rl b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.rl index 949fde6b3cb..51d42dd64ab 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.rl +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar-machine.rl @@ -102,7 +102,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; %%{ diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc index a115064e450..ff13bdd1ebe 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-myanmar.cc @@ -36,7 +36,7 @@ */ static const hb_tag_t -myanmar_features[] = +basic_features[] = { /* * Basic features. @@ -46,6 +46,10 @@ myanmar_features[] = HB_TAG('p','r','e','f'), HB_TAG('b','l','w','f'), HB_TAG('p','s','t','f'), +}; +static const hb_tag_t +other_features[] = +{ /* * Other features. * These features are applied all at once, after final_reordering. @@ -58,25 +62,6 @@ myanmar_features[] = HB_TAG('d','i','s','t'), }; -/* - * Must be in the same order as the myanmar_features array. - */ -enum { - _RPHF, - _PREF, - _BLWF, - _PSTF, - - _PRES, - _ABVS, - _BLWS, - _PSTS, - _DIST, - - MYANMAR_NUM_FEATURES, - MYANMAR_BASIC_FEATURES = _PRES /* Don't forget to update this! */ -}; - static void setup_syllables (const hb_ot_shape_plan_t *plan, hb_font_t *font, @@ -98,28 +83,27 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); - map->add_bool_feature (HB_TAG('l','o','c','l')); + map->add_global_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_global_bool_feature (HB_TAG('c','c','m','p')); - unsigned int i = 0; map->add_gsub_pause (initial_reordering); - for (; i < MYANMAR_BASIC_FEATURES; i++) { - map->add_bool_feature (myanmar_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) + { + map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); map->add_gsub_pause (NULL); } map->add_gsub_pause (final_reordering); - for (; i < MYANMAR_NUM_FEATURES; i++) { - map->add_bool_feature (myanmar_features[i]); - } + for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) + map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); } static void override_features_myanmar (hb_ot_shape_planner_t *plan) { - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); + plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); /* * Note: @@ -130,7 +114,7 @@ override_features_myanmar (hb_ot_shape_planner_t *plan) * 'mkmk' however. */ if (hb_options ().uniscribe_bug_compatible) - plan->map.add_feature (HB_TAG('m','a','r','k'), 0, true); + plan->map.add_feature (HB_TAG('m','a','r','k'), 0, F_GLOBAL); } diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh index 3c9922dc905..1474a3df070 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-private.hh @@ -185,6 +185,20 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) return &_hb_ot_complex_shaper_thai; +#if 0 + /* Note: + * Currently we don't have a separate Hangul shaper. The default shaper handles + * Hangul by enabling jamo features. We may want to implement a separate shaper + * in the future. See this thread for details of what such a shaper would do: + * + * http://lists.freedesktop.org/archives/harfbuzz/2013-April/003070.html + */ + /* Unicode-1.1 additions */ + case HB_SCRIPT_HANGUL: + + return &_hb_ot_complex_shaper_hangul; +#endif + /* ^--- Add new shapers here */ diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.hh b/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.hh index 6f3dd3cdc74..86b7ae7d5ca 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.hh @@ -109,7 +109,7 @@ static const int sea_syllable_machine_en_main = 2; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.rl b/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.rl index 434be6bcd04..46140fc4d5f 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.rl +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-sea-machine.rl @@ -79,7 +79,7 @@ main := |* static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts HB_UNUSED, te, act; + unsigned int p, pe, eof, ts HB_UNUSED, te HB_UNUSED, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; %%{ diff --git a/gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc b/gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc index db458e5a7d2..9c0c303e3df 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-complex-sea.cc @@ -38,7 +38,7 @@ */ static const hb_tag_t -sea_features[] = +basic_features[] = { /* * Basic features. @@ -48,6 +48,10 @@ sea_features[] = HB_TAG('a','b','v','f'), HB_TAG('b','l','w','f'), HB_TAG('p','s','t','f'), +}; +static const hb_tag_t +other_features[] = +{ /* * Other features. * These features are applied all at once, after final_reordering. @@ -60,25 +64,6 @@ sea_features[] = HB_TAG('d','i','s','t'), }; -/* - * Must be in the same order as the sea_features array. - */ -enum { - _PREF, - _ABVF, - _BLWF, - _PSTF, - - _PRES, - _ABVS, - _BLWS, - _PSTS, - _DIST, - - SEA_NUM_FEATURES, - SEA_BASIC_FEATURES = _PRES /* Don't forget to update this! */ -}; - static void setup_syllables (const hb_ot_shape_plan_t *plan, hb_font_t *font, @@ -100,28 +85,26 @@ collect_features_sea (hb_ot_shape_planner_t *plan) /* Do this before any lookups have been applied. */ map->add_gsub_pause (setup_syllables); - map->add_bool_feature (HB_TAG('l','o','c','l')); + map->add_global_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_global_bool_feature (HB_TAG('c','c','m','p')); - - unsigned int i = 0; map->add_gsub_pause (initial_reordering); - for (; i < SEA_BASIC_FEATURES; i++) { - map->add_bool_feature (sea_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) + { + map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); map->add_gsub_pause (NULL); } map->add_gsub_pause (final_reordering); - for (; i < SEA_NUM_FEATURES; i++) { - map->add_bool_feature (sea_features[i]); - } + for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) + map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); } static void override_features_sea (hb_ot_shape_planner_t *plan) { - plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); + plan->map.add_feature (HB_TAG('l','i','g','a'), 0, F_GLOBAL); } diff --git a/gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh b/gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh index 5e9cb061780..ec653513f1b 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-fallback-private.hh @@ -41,4 +41,9 @@ HB_INTERNAL void _hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_ hb_buffer_t *buffer); +HB_INTERNAL void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); + + #endif /* HB_OT_SHAPE_FALLBACK_PRIVATE_HH */ diff --git a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc index 6f3426e6b49..3341825449b 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc @@ -25,6 +25,7 @@ */ #include "hb-ot-shape-fallback-private.hh" +#include "hb-ot-layout-gsubgpos-private.hh" static unsigned int recategorize_combining_class (hb_codepoint_t u, @@ -407,3 +408,48 @@ _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, } position_cluster (plan, font, buffer, start, count); } + + +/* Performs old-style TrueType kerning. */ +void +_hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) +{ + unsigned int count = buffer->len; + hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ? + HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n')); + + OT::hb_apply_context_t c (1, font, buffer, kern_mask, true/*auto_zwj*/); + c.set_lookup_props (OT::LookupFlag::IgnoreMarks); + + for (buffer->idx = 0; buffer->idx < count;) + { + OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, buffer->idx, 1); + if (!skippy_iter.next ()) + { + buffer->idx++; + continue; + } + + hb_position_t x_kern, y_kern, kern1, kern2; + font->get_glyph_kerning_for_direction (buffer->info[buffer->idx].codepoint, + buffer->info[skippy_iter.idx].codepoint, + buffer->props.direction, + &x_kern, &y_kern); + + kern1 = x_kern >> 1; + kern2 = x_kern - kern1; + buffer->pos[buffer->idx].x_advance += kern1; + buffer->pos[skippy_iter.idx].x_advance += kern2; + buffer->pos[skippy_iter.idx].x_offset += kern2; + + kern1 = y_kern >> 1; + kern2 = y_kern - kern1; + buffer->pos[buffer->idx].y_advance += kern1; + buffer->pos[skippy_iter.idx].y_advance += kern2; + buffer->pos[skippy_iter.idx].y_offset += kern2; + + buffer->idx = skippy_iter.idx; + } +} diff --git a/gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh b/gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh index 8112f03aee9..085d48511d0 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-normalize-private.hh @@ -41,7 +41,6 @@ enum hb_ot_shape_normalization_mode_t { HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED, HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */ HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */ - HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL, /* including base-to-base composition */ HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS }; diff --git a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc index 344c0ff8497..7f83d9d258c 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc @@ -170,7 +170,7 @@ decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint } /* Returns 0 if didn't decompose, number of resulting characters otherwise. */ -static inline bool +static inline unsigned int decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u) { unsigned int len, i; @@ -191,7 +191,6 @@ decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_ return len; } -/* Returns true if recomposition may be benefitial. */ static inline void decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest) { @@ -231,7 +230,6 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, uns } } -/* Returns true if recomposition may be benefitial. */ static inline void decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end) { @@ -353,12 +351,11 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, while (buffer->idx < count) { hb_codepoint_t composed, glyph; - if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't try to - * compose a non-mark character with it's preceding starter. This is just an - * optimization to avoid trying to compose every two neighboring glyphs in most - * scripts. */ - (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL || - HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur()))) && + if (/* We don't try to compose a non-mark character with it's preceding starter. + * This is both an optimization to avoid trying to compose every two neighboring + * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul + * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */ + HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur())) && /* If there's anything between the starter and this char, they should have CCC * smaller than this character's. */ (starter == buffer->out_len - 1 || diff --git a/gfx/harfbuzz/src/hb-ot-shape-private.hh b/gfx/harfbuzz/src/hb-ot-shape-private.hh index 23e80b7bdfa..9599f8e722c 100644 --- a/gfx/harfbuzz/src/hb-ot-shape-private.hh +++ b/gfx/harfbuzz/src/hb-ot-shape-private.hh @@ -33,10 +33,6 @@ -/* buffer var allocations, used during the entire shaping process */ -#define unicode_props0() var2.u8[0] -#define unicode_props1() var2.u8[1] - struct hb_ot_shape_plan_t @@ -89,37 +85,4 @@ struct hb_ot_shape_planner_t }; - -inline void -_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode) -{ - info->unicode_props0() = ((unsigned int) unicode->general_category (info->codepoint)) | - (unicode->is_default_ignorable (info->codepoint) ? 0x80 : 0); - info->unicode_props1() = unicode->modified_combining_class (info->codepoint); -} - -inline hb_unicode_general_category_t -_hb_glyph_info_get_general_category (const hb_glyph_info_t *info) -{ - return (hb_unicode_general_category_t) (info->unicode_props0() & 0x7F); -} - -inline void -_hb_glyph_info_set_modified_combining_class (hb_glyph_info_t *info, unsigned int modified_class) -{ - info->unicode_props1() = modified_class; -} - -inline unsigned int -_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) -{ - return info->unicode_props1(); -} - -inline hb_bool_t -_hb_glyph_info_is_default_ignorable (const hb_glyph_info_t *info) -{ - return !!(info->unicode_props0() & 0x80); -} - #endif /* HB_OT_SHAPE_PRIVATE_HH */ diff --git a/gfx/harfbuzz/src/hb-ot-shape.cc b/gfx/harfbuzz/src/hb-ot-shape.cc index d529223ad60..f65861f959f 100644 --- a/gfx/harfbuzz/src/hb-ot-shape.cc +++ b/gfx/harfbuzz/src/hb-ot-shape.cc @@ -83,12 +83,12 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, switch (props->direction) { case HB_DIRECTION_LTR: - map->add_bool_feature (HB_TAG ('l','t','r','a')); - map->add_bool_feature (HB_TAG ('l','t','r','m')); + map->add_global_bool_feature (HB_TAG ('l','t','r','a')); + map->add_global_bool_feature (HB_TAG ('l','t','r','m')); break; case HB_DIRECTION_RTL: - map->add_bool_feature (HB_TAG ('r','t','l','a')); - map->add_bool_feature (HB_TAG ('r','t','l','m'), false); + map->add_global_bool_feature (HB_TAG ('r','t','l','a')); + map->add_feature (HB_TAG ('r','t','l','m'), 1, F_NONE); break; case HB_DIRECTION_TTB: case HB_DIRECTION_BTT: @@ -97,30 +97,31 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, break; } -#define ADD_FEATURES(array) \ - HB_STMT_START { \ - for (unsigned int i = 0; i < ARRAY_LENGTH (array); i++) \ - map->add_bool_feature (array[i]); \ - } HB_STMT_END - if (planner->shaper->collect_features) planner->shaper->collect_features (planner); - ADD_FEATURES (common_features); + for (unsigned int i = 0; i < ARRAY_LENGTH (common_features); i++) + map->add_global_bool_feature (common_features[i]); if (HB_DIRECTION_IS_HORIZONTAL (props->direction)) - ADD_FEATURES (horizontal_features); + for (unsigned int i = 0; i < ARRAY_LENGTH (horizontal_features); i++) + map->add_feature (horizontal_features[i], 1, F_GLOBAL | + (horizontal_features[i] == HB_TAG('k','e','r','n') ? + F_HAS_FALLBACK : F_NONE)); else - ADD_FEATURES (vertical_features); + for (unsigned int i = 0; i < ARRAY_LENGTH (vertical_features); i++) + map->add_feature (vertical_features[i], 1, F_GLOBAL | + (vertical_features[i] == HB_TAG('v','k','r','n') ? + F_HAS_FALLBACK : F_NONE)); if (planner->shaper->override_features) planner->shaper->override_features (planner); -#undef ADD_FEATURES - for (unsigned int i = 0; i < num_user_features; i++) { const hb_feature_t *feature = &user_features[i]; - map->add_feature (feature->tag, feature->value, (feature->start == 0 && feature->end == (unsigned int) -1)); + map->add_feature (feature->tag, feature->value, + (feature->start == 0 && feature->end == (unsigned int) -1) ? + F_GLOBAL : F_NONE); } } @@ -491,31 +492,6 @@ hb_ot_position_complex (hb_ot_shape_context_t *c) return ret; } -static inline void -hb_ot_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 x_kern, y_kern, kern1, kern2; - c->font->get_glyph_kerning_for_direction (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; - } -} - static inline void hb_ot_position (hb_ot_shape_context_t *c) { @@ -532,7 +508,7 @@ hb_ot_position (hb_ot_shape_context_t *c) /* Visual fallback goes here. */ if (fallback) - hb_ot_truetype_kern (c); + _hb_ot_shape_fallback_kern (c->plan, c->font, c->buffer); } @@ -651,8 +627,6 @@ hb_ot_shape_glyphs_closure (hb_font_t *font, { hb_ot_shape_plan_t plan; - buffer->guess_segment_properties (); - const char *shapers[] = {"ot", NULL}; hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shapers); diff --git a/gfx/harfbuzz/src/hb-private.hh b/gfx/harfbuzz/src/hb-private.hh index 15e4f5f6920..f1a9c3afea6 100644 --- a/gfx/harfbuzz/src/hb-private.hh +++ b/gfx/harfbuzz/src/hb-private.hh @@ -376,6 +376,14 @@ struct hb_prealloced_array_t } }; +#define HB_AUTO_ARRAY_PREALLOCED 64 +template +struct hb_auto_array_t : hb_prealloced_array_t +{ + hb_auto_array_t (void) { hb_prealloced_array_t::init (); } + ~hb_auto_array_t (void) { hb_prealloced_array_t::finish (); } +}; + #define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT} template @@ -509,17 +517,19 @@ static inline uint32_t hb_uint32_swap (const uint32_t v) #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]) -#define hb_be_uint24_put(v,V) HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] (V); } HB_STMT_END +#define hb_be_uint24_put(v,V) HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] = (V); } HB_STMT_END #define hb_be_uint24_get(v) (uint32_t) ((v[0] << 16) + (v[1] << 8) + v[2]) #define hb_be_uint24_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]) /* ASCII tag/character handling */ -static inline unsigned char ISALPHA (unsigned char c) +static inline bool ISALPHA (unsigned char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } -static inline unsigned char ISALNUM (unsigned char c) +static inline bool ISALNUM (unsigned char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } +static inline bool ISSPACE (unsigned char c) +{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } 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) @@ -594,6 +604,8 @@ _hb_debug_msg_va (const char *what, if (func) { + unsigned int func_len = strlen (func); +#ifndef HB_DEBUG_VERBOSE /* Skip "typename" */ if (0 == strncmp (func, "typename ", 9)) func += 9; @@ -603,7 +615,9 @@ _hb_debug_msg_va (const char *what, func = space + 1; /* Skip parameter list */ const char *paren = strchr (func, '('); - unsigned int func_len = paren ? paren - func : strlen (func); + if (paren) + func_len = paren - func; +#endif fprintf (stderr, "%.*s: ", func_len, func); } @@ -841,8 +855,9 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o { /* Pain because we don't know whether s is nul-terminated. */ char buf[64]; - strncpy (buf, s, MIN (ARRAY_LENGTH (buf) - 1, len)); - buf[MIN (ARRAY_LENGTH (buf) - 1, len)] = '\0'; + len = MIN (ARRAY_LENGTH (buf) - 1, len); + strncpy (buf, s, len); + buf[len] = '\0'; char *end; errno = 0; diff --git a/gfx/harfbuzz/src/hb-set-private.hh b/gfx/harfbuzz/src/hb-set-private.hh index 5e30a7e3616..c2b3e46d93d 100644 --- a/gfx/harfbuzz/src/hb-set-private.hh +++ b/gfx/harfbuzz/src/hb-set-private.hh @@ -32,47 +32,29 @@ #include "hb-object-private.hh" -struct hb_set_digest_common_bits_t -{ - ASSERT_POD (); - - typedef unsigned int mask_t; - - inline void init (void) { - mask = ~0; - value = (mask_t) -1; - } - - inline void add (hb_codepoint_t g) { - if (unlikely (value == (mask_t) -1)) { - value = g; - return; - } - - mask ^= (g & mask) ^ value; - value &= mask; - } - - inline void add_range (hb_codepoint_t a, hb_codepoint_t b) { - /* The negation here stands for ~(x-1). */ - mask &= -(1 << _hb_bit_storage (a ^ b)); - value &= mask; - } - - inline bool may_have (hb_codepoint_t g) const { - return (g & mask) == value; - } - - private: - mask_t mask; - mask_t value; -}; +/* + * The set digests here implement various "filters" that support + * "approximate member query". Conceptually these are like Bloom + * Filter and Quotient Filter, however, much smaller, faster, and + * designed to fit the requirements of our uses for glyph coverage + * queries. As a result, our filters have much higher. + */ +template struct hb_set_digest_lowest_bits_t { ASSERT_POD (); - typedef unsigned long mask_t; + static const unsigned int num_bits = 0 + + (sizeof (mask_t) >= 1 ? 3 : 0) + + (sizeof (mask_t) >= 2 ? 1 : 0) + + (sizeof (mask_t) >= 4 ? 1 : 0) + + (sizeof (mask_t) >= 8 ? 1 : 0) + + (sizeof (mask_t) >= 16? 1 : 0) + + 0; + + ASSERT_STATIC (shift < sizeof (hb_codepoint_t) * 8); + ASSERT_STATIC (shift + num_bits <= sizeof (hb_codepoint_t) * 8); inline void init (void) { mask = 0; @@ -83,7 +65,7 @@ struct hb_set_digest_lowest_bits_t } inline void add_range (hb_codepoint_t a, hb_codepoint_t b) { - if (b - a >= sizeof (mask_t) * 8 - 1) + if ((b >> shift) - (a >> shift) >= sizeof (mask_t) * 8 - 1) mask = (mask_t) -1; else { mask_t ma = mask_for (a); @@ -98,39 +80,66 @@ struct hb_set_digest_lowest_bits_t private: - static inline mask_t mask_for (hb_codepoint_t g) { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); } + static inline mask_t mask_for (hb_codepoint_t g) { + return ((mask_t) 1) << ((g >> shift) & (sizeof (mask_t) * 8 - 1)); + } mask_t mask; }; -struct hb_set_digest_t +template +struct hb_set_digest_combiner_t { ASSERT_POD (); inline void init (void) { - digest1.init (); - digest2.init (); + head.init (); + tail.init (); } inline void add (hb_codepoint_t g) { - digest1.add (g); - digest2.add (g); + head.add (g); + tail.add (g); } inline void add_range (hb_codepoint_t a, hb_codepoint_t b) { - digest1.add_range (a, b); - digest2.add_range (a, b); + head.add_range (a, b); + tail.add_range (a, b); } inline bool may_have (hb_codepoint_t g) const { - return digest1.may_have (g) && digest2.may_have (g); + return head.may_have (g) && tail.may_have (g); } private: - hb_set_digest_common_bits_t digest1; - hb_set_digest_lowest_bits_t digest2; + head_t head; + tail_t tail; }; +/* + * hb_set_digest_t + * + * This is a combination of digests that performs "best". + * There is not much science to this: it's a result of intuition + * and testing. + */ +typedef hb_set_digest_combiner_t +< + hb_set_digest_lowest_bits_t, + hb_set_digest_combiner_t + < + hb_set_digest_lowest_bits_t, + hb_set_digest_lowest_bits_t + > +> hb_set_digest_t; + + + +/* + * hb_set_t + */ + + /* TODO Make this faster and memmory efficient. */ struct hb_set_t diff --git a/gfx/harfbuzz/src/hb-set.cc b/gfx/harfbuzz/src/hb-set.cc index 5f427a5d8e0..3c9573fbceb 100644 --- a/gfx/harfbuzz/src/hb-set.cc +++ b/gfx/harfbuzz/src/hb-set.cc @@ -27,7 +27,6 @@ #include "hb-set-private.hh" - /* Public API */ diff --git a/gfx/harfbuzz/src/hb-shape-plan.cc b/gfx/harfbuzz/src/hb-shape-plan.cc index 22a226f3a6c..a6d2d262100 100644 --- a/gfx/harfbuzz/src/hb-shape-plan.cc +++ b/gfx/harfbuzz/src/hb-shape-plan.cc @@ -27,6 +27,7 @@ #include "hb-shape-plan-private.hh" #include "hb-shaper-private.hh" #include "hb-font-private.hh" +#include "hb-buffer-private.hh" #define HB_SHAPER_IMPLEMENT(shaper) \ HB_SHAPER_DATA_ENSURE_DECLARE(shaper, face) \ @@ -178,9 +179,14 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, const hb_feature_t *features, unsigned int num_features) { - if (unlikely (shape_plan->face != font->face)) + if (unlikely (hb_object_is_inert (shape_plan) || + hb_object_is_inert (font) || + hb_object_is_inert (buffer))) return false; + assert (shape_plan->face == font->face); + assert (hb_segment_properties_equal (&shape_plan->props, &buffer->props)); + #define HB_SHAPER_EXECUTE(shaper) \ HB_STMT_START { \ return HB_SHAPER_DATA (shaper, shape_plan) && \ diff --git a/gfx/harfbuzz/src/hb-shape.cc b/gfx/harfbuzz/src/hb-shape.cc index 7ae56e39fa2..67ef7e6a8f5 100644 --- a/gfx/harfbuzz/src/hb-shape.cc +++ b/gfx/harfbuzz/src/hb-shape.cc @@ -38,10 +38,8 @@ static void parse_space (const char **pp, const char *end) { char c; -#define ISSPACE(c) ((c)==' '||(c)=='\f'||(c)=='\n'||(c)=='\r'||(c)=='\t'||(c)=='\v') while (*pp < end && (c = **pp, ISSPACE (c))) (*pp)++; -#undef ISSPACE } static hb_bool_t @@ -60,16 +58,19 @@ static hb_bool_t parse_uint (const char **pp, const char *end, unsigned int *pv) { char buf[32]; - strncpy (buf, *pp, end - *pp); - buf[ARRAY_LENGTH (buf) - 1] = '\0'; + unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp)); + strncpy (buf, *pp, len); + buf[len] = '\0'; char *p = buf; char *pend = p; unsigned int v; + /* Intentionally use strtol instead of strtoul, such that + * -1 turns into "big number"... */ + errno = 0; v = strtol (p, &pend, 0); - - if (p == pend) + if (errno || p == pend) return false; *pv = v; @@ -255,8 +256,6 @@ hb_shape_full (hb_font_t *font, assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE); - buffer->guess_segment_properties (); - hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list); hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); hb_shape_plan_destroy (shape_plan); diff --git a/gfx/harfbuzz/src/hb-unicode-private.hh b/gfx/harfbuzz/src/hb-unicode-private.hh index 724c6f94ed9..155a8a350b7 100644 --- a/gfx/harfbuzz/src/hb-unicode-private.hh +++ b/gfx/harfbuzz/src/hb-unicode-private.hh @@ -129,6 +129,11 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE * be. That has been reported to the Unicode Technical Committee for * consideration. As such, we include it here, since Uniscribe removes it. * + * Note: While U+115F and U+1160 are Default_Ignorable, we do NOT want to + * hide them, as the way Uniscribe has implemented them is with regular + * spacing glyphs, and that's the way fonts are made to work. As such, + * we make exceptions for those two. + * * Gathered from: * http://unicode.org/cldr/utility/list-unicodeset.jsp?a=[:DI:]&abb=on&ucd=on&esc=on * @@ -141,8 +146,8 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE * * 00AD ;SOFT HYPHEN * 034F ;COMBINING GRAPHEME JOINER - * 115F ;HANGUL CHOSEONG FILLER - * 1160 ;HANGUL JUNGSEONG FILLER + * #115F ;HANGUL CHOSEONG FILLER + * #1160 ;HANGUL JUNGSEONG FILLER * 17B4 ;KHMER VOWEL INHERENT AQ * 17B5 ;KHMER VOWEL INHERENT AA * 180B..180D ;MONGOLIAN FREE VARIATION SELECTOR THREE @@ -168,7 +173,6 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE switch (page) { case 0x00: return unlikely (ch == 0x00AD); case 0x03: return unlikely (ch == 0x034F); - case 0x11: return hb_in_range (ch, 0x115F, 0x1160); case 0x17: return hb_in_range (ch, 0x17B4, 0x17B5); case 0x18: return hb_in_range (ch, 0x180B, 0x180E); case 0x20: return hb_in_ranges (ch, 0x200B, 0x200F, diff --git a/gfx/harfbuzz/src/hb-version.h b/gfx/harfbuzz/src/hb-version.h index ebe0401ba95..ec2d532f33a 100644 --- a/gfx/harfbuzz/src/hb-version.h +++ b/gfx/harfbuzz/src/hb-version.h @@ -38,9 +38,9 @@ HB_BEGIN_DECLS #define HB_VERSION_MAJOR 0 #define HB_VERSION_MINOR 9 -#define HB_VERSION_MICRO 12 +#define HB_VERSION_MICRO 16 -#define HB_VERSION_STRING "0.9.12" +#define HB_VERSION_STRING "0.9.16" #define HB_VERSION_CHECK(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) >= \ diff --git a/gfx/harfbuzz/src/test-buffer-serialize.cc b/gfx/harfbuzz/src/test-buffer-serialize.cc new file mode 100644 index 00000000000..3577dbf688e --- /dev/null +++ b/gfx/harfbuzz/src/test-buffer-serialize.cc @@ -0,0 +1,126 @@ +/* + * Copyright © 2010,2011,2013 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "hb.h" +#ifdef HAVE_FREETYPE +#include "hb-ft.h" +#endif + +#ifdef HAVE_GLIB +#include +#endif +#include +#include + +int +main (int argc, char **argv) +{ + hb_blob_t *blob = NULL; + + if (argc != 2) { + fprintf (stderr, "usage: %s font-file\n", argv[0]); + exit (1); + } + + /* Create the blob */ + { + const char *font_data; + unsigned int len; + hb_destroy_func_t destroy; + void *user_data; + hb_memory_mode_t mm; + +#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; + mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE; +#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); + mm = HB_MEMORY_MODE_WRITABLE; +#endif + + blob = hb_blob_create (font_data, len, mm, user_data, destroy); + } + + hb_face_t *face = hb_face_create (blob, 0 /* first face */); + hb_blob_destroy (blob); + blob = NULL; + + unsigned int upem = hb_face_get_upem (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + hb_font_set_scale (font, upem, upem); +#ifdef HAVE_FREETYPE + hb_ft_font_set_funcs (font); +#endif + + hb_buffer_t *buf; + buf = hb_buffer_create (); + + bool ret = true; + char line[BUFSIZ], out[BUFSIZ]; + while (fgets (line, sizeof(line), stdin) != 0) + { + hb_buffer_clear_contents (buf); + + const char *p = line; + while (hb_buffer_deserialize_glyphs (buf, + p, -1, &p, + font, + HB_BUFFER_SERIALIZE_FORMAT_JSON)) + ; + if (*p && *p != '\n') + ret = false; + + hb_buffer_serialize_glyphs (buf, 0, hb_buffer_get_length (buf), + out, sizeof (out), NULL, + font, HB_BUFFER_SERIALIZE_FORMAT_JSON, + HB_BUFFER_SERIALIZE_FLAGS_DEFAULT); + puts (out); + } + + hb_buffer_destroy (buf); + + hb_font_destroy (font); + + return !ret; +} diff --git a/gfx/harfbuzz/src/test.cc b/gfx/harfbuzz/src/test.cc index 22108b86b7a..1acb6ead70b 100644 --- a/gfx/harfbuzz/src/test.cc +++ b/gfx/harfbuzz/src/test.cc @@ -100,6 +100,7 @@ main (int argc, char **argv) hb_buffer_t *buffer = hb_buffer_create (); hb_buffer_add_utf8 (buffer, "\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb0\xe0\xa5\x8d\xe0\xa4\x95", -1, 0, -1); + hb_buffer_guess_segment_properties (buffer); hb_shape (font, buffer, NULL, 0); diff --git a/layout/reftests/font-features/reftest.list b/layout/reftests/font-features/reftest.list index ebaddcec8da..0f229ab64b1 100644 --- a/layout/reftests/font-features/reftest.list +++ b/layout/reftests/font-features/reftest.list @@ -51,9 +51,9 @@ skip-if(B2G) HTTP(..) == font-features-turkish-override-5.html font-features-tur HTTP(..) == font-features-order-1.html font-features-ref.html HTTP(..) == font-features-order-2.html font-features-noliga.html -# sanity check for kerning - with no spaces, kerning should occur (XP version of Arial doesn't contain kerning data) +# sanity check for kerning - with no spaces, kerning should occur HTTP(..) == kerning-sanity-check-kern.html kerning-sanity-check-default.html -fails-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) HTTP(..) != kerning-sanity-check-nokern.html kerning-sanity-check-default.html +HTTP(..) != kerning-sanity-check-nokern.html kerning-sanity-check-default.html # OpenType features should work across inter-word spaces HTTP(..) == font-features-across-space-1.html font-features-across-space-1-ref.html