bug 863248 - update harfbuzz to version 0.9.16 from upstream. r=jdaggett

This commit is contained in:
Jonathan Kew 2013-04-30 13:02:25 +01:00
parent 6535ed8137
commit e73c66cc0a
54 changed files with 2988 additions and 931 deletions

View File

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

View File

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

View File

@ -47,22 +47,18 @@
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
/* 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))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <typename T>
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 <typename Type>
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<Type> (base, offset);
}
inline Type& operator () (void *base)
{
unsigned int offset = *this;
return StructAtOffset<Type> (base, offset);
}
inline Type& serialize (hb_serialize_context_t *c, void *base)
{
@ -947,21 +949,22 @@ template <typename Type>
struct SortedArrayOf : ArrayOf<Type> {
template <typename SearchType>
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;
}
};

View File

@ -129,8 +129,7 @@ struct RecordListOf : RecordArrayOf<Type>
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) {

View File

@ -519,12 +519,12 @@ struct SinglePosFormat2
struct SinglePos
{
template <typename context_t>
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 <typename context_t>
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 <typename context_t>
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 <typename context_t>
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 <typename context_t>
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 <typename context_t>
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 <typename context_t>
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<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
template <typename context_t>
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 <typename context_t>
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 <typename set_t>
@ -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 <typename context_t>
static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
template <typename context_t>
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 <typename context_t>
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;
}

View File

@ -192,17 +192,6 @@ struct SingleSubstFormat2
struct SingleSubst
{
template <typename context_t>
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<GlyphID> &glyphs,
Supplier<GlyphID> &substitutes,
@ -230,6 +219,17 @@ struct SingleSubst
}
}
template <typename context_t>
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 <typename context_t>
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<GlyphID> &glyphs,
Supplier<unsigned int> &substitute_len_list,
@ -410,6 +401,16 @@ struct MultipleSubst
}
}
template <typename context_t>
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 <typename context_t>
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<GlyphID> &glyphs,
Supplier<unsigned int> &alternate_len_list,
@ -561,6 +552,16 @@ struct AlternateSubst
}
}
template <typename context_t>
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 <typename context_t>
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<GlyphID> &first_glyphs,
Supplier<unsigned int> &ligature_per_first_glyph_count_list,
@ -869,6 +860,16 @@ struct LigatureSubst
}
}
template <typename context_t>
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 <typename context_t>
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 <typename context_t>
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 <typename context_t>
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 <typename context_t>
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<hb_closure_context_t>);
return TRACE_RETURN (process (c));
c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
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<hb_collect_glyphs_context_t>);
return TRACE_RETURN (process (c));
c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
return TRACE_RETURN (dispatch (c));
}
template <typename set_t>
@ -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 <typename context_t>
static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
template <typename context_t>
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 <typename context_t>
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;
}

View File

@ -38,7 +38,7 @@ namespace OT {
#define TRACE_PROCESS(this) \
#define TRACE_DISPATCH(this) \
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename context_t>
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 <typename context_t>
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 <typename context_t>
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<typename T::LookupSubTable> ().process (c, get_type ());
return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
}
inline bool sanitize_self (hb_sanitize_context_t *c) {

View File

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

View File

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

View File

@ -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<pause_map_t, 1> 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 */

View File

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

View File

@ -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_t *> (&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]);
}
}

View File

@ -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<hb_codepoint_t> (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 */
};

View File

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

View File

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

View File

@ -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;
%%{

View File

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

View File

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

View File

@ -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;
%%{

View File

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

View File

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

View File

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

View File

@ -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;
%%{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -376,6 +376,14 @@ struct hb_prealloced_array_t
}
};
#define HB_AUTO_ARRAY_PREALLOCED 64
template <typename Type>
struct hb_auto_array_t : hb_prealloced_array_t <Type, HB_AUTO_ARRAY_PREALLOCED>
{
hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::init (); }
~hb_auto_array_t (void) { hb_prealloced_array_t<Type, HB_AUTO_ARRAY_PREALLOCED>::finish (); }
};
#define HB_LOCKABLE_SET_INIT {HB_PREALLOCED_ARRAY_INIT}
template <typename item_t, typename lock_t>
@ -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;

View File

@ -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 <typename mask_t, unsigned int shift>
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 <typename head_t, typename tail_t>
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<unsigned long, 4>,
hb_set_digest_combiner_t
<
hb_set_digest_lowest_bits_t<unsigned long, 0>,
hb_set_digest_lowest_bits_t<unsigned long, 9>
>
> hb_set_digest_t;
/*
* hb_set_t
*/
/* TODO Make this faster and memmory efficient. */
struct hb_set_t

View File

@ -27,7 +27,6 @@
#include "hb-set-private.hh"
/* Public API */

View File

@ -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) && \

View File

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

View File

@ -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<hb_codepoint_t> (ch, 0x115F, 0x1160);
case 0x17: return hb_in_range<hb_codepoint_t> (ch, 0x17B4, 0x17B5);
case 0x18: return hb_in_range<hb_codepoint_t> (ch, 0x180B, 0x180E);
case 0x20: return hb_in_ranges<hb_codepoint_t> (ch, 0x200B, 0x200F,

View File

@ -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) >= \

View File

@ -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 <glib.h>
#endif
#include <stdlib.h>
#include <stdio.h>
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;
}

View File

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

View File

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