diff options
author | bashi@chromium.org <bashi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-05 00:33:17 +0000 |
---|---|---|
committer | bashi@chromium.org <bashi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-05 00:33:17 +0000 |
commit | f4e59db002be2b735b9b96b0b54ab3234851e6eb (patch) | |
tree | 94de05308f504462d5ff92671e7ae01be9efbbff /third_party | |
parent | 56510ba355dee2cd6592cdf0d27c4c41ef0cae8b (diff) | |
download | chromium_src-f4e59db002be2b735b9b96b0b54ab3234851e6eb.zip chromium_src-f4e59db002be2b735b9b96b0b54ab3234851e6eb.tar.gz chromium_src-f4e59db002be2b735b9b96b0b54ab3234851e6eb.tar.bz2 |
Roll harfbuzz-ng 3b8fd9c48f4bde368bf2d465c148b9743a9216ee
The revision provides HB_NO_MT macro that disables multi-threading
support. We don't need multi-threading support for harfbuzz-ng.
BUG=none
TEST=compiled ("make harfbuzz-ng")
Review URL: https://chromiumcodereview.appspot.com/10510004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140446 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
77 files changed, 4971 insertions, 2131 deletions
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium index 9930732..f66a274 100644 --- a/third_party/harfbuzz-ng/README.chromium +++ b/third_party/harfbuzz-ng/README.chromium @@ -2,8 +2,8 @@ Name: harfbuzz-ng Short Name: harfbuzz-ng URL: http://freedesktop.org/wiki/Software/HarfBuzz Version: unknown -Date: 20120127 -Revision: 1a5a91dc0d8bf4b72a2f22dc6300b06ad7000b79 +Date: 20120604 +Revision: 3b8fd9c48f4bde368bf2d465c148b9743a9216ee Security Critical: yes Description: diff --git a/third_party/harfbuzz-ng/harfbuzz.gyp b/third_party/harfbuzz-ng/harfbuzz.gyp index ea8e48d..6a69487 100644 --- a/third_party/harfbuzz-ng/harfbuzz.gyp +++ b/third_party/harfbuzz-ng/harfbuzz.gyp @@ -13,13 +13,16 @@ 'defines': [ 'HAVE_OT', 'HAVE_ICU', + 'HB_NO_MT', ], 'sources': [ + 'src/hb-atomic-private.hh', 'src/hb-blob.cc', 'src/hb-blob.h', 'src/hb-buffer-private.hh', 'src/hb-buffer.cc', 'src/hb-buffer.h', + 'src/hb-cache-private.hh', 'src/hb-common.cc', 'src/hb-common.h', 'src/hb-fallback-shape-private.hh', @@ -56,18 +59,21 @@ 'src/hb-ot-shape-complex-arabic-table.hh', 'src/hb-ot-shape-complex-arabic.cc', 'src/hb-ot-shape-complex-indic-machine.hh', + 'src/hb-ot-shape-complex-indic-private.hh', 'src/hb-ot-shape-complex-indic-table.hh', 'src/hb-ot-shape-complex-indic.cc', 'src/hb-ot-shape-complex-misc.cc', 'src/hb-ot-shape-complex-private.hh', 'src/hb-ot-shape-normalize.cc', + 'src/hb-ot-shape-normalize-private.hh', 'src/hb-ot-shape-private.hh', 'src/hb-ot-shape.cc', - 'src/hb-ot-shape.h', 'src/hb-ot-tag.cc', 'src/hb-ot-tag.h', 'src/hb-ot.h', 'src/hb-private.hh', + 'src/hb-set.cc', + 'src/hb-set-private.hh', 'src/hb-shape.cc', 'src/hb-shape.h', 'src/hb-tt-font.cc', @@ -75,6 +81,7 @@ 'src/hb-unicode.cc', 'src/hb-unicode.h', 'src/hb-version.h', + 'src/hb-warning.cc', 'src/hb.h', ], 'sources/': [ diff --git a/third_party/harfbuzz-ng/src/hb-atomic-private.hh b/third_party/harfbuzz-ng/src/hb-atomic-private.hh new file mode 100644 index 0000000..d6bd1c9 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-atomic-private.hh @@ -0,0 +1,79 @@ +/* + * Copyright © 2007 Chris Wilson + * Copyright © 2009,2010 Red Hat, Inc. + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Contributor(s): + * Chris Wilson <chris@chris-wilson.co.uk> + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_ATOMIC_PRIVATE_HH +#define HB_ATOMIC_PRIVATE_HH + +#include "hb-private.hh" + + +/* atomic_int */ + +/* We need external help for these */ + +#if 0 + + +#elif !defined(HB_NO_MT) && defined(_MSC_VER) && _MSC_VER >= 1600 + +#include <intrin.h> +typedef long hb_atomic_int_t; +#define hb_atomic_int_add(AI, V) _InterlockedExchangeAdd (&(AI), (V)) + + +#elif !defined(HB_NO_MT) && defined(__APPLE__) + +#include <libkern/OSAtomic.h> +typedef int32_t hb_atomic_int_t; +#define hb_atomic_int_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V)) + + +#elif !defined(HB_NO_MT) && defined(HAVE_GLIB) + +#include <glib.h> +typedef volatile int hb_atomic_int_t; +#if GLIB_CHECK_VERSION(2,29,5) +#define hb_atomic_int_add(AI, V) g_atomic_int_add (&(AI), (V)) +#else +#define hb_atomic_int_add(AI, V) g_atomic_int_exchange_and_add (&(AI), (V)) +#endif + + +#else + +#define HB_ATOMIC_INT_NIL 1 +typedef volatile int hb_atomic_int_t; +#define hb_atomic_int_add(AI, V) (((AI) += (V)) - (V)) + +#endif + + +#endif /* HB_ATOMIC_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-blob.cc b/third_party/harfbuzz-ng/src/hb-blob.cc index b2b1d9c..ee997ad 100644 --- a/third_party/harfbuzz-ng/src/hb-blob.cc +++ b/third_party/harfbuzz-ng/src/hb-blob.cc @@ -301,7 +301,7 @@ _try_writable (hb_blob_t *blob) return TRUE; - DEBUG_MSG_FUNC (BLOB, blob, "currect data is -> %p\n", blob->data); + DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data); char *new_data; diff --git a/third_party/harfbuzz-ng/src/hb-blob.h b/third_party/harfbuzz-ng/src/hb-blob.h index 50c9ae3..360310b 100644 --- a/third_party/harfbuzz-ng/src/hb-blob.h +++ b/third_party/harfbuzz-ng/src/hb-blob.h @@ -24,6 +24,10 @@ * Red Hat Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_BLOB_H #define HB_BLOB_H diff --git a/third_party/harfbuzz-ng/src/hb-buffer-private.hh b/third_party/harfbuzz-ng/src/hb-buffer-private.hh index 4292222..e9e0f82 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer-private.hh +++ b/third_party/harfbuzz-ng/src/hb-buffer-private.hh @@ -70,6 +70,15 @@ struct _hb_buffer_t { hb_glyph_info_t *out_info; hb_glyph_position_t *pos; + inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; } + inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; } + + inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; } + inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; } + + inline hb_glyph_info_t &prev (void) { return out_info[out_len - 1]; } + inline hb_glyph_info_t prev (void) const { return info[out_len - 1]; } + unsigned int serial; uint8_t allocated_var_bytes[8]; const char *allocated_var_owner[8]; @@ -104,7 +113,7 @@ struct _hb_buffer_t { const uint16_t *glyph_data_be); HB_INTERNAL void replace_glyphs (unsigned int num_in, unsigned int num_out, - const uint16_t *glyph_data); + const hb_codepoint_t *glyph_data); HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index); /* Makes a copy of the glyph at idx to output and replace glyph_index */ HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index); @@ -131,6 +140,11 @@ struct _hb_buffer_t { unsigned int cluster_start, unsigned int cluster_end); + HB_INTERNAL void merge_clusters (unsigned int start, + unsigned int end); + HB_INTERNAL void merge_out_clusters (unsigned int start, + unsigned int end); + /* Internal methods */ HB_INTERNAL bool enlarge (unsigned int size); diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc index e8bdfb1..c566a4a 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer.cc +++ b/third_party/harfbuzz-ng/src/hb-buffer.cc @@ -223,6 +223,7 @@ hb_buffer_t::swap_buffers (void) if (unlikely (in_error)) return; assert (have_output); + have_output = FALSE; if (out_info != info) { @@ -270,7 +271,7 @@ hb_buffer_t::replace_glyphs_be16 (unsigned int num_in, void hb_buffer_t::replace_glyphs (unsigned int num_in, unsigned int num_out, - const uint16_t *glyph_data) + const uint32_t *glyph_data) { if (!make_room_for (num_in, num_out)) return; @@ -431,6 +432,29 @@ hb_buffer_t::reverse_clusters (void) } void +hb_buffer_t::merge_clusters (unsigned int start, + unsigned int end) +{ + unsigned int cluster = this->info[start].cluster; + + for (unsigned int i = start + 1; i < end; i++) + cluster = MIN (cluster, this->info[i].cluster); + for (unsigned int i = start; i < end; i++) + this->info[i].cluster = cluster; +} +void +hb_buffer_t::merge_out_clusters (unsigned int start, + unsigned int end) +{ + unsigned int cluster = this->out_info[start].cluster; + + for (unsigned int i = start + 1; i < end; i++) + cluster = MIN (cluster, this->out_info[i].cluster); + for (unsigned int i = start; i < end; i++) + this->out_info[i].cluster = cluster; +} + +void hb_buffer_t::guess_properties (void) { /* If script is set to INVALID, guess from buffer contents */ diff --git a/third_party/harfbuzz-ng/src/hb-buffer.h b/third_party/harfbuzz-ng/src/hb-buffer.h index 9582ebe..ca1bbf4 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer.h +++ b/third_party/harfbuzz-ng/src/hb-buffer.h @@ -27,6 +27,10 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_BUFFER_H #define HB_BUFFER_H diff --git a/third_party/harfbuzz-ng/src/hb-cache-private.hh b/third_party/harfbuzz-ng/src/hb-cache-private.hh new file mode 100644 index 0000000..a0928a0 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-cache-private.hh @@ -0,0 +1,72 @@ +/* + * Copyright © 2012 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_CACHE_PRIVATE_HH +#define HB_CACHE_PRIVATE_HH + +#include "hb-private.hh" + + +/* Implements a lock-free cache for int->int functions. */ + +template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits> +struct hb_cache_t +{ + ASSERT_STATIC (key_bits >= cache_bits); + ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int)); + + inline void clear (void) + { + memset (values, 255, sizeof (values)); + } + + inline bool get (unsigned int key, unsigned int *value) + { + unsigned int k = key & ((1<<cache_bits)-1); + unsigned int v = values[k]; + if ((v >> value_bits) != (key >> cache_bits)) + return false; + } + + inline bool set (unsigned int key, unsigned int value) + { + if (unlikely ((key >> key_bits) || (value >> value_bits))) + return false; /* Overflows */ + unsigned int k = key & ((1<<cache_bits)-1); + unsigned int v = ((key>>cache_bits)<<value_bits) | value; + values[k] = v; + return true; + } + + private: + unsigned int values[1<<cache_bits]; +}; + +typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t; +typedef hb_cache_t<16, 24, 8> hb_advance_cache_t; + + +#endif /* HB_CACHE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-common.cc b/third_party/harfbuzz-ng/src/hb-common.cc index 6093289..bfbba65 100644 --- a/third_party/harfbuzz-ng/src/hb-common.cc +++ b/third_party/harfbuzz-ng/src/hb-common.cc @@ -1,6 +1,6 @@ /* * Copyright © 2009,2010 Red Hat, Inc. - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -80,7 +80,7 @@ hb_direction_from_string (const char *str, int len) char c = TOLOWER (str[0]); for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++) if (c == direction_strings[i][0]) - return (hb_direction_t) i; + return (hb_direction_t) (HB_DIRECTION_LTR + i); return HB_DIRECTION_INVALID; } @@ -88,8 +88,9 @@ hb_direction_from_string (const char *str, int len) const char * hb_direction_to_string (hb_direction_t direction) { - if (likely ((unsigned int) direction < ARRAY_LENGTH (direction_strings))) - return direction_strings[direction]; + if (likely ((unsigned int) (direction - HB_DIRECTION_LTR) + < ARRAY_LENGTH (direction_strings))) + return direction_strings[direction - HB_DIRECTION_LTR]; return "invalid"; } @@ -264,20 +265,30 @@ hb_script_to_iso15924_tag (hb_script_t script) hb_direction_t hb_script_get_horizontal_direction (hb_script_t script) { + /* http://goo.gl/x9ilM */ switch ((hb_tag_t) script) { + /* Unicode-1.1 additions */ case HB_SCRIPT_ARABIC: case HB_SCRIPT_HEBREW: + + /* Unicode-3.0 additions */ case HB_SCRIPT_SYRIAC: case HB_SCRIPT_THAANA: /* Unicode-4.0 additions */ case HB_SCRIPT_CYPRIOT: + /* Unicode-4.1 additions */ + case HB_SCRIPT_KHAROSHTHI: + /* Unicode-5.0 additions */ case HB_SCRIPT_PHOENICIAN: case HB_SCRIPT_NKO: + /* Unicode-5.1 additions */ + case HB_SCRIPT_LYDIAN: + /* Unicode-5.2 additions */ case HB_SCRIPT_AVESTAN: case HB_SCRIPT_IMPERIAL_ARAMAIC: @@ -290,6 +301,10 @@ hb_script_get_horizontal_direction (hb_script_t script) /* Unicode-6.0 additions */ case HB_SCRIPT_MANDAIC: + /* Unicode-6.1 additions */ + case HB_SCRIPT_MEROITIC_CURSIVE: + case HB_SCRIPT_MEROITIC_HIEROGLYPHS: + return HB_DIRECTION_RTL; } diff --git a/third_party/harfbuzz-ng/src/hb-common.h b/third_party/harfbuzz-ng/src/hb-common.h index b7fef32..562b04c 100644 --- a/third_party/harfbuzz-ng/src/hb-common.h +++ b/third_party/harfbuzz-ng/src/hb-common.h @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009 Red Hat, Inc. - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -26,6 +26,10 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_COMMON_H #define HB_COMMON_H @@ -89,39 +93,40 @@ typedef uint32_t hb_tag_t; #define HB_TAG_NONE HB_TAG(0,0,0,0) -/* len=-1 means s is NUL-terminated */ -hb_tag_t hb_tag_from_string (const char *s, int len); +/* len=-1 means str is NUL-terminated */ +hb_tag_t hb_tag_from_string (const char *str, int len); /* hb_direction_t */ typedef enum { - HB_DIRECTION_INVALID = -1, - HB_DIRECTION_LTR = 0, + HB_DIRECTION_INVALID = 0, + HB_DIRECTION_LTR = 4, HB_DIRECTION_RTL, HB_DIRECTION_TTB, HB_DIRECTION_BTT } hb_direction_t; -/* len=-1 means s is NUL-terminated */ +/* len=-1 means str is NUL-terminated */ hb_direction_t hb_direction_from_string (const char *str, int len); const char * hb_direction_to_string (hb_direction_t direction); -#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 0) -#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 2) -#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 0) -#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 1) -#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1)) +#define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4) +#define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6) +#define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4) +#define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5) +#define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4) +#define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1)) /* Direction must be valid */ /* hb_language_t */ typedef struct _hb_language_t *hb_language_t; -/* len=-1 means s is NUL-terminated */ +/* len=-1 means str is NUL-terminated */ hb_language_t hb_language_from_string (const char *str, int len); @@ -174,119 +179,138 @@ typedef enum /* hb_script_t */ /* http://unicode.org/iso15924/ */ +/* http://goo.gl/x9ilM */ typedef enum { - HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), - HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), - HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), - HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), - HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), - HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), - HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), - HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), - HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), - HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), - HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), - HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), - HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), - HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), - HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), - HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), - HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), - HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), - HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), - HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), - HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), - HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), - HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), - HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), - HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), - HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), - HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), - HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), - HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), - HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), - HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), - HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), - HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), - HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), - HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), - HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), - HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), - HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), - HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), - HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), - HB_SCRIPT_CANADIAN_ABORIGINAL = HB_TAG ('C','a','n','s'), - HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), - HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), - HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), - HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), - HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), + /* Unicode-1.1 additions */ + HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), + HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), + HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), + HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), + HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), + HB_SCRIPT_CANADIAN_ABORIGINAL = HB_TAG ('C','a','n','s'), + HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), + HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), + HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), + HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), + HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), + HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), + HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), + HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), + HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), + HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), + HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), + HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), + HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), + HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), + HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), + HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), + HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), + HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), + HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), + HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), + HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), + HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), + HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), + HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), + HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), + HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), + HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), + + /* Unicode-2.0 additions */ + HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), + + /* Unicode-3.0 additions */ + HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), + HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), + HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), + HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), + HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), + + /* Unicode-3.1 additions */ + HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), + HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), + HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), + + /* Unicode-3.2 additions */ + HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), + HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), + HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), + HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /* Unicode-4.0 additions */ - HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), - HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), - HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), - HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), - HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), - HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), - HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), - HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), + HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), + HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), + HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), + HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), + HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), + HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), + HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), + HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /* Unicode-4.1 additions */ - HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), - HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), - HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), - HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), - HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), - HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), - HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), + HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), + HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), + HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), + HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), + HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), + HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), + HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /* Unicode-5.0 additions */ - HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), - HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), - HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), - HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), - HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), - HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), + HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), + HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), + HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), + HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), + HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), + HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /* Unicode-5.1 additions */ - HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), - HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), - HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), - HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), - HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), - HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), - HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), - HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), - HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), - HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), - HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), + HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), + HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), + HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), + HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), + HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), + HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), + HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), + HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), + HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), + HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), + HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /* Unicode-5.2 additions */ - HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), - HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), - HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), - HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), - HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), - HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), - HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), - HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), - HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), - HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), - HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), - HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), - HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), - HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), - HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), + HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), + HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), + HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), + HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), + HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), + HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), + HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), + HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), + HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), + HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), + HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), + HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), + HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /* Unicode-6.0 additions */ - HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), - HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), - HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), + HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), + HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), + HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), + + /* Unicode-6.1 additions */ + HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), + HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), + HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), + HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), + HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), + HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), + HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /* No script set */ - HB_SCRIPT_INVALID = HB_TAG_NONE + HB_SCRIPT_INVALID = HB_TAG_NONE } hb_script_t; diff --git a/third_party/harfbuzz-ng/src/hb-fallback-shape-private.hh b/third_party/harfbuzz-ng/src/hb-fallback-shape-private.hh index d0beb16..159456d 100644 --- a/third_party/harfbuzz-ng/src/hb-fallback-shape-private.hh +++ b/third_party/harfbuzz-ng/src/hb-fallback-shape-private.hh @@ -36,11 +36,10 @@ HB_BEGIN_DECLS HB_INTERNAL hb_bool_t -hb_fallback_shape (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options); +_hb_fallback_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-fallback-shape.cc b/third_party/harfbuzz-ng/src/hb-fallback-shape.cc index 2fd527f..20ea43e 100644 --- a/third_party/harfbuzz-ng/src/hb-fallback-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-fallback-shape.cc @@ -29,11 +29,10 @@ #include "hb-buffer-private.hh" hb_bool_t -hb_fallback_shape (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options) +_hb_fallback_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features HB_UNUSED, + unsigned int num_features HB_UNUSED) { buffer->guess_properties (); diff --git a/third_party/harfbuzz-ng/src/hb-font-private.hh b/third_party/harfbuzz-ng/src/hb-font-private.hh index d896e72..e10e105 100644 --- a/third_party/harfbuzz-ng/src/hb-font-private.hh +++ b/third_party/harfbuzz-ng/src/hb-font-private.hh @@ -50,6 +50,8 @@ HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \ HB_FONT_FUNC_IMPLEMENT (glyph_extents) \ HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ + HB_FONT_FUNC_IMPLEMENT (glyph_name) \ + HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \ /* ^--- Add new callbacks here */ struct _hb_font_funcs_t { diff --git a/third_party/harfbuzz-ng/src/hb-font.cc b/third_party/harfbuzz-ng/src/hb-font.cc index d549455..1862ac3 100644 --- a/third_party/harfbuzz-ng/src/hb-font.cc +++ b/third_party/harfbuzz-ng/src/hb-font.cc @@ -33,6 +33,8 @@ #include "hb-open-file-private.hh" #include "hb-ot-head-table.hh" +#include "hb-cache-private.hh" + #include <string.h> @@ -42,7 +44,7 @@ */ static hb_bool_t -hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t unicode, hb_codepoint_t variation_selector, @@ -57,7 +59,7 @@ hb_font_get_glyph_nil (hb_font_t *font HB_UNUSED, } static hb_position_t -hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_h_advance_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, void *user_data HB_UNUSED) @@ -69,7 +71,7 @@ hb_font_get_glyph_h_advance_nil (hb_font_t *font HB_UNUSED, } static hb_position_t -hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_v_advance_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, void *user_data HB_UNUSED) @@ -81,7 +83,7 @@ hb_font_get_glyph_v_advance_nil (hb_font_t *font HB_UNUSED, } static hb_bool_t -hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_h_origin_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, hb_position_t *x, @@ -89,9 +91,7 @@ hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { if (font->parent) { - hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent, - glyph, - x, y); + hb_bool_t ret = hb_font_get_glyph_h_origin (font->parent, glyph, x, y); if (ret) font->parent_scale_position (x, y); return ret; @@ -102,7 +102,7 @@ hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, } static hb_bool_t -hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_v_origin_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, hb_position_t *x, @@ -110,9 +110,7 @@ hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { if (font->parent) { - hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent, - glyph, - x, y); + hb_bool_t ret = hb_font_get_glyph_v_origin (font->parent, glyph, x, y); if (ret) font->parent_scale_position (x, y); return ret; @@ -123,7 +121,7 @@ hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, } static hb_position_t -hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_h_kerning_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t left_glyph, hb_codepoint_t right_glyph, @@ -136,7 +134,7 @@ hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, } static hb_position_t -hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_v_kerning_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph, @@ -149,7 +147,7 @@ hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, } static hb_bool_t -hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_extents_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, hb_glyph_extents_t *extents, @@ -171,7 +169,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, } static hb_bool_t -hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, +hb_font_get_glyph_contour_point_nil (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, unsigned int point_index, @@ -180,9 +178,7 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { if (font->parent) { - hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent, - glyph, point_index, - x, y); + hb_bool_t ret = hb_font_get_glyph_contour_point (font->parent, glyph, point_index, x, y); if (ret) font->parent_scale_position (x, y); return ret; @@ -192,6 +188,34 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, return FALSE; } +static hb_bool_t +hb_font_get_glyph_name_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) +{ + if (font->parent) + return hb_font_get_glyph_name (font->parent, glyph, name, size); + + snprintf (name, size, "gid%u", glyph); + return FALSE; +} + +static hb_bool_t +hb_font_get_glyph_from_name_nil (hb_font_t *font, + void *font_data HB_UNUSED, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + if (font->parent) + return hb_font_get_glyph_from_name (font->parent, name, len, glyph); + + *glyph = 0; + return FALSE; +} + static hb_font_funcs_t _hb_font_funcs_nil = { HB_OBJECT_HEADER_STATIC, @@ -403,6 +427,28 @@ hb_font_get_glyph_contour_point (hb_font_t *font, font->klass->user_data.glyph_contour_point); } +hb_bool_t +hb_font_get_glyph_name (hb_font_t *font, + hb_codepoint_t glyph, + char *name, unsigned int size) +{ + return font->klass->get.glyph_name (font, font->user_data, + glyph, + name, size, + font->klass->user_data.glyph_name); +} + +hb_bool_t +hb_font_get_glyph_from_name (hb_font_t *font, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph) +{ + return font->klass->get.glyph_from_name (font, font->user_data, + name, len, + glyph, + font->klass->user_data.glyph_from_name); +} + /* A bit higher-level, and with fallback */ @@ -729,7 +775,7 @@ hb_face_set_index (hb_face_t *face, if (hb_object_is_inert (face)) return; - face->index = 0; + face->index = index; } unsigned int diff --git a/third_party/harfbuzz-ng/src/hb-font.h b/third_party/harfbuzz-ng/src/hb-font.h index 8a9dda5..b98759b 100644 --- a/third_party/harfbuzz-ng/src/hb-font.h +++ b/third_party/harfbuzz-ng/src/hb-font.h @@ -24,6 +24,10 @@ * Red Hat Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_FONT_H #define HB_FONT_H @@ -188,6 +192,16 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo void *user_data); +typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data); +typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data); + + /* func setters */ void @@ -231,6 +245,15 @@ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_contour_point_func_t func, void *user_data, hb_destroy_func_t destroy); +void +hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_name_func_t glyph_func, + void *user_data, hb_destroy_func_t destroy); +void +hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_from_name_func_t glyph_func, + void *user_data, hb_destroy_func_t destroy); + /* func dispatch */ @@ -272,6 +295,15 @@ hb_font_get_glyph_contour_point (hb_font_t *font, hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y); +hb_bool_t +hb_font_get_glyph_name (hb_font_t *font, + hb_codepoint_t glyph, + char *name, unsigned int size); +hb_bool_t +hb_font_get_glyph_from_name (hb_font_t *font, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph); + /* high-level funcs, with fallback */ diff --git a/third_party/harfbuzz-ng/src/hb-ft.cc b/third_party/harfbuzz-ng/src/hb-ft.cc index 23c2cc0..90adc0d 100644 --- a/third_party/harfbuzz-ng/src/hb-ft.cc +++ b/third_party/harfbuzz-ng/src/hb-ft.cc @@ -61,6 +61,8 @@ * provide any API to get to the transform/delta set on the face. :( * * - Always use FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH? + * + * - FT_Load_Glyph() is exteremely costly. Do something about it? */ @@ -229,21 +231,55 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, return TRUE; } +static hb_bool_t +hb_ft_get_glyph_name (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data 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) + snprintf (name, size, "gid%u", glyph); + + return ret; +} + +static hb_bool_t +hb_ft_get_glyph_from_name (hb_font_t *font, + void *font_data, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + + if (len < 0) + *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); + else { + /* Make a nul-terminated version. */ + char buf[128]; + len = MIN (len, (int) sizeof (buf) - 1); + strncpy (buf, name, len); + buf[len] = '\0'; + *glyph = FT_Get_Name_Index (ft_face, buf); + } + + return *glyph != 0; +} + + static hb_font_funcs_t ft_ffuncs = { HB_OBJECT_HEADER_STATIC, TRUE, /* immutable */ { - hb_ft_get_glyph, - hb_ft_get_glyph_h_advance, - hb_ft_get_glyph_v_advance, - hb_ft_get_glyph_h_origin, - hb_ft_get_glyph_v_origin, - hb_ft_get_glyph_h_kerning, - hb_ft_get_glyph_v_kerning, - hb_ft_get_glyph_extents, - hb_ft_get_glyph_contour_point, +#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT } }; diff --git a/third_party/harfbuzz-ng/src/hb-ft.h b/third_party/harfbuzz-ng/src/hb-ft.h index c1772ac..696251e 100644 --- a/third_party/harfbuzz-ng/src/hb-ft.h +++ b/third_party/harfbuzz-ng/src/hb-ft.h @@ -29,8 +29,6 @@ #include "hb.h" -#include "hb-font.h" - #include <ft2build.h> #include FT_FREETYPE_H diff --git a/third_party/harfbuzz-ng/src/hb-glib.cc b/third_party/harfbuzz-ng/src/hb-glib.cc index f990988..26d40a3 100644 --- a/third_party/harfbuzz-ng/src/hb-glib.cc +++ b/third_party/harfbuzz-ng/src/hb-glib.cc @@ -144,7 +144,16 @@ glib_script_to_script[] = /* Unicode-6.0 additions */ HB_SCRIPT_BATAK, HB_SCRIPT_BRAHMI, - HB_SCRIPT_MANDAIC + HB_SCRIPT_MANDAIC, + + /* Unicode-6.1 additions */ + HB_SCRIPT_CHAKMA, + HB_SCRIPT_MEROITIC_CURSIVE, + HB_SCRIPT_MEROITIC_HIEROGLYPHS, + HB_SCRIPT_MIAO, + HB_SCRIPT_SHARADA, + HB_SCRIPT_SORA_SOMPENG, + HB_SCRIPT_TAKRI }; #endif diff --git a/third_party/harfbuzz-ng/src/hb-glib.h b/third_party/harfbuzz-ng/src/hb-glib.h index 3bc3ebf..63a9d33 100644 --- a/third_party/harfbuzz-ng/src/hb-glib.h +++ b/third_party/harfbuzz-ng/src/hb-glib.h @@ -30,6 +30,7 @@ #define HB_GLIB_H #include "hb.h" + #include <glib.h> HB_BEGIN_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-gobject-enums.cc b/third_party/harfbuzz-ng/src/hb-gobject-enums.cc index 9d16c85..64adbc9 100644 --- a/third_party/harfbuzz-ng/src/hb-gobject-enums.cc +++ b/third_party/harfbuzz-ng/src/hb-gobject-enums.cc @@ -148,83 +148,83 @@ hb_script_t_hb_script_t_get_type (void) { static const GEnumValue values[] = { { HB_SCRIPT_COMMON, "HB_SCRIPT_COMMON", "common" }, - { HB_SCRIPT_INHERITED, "HB_SCRIPT_INHERITED", "inherited" }, { HB_SCRIPT_ARABIC, "HB_SCRIPT_ARABIC", "arabic" }, { HB_SCRIPT_ARMENIAN, "HB_SCRIPT_ARMENIAN", "armenian" }, { HB_SCRIPT_BENGALI, "HB_SCRIPT_BENGALI", "bengali" }, { HB_SCRIPT_BOPOMOFO, "HB_SCRIPT_BOPOMOFO", "bopomofo" }, + { HB_SCRIPT_CANADIAN_ABORIGINAL, "HB_SCRIPT_CANADIAN_ABORIGINAL", "canadian-aboriginal" }, { HB_SCRIPT_CHEROKEE, "HB_SCRIPT_CHEROKEE", "cherokee" }, { HB_SCRIPT_COPTIC, "HB_SCRIPT_COPTIC", "coptic" }, { HB_SCRIPT_CYRILLIC, "HB_SCRIPT_CYRILLIC", "cyrillic" }, - { HB_SCRIPT_DESERET, "HB_SCRIPT_DESERET", "deseret" }, { HB_SCRIPT_DEVANAGARI, "HB_SCRIPT_DEVANAGARI", "devanagari" }, - { HB_SCRIPT_ETHIOPIC, "HB_SCRIPT_ETHIOPIC", "ethiopic" }, { HB_SCRIPT_GEORGIAN, "HB_SCRIPT_GEORGIAN", "georgian" }, - { HB_SCRIPT_GOTHIC, "HB_SCRIPT_GOTHIC", "gothic" }, { HB_SCRIPT_GREEK, "HB_SCRIPT_GREEK", "greek" }, { HB_SCRIPT_GUJARATI, "HB_SCRIPT_GUJARATI", "gujarati" }, { HB_SCRIPT_GURMUKHI, "HB_SCRIPT_GURMUKHI", "gurmukhi" }, - { HB_SCRIPT_HAN, "HB_SCRIPT_HAN", "han" }, { HB_SCRIPT_HANGUL, "HB_SCRIPT_HANGUL", "hangul" }, + { HB_SCRIPT_HAN, "HB_SCRIPT_HAN", "han" }, { HB_SCRIPT_HEBREW, "HB_SCRIPT_HEBREW", "hebrew" }, { HB_SCRIPT_HIRAGANA, "HB_SCRIPT_HIRAGANA", "hiragana" }, + { HB_SCRIPT_INHERITED, "HB_SCRIPT_INHERITED", "inherited" }, { HB_SCRIPT_KANNADA, "HB_SCRIPT_KANNADA", "kannada" }, { HB_SCRIPT_KATAKANA, "HB_SCRIPT_KATAKANA", "katakana" }, - { HB_SCRIPT_KHMER, "HB_SCRIPT_KHMER", "khmer" }, { HB_SCRIPT_LAO, "HB_SCRIPT_LAO", "lao" }, { HB_SCRIPT_LATIN, "HB_SCRIPT_LATIN", "latin" }, { HB_SCRIPT_MALAYALAM, "HB_SCRIPT_MALAYALAM", "malayalam" }, { HB_SCRIPT_MONGOLIAN, "HB_SCRIPT_MONGOLIAN", "mongolian" }, - { HB_SCRIPT_MYANMAR, "HB_SCRIPT_MYANMAR", "myanmar" }, { HB_SCRIPT_OGHAM, "HB_SCRIPT_OGHAM", "ogham" }, - { HB_SCRIPT_OLD_ITALIC, "HB_SCRIPT_OLD_ITALIC", "old-italic" }, { HB_SCRIPT_ORIYA, "HB_SCRIPT_ORIYA", "oriya" }, { HB_SCRIPT_RUNIC, "HB_SCRIPT_RUNIC", "runic" }, - { HB_SCRIPT_SINHALA, "HB_SCRIPT_SINHALA", "sinhala" }, { HB_SCRIPT_SYRIAC, "HB_SCRIPT_SYRIAC", "syriac" }, { HB_SCRIPT_TAMIL, "HB_SCRIPT_TAMIL", "tamil" }, { HB_SCRIPT_TELUGU, "HB_SCRIPT_TELUGU", "telugu" }, - { HB_SCRIPT_THAANA, "HB_SCRIPT_THAANA", "thaana" }, { HB_SCRIPT_THAI, "HB_SCRIPT_THAI", "thai" }, - { HB_SCRIPT_TIBETAN, "HB_SCRIPT_TIBETAN", "tibetan" }, - { HB_SCRIPT_CANADIAN_ABORIGINAL, "HB_SCRIPT_CANADIAN_ABORIGINAL", "canadian-aboriginal" }, { HB_SCRIPT_YI, "HB_SCRIPT_YI", "yi" }, - { HB_SCRIPT_TAGALOG, "HB_SCRIPT_TAGALOG", "tagalog" }, - { HB_SCRIPT_HANUNOO, "HB_SCRIPT_HANUNOO", "hanunoo" }, + { HB_SCRIPT_TIBETAN, "HB_SCRIPT_TIBETAN", "tibetan" }, + { HB_SCRIPT_ETHIOPIC, "HB_SCRIPT_ETHIOPIC", "ethiopic" }, + { HB_SCRIPT_KHMER, "HB_SCRIPT_KHMER", "khmer" }, + { HB_SCRIPT_MYANMAR, "HB_SCRIPT_MYANMAR", "myanmar" }, + { HB_SCRIPT_SINHALA, "HB_SCRIPT_SINHALA", "sinhala" }, + { HB_SCRIPT_THAANA, "HB_SCRIPT_THAANA", "thaana" }, + { HB_SCRIPT_DESERET, "HB_SCRIPT_DESERET", "deseret" }, + { HB_SCRIPT_GOTHIC, "HB_SCRIPT_GOTHIC", "gothic" }, + { HB_SCRIPT_OLD_ITALIC, "HB_SCRIPT_OLD_ITALIC", "old-italic" }, { HB_SCRIPT_BUHID, "HB_SCRIPT_BUHID", "buhid" }, + { HB_SCRIPT_HANUNOO, "HB_SCRIPT_HANUNOO", "hanunoo" }, + { HB_SCRIPT_TAGALOG, "HB_SCRIPT_TAGALOG", "tagalog" }, { HB_SCRIPT_TAGBANWA, "HB_SCRIPT_TAGBANWA", "tagbanwa" }, { HB_SCRIPT_BRAILLE, "HB_SCRIPT_BRAILLE", "braille" }, { HB_SCRIPT_CYPRIOT, "HB_SCRIPT_CYPRIOT", "cypriot" }, { HB_SCRIPT_LIMBU, "HB_SCRIPT_LIMBU", "limbu" }, + { HB_SCRIPT_LINEAR_B, "HB_SCRIPT_LINEAR_B", "linear-b" }, { HB_SCRIPT_OSMANYA, "HB_SCRIPT_OSMANYA", "osmanya" }, { HB_SCRIPT_SHAVIAN, "HB_SCRIPT_SHAVIAN", "shavian" }, - { HB_SCRIPT_LINEAR_B, "HB_SCRIPT_LINEAR_B", "linear-b" }, { HB_SCRIPT_TAI_LE, "HB_SCRIPT_TAI_LE", "tai-le" }, { HB_SCRIPT_UGARITIC, "HB_SCRIPT_UGARITIC", "ugaritic" }, - { HB_SCRIPT_NEW_TAI_LUE, "HB_SCRIPT_NEW_TAI_LUE", "new-tai-lue" }, { HB_SCRIPT_BUGINESE, "HB_SCRIPT_BUGINESE", "buginese" }, { HB_SCRIPT_GLAGOLITIC, "HB_SCRIPT_GLAGOLITIC", "glagolitic" }, - { HB_SCRIPT_TIFINAGH, "HB_SCRIPT_TIFINAGH", "tifinagh" }, - { HB_SCRIPT_SYLOTI_NAGRI, "HB_SCRIPT_SYLOTI_NAGRI", "syloti-nagri" }, - { HB_SCRIPT_OLD_PERSIAN, "HB_SCRIPT_OLD_PERSIAN", "old-persian" }, { HB_SCRIPT_KHAROSHTHI, "HB_SCRIPT_KHAROSHTHI", "kharoshthi" }, - { HB_SCRIPT_UNKNOWN, "HB_SCRIPT_UNKNOWN", "unknown" }, + { HB_SCRIPT_NEW_TAI_LUE, "HB_SCRIPT_NEW_TAI_LUE", "new-tai-lue" }, + { HB_SCRIPT_OLD_PERSIAN, "HB_SCRIPT_OLD_PERSIAN", "old-persian" }, + { HB_SCRIPT_SYLOTI_NAGRI, "HB_SCRIPT_SYLOTI_NAGRI", "syloti-nagri" }, + { HB_SCRIPT_TIFINAGH, "HB_SCRIPT_TIFINAGH", "tifinagh" }, { HB_SCRIPT_BALINESE, "HB_SCRIPT_BALINESE", "balinese" }, { HB_SCRIPT_CUNEIFORM, "HB_SCRIPT_CUNEIFORM", "cuneiform" }, - { HB_SCRIPT_PHOENICIAN, "HB_SCRIPT_PHOENICIAN", "phoenician" }, - { HB_SCRIPT_PHAGS_PA, "HB_SCRIPT_PHAGS_PA", "phags-pa" }, { HB_SCRIPT_NKO, "HB_SCRIPT_NKO", "nko" }, + { HB_SCRIPT_PHAGS_PA, "HB_SCRIPT_PHAGS_PA", "phags-pa" }, + { HB_SCRIPT_PHOENICIAN, "HB_SCRIPT_PHOENICIAN", "phoenician" }, + { HB_SCRIPT_UNKNOWN, "HB_SCRIPT_UNKNOWN", "unknown" }, + { HB_SCRIPT_CARIAN, "HB_SCRIPT_CARIAN", "carian" }, + { HB_SCRIPT_CHAM, "HB_SCRIPT_CHAM", "cham" }, { HB_SCRIPT_KAYAH_LI, "HB_SCRIPT_KAYAH_LI", "kayah-li" }, { HB_SCRIPT_LEPCHA, "HB_SCRIPT_LEPCHA", "lepcha" }, + { HB_SCRIPT_LYCIAN, "HB_SCRIPT_LYCIAN", "lycian" }, + { HB_SCRIPT_LYDIAN, "HB_SCRIPT_LYDIAN", "lydian" }, + { HB_SCRIPT_OL_CHIKI, "HB_SCRIPT_OL_CHIKI", "ol-chiki" }, { HB_SCRIPT_REJANG, "HB_SCRIPT_REJANG", "rejang" }, - { HB_SCRIPT_SUNDANESE, "HB_SCRIPT_SUNDANESE", "sundanese" }, { HB_SCRIPT_SAURASHTRA, "HB_SCRIPT_SAURASHTRA", "saurashtra" }, - { HB_SCRIPT_CHAM, "HB_SCRIPT_CHAM", "cham" }, - { HB_SCRIPT_OL_CHIKI, "HB_SCRIPT_OL_CHIKI", "ol-chiki" }, + { HB_SCRIPT_SUNDANESE, "HB_SCRIPT_SUNDANESE", "sundanese" }, { HB_SCRIPT_VAI, "HB_SCRIPT_VAI", "vai" }, - { HB_SCRIPT_CARIAN, "HB_SCRIPT_CARIAN", "carian" }, - { HB_SCRIPT_LYCIAN, "HB_SCRIPT_LYCIAN", "lycian" }, - { HB_SCRIPT_LYDIAN, "HB_SCRIPT_LYDIAN", "lydian" }, { HB_SCRIPT_AVESTAN, "HB_SCRIPT_AVESTAN", "avestan" }, { HB_SCRIPT_BAMUM, "HB_SCRIPT_BAMUM", "bamum" }, { HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, "HB_SCRIPT_EGYPTIAN_HIEROGLYPHS", "egyptian-hieroglyphs" }, @@ -243,6 +243,13 @@ hb_script_t_hb_script_t_get_type (void) { HB_SCRIPT_BATAK, "HB_SCRIPT_BATAK", "batak" }, { HB_SCRIPT_BRAHMI, "HB_SCRIPT_BRAHMI", "brahmi" }, { HB_SCRIPT_MANDAIC, "HB_SCRIPT_MANDAIC", "mandaic" }, + { HB_SCRIPT_CHAKMA, "HB_SCRIPT_CHAKMA", "chakma" }, + { HB_SCRIPT_MEROITIC_CURSIVE, "HB_SCRIPT_MEROITIC_CURSIVE", "meroitic-cursive" }, + { HB_SCRIPT_MEROITIC_HIEROGLYPHS, "HB_SCRIPT_MEROITIC_HIEROGLYPHS", "meroitic-hieroglyphs" }, + { HB_SCRIPT_MIAO, "HB_SCRIPT_MIAO", "miao" }, + { HB_SCRIPT_SHARADA, "HB_SCRIPT_SHARADA", "sharada" }, + { HB_SCRIPT_SORA_SOMPENG, "HB_SCRIPT_SORA_SOMPENG", "sora-sompeng" }, + { HB_SCRIPT_TAKRI, "HB_SCRIPT_TAKRI", "takri" }, { HB_SCRIPT_INVALID, "HB_SCRIPT_INVALID", "invalid" }, { 0, NULL, NULL } }; diff --git a/third_party/harfbuzz-ng/src/hb-gobject.h b/third_party/harfbuzz-ng/src/hb-gobject.h index 25fc941..4f23fdd 100644 --- a/third_party/harfbuzz-ng/src/hb-gobject.h +++ b/third_party/harfbuzz-ng/src/hb-gobject.h @@ -28,6 +28,7 @@ #define HB_GOBJECT_H #include "hb.h" + #include <glib-object.h> HB_BEGIN_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape.h b/third_party/harfbuzz-ng/src/hb-graphite2-private.hh index 1897e84..644ea75 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape.h +++ b/third_party/harfbuzz-ng/src/hb-graphite2-private.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2010 Red Hat, Inc. + * Copyright © 2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -21,27 +21,22 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_SHAPE_H -#define HB_OT_SHAPE_H +#ifndef HB_GRAPHITE2_PRIVATE_HH +#define HB_GRAPHITE2_PRIVATE_HH -#include "hb-common.h" -#include "hb-shape.h" +#include "hb-private.hh" +#include "hb-graphite2.h" -HB_BEGIN_DECLS +HB_INTERNAL hb_bool_t +_hb_graphite2_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features); -hb_bool_t -hb_ot_shape (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options); - -HB_END_DECLS - -#endif /* HB_OT_SHAPE_H */ +#endif /* HB_GRAPHITE2_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-graphite2.cc b/third_party/harfbuzz-ng/src/hb-graphite2.cc index 0675759..eab2eae 100644 --- a/third_party/harfbuzz-ng/src/hb-graphite2.cc +++ b/third_party/harfbuzz-ng/src/hb-graphite2.cc @@ -130,6 +130,7 @@ static void _hb_gr_font_data_destroy (void *data) hb_gr_font_data_t *f = (hb_gr_font_data_t *) data; gr_font_destroy (f->grfont); + free (f); } static hb_user_data_key_t hb_gr_data_key; @@ -212,15 +213,17 @@ _hb_gr_font_get_data (hb_font_t *font) hb_bool_t -hb_graphite_shape (hb_font_t *font, +_hb_graphite_shape (hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options) + unsigned int num_features) { buffer->guess_properties (); + /* XXX We do a hell of a lot of stuff just to figure out this font + * is not graphite! Shouldn't do. */ + hb_gr_font_data_t *data = _hb_gr_font_get_data (font); if (!data->grface) return FALSE; @@ -244,11 +247,10 @@ hb_graphite_shape (hb_font_t *font, features++; } - unsigned short *gids = NULL; + hb_codepoint_t *gids = NULL, *pg; hb_gr_cluster_t *clusters = NULL; gr_segment *seg = NULL; uint32_t *text = NULL; - unsigned short *pg; const gr_slot *is; unsigned int ci = 0, ic = 0; float curradvx = 0., curradvy = 0.; @@ -277,7 +279,7 @@ hb_graphite_shape (hb_font_t *font, clusters = (hb_gr_cluster_t *) calloc (charlen, sizeof (hb_gr_cluster_t)); if (!glyphlen || !clusters) goto dieout; - gids = (uint16_t *) malloc (glyphlen * sizeof (uint16_t)); + gids = (hb_codepoint_t *) malloc (glyphlen * sizeof (hb_codepoint_t)); if (!gids) goto dieout; pg = gids; diff --git a/third_party/harfbuzz-ng/src/hb-graphite2.h b/third_party/harfbuzz-ng/src/hb-graphite2.h index 68bd019..2d16cc8 100644 --- a/third_party/harfbuzz-ng/src/hb-graphite2.h +++ b/third_party/harfbuzz-ng/src/hb-graphite2.h @@ -26,20 +26,14 @@ #ifndef HB_GRAPHITE2_H #define HB_GRAPHITE2_H -#include "hb-common.h" -#include "hb-shape.h" +#include "hb.h" HB_BEGIN_DECLS #define HB_GRAPHITE_TAG_Silf HB_TAG('S','i','l','f') -hb_bool_t -hb_graphite_shape (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options); +/* TODO add gr_font/face etc getters and other glue API */ HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-icu.h b/third_party/harfbuzz-ng/src/hb-icu.h index ecabec2..d22a8e1 100644 --- a/third_party/harfbuzz-ng/src/hb-icu.h +++ b/third_party/harfbuzz-ng/src/hb-icu.h @@ -30,6 +30,7 @@ #define HB_ICU_H #include "hb.h" + #include <unicode/uscript.h> diff --git a/third_party/harfbuzz-ng/src/hb-mutex-private.hh b/third_party/harfbuzz-ng/src/hb-mutex-private.hh index 9855a565..44b48df 100644 --- a/third_party/harfbuzz-ng/src/hb-mutex-private.hh +++ b/third_party/harfbuzz-ng/src/hb-mutex-private.hh @@ -35,27 +35,16 @@ #include "hb-private.hh" - /* mutex */ /* We need external help for these */ -#ifdef HAVE_GLIB +#if 0 -#include <glib.h> -typedef GStaticMutex hb_mutex_impl_t; -#define HB_MUTEX_IMPL_INIT G_STATIC_MUTEX_INIT -#define hb_mutex_impl_init(M) g_static_mutex_init (M) -#define hb_mutex_impl_lock(M) g_static_mutex_lock (M) -#define hb_mutex_impl_unlock(M) g_static_mutex_unlock (M) -#define hb_mutex_impl_free(M) g_static_mutex_free (M) - - -#elif defined(_MSC_VER) || defined(__MINGW32__) +#elif !defined(HB_NO_MT) && defined(_MSC_VER) || defined(__MINGW32__) #include <windows.h> - typedef CRITICAL_SECTION hb_mutex_impl_t; #define HB_MUTEX_IMPL_INIT { NULL, 0, 0, NULL, NULL, 0 } #define hb_mutex_impl_init(M) InitializeCriticalSection (M) @@ -64,10 +53,31 @@ typedef CRITICAL_SECTION hb_mutex_impl_t; #define hb_mutex_impl_free(M) DeleteCriticalSection (M) -#else +#elif !defined(HB_NO_MT) && defined(__APPLE__) + +#include <pthread.h> +typedef pthread_mutex_t hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER +#define hb_mutex_impl_init(M) pthread_mutex_init (M, NULL) +#define hb_mutex_impl_lock(M) pthread_mutex_lock (M) +#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M) +#define hb_mutex_impl_free(M) pthread_mutex_destroy (M) -#warning "Could not find any system to define platform macros, library will NOT be thread-safe" +#elif !defined(HB_NO_MT) && defined(HAVE_GLIB) + +#include <glib.h> +typedef GStaticMutex hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT G_STATIC_MUTEX_INIT +#define hb_mutex_impl_init(M) g_static_mutex_init (M) +#define hb_mutex_impl_lock(M) g_static_mutex_lock (M) +#define hb_mutex_impl_unlock(M) g_static_mutex_unlock (M) +#define hb_mutex_impl_free(M) g_static_mutex_free (M) + + +#else + +#define HB_MUTEX_IMPL_NIL 1 typedef volatile int hb_mutex_impl_t; #define HB_MUTEX_IMPL_INIT 0 #define hb_mutex_impl_init(M) ((void) (*(M) = 0)) @@ -75,7 +85,6 @@ typedef volatile int hb_mutex_impl_t; #define hb_mutex_impl_unlock(M) ((void) (*(M) = 0)) #define hb_mutex_impl_free(M) ((void) (*(M) = 2)) - #endif diff --git a/third_party/harfbuzz-ng/src/hb-object-private.hh b/third_party/harfbuzz-ng/src/hb-object-private.hh index 2e4a385..e3c9d21 100644 --- a/third_party/harfbuzz-ng/src/hb-object-private.hh +++ b/third_party/harfbuzz-ng/src/hb-object-private.hh @@ -34,10 +34,10 @@ #include "hb-private.hh" +#include "hb-atomic-private.hh" #include "hb-mutex-private.hh" - /* Debug */ #ifndef HB_DEBUG_OBJECT @@ -45,76 +45,28 @@ #endif -/* atomic_int */ - -/* We need external help for these */ - -#ifdef HAVE_GLIB - -#include <glib.h> - -typedef volatile int hb_atomic_int_t; -#if GLIB_CHECK_VERSION(2,29,5) -#define hb_atomic_int_add(AI, V) g_atomic_int_add (&(AI), V) -#else -#define hb_atomic_int_add(AI, V) g_atomic_int_exchange_and_add (&(AI), V) -#endif -#define hb_atomic_int_get(AI) g_atomic_int_get (&(AI)) -#define hb_atomic_int_set(AI, V) g_atomic_int_set (&(AI), V) - - -#elif defined(_MSC_VER) && _MSC_VER >= 1600 - -#include <intrin.h> - -typedef long hb_atomic_int_t; -#define hb_atomic_int_add(AI, V) _InterlockedExchangeAdd (&(AI), V) -#define hb_atomic_int_get(AI) (_ReadBarrier (), (AI)) -#define hb_atomic_int_set(AI, V) ((void) _InterlockedExchange (&(AI), (V))) - - -#else - -#ifdef _MSC_VER -#pragma message("Could not find any system to define atomic_int macros, library will NOT be thread-safe") -#else -#warning "Could not find any system to define atomic_int macros, library will NOT be thread-safe" -#endif - -typedef volatile int hb_atomic_int_t; -#define hb_atomic_int_add(AI, V) ((AI) += (V), (AI) - (V)) -#define hb_atomic_int_get(AI) (AI) -#define hb_atomic_int_set(AI, V) ((void) ((AI) = (V))) - - -#endif - - - - /* reference_count */ -typedef struct { +struct hb_reference_count_t +{ hb_atomic_int_t ref_count; #define HB_REFERENCE_COUNT_INVALID_VALUE ((hb_atomic_int_t) -1) #define HB_REFERENCE_COUNT_INVALID {HB_REFERENCE_COUNT_INVALID_VALUE} - inline void init (int v) { ref_count = v; /* non-atomic is fine */ } - inline int inc (void) { return hb_atomic_int_add (ref_count, 1); } - inline int dec (void) { return hb_atomic_int_add (ref_count, -1); } - inline void set (int v) { hb_atomic_int_set (ref_count, v); } + inline void init (int v) { const_cast<hb_atomic_int_t &> (ref_count) = v; } + inline int inc (void) { return hb_atomic_int_add (const_cast<hb_atomic_int_t &> (ref_count), 1); } + inline int dec (void) { return hb_atomic_int_add (const_cast<hb_atomic_int_t &> (ref_count), -1); } - inline int get (void) const { return hb_atomic_int_get (ref_count); } - inline bool is_invalid (void) const { return get () == HB_REFERENCE_COUNT_INVALID_VALUE; } + inline bool is_invalid (void) const { return ref_count == HB_REFERENCE_COUNT_INVALID_VALUE; } -} hb_reference_count_t; +}; /* user_data */ -struct hb_user_data_array_t { - +struct hb_user_data_array_t +{ struct hb_user_data_item_t { hb_user_data_key_t *key; void *data; @@ -141,9 +93,8 @@ struct hb_user_data_array_t { /* object_header */ -typedef struct _hb_object_header_t hb_object_header_t; - -struct _hb_object_header_t { +struct hb_object_header_t +{ hb_reference_count_t ref_count; hb_user_data_array_t user_data; @@ -200,17 +151,18 @@ struct _hb_object_header_t { } inline void trace (const char *function) const { + if (unlikely (!this)) return; + /* XXX We cannot use DEBUG_MSG_FUNC here since that one currecntly only + * prints the class name and throws away the template info. */ DEBUG_MSG (OBJECT, (void *) this, - "refcount=%d %s", - this ? ref_count.get () : 0, - function); + "%s refcount=%d", + function, + this ? ref_count.ref_count : 0); } }; - - /* object */ template <typename Type> @@ -261,7 +213,4 @@ static inline void *hb_object_get_user_data (Type *obj, } - - - #endif /* HB_OBJECT_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-open-file-private.hh b/third_party/harfbuzz-ng/src/hb-open-file-private.hh index 62e1f17..ce18580 100644 --- a/third_party/harfbuzz-ng/src/hb-open-file-private.hh +++ b/third_party/harfbuzz-ng/src/hb-open-file-private.hh @@ -1,5 +1,6 @@ /* * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,6 +23,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_OPEN_FILE_PRIVATE_HH @@ -51,7 +53,7 @@ typedef struct TableRecord { inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } Tag tag; /* 4-byte identifier. */ @@ -100,8 +102,7 @@ typedef struct OffsetTable public: inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && c->check_array (tables, TableRecord::static_size, numTables); + return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables)); } private: @@ -129,7 +130,7 @@ struct TTCHeaderVersion1 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return table.sanitize (c, this); + return TRACE_RETURN (table.sanitize (c, this)); } private: @@ -168,11 +169,11 @@ struct TTCHeader inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!u.header.version.sanitize (c))) return false; + if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false); switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ - case 1: return u.version1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.version1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -230,14 +231,14 @@ struct OpenTypeFontFile inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!u.tag.sanitize (c))) return false; + if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false); switch (u.tag) { case CFFTag: /* All the non-collection tags */ case TrueTag: case Typ1Tag: - case TrueTypeTag: return u.fontFace.sanitize (c); - case TTCTag: return u.ttcHeader.sanitize (c); - default: return true; + case TrueTypeTag: return TRACE_RETURN (u.fontFace.sanitize (c)); + case TTCTag: return TRACE_RETURN (u.ttcHeader.sanitize (c)); + default: return TRACE_RETURN (true); } } diff --git a/third_party/harfbuzz-ng/src/hb-open-type-private.hh b/third_party/harfbuzz-ng/src/hb-open-type-private.hh index 8143b28..f4a2ba9 100644 --- a/third_party/harfbuzz-ng/src/hb-open-type-private.hh +++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh @@ -1,5 +1,6 @@ /* * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,6 +23,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_OPEN_TYPE_PRIVATE_HH @@ -153,7 +155,7 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) #define TRACE_SANITIZE() \ - hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, NULL, HB_FUNC); + hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, ""); struct hb_sanitize_context_t @@ -164,24 +166,24 @@ struct hb_sanitize_context_t this->writable = false; } - inline void setup (void) + inline void start_processing (void) { this->start = hb_blob_get_data (this->blob, NULL); this->end = this->start + hb_blob_get_length (this->blob); this->edit_count = 0; this->debug_depth = 0; - DEBUG_MSG (SANITIZE, this->blob, - "init [%p..%p] (%lu bytes)", - this->start, this->end, - (unsigned long) (this->end - this->start)); + DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, +1, + "start [%p..%p] (%lu bytes)", + this->start, this->end, + (unsigned long) (this->end - this->start)); } - inline void finish (void) + inline void end_processing (void) { - DEBUG_MSG (SANITIZE, this->blob, - "fini [%p..%p] %u edit requests", - this->start, this->end, this->edit_count); + DEBUG_MSG_LEVEL (SANITIZE, this->blob, 0, -1, + "end [%p..%p] %u edit requests", + this->start, this->end, this->edit_count); hb_blob_destroy (this->blob); this->blob = NULL; @@ -191,18 +193,13 @@ struct hb_sanitize_context_t inline bool check_range (const void *base, unsigned int len) const { const char *p = (const char *) base; - bool ret = this->start <= p && - p <= this->end && - (unsigned int) (this->end - p) >= len; - - DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, - "%-*d-> range [%p..%p] (%d bytes) in [%p..%p] -> %s", - this->debug_depth, this->debug_depth, - p, p + len, len, - this->start, this->end, - ret ? "pass" : "FAIL"); - return likely (ret); + hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL, + "check_range [%p..%p] (%d bytes) in [%p..%p]", + p, p + len, len, + this->start, this->end); + + return TRACE_RETURN (likely (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len)); } inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const @@ -210,14 +207,12 @@ struct hb_sanitize_context_t const char *p = (const char *) base; bool overflows = _hb_unsigned_int_mul_overflows (len, record_size); - DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, - "%-*d-> array [%p..%p] (%d*%d=%ld bytes) in [%p..%p] -> %s", - this->debug_depth, this->debug_depth, - p, p + (record_size * len), record_size, len, (unsigned long) record_size * len, - this->start, this->end, - !overflows ? "does not overflow" : "OVERFLOWS FAIL"); + hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL, + "check_array [%p..%p] (%d*%d=%ld bytes) in [%p..%p]", + p, p + (record_size * len), record_size, len, (unsigned long) record_size * len, + this->start, this->end); - return likely (!overflows && this->check_range (base, record_size * len)); + return TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len))); } template <typename Type> @@ -226,23 +221,21 @@ struct hb_sanitize_context_t return likely (this->check_range (obj, obj->min_size)); } - inline bool can_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) + inline bool may_edit (const void *base HB_UNUSED, unsigned int len HB_UNUSED) { const char *p = (const char *) base; this->edit_count++; - DEBUG_MSG_LEVEL (SANITIZE, this->blob, this->debug_depth, - "%-*d-> edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", - this->debug_depth, this->debug_depth, - this->edit_count, - p, p + len, len, - this->start, this->end, - this->writable ? "granted" : "REJECTED"); + hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&this->debug_depth, "SANITIZE", this->blob, NULL, + "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", + this->edit_count, + p, p + len, len, + this->start, this->end); - return this->writable; + return TRACE_RETURN (this->writable); } - unsigned int debug_depth; + mutable unsigned int debug_depth; const char *start, *end; bool writable; unsigned int edit_count; @@ -266,10 +259,10 @@ struct Sanitizer retry: DEBUG_MSG_FUNC (SANITIZE, blob, "start"); - c->setup (); + c->start_processing (); if (unlikely (!c->start)) { - c->finish (); + c->end_processing (); return blob; } @@ -303,7 +296,7 @@ struct Sanitizer } } - c->finish (); + c->end_processing (); DEBUG_MSG_FUNC (SANITIZE, blob, sane ? "PASSED" : "FAILED"); if (sane) @@ -374,7 +367,7 @@ struct IntType inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return likely (c->check_struct (this)); + return TRACE_RETURN (likely (c->check_struct (this))); } protected: BEInt<Type, sizeof (Type)> v; @@ -404,7 +397,7 @@ struct LONGDATETIME { inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return likely (c->check_struct (this)); + return TRACE_RETURN (likely (c->check_struct (this))); } private: LONG major; @@ -468,7 +461,7 @@ struct FixedVersion inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } USHORT major; @@ -496,26 +489,26 @@ struct GenericOffsetTo : OffsetType inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); - if (unlikely (!c->check_struct (this))) return false; + if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); unsigned int offset = *this; - if (unlikely (!offset)) return true; + if (unlikely (!offset)) return TRACE_RETURN (true); Type &obj = StructAtOffset<Type> (base, offset); - return likely (obj.sanitize (c)) || neuter (c); + return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c)); } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { TRACE_SANITIZE (); - if (unlikely (!c->check_struct (this))) return false; + if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); unsigned int offset = *this; - if (unlikely (!offset)) return true; + if (unlikely (!offset)) return TRACE_RETURN (true); Type &obj = StructAtOffset<Type> (base, offset); - return likely (obj.sanitize (c, user_data)) || neuter (c); + return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c)); } private: /* Set the offset to Null */ inline bool neuter (hb_sanitize_context_t *c) { - if (c->can_edit (this, this->static_size)) { + if (c->may_edit (this, this->static_size)) { this->set (0); /* 0 is Null offset */ return true; } @@ -561,7 +554,7 @@ struct GenericArrayOf inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!sanitize_shallow (c))) return false; + if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); /* Note: for structs that do not reference other structs, * we do not need to call their sanitize() as we already did @@ -572,33 +565,32 @@ struct GenericArrayOf */ (void) (false && array[0].sanitize (c)); - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); - if (unlikely (!sanitize_shallow (c))) return false; + if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!array[i].sanitize (c, base))) - return false; - return true; + return TRACE_RETURN (false); + return TRACE_RETURN (true); } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { TRACE_SANITIZE (); - if (unlikely (!sanitize_shallow (c))) return false; + if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!array[i].sanitize (c, base, user_data))) - return false; - return true; + return TRACE_RETURN (false); + return TRACE_RETURN (true); } private: inline bool sanitize_shallow (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && c->check_array (this, Type::static_size, len); + return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len)); } public: @@ -640,12 +632,12 @@ struct OffsetListOf : OffsetArrayOf<Type> inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return OffsetArrayOf<Type>::sanitize (c, this); + return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this)); } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, T user_data) { TRACE_SANITIZE (); - return OffsetArrayOf<Type>::sanitize (c, this, user_data); + return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data)); } }; @@ -670,7 +662,7 @@ struct HeadlessArrayOf inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!sanitize_shallow (c))) return false; + if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); /* Note: for structs that do not reference other structs, * we do not need to call their sanitize() as we already did @@ -681,7 +673,7 @@ struct HeadlessArrayOf */ (void) (false && array[0].sanitize (c)); - return true; + return TRACE_RETURN (true); } USHORT len; diff --git a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh index a4d8d5f..32d64ca 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh @@ -1,5 +1,6 @@ /* * Copyright © 2010 Red Hat, Inc. + * Copyright © 2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,6 +23,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_OT_HEAD_TABLE_HH @@ -49,7 +51,7 @@ struct head inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) && likely (version.major == 1); + return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); } private: diff --git a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh index 34bf494..2eea05a 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -44,7 +44,7 @@ struct hhea inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) && likely (version.major == 1); + return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); } private: diff --git a/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh index b58799c..35cfb48 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -54,7 +54,7 @@ struct hmtx TRACE_SANITIZE (); /* We don't check for anything specific here. The users of the * struct do all the hard work... */ - return true; + return TRACE_RETURN (true); } private: diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh index 5d19e08..2943a7f 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009 Red Hat, Inc. - * Copyright © 2010 Google, Inc. + * Copyright © 2010,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -30,11 +30,10 @@ #define HB_OT_LAYOUT_COMMON_PRIVATE_HH #include "hb-ot-layout-private.hh" - #include "hb-open-type-private.hh" +#include "hb-set-private.hh" -#define NO_CONTEXT ((unsigned int) 0x110000) #define NOT_COVERED ((unsigned int) 0x110000) #define MAX_NESTING_LEVEL 8 @@ -60,8 +59,7 @@ struct Record inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); - return c->check_struct (this) - && offset.sanitize (c, base); + return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base)); } Tag tag; /* 4-byte Tag identifier */ @@ -115,7 +113,7 @@ struct RecordListOf : RecordArrayOf<Type> inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return RecordArrayOf<Type>::sanitize (c, this); + return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this)); } }; @@ -129,7 +127,11 @@ struct RangeRecord inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); + } + + inline bool intersects (const hb_set_t *glyphs) const { + return glyphs->intersects (start, end); } GlyphID start; /* First GlyphID in the range */ @@ -184,8 +186,7 @@ struct LangSys inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && featureIndex.sanitize (c); + return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c)); } Offset lookupOrder; /* = Null (reserved for an offset to a @@ -223,8 +224,7 @@ struct Script inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return defaultLangSys.sanitize (c, this) - && langSys.sanitize (c, this); + return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); } private: @@ -254,8 +254,7 @@ struct Feature inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && lookupIndex.sanitize (c); + return TRACE_RETURN (c->check_struct (this) && lookupIndex.sanitize (c)); } Offset featureParams; /* Offset to Feature Parameters table (if one @@ -272,7 +271,7 @@ typedef RecordListOf<Feature> FeatureList; struct LookupFlag : USHORT { - enum { + enum Flags { RightToLeft = 0x0001u, IgnoreBaseGlyphs = 0x0002u, IgnoreLigatures = 0x0004u, @@ -309,14 +308,13 @@ struct Lookup inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); /* Real sanitize of the subtables is done by GSUB/GPOS/... */ - if (!(c->check_struct (this) - && subTable.sanitize (c))) return false; + if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false); if (unlikely (lookupFlag & LookupFlag::UseMarkFilteringSet)) { USHORT &markFilteringSet = StructAfter<USHORT> (subTable); - if (!markFilteringSet.sanitize (c)) return false; + if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false); } - return true; + return TRACE_RETURN (true); } USHORT lookupType; /* Different enumerations for GSUB and GPOS */ @@ -352,9 +350,25 @@ struct CoverageFormat1 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return glyphArray.sanitize (c); + return TRACE_RETURN (glyphArray.sanitize (c)); } + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { + return glyphs->has (glyphArray[index]); + } + + struct Iter { + inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; + inline bool more (void) { return i < c->glyphArray.len; } + inline void next (void) { i++; } + inline uint16_t get_glyph (void) { return c->glyphArray[i]; } + inline uint16_t get_coverage (void) { return i; } + + private: + const struct CoverageFormat1 *c; + unsigned int i; + }; + private: USHORT coverageFormat; /* Format identifier--format = 1 */ SortedArrayOf<GlyphID> @@ -380,9 +394,50 @@ struct CoverageFormat2 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return rangeRecord.sanitize (c); + return TRACE_RETURN (rangeRecord.sanitize (c)); + } + + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { + unsigned int i; + unsigned int count = rangeRecord.len; + for (i = 0; i < count; i++) { + const RangeRecord &range = rangeRecord[i]; + if (range.value <= index && + index < (unsigned int) range.value + (range.end - range.start) && + range.intersects (glyphs)) + return true; + else if (index < range.value) + return false; + } + return false; } + struct Iter { + inline void init (const CoverageFormat2 &c_) { + c = &c_; + coverage = 0; + i = 0; + j = c->rangeRecord.len ? c_.rangeRecord[0].start : 0; + } + inline bool more (void) { return i < c->rangeRecord.len; } + inline void next (void) { + coverage++; + if (j == c->rangeRecord[i].end) { + i++; + if (more ()) + j = c->rangeRecord[i].start; + return; + } + j++; + } + inline uint16_t get_glyph (void) { return j; } + inline uint16_t get_coverage (void) { return coverage; } + + private: + const struct CoverageFormat2 *c; + unsigned int i, j, coverage; + }; + private: USHORT coverageFormat; /* Format identifier--format = 2 */ SortedArrayOf<RangeRecord> @@ -408,14 +463,79 @@ struct Coverage inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); + switch (u.format) { + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + default:return TRACE_RETURN (true); + } + } + + inline bool intersects (const hb_set_t *glyphs) const { + /* TODO speed this up */ + Coverage::Iter iter; + for (iter.init (*this); iter.more (); iter.next ()) { + if (glyphs->has (iter.get_glyph ())) + return true; + } + return false; + } + + inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - default:return true; + case 1: return u.format1.intersects_coverage (glyphs, index); + case 2: return u.format2.intersects_coverage (glyphs, index); + default:return false; } } + struct Iter { + Iter (void) : format (0) {}; + inline void init (const Coverage &c_) { + format = c_.u.format; + switch (format) { + case 1: return u.format1.init (c_.u.format1); + case 2: return u.format2.init (c_.u.format2); + default:return; + } + } + inline bool more (void) { + switch (format) { + case 1: return u.format1.more (); + case 2: return u.format2.more (); + default:return true; + } + } + inline void next (void) { + switch (format) { + case 1: u.format1.next (); break; + case 2: u.format2.next (); break; + default: break; + } + } + inline uint16_t get_glyph (void) { + switch (format) { + case 1: return u.format1.get_glyph (); + case 2: return u.format2.get_glyph (); + default:return true; + } + } + inline uint16_t get_coverage (void) { + switch (format) { + case 1: return u.format1.get_coverage (); + case 2: return u.format2.get_coverage (); + default:return true; + } + } + + private: + unsigned int format; + union { + CoverageFormat1::Iter format1; + CoverageFormat2::Iter format2; + } u; + }; + private: union { USHORT format; /* Format identifier */ @@ -445,8 +565,15 @@ struct ClassDefFormat1 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && classValue.sanitize (c); + return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c)); + } + + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { + unsigned int count = classValue.len; + for (unsigned int i = 0; i < count; i++) + if (classValue[i] == klass && glyphs->has (startGlyph + i)) + return true; + return false; } USHORT classFormat; /* Format identifier--format = 1 */ @@ -472,7 +599,15 @@ struct ClassDefFormat2 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return rangeRecord.sanitize (c); + return TRACE_RETURN (rangeRecord.sanitize (c)); + } + + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { + unsigned int count = rangeRecord.len; + for (unsigned int i = 0; i < count; i++) + if (rangeRecord[i].value == klass && rangeRecord[i].intersects (glyphs)) + return true; + return false; } USHORT classFormat; /* Format identifier--format = 2 */ @@ -498,11 +633,19 @@ struct ClassDef inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); + switch (u.format) { + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + default:return TRACE_RETURN (true); + } + } + + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - default:return true; + case 1: return u.format1.intersects_class (glyphs, klass); + case 2: return u.format2.intersects_class (glyphs, klass); + default:return false; } } @@ -574,8 +717,7 @@ struct Device inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && c->check_range (this, this->get_size ()); + return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ())); } private: diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh index ee9c508..f29fc14 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009 Red Hat, Inc. - * Copyright © 2010,2011 Google, Inc. + * Copyright © 2010,2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -71,8 +71,7 @@ struct AttachList inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && attachPoint.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); } private: @@ -102,7 +101,7 @@ struct CaretValueFormat1 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } private: @@ -128,7 +127,7 @@ struct CaretValueFormat2 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } private: @@ -151,8 +150,7 @@ struct CaretValueFormat3 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && deviceTable.sanitize (c, this); + return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this)); } private: @@ -180,12 +178,12 @@ struct CaretValue inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - case 3: return u.format3.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + case 3: return TRACE_RETURN (u.format3.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -221,7 +219,7 @@ struct LigGlyph inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return carets.sanitize (c, this); + return TRACE_RETURN (carets.sanitize (c, this)); } private: @@ -255,8 +253,7 @@ struct LigCaretList inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && ligGlyph.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); } private: @@ -278,7 +275,7 @@ struct MarkGlyphSetsFormat1 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this)); } private: @@ -302,10 +299,10 @@ struct MarkGlyphSets inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -327,7 +324,7 @@ struct GDEF { static const hb_tag_t Tag = HB_OT_TAG_GDEF; - enum { + enum GlyphClasses { UnclassifiedGlyph = 0, BaseGlyph = 1, LigatureGlyph = 2, @@ -365,12 +362,13 @@ struct GDEF inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return version.sanitize (c) && likely (version.major == 1) - && glyphClassDef.sanitize (c, this) - && attachList.sanitize (c, this) - && ligCaretList.sanitize (c, this) - && markAttachClassDef.sanitize (c, this) - && (version.to_int () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this)); + return TRACE_RETURN (version.sanitize (c) && + likely (version.major == 1) && + glyphClassDef.sanitize (c, this) && + attachList.sanitize (c, this) && + ligCaretList.sanitize (c, this) && + markAttachClassDef.sanitize (c, this) && + (version.to_int () < 0x00010002 || markGlyphSetsDef[0].sanitize (c, this))); } diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh index 412850b..71c13a2 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009,2010 Red Hat, Inc. - * Copyright © 2010 Google, Inc. + * Copyright © 2010,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -46,8 +46,7 @@ typedef Value ValueRecord[VAR]; struct ValueFormat : USHORT { - enum - { + enum Flags { xPlacement = 0x0001, /* Includes horizontal adjustment for placement */ yPlacement = 0x0002, /* Includes vertical adjustment for placement */ xAdvance = 0x0004, /* Includes horizontal adjustment for advance */ @@ -172,40 +171,39 @@ struct ValueFormat : USHORT inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) { TRACE_SANITIZE (); - return c->check_range (values, get_size ()) - && (!has_device () || sanitize_value_devices (c, base, values)); + return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); } inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) { TRACE_SANITIZE (); unsigned int len = get_len (); - if (!c->check_array (values, get_size (), count)) return false; + if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false); - if (!has_device ()) return true; + if (!has_device ()) return TRACE_RETURN (true); for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) - return false; + return TRACE_RETURN (false); values += len; } - return true; + return TRACE_RETURN (true); } /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) { TRACE_SANITIZE (); - if (!has_device ()) return true; + if (!has_device ()) return TRACE_RETURN (true); for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) - return false; + return TRACE_RETURN (false); values += stride; } - return true; + return TRACE_RETURN (true); } }; @@ -224,7 +222,7 @@ struct AnchorFormat1 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } private: @@ -256,7 +254,7 @@ struct AnchorFormat2 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } private: @@ -287,9 +285,7 @@ struct AnchorFormat3 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && xDeviceTable.sanitize (c, this) - && yDeviceTable.sanitize (c, this); + return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } private: @@ -324,12 +320,12 @@ struct Anchor inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - case 3: return u.format3.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + case 3: return TRACE_RETURN (u.format3.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -354,13 +350,13 @@ struct AnchorMatrix inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) { TRACE_SANITIZE (); - if (!c->check_struct (this)) return false; - if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false; + if (!c->check_struct (this)) return TRACE_RETURN (false); + if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false); unsigned int count = rows * cols; - if (!c->check_array (matrix, matrix[0].static_size, count)) return false; + if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false); for (unsigned int i = 0; i < count; i++) - if (!matrix[i].sanitize (c, this)) return false; - return true; + if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false); + return TRACE_RETURN (true); } USHORT rows; /* Number of rows */ @@ -379,8 +375,7 @@ struct MarkRecord inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); - return c->check_struct (this) - && markAnchor.sanitize (c, base); + return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base)); } private: @@ -408,21 +403,21 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde hb_position_t mark_x, mark_y, base_x, base_y; - mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->idx].codepoint, &mark_x, &mark_y); + mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y); glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y); - hb_glyph_position_t &o = c->buffer->pos[c->buffer->idx]; + hb_glyph_position_t &o = c->buffer->cur_pos(); o.x_offset = base_x - mark_x; o.y_offset = base_y - mark_y; o.attach_lookback() = c->buffer->idx - glyph_pos; c->buffer->idx++; - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return ArrayOf<MarkRecord>::sanitize (c, this); + return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this)); } }; @@ -437,22 +432,19 @@ struct SinglePosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); valueFormat.apply_value (c->font, c->direction, this, - values, c->buffer->pos[c->buffer->idx]); + values, c->buffer->cur_pos()); c->buffer->idx++; - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && coverage.sanitize (c, this) - && valueFormat.sanitize_value (c, this, values); + return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values)); } private: @@ -477,26 +469,22 @@ struct SinglePosFormat2 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); - if (likely (index >= valueCount)) - return false; + if (likely (index >= valueCount)) return TRACE_RETURN (false); valueFormat.apply_value (c->font, c->direction, this, &values[index * valueFormat.get_len ()], - c->buffer->pos[c->buffer->idx]); + c->buffer->cur_pos()); c->buffer->idx++; - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && coverage.sanitize (c, this) - && valueFormat.sanitize_values (c, this, values, valueCount); + return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount)); } private: @@ -522,19 +510,19 @@ struct SinglePos { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - case 2: return u.format2.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + case 2: return TRACE_RETURN (u.format2.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -581,18 +569,18 @@ struct PairSet if (c->buffer->info[pos].codepoint == record->secondGlyph) { valueFormats[0].apply_value (c->font, c->direction, this, - &record->values[0], c->buffer->pos[c->buffer->idx]); + &record->values[0], c->buffer->cur_pos()); valueFormats[1].apply_value (c->font, c->direction, this, &record->values[len1], c->buffer->pos[pos]); if (len2) pos++; c->buffer->idx = pos; - return true; + return TRACE_RETURN (true); } record = &StructAtOffset<PairValueRecord> (record, record_size); } - return false; + return TRACE_RETURN (false); } struct sanitize_closure_t { @@ -605,12 +593,12 @@ struct PairSet inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) { TRACE_SANITIZE (); if (!(c->check_struct (this) - && c->check_array (array, USHORT::static_size * closure->stride, len))) return false; + && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false); unsigned int count = len; PairValueRecord *record = CastP<PairValueRecord> (array); - return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) - && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride); + return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) + && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); } private: @@ -630,17 +618,14 @@ struct PairPosFormat1 { TRACE_APPLY (); hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (skippy_iter.has_no_chance ()) - return false; + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); - if (!skippy_iter.next ()) - return false; + if (!skippy_iter.next ()) return TRACE_RETURN (false); - return (this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx); + return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx)); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -655,9 +640,7 @@ struct PairPosFormat1 1 + len1 + len2 }; - return c->check_struct (this) - && coverage.sanitize (c, this) - && pairSet.sanitize (c, this, &closure); + return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); } private: @@ -687,28 +670,24 @@ struct PairPosFormat2 { TRACE_APPLY (); hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (skippy_iter.has_no_chance ()) - return false; + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); - if (!skippy_iter.next ()) - return false; + if (!skippy_iter.next ()) return TRACE_RETURN (false); unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); unsigned int record_len = len1 + len2; - unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->idx].codepoint); + unsigned int klass1 = (this+classDef1) (c->buffer->cur().codepoint); unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint); - if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) - return false; + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false); const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; valueFormat1.apply_value (c->font, c->direction, this, - v, c->buffer->pos[c->buffer->idx]); + v, c->buffer->cur_pos()); valueFormat2.apply_value (c->font, c->direction, this, v + len1, c->buffer->pos[skippy_iter.idx]); @@ -716,7 +695,7 @@ struct PairPosFormat2 if (len2) c->buffer->idx++; - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { @@ -724,16 +703,16 @@ struct PairPosFormat2 if (!(c->check_struct (this) && coverage.sanitize (c, this) && classDef1.sanitize (c, this) - && classDef2.sanitize (c, this))) return false; + && classDef2.sanitize (c, this))) return TRACE_RETURN (false); unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); unsigned int stride = len1 + len2; unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; - return c->check_array (values, record_size, count) && - valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && - valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride); + return TRACE_RETURN (c->check_array (values, record_size, count) && + valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); } private: @@ -775,19 +754,19 @@ struct PairPos { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - case 2: return u.format2.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + case 2: return TRACE_RETURN (u.format2.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -806,8 +785,7 @@ struct EntryExitRecord inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); - return entryAnchor.sanitize (c, base) - && exitAnchor.sanitize (c, base); + return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); } private: @@ -833,23 +811,18 @@ struct CursivePosFormat1 TRACE_APPLY (); /* We don't handle mark glyphs here. */ - if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) - return false; + if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) return TRACE_RETURN (false); hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (skippy_iter.has_no_chance ()) - return false; + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); - const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->idx].codepoint)]; - if (!this_record.exitAnchor) - return false; + const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->cur().codepoint)]; + if (!this_record.exitAnchor) return TRACE_RETURN (false); - if (!skippy_iter.next ()) - return false; + if (!skippy_iter.next ()) return TRACE_RETURN (false); const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)]; - if (!next_record.entryAnchor) - return false; + if (!next_record.entryAnchor) return TRACE_RETURN (false); unsigned int i = c->buffer->idx; unsigned int j = skippy_iter.idx; @@ -912,13 +885,12 @@ struct CursivePosFormat1 } c->buffer->idx = j; - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && entryExitRecord.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); } private: @@ -942,17 +914,17 @@ struct CursivePos { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -977,34 +949,27 @@ struct MarkBasePosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (mark_index == NOT_COVERED)) - return false; + unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint); + 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::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) - return false; + if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false); /* The following assertion is too strong, so we've disabled it. */ - if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) - {/*return false;*/} + if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/} unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint); - if (base_index == NOT_COVERED) - return false; + if (base_index == NOT_COVERED) return TRACE_RETURN (false); - return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx); + return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && markCoverage.sanitize (c, this) - && baseCoverage.sanitize (c, this) - && markArray.sanitize (c, this) - && baseArray.sanitize (c, this, (unsigned int) classCount); + return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) && + markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount)); } private: @@ -1035,17 +1000,17 @@ struct MarkBasePos { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -1075,56 +1040,51 @@ struct MarkLigPosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (mark_index == NOT_COVERED)) - return false; + unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint); + 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::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) - return false; + if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false); /* The following assertion is too strong, so we've disabled it. */ - if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) - {/*return false;*/} + if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)) {/*return TRACE_RETURN (false);*/} unsigned int j = skippy_iter.idx; unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint); - if (lig_index == NOT_COVERED) - return false; + if (lig_index == NOT_COVERED) return TRACE_RETURN (false); const LigatureArray& lig_array = this+ligatureArray; const LigatureAttach& lig_attach = lig_array[lig_index]; /* Find component to attach to */ unsigned int comp_count = lig_attach.rows; - if (unlikely (!comp_count)) - return false; + if (unlikely (!comp_count)) return TRACE_RETURN (false); + unsigned int comp_index; /* We must now check whether the ligature ID of the current mark glyph * is identical to the ligature ID of the found ligature. If yes, we * can directly use the component index. If not, we attach the mark * glyph to the last component of the ligature. */ - if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->idx].lig_id() && c->buffer->info[c->buffer->idx].lig_comp()) + if (get_lig_id (c->buffer->info[j]) && + get_lig_id (c->buffer->cur()) && + get_lig_comp (c->buffer->cur()) > 0) { - comp_index = c->buffer->info[c->buffer->idx].lig_comp() - 1; + comp_index = get_lig_comp (c->buffer->cur()) - 1; if (comp_index >= comp_count) comp_index = comp_count - 1; } else comp_index = comp_count - 1; - return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j); + return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && markCoverage.sanitize (c, this) - && ligatureCoverage.sanitize (c, this) - && markArray.sanitize (c, this) - && ligatureArray.sanitize (c, this, (unsigned int) classCount); + return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) && + markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount)); } private: @@ -1156,17 +1116,17 @@ struct MarkLigPos { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -1191,42 +1151,37 @@ struct MarkMarkPosFormat1 inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (mark1_index == NOT_COVERED)) - return false; + unsigned int mark1_index = (this+mark1Coverage) (c->buffer->cur().codepoint); + 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::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); - if (!skippy_iter.prev (&property)) - return false; + if (!skippy_iter.prev (&property)) return TRACE_RETURN (false); - if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) - return false; + if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return TRACE_RETURN (false); unsigned int j = skippy_iter.idx; /* Two marks match only if they belong to the same base, or same component * of the same ligature. That is, the component numbers must match, and * if those are non-zero, the ligid number should also match. */ - if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->idx].lig_comp()) || - (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->idx].lig_id())) - return false; + if ((get_lig_comp (c->buffer->cur())) || + (get_lig_comp (c->buffer->info[j]) > 0 && + get_lig_id (c->buffer->cur()))) + return TRACE_RETURN (false); unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint); - if (mark2_index == NOT_COVERED) - return false; + if (mark2_index == NOT_COVERED) return TRACE_RETURN (false); - return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j); + return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) - && mark1Coverage.sanitize (c, this) - && mark2Coverage.sanitize (c, this) - && mark1Array.sanitize (c, this) - && mark2Array.sanitize (c, this, (unsigned int) classCount); + return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) && + mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this) + && mark2Array.sanitize (c, this, (unsigned int) classCount)); } private: @@ -1259,17 +1214,17 @@ struct MarkMarkPos { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -1291,7 +1246,7 @@ struct ContextPos : Context inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return Context::apply (c, position_lookup); + return TRACE_RETURN (Context::apply (c, position_lookup)); } }; @@ -1303,7 +1258,7 @@ struct ChainContextPos : ChainContext inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return ChainContext::apply (c, position_lookup); + return TRACE_RETURN (ChainContext::apply (c, position_lookup)); } }; @@ -1336,7 +1291,7 @@ struct PosLookupSubTable { friend struct PosLookup; - enum { + enum Type { Single = 1, Pair = 2, Cursive = 3, @@ -1352,32 +1307,32 @@ struct PosLookupSubTable { TRACE_APPLY (); switch (lookup_type) { - case Single: return u.single.apply (c); - case Pair: return u.pair.apply (c); - case Cursive: return u.cursive.apply (c); - case MarkBase: return u.markBase.apply (c); - case MarkLig: return u.markLig.apply (c); - case MarkMark: return u.markMark.apply (c); - case Context: return u.c.apply (c); - case ChainContext: return u.chainContext.apply (c); - case Extension: return u.extension.apply (c); - default:return false; + case Single: return TRACE_RETURN (u.single.apply (c)); + case Pair: return TRACE_RETURN (u.pair.apply (c)); + case Cursive: return TRACE_RETURN (u.cursive.apply (c)); + case MarkBase: return TRACE_RETURN (u.markBase.apply (c)); + case MarkLig: return TRACE_RETURN (u.markLig.apply (c)); + case MarkMark: return TRACE_RETURN (u.markMark.apply (c)); + case Context: return TRACE_RETURN (u.c.apply (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.apply (c)); + case Extension: return TRACE_RETURN (u.extension.apply (c)); + default: return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { TRACE_SANITIZE (); switch (lookup_type) { - case Single: return u.single.sanitize (c); - case Pair: return u.pair.sanitize (c); - case Cursive: return u.cursive.sanitize (c); - case MarkBase: return u.markBase.sanitize (c); - case MarkLig: return u.markLig.sanitize (c); - case MarkMark: return u.markMark.sanitize (c); - case Context: return u.c.sanitize (c); - case ChainContext: return u.chainContext.sanitize (c); - case Extension: return u.extension.sanitize (c); - default:return true; + case Single: return TRACE_RETURN (u.single.sanitize (c)); + case Pair: return TRACE_RETURN (u.pair.sanitize (c)); + case Cursive: return TRACE_RETURN (u.cursive.sanitize (c)); + case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c)); + case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c)); + case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c)); + case Context: return TRACE_RETURN (u.c.sanitize (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c)); + case Extension: return TRACE_RETURN (u.extension.sanitize (c)); + default: return TRACE_RETURN (true); } } @@ -1404,25 +1359,11 @@ struct PosLookup : Lookup inline const PosLookupSubTable& get_subtable (unsigned int i) const { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; } - inline bool apply_once (hb_font_t *font, - hb_buffer_t *buffer, - hb_mask_t lookup_mask, - unsigned int context_length, - unsigned int nesting_level_left) const + inline bool apply_once (hb_apply_context_t *c) const { unsigned int lookup_type = get_type (); - hb_apply_context_t c[1] = {{0}}; - - c->font = font; - c->face = font->face; - c->buffer = buffer; - c->direction = buffer->props.direction; - c->lookup_mask = lookup_mask; - c->context_length = context_length; - c->nesting_level_left = nesting_level_left; - c->lookup_props = get_props (); - - if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property)) + + if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property)) return false; for (unsigned int i = 0; i < get_subtable_count (); i++) @@ -1432,23 +1373,22 @@ struct PosLookup : Lookup return false; } - inline bool apply_string (hb_font_t *font, - hb_buffer_t *buffer, - hb_mask_t mask) const + inline bool apply_string (hb_apply_context_t *c) const { bool ret = false; - if (unlikely (!buffer->len)) + if (unlikely (!c->buffer->len)) return false; - buffer->idx = 0; - while (buffer->idx < buffer->len) + c->set_lookup (*this); + + c->buffer->idx = 0; + while (c->buffer->idx < c->buffer->len) { - if ((buffer->info[buffer->idx].mask & mask) && - apply_once (font, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) + if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c)) ret = true; else - buffer->idx++; + c->buffer->idx++; } return ret; @@ -1456,9 +1396,9 @@ struct PosLookup : Lookup inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!Lookup::sanitize (c))) return false; + if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable); - return list.sanitize (c, this, get_type ()); + return TRACE_RETURN (list.sanitize (c, this, get_type ())); } }; @@ -1475,20 +1415,17 @@ struct GPOS : GSUBGPOS inline const PosLookup& get_lookup (unsigned int i) const { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } - inline bool position_lookup (hb_font_t *font, - hb_buffer_t *buffer, - unsigned int lookup_index, - hb_mask_t mask) const - { return get_lookup (lookup_index).apply_string (font, buffer, mask); } + inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) const + { return get_lookup (lookup_index).apply_string (c); } static inline void position_start (hb_buffer_t *buffer); static inline void position_finish (hb_buffer_t *buffer); inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!GSUBGPOS::sanitize (c))) return false; + if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); - return list.sanitize (c, this); + return TRACE_RETURN (list.sanitize (c, this)); } public: DEFINE_SIZE_STATIC (10); @@ -1564,8 +1501,8 @@ GPOS::position_finish (hb_buffer_t *buffer) for (unsigned int i = 0; i < len; i++) fix_mark_attachment (pos, i, direction); - HB_BUFFER_DEALLOCATE_VAR (buffer, lig_comp); - HB_BUFFER_DEALLOCATE_VAR (buffer, lig_id); + HB_BUFFER_DEALLOCATE_VAR (buffer, syllable); + HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props); HB_BUFFER_DEALLOCATE_VAR (buffer, props_cache); } @@ -1575,16 +1512,16 @@ GPOS::position_finish (hb_buffer_t *buffer) inline bool ExtensionPos::apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return get_subtable ().apply (c, get_type ()); + return TRACE_RETURN (get_subtable ().apply (c, get_type ())); } inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!Extension::sanitize (c))) return false; + if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false); unsigned int offset = get_offset (); - if (unlikely (!offset)) return true; - return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ()); + if (unlikely (!offset)) return TRACE_RETURN (true); + return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ())); } static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) @@ -1595,10 +1532,10 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i if (unlikely (c->nesting_level_left == 0)) return false; - if (unlikely (c->context_length < 1)) - return false; - - return l.apply_once (c->font, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1); + hb_apply_context_t new_c (*c); + new_c.nesting_level_left--; + new_c.set_lookup (l); + return l.apply_once (&new_c); } diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh index f7ec3cc..f6a7575 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009,2010 Red Hat, Inc. - * Copyright © 2010 Google, Inc. + * Copyright © 2010,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -39,26 +39,40 @@ struct SingleSubstFormat1 private: + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + hb_codepoint_t glyph_id = iter.get_glyph (); + if (c->glyphs->has (glyph_id)) + c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF); + } + } + + inline bool would_apply (hb_codepoint_t glyph_id) const + { + return (this+coverage) (glyph_id) != NOT_COVERED; + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; + hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage) (glyph_id); - if (likely (index == NOT_COVERED)) - return false; + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); /* According to the Adobe Annotated OpenType Suite, result is always * limited to 16bit. */ glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF; c->replace_glyph (glyph_id); - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && deltaGlyphID.sanitize (c); + return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); } private: @@ -78,27 +92,39 @@ struct SingleSubstFormat2 private: + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + if (c->glyphs->has (iter.get_glyph ())) + c->glyphs->add (substitute[iter.get_coverage ()]); + } + } + + inline bool would_apply (hb_codepoint_t glyph_id) const + { + return (this+coverage) (glyph_id) != NOT_COVERED; + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; + hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage) (glyph_id); - if (likely (index == NOT_COVERED)) - return false; + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); - if (unlikely (index >= substitute.len)) - return false; + if (unlikely (index >= substitute.len)) return TRACE_RETURN (false); glyph_id = substitute[index]; c->replace_glyph (glyph_id); - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && substitute.sanitize (c); + return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c)); } private: @@ -119,23 +145,42 @@ struct SingleSubst private: + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + switch (u.format) { + case 1: u.format1.closure (c); break; + case 2: u.format2.closure (c); break; + default: break; + } + } + + inline bool would_apply (hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.would_apply (glyph_id); + case 2: return u.format2.would_apply (glyph_id); + default:return false; + } + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - case 2: return u.format2.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + case 2: return TRACE_RETURN (u.format2.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -153,23 +198,30 @@ struct Sequence friend struct MultipleSubstFormat1; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + unsigned int count = substitute.len; + for (unsigned int i = 0; i < count; i++) + c->glyphs->add (substitute[i]); + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - if (unlikely (!substitute.len)) - return false; + if (unlikely (!substitute.len)) return TRACE_RETURN (false); - if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE) - c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH); - c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array); + unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0; + c->replace_glyphs_be16 (1, substitute.len, (const uint16_t *) substitute.array, klass); - return true; + return TRACE_RETURN (true); } public: inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return substitute.sanitize (c); + return TRACE_RETURN (substitute.sanitize (c)); } private: @@ -185,21 +237,34 @@ struct MultipleSubstFormat1 private: + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + if (c->glyphs->has (iter.get_glyph ())) + (this+sequence[iter.get_coverage ()]).closure (c); + } + } + + inline bool would_apply (hb_codepoint_t glyph_id) const + { + return (this+coverage) (glyph_id) != NOT_COVERED; + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); - return (this+sequence[index]).apply (c); + return TRACE_RETURN ((this+sequence[index]).apply (c)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && sequence.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this)); } private: @@ -220,21 +285,38 @@ struct MultipleSubst private: + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + switch (u.format) { + case 1: u.format1.closure (c); break; + default: break; + } + } + + inline bool would_apply (hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.would_apply (glyph_id); + default:return false; + } + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -255,40 +337,56 @@ struct AlternateSubstFormat1 private: + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + if (c->glyphs->has (iter.get_glyph ())) { + const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; + unsigned int count = alt_set.len; + for (unsigned int i = 0; i < count; i++) + c->glyphs->add (alt_set[i]); + } + } + } + + inline bool would_apply (hb_codepoint_t glyph_id) const + { + return (this+coverage) (glyph_id) != NOT_COVERED; + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; - hb_mask_t glyph_mask = c->buffer->info[c->buffer->idx].mask; - hb_mask_t lookup_mask = c->lookup_mask; + hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage) (glyph_id); - if (likely (index == NOT_COVERED)) - return false; + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const AlternateSet &alt_set = this+alternateSet[index]; - if (unlikely (!alt_set.len)) - return false; + if (unlikely (!alt_set.len)) return TRACE_RETURN (false); + + hb_mask_t glyph_mask = c->buffer->cur().mask; + hb_mask_t lookup_mask = c->lookup_mask; /* Note: This breaks badly if two features enabled this lookup together. */ unsigned int shift = _hb_ctz (lookup_mask); unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); - if (unlikely (alt_index > alt_set.len || alt_index == 0)) - return false; + if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false); glyph_id = alt_set[alt_index - 1]; c->replace_glyph (glyph_id); - return true; + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && alternateSet.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); } private: @@ -309,21 +407,38 @@ struct AlternateSubst private: + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + switch (u.format) { + case 1: u.format1.closure (c); break; + default: break; + } + } + + inline bool would_apply (hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.would_apply (glyph_id); + default:return false; + } + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -340,16 +455,30 @@ struct Ligature friend struct LigatureSet; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + unsigned int count = component.len; + for (unsigned int i = 1; i < count; i++) + if (!c->glyphs->has (component[i])) + return; + c->glyphs->add (ligGlyph); + } + + inline bool would_apply (hb_codepoint_t second) const + { + return component.len == 2 && component[1] == second; + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); unsigned int count = component.len; - if (unlikely (count < 2)) - return false; + if (unlikely (count < 2)) return TRACE_RETURN (false); hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); - if (skippy_iter.has_no_chance ()) - return false; + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); bool first_was_mark = (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK); bool found_non_mark = false; @@ -358,26 +487,22 @@ struct Ligature { unsigned int property; - if (!skippy_iter.next (&property)) - return false; + if (!skippy_iter.next (&property)) return TRACE_RETURN (false); found_non_mark |= !(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK); - if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) - return false; + if (likely (c->buffer->info[skippy_iter.idx].codepoint != component[i])) return TRACE_RETURN (false); } - if (first_was_mark && found_non_mark) - c->guess_glyph_class (HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE); + unsigned int klass = first_was_mark && found_non_mark ? HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE : 0; /* Allocate new ligature id */ unsigned int lig_id = allocate_lig_id (c->buffer); - c->buffer->info[c->buffer->idx].lig_comp() = 0; - c->buffer->info[c->buffer->idx].lig_id() = lig_id; + set_lig_props (c->buffer->cur(), lig_id, 0); if (skippy_iter.idx < c->buffer->idx + count) /* No input glyphs skipped */ { - c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph); + c->replace_glyphs_be16 (count, 1, (const uint16_t *) &ligGlyph, klass); } else { @@ -394,9 +519,8 @@ struct Ligature { while (c->should_mark_skip_current_glyph ()) { - c->buffer->info[c->buffer->idx].lig_comp() = i; - c->buffer->info[c->buffer->idx].lig_id() = lig_id; - c->replace_glyph (c->buffer->info[c->buffer->idx].codepoint); + set_lig_props (c->buffer->cur(), lig_id, i); + c->replace_glyph (c->buffer->cur().codepoint); } /* Skip the base glyph */ @@ -404,14 +528,13 @@ struct Ligature } } - return true; + return TRACE_RETURN (true); } public: inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return ligGlyph.sanitize (c) - && component.sanitize (c); + return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c)); } private: @@ -429,6 +552,27 @@ struct LigatureSet friend struct LigatureSubstFormat1; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + (this+ligature[i]).closure (c); + } + + inline bool would_apply (hb_codepoint_t second) const + { + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + { + const Ligature &lig = this+ligature[i]; + if (lig.would_apply (second)) + return true; + } + return false; + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); @@ -436,17 +580,16 @@ struct LigatureSet for (unsigned int i = 0; i < num_ligs; i++) { const Ligature &lig = this+ligature[i]; - if (lig.apply (c)) - return true; + if (lig.apply (c)) return TRACE_RETURN (true); } - return false; + return TRACE_RETURN (false); } public: inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return ligature.sanitize (c, this); + return TRACE_RETURN (ligature.sanitize (c, this)); } private: @@ -462,23 +605,39 @@ struct LigatureSubstFormat1 friend struct LigatureSubst; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + if (c->glyphs->has (iter.get_glyph ())) + (this+ligatureSet[iter.get_coverage ()]).closure (c); + } + } + + inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const + { + unsigned int index; + return (index = (this+coverage) (first)) != NOT_COVERED && + (this+ligatureSet[index]).would_apply (second); + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - hb_codepoint_t glyph_id = c->buffer->info[c->buffer->idx].codepoint; + hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage) (glyph_id); - if (likely (index == NOT_COVERED)) - return false; + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const LigatureSet &lig_set = this+ligatureSet[index]; - return lig_set.apply (c); + return TRACE_RETURN (lig_set.apply (c)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && ligatureSet.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); } private: @@ -498,21 +657,39 @@ struct LigatureSubst friend struct SubstLookupSubTable; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + switch (u.format) { + case 1: u.format1.closure (c); break; + default: break; + } + } + + inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const + { + switch (u.format) { + case 1: return u.format1.would_apply (first, second); + default:return false; + } + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -525,16 +702,24 @@ struct LigatureSubst static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index); +static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index); struct ContextSubst : Context { friend struct SubstLookupSubTable; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + return Context::closure (c, closure_lookup); + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return Context::apply (c, substitute_lookup); + return TRACE_RETURN (Context::apply (c, substitute_lookup)); } }; @@ -543,10 +728,17 @@ struct ChainContextSubst : ChainContext friend struct SubstLookupSubTable; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + return ChainContext::closure (c, closure_lookup); + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return ChainContext::apply (c, substitute_lookup); + return TRACE_RETURN (ChainContext::apply (c, substitute_lookup)); } }; @@ -564,6 +756,10 @@ struct ExtensionSubst : Extension return StructAtOffset<SubstLookupSubTable> (this, offset); } + inline void closure (hb_closure_context_t *c) const; + inline bool would_apply (hb_codepoint_t glyph_id) const; + inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const; + inline bool apply (hb_apply_context_t *c) const; inline bool sanitize (hb_sanitize_context_t *c); @@ -577,15 +773,40 @@ struct ReverseChainSingleSubstFormat1 friend struct ReverseChainSingleSubst; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + unsigned int count; + + count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+backtrack[i]).intersects (c->glyphs)) + return; + + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + if (!(this+lookahead[i]).intersects (c->glyphs)) + return; + + const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + if (c->glyphs->has (iter.get_glyph ())) + c->glyphs->add (substitute[iter.get_coverage ()]); + } + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); - if (unlikely (c->context_length != NO_CONTEXT)) - return false; /* No chaining to this type */ + if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL)) + return TRACE_RETURN (false); /* No chaining to this type */ - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); @@ -598,24 +819,23 @@ struct ReverseChainSingleSubstFormat1 match_coverage, this, 1)) { - c->buffer->info[c->buffer->idx].codepoint = substitute[index]; + c->buffer->cur().codepoint = substitute[index]; c->buffer->idx--; /* Reverse! */ - return true; + return TRACE_RETURN (true); } - return false; + return TRACE_RETURN (false); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!(coverage.sanitize (c, this) - && backtrack.sanitize (c, this))) - return false; + if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) + return TRACE_RETURN (false); OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); if (!lookahead.sanitize (c, this)) - return false; + return TRACE_RETURN (false); ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); - return substitute.sanitize (c); + return TRACE_RETURN (substitute.sanitize (c)); } private: @@ -643,21 +863,31 @@ struct ReverseChainSingleSubst friend struct SubstLookupSubTable; private: + + inline void closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (); + switch (u.format) { + case 1: u.format1.closure (c); break; + default: break; + } + } + inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -678,7 +908,7 @@ struct SubstLookupSubTable { friend struct SubstLookup; - enum { + enum Type { Single = 1, Multiple = 2, Alternate = 3, @@ -689,34 +919,73 @@ struct SubstLookupSubTable ReverseChainSingle = 8 }; + inline void closure (hb_closure_context_t *c, + unsigned int lookup_type) const + { + TRACE_CLOSURE (); + switch (lookup_type) { + case Single: u.single.closure (c); break; + case Multiple: u.multiple.closure (c); break; + case Alternate: u.alternate.closure (c); break; + case Ligature: u.ligature.closure (c); break; + case Context: u.c.closure (c); break; + case ChainContext: u.chainContext.closure (c); break; + case Extension: u.extension.closure (c); break; + case ReverseChainSingle: u.reverseChainContextSingle.closure (c); break; + default: break; + } + } + + inline bool would_apply (hb_codepoint_t glyph_id, + unsigned int lookup_type) const + { + switch (lookup_type) { + case Single: return u.single.would_apply (glyph_id); + case Multiple: return u.multiple.would_apply (glyph_id); + case Alternate: return u.alternate.would_apply (glyph_id); + case Extension: return u.extension.would_apply (glyph_id); + default: return false; + } + } + inline bool would_apply (hb_codepoint_t first, + hb_codepoint_t second, + unsigned int lookup_type) const + { + switch (lookup_type) { + case Ligature: return u.ligature.would_apply (first, second); + case Extension: return u.extension.would_apply (first, second); + default: return false; + } + } + inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const { TRACE_APPLY (); switch (lookup_type) { - case Single: return u.single.apply (c); - case Multiple: return u.multiple.apply (c); - case Alternate: return u.alternate.apply (c); - case Ligature: return u.ligature.apply (c); - case Context: return u.c.apply (c); - case ChainContext: return u.chainContext.apply (c); - case Extension: return u.extension.apply (c); - case ReverseChainSingle: return u.reverseChainContextSingle.apply (c); - default:return false; + case Single: return TRACE_RETURN (u.single.apply (c)); + case Multiple: return TRACE_RETURN (u.multiple.apply (c)); + case Alternate: return TRACE_RETURN (u.alternate.apply (c)); + case Ligature: return TRACE_RETURN (u.ligature.apply (c)); + case Context: return TRACE_RETURN (u.c.apply (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.apply (c)); + case Extension: return TRACE_RETURN (u.extension.apply (c)); + case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.apply (c)); + default: return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { TRACE_SANITIZE (); switch (lookup_type) { - case Single: return u.single.sanitize (c); - case Multiple: return u.multiple.sanitize (c); - case Alternate: return u.alternate.sanitize (c); - case Ligature: return u.ligature.sanitize (c); - case Context: return u.c.sanitize (c); - case ChainContext: return u.chainContext.sanitize (c); - case Extension: return u.extension.sanitize (c); - case ReverseChainSingle: return u.reverseChainContextSingle.sanitize (c); - default:return true; + case Single: return TRACE_RETURN (u.single.sanitize (c)); + case Multiple: return TRACE_RETURN (u.multiple.sanitize (c)); + case Alternate: return TRACE_RETURN (u.alternate.sanitize (c)); + case Ligature: return TRACE_RETURN (u.ligature.sanitize (c)); + case Context: return TRACE_RETURN (u.c.sanitize (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c)); + case Extension: return TRACE_RETURN (u.extension.sanitize (c)); + case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c)); + default: return TRACE_RETURN (true); } } @@ -753,25 +1022,38 @@ struct SubstLookup : Lookup return lookup_type_is_reverse (type); } + inline void closure (hb_closure_context_t *c) const + { + unsigned int lookup_type = get_type (); + unsigned int count = get_subtable_count (); + for (unsigned int i = 0; i < count; i++) + get_subtable (i).closure (c, lookup_type); + } - inline bool apply_once (hb_face_t *face, - hb_buffer_t *buffer, - hb_mask_t lookup_mask, - unsigned int context_length, - unsigned int nesting_level_left) const + inline bool would_apply (hb_codepoint_t glyph_id) const + { + unsigned int lookup_type = get_type (); + unsigned int count = get_subtable_count (); + for (unsigned int i = 0; i < count; i++) + if (get_subtable (i).would_apply (glyph_id, lookup_type)) + return true; + return false; + } + inline bool would_apply (hb_codepoint_t first, hb_codepoint_t second) const { unsigned int lookup_type = get_type (); - hb_apply_context_t c[1] = {{0}}; + unsigned int count = get_subtable_count (); + for (unsigned int i = 0; i < count; i++) + if (get_subtable (i).would_apply (first, second, lookup_type)) + return true; + return false; + } - c->face = face; - c->buffer = buffer; - c->direction = buffer->props.direction; - c->lookup_mask = lookup_mask; - c->context_length = context_length; - c->nesting_level_left = nesting_level_left; - c->lookup_props = get_props (); + inline bool apply_once (hb_apply_context_t *c) const + { + unsigned int lookup_type = get_type (); - if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property)) + if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->cur(), c->lookup_props, &c->property)) return false; if (unlikely (lookup_type == SubstLookupSubTable::Extension)) @@ -781,8 +1063,8 @@ struct SubstLookup : Lookup * * This is rather slow to do this here for every glyph, * but it's easiest, and who uses extension lookups anyway?!*/ - unsigned int count = get_subtable_count (); unsigned int type = get_subtable(0).u.extension.get_type (); + unsigned int count = get_subtable_count (); for (unsigned int i = 1; i < count; i++) if (get_subtable(i).u.extension.get_type () != type) return false; @@ -796,46 +1078,44 @@ struct SubstLookup : Lookup return false; } - inline bool apply_string (hb_face_t *face, - hb_buffer_t *buffer, - hb_mask_t mask) const + inline bool apply_string (hb_apply_context_t *c) const { bool ret = false; - if (unlikely (!buffer->len)) + if (unlikely (!c->buffer->len)) return false; + c->set_lookup (*this); + if (likely (!is_reverse ())) { /* in/out forward substitution */ - buffer->clear_output (); - buffer->idx = 0; - while (buffer->idx < buffer->len) + c->buffer->clear_output (); + c->buffer->idx = 0; + while (c->buffer->idx < c->buffer->len) { - if ((buffer->info[buffer->idx].mask & mask) && - apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) + if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c)) ret = true; else - buffer->next_glyph (); + c->buffer->next_glyph (); } if (ret) - buffer->swap_buffers (); + c->buffer->swap_buffers (); } else { /* in-place backward substitution */ - buffer->idx = buffer->len - 1; + c->buffer->idx = c->buffer->len - 1; do { - if ((buffer->info[buffer->idx].mask & mask) && - apply_once (face, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL)) + if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c)) ret = true; else - buffer->idx--; + c->buffer->idx--; } - while ((int) buffer->idx >= 0); + while ((int) c->buffer->idx >= 0); } return ret; @@ -843,9 +1123,9 @@ struct SubstLookup : Lookup inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!Lookup::sanitize (c))) return false; + if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable); - return list.sanitize (c, this, get_type ()); + return TRACE_RETURN (list.sanitize (c, this, get_type ())); } }; @@ -862,20 +1142,21 @@ struct GSUB : GSUBGPOS inline const SubstLookup& get_lookup (unsigned int i) const { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } - inline bool substitute_lookup (hb_face_t *face, - hb_buffer_t *buffer, - unsigned int lookup_index, - hb_mask_t mask) const - { return get_lookup (lookup_index).apply_string (face, buffer, mask); } + inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) const + { return get_lookup (lookup_index).apply_string (c); } static inline void substitute_start (hb_buffer_t *buffer); static inline void substitute_finish (hb_buffer_t *buffer); + inline void closure_lookup (hb_closure_context_t *c, + unsigned int lookup_index) const + { return get_lookup (lookup_index).closure (c); } + inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!GSUBGPOS::sanitize (c))) return false; + if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); - return list.sanitize (c, this); + return TRACE_RETURN (list.sanitize (c, this)); } public: DEFINE_SIZE_STATIC (10); @@ -886,35 +1167,50 @@ void GSUB::substitute_start (hb_buffer_t *buffer) { HB_BUFFER_ALLOCATE_VAR (buffer, props_cache); - HB_BUFFER_ALLOCATE_VAR (buffer, lig_id); - HB_BUFFER_ALLOCATE_VAR (buffer, lig_comp); + HB_BUFFER_ALLOCATE_VAR (buffer, lig_props); + HB_BUFFER_ALLOCATE_VAR (buffer, syllable); unsigned int count = buffer->len; for (unsigned int i = 0; i < count; i++) - buffer->info[i].props_cache() = buffer->info[i].lig_id() = buffer->info[i].lig_comp() = 0; + buffer->info[i].props_cache() = buffer->info[i].lig_props() = buffer->info[i].syllable() = 0; } void -GSUB::substitute_finish (hb_buffer_t *buffer) +GSUB::substitute_finish (hb_buffer_t *buffer HB_UNUSED) { } /* Out-of-class implementation for methods recursing */ +inline void ExtensionSubst::closure (hb_closure_context_t *c) const +{ + get_subtable ().closure (c, get_type ()); +} + +inline bool ExtensionSubst::would_apply (hb_codepoint_t glyph_id) const +{ + return get_subtable ().would_apply (glyph_id, get_type ()); +} + +inline bool ExtensionSubst::would_apply (hb_codepoint_t first, hb_codepoint_t second) const +{ + return get_subtable ().would_apply (first, second, get_type ()); +} + inline bool ExtensionSubst::apply (hb_apply_context_t *c) const { TRACE_APPLY (); - return get_subtable ().apply (c, get_type ()); + return TRACE_RETURN (get_subtable ().apply (c, get_type ())); } inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (unlikely (!Extension::sanitize (c))) return false; + if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false); unsigned int offset = get_offset (); - if (unlikely (!offset)) return true; - return StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()); + if (unlikely (!offset)) return TRACE_RETURN (true); + return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ())); } inline bool ExtensionSubst::is_reverse (void) const @@ -925,18 +1221,31 @@ inline bool ExtensionSubst::is_reverse (void) const return SubstLookup::lookup_type_is_reverse (type); } -static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) +static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index) { const GSUB &gsub = *(c->face->ot_layout->gsub); const SubstLookup &l = gsub.get_lookup (lookup_index); if (unlikely (c->nesting_level_left == 0)) - return false; + return; + + c->nesting_level_left--; + l.closure (c); + c->nesting_level_left++; +} - if (unlikely (c->context_length < 1)) +static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) +{ + const GSUB &gsub = *(c->face->ot_layout->gsub); + const SubstLookup &l = gsub.get_lookup (lookup_index); + + if (unlikely (c->nesting_level_left == 0)) return false; - return l.apply_once (c->face, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1); + hb_apply_context_t new_c (*c); + new_c.nesting_level_left--; + new_c.set_lookup (l); + return l.apply_once (&new_c); } diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh index 13386c2..a2e4b2f 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009,2010 Red Hat, Inc. - * Copyright © 2010 Google, Inc. + * Copyright © 2010,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -33,50 +33,112 @@ #include "hb-ot-layout-gdef-table.hh" -/* buffer var allocations */ -#define lig_id() var2.u8[2] /* unique ligature id */ -#define lig_comp() var2.u8[3] /* component number in the ligature (0 = base) */ + +/* unique ligature id */ +/* component number in the ligature (0 = base) */ +static inline void +set_lig_props (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp) +{ + info.lig_props() = (lig_id << 4) | (lig_comp & 0x0F); +} +static inline unsigned int +get_lig_id (hb_glyph_info_t &info) +{ + return info.lig_props() >> 4; +} +static inline unsigned int +get_lig_comp (hb_glyph_info_t &info) +{ + return info.lig_props() & 0x0F; +} static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) { - uint8_t lig_id = buffer->next_serial (); - if (unlikely (!lig_id)) lig_id = buffer->next_serial (); /* in case of overflow */ + uint8_t lig_id = buffer->next_serial () & 0x0F; + if (unlikely (!lig_id)) + lig_id = allocate_lig_id (buffer); /* in case of overflow */ return lig_id; } +#ifndef HB_DEBUG_CLOSURE +#define HB_DEBUG_CLOSURE (HB_DEBUG+0) +#endif + +#define TRACE_CLOSURE() \ + hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, ""); + + +/* TODO Add TRACE_RETURN annotation for would_apply */ + + +struct hb_closure_context_t +{ + hb_face_t *face; + hb_set_t *glyphs; + unsigned int nesting_level_left; + unsigned int debug_depth; + + + hb_closure_context_t (hb_face_t *face_, + hb_set_t *glyphs_, + unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : + face (face_), glyphs (glyphs_), + nesting_level_left (nesting_level_left_), + debug_depth (0) {} +}; + + + #ifndef HB_DEBUG_APPLY #define HB_DEBUG_APPLY (HB_DEBUG+0) #endif #define TRACE_APPLY() \ - hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, NULL, HB_FUNC); + hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->cur().codepoint); struct hb_apply_context_t { - unsigned int debug_depth; hb_font_t *font; hb_face_t *face; hb_buffer_t *buffer; hb_direction_t direction; hb_mask_t lookup_mask; - unsigned int context_length; unsigned int nesting_level_left; unsigned int lookup_props; unsigned int property; /* propety of first glyph */ + unsigned int debug_depth; + + + hb_apply_context_t (hb_font_t *font_, + hb_face_t *face_, + hb_buffer_t *buffer_, + hb_mask_t lookup_mask_) : + font (font_), face (face_), buffer (buffer_), + direction (buffer_->props.direction), + lookup_mask (lookup_mask_), + nesting_level_left (MAX_NESTING_LEVEL), + lookup_props (0), property (0), debug_depth (0) {} + + void set_lookup (const Lookup &l) { + lookup_props = l.get_props (); + } struct mark_skipping_forward_iterator_t { inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_, unsigned int start_index_, - unsigned int num_items_) + unsigned int num_items_, + bool context_match = false) { c = c_; idx = start_index_; num_items = num_items_; - end = MIN (c->buffer->len, c->buffer->idx + c->context_length); + mask = context_match ? -1 : c->lookup_mask; + syllable = context_match ? 0 : c->buffer->cur().syllable (); + end = c->buffer->len; } inline bool has_no_chance (void) const { @@ -93,7 +155,7 @@ struct hb_apply_context_t idx++; } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out)); num_items--; - return true; + return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ()); } inline bool next (unsigned int *property_out = NULL) { @@ -104,6 +166,8 @@ struct hb_apply_context_t private: hb_apply_context_t *c; unsigned int num_items; + hb_mask_t mask; + uint8_t syllable; unsigned int end; }; @@ -111,11 +175,15 @@ struct hb_apply_context_t { inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_, unsigned int start_index_, - unsigned int num_items_) + unsigned int num_items_, + hb_mask_t mask_ = 0, + bool match_syllable_ = true) { c = c_; idx = start_index_; num_items = num_items_; + mask = mask_ ? mask_ : c->lookup_mask; + syllable = match_syllable_ ? c->buffer->cur().syllable () : 0; } inline bool has_no_chance (void) const { @@ -132,7 +200,7 @@ struct hb_apply_context_t idx--; } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out)); num_items--; - return true; + return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ()); } inline bool prev (unsigned int *property_out = NULL) { @@ -143,69 +211,92 @@ struct hb_apply_context_t private: hb_apply_context_t *c; unsigned int num_items; + hb_mask_t mask; + uint8_t syllable; }; inline bool should_mark_skip_current_glyph (void) const { - return _hb_ot_layout_skip_mark (face, &buffer->info[buffer->idx], lookup_props, NULL); + return _hb_ot_layout_skip_mark (face, &buffer->cur(), lookup_props, NULL); } - inline void replace_glyph (hb_codepoint_t glyph_index) const + inline void replace_glyph (hb_codepoint_t glyph_index, + unsigned int klass = 0) const { - clear_property (); + buffer->cur().props_cache() = klass; /*XXX if has gdef? */ buffer->replace_glyph (glyph_index); } inline void replace_glyphs_be16 (unsigned int num_in, unsigned int num_out, - const uint16_t *glyph_data_be) const + const uint16_t *glyph_data_be, + unsigned int klass = 0) const { - clear_property (); + buffer->cur().props_cache() = klass; /* XXX if has gdef? */ buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be); } - - inline void guess_glyph_class (unsigned int klass) - { - /* XXX if ! has gdef */ - buffer->info[buffer->idx].props_cache() = klass; - } - - private: - inline void clear_property (void) const - { - /* XXX if has gdef */ - buffer->info[buffer->idx].props_cache() = 0; - } }; +typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); +typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index); typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index); -struct ContextFuncs +struct ContextClosureFuncs +{ + intersects_func_t intersects; + closure_lookup_func_t closure; +}; +struct ContextApplyFuncs { match_func_t match; apply_lookup_func_t apply; }; +static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) +{ + return glyphs->has (value); +} +static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + return class_def.intersects_class (glyphs, value); +} +static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) +{ + const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; + return (data+coverage).intersects (glyphs); +} + +static inline bool intersects_array (hb_closure_context_t *c, + unsigned int count, + const USHORT values[], + intersects_func_t intersects_func, + const void *intersects_data) +{ + for (unsigned int i = 0; i < count; i++) + if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) + return false; + return true; +} + static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) { return glyph_id == value; } - static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) { const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); return class_def.get_class (glyph_id) == value; } - static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) { const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; - return (data+coverage) (glyph_id) != NOT_COVERED; + return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; } @@ -214,7 +305,7 @@ static inline bool match_input (hb_apply_context_t *c, const USHORT input[], /* Array of input values--start with second glyph */ match_func_t match_func, const void *match_data, - unsigned int *context_length_out) + unsigned int *end_offset = NULL) { hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); if (skippy_iter.has_no_chance ()) @@ -229,7 +320,8 @@ static inline bool match_input (hb_apply_context_t *c, return false; } - *context_length_out = skippy_iter.idx - c->buffer->idx + 1; + if (end_offset) + *end_offset = skippy_iter.idx - c->buffer->idx + 1; return true; } @@ -240,7 +332,7 @@ static inline bool match_backtrack (hb_apply_context_t *c, match_func_t match_func, const void *match_data) { - hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count); + hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); if (skippy_iter.has_no_chance ()) return false; @@ -263,7 +355,7 @@ static inline bool match_lookahead (hb_apply_context_t *c, const void *match_data, unsigned int offset) { - hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count); + hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); if (skippy_iter.has_no_chance ()) return false; @@ -285,7 +377,7 @@ struct LookupRecord { inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } USHORT sequenceIndex; /* Index into current glyph @@ -297,6 +389,14 @@ struct LookupRecord }; +static inline void closure_lookup (hb_closure_context_t *c, + unsigned int lookupCount, + const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ + closure_lookup_func_t closure_func) +{ + for (unsigned int i = 0; i < lookupCount; i++) + closure_func (c, lookupRecord->lookupListIndex); +} static inline bool apply_lookup (hb_apply_context_t *c, unsigned int count, /* Including the first glyph */ @@ -304,7 +404,7 @@ static inline bool apply_lookup (hb_apply_context_t *c, const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ apply_lookup_func_t apply_func) { - unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length); + unsigned int end = c->buffer->len; if (unlikely (count == 0 || c->buffer->idx + count > end)) return false; @@ -360,25 +460,45 @@ static inline bool apply_lookup (hb_apply_context_t *c, /* Contextual lookups */ -struct ContextLookupContext +struct ContextClosureLookupContext { - ContextFuncs funcs; + ContextClosureFuncs funcs; + const void *intersects_data; +}; + +struct ContextApplyLookupContext +{ + ContextApplyFuncs funcs; const void *match_data; }; -static inline bool context_lookup (hb_apply_context_t *c, - unsigned int inputCount, /* Including the first glyph (not matched) */ - const USHORT input[], /* Array of input values--start with second glyph */ - unsigned int lookupCount, - const LookupRecord lookupRecord[], - ContextLookupContext &lookup_context) +static inline void context_closure_lookup (hb_closure_context_t *c, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const USHORT input[], /* Array of input values--start with second glyph */ + unsigned int lookupCount, + const LookupRecord lookupRecord[], + ContextClosureLookupContext &lookup_context) +{ + if (intersects_array (c, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data)) + closure_lookup (c, + lookupCount, lookupRecord, + lookup_context.funcs.closure); +} + + +static inline bool context_apply_lookup (hb_apply_context_t *c, + unsigned int inputCount, /* Including the first glyph (not matched) */ + const USHORT input[], /* Array of input values--start with second glyph */ + unsigned int lookupCount, + const LookupRecord lookupRecord[], + ContextApplyLookupContext &lookup_context) { - hb_apply_context_t new_context = *c; return match_input (c, inputCount, input, - lookup_context.funcs.match, lookup_context.match_data, - &new_context.context_length) - && apply_lookup (&new_context, + lookup_context.funcs.match, lookup_context.match_data) + && apply_lookup (c, inputCount, lookupCount, lookupRecord, lookup_context.funcs.apply); @@ -389,14 +509,22 @@ struct Rule friend struct RuleSet; private: - inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const + + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const + { + TRACE_CLOSURE (); + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); + context_closure_lookup (c, + inputCount, input, + lookupCount, lookupRecord, + lookup_context); + } + + inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); - return context_lookup (c, - inputCount, input, - lookupCount, lookupRecord, - lookup_context); + return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); } public: @@ -405,13 +533,13 @@ struct Rule return inputCount.sanitize (c) && lookupCount.sanitize (c) && c->check_range (input, - input[0].static_size * inputCount - + lookupRecordX[0].static_size * lookupCount); + input[0].static_size * inputCount + + lookupRecordX[0].static_size * lookupCount); } private: USHORT inputCount; /* Total number of glyphs in input - * glyph sequence--includes the first + * glyph sequence--includes the first * glyph */ USHORT lookupCount; /* Number of LookupRecords */ USHORT input[VAR]; /* Array of match inputs--start with @@ -424,22 +552,29 @@ struct Rule struct RuleSet { - inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context) const + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const + { + TRACE_CLOSURE (); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + (this+rule[i]).closure (c, lookup_context); + } + + inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) { if ((this+rule[i]).apply (c, lookup_context)) - return true; + return TRACE_RETURN (true); } - - return false; + return TRACE_RETURN (false); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return rule.sanitize (c, this); + return TRACE_RETURN (rule.sanitize (c, this)); } private: @@ -456,25 +591,44 @@ struct ContextFormat1 friend struct Context; private: + + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + + const Coverage &cov = (this+coverage); + + struct ContextClosureLookupContext lookup_context = { + {intersects_glyph, closure_func}, + NULL + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (cov.intersects_coverage (c->glyphs, i)) { + const RuleSet &rule_set = this+ruleSet[i]; + rule_set.closure (c, lookup_context); + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) - return false; + return TRACE_RETURN (false); const RuleSet &rule_set = this+ruleSet[index]; - struct ContextLookupContext lookup_context = { + struct ContextApplyLookupContext lookup_context = { {match_glyph, apply_func}, NULL }; - return rule_set.apply (c, lookup_context); + return TRACE_RETURN (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && ruleSet.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); } private: @@ -495,28 +649,47 @@ struct ContextFormat2 friend struct Context; private: + + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + if (!(this+coverage).intersects (c->glyphs)) + return; + + const ClassDef &class_def = this+classDef; + + struct ContextClosureLookupContext lookup_context = { + {intersects_class, closure_func}, + NULL + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (class_def.intersects_class (c->glyphs, i)) { + const RuleSet &rule_set = this+ruleSet[i]; + rule_set.closure (c, lookup_context); + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const ClassDef &class_def = this+classDef; - index = class_def (c->buffer->info[c->buffer->idx].codepoint); + index = class_def (c->buffer->cur().codepoint); const RuleSet &rule_set = this+ruleSet[index]; - struct ContextLookupContext lookup_context = { + struct ContextApplyLookupContext lookup_context = { {match_class, apply_func}, &class_def }; - return rule_set.apply (c, lookup_context); + return TRACE_RETURN (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && classDef.sanitize (c, this) - && ruleSet.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); } private: @@ -540,33 +713,47 @@ struct ContextFormat3 friend struct Context; private: + + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + if (!(this+coverage[0]).intersects (c->glyphs)) + return; + + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); + struct ContextClosureLookupContext lookup_context = { + {intersects_coverage, closure_func}, + this + }; + context_closure_lookup (c, + glyphCount, (const USHORT *) (coverage + 1), + lookupCount, lookupRecord, + lookup_context); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); - unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); - struct ContextLookupContext lookup_context = { + struct ContextApplyLookupContext lookup_context = { {match_coverage, apply_func}, this }; - return context_lookup (c, - glyphCount, (const USHORT *) (coverage + 1), - lookupCount, lookupRecord, - lookup_context); + return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!c->check_struct (this)) return false; + if (!c->check_struct (this)) return TRACE_RETURN (false); unsigned int count = glyphCount; - if (!c->check_array (coverage, coverage[0].static_size, count)) return false; + if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); for (unsigned int i = 0; i < count; i++) - if (!coverage[i].sanitize (c, this)) return false; + if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); - return c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount); + return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); } private: @@ -586,25 +773,37 @@ struct ContextFormat3 struct Context { protected: + + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + switch (u.format) { + case 1: u.format1.closure (c, closure_func); break; + case 2: u.format2.closure (c, closure_func); break; + case 3: u.format3.closure (c, closure_func); break; + default: break; + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c, apply_func); - case 2: return u.format2.apply (c, apply_func); - case 3: return u.format3.apply (c, apply_func); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c, apply_func)); + case 2: return TRACE_RETURN (u.format2.apply (c, apply_func)); + case 3: return TRACE_RETURN (u.format3.apply (c, apply_func)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - case 3: return u.format3.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + case 3: return TRACE_RETURN (u.format3.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -620,42 +819,67 @@ struct Context /* Chaining Contextual lookups */ -struct ChainContextLookupContext +struct ChainContextClosureLookupContext +{ + ContextClosureFuncs funcs; + const void *intersects_data[3]; +}; + +struct ChainContextApplyLookupContext { - ContextFuncs funcs; + ContextApplyFuncs funcs; const void *match_data[3]; }; -static inline bool chain_context_lookup (hb_apply_context_t *c, - unsigned int backtrackCount, - const USHORT backtrack[], - unsigned int inputCount, /* Including the first glyph (not matched) */ - const USHORT input[], /* Array of input values--start with second glyph */ - unsigned int lookaheadCount, - const USHORT lookahead[], - unsigned int lookupCount, - const LookupRecord lookupRecord[], - ChainContextLookupContext &lookup_context) +static inline void chain_context_closure_lookup (hb_closure_context_t *c, + unsigned int backtrackCount, + const USHORT backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const USHORT input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const USHORT lookahead[], + unsigned int lookupCount, + const LookupRecord lookupRecord[], + ChainContextClosureLookupContext &lookup_context) { - /* First guess */ - if (unlikely (c->buffer->backtrack_len () < backtrackCount || - c->buffer->idx + inputCount + lookaheadCount > c->buffer->len || - inputCount + lookaheadCount > c->context_length)) - return false; + if (intersects_array (c, + backtrackCount, backtrack, + lookup_context.funcs.intersects, lookup_context.intersects_data[0]) + && intersects_array (c, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data[1]) + && intersects_array (c, + lookaheadCount, lookahead, + lookup_context.funcs.intersects, lookup_context.intersects_data[2])) + closure_lookup (c, + lookupCount, lookupRecord, + lookup_context.funcs.closure); +} - hb_apply_context_t new_context = *c; +static inline bool chain_context_apply_lookup (hb_apply_context_t *c, + unsigned int backtrackCount, + const USHORT backtrack[], + unsigned int inputCount, /* Including the first glyph (not matched) */ + const USHORT input[], /* Array of input values--start with second glyph */ + unsigned int lookaheadCount, + const USHORT lookahead[], + unsigned int lookupCount, + const LookupRecord lookupRecord[], + ChainContextApplyLookupContext &lookup_context) +{ + unsigned int lookahead_offset; return match_backtrack (c, backtrackCount, backtrack, lookup_context.funcs.match, lookup_context.match_data[0]) && match_input (c, inputCount, input, lookup_context.funcs.match, lookup_context.match_data[1], - &new_context.context_length) + &lookahead_offset) && match_lookahead (c, lookaheadCount, lookahead, lookup_context.funcs.match, lookup_context.match_data[2], - new_context.context_length) - && apply_lookup (&new_context, + lookahead_offset) + && apply_lookup (c, inputCount, lookupCount, lookupRecord, lookup_context.funcs.apply); @@ -666,30 +890,44 @@ struct ChainRule friend struct ChainRuleSet; private: - inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const + + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const + { + TRACE_CLOSURE (); + const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); + const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); + chain_context_closure_lookup (c, + backtrack.len, backtrack.array, + input.len, input.array, + lookahead.len, lookahead.array, + lookup.len, lookup.array, + lookup_context); + } + + inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); - return chain_context_lookup (c, - backtrack.len, backtrack.array, - input.len, input.array, - lookahead.len, lookahead.array, - lookup.len, lookup.array, - lookup_context); + return TRACE_RETURN (chain_context_apply_lookup (c, + backtrack.len, backtrack.array, + input.len, input.array, + lookahead.len, lookahead.array, lookup.len, + lookup.array, lookup_context)); } public: inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!backtrack.sanitize (c)) return false; + if (!backtrack.sanitize (c)) return TRACE_RETURN (false); HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); - if (!input.sanitize (c)) return false; + if (!input.sanitize (c)) return TRACE_RETURN (false); ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); - if (!lookahead.sanitize (c)) return false; + if (!lookahead.sanitize (c)) return TRACE_RETURN (false); ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); - return lookup.sanitize (c); + return TRACE_RETURN (lookup.sanitize (c)); } private: @@ -712,22 +950,28 @@ struct ChainRule struct ChainRuleSet { - inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_context) const + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const + { + TRACE_CLOSURE (); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + (this+rule[i]).closure (c, lookup_context); + } + + inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) - { if ((this+rule[i]).apply (c, lookup_context)) - return true; - } + return TRACE_RETURN (true); - return false; + return TRACE_RETURN (false); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return rule.sanitize (c, this); + return TRACE_RETURN (rule.sanitize (c, this)); } private: @@ -743,25 +987,42 @@ struct ChainContextFormat1 friend struct ChainContext; private: + + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + const Coverage &cov = (this+coverage); + + struct ChainContextClosureLookupContext lookup_context = { + {intersects_glyph, closure_func}, + {NULL, NULL, NULL} + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (cov.intersects_coverage (c->glyphs, i)) { + const ChainRuleSet &rule_set = this+ruleSet[i]; + rule_set.closure (c, lookup_context); + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const ChainRuleSet &rule_set = this+ruleSet[index]; - struct ChainContextLookupContext lookup_context = { + struct ChainContextApplyLookupContext lookup_context = { {match_glyph, apply_func}, {NULL, NULL, NULL} }; - return rule_set.apply (c, lookup_context); + return TRACE_RETURN (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && ruleSet.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); } private: @@ -781,35 +1042,58 @@ struct ChainContextFormat2 friend struct ChainContext; private: + + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + if (!(this+coverage).intersects (c->glyphs)) + return; + + const ClassDef &backtrack_class_def = this+backtrackClassDef; + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + + struct ChainContextClosureLookupContext lookup_context = { + {intersects_class, closure_func}, + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + if (input_class_def.intersects_class (c->glyphs, i)) { + const ChainRuleSet &rule_set = this+ruleSet[i]; + rule_set.closure (c, lookup_context); + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef; - index = input_class_def (c->buffer->info[c->buffer->idx].codepoint); + index = input_class_def (c->buffer->cur().codepoint); const ChainRuleSet &rule_set = this+ruleSet[index]; - struct ChainContextLookupContext lookup_context = { + struct ChainContextApplyLookupContext lookup_context = { {match_class, apply_func}, {&backtrack_class_def, &input_class_def, &lookahead_class_def} }; - return rule_set.apply (c, lookup_context); + return TRACE_RETURN (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return coverage.sanitize (c, this) - && backtrackClassDef.sanitize (c, this) - && inputClassDef.sanitize (c, this) - && lookaheadClassDef.sanitize (c, this) - && ruleSet.sanitize (c, this); + return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && + inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && + ruleSet.sanitize (c, this)); } private: @@ -842,38 +1126,58 @@ struct ChainContextFormat3 private: + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + if (!(this+input[0]).intersects (c->glyphs)) + return; + + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); + struct ChainContextClosureLookupContext lookup_context = { + {intersects_coverage, closure_func}, + {this, this, this} + }; + chain_context_closure_lookup (c, + backtrack.len, (const USHORT *) backtrack.array, + input.len, (const USHORT *) input.array + 1, + lookahead.len, (const USHORT *) lookahead.array, + lookup.len, lookup.array, + lookup_context); + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); - unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->idx].codepoint); - if (likely (index == NOT_COVERED)) - return false; + unsigned int index = (this+input[0]) (c->buffer->cur().codepoint); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); - struct ChainContextLookupContext lookup_context = { + struct ChainContextApplyLookupContext lookup_context = { {match_coverage, apply_func}, {this, this, this} }; - return chain_context_lookup (c, - backtrack.len, (const USHORT *) backtrack.array, - input.len, (const USHORT *) input.array + 1, - lookahead.len, (const USHORT *) lookahead.array, - lookup.len, lookup.array, - lookup_context); + return TRACE_RETURN (chain_context_apply_lookup (c, + backtrack.len, (const USHORT *) backtrack.array, + input.len, (const USHORT *) input.array + 1, + lookahead.len, (const USHORT *) lookahead.array, + lookup.len, lookup.array, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!backtrack.sanitize (c, this)) return false; + if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); - if (!input.sanitize (c, this)) return false; + if (!input.sanitize (c, this)) return TRACE_RETURN (false); OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); - if (!lookahead.sanitize (c, this)) return false; + if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); - return lookup.sanitize (c); + return TRACE_RETURN (lookup.sanitize (c)); } private: @@ -900,25 +1204,37 @@ struct ChainContextFormat3 struct ChainContext { protected: + + inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + { + TRACE_CLOSURE (); + switch (u.format) { + case 1: u.format1.closure (c, closure_func); break; + case 2: u.format2.closure (c, closure_func); break; + case 3: u.format3.closure (c, closure_func); break; + default: break; + } + } + inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const { TRACE_APPLY (); switch (u.format) { - case 1: return u.format1.apply (c, apply_func); - case 2: return u.format2.apply (c, apply_func); - case 3: return u.format3.apply (c, apply_func); - default:return false; + case 1: return TRACE_RETURN (u.format1.apply (c, apply_func)); + case 2: return TRACE_RETURN (u.format2.apply (c, apply_func)); + case 3: return TRACE_RETURN (u.format3.apply (c, apply_func)); + default:return TRACE_RETURN (false); } } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - case 2: return u.format2.sanitize (c); - case 3: return u.format3.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + case 2: return TRACE_RETURN (u.format2.sanitize (c)); + case 3: return TRACE_RETURN (u.format3.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -942,7 +1258,7 @@ struct ExtensionFormat1 inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this); + return TRACE_RETURN (c->check_struct (this)); } private: @@ -975,10 +1291,10 @@ struct Extension inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - if (!u.format.sanitize (c)) return false; + if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { - case 1: return u.format1.sanitize (c); - default:return true; + case 1: return TRACE_RETURN (u.format1.sanitize (c)); + default:return TRACE_RETURN (true); } } @@ -1032,10 +1348,10 @@ struct GSUBGPOS inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return version.sanitize (c) && likely (version.major == 1) - && scriptList.sanitize (c, this) - && featureList.sanitize (c, this) - && lookupList.sanitize (c, this); + return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && + scriptList.sanitize (c, this) && + featureList.sanitize (c, this) && + lookupList.sanitize (c, this)); } protected: diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh index bf7e43b..f860e7b 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh @@ -33,6 +33,7 @@ #include "hb-font-private.hh" #include "hb-buffer-private.hh" +#include "hb-ot-shape-complex-private.hh" @@ -40,9 +41,6 @@ * GDEF */ -/* buffer var allocations */ -#define props_cache() var1.u16[1] /* glyph_props cache */ - /* XXX cleanup */ typedef enum { HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0001, diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc index f3e0713..ded3dcc 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc @@ -460,7 +460,8 @@ hb_ot_layout_substitute_lookup (hb_face_t *face, unsigned int lookup_index, hb_mask_t mask) { - return _get_gsub (face).substitute_lookup (face, buffer, lookup_index, mask); + hb_apply_context_t c (NULL, face, buffer, mask); + return _get_gsub (face).substitute_lookup (&c, lookup_index); } void @@ -469,6 +470,14 @@ hb_ot_layout_substitute_finish (hb_buffer_t *buffer HB_UNUSED) GSUB::substitute_finish (buffer); } +void +hb_ot_layout_substitute_closure_lookup (hb_face_t *face, + hb_set_t *glyphs, + unsigned int lookup_index) +{ + hb_closure_context_t c (face, glyphs); + _get_gsub (face).closure_lookup (&c, lookup_index); +} /* * GPOS @@ -492,7 +501,8 @@ hb_ot_layout_position_lookup (hb_font_t *font, unsigned int lookup_index, hb_mask_t mask) { - return _get_gpos (font->face).position_lookup (font, buffer, lookup_index, mask); + hb_apply_context_t c (font, font->face, buffer, mask); + return _get_gpos (font->face).position_lookup (&c, lookup_index); } void diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.h b/third_party/harfbuzz-ng/src/hb-ot-layout.h index 447e35d..b8b5baf 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout.h +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.h @@ -24,12 +24,14 @@ * Red Hat Author(s): Behdad Esfahbod */ +#ifndef HB_OT_H_IN +#error "Include <hb-ot.h> instead." +#endif + #ifndef HB_OT_LAYOUT_H #define HB_OT_LAYOUT_H -#include "hb-common.h" -#include "hb-buffer.h" -#include "hb-font.h" +#include "hb.h" #include "hb-ot-tag.h" @@ -180,6 +182,12 @@ hb_ot_layout_substitute_lookup (hb_face_t *face, void hb_ot_layout_substitute_finish (hb_buffer_t *buffer); + +void +hb_ot_layout_substitute_closure_lookup (hb_face_t *face, + hb_set_t *glyphs, + unsigned int lookup_index); + /* * GPOS */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-map-private.hh b/third_party/harfbuzz-ng/src/hb-ot-map-private.hh index 710cc0a..3811206 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-map-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-map-private.hh @@ -69,6 +69,10 @@ struct hb_ot_map_t inline void position (hb_font_t *font, hb_buffer_t *buffer) const { apply (1, (hb_ot_map_t::apply_lookup_func_t) hb_ot_layout_position_lookup, font, buffer); } + HB_INTERNAL void substitute_closure (hb_face_t *face, + hb_set_t *glyphs) const; + + inline void finish (void) { features.finish (); lookups[0].finish (); diff --git a/third_party/harfbuzz-ng/src/hb-ot-map.cc b/third_party/harfbuzz-ng/src/hb-ot-map.cc index a54e306..bebf3ed 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-map.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-map.cc @@ -95,6 +95,21 @@ void hb_ot_map_t::apply (unsigned int table_index, apply_lookup_func (face_or_font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); } +void hb_ot_map_t::substitute_closure (hb_face_t *face, + hb_set_t *glyphs) const +{ + unsigned int table_index = 0; + unsigned int i = 0; + + 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_closure_lookup (face, glyphs, lookups[table_index][i].index); + } + + for (; i < lookups[table_index].len; i++) + hb_ot_layout_substitute_closure_lookup (face, glyphs, lookups[table_index][i].index); +} void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func, void *user_data) { diff --git a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh index c3ac1c2..e270490 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -47,9 +47,8 @@ struct maxp inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) && - likely (version.major == 1 || - (version.major == 0 && version.minor == 0x5000)); + return TRACE_RETURN (c->check_struct (this) && + likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000))); } /* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-name-table.hh b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh index 0e9f7a4..9077c8c 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-name-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -57,8 +57,7 @@ struct NameRecord inline bool sanitize (hb_sanitize_context_t *c, void *base) { TRACE_SANITIZE (); /* We can check from base all the way up to the end of string... */ - return c->check_struct (this) && - c->check_range ((char *) base, (unsigned int) length + offset); + return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset)); } USHORT platformID; /* Platform ID. */ @@ -102,16 +101,16 @@ struct name char *string_pool = (char *) this + stringOffset; unsigned int _count = count; for (unsigned int i = 0; i < _count; i++) - if (!nameRecord[i].sanitize (c, string_pool)) return false; - return true; + if (!nameRecord[i].sanitize (c, string_pool)) return TRACE_RETURN (false); + return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c) { TRACE_SANITIZE (); - return c->check_struct (this) && - likely (format == 0 || format == 1) && - c->check_array (nameRecord, nameRecord[0].static_size, count) && - sanitize_records (c); + return TRACE_RETURN (c->check_struct (this) && + likely (format == 0 || format == 1) && + c->check_array (nameRecord, nameRecord[0].static_size, count) && + sanitize_records (c)); } /* We only implement format 0 for now. */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh index 5aa8716..df85086 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-table.hh @@ -1,46 +1,20 @@ -/* - * Copyright © 2011 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH -#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH - -#include "hb-private.hh" - - /* == Start of generated table == */ /* * The following table is generated by running: * - * ./gen-arabic-table.py ArabicShaping.txt + * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt * * on files with these headers: * * # ArabicShaping-6.1.0.txt * # Date: 2011-04-15, 23:16:00 GMT [KW] + * UnicodeData.txt does not have a header. */ + +#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH +#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH + + static const uint8_t joining_table[] = { @@ -752,7 +726,217 @@ static const uint8_t joining_table[] = #define JOINING_TABLE_FIRST 0x0600 #define JOINING_TABLE_LAST 0x08AC -/* == End of generated table == */ + +static const uint16_t shaping_table[][4] = +{ + {0x0621, 0x0621, 0x0621, 0xFE80}, /* U+0621 ARABIC LETTER HAMZA ISOLATED FORM */ + {0x0622, 0x0622, 0xFE82, 0xFE81}, /* U+0622 ARABIC LETTER ALEF WITH MADDA ABOVE */ + {0x0623, 0x0623, 0xFE84, 0xFE83}, /* U+0623 ARABIC LETTER ALEF WITH HAMZA ABOVE */ + {0x0624, 0x0624, 0xFE86, 0xFE85}, /* U+0624 ARABIC LETTER WAW WITH HAMZA ABOVE */ + {0x0625, 0x0625, 0xFE88, 0xFE87}, /* U+0625 ARABIC LETTER ALEF WITH HAMZA BELOW */ + {0xFE8B, 0xFE8C, 0xFE8A, 0xFE89}, /* U+0626 ARABIC LETTER YEH WITH HAMZA ABOVE */ + {0x0627, 0x0627, 0xFE8E, 0xFE8D}, /* U+0627 ARABIC LETTER ALEF */ + {0xFE91, 0xFE92, 0xFE90, 0xFE8F}, /* U+0628 ARABIC LETTER BEH */ + {0x0629, 0x0629, 0xFE94, 0xFE93}, /* U+0629 ARABIC LETTER TEH MARBUTA */ + {0xFE97, 0xFE98, 0xFE96, 0xFE95}, /* U+062A ARABIC LETTER TEH */ + {0xFE9B, 0xFE9C, 0xFE9A, 0xFE99}, /* U+062B ARABIC LETTER THEH */ + {0xFE9F, 0xFEA0, 0xFE9E, 0xFE9D}, /* U+062C ARABIC LETTER JEEM */ + {0xFEA3, 0xFEA4, 0xFEA2, 0xFEA1}, /* U+062D ARABIC LETTER HAH */ + {0xFEA7, 0xFEA8, 0xFEA6, 0xFEA5}, /* U+062E ARABIC LETTER KHAH */ + {0x062F, 0x062F, 0xFEAA, 0xFEA9}, /* U+062F ARABIC LETTER DAL */ + {0x0630, 0x0630, 0xFEAC, 0xFEAB}, /* U+0630 ARABIC LETTER THAL */ + {0x0631, 0x0631, 0xFEAE, 0xFEAD}, /* U+0631 ARABIC LETTER REH */ + {0x0632, 0x0632, 0xFEB0, 0xFEAF}, /* U+0632 ARABIC LETTER ZAIN */ + {0xFEB3, 0xFEB4, 0xFEB2, 0xFEB1}, /* U+0633 ARABIC LETTER SEEN */ + {0xFEB7, 0xFEB8, 0xFEB6, 0xFEB5}, /* U+0634 ARABIC LETTER SHEEN */ + {0xFEBB, 0xFEBC, 0xFEBA, 0xFEB9}, /* U+0635 ARABIC LETTER SAD */ + {0xFEBF, 0xFEC0, 0xFEBE, 0xFEBD}, /* U+0636 ARABIC LETTER DAD */ + {0xFEC3, 0xFEC4, 0xFEC2, 0xFEC1}, /* U+0637 ARABIC LETTER TAH */ + {0xFEC7, 0xFEC8, 0xFEC6, 0xFEC5}, /* U+0638 ARABIC LETTER ZAH */ + {0xFECB, 0xFECC, 0xFECA, 0xFEC9}, /* U+0639 ARABIC LETTER AIN */ + {0xFECF, 0xFED0, 0xFECE, 0xFECD}, /* U+063A ARABIC LETTER GHAIN */ + {0x063B, 0x063B, 0x063B, 0x063B}, /* U+063B */ + {0x063C, 0x063C, 0x063C, 0x063C}, /* U+063C */ + {0x063D, 0x063D, 0x063D, 0x063D}, /* U+063D */ + {0x063E, 0x063E, 0x063E, 0x063E}, /* U+063E */ + {0x063F, 0x063F, 0x063F, 0x063F}, /* U+063F */ + {0x0640, 0x0640, 0x0640, 0x0640}, /* U+0640 */ + {0xFED3, 0xFED4, 0xFED2, 0xFED1}, /* U+0641 ARABIC LETTER FEH */ + {0xFED7, 0xFED8, 0xFED6, 0xFED5}, /* U+0642 ARABIC LETTER QAF */ + {0xFEDB, 0xFEDC, 0xFEDA, 0xFED9}, /* U+0643 ARABIC LETTER KAF */ + {0xFEDF, 0xFEE0, 0xFEDE, 0xFEDD}, /* U+0644 ARABIC LETTER LAM */ + {0xFEE3, 0xFEE4, 0xFEE2, 0xFEE1}, /* U+0645 ARABIC LETTER MEEM */ + {0xFEE7, 0xFEE8, 0xFEE6, 0xFEE5}, /* U+0646 ARABIC LETTER NOON */ + {0xFEEB, 0xFEEC, 0xFEEA, 0xFEE9}, /* U+0647 ARABIC LETTER HEH */ + {0x0648, 0x0648, 0xFEEE, 0xFEED}, /* U+0648 ARABIC LETTER WAW */ + {0xFBE8, 0xFBE9, 0xFEF0, 0xFEEF}, /* U+0649 ARABIC LETTER */ + {0xFEF3, 0xFEF4, 0xFEF2, 0xFEF1}, /* U+064A ARABIC LETTER YEH */ + {0x064B, 0x064B, 0x064B, 0x064B}, /* U+064B */ + {0x064C, 0x064C, 0x064C, 0x064C}, /* U+064C */ + {0x064D, 0x064D, 0x064D, 0x064D}, /* U+064D */ + {0x064E, 0x064E, 0x064E, 0x064E}, /* U+064E */ + {0x064F, 0x064F, 0x064F, 0x064F}, /* U+064F */ + {0x0650, 0x0650, 0x0650, 0x0650}, /* U+0650 */ + {0x0651, 0x0651, 0x0651, 0x0651}, /* U+0651 */ + {0x0652, 0x0652, 0x0652, 0x0652}, /* U+0652 */ + {0x0653, 0x0653, 0x0653, 0x0653}, /* U+0653 */ + {0x0654, 0x0654, 0x0654, 0x0654}, /* U+0654 */ + {0x0655, 0x0655, 0x0655, 0x0655}, /* U+0655 */ + {0x0656, 0x0656, 0x0656, 0x0656}, /* U+0656 */ + {0x0657, 0x0657, 0x0657, 0x0657}, /* U+0657 */ + {0x0658, 0x0658, 0x0658, 0x0658}, /* U+0658 */ + {0x0659, 0x0659, 0x0659, 0x0659}, /* U+0659 */ + {0x065A, 0x065A, 0x065A, 0x065A}, /* U+065A */ + {0x065B, 0x065B, 0x065B, 0x065B}, /* U+065B */ + {0x065C, 0x065C, 0x065C, 0x065C}, /* U+065C */ + {0x065D, 0x065D, 0x065D, 0x065D}, /* U+065D */ + {0x065E, 0x065E, 0x065E, 0x065E}, /* U+065E */ + {0x065F, 0x065F, 0x065F, 0x065F}, /* U+065F */ + {0x0660, 0x0660, 0x0660, 0x0660}, /* U+0660 */ + {0x0661, 0x0661, 0x0661, 0x0661}, /* U+0661 */ + {0x0662, 0x0662, 0x0662, 0x0662}, /* U+0662 */ + {0x0663, 0x0663, 0x0663, 0x0663}, /* U+0663 */ + {0x0664, 0x0664, 0x0664, 0x0664}, /* U+0664 */ + {0x0665, 0x0665, 0x0665, 0x0665}, /* U+0665 */ + {0x0666, 0x0666, 0x0666, 0x0666}, /* U+0666 */ + {0x0667, 0x0667, 0x0667, 0x0667}, /* U+0667 */ + {0x0668, 0x0668, 0x0668, 0x0668}, /* U+0668 */ + {0x0669, 0x0669, 0x0669, 0x0669}, /* U+0669 */ + {0x066A, 0x066A, 0x066A, 0x066A}, /* U+066A */ + {0x066B, 0x066B, 0x066B, 0x066B}, /* U+066B */ + {0x066C, 0x066C, 0x066C, 0x066C}, /* U+066C */ + {0x066D, 0x066D, 0x066D, 0x066D}, /* U+066D */ + {0x066E, 0x066E, 0x066E, 0x066E}, /* U+066E */ + {0x066F, 0x066F, 0x066F, 0x066F}, /* U+066F */ + {0x0670, 0x0670, 0x0670, 0x0670}, /* U+0670 */ + {0x0671, 0x0671, 0xFB51, 0xFB50}, /* U+0671 ARABIC LETTER ALEF WASLA */ + {0x0672, 0x0672, 0x0672, 0x0672}, /* U+0672 */ + {0x0673, 0x0673, 0x0673, 0x0673}, /* U+0673 */ + {0x0674, 0x0674, 0x0674, 0x0674}, /* U+0674 */ + {0x0675, 0x0675, 0x0675, 0x0675}, /* U+0675 */ + {0x0676, 0x0676, 0x0676, 0x0676}, /* U+0676 */ + {0x0677, 0x0677, 0x0677, 0xFBDD}, /* U+0677 ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM */ + {0x0678, 0x0678, 0x0678, 0x0678}, /* U+0678 */ + {0xFB68, 0xFB69, 0xFB67, 0xFB66}, /* U+0679 ARABIC LETTER TTEH */ + {0xFB60, 0xFB61, 0xFB5F, 0xFB5E}, /* U+067A ARABIC LETTER TTEHEH */ + {0xFB54, 0xFB55, 0xFB53, 0xFB52}, /* U+067B ARABIC LETTER BEEH */ + {0x067C, 0x067C, 0x067C, 0x067C}, /* U+067C */ + {0x067D, 0x067D, 0x067D, 0x067D}, /* U+067D */ + {0xFB58, 0xFB59, 0xFB57, 0xFB56}, /* U+067E ARABIC LETTER PEH */ + {0xFB64, 0xFB65, 0xFB63, 0xFB62}, /* U+067F ARABIC LETTER TEHEH */ + {0xFB5C, 0xFB5D, 0xFB5B, 0xFB5A}, /* U+0680 ARABIC LETTER BEHEH */ + {0x0681, 0x0681, 0x0681, 0x0681}, /* U+0681 */ + {0x0682, 0x0682, 0x0682, 0x0682}, /* U+0682 */ + {0xFB78, 0xFB79, 0xFB77, 0xFB76}, /* U+0683 ARABIC LETTER NYEH */ + {0xFB74, 0xFB75, 0xFB73, 0xFB72}, /* U+0684 ARABIC LETTER DYEH */ + {0x0685, 0x0685, 0x0685, 0x0685}, /* U+0685 */ + {0xFB7C, 0xFB7D, 0xFB7B, 0xFB7A}, /* U+0686 ARABIC LETTER TCHEH */ + {0xFB80, 0xFB81, 0xFB7F, 0xFB7E}, /* U+0687 ARABIC LETTER TCHEHEH */ + {0x0688, 0x0688, 0xFB89, 0xFB88}, /* U+0688 ARABIC LETTER DDAL */ + {0x0689, 0x0689, 0x0689, 0x0689}, /* U+0689 */ + {0x068A, 0x068A, 0x068A, 0x068A}, /* U+068A */ + {0x068B, 0x068B, 0x068B, 0x068B}, /* U+068B */ + {0x068C, 0x068C, 0xFB85, 0xFB84}, /* U+068C ARABIC LETTER DAHAL */ + {0x068D, 0x068D, 0xFB83, 0xFB82}, /* U+068D ARABIC LETTER DDAHAL */ + {0x068E, 0x068E, 0xFB87, 0xFB86}, /* U+068E ARABIC LETTER DUL */ + {0x068F, 0x068F, 0x068F, 0x068F}, /* U+068F */ + {0x0690, 0x0690, 0x0690, 0x0690}, /* U+0690 */ + {0x0691, 0x0691, 0xFB8D, 0xFB8C}, /* U+0691 ARABIC LETTER RREH */ + {0x0692, 0x0692, 0x0692, 0x0692}, /* U+0692 */ + {0x0693, 0x0693, 0x0693, 0x0693}, /* U+0693 */ + {0x0694, 0x0694, 0x0694, 0x0694}, /* U+0694 */ + {0x0695, 0x0695, 0x0695, 0x0695}, /* U+0695 */ + {0x0696, 0x0696, 0x0696, 0x0696}, /* U+0696 */ + {0x0697, 0x0697, 0x0697, 0x0697}, /* U+0697 */ + {0x0698, 0x0698, 0xFB8B, 0xFB8A}, /* U+0698 ARABIC LETTER JEH */ + {0x0699, 0x0699, 0x0699, 0x0699}, /* U+0699 */ + {0x069A, 0x069A, 0x069A, 0x069A}, /* U+069A */ + {0x069B, 0x069B, 0x069B, 0x069B}, /* U+069B */ + {0x069C, 0x069C, 0x069C, 0x069C}, /* U+069C */ + {0x069D, 0x069D, 0x069D, 0x069D}, /* U+069D */ + {0x069E, 0x069E, 0x069E, 0x069E}, /* U+069E */ + {0x069F, 0x069F, 0x069F, 0x069F}, /* U+069F */ + {0x06A0, 0x06A0, 0x06A0, 0x06A0}, /* U+06A0 */ + {0x06A1, 0x06A1, 0x06A1, 0x06A1}, /* U+06A1 */ + {0x06A2, 0x06A2, 0x06A2, 0x06A2}, /* U+06A2 */ + {0x06A3, 0x06A3, 0x06A3, 0x06A3}, /* U+06A3 */ + {0xFB6C, 0xFB6D, 0xFB6B, 0xFB6A}, /* U+06A4 ARABIC LETTER VEH */ + {0x06A5, 0x06A5, 0x06A5, 0x06A5}, /* U+06A5 */ + {0xFB70, 0xFB71, 0xFB6F, 0xFB6E}, /* U+06A6 ARABIC LETTER PEHEH */ + {0x06A7, 0x06A7, 0x06A7, 0x06A7}, /* U+06A7 */ + {0x06A8, 0x06A8, 0x06A8, 0x06A8}, /* U+06A8 */ + {0xFB90, 0xFB91, 0xFB8F, 0xFB8E}, /* U+06A9 ARABIC LETTER KEHEH */ + {0x06AA, 0x06AA, 0x06AA, 0x06AA}, /* U+06AA */ + {0x06AB, 0x06AB, 0x06AB, 0x06AB}, /* U+06AB */ + {0x06AC, 0x06AC, 0x06AC, 0x06AC}, /* U+06AC */ + {0xFBD5, 0xFBD6, 0xFBD4, 0xFBD3}, /* U+06AD ARABIC LETTER NG */ + {0x06AE, 0x06AE, 0x06AE, 0x06AE}, /* U+06AE */ + {0xFB94, 0xFB95, 0xFB93, 0xFB92}, /* U+06AF ARABIC LETTER GAF */ + {0x06B0, 0x06B0, 0x06B0, 0x06B0}, /* U+06B0 */ + {0xFB9C, 0xFB9D, 0xFB9B, 0xFB9A}, /* U+06B1 ARABIC LETTER NGOEH */ + {0x06B2, 0x06B2, 0x06B2, 0x06B2}, /* U+06B2 */ + {0xFB98, 0xFB99, 0xFB97, 0xFB96}, /* U+06B3 ARABIC LETTER GUEH */ + {0x06B4, 0x06B4, 0x06B4, 0x06B4}, /* U+06B4 */ + {0x06B5, 0x06B5, 0x06B5, 0x06B5}, /* U+06B5 */ + {0x06B6, 0x06B6, 0x06B6, 0x06B6}, /* U+06B6 */ + {0x06B7, 0x06B7, 0x06B7, 0x06B7}, /* U+06B7 */ + {0x06B8, 0x06B8, 0x06B8, 0x06B8}, /* U+06B8 */ + {0x06B9, 0x06B9, 0x06B9, 0x06B9}, /* U+06B9 */ + {0x06BA, 0x06BA, 0xFB9F, 0xFB9E}, /* U+06BA ARABIC LETTER NOON GHUNNA */ + {0xFBA2, 0xFBA3, 0xFBA1, 0xFBA0}, /* U+06BB ARABIC LETTER RNOON */ + {0x06BC, 0x06BC, 0x06BC, 0x06BC}, /* U+06BC */ + {0x06BD, 0x06BD, 0x06BD, 0x06BD}, /* U+06BD */ + {0xFBAC, 0xFBAD, 0xFBAB, 0xFBAA}, /* U+06BE ARABIC LETTER HEH DOACHASHMEE */ + {0x06BF, 0x06BF, 0x06BF, 0x06BF}, /* U+06BF */ + {0x06C0, 0x06C0, 0xFBA5, 0xFBA4}, /* U+06C0 ARABIC LETTER HEH WITH YEH ABOVE */ + {0xFBA8, 0xFBA9, 0xFBA7, 0xFBA6}, /* U+06C1 ARABIC LETTER HEH GOAL */ + {0x06C2, 0x06C2, 0x06C2, 0x06C2}, /* U+06C2 */ + {0x06C3, 0x06C3, 0x06C3, 0x06C3}, /* U+06C3 */ + {0x06C4, 0x06C4, 0x06C4, 0x06C4}, /* U+06C4 */ + {0x06C5, 0x06C5, 0xFBE1, 0xFBE0}, /* U+06C5 ARABIC LETTER KIRGHIZ OE */ + {0x06C6, 0x06C6, 0xFBDA, 0xFBD9}, /* U+06C6 ARABIC LETTER OE */ + {0x06C7, 0x06C7, 0xFBD8, 0xFBD7}, /* U+06C7 ARABIC LETTER U */ + {0x06C8, 0x06C8, 0xFBDC, 0xFBDB}, /* U+06C8 ARABIC LETTER YU */ + {0x06C9, 0x06C9, 0xFBE3, 0xFBE2}, /* U+06C9 ARABIC LETTER KIRGHIZ YU */ + {0x06CA, 0x06CA, 0x06CA, 0x06CA}, /* U+06CA */ + {0x06CB, 0x06CB, 0xFBDF, 0xFBDE}, /* U+06CB ARABIC LETTER VE */ + {0xFBFE, 0xFBFF, 0xFBFD, 0xFBFC}, /* U+06CC ARABIC LETTER FARSI YEH */ + {0x06CD, 0x06CD, 0x06CD, 0x06CD}, /* U+06CD */ + {0x06CE, 0x06CE, 0x06CE, 0x06CE}, /* U+06CE */ + {0x06CF, 0x06CF, 0x06CF, 0x06CF}, /* U+06CF */ + {0xFBE6, 0xFBE7, 0xFBE5, 0xFBE4}, /* U+06D0 ARABIC LETTER E */ + {0x06D1, 0x06D1, 0x06D1, 0x06D1}, /* U+06D1 */ + {0x06D2, 0x06D2, 0xFBAF, 0xFBAE}, /* U+06D2 ARABIC LETTER YEH BARREE */ + {0x06D3, 0x06D3, 0xFBB1, 0xFBB0}, /* U+06D3 ARABIC LETTER YEH BARREE WITH HAMZA ABOVE */ +}; + +#define SHAPING_TABLE_FIRST 0x0621 +#define SHAPING_TABLE_LAST 0x06D3 + + +static const struct { + uint16_t first; + struct { + uint16_t second; + uint16_t ligature; + } ligatures[4]; +} ligature_table[] = +{ + { 0xFEDF, { + { 0xFE88, 0xFEF9 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */ + { 0xFE82, 0xFEF5 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */ + { 0xFE8E, 0xFEFB }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */ + { 0xFE84, 0xFEF7 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */ + }}, + { 0xFEE0, { + { 0xFE88, 0xFEFA }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */ + { 0xFE82, 0xFEF6 }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */ + { 0xFE8E, 0xFEFC }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */ + { 0xFE84, 0xFEF8 }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */ + }}, +}; #endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */ + +/* == End of generated table == */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc index 2b863ef..54460f0 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic.cc @@ -25,11 +25,12 @@ */ #include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-private.hh" /* buffer var allocations */ -#define arabic_shaping_action() complex_var_temporary_u16() /* arabic shaping action */ +#define arabic_shaping_action() complex_var_temporary_u8() /* arabic shaping action */ /* @@ -58,8 +59,6 @@ enum { static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_category_t gen_cat) { - /* TODO Macroize the magic bit operations */ - if (likely (hb_in_range<hb_codepoint_t> (u, JOINING_TABLE_FIRST, JOINING_TABLE_LAST))) { unsigned int j_type = joining_table[u - JOINING_TABLE_FIRST]; if (likely (j_type != JOINING_TYPE_X)) @@ -82,7 +81,23 @@ static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_categ JOINING_TYPE_T : JOINING_TYPE_U; } +static hb_codepoint_t get_arabic_shape (hb_codepoint_t u, unsigned int shape) +{ + if (likely (hb_in_range<hb_codepoint_t> (u, SHAPING_TABLE_FIRST, SHAPING_TABLE_LAST)) && shape < 4) + return shaping_table[u - SHAPING_TABLE_FIRST][shape]; + return u; +} +static uint16_t get_ligature (hb_codepoint_t first, hb_codepoint_t second) +{ + if (unlikely (!second)) return 0; + for (unsigned i = 0; i < ARRAY_LENGTH (ligature_table); i++) + if (ligature_table[i].first == first) + for (unsigned j = 0; j < ARRAY_LENGTH (ligature_table[i].ligatures); j++) + if (ligature_table[i].ligatures[j].second == second) + return ligature_table[i].ligatures[j].ligature; + return 0; +} static const hb_tag_t arabic_syriac_features[] = { @@ -150,7 +165,8 @@ static const struct arabic_state_table_entry { void -_hb_ot_shape_complex_collect_features_arabic (hb_ot_map_builder_t *map, const hb_segment_properties_t *props) +_hb_ot_shape_complex_collect_features_arabic (hb_ot_map_builder_t *map, + const hb_segment_properties_t *props) { /* For Language forms (in ArabicOT speak), we do the iso/fina/medi/init together, * then rlig and calt each in their own stage. This makes IranNastaliq's ALLAH @@ -183,14 +199,51 @@ _hb_ot_shape_complex_collect_features_arabic (hb_ot_map_builder_t *map, const hb map->add_bool_feature (HB_TAG('c','s','w','h')); } -bool -_hb_ot_shape_complex_prefer_decomposed_arabic (void) +hb_ot_shape_normalization_mode_t +_hb_ot_shape_complex_normalization_preference_arabic (void) { - return FALSE; + return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; +} + + +static void +arabic_fallback_shape (hb_font_t *font, hb_buffer_t *buffer) +{ + unsigned int count = buffer->len; + hb_codepoint_t glyph; + + /* Shape to presentation forms */ + for (unsigned int i = 0; i < count; i++) { + hb_codepoint_t u = buffer->info[i].codepoint; + hb_codepoint_t shaped = get_arabic_shape (u, buffer->info[i].arabic_shaping_action()); + if (shaped != u && hb_font_get_glyph (font, shaped, 0, &glyph)) + buffer->info[i].codepoint = shaped; + } + + /* Mandatory ligatures */ + buffer->clear_output (); + for (buffer->idx = 0; buffer->idx + 1 < count;) { + hb_codepoint_t ligature = get_ligature (buffer->cur().codepoint, + buffer->cur(+1).codepoint); + if (likely (!ligature) || !(hb_font_get_glyph (font, ligature, 0, &glyph))) { + buffer->next_glyph (); + continue; + } + + buffer->replace_glyphs (2, 1, &ligature); + + /* Technically speaking we can skip marks and stuff, like the GSUB path does. + * But who cares, we're in fallback! */ + } + for (; buffer->idx < count;) + buffer->next_glyph (); + buffer->swap_buffers (); } void -_hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map, hb_buffer_t *buffer) +_hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map, + hb_buffer_t *buffer, + hb_font_t *font) { unsigned int count = buffer->len; unsigned int prev = 0, state = 0; @@ -199,7 +252,7 @@ _hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map, hb_buffer_t *buffer) for (unsigned int i = 0; i < count; i++) { - unsigned int this_type = get_joining_type (buffer->info[i].codepoint, (hb_unicode_general_category_t) buffer->info[i].general_category()); + unsigned int this_type = get_joining_type (buffer->info[i].codepoint, _hb_glyph_info_get_general_category (&buffer->info[i])); if (unlikely (this_type == JOINING_TYPE_T)) { buffer->info[i].arabic_shaping_action() = NONE; @@ -218,12 +271,27 @@ _hb_ot_shape_complex_setup_masks_arabic (hb_ot_map_t *map, hb_buffer_t *buffer) } hb_mask_t mask_array[TOTAL_NUM_FEATURES + 1] = {0}; + hb_mask_t total_masks = 0; unsigned int num_masks = buffer->props.script == HB_SCRIPT_SYRIAC ? SYRIAC_NUM_FEATURES : COMMON_NUM_FEATURES; - for (unsigned int i = 0; i < num_masks; i++) + for (unsigned int i = 0; i < num_masks; i++) { mask_array[i] = map->get_1_mask (arabic_syriac_features[i]); + total_masks |= mask_array[i]; + } - for (unsigned int i = 0; i < count; i++) - buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()]; + if (total_masks) { + /* Has OpenType tables */ + for (unsigned int i = 0; i < count; i++) + buffer->info[i].mask |= mask_array[buffer->info[i].arabic_shaping_action()]; + } else if (buffer->props.script == HB_SCRIPT_ARABIC) { + /* Fallback Arabic shaping to Presentation Forms */ + /* Pitfalls: + * - This path fires if user force-set init/medi/fina/isol off, + * - If font does not declare script 'arab', well, what to do? + * Most probably it's safe to assume that init/medi/fina/isol + * still mean Arabic shaping, although they do not have to. + */ + arabic_fallback_shape (font, buffer); + } HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); } diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh index 5c42355..0e9a53d 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.hh @@ -1,7 +1,7 @@ #line 1 "hb-ot-shape-complex-indic-machine.rl" /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -36,174 +36,154 @@ HB_BEGIN_DECLS #line 38 "hb-ot-shape-complex-indic-machine.hh.tmp" static const unsigned char _indic_syllable_machine_trans_keys[] = { - 0u, 0u, 5u, 5u, 1u, 2u, 1u, 2u, 5u, 5u, 1u, 5u, 5u, 5u, 1u, 2u, - 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, - 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, - 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, - 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, 0u, 12u, - 0u, 12u, 0 + 5u, 5u, 1u, 2u, 1u, 2u, 5u, 5u, 1u, 5u, 1u, 2u, 5u, 5u, 1u, 13u, + 4u, 11u, 4u, 11u, 5u, 11u, 1u, 10u, 1u, 10u, 10u, 10u, 10u, 10u, 4u, 10u, + 5u, 10u, 8u, 10u, 5u, 10u, 6u, 10u, 9u, 10u, 4u, 11u, 1u, 13u, 4u, 10u, + 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 8u, 10u, 10u, 10u, 10u, 10u, 4u, 10u, + 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 8u, 10u, 10u, 10u, 10u, 10u, 0 }; static const char _indic_syllable_machine_key_spans[] = { - 0, 1, 2, 2, 1, 5, 1, 2, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, - 13 + 1, 2, 2, 1, 5, 2, 1, 13, + 8, 8, 7, 10, 10, 1, 1, 7, + 6, 3, 6, 5, 2, 8, 13, 7, + 7, 6, 7, 6, 3, 1, 1, 7, + 7, 6, 7, 6, 3, 1, 1 }; -static const short _indic_syllable_machine_index_offsets[] = { - 0, 0, 2, 5, 8, 10, 16, 18, - 21, 35, 49, 63, 77, 91, 105, 119, - 133, 147, 161, 175, 189, 203, 217, 231, - 245, 259, 273, 287, 301, 315, 329, 343, - 357, 371, 385, 399, 413, 427, 441, 455, - 469 +static const unsigned char _indic_syllable_machine_index_offsets[] = { + 0, 2, 5, 8, 10, 16, 19, 21, + 35, 44, 53, 61, 72, 83, 85, 87, + 95, 102, 106, 113, 119, 122, 131, 145, + 153, 161, 168, 176, 183, 187, 189, 191, + 199, 207, 214, 222, 229, 233, 235 }; static const char _indic_syllable_machine_indicies[] = { - 0, 1, 2, 2, 1, 3, 3, - 1, 4, 1, 2, 2, 1, 1, 0, - 1, 5, 1, 6, 6, 1, 7, 6, - 8, 9, 1, 1, 1, 1, 1, 1, - 1, 1, 10, 1, 11, 12, 13, 14, - 1, 1, 1, 1, 1, 1, 1, 1, - 15, 1, 16, 17, 18, 19, 20, 21, - 22, 22, 23, 24, 25, 26, 27, 1, - 16, 17, 18, 19, 20, 28, 22, 22, - 23, 24, 25, 26, 27, 1, 29, 30, - 31, 32, 33, 1, 34, 35, 36, 37, - 38, 1, 39, 1, 29, 30, 31, 32, - 1, 1, 34, 35, 36, 37, 38, 1, - 39, 1, 29, 30, 31, 32, 1, 1, - 1, 1, 36, 37, 38, 1, 39, 1, - 29, 30, 31, 32, 40, 2, 1, 1, - 36, 37, 38, 1, 39, 1, 29, 30, - 31, 32, 1, 2, 1, 1, 36, 37, - 38, 1, 39, 1, 29, 30, 31, 32, - 1, 1, 1, 1, 1, 1, 38, 1, - 39, 1, 29, 30, 31, 32, 1, 1, - 1, 1, 1, 1, 41, 1, 39, 1, - 29, 30, 31, 32, 1, 1, 1, 1, - 1, 1, 1, 1, 39, 1, 42, 43, - 44, 45, 46, 4, 47, 47, 48, 49, - 50, 1, 51, 1, 42, 43, 44, 45, - 1, 4, 47, 47, 48, 49, 50, 1, - 51, 1, 42, 43, 44, 45, 1, 1, - 1, 1, 48, 49, 50, 1, 51, 1, - 42, 43, 44, 45, 52, 3, 1, 1, - 48, 49, 50, 1, 51, 1, 42, 43, - 44, 45, 1, 3, 1, 1, 48, 49, - 50, 1, 51, 1, 42, 43, 44, 45, - 1, 1, 1, 1, 1, 1, 50, 1, - 51, 1, 42, 43, 44, 45, 1, 1, - 1, 1, 1, 1, 53, 1, 51, 1, - 42, 43, 44, 45, 1, 1, 1, 1, - 1, 1, 1, 1, 51, 1, 16, 17, - 18, 19, 1, 21, 22, 22, 23, 24, - 25, 26, 27, 1, 16, 6, 6, 19, - 1, 1, 54, 54, 1, 24, 25, 1, - 27, 1, 16, 6, 6, 19, 1, 1, - 1, 1, 1, 24, 25, 1, 27, 1, - 16, 17, 18, 19, 1, 1, 1, 1, - 1, 1, 25, 1, 27, 1, 16, 17, - 18, 19, 1, 1, 1, 1, 1, 1, - 55, 1, 27, 1, 16, 17, 18, 19, - 1, 1, 1, 1, 1, 1, 1, 1, - 27, 1, 16, 17, 18, 19, 56, 57, - 1, 1, 23, 24, 25, 1, 27, 1, - 16, 17, 18, 19, 1, 57, 1, 1, - 23, 24, 25, 1, 27, 1, 16, 17, - 18, 19, 1, 1, 1, 1, 23, 24, - 25, 1, 27, 1, 16, 17, 18, 19, - 1, 58, 1, 1, 23, 24, 25, 1, - 27, 1, 16, 17, 18, 19, 1, 1, - 59, 59, 1, 24, 25, 1, 27, 1, - 16, 17, 18, 19, 1, 1, 1, 1, - 1, 24, 25, 1, 27, 1, 16, 6, - 6, 9, 1, 1, 54, 54, 1, 24, - 25, 1, 10, 1, 0 + 1, 0, 2, 2, 0, 4, 4, 3, + 5, 3, 4, 4, 3, 3, 5, 3, + 7, 7, 6, 8, 6, 2, 10, 11, + 9, 9, 9, 9, 9, 9, 9, 9, + 12, 12, 9, 14, 15, 16, 16, 17, + 18, 19, 20, 13, 21, 15, 16, 16, + 17, 18, 19, 20, 13, 15, 16, 16, + 17, 18, 19, 20, 13, 2, 2, 13, + 13, 13, 22, 22, 13, 18, 19, 13, + 2, 2, 13, 13, 13, 13, 13, 13, + 18, 19, 13, 19, 13, 23, 13, 24, + 25, 13, 13, 17, 18, 19, 13, 25, + 13, 13, 17, 18, 19, 13, 17, 18, + 19, 13, 26, 13, 13, 17, 18, 19, + 13, 27, 27, 13, 18, 19, 13, 18, + 19, 13, 14, 28, 16, 16, 17, 18, + 19, 20, 13, 2, 2, 11, 13, 13, + 22, 22, 13, 18, 19, 13, 12, 12, + 13, 30, 5, 31, 32, 33, 34, 35, + 29, 4, 5, 31, 32, 33, 34, 35, + 29, 5, 31, 32, 33, 34, 35, 29, + 36, 37, 29, 29, 33, 34, 35, 29, + 37, 29, 29, 33, 34, 35, 29, 33, + 34, 35, 29, 35, 29, 38, 29, 40, + 8, 41, 41, 42, 43, 44, 39, 7, + 8, 41, 41, 42, 43, 44, 39, 8, + 41, 41, 42, 43, 44, 39, 45, 46, + 39, 39, 42, 43, 44, 39, 46, 39, + 39, 42, 43, 44, 39, 42, 43, 44, + 39, 44, 39, 47, 39, 0 }; static const char _indic_syllable_machine_trans_targs[] = { - 2, 0, 14, 22, 3, 7, 10, 9, - 11, 12, 20, 9, 10, 11, 12, 20, - 9, 10, 11, 12, 28, 29, 6, 34, - 31, 32, 37, 20, 40, 9, 10, 11, - 12, 13, 1, 5, 15, 17, 18, 20, - 16, 19, 9, 10, 11, 12, 21, 4, - 23, 25, 26, 20, 24, 27, 30, 33, - 35, 36, 38, 39 + 7, 1, 8, 7, 25, 2, 7, 33, + 5, 7, 21, 23, 31, 7, 9, 11, + 0, 15, 13, 14, 18, 10, 12, 7, + 16, 17, 19, 20, 22, 7, 24, 3, + 4, 26, 29, 30, 27, 28, 7, 7, + 32, 6, 34, 37, 38, 35, 36, 7 }; static const char _indic_syllable_machine_trans_actions[] = { + 1, 0, 2, 3, 2, 0, 4, 2, + 0, 7, 2, 2, 2, 8, 2, 0, + 0, 0, 0, 0, 0, 2, 0, 9, + 0, 0, 0, 0, 0, 10, 2, 0, + 0, 0, 0, 0, 0, 0, 11, 12, + 2, 0, 0, 0, 0, 0, 0, 13 +}; + +static const char _indic_syllable_machine_to_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 3, 3, 3, - 3, 0, 0, 0, 0, 0, 0, 3, - 0, 0, 4, 4, 4, 4, 0, 0, - 0, 0, 0, 4, 0, 0, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 }; -static const char _indic_syllable_machine_eof_actions[] = { +static const char _indic_syllable_machine_from_state_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 6, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 4, 4, 4, - 4, 4, 4, 4, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2 + 0, 0, 0, 0, 0, 0, 0 }; -static const int indic_syllable_machine_start = 8; -static const int indic_syllable_machine_first_final = 8; -static const int indic_syllable_machine_error = 0; +static const unsigned char _indic_syllable_machine_eof_trans[] = { + 1, 1, 4, 4, 4, 7, 7, 0, + 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 30, + 30, 30, 30, 30, 30, 30, 30, 40, + 40, 40, 40, 40, 40, 40, 40 +}; + +static const int indic_syllable_machine_start = 7; +static const int indic_syllable_machine_first_final = 7; +static const int indic_syllable_machine_error = -1; -static const int indic_syllable_machine_en_main = 8; +static const int indic_syllable_machine_en_main = 7; #line 38 "hb-ot-shape-complex-indic-machine.rl" -#line 83 "hb-ot-shape-complex-indic-machine.rl" +#line 79 "hb-ot-shape-complex-indic-machine.rl" - -static void -set_cluster (hb_buffer_t *buffer, - unsigned int start, unsigned int end) -{ - unsigned int cluster = buffer->info[start].cluster; - - for (unsigned int i = start + 1; i < end; i++) - cluster = MIN (cluster, buffer->info[i].cluster); - for (unsigned int i = start; i < end; i++) - buffer->info[i].cluster = cluster; -} +#define process_syllable(func) \ + HB_STMT_START { \ + /* fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #func); */ \ + for (unsigned int i = last; i < p+1; i++) \ + info[i].syllable() = syllable_serial; \ + PASTE (initial_reordering_, func) (map, buffer, mask_array, last, p+1); \ + last = p+1; \ + syllable_serial++; \ + if (unlikely (!syllable_serial)) syllable_serial++; \ + } HB_STMT_END static void find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array) { - unsigned int p, pe, eof; + unsigned int p, pe, eof, ts, te, act; int cs; + hb_glyph_info_t *info = buffer->info; -#line 194 "hb-ot-shape-complex-indic-machine.hh.tmp" +#line 170 "hb-ot-shape-complex-indic-machine.hh.tmp" { cs = indic_syllable_machine_start; + ts = 0; + te = 0; + act = 0; } -#line 106 "hb-ot-shape-complex-indic-machine.rl" +#line 101 "hb-ot-shape-complex-indic-machine.rl" p = 0; pe = eof = buffer->len; unsigned int last = 0; + uint8_t syllable_serial = 1; -#line 207 "hb-ot-shape-complex-indic-machine.hh.tmp" +#line 187 "hb-ot-shape-complex-indic-machine.hh.tmp" { int _slen; int _trans; @@ -211,17 +191,24 @@ find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_arr const char *_inds; if ( p == pe ) goto _test_eof; - if ( cs == 0 ) - goto _out; _resume: + switch ( _indic_syllable_machine_from_state_actions[cs] ) { + case 6: +#line 1 "hb-ot-shape-complex-indic-machine.rl" + {ts = p;} + break; +#line 201 "hb-ot-shape-complex-indic-machine.hh.tmp" + } + _keys = _indic_syllable_machine_trans_keys + (cs<<1); _inds = _indic_syllable_machine_indicies + _indic_syllable_machine_index_offsets[cs]; _slen = _indic_syllable_machine_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=( buffer->info[p].indic_category()) && - ( buffer->info[p].indic_category()) <= _keys[1] ? - ( buffer->info[p].indic_category()) - _keys[0] : _slen ]; + _trans = _inds[ _slen > 0 && _keys[0] <=( info[p].indic_category()) && + ( info[p].indic_category()) <= _keys[1] ? + ( info[p].indic_category()) - _keys[0] : _slen ]; +_eof_trans: cs = _indic_syllable_machine_trans_targs[_trans]; if ( _indic_syllable_machine_trans_actions[_trans] == 0 ) @@ -229,73 +216,75 @@ _resume: switch ( _indic_syllable_machine_trans_actions[_trans] ) { case 2: -#line 62 "hb-ot-shape-complex-indic-machine.rl" - { found_consonant_syllable (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } +#line 1 "hb-ot-shape-complex-indic-machine.rl" + {te = p+1;} break; - case 3: -#line 63 "hb-ot-shape-complex-indic-machine.rl" - { found_vowel_syllable (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } + case 9: +#line 72 "hb-ot-shape-complex-indic-machine.rl" + {te = p+1;{ process_syllable (consonant_syllable); }} break; - case 4: -#line 64 "hb-ot-shape-complex-indic-machine.rl" - { found_standalone_cluster (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } + case 11: +#line 73 "hb-ot-shape-complex-indic-machine.rl" + {te = p+1;{ process_syllable (vowel_syllable); }} + break; + case 13: +#line 74 "hb-ot-shape-complex-indic-machine.rl" + {te = p+1;{ process_syllable (standalone_cluster); }} + break; + case 7: +#line 75 "hb-ot-shape-complex-indic-machine.rl" + {te = p+1;{ process_syllable (non_indic); }} + break; + case 8: +#line 72 "hb-ot-shape-complex-indic-machine.rl" + {te = p;p--;{ process_syllable (consonant_syllable); }} + break; + case 10: +#line 73 "hb-ot-shape-complex-indic-machine.rl" + {te = p;p--;{ process_syllable (vowel_syllable); }} + break; + case 12: +#line 74 "hb-ot-shape-complex-indic-machine.rl" + {te = p;p--;{ process_syllable (standalone_cluster); }} break; case 1: -#line 65 "hb-ot-shape-complex-indic-machine.rl" - { found_non_indic (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } +#line 72 "hb-ot-shape-complex-indic-machine.rl" + {{p = ((te))-1;}{ process_syllable (consonant_syllable); }} + break; + case 3: +#line 73 "hb-ot-shape-complex-indic-machine.rl" + {{p = ((te))-1;}{ process_syllable (vowel_syllable); }} + break; + case 4: +#line 74 "hb-ot-shape-complex-indic-machine.rl" + {{p = ((te))-1;}{ process_syllable (standalone_cluster); }} break; -#line 256 "hb-ot-shape-complex-indic-machine.hh.tmp" +#line 263 "hb-ot-shape-complex-indic-machine.hh.tmp" } _again: - if ( cs == 0 ) - goto _out; + switch ( _indic_syllable_machine_to_state_actions[cs] ) { + case 5: +#line 1 "hb-ot-shape-complex-indic-machine.rl" + {ts = 0;} + break; +#line 272 "hb-ot-shape-complex-indic-machine.hh.tmp" + } + if ( ++p != pe ) goto _resume; _test_eof: {} if ( p == eof ) { - switch ( _indic_syllable_machine_eof_actions[cs] ) { - case 2: -#line 62 "hb-ot-shape-complex-indic-machine.rl" - { found_consonant_syllable (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } - break; - case 3: -#line 63 "hb-ot-shape-complex-indic-machine.rl" - { found_vowel_syllable (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } - break; - case 4: -#line 64 "hb-ot-shape-complex-indic-machine.rl" - { found_standalone_cluster (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } - break; - case 1: -#line 65 "hb-ot-shape-complex-indic-machine.rl" - { found_non_indic (map, buffer, mask_array, last, p); } -#line 67 "hb-ot-shape-complex-indic-machine.rl" - { set_cluster (buffer, p, last); last = p; } - break; -#line 292 "hb-ot-shape-complex-indic-machine.hh.tmp" + if ( _indic_syllable_machine_eof_trans[cs] > 0 ) { + _trans = _indic_syllable_machine_eof_trans[cs] - 1; + goto _eof_trans; } } - _out: {} } -#line 114 "hb-ot-shape-complex-indic-machine.rl" +#line 110 "hb-ot-shape-complex-indic-machine.rl" } diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh new file mode 100644 index 0000000..64af0da --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh @@ -0,0 +1,270 @@ +/* + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH +#define HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH + +#include "hb-private.hh" + + +#include "hb-ot-shape-complex-private.hh" + + +/* buffer var allocations */ +#define indic_category() complex_var_persistent_u8_0() /* indic_category_t */ +#define indic_position() complex_var_persistent_u8_1() /* indic_matra_category_t */ + +#define INDIC_TABLE_ELEMENT_TYPE uint8_t + +/* Cateories used in the OpenType spec: + * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx + */ +/* Note: This enum is duplicated in the -machine.rl source file. + * Not sure how to avoid duplication. */ +enum indic_category_t { + OT_X = 0, + OT_C, + OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */ + OT_V, + OT_N, + OT_H, + OT_ZWNJ, + OT_ZWJ, + OT_M, + OT_SM, + OT_VD, + OT_A, + OT_NBSP, + OT_DOTTEDCIRCLE /* Not in the spec, but special in Uniscribe. /Very very/ special! */ +}; + +/* Visual positions in a syllable from left to right. */ +enum indic_position_t { + POS_RA_TO_BECOME_REPH, + POS_PRE_M, + POS_PRE_C, + POS_BASE_C, + POS_ABOVE_C, + POS_BELOW_C, + POS_ABOVE_M, + POS_BELOW_M, + POS_POST_C, + POS_POST_M, + POS_SMVD +}; + +/* Categories used in IndicSyllabicCategory.txt from UCD. */ +enum indic_syllabic_category_t { + INDIC_SYLLABIC_CATEGORY_OTHER = OT_X, + + INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_X, + INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM, + INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP, + INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_C, + INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_C, + INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X, + INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N, + INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_X, + INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X, + INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_X, + INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H, + INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM, + INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V, + INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M, + INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V +}; + +/* Categories used in IndicSMatraCategory.txt from UCD */ +enum indic_matra_category_t { + INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_BASE_C, + + INDIC_MATRA_CATEGORY_LEFT = POS_PRE_M, + INDIC_MATRA_CATEGORY_TOP = POS_ABOVE_M, + INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW_M, + INDIC_MATRA_CATEGORY_RIGHT = POS_POST_M, + + /* We don't really care much about these since we decompose them + * in the generic pre-shaping layer. They will only be used if + * the font does not cover the decomposition. In which case, we + * define these as aliases to the place we want the split-matra + * glyph to show up. Quite arbitrary. + * + * TODO: There are some split matras without Unicode decompositions. + * We have to figure out what to do with them. + */ + INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = POS_POST_M, + INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = POS_PRE_M, + INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = POS_BELOW_M, + INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = POS_POST_M, + INDIC_MATRA_CATEGORY_TOP_AND_LEFT = POS_PRE_M, + INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = POS_PRE_M, + INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = POS_POST_M, + + INDIC_MATRA_CATEGORY_INVISIBLE = INDIC_MATRA_CATEGORY_NOT_APPLICABLE, + INDIC_MATRA_CATEGORY_OVERSTRUCK = INDIC_MATRA_CATEGORY_NOT_APPLICABLE, + INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = INDIC_MATRA_CATEGORY_NOT_APPLICABLE +}; + +/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation + * because gcc fails to optimize the latter and fills the table in at runtime. */ +#define INDIC_COMBINE_CATEGORIES(S,M) \ + (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \ + ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \ + ((M << 4) | S)) + + +#include "hb-ot-shape-complex-indic-table.hh" + +/* XXX + * This is a hack for now. We should: + * 1. Move this data into the main Indic table, + * and/or + * 2. Probe font lookups to determine consonant positions. + */ +static const struct consonant_position_t { + hb_codepoint_t u; + indic_position_t position; +} consonant_positions[] = { + {0x0930, POS_BELOW_C}, + {0x09AC, POS_BELOW_C}, + {0x09AF, POS_POST_C}, + {0x09B0, POS_BELOW_C}, + {0x09F0, POS_BELOW_C}, + {0x0A2F, POS_POST_C}, + {0x0A30, POS_BELOW_C}, + {0x0A35, POS_BELOW_C}, + {0x0A39, POS_BELOW_C}, + {0x0AB0, POS_BELOW_C}, + {0x0B24, POS_BELOW_C}, + {0x0B28, POS_BELOW_C}, + {0x0B2C, POS_BELOW_C}, + {0x0B2D, POS_BELOW_C}, + {0x0B2E, POS_BELOW_C}, + {0x0B2F, POS_POST_C}, + {0x0B30, POS_BELOW_C}, + {0x0B32, POS_BELOW_C}, + {0x0B33, POS_BELOW_C}, + {0x0B5F, POS_POST_C}, + {0x0B71, POS_BELOW_C}, + {0x0C15, POS_BELOW_C}, + {0x0C16, POS_BELOW_C}, + {0x0C17, POS_BELOW_C}, + {0x0C18, POS_BELOW_C}, + {0x0C19, POS_BELOW_C}, + {0x0C1A, POS_BELOW_C}, + {0x0C1B, POS_BELOW_C}, + {0x0C1C, POS_BELOW_C}, + {0x0C1D, POS_BELOW_C}, + {0x0C1E, POS_BELOW_C}, + {0x0C1F, POS_BELOW_C}, + {0x0C20, POS_BELOW_C}, + {0x0C21, POS_BELOW_C}, + {0x0C22, POS_BELOW_C}, + {0x0C23, POS_BELOW_C}, + {0x0C24, POS_BELOW_C}, + {0x0C25, POS_BELOW_C}, + {0x0C26, POS_BELOW_C}, + {0x0C27, POS_BELOW_C}, + {0x0C28, POS_BELOW_C}, + {0x0C2A, POS_BELOW_C}, + {0x0C2B, POS_BELOW_C}, + {0x0C2C, POS_BELOW_C}, + {0x0C2D, POS_BELOW_C}, + {0x0C2E, POS_BELOW_C}, + {0x0C2F, POS_BELOW_C}, + {0x0C30, POS_BELOW_C}, + {0x0C32, POS_BELOW_C}, + {0x0C33, POS_BELOW_C}, + {0x0C35, POS_BELOW_C}, + {0x0C36, POS_BELOW_C}, + {0x0C37, POS_BELOW_C}, + {0x0C38, POS_BELOW_C}, + {0x0C39, POS_BELOW_C}, + {0x0C95, POS_BELOW_C}, + {0x0C96, POS_BELOW_C}, + {0x0C97, POS_BELOW_C}, + {0x0C98, POS_BELOW_C}, + {0x0C99, POS_BELOW_C}, + {0x0C9A, POS_BELOW_C}, + {0x0C9B, POS_BELOW_C}, + {0x0C9C, POS_BELOW_C}, + {0x0C9D, POS_BELOW_C}, + {0x0C9E, POS_BELOW_C}, + {0x0C9F, POS_BELOW_C}, + {0x0CA0, POS_BELOW_C}, + {0x0CA1, POS_BELOW_C}, + {0x0CA2, POS_BELOW_C}, + {0x0CA3, POS_BELOW_C}, + {0x0CA4, POS_BELOW_C}, + {0x0CA5, POS_BELOW_C}, + {0x0CA6, POS_BELOW_C}, + {0x0CA7, POS_BELOW_C}, + {0x0CA8, POS_BELOW_C}, + {0x0CAA, POS_BELOW_C}, + {0x0CAB, POS_BELOW_C}, + {0x0CAC, POS_BELOW_C}, + {0x0CAD, POS_BELOW_C}, + {0x0CAE, POS_BELOW_C}, + {0x0CAF, POS_BELOW_C}, + {0x0CB0, POS_BELOW_C}, + {0x0CB2, POS_BELOW_C}, + {0x0CB3, POS_BELOW_C}, + {0x0CB5, POS_BELOW_C}, + {0x0CB6, POS_BELOW_C}, + {0x0CB7, POS_BELOW_C}, + {0x0CB8, POS_BELOW_C}, + {0x0CB9, POS_BELOW_C}, + {0x0CDE, POS_BELOW_C}, + {0x0D2F, POS_POST_C}, + {0x0D30, POS_POST_C}, + {0x0D32, POS_BELOW_C}, + {0x0D35, POS_POST_C}, +}; + +/* XXX + * This is a hack for now. We should move this data into the main Indic table. + * Or completely remove it and just check in the tables. + */ +static const hb_codepoint_t ra_chars[] = { + 0x0930, /* Devanagari */ + 0x09B0, /* Bengali */ + 0x09F0, /* Bengali */ + 0x0A30, /* Gurmukhi */ /* No Reph */ + 0x0AB0, /* Gujarati */ + 0x0B30, /* Oriya */ + 0x0BB0, /* Tamil */ /* No Reph */ + 0x0C30, /* Telugu */ /* No Reph */ + 0x0CB0, /* Kannada */ + 0x0D30, /* Malayalam */ /* No Reph */ +}; + + +#endif /* HB_OT_SHAPE_COMPLEX_INDIC_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.hh index 5077e8a..5b4b344 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-table.hh @@ -1,35 +1,3 @@ -/* - * Copyright © 2011 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH -#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH - -#include "hb-private.hh" - - /* == Start of generated table == */ /* * The following table is generated by running: @@ -38,57 +6,60 @@ * * on files with these headers: * - * # IndicSyllabicCategory-6.0.0.txt - * # Date: 2010-05-25, 11:45:00 PDT [KW] - * # IndicMatraCategory-6.0.0.txt - * # Date: 2010-07-14, 15:03:00 PDT [KW] - * # Blocks-6.0.0.txt - * # Date: 2010-06-04, 11:12:00 PDT [KW] + * # IndicSyllabicCategory-6.1.0.txt + * # Date: 2011-08-31, 23:54:00 GMT [KW] + * # IndicMatraCategory-6.1.0.txt + * # Date: 2011-08-31, 23:50:00 GMT [KW] + * # Blocks-6.1.0.txt + * # Date: 2011-06-14, 18:26:00 GMT [KW, LI] */ +#ifndef HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH +#define HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH -#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 9 chars; Avagraha */ -#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 31 chars; Bindu */ -#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 116 chars; Consonant */ + +#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 11 chars; Avagraha */ +#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 34 chars; Bindu */ +#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 123 chars; Consonant */ #define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 2 chars; Consonant_Dead */ -#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 16 chars; Consonant_Final */ +#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 17 chars; Consonant_Final */ #define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 1 chars; Consonant_Head_Letter */ #define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 12 chars; Consonant_Medial */ #define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 4 chars; Consonant_Placeholder */ #define ISC_CR INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA /* 5 chars; Consonant_Repha */ -#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 9 chars; Consonant_Subjoined */ +#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 10 chars; Consonant_Subjoined */ #define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */ -#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 11 chars; Nukta */ +#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 12 chars; Nukta */ #define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */ #define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 1 chars; Register_Shifter */ #define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 3 chars; Tone_Letter */ #define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 16 chars; Tone_Mark */ -#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 29 chars; Virama */ -#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 19 chars; Visarga */ +#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 34 chars; Virama */ +#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 25 chars; Visarga */ #define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 5 chars; Vowel */ -#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 161 chars; Vowel_Dependent */ -#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 53 chars; Vowel_Independent */ +#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 165 chars; Vowel_Dependent */ +#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 59 chars; Vowel_Independent */ -#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 60 chars; Bottom */ +#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 65 chars; Bottom */ #define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */ -#define IMC_I INDIC_MATRA_CATEGORY_INVISIBLE /* 4 chars; Invisible */ -#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 25 chars; Left */ +#define IMC_I INDIC_MATRA_CATEGORY_INVISIBLE /* 6 chars; Invisible */ +#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 30 chars; Left */ #define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 8 chars; Left_And_Right */ #define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */ #define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 2 chars; Overstruck */ -#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 70 chars; Right */ -#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 74 chars; Top */ -#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 5 chars; Top_And_Bottom */ +#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 75 chars; Right */ +#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 83 chars; Top */ +#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 6 chars; Top_And_Bottom */ #define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */ #define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 4 chars; Top_And_Left */ #define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 2 chars; Top_And_Left_And_Right */ -#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 7 chars; Top_And_Right */ +#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 8 chars; Top_And_Right */ #define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 5 chars; Visual_Order_Left */ #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M) -static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = { +static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { #define indic_offset_0x0900 0 @@ -534,9 +505,9 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = { /* 1B90 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), /* 1B98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), /* 1BA0 */ _(C,x), _(CS,x), _(CS,x), _(CS,x), _(M,T), _(M,B), _(M,L), _(M,R), - /* 1BA8 */ _(M,T), _(M,T), _(V,R), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), + /* 1BA8 */ _(M,T), _(M,T), _(V,R), _(V,x), _(CS,x), _(CS,x), _(C,x), _(C,x), /* 1BB0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), - /* 1BB8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1BB8 */ _(x,x), _(x,x), _(A,x), _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), /* Batak (1BC0..1BFF) */ @@ -562,7 +533,19 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = { /* 1C40 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), /* 1C48 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), -#define indic_offset_0xa800 2976 +#define indic_offset_0x1cd0 2976 + + + /* Vedic Extensions (1CD0..1CFF) */ + + /* 1CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1CE0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1CE8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1CF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0xa800 3024 /* Syloti Nagri (A800..A82F) */ @@ -696,21 +679,28 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = { /* AAD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), /* AAD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), -#define indic_offset_0xabc0 3712 + /* Meetei Mayek Extensions (AAE0..AAFF) */ + + /* AAE0 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* AAE8 */ _(C,x), _(C,x), _(C,x), _(M,L), _(M,B), _(M,T), _(M,L), _(M,R), + /* AAF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Vs,x), _(V,I), _(x,x), + /* AAF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0xabc0 3792 /* Meetei Mayek (ABC0..ABFF) */ /* ABC0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* ABC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), - /* ABD0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* ABC8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(VI,x), _(VI,x), + /* ABD0 */ _(C,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), /* ABD8 */ _(C,x), _(C,x), _(C,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), _(CF,x), /* ABE0 */ _(CF,x), _(CF,x), _(CF,x), _(M,R), _(M,R), _(M,T), _(M,R), _(M,R), /* ABE8 */ _(M,B), _(M,R), _(M,R), _(x,x), _(TM,x), _(V,B), _(x,x), _(x,x), /* ABF0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), /* ABF8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), -#define indic_offset_0x10a00 3776 +#define indic_offset_0x10a00 3856 /* Kharoshthi (10A00..10A5F) */ @@ -728,7 +718,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = { /* 10A50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), /* 10A58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), -#define indic_offset_0x11000 3872 +#define indic_offset_0x11000 3952 /* Brahmi (11000..1107F) */ @@ -763,9 +753,59 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[4080] = { /* 110C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), /* 110C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), -#define indic_offset_total 4080 +#define indic_offset_0x11100 4160 + + + /* Chakma (11100..1114F) */ + + /* 11100 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), + /* 11108 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11110 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11118 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11120 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(M,T), + /* 11128 */ _(M,T), _(M,T), _(M,B), _(M,B), _(M,L), _(M,T), _(M,TB), _(M,TB), + /* 11130 */ _(M,T), _(M,B), _(M,B), _(V,I), _(V,T), _(x,x), _(x,x), _(x,x), + /* 11138 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11140 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 11148 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_0x11180 4240 + + + /* Sharada (11180..111DF) */ + + /* 11180 */ _(Bi,x), _(Bi,x), _(Vs,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 11188 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 11190 */ _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11198 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 111A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 111A8 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 111B0 */ _(C,x), _(C,x), _(C,x), _(M,R), _(M,L), _(M,R), _(M,B), _(M,B), + /* 111B8 */ _(M,B), _(M,B), _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,TR), + /* 111C0 */ _(V,R), _(A,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 111C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 111D0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 111D8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), -}; +#define indic_offset_0x11680 4336 + + + /* Takri (11680..116CF) */ + + /* 11680 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), + /* 11688 */ _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11690 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 11698 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 116A0 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), + /* 116A8 */ _(C,x), _(C,x), _(C,x), _(Bi,x), _(Vs,x), _(M,T), _(M,L), _(M,R), + /* 116B0 */ _(M,B), _(M,B), _(M,T), _(M,T), _(M,T), _(M,T), _(V,T), _(N,x), + /* 116B8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 116C0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 116C8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + +#define indic_offset_total 4416 + +}; /* Table occupancy: 60% */ static INDIC_TABLE_ELEMENT_TYPE get_indic_categories (hb_codepoint_t u) @@ -774,10 +814,14 @@ get_indic_categories (hb_codepoint_t u) if (0x1700 <= u && u <= 0x1800) return indic_table[u - 0x1700 + indic_offset_0x1700]; if (0x1900 <= u && u <= 0x1AB0) return indic_table[u - 0x1900 + indic_offset_0x1900]; if (0x1B00 <= u && u <= 0x1C50) return indic_table[u - 0x1B00 + indic_offset_0x1b00]; - if (0xA800 <= u && u <= 0xAAE0) return indic_table[u - 0xA800 + indic_offset_0xa800]; + if (0x1CD0 <= u && u <= 0x1D00) return indic_table[u - 0x1CD0 + indic_offset_0x1cd0]; + if (0xA800 <= u && u <= 0xAB00) return indic_table[u - 0xA800 + indic_offset_0xa800]; if (0xABC0 <= u && u <= 0xAC00) return indic_table[u - 0xABC0 + indic_offset_0xabc0]; if (0x10A00 <= u && u <= 0x10A60) return indic_table[u - 0x10A00 + indic_offset_0x10a00]; if (0x11000 <= u && u <= 0x110D0) return indic_table[u - 0x11000 + indic_offset_0x11000]; + if (0x11100 <= u && u <= 0x11150) return indic_table[u - 0x11100 + indic_offset_0x11100]; + if (0x11180 <= u && u <= 0x111E0) return indic_table[u - 0x11180 + indic_offset_0x11180]; + if (0x11680 <= u && u <= 0x116D0) return indic_table[u - 0x11680 + indic_offset_0x11680]; if (unlikely (u == 0x00A0)) return _(CP,x); if (unlikely (u == 0x25CC)) return _(CP,x); return _(x,x); @@ -823,8 +867,6 @@ get_indic_categories (hb_codepoint_t u) #undef IMC_TR #undef IMC_VOL +#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */ /* == End of generated table == */ - - -#endif /* HB_OT_SHAPE_COMPLEX_INDIC_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc index 9f50ef2..0c5479e 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,231 +24,19 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-complex-indic-private.hh" +#include "hb-ot-shape-private.hh" +static const struct indic_options_t +{ + indic_options_t (void) + { + char *c = getenv ("HB_OT_INDIC_OPTIONS"); + uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible"); + } - -/* buffer var allocations */ -#define indic_category() complex_var_persistent_u8_0() /* indic_category_t */ -#define indic_position() complex_var_persistent_u8_1() /* indic_matra_category_t */ - -#define INDIC_TABLE_ELEMENT_TYPE uint8_t - -/* Cateories used in the OpenType spec: - * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx - */ -/* Note: This enum is duplicated in the -machine.rl source file. - * Not sure how to avoid duplication. */ -enum indic_category_t { - OT_X = 0, - OT_C, - OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */ - OT_V, - OT_N, - OT_H, - OT_ZWNJ, - OT_ZWJ, - OT_M, - OT_SM, - OT_VD, - OT_A, - OT_NBSP -}; - -/* Visual positions in a syllable from left to right. */ -enum indic_position_t { - POS_PRE, - POS_BASE, - POS_ABOVE, - POS_BELOW, - POS_POST -}; - -/* Categories used in IndicSyllabicCategory.txt from UCD */ -/* The assignments are guesswork */ -enum indic_syllabic_category_t { - INDIC_SYLLABIC_CATEGORY_OTHER = OT_X, - - INDIC_SYLLABIC_CATEGORY_AVAGRAHA = OT_X, - INDIC_SYLLABIC_CATEGORY_BINDU = OT_SM, - INDIC_SYLLABIC_CATEGORY_CONSONANT = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP, - INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_C, - INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_C, - INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER = OT_X, - INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N, - INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_X, - INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X, - INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_X, - INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H, - INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM, - INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V, - INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT = OT_M, - INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT = OT_V -}; - -/* Categories used in IndicSMatraCategory.txt from UCD */ -enum indic_matra_category_t { - INDIC_MATRA_CATEGORY_NOT_APPLICABLE = POS_BASE, - - INDIC_MATRA_CATEGORY_LEFT = POS_PRE, - INDIC_MATRA_CATEGORY_TOP = POS_ABOVE, - INDIC_MATRA_CATEGORY_BOTTOM = POS_BELOW, - INDIC_MATRA_CATEGORY_RIGHT = POS_POST, - - /* We don't really care much about these since we decompose them - * in the generic pre-shaping layer. They will only be used if - * the font does not cover the decomposition. In which case, we - * define these as aliases to the place we want the split-matra - * glyph to show up. Quite arbitrary. */ - INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_BOTTOM, - INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_LEFT, - INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM, - INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_BOTTOM, - INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_LEFT, - INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_LEFT, - INDIC_MATRA_CATEGORY_TOP_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, - - INDIC_MATRA_CATEGORY_INVISIBLE = INDIC_MATRA_CATEGORY_NOT_APPLICABLE, - INDIC_MATRA_CATEGORY_OVERSTRUCK = INDIC_MATRA_CATEGORY_NOT_APPLICABLE, - INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = INDIC_MATRA_CATEGORY_NOT_APPLICABLE -}; - -/* Note: We use ASSERT_STATIC_EXPR_ZERO() instead of ASSERT_STATIC_EXPR() and the comma operation - * because gcc fails to optimize the latter and fills the table in at runtime. */ -#define INDIC_COMBINE_CATEGORIES(S,M) \ - (ASSERT_STATIC_EXPR_ZERO (M == INDIC_MATRA_CATEGORY_NOT_APPLICABLE || (S == INDIC_SYLLABIC_CATEGORY_VIRAMA || S == INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT)) + \ - ASSERT_STATIC_EXPR_ZERO (S < 16 && M < 16) + \ - ((M << 4) | S)) - -#include "hb-ot-shape-complex-indic-table.hh" - -/* XXX - * This is a hack for now. We should: - * 1. Move this data into the main Indic table, - * and/or - * 2. Probe font lookups to determine consonant positions. - */ -static const struct consonant_position_t { - hb_codepoint_t u; - indic_position_t position; -} consonant_positions[] = { - {0x0930, POS_BELOW}, - {0x09AC, POS_BELOW}, - {0x09AF, POS_POST}, - {0x09B0, POS_BELOW}, - {0x09F0, POS_BELOW}, - {0x0A2F, POS_POST}, - {0x0A30, POS_BELOW}, - {0x0A35, POS_BELOW}, - {0x0A39, POS_BELOW}, - {0x0AB0, POS_BELOW}, - {0x0B24, POS_BELOW}, - {0x0B28, POS_BELOW}, - {0x0B2C, POS_BELOW}, - {0x0B2D, POS_BELOW}, - {0x0B2E, POS_BELOW}, - {0x0B2F, POS_POST}, - {0x0B30, POS_BELOW}, - {0x0B32, POS_BELOW}, - {0x0B33, POS_BELOW}, - {0x0B5F, POS_POST}, - {0x0B71, POS_BELOW}, - {0x0C15, POS_BELOW}, - {0x0C16, POS_BELOW}, - {0x0C17, POS_BELOW}, - {0x0C18, POS_BELOW}, - {0x0C19, POS_BELOW}, - {0x0C1A, POS_BELOW}, - {0x0C1B, POS_BELOW}, - {0x0C1C, POS_BELOW}, - {0x0C1D, POS_BELOW}, - {0x0C1E, POS_BELOW}, - {0x0C1F, POS_BELOW}, - {0x0C20, POS_BELOW}, - {0x0C21, POS_BELOW}, - {0x0C22, POS_BELOW}, - {0x0C23, POS_BELOW}, - {0x0C24, POS_BELOW}, - {0x0C25, POS_BELOW}, - {0x0C26, POS_BELOW}, - {0x0C27, POS_BELOW}, - {0x0C28, POS_BELOW}, - {0x0C2A, POS_BELOW}, - {0x0C2B, POS_BELOW}, - {0x0C2C, POS_BELOW}, - {0x0C2D, POS_BELOW}, - {0x0C2E, POS_BELOW}, - {0x0C2F, POS_BELOW}, - {0x0C30, POS_BELOW}, - {0x0C32, POS_BELOW}, - {0x0C33, POS_BELOW}, - {0x0C35, POS_BELOW}, - {0x0C36, POS_BELOW}, - {0x0C37, POS_BELOW}, - {0x0C38, POS_BELOW}, - {0x0C39, POS_BELOW}, - {0x0C95, POS_BELOW}, - {0x0C96, POS_BELOW}, - {0x0C97, POS_BELOW}, - {0x0C98, POS_BELOW}, - {0x0C99, POS_BELOW}, - {0x0C9A, POS_BELOW}, - {0x0C9B, POS_BELOW}, - {0x0C9C, POS_BELOW}, - {0x0C9D, POS_BELOW}, - {0x0C9E, POS_BELOW}, - {0x0C9F, POS_BELOW}, - {0x0CA0, POS_BELOW}, - {0x0CA1, POS_BELOW}, - {0x0CA2, POS_BELOW}, - {0x0CA3, POS_BELOW}, - {0x0CA4, POS_BELOW}, - {0x0CA5, POS_BELOW}, - {0x0CA6, POS_BELOW}, - {0x0CA7, POS_BELOW}, - {0x0CA8, POS_BELOW}, - {0x0CAA, POS_BELOW}, - {0x0CAB, POS_BELOW}, - {0x0CAC, POS_BELOW}, - {0x0CAD, POS_BELOW}, - {0x0CAE, POS_BELOW}, - {0x0CAF, POS_BELOW}, - {0x0CB0, POS_BELOW}, - {0x0CB2, POS_BELOW}, - {0x0CB3, POS_BELOW}, - {0x0CB5, POS_BELOW}, - {0x0CB6, POS_BELOW}, - {0x0CB7, POS_BELOW}, - {0x0CB8, POS_BELOW}, - {0x0CB9, POS_BELOW}, - {0x0CDE, POS_BELOW}, - {0x0D2F, POS_POST}, - {0x0D30, POS_POST}, - {0x0D32, POS_BELOW}, - {0x0D35, POS_POST}, -}; - -/* XXX - * This is a hack for now. We should move this data into the main Indic table. - */ -static const hb_codepoint_t ra_chars[] = { - 0x0930, /* Devanagari */ - 0x09B0, /* Bengali */ - 0x09F0, /* Bengali */ -//0x09F1, /* Bengali */ -//0x0A30, /* Gurmukhi */ - 0x0AB0, /* Gujarati */ - 0x0B30, /* Oriya */ -//0x0BB0, /* Tamil */ -//0x0C30, /* Telugu */ - 0x0CB0, /* Kannada */ -//0x0D30, /* Malayalam */ -}; + bool uniscribe_bug_compatible; +} options; static int compare_codepoint (const void *pa, const void *pb) @@ -269,7 +57,7 @@ consonant_position (hb_codepoint_t u) sizeof (consonant_positions[0]), compare_codepoint); - return record ? record->position : POS_BASE; + return record ? record->position : POS_BASE_C; } static bool @@ -290,24 +78,32 @@ is_joiner (const hb_glyph_info_t &info) static bool is_consonant (const hb_glyph_info_t &info) { - return !!(FLAG (info.indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra))); + /* Note: + * + * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels + * cannot happen in a consonant syllable. The plus side however is, we can call the + * consonant syllable logic from the vowel syllable function and get it all right! */ + return !!(FLAG (info.indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE))); } -static const struct { +struct feature_list_t { hb_tag_t tag; hb_bool_t is_global; -} indic_basic_features[] = +}; + +static const feature_list_t +indic_basic_features[] = { {HB_TAG('n','u','k','t'), true}, {HB_TAG('a','k','h','n'), false}, {HB_TAG('r','p','h','f'), false}, - {HB_TAG('r','k','r','f'), false}, + {HB_TAG('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('v','a','t','u'), true}, {HB_TAG('p','s','t','f'), false}, {HB_TAG('c','j','c','t'), false}, + {HB_TAG('v','a','t','u'), true}, }; /* Same order as the indic_basic_features array */ @@ -315,26 +111,33 @@ enum { _NUKT, AKHN, RPHF, - RKRF, + _RKRF, PREF, BLWF, HALF, - _VATU, PSTF, - CJCT + CJCT, + VATU }; -static const hb_tag_t indic_other_features[] = +static const feature_list_t +indic_other_features[] = { - HB_TAG('p','r','e','s'), - HB_TAG('a','b','v','s'), - HB_TAG('b','l','w','s'), - HB_TAG('p','s','t','s'), - HB_TAG('h','a','l','n'), - - HB_TAG('d','i','s','t'), - HB_TAG('a','b','v','m'), - HB_TAG('b','l','w','m'), + {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('d','i','s','t'), true}, + {HB_TAG('a','b','v','m'), true}, + {HB_TAG('b','l','w','m'), true}, +}; + +/* Same order as the indic_other_features array */ +enum { + INIT }; @@ -350,7 +153,8 @@ final_reordering (const hb_ot_map_t *map, void *user_data HB_UNUSED); void -_hb_ot_shape_complex_collect_features_indic (hb_ot_map_builder_t *map, const hb_segment_properties_t *props) +_hb_ot_shape_complex_collect_features_indic (hb_ot_map_builder_t *map, + const hb_segment_properties_t *props HB_UNUSED) { map->add_bool_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if @@ -359,26 +163,32 @@ _hb_ot_shape_complex_collect_features_indic (hb_ot_map_builder_t *map, const hb_ map->add_gsub_pause (initial_reordering, NULL); - for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) + for (unsigned int i = 0; i < ARRAY_LENGTH (indic_basic_features); i++) { map->add_bool_feature (indic_basic_features[i].tag, indic_basic_features[i].is_global); + map->add_gsub_pause (NULL, NULL); + } map->add_gsub_pause (final_reordering, NULL); - for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++) - map->add_bool_feature (indic_other_features[i], true); + for (unsigned int i = 0; i < ARRAY_LENGTH (indic_other_features); i++) { + map->add_bool_feature (indic_other_features[i].tag, indic_other_features[i].is_global); + map->add_gsub_pause (NULL, NULL); + } } -bool -_hb_ot_shape_complex_prefer_decomposed_indic (void) +hb_ot_shape_normalization_mode_t +_hb_ot_shape_complex_normalization_preference_indic (void) { /* We want split matras decomposed by the common shaping logic. */ - return TRUE; + return HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED; } void -_hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map, hb_buffer_t *buffer) +_hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map HB_UNUSED, + hb_buffer_t *buffer, + hb_font_t *font HB_UNUSED) { HB_BUFFER_ALLOCATE_VAR (buffer, indic_category); HB_BUFFER_ALLOCATE_VAR (buffer, indic_position); @@ -389,19 +199,36 @@ _hb_ot_shape_complex_setup_masks_indic (hb_ot_map_t *map, hb_buffer_t *buffer) unsigned int count = buffer->len; for (unsigned int i = 0; i < count; i++) { - unsigned int type = get_indic_categories (buffer->info[i].codepoint); - - buffer->info[i].indic_category() = type & 0x0F; - buffer->info[i].indic_position() = type >> 4; - - if (buffer->info[i].indic_category() == OT_C) { - buffer->info[i].indic_position() = consonant_position (buffer->info[i].codepoint); - if (is_ra (buffer->info[i].codepoint)) - buffer->info[i].indic_category() = OT_Ra; - } else if (buffer->info[i].codepoint == 0x200C) - buffer->info[i].indic_category() = OT_ZWNJ; - else if (buffer->info[i].codepoint == 0x200D) - buffer->info[i].indic_category() = OT_ZWJ; + hb_glyph_info_t &info = buffer->info[i]; + unsigned int type = get_indic_categories (info.codepoint); + + info.indic_category() = type & 0x0F; + info.indic_position() = type >> 4; + + /* The spec says U+0952 is OT_A. However, testing shows that Uniscribe + * treats U+0951..U+0952 all as OT_VD. + * TESTS: + * U+092E,U+0947,U+0952 + * U+092E,U+0952,U+0947 + * U+092E,U+0947,U+0951 + * U+092E,U+0951,U+0947 + * */ + if (unlikely (hb_in_range<hb_codepoint_t> (info.codepoint, 0x0951, 0x0954))) + info.indic_category() = OT_VD; + + if (info.indic_category() == OT_C) { + info.indic_position() = consonant_position (info.codepoint); + if (is_ra (info.codepoint)) + info.indic_category() = OT_Ra; + } else if (info.indic_category() == OT_SM || + info.indic_category() == OT_VD) { + info.indic_position() = POS_SMVD; + } else if (unlikely (info.codepoint == 0x200C)) + info.indic_category() = OT_ZWNJ; + else if (unlikely (info.codepoint == 0x200D)) + info.indic_category() = OT_ZWJ; + else if (unlikely (info.codepoint == 0x25CC)) + info.indic_category() = OT_DOTTEDCIRCLE; } } @@ -414,15 +241,15 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) return a < b ? -1 : a == b ? 0 : +1; } +/* Rules from: + * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ + static void -found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, - unsigned int start, unsigned int end) +initial_reordering_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, + unsigned int start, unsigned int end) { - unsigned int i; hb_glyph_info_t *info = buffer->info; - /* Comments from: - * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ /* 1. Find base consonant: * @@ -439,52 +266,65 @@ found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t */ unsigned int base = end; + bool has_reph = false; - /* -> starting from the end of the syllable, move backwards */ - i = end; - unsigned int limit = start; - if (info[start].indic_category() == OT_Ra && start + 2 <= end) { - limit += 2; - base = start; - }; - do { - i--; - /* -> until a consonant is found */ - if (is_consonant (info[i])) + { + /* -> If the syllable starts with Ra + Halant (in a script that has Reph) + * and has more than one consonant, Ra is excluded from candidates for + * base consonants. */ + unsigned int limit = start; + if (mask_array[RPHF] && + start + 3 <= end && + info[start].indic_category() == OT_Ra && + info[start + 1].indic_category() == OT_H && + !is_joiner (info[start + 2])) { - /* -> that does not have a below-base or post-base form - * (post-base forms have to follow below-base forms), */ - if (info[i].indic_position() != POS_BELOW && - info[i].indic_position() != POS_POST) + limit += 2; + base = start; + has_reph = true; + }; + + /* -> starting from the end of the syllable, move backwards */ + unsigned int i = end; + do { + i--; + /* -> until a consonant is found */ + if (is_consonant (info[i])) { - base = i; - break; - } - - /* -> or that is not a pre-base reordering Ra, - * - * TODO - */ + /* -> that does not have a below-base or post-base form + * (post-base forms have to follow below-base forms), */ + if (info[i].indic_position() != POS_BELOW_C && + info[i].indic_position() != POS_POST_C) + { + base = i; + break; + } - /* -> o If the syllable starts with Ra + Halant (in a script that has Reph) - * and has more than one consonant, Ra is excluded from candidates for - * base consonants. - * - * IMPLEMENTATION NOTES: - * - * We do this by adjusting limit accordingly before entering the loop. - */ + /* -> or that is not a pre-base reordering Ra, + * + * TODO + */ - /* -> or arrive at the first consonant. The consonant stopped at will - * be the base. */ - base = i; + /* -> or arrive at the first consonant. The consonant stopped at will + * be the base. */ + base = i; + } + else + if (is_joiner (info[i])) + break; + } while (i > limit); + if (base < start) + base = start; /* Just in case... */ + + + /* -> If the syllable starts with Ra + Halant (in a script that has Reph) + * and has more than one consonant, Ra is excluded from candidates for + * base consonants. */ + if (has_reph && base == start) { + /* Have no other consonant, so Reph is not formed and Ra becomes base. */ + has_reph = false; } - else - if (is_joiner (info[i])) - break; - } while (i > limit); - if (base < start) - base = start; /* Just in case... */ + } /* 2. Decompose and reorder Matras: @@ -521,30 +361,23 @@ found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t /* Reorder characters */ - for (i = start; i < base; i++) - info[i].indic_position() = POS_PRE; - info[base].indic_position() = POS_BASE; - + for (unsigned int i = start; i < base; i++) + info[i].indic_position() = POS_PRE_C; + info[base].indic_position() = POS_BASE_C; /* Handle beginning Ra */ - if (start + 3 <= end && - info[start].indic_category() == OT_Ra && - info[start + 1].indic_category() == OT_H && - !is_joiner (info[start + 2])) - { - info[start].indic_position() = POS_POST; - info[start].mask = mask_array[RPHF]; - } + if (has_reph) + info[start].indic_position() = POS_RA_TO_BECOME_REPH; /* For old-style Indic script tags, move the first post-base Halant after * last consonant. */ if ((map->get_chosen_script (0) & 0x000000FF) != '2') { /* We should only do this for Indic scripts which have a version two I guess. */ - for (i = base + 1; i < end; i++) + for (unsigned int i = base + 1; i < end; i++) if (info[i].indic_category() == OT_H) { unsigned int j; for (j = end - 1; j > i; j--) - if ((FLAG (info[j].indic_category()) & (FLAG (OT_C) | FLAG (OT_Ra)))) + if (is_consonant (info[j])) break; if (j > i) { /* Move Halant to after last consonant. */ @@ -557,38 +390,68 @@ found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t } /* Attach ZWJ, ZWNJ, nukta, and halant to previous char to move with them. */ - for (i = start + 1; i < end; i++) - if ((FLAG (info[i].indic_category()) & - (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H)))) - info[i].indic_position() = info[i - 1].indic_position(); + if (!options.uniscribe_bug_compatible) + { + /* Please update the Uniscribe branch when touching this! */ + for (unsigned int i = start + 1; i < end; i++) + if ((FLAG (info[i].indic_category()) & (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H)))) + info[i].indic_position() = info[i - 1].indic_position(); + } else { + /* + * Uniscribe doesn't move the Halant with Left Matra. + * TEST: U+092B,U+093F,U+094DE + */ + /* Please update the non-Uniscribe branch when touching this! */ + for (unsigned int i = start + 1; i < end; i++) + if ((FLAG (info[i].indic_category()) & (FLAG (OT_ZWNJ) | FLAG (OT_ZWJ) | FLAG (OT_N) | FLAG (OT_H)))) { + info[i].indic_position() = info[i - 1].indic_position(); + if (info[i].indic_category() == OT_H && info[i].indic_position() == POS_PRE_M) + for (unsigned int j = i; j > start; j--) + if (info[j - 1].indic_position() != POS_PRE_M) { + info[i].indic_position() = info[j - 1].indic_position(); + break; + } + } + } /* We do bubble-sort, skip malicious clusters attempts */ - if (end - start > 20) - return; - - /* Sit tight, rock 'n roll! */ - hb_bubble_sort (info + start, end - start, compare_indic_order); + if (end - start < 64) + { + /* Sit tight, rock 'n roll! */ + hb_bubble_sort (info + start, end - start, compare_indic_order); + /* Find base again */ + base = end; + for (unsigned int i = start; i < end; i++) + if (info[i].indic_position() == POS_BASE_C) { + base = i; + break; + } + } /* Setup masks now */ { hb_mask_t mask; + /* Reph */ + for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) + info[i].mask |= mask_array[RPHF]; + /* Pre-base */ mask = mask_array[HALF] | mask_array[AKHN] | mask_array[CJCT]; - for (i = start; i < base; i++) + for (unsigned int i = start; i < base; i++) info[i].mask |= mask; /* Base */ mask = mask_array[AKHN] | mask_array[CJCT]; info[base].mask |= mask; /* Post-base */ mask = mask_array[BLWF] | mask_array[PSTF] | mask_array[CJCT]; - for (i = base + 1; i < end; i++) + for (unsigned int i = base + 1; i < end; i++) info[i].mask |= mask; } /* Apply ZWJ/ZWNJ effects */ - for (i = start + 1; i < end; i++) + for (unsigned int i = start + 1; i < end; i++) if (is_joiner (info[i])) { bool non_joiner = info[i].indic_category() == OT_ZWNJ; unsigned int j = i; @@ -596,14 +459,9 @@ found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t do { j--; - /* Reading the Unicode and OpenType specs, I think the following line - * is correct, but this is not what the test suite expects currently. - * The test suite has been drinking, not me... But disable while - * investigating. - */ - //info[j].mask &= !mask_array[CJCT]; + info[j].mask &= ~mask_array[CJCT]; if (non_joiner) - info[j].mask &= !mask_array[HALF]; + info[j].mask &= ~mask_array[HALF]; } while (j > start && !is_consonant (info[j])); } @@ -611,28 +469,41 @@ found_consonant_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t static void -found_vowel_syllable (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, - unsigned int start, unsigned int end) +initial_reordering_vowel_syllable (const hb_ot_map_t *map, + hb_buffer_t *buffer, + hb_mask_t *mask_array, + unsigned int start, unsigned int end) { - /* TODO - * Not clear to me how this should work. Do the matras move to before the - * independent vowel? No idea. - */ + /* We made the vowels look like consonants. So let's call the consonant logic! */ + initial_reordering_consonant_syllable (map, buffer, mask_array, start, end); } static void -found_standalone_cluster (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, - unsigned int start, unsigned int end) +initial_reordering_standalone_cluster (const hb_ot_map_t *map, + hb_buffer_t *buffer, + hb_mask_t *mask_array, + unsigned int start, unsigned int end) { - /* TODO - * Easiest thing to do here is to convert the NBSP to consonant and - * call found_consonant_syllable. - */ + /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain. + * Only if not in compatibility mode that is... */ + + if (options.uniscribe_bug_compatible) + { + /* For dotted-circle, this is what Uniscribe does: + * If dotted-circle is the last glyph, it just does nothing. + * Ie. It doesn't form Reph. */ + if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE) + return; + } + + initial_reordering_consonant_syllable (map, buffer, mask_array, start, end); } static void -found_non_indic (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array, - unsigned int start, unsigned int end) +initial_reordering_non_indic (const hb_ot_map_t *map HB_UNUSED, + hb_buffer_t *buffer HB_UNUSED, + hb_mask_t *mask_array HB_UNUSED, + unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) { /* Nothing to do right now. If we ever switch to using the output * buffer in the reordering process, we'd need to next_glyph() here. */ @@ -641,26 +512,8 @@ found_non_indic (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_ar #include "hb-ot-shape-complex-indic-machine.hh" static void -remove_joiners (hb_buffer_t *buffer) -{ - /* For now we remove joiners. However, Uniscbire seems to keep them - * and output a zero-width space glyph for them. It is not clear to - * me how that is supposed to interact with GSUB. */ - - buffer->clear_output (); - unsigned int count = buffer->len; - for (buffer->idx = 0; buffer->idx < count;) - if (unlikely (is_joiner (buffer->info[buffer->idx]))) - buffer->skip_glyph (); - else - buffer->next_glyph (); - - buffer->swap_buffers (); -} - -static void initial_reordering (const hb_ot_map_t *map, - hb_face_t *face, + hb_face_t *face HB_UNUSED, hb_buffer_t *buffer, void *user_data HB_UNUSED) { @@ -670,24 +523,40 @@ initial_reordering (const hb_ot_map_t *map, mask_array[i] = map->get_1_mask (indic_basic_features[i].tag); find_syllables (map, buffer, mask_array); - - remove_joiners (buffer); } static void -final_reordering (const hb_ot_map_t *map, - hb_face_t *face, - hb_buffer_t *buffer, - void *user_data HB_UNUSED) +final_reordering_syllable (hb_buffer_t *buffer, hb_mask_t *mask_array, + unsigned int start, unsigned int end) { + hb_glyph_info_t *info = buffer->info; + /* 4. Final reordering: * * After the localized forms and basic shaping forms GSUB features have been * applied (see below), the shaping engine performs some final glyph * reordering before applying all the remaining font features to the entire * cluster. - * - * o Reorder matras: + */ + + /* Find base again */ + unsigned int base = end; + for (unsigned int i = start; i < end; i++) + if (info[i].indic_position() == POS_BASE_C) { + base = i; + break; + } + + if (base == start) { + /* There's no Reph, and no left Matra to reposition. Just merge the cluster + * and go home. */ + buffer->merge_clusters (start, end); + return; + } + + unsigned int start_of_last_cluster = base; + + /* o Reorder matras: * * If a pre-base matra character had been reordered before applying basic * features, the glyph can be moved closer to the main consonant based on @@ -695,49 +564,197 @@ final_reordering (const hb_ot_map_t *map, * defined as “after last standalone halant glyph, after initial matra * position and before the main consonant”. If ZWJ or ZWNJ follow this * halant, position is moved after it. - * - * o Reorder reph: + */ + + { + unsigned int new_matra_pos = base - 1; + while (new_matra_pos > start && + !(FLAG (info[new_matra_pos].indic_category()) & (FLAG (OT_M) | FLAG (OT_H)))) + new_matra_pos--; + /* If we found no Halant we are done. Otherwise only proceed if the Halant does + * not belong to the Matra itself! */ + if (info[new_matra_pos].indic_category() == OT_H && + info[new_matra_pos].indic_position() != POS_PRE_M) { + /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */ + if (new_matra_pos + 1 < end && is_joiner (info[new_matra_pos + 1])) + new_matra_pos++; + + /* Now go see if there's actually any matras... */ + for (unsigned int i = new_matra_pos; i > start; i--) + if (info[i - 1].indic_position () == POS_PRE_M) + { + unsigned int old_matra_pos = i - 1; + hb_glyph_info_t matra = info[old_matra_pos]; + memmove (&info[old_matra_pos], &info[old_matra_pos + 1], (new_matra_pos - old_matra_pos) * sizeof (info[0])); + info[new_matra_pos] = matra; + start_of_last_cluster = MIN (new_matra_pos, start_of_last_cluster); + new_matra_pos--; + } + } + } + + + /* o Reorder reph: * * Reph’s original position is always at the beginning of the syllable, * (i.e. it is not reordered at the character reordering stage). However, * it will be reordered according to the basic-forms shaping results. * Possible positions for reph, depending on the script, are; after main, * before post-base consonant forms, and after post-base consonant forms. - * - * 1. If reph should be positioned after post-base consonant forms, - * proceed to step 5. - * - * 2. If the reph repositioning class is not after post-base: target - * position is after the first explicit halant glyph between the - * first post-reph consonant and last main consonant. If ZWJ or ZWNJ - * are following this halant, position is moved after it. If such - * position is found, this is the target position. Otherwise, - * proceed to the next step. - * - * Note: in old-implementation fonts, where classifications were - * fixed in shaping engine, there was no case where reph position - * will be found on this step. - * - * 3. If reph should be repositioned after the main consonant: from the - * first consonant not ligated with main, or find the first - * consonant that is not a potential pre-base reordering Ra. - * - * - * 4. If reph should be positioned before post-base consonant, find - * first post-base classified consonant not ligated with main. If no - * consonant is found, the target position should be before the - * first matra, syllable modifier sign or vedic sign. - * - * 5. If no consonant is found in steps 3 or 4, move reph to a position - * immediately before the first post-base matra, syllable modifier - * sign or vedic sign that has a reordering class after the intended - * reph position. For example, if the reordering position for reph - * is post-main, it will skip above-base matras that also have a - * post-main position. - * - * 6. Otherwise, reorder reph to the end of the syllable. - * - * o Reorder pre-base reordering consonants: + */ + + /* If there's anything after the Ra that has the REPH pos, it ought to be halant. + * Which means that the font has failed to ligate the Reph. In which case, we + * shouldn't move. */ + if (start + 1 < end && + info[start].indic_position() == POS_RA_TO_BECOME_REPH && + info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH) + { + unsigned int new_reph_pos; + + enum reph_position_t { + REPH_AFTER_MAIN, + REPH_BEFORE_SUBSCRIPT, + REPH_AFTER_SUBSCRIPT, + REPH_BEFORE_POSTSCRIPT, + REPH_AFTER_POSTSCRIPT, + } reph_pos; + + /* XXX Figure out old behavior too */ + switch ((hb_tag_t) buffer->props.script) + { + case HB_SCRIPT_MALAYALAM: + case HB_SCRIPT_ORIYA: + reph_pos = REPH_AFTER_MAIN; + break; + + case HB_SCRIPT_GURMUKHI: + reph_pos = REPH_BEFORE_SUBSCRIPT; + break; + + case HB_SCRIPT_BENGALI: + reph_pos = REPH_AFTER_SUBSCRIPT; + break; + + default: + case HB_SCRIPT_DEVANAGARI: + case HB_SCRIPT_GUJARATI: + reph_pos = REPH_BEFORE_POSTSCRIPT; + break; + + case HB_SCRIPT_KANNADA: + case HB_SCRIPT_TAMIL: + case HB_SCRIPT_TELUGU: + reph_pos = REPH_AFTER_POSTSCRIPT; + break; + } + + /* 1. If reph should be positioned after post-base consonant forms, + * proceed to step 5. + */ + if (reph_pos == REPH_AFTER_POSTSCRIPT) + { + goto reph_step_5; + } + + /* 2. If the reph repositioning class is not after post-base: target + * position is after the first explicit halant glyph between the + * first post-reph consonant and last main consonant. If ZWJ or ZWNJ + * are following this halant, position is moved after it. If such + * position is found, this is the target position. Otherwise, + * proceed to the next step. + * + * Note: in old-implementation fonts, where classifications were + * fixed in shaping engine, there was no case where reph position + * will be found on this step. + */ + { + new_reph_pos = start + 1; + while (new_reph_pos < base && info[new_reph_pos].indic_category() != OT_H) + new_reph_pos++; + + if (new_reph_pos < base && info[new_reph_pos].indic_category() == OT_H) { + /* ->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++; + goto reph_move; + } + } + + /* 3. If reph should be repositioned after the main consonant: find the + * first consonant not ligated with main, or find the first + * consonant that is not a potential pre-base reordering Ra. + */ + if (reph_pos == REPH_AFTER_MAIN) + { + /* XXX */ + } + + /* 4. If reph should be positioned before post-base consonant, find + * first post-base classified consonant not ligated with main. If no + * consonant is found, the target position should be before the + * first matra, syllable modifier sign or vedic sign. + */ + /* This is our take on what step 4 is trying to say (and failing, BADLY). */ + if (reph_pos == REPH_AFTER_SUBSCRIPT) + { + new_reph_pos = base; + while (new_reph_pos < end && + !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_POST_M) | FLAG (POS_SMVD)))) + new_reph_pos++; + if (new_reph_pos < end) + goto reph_move; + } + + /* 5. If no consonant is found in steps 3 or 4, move reph to a position + * immediately before the first post-base matra, syllable modifier + * sign or vedic sign that has a reordering class after the intended + * reph position. For example, if the reordering position for reph + * is post-main, it will skip above-base matras that also have a + * post-main position. + */ + reph_step_5: + { + /* XXX */ + } + + /* 6. Otherwise, reorder reph to the end of the syllable. + */ + { + new_reph_pos = end - 1; + while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD) + new_reph_pos--; + + /* + * If the Reph is to be ending up after a Matra,Halant sequence, + * position it before that Halant so it can interact with the Matra. + * However, if it's a plain Consonant,Halant we shouldn't do that. + * Uniscribe doesn't do this. + * TEST: U+0930,U+094D,U+0915,U+094B,U+094D + */ + if (!options.uniscribe_bug_compatible && + unlikely (info[new_reph_pos].indic_category() == OT_H)) { + for (unsigned int i = base + 1; i < new_reph_pos; i++) + if (info[i].indic_category() == OT_M) { + /* Ok, got it. */ + new_reph_pos--; + } + } + goto reph_move; + } + + reph_move: + { + /* Move */ + hb_glyph_info_t reph = info[start]; + memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0])); + info[new_reph_pos] = reph; + start_of_last_cluster = start; /* Yay, one big cluster! */ + } + } + + + /* o Reorder pre-base reordering consonants: * * If a pre-base reordering consonant is found, reorder it according to * the following rules: @@ -757,6 +774,69 @@ final_reordering (const hb_ot_map_t *map, + /* Apply 'init' to the Left Matra if it's a word start. */ + if (info[start].indic_position () == POS_PRE_M && + (!start || + !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) & + (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))) + info[start].mask |= mask_array[INIT]; + + + + /* Finish off the clusters and go home! */ + + if (!options.uniscribe_bug_compatible) + { + /* This is what Uniscribe does. Ie. add cluster boundaries after Halant,ZWNJ. + * This means, half forms are submerged into the main consonants cluster. + * This is unnecessary, and makes cursor positioning harder, but that's what + * Uniscribe does. */ + unsigned int cluster_start = start; + for (unsigned int i = start + 1; i < start_of_last_cluster; i++) + if (info[i - 1].indic_category() == OT_H && info[i].indic_category() == OT_ZWNJ) { + i++; + buffer->merge_clusters (cluster_start, i); + cluster_start = i; + } + start_of_last_cluster = cluster_start; + } + + buffer->merge_clusters (start_of_last_cluster, end); +} + + +static void +final_reordering (const hb_ot_map_t *map, + hb_face_t *face HB_UNUSED, + hb_buffer_t *buffer, + void *user_data HB_UNUSED) +{ + unsigned int count = buffer->len; + if (!count) return; + + hb_mask_t mask_array[ARRAY_LENGTH (indic_other_features)] = {0}; + unsigned int num_masks = ARRAY_LENGTH (indic_other_features); + for (unsigned int i = 0; i < num_masks; i++) + mask_array[i] = map->get_1_mask (indic_other_features[i].tag); + + hb_glyph_info_t *info = buffer->info; + unsigned int last = 0; + unsigned int last_syllable = info[0].syllable(); + for (unsigned int i = 1; i < count; i++) + if (last_syllable != info[i].syllable()) { + final_reordering_syllable (buffer, mask_array, last, i); + last = i; + last_syllable = info[last].syllable(); + } + final_reordering_syllable (buffer, mask_array, last, count); + HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); } diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc index 230704f..d93d4c6 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc @@ -27,7 +27,7 @@ #include "hb-ot-shape-complex-private.hh" -/* TODO Add kana, hangul, and other small sahpers here */ +/* TODO Add kana, and other small shapers here */ /* When adding trivial shapers, eg. kana, hangul, etc, we can either * add a full shaper enum value for them, or switch on the script in @@ -37,19 +37,157 @@ */ void -_hb_ot_shape_complex_collect_features_default (hb_ot_map_builder_t *map, const hb_segment_properties_t *props) +_hb_ot_shape_complex_collect_features_default (hb_ot_map_builder_t *map HB_UNUSED, + const hb_segment_properties_t *props HB_UNUSED) { } -bool -_hb_ot_shape_complex_prefer_decomposed_default (void) +hb_ot_shape_normalization_mode_t +_hb_ot_shape_complex_normalization_preference_default (void) { - return FALSE; + return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; } void -_hb_ot_shape_complex_setup_masks_default (hb_ot_map_t *map, hb_buffer_t *buffer) +_hb_ot_shape_complex_setup_masks_default (hb_ot_map_t *map HB_UNUSED, + hb_buffer_t *buffer HB_UNUSED, + hb_font_t *font HB_UNUSED) { } + +/* Hangul shaper */ + +static const hb_tag_t hangul_features[] = +{ + HB_TAG('l','j','m','o'), + HB_TAG('v','j','m','o'), + HB_TAG('t','j','m','o'), +}; + +void +_hb_ot_shape_complex_collect_features_hangul (hb_ot_map_builder_t *map, + const hb_segment_properties_t *props HB_UNUSED) +{ + for (unsigned int i = 0; i < ARRAY_LENGTH (hangul_features); i++) + map->add_bool_feature (hangul_features[i]); +} + +hb_ot_shape_normalization_mode_t +_hb_ot_shape_complex_normalization_preference_hangul (void) +{ + return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL; +} + +void +_hb_ot_shape_complex_setup_masks_hangul (hb_ot_map_t *map HB_UNUSED, + hb_buffer_t *buffer HB_UNUSED, + hb_font_t *font HB_UNUSED) +{ +} + + + +/* Thai / Lao shaper */ + +void +_hb_ot_shape_complex_collect_features_thai (hb_ot_map_builder_t *map HB_UNUSED, + const hb_segment_properties_t *props HB_UNUSED) +{ +} + +hb_ot_shape_normalization_mode_t +_hb_ot_shape_complex_normalization_preference_thai (void) +{ + return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL; +} + +void +_hb_ot_shape_complex_setup_masks_thai (hb_ot_map_t *map HB_UNUSED, + hb_buffer_t *buffer, + hb_font_t *font HB_UNUSED) +{ + /* The following is NOT specified in the MS OT Thai spec, however, it seems + * to be what Uniscribe and other engines implement. According to Eric Muller: + * + * When you have a sara am, decompose it in nikhahit + sara a, *and* mode the + * nihka hit backwards over any *tone* mark (0E48-0E4B). + * + * <0E14, 0E4B, 0E33> -> <0E14, 0E4D, 0E4B, 0E32> + * + * This reordering is legit only when the nikhahit comes from a sara am, not + * when it's there to start with. The string <0E14, 0E4B, 0E4D> is probably + * not what a u↪ser wanted, but the rendering is nevertheless nikhahit above + * chattawa. + * + * Same for Lao. + */ + + /* + * Here are the characters of significance: + * + * Thai Lao + * SARA AM: U+0E33 U+0EB3 + * SARA AA: U+0E32 U+0EB2 + * Nikhahit: U+0E4D U+0ECD + * + * Tone marks: + * Thai: <0E48..0E4B> CCC=107 + * Lao: <0EC8..0ECB> CCC=122 + * + * Note how the Lao versions are the same as Thai + 0x80. + */ + + /* We only get one script at a time, so a script-agnostic implementation + * is adequate here. */ +#define IS_SARA_AM(x) (((x) & ~0x0080) == 0x0E33) +#define NIKHAHIT_FROM_SARA_AM(x) ((x) - 0xE33 + 0xE4D) +#define SARA_AA_FROM_SARA_AM(x) ((x) - 1) +#define IS_TONE_MARK(x) (((x) & ~0x0083) == 0x0E48) + + buffer->clear_output (); + unsigned int count = buffer->len; + for (buffer->idx = 0; buffer->idx < count;) + { + hb_codepoint_t u = buffer->cur().codepoint; + if (likely (!IS_SARA_AM (u))) { + buffer->next_glyph (); + continue; + } + + /* Is SARA AM. Decompose and reorder. */ + hb_codepoint_t decomposed[2] = {hb_codepoint_t (NIKHAHIT_FROM_SARA_AM (u)), + hb_codepoint_t (SARA_AA_FROM_SARA_AM (u))}; + buffer->replace_glyphs (1, 2, decomposed); + if (unlikely (buffer->in_error)) + return; + + /* Ok, let's see... */ + unsigned int end = buffer->out_len; + unsigned int start = end - 2; + while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint)) + start--; + + /* Move Nikhahit (end-2) to the beginning */ + hb_glyph_info_t t = buffer->out_info[end - 2]; + memmove (buffer->out_info + start + 1, + buffer->out_info + start, + sizeof (buffer->out_info[0]) * (end - start - 2)); + buffer->out_info[start] = t; + + /* XXX Make this easier! */ + /* Make cluster */ + for (; start > 0 && buffer->out_info[start - 1].cluster == buffer->out_info[start].cluster; start--) + ; + for (; buffer->idx < count;) + if (buffer->cur().cluster == buffer->prev().cluster) + buffer->next_glyph (); + else + break; + end = buffer->out_len; + + buffer->merge_out_clusters (start, end); + } + buffer->swap_buffers (); +} diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh index 8b775fb..ba962b5 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-private.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2010,2011 Google, Inc. + * Copyright © 2010,2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -30,26 +30,31 @@ #include "hb-private.hh" #include "hb-ot-map-private.hh" +#include "hb-ot-shape-normalize-private.hh" /* buffer var allocations, used during the entire shaping process */ -#define general_category() var1.u8[0] /* unicode general_category (hb_unicode_general_category_t) */ -#define combining_class() var1.u8[1] /* unicode combining_class (uint8_t) */ +#define unicode_props0() var1.u8[0] +#define unicode_props1() var1.u8[1] + +/* buffer var allocations, used during the GSUB/GPOS processing */ +#define props_cache() var1.u16[1] /* GSUB/GPOS glyph_props cache */ +#define syllable() var2.u8[0] /* GSUB/GPOS shaping boundaries */ +#define lig_props() var2.u8[1] /* GSUB/GPOS ligature tracking */ /* buffer var allocations, used by complex shapers */ -#define complex_var_persistent_u8_0() var2.u8[0] -#define complex_var_persistent_u8_1() var2.u8[1] -#define complex_var_persistent_u16() var2.u16[0] -#define complex_var_temporary_u8_0() var2.u8[2] -#define complex_var_temporary_u8_1() var2.u8[3] -#define complex_var_temporary_u16() var2.u16[1] +#define complex_var_persistent_u8_0() var2.u8[2] +#define complex_var_persistent_u8_1() var2.u8[3] +#define complex_var_temporary_u8() var2.u8[0] #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \ HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \ HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \ + HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \ HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ + HB_COMPLEX_SHAPER_IMPLEMENT (thai) \ /* ^--- Add new shapers here */ enum hb_ot_complex_shaper_t { @@ -63,78 +68,152 @@ enum hb_ot_complex_shaper_t { static inline hb_ot_complex_shaper_t hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) { - switch ((int) props->script) + switch ((hb_tag_t) props->script) { default: return hb_ot_complex_shaper_default; + + /* Unicode-1.1 additions */ case HB_SCRIPT_ARABIC: - case HB_SCRIPT_MANDAIC: case HB_SCRIPT_MONGOLIAN: - case HB_SCRIPT_NKO: case HB_SCRIPT_SYRIAC: + + /* Unicode-5.0 additions */ + case HB_SCRIPT_NKO: + + /* Unicode-6.0 additions */ + case HB_SCRIPT_MANDAIC: + return hb_ot_complex_shaper_arabic; + + /* Unicode-1.1 additions */ + case HB_SCRIPT_HANGUL: + + return hb_ot_complex_shaper_hangul; + + + /* Unicode-1.1 additions */ + case HB_SCRIPT_THAI: + case HB_SCRIPT_LAO: + + return hb_ot_complex_shaper_thai; + + + + /* ^--- Add new shapers here */ + + #if 0 /* Note: * * These disabled scripts are listed in ucd/IndicSyllabicCategory.txt, but according - * to Martin Hosken do not require complex shaping. + * to Martin Hosken and Jonathan Kew do not require complex shaping. + * + * TODO We should automate figuring out which scripts do not need complex shaping * * TODO We currently keep data for these scripts in our indic table. Need to fix the * generator to not do that. */ + /* Simple? */ - case HB_SCRIPT_BATAK: - case HB_SCRIPT_BRAHMI: + + /* Unicode-3.2 additions */ + case HB_SCRIPT_BUHID: case HB_SCRIPT_HANUNOO: - case HB_SCRIPT_MEETEI_MAYEK: + + /* Unicode-5.1 additions */ case HB_SCRIPT_SAURASHTRA: + /* Unicode-5.2 additions */ + case HB_SCRIPT_MEETEI_MAYEK: + + /* Unicode-6.0 additions */ + case HB_SCRIPT_BATAK: + case HB_SCRIPT_BRAHMI: + + /* Simple */ - case HB_SCRIPT_KAYAH_LI: + + /* Unicode-1.1 additions */ + /* These have their own shaper now. */ case HB_SCRIPT_LAO: - case HB_SCRIPT_LIMBU: - case HB_SCRIPT_PHAGS_PA: - case HB_SCRIPT_SYLOTI_NAGRI: + case HB_SCRIPT_THAI: + + /* Unicode-2.0 additions */ + case HB_SCRIPT_TIBETAN: + + /* Unicode-3.2 additions */ case HB_SCRIPT_TAGALOG: case HB_SCRIPT_TAGBANWA: + + /* Unicode-4.0 additions */ + case HB_SCRIPT_LIMBU: case HB_SCRIPT_TAI_LE: + + /* Unicode-4.1 additions */ + case HB_SCRIPT_SYLOTI_NAGRI: + + /* Unicode-5.0 additions */ + case HB_SCRIPT_PHAGS_PA: + + /* Unicode-5.1 additions */ + case HB_SCRIPT_KAYAH_LI: + + /* Unicode-5.2 additions */ case HB_SCRIPT_TAI_VIET: - case HB_SCRIPT_THAI: - case HB_SCRIPT_TIBETAN: + /* May need Indic treatment in the future? */ + + /* Unicode-3.0 additions */ case HB_SCRIPT_MYANMAR: + + #endif - case HB_SCRIPT_BALINESE: + /* Unicode-1.1 additions */ case HB_SCRIPT_BENGALI: - case HB_SCRIPT_BUGINESE: - case HB_SCRIPT_BUHID: - case HB_SCRIPT_CHAM: case HB_SCRIPT_DEVANAGARI: case HB_SCRIPT_GUJARATI: case HB_SCRIPT_GURMUKHI: - case HB_SCRIPT_JAVANESE: - case HB_SCRIPT_KAITHI: case HB_SCRIPT_KANNADA: - case HB_SCRIPT_KHAROSHTHI: - case HB_SCRIPT_KHMER: - case HB_SCRIPT_LEPCHA: case HB_SCRIPT_MALAYALAM: - case HB_SCRIPT_NEW_TAI_LUE: case HB_SCRIPT_ORIYA: - case HB_SCRIPT_REJANG: + case HB_SCRIPT_TAMIL: + case HB_SCRIPT_TELUGU: + + /* Unicode-3.0 additions */ + case HB_SCRIPT_KHMER: case HB_SCRIPT_SINHALA: + + /* Unicode-4.1 additions */ + case HB_SCRIPT_BUGINESE: + case HB_SCRIPT_KHAROSHTHI: + case HB_SCRIPT_NEW_TAI_LUE: + + /* Unicode-5.0 additions */ + case HB_SCRIPT_BALINESE: + + /* Unicode-5.1 additions */ + case HB_SCRIPT_CHAM: + case HB_SCRIPT_LEPCHA: + case HB_SCRIPT_REJANG: case HB_SCRIPT_SUNDANESE: + + /* Unicode-5.2 additions */ + case HB_SCRIPT_JAVANESE: + case HB_SCRIPT_KAITHI: case HB_SCRIPT_TAI_THAM: - case HB_SCRIPT_TAMIL: - case HB_SCRIPT_TELUGU: - return hb_ot_complex_shaper_indic; - /* ^--- Add new shapers here */ + /* Unicode-6.1 additions */ + case HB_SCRIPT_CHAKMA: + case HB_SCRIPT_SHARADA: + case HB_SCRIPT_TAKRI: + + return hb_ot_complex_shaper_indic; } } @@ -170,26 +249,26 @@ hb_ot_shape_complex_collect_features (hb_ot_complex_shaper_t shaper, /* - * prefer_decomposed() + * normalization_preference() * * Called during shape_execute(). * * Shapers should return TRUE if it prefers decomposed (NFD) input rather than precomposed (NFC). */ -typedef bool hb_ot_shape_complex_prefer_decomposed_func_t (void); +typedef hb_ot_shape_normalization_mode_t hb_ot_shape_complex_normalization_preference_func_t (void); #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ - HB_INTERNAL hb_ot_shape_complex_prefer_decomposed_func_t _hb_ot_shape_complex_prefer_decomposed_##name; + HB_INTERNAL hb_ot_shape_complex_normalization_preference_func_t _hb_ot_shape_complex_normalization_preference_##name; HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS #undef HB_COMPLEX_SHAPER_IMPLEMENT -static inline bool -hb_ot_shape_complex_prefer_decomposed (hb_ot_complex_shaper_t shaper) +static inline hb_ot_shape_normalization_mode_t +hb_ot_shape_complex_normalization_preference (hb_ot_complex_shaper_t shaper) { switch (shaper) { default: #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ - case hb_ot_complex_shaper_##name: return _hb_ot_shape_complex_prefer_decomposed_##name (); + case hb_ot_complex_shaper_##name: return _hb_ot_shape_complex_normalization_preference_##name (); HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS #undef HB_COMPLEX_SHAPER_IMPLEMENT } @@ -203,7 +282,7 @@ hb_ot_shape_complex_prefer_decomposed (hb_ot_complex_shaper_t shaper) * Shapers should use map to get feature masks and set on buffer. */ -typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer_t *buffer); +typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer_t *buffer, hb_font_t *font); #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ HB_INTERNAL hb_ot_shape_complex_setup_masks_func_t _hb_ot_shape_complex_setup_masks_##name; HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS @@ -212,12 +291,13 @@ typedef void hb_ot_shape_complex_setup_masks_func_t (hb_ot_map_t *map, hb_buffer static inline void hb_ot_shape_complex_setup_masks (hb_ot_complex_shaper_t shaper, hb_ot_map_t *map, - hb_buffer_t *buffer) + hb_buffer_t *buffer, + hb_font_t *font) { switch (shaper) { default: #define HB_COMPLEX_SHAPER_IMPLEMENT(name) \ - case hb_ot_complex_shaper_##name: _hb_ot_shape_complex_setup_masks_##name (map, buffer); return; + case hb_ot_complex_shaper_##name: _hb_ot_shape_complex_setup_masks_##name (map, buffer, font); return; HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS #undef HB_COMPLEX_SHAPER_IMPLEMENT } diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-normalize-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize-private.hh new file mode 100644 index 0000000..bb81f00 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize-private.hh @@ -0,0 +1,46 @@ +/* + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_SHAPE_NORMALIZE_PRIVATE_HH +#define HB_OT_SHAPE_NORMALIZE_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-font.h" +#include "hb-buffer.h" + + +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_FULL /* including base-to-base composition */ +}; + +HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font, + hb_buffer_t *buffer, + hb_ot_shape_normalization_mode_t mode); + +#endif /* HB_OT_SHAPE_NORMALIZE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc index eb9f32a..a9019fb 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,8 +24,8 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb-ot-shape-normalize-private.hh" #include "hb-ot-shape-private.hh" -#include "hb-ot-shape-complex-private.hh" /* @@ -34,8 +34,10 @@ * This file exports one main function: _hb_ot_shape_normalize(). * * This function closely reflects the Unicode Normalization Algorithm, - * yet it's different. The shaper an either prefer decomposed (NFD) or - * composed (NFC). + * yet it's different. + * + * Each shaper specifies whether it prefers decomposed (NFD) or composed (NFC). + * The logic however tries to use whatever the font can support. * * In general what happens is that: each grapheme is decomposed in a chain * of 1:2 decompositions, marks reordered, and then recomposed if desired, @@ -56,8 +58,8 @@ * which typically has better mark positioning. * * - When a font does not support a combining mark, but supports it precomposed - * with previous base. This needs the itemizer to have this knowledge too. - * We need ot provide assistance to the itemizer. + * with previous base, use that. This needs the itemizer to have this + * knowledge too. We need to provide assistance to the itemizer. * * - When a font does not support a character but supports its decomposition, * well, use the decomposition. @@ -67,45 +69,42 @@ */ static void -output_glyph (hb_ot_shape_context_t *c, - hb_codepoint_t glyph) +output_glyph (hb_buffer_t *buffer, hb_codepoint_t glyph) { - hb_buffer_t *buffer = c->buffer; - buffer->output_glyph (glyph); - hb_glyph_info_set_unicode_props (&buffer->out_info[buffer->out_len - 1], buffer->unicode); + _hb_glyph_info_set_unicode_props (&buffer->prev(), buffer->unicode); } static bool -decompose (hb_ot_shape_context_t *c, +decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t ab) { hb_codepoint_t a, b, glyph; - if (!hb_unicode_decompose (c->buffer->unicode, ab, &a, &b) || - (b && !hb_font_get_glyph (c->font, b, 0, &glyph))) + if (!hb_unicode_decompose (buffer->unicode, ab, &a, &b) || + (b && !hb_font_get_glyph (font, b, 0, &glyph))) return FALSE; - bool has_a = hb_font_get_glyph (c->font, a, 0, &glyph); + bool has_a = hb_font_get_glyph (font, a, 0, &glyph); if (shortest && has_a) { /* Output a and b */ - output_glyph (c, a); + output_glyph (buffer, a); if (b) - output_glyph (c, b); + output_glyph (buffer, b); return TRUE; } - if (decompose (c, shortest, a)) { + if (decompose (font, buffer, shortest, a)) { if (b) - output_glyph (c, b); + output_glyph (buffer, b); return TRUE; } if (has_a) { - output_glyph (c, a); + output_glyph (buffer, a); if (b) - output_glyph (c, b); + output_glyph (buffer, b); return TRUE; } @@ -113,60 +112,60 @@ decompose (hb_ot_shape_context_t *c, } static void -decompose_current_glyph (hb_ot_shape_context_t *c, +decompose_current_glyph (hb_font_t *font, hb_buffer_t *buffer, bool shortest) { - if (decompose (c, shortest, c->buffer->info[c->buffer->idx].codepoint)) - c->buffer->skip_glyph (); + if (decompose (font, buffer, shortest, buffer->cur().codepoint)) + buffer->skip_glyph (); else - c->buffer->next_glyph (); + buffer->next_glyph (); } static void -decompose_single_char_cluster (hb_ot_shape_context_t *c, +decompose_single_char_cluster (hb_font_t *font, hb_buffer_t *buffer, bool will_recompose) { hb_codepoint_t glyph; /* If recomposing and font supports this, we're good to go */ - if (will_recompose && hb_font_get_glyph (c->font, c->buffer->info[c->buffer->idx].codepoint, 0, &glyph)) { - c->buffer->next_glyph (); + if (will_recompose && hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph)) { + buffer->next_glyph (); return; } - decompose_current_glyph (c, will_recompose); + decompose_current_glyph (font, buffer, will_recompose); } static void -decompose_multi_char_cluster (hb_ot_shape_context_t *c, +decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end) { /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ - for (unsigned int i = c->buffer->idx; i < end; i++) - if (unlikely (is_variation_selector (c->buffer->info[i].codepoint))) { - while (c->buffer->idx < end) - c->buffer->next_glyph (); + for (unsigned int i = buffer->idx; i < end; i++) + if (unlikely (_hb_unicode_is_variation_selector (buffer->info[i].codepoint))) { + while (buffer->idx < end) + buffer->next_glyph (); return; } - while (c->buffer->idx < end) - decompose_current_glyph (c, FALSE); + while (buffer->idx < end) + decompose_current_glyph (font, buffer, FALSE); } static int compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) { - unsigned int a = pa->combining_class(); - unsigned int b = pb->combining_class(); + unsigned int a = _hb_glyph_info_get_modified_combining_class (pa); + unsigned int b = _hb_glyph_info_get_modified_combining_class (pb); return a < b ? -1 : a == b ? 0 : +1; } void -_hb_ot_shape_normalize (hb_ot_shape_context_t *c) +_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, + hb_ot_shape_normalization_mode_t mode) { - hb_buffer_t *buffer = c->buffer; - bool recompose = !hb_ot_shape_complex_prefer_decomposed (c->plan->shaper); + bool recompose = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED; bool has_multichar_clusters = FALSE; unsigned int count; @@ -185,31 +184,20 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c) { unsigned int end; for (end = buffer->idx + 1; end < count; end++) - if (buffer->info[buffer->idx].cluster != buffer->info[end].cluster) + if (buffer->cur().cluster != buffer->info[end].cluster) break; if (buffer->idx + 1 == end) - decompose_single_char_cluster (c, recompose); + decompose_single_char_cluster (font, buffer, recompose); else { - decompose_multi_char_cluster (c, end); + decompose_multi_char_cluster (font, buffer, end); has_multichar_clusters = TRUE; } } buffer->swap_buffers (); - /* Technically speaking, two characters with ccc=0 may combine. But all - * those cases are in languages that the indic module handles (which expects - * decomposed), or in Hangul jamo, which again, we want decomposed anyway. - * So we don't bother combining across cluster boundaries. This is a huge - * performance saver if the compose() callback is slow. - * - * TODO: Am I right about Hangul? If I am, we should add a Hangul module - * that requests decomposed. If for Hangul we end up wanting composed, we - * can do that in the Hangul module. - */ - - if (!has_multichar_clusters) + if (mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL && !has_multichar_clusters) return; /* Done! */ @@ -218,12 +206,12 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c) count = buffer->len; for (unsigned int i = 0; i < count; i++) { - if (buffer->info[i].combining_class() == 0) + if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0) continue; unsigned int end; for (end = i + 1; end < count; end++) - if (buffer->info[end].combining_class() == 0) + if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0) break; /* We are going to do a bubble-sort. Only do this if the @@ -254,33 +242,38 @@ _hb_ot_shape_normalize (hb_ot_shape_context_t *c) buffer->next_glyph (); while (buffer->idx < count) { - if (buffer->info[buffer->idx].combining_class() == 0) { - starter = buffer->out_len; - buffer->next_glyph (); - continue; - } - hb_codepoint_t composed, glyph; - if ((buffer->out_info[buffer->out_len - 1].combining_class() >= - buffer->info[buffer->idx].combining_class()) || - !hb_unicode_compose (c->buffer->unicode, - buffer->out_info[starter].codepoint, - buffer->info[buffer->idx].codepoint, - &composed) || - !hb_font_get_glyph (c->font, composed, 0, &glyph)) + if (/* If mode is NOT COMPOSED_FULL (ie. it's COMPOSED_DIACRITICS), we don't try to + * compose a CCC=0 character with it's preceding starter. */ + (mode == HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL || + _hb_glyph_info_get_modified_combining_class (&buffer->cur()) != 0) && + /* If there's anything between the starter and this char, they should have CCC + * smaller than this character's. */ + (starter == buffer->out_len - 1 || + _hb_glyph_info_get_modified_combining_class (&buffer->prev()) < _hb_glyph_info_get_modified_combining_class (&buffer->cur())) && + /* And compose. */ + hb_unicode_compose (buffer->unicode, + buffer->out_info[starter].codepoint, + buffer->cur().codepoint, + &composed) && + /* And the font has glyph for the composite. */ + hb_font_get_glyph (font, composed, 0, &glyph)) { - /* Blocked, or doesn't compose. */ - buffer->next_glyph (); + /* Composes. Modify starter and carry on. */ + buffer->out_info[starter].codepoint = composed; + /* XXX update cluster */ + _hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode); + + buffer->skip_glyph (); continue; } - /* Composes. Modify starter and carry on. */ - buffer->out_info[starter].codepoint = composed; - hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode); + /* Blocked, or doesn't compose. */ + buffer->next_glyph (); - buffer->skip_glyph (); + if (_hb_glyph_info_get_modified_combining_class (&buffer->prev()) == 0) + starter = buffer->out_len - 1; } buffer->swap_buffers (); } - diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh index c49c2b0..df0c705 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh @@ -29,19 +29,12 @@ #include "hb-private.hh" -#include "hb-ot-shape.h" - #include "hb-ot-map-private.hh" #include "hb-ot-shape-complex-private.hh" - -enum hb_ot_complex_shaper_t; - struct hb_ot_shape_plan_t { - friend struct hb_ot_shape_planner_t; - hb_ot_map_t map; hb_ot_complex_shaper_t shaper; @@ -52,78 +45,39 @@ struct hb_ot_shape_plan_t NO_COPY (hb_ot_shape_plan_t); }; -struct hb_ot_shape_planner_t -{ - hb_ot_map_builder_t map; - hb_ot_complex_shaper_t shaper; - - hb_ot_shape_planner_t (void) : map () {} - ~hb_ot_shape_planner_t (void) { map.finish (); } - inline void compile (hb_face_t *face, - const hb_segment_properties_t *props, - struct hb_ot_shape_plan_t &plan) - { - plan.shaper = shaper; - map.compile (face, props, plan.map); - } - private: - NO_COPY (hb_ot_shape_planner_t); -}; +HB_INTERNAL hb_bool_t +_hb_ot_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features); -struct hb_ot_shape_context_t +inline void +_hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode) { - /* Input to hb_ot_shape_execute() */ - hb_ot_shape_plan_t *plan; - hb_font_t *font; - hb_face_t *face; - hb_buffer_t *buffer; - const hb_feature_t *user_features; - unsigned int num_user_features; - - /* Transient stuff */ - hb_direction_t target_direction; - hb_bool_t applied_substitute_complex; - hb_bool_t applied_position_complex; -}; - + info->unicode_props0() = ((unsigned int) hb_unicode_general_category (unicode, info->codepoint)) | + (_hb_unicode_is_zero_width (info->codepoint) ? 0x80 : 0); + info->unicode_props1() = _hb_unicode_modified_combining_class (unicode, info->codepoint); +} -static inline hb_bool_t -is_variation_selector (hb_codepoint_t unicode) +inline hb_unicode_general_category_t +_hb_glyph_info_get_general_category (const hb_glyph_info_t *info) { - return unlikely ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */ - (unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SELECTOR-1..16 */ - (unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SELECTOR-17..256 */ + return (hb_unicode_general_category_t) (info->unicode_props0() & 0x7F); } -static inline unsigned int -_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t unicode) +inline unsigned int +_hb_glyph_info_get_modified_combining_class (const hb_glyph_info_t *info) { - int c = hb_unicode_combining_class (ufuncs, unicode); - - /* Modify the combining-class to suit Arabic better. See: - * http://unicode.org/faq/normalization.html#8 - * http://unicode.org/faq/normalization.html#9 - */ - if (unlikely (hb_in_range<int> (c, 27, 33))) - c = c == 33 ? 27 : c + 1; - - return c; + return info->unicode_props1(); } -static inline void -hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_unicode_funcs_t *unicode) +inline hb_bool_t +_hb_glyph_info_is_zero_width (const hb_glyph_info_t *info) { - info->general_category() = hb_unicode_general_category (unicode, info->codepoint); - info->combining_class() = _hb_unicode_modified_combining_class (unicode, info->codepoint); + return !!(info->unicode_props0() & 0x80); } -HB_INTERNAL void _hb_set_unicode_props (hb_buffer_t *buffer); - -HB_INTERNAL void _hb_ot_shape_normalize (hb_ot_shape_context_t *c); - - #endif /* HB_OT_SHAPE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape.cc b/third_party/harfbuzz-ng/src/hb-ot-shape.cc index 4275afc..8b1d670 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape.cc @@ -27,26 +27,28 @@ */ #include "hb-ot-shape-private.hh" -#include "hb-ot-shape-complex-private.hh" +#include "hb-ot-shape-normalize-private.hh" #include "hb-font-private.hh" +#include "hb-set-private.hh" hb_tag_t common_features[] = { HB_TAG('c','c','m','p'), + HB_TAG('l','i','g','a'), HB_TAG('l','o','c','l'), HB_TAG('m','a','r','k'), HB_TAG('m','k','m','k'), HB_TAG('r','l','i','g'), }; + hb_tag_t horizontal_features[] = { HB_TAG('c','a','l','t'), HB_TAG('c','l','i','g'), HB_TAG('c','u','r','s'), HB_TAG('k','e','r','n'), - HB_TAG('l','i','g','a'), }; /* Note: @@ -62,6 +64,28 @@ hb_tag_t vertical_features[] = { HB_TAG('v','r','t','2'), }; + + +struct hb_ot_shape_planner_t +{ + hb_ot_map_builder_t map; + hb_ot_complex_shaper_t shaper; + + hb_ot_shape_planner_t (void) : map () {} + ~hb_ot_shape_planner_t (void) { map.finish (); } + + inline void compile (hb_face_t *face, + const hb_segment_properties_t *props, + struct hb_ot_shape_plan_t &plan) + { + plan.shaper = shaper; + map.compile (face, props, plan.map); + } + + private: + NO_COPY (hb_ot_shape_planner_t); +}; + static void hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, const hb_segment_properties_t *props, @@ -108,13 +132,28 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, } +struct hb_ot_shape_context_t +{ + /* Input to hb_ot_shape_execute() */ + hb_ot_shape_plan_t *plan; + hb_font_t *font; + hb_face_t *face; + hb_buffer_t *buffer; + const hb_feature_t *user_features; + unsigned int num_user_features; + + /* Transient stuff */ + hb_direction_t target_direction; + hb_bool_t applied_position_complex; +}; + static void hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) { hb_mask_t global_mask = c->plan->map.get_global_mask (); c->buffer->reset_masks (global_mask); - hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer); + hb_ot_shape_complex_setup_masks (c->plan->shaper, &c->plan->map, c->buffer, c->font); for (unsigned int i = 0; i < c->num_user_features; i++) { @@ -132,12 +171,12 @@ hb_ot_shape_setup_masks (hb_ot_shape_context_t *c) /* Prepare */ -void -_hb_set_unicode_props (hb_buffer_t *buffer) +static void +hb_set_unicode_props (hb_buffer_t *buffer) { unsigned int count = buffer->len; - for (unsigned int i = 1; i < count; i++) - hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); + for (unsigned int i = 0; i < count; i++) + _hb_glyph_info_set_unicode_props (&buffer->info[i], buffer->unicode); } static void @@ -145,11 +184,11 @@ hb_form_clusters (hb_buffer_t *buffer) { unsigned int count = buffer->len; for (unsigned int i = 1; i < count; i++) - if (FLAG (buffer->info[i].general_category()) & + if (FLAG (_hb_glyph_info_get_general_category (&buffer->info[i])) & (FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))) - buffer->info[i].cluster = buffer->info[i - 1].cluster; + buffer->info[i].cluster = buffer->info[i - 1].cluster; /* XXX do the min() here */ } static void @@ -205,17 +244,16 @@ hb_map_glyphs (hb_font_t *font, unsigned int count = buffer->len - 1; for (buffer->idx = 0; buffer->idx < count;) { - if (unlikely (is_variation_selector (buffer->info[buffer->idx + 1].codepoint))) { - hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, buffer->info[buffer->idx + 1].codepoint, &glyph); - buffer->replace_glyph (glyph); - buffer->skip_glyph (); + if (unlikely (_hb_unicode_is_variation_selector (buffer->cur(+1).codepoint))) { + hb_font_get_glyph (font, buffer->cur().codepoint, buffer->cur(+1).codepoint, &glyph); + buffer->replace_glyphs (2, 1, &glyph); } else { - hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph); + hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph); buffer->replace_glyph (glyph); } } if (likely (buffer->idx < buffer->len)) { - hb_font_get_glyph (font, buffer->info[buffer->idx].codepoint, 0, &glyph); + hb_font_get_glyph (font, buffer->cur().codepoint, 0, &glyph); buffer->replace_glyph (glyph); } buffer->swap_buffers (); @@ -236,7 +274,6 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c) { if (hb_ot_layout_has_substitution (c->face)) { c->plan->map.substitute (c->face, c->buffer); - c->applied_substitute_complex = TRUE; } hb_ot_layout_substitute_finish (c->buffer); @@ -244,12 +281,6 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c) return; } -static void -hb_substitute_complex_fallback (hb_ot_shape_context_t *c HB_UNUSED) -{ - /* TODO Arabic */ -} - /* Position */ @@ -342,6 +373,23 @@ hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) hb_truetype_kern (c); } +static void +hb_hide_zerowidth (hb_ot_shape_context_t *c) +{ + /* TODO Save the space character in the font? */ + hb_codepoint_t space; + if (!hb_font_get_glyph (c->font, ' ', 0, &space)) + return; /* No point! */ + + unsigned int count = c->buffer->len; + for (unsigned int i = 0; i < count; i++) + if (unlikely (_hb_glyph_info_is_zero_width (&c->buffer->info[i]))) { + c->buffer->info[i].codepoint = space; + c->buffer->pos[i].x_advance = 0; + c->buffer->pos[i].y_advance = 0; + } +} + /* Do it! */ @@ -353,16 +401,16 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) /* Save the original direction, we use it later. */ c->target_direction = c->buffer->props.direction; - HB_BUFFER_ALLOCATE_VAR (c->buffer, general_category); - HB_BUFFER_ALLOCATE_VAR (c->buffer, combining_class); + HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props0); + HB_BUFFER_ALLOCATE_VAR (c->buffer, unicode_props1); - _hb_set_unicode_props (c->buffer); /* BUFFER: Set general_category and combining_class */ + hb_set_unicode_props (c->buffer); hb_form_clusters (c->buffer); hb_ensure_native_direction (c->buffer); - _hb_ot_shape_normalize (c); + _hb_ot_shape_normalize (c->font, c->buffer, hb_ot_shape_complex_normalization_preference (c->plan->shaper)); hb_ot_shape_setup_masks (c); @@ -371,9 +419,6 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) hb_substitute_default (c); hb_ot_substitute_complex (c); - - if (!c->applied_substitute_complex) - hb_substitute_complex_fallback (c); } /* POSITION */ @@ -393,8 +438,10 @@ hb_ot_shape_execute_internal (hb_ot_shape_context_t *c) hb_position_complex_fallback_visual (c); } - HB_BUFFER_DEALLOCATE_VAR (c->buffer, combining_class); - HB_BUFFER_DEALLOCATE_VAR (c->buffer, general_category); + hb_hide_zerowidth (c); + + HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1); + HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0); c->buffer->props.direction = c->target_direction; @@ -410,6 +457,8 @@ hb_ot_shape_plan_internal (hb_ot_shape_plan_t *plan, { hb_ot_shape_planner_t planner; + assert (HB_DIRECTION_IS_VALID (props->direction)); + planner.shaper = hb_ot_shape_complex_categorize (props); hb_ot_shape_collect_features (&planner, props, user_features, num_user_features); @@ -429,11 +478,10 @@ hb_ot_shape_execute (hb_ot_shape_plan_t *plan, } hb_bool_t -hb_ot_shape (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options) +_hb_ot_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) { hb_ot_shape_plan_t plan; @@ -446,3 +494,35 @@ hb_ot_shape (hb_font_t *font, } +void +hb_ot_shape_glyphs_closure (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + hb_set_t *glyphs) +{ + hb_ot_shape_plan_t plan; + + buffer->guess_properties (); + + hb_ot_shape_plan_internal (&plan, font->face, &buffer->props, features, num_features); + + /* TODO: normalization? have shapers do closure()? */ + /* TODO: Deal with mirrored chars? */ + hb_map_glyphs (font, buffer); + + /* Seed it. It's user's responsibility to have cleard glyphs + * if that's what they desire. */ + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + hb_set_add (glyphs, buffer->info[i].codepoint); + + /* And find transitive closure. */ + hb_set_t copy; + copy.init (); + + do { + copy.set (glyphs); + plan.map.substitute_closure (font->face, glyphs); + } while (!copy.equal (glyphs)); +} diff --git a/third_party/harfbuzz-ng/src/hb-ot-tag.h b/third_party/harfbuzz-ng/src/hb-ot-tag.h index 427a069..1bf12ab 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-tag.h +++ b/third_party/harfbuzz-ng/src/hb-ot-tag.h @@ -24,10 +24,14 @@ * Red Hat Author(s): Behdad Esfahbod */ +#ifndef HB_OT_H_IN +#error "Include <hb-ot.h> instead." +#endif + #ifndef HB_OT_TAG_H #define HB_OT_TAG_H -#include "hb-common.h" +#include "hb.h" HB_BEGIN_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-ot.h b/third_party/harfbuzz-ng/src/hb-ot.h index fd6dd58..2d750c3 100644 --- a/third_party/harfbuzz-ng/src/hb-ot.h +++ b/third_party/harfbuzz-ng/src/hb-ot.h @@ -26,14 +26,23 @@ #ifndef HB_OT_H #define HB_OT_H +#define HB_OT_H_IN #include "hb.h" #include "hb-ot-layout.h" -#include "hb-ot-shape.h" #include "hb-ot-tag.h" HB_BEGIN_DECLS + +void +hb_ot_shape_glyphs_closure (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features, + hb_set_t *glyphs); + HB_END_DECLS +#undef HB_OT_H_IN #endif /* HB_OT_H */ diff --git a/third_party/harfbuzz-ng/src/hb-private.hh b/third_party/harfbuzz-ng/src/hb-private.hh index c757e2dc..aa86072 100644 --- a/third_party/harfbuzz-ng/src/hb-private.hh +++ b/third_party/harfbuzz-ng/src/hb-private.hh @@ -1,6 +1,6 @@ /* * Copyright © 2007,2008,2009 Red Hat, Inc. - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -33,7 +33,12 @@ #include "config.h" #endif -#include "hb-common.h" +#include "hb.h" +#define HB_H_IN +#ifdef HAVE_OT +#include "hb-ot.h" +#define HB_OT_H_IN +#endif #include <stdlib.h> #include <stddef.h> @@ -86,6 +91,8 @@ template <typename Type> static inline Type MAX (const Type &a, const Type &b) { #define ASSERT_STATIC_EXPR(_cond) ((void) sizeof (char[(_cond) ? 1 : -1])) #define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * sizeof (char[(_cond) ? 1 : -1])) +#define _PASTE1(a,b) a##b +#define PASTE(a,b) _PASTE1(a,b) /* Lets assert int types. Saves trouble down the road. */ @@ -437,6 +444,14 @@ static inline uint16_t hb_be_uint16 (const uint16_t v) return (uint16_t) (V[0] << 8) + V[1]; } +/* Note, of the following macros, uint16_get is the one called many many times. + * If there is any optimizations to be done, it's in that macro. However, I + * already confirmed that on my T400 ThinkPad at least, using bswap_16(), which + * results in a single ror instruction, does NOT speed this up. In fact, it + * resulted in a minor slowdown. At any rate, note that v may not be correctly + * aligned, so I think the current implementation is optimal. + */ + #define hb_be_uint16_put(v,V) HB_STMT_START { v[0] = (V>>8); v[1] = (V); } HB_STMT_END #define hb_be_uint16_get(v) (uint16_t) ((v[0] << 8) + v[1]) #define hb_be_uint16_eq(a,b) (a[0] == b[0] && a[1] == b[1]) @@ -488,62 +503,106 @@ _hb_debug (unsigned int level, #define DEBUG_LEVEL(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT)) #define DEBUG(WHAT) (DEBUG_LEVEL (WHAT, 0)) -template <int max_level> inline bool /* always returns TRUE */ +template <int max_level> inline void +_hb_debug_msg_va (const char *what, + const void *obj, + const char *func, + bool indented, + unsigned int level, + int level_dir, + const char *message, + va_list ap) +{ + if (!_hb_debug (level, max_level)) + return; + + fprintf (stderr, "%-10s", what ? what : ""); + + if (obj) + fprintf (stderr, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) obj); + else + fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), ""); + + if (indented) { + static const char bars[] = "││││││││││││││││││││││││││││││││││││││││"; + fprintf (stderr, "%2d %s├%s", + level, + bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars), 3 * level), + level_dir ? (level_dir > 0 ? "╮" : "╯") : "╴"); + } else + fprintf (stderr, " ├╴"); + + if (func) { + /* If there's a class name, just write that. */ + const char *dotdot = strstr (func, "::"); + const char *space = strchr (func, ' '); + if (space && dotdot && space < dotdot) + func = space + 1; + unsigned int func_len = dotdot ? dotdot - func : strlen (func); + fprintf (stderr, "%.*s: ", func_len, func); + } + + if (message) + vfprintf (stderr, message, ap); + + fprintf (stderr, "\n"); +} +template <> inline void +_hb_debug_msg_va<0> (const char *what HB_UNUSED, + const void *obj HB_UNUSED, + const char *func HB_UNUSED, + bool indented HB_UNUSED, + unsigned int level HB_UNUSED, + int level_dir HB_UNUSED, + const char *message HB_UNUSED, + va_list ap HB_UNUSED) {} + +template <int max_level> inline void _hb_debug_msg (const char *what, const void *obj, const char *func, bool indented, - int level, + unsigned int level, + int level_dir, const char *message, - ...) HB_PRINTF_FUNC(6, 7); -template <int max_level> inline bool /* always returns TRUE */ + ...) HB_PRINTF_FUNC(7, 8); +template <int max_level> inline void _hb_debug_msg (const char *what, const void *obj, const char *func, bool indented, - int level, + unsigned int level, + int level_dir, const char *message, ...) { va_list ap; va_start (ap, message); - - (void) (_hb_debug (level, max_level) && - fprintf (stderr, "%s", what) && - (obj && fprintf (stderr, "(%p)", obj), TRUE) && - fprintf (stderr, ": ") && - (func && fprintf (stderr, "%s: ", func), TRUE) && - (indented && fprintf (stderr, "%-*d-> ", level + 1, level), TRUE) && - vfprintf (stderr, message, ap) && - fprintf (stderr, "\n")); - + _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap); va_end (ap); - - return TRUE; -} -template <> inline bool /* always returns TRUE */ -_hb_debug_msg<0> (const char *what, - const void *obj, - const char *func, - bool indented, - int level, - const char *message, - ...) HB_PRINTF_FUNC(6, 7); -template <> inline bool /* always returns TRUE */ -_hb_debug_msg<0> (const char *what, - const void *obj, - const char *func, - bool indented, - int level, - const char *message, - ...) -{ - return TRUE; } - -#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, FALSE, (LEVEL), __VA_ARGS__) -#define DEBUG_MSG(WHAT, OBJ, ...) DEBUG_MSG_LEVEL (WHAT, OBJ, 0, __VA_ARGS__) -#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, FALSE, 0, __VA_ARGS__) +template <> inline void +_hb_debug_msg<0> (const char *what HB_UNUSED, + const void *obj HB_UNUSED, + const char *func HB_UNUSED, + bool indented HB_UNUSED, + unsigned int level HB_UNUSED, + int level_dir HB_UNUSED, + const char *message HB_UNUSED, + ...) HB_PRINTF_FUNC(7, 8); +template <> inline void +_hb_debug_msg<0> (const char *what HB_UNUSED, + const void *obj HB_UNUSED, + const char *func HB_UNUSED, + bool indented HB_UNUSED, + unsigned int level HB_UNUSED, + int level_dir HB_UNUSED, + const char *message HB_UNUSED, + ...) {} + +#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, TRUE, (LEVEL), (LEVEL_DIR), __VA_ARGS__) +#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), NULL, FALSE, 0, 0, __VA_ARGS__) +#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, FALSE, 0, 0, __VA_ARGS__) /* @@ -553,29 +612,64 @@ _hb_debug_msg<0> (const char *what, template <int max_level> struct hb_auto_trace_t { explicit inline hb_auto_trace_t (unsigned int *plevel_, - const char *what, - const void *obj, + const char *what_, + const void *obj_, const char *func, - const char *message) : plevel(plevel_) + const char *message, + ...) : plevel (plevel_), what (what_), obj (obj_), returned (false) + { + if (plevel) ++*plevel; + + va_list ap; + va_start (ap, message); + _hb_debug_msg_va<max_level> (what, obj, func, TRUE, plevel ? *plevel : 0, +1, message, ap); + va_end (ap); + } + inline ~hb_auto_trace_t (void) { - if (max_level) ++*plevel; - /* TODO support variadic args here */ - _hb_debug_msg<max_level> (what, obj, func, TRUE, *plevel, "%s", message); + if (unlikely (!returned)) { + fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN. This is a bug, please report. Level was %d.\n", plevel ? *plevel : -1); + _hb_debug_msg<max_level> (what, obj, NULL, TRUE, plevel ? *plevel : 1, -1, " "); + return; + } + + if (plevel) --*plevel; + } + + inline bool ret (bool v) + { + if (unlikely (returned)) { + fprintf (stderr, "OUCH, double calls to TRACE_RETURN. This is a bug, please report.\n"); + return v; + } + + _hb_debug_msg<max_level> (what, obj, NULL, TRUE, plevel ? *plevel : 1, -1, "return %s", v ? "true" : "false"); + if (plevel) --*plevel; + plevel = NULL; + returned = true; + return v; } - ~hb_auto_trace_t (void) { if (max_level) --*plevel; } private: unsigned int *plevel; + bool returned; + const char *what; + const void *obj; }; template <> /* Optimize when tracing is disabled */ struct hb_auto_trace_t<0> { - explicit inline hb_auto_trace_t (unsigned int *plevel_, - const char *what, - const void *obj, - const char *func, - const char *message) {} + explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED, + const char *what HB_UNUSED, + const void *obj HB_UNUSED, + const char *func HB_UNUSED, + const char *message HB_UNUSED, + ...) {} + + template <typename T> + inline T ret (T v) { return v; } }; +#define TRACE_RETURN(RET) trace.ret (RET) /* Misc */ diff --git a/third_party/harfbuzz-ng/src/hb-set-private.hh b/third_party/harfbuzz-ng/src/hb-set-private.hh new file mode 100644 index 0000000..9d8ba4a --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-set-private.hh @@ -0,0 +1,169 @@ +/* + * Copyright © 2012 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_SET_PRIVATE_HH +#define HB_SET_PRIVATE_HH + +#include "hb-private.hh" +#include "hb-set.h" +#include "hb-object-private.hh" + + +/* TODO Make this faster and memmory efficient. */ + +struct _hb_set_t +{ + inline void init (void) { + clear (); + } + inline void fini (void) { + } + inline void clear (void) { + memset (elts, 0, sizeof elts); + } + inline bool empty (void) const { + for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++) + if (elts[i]) + return false; + return true; + } + inline void add (hb_codepoint_t g) + { + if (unlikely (g == SENTINEL)) return; + if (unlikely (g > MAX_G)) return; + elt (g) |= mask (g); + } + inline void del (hb_codepoint_t g) + { + if (unlikely (g > MAX_G)) return; + elt (g) &= ~mask (g); + } + inline bool has (hb_codepoint_t g) const + { + if (unlikely (g > MAX_G)) return false; + return !!(elt (g) & mask (g)); + } + inline bool intersects (hb_codepoint_t first, + hb_codepoint_t last) const + { + if (unlikely (first > MAX_G)) return false; + if (unlikely (last > MAX_G)) last = MAX_G; + unsigned int end = last + 1; + for (hb_codepoint_t i = first; i < end; i++) + if (has (i)) + return true; + return false; + } + inline bool equal (const hb_set_t *other) const + { + for (unsigned int i = 0; i < ELTS; i++) + if (elts[i] != other->elts[i]) + return false; + return true; + } + inline void set (const hb_set_t *other) + { + for (unsigned int i = 0; i < ELTS; i++) + elts[i] = other->elts[i]; + } + inline void union_ (const hb_set_t *other) + { + for (unsigned int i = 0; i < ELTS; i++) + elts[i] |= other->elts[i]; + } + inline void intersect (const hb_set_t *other) + { + for (unsigned int i = 0; i < ELTS; i++) + elts[i] &= other->elts[i]; + } + inline void subtract (const hb_set_t *other) + { + for (unsigned int i = 0; i < ELTS; i++) + elts[i] &= ~other->elts[i]; + } + inline void symmetric_difference (const hb_set_t *other) + { + for (unsigned int i = 0; i < ELTS; i++) + elts[i] ^= other->elts[i]; + } + inline bool next (hb_codepoint_t *codepoint) + { + if (unlikely (*codepoint == SENTINEL)) { + hb_codepoint_t i = get_min (); + if (i != SENTINEL) { + *codepoint = i; + return true; + } else + return false; + } + for (hb_codepoint_t i = *codepoint + 1; i < MAX_G + 1; i++) + if (has (i)) { + *codepoint = i; + return true; + } + return false; + } + inline hb_codepoint_t get_min (void) const + { + for (unsigned int i = 0; i < ELTS; i++) + if (elts[i]) + for (unsigned int j = 0; i < BITS; j++) + if (elts[i] & (1 << j)) + return i * BITS + j; + return SENTINEL; + } + inline hb_codepoint_t get_max (void) const + { + for (unsigned int i = ELTS; i; i--) + if (elts[i - 1]) + for (unsigned int j = BITS; j; j--) + if (elts[i - 1] & (1 << (j - 1))) + return (i - 1) * BITS + (j - 1); + return SENTINEL; + } + + typedef uint32_t elt_t; + static const unsigned int MAX_G = 65536 - 1; /* XXX Fix this... */ + static const unsigned int SHIFT = 5; + static const unsigned int BITS = (1 << SHIFT); + static const unsigned int MASK = BITS - 1; + static const unsigned int ELTS = (MAX_G + 1 + (BITS - 1)) / BITS; + static const hb_codepoint_t SENTINEL = (hb_codepoint_t) -1; + + elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; } + elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; } + elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); } + + hb_object_header_t header; + elt_t elts[ELTS]; /* XXX 8kb */ + + ASSERT_STATIC (sizeof (elt_t) * 8 == BITS); + ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G); +}; + + + +#endif /* HB_SET_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-set.cc b/third_party/harfbuzz-ng/src/hb-set.cc new file mode 100644 index 0000000..5045386 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-set.cc @@ -0,0 +1,191 @@ +/* + * Copyright © 2012 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-set-private.hh" + + + +/* Public API */ + +static hb_set_t _hb_set_nil = { + HB_OBJECT_HEADER_STATIC, + + {0} /* elts */ +}; + + +hb_set_t * +hb_set_create () +{ + hb_set_t *set; + + if (!(set = hb_object_create<hb_set_t> ())) + return &_hb_set_nil; + + set->clear (); + + return set; +} + +hb_set_t * +hb_set_get_empty (void) +{ + return &_hb_set_nil; +} + +hb_set_t * +hb_set_reference (hb_set_t *set) +{ + return hb_object_reference (set); +} + +void +hb_set_destroy (hb_set_t *set) +{ + if (!hb_object_destroy (set)) return; + + set->fini (); + + free (set); +} + +hb_bool_t +hb_set_set_user_data (hb_set_t *set, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (set, key, data, destroy, replace); +} + +void * +hb_set_get_user_data (hb_set_t *set, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (set, key); +} + + +hb_bool_t +hb_set_allocation_successful (hb_set_t *set HB_UNUSED) +{ + return TRUE; +} + +void +hb_set_clear (hb_set_t *set) +{ + set->clear (); +} + +hb_bool_t +hb_set_empty (hb_set_t *set) +{ + return set->empty (); +} + +hb_bool_t +hb_set_has (hb_set_t *set, + hb_codepoint_t codepoint) +{ + return set->has (codepoint); +} + +void +hb_set_add (hb_set_t *set, + hb_codepoint_t codepoint) +{ + set->add (codepoint); +} + +void +hb_set_del (hb_set_t *set, + hb_codepoint_t codepoint) +{ + set->del (codepoint); +} + +hb_bool_t +hb_set_equal (hb_set_t *set, + hb_set_t *other) +{ + return set->equal (other); +} + +void +hb_set_set (hb_set_t *set, + hb_set_t *other) +{ + set->set (other); +} + +void +hb_set_union (hb_set_t *set, + hb_set_t *other) +{ + set->union_ (other); +} + +void +hb_set_intersect (hb_set_t *set, + hb_set_t *other) +{ + set->intersect (other); +} + +void +hb_set_subtract (hb_set_t *set, + hb_set_t *other) +{ + set->subtract (other); +} + +void +hb_set_symmetric_difference (hb_set_t *set, + hb_set_t *other) +{ + set->symmetric_difference (other); +} + +hb_codepoint_t +hb_set_min (hb_set_t *set) +{ + return set->get_min (); +} + +hb_codepoint_t +hb_set_max (hb_set_t *set) +{ + return set->get_max (); +} + +hb_bool_t +hb_set_next (hb_set_t *set, + hb_codepoint_t *codepoint) +{ + return set->next (codepoint); +} diff --git a/third_party/harfbuzz-ng/src/hb-set.h b/third_party/harfbuzz-ng/src/hb-set.h new file mode 100644 index 0000000..97e68e4 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-set.h @@ -0,0 +1,132 @@ +/* + * Copyright © 2012 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_H_IN +#error "Include <hb.h> instead." +#endif + +#ifndef HB_SET_H +#define HB_SET_H + +#include "hb-common.h" + +HB_BEGIN_DECLS + + +typedef struct _hb_set_t hb_set_t; + + +hb_set_t * +hb_set_create (void); + +hb_set_t * +hb_set_get_empty (void); + +hb_set_t * +hb_set_reference (hb_set_t *set); + +void +hb_set_destroy (hb_set_t *set); + +hb_bool_t +hb_set_set_user_data (hb_set_t *set, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + +void * +hb_set_get_user_data (hb_set_t *set, + hb_user_data_key_t *key); + + +/* Returns FALSE if allocation has failed before */ +hb_bool_t +hb_set_allocation_successful (hb_set_t *set); + +void +hb_set_clear (hb_set_t *set); + +hb_bool_t +hb_set_empty (hb_set_t *set); + +hb_bool_t +hb_set_has (hb_set_t *set, + hb_codepoint_t codepoint); + +/* Right now limited to 16-bit integers. Eventually will do full codepoint range, sans -1 + * which we will use as a sentinel. */ +void +hb_set_add (hb_set_t *set, + hb_codepoint_t codepoint); + +void +hb_set_del (hb_set_t *set, + hb_codepoint_t codepoint); + +hb_bool_t +hb_set_equal (hb_set_t *set, + hb_set_t *other); + +void +hb_set_set (hb_set_t *set, + hb_set_t *other); + +void +hb_set_union (hb_set_t *set, + hb_set_t *other); + +void +hb_set_intersect (hb_set_t *set, + hb_set_t *other); + +void +hb_set_subtract (hb_set_t *set, + hb_set_t *other); + +void +hb_set_symmetric_difference (hb_set_t *set, + hb_set_t *other); + +/* Returns -1 if set empty. */ +hb_codepoint_t +hb_set_min (hb_set_t *set); + +/* Returns -1 if set empty. */ +hb_codepoint_t +hb_set_max (hb_set_t *set); + +/* Pass -1 in to get started. */ +hb_bool_t +hb_set_next (hb_set_t *set, + hb_codepoint_t *codepoint); + +/* TODO: Add faster iteration API? */ + + +HB_END_DECLS + +#endif /* HB_SET_H */ diff --git a/third_party/harfbuzz-ng/src/hb-shape.cc b/third_party/harfbuzz-ng/src/hb-shape.cc index 9357f81..d97028e 100644 --- a/third_party/harfbuzz-ng/src/hb-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-shape.cc @@ -31,30 +31,29 @@ #include "hb-buffer-private.hh" #ifdef HAVE_GRAPHITE -#include "hb-graphite2.h" +#include "hb-graphite2-private.hh" #endif #ifdef HAVE_UNISCRIBE -# include "hb-uniscribe.h" +# include "hb-uniscribe-private.hh" #endif #ifdef HAVE_OT -# include "hb-ot-shape.h" +# include "hb-ot-shape-private.hh" #endif #include "hb-fallback-shape-private.hh" typedef hb_bool_t (*hb_shape_func_t) (hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options); + unsigned int num_features); -#define HB_SHAPER_IMPLEMENT(name) {#name, hb_##name##_shape} +#define HB_SHAPER_IMPLEMENT(name) {#name, _hb_##name##_shape} static struct hb_shaper_pair_t { char name[16]; hb_shape_func_t func; } shapers[] = { /* v--- Add new shapers in the right place here */ #ifdef HAVE_GRAPHITE - HB_SHAPER_IMPLEMENT (graphite), + HB_SHAPER_IMPLEMENT (graphite2), #endif #ifdef HAVE_UNISCRIBE HB_SHAPER_IMPLEMENT (uniscribe), @@ -120,22 +119,19 @@ hb_shape_full (hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features, - const char * const *shaper_options, const char * const *shaper_list) { + hb_font_make_immutable (font); /* So we can safely cache stuff on it */ + if (likely (!shaper_list)) { for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++) - if (likely (shapers[i].func (font, buffer, - features, num_features, - shaper_options))) + if (likely (shapers[i].func (font, buffer, features, num_features))) return TRUE; } else { while (*shaper_list) { for (unsigned int i = 0; i < ARRAY_LENGTH (shapers); i++) if (0 == strcmp (*shaper_list, shapers[i].name)) { - if (likely (shapers[i].func (font, buffer, - features, num_features, - shaper_options))) + if (likely (shapers[i].func (font, buffer, features, num_features))) return TRUE; break; } @@ -151,5 +147,5 @@ hb_shape (hb_font_t *font, const hb_feature_t *features, unsigned int num_features) { - hb_shape_full (font, buffer, features, num_features, NULL, NULL); + hb_shape_full (font, buffer, features, num_features, NULL); } diff --git a/third_party/harfbuzz-ng/src/hb-shape.h b/third_party/harfbuzz-ng/src/hb-shape.h index 685b11d..1a0d6cf 100644 --- a/third_party/harfbuzz-ng/src/hb-shape.h +++ b/third_party/harfbuzz-ng/src/hb-shape.h @@ -24,6 +24,10 @@ * Red Hat Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_SHAPE_H #define HB_SHAPE_H @@ -53,7 +57,6 @@ hb_shape_full (hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features, - const char * const *shaper_options, const char * const *shaper_list); const char ** diff --git a/third_party/harfbuzz-ng/src/hb-tt-font.cc b/third_party/harfbuzz-ng/src/hb-tt-font.cc index ccd86e1..b2f24f6 100644 --- a/third_party/harfbuzz-ng/src/hb-tt-font.cc +++ b/third_party/harfbuzz-ng/src/hb-tt-font.cc @@ -24,12 +24,13 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb-font-private.hh" /* Shall be first since may include windows.h */ + #include "hb-open-type-private.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-hmtx-table.hh" -#include "hb-font-private.hh" #include "hb-blob.h" #include <string.h> diff --git a/third_party/harfbuzz-ng/src/hb-unicode-private.hh b/third_party/harfbuzz-ng/src/hb-unicode-private.hh index 2ad8a49..ddba1ac 100644 --- a/third_party/harfbuzz-ng/src/hb-unicode-private.hh +++ b/third_party/harfbuzz-ng/src/hb-unicode-private.hh @@ -97,11 +97,62 @@ extern HB_INTERNAL hb_unicode_funcs_t _hb_glib_unicode_funcs; extern HB_INTERNAL hb_unicode_funcs_t _hb_icu_unicode_funcs; #define _hb_unicode_funcs_default _hb_icu_unicode_funcs #else +#define HB_UNICODE_FUNCS_NIL 1 extern HB_INTERNAL hb_unicode_funcs_t _hb_unicode_funcs_nil; #define _hb_unicode_funcs_default _hb_unicode_funcs_nil #endif +HB_INTERNAL unsigned int +_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode); +static inline hb_bool_t +_hb_unicode_is_variation_selector (hb_codepoint_t unicode) +{ + return unlikely ((unicode >= 0x180B && unicode <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR ONE..THREE */ + (unicode >= 0xFE00 && unicode <= 0xFE0F) || /* VARIATION SELECTOR-1..16 */ + (unicode >= 0xE0100 && unicode <= 0xE01EF)); /* VARIATION SELECTOR-17..256 */ +} + +/* Zero-Width invisible characters: + * + * 00AD SOFT HYPHEN + * 034F COMBINING GRAPHEME JOINER + * + * 200B ZERO WIDTH SPACE + * 200C ZERO WIDTH NON-JOINER + * 200D ZERO WIDTH JOINER + * 200E LEFT-TO-RIGHT MARK + * 200F RIGHT-TO-LEFT MARK + * + * 2028 LINE SEPARATOR + * + * 202A LEFT-TO-RIGHT EMBEDDING + * 202B RIGHT-TO-LEFT EMBEDDING + * 202C POP DIRECTIONAL FORMATTING + * 202D LEFT-TO-RIGHT OVERRIDE + * 202E RIGHT-TO-LEFT OVERRIDE + * + * 2060 WORD JOINER + * 2061 FUNCTION APPLICATION + * 2062 INVISIBLE TIMES + * 2063 INVISIBLE SEPARATOR + * + * FEFF ZERO WIDTH NO-BREAK SPACE + */ +static inline hb_bool_t +_hb_unicode_is_zero_width (hb_codepoint_t ch) +{ + return ((ch & ~0x007F) == 0x2000 && ( + (ch >= 0x200B && ch <= 0x200F) || + (ch >= 0x202A && ch <= 0x202E) || + (ch >= 0x2060 && ch <= 0x2063) || + (ch == 0x2028) + )) || unlikely (ch == 0x0009 + || ch == 0x00AD + || ch == 0x034F + || ch == 0xFEFF); +} #endif /* HB_UNICODE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-unicode.cc b/third_party/harfbuzz-ng/src/hb-unicode.cc index 4b285c5..f2fbebb 100644 --- a/third_party/harfbuzz-ng/src/hb-unicode.cc +++ b/third_party/harfbuzz-ng/src/hb-unicode.cc @@ -85,7 +85,6 @@ hb_unicode_compose_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t *ab HB_UNUSED, void *user_data HB_UNUSED) { - /* TODO handle Hangul jamo here? */ return FALSE; } @@ -96,7 +95,6 @@ hb_unicode_decompose_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t *b HB_UNUSED, void *user_data HB_UNUSED) { - /* TODO handle Hangul jamo here? */ return FALSE; } @@ -271,3 +269,58 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, return ufuncs->func.decompose (ufuncs, ab, a, b, ufuncs->user_data.decompose); } + + +unsigned int +_hb_unicode_modified_combining_class (hb_unicode_funcs_t *ufuncs, + hb_codepoint_t unicode) +{ + int c = hb_unicode_combining_class (ufuncs, unicode); + + if (unlikely (hb_in_range<int> (c, 27, 33))) + { + /* Modify the combining-class to suit Arabic better. See: + * http://unicode.org/faq/normalization.html#8 + * http://unicode.org/faq/normalization.html#9 + */ + c = c == 33 ? 27 : c + 1; + } + else if (unlikely (hb_in_range<int> (c, 10, 25))) + { + /* The equivalent fix for Hebrew is more complex. + * + * We permute the "fixed-position" classes 10-25 into the order + * described in the SBL Hebrew manual: + * + * http://www.sbl-site.org/Fonts/SBLHebrewUserManual1.5x.pdf + * + * (as recommended by: + * http://forum.fontlab.com/archive-old-microsoft-volt-group/vista-and-diacritic-ordering-t6751.0.html) + * + * More details here: + * https://bugzilla.mozilla.org/show_bug.cgi?id=662055 + */ + static const int permuted_hebrew_classes[25 - 10 + 1] = { + /* 10 sheva */ 22, + /* 11 hataf segol */ 15, + /* 12 hataf patah */ 16, + /* 13 hataf qamats */ 17, + /* 14 hiriq */ 23, + /* 15 tsere */ 18, + /* 16 segol */ 19, + /* 17 patah */ 20, + /* 18 qamats */ 21, + /* 19 holam */ 14, + /* 20 qubuts */ 24, + /* 21 dagesh */ 12, + /* 22 meteg */ 25, + /* 23 rafe */ 13, + /* 24 shin dot */ 10, + /* 25 sin dot */ 11, + }; + c = permuted_hebrew_classes[c - 10]; + } + + return c; +} + diff --git a/third_party/harfbuzz-ng/src/hb-unicode.h b/third_party/harfbuzz-ng/src/hb-unicode.h index 13886df..205e4c7 100644 --- a/third_party/harfbuzz-ng/src/hb-unicode.h +++ b/third_party/harfbuzz-ng/src/hb-unicode.h @@ -28,6 +28,10 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_UNICODE_H #define HB_UNICODE_H diff --git a/third_party/harfbuzz-ng/src/hb-uniscribe-private.hh b/third_party/harfbuzz-ng/src/hb-uniscribe-private.hh new file mode 100644 index 0000000..239ab0c --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-uniscribe-private.hh @@ -0,0 +1,42 @@ +/* + * Copyright © 2012 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_UNISCRIBE_PRIVATE_HH +#define HB_UNISCRIBE_PRIVATE_HH + +#include "hb-private.hh" + +#include "hb-uniscribe.h" + + +HB_INTERNAL hb_bool_t +_hb_uniscribe_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features); + + +#endif /* HB_UNISCRIBE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-uniscribe.cc b/third_party/harfbuzz-ng/src/hb-uniscribe.cc index ce86074..584d641 100644 --- a/third_party/harfbuzz-ng/src/hb-uniscribe.cc +++ b/third_party/harfbuzz-ng/src/hb-uniscribe.cc @@ -223,11 +223,10 @@ hb_uniscribe_font_get_hfont (hb_font_t *font) hb_bool_t -hb_uniscribe_shape (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options) +_hb_uniscribe_shape (hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) { buffer->guess_properties (); @@ -360,6 +359,9 @@ retry: glyph_props + glyphs_offset, (int *) &glyphs_len); + for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++) + log_clusters[j] += glyphs_offset; + if (unlikely (items[i].a.fNoGlyphIndex)) FAIL ("ScriptShapeOpenType() set fNoGlyphIndex"); if (unlikely (hr == E_OUTOFMEMORY)) diff --git a/third_party/harfbuzz-ng/src/hb-uniscribe.h b/third_party/harfbuzz-ng/src/hb-uniscribe.h index dbcacd7..216610e 100644 --- a/third_party/harfbuzz-ng/src/hb-uniscribe.h +++ b/third_party/harfbuzz-ng/src/hb-uniscribe.h @@ -27,8 +27,7 @@ #ifndef HB_UNISCRIBE_H #define HB_UNISCRIBE_H -#include "hb-common.h" -#include "hb-shape.h" +#include "hb.h" #define _WIN32_WINNT 0x0500 #include <windows.h> @@ -36,13 +35,6 @@ HB_BEGIN_DECLS -hb_bool_t -hb_uniscribe_shape (hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features, - const char * const *shaper_options); - LOGFONTW * hb_uniscribe_font_get_logfontw (hb_font_t *font); diff --git a/third_party/harfbuzz-ng/src/hb-version.h b/third_party/harfbuzz-ng/src/hb-version.h index c1e3cab..43ec9cf 100644 --- a/third_party/harfbuzz-ng/src/hb-version.h +++ b/third_party/harfbuzz-ng/src/hb-version.h @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_VERSION_H #define HB_VERSION_H @@ -33,10 +37,10 @@ HB_BEGIN_DECLS #define HB_VERSION_MAJOR 0 -#define HB_VERSION_MINOR 7 +#define HB_VERSION_MINOR 9 #define HB_VERSION_MICRO 0 -#define HB_VERSION_STRING "0.7.0" +#define HB_VERSION_STRING "0.9.0" #define HB_VERSION_CHECK(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) >= \ diff --git a/third_party/harfbuzz-ng/src/hb-warning.cc b/third_party/harfbuzz-ng/src/hb-warning.cc new file mode 100644 index 0000000..c13731b --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-warning.cc @@ -0,0 +1,66 @@ +/* + * Copyright © 2012 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-atomic-private.hh" +#include "hb-mutex-private.hh" + + +#if !defined(HB_NO_MT) && defined(HB_ATOMIC_INT_NIL) +#ifdef _MSC_VER +#pragma message("Could not find any system to define atomic_int macros, library will NOT be thread-safe") +#else +#warning "Could not find any system to define atomic_int macros, library will NOT be thread-safe" +#endif +#endif + +#if !defined(HB_NO_MT) && defined(HB_MUTEX_IMPL_NIL) +#ifdef _MSC_VER +#pragma message("Could not find any system to define mutex macros, library will NOT be thread-safe") +#else +#warning "Could not find any system to define mutex macros, library will NOT be thread-safe" +#endif +#endif + +#if !defined(HB_NO_MT) && (defined(HB_ATOMIC_INT_NIL) || defined(HB_MUTEX_IMPL_NIL)) +#ifdef _MSC_VER +#pragma message("To suppress these warnings, define HB_NO_MT") +#else +#warning "To suppress these warnings, define HB_NO_MT" +#endif +#endif + + +#include "hb-unicode-private.hh" + +#if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL) +#ifdef _MSC_VER +#pragma message("Could not find any Unicode functions implementation, you have to provide your own") +#pragma message("To suppress this warnings, define HB_NO_UNICODE_FUNCS") +#else +#warning "Could not find any Unicode functions implementation, you have to provide your own" +#warning "To suppress this warning, define HB_NO_UNICODE_FUNCS" +#endif +#endif diff --git a/third_party/harfbuzz-ng/src/hb.h b/third_party/harfbuzz-ng/src/hb.h index 0a2ebd9..d36040e2 100644 --- a/third_party/harfbuzz-ng/src/hb.h +++ b/third_party/harfbuzz-ng/src/hb.h @@ -26,11 +26,13 @@ #ifndef HB_H #define HB_H +#define HB_H_IN #include "hb-blob.h" #include "hb-buffer.h" #include "hb-common.h" #include "hb-font.h" +#include "hb-set.h" #include "hb-shape.h" #include "hb-unicode.h" #include "hb-version.h" @@ -38,4 +40,5 @@ HB_BEGIN_DECLS HB_END_DECLS +#undef HB_H_IN #endif /* HB_H */ diff --git a/third_party/harfbuzz-ng/src/indic.cc b/third_party/harfbuzz-ng/src/indic.cc new file mode 100644 index 0000000..e00311d --- /dev/null +++ b/third_party/harfbuzz-ng/src/indic.cc @@ -0,0 +1,46 @@ +/* + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb-ot-shape-complex-indic-private.hh" + +int +main (void) +{ + hb_unicode_funcs_t *funcs = hb_unicode_funcs_get_default (); + + printf ("There are split matras without a Unicode decomposition:\n"); + for (hb_codepoint_t u = 0; u < 0x110000; u++) + { + unsigned int type = get_indic_categories (u); + + unsigned int category = type & 0x0F; + unsigned int position = type >> 4; + + hb_codepoint_t a, b; + if (!hb_unicode_decompose (funcs, u, &a, &b)) + printf ("U+%04X\n", u); + } +} diff --git a/third_party/harfbuzz-ng/src/main.cc b/third_party/harfbuzz-ng/src/main.cc index 442b1b9..03b6e6c 100644 --- a/third_party/harfbuzz-ng/src/main.cc +++ b/third_party/harfbuzz-ng/src/main.cc @@ -124,10 +124,11 @@ main (int argc, char **argv) const LangSys &langsys = n_langsys == -1 ? script.get_default_lang_sys () : script.get_lang_sys (n_langsys); - printf (n_langsys == -1 - ? " Default Language System\n" - : " Language System %2d of %2d: %.4s\n", n_langsys, num_langsys, - (const char *)script.get_lang_sys_tag (n_langsys)); + if (n_langsys == -1) + printf (" Default Language System\n"); + else + printf (" Language System %2d of %2d: %.4s\n", n_langsys, num_langsys, + (const char *)script.get_lang_sys_tag (n_langsys)); if (langsys.get_required_feature_index () == Index::NOT_FOUND_INDEX) printf (" No required feature\n"); |