diff options
author | jshin@chromium.org <jshin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-11 20:33:21 +0000 |
---|---|---|
committer | jshin@chromium.org <jshin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-11 20:33:21 +0000 |
commit | 307f7bdd33cf295aac89b436982d40d8ba63fc6a (patch) | |
tree | 6aa1ed56388d1bb2066eacdbaf05c760d1b8f3b3 /third_party/harfbuzz-ng | |
parent | abebfb09457bd903745e5809b3c5ecb99e8f1c63 (diff) | |
download | chromium_src-307f7bdd33cf295aac89b436982d40d8ba63fc6a.zip chromium_src-307f7bdd33cf295aac89b436982d40d8ba63fc6a.tar.gz chromium_src-307f7bdd33cf295aac89b436982d40d8ba63fc6a.tar.bz2 |
Update harfbuzz-ng to 0.9.10 (Jan 3, 2013)
Previous revision: 431bef2e16c7888ca3960f5797432d3a20903550
New revision: 34e6c3e3e452bdf6f93df565a70453a6e74d4c6e
BUG=160254
TEST=See the bug.
Review URL: https://codereview.chromium.org/11781005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176429 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/harfbuzz-ng')
75 files changed, 5191 insertions, 3036 deletions
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium index 7e29086..ec10ad8 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: 20121102 -Revision: 431bef2e16c7888ca3960f5797432d3a20903550 +Date: 20120103 +Revision: 34e6c3e3e452bdf6f93df565a70453a6e74d4c6e (0.9.10) Security Critical: yes License: MIT License File: NOT_SHIPPED @@ -12,4 +12,4 @@ Description: This is harfbuzz-ng, a new implementation of harfbuzz with a different API from the old one. -I also deleted all unneeded files from the root directory (but left src/ alone). +I also deleted all unneeded files from the root directory and src/ directory (hb-icu-le, hb-ucdn, hb-old, scripts to generate data tables, automake/conf files). diff --git a/third_party/harfbuzz-ng/harfbuzz.gyp b/third_party/harfbuzz-ng/harfbuzz.gyp index 58bcbd4..af5d0fc 100644 --- a/third_party/harfbuzz-ng/harfbuzz.gyp +++ b/third_party/harfbuzz-ng/harfbuzz.gyp @@ -58,12 +58,13 @@ 'src/hb-ot-shape-complex-arabic-fallback.hh', 'src/hb-ot-shape-complex-arabic-table.hh', 'src/hb-ot-shape-complex-arabic.cc', + 'src/hb-ot-shape-complex-default.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-complex-thai.cc', 'src/hb-ot-shape-fallback-private.hh', 'src/hb-ot-shape-fallback.cc', 'src/hb-ot-shape-normalize-private.hh', diff --git a/third_party/harfbuzz-ng/src/hb-atomic-private.hh b/third_party/harfbuzz-ng/src/hb-atomic-private.hh index 5861a71..67579cd 100644 --- a/third_party/harfbuzz-ng/src/hb-atomic-private.hh +++ b/third_party/harfbuzz-ng/src/hb-atomic-private.hh @@ -59,7 +59,7 @@ static inline void HBMemoryBarrier (void) { } #endif -typedef long hb_atomic_int_t; +typedef LONG hb_atomic_int_t; #define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) #define hb_atomic_ptr_get(P) (HBMemoryBarrier (), (void *) *(P)) @@ -69,12 +69,25 @@ typedef long hb_atomic_int_t; #elif !defined(HB_NO_MT) && defined(__APPLE__) #include <libkern/OSAtomic.h> +#ifdef __MAC_OS_X_MIN_REQUIRED +#include <AvailabilityMacros.h> +#elif defined(__IPHONE_OS_MIN_REQUIRED) +#include <Availability.h> +#endif typedef int32_t hb_atomic_int_t; #define hb_atomic_int_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V)) #define hb_atomic_ptr_get(P) (OSMemoryBarrier (), (void *) *(P)) +#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) #define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P)) +#else +#if __ppc64__ || __x86_64__ +#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) +#else +#define hb_atomic_ptr_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) +#endif +#endif #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) diff --git a/third_party/harfbuzz-ng/src/hb-buffer-private.hh b/third_party/harfbuzz-ng/src/hb-buffer-private.hh index c1acffd..13cf4bb 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer-private.hh +++ b/third_party/harfbuzz-ng/src/hb-buffer-private.hh @@ -36,48 +36,11 @@ #include "hb-unicode-private.hh" - ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20); ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)); /* - * hb_segment_properties_t - */ - -typedef struct hb_segment_properties_t { - hb_direction_t direction; - hb_script_t script; - hb_language_t language; - ASSERT_POD (); -} hb_segment_properties_t; - -#define _HB_BUFFER_PROPS_DEFAULT { HB_DIRECTION_INVALID, HB_SCRIPT_INVALID, HB_LANGUAGE_INVALID } - -static inline hb_bool_t -hb_segment_properties_equal (const hb_segment_properties_t *a, - const hb_segment_properties_t *b) -{ - return a->direction == b->direction && - a->script == b->script && - a->language == b->language; -} - - -#if 0 -static inline unsigned int -hb_segment_properties_hash (const hb_segment_properties_t *p) -{ - /* TODO improve */ - return (unsigned int) p->direction + - (unsigned int) p->script + - (intptr_t) (p->language); -} -#endif - - - -/* * hb_buffer_t */ @@ -89,6 +52,7 @@ struct hb_buffer_t { hb_unicode_funcs_t *unicode; /* Unicode functions */ hb_segment_properties_t props; /* Script, language, direction */ + hb_buffer_flags_t flags; /* BOT / EOT / etc. */ /* Buffer contents */ @@ -133,6 +97,7 @@ struct hb_buffer_t { /* Methods */ HB_INTERNAL void reset (void); + HB_INTERNAL void clear (void); inline unsigned int backtrack_len (void) const { return have_output? out_len : idx; } @@ -144,13 +109,12 @@ struct hb_buffer_t { HB_INTERNAL void deallocate_var_all (void); HB_INTERNAL void add (hb_codepoint_t codepoint, - hb_mask_t mask, unsigned int cluster); HB_INTERNAL void reverse_range (unsigned int start, unsigned int end); HB_INTERNAL void reverse (void); HB_INTERNAL void reverse_clusters (void); - HB_INTERNAL void guess_properties (void); + HB_INTERNAL void guess_segment_properties (void); HB_INTERNAL void swap_buffers (void); HB_INTERNAL void remove_output (void); diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc index 06b5c05..4b644e4 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer.cc +++ b/third_party/harfbuzz-ng/src/hb-buffer.cc @@ -35,6 +35,29 @@ #define HB_DEBUG_BUFFER (HB_DEBUG+0) #endif + +hb_bool_t +hb_segment_properties_equal (const hb_segment_properties_t *a, + const hb_segment_properties_t *b) +{ + return a->direction == b->direction && + a->script == b->script && + a->language == b->language && + a->reserved1 == b->reserved1 && + a->reserved2 == b->reserved2; + +} + +unsigned int +hb_segment_properties_hash (const hb_segment_properties_t *p) +{ + return (unsigned int) p->direction ^ + (unsigned int) p->script ^ + (intptr_t) (p->language); +} + + + /* Here is how the buffer works internally: * * There are two info pointers: info and out_info. They always have @@ -142,8 +165,18 @@ hb_buffer_t::reset (void) hb_unicode_funcs_destroy (unicode); unicode = hb_unicode_funcs_get_default (); - hb_segment_properties_t default_props = _HB_BUFFER_PROPS_DEFAULT; + clear (); +} + +void +hb_buffer_t::clear (void) +{ + if (unlikely (hb_object_is_inert (this))) + return; + + hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; props = default_props; + flags = HB_BUFFER_FLAGS_DEFAULT; content_type = HB_BUFFER_CONTENT_TYPE_INVALID; in_error = false; @@ -165,7 +198,6 @@ hb_buffer_t::reset (void) void hb_buffer_t::add (hb_codepoint_t codepoint, - hb_mask_t mask, unsigned int cluster) { hb_glyph_info_t *glyph; @@ -176,7 +208,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint, memset (glyph, 0, sizeof (*glyph)); glyph->codepoint = codepoint; - glyph->mask = mask; + glyph->mask = 1; glyph->cluster = cluster; len++; @@ -459,10 +491,10 @@ hb_buffer_t::merge_out_clusters (unsigned int start, } void -hb_buffer_t::guess_properties (void) +hb_buffer_t::guess_segment_properties (void) { - if (unlikely (!len)) return; - assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE); + assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || + (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); /* If script is set to INVALID, guess from buffer contents */ if (props.script == HB_SCRIPT_INVALID) { @@ -561,7 +593,7 @@ void hb_buffer_t::deallocate_var_all (void) /* Public API */ hb_buffer_t * -hb_buffer_create () +hb_buffer_create (void) { hb_buffer_t *buffer; @@ -580,7 +612,8 @@ hb_buffer_get_empty (void) HB_OBJECT_HEADER_STATIC, const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), - _HB_BUFFER_PROPS_DEFAULT, + HB_SEGMENT_PROPERTIES_DEFAULT, + HB_BUFFER_FLAGS_DEFAULT, HB_BUFFER_CONTENT_TYPE_INVALID, true, /* in_error */ @@ -715,6 +748,40 @@ hb_buffer_get_language (hb_buffer_t *buffer) return buffer->props.language; } +void +hb_buffer_set_segment_properties (hb_buffer_t *buffer, + const hb_segment_properties_t *props) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->props = *props; +} + +void +hb_buffer_get_segment_properties (hb_buffer_t *buffer, + hb_segment_properties_t *props) +{ + *props = buffer->props; +} + + +void +hb_buffer_set_flags (hb_buffer_t *buffer, + hb_buffer_flags_t flags) +{ + if (unlikely (hb_object_is_inert (buffer))) + return; + + buffer->flags = flags; +} + +hb_buffer_flags_t +hb_buffer_get_flags (hb_buffer_t *buffer) +{ + return buffer->flags; +} + void hb_buffer_reset (hb_buffer_t *buffer) @@ -722,6 +789,12 @@ hb_buffer_reset (hb_buffer_t *buffer) buffer->reset (); } +void +hb_buffer_clear (hb_buffer_t *buffer) +{ + buffer->clear (); +} + hb_bool_t hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) { @@ -737,10 +810,9 @@ hb_buffer_allocation_successful (hb_buffer_t *buffer) void hb_buffer_add (hb_buffer_t *buffer, hb_codepoint_t codepoint, - hb_mask_t mask, unsigned int cluster) { - buffer->add (codepoint, mask, cluster); + buffer->add (codepoint, cluster); buffer->clear_context (1); } @@ -814,9 +886,9 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer) } void -hb_buffer_guess_properties (hb_buffer_t *buffer) +hb_buffer_guess_segment_properties (hb_buffer_t *buffer) { - buffer->guess_properties (); + buffer->guess_segment_properties (); } template <typename T> @@ -869,7 +941,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer, hb_codepoint_t u; const T *old_next = next; next = hb_utf_next (next, end, &u); - buffer->add (u, 1, old_next - (const T *) text); + buffer->add (u, old_next - (const T *) text); } /* Add post-context */ @@ -992,3 +1064,231 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer) } normalize_glyphs_cluster (buffer, start, end, backward); } + + +/* + * Serialize + */ + +static const char *serialize_formats[] = { + "text", + "json", + NULL +}; + +const char ** +hb_buffer_serialize_list_formats (void) +{ + return serialize_formats; +} + +hb_buffer_serialize_format_t +hb_buffer_serialize_format_from_string (const char *str, int len) +{ + /* Upper-case it. */ + return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020); +} + +const char * +hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) +{ + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; + case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL; + } +} + +static unsigned int +_hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + /* In the following code, we know b is large enough that no overflow can happen. */ + +#define APPEND(s) HB_STMT_START { strcpy (p, s); p += strlen (s); } HB_STMT_END + + if (i) + *p++ = ','; + + *p++ = '{'; + + APPEND ("\"g\":"); + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) + { + char g[128]; + hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); + *p++ = '"'; + for (char *q = g; *q; q++) { + if (*q == '"') + *p++ = '\\'; + *p++ = *q; + } + *p++ = '"'; + } + else + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster); + } + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + { + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", + pos[i].x_offset, pos[i].y_offset); + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", + pos[i].x_advance, pos[i].y_advance); + } + + *p++ = '}'; + + if (buf_size > (p - b)) + { + unsigned int l = p - b; + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + } + + return end - start; +} + +static unsigned int +_hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL); + hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, NULL); + hb_direction_t direction = hb_buffer_get_direction (buffer); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + /* In the following code, we know b is large enough that no overflow can happen. */ + + if (i) + *p++ = '|'; + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) + { + hb_font_glyph_to_string (font, info[i].codepoint, p, 128); + p += strlen (p); + } + else + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster); + } + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) + { + if (pos[i].x_offset || pos[i].y_offset) + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset); + + *p++ = '+'; + if (HB_DIRECTION_IS_HORIZONTAL (direction) || pos[i].x_advance) + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance); + if (HB_DIRECTION_IS_VERTICAL (direction) || pos->y_advance) + p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance); + } + + if (buf_size > (p - b)) + { + unsigned int l = p - b; + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + } + + return end - start; +} + +/* Returns number of items, starting at start, that were serialized. */ +unsigned int +hb_buffer_serialize_glyphs (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) +{ + assert (start <= end && end <= buffer->len); + + *buf_consumed = 0; + + assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || + buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + + if (unlikely (start == end)) + return 0; + + if (!font) + font = hb_font_get_empty (); + + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + return _hb_buffer_serialize_glyphs_text (buffer, start, end, + buf, buf_size, buf_consumed, + font, flags); + + case HB_BUFFER_SERIALIZE_FORMAT_JSON: + return _hb_buffer_serialize_glyphs_json (buffer, start, end, + buf, buf_size, buf_consumed, + font, flags); + + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: + return 0; + + } +} + +hb_bool_t +hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + unsigned int *buf_consumed, + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format) +{ + return false; +} diff --git a/third_party/harfbuzz-ng/src/hb-buffer.h b/third_party/harfbuzz-ng/src/hb-buffer.h index dc63d1b..48ec4a5 100644 --- a/third_party/harfbuzz-ng/src/hb-buffer.h +++ b/third_party/harfbuzz-ng/src/hb-buffer.h @@ -36,12 +36,11 @@ #include "hb-common.h" #include "hb-unicode.h" +#include "hb-font.h" HB_BEGIN_DECLS -typedef struct hb_buffer_t hb_buffer_t; - typedef struct hb_glyph_info_t { hb_codepoint_t codepoint; hb_mask_t mask; @@ -62,13 +61,37 @@ typedef struct hb_glyph_position_t { hb_var_int_t var; } hb_glyph_position_t; -typedef enum { - HB_BUFFER_CONTENT_TYPE_INVALID = 0, - HB_BUFFER_CONTENT_TYPE_UNICODE, - HB_BUFFER_CONTENT_TYPE_GLYPHS -} hb_buffer_content_type_t; + +typedef struct hb_segment_properties_t { + hb_direction_t direction; + hb_script_t script; + hb_language_t language; + /*< private >*/ + void *reserved1; + void *reserved2; +} hb_segment_properties_t; + +#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \ + HB_SCRIPT_INVALID, \ + HB_LANGUAGE_INVALID, \ + NULL, \ + NULL} + +hb_bool_t +hb_segment_properties_equal (const hb_segment_properties_t *a, + const hb_segment_properties_t *b); + +unsigned int +hb_segment_properties_hash (const hb_segment_properties_t *p); + +/* + * hb_buffer_t + */ + +typedef struct hb_buffer_t hb_buffer_t; + hb_buffer_t * hb_buffer_create (void); @@ -93,6 +116,12 @@ hb_buffer_get_user_data (hb_buffer_t *buffer, hb_user_data_key_t *key); +typedef enum { + HB_BUFFER_CONTENT_TYPE_INVALID = 0, + HB_BUFFER_CONTENT_TYPE_UNICODE, + HB_BUFFER_CONTENT_TYPE_GLYPHS +} hb_buffer_content_type_t; + void hb_buffer_set_content_type (hb_buffer_t *buffer, hb_buffer_content_type_t content_type); @@ -126,15 +155,46 @@ void hb_buffer_set_language (hb_buffer_t *buffer, hb_language_t language); + hb_language_t hb_buffer_get_language (hb_buffer_t *buffer); +void +hb_buffer_set_segment_properties (hb_buffer_t *buffer, + const hb_segment_properties_t *props); + +void +hb_buffer_get_segment_properties (hb_buffer_t *buffer, + hb_segment_properties_t *props); + +void +hb_buffer_guess_segment_properties (hb_buffer_t *buffer); + + +typedef enum { + HB_BUFFER_FLAGS_DEFAULT = 0x00000000, + HB_BUFFER_FLAG_BOT = 0x00000001, /* Beginning-of-text */ + HB_BUFFER_FLAG_EOT = 0x00000002, /* End-of-text */ + HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004 +} hb_buffer_flags_t; + +void +hb_buffer_set_flags (hb_buffer_t *buffer, + hb_buffer_flags_t flags); + +hb_buffer_flags_t +hb_buffer_get_flags (hb_buffer_t *buffer); + /* Resets the buffer. Afterwards it's as if it was just created, * except that it has a larger buffer allocated perhaps... */ void hb_buffer_reset (hb_buffer_t *buffer); +/* Like reset, but does NOT clear unicode_funcs. */ +void +hb_buffer_clear (hb_buffer_t *buffer); + /* Returns false if allocation failed */ hb_bool_t hb_buffer_pre_allocate (hb_buffer_t *buffer, @@ -151,16 +211,12 @@ hb_buffer_reverse (hb_buffer_t *buffer); void hb_buffer_reverse_clusters (hb_buffer_t *buffer); -void -hb_buffer_guess_properties (hb_buffer_t *buffer); - /* Filling the buffer in */ void hb_buffer_add (hb_buffer_t *buffer, hb_codepoint_t codepoint, - hb_mask_t mask, unsigned int cluster); void @@ -213,11 +269,53 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer, void hb_buffer_normalize_glyphs (hb_buffer_t *buffer); + /* - * NOT IMPLEMENTED - void - hb_buffer_normalize_characters (hb_buffer_t *buffer); -*/ + * Serialize + */ + +typedef enum { + HB_BUFFER_SERIALIZE_FLAGS_DEFAULT = 0x00000000, + HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001, + HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002, + HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004 +} hb_buffer_serialize_flags_t; + +typedef enum { + HB_BUFFER_SERIALIZE_FORMAT_TEXT = HB_TAG('T','E','X','T'), + HB_BUFFER_SERIALIZE_FORMAT_JSON = HB_TAG('J','S','O','N'), + HB_BUFFER_SERIALIZE_FORMAT_INVALID = HB_TAG_NONE +} hb_buffer_serialize_format_t; + +/* len=-1 means str is NUL-terminated. */ +hb_buffer_serialize_format_t +hb_buffer_serialize_format_from_string (const char *str, int len); + +const char * +hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format); + +const char ** +hb_buffer_serialize_list_formats (void); + +/* Returns number of items, starting at start, that were serialized. */ +unsigned int +hb_buffer_serialize_glyphs (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); + +hb_bool_t +hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + unsigned int *buf_consumed, + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-common.cc b/third_party/harfbuzz-ng/src/hb-common.cc index 33a514d..9422555 100644 --- a/third_party/harfbuzz-ng/src/hb-common.cc +++ b/third_party/harfbuzz-ng/src/hb-common.cc @@ -363,8 +363,7 @@ bool hb_user_data_array_t::set (hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy, - hb_bool_t replace, - hb_mutex_t &lock) + hb_bool_t replace) { if (!key) return false; @@ -382,20 +381,13 @@ hb_user_data_array_t::set (hb_user_data_key_t *key, } void * -hb_user_data_array_t::get (hb_user_data_key_t *key, - hb_mutex_t &lock) +hb_user_data_array_t::get (hb_user_data_key_t *key) { hb_user_data_item_t item = {NULL }; return items.find (key, &item, lock) ? item.data : NULL; } -void -hb_user_data_array_t::finish (hb_mutex_t &lock) -{ - items.finish (lock); -} - /* hb_version */ diff --git a/third_party/harfbuzz-ng/src/hb-coretext.cc b/third_party/harfbuzz-ng/src/hb-coretext.cc index 4152a39..8f94795 100644 --- a/third_party/harfbuzz-ng/src/hb-coretext.cc +++ b/third_party/harfbuzz-ng/src/hb-coretext.cc @@ -29,10 +29,6 @@ #define HB_SHAPER coretext #include "hb-shaper-impl-private.hh" -#define GlyphID GlyphID_mac -#include <ApplicationServices/ApplicationServices.h> -#undef GlyphID - #include "hb-coretext.h" @@ -95,6 +91,14 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) free (data); } +CGFontRef +hb_coretext_face_get_cg_font (hb_face_t *face) +{ + if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; + hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); + return face_data->cg_font; +} + /* * shaper font data @@ -153,19 +157,19 @@ _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_ { } - -/* - * shaper - */ - CTFontRef hb_coretext_font_get_ct_font (hb_font_t *font) { - if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return 0; + if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return NULL; hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); return font_data->ct_font; } + +/* + * shaper + */ + hb_bool_t _hb_coretext_shape (hb_shape_plan_t *shape_plan, hb_font_t *font, @@ -212,26 +216,22 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, CFDictionaryRef attrs = CFDictionaryCreate (kCFAllocatorDefault, (const void**) &kCTFontAttributeName, (const void**) &font_data->ct_font, - 1, // count of attributes + 1, /* count of attributes */ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - // TODO: support features + /* TODO: support features */ - // Now we can create an attributed string CFAttributedStringRef attr_string = CFAttributedStringCreate (kCFAllocatorDefault, string_ref, attrs); CFRelease (string_ref); CFRelease (attrs); - // Create the CoreText line from our string, then we're done with it CTLineRef line = CTLineCreateWithAttributedString (attr_string); CFRelease (attr_string); - // and finally retrieve the glyph data and store into the gfxTextRun CFArrayRef glyph_runs = CTLineGetGlyphRuns (line); unsigned int num_runs = CFArrayGetCount (glyph_runs); - // Iterate through the glyph runs. bool success = true; buffer->len = 0; @@ -246,11 +246,9 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, buffer->ensure (buffer->len + num_glyphs); - // retrieve the laid-out glyph data from the CTRun - - // Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds, - // and so copying data to our own buffer with CTRunGetGlyphs will be - // extremely rare. + /* Testing indicates that CTRunGetGlyphsPtr (almost?) always succeeds, + * and so copying data to our own buffer with CTRunGetGlyphs will be + * extremely rare. */ unsigned int scratch_size; char *scratch = (char *) buffer->get_scratch_buffer (&scratch_size); @@ -294,7 +292,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, info->codepoint = glyphs[j]; info->cluster = string_indices[j]; - // currently, we do all x-positioning by setting the advance, we never use x-offset + /* Currently, we do all x-positioning by setting the advance, we never use x-offset. */ info->mask = advance; info->var1.u32 = 0; info->var2.u32 = positions[j].y; @@ -316,12 +314,13 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, pos->y_offset = info->var2.u32; } - // Fix up clusters so that we never return out-of-order indices; - // if core text has reordered glyphs, we'll merge them to the - // beginning of the reordered cluster. - // This does *not* mean we'll form the same clusters as Uniscribe - // or the native OT backend, only that the cluster indices will be - // non-decreasing in the output buffer. + /* Fix up clusters so that we never return out-of-order indices; + * if core text has reordered glyphs, we'll merge them to the + * beginning of the reordered cluster. + * + * This does *not* mean we'll form the same clusters as Uniscribe + * or the native OT backend, only that the cluster indices will be + * monotonic in the output buffer. */ if (HB_DIRECTION_IS_FORWARD (buffer->props.direction)) { unsigned int prev_cluster = 0; for (unsigned int i = 0; i < count; i++) { @@ -337,7 +336,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, prev_cluster = curr_cluster; } } else { - // For RTL runs, we make them non-increasing instead. unsigned int prev_cluster = (unsigned int)-1; for (unsigned int i = 0; i < count; i++) { unsigned int curr_cluster = buffer->info[i].cluster; diff --git a/third_party/harfbuzz-ng/src/hb-coretext.h b/third_party/harfbuzz-ng/src/hb-coretext.h index 0b34203..c4954fa 100644 --- a/third_party/harfbuzz-ng/src/hb-coretext.h +++ b/third_party/harfbuzz-ng/src/hb-coretext.h @@ -34,6 +34,9 @@ HB_BEGIN_DECLS +CGFontRef +hb_coretext_face_get_cg_font (hb_face_t *face); + CTFontRef hb_coretext_font_get_ct_font (hb_font_t *font); diff --git a/third_party/harfbuzz-ng/src/hb-fallback-shape.cc b/third_party/harfbuzz-ng/src/hb-fallback-shape.cc index 3f9024f..bdc8a80 100644 --- a/third_party/harfbuzz-ng/src/hb-fallback-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-fallback-shape.cc @@ -35,13 +35,13 @@ struct hb_fallback_shaper_face_data_t {}; hb_fallback_shaper_face_data_t * -_hb_fallback_shaper_face_data_create (hb_face_t *face) +_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED) { return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data) +_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED) { } @@ -53,13 +53,13 @@ _hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data) struct hb_fallback_shaper_font_data_t {}; hb_fallback_shaper_font_data_t * -_hb_fallback_shaper_font_data_create (hb_font_t *font) +_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED) { return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data) +_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED) { } @@ -89,7 +89,7 @@ _hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_ */ hb_bool_t -_hb_fallback_shape (hb_shape_plan_t *shape_plan, +_hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features HB_UNUSED, @@ -98,7 +98,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan, hb_codepoint_t space; font->get_glyph (' ', 0, &space); - buffer->guess_properties (); + buffer->guess_segment_properties (); buffer->clear_positions (); unsigned int count = buffer->len; diff --git a/third_party/harfbuzz-ng/src/hb-font-private.hh b/third_party/harfbuzz-ng/src/hb-font-private.hh index b6dafbf..48fbb0e 100644 --- a/third_party/harfbuzz-ng/src/hb-font-private.hh +++ b/third_party/harfbuzz-ng/src/hb-font-private.hh @@ -100,6 +100,7 @@ struct hb_face_t { unsigned int index; mutable unsigned int upem; + mutable unsigned int num_glyphs; struct hb_shaper_data_t shaper_data; @@ -130,8 +131,16 @@ struct hb_face_t { return upem; } + inline unsigned int get_num_glyphs (void) const + { + if (unlikely (num_glyphs == (unsigned int) -1)) + load_num_glyphs (); + return num_glyphs; + } + private: HB_INTERNAL void load_upem (void) const; + HB_INTERNAL void load_num_glyphs (void) const; }; #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS diff --git a/third_party/harfbuzz-ng/src/hb-font.cc b/third_party/harfbuzz-ng/src/hb-font.cc index 0627032..b59fdeb 100644 --- a/third_party/harfbuzz-ng/src/hb-font.cc +++ b/third_party/harfbuzz-ng/src/hb-font.cc @@ -34,6 +34,7 @@ #include "hb-blob.h" #include "hb-open-file-private.hh" #include "hb-ot-head-table.hh" +#include "hb-ot-maxp-table.hh" #include "hb-cache-private.hh" @@ -520,6 +521,7 @@ static const hb_face_t _hb_face_nil = { 0, /* index */ 1000, /* upem */ + 0, /* num_glyphs */ { #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, @@ -549,6 +551,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, face->destroy = destroy; face->upem = 0; + face->num_glyphs = (unsigned int) -1; return face; } @@ -736,7 +739,6 @@ hb_face_get_upem (hb_face_t *face) return face->get_upem (); } - void hb_face_t::load_upem (void) const { @@ -746,6 +748,31 @@ hb_face_t::load_upem (void) const hb_blob_destroy (head_blob); } +void +hb_face_set_glyph_count (hb_face_t *face, + unsigned int glyph_count) +{ + if (hb_object_is_inert (face)) + return; + + face->num_glyphs = glyph_count; +} + +unsigned int +hb_face_get_glyph_count (hb_face_t *face) +{ + return face->get_num_glyphs (); +} + +void +hb_face_t::load_num_glyphs (void) const +{ + hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp)); + const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob); + num_glyphs = maxp_table->get_num_glyphs (); + hb_blob_destroy (maxp_blob); +} + /* * hb_font_t diff --git a/third_party/harfbuzz-ng/src/hb-font.h b/third_party/harfbuzz-ng/src/hb-font.h index d796856..88d4895 100644 --- a/third_party/harfbuzz-ng/src/hb-font.h +++ b/third_party/harfbuzz-ng/src/hb-font.h @@ -105,6 +105,13 @@ hb_face_set_upem (hb_face_t *face, unsigned int hb_face_get_upem (hb_face_t *face); +void +hb_face_set_glyph_count (hb_face_t *face, + unsigned int glyph_count); + +unsigned int +hb_face_get_glyph_count (hb_face_t *face); + /* * hb_font_funcs_t diff --git a/third_party/harfbuzz-ng/src/hb-ft.cc b/third_party/harfbuzz-ng/src/hb-ft.cc index 9ac556e..6198185 100644 --- a/third_party/harfbuzz-ng/src/hb-ft.cc +++ b/third_party/harfbuzz-ng/src/hb-ft.cc @@ -242,7 +242,7 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, FT_Face ft_face = (FT_Face) font_data; hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); - if (!ret) + if (!ret || (size && !*name)) snprintf (name, size, "gid%u", glyph); return ret; diff --git a/third_party/harfbuzz-ng/src/hb-glib.cc b/third_party/harfbuzz-ng/src/hb-glib.cc index 0462758..676e660 100644 --- a/third_party/harfbuzz-ng/src/hb-glib.cc +++ b/third_party/harfbuzz-ng/src/hb-glib.cc @@ -334,7 +334,7 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, } static unsigned int -hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, +hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t u, hb_codepoint_t *decomposed, void *user_data HB_UNUSED) diff --git a/third_party/harfbuzz-ng/src/hb-graphite2.cc b/third_party/harfbuzz-ng/src/hb-graphite2.cc index 6c890d4..16ef9a4 100644 --- a/third_party/harfbuzz-ng/src/hb-graphite2.cc +++ b/third_party/harfbuzz-ng/src/hb-graphite2.cc @@ -113,7 +113,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face) hb_blob_destroy (silf_blob); data->face = face; - data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_default); + data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll); if (unlikely (!data->grface)) { free (data); @@ -141,6 +141,13 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data) free (data); } +gr_face * +hb_graphite2_face_get_gr_face (hb_face_t *face) +{ + if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL; + return HB_SHAPER_DATA_GET (face)->grface; +} + /* * shaper font data @@ -168,6 +175,13 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data) gr_font_destroy (data); } +gr_font * +hb_graphite2_font_get_gr_font (hb_font_t *font) +{ + if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL; + return HB_SHAPER_DATA_GET (font); +} + /* * shaper shape_plan data @@ -311,10 +325,18 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan, } ci++; - buffer->clear_output (); + //buffer->clear_output (); for (unsigned int i = 0; i < ci; ++i) - buffer->replace_glyphs (clusters[i].num_chars, clusters[i].num_glyphs, gids + clusters[i].base_glyph); - buffer->swap_buffers (); + { + for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j) + { + hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j]; + info->codepoint = gids[clusters[i].base_glyph + j]; + info->cluster = gr_cinfo_base(gr_seg_cinfo(seg, clusters[i].base_char)); + } + } + buffer->len = glyph_count; + //buffer->swap_buffers (); if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) curradvx = gr_seg_advance_X(seg); diff --git a/third_party/harfbuzz-ng/src/hb-graphite2.h b/third_party/harfbuzz-ng/src/hb-graphite2.h index 8122495..bea68f9 100644 --- a/third_party/harfbuzz-ng/src/hb-graphite2.h +++ b/third_party/harfbuzz-ng/src/hb-graphite2.h @@ -33,7 +33,13 @@ HB_BEGIN_DECLS #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f') -/* TODO add gr_font/face etc getters and other glue API */ + +gr_face * +hb_graphite2_face_get_gr_face (hb_face_t *face); + +gr_font * +hb_graphite2_font_get_gr_font (hb_font_t *font); + HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-icu-le.cc b/third_party/harfbuzz-ng/src/hb-icu-le.cc index d73752d..c05d330 100644 --- a/third_party/harfbuzz-ng/src/hb-icu-le.cc +++ b/third_party/harfbuzz-ng/src/hb-icu-le.cc @@ -43,13 +43,13 @@ struct hb_icu_le_shaper_face_data_t {}; hb_icu_le_shaper_face_data_t * -_hb_icu_le_shaper_face_data_create (hb_face_t *face) +_hb_icu_le_shaper_face_data_create (hb_face_t *face HB_UNUSED) { return (hb_icu_le_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data) +_hb_icu_le_shaper_face_data_destroy (hb_icu_le_shaper_face_data_t *data HB_UNUSED) { } @@ -88,7 +88,7 @@ _hb_icu_le_shaper_font_data_destroy (hb_icu_le_shaper_font_data_t *data) struct hb_icu_le_shaper_shape_plan_data_t {}; hb_icu_le_shaper_shape_plan_data_t * -_hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, +_hb_icu_le_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, const hb_feature_t *user_features, unsigned int num_user_features) { @@ -115,7 +115,7 @@ _hb_icu_le_shape (hb_shape_plan_t *shape_plan, LEFontInstance *font_instance = HB_SHAPER_DATA_GET (font); le_int32 script_code = hb_icu_script_from_script (shape_plan->props.script); le_int32 language_code = -1 /* TODO */; - le_int32 typography_flags = 3; // essential for ligatures and kerning + le_int32 typography_flags = 3; /* Needed for ligatures and kerning */ LEErrorCode status = LE_NO_ERROR; le_engine *le = le_create ((const le_font *) font_instance, script_code, diff --git a/third_party/harfbuzz-ng/src/hb-object-private.hh b/third_party/harfbuzz-ng/src/hb-object-private.hh index c48f242..8a9ae34d 100644 --- a/third_party/harfbuzz-ng/src/hb-object-private.hh +++ b/third_party/harfbuzz-ng/src/hb-object-private.hh @@ -65,7 +65,7 @@ struct hb_reference_count_t /* user_data */ -#define HB_USER_DATA_ARRAY_INIT {HB_LOCKABLE_SET_INIT} +#define HB_USER_DATA_ARRAY_INIT {HB_MUTEX_INIT, HB_LOCKABLE_SET_INIT} struct hb_user_data_array_t { /* TODO Add tracing. */ @@ -81,20 +81,19 @@ struct hb_user_data_array_t void finish (void) { if (destroy) destroy (data); } }; + hb_mutex_t lock; hb_lockable_set_t<hb_user_data_item_t, hb_mutex_t> items; - inline void init (void) { items.init (); } + inline void init (void) { lock.init (); items.init (); } HB_INTERNAL bool set (hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy, - hb_bool_t replace, - hb_mutex_t &lock); + hb_bool_t replace); - HB_INTERNAL void *get (hb_user_data_key_t *key, - hb_mutex_t &lock); + HB_INTERNAL void *get (hb_user_data_key_t *key); - HB_INTERNAL void finish (hb_mutex_t &lock); + inline void finish (void) { items.finish (lock); lock.finish (); } }; @@ -103,10 +102,9 @@ struct hb_user_data_array_t struct hb_object_header_t { hb_reference_count_t ref_count; - hb_mutex_t mutex; hb_user_data_array_t user_data; -#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_MUTEX_INIT, HB_USER_DATA_ARRAY_INIT} +#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INVALID, HB_USER_DATA_ARRAY_INIT} static inline void *create (unsigned int size) { hb_object_header_t *obj = (hb_object_header_t *) calloc (1, size); @@ -119,7 +117,6 @@ struct hb_object_header_t inline void init (void) { ref_count.init (1); - mutex.init (); user_data.init (); } @@ -140,20 +137,11 @@ struct hb_object_header_t return false; ref_count.finish (); /* Do this before user_data */ - user_data.finish (mutex); - mutex.finish (); + user_data.finish (); return true; } - inline void lock (void) { - mutex.lock (); - } - - inline void unlock (void) { - mutex.unlock (); - } - inline bool set_user_data (hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy_func, @@ -161,14 +149,14 @@ struct hb_object_header_t if (unlikely (!this || this->is_inert ())) return false; - return user_data.set (key, data, destroy_func, replace, mutex); + return user_data.set (key, data, destroy_func, replace); } inline void *get_user_data (hb_user_data_key_t *key) { if (unlikely (!this || this->is_inert ())) return NULL; - return user_data.get (key, mutex); + return user_data.get (key); } inline void trace (const char *function) const { @@ -219,18 +207,6 @@ static inline bool hb_object_destroy (Type *obj) return obj->header.destroy (); } template <typename Type> -static inline void hb_object_lock (Type *obj) -{ - hb_object_trace (obj, HB_FUNC); - return obj->header.lock (); -} -template <typename Type> -static inline void hb_object_unlock (Type *obj) -{ - hb_object_trace (obj, HB_FUNC); - return obj->header.unlock (); -} -template <typename Type> static inline bool hb_object_set_user_data (Type *obj, hb_user_data_key_t *key, void * data, diff --git a/third_party/harfbuzz-ng/src/hb-old.cc b/third_party/harfbuzz-ng/src/hb-old.cc index 529bffa..a7ea8ed 100644 --- a/third_party/harfbuzz-ng/src/hb-old.cc +++ b/third_party/harfbuzz-ng/src/hb-old.cc @@ -100,7 +100,7 @@ hb_old_convertStringToGlyphIndices (HB_Font old_font, glyphs[i] = u; } - *numGlyphs = length; // XXX + *numGlyphs = length; /* XXX */ return true; } @@ -110,7 +110,7 @@ hb_old_getGlyphAdvances (HB_Font old_font, const HB_Glyph *glyphs, hb_uint32 numGlyphs, HB_Fixed *advances, - int flags /*HB_ShaperFlag*/) + int flags /*HB_ShaperFlag*/ HB_UNUSED) { hb_font_t *font = (hb_font_t *) old_font->userData; @@ -123,7 +123,7 @@ hb_old_canRender (HB_Font old_font, const HB_UChar16 *string, hb_uint32 length) { - return true; // TODO + return true; /* TODO */ } static HB_Error @@ -135,7 +135,7 @@ hb_old_getPointInOutline (HB_Font old_font, HB_Fixed *ypos, hb_uint32 *nPoints) { - return HB_Err_Ok; // TODO + return HB_Err_Ok; /* TODO */ } static void @@ -230,8 +230,8 @@ _hb_old_shaper_font_data_create (hb_font_t *font) data->klass = &hb_old_font_class; data->x_ppem = font->x_ppem; data->y_ppem = font->y_ppem; - data->x_scale = font->x_scale; // XXX - data->y_scale = font->y_scale; // XXX + data->x_scale = font->x_scale; /* XXX */ + data->y_scale = font->y_scale; /* XXX */ data->userData = font; return data; @@ -251,15 +251,15 @@ _hb_old_shaper_font_data_destroy (hb_old_shaper_font_data_t *data) struct hb_old_shaper_shape_plan_data_t {}; hb_old_shaper_shape_plan_data_t * -_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, - const hb_feature_t *user_features, - unsigned int num_user_features) +_hb_old_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED, + const hb_feature_t *user_features HB_UNUSED, + unsigned int num_user_features HB_UNUSED) { return (hb_old_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; } void -_hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data) +_hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data HB_UNUSED) { } @@ -269,7 +269,7 @@ _hb_old_shaper_shape_plan_data_destroy (hb_old_shaper_shape_plan_data_t *data) */ hb_bool_t -_hb_old_shape (hb_shape_plan_t *shape_plan, +_hb_old_shape (hb_shape_plan_t *shape_plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, @@ -369,7 +369,7 @@ retry: *p = MIN (*p, buffer->info[i].cluster); } for (unsigned int i = 1; i < num_glyphs; i++) - if (vis_clusters[i] == -1) + if (vis_clusters[i] == (uint32_t) -1) vis_clusters[i] = vis_clusters[i - 1]; #undef utf16_index 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 31fedfb..250504a 100644 --- a/third_party/harfbuzz-ng/src/hb-open-file-private.hh +++ b/third_party/harfbuzz-ng/src/hb-open-file-private.hh @@ -54,7 +54,7 @@ struct TTCHeader; typedef struct TableRecord { inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -103,7 +103,7 @@ typedef struct OffsetTable public: inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables)); } @@ -131,7 +131,7 @@ struct TTCHeaderVersion1 inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (table.sanitize (c, this)); } @@ -170,7 +170,7 @@ struct TTCHeader } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); 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 */ @@ -232,7 +232,7 @@ struct OpenTypeFontFile } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false); switch (u.tag) { case CFFTag: /* All the non-collection tags */ @@ -255,7 +255,7 @@ struct OpenTypeFontFile }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OPEN_FILE_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-open-type-private.hh b/third_party/harfbuzz-ng/src/hb-open-type-private.hh index 3067b90..5bfeb16 100644 --- a/third_party/harfbuzz-ng/src/hb-open-type-private.hh +++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh @@ -37,6 +37,7 @@ namespace OT { + /* * Casts */ @@ -138,13 +139,13 @@ static const void *_NullPool[64 / sizeof (void *)]; /* Generic nul-content Null objects. */ template <typename Type> static inline const Type& Null (void) { - ASSERT_STATIC (Type::min_size <= sizeof (_NullPool)); + ASSERT_STATIC (sizeof (Type) <= sizeof (_NullPool)); return *CastP<Type> (_NullPool); } /* Specializaiton for arbitrary-content arbitrary-sized Null objects. */ #define DEFINE_NULL_DATA(Type, data) \ -static const char _Null##Type[Type::min_size + 1] = data; /* +1 is for nul-termination in data */ \ +static const char _Null##Type[sizeof (Type) + 1] = data; /* +1 is for nul-termination in data */ \ template <> \ inline const Type& Null<Type> (void) { \ return *CastP<Type> (_Null##Type); \ @@ -165,12 +166,22 @@ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) #endif -#define TRACE_SANITIZE() \ - hb_auto_trace_t<HB_DEBUG_SANITIZE> trace (&c->debug_depth, "SANITIZE", this, HB_FUNC, ""); +#define TRACE_SANITIZE(this) \ + hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + ""); struct hb_sanitize_context_t { + inline const char *get_name (void) { return "SANITIZE"; } + static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE; + typedef bool return_t; + template <typename T> + inline return_t process (const T &obj) { return obj.sanitize (this); } + static return_t default_return_value (void) { return true; } + bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; } + inline void init (hb_blob_t *b) { this->blob = hb_blob_reference (b); @@ -205,10 +216,11 @@ struct hb_sanitize_context_t { const char *p = (const char *) base; - 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); + hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> 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)); } @@ -218,10 +230,11 @@ struct hb_sanitize_context_t const char *p = (const char *) base; bool overflows = _hb_unsigned_int_mul_overflows (len, record_size); - 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); + hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> 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 TRACE_RETURN (likely (!overflows && this->check_range (base, record_size * len))); } @@ -237,11 +250,13 @@ struct hb_sanitize_context_t const char *p = (const char *) base; this->edit_count++; - 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); + hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> 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, + this->writable ? "GRANTED" : "DENIED"); return TRACE_RETURN (this->writable); } @@ -336,8 +351,10 @@ struct Sanitizer #endif -#define TRACE_SERIALIZE() \ - hb_auto_trace_t<HB_DEBUG_SERIALIZE> trace (&c->debug_depth, "SERIALIZE", c, HB_FUNC, ""); +#define TRACE_SERIALIZE(this) \ + hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \ + (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ + ""); struct hb_serialize_context_t @@ -518,32 +535,43 @@ struct BEInt<Type, 4> inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); } private: uint8_t v[4]; }; +template <typename Type> +struct BEInt<Type, 3> +{ + public: + inline void set (Type i) { hb_be_uint24_put (v,i); } + inline operator Type (void) const { return hb_be_uint24_get (v); } + inline bool operator == (const BEInt<Type, 3>& o) const { return hb_be_uint24_eq (v, o.v); } + inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); } + private: uint8_t v[3]; +}; /* Integer types in big-endian order and no alignment requirement */ -template <typename Type> +template <typename Type, unsigned int Size> struct IntType { inline void set (Type i) { v.set (i); } inline operator Type(void) const { return v; } - inline bool operator == (const IntType<Type> &o) const { return v == o.v; } - inline bool operator != (const IntType<Type> &o) const { return v != o.v; } - static inline int cmp (const IntType<Type> *a, const IntType<Type> *b) { return b->cmp (*a); } - inline int cmp (IntType<Type> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; } + inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; } + inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; } + static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); } + inline int cmp (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; } 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 (); + TRACE_SANITIZE (this); return TRACE_RETURN (likely (c->check_struct (this))); } protected: - BEInt<Type, sizeof (Type)> v; + BEInt<Type, Size> v; public: - DEFINE_SIZE_STATIC (sizeof (Type)); + DEFINE_SIZE_STATIC (Size); }; -typedef IntType<uint16_t> USHORT; /* 16-bit unsigned integer. */ -typedef IntType<int16_t> SHORT; /* 16-bit signed integer. */ -typedef IntType<uint32_t> ULONG; /* 32-bit unsigned integer. */ -typedef IntType<int32_t> LONG; /* 32-bit signed integer. */ +typedef IntType<uint16_t, 2> USHORT; /* 16-bit unsigned integer. */ +typedef IntType<int16_t, 2> SHORT; /* 16-bit signed integer. */ +typedef IntType<uint32_t, 4> ULONG; /* 32-bit unsigned integer. */ +typedef IntType<int32_t, 4> LONG; /* 32-bit signed integer. */ +typedef IntType<uint32_t, 3> UINT24; /* 24-bit unsigned integer. */ /* 16-bit signed integer (SHORT) that describes a quantity in FUnits. */ typedef SHORT FWORD; @@ -556,7 +584,7 @@ typedef USHORT UFWORD; struct LONGDATETIME { inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (likely (c->check_struct (this))); } private: @@ -620,7 +648,7 @@ struct FixedVersion inline uint32_t to_int (void) const { return (major << 16) + minor; } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -660,7 +688,7 @@ struct GenericOffsetTo : OffsetType } inline bool sanitize (hb_sanitize_context_t *c, void *base) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); unsigned int offset = *this; if (unlikely (!offset)) return TRACE_RETURN (true); @@ -669,7 +697,7 @@ struct GenericOffsetTo : OffsetType } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); unsigned int offset = *this; if (unlikely (!offset)) return TRACE_RETURN (true); @@ -677,7 +705,13 @@ struct GenericOffsetTo : OffsetType return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c)); } - private: + inline bool try_set (hb_sanitize_context_t *c, const OffsetType &v) { + if (c->may_edit (this, this->static_size)) { + this->set (v); + return true; + } + return false; + } /* Set the offset to Null */ inline bool neuter (hb_sanitize_context_t *c) { if (c->may_edit (this, this->static_size)) { @@ -733,7 +767,7 @@ struct GenericArrayOf inline bool serialize (hb_serialize_context_t *c, unsigned int items_len) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); len.set (items_len); /* TODO(serialize) Overflow? */ if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); @@ -744,7 +778,7 @@ struct GenericArrayOf Supplier<Type> &items, unsigned int items_len) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false); for (unsigned int i = 0; i < items_len; i++) array[i] = items[i]; @@ -753,7 +787,7 @@ struct GenericArrayOf } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); /* Note: for structs that do not reference other structs, @@ -768,7 +802,7 @@ struct GenericArrayOf return TRACE_RETURN (true); } inline bool sanitize (hb_sanitize_context_t *c, void *base) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); unsigned int count = len; for (unsigned int i = 0; i < count; i++) @@ -778,7 +812,7 @@ struct GenericArrayOf } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); unsigned int count = len; for (unsigned int i = 0; i < count; i++) @@ -789,7 +823,7 @@ struct GenericArrayOf private: inline bool sanitize_shallow (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len)); } @@ -831,12 +865,12 @@ struct OffsetListOf : OffsetArrayOf<Type> } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (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 (); + TRACE_SANITIZE (this); return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data)); } }; @@ -859,7 +893,7 @@ struct HeadlessArrayOf Supplier<Type> &items, unsigned int items_len) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); len.set (items_len); /* TODO(serialize) Overflow? */ if (unlikely (!items_len)) return TRACE_RETURN (true); @@ -876,7 +910,7 @@ struct HeadlessArrayOf } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); /* Note: for structs that do not reference other structs, @@ -922,7 +956,7 @@ struct SortedArrayOf : ArrayOf<Type> { }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OPEN_TYPE_PRIVATE_HH */ 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 0934168..3a94512 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh @@ -47,12 +47,12 @@ struct head inline unsigned int get_upem (void) const { unsigned int upem = unitsPerEm; - /* If no valid head table found, assume 1000, which matches typicaly Type1 usage. */ + /* If no valid head table found, assume 1000, which matches typical Type1 usage. */ return 16 <= upem && upem <= 16384 ? upem : 1000; } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); } @@ -143,7 +143,7 @@ struct head }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_HEAD_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh index 5009e6b..2b89c4e 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh @@ -45,7 +45,7 @@ struct hhea static const hb_tag_t Tag = HB_OT_TAG_hhea; inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); } @@ -91,7 +91,7 @@ struct hhea }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_HHEA_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh index feb6016..b94337d 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh @@ -53,7 +53,7 @@ struct hmtx static const hb_tag_t Tag = HB_OT_TAG_hmtx; inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); /* We don't check for anything specific here. The users of the * struct do all the hard work... */ return TRACE_RETURN (true); @@ -86,7 +86,7 @@ struct hmtx }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_HMTX_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh index f5a067a..e6018db 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 @@ -60,9 +60,14 @@ struct Record return tag.cmp (a); } + struct sanitize_closure_t { + hb_tag_t tag; + void *list_base; + }; inline bool sanitize (hb_sanitize_context_t *c, void *base) { - TRACE_SANITIZE (); - return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base)); + TRACE_SANITIZE (this); + const sanitize_closure_t closure = {tag, base}; + return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure)); } Tag tag; /* 4-byte Tag identifier */ @@ -115,7 +120,7 @@ struct RecordListOf : RecordArrayOf<Type> { return this+RecordArrayOf<Type>::operator [](i).offset; } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this)); } }; @@ -129,7 +134,7 @@ struct RangeRecord } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -192,8 +197,9 @@ struct LangSys return reqFeatureIndex;; } - inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + inline bool sanitize (hb_sanitize_context_t *c, + const Record<LangSys>::sanitize_closure_t * = NULL) { + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c)); } @@ -230,8 +236,9 @@ struct Script inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } - inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + inline bool sanitize (hb_sanitize_context_t *c, + const Record<Script>::sanitize_closure_t * = NULL) { + TRACE_SANITIZE (this); return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); } @@ -249,6 +256,219 @@ struct Script typedef RecordListOf<Script> ScriptList; +/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ +struct FeatureParamsSize +{ + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); + + /* This subtable has some "history", if you will. Some earlier versions of + * Adobe tools calculated the offset of the FeatureParams sutable from the + * beginning of the FeatureList table! Now, that is dealt with in the + * Feature implementation. But we still need to be able to tell junk from + * real data. Note: We don't check that the nameID actually exists. + * + * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk : + * + * Yes, it is correct that a new version of the AFDKO (version 2.0) will be + * coming out soon, and that the makeotf program will build a font with a + * 'size' feature that is correct by the specification. + * + * The specification for this feature tag is in the "OpenType Layout Tag + * Registry". You can see a copy of this at: + * http://partners.adobe.com/public/developer/opentype/index_tag8.html#size + * + * Here is one set of rules to determine if the 'size' feature is built + * correctly, or as by the older versions of MakeOTF. You may be able to do + * better. + * + * Assume that the offset to the size feature is according to specification, + * and make the following value checks. If it fails, assume the the size + * feature is calculated as versions of MakeOTF before the AFDKO 2.0 built it. + * If this fails, reject the 'size' feature. The older makeOTF's calculated the + * offset from the beginning of the FeatureList table, rather than from the + * beginning of the 'size' Feature table. + * + * If "design size" == 0: + * fails check + * + * Else if ("subfamily identifier" == 0 and + * "range start" == 0 and + * "range end" == 0 and + * "range start" == 0 and + * "menu name ID" == 0) + * passes check: this is the format used when there is a design size + * specified, but there is no recommended size range. + * + * Else if ("design size" < "range start" or + * "design size" > "range end" or + * "range end" <= "range start" or + * "menu name ID" < 256 or + * "menu name ID" > 32767 or + * menu name ID is not a name ID which is actually in the name table) + * fails test + * Else + * passes test. + */ + + if (!designSize) + return TRACE_RETURN (false); + else if (subfamilyID == 0 && + subfamilyNameID == 0 && + rangeStart == 0 && + rangeEnd == 0) + return TRACE_RETURN (true); + else if (designSize < rangeStart || + designSize > rangeEnd || + subfamilyNameID < 256 || + subfamilyNameID > 32767) + return TRACE_RETURN (false); + else + return TRACE_RETURN (true); + } + + USHORT designSize; /* Represents the design size in 720/inch + * units (decipoints). The design size entry + * must be non-zero. When there is a design + * size but no recommended size range, the + * rest of the array will consist of zeros. */ + USHORT subfamilyID; /* Has no independent meaning, but serves + * as an identifier that associates fonts + * in a subfamily. All fonts which share a + * Preferred or Font Family name and which + * differ only by size range shall have the + * same subfamily value, and no fonts which + * differ in weight or style shall have the + * same subfamily value. If this value is + * zero, the remaining fields in the array + * will be ignored. */ + USHORT subfamilyNameID;/* If the preceding value is non-zero, this + * value must be set in the range 256 - 32767 + * (inclusive). It records the value of a + * field in the name table, which must + * contain English-language strings encoded + * in Windows Unicode and Macintosh Roman, + * and may contain additional strings + * localized to other scripts and languages. + * Each of these strings is the name an + * application should use, in combination + * with the family name, to represent the + * subfamily in a menu. Applications will + * choose the appropriate version based on + * their selection criteria. */ + USHORT rangeStart; /* Large end of the recommended usage range + * (inclusive), stored in 720/inch units + * (decipoints). */ + USHORT rangeEnd; /* Small end of the recommended usage range + (exclusive), stored in 720/inch units + * (decipoints). */ + public: + DEFINE_SIZE_STATIC (10); +}; + +/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */ +struct FeatureParamsStylisticSet +{ + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (this); + /* Right now minorVersion is at zero. Which means, any table supports + * the uiNameID field. */ + return TRACE_RETURN (c->check_struct (this)); + } + + USHORT minorVersion; /* (set to 0): This corresponds to a “minor” + * version number. Additional data may be + * added to the end of this Feature Parameters + * table in the future. */ + + USHORT uiNameID; /* The 'name' table name ID that specifies a + * string (or strings, for multiple languages) + * for a user-interface label for this + * feature. The values of uiLabelNameId and + * sampleTextNameId are expected to be in the + * font-specific name ID range (256-32767), + * though that is not a requirement in this + * Feature Parameters specification. The + * user-interface label for the feature can + * be provided in multiple languages. An + * English string should be included as a + * fallback. The string should be kept to a + * minimal length to fit comfortably with + * different application interfaces. */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct FeatureParamsCharacterVariants +{ + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (this); + return TRACE_RETURN (c->check_struct (this) && + characters.sanitize (c)); + } + + USHORT format; /* Format number is set to 0. */ + USHORT featUILableNameID; /* The ‘name’ table name ID that + * specifies a string (or strings, + * for multiple languages) for a + * user-interface label for this + * feature. (May be NULL.) */ + USHORT featUITooltipTextNameID;/* The ‘name’ table name ID that + * specifies a string (or strings, + * for multiple languages) that an + * application can use for tooltip + * text for this feature. (May be + * NULL.) */ + USHORT sampleTextNameID; /* The ‘name’ table name ID that + * specifies sample text that + * illustrates the effect of this + * feature. (May be NULL.) */ + USHORT numNamedParameters; /* Number of named parameters. (May + * be zero.) */ + USHORT firstParamUILabelNameID;/* The first ‘name’ table name ID + * used to specify strings for + * user-interface labels for the + * feature parameters. (Must be zero + * if numParameters is zero.) */ + ArrayOf<UINT24> + characters; /* Array of the Unicode Scalar Value + * of the characters for which this + * feature provides glyph variants. + * (May be zero.) */ + public: + DEFINE_SIZE_ARRAY (14, characters); +}; + +struct FeatureParams +{ + inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) { + TRACE_SANITIZE (this); + if (tag == HB_TAG ('s','i','z','e')) + return TRACE_RETURN (u.size.sanitize (c)); + if ((tag & 0xFFFF0000) == HB_TAG ('s','s','\0','\0')) /* ssXX */ + return TRACE_RETURN (u.stylisticSet.sanitize (c)); + if ((tag & 0xFFFF0000) == HB_TAG ('c','v','\0','\0')) /* cvXX */ + return TRACE_RETURN (u.characterVariants.sanitize (c)); + return TRACE_RETURN (true); + } + + inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const + { + if (tag == HB_TAG ('s','i','z','e')) + return u.size; + return Null(FeatureParamsSize); + } + + private: + union { + FeatureParamsSize size; + FeatureParamsStylisticSet stylisticSet; + FeatureParamsCharacterVariants characterVariants; + } u; + DEFINE_SIZE_STATIC (17); +}; + struct Feature { inline unsigned int get_lookup_count (void) const @@ -260,12 +480,54 @@ struct Feature unsigned int *lookup_tags /* OUT */) const { return lookupIndex.get_indexes (start_index, lookup_count, lookup_tags); } - inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); - return TRACE_RETURN (c->check_struct (this) && lookupIndex.sanitize (c)); + inline const FeatureParams &get_feature_params (void) const + { return this+featureParams; } + + inline bool sanitize (hb_sanitize_context_t *c, + const Record<Feature>::sanitize_closure_t *closure) { + TRACE_SANITIZE (this); + if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) + return TRACE_RETURN (false); + + /* Some earlier versions of Adobe tools calculated the offset of the + * FeatureParams subtable from the beginning of the FeatureList table! + * + * If sanitizing "failed" for the FeatureParams subtable, try it with the + * alternative location. We would know sanitize "failed" if old value + * of the offset was non-zero, but it's zeroed now. + * + * Only do this for the 'size' feature, since at the time of the faulty + * Adobe tools, only the 'size' feature had FeatureParams defined. + */ + + Offset orig_offset = featureParams; + if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) + return TRACE_RETURN (false); + + if (likely (!orig_offset)) + return TRACE_RETURN (true); + + if (featureParams == 0 && closure && + closure->tag == HB_TAG ('s','i','z','e') && + closure->list_base && closure->list_base < this) + { + unsigned int new_offset_int = (unsigned int) orig_offset - + ((char *) this - (char *) closure->list_base); + + Offset new_offset; + /* Check that it did not overflow. */ + new_offset.set (new_offset_int); + if (new_offset == new_offset_int && + featureParams.try_set (c, new_offset) && + !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) + return TRACE_RETURN (false); + } + + return TRACE_RETURN (true); } - Offset featureParams; /* Offset to Feature Parameters table (if one + OffsetTo<FeatureParams> + featureParams; /* Offset to Feature Parameters table (if one * has been defined for the feature), relative * to the beginning of the Feature Table; = Null * if not required */ @@ -318,7 +580,7 @@ struct Lookup uint32_t lookup_props, unsigned int num_subtables) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); lookupType.set (lookup_type); lookupFlag.set (lookup_props & 0xFFFF); @@ -332,7 +594,7 @@ struct Lookup } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); /* Real sanitize of the subtables is done by GSUB/GPOS/... */ if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) @@ -377,7 +639,7 @@ struct CoverageFormat1 Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); glyphArray.len.set (num_glyphs); if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false); @@ -388,7 +650,7 @@ struct CoverageFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (glyphArray.sanitize (c)); } @@ -403,6 +665,8 @@ struct CoverageFormat1 glyphs->add (glyphArray[i]); } + public: + /* Older compilers need this to be public. */ struct Iter { inline void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; }; inline bool more (void) { return i < c->glyphArray.len; } @@ -414,6 +678,7 @@ struct CoverageFormat1 const struct CoverageFormat1 *c; unsigned int i; }; + private: protected: USHORT coverageFormat; /* Format identifier--format = 1 */ @@ -442,7 +707,7 @@ struct CoverageFormat2 Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!num_glyphs)) return TRACE_RETURN (true); @@ -471,7 +736,7 @@ struct CoverageFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (rangeRecord.sanitize (c)); } @@ -497,6 +762,8 @@ struct CoverageFormat2 rangeRecord[i].add_coverage (glyphs); } + public: + /* Older compilers need this to be public. */ struct Iter { inline void init (const CoverageFormat2 &c_) { c = &c_; @@ -522,6 +789,7 @@ struct CoverageFormat2 const struct CoverageFormat2 *c; unsigned int i, j, coverage; }; + private: protected: USHORT coverageFormat; /* Format identifier--format = 2 */ @@ -535,8 +803,6 @@ struct CoverageFormat2 struct Coverage { - inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_coverage (glyph_id); } - inline unsigned int get_coverage (hb_codepoint_t glyph_id) const { switch (u.format) { @@ -550,7 +816,7 @@ struct Coverage Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); unsigned int num_ranges = 1; for (unsigned int i = 1; i < num_glyphs; i++) @@ -565,7 +831,7 @@ struct Coverage } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -676,10 +942,18 @@ struct ClassDefFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c)); } + template <typename set_t> + inline void add_class (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->add (startGlyph + i); + } + 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++) @@ -711,10 +985,18 @@ struct ClassDefFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (rangeRecord.sanitize (c)); } + template <typename set_t> + inline void add_class (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].add_coverage (glyphs); + } + 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++) @@ -734,8 +1016,6 @@ struct ClassDefFormat2 struct ClassDef { - inline unsigned int operator () (hb_codepoint_t glyph_id) const { return get_class (glyph_id); } - inline unsigned int get_class (hb_codepoint_t glyph_id) const { switch (u.format) { @@ -746,7 +1026,7 @@ struct ClassDef } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -755,6 +1035,14 @@ struct ClassDef } } + inline void add_class (hb_set_t *glyphs, unsigned int klass) const { + switch (u.format) { + case 1: u.format1.add_class (glyphs, klass); return; + case 2: u.format2.add_class (glyphs, klass); return; + default:return; + } + } + inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const { switch (u.format) { case 1: return u.format1.intersects_class (glyphs, klass); @@ -830,7 +1118,7 @@ struct Device } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ())); } @@ -848,7 +1136,7 @@ struct Device }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_LAYOUT_COMMON_PRIVATE_HH */ 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 92ae1cf..ff2d09c 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 @@ -51,7 +51,7 @@ struct AttachList unsigned int *point_count /* IN/OUT */, unsigned int *point_array /* OUT */) const { - unsigned int index = (this+coverage) (glyph_id); + unsigned int index = (this+coverage).get_coverage (glyph_id); if (index == NOT_COVERED) { if (point_count) @@ -72,7 +72,7 @@ struct AttachList } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); } @@ -102,7 +102,7 @@ struct CaretValueFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -128,7 +128,7 @@ struct CaretValueFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -151,7 +151,7 @@ struct CaretValueFormat3 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this)); } @@ -179,7 +179,7 @@ struct CaretValue } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -220,7 +220,7 @@ struct LigGlyph } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (carets.sanitize (c, this)); } @@ -242,7 +242,7 @@ struct LigCaretList unsigned int *caret_count /* IN/OUT */, hb_position_t *caret_array /* OUT */) const { - unsigned int index = (this+coverage) (glyph_id); + unsigned int index = (this+coverage).get_coverage (glyph_id); if (index == NOT_COVERED) { if (caret_count) @@ -254,7 +254,7 @@ struct LigCaretList } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); } @@ -276,7 +276,7 @@ struct MarkGlyphSetsFormat1 { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this)); } @@ -300,7 +300,7 @@ struct MarkGlyphSets } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -337,6 +337,8 @@ struct GDEF inline bool has_glyph_classes (void) const { return glyphClassDef != 0; } inline unsigned int get_glyph_class (hb_codepoint_t glyph) const { return (this+glyphClassDef).get_class (glyph); } + inline void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const + { (this+glyphClassDef).add_class (glyphs, klass); } inline bool has_mark_attachment_types (void) const { return markAttachClassDef != 0; } inline unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const @@ -363,7 +365,7 @@ struct GDEF { return version.to_int () >= 0x00010002 && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && glyphClassDef.sanitize (c, this) && @@ -383,13 +385,13 @@ struct GDEF switch (klass) { default: - case UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; - case BaseGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH; - case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE; - case ComponentGlyph: return HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT; + case UnclassifiedGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED; + case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; + case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; + case ComponentGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT; case MarkGlyph: klass = get_mark_attachment_type (glyph); - return HB_OT_LAYOUT_GLYPH_CLASS_MARK | (klass << 8); + return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); } } @@ -423,7 +425,7 @@ struct GDEF }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */ 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 41cb93d..d27ce4f 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 @@ -172,12 +172,12 @@ struct ValueFormat : USHORT } inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); 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 (); + TRACE_SANITIZE (this); unsigned int len = get_len (); if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false); @@ -195,7 +195,7 @@ struct ValueFormat : USHORT /* 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 (); + TRACE_SANITIZE (this); if (!has_device ()) return TRACE_RETURN (true); @@ -212,9 +212,6 @@ struct ValueFormat : USHORT struct AnchorFormat1 { - friend struct Anchor; - - private: inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, hb_position_t *x, hb_position_t *y) const { @@ -223,7 +220,7 @@ struct AnchorFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -237,9 +234,6 @@ struct AnchorFormat1 struct AnchorFormat2 { - friend struct Anchor; - - private: inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id, hb_position_t *x, hb_position_t *y) const { @@ -255,7 +249,7 @@ struct AnchorFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -270,9 +264,6 @@ struct AnchorFormat2 struct AnchorFormat3 { - friend struct Anchor; - - private: inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, hb_position_t *x, hb_position_t *y) const { @@ -286,7 +277,7 @@ struct AnchorFormat3 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } @@ -321,7 +312,7 @@ struct Anchor } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -351,7 +342,7 @@ struct AnchorMatrix } inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); 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; @@ -376,7 +367,7 @@ struct MarkRecord friend struct MarkArray; inline bool sanitize (hb_sanitize_context_t *c, void *base) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base)); } @@ -396,7 +387,7 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde const AnchorMatrix &anchors, unsigned int class_count, unsigned int glyph_pos) const { - TRACE_APPLY (); + TRACE_APPLY (this); const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index); unsigned int mark_class = record.klass; @@ -418,7 +409,7 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this)); } }; @@ -428,9 +419,11 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde struct SinglePosFormat1 { - friend struct SinglePos; - - private: + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + } inline const Coverage &get_coverage (void) const { @@ -439,8 +432,8 @@ struct SinglePosFormat1 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); valueFormat.apply_value (c->font, c->direction, this, @@ -451,7 +444,7 @@ struct SinglePosFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values)); } @@ -471,9 +464,11 @@ struct SinglePosFormat1 struct SinglePosFormat2 { - friend struct SinglePos; - - private: + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + } inline const Coverage &get_coverage (void) const { @@ -482,8 +477,8 @@ struct SinglePosFormat2 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (likely (index >= valueCount)) return TRACE_RETURN (false); @@ -497,7 +492,7 @@ struct SinglePosFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount)); } @@ -517,31 +512,19 @@ struct SinglePosFormat2 struct SinglePos { - friend struct PosLookupSubTable; - - private: - - inline const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return u.format1.get_coverage (); - case 2: return u.format2.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_APPLY (); + TRACE_PROCESS (this); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - case 2: return TRACE_RETURN (u.format2.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + case 2: return TRACE_RETURN (c->process (u.format2)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -577,17 +560,34 @@ struct PairSet { friend struct PairPosFormat1; + inline void collect_glyphs (hb_collect_glyphs_context_t *c, + const ValueFormat *valueFormats) const + { + TRACE_COLLECT_GLYPHS (this); + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned int record_size = USHORT::static_size * (1 + len1 + len2); + + const PairValueRecord *record = CastP<PairValueRecord> (array); + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + c->input->add (record->secondGlyph); + record = &StructAtOffset<PairValueRecord> (record, record_size); + } + } + inline bool apply (hb_apply_context_t *c, const ValueFormat *valueFormats, unsigned int pos) const { - TRACE_APPLY (); + TRACE_APPLY (this); unsigned int len1 = valueFormats[0].get_len (); unsigned int len2 = valueFormats[1].get_len (); unsigned int record_size = USHORT::static_size * (1 + len1 + len2); - unsigned int count = len; const PairValueRecord *record = CastP<PairValueRecord> (array); + unsigned int count = len; for (unsigned int i = 0; i < count; i++) { if (c->buffer->info[pos].codepoint == record->secondGlyph) @@ -615,7 +615,7 @@ struct PairSet }; inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!(c->check_struct (this) && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false); @@ -635,9 +635,14 @@ struct PairSet struct PairPosFormat1 { - friend struct PairPos; - - private: + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + unsigned int count = pairSet.len; + for (unsigned int i = 0; i < count; i++) + (this+pairSet[i]).collect_glyphs (c, &valueFormat1); + } inline const Coverage &get_coverage (void) const { @@ -646,11 +651,11 @@ struct PairPosFormat1 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (!skippy_iter.next ()) return TRACE_RETURN (false); @@ -659,7 +664,7 @@ struct PairPosFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); @@ -693,9 +698,23 @@ struct PairPosFormat1 struct PairPosFormat2 { - friend struct PairPos; + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + /* (this+coverage).add_coverage (c->input); // Don't need this. */ - private: + /* TODO only add values for pairs that have nonzero adjustments. */ + + unsigned int count1 = class1Count; + const ClassDef &klass1 = this+classDef1; + for (unsigned int i = 0; i < count1; i++) + klass1.add_class (c->input, i); + + unsigned int count2 = class2Count; + const ClassDef &klass2 = this+classDef2; + for (unsigned int i = 0; i < count2; i++) + klass2.add_class (c->input, i); + } inline const Coverage &get_coverage (void) const { @@ -704,11 +723,11 @@ struct PairPosFormat2 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (!skippy_iter.next ()) return TRACE_RETURN (false); @@ -717,8 +736,8 @@ struct PairPosFormat2 unsigned int len2 = valueFormat2.get_len (); unsigned int record_len = len1 + len2; - unsigned int klass1 = (this+classDef1) (c->buffer->cur().codepoint); - unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint); + unsigned int klass1 = (this+classDef1).get_class (c->buffer->cur().codepoint); + unsigned int klass2 = (this+classDef2).get_class (c->buffer->info[skippy_iter.idx].codepoint); if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false); const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; @@ -735,7 +754,7 @@ struct PairPosFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!(c->check_struct (this) && coverage.sanitize (c, this) && classDef1.sanitize (c, this) @@ -783,31 +802,19 @@ struct PairPosFormat2 struct PairPos { - friend struct PosLookupSubTable; - - private: - - inline const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return u.format1.get_coverage (); - case 2: return u.format2.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_APPLY (); + TRACE_PROCESS (this); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - case 2: return TRACE_RETURN (u.format2.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + case 2: return TRACE_RETURN (c->process (u.format2)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -830,7 +837,7 @@ struct EntryExitRecord friend struct CursivePosFormat1; inline bool sanitize (hb_sanitize_context_t *c, void *base) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); } @@ -849,9 +856,11 @@ struct EntryExitRecord struct CursivePosFormat1 { - friend struct CursivePos; - - private: + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + } inline const Coverage &get_coverage (void) const { @@ -860,20 +869,20 @@ struct CursivePosFormat1 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); /* We don't handle mark glyphs here. */ - if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK) return TRACE_RETURN (false); + if (c->property & HB_OT_LAYOUT_GLYPH_PROPS_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 TRACE_RETURN (false); - const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->cur().codepoint)]; + const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (c->buffer->cur().codepoint)]; if (!this_record.exitAnchor) return TRACE_RETURN (false); if (!skippy_iter.next ()) return TRACE_RETURN (false); - const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)]; + const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (c->buffer->info[skippy_iter.idx].codepoint)]; if (!next_record.entryAnchor) return TRACE_RETURN (false); unsigned int i = c->buffer->idx; @@ -941,7 +950,7 @@ struct CursivePosFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); } @@ -959,29 +968,18 @@ struct CursivePosFormat1 struct CursivePos { - friend struct PosLookupSubTable; - - private: - - inline const Coverage &get_coverage (void) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { + TRACE_PROCESS (this); switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1004,9 +1002,13 @@ typedef AnchorMatrix BaseArray; /* base-major-- struct MarkBasePosFormat1 { - friend struct MarkBasePos; - - private: + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+markCoverage).add_coverage (c->input); + (this+baseCoverage).add_coverage (c->input); + /* TODO only add combinations that have nonzero adjustment. */ + } inline const Coverage &get_coverage (void) const { @@ -1015,8 +1017,8 @@ struct MarkBasePosFormat1 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int mark_index = (this+markCoverage).get_coverage (c->buffer->cur().codepoint); if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); /* now we search backwards for a non-mark glyph */ @@ -1030,16 +1032,16 @@ struct MarkBasePosFormat1 } while (1); /* The following assertion is too strong, so we've disabled it. */ - if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/} + if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/} - unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint); + unsigned int base_index = (this+baseCoverage).get_coverage (c->buffer->info[skippy_iter.idx].codepoint); if (base_index == NOT_COVERED) return TRACE_RETURN (false); 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 (); + TRACE_SANITIZE (this); 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)); } @@ -1065,29 +1067,18 @@ struct MarkBasePosFormat1 struct MarkBasePos { - friend struct PosLookupSubTable; - - private: - - inline const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_APPLY (); + TRACE_PROCESS (this); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1115,9 +1106,13 @@ typedef OffsetListOf<LigatureAttach> LigatureArray; struct MarkLigPosFormat1 { - friend struct MarkLigPos; - - private: + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+markCoverage).add_coverage (c->input); + (this+ligatureCoverage).add_coverage (c->input); + /* TODO only add combinations that have nonzero adjustment. */ + } inline const Coverage &get_coverage (void) const { @@ -1126,8 +1121,8 @@ struct MarkLigPosFormat1 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int mark_index = (this+markCoverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int mark_index = (this+markCoverage).get_coverage (c->buffer->cur().codepoint); if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); /* now we search backwards for a non-mark glyph */ @@ -1136,10 +1131,10 @@ struct MarkLigPosFormat1 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 TRACE_RETURN (false);*/} + if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/} unsigned int j = skippy_iter.idx; - unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint); + unsigned int lig_index = (this+ligatureCoverage).get_coverage (c->buffer->info[j].codepoint); if (lig_index == NOT_COVERED) return TRACE_RETURN (false); const LigatureArray& lig_array = this+ligatureArray; @@ -1166,7 +1161,7 @@ struct MarkLigPosFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); 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)); } @@ -1193,29 +1188,18 @@ struct MarkLigPosFormat1 struct MarkLigPos { - friend struct PosLookupSubTable; - - private: - - inline const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_APPLY (); + TRACE_PROCESS (this); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1238,9 +1222,13 @@ typedef AnchorMatrix Mark2Array; /* mark2-major-- struct MarkMarkPosFormat1 { - friend struct MarkMarkPos; - - private: + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+mark1Coverage).add_coverage (c->input); + (this+mark2Coverage).add_coverage (c->input); + /* TODO only add combinations that have nonzero adjustment. */ + } inline const Coverage &get_coverage (void) const { @@ -1249,8 +1237,8 @@ struct MarkMarkPosFormat1 inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int mark1_index = (this+mark1Coverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int mark1_index = (this+mark1Coverage).get_coverage (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 */ @@ -1258,7 +1246,7 @@ struct MarkMarkPosFormat1 hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1); if (!skippy_iter.prev (&property)) return TRACE_RETURN (false); - if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) return TRACE_RETURN (false); + if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) return TRACE_RETURN (false); unsigned int j = skippy_iter.idx; @@ -1283,14 +1271,14 @@ struct MarkMarkPosFormat1 return TRACE_RETURN (false); good: - unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint); + unsigned int mark2_index = (this+mark2Coverage).get_coverage (c->buffer->info[j].codepoint); if (mark2_index == NOT_COVERED) return TRACE_RETURN (false); 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 (); + TRACE_SANITIZE (this); 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)); @@ -1319,29 +1307,18 @@ struct MarkMarkPosFormat1 struct MarkMarkPos { - friend struct PosLookupSubTable; - - private: - - inline const Coverage &get_coverage (void) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { + TRACE_PROCESS (this); switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1357,50 +1334,13 @@ struct MarkMarkPos }; -static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index); +struct ContextPos : Context {}; -struct ContextPos : Context -{ - friend struct PosLookupSubTable; - - private: - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - return TRACE_RETURN (Context::apply (c, position_lookup)); - } -}; +struct ChainContextPos : ChainContext {}; -struct ChainContextPos : ChainContext +struct ExtensionPos : Extension<ExtensionPos> { - friend struct PosLookupSubTable; - - private: - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - return TRACE_RETURN (ChainContext::apply (c, position_lookup)); - } -}; - - -struct ExtensionPos : Extension -{ - friend struct PosLookupSubTable; - - private: - inline const struct PosLookupSubTable& get_subtable (void) const - { - unsigned int offset = get_offset (); - if (unlikely (!offset)) return Null(PosLookupSubTable); - return StructAtOffset<PosLookupSubTable> (this, offset); - } - - inline const Coverage &get_coverage (void) const; - - inline bool apply (hb_apply_context_t *c) const; - - inline bool sanitize (hb_sanitize_context_t *c); + typedef struct PosLookupSubTable LookupSubTable; }; @@ -1426,41 +1366,26 @@ struct PosLookupSubTable Extension = 9 }; - inline const Coverage &get_coverage (unsigned int lookup_type) const - { - switch (lookup_type) { - case Single: return u.single.get_coverage (); - case Pair: return u.pair.get_coverage (); - case Cursive: return u.cursive.get_coverage (); - case MarkBase: return u.markBase.get_coverage (); - case MarkLig: return u.markLig.get_coverage (); - case MarkMark: return u.markMark.get_coverage (); - case Context: return u.context.get_coverage (); - case ChainContext: return u.chainContext.get_coverage (); - case Extension: return u.extension.get_coverage (); - default: return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const { - TRACE_APPLY (); + TRACE_PROCESS (this); switch (lookup_type) { - 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.context.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); + case Single: return TRACE_RETURN (u.single.process (c)); + case Pair: return TRACE_RETURN (u.pair.process (c)); + case Cursive: return TRACE_RETURN (u.cursive.process (c)); + case MarkBase: return TRACE_RETURN (u.markBase.process (c)); + case MarkLig: return TRACE_RETURN (u.markLig.process (c)); + case MarkMark: return TRACE_RETURN (u.markMark.process (c)); + case Context: return TRACE_RETURN (u.context.process (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.process (c)); + case Extension: return TRACE_RETURN (u.extension.process (c)); + default: return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.header.sub_format.sanitize (c)) return TRACE_RETURN (false); switch (lookup_type) { @@ -1480,7 +1405,7 @@ struct PosLookupSubTable protected: union { struct { - USHORT sub_format; + USHORT sub_format; } header; SinglePos single; PairPos pair; @@ -1502,35 +1427,54 @@ struct PosLookup : Lookup inline const PosLookupSubTable& get_subtable (unsigned int i) const { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; } + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const + { + TRACE_PROCESS (this); + unsigned int lookup_type = get_type (); + unsigned int count = get_subtable_count (); + for (unsigned int i = 0; i < count; i++) { + typename context_t::return_t r = get_subtable (i).process (c, lookup_type); + if (c->stop_sublookup_iteration (r)) + return TRACE_RETURN (r); + } + return TRACE_RETURN (c->default_return_value ()); + } + template <typename context_t> + static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index); + + inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + c->set_recurse_func (NULL); + return TRACE_RETURN (process (c)); + } + template <typename set_t> inline void add_coverage (set_t *glyphs) const { + hb_get_coverage_context_t c; const Coverage *last = NULL; unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - const Coverage *c = &get_subtable (i).get_coverage (get_type ()); - if (c != last) { - c->add_coverage (glyphs); - last = c; + const Coverage *coverage = &get_subtable (i).process (&c, get_type ()); + if (coverage != last) { + coverage->add_coverage (glyphs); + last = coverage; } } } inline bool apply_once (hb_apply_context_t *c) const { - unsigned int lookup_type = get_type (); - + TRACE_APPLY (this); if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property)) - return false; - - unsigned int count = get_subtable_count (); - for (unsigned int i = 0; i < count; i++) - if (get_subtable (i).apply (c, lookup_type)) - return true; - - return false; + return TRACE_RETURN (false); + return TRACE_RETURN (process (c)); } + static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); + inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const { bool ret = false; @@ -1538,6 +1482,7 @@ struct PosLookup : Lookup if (unlikely (!c->buffer->len || !c->lookup_mask)) return false; + c->set_recurse_func (apply_recurse_func); c->set_lookup (*this); c->buffer->idx = 0; @@ -1556,7 +1501,7 @@ struct PosLookup : Lookup } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable); return TRACE_RETURN (list.sanitize (c, this, get_type ())); @@ -1576,15 +1521,11 @@ struct GPOS : GSUBGPOS inline const PosLookup& get_lookup (unsigned int i) const { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } - template <typename set_t> - inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const - { get_lookup (lookup_index).add_coverage (glyphs); } - static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attahced_marks); inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); return TRACE_RETURN (list.sanitize (c, this)); @@ -1673,38 +1614,25 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t /* Out-of-class implementation for methods recursing */ -inline const Coverage & ExtensionPos::get_coverage (void) const +template <typename context_t> +inline typename context_t::return_t PosLookup::process_recurse_func (context_t *c, unsigned int lookup_index) { - return get_subtable ().get_coverage (get_type ()); -} - -inline bool ExtensionPos::apply (hb_apply_context_t *c) const -{ - TRACE_APPLY (); - 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 TRACE_RETURN (false); - unsigned int offset = get_offset (); - if (unlikely (!offset)) return TRACE_RETURN (true); - return TRACE_RETURN (StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ())); + const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); + const PosLookup &l = gpos.get_lookup (lookup_index); + return l.process (c); } -static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index) +inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) { const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos); const PosLookup &l = gpos.get_lookup (lookup_index); - - if (unlikely (c->nesting_level_left == 0)) - return false; - - hb_apply_context_t new_c (*c); - new_c.nesting_level_left--; - new_c.set_lookup (l); - return l.apply_once (&new_c); + unsigned int saved_lookup_props = c->lookup_props; + unsigned int saved_property = c->property; + c->set_lookup (l); + bool ret = l.apply_once (c); + c->lookup_props = saved_lookup_props; + c->property = saved_property; + return ret; } @@ -1712,7 +1640,7 @@ static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_i #undef cursive_chain -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */ 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 05b18cc..2642acb 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 @@ -37,13 +37,9 @@ namespace OT { struct SingleSubstFormat1 { - friend struct SingleSubst; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); Coverage::Iter iter; for (iter.init (this+coverage); iter.more (); iter.next ()) { hb_codepoint_t glyph_id = iter.get_glyph (); @@ -52,16 +48,33 @@ struct SingleSubstFormat1 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + hb_codepoint_t glyph_id = iter.get_glyph (); + c->input->add (glyph_id); + c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF); + } + } + inline const Coverage &get_coverage (void) const { return this+coverage; } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (this); + return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + } + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage) (glyph_id); + unsigned int index = (this+coverage).get_coverage (glyph_id); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); /* According to the Adobe Annotated OpenType Suite, result is always @@ -77,7 +90,7 @@ struct SingleSubstFormat1 unsigned int num_glyphs, int delta) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ @@ -85,7 +98,7 @@ struct SingleSubstFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); } @@ -102,13 +115,9 @@ struct SingleSubstFormat1 struct SingleSubstFormat2 { - friend struct SingleSubst; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); Coverage::Iter iter; for (iter.init (this+coverage); iter.more (); iter.next ()) { if (c->glyphs->has (iter.get_glyph ())) @@ -116,16 +125,32 @@ struct SingleSubstFormat2 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + c->input->add (iter.get_glyph ()); + c->output->add (substitute[iter.get_coverage ()]); + } + } + inline const Coverage &get_coverage (void) const { return this+coverage; } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (this); + return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + } + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage) (glyph_id); + unsigned int index = (this+coverage).get_coverage (glyph_id); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); if (unlikely (index >= substitute.len)) return TRACE_RETURN (false); @@ -141,7 +166,7 @@ struct SingleSubstFormat2 Supplier<GlyphID> &substitutes, unsigned int num_glyphs) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false); if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); @@ -149,7 +174,7 @@ struct SingleSubstFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c)); } @@ -167,37 +192,14 @@ struct SingleSubstFormat2 struct SingleSubst { - friend struct SubstLookupSubTable; - friend struct SubstLookup; - - 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 const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return u.format1.get_coverage (); - case 2: return u.format2.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_APPLY (); + TRACE_PROCESS (this); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - case 2: return TRACE_RETURN (u.format2.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + case 2: return TRACE_RETURN (c->process (u.format2)); + default:return TRACE_RETURN (c->default_return_value ()); } } @@ -206,7 +208,7 @@ struct SingleSubst Supplier<GlyphID> &substitutes, unsigned int num_glyphs) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); unsigned int format = 2; int delta; @@ -229,7 +231,7 @@ struct SingleSubst } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -249,24 +251,28 @@ struct SingleSubst struct Sequence { - friend struct MultipleSubstFormat1; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); unsigned int count = substitute.len; for (unsigned int i = 0; i < count; i++) c->glyphs->add (substitute[i]); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + unsigned int count = substitute.len; + for (unsigned int i = 0; i < count; i++) + c->output->add (substitute[i]); + } + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); if (unlikely (!substitute.len)) return TRACE_RETURN (false); - unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0; + unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; unsigned int count = substitute.len; for (unsigned int i = 0; i < count; i++) { set_lig_props_for_component (c->buffer->cur(), i); @@ -281,15 +287,14 @@ struct Sequence Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); return TRACE_RETURN (true); } - public: inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (substitute.sanitize (c)); } @@ -302,13 +307,9 @@ struct Sequence struct MultipleSubstFormat1 { - friend struct MultipleSubst; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); Coverage::Iter iter; for (iter.init (this+coverage); iter.more (); iter.next ()) { if (c->glyphs->has (iter.get_glyph ())) @@ -316,16 +317,31 @@ struct MultipleSubstFormat1 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + unsigned int count = sequence.len; + for (unsigned int i = 0; i < count; i++) + (this+sequence[i]).collect_glyphs (c); + } + inline const Coverage &get_coverage (void) const { return this+coverage; } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (this); + return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + } + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); return TRACE_RETURN ((this+sequence[index]).apply (c)); @@ -337,7 +353,7 @@ struct MultipleSubstFormat1 unsigned int num_glyphs, Supplier<GlyphID> &substitute_glyphs_list) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false); for (unsigned int i = 0; i < num_glyphs; i++) @@ -350,7 +366,7 @@ struct MultipleSubstFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this)); } @@ -368,34 +384,13 @@ struct MultipleSubstFormat1 struct MultipleSubst { - friend struct SubstLookupSubTable; - friend struct SubstLookup; - - 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 const Coverage &get_coverage (void) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { + TRACE_PROCESS (this); switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } @@ -405,7 +400,7 @@ struct MultipleSubst unsigned int num_glyphs, Supplier<GlyphID> &substitute_glyphs_list) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); unsigned int format = 1; u.format.set (format); @@ -416,7 +411,7 @@ struct MultipleSubst } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -437,13 +432,9 @@ typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in struct AlternateSubstFormat1 { - friend struct AlternateSubst; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); Coverage::Iter iter; for (iter.init (this+coverage); iter.more (); iter.next ()) { if (c->glyphs->has (iter.get_glyph ())) { @@ -455,17 +446,36 @@ struct AlternateSubstFormat1 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + c->input->add (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->output->add (alt_set[i]); + } + } + inline const Coverage &get_coverage (void) const { return this+coverage; } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (this); + return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + } + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage) (glyph_id); + unsigned int index = (this+coverage).get_coverage (glyph_id); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const AlternateSet &alt_set = this+alternateSet[index]; @@ -494,7 +504,7 @@ struct AlternateSubstFormat1 unsigned int num_glyphs, Supplier<GlyphID> &alternate_glyphs_list) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false); for (unsigned int i = 0; i < num_glyphs; i++) @@ -507,7 +517,7 @@ struct AlternateSubstFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); } @@ -525,34 +535,13 @@ struct AlternateSubstFormat1 struct AlternateSubst { - friend struct SubstLookupSubTable; - friend struct SubstLookup; - - private: - - inline void closure (hb_closure_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_CLOSURE (); + TRACE_PROCESS (this); switch (u.format) { - case 1: u.format1.closure (c); break; - default: break; - } - } - - inline const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } @@ -562,7 +551,7 @@ struct AlternateSubst unsigned int num_glyphs, Supplier<GlyphID> &alternate_glyphs_list) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); unsigned int format = 1; u.format.set (format); @@ -573,7 +562,7 @@ struct AlternateSubst } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -591,13 +580,9 @@ struct AlternateSubst struct Ligature { - friend struct LigatureSet; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); unsigned int count = component.len; for (unsigned int i = 1; i < count; i++) if (!c->glyphs->has (component[i])) @@ -605,27 +590,37 @@ struct Ligature c->glyphs->add (ligGlyph); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + unsigned int count = component.len; + for (unsigned int i = 1; i < count; i++) + c->input->add (component[i]); + c->output->add (ligGlyph); + } + inline bool would_apply (hb_would_apply_context_t *c) const { + TRACE_WOULD_APPLY (this); if (c->len != component.len) - return false; + return TRACE_RETURN (false); for (unsigned int i = 1; i < c->len; i++) if (likely (c->glyphs[i] != component[i])) - return false; + return TRACE_RETURN (false); - return true; + return TRACE_RETURN (true); } inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); unsigned int count = component.len; if (unlikely (count < 1)) return TRACE_RETURN (false); - unsigned int end_offset; - bool is_mark_ligature; - unsigned int total_component_count; + unsigned int end_offset = 0; + bool is_mark_ligature = false; + unsigned int total_component_count = 0; if (likely (!match_input (c, count, &component[1], @@ -656,7 +651,7 @@ struct Ligature Supplier<GlyphID> &components, /* Starting from second */ unsigned int num_components /* Including first component */) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); ligGlyph = ligature; if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false); @@ -665,7 +660,7 @@ struct Ligature public: inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c)); } @@ -681,33 +676,38 @@ struct Ligature struct LigatureSet { - friend struct LigatureSubstFormat1; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) (this+ligature[i]).closure (c); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + unsigned int num_ligs = ligature.len; + for (unsigned int i = 0; i < num_ligs; i++) + (this+ligature[i]).collect_glyphs (c); + } + inline bool would_apply (hb_would_apply_context_t *c) const { + TRACE_WOULD_APPLY (this); 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 (c)) - return true; + return TRACE_RETURN (true); } - return false; + return TRACE_RETURN (false); } inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) { @@ -724,7 +724,7 @@ struct LigatureSet unsigned int num_ligatures, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false); for (unsigned int i = 0; i < num_ligatures; i++) @@ -737,9 +737,8 @@ struct LigatureSet return TRACE_RETURN (true); } - public: inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (ligature.sanitize (c, this)); } @@ -753,13 +752,9 @@ struct LigatureSet struct LigatureSubstFormat1 { - friend struct LigatureSubst; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); Coverage::Iter iter; for (iter.init (this+coverage); iter.more (); iter.next ()) { if (c->glyphs->has (iter.get_glyph ())) @@ -767,6 +762,16 @@ struct LigatureSubstFormat1 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + Coverage::Iter iter; + for (iter.init (this+coverage); iter.more (); iter.next ()) { + c->input->add (iter.get_glyph ()); + (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c); + } + } + inline const Coverage &get_coverage (void) const { return this+coverage; @@ -774,15 +779,20 @@ struct LigatureSubstFormat1 inline bool would_apply (hb_would_apply_context_t *c) const { - return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c); + TRACE_WOULD_APPLY (this); + unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + + const LigatureSet &lig_set = this+ligatureSet[index]; + return TRACE_RETURN (lig_set.would_apply (c)); } inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; - unsigned int index = (this+coverage) (glyph_id); + unsigned int index = (this+coverage).get_coverage (glyph_id); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const LigatureSet &lig_set = this+ligatureSet[index]; @@ -797,7 +807,7 @@ struct LigatureSubstFormat1 Supplier<unsigned int> &component_count_list, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false); for (unsigned int i = 0; i < num_first_glyphs; i++) @@ -812,7 +822,7 @@ struct LigatureSubstFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); } @@ -830,42 +840,13 @@ struct LigatureSubstFormat1 struct LigatureSubst { - friend struct SubstLookupSubTable; - friend struct SubstLookup; - - private: - - inline void closure (hb_closure_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_CLOSURE (); + TRACE_PROCESS (this); switch (u.format) { - case 1: u.format1.closure (c); break; - default: break; - } - } - - inline const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool would_apply (hb_would_apply_context_t *c) const - { - switch (u.format) { - case 1: return u.format1.would_apply (c); - default:return false; - } - } - - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } @@ -877,7 +858,7 @@ struct LigatureSubst Supplier<unsigned int> &component_count_list, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); unsigned int format = 1; u.format.set (format); @@ -889,7 +870,7 @@ struct LigatureSubst } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -905,70 +886,13 @@ 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 {}; -struct ContextSubst : Context -{ - friend struct SubstLookupSubTable; +struct ChainContextSubst : ChainContext {}; - 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 TRACE_RETURN (Context::apply (c, substitute_lookup)); - } -}; - -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 TRACE_RETURN (ChainContext::apply (c, substitute_lookup)); - } -}; - - -struct ExtensionSubst : Extension +struct ExtensionSubst : Extension<ExtensionSubst> { - friend struct SubstLookupSubTable; - friend struct SubstLookup; - - private: - inline const struct SubstLookupSubTable& get_subtable (void) const - { - unsigned int offset = get_offset (); - if (unlikely (!offset)) return Null(SubstLookupSubTable); - return StructAtOffset<SubstLookupSubTable> (this, offset); - } - - inline void closure (hb_closure_context_t *c) const; - - inline const Coverage &get_coverage (void) const; - - inline bool would_apply (hb_would_apply_context_t *c) const; - - inline bool apply (hb_apply_context_t *c) const; - - inline bool sanitize (hb_sanitize_context_t *c); + typedef struct SubstLookupSubTable LookupSubTable; inline bool is_reverse (void) const; }; @@ -976,13 +900,9 @@ struct ExtensionSubst : Extension struct ReverseChainSingleSubstFormat1 { - friend struct ReverseChainSingleSubst; - - private: - inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); unsigned int count; @@ -1005,18 +925,48 @@ struct ReverseChainSingleSubstFormat1 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + unsigned int count; + + (this+coverage).add_coverage (c->input); + + count = backtrack.len; + for (unsigned int i = 0; i < count; i++) + (this+backtrack[i]).add_coverage (c->before); + + count = lookahead.len; + for (unsigned int i = 0; i < count; i++) + (this+lookahead[i]).add_coverage (c->after); + + const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); + count = substitute.len; + for (unsigned int i = 0; i < count; i++) + c->output->add (substitute[i]); + } + inline const Coverage &get_coverage (void) const { return this+coverage; } + inline bool would_apply (hb_would_apply_context_t *c) const + { + TRACE_WOULD_APPLY (this); + return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + } + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); + TRACE_APPLY (this); 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->cur().codepoint); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); @@ -1039,7 +989,7 @@ struct ReverseChainSingleSubstFormat1 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) return TRACE_RETURN (false); OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); @@ -1071,38 +1021,18 @@ struct ReverseChainSingleSubstFormat1 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 const Coverage &get_coverage (void) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { + TRACE_PROCESS (this); switch (u.format) { - case 1: return u.format1.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool apply (hb_apply_context_t *c) const - { - TRACE_APPLY (); - switch (u.format) { - case 1: return TRACE_RETURN (u.format1.apply (c)); - default:return TRACE_RETURN (false); + case 1: return TRACE_RETURN (c->process (u.format1)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1138,82 +1068,25 @@ struct SubstLookupSubTable ReverseChainSingle = 8 }; - inline void closure (hb_closure_context_t *c, - unsigned int lookup_type) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const { - TRACE_CLOSURE (); + TRACE_PROCESS (this); 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.context.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 const Coverage &get_coverage (unsigned int lookup_type) const - { - switch (lookup_type) { - case Single: return u.single.get_coverage (); - case Multiple: return u.multiple.get_coverage (); - case Alternate: return u.alternate.get_coverage (); - case Ligature: return u.ligature.get_coverage (); - case Context: return u.context.get_coverage (); - case ChainContext: return u.chainContext.get_coverage (); - case Extension: return u.extension.get_coverage (); - case ReverseChainSingle: return u.reverseChainContextSingle.get_coverage (); - default: return Null(Coverage); - } - } - - inline bool would_apply (hb_would_apply_context_t *c, - unsigned int lookup_type) const - { - TRACE_WOULD_APPLY (); - if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false; - if (c->len == 1) { - switch (lookup_type) { - case Single: - case Multiple: - case Alternate: - case ReverseChainSingle: - return true; - } - } - - /* Only need to look further for lookups that support substitutions - * of input longer than 1. */ - switch (lookup_type) { - case Ligature: return u.ligature.would_apply (c); - case Context: return u.context.would_apply (c); - case ChainContext: return u.chainContext.would_apply (c); - case Extension: return u.extension.would_apply (c); - default: return false; - } - } - - inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const - { - TRACE_APPLY (); - switch (lookup_type) { - 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.context.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); + case Single: return TRACE_RETURN (u.single.process (c)); + case Multiple: return TRACE_RETURN (u.multiple.process (c)); + case Alternate: return TRACE_RETURN (u.alternate.process (c)); + case Ligature: return TRACE_RETURN (u.ligature.process (c)); + case Context: return TRACE_RETURN (u.context.process (c)); + case ChainContext: return TRACE_RETURN (u.chainContext.process (c)); + case Extension: return TRACE_RETURN (u.extension.process (c)); + case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.process (c)); + default: return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.header.sub_format.sanitize (c)) return TRACE_RETURN (false); switch (lookup_type) { @@ -1264,55 +1137,68 @@ struct SubstLookup : Lookup return lookup_type_is_reverse (type); } - inline void closure (hb_closure_context_t *c) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { + TRACE_PROCESS (this); unsigned int lookup_type = get_type (); unsigned int count = get_subtable_count (); - for (unsigned int i = 0; i < count; i++) - get_subtable (i).closure (c, lookup_type); + for (unsigned int i = 0; i < count; i++) { + typename context_t::return_t r = get_subtable (i).process (c, lookup_type); + if (c->stop_sublookup_iteration (r)) + return TRACE_RETURN (r); + } + return TRACE_RETURN (c->default_return_value ()); + } + template <typename context_t> + static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index); + + inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const + { + TRACE_CLOSURE (this); + c->set_recurse_func (process_recurse_func<hb_closure_context_t>); + return TRACE_RETURN (process (c)); + } + + inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + c->set_recurse_func (process_recurse_func<hb_collect_glyphs_context_t>); + return TRACE_RETURN (process (c)); } template <typename set_t> inline void add_coverage (set_t *glyphs) const { + hb_get_coverage_context_t c; const Coverage *last = NULL; unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - const Coverage *c = &get_subtable (i).get_coverage (get_type ()); - if (c != last) { - c->add_coverage (glyphs); - last = c; + const Coverage *coverage = &get_subtable (i).process (&c, get_type ()); + if (coverage != last) { + coverage->add_coverage (glyphs); + last = coverage; } } } inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const { - if (unlikely (!c->len)) return false; - if (!digest->may_have (c->glyphs[0])) return false; - 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 (c, lookup_type)) - return true; - return false; + TRACE_WOULD_APPLY (this); + if (unlikely (!c->len)) return TRACE_RETURN (false); + if (!digest->may_have (c->glyphs[0])) return TRACE_RETURN (false); + return TRACE_RETURN (process (c)); } inline bool apply_once (hb_apply_context_t *c) const { - unsigned int lookup_type = get_type (); - + TRACE_APPLY (this); if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property)) - return false; - - unsigned int count = get_subtable_count (); - for (unsigned int i = 0; i < count; i++) - if (get_subtable (i).apply (c, lookup_type)) - return true; - - return false; + return TRACE_RETURN (false); + return TRACE_RETURN (process (c)); } + static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const { bool ret = false; @@ -1320,6 +1206,7 @@ struct SubstLookup : Lookup if (unlikely (!c->buffer->len || !c->lookup_mask)) return false; + c->set_recurse_func (apply_recurse_func); c->set_lookup (*this); if (likely (!is_reverse ())) @@ -1361,11 +1248,9 @@ struct SubstLookup : Lookup return ret; } - private: inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, unsigned int i) { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); } - public: inline bool serialize_single (hb_serialize_context_t *c, uint32_t lookup_props, @@ -1373,7 +1258,7 @@ struct SubstLookup : Lookup Supplier<GlyphID> &substitutes, unsigned int num_glyphs) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false); return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); } @@ -1385,7 +1270,7 @@ struct SubstLookup : Lookup unsigned int num_glyphs, Supplier<GlyphID> &substitute_glyphs_list) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false); return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); @@ -1398,7 +1283,7 @@ struct SubstLookup : Lookup unsigned int num_glyphs, Supplier<GlyphID> &alternate_glyphs_list) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false); return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); @@ -1413,7 +1298,7 @@ struct SubstLookup : Lookup Supplier<unsigned int> &component_count_list, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { - TRACE_SERIALIZE (); + TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false); return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs, ligatures_list, component_count_list, component_list)); @@ -1421,7 +1306,7 @@ struct SubstLookup : Lookup inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable); if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false); @@ -1456,19 +1341,11 @@ struct GSUB : GSUBGPOS inline const SubstLookup& get_lookup (unsigned int i) const { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } - template <typename set_t> - inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const - { get_lookup (lookup_index).add_coverage (glyphs); } - static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); static inline void substitute_finish (hb_font_t *font, 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 (); + TRACE_SANITIZE (this); if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); return TRACE_RETURN (list.sanitize (c, this)); @@ -1501,73 +1378,37 @@ GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSE /* Out-of-class implementation for methods recursing */ -inline void ExtensionSubst::closure (hb_closure_context_t *c) const -{ - get_subtable ().closure (c, get_type ()); -} - -inline const Coverage & ExtensionSubst::get_coverage (void) const -{ - return get_subtable ().get_coverage (get_type ()); -} - -inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const -{ - return get_subtable ().would_apply (c, get_type ()); -} - -inline bool ExtensionSubst::apply (hb_apply_context_t *c) const -{ - TRACE_APPLY (); - 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 TRACE_RETURN (false); - unsigned int offset = get_offset (); - 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 { unsigned int type = get_type (); if (unlikely (type == SubstLookupSubTable::Extension)) - return CastR<ExtensionSubst> (get_subtable()).is_reverse (); + return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse (); return SubstLookup::lookup_type_is_reverse (type); } -static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index) +template <typename context_t> +inline typename context_t::return_t SubstLookup::process_recurse_func (context_t *c, unsigned int lookup_index) { const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); const SubstLookup &l = gsub.get_lookup (lookup_index); - - if (unlikely (c->nesting_level_left == 0)) - return; - - c->nesting_level_left--; - l.closure (c); - c->nesting_level_left++; + return l.process (c); } -static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index) +inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) { const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); const SubstLookup &l = gsub.get_lookup (lookup_index); - - if (unlikely (c->nesting_level_left == 0)) - return false; - - hb_apply_context_t new_c (*c); - new_c.nesting_level_left--; - new_c.set_lookup (l); - return l.apply_once (&new_c); + unsigned int saved_lookup_props = c->lookup_props; + unsigned int saved_property = c->property; + c->set_lookup (l); + bool ret = l.apply_once (c); + c->lookup_props = saved_lookup_props; + c->property = saved_property; + return ret; } -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh index dd7bdd3..40be861 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 @@ -37,44 +37,82 @@ namespace OT { + +#define TRACE_PROCESS(this) \ + hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + ""); + + #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, ""); - +#define TRACE_CLOSURE(this) \ + hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + ""); struct hb_closure_context_t { + inline const char *get_name (void) { return "CLOSURE"; } + static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE; + typedef hb_void_t return_t; + typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); + template <typename T> + inline return_t process (const T &obj) { obj.closure (this); return HB_VOID; } + static return_t default_return_value (void) { return HB_VOID; } + bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; } + return_t recurse (unsigned int lookup_index) + { + if (unlikely (nesting_level_left == 0 || !recurse_func)) + return default_return_value (); + + nesting_level_left--; + recurse_func (this, lookup_index); + nesting_level_left++; + return HB_VOID; + } + hb_face_t *face; hb_set_t *glyphs; + recurse_func_t recurse_func; 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_), + recurse_func (NULL), nesting_level_left (nesting_level_left_), debug_depth (0) {} + + void set_recurse_func (recurse_func_t func) { recurse_func = func; } }; -/* TODO Add TRACE_RETURN annotation to gsub. */ #ifndef HB_DEBUG_WOULD_APPLY #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) #endif -#define TRACE_WOULD_APPLY() \ - hb_auto_trace_t<HB_DEBUG_WOULD_APPLY> trace (&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, "%d glyphs", c->len); - +#define TRACE_WOULD_APPLY(this) \ + hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + "%d glyphs", c->len); struct hb_would_apply_context_t { + inline const char *get_name (void) { return "WOULD_APPLY"; } + static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY; + typedef bool return_t; + template <typename T> + inline return_t process (const T &obj) { return obj.would_apply (this); } + static return_t default_return_value (void) { return false; } + bool stop_sublookup_iteration (const return_t r) const { return r; } + hb_face_t *face; const hb_codepoint_t *glyphs; unsigned int len; @@ -89,31 +127,146 @@ struct hb_would_apply_context_t glyphs (glyphs_), len (len_), zero_context (zero_context_), - debug_depth (0) {}; + debug_depth (0) {} +}; + + + +#ifndef HB_DEBUG_COLLECT_GLYPHS +#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) +#endif + +#define TRACE_COLLECT_GLYPHS(this) \ + hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + ""); + +struct hb_collect_glyphs_context_t +{ + inline const char *get_name (void) { return "COLLECT_GLYPHS"; } + static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS; + typedef hb_void_t return_t; + typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); + template <typename T> + inline return_t process (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } + static return_t default_return_value (void) { return HB_VOID; } + bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; } + return_t recurse (unsigned int lookup_index) + { + if (unlikely (nesting_level_left == 0 || !recurse_func)) + return default_return_value (); + + /* Note that GPOS sets recurse_func to NULL already, so it doesn't get + * past the previous check. For GSUB, we only want to collect the output + * glyphs in the recursion. If output is not requested, we can go home now. */ + + if (output == hb_set_get_empty ()) + return HB_VOID; + + hb_set_t *old_before = before; + hb_set_t *old_input = input; + hb_set_t *old_after = after; + before = input = after = hb_set_get_empty (); + + nesting_level_left--; + recurse_func (this, lookup_index); + nesting_level_left++; + + before = old_before; + input = old_input; + after = old_after; + + return HB_VOID; + } + + hb_face_t *face; + hb_set_t *before; + hb_set_t *input; + hb_set_t *after; + hb_set_t *output; + recurse_func_t recurse_func; + unsigned int nesting_level_left; + unsigned int debug_depth; + + hb_collect_glyphs_context_t (hb_face_t *face_, + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output, /* OUT. May be NULL */ + unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : + face (face_), + before (glyphs_before ? glyphs_before : hb_set_get_empty ()), + input (glyphs_input ? glyphs_input : hb_set_get_empty ()), + after (glyphs_after ? glyphs_after : hb_set_get_empty ()), + output (glyphs_output ? glyphs_output : hb_set_get_empty ()), + recurse_func (NULL), + nesting_level_left (nesting_level_left_), + debug_depth (0) {} + + void set_recurse_func (recurse_func_t func) { recurse_func = func; } +}; + + + +struct hb_get_coverage_context_t +{ + inline const char *get_name (void) { return "GET_COVERAGE"; } + static const unsigned int max_debug_depth = 0; + typedef const Coverage &return_t; + template <typename T> + inline return_t process (const T &obj) { return obj.get_coverage (); } + static return_t default_return_value (void) { return Null(Coverage); } + + hb_get_coverage_context_t (void) : + debug_depth (0) {} + + unsigned int debug_depth; }; + #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, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); - +#define TRACE_APPLY(this) \ + hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ + "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); struct hb_apply_context_t { + inline const char *get_name (void) { return "APPLY"; } + static const unsigned int max_debug_depth = HB_DEBUG_APPLY; + typedef bool return_t; + typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index); + template <typename T> + inline return_t process (const T &obj) { return obj.apply (this); } + static return_t default_return_value (void) { return false; } + bool stop_sublookup_iteration (const return_t r) const { return r; } + return_t recurse (unsigned int lookup_index) + { + if (unlikely (nesting_level_left == 0 || !recurse_func)) + return default_return_value (); + + nesting_level_left--; + bool ret = recurse_func (this, lookup_index); + nesting_level_left++; + return ret; + } + hb_font_t *font; hb_face_t *face; hb_buffer_t *buffer; hb_direction_t direction; hb_mask_t lookup_mask; + recurse_func_t recurse_func; unsigned int nesting_level_left; unsigned int lookup_props; unsigned int property; /* propety of first glyph */ - unsigned int debug_depth; const GDEF &gdef; bool has_glyph_classes; + unsigned int debug_depth; hb_apply_context_t (hb_font_t *font_, @@ -122,18 +275,16 @@ struct hb_apply_context_t font (font_), face (font->face), buffer (buffer_), direction (buffer_->props.direction), lookup_mask (lookup_mask_), + recurse_func (NULL), nesting_level_left (MAX_NESTING_LEVEL), - lookup_props (0), property (0), debug_depth (0), + lookup_props (0), property (0), gdef (*hb_ot_layout_from_face (face)->gdef), - has_glyph_classes (gdef.has_glyph_classes ()) {} + has_glyph_classes (gdef.has_glyph_classes ()), + debug_depth (0) {} - void set_lookup_props (unsigned int lookup_props_) { - lookup_props = lookup_props_; - } - - void set_lookup (const Lookup &l) { - lookup_props = l.get_props (); - } + void set_recurse_func (recurse_func_t func) { recurse_func = func; } + void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } + void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } struct mark_skipping_forward_iterator_t { @@ -264,7 +415,7 @@ struct hb_apply_context_t if (glyph_props & lookup_props & LookupFlag::IgnoreFlags) return false; - if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) + if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) return match_properties_mark (glyph, glyph_props, lookup_props); return true; @@ -295,7 +446,7 @@ struct hb_apply_context_t *property_out = property; /* If it's a mark, skip it if we don't accept it. */ - if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)) + if (unlikely (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) return !match_properties (info->codepoint, property, lookup_props); /* If not a mark, don't skip. */ @@ -339,21 +490,23 @@ struct hb_apply_context_t typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); +typedef void (*collect_glyphs_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 ContextClosureFuncs { intersects_func_t intersects; - closure_lookup_func_t closure; +}; +struct ContextCollectGlyphsFuncs +{ + collect_glyphs_func_t collect; }; 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); @@ -382,6 +535,32 @@ static inline bool intersects_array (hb_closure_context_t *c, } +static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) +{ + glyphs->add (value); +} +static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data) +{ + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); + class_def.add_class (glyphs, value); +} +static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) +{ + const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; + (data+coverage).add_coverage (glyphs); +} +static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, + hb_set_t *glyphs, + unsigned int count, + const USHORT values[], + collect_glyphs_func_t collect_func, + const void *collect_data) +{ + for (unsigned int i = 0; i < count; i++) + collect_func (glyphs, values[i], collect_data); +} + + static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) { return glyph_id == value; @@ -397,7 +576,6 @@ static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; } - static inline bool would_match_input (hb_would_apply_context_t *c, unsigned int count, /* Including the first glyph (not matched) */ const USHORT input[], /* Array of input values--start with second glyph */ @@ -422,7 +600,7 @@ static inline bool match_input (hb_apply_context_t *c, bool *p_is_mark_ligature = NULL, unsigned int *p_total_component_count = NULL) { - hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); + TRACE_APPLY (NULL); hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1); if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); @@ -445,7 +623,7 @@ static inline bool match_input (hb_apply_context_t *c, * ligate with a conjunct...) */ - bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK); + bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK); unsigned int total_component_count = 0; total_component_count += get_lig_num_comps (c->buffer->cur()); @@ -478,7 +656,7 @@ static inline bool match_input (hb_apply_context_t *c, return TRACE_RETURN (false); } - is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK); + is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK); total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]); } @@ -495,10 +673,10 @@ static inline bool match_input (hb_apply_context_t *c, } static inline void ligate_input (hb_apply_context_t *c, unsigned int count, /* Including the first glyph (not matched) */ - const USHORT input[], /* Array of input values--start with second glyph */ + const USHORT input[] HB_UNUSED, /* Array of input values--start with second glyph */ hb_codepoint_t lig_glyph, - match_func_t match_func, - const void *match_data, + match_func_t match_func HB_UNUSED, + const void *match_data HB_UNUSED, bool is_mark_ligature, unsigned int total_component_count) { @@ -530,7 +708,7 @@ static inline void ligate_input (hb_apply_context_t *c, * https://bugzilla.gnome.org/show_bug.cgi?id=437633 */ - unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE; + unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer); unsigned int last_lig_id = get_lig_id (c->buffer->cur()); unsigned int last_num_components = get_lig_num_comps (c->buffer->cur()); @@ -579,7 +757,7 @@ static inline bool match_backtrack (hb_apply_context_t *c, match_func_t match_func, const void *match_data) { - hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); + TRACE_APPLY (NULL); hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); if (skippy_iter.has_no_chance ()) @@ -604,7 +782,7 @@ static inline bool match_lookahead (hb_apply_context_t *c, const void *match_data, unsigned int offset) { - hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); + TRACE_APPLY (NULL); 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 ()) @@ -627,7 +805,7 @@ static inline bool match_lookahead (hb_apply_context_t *c, struct LookupRecord { inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -640,22 +818,22 @@ 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) +template <typename context_t> +static inline void recurse_lookups (context_t *c, + unsigned int lookupCount, + const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) { for (unsigned int i = 0; i < lookupCount; i++) - closure_func (c, lookupRecord->lookupListIndex); + c->recurse (lookupRecord->lookupListIndex); } static inline bool apply_lookup (hb_apply_context_t *c, unsigned int count, /* Including the first glyph */ unsigned int lookupCount, - const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ - apply_lookup_func_t apply_func) + const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) { - hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); + TRACE_APPLY (NULL); + unsigned int end = c->buffer->len; if (unlikely (count == 0 || c->buffer->idx + count > end)) return TRACE_RETURN (false); @@ -684,7 +862,7 @@ static inline bool apply_lookup (hb_apply_context_t *c, unsigned int old_pos = c->buffer->idx; /* Apply a lookup */ - bool done = apply_func (c, lookupRecord->lookupListIndex); + bool done = c->recurse (lookupRecord->lookupListIndex); lookupRecord++; lookupCount--; @@ -718,6 +896,12 @@ struct ContextClosureLookupContext const void *intersects_data; }; +struct ContextCollectGlyphsLookupContext +{ + ContextCollectGlyphsFuncs funcs; + const void *collect_data; +}; + struct ContextApplyLookupContext { ContextApplyFuncs funcs; @@ -734,17 +918,29 @@ static inline void context_closure_lookup (hb_closure_context_t *c, 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); + recurse_lookups (c, + lookupCount, lookupRecord); } +static inline void context_collect_glyphs_lookup (hb_collect_glyphs_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[], + ContextCollectGlyphsLookupContext &lookup_context) +{ + collect_array (c, c->input, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.collect, lookup_context.collect_data); + recurse_lookups (c, + lookupCount, lookupRecord); +} static inline bool context_would_apply_lookup (hb_would_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[], + unsigned int lookupCount HB_UNUSED, + const LookupRecord lookupRecord[] HB_UNUSED, ContextApplyLookupContext &lookup_context) { return would_match_input (c, @@ -763,19 +959,14 @@ static inline bool context_apply_lookup (hb_apply_context_t *c, lookup_context.funcs.match, lookup_context.match_data) && apply_lookup (c, inputCount, - lookupCount, lookupRecord, - lookup_context.funcs.apply); + lookupCount, lookupRecord); } struct Rule { - friend struct RuleSet; - - private: - inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); context_closure_lookup (c, inputCount, input, @@ -783,23 +974,33 @@ struct Rule lookup_context); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const + { + TRACE_COLLECT_GLYPHS (this); + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); + context_collect_glyphs_lookup (c, + inputCount, input, + lookupCount, lookupRecord, + lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); } inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { - TRACE_APPLY (); + TRACE_APPLY (this); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); } public: inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return inputCount.sanitize (c) && lookupCount.sanitize (c) && c->check_range (input, @@ -824,15 +1025,23 @@ struct RuleSet { inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) (this+rule[i]).closure (c, lookup_context); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const + { + TRACE_COLLECT_GLYPHS (this); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + (this+rule[i]).collect_glyphs (c, lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) { @@ -844,7 +1053,7 @@ struct RuleSet inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { - TRACE_APPLY (); + TRACE_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) { @@ -855,7 +1064,7 @@ struct RuleSet } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (rule.sanitize (c, this)); } @@ -870,18 +1079,14 @@ struct RuleSet struct ContextFormat1 { - friend struct Context; - - private: - - inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); const Coverage &cov = (this+coverage); struct ContextClosureLookupContext lookup_context = { - {intersects_glyph, closure_func}, + {intersects_glyph}, NULL }; @@ -893,35 +1098,55 @@ struct ContextFormat1 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + + struct ContextCollectGlyphsLookupContext lookup_context = { + {collect_glyph}, + NULL + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + (this+ruleSet[i]).collect_glyphs (c, lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); - const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])]; + const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; struct ContextApplyLookupContext lookup_context = { - {match_glyph, NULL}, + {match_glyph}, NULL }; return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); } - inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const + inline const Coverage &get_coverage (void) const + { + return this+coverage; + } + + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const RuleSet &rule_set = this+ruleSet[index]; struct ContextApplyLookupContext lookup_context = { - {match_glyph, apply_func}, + {match_glyph}, NULL }; return TRACE_RETURN (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); } @@ -940,21 +1165,17 @@ struct ContextFormat1 struct ContextFormat2 { - friend struct Context; - - private: - - inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); if (!(this+coverage).intersects (c->glyphs)) return; const ClassDef &class_def = this+classDef; struct ContextClosureLookupContext lookup_context = { - {intersects_class, closure_func}, - NULL + {intersects_class}, + &class_def }; unsigned int count = ruleSet.len; @@ -965,38 +1186,59 @@ struct ContextFormat2 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + + const ClassDef &class_def = this+classDef; + struct ContextCollectGlyphsLookupContext lookup_context = { + {collect_class}, + &class_def + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + (this+ruleSet[i]).collect_glyphs (c, lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); const ClassDef &class_def = this+classDef; - unsigned int index = class_def (c->glyphs[0]); + unsigned int index = class_def.get_class (c->glyphs[0]); const RuleSet &rule_set = this+ruleSet[index]; struct ContextApplyLookupContext lookup_context = { - {match_class, NULL}, + {match_class}, &class_def }; return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); } - inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const + inline const Coverage &get_coverage (void) const + { + return this+coverage; + } + + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int index = (this+coverage).get_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->cur().codepoint); + index = class_def.get_class (c->buffer->cur().codepoint); const RuleSet &rule_set = this+ruleSet[index]; struct ContextApplyLookupContext lookup_context = { - {match_class, apply_func}, + {match_class}, &class_def }; return TRACE_RETURN (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); } @@ -1018,19 +1260,15 @@ struct ContextFormat2 struct ContextFormat3 { - friend struct Context; - - private: - - inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); 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}, + {intersects_coverage}, this }; context_closure_lookup (c, @@ -1039,34 +1277,56 @@ struct ContextFormat3 lookup_context); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage[0]).add_coverage (c->input); + + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); + struct ContextCollectGlyphsLookupContext lookup_context = { + {collect_coverage}, + this + }; + + context_collect_glyphs_lookup (c, + glyphCount, (const USHORT *) (coverage + 1), + lookupCount, lookupRecord, + lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); struct ContextApplyLookupContext lookup_context = { - {match_coverage, NULL}, + {match_coverage}, this }; return TRACE_RETURN (context_would_apply_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 + inline const Coverage &get_coverage (void) const { - TRACE_APPLY (); - unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint); + return this+coverage[0]; + } + + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int index = (this+coverage[0]).get_coverage (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 ContextApplyLookupContext lookup_context = { - {match_coverage, apply_func}, + {match_coverage}, this }; 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 (); + TRACE_SANITIZE (this); if (!c->check_struct (this)) return TRACE_RETURN (false); unsigned int count = glyphCount; if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); @@ -1092,52 +1352,20 @@ struct ContextFormat3 struct Context { - protected: - - inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_CLOSURE (); + TRACE_PROCESS (this); 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 const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return this + u.format1.coverage; - case 2: return this + u.format2.coverage; - case 3: return this + u.format3.coverage[0]; - default:return Null(Coverage); - } - } - - inline bool would_apply (hb_would_apply_context_t *c) const - { - switch (u.format) { - case 1: return u.format1.would_apply (c); - case 2: return u.format2.would_apply (c); - case 3: return u.format3.would_apply (c); - default:return false; - } - } - - inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const - { - TRACE_APPLY (); - switch (u.format) { - 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); + case 1: return TRACE_RETURN (c->process (u.format1)); + case 2: return TRACE_RETURN (c->process (u.format2)); + case 3: return TRACE_RETURN (c->process (u.format3)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1165,6 +1393,12 @@ struct ChainContextClosureLookupContext const void *intersects_data[3]; }; +struct ChainContextCollectGlyphsLookupContext +{ + ContextCollectGlyphsFuncs funcs; + const void *collect_data[3]; +}; + struct ChainContextApplyLookupContext { ContextApplyFuncs funcs; @@ -1191,20 +1425,43 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c, && intersects_array (c, lookaheadCount, lookahead, lookup_context.funcs.intersects, lookup_context.intersects_data[2])) - closure_lookup (c, - lookupCount, lookupRecord, - lookup_context.funcs.closure); + recurse_lookups (c, + lookupCount, lookupRecord); +} + +static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_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[], + ChainContextCollectGlyphsLookupContext &lookup_context) +{ + collect_array (c, c->before, + backtrackCount, backtrack, + lookup_context.funcs.collect, lookup_context.collect_data[0]); + collect_array (c, c->input, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.collect, lookup_context.collect_data[1]); + collect_array (c, c->after, + lookaheadCount, lookahead, + lookup_context.funcs.collect, lookup_context.collect_data[2]); + recurse_lookups (c, + lookupCount, lookupRecord); } static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, unsigned int backtrackCount, - const USHORT backtrack[], + const USHORT backtrack[] HB_UNUSED, 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[], + const USHORT lookahead[] HB_UNUSED, + unsigned int lookupCount HB_UNUSED, + const LookupRecord lookupRecord[] HB_UNUSED, ChainContextApplyLookupContext &lookup_context) { return (c->zero_context ? !backtrackCount && !lookaheadCount : true) @@ -1224,7 +1481,7 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c, const LookupRecord lookupRecord[], ChainContextApplyLookupContext &lookup_context) { - unsigned int lookahead_offset; + unsigned int lookahead_offset = 0; return match_input (c, inputCount, input, lookup_context.funcs.match, lookup_context.match_data[1], @@ -1238,19 +1495,14 @@ static inline bool chain_context_apply_lookup (hb_apply_context_t *c, lookahead_offset) && apply_lookup (c, inputCount, - lookupCount, lookupRecord, - lookup_context.funcs.apply); + lookupCount, lookupRecord); } struct ChainRule { - friend struct ChainRuleSet; - - private: - inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); @@ -1262,9 +1514,23 @@ struct ChainRule lookup_context); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const + { + TRACE_COLLECT_GLYPHS (this); + 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_collect_glyphs_lookup (c, + backtrack.len, backtrack.array, + input.len, input.array, + lookahead.len, lookahead.array, + lookup.len, lookup.array, + lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); @@ -1277,7 +1543,7 @@ struct ChainRule inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { - TRACE_APPLY (); + TRACE_APPLY (this); const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); @@ -1288,9 +1554,8 @@ struct ChainRule lookup.array, lookup_context)); } - public: inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!backtrack.sanitize (c)) return TRACE_RETURN (false); HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); if (!input.sanitize (c)) return TRACE_RETURN (false); @@ -1322,15 +1587,23 @@ struct ChainRuleSet { inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) (this+rule[i]).closure (c, lookup_context); } + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const + { + TRACE_COLLECT_GLYPHS (this); + unsigned int num_rules = rule.len; + for (unsigned int i = 0; i < num_rules; i++) + (this+rule[i]).collect_glyphs (c, lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) if ((this+rule[i]).would_apply (c, lookup_context)) @@ -1341,7 +1614,7 @@ struct ChainRuleSet inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { - TRACE_APPLY (); + TRACE_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) if ((this+rule[i]).apply (c, lookup_context)) @@ -1351,7 +1624,7 @@ struct ChainRuleSet } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (rule.sanitize (c, this)); } @@ -1365,17 +1638,13 @@ struct ChainRuleSet struct ChainContextFormat1 { - friend struct ChainContext; - - private: - - inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); const Coverage &cov = (this+coverage); struct ChainContextClosureLookupContext lookup_context = { - {intersects_glyph, closure_func}, + {intersects_glyph}, {NULL, NULL, NULL} }; @@ -1387,34 +1656,54 @@ struct ChainContextFormat1 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + + struct ChainContextCollectGlyphsLookupContext lookup_context = { + {collect_glyph}, + {NULL, NULL, NULL} + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + (this+ruleSet[i]).collect_glyphs (c, lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); - const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])]; + const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; struct ChainContextApplyLookupContext lookup_context = { - {match_glyph, NULL}, + {match_glyph}, {NULL, NULL, NULL} }; return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); } - inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const + inline const Coverage &get_coverage (void) const + { + return this+coverage; + } + + inline bool apply (hb_apply_context_t *c) const { - TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + TRACE_APPLY (this); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { - {match_glyph, apply_func}, + {match_glyph}, {NULL, NULL, NULL} }; return TRACE_RETURN (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); } @@ -1432,13 +1721,9 @@ struct ChainContextFormat1 struct ChainContextFormat2 { - friend struct ChainContext; - - private: - - inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); if (!(this+coverage).intersects (c->glyphs)) return; @@ -1447,7 +1732,7 @@ struct ChainContextFormat2 const ClassDef &lookahead_class_def = this+lookaheadClassDef; struct ChainContextClosureLookupContext lookup_context = { - {intersects_class, closure_func}, + {intersects_class}, {&backtrack_class_def, &input_class_def, &lookahead_class_def} @@ -1461,35 +1746,65 @@ struct ChainContextFormat2 } } + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const + { + TRACE_COLLECT_GLYPHS (this); + (this+coverage).add_coverage (c->input); + + const ClassDef &backtrack_class_def = this+backtrackClassDef; + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + + struct ChainContextCollectGlyphsLookupContext lookup_context = { + {collect_class}, + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} + }; + + unsigned int count = ruleSet.len; + for (unsigned int i = 0; i < count; i++) + (this+ruleSet[i]).collect_glyphs (c, lookup_context); + } + inline bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); + const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; - unsigned int index = input_class_def (c->glyphs[0]); + unsigned int index = input_class_def.get_class (c->glyphs[0]); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { - {match_class, NULL}, - {NULL, &input_class_def, NULL} + {match_class}, + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} }; return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); } - inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const + inline const Coverage &get_coverage (void) const { - TRACE_APPLY (); - unsigned int index = (this+coverage) (c->buffer->cur().codepoint); + return this+coverage; + } + + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (this); + unsigned int index = (this+coverage).get_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->cur().codepoint); + index = input_class_def.get_class (c->buffer->cur().codepoint); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { - {match_class, apply_func}, + {match_class}, {&backtrack_class_def, &input_class_def, &lookahead_class_def} @@ -1498,7 +1813,7 @@ struct ChainContextFormat2 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && ruleSet.sanitize (c, this)); @@ -1530,13 +1845,9 @@ struct ChainContextFormat2 struct ChainContextFormat3 { - friend struct ChainContext; - - private: - - inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const + inline void closure (hb_closure_context_t *c) const { - TRACE_CLOSURE (); + TRACE_CLOSURE (this); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); if (!(this+input[0]).intersects (c->glyphs)) @@ -1545,7 +1856,7 @@ struct ChainContextFormat3 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); struct ChainContextClosureLookupContext lookup_context = { - {intersects_coverage, closure_func}, + {intersects_coverage}, {this, this, this} }; chain_context_closure_lookup (c, @@ -1556,21 +1867,36 @@ struct ChainContextFormat3 lookup_context); } - inline const Coverage &get_coverage (void) const + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const { + TRACE_COLLECT_GLYPHS (this); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); - return this+input[0]; + + (this+input[0]).add_coverage (c->input); + + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); + struct ChainContextCollectGlyphsLookupContext lookup_context = { + {collect_coverage}, + {this, this, this} + }; + chain_context_collect_glyphs_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 would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (); + TRACE_WOULD_APPLY (this); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); struct ChainContextApplyLookupContext lookup_context = { - {match_coverage, NULL}, + {match_coverage}, {this, this, this} }; return TRACE_RETURN (chain_context_would_apply_lookup (c, @@ -1580,18 +1906,24 @@ struct ChainContextFormat3 lookup.len, lookup.array, lookup_context)); } - inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const + inline const Coverage &get_coverage (void) const { - TRACE_APPLY (); const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + return this+input[0]; + } - unsigned int index = (this+input[0]) (c->buffer->cur().codepoint); + inline bool apply (hb_apply_context_t *c) const + { + TRACE_APPLY (this); + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); + + unsigned int index = (this+input[0]).get_coverage (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 ChainContextApplyLookupContext lookup_context = { - {match_coverage, apply_func}, + {match_coverage}, {this, this, this} }; return TRACE_RETURN (chain_context_apply_lookup (c, @@ -1602,7 +1934,7 @@ struct ChainContextFormat3 } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); if (!input.sanitize (c, this)) return TRACE_RETURN (false); @@ -1635,52 +1967,20 @@ 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 const Coverage &get_coverage (void) const - { - switch (u.format) { - case 1: return this + u.format1.coverage; - case 2: return this + u.format2.coverage; - case 3: return u.format3.get_coverage (); - default:return Null(Coverage); - } - } - - inline bool would_apply (hb_would_apply_context_t *c) const - { - switch (u.format) { - case 1: return u.format1.would_apply (c); - case 2: return u.format2.would_apply (c); - case 3: return u.format3.would_apply (c); - default:return false; - } - } - - inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const { - TRACE_APPLY (); + TRACE_PROCESS (this); switch (u.format) { - 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); + case 1: return TRACE_RETURN (c->process (u.format1)); + case 2: return TRACE_RETURN (c->process (u.format2)); + case 3: return TRACE_RETURN (c->process (u.format3)); + default:return TRACE_RETURN (c->default_return_value ()); } } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1702,14 +2002,11 @@ struct ChainContext struct ExtensionFormat1 { - friend struct Extension; - - protected: inline unsigned int get_type (void) const { return extensionLookupType; } inline unsigned int get_offset (void) const { return extensionOffset; } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this)); } @@ -1724,6 +2021,7 @@ struct ExtensionFormat1 DEFINE_SIZE_STATIC (8); }; +template <typename T> struct Extension { inline unsigned int get_type (void) const @@ -1741,8 +2039,22 @@ struct Extension } } - inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + template <typename X> + inline const X& get_subtable (void) const + { + unsigned int offset = get_offset (); + if (unlikely (!offset)) return Null(typename T::LookupSubTable); + return StructAtOffset<typename T::LookupSubTable> (this, offset); + } + + template <typename context_t> + inline typename context_t::return_t process (context_t *c) const + { + return get_subtable<typename T::LookupSubTable> ().process (c, get_type ()); + } + + inline bool sanitize_self (hb_sanitize_context_t *c) { + TRACE_SANITIZE (this); if (!u.format.sanitize (c)) return TRACE_RETURN (false); switch (u.format) { case 1: return TRACE_RETURN (u.format1.sanitize (c)); @@ -1750,6 +2062,14 @@ struct Extension } } + inline bool sanitize (hb_sanitize_context_t *c) { + TRACE_SANITIZE (this); + if (!sanitize_self (c)) return TRACE_RETURN (false); + unsigned int offset = get_offset (); + if (unlikely (!offset)) return TRACE_RETURN (true); + return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ())); + } + protected: union { USHORT format; /* Format identifier */ @@ -1799,7 +2119,7 @@ struct GSUBGPOS { return (this+lookupList)[i]; } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && scriptList.sanitize (c, this) && featureList.sanitize (c, this) && @@ -1820,7 +2140,7 @@ struct GSUBGPOS }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh index 70fda8e..49093de 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh @@ -50,12 +50,12 @@ */ typedef enum { - HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0x0001, - HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 0x0002, - HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 0x0004, - HB_OT_LAYOUT_GLYPH_CLASS_MARK = 0x0008, - HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 0x0010 -} hb_ot_layout_glyph_class_t; + HB_OT_LAYOUT_GLYPH_PROPS_UNCLASSIFIED = 0x0001, + HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH = 0x0002, + HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE = 0x0004, + HB_OT_LAYOUT_GLYPH_PROPS_MARK = 0x0008, + HB_OT_LAYOUT_GLYPH_PROPS_COMPONENT = 0x0010 +} hb_ot_layout_glyph_class_mask_t; @@ -123,7 +123,7 @@ get_lig_comp (const hb_glyph_info_t &info) static inline unsigned int get_lig_num_comps (const hb_glyph_info_t &info) { - if ((info.glyph_props() & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE) && is_a_ligature (info)) + if ((info.glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE) && is_a_ligature (info)) return info.lig_props() & 0x0F; else return 1; @@ -138,7 +138,7 @@ static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) { HB_INTERNAL hb_bool_t -hb_ot_layout_would_substitute_lookup_fast (hb_face_t *face, +hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, unsigned int lookup_index, const hb_codepoint_t *glyphs, unsigned int glyphs_length, diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc index e241e33..5c266e6 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc @@ -33,7 +33,6 @@ #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" -#include "hb-ot-maxp-table.hh" #include <stdlib.h> #include <string.h> @@ -71,9 +70,9 @@ _hb_ot_layout_create (hb_face_t *face) } for (unsigned int i = 0; i < layout->gsub_lookup_count; i++) - layout->gsub->add_coverage (&layout->gsub_digests[i], i); + layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]); for (unsigned int i = 0; i < layout->gpos_lookup_count; i++) - layout->gpos->add_coverage (&layout->gpos_digests[i], i); + layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]); return layout; } @@ -121,6 +120,20 @@ hb_ot_layout_has_glyph_classes (hb_face_t *face) return _get_gdef (face).has_glyph_classes (); } +hb_ot_layout_glyph_class_t +hb_ot_layout_get_glyph_class (hb_face_t *face, + hb_codepoint_t glyph) +{ + return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph); +} + +void +hb_ot_layout_get_glyphs_in_class (hb_face_t *face, + hb_ot_layout_glyph_class_t klass, + hb_set_t *glyphs /* OUT */) +{ + return _get_gdef (face).get_glyphs_in_class (klass, glyphs); +} unsigned int hb_ot_layout_get_attach_points (hb_face_t *face, @@ -374,12 +387,12 @@ hb_ot_layout_language_find_feature (hb_face_t *face, } unsigned int -hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, - hb_tag_t table_tag, - unsigned int feature_index, - unsigned int start_offset, - unsigned int *lookup_count /* IN/OUT */, - unsigned int *lookup_indexes /* OUT */) +hb_ot_layout_feature_get_lookups (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + unsigned int start_offset, + unsigned int *lookup_count /* IN/OUT */, + unsigned int *lookup_indexes /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); const OT::Feature &f = g.get_feature (feature_index); @@ -387,6 +400,219 @@ hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes); } +static void +_hb_ot_layout_collect_lookups_lookups (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + hb_set_t *lookup_indexes /* OUT */) +{ + unsigned int lookup_indices[32]; + unsigned int offset, len; + + offset = 0; + do { + len = ARRAY_LENGTH (lookup_indices); + hb_ot_layout_feature_get_lookups (face, + table_tag, + feature_index, + offset, &len, + lookup_indices); + + for (unsigned int i = 0; i < len; i++) + lookup_indexes->add (lookup_indices[i]); + + offset += len; + } while (len == ARRAY_LENGTH (lookup_indices)); +} + +static void +_hb_ot_layout_collect_lookups_features (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + unsigned int language_index, + const hb_tag_t *features, + hb_set_t *lookup_indexes /* OUT */) +{ + unsigned int required_feature_index; + if (hb_ot_layout_language_get_required_feature_index (face, + table_tag, + script_index, + language_index, + &required_feature_index)) + _hb_ot_layout_collect_lookups_lookups (face, + table_tag, + required_feature_index, + lookup_indexes); + + if (!features) + { + /* All features */ + unsigned int feature_indices[32]; + unsigned int offset, len; + + offset = 0; + do { + len = ARRAY_LENGTH (feature_indices); + hb_ot_layout_language_get_feature_indexes (face, + table_tag, + script_index, + language_index, + offset, &len, + feature_indices); + + for (unsigned int i = 0; i < len; i++) + _hb_ot_layout_collect_lookups_lookups (face, + table_tag, + feature_indices[i], + lookup_indexes); + + offset += len; + } while (len == ARRAY_LENGTH (feature_indices)); + } + else + { + for (; *features; features++) + { + unsigned int feature_index; + if (hb_ot_layout_language_find_feature (face, + table_tag, + script_index, + language_index, + *features, + &feature_index)) + _hb_ot_layout_collect_lookups_lookups (face, + table_tag, + feature_index, + lookup_indexes); + } + } +} + +static void +_hb_ot_layout_collect_lookups_languages (hb_face_t *face, + hb_tag_t table_tag, + unsigned int script_index, + const hb_tag_t *languages, + const hb_tag_t *features, + hb_set_t *lookup_indexes /* OUT */) +{ + _hb_ot_layout_collect_lookups_features (face, + table_tag, + script_index, + HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, + features, + lookup_indexes); + + if (!languages) + { + /* All languages */ + unsigned int count = hb_ot_layout_script_get_language_tags (face, + table_tag, + script_index, + 0, NULL, NULL); + for (unsigned int language_index = 0; language_index < count; language_index++) + _hb_ot_layout_collect_lookups_features (face, + table_tag, + script_index, + language_index, + features, + lookup_indexes); + } + else + { + for (; *languages; languages++) + { + unsigned int language_index; + if (hb_ot_layout_script_find_language (face, + table_tag, + script_index, + *languages, + &language_index)) + _hb_ot_layout_collect_lookups_features (face, + table_tag, + script_index, + language_index, + features, + lookup_indexes); + } + } +} + +void +hb_ot_layout_collect_lookups (hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *scripts, + const hb_tag_t *languages, + const hb_tag_t *features, + hb_set_t *lookup_indexes /* OUT */) +{ + if (!scripts) + { + /* All scripts */ + unsigned int count = hb_ot_layout_table_get_script_tags (face, + table_tag, + 0, NULL, NULL); + for (unsigned int script_index = 0; script_index < count; script_index++) + _hb_ot_layout_collect_lookups_languages (face, + table_tag, + script_index, + languages, + features, + lookup_indexes); + } + else + { + for (; *scripts; scripts++) + { + unsigned int script_index; + if (hb_ot_layout_table_find_script (face, + table_tag, + *scripts, + &script_index)) + _hb_ot_layout_collect_lookups_languages (face, + table_tag, + script_index, + languages, + features, + lookup_indexes); + } + } +} + +void +hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, + hb_tag_t table_tag, + unsigned int lookup_index, + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output /* OUT. May be NULL */) +{ + if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; + + OT::hb_collect_glyphs_context_t c (face, + glyphs_before, + glyphs_input, + glyphs_after, + glyphs_output); + + switch (table_tag) + { + case HB_OT_TAG_GSUB: + { + const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); + l.collect_glyphs_lookup (&c); + return; + } + case HB_OT_TAG_GPOS: + { + const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index); + l.collect_glyphs_lookup (&c); + return; + } + } +} + /* * OT::GSUB @@ -399,18 +625,18 @@ hb_ot_layout_has_substitution (hb_face_t *face) } hb_bool_t -hb_ot_layout_would_substitute_lookup (hb_face_t *face, +hb_ot_layout_lookup_would_substitute (hb_face_t *face, unsigned int lookup_index, const hb_codepoint_t *glyphs, unsigned int glyphs_length, hb_bool_t zero_context) { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false; - return hb_ot_layout_would_substitute_lookup_fast (face, lookup_index, glyphs, glyphs_length, zero_context); + return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context); } hb_bool_t -hb_ot_layout_would_substitute_lookup_fast (hb_face_t *face, +hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, unsigned int lookup_index, const hb_codepoint_t *glyphs, unsigned int glyphs_length, @@ -452,12 +678,15 @@ hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer) } void -hb_ot_layout_substitute_closure_lookup (hb_face_t *face, +hb_ot_layout_lookup_substitute_closure (hb_face_t *face, unsigned int lookup_index, hb_set_t *glyphs) { OT::hb_closure_context_t c (face, glyphs); - _get_gsub (face).closure_lookup (&c, lookup_index); + + const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index); + + l.closure (&c); } /* @@ -496,3 +725,48 @@ hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t ze { OT::GPOS::position_finish (font, buffer, zero_width_attached_marks); } + +hb_bool_t +hb_ot_layout_get_size_params (hb_face_t *face, + unsigned int *design_size, /* OUT. May be NULL */ + unsigned int *subfamily_id, /* OUT. May be NULL */ + unsigned int *subfamily_name_id, /* OUT. May be NULL */ + unsigned int *range_start, /* OUT. May be NULL */ + unsigned int *range_end /* OUT. May be NULL */) +{ + const OT::GPOS &gpos = _get_gpos (face); + const hb_tag_t tag = HB_TAG ('s','i','z','e'); + + unsigned int num_features = gpos.get_feature_count (); + for (unsigned int i = 0; i < num_features; i++) + { + if (tag == gpos.get_feature_tag (i)) + { + const OT::Feature &f = gpos.get_feature (i); + const OT::FeatureParamsSize ¶ms = f.get_feature_params ().get_size_params (tag); + + if (params.designSize) + { +#define PARAM(a, A) if (a) *a = params.A + PARAM (design_size, designSize); + PARAM (subfamily_id, subfamilyID); + PARAM (subfamily_name_id, subfamilyNameID); + PARAM (range_start, rangeStart); + PARAM (range_end, rangeEnd); +#undef PARAM + + return true; + } + } + } + +#define PARAM(a, A) if (a) *a = 0 + PARAM (design_size, designSize); + PARAM (subfamily_id, subfamilyID); + PARAM (subfamily_name_id, subfamilyNameID); + PARAM (range_start, rangeStart); + PARAM (range_end, rangeEnd); +#undef PARAM + + return false; +} diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.h b/third_party/harfbuzz-ng/src/hb-ot-layout.h index d431a38..134f1a6 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-layout.h +++ b/third_party/harfbuzz-ng/src/hb-ot-layout.h @@ -50,6 +50,24 @@ HB_BEGIN_DECLS hb_bool_t hb_ot_layout_has_glyph_classes (hb_face_t *face); +typedef enum { + HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0, + HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 1, + HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE = 2, + HB_OT_LAYOUT_GLYPH_CLASS_MARK = 3, + HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT = 4 +} hb_ot_layout_glyph_class_t; + +hb_ot_layout_glyph_class_t +hb_ot_layout_get_glyph_class (hb_face_t *face, + hb_codepoint_t glyph); + +void +hb_ot_layout_get_glyphs_in_class (hb_face_t *face, + hb_ot_layout_glyph_class_t klass, + hb_set_t *glyphs /* OUT */); + + /* Not that useful. Provides list of attach points for a glyph that a * client may want to cache */ unsigned int @@ -154,12 +172,60 @@ hb_ot_layout_language_find_feature (hb_face_t *face, unsigned int *feature_index); unsigned int -hb_ot_layout_feature_get_lookup_indexes (hb_face_t *face, +hb_ot_layout_feature_get_lookups (hb_face_t *face, + hb_tag_t table_tag, + unsigned int feature_index, + unsigned int start_offset, + unsigned int *lookup_count /* IN/OUT */, + unsigned int *lookup_indexes /* OUT */); + +void +hb_ot_layout_collect_lookups (hb_face_t *face, + hb_tag_t table_tag, + const hb_tag_t *scripts, + const hb_tag_t *languages, + const hb_tag_t *features, + hb_set_t *lookup_indexes /* OUT */); + +void +hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, + hb_tag_t table_tag, + hb_set_t *lookup_indexes /* OUT */); + +void +hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, + hb_tag_t table_tag, + unsigned int lookup_index, + hb_set_t *glyphs_before, /* OUT. May be NULL */ + hb_set_t *glyphs_input, /* OUT. May be NULL */ + hb_set_t *glyphs_after, /* OUT. May be NULL */ + hb_set_t *glyphs_output /* OUT. May be NULL */); + +#ifdef HB_NOT_IMPLEMENTED +typedef struct +{ + const hb_codepoint_t *before, + unsigned int before_length, + const hb_codepoint_t *input, + unsigned int input_length, + const hb_codepoint_t *after, + unsigned int after_length, +} hb_ot_layout_glyph_sequence_t; + +typedef hb_bool_t +(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font, + hb_tag_t table_tag, + unsigned int lookup_index, + const hb_ot_layout_glyph_sequence_t *sequence, + void *user_data); + +void +Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face, hb_tag_t table_tag, - unsigned int feature_index, - unsigned int start_offset, - unsigned int *lookup_count /* IN/OUT */, - unsigned int *lookup_indexes /* OUT */); + unsigned int lookup_index, + hb_ot_layout_glyph_sequence_func_t callback, + void *user_data); +#endif /* @@ -170,16 +236,30 @@ hb_bool_t hb_ot_layout_has_substitution (hb_face_t *face); hb_bool_t -hb_ot_layout_would_substitute_lookup (hb_face_t *face, +hb_ot_layout_lookup_would_substitute (hb_face_t *face, unsigned int lookup_index, const hb_codepoint_t *glyphs, unsigned int glyphs_length, hb_bool_t zero_context); void -hb_ot_layout_substitute_closure_lookup (hb_face_t *face, +hb_ot_layout_lookup_substitute_closure (hb_face_t *face, unsigned int lookup_index, - hb_set_t *glyphs); + hb_set_t *glyphs + /*TODO , hb_bool_t inclusive */); + +#ifdef HB_NOT_IMPLEMENTED +/* Note: You better have GDEF when using this API, or marks won't do much. */ +hb_bool_t +Xhb_ot_layout_lookup_substitute (hb_font_t *font, + unsigned int lookup_index, + const hb_ot_layout_glyph_sequence_t *sequence, + unsigned int out_size, + hb_codepoint_t *glyphs_out, /* OUT */ + unsigned int *clusters_out, /* OUT */ + unsigned int *out_length /* OUT */); +#endif + /* * GPOS @@ -188,6 +268,25 @@ hb_ot_layout_substitute_closure_lookup (hb_face_t *face, hb_bool_t hb_ot_layout_has_positioning (hb_face_t *face); +#ifdef HB_NOT_IMPLEMENTED +/* Note: You better have GDEF when using this API, or marks won't do much. */ +hb_bool_t +Xhb_ot_layout_lookup_position (hb_font_t *font, + unsigned int lookup_index, + const hb_ot_layout_glyph_sequence_t *sequence, + hb_glyph_position_t *positions /* IN / OUT */); +#endif + +/* Optical 'size' feature info. Returns true if found. + * http://www.microsoft.com/typography/otspec/features_pt.htm#size */ +hb_bool_t +hb_ot_layout_get_size_params (hb_face_t *face, + unsigned int *design_size, /* OUT. May be NULL */ + unsigned int *subfamily_id, /* OUT. May be NULL */ + unsigned int *subfamily_name_id, /* OUT. May be NULL */ + unsigned int *range_start, /* OUT. May be NULL */ + unsigned int *range_end /* OUT. May be NULL */); + HB_END_DECLS 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 7eb85c89..b140207 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-map-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-map-private.hh @@ -115,10 +115,7 @@ struct hb_ot_map_t *lookup_count = end - start; } - inline hb_tag_t get_chosen_script (unsigned int table_index) const - { return chosen_script[table_index]; } - - HB_INTERNAL void substitute_closure (const struct hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const; + HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const; HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; @@ -130,6 +127,9 @@ struct hb_ot_map_t pauses[1].finish (); } + public: + hb_tag_t chosen_script[2]; + bool found_script[2]; private: @@ -140,7 +140,6 @@ struct hb_ot_map_t hb_mask_t global_mask; - hb_tag_t chosen_script[2]; hb_prealloced_array_t<feature_map_t, 8> features; hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */ hb_prealloced_array_t<pause_map_t, 1> pauses[2]; /* GSUB/GPOS */ @@ -151,7 +150,8 @@ struct hb_ot_map_builder_t { public: - hb_ot_map_builder_t (void) { memset (this, 0, sizeof (*this)); } + HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_, + const hb_segment_properties_t *props_); HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback = false); @@ -163,9 +163,7 @@ struct hb_ot_map_builder_t inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func) { add_pause (1, pause_func); } - HB_INTERNAL void compile (hb_face_t *face, - const hb_segment_properties_t *props, - struct hb_ot_map_t &m); + HB_INTERNAL void compile (struct hb_ot_map_t &m); inline void finish (void) { feature_infos.finish (); @@ -195,6 +193,17 @@ struct hb_ot_map_builder_t HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func); + public: + + hb_face_t *face; + hb_segment_properties_t props; + + hb_tag_t chosen_script[2]; + bool found_script[2]; + unsigned int script_index[2], language_index[2]; + + private: + unsigned int current_stage[2]; /* GSUB/GPOS */ hb_prealloced_array_t<feature_info_t,16> feature_infos; hb_prealloced_array_t<pause_info_t, 1> pauses[2]; /* GSUB/GPOS */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-map.cc b/third_party/harfbuzz-ng/src/hb-ot-map.cc index f290c98..62f7904 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-map.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-map.cc @@ -41,11 +41,11 @@ hb_ot_map_t::add_lookups (hb_face_t *face, offset = 0; do { len = ARRAY_LENGTH (lookup_indices); - hb_ot_layout_feature_get_lookup_indexes (face, - table_tags[table_index], - feature_index, - offset, &len, - lookup_indices); + hb_ot_layout_feature_get_lookups (face, + table_tags[table_index], + feature_index, + offset, &len, + lookup_indices); for (unsigned int i = 0; i < len; i++) { hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push (); @@ -59,6 +59,30 @@ hb_ot_map_t::add_lookups (hb_face_t *face, } while (len == ARRAY_LENGTH (lookup_indices)); } +hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_, + const hb_segment_properties_t *props_) +{ + memset (this, 0, sizeof (*this)); + + face = face_; + props = *props_; + + + /* Fetch script/language indices for GSUB/GPOS. We need these later to skip + * features not available in either table and not waste precious bits for them. */ + + hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE}; + hb_tag_t language_tag; + + hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]); + language_tag = hb_ot_tag_from_language (props.language); + + for (unsigned int table_index = 0; table_index < 2; table_index++) { + hb_tag_t table_tag = table_tags[table_index]; + found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]); + hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]); + } +} void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value, bool global, bool has_fallback) { @@ -114,11 +138,10 @@ void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_ hb_ot_layout_position_lookup (font, buffer, lookups[table_index][i].index, lookups[table_index][i].mask); } -void hb_ot_map_t::substitute_closure (const hb_ot_shape_plan_t *plan, hb_face_t *face, hb_set_t *glyphs) const +void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const { - unsigned int table_index = 0; for (unsigned int i = 0; i < lookups[table_index].len; i++) - hb_ot_layout_substitute_closure_lookup (face, lookups[table_index][i].index, glyphs); + hb_set_add (lookups_out, 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) @@ -133,32 +156,17 @@ void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::paus } void -hb_ot_map_builder_t::compile (hb_face_t *face, - const hb_segment_properties_t *props, - hb_ot_map_t &m) +hb_ot_map_builder_t::compile (hb_ot_map_t &m) { - m.global_mask = 1; + m.global_mask = 1; - if (!feature_infos.len) - return; - - - /* Fetch script/language indices for GSUB/GPOS. We need these later to skip - * features not available in either table and not waste precious bits for them. */ - - hb_tag_t script_tags[3] = {HB_TAG_NONE}; - hb_tag_t language_tag; - - hb_ot_tags_from_script (props->script, &script_tags[0], &script_tags[1]); - language_tag = hb_ot_tag_from_language (props->language); - - unsigned int script_index[2], language_index[2]; for (unsigned int table_index = 0; table_index < 2; table_index++) { - hb_tag_t table_tag = table_tags[table_index]; - hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &m.chosen_script[table_index]); - hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]); + m.chosen_script[table_index] = chosen_script[table_index]; + m.found_script[table_index] = found_script[table_index]; } + if (!feature_infos.len) + return; /* Sort features and merge duplicates */ { 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 9e113c7..0ce3ebc 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh @@ -48,7 +48,7 @@ struct maxp } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000))); } @@ -63,7 +63,7 @@ struct maxp }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_MAXP_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-name-table.hh b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh index 6cc7a5ea..75a1b94 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-name-table.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh @@ -57,7 +57,7 @@ struct NameRecord } inline bool sanitize (hb_sanitize_context_t *c, void *base) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); /* We can check from base all the way up to the end of string... */ return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset)); } @@ -99,7 +99,7 @@ struct name } inline bool sanitize_records (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); char *string_pool = (char *) this + stringOffset; unsigned int _count = count; for (unsigned int i = 0; i < _count; i++) @@ -108,7 +108,7 @@ struct name } inline bool sanitize (hb_sanitize_context_t *c) { - TRACE_SANITIZE (); + TRACE_SANITIZE (this); return TRACE_RETURN (c->check_struct (this) && likely (format == 0 || format == 1) && c->check_array (nameRecord, nameRecord[0].static_size, count) && @@ -126,7 +126,7 @@ struct name }; -} // namespace OT +} /* namespace OT */ #endif /* HB_OT_NAME_TABLE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh index bf68561..4fcd0a2 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-fallback.hh @@ -53,7 +53,7 @@ enum { }; static OT::SubstLookup * -arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan, +arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font, unsigned int feature_index) { @@ -103,7 +103,7 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan, } static OT::SubstLookup * -arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan, +arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font) { OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)]; 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 5e29167..730a275 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 @@ -6,8 +6,8 @@ * * on files with these headers: * - * # ArabicShaping-6.1.0.txt - * # Date: 2011-04-15, 23:16:00 GMT [KW] + * # ArabicShaping-6.2.0.txt + * # Date: 2012-05-15, 21:05:00 GMT [KW] * UnicodeData.txt does not have a header. */ 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 8428534..35356fe 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 @@ -64,15 +64,31 @@ static unsigned int get_joining_type (hb_codepoint_t u, hb_unicode_general_categ return j_type; } - /* Mongolian joining data is not in ArabicJoining.txt yet */ + /* Mongolian joining data is not in ArabicJoining.txt yet. */ if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1800, 0x18AF))) { + if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x1880, 0x1886))) + return JOINING_TYPE_U; + /* All letters, SIBE SYLLABLE BOUNDARY MARKER, and NIRUGU are D */ - if (gen_cat == HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER || u == 0x1807 || u == 0x180A) + if ((FLAG(gen_cat) & (FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) | + FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER))) + || u == 0x1807 || u == 0x180A) + return JOINING_TYPE_D; + } + + /* 'Phags-pa joining data is not in ArabicJoining.txt yet. */ + if (unlikely (hb_in_range<hb_codepoint_t> (u, 0xA840, 0xA872))) + { + if (unlikely (u == 0xA872)) + /* XXX Looks like this should be TYPE_L, but we don't support that yet! */ + return JOINING_TYPE_R; + return JOINING_TYPE_D; } - if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) { + if (unlikely (hb_in_range<hb_codepoint_t> (u, 0x200C, 0x200D))) + { return u == 0x200C ? JOINING_TYPE_U : JOINING_TYPE_C; } @@ -235,17 +251,18 @@ arabic_joining (hb_buffer_t *buffer) HB_BUFFER_ALLOCATE_VAR (buffer, arabic_shaping_action); /* Check pre-context */ - for (unsigned int i = 0; i < buffer->context_len[0]; i++) - { - unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i])); + if (!(buffer->flags & HB_BUFFER_FLAG_BOT)) + for (unsigned int i = 0; i < buffer->context_len[0]; i++) + { + unsigned int this_type = get_joining_type (buffer->context[0][i], buffer->unicode->general_category (buffer->context[0][i])); - if (unlikely (this_type == JOINING_TYPE_T)) - continue; + if (unlikely (this_type == JOINING_TYPE_T)) + continue; - const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; - state = entry->next_state; - break; - } + const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; + state = entry->next_state; + break; + } for (unsigned int i = 0; i < count; i++) { @@ -267,18 +284,19 @@ arabic_joining (hb_buffer_t *buffer) state = entry->next_state; } - for (unsigned int i = 0; i < buffer->context_len[1]; i++) - { - unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[0][i])); + if (!(buffer->flags & HB_BUFFER_FLAG_EOT)) + for (unsigned int i = 0; i < buffer->context_len[1]; i++) + { + unsigned int this_type = get_joining_type (buffer->context[1][i], buffer->unicode->general_category (buffer->context[1][i])); - if (unlikely (this_type == JOINING_TYPE_T)) - continue; + if (unlikely (this_type == JOINING_TYPE_T)) + continue; - const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; - if (entry->prev_action != NONE && prev != (unsigned int) -1) - buffer->info[prev].arabic_shaping_action() = entry->prev_action; - break; - } + const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; + if (entry->prev_action != NONE && prev != (unsigned int) -1) + buffer->info[prev].arabic_shaping_action() = entry->prev_action; + break; + } HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); @@ -287,7 +305,7 @@ arabic_joining (hb_buffer_t *buffer) static void setup_masks_arabic (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, - hb_font_t *font) + hb_font_t *font HB_UNUSED) { const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; @@ -333,6 +351,9 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = data_destroy_arabic, NULL, /* preprocess_text_arabic */ NULL, /* normalization_preference */ + NULL, /* decompose */ + NULL, /* compose */ setup_masks_arabic, true, /* zero_width_attached_marks */ + true, /* fallback_position */ }; diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-default.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-default.cc new file mode 100644 index 0000000..5340293 --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-default.cc @@ -0,0 +1,226 @@ +/* + * Copyright © 2010,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-private.hh" + + +/* TODO Add kana, and other small shapers here */ + + +/* The default shaper *only* adds additional per-script features.*/ + +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'), + HB_TAG_NONE +}; + +static const hb_tag_t tibetan_features[] = +{ + HB_TAG('a','b','v','s'), + HB_TAG('b','l','w','s'), + HB_TAG('a','b','v','m'), + HB_TAG('b','l','w','m'), + HB_TAG_NONE +}; + +static void +collect_features_default (hb_ot_shape_planner_t *plan) +{ + const hb_tag_t *script_features = NULL; + + switch ((hb_tag_t) plan->props.script) + { + /* Unicode-1.1 additions */ + case HB_SCRIPT_HANGUL: + script_features = hangul_features; + break; + + /* Unicode-2.0 additions */ + case HB_SCRIPT_TIBETAN: + script_features = tibetan_features; + break; + } + + for (; script_features && *script_features; script_features++) + plan->map.add_bool_feature (*script_features); +} + +static hb_ot_shape_normalization_mode_t +normalization_preference_default (const hb_segment_properties_t *props) +{ + switch ((hb_tag_t) props->script) + { + /* Unicode-1.1 additions */ + case HB_SCRIPT_HANGUL: + return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL; + } + return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; +} + +static bool +compose_default (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab) +{ + /* Hebrew presentation-form shaping. + * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 + * Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA; + * Note that some letters do not have a dagesh presForm encoded. + */ + static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = { + 0xFB30, /* ALEF */ + 0xFB31, /* BET */ + 0xFB32, /* GIMEL */ + 0xFB33, /* DALET */ + 0xFB34, /* HE */ + 0xFB35, /* VAV */ + 0xFB36, /* ZAYIN */ + 0x0000, /* HET */ + 0xFB38, /* TET */ + 0xFB39, /* YOD */ + 0xFB3A, /* FINAL KAF */ + 0xFB3B, /* KAF */ + 0xFB3C, /* LAMED */ + 0x0000, /* FINAL MEM */ + 0xFB3E, /* MEM */ + 0x0000, /* FINAL NUN */ + 0xFB40, /* NUN */ + 0xFB41, /* SAMEKH */ + 0x0000, /* AYIN */ + 0xFB43, /* FINAL PE */ + 0xFB44, /* PE */ + 0x0000, /* FINAL TSADI */ + 0xFB46, /* TSADI */ + 0xFB47, /* QOF */ + 0xFB48, /* RESH */ + 0xFB49, /* SHIN */ + 0xFB4A /* TAV */ + }; + + bool found = c->unicode->compose (a, b, ab); + + if (!found && (b & ~0x7F) == 0x0580) { + /* Special-case Hebrew presentation forms that are excluded from + * standard normalization, but wanted for old fonts. */ + switch (b) { + case 0x05B4: /* HIRIQ */ + if (a == 0x05D9) { /* YOD */ + *ab = 0xFB1D; + found = true; + } + break; + case 0x05B7: /* patah */ + if (a == 0x05F2) { /* YIDDISH YOD YOD */ + *ab = 0xFB1F; + found = true; + } else if (a == 0x05D0) { /* ALEF */ + *ab = 0xFB2E; + found = true; + } + break; + case 0x05B8: /* QAMATS */ + if (a == 0x05D0) { /* ALEF */ + *ab = 0xFB2F; + found = true; + } + break; + case 0x05B9: /* HOLAM */ + if (a == 0x05D5) { /* VAV */ + *ab = 0xFB4B; + found = true; + } + break; + case 0x05BC: /* DAGESH */ + if (a >= 0x05D0 && a <= 0x05EA) { + *ab = sDageshForms[a - 0x05D0]; + found = (*ab != 0); + } else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */ + *ab = 0xFB2C; + found = true; + } else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */ + *ab = 0xFB2D; + found = true; + } + break; + case 0x05BF: /* RAFE */ + switch (a) { + case 0x05D1: /* BET */ + *ab = 0xFB4C; + found = true; + break; + case 0x05DB: /* KAF */ + *ab = 0xFB4D; + found = true; + break; + case 0x05E4: /* PE */ + *ab = 0xFB4E; + found = true; + break; + } + break; + case 0x05C1: /* SHIN DOT */ + if (a == 0x05E9) { /* SHIN */ + *ab = 0xFB2A; + found = true; + } else if (a == 0xFB49) { /* SHIN WITH DAGESH */ + *ab = 0xFB2C; + found = true; + } + break; + case 0x05C2: /* SIN DOT */ + if (a == 0x05E9) { /* SHIN */ + *ab = 0xFB2B; + found = true; + } else if (a == 0xFB49) { /* SHIN WITH DAGESH */ + *ab = 0xFB2D; + found = true; + } + break; + } + } + + return found; +} + +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = +{ + "default", + collect_features_default, + NULL, /* override_features */ + NULL, /* data_create */ + NULL, /* data_destroy */ + NULL, /* preprocess_text */ + normalization_preference_default, + NULL, /* decompose */ + compose_default, + NULL, /* setup_masks */ + true, /* zero_width_attached_marks */ + true, /* fallback_position */ +}; 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 53f22e3..ed40b96 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 @@ -51,45 +51,52 @@ static const unsigned char _indic_syllable_machine_trans_keys[] = { 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 4u, 4u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 14u, 4u, 14u, 4u, 14u, - 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 1u, 16u, - 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, - 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, - 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, - 3u, 13u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, - 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, - 4u, 14u, 6u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 14u, 3u, 14u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, - 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, - 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, - 5u, 9u, 9u, 9u, 9u, 9u, 3u, 13u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, + 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, 4u, 14u, + 4u, 14u, 5u, 7u, 5u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 5u, 7u, 5u, 7u, + 7u, 7u, 5u, 7u, 5u, 7u, 7u, 7u, 1u, 16u, 13u, 13u, 4u, 4u, 6u, 6u, + 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, 6u, 6u, 16u, 16u, 4u, 7u, + 6u, 6u, 16u, 16u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, + 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, + 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, + 5u, 9u, 9u, 9u, 9u, 9u, 3u, 17u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, - 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 3u, 14u, 1u, 16u, 3u, 14u, - 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, - 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, - 1u, 16u, 1u, 16u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, - 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, - 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, - 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 13u, 3u, 9u, 8u, 9u, 3u, 9u, - 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, - 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 3u, 14u, 1u, 16u, + 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, - 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, 3u, 14u, 4u, 14u, 3u, 14u, - 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, - 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 14u, - 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 13u, + 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 3u, 14u, 3u, 14u, + 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, + 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, + 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 17u, 3u, 9u, + 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, + 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, + 3u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, + 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, + 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, + 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, 1u, 16u, 3u, 14u, + 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, + 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, + 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 17u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 3u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, - 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, - 1u, 16u, 3u, 14u, 1u, 16u, 0 + 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 14u, + 3u, 14u, 4u, 14u, 3u, 14u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, + 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, + 4u, 14u, 1u, 16u, 3u, 17u, 3u, 14u, 4u, 14u, 5u, 14u, 8u, 14u, 5u, 9u, + 9u, 9u, 9u, 9u, 3u, 17u, 3u, 9u, 8u, 9u, 3u, 9u, 3u, 13u, 3u, 14u, + 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, + 5u, 14u, 3u, 14u, 4u, 14u, 6u, 14u, 3u, 14u, 1u, 16u, 3u, 14u, 3u, 14u, + 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, + 1u, 16u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, + 1u, 16u, 1u, 16u, 1u, 16u, 3u, 14u, 3u, 14u, 1u, 16u, 1u, 16u, 1u, 16u, + 1u, 16u, 1u, 16u, 3u, 14u, 1u, 16u, 3u, 17u, 1u, 16u, 4u, 14u, 1u, 16u, + 3u, 17u, 3u, 14u, 4u, 14u, 5u, 9u, 9u, 9u, 9u, 9u, 3u, 14u, 3u, 14u, + 1u, 16u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 5u, 14u, 3u, 14u, + 4u, 14u, 5u, 14u, 3u, 14u, 4u, 14u, 8u, 14u, 3u, 17u, 3u, 9u, 8u, 9u, + 3u, 9u, 3u, 13u, 1u, 16u, 0 }; static const char _indic_syllable_machine_key_spans[] = { @@ -110,45 +117,52 @@ static const char _indic_syllable_machine_key_spans[] = { 3, 3, 1, 3, 3, 1, 3, 3, 1, 1, 1, 1, 4, 1, 1, 4, 1, 1, 4, 1, 1, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 16, - 12, 12, 11, 16, 12, 12, 11, 16, - 12, 12, 11, 16, 12, 12, 11, 16, - 12, 12, 11, 10, 7, 5, 1, 1, - 11, 7, 2, 7, 11, 12, 12, 11, - 10, 12, 11, 10, 12, 11, 10, 12, - 11, 9, 12, 11, 16, 12, 12, 16, - 16, 16, 16, 16, 12, 12, 16, 16, - 16, 16, 16, 12, 12, 16, 16, 16, - 16, 16, 12, 12, 16, 16, 16, 16, - 16, 12, 12, 12, 12, 11, 16, 12, - 12, 11, 16, 12, 12, 11, 16, 12, - 12, 11, 16, 12, 12, 11, 10, 7, - 5, 1, 1, 11, 7, 2, 7, 11, + 11, 11, 11, 11, 11, 11, 11, 11, + 11, 3, 3, 3, 3, 1, 3, 3, + 1, 3, 3, 1, 16, 1, 1, 1, + 1, 4, 1, 1, 4, 1, 1, 4, + 1, 1, 16, 15, 12, 11, 16, 15, + 12, 11, 16, 15, 12, 11, 16, 15, + 12, 11, 16, 15, 12, 11, 10, 7, + 5, 1, 1, 15, 7, 2, 7, 11, 12, 12, 11, 10, 12, 11, 10, 12, - 11, 10, 12, 11, 9, 12, 16, 12, - 12, 16, 16, 16, 16, 16, 12, 12, - 16, 16, 16, 16, 16, 12, 12, 16, - 16, 16, 16, 16, 12, 12, 16, 16, - 16, 16, 11, 16, 12, 12, 11, 16, - 12, 12, 11, 16, 12, 12, 11, 16, - 12, 12, 11, 16, 12, 12, 11, 10, - 7, 5, 1, 1, 11, 7, 2, 7, - 11, 12, 12, 11, 10, 12, 11, 10, - 12, 11, 10, 12, 11, 9, 12, 16, + 11, 10, 12, 11, 9, 12, 11, 16, 12, 12, 16, 16, 16, 16, 16, 12, 12, 16, 16, 16, 16, 16, 12, 12, 16, 16, 16, 16, 16, 12, 12, 16, - 16, 16, 16, 16, 11, 12, 11, 12, - 12, 11, 16, 12, 12, 11, 16, 12, - 12, 11, 16, 12, 12, 11, 16, 12, - 12, 11, 10, 7, 5, 1, 1, 11, + 16, 16, 16, 16, 12, 12, 12, 12, + 11, 16, 15, 12, 11, 16, 15, 12, + 11, 16, 15, 12, 11, 16, 15, 12, + 11, 10, 7, 5, 1, 1, 15, 7, + 2, 7, 11, 12, 12, 11, 10, 12, + 11, 10, 12, 11, 10, 12, 11, 9, + 12, 16, 12, 12, 16, 16, 16, 16, + 16, 12, 12, 16, 16, 16, 16, 16, + 12, 12, 16, 16, 16, 16, 16, 12, + 12, 16, 16, 16, 16, 11, 16, 12, + 12, 11, 16, 15, 12, 11, 16, 15, + 12, 11, 16, 15, 12, 11, 16, 15, + 12, 11, 10, 7, 5, 1, 1, 15, 7, 2, 7, 11, 12, 12, 11, 10, 12, 11, 10, 12, 11, 10, 12, 11, 9, 12, 16, 12, 12, 16, 16, 16, 16, 16, 12, 12, 16, 16, 16, 16, 16, 12, 12, 16, 16, 16, 16, 16, - 12, 12, 16, 16, 16, 16, 16, 12, - 16, 12, 16 + 12, 12, 16, 16, 16, 16, 16, 11, + 12, 11, 12, 12, 11, 16, 15, 12, + 11, 16, 15, 12, 11, 16, 15, 12, + 11, 16, 15, 12, 11, 10, 7, 5, + 1, 1, 15, 7, 2, 7, 11, 12, + 12, 11, 10, 12, 11, 10, 12, 11, + 10, 12, 11, 9, 12, 16, 12, 12, + 16, 16, 16, 16, 16, 12, 12, 16, + 16, 16, 16, 16, 12, 12, 16, 16, + 16, 16, 16, 12, 12, 16, 16, 16, + 16, 16, 12, 16, 15, 16, 11, 16, + 15, 12, 11, 5, 1, 1, 12, 12, + 16, 12, 11, 10, 12, 11, 10, 12, + 11, 10, 12, 11, 7, 15, 7, 2, + 7, 11, 16 }; static const short _indic_syllable_machine_index_offsets[] = { @@ -170,44 +184,51 @@ static const short _indic_syllable_machine_index_offsets[] = { 681, 683, 685, 687, 689, 694, 696, 698, 703, 705, 707, 712, 714, 716, 728, 740, 752, 764, 776, 788, 800, 812, 824, 836, - 853, 866, 879, 891, 908, 921, 934, 946, - 963, 976, 989, 1001, 1018, 1031, 1044, 1056, - 1073, 1086, 1099, 1111, 1122, 1130, 1136, 1138, - 1140, 1152, 1160, 1163, 1171, 1183, 1196, 1209, - 1221, 1232, 1245, 1257, 1268, 1281, 1293, 1304, - 1317, 1329, 1339, 1352, 1364, 1381, 1394, 1407, - 1424, 1441, 1458, 1475, 1492, 1505, 1518, 1535, - 1552, 1569, 1586, 1603, 1616, 1629, 1646, 1663, - 1680, 1697, 1714, 1727, 1740, 1757, 1774, 1791, - 1808, 1825, 1838, 1851, 1864, 1877, 1889, 1906, - 1919, 1932, 1944, 1961, 1974, 1987, 1999, 2016, - 2029, 2042, 2054, 2071, 2084, 2097, 2109, 2120, - 2128, 2134, 2136, 2138, 2150, 2158, 2161, 2169, - 2181, 2194, 2207, 2219, 2230, 2243, 2255, 2266, - 2279, 2291, 2302, 2315, 2327, 2337, 2350, 2367, - 2380, 2393, 2410, 2427, 2444, 2461, 2478, 2491, - 2504, 2521, 2538, 2555, 2572, 2589, 2602, 2615, - 2632, 2649, 2666, 2683, 2700, 2713, 2726, 2743, - 2760, 2777, 2794, 2806, 2823, 2836, 2849, 2861, - 2878, 2891, 2904, 2916, 2933, 2946, 2959, 2971, - 2988, 3001, 3014, 3026, 3043, 3056, 3069, 3081, - 3092, 3100, 3106, 3108, 3110, 3122, 3130, 3133, - 3141, 3153, 3166, 3179, 3191, 3202, 3215, 3227, - 3238, 3251, 3263, 3274, 3287, 3299, 3309, 3322, - 3339, 3352, 3365, 3382, 3399, 3416, 3433, 3450, - 3463, 3476, 3493, 3510, 3527, 3544, 3561, 3574, - 3587, 3604, 3621, 3638, 3655, 3672, 3685, 3698, - 3715, 3732, 3749, 3766, 3783, 3795, 3808, 3820, - 3833, 3846, 3858, 3875, 3888, 3901, 3913, 3930, - 3943, 3956, 3968, 3985, 3998, 4011, 4023, 4040, - 4053, 4066, 4078, 4089, 4097, 4103, 4105, 4107, - 4119, 4127, 4130, 4138, 4150, 4163, 4176, 4188, - 4199, 4212, 4224, 4235, 4248, 4260, 4271, 4284, - 4296, 4306, 4319, 4336, 4349, 4362, 4379, 4396, - 4413, 4430, 4447, 4460, 4473, 4490, 4507, 4524, - 4541, 4558, 4571, 4584, 4601, 4618, 4635, 4652, - 4669, 4682, 4695, 4712, 4729, 4746, 4763, 4780, - 4793, 4810, 4823 + 848, 860, 864, 868, 872, 876, 878, 882, + 886, 888, 892, 896, 898, 915, 917, 919, + 921, 923, 928, 930, 932, 937, 939, 941, + 946, 948, 950, 967, 983, 996, 1008, 1025, + 1041, 1054, 1066, 1083, 1099, 1112, 1124, 1141, + 1157, 1170, 1182, 1199, 1215, 1228, 1240, 1251, + 1259, 1265, 1267, 1269, 1285, 1293, 1296, 1304, + 1316, 1329, 1342, 1354, 1365, 1378, 1390, 1401, + 1414, 1426, 1437, 1450, 1462, 1472, 1485, 1497, + 1514, 1527, 1540, 1557, 1574, 1591, 1608, 1625, + 1638, 1651, 1668, 1685, 1702, 1719, 1736, 1749, + 1762, 1779, 1796, 1813, 1830, 1847, 1860, 1873, + 1890, 1907, 1924, 1941, 1958, 1971, 1984, 1997, + 2010, 2022, 2039, 2055, 2068, 2080, 2097, 2113, + 2126, 2138, 2155, 2171, 2184, 2196, 2213, 2229, + 2242, 2254, 2265, 2273, 2279, 2281, 2283, 2299, + 2307, 2310, 2318, 2330, 2343, 2356, 2368, 2379, + 2392, 2404, 2415, 2428, 2440, 2451, 2464, 2476, + 2486, 2499, 2516, 2529, 2542, 2559, 2576, 2593, + 2610, 2627, 2640, 2653, 2670, 2687, 2704, 2721, + 2738, 2751, 2764, 2781, 2798, 2815, 2832, 2849, + 2862, 2875, 2892, 2909, 2926, 2943, 2955, 2972, + 2985, 2998, 3010, 3027, 3043, 3056, 3068, 3085, + 3101, 3114, 3126, 3143, 3159, 3172, 3184, 3201, + 3217, 3230, 3242, 3253, 3261, 3267, 3269, 3271, + 3287, 3295, 3298, 3306, 3318, 3331, 3344, 3356, + 3367, 3380, 3392, 3403, 3416, 3428, 3439, 3452, + 3464, 3474, 3487, 3504, 3517, 3530, 3547, 3564, + 3581, 3598, 3615, 3628, 3641, 3658, 3675, 3692, + 3709, 3726, 3739, 3752, 3769, 3786, 3803, 3820, + 3837, 3850, 3863, 3880, 3897, 3914, 3931, 3948, + 3960, 3973, 3985, 3998, 4011, 4023, 4040, 4056, + 4069, 4081, 4098, 4114, 4127, 4139, 4156, 4172, + 4185, 4197, 4214, 4230, 4243, 4255, 4266, 4274, + 4280, 4282, 4284, 4300, 4308, 4311, 4319, 4331, + 4344, 4357, 4369, 4380, 4393, 4405, 4416, 4429, + 4441, 4452, 4465, 4477, 4487, 4500, 4517, 4530, + 4543, 4560, 4577, 4594, 4611, 4628, 4641, 4654, + 4671, 4688, 4705, 4722, 4739, 4752, 4765, 4782, + 4799, 4816, 4833, 4850, 4863, 4876, 4893, 4910, + 4927, 4944, 4961, 4974, 4991, 5007, 5024, 5036, + 5053, 5069, 5082, 5094, 5100, 5102, 5104, 5117, + 5130, 5147, 5160, 5172, 5183, 5196, 5208, 5219, + 5232, 5244, 5255, 5268, 5280, 5288, 5304, 5312, + 5315, 5323, 5335 }; static const short _indic_syllable_machine_indicies[] = { @@ -285,7 +306,7 @@ static const short _indic_syllable_machine_indicies[] = { 76, 76, 76, 76, 76, 76, 109, 76, 109, 80, 80, 81, 76, 76, 76, 76, 76, 110, 109, 76, 111, 80, 80, 81, - 76, 76, 76, 76, 76, 76, 111, 76, + 82, 82, 82, 82, 82, 82, 111, 82, 111, 80, 80, 81, 76, 76, 76, 76, 76, 112, 111, 76, 113, 80, 80, 81, 76, 76, 76, 76, 76, 76, 113, 76, @@ -315,569 +336,640 @@ static const short _indic_syllable_machine_indicies[] = { 114, 149, 148, 114, 150, 118, 118, 119, 114, 114, 114, 114, 114, 114, 150, 114, 150, 118, 118, 119, 114, 114, 114, 114, - 114, 151, 150, 114, 153, 154, 155, 156, - 157, 158, 81, 159, 160, 152, 161, 161, - 162, 163, 164, 165, 152, 167, 168, 169, - 170, 5, 171, 172, 173, 166, 166, 37, - 174, 166, 175, 168, 176, 176, 5, 171, - 172, 173, 166, 166, 166, 174, 166, 168, - 176, 176, 5, 171, 172, 173, 166, 166, - 166, 174, 166, 177, 166, 166, 166, 18, - 178, 166, 171, 172, 166, 166, 166, 166, - 179, 166, 177, 166, 180, 181, 182, 183, - 5, 171, 172, 173, 166, 166, 35, 184, - 166, 185, 181, 186, 186, 5, 171, 172, - 173, 166, 166, 166, 184, 166, 181, 186, - 186, 5, 171, 172, 173, 166, 166, 166, - 184, 166, 187, 166, 166, 166, 18, 188, - 166, 171, 172, 166, 166, 166, 166, 179, - 166, 187, 166, 189, 190, 191, 192, 5, - 171, 172, 173, 166, 166, 33, 193, 166, - 194, 190, 195, 195, 5, 171, 172, 173, - 166, 166, 166, 193, 166, 190, 195, 195, - 5, 171, 172, 173, 166, 166, 166, 193, - 166, 196, 166, 166, 166, 18, 197, 166, - 171, 172, 166, 166, 166, 166, 179, 166, - 196, 166, 198, 199, 200, 201, 5, 171, - 172, 173, 166, 166, 31, 202, 166, 203, - 199, 204, 204, 5, 171, 172, 173, 166, - 166, 166, 202, 166, 199, 204, 204, 5, - 171, 172, 173, 166, 166, 166, 202, 166, - 205, 166, 166, 166, 18, 206, 166, 171, - 172, 166, 166, 166, 166, 179, 166, 205, - 166, 207, 208, 209, 210, 5, 171, 172, - 173, 166, 166, 29, 211, 166, 212, 208, - 213, 213, 5, 171, 172, 173, 166, 166, - 166, 211, 166, 208, 213, 213, 5, 171, - 172, 173, 166, 166, 166, 211, 166, 18, - 214, 166, 171, 172, 166, 166, 166, 166, - 179, 166, 171, 172, 166, 166, 166, 166, - 179, 166, 215, 166, 166, 166, 172, 166, - 172, 166, 216, 166, 217, 166, 218, 219, - 166, 171, 172, 166, 166, 166, 3, 166, - 2, 166, 166, 166, 166, 171, 172, 166, - 171, 172, 166, 217, 166, 166, 166, 166, - 171, 172, 166, 217, 166, 218, 166, 166, - 171, 172, 166, 166, 166, 3, 166, 18, - 166, 220, 220, 5, 171, 172, 166, 166, - 166, 166, 179, 166, 221, 27, 222, 223, - 8, 171, 172, 166, 166, 166, 166, 179, - 166, 27, 222, 223, 8, 171, 172, 166, - 166, 166, 166, 179, 166, 222, 222, 8, - 171, 172, 166, 166, 166, 166, 179, 166, - 224, 24, 225, 226, 11, 171, 172, 166, - 166, 166, 166, 179, 166, 24, 225, 226, - 11, 171, 172, 166, 166, 166, 166, 179, - 166, 225, 225, 11, 171, 172, 166, 166, - 166, 166, 179, 166, 227, 21, 228, 229, - 14, 171, 172, 166, 166, 166, 166, 179, - 166, 21, 228, 229, 14, 171, 172, 166, - 166, 166, 166, 179, 166, 228, 228, 14, - 171, 172, 166, 166, 166, 166, 179, 166, - 230, 18, 166, 231, 166, 171, 172, 166, - 166, 166, 166, 179, 166, 18, 166, 231, - 166, 171, 172, 166, 166, 166, 166, 179, - 166, 232, 166, 171, 172, 166, 166, 166, - 166, 179, 166, 18, 166, 166, 166, 166, - 171, 172, 166, 166, 166, 166, 179, 166, - 208, 213, 213, 5, 171, 172, 166, 166, - 166, 166, 211, 166, 1, 2, 166, 166, - 18, 214, 166, 171, 172, 166, 166, 166, - 166, 179, 166, 1, 166, 207, 208, 213, - 213, 5, 171, 172, 173, 166, 166, 166, - 211, 166, 207, 208, 209, 213, 5, 171, - 172, 173, 166, 166, 29, 211, 166, 205, - 166, 233, 166, 220, 220, 5, 171, 172, - 166, 166, 166, 166, 179, 166, 205, 166, - 205, 166, 166, 166, 166, 166, 166, 171, - 172, 166, 166, 166, 166, 179, 166, 205, - 166, 205, 166, 166, 166, 166, 234, 166, - 171, 172, 166, 166, 166, 166, 179, 166, - 205, 166, 205, 166, 233, 166, 166, 166, - 166, 171, 172, 166, 166, 166, 166, 179, - 166, 205, 166, 205, 2, 166, 166, 18, - 206, 166, 171, 172, 166, 166, 166, 166, - 179, 166, 205, 166, 198, 199, 204, 204, - 5, 171, 172, 173, 166, 166, 166, 202, - 166, 198, 199, 200, 204, 5, 171, 172, - 173, 166, 166, 31, 202, 166, 196, 166, - 235, 166, 220, 220, 5, 171, 172, 166, - 166, 166, 166, 179, 166, 196, 166, 196, - 166, 166, 166, 166, 166, 166, 171, 172, - 166, 166, 166, 166, 179, 166, 196, 166, - 196, 166, 166, 166, 166, 236, 166, 171, - 172, 166, 166, 166, 166, 179, 166, 196, - 166, 196, 166, 235, 166, 166, 166, 166, - 171, 172, 166, 166, 166, 166, 179, 166, - 196, 166, 196, 2, 166, 166, 18, 197, - 166, 171, 172, 166, 166, 166, 166, 179, - 166, 196, 166, 189, 190, 195, 195, 5, - 171, 172, 173, 166, 166, 166, 193, 166, - 189, 190, 191, 195, 5, 171, 172, 173, - 166, 166, 33, 193, 166, 187, 166, 237, - 166, 220, 220, 5, 171, 172, 166, 166, - 166, 166, 179, 166, 187, 166, 187, 166, - 166, 166, 166, 166, 166, 171, 172, 166, - 166, 166, 166, 179, 166, 187, 166, 187, - 166, 166, 166, 166, 238, 166, 171, 172, - 166, 166, 166, 166, 179, 166, 187, 166, - 187, 166, 237, 166, 166, 166, 166, 171, - 172, 166, 166, 166, 166, 179, 166, 187, - 166, 187, 2, 166, 166, 18, 188, 166, - 171, 172, 166, 166, 166, 166, 179, 166, - 187, 166, 180, 181, 186, 186, 5, 171, - 172, 173, 166, 166, 166, 184, 166, 180, - 181, 182, 186, 5, 171, 172, 173, 166, - 166, 35, 184, 166, 177, 166, 239, 166, - 220, 220, 5, 171, 172, 166, 166, 166, - 166, 179, 166, 177, 166, 177, 166, 166, - 166, 166, 166, 166, 171, 172, 166, 166, - 166, 166, 179, 166, 177, 166, 177, 166, - 166, 166, 166, 240, 166, 171, 172, 166, - 166, 166, 166, 179, 166, 177, 166, 177, - 166, 239, 166, 166, 166, 166, 171, 172, - 166, 166, 166, 166, 179, 166, 177, 166, - 177, 2, 166, 166, 18, 178, 166, 171, - 172, 166, 166, 166, 166, 179, 166, 177, - 166, 167, 168, 176, 176, 5, 171, 172, - 173, 166, 166, 166, 174, 166, 167, 168, - 169, 176, 5, 171, 172, 173, 166, 166, - 37, 174, 166, 242, 243, 244, 245, 43, - 246, 247, 241, 241, 241, 75, 248, 241, - 249, 243, 250, 245, 43, 246, 247, 241, - 241, 241, 241, 248, 241, 243, 250, 245, - 43, 246, 247, 241, 241, 241, 241, 248, - 241, 251, 241, 241, 241, 56, 252, 241, - 246, 247, 241, 241, 241, 241, 253, 241, - 251, 241, 254, 255, 256, 257, 43, 246, - 247, 241, 241, 241, 73, 258, 241, 259, - 255, 260, 260, 43, 246, 247, 241, 241, - 241, 241, 258, 241, 255, 260, 260, 43, - 246, 247, 241, 241, 241, 241, 258, 241, - 261, 241, 241, 241, 56, 262, 241, 246, - 247, 241, 241, 241, 241, 253, 241, 261, - 241, 263, 264, 265, 266, 43, 246, 247, - 241, 241, 241, 71, 267, 241, 268, 264, - 269, 269, 43, 246, 247, 241, 241, 241, - 241, 267, 241, 264, 269, 269, 43, 246, - 247, 241, 241, 241, 241, 267, 241, 270, - 241, 241, 241, 56, 271, 241, 246, 247, - 241, 241, 241, 241, 253, 241, 270, 241, - 272, 273, 274, 275, 43, 246, 247, 241, - 241, 241, 69, 276, 241, 277, 273, 278, - 278, 43, 246, 247, 241, 241, 241, 241, - 276, 241, 273, 278, 278, 43, 246, 247, - 241, 241, 241, 241, 276, 241, 279, 241, - 241, 241, 56, 280, 241, 246, 247, 241, - 241, 241, 241, 253, 241, 279, 241, 281, - 282, 283, 284, 43, 246, 247, 241, 241, - 241, 67, 285, 241, 286, 282, 287, 287, - 43, 246, 247, 241, 241, 241, 241, 285, - 241, 282, 287, 287, 43, 246, 247, 241, - 241, 241, 241, 285, 241, 56, 288, 241, - 246, 247, 241, 241, 241, 241, 253, 241, - 246, 247, 241, 241, 241, 241, 253, 241, - 289, 241, 241, 241, 247, 241, 247, 241, - 290, 241, 291, 241, 292, 293, 241, 246, - 247, 241, 241, 241, 41, 241, 40, 241, - 241, 241, 241, 246, 247, 241, 246, 247, - 241, 291, 241, 241, 241, 241, 246, 247, - 241, 291, 241, 292, 241, 241, 246, 247, - 241, 241, 241, 41, 241, 56, 241, 294, - 294, 43, 246, 247, 241, 241, 241, 241, - 253, 241, 295, 65, 296, 297, 46, 246, - 247, 241, 241, 241, 241, 253, 241, 65, - 296, 297, 46, 246, 247, 241, 241, 241, - 241, 253, 241, 296, 296, 46, 246, 247, - 241, 241, 241, 241, 253, 241, 298, 62, - 299, 300, 49, 246, 247, 241, 241, 241, - 241, 253, 241, 62, 299, 300, 49, 246, - 247, 241, 241, 241, 241, 253, 241, 299, - 299, 49, 246, 247, 241, 241, 241, 241, - 253, 241, 301, 59, 302, 303, 52, 246, - 247, 241, 241, 241, 241, 253, 241, 59, - 302, 303, 52, 246, 247, 241, 241, 241, - 241, 253, 241, 302, 302, 52, 246, 247, - 241, 241, 241, 241, 253, 241, 304, 56, - 241, 305, 241, 246, 247, 241, 241, 241, - 241, 253, 241, 56, 241, 305, 241, 246, - 247, 241, 241, 241, 241, 253, 241, 306, - 241, 246, 247, 241, 241, 241, 241, 253, - 241, 56, 241, 241, 241, 241, 246, 247, - 241, 241, 241, 241, 253, 241, 39, 40, - 241, 241, 56, 288, 241, 246, 247, 241, - 241, 241, 241, 253, 241, 39, 241, 281, - 282, 287, 287, 43, 246, 247, 241, 241, - 241, 241, 285, 241, 281, 282, 283, 287, - 43, 246, 247, 241, 241, 241, 67, 285, - 241, 279, 241, 307, 241, 294, 294, 43, - 246, 247, 241, 241, 241, 241, 253, 241, - 279, 241, 279, 241, 241, 241, 241, 241, - 241, 246, 247, 241, 241, 241, 241, 253, - 241, 279, 241, 279, 241, 241, 241, 241, - 308, 241, 246, 247, 241, 241, 241, 241, - 253, 241, 279, 241, 279, 241, 307, 241, - 241, 241, 241, 246, 247, 241, 241, 241, - 241, 253, 241, 279, 241, 279, 40, 241, - 241, 56, 280, 241, 246, 247, 241, 241, - 241, 241, 253, 241, 279, 241, 272, 273, - 278, 278, 43, 246, 247, 241, 241, 241, - 241, 276, 241, 272, 273, 274, 278, 43, - 246, 247, 241, 241, 241, 69, 276, 241, - 270, 241, 309, 241, 294, 294, 43, 246, - 247, 241, 241, 241, 241, 253, 241, 270, - 241, 270, 241, 241, 241, 241, 241, 241, - 246, 247, 241, 241, 241, 241, 253, 241, - 270, 241, 270, 241, 241, 241, 241, 310, - 241, 246, 247, 241, 241, 241, 241, 253, - 241, 270, 241, 270, 241, 309, 241, 241, - 241, 241, 246, 247, 241, 241, 241, 241, - 253, 241, 270, 241, 270, 40, 241, 241, - 56, 271, 241, 246, 247, 241, 241, 241, - 241, 253, 241, 270, 241, 263, 264, 269, - 269, 43, 246, 247, 241, 241, 241, 241, - 267, 241, 263, 264, 265, 269, 43, 246, - 247, 241, 241, 241, 71, 267, 241, 261, - 241, 311, 241, 294, 294, 43, 246, 247, - 241, 241, 241, 241, 253, 241, 261, 241, - 261, 241, 241, 241, 241, 241, 241, 246, - 247, 241, 241, 241, 241, 253, 241, 261, - 241, 261, 241, 241, 241, 241, 312, 241, - 246, 247, 241, 241, 241, 241, 253, 241, - 261, 241, 261, 241, 311, 241, 241, 241, - 241, 246, 247, 241, 241, 241, 241, 253, - 241, 261, 241, 261, 40, 241, 241, 56, - 262, 241, 246, 247, 241, 241, 241, 241, - 253, 241, 261, 241, 254, 255, 260, 260, - 43, 246, 247, 241, 241, 241, 241, 258, - 241, 254, 255, 256, 260, 43, 246, 247, - 241, 241, 241, 73, 258, 241, 251, 241, - 313, 241, 294, 294, 43, 246, 247, 241, - 241, 241, 241, 253, 241, 251, 241, 251, - 241, 241, 241, 241, 241, 241, 246, 247, - 241, 241, 241, 241, 253, 241, 251, 241, - 251, 241, 241, 241, 241, 314, 241, 246, - 247, 241, 241, 241, 241, 253, 241, 251, - 241, 251, 241, 313, 241, 241, 241, 241, - 246, 247, 241, 241, 241, 241, 253, 241, - 251, 241, 74, 42, 42, 43, 241, 241, - 241, 241, 241, 241, 74, 241, 251, 40, - 241, 241, 56, 252, 241, 246, 247, 241, - 241, 241, 241, 253, 241, 251, 241, 242, - 243, 250, 245, 43, 246, 247, 241, 241, - 241, 241, 248, 241, 316, 156, 317, 317, - 81, 159, 160, 315, 315, 315, 315, 163, - 315, 156, 317, 317, 81, 159, 160, 315, - 315, 315, 315, 163, 315, 318, 315, 315, - 315, 95, 319, 315, 159, 160, 315, 315, - 315, 315, 320, 315, 318, 315, 321, 322, - 323, 324, 81, 159, 160, 315, 315, 315, - 112, 325, 315, 326, 322, 327, 327, 81, - 159, 160, 315, 315, 315, 315, 325, 315, - 322, 327, 327, 81, 159, 160, 315, 315, - 315, 315, 325, 315, 328, 315, 315, 315, - 95, 329, 315, 159, 160, 315, 315, 315, - 315, 320, 315, 328, 315, 330, 331, 332, - 333, 81, 159, 160, 315, 315, 315, 110, - 334, 315, 335, 331, 336, 336, 81, 159, - 160, 315, 315, 315, 315, 334, 315, 331, - 336, 336, 81, 159, 160, 315, 315, 315, - 315, 334, 315, 337, 315, 315, 315, 95, - 338, 315, 159, 160, 315, 315, 315, 315, - 320, 315, 337, 315, 339, 340, 341, 342, - 81, 159, 160, 315, 315, 315, 108, 343, - 315, 344, 340, 345, 345, 81, 159, 160, - 315, 315, 315, 315, 343, 315, 340, 345, - 345, 81, 159, 160, 315, 315, 315, 315, - 343, 315, 346, 315, 315, 315, 95, 347, - 315, 159, 160, 315, 315, 315, 315, 320, - 315, 346, 315, 348, 349, 350, 351, 81, - 159, 160, 315, 315, 315, 106, 352, 315, - 353, 349, 354, 354, 81, 159, 160, 315, - 315, 315, 315, 352, 315, 349, 354, 354, - 81, 159, 160, 315, 315, 315, 315, 352, - 315, 95, 355, 315, 159, 160, 315, 315, - 315, 315, 320, 315, 159, 160, 315, 315, - 315, 315, 320, 315, 356, 315, 315, 315, - 160, 315, 160, 315, 357, 315, 358, 315, - 359, 360, 315, 159, 160, 315, 315, 315, - 79, 315, 78, 315, 315, 315, 315, 159, - 160, 315, 159, 160, 315, 358, 315, 315, - 315, 315, 159, 160, 315, 358, 315, 359, - 315, 315, 159, 160, 315, 315, 315, 79, - 315, 95, 315, 361, 361, 81, 159, 160, - 315, 315, 315, 315, 320, 315, 362, 104, - 363, 364, 85, 159, 160, 315, 315, 315, - 315, 320, 315, 104, 363, 364, 85, 159, - 160, 315, 315, 315, 315, 320, 315, 363, - 363, 85, 159, 160, 315, 315, 315, 315, - 320, 315, 365, 101, 366, 367, 88, 159, - 160, 315, 315, 315, 315, 320, 315, 101, - 366, 367, 88, 159, 160, 315, 315, 315, - 315, 320, 315, 366, 366, 88, 159, 160, - 315, 315, 315, 315, 320, 315, 368, 98, - 369, 370, 91, 159, 160, 315, 315, 315, - 315, 320, 315, 98, 369, 370, 91, 159, - 160, 315, 315, 315, 315, 320, 315, 369, - 369, 91, 159, 160, 315, 315, 315, 315, - 320, 315, 371, 95, 315, 372, 315, 159, - 160, 315, 315, 315, 315, 320, 315, 95, - 315, 372, 315, 159, 160, 315, 315, 315, - 315, 320, 315, 373, 315, 159, 160, 315, - 315, 315, 315, 320, 315, 95, 315, 315, - 315, 315, 159, 160, 315, 315, 315, 315, - 320, 315, 77, 78, 315, 315, 95, 355, - 315, 159, 160, 315, 315, 315, 315, 320, - 315, 77, 315, 348, 349, 354, 354, 81, - 159, 160, 315, 315, 315, 315, 352, 315, - 348, 349, 350, 354, 81, 159, 160, 315, - 315, 315, 106, 352, 315, 346, 315, 374, - 315, 361, 361, 81, 159, 160, 315, 315, - 315, 315, 320, 315, 346, 315, 346, 315, - 315, 315, 315, 315, 315, 159, 160, 315, - 315, 315, 315, 320, 315, 346, 315, 346, - 315, 315, 315, 315, 375, 315, 159, 160, - 315, 315, 315, 315, 320, 315, 346, 315, - 346, 315, 374, 315, 315, 315, 315, 159, - 160, 315, 315, 315, 315, 320, 315, 346, - 315, 346, 78, 315, 315, 95, 347, 315, - 159, 160, 315, 315, 315, 315, 320, 315, - 346, 315, 339, 340, 345, 345, 81, 159, - 160, 315, 315, 315, 315, 343, 315, 339, - 340, 341, 345, 81, 159, 160, 315, 315, - 315, 108, 343, 315, 337, 315, 376, 315, - 361, 361, 81, 159, 160, 315, 315, 315, - 315, 320, 315, 337, 315, 337, 315, 315, - 315, 315, 315, 315, 159, 160, 315, 315, - 315, 315, 320, 315, 337, 315, 337, 315, - 315, 315, 315, 377, 315, 159, 160, 315, - 315, 315, 315, 320, 315, 337, 315, 337, - 315, 376, 315, 315, 315, 315, 159, 160, - 315, 315, 315, 315, 320, 315, 337, 315, - 337, 78, 315, 315, 95, 338, 315, 159, - 160, 315, 315, 315, 315, 320, 315, 337, - 315, 330, 331, 336, 336, 81, 159, 160, - 315, 315, 315, 315, 334, 315, 330, 331, - 332, 336, 81, 159, 160, 315, 315, 315, - 110, 334, 315, 328, 315, 378, 315, 361, - 361, 81, 159, 160, 315, 315, 315, 315, - 320, 315, 328, 315, 328, 315, 315, 315, - 315, 315, 315, 159, 160, 315, 315, 315, - 315, 320, 315, 328, 315, 328, 315, 315, - 315, 315, 379, 315, 159, 160, 315, 315, - 315, 315, 320, 315, 328, 315, 328, 315, - 378, 315, 315, 315, 315, 159, 160, 315, - 315, 315, 315, 320, 315, 328, 315, 328, - 78, 315, 315, 95, 329, 315, 159, 160, - 315, 315, 315, 315, 320, 315, 328, 315, - 321, 322, 327, 327, 81, 159, 160, 315, - 315, 315, 315, 325, 315, 321, 322, 323, - 327, 81, 159, 160, 315, 315, 315, 112, - 325, 315, 318, 315, 380, 315, 361, 361, - 81, 159, 160, 315, 315, 315, 315, 320, - 315, 318, 315, 318, 315, 315, 315, 315, - 315, 315, 159, 160, 315, 315, 315, 315, - 320, 315, 318, 315, 318, 315, 315, 315, - 315, 381, 315, 159, 160, 315, 315, 315, - 315, 320, 315, 318, 315, 318, 315, 380, - 315, 315, 315, 315, 159, 160, 315, 315, - 315, 315, 320, 315, 318, 315, 318, 78, - 315, 315, 95, 319, 315, 159, 160, 315, - 315, 315, 315, 320, 315, 318, 315, 113, - 80, 80, 81, 382, 382, 382, 382, 382, - 162, 113, 382, 155, 156, 317, 317, 81, - 159, 160, 315, 315, 315, 315, 163, 315, - 113, 80, 80, 81, 382, 382, 382, 382, - 382, 382, 113, 382, 384, 385, 386, 387, - 119, 388, 389, 383, 383, 383, 151, 390, - 383, 391, 385, 387, 387, 119, 388, 389, - 383, 383, 383, 383, 390, 383, 385, 387, - 387, 119, 388, 389, 383, 383, 383, 383, - 390, 383, 392, 383, 383, 383, 132, 393, - 383, 388, 389, 383, 383, 383, 383, 394, - 383, 392, 383, 395, 396, 397, 398, 119, - 388, 389, 383, 383, 383, 149, 399, 383, - 400, 396, 401, 401, 119, 388, 389, 383, - 383, 383, 383, 399, 383, 396, 401, 401, - 119, 388, 389, 383, 383, 383, 383, 399, - 383, 402, 383, 383, 383, 132, 403, 383, - 388, 389, 383, 383, 383, 383, 394, 383, - 402, 383, 404, 405, 406, 407, 119, 388, - 389, 383, 383, 383, 147, 408, 383, 409, - 405, 410, 410, 119, 388, 389, 383, 383, - 383, 383, 408, 383, 405, 410, 410, 119, - 388, 389, 383, 383, 383, 383, 408, 383, - 411, 383, 383, 383, 132, 412, 383, 388, - 389, 383, 383, 383, 383, 394, 383, 411, - 383, 413, 414, 415, 416, 119, 388, 389, - 383, 383, 383, 145, 417, 383, 418, 414, - 419, 419, 119, 388, 389, 383, 383, 383, - 383, 417, 383, 414, 419, 419, 119, 388, - 389, 383, 383, 383, 383, 417, 383, 420, - 383, 383, 383, 132, 421, 383, 388, 389, - 383, 383, 383, 383, 394, 383, 420, 383, - 422, 423, 424, 425, 119, 388, 389, 383, - 383, 383, 143, 426, 383, 427, 423, 428, - 428, 119, 388, 389, 383, 383, 383, 383, - 426, 383, 423, 428, 428, 119, 388, 389, - 383, 383, 383, 383, 426, 383, 132, 429, - 383, 388, 389, 383, 383, 383, 383, 394, - 383, 388, 389, 383, 383, 383, 383, 394, - 383, 430, 383, 383, 383, 389, 383, 389, - 383, 431, 383, 432, 383, 433, 434, 383, - 388, 389, 383, 383, 383, 117, 383, 116, - 383, 383, 383, 383, 388, 389, 383, 388, - 389, 383, 432, 383, 383, 383, 383, 388, - 389, 383, 432, 383, 433, 383, 383, 388, - 389, 383, 383, 383, 117, 383, 132, 383, - 435, 435, 119, 388, 389, 383, 383, 383, - 383, 394, 383, 436, 141, 437, 438, 122, - 388, 389, 383, 383, 383, 383, 394, 383, - 141, 437, 438, 122, 388, 389, 383, 383, - 383, 383, 394, 383, 437, 437, 122, 388, - 389, 383, 383, 383, 383, 394, 383, 439, - 138, 440, 441, 125, 388, 389, 383, 383, - 383, 383, 394, 383, 138, 440, 441, 125, - 388, 389, 383, 383, 383, 383, 394, 383, - 440, 440, 125, 388, 389, 383, 383, 383, - 383, 394, 383, 442, 135, 443, 444, 128, - 388, 389, 383, 383, 383, 383, 394, 383, - 135, 443, 444, 128, 388, 389, 383, 383, - 383, 383, 394, 383, 443, 443, 128, 388, - 389, 383, 383, 383, 383, 394, 383, 445, - 132, 383, 446, 383, 388, 389, 383, 383, - 383, 383, 394, 383, 132, 383, 446, 383, - 388, 389, 383, 383, 383, 383, 394, 383, - 447, 383, 388, 389, 383, 383, 383, 383, - 394, 383, 132, 383, 383, 383, 383, 388, - 389, 383, 383, 383, 383, 394, 383, 115, - 116, 383, 383, 132, 429, 383, 388, 389, - 383, 383, 383, 383, 394, 383, 115, 383, - 422, 423, 428, 428, 119, 388, 389, 383, - 383, 383, 383, 426, 383, 422, 423, 424, - 428, 119, 388, 389, 383, 383, 383, 143, - 426, 383, 420, 383, 448, 383, 435, 435, - 119, 388, 389, 383, 383, 383, 383, 394, - 383, 420, 383, 420, 383, 383, 383, 383, - 383, 383, 388, 389, 383, 383, 383, 383, - 394, 383, 420, 383, 420, 383, 383, 383, - 383, 449, 383, 388, 389, 383, 383, 383, - 383, 394, 383, 420, 383, 420, 383, 448, - 383, 383, 383, 383, 388, 389, 383, 383, - 383, 383, 394, 383, 420, 383, 420, 116, - 383, 383, 132, 421, 383, 388, 389, 383, - 383, 383, 383, 394, 383, 420, 383, 413, - 414, 419, 419, 119, 388, 389, 383, 383, - 383, 383, 417, 383, 413, 414, 415, 419, - 119, 388, 389, 383, 383, 383, 145, 417, - 383, 411, 383, 450, 383, 435, 435, 119, - 388, 389, 383, 383, 383, 383, 394, 383, - 411, 383, 411, 383, 383, 383, 383, 383, - 383, 388, 389, 383, 383, 383, 383, 394, - 383, 411, 383, 411, 383, 383, 383, 383, - 451, 383, 388, 389, 383, 383, 383, 383, - 394, 383, 411, 383, 411, 383, 450, 383, - 383, 383, 383, 388, 389, 383, 383, 383, - 383, 394, 383, 411, 383, 411, 116, 383, - 383, 132, 412, 383, 388, 389, 383, 383, - 383, 383, 394, 383, 411, 383, 404, 405, - 410, 410, 119, 388, 389, 383, 383, 383, - 383, 408, 383, 404, 405, 406, 410, 119, - 388, 389, 383, 383, 383, 147, 408, 383, - 402, 383, 452, 383, 435, 435, 119, 388, - 389, 383, 383, 383, 383, 394, 383, 402, - 383, 402, 383, 383, 383, 383, 383, 383, - 388, 389, 383, 383, 383, 383, 394, 383, - 402, 383, 402, 383, 383, 383, 383, 453, - 383, 388, 389, 383, 383, 383, 383, 394, - 383, 402, 383, 402, 383, 452, 383, 383, - 383, 383, 388, 389, 383, 383, 383, 383, - 394, 383, 402, 383, 402, 116, 383, 383, - 132, 403, 383, 388, 389, 383, 383, 383, - 383, 394, 383, 402, 383, 395, 396, 401, - 401, 119, 388, 389, 383, 383, 383, 383, - 399, 383, 395, 396, 397, 401, 119, 388, - 389, 383, 383, 383, 149, 399, 383, 392, - 383, 454, 383, 435, 435, 119, 388, 389, - 383, 383, 383, 383, 394, 383, 392, 383, - 392, 383, 383, 383, 383, 383, 383, 388, - 389, 383, 383, 383, 383, 394, 383, 392, - 383, 392, 383, 383, 383, 383, 455, 383, - 388, 389, 383, 383, 383, 383, 394, 383, - 392, 383, 392, 383, 454, 383, 383, 383, - 383, 388, 389, 383, 383, 383, 383, 394, - 383, 392, 383, 392, 116, 383, 383, 132, - 393, 383, 388, 389, 383, 383, 383, 383, - 394, 383, 392, 383, 384, 385, 387, 387, - 119, 388, 389, 383, 383, 383, 383, 390, - 383, 153, 154, 382, 382, 382, 382, 382, - 382, 382, 382, 161, 161, 382, 382, 382, - 153, 382, 167, 456, 169, 170, 5, 171, - 172, 173, 166, 166, 37, 174, 166, 177, - 154, 166, 166, 18, 178, 166, 171, 172, - 166, 161, 161, 166, 179, 166, 177, 166, + 114, 151, 150, 114, 113, 80, 80, 81, + 76, 76, 76, 76, 76, 152, 113, 76, + 111, 80, 80, 81, 0, 0, 0, 0, + 0, 153, 111, 0, 154, 154, 155, 0, + 6, 6, 155, 0, 156, 156, 157, 0, + 158, 158, 157, 0, 157, 0, 159, 159, + 160, 0, 161, 161, 160, 0, 160, 0, + 162, 162, 163, 0, 164, 164, 163, 0, + 163, 0, 165, 166, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 165, 0, 167, 0, 168, 0, 169, + 0, 170, 0, 171, 162, 162, 163, 0, + 172, 0, 173, 0, 174, 159, 159, 160, + 0, 175, 0, 176, 0, 177, 156, 156, + 157, 0, 178, 0, 179, 0, 181, 182, + 183, 184, 185, 186, 81, 187, 188, 180, + 189, 189, 152, 190, 191, 192, 180, 194, + 195, 196, 197, 5, 198, 199, 200, 193, + 193, 37, 201, 193, 193, 181, 193, 202, + 195, 203, 203, 5, 198, 199, 200, 193, + 193, 193, 201, 193, 195, 203, 203, 5, + 198, 199, 200, 193, 193, 193, 201, 193, + 204, 193, 193, 193, 18, 205, 193, 198, + 199, 193, 193, 193, 193, 206, 193, 204, + 193, 207, 208, 209, 210, 5, 198, 199, + 200, 193, 193, 35, 211, 193, 193, 204, + 193, 212, 208, 213, 213, 5, 198, 199, + 200, 193, 193, 193, 211, 193, 208, 213, + 213, 5, 198, 199, 200, 193, 193, 193, + 211, 193, 214, 193, 193, 193, 18, 215, + 193, 198, 199, 193, 193, 193, 193, 206, + 193, 214, 193, 216, 217, 218, 219, 5, + 198, 199, 200, 193, 193, 33, 220, 193, + 193, 214, 193, 221, 217, 222, 222, 5, + 198, 199, 200, 193, 193, 193, 220, 193, + 217, 222, 222, 5, 198, 199, 200, 193, + 193, 193, 220, 193, 223, 193, 193, 193, + 18, 224, 193, 198, 199, 193, 193, 193, + 193, 206, 193, 223, 193, 225, 226, 227, + 228, 5, 198, 199, 200, 193, 193, 31, + 229, 193, 193, 223, 193, 230, 226, 231, + 231, 5, 198, 199, 200, 193, 193, 193, + 229, 193, 226, 231, 231, 5, 198, 199, + 200, 193, 193, 193, 229, 193, 232, 193, + 193, 193, 18, 233, 193, 198, 199, 193, + 193, 193, 193, 206, 193, 232, 193, 234, + 235, 236, 237, 5, 198, 199, 200, 193, + 193, 29, 238, 193, 193, 232, 193, 239, + 235, 240, 240, 5, 198, 199, 200, 193, + 193, 193, 238, 193, 235, 240, 240, 5, + 198, 199, 200, 193, 193, 193, 238, 193, + 18, 241, 193, 198, 199, 193, 193, 193, + 193, 206, 193, 198, 199, 193, 193, 193, + 193, 206, 193, 242, 193, 193, 193, 199, + 193, 199, 193, 243, 193, 244, 193, 245, + 246, 193, 198, 199, 193, 193, 193, 3, + 193, 193, 193, 1, 193, 2, 193, 193, + 193, 193, 198, 199, 193, 198, 199, 193, + 244, 193, 193, 193, 193, 198, 199, 193, + 244, 193, 245, 193, 193, 198, 199, 193, + 193, 193, 3, 193, 18, 193, 247, 247, + 5, 198, 199, 193, 193, 193, 193, 206, + 193, 248, 27, 249, 250, 8, 198, 199, + 193, 193, 193, 193, 206, 193, 27, 249, + 250, 8, 198, 199, 193, 193, 193, 193, + 206, 193, 249, 249, 8, 198, 199, 193, + 193, 193, 193, 206, 193, 251, 24, 252, + 253, 11, 198, 199, 193, 193, 193, 193, + 206, 193, 24, 252, 253, 11, 198, 199, + 193, 193, 193, 193, 206, 193, 252, 252, + 11, 198, 199, 193, 193, 193, 193, 206, + 193, 254, 21, 255, 256, 14, 198, 199, + 193, 193, 193, 193, 206, 193, 21, 255, + 256, 14, 198, 199, 193, 193, 193, 193, + 206, 193, 255, 255, 14, 198, 199, 193, + 193, 193, 193, 206, 193, 257, 18, 193, + 258, 193, 198, 199, 193, 193, 193, 193, + 206, 193, 18, 193, 258, 193, 198, 199, + 193, 193, 193, 193, 206, 193, 259, 193, + 198, 199, 193, 193, 193, 193, 206, 193, + 18, 193, 193, 193, 193, 198, 199, 193, + 193, 193, 193, 206, 193, 235, 240, 240, + 5, 198, 199, 193, 193, 193, 193, 238, + 193, 1, 2, 193, 193, 18, 241, 193, + 198, 199, 193, 193, 193, 193, 206, 193, + 1, 193, 234, 235, 240, 240, 5, 198, + 199, 200, 193, 193, 193, 238, 193, 234, + 235, 236, 240, 5, 198, 199, 200, 193, + 193, 29, 238, 193, 232, 193, 260, 193, + 247, 247, 5, 198, 199, 193, 193, 193, + 193, 206, 193, 232, 193, 232, 193, 193, + 193, 193, 193, 193, 198, 199, 193, 193, + 193, 193, 206, 193, 232, 193, 232, 193, + 193, 193, 193, 261, 193, 198, 199, 193, + 193, 193, 193, 206, 193, 232, 193, 232, + 193, 260, 193, 193, 193, 193, 198, 199, + 193, 193, 193, 193, 206, 193, 232, 193, + 232, 2, 193, 193, 18, 233, 193, 198, + 199, 193, 193, 193, 193, 206, 193, 232, + 193, 225, 226, 231, 231, 5, 198, 199, + 200, 193, 193, 193, 229, 193, 225, 226, + 227, 231, 5, 198, 199, 200, 193, 193, + 31, 229, 193, 223, 193, 262, 193, 247, + 247, 5, 198, 199, 193, 193, 193, 193, + 206, 193, 223, 193, 223, 193, 193, 193, + 193, 193, 193, 198, 199, 193, 193, 193, + 193, 206, 193, 223, 193, 223, 193, 193, + 193, 193, 263, 193, 198, 199, 193, 193, + 193, 193, 206, 193, 223, 193, 223, 193, + 262, 193, 193, 193, 193, 198, 199, 193, + 193, 193, 193, 206, 193, 223, 193, 223, + 2, 193, 193, 18, 224, 193, 198, 199, + 193, 193, 193, 193, 206, 193, 223, 193, + 216, 217, 222, 222, 5, 198, 199, 200, + 193, 193, 193, 220, 193, 216, 217, 218, + 222, 5, 198, 199, 200, 193, 193, 33, + 220, 193, 214, 193, 264, 193, 247, 247, + 5, 198, 199, 193, 193, 193, 193, 206, + 193, 214, 193, 214, 193, 193, 193, 193, + 193, 193, 198, 199, 193, 193, 193, 193, + 206, 193, 214, 193, 214, 193, 193, 193, + 193, 265, 193, 198, 199, 193, 193, 193, + 193, 206, 193, 214, 193, 214, 193, 264, + 193, 193, 193, 193, 198, 199, 193, 193, + 193, 193, 206, 193, 214, 193, 214, 2, + 193, 193, 18, 215, 193, 198, 199, 193, + 193, 193, 193, 206, 193, 214, 193, 207, + 208, 213, 213, 5, 198, 199, 200, 193, + 193, 193, 211, 193, 207, 208, 209, 213, + 5, 198, 199, 200, 193, 193, 35, 211, + 193, 204, 193, 266, 193, 247, 247, 5, + 198, 199, 193, 193, 193, 193, 206, 193, + 204, 193, 204, 193, 193, 193, 193, 193, + 193, 198, 199, 193, 193, 193, 193, 206, + 193, 204, 193, 204, 193, 193, 193, 193, + 267, 193, 198, 199, 193, 193, 193, 193, + 206, 193, 204, 193, 204, 193, 266, 193, + 193, 193, 193, 198, 199, 193, 193, 193, + 193, 206, 193, 204, 193, 204, 2, 193, + 193, 18, 205, 193, 198, 199, 193, 193, + 193, 193, 206, 193, 204, 193, 194, 195, + 203, 203, 5, 198, 199, 200, 193, 193, + 193, 201, 193, 194, 195, 196, 203, 5, + 198, 199, 200, 193, 193, 37, 201, 193, + 269, 270, 271, 272, 43, 273, 274, 268, + 268, 268, 75, 275, 268, 276, 270, 277, + 272, 43, 273, 274, 268, 268, 268, 268, + 275, 268, 270, 277, 272, 43, 273, 274, + 268, 268, 268, 268, 275, 268, 278, 268, + 268, 268, 56, 279, 268, 273, 274, 268, + 268, 268, 268, 280, 268, 278, 268, 281, + 282, 283, 284, 43, 273, 274, 268, 268, + 268, 73, 285, 268, 268, 278, 268, 286, + 282, 287, 287, 43, 273, 274, 268, 268, + 268, 268, 285, 268, 282, 287, 287, 43, + 273, 274, 268, 268, 268, 268, 285, 268, + 288, 268, 268, 268, 56, 289, 268, 273, + 274, 268, 268, 268, 268, 280, 268, 288, + 268, 290, 291, 292, 293, 43, 273, 274, + 268, 268, 268, 71, 294, 268, 268, 288, + 268, 295, 291, 296, 296, 43, 273, 274, + 268, 268, 268, 268, 294, 268, 291, 296, + 296, 43, 273, 274, 268, 268, 268, 268, + 294, 268, 297, 268, 268, 268, 56, 298, + 268, 273, 274, 268, 268, 268, 268, 280, + 268, 297, 268, 299, 300, 301, 302, 43, + 273, 274, 268, 268, 268, 69, 303, 268, + 268, 297, 268, 304, 300, 305, 305, 43, + 273, 274, 268, 268, 268, 268, 303, 268, + 300, 305, 305, 43, 273, 274, 268, 268, + 268, 268, 303, 268, 306, 268, 268, 268, + 56, 307, 268, 273, 274, 268, 268, 268, + 268, 280, 268, 306, 268, 308, 309, 310, + 311, 43, 273, 274, 268, 268, 268, 67, + 312, 268, 268, 306, 268, 313, 309, 314, + 314, 43, 273, 274, 268, 268, 268, 268, + 312, 268, 309, 314, 314, 43, 273, 274, + 268, 268, 268, 268, 312, 268, 56, 315, + 268, 273, 274, 268, 268, 268, 268, 280, + 268, 273, 274, 268, 268, 268, 268, 280, + 268, 316, 268, 268, 268, 274, 268, 274, + 268, 317, 268, 318, 268, 319, 320, 268, + 273, 274, 268, 268, 268, 41, 268, 268, + 268, 39, 268, 40, 268, 268, 268, 268, + 273, 274, 268, 273, 274, 268, 318, 268, + 268, 268, 268, 273, 274, 268, 318, 268, + 319, 268, 268, 273, 274, 268, 268, 268, + 41, 268, 56, 268, 321, 321, 43, 273, + 274, 268, 268, 268, 268, 280, 268, 322, + 65, 323, 324, 46, 273, 274, 268, 268, + 268, 268, 280, 268, 65, 323, 324, 46, + 273, 274, 268, 268, 268, 268, 280, 268, + 323, 323, 46, 273, 274, 268, 268, 268, + 268, 280, 268, 325, 62, 326, 327, 49, + 273, 274, 268, 268, 268, 268, 280, 268, + 62, 326, 327, 49, 273, 274, 268, 268, + 268, 268, 280, 268, 326, 326, 49, 273, + 274, 268, 268, 268, 268, 280, 268, 328, + 59, 329, 330, 52, 273, 274, 268, 268, + 268, 268, 280, 268, 59, 329, 330, 52, + 273, 274, 268, 268, 268, 268, 280, 268, + 329, 329, 52, 273, 274, 268, 268, 268, + 268, 280, 268, 331, 56, 268, 332, 268, + 273, 274, 268, 268, 268, 268, 280, 268, + 56, 268, 332, 268, 273, 274, 268, 268, + 268, 268, 280, 268, 333, 268, 273, 274, + 268, 268, 268, 268, 280, 268, 56, 268, + 268, 268, 268, 273, 274, 268, 268, 268, + 268, 280, 268, 39, 40, 268, 268, 56, + 315, 268, 273, 274, 268, 268, 268, 268, + 280, 268, 39, 268, 308, 309, 314, 314, + 43, 273, 274, 268, 268, 268, 268, 312, + 268, 308, 309, 310, 314, 43, 273, 274, + 268, 268, 268, 67, 312, 268, 306, 268, + 334, 268, 321, 321, 43, 273, 274, 268, + 268, 268, 268, 280, 268, 306, 268, 306, + 268, 268, 268, 268, 268, 268, 273, 274, + 268, 268, 268, 268, 280, 268, 306, 268, + 306, 268, 268, 268, 268, 335, 268, 273, + 274, 268, 268, 268, 268, 280, 268, 306, + 268, 306, 268, 334, 268, 268, 268, 268, + 273, 274, 268, 268, 268, 268, 280, 268, + 306, 268, 306, 40, 268, 268, 56, 307, + 268, 273, 274, 268, 268, 268, 268, 280, + 268, 306, 268, 299, 300, 305, 305, 43, + 273, 274, 268, 268, 268, 268, 303, 268, + 299, 300, 301, 305, 43, 273, 274, 268, + 268, 268, 69, 303, 268, 297, 268, 336, + 268, 321, 321, 43, 273, 274, 268, 268, + 268, 268, 280, 268, 297, 268, 297, 268, + 268, 268, 268, 268, 268, 273, 274, 268, + 268, 268, 268, 280, 268, 297, 268, 297, + 268, 268, 268, 268, 337, 268, 273, 274, + 268, 268, 268, 268, 280, 268, 297, 268, + 297, 268, 336, 268, 268, 268, 268, 273, + 274, 268, 268, 268, 268, 280, 268, 297, + 268, 297, 40, 268, 268, 56, 298, 268, + 273, 274, 268, 268, 268, 268, 280, 268, + 297, 268, 290, 291, 296, 296, 43, 273, + 274, 268, 268, 268, 268, 294, 268, 290, + 291, 292, 296, 43, 273, 274, 268, 268, + 268, 71, 294, 268, 288, 268, 338, 268, + 321, 321, 43, 273, 274, 268, 268, 268, + 268, 280, 268, 288, 268, 288, 268, 268, + 268, 268, 268, 268, 273, 274, 268, 268, + 268, 268, 280, 268, 288, 268, 288, 268, + 268, 268, 268, 339, 268, 273, 274, 268, + 268, 268, 268, 280, 268, 288, 268, 288, + 268, 338, 268, 268, 268, 268, 273, 274, + 268, 268, 268, 268, 280, 268, 288, 268, + 288, 40, 268, 268, 56, 289, 268, 273, + 274, 268, 268, 268, 268, 280, 268, 288, + 268, 281, 282, 287, 287, 43, 273, 274, + 268, 268, 268, 268, 285, 268, 281, 282, + 283, 287, 43, 273, 274, 268, 268, 268, + 73, 285, 268, 278, 268, 340, 268, 321, + 321, 43, 273, 274, 268, 268, 268, 268, + 280, 268, 278, 268, 278, 268, 268, 268, + 268, 268, 268, 273, 274, 268, 268, 268, + 268, 280, 268, 278, 268, 278, 268, 268, + 268, 268, 341, 268, 273, 274, 268, 268, + 268, 268, 280, 268, 278, 268, 278, 268, + 340, 268, 268, 268, 268, 273, 274, 268, + 268, 268, 268, 280, 268, 278, 268, 74, + 42, 42, 43, 268, 268, 268, 268, 268, + 268, 74, 268, 278, 40, 268, 268, 56, + 279, 268, 273, 274, 268, 268, 268, 268, + 280, 268, 278, 268, 269, 270, 277, 272, + 43, 273, 274, 268, 268, 268, 268, 275, + 268, 343, 184, 344, 344, 81, 187, 188, + 342, 342, 342, 342, 190, 342, 184, 344, + 344, 81, 187, 188, 342, 342, 342, 342, + 190, 342, 345, 342, 342, 342, 95, 346, + 342, 187, 188, 342, 342, 342, 342, 347, + 342, 345, 342, 348, 349, 350, 351, 81, + 187, 188, 342, 342, 342, 112, 352, 342, + 342, 345, 342, 353, 349, 354, 354, 81, + 187, 188, 342, 342, 342, 342, 352, 342, + 349, 354, 354, 81, 187, 188, 342, 342, + 342, 342, 352, 342, 355, 342, 342, 342, + 95, 356, 342, 187, 188, 342, 342, 342, + 342, 347, 342, 355, 342, 357, 358, 359, + 360, 81, 187, 188, 342, 342, 342, 110, + 361, 342, 342, 355, 342, 362, 358, 363, + 363, 81, 187, 188, 342, 342, 342, 342, + 361, 342, 358, 363, 363, 81, 187, 188, + 342, 342, 342, 342, 361, 342, 364, 342, + 342, 342, 95, 365, 342, 187, 188, 342, + 342, 342, 342, 347, 342, 364, 342, 366, + 367, 368, 369, 81, 187, 188, 342, 342, + 342, 108, 370, 342, 342, 364, 342, 371, + 367, 372, 372, 81, 187, 188, 342, 342, + 342, 342, 370, 342, 367, 372, 372, 81, + 187, 188, 342, 342, 342, 342, 370, 342, + 373, 342, 342, 342, 95, 374, 342, 187, + 188, 342, 342, 342, 342, 347, 342, 373, + 342, 375, 376, 377, 378, 81, 187, 188, + 342, 342, 342, 106, 379, 342, 342, 373, + 342, 380, 376, 381, 381, 81, 187, 188, + 342, 342, 342, 342, 379, 342, 376, 381, + 381, 81, 187, 188, 342, 342, 342, 342, + 379, 342, 95, 382, 342, 187, 188, 342, + 342, 342, 342, 347, 342, 187, 188, 342, + 342, 342, 342, 347, 342, 383, 342, 342, + 342, 188, 342, 188, 342, 384, 342, 385, + 342, 386, 387, 342, 187, 188, 342, 342, + 342, 79, 342, 342, 342, 77, 342, 78, + 342, 342, 342, 342, 187, 188, 342, 187, + 188, 342, 385, 342, 342, 342, 342, 187, + 188, 342, 385, 342, 386, 342, 342, 187, + 188, 342, 342, 342, 79, 342, 95, 342, + 388, 388, 81, 187, 188, 342, 342, 342, + 342, 347, 342, 389, 104, 390, 391, 85, + 187, 188, 342, 342, 342, 342, 347, 342, + 104, 390, 391, 85, 187, 188, 342, 342, + 342, 342, 347, 342, 390, 390, 85, 187, + 188, 342, 342, 342, 342, 347, 342, 392, + 101, 393, 394, 88, 187, 188, 342, 342, + 342, 342, 347, 342, 101, 393, 394, 88, + 187, 188, 342, 342, 342, 342, 347, 342, + 393, 393, 88, 187, 188, 342, 342, 342, + 342, 347, 342, 395, 98, 396, 397, 91, + 187, 188, 342, 342, 342, 342, 347, 342, + 98, 396, 397, 91, 187, 188, 342, 342, + 342, 342, 347, 342, 396, 396, 91, 187, + 188, 342, 342, 342, 342, 347, 342, 398, + 95, 342, 399, 342, 187, 188, 342, 342, + 342, 342, 347, 342, 95, 342, 399, 342, + 187, 188, 342, 342, 342, 342, 347, 342, + 400, 342, 187, 188, 342, 342, 342, 342, + 347, 342, 95, 342, 342, 342, 342, 187, + 188, 342, 342, 342, 342, 347, 342, 77, + 78, 342, 342, 95, 382, 342, 187, 188, + 342, 342, 342, 342, 347, 342, 77, 342, + 375, 376, 381, 381, 81, 187, 188, 342, + 342, 342, 342, 379, 342, 375, 376, 377, + 381, 81, 187, 188, 342, 342, 342, 106, + 379, 342, 373, 342, 401, 342, 388, 388, + 81, 187, 188, 342, 342, 342, 342, 347, + 342, 373, 342, 373, 342, 342, 342, 342, + 342, 342, 187, 188, 342, 342, 342, 342, + 347, 342, 373, 342, 373, 342, 342, 342, + 342, 402, 342, 187, 188, 342, 342, 342, + 342, 347, 342, 373, 342, 373, 342, 401, + 342, 342, 342, 342, 187, 188, 342, 342, + 342, 342, 347, 342, 373, 342, 373, 78, + 342, 342, 95, 374, 342, 187, 188, 342, + 342, 342, 342, 347, 342, 373, 342, 366, + 367, 372, 372, 81, 187, 188, 342, 342, + 342, 342, 370, 342, 366, 367, 368, 372, + 81, 187, 188, 342, 342, 342, 108, 370, + 342, 364, 342, 403, 342, 388, 388, 81, + 187, 188, 342, 342, 342, 342, 347, 342, + 364, 342, 364, 342, 342, 342, 342, 342, + 342, 187, 188, 342, 342, 342, 342, 347, + 342, 364, 342, 364, 342, 342, 342, 342, + 404, 342, 187, 188, 342, 342, 342, 342, + 347, 342, 364, 342, 364, 342, 403, 342, + 342, 342, 342, 187, 188, 342, 342, 342, + 342, 347, 342, 364, 342, 364, 78, 342, + 342, 95, 365, 342, 187, 188, 342, 342, + 342, 342, 347, 342, 364, 342, 357, 358, + 363, 363, 81, 187, 188, 342, 342, 342, + 342, 361, 342, 357, 358, 359, 363, 81, + 187, 188, 342, 342, 342, 110, 361, 342, + 355, 342, 405, 342, 388, 388, 81, 187, + 188, 342, 342, 342, 342, 347, 342, 355, + 342, 355, 342, 342, 342, 342, 342, 342, + 187, 188, 342, 342, 342, 342, 347, 342, + 355, 342, 355, 342, 342, 342, 342, 406, + 342, 187, 188, 342, 342, 342, 342, 347, + 342, 355, 342, 355, 342, 405, 342, 342, + 342, 342, 187, 188, 342, 342, 342, 342, + 347, 342, 355, 342, 355, 78, 342, 342, + 95, 356, 342, 187, 188, 342, 342, 342, + 342, 347, 342, 355, 342, 348, 349, 354, + 354, 81, 187, 188, 342, 342, 342, 342, + 352, 342, 348, 349, 350, 354, 81, 187, + 188, 342, 342, 342, 112, 352, 342, 345, + 342, 407, 342, 388, 388, 81, 187, 188, + 342, 342, 342, 342, 347, 342, 345, 342, + 345, 342, 342, 342, 342, 342, 342, 187, + 188, 342, 342, 342, 342, 347, 342, 345, + 342, 345, 342, 342, 342, 342, 408, 342, + 187, 188, 342, 342, 342, 342, 347, 342, + 345, 342, 345, 342, 407, 342, 342, 342, + 342, 187, 188, 342, 342, 342, 342, 347, + 342, 345, 342, 345, 78, 342, 342, 95, + 346, 342, 187, 188, 342, 342, 342, 342, + 347, 342, 345, 342, 113, 80, 80, 81, + 409, 409, 409, 409, 409, 152, 113, 409, + 183, 184, 344, 344, 81, 187, 188, 342, + 342, 342, 342, 190, 342, 113, 80, 80, + 81, 409, 409, 409, 409, 409, 409, 113, + 409, 411, 412, 413, 414, 119, 415, 416, + 410, 410, 410, 151, 417, 410, 418, 412, + 414, 414, 119, 415, 416, 410, 410, 410, + 410, 417, 410, 412, 414, 414, 119, 415, + 416, 410, 410, 410, 410, 417, 410, 419, + 410, 410, 410, 132, 420, 410, 415, 416, + 410, 410, 410, 410, 421, 410, 419, 410, + 422, 423, 424, 425, 119, 415, 416, 410, + 410, 410, 149, 426, 410, 410, 419, 410, + 427, 423, 428, 428, 119, 415, 416, 410, + 410, 410, 410, 426, 410, 423, 428, 428, + 119, 415, 416, 410, 410, 410, 410, 426, + 410, 429, 410, 410, 410, 132, 430, 410, + 415, 416, 410, 410, 410, 410, 421, 410, + 429, 410, 431, 432, 433, 434, 119, 415, + 416, 410, 410, 410, 147, 435, 410, 410, + 429, 410, 436, 432, 437, 437, 119, 415, + 416, 410, 410, 410, 410, 435, 410, 432, + 437, 437, 119, 415, 416, 410, 410, 410, + 410, 435, 410, 438, 410, 410, 410, 132, + 439, 410, 415, 416, 410, 410, 410, 410, + 421, 410, 438, 410, 440, 441, 442, 443, + 119, 415, 416, 410, 410, 410, 145, 444, + 410, 410, 438, 410, 445, 441, 446, 446, + 119, 415, 416, 410, 410, 410, 410, 444, + 410, 441, 446, 446, 119, 415, 416, 410, + 410, 410, 410, 444, 410, 447, 410, 410, + 410, 132, 448, 410, 415, 416, 410, 410, + 410, 410, 421, 410, 447, 410, 449, 450, + 451, 452, 119, 415, 416, 410, 410, 410, + 143, 453, 410, 410, 447, 410, 454, 450, + 455, 455, 119, 415, 416, 410, 410, 410, + 410, 453, 410, 450, 455, 455, 119, 415, + 416, 410, 410, 410, 410, 453, 410, 132, + 456, 410, 415, 416, 410, 410, 410, 410, + 421, 410, 415, 416, 410, 410, 410, 410, + 421, 410, 457, 410, 410, 410, 416, 410, + 416, 410, 458, 410, 459, 410, 460, 461, + 410, 415, 416, 410, 410, 410, 117, 410, + 410, 410, 115, 410, 116, 410, 410, 410, + 410, 415, 416, 410, 415, 416, 410, 459, + 410, 410, 410, 410, 415, 416, 410, 459, + 410, 460, 410, 410, 415, 416, 410, 410, + 410, 117, 410, 132, 410, 462, 462, 119, + 415, 416, 410, 410, 410, 410, 421, 410, + 463, 141, 464, 465, 122, 415, 416, 410, + 410, 410, 410, 421, 410, 141, 464, 465, + 122, 415, 416, 410, 410, 410, 410, 421, + 410, 464, 464, 122, 415, 416, 410, 410, + 410, 410, 421, 410, 466, 138, 467, 468, + 125, 415, 416, 410, 410, 410, 410, 421, + 410, 138, 467, 468, 125, 415, 416, 410, + 410, 410, 410, 421, 410, 467, 467, 125, + 415, 416, 410, 410, 410, 410, 421, 410, + 469, 135, 470, 471, 128, 415, 416, 410, + 410, 410, 410, 421, 410, 135, 470, 471, + 128, 415, 416, 410, 410, 410, 410, 421, + 410, 470, 470, 128, 415, 416, 410, 410, + 410, 410, 421, 410, 472, 132, 410, 473, + 410, 415, 416, 410, 410, 410, 410, 421, + 410, 132, 410, 473, 410, 415, 416, 410, + 410, 410, 410, 421, 410, 474, 410, 415, + 416, 410, 410, 410, 410, 421, 410, 132, + 410, 410, 410, 410, 415, 416, 410, 410, + 410, 410, 421, 410, 115, 116, 410, 410, + 132, 456, 410, 415, 416, 410, 410, 410, + 410, 421, 410, 115, 410, 449, 450, 455, + 455, 119, 415, 416, 410, 410, 410, 410, + 453, 410, 449, 450, 451, 455, 119, 415, + 416, 410, 410, 410, 143, 453, 410, 447, + 410, 475, 410, 462, 462, 119, 415, 416, + 410, 410, 410, 410, 421, 410, 447, 410, + 447, 410, 410, 410, 410, 410, 410, 415, + 416, 410, 410, 410, 410, 421, 410, 447, + 410, 447, 410, 410, 410, 410, 476, 410, + 415, 416, 410, 410, 410, 410, 421, 410, + 447, 410, 447, 410, 475, 410, 410, 410, + 410, 415, 416, 410, 410, 410, 410, 421, + 410, 447, 410, 447, 116, 410, 410, 132, + 448, 410, 415, 416, 410, 410, 410, 410, + 421, 410, 447, 410, 440, 441, 446, 446, + 119, 415, 416, 410, 410, 410, 410, 444, + 410, 440, 441, 442, 446, 119, 415, 416, + 410, 410, 410, 145, 444, 410, 438, 410, + 477, 410, 462, 462, 119, 415, 416, 410, + 410, 410, 410, 421, 410, 438, 410, 438, + 410, 410, 410, 410, 410, 410, 415, 416, + 410, 410, 410, 410, 421, 410, 438, 410, + 438, 410, 410, 410, 410, 478, 410, 415, + 416, 410, 410, 410, 410, 421, 410, 438, + 410, 438, 410, 477, 410, 410, 410, 410, + 415, 416, 410, 410, 410, 410, 421, 410, + 438, 410, 438, 116, 410, 410, 132, 439, + 410, 415, 416, 410, 410, 410, 410, 421, + 410, 438, 410, 431, 432, 437, 437, 119, + 415, 416, 410, 410, 410, 410, 435, 410, + 431, 432, 433, 437, 119, 415, 416, 410, + 410, 410, 147, 435, 410, 429, 410, 479, + 410, 462, 462, 119, 415, 416, 410, 410, + 410, 410, 421, 410, 429, 410, 429, 410, + 410, 410, 410, 410, 410, 415, 416, 410, + 410, 410, 410, 421, 410, 429, 410, 429, + 410, 410, 410, 410, 480, 410, 415, 416, + 410, 410, 410, 410, 421, 410, 429, 410, + 429, 410, 479, 410, 410, 410, 410, 415, + 416, 410, 410, 410, 410, 421, 410, 429, + 410, 429, 116, 410, 410, 132, 430, 410, + 415, 416, 410, 410, 410, 410, 421, 410, + 429, 410, 422, 423, 428, 428, 119, 415, + 416, 410, 410, 410, 410, 426, 410, 422, + 423, 424, 428, 119, 415, 416, 410, 410, + 410, 149, 426, 410, 419, 410, 481, 410, + 462, 462, 119, 415, 416, 410, 410, 410, + 410, 421, 410, 419, 410, 419, 410, 410, + 410, 410, 410, 410, 415, 416, 410, 410, + 410, 410, 421, 410, 419, 410, 419, 410, + 410, 410, 410, 482, 410, 415, 416, 410, + 410, 410, 410, 421, 410, 419, 410, 419, + 410, 481, 410, 410, 410, 410, 415, 416, + 410, 410, 410, 410, 421, 410, 419, 410, + 419, 116, 410, 410, 132, 420, 410, 415, + 416, 410, 410, 410, 410, 421, 410, 419, + 410, 411, 412, 414, 414, 119, 415, 416, + 410, 410, 410, 410, 417, 410, 181, 182, + 183, 184, 483, 344, 81, 187, 188, 342, + 189, 189, 152, 190, 342, 181, 342, 194, + 484, 196, 197, 5, 198, 199, 200, 193, + 193, 37, 201, 193, 193, 181, 193, 204, + 182, 183, 184, 485, 486, 81, 487, 488, + 193, 189, 189, 152, 489, 193, 204, 193, + 113, 80, 80, 81, 198, 199, 193, 193, + 193, 152, 490, 193, 491, 2, 342, 342, + 342, 408, 342, 187, 188, 342, 342, 342, + 342, 347, 342, 491, 342, 492, 349, 493, + 494, 81, 487, 488, 193, 193, 193, 153, + 352, 193, 193, 491, 193, 495, 349, 354, + 354, 81, 487, 488, 193, 193, 193, 193, + 352, 193, 349, 354, 354, 81, 487, 488, + 193, 193, 193, 193, 352, 193, 496, 193, + 193, 193, 488, 193, 488, 193, 243, 193, + 492, 349, 354, 354, 81, 487, 488, 193, + 193, 193, 193, 352, 193, 492, 349, 493, + 354, 81, 487, 488, 193, 193, 193, 153, + 352, 193, 204, 193, 266, 113, 497, 497, + 155, 198, 199, 193, 193, 193, 193, 490, + 193, 204, 193, 498, 179, 499, 500, 157, + 487, 488, 193, 193, 193, 193, 501, 193, + 179, 499, 500, 157, 487, 488, 193, 193, + 193, 193, 501, 193, 499, 499, 157, 487, + 488, 193, 193, 193, 193, 501, 193, 502, + 176, 503, 504, 160, 487, 488, 193, 193, + 193, 193, 501, 193, 176, 503, 504, 160, + 487, 488, 193, 193, 193, 193, 501, 193, + 503, 503, 160, 487, 488, 193, 193, 193, + 193, 501, 193, 505, 173, 506, 507, 163, + 487, 488, 193, 193, 193, 193, 501, 193, + 173, 506, 507, 163, 487, 488, 193, 193, + 193, 193, 501, 193, 506, 506, 163, 487, + 488, 193, 193, 193, 193, 501, 193, 508, + 170, 193, 509, 193, 487, 488, 193, 193, + 193, 193, 501, 193, 170, 193, 509, 193, + 487, 488, 193, 193, 193, 193, 501, 193, + 487, 488, 193, 193, 193, 193, 501, 193, + 510, 193, 511, 512, 193, 487, 488, 193, + 193, 193, 167, 193, 193, 193, 165, 193, + 166, 193, 193, 193, 193, 487, 488, 193, + 487, 488, 193, 510, 193, 193, 193, 193, + 487, 488, 193, 510, 193, 511, 193, 193, + 487, 488, 193, 193, 193, 167, 193, 491, + 166, 342, 342, 95, 346, 342, 187, 188, + 342, 342, 342, 342, 347, 342, 491, 342, 0 }; static const short _indic_syllable_machine_trans_targs[] = { - 143, 168, 170, 171, 3, 174, 4, 6, - 177, 7, 9, 180, 10, 12, 183, 13, - 15, 16, 164, 18, 19, 182, 21, 22, - 179, 24, 25, 176, 185, 189, 193, 196, - 200, 203, 207, 210, 214, 217, 143, 243, - 245, 246, 39, 249, 40, 42, 252, 43, - 45, 255, 46, 48, 258, 49, 51, 52, - 239, 54, 55, 257, 57, 58, 254, 60, - 61, 251, 260, 263, 267, 270, 274, 277, - 281, 284, 288, 292, 143, 316, 318, 319, - 75, 322, 143, 76, 78, 325, 79, 81, - 328, 82, 84, 331, 85, 87, 88, 312, - 90, 91, 330, 93, 94, 327, 96, 97, - 324, 333, 336, 340, 343, 347, 350, 354, - 357, 361, 143, 391, 393, 394, 110, 397, - 111, 113, 400, 114, 116, 403, 117, 119, - 406, 120, 122, 123, 387, 125, 126, 405, - 128, 129, 402, 131, 132, 399, 408, 411, - 415, 418, 422, 425, 429, 432, 436, 439, - 143, 144, 219, 293, 295, 364, 366, 313, - 315, 367, 365, 363, 440, 441, 143, 145, - 147, 35, 218, 165, 167, 187, 216, 146, - 34, 148, 212, 0, 149, 151, 33, 211, - 209, 150, 32, 152, 205, 153, 155, 31, - 204, 202, 154, 30, 156, 198, 157, 159, - 29, 197, 195, 158, 28, 160, 191, 161, - 163, 27, 190, 188, 162, 26, 173, 166, - 143, 169, 1, 172, 2, 175, 5, 23, - 178, 8, 20, 181, 11, 17, 184, 14, - 186, 192, 194, 199, 201, 206, 208, 213, - 215, 143, 220, 222, 71, 290, 240, 242, - 291, 221, 70, 223, 286, 36, 224, 226, - 69, 285, 283, 225, 68, 227, 279, 228, - 230, 67, 278, 276, 229, 66, 231, 272, - 232, 234, 65, 271, 269, 233, 64, 235, - 265, 236, 238, 63, 264, 262, 237, 62, - 248, 241, 143, 244, 37, 247, 38, 250, - 41, 59, 253, 44, 56, 256, 47, 53, - 259, 50, 261, 266, 268, 273, 275, 280, - 282, 287, 289, 143, 294, 106, 296, 359, - 72, 297, 299, 105, 358, 356, 298, 104, - 300, 352, 301, 303, 103, 351, 349, 302, - 102, 304, 345, 305, 307, 101, 344, 342, - 306, 100, 308, 338, 309, 311, 99, 337, - 335, 310, 98, 321, 314, 143, 317, 73, - 320, 74, 323, 77, 95, 326, 80, 92, - 329, 83, 89, 332, 86, 334, 339, 341, - 346, 348, 353, 355, 360, 362, 143, 143, - 368, 370, 142, 141, 388, 390, 438, 369, - 371, 434, 107, 372, 374, 140, 433, 431, - 373, 139, 375, 427, 376, 378, 138, 426, - 424, 377, 137, 379, 420, 380, 382, 136, - 419, 417, 381, 135, 383, 413, 384, 386, - 134, 412, 410, 385, 133, 396, 389, 143, - 392, 108, 395, 109, 398, 112, 130, 401, - 115, 127, 404, 118, 124, 407, 121, 409, - 414, 416, 421, 423, 428, 430, 435, 437, - 442 + 170, 195, 197, 198, 3, 201, 4, 6, + 204, 7, 9, 207, 10, 12, 210, 13, + 15, 16, 191, 18, 19, 209, 21, 22, + 206, 24, 25, 203, 212, 216, 220, 223, + 227, 230, 234, 237, 241, 244, 170, 270, + 272, 273, 39, 276, 40, 42, 279, 43, + 45, 282, 46, 48, 285, 49, 51, 52, + 266, 54, 55, 284, 57, 58, 281, 60, + 61, 278, 287, 290, 294, 297, 301, 304, + 308, 311, 315, 319, 170, 343, 345, 346, + 75, 349, 170, 76, 78, 352, 79, 81, + 355, 82, 84, 358, 85, 87, 88, 339, + 90, 91, 357, 93, 94, 354, 96, 97, + 351, 360, 363, 367, 370, 374, 377, 381, + 384, 388, 170, 418, 420, 421, 110, 424, + 111, 113, 427, 114, 116, 430, 117, 119, + 433, 120, 122, 123, 414, 125, 126, 432, + 128, 129, 429, 131, 132, 426, 435, 438, + 442, 445, 449, 452, 456, 459, 463, 466, + 392, 478, 146, 481, 148, 484, 149, 151, + 487, 152, 154, 490, 155, 493, 495, 496, + 159, 160, 492, 162, 163, 489, 165, 166, + 486, 168, 169, 483, 170, 171, 246, 320, + 322, 391, 393, 340, 342, 394, 390, 467, + 468, 170, 172, 174, 35, 245, 192, 194, + 214, 243, 173, 34, 175, 239, 0, 176, + 178, 33, 238, 236, 177, 32, 179, 232, + 180, 182, 31, 231, 229, 181, 30, 183, + 225, 184, 186, 29, 224, 222, 185, 28, + 187, 218, 188, 190, 27, 217, 215, 189, + 26, 200, 193, 170, 196, 1, 199, 2, + 202, 5, 23, 205, 8, 20, 208, 11, + 17, 211, 14, 213, 219, 221, 226, 228, + 233, 235, 240, 242, 170, 247, 249, 71, + 317, 267, 269, 318, 248, 70, 250, 313, + 36, 251, 253, 69, 312, 310, 252, 68, + 254, 306, 255, 257, 67, 305, 303, 256, + 66, 258, 299, 259, 261, 65, 298, 296, + 260, 64, 262, 292, 263, 265, 63, 291, + 289, 264, 62, 275, 268, 170, 271, 37, + 274, 38, 277, 41, 59, 280, 44, 56, + 283, 47, 53, 286, 50, 288, 293, 295, + 300, 302, 307, 309, 314, 316, 170, 321, + 106, 323, 386, 72, 324, 326, 105, 385, + 383, 325, 104, 327, 379, 328, 330, 103, + 378, 376, 329, 102, 331, 372, 332, 334, + 101, 371, 369, 333, 100, 335, 365, 336, + 338, 99, 364, 362, 337, 98, 348, 341, + 170, 344, 73, 347, 74, 350, 77, 95, + 353, 80, 92, 356, 83, 89, 359, 86, + 361, 366, 368, 373, 375, 380, 382, 387, + 389, 170, 170, 395, 397, 142, 141, 415, + 417, 465, 396, 398, 461, 107, 399, 401, + 140, 460, 458, 400, 139, 402, 454, 403, + 405, 138, 453, 451, 404, 137, 406, 447, + 407, 409, 136, 446, 444, 408, 135, 410, + 440, 411, 413, 134, 439, 437, 412, 133, + 423, 416, 170, 419, 108, 422, 109, 425, + 112, 130, 428, 115, 127, 431, 118, 124, + 434, 121, 436, 441, 443, 448, 450, 455, + 457, 462, 464, 143, 469, 470, 480, 475, + 477, 498, 471, 472, 473, 144, 479, 474, + 476, 145, 482, 147, 167, 156, 485, 150, + 164, 488, 153, 161, 491, 158, 494, 157, + 497 }; static const char _indic_syllable_machine_trans_actions[] = { @@ -900,44 +992,51 @@ static const char _indic_syllable_machine_trans_actions[] = { 2, 0, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 10, 2, 2, 6, 2, 11, 11, 0, - 0, 2, 6, 2, 0, 2, 12, 2, - 2, 0, 2, 0, 0, 2, 2, 2, - 0, 2, 2, 0, 2, 2, 0, 2, - 2, 2, 0, 2, 2, 2, 2, 0, - 2, 2, 2, 0, 2, 2, 2, 2, - 0, 2, 2, 2, 0, 2, 2, 2, - 2, 0, 2, 2, 2, 0, 2, 0, - 13, 0, 0, 2, 0, 2, 0, 0, + 6, 8, 0, 2, 0, 2, 0, 0, + 2, 0, 0, 2, 0, 2, 0, 0, + 0, 0, 2, 0, 0, 2, 0, 0, + 2, 0, 0, 2, 11, 2, 2, 6, + 2, 12, 12, 0, 0, 2, 2, 6, + 2, 13, 2, 2, 0, 2, 0, 0, + 2, 2, 2, 0, 2, 2, 0, 2, + 2, 0, 2, 2, 2, 0, 2, 2, + 2, 2, 0, 2, 2, 2, 0, 2, + 2, 2, 2, 0, 2, 2, 2, 0, + 2, 2, 2, 2, 0, 2, 2, 2, + 0, 2, 0, 14, 0, 0, 2, 0, + 2, 0, 0, 2, 0, 0, 2, 0, + 0, 2, 0, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 15, 2, 2, 0, + 2, 0, 0, 2, 2, 0, 2, 2, + 0, 2, 2, 0, 2, 2, 2, 0, + 2, 2, 2, 2, 0, 2, 2, 2, + 0, 2, 2, 2, 2, 0, 2, 2, + 2, 0, 2, 2, 2, 2, 0, 2, + 2, 2, 0, 2, 0, 16, 0, 0, + 2, 0, 2, 0, 0, 2, 0, 0, + 2, 0, 0, 2, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 17, 6, + 0, 6, 6, 0, 6, 2, 0, 6, + 2, 6, 0, 6, 6, 6, 2, 0, + 6, 2, 6, 0, 6, 6, 6, 2, + 0, 6, 2, 6, 0, 6, 6, 6, + 2, 0, 6, 2, 6, 0, 6, 0, + 18, 0, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 14, 2, 2, 0, 2, 0, 0, - 2, 2, 0, 2, 2, 0, 2, 2, + 2, 19, 20, 2, 2, 0, 0, 0, + 0, 2, 2, 2, 2, 0, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 0, - 2, 0, 15, 0, 0, 2, 0, 2, + 2, 0, 21, 0, 0, 2, 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 16, 6, 0, 6, 6, - 0, 6, 2, 0, 6, 2, 6, 0, - 6, 6, 6, 2, 0, 6, 2, 6, - 0, 6, 6, 6, 2, 0, 6, 2, - 6, 0, 6, 6, 6, 2, 0, 6, - 2, 6, 0, 6, 0, 17, 0, 0, - 2, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 0, 2, 0, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 18, 19, - 2, 2, 0, 0, 0, 0, 2, 2, - 2, 2, 0, 2, 2, 0, 2, 2, - 2, 0, 2, 2, 2, 2, 0, 2, - 2, 2, 0, 2, 2, 2, 2, 0, - 2, 2, 2, 0, 2, 2, 2, 2, - 0, 2, 2, 2, 0, 2, 0, 20, - 0, 0, 2, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 0, 0, 8, 2, 0, + 0, 2, 2, 8, 8, 0, 8, 8, + 0, 0, 2, 0, 0, 0, 2, 0, + 0, 2, 0, 0, 2, 0, 0, 0, 2 }; @@ -959,7 +1058,14 @@ static const char _indic_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1018,7 +1124,14 @@ static const char _indic_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1073,63 +1186,70 @@ static const short _indic_syllable_machine_eof_trans[] = { 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 115, 115, 115, 115, 115, + 83, 77, 77, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, - 115, 115, 115, 115, 115, 115, 115, 0, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 242, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 316, 316, 316, 316, - 316, 316, 316, 316, 383, 316, 383, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, - 383, 167, 167 + 115, 115, 115, 115, 115, 115, 115, 77, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 269, 269, 269, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 343, + 343, 343, 343, 343, 343, 343, 343, 410, + 343, 410, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 411, 411, 411, 411, 411, + 411, 411, 411, 343, 194, 194, 194, 343, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 343 }; -static const int indic_syllable_machine_start = 143; -static const int indic_syllable_machine_first_final = 143; +static const int indic_syllable_machine_start = 170; +static const int indic_syllable_machine_first_final = 170; static const int indic_syllable_machine_error = -1; -static const int indic_syllable_machine_en_main = 143; +static const int indic_syllable_machine_en_main = 170; #line 36 "../../src/hb-ot-shape-complex-indic-machine.rl" -#line 90 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 91 "../../src/hb-ot-shape-complex-indic-machine.rl" #define found_syllable(syllable_type) \ @@ -1145,11 +1265,11 @@ static const int indic_syllable_machine_en_main = 143; static void find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof, ts, te, act; + unsigned int p, pe, eof, ts HB_UNUSED, te, act; int cs; hb_glyph_info_t *info = buffer->info; -#line 1153 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" +#line 1273 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" { cs = indic_syllable_machine_start; ts = 0; @@ -1157,7 +1277,7 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 111 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 112 "../../src/hb-ot-shape-complex-indic-machine.rl" p = 0; @@ -1166,7 +1286,7 @@ find_syllables (hb_buffer_t *buffer) unsigned int last = 0; unsigned int syllable_serial = 1; -#line 1170 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" +#line 1290 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" { int _slen; int _trans; @@ -1176,11 +1296,11 @@ find_syllables (hb_buffer_t *buffer) goto _test_eof; _resume: switch ( _indic_syllable_machine_from_state_actions[cs] ) { - case 9: -#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 10: +#line 1 "NONE" {ts = p;} break; -#line 1184 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" +#line 1304 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -1199,68 +1319,71 @@ _eof_trans: switch ( _indic_syllable_machine_trans_actions[_trans] ) { case 2: -#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 1 "NONE" {te = p+1;} break; - case 13: -#line 82 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 14: +#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p+1;{ found_syllable (consonant_syllable); }} break; - case 15: -#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 16: +#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p+1;{ found_syllable (vowel_syllable); }} break; - case 20: -#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 21: +#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p+1;{ found_syllable (standalone_cluster); }} break; - case 17: -#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 18: +#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p+1;{ found_syllable (broken_cluster); }} break; - case 10: -#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 11: +#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p+1;{ found_syllable (non_indic_cluster); }} break; - case 12: -#line 82 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 13: +#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (consonant_syllable); }} break; - case 14: -#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 15: +#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (vowel_syllable); }} break; - case 19: -#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 20: +#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (standalone_cluster); }} break; - case 16: -#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 17: +#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; - case 18: -#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 19: +#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (non_indic_cluster); }} break; case 1: -#line 82 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (consonant_syllable); }} break; case 3: -#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (vowel_syllable); }} break; case 7: -#line 84 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (standalone_cluster); }} break; case 4: -#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (broken_cluster); }} break; case 5: -#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 1 "NONE" { switch( act ) { + case 1: + {{p = ((te))-1;} found_syllable (consonant_syllable); } + break; case 4: {{p = ((te))-1;} found_syllable (broken_cluster); } break; @@ -1270,28 +1393,34 @@ _eof_trans: } } break; + case 8: +#line 1 "NONE" + {te = p+1;} +#line 83 "../../src/hb-ot-shape-complex-indic-machine.rl" + {act = 1;} + break; case 6: -#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 1 "NONE" {te = p+1;} -#line 85 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl" {act = 4;} break; - case 11: -#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 12: +#line 1 "NONE" {te = p+1;} -#line 86 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 87 "../../src/hb-ot-shape-complex-indic-machine.rl" {act = 5;} break; -#line 1286 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" +#line 1415 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" } _again: switch ( _indic_syllable_machine_to_state_actions[cs] ) { - case 8: -#line 1 "../../src/hb-ot-shape-complex-indic-machine.rl" + case 9: +#line 1 "NONE" {ts = 0;} break; -#line 1295 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" +#line 1424 "../../src/hb-ot-shape-complex-indic-machine.hh.tmp" } if ( ++p != pe ) @@ -1307,7 +1436,7 @@ _again: } -#line 120 "../../src/hb-ot-shape-complex-indic-machine.rl" +#line 121 "../../src/hb-ot-shape-complex-indic-machine.rl" } diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.rl b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.rl index 53dc20d..11115c9 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.rl +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-machine.rl @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright © 2011,2012 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -29,8 +29,6 @@ #include "hb-private.hh" -HB_BEGIN_DECLS - %%{ machine indic_syllable_machine; alphtype unsigned char; @@ -42,78 +40,85 @@ HB_BEGIN_DECLS # Same order as enum indic_category_t. Not sure how to avoid duplication. X = 0; C = 1; -Ra = 2; -V = 3; -N = 4; -H = 5; -ZWNJ = 6; -ZWJ = 7; -M = 8; -SM = 9; -VD = 10; -A = 11; -NBSP = 12; - -c = C | Ra; -z = ZWJ|ZWNJ; -matra_group = M N? H?; -syllable_tail = SM? (VD VD?)?; - -action found_consonant_syllable { found_consonant_syllable (map, buffer, mask_array, last, p); } -action found_vowel_syllable { found_vowel_syllable (map, buffer, mask_array, last, p); } -action found_standalone_cluster { found_standalone_cluster (map, buffer, mask_array, last, p); } -action found_non_indic { found_non_indic (map, buffer, mask_array, last, p); } - -action next_syllable { set_cluster (buffer, p, last); last = p; } - -consonant_syllable = (c.N? (z.H|H.z?))* c.N? A? (H.z? | matra_group*)? syllable_tail %(found_consonant_syllable); -vowel_syllable = (Ra H)? V N? (z.H.c | ZWJ.c)? matra_group* syllable_tail %(found_vowel_syllable); -standalone_cluster = (Ra H)? NBSP N? (z? H c)? matra_group* syllable_tail %(found_standalone_cluster); -non_indic = X %(found_non_indic); - -syllable = - consonant_syllable - | vowel_syllable - | standalone_cluster - | non_indic - ; - -main := (syllable %(next_syllable))**; - -}%% +V = 2; +N = 3; +H = 4; +ZWNJ = 5; +ZWJ = 6; +M = 7; +SM = 8; +VD = 9; +A = 10; +NBSP = 11; +DOTTEDCIRCLE = 12; +RS = 13; +Coeng = 14; +Repha = 15; +Ra = 16; +CM = 17; + +c = (C | Ra)CM*; # is_consonant +n = ((ZWNJ?.RS)? (N.N?)?); # is_consonant_modifier +z = ZWJ|ZWNJ; # is_joiner +h = H | Coeng; # is_halant_or_coeng +reph = (Ra H | Repha); # possible reph + +cn = c.ZWJ?.n?; +forced_rakar = ZWJ H ZWJ Ra; +matra_group = z{0,3}.M.N?.(H | forced_rakar)?; +syllable_tail = (Coeng (cn|V))? (SM.ZWNJ?)? (VD VD?)?; +place_holder = NBSP | DOTTEDCIRCLE; +halant_group = (z?.h.(ZWJ.N?)?); +final_halant_group = halant_group | h.ZWNJ; +halant_or_matra_group = (final_halant_group | (h.ZWJ)? matra_group{0,4}); + + +consonant_syllable = Repha? (cn.halant_group){0,4} cn A? halant_or_matra_group? syllable_tail; +vowel_syllable = reph? V.n? (ZWJ | (halant_group.cn){0,4} halant_or_matra_group? syllable_tail); +standalone_cluster = reph? place_holder.n? (halant_group.cn){0,4} halant_or_matra_group? syllable_tail; +broken_cluster = reph? n? (halant_group.cn){0,4} halant_or_matra_group syllable_tail; +other = any; + +main := |* + consonant_syllable => { found_syllable (consonant_syllable); }; + vowel_syllable => { found_syllable (vowel_syllable); }; + standalone_cluster => { found_syllable (standalone_cluster); }; + broken_cluster => { found_syllable (broken_cluster); }; + other => { found_syllable (non_indic_cluster); }; +*|; -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 found_syllable(syllable_type) \ + HB_STMT_START { \ + if (0) fprintf (stderr, "syllable %d..%d %s\n", last, p+1, #syllable_type); \ + for (unsigned int i = last; i < p+1; i++) \ + info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + last = p+1; \ + syllable_serial++; \ + if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ + } HB_STMT_END static void -find_syllables (const hb_ot_map_t *map, hb_buffer_t *buffer, hb_mask_t *mask_array) +find_syllables (hb_buffer_t *buffer) { - unsigned int p, pe, eof; + unsigned int p, pe, eof, ts HB_UNUSED, te, act; int cs; + hb_glyph_info_t *info = buffer->info; %%{ write init; - getkey buffer->info[p].indic_category(); + getkey info[p].indic_category(); }%% p = 0; pe = eof = buffer->len; unsigned int last = 0; + unsigned int syllable_serial = 1; %%{ write exec; }%% } -HB_END_DECLS - #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */ diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic-private.hh index 91b0be5..e36090e 100644 --- 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 @@ -39,7 +39,7 @@ #define indic_position() complex_var_u8_1() /* indic_matra_category_t */ -#define INDIC_TABLE_ELEMENT_TYPE uint8_t +#define INDIC_TABLE_ELEMENT_TYPE uint16_t /* Cateories used in the OpenType spec: * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx @@ -63,7 +63,8 @@ enum indic_category_t { OT_RS, /* Register Shifter, used in Khmer OT spec */ OT_Coeng, OT_Repha, - OT_Ra /* Not explicitly listed in the OT spec, but used in the grammar. */ + OT_Ra, /* Not explicitly listed in the OT spec, but used in the grammar. */ + OT_CM }; /* Visual positions in a syllable from left to right. */ @@ -103,7 +104,7 @@ enum indic_syllabic_category_t { 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_MEDIAL = OT_CM, INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER = OT_NBSP, INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED = OT_C, INDIC_SYLLABIC_CATEGORY_CONSONANT_REPHA = OT_Repha, @@ -111,7 +112,7 @@ enum indic_syllabic_category_t { INDIC_SYLLABIC_CATEGORY_NUKTA = OT_N, INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER = OT_RS, INDIC_SYLLABIC_CATEGORY_TONE_LETTER = OT_X, - INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_X, + INDIC_SYLLABIC_CATEGORY_TONE_MARK = OT_N, INDIC_SYLLABIC_CATEGORY_VIRAMA = OT_H, INDIC_SYLLABIC_CATEGORY_VISARGA = OT_SM, INDIC_SYLLABIC_CATEGORY_VOWEL = OT_V, @@ -138,16 +139,16 @@ enum indic_matra_category_t { 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 + INDIC_MATRA_CATEGORY_OVERSTRUCK = POS_AFTER_MAIN, + INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT = POS_PRE_M }; /* 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)) + ASSERT_STATIC_EXPR_ZERO (S < 255 && M < 255) + \ + ((M << 8) | S)) #include "hb-ot-shape-complex-indic-table.hh" @@ -221,7 +222,7 @@ matra_position (hb_codepoint_t u, indic_position_t side) case POS_ABOVE_C: return MATRA_POS_TOP (u); case POS_BELOW_C: return MATRA_POS_BOTTOM (u); }; - abort (); + return side; } @@ -285,7 +286,7 @@ is_joiner (const hb_glyph_info_t &info) * 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! */ -#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)) +#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CM) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_NBSP) | FLAG (OT_DOTTEDCIRCLE)) static inline bool is_consonant (const hb_glyph_info_t &info) { @@ -304,8 +305,8 @@ set_indic_properties (hb_glyph_info_t &info) { hb_codepoint_t u = info.codepoint; unsigned int type = get_indic_categories (u); - indic_category_t cat = (indic_category_t) (type & 0x0F); - indic_position_t pos = (indic_position_t) (type >> 4); + indic_category_t cat = (indic_category_t) (type & 0x7F); + indic_position_t pos = (indic_position_t) (type >> 8); /* 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 5b4b344..70765b6 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 @@ -6,12 +6,12 @@ * * on files with these headers: * - * # 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] + * # IndicSyllabicCategory-6.2.0.txt + * # Date: 2012-05-15, 21:12:00 GMT [KW] + * # IndicMatraCategory-6.2.0.txt + * # Date: 2012-05-15, 21:10:00 GMT [KW] + * # Blocks-6.2.0.txt + * # Date: 2012-05-14, 22:42:00 GMT [KW, LI] */ #ifndef 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 30a9a1f..1bc8a77 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 @@ -123,6 +123,8 @@ static const indic_config_t indic_configs[] = {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA}, {HB_SCRIPT_SINHALA, false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT}, {HB_SCRIPT_KHMER, false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT, REPH_MODE_VIS_REPHA}, + /* Myanmar does not have the "old_indic" behavior, even though it has a "new" tag. */ + {HB_SCRIPT_MYANMAR, false,0x1039,BASE_POS_LAST, REPH_POS_DEFAULT, REPH_MODE_EXPLICIT}, }; @@ -247,6 +249,8 @@ override_features_indic (hb_ot_shape_planner_t *plan) /* Uniscribe does not apply 'kern'. */ if (indic_options ().uniscribe_bug_compatible) plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true); + + plan->map.add_feature (HB_TAG('l','i','g','a'), 0, true); } @@ -265,7 +269,7 @@ struct would_substitute_feature_t hb_face_t *face) const { for (unsigned int i = 0; i < count; i++) - if (hb_ot_layout_would_substitute_lookup_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) + if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) return true; return false; } @@ -303,6 +307,7 @@ struct indic_shape_plan_t bool is_old_spec; hb_codepoint_t virama_glyph; + would_substitute_feature_t rphf; would_substitute_feature_t pref; would_substitute_feature_t blwf; would_substitute_feature_t pstf; @@ -324,9 +329,10 @@ data_create_indic (const hb_ot_shape_plan_t *plan) break; } - indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2'); + indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FF) != '2'); indic_plan->virama_glyph = (hb_codepoint_t) -1; + indic_plan->rphf.init (&plan->map, HB_TAG('r','p','h','f')); indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f')); indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f')); indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f')); @@ -428,7 +434,9 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan, * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */ static void -initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, +initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, + hb_face_t *face, + hb_buffer_t *buffer, unsigned int start, unsigned int end) { const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; @@ -459,22 +467,36 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer unsigned int limit = start; if (indic_plan->mask_array[RPHF] && start + 3 <= end && - info[start].indic_category() == OT_Ra && - info[start + 1].indic_category() == OT_H && - (/* TODO Handle other Reph modes. */ + ( (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ) )) { - limit += 2; - while (limit < end && is_joiner (info[limit])) - limit++; - base = start; - has_reph = true; - }; + /* See if it matches the 'rphf' feature. */ + hb_codepoint_t glyphs[2] = {info[start].codepoint, info[start + 1].codepoint}; + if (indic_plan->rphf.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) + { + limit += 2; + while (limit < end && is_joiner (info[limit])) + limit++; + base = start; + has_reph = true; + } + } else if (indic_plan->config->reph_mode == REPH_MODE_LOG_REPHA && info[start].indic_category() == OT_Repha) + { + limit += 1; + while (limit < end && is_joiner (info[limit])) + limit++; + base = start; + has_reph = true; + } switch (indic_plan->config->base_pos) { + default: + assert (false); + /* fallthrough */ + case BASE_POS_LAST: { /* -> starting from the end of the syllable, move backwards */ @@ -514,7 +536,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer * half form. * A ZWJ before a Halant, requests a subjoined form instead, and hence * search continues. This is particularly important for Bengali - * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */ + * sequence Ra,H,Ya that should form Ya-Phalaa by subjoining Ya. */ if (start < i && info[i].indic_category() == OT_ZWJ && info[i - 1].indic_category() == OT_H) @@ -548,9 +570,6 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer info[i].indic_position() = POS_BELOW_C; } break; - - default: - abort (); } /* -> If the syllable starts with Ra + Halant (in a script that has Reph) @@ -558,7 +577,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer * base consonants. * * Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */ - if (has_reph && base == start && start + 2 == limit) { + if (has_reph && base == start && start - limit <= 2) { /* Have no other consonant, so Reph is not formed and Ra becomes base. */ has_reph = false; } @@ -651,13 +670,17 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS))) { info[i].indic_position() = last_pos; - if (unlikely (indic_options ().uniscribe_bug_compatible && - info[i].indic_category() == OT_H && + if (unlikely (info[i].indic_category() == OT_H && info[i].indic_position() == POS_PRE_M)) { /* * Uniscribe doesn't move the Halant with Left Matra. * TEST: U+092B,U+093F,U+094DE + * We follow. This is important for the Sinhala + * U+0DDA split matra since it decomposes to U+0DD9,U+0DCA + * where U+0DD9 is a left matra and U+0DCA is the virama. + * We don't want to move the virama with the left matra. + * TEST: U+0D9A,U+0DDA */ for (unsigned int j = i; j > start; j--) if (info[j - 1].indic_position() != POS_PRE_M) { @@ -725,9 +748,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer if (indic_plan->mask_array[PREF] && base + 2 < end) { /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */ - for (unsigned int i = base + 1; i + 1 < end; i++) - if (is_halant_or_coeng (info[i + (indic_plan->is_old_spec ? 1 : 0)]) && - info[i + (indic_plan->is_old_spec ? 0 : 1)].indic_category() == OT_Ra) + for (unsigned int i = base + 1; i + 1 < end; i++) { + hb_codepoint_t glyphs[2] = {info[i].codepoint, info[i + 1].codepoint}; + if (indic_plan->pref.would_substitute (glyphs, ARRAY_LENGTH (glyphs), true, face)) { info[i++].mask |= indic_plan->mask_array[PREF]; info[i++].mask |= indic_plan->mask_array[PREF]; @@ -743,6 +766,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer break; } + } } /* Apply ZWJ/ZWNJ effects */ @@ -768,15 +792,17 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer static void initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan, + hb_face_t *face, hb_buffer_t *buffer, unsigned int start, unsigned int end) { /* We made the vowels look like consonants. So let's call the consonant logic! */ - initial_reordering_consonant_syllable (plan, buffer, start, end); + initial_reordering_consonant_syllable (plan, face, buffer, start, end); } static void initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, + hb_face_t *face, hb_buffer_t *buffer, unsigned int start, unsigned int end) { @@ -792,20 +818,22 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, return; } - initial_reordering_consonant_syllable (plan, buffer, start, end); + initial_reordering_consonant_syllable (plan, face, buffer, start, end); } static void initial_reordering_broken_cluster (const hb_ot_shape_plan_t *plan, + hb_face_t *face, hb_buffer_t *buffer, unsigned int start, unsigned int end) { /* We already inserted dotted-circles, so just call the standalone_cluster. */ - initial_reordering_standalone_cluster (plan, buffer, start, end); + initial_reordering_standalone_cluster (plan, face, buffer, start, end); } static void initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_face_t *face HB_UNUSED, hb_buffer_t *buffer HB_UNUSED, unsigned int start HB_UNUSED, unsigned int end HB_UNUSED) { @@ -816,21 +844,22 @@ initial_reordering_non_indic_cluster (const hb_ot_shape_plan_t *plan HB_UNUSED, static void initial_reordering_syllable (const hb_ot_shape_plan_t *plan, + hb_face_t *face, hb_buffer_t *buffer, unsigned int start, unsigned int end) { syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { - case consonant_syllable: initial_reordering_consonant_syllable (plan, buffer, start, end); return; - case vowel_syllable: initial_reordering_vowel_syllable (plan, buffer, start, end); return; - case standalone_cluster: initial_reordering_standalone_cluster (plan, buffer, start, end); return; - case broken_cluster: initial_reordering_broken_cluster (plan, buffer, start, end); return; - case non_indic_cluster: initial_reordering_non_indic_cluster (plan, buffer, start, end); return; + case consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); return; + case vowel_syllable: initial_reordering_vowel_syllable (plan, face, buffer, start, end); return; + case standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); return; + case broken_cluster: initial_reordering_broken_cluster (plan, face, buffer, start, end); return; + case non_indic_cluster: initial_reordering_non_indic_cluster (plan, face, buffer, start, end); return; } } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan, +insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font, hb_buffer_t *buffer) { @@ -850,7 +879,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan, if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph)) return; - hb_glyph_info_t dottedcircle; + hb_glyph_info_t dottedcircle = {0}; dottedcircle.codepoint = 0x25CC; set_indic_properties (dottedcircle); dottedcircle.codepoint = dottedcircle_glyph; @@ -865,14 +894,23 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan, syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) { + last_syllable = syllable; + hb_glyph_info_t info = dottedcircle; info.cluster = buffer->cur().cluster; info.mask = buffer->cur().mask; info.syllable() = buffer->cur().syllable(); + + /* Insert dottedcircle after possible Repha. */ + while (buffer->idx < buffer->len && + last_syllable == buffer->cur().syllable() && + buffer->cur().indic_category() == OT_Repha) + buffer->next_glyph (); + buffer->output_info (info); - last_syllable = syllable; } - buffer->next_glyph (); + else + buffer->next_glyph (); } buffer->swap_buffers (); @@ -893,11 +931,11 @@ initial_reordering (const hb_ot_shape_plan_t *plan, unsigned int last_syllable = info[0].syllable(); for (unsigned int i = 1; i < count; i++) if (last_syllable != info[i].syllable()) { - initial_reordering_syllable (plan, buffer, last, i); + initial_reordering_syllable (plan, font->face, buffer, last, i); last = i; last_syllable = info[last].syllable(); } - initial_reordering_syllable (plan, buffer, last, count); + initial_reordering_syllable (plan, font->face, buffer, last, count); } static void @@ -1224,7 +1262,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, static void final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, + hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { unsigned int count = buffer->len; @@ -1251,11 +1289,113 @@ final_reordering (const hb_ot_shape_plan_t *plan, static hb_ot_shape_normalization_mode_t -normalization_preference_indic (const hb_ot_shape_plan_t *plan) +normalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED) { return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; } +static bool +decompose_indic (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b) +{ + switch (ab) + { + /* Don't decompose these. */ + case 0x0931 : return false; + case 0x0B94 : return false; + + + /* + * Decompose split matras that don't have Unicode decompositions. + */ + + case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; + case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; + case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; + case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; + case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; + case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; + case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; + case 0x1925 : *a = 0x1920; *b= 0x1923; return true; + case 0x1926 : *a = 0x1920; *b= 0x1924; return true; + case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; + case 0x1112E : *a = 0x11127; *b= 0x11131; return true; + case 0x1112F : *a = 0x11127; *b= 0x11132; return true; +#if 0 + /* This one has no decomposition in Unicode, but needs no decomposition either. */ + /* case 0x0AC9 : return false; */ + case 0x0B57 : *a = no decomp, -> RIGHT; return true; + case 0x1C29 : *a = no decomp, -> LEFT; return true; + case 0xA9C0 : *a = no decomp, -> RIGHT; return true; + case 0x111BF : *a = no decomp, -> ABOVE; return true; +#endif + } + + if ((ab == 0x0DDA || hb_in_range<hb_codepoint_t> (ab, 0x0DDC, 0x0DDE))) + { + /* + * Sinhala split matras... Let the fun begin. + * + * These four characters have Unicode decompositions. However, Uniscribe + * decomposes them "Khmer-style", that is, it uses the character itself to + * get the second half. The first half of all four decompositions is always + * U+0DD9. + * + * Now, there are buggy fonts, namely, the widely used lklug.ttf, that are + * broken with Uniscribe. But we need to support them. As such, we only + * do the Uniscribe-style decomposition if the character is transformed into + * its "sec.half" form by the 'pstf' feature. Otherwise, we fall back to + * Unicode decomposition. + * + * Note that we can't unconditionally use Unicode decomposition. That would + * break some other fonts, that are designed to work with Uniscribe, and + * don't have positioning features for the Unicode-style decomposition. + * + * Argh... + * + * The Uniscribe behavior is now documented in the newly published Sinhala + * spec in 2012: + * + * http://www.microsoft.com/typography/OpenTypeDev/sinhala/intro.htm#shaping + */ + + const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; + + hb_codepoint_t glyph; + + if (indic_options ().uniscribe_bug_compatible || + (c->font->get_glyph (ab, 0, &glyph) && + indic_plan->pstf.would_substitute (&glyph, 1, true, c->font->face))) + { + /* Ok, safe to use Uniscribe-style decomposition. */ + *a = 0x0DD9; + *b = ab; + return true; + } + } + + return c->unicode->decompose (ab, a, b); +} + +static bool +compose_indic (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab) +{ + /* Avoid recomposing split matras. */ + if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (c->unicode->general_category (a))) + return false; + + /* Composition-exclusion exceptions that we want to recompose. */ + if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } + + return c->unicode->compose (a, b, ab); +} + + const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = { "indic", @@ -1265,6 +1405,9 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = data_destroy_indic, NULL, /* preprocess_text */ normalization_preference_indic, + decompose_indic, + compose_indic, setup_masks_indic, false, /* zero_width_attached_marks */ + false, /* fallback_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 deleted file mode 100644 index 13bc22b..0000000 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-misc.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright © 2010,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-private.hh" - - -/* TODO Add kana, and other small shapers here */ - - -/* The default shaper *only* adds additional per-script features.*/ - -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'), - HB_TAG_NONE -}; - -static const hb_tag_t tibetan_features[] = -{ - HB_TAG('a','b','v','s'), - HB_TAG('b','l','w','s'), - HB_TAG('a','b','v','m'), - HB_TAG('b','l','w','m'), - HB_TAG_NONE -}; - -static void -collect_features_default (hb_ot_shape_planner_t *plan) -{ - const hb_tag_t *script_features = NULL; - - switch ((hb_tag_t) plan->props.script) - { - /* Unicode-1.1 additions */ - case HB_SCRIPT_HANGUL: - script_features = hangul_features; - break; - - /* Unicode-2.0 additions */ - case HB_SCRIPT_TIBETAN: - script_features = tibetan_features; - break; - } - - for (; script_features && *script_features; script_features++) - plan->map.add_bool_feature (*script_features); -} - -static hb_ot_shape_normalization_mode_t -normalization_preference_default (const hb_ot_shape_plan_t *plan) -{ - switch ((hb_tag_t) plan->props.script) - { - /* Unicode-1.1 additions */ - case HB_SCRIPT_HANGUL: - return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_FULL; - } - return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS; -} - -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = -{ - "default", - collect_features_default, - NULL, /* override_features */ - NULL, /* data_create */ - NULL, /* data_destroy */ - NULL, /* preprocess_text */ - normalization_preference_default, - NULL, /* setup_masks */ - true, /* zero_width_attached_marks */ -}; - - -/* Thai / Lao shaper */ - -static void -preprocess_text_thai (const hb_ot_shape_plan_t *plan 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 AA, *and* move the - * NIKHAHIT 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 user wanted, but the rendering is nevertheless nikhahit above - * chattawa. - * - * Same for Lao. - * - * Note: - * - * Uniscribe also does so below-marks reordering. Namely, it positions U+0E3A - * after U+0E38 and U+0E39. We do that by modifying the ccc for U+0E3A. - * See unicode->modified_combining_class (). Lao does NOT have a U+0E3A - * equivalent. - */ - - - /* - * 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 - * - * Testing shows that Uniscribe reorder the following marks: - * Thai: <0E31,0E34..0E37,0E47..0E4E> - * Lao: <0EB1,0EB4..0EB7,0EC7..0ECE> - * - * 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) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31)) - - 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--; - - if (start + 2 < end) - { - /* Move Nikhahit (end-2) to the beginning */ - buffer->merge_out_clusters (start, end); - 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; - } - else - { - /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the - * previous cluster. */ - if (start) - buffer->merge_out_clusters (start - 1, end); - } - } - buffer->swap_buffers (); -} - -const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = -{ - "thai", - NULL, /* collect_features */ - NULL, /* override_features */ - NULL, /* data_create */ - NULL, /* data_destroy */ - preprocess_text_thai, - NULL, /* normalization_preference */ - NULL, /* setup_masks */ - true, /* zero_width_attached_marks */ -}; 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 e84c490..26871c2 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 @@ -56,6 +56,7 @@ struct hb_ot_complex_shaper_t /* collect_features() * Called during shape_plan(). * Shapers should use plan->map to add their features and callbacks. + * May be NULL. */ void (*collect_features) (hb_ot_shape_planner_t *plan); @@ -63,6 +64,7 @@ struct hb_ot_complex_shaper_t * Called during shape_plan(). * Shapers should use plan->map to override features and add callbacks after * common features are added. + * May be NULL. */ void (*override_features) (hb_ot_shape_planner_t *plan); @@ -78,13 +80,15 @@ struct hb_ot_complex_shaper_t * Called when the shape_plan is being destroyed. * plan->data is passed here for destruction. * If NULL is returned, means a plan failure. - * May be NULL. */ + * May be NULL. + */ void (*data_destroy) (void *data); /* preprocess_text() * Called during shape(). * Shapers can use to modify text before shaping starts. + * May be NULL. */ void (*preprocess_text) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -93,20 +97,41 @@ struct hb_ot_complex_shaper_t /* normalization_preference() * Called during shape(). + * May be NULL. */ hb_ot_shape_normalization_mode_t - (*normalization_preference) (const hb_ot_shape_plan_t *plan); + (*normalization_preference) (const hb_segment_properties_t *props); + + /* decompose() + * Called during shape()'s normalization. + * May be NULL. + */ + bool (*decompose) (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b); + + /* compose() + * Called during shape()'s normalization. + * May be NULL. + */ + bool (*compose) (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab); /* setup_masks() * Called during shape(). * Shapers should use map to get feature masks and set on buffer. * Shapers may NOT modify characters. + * May be NULL. */ void (*setup_masks) (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, hb_font_t *font); bool zero_width_attached_marks; + bool fallback_position; }; #define HB_COMPLEX_SHAPER_IMPLEMENT(name) extern HB_INTERNAL const hb_ot_complex_shaper_t _hb_ot_complex_shaper_##name; @@ -115,9 +140,9 @@ HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS static inline const hb_ot_complex_shaper_t * -hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) +hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) { - switch ((hb_tag_t) props->script) + switch ((hb_tag_t) planner->props.script) { default: return &_hb_ot_complex_shaper_default; @@ -130,11 +155,18 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) /* Unicode-5.0 additions */ case HB_SCRIPT_NKO: + case HB_SCRIPT_PHAGS_PA: /* Unicode-6.0 additions */ case HB_SCRIPT_MANDAIC: - return &_hb_ot_complex_shaper_arabic; + /* For Arabic script, use the Arabic shaper even if no OT script tag was found. + * This is because we do fallback shaping for Arabic script (and not others). */ + if (planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT || + planner->props.script == HB_SCRIPT_ARABIC) + return &_hb_ot_complex_shaper_arabic; + else + return &_hb_ot_complex_shaper_default; /* Unicode-1.1 additions */ @@ -170,9 +202,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) /* 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: @@ -197,11 +226,9 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) case HB_SCRIPT_TAI_LE: /* Unicode-4.1 additions */ + case HB_SCRIPT_KHAROSHTHI: case HB_SCRIPT_SYLOTI_NAGRI: - /* Unicode-5.0 additions */ - case HB_SCRIPT_PHAGS_PA: - /* Unicode-5.1 additions */ case HB_SCRIPT_KAYAH_LI: @@ -209,12 +236,6 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) case HB_SCRIPT_TAI_VIET: - /* May need Indic treatment in the future? */ - - /* Unicode-3.0 additions */ - case HB_SCRIPT_MYANMAR: - - #endif /* Unicode-1.1 additions */ @@ -229,12 +250,10 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) 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 */ @@ -249,14 +268,44 @@ hb_ot_shape_complex_categorize (const hb_segment_properties_t *props) /* Unicode-5.2 additions */ case HB_SCRIPT_JAVANESE: case HB_SCRIPT_KAITHI: + case HB_SCRIPT_MEETEI_MAYEK: case HB_SCRIPT_TAI_THAM: + /* Unicode-6.1 additions */ case HB_SCRIPT_CHAKMA: case HB_SCRIPT_SHARADA: case HB_SCRIPT_TAKRI: - return &_hb_ot_complex_shaper_indic; + /* Only use Indic shaper if the font has Indic tables. */ + if (planner->map.found_script[0]) + return &_hb_ot_complex_shaper_indic; + else + return &_hb_ot_complex_shaper_default; + + case HB_SCRIPT_KHMER: + /* A number of Khmer fonts in the wild don't have a 'pref' feature, + * and as such won't shape properly via the Indic shaper; + * however, they typically have 'liga' / 'clig' features that implement + * the necessary "reordering" by means of ligature substitutions. + * So we send such pref-less fonts through the generic shaper instead. */ + if (planner->map.found_script[0] && + hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB, + planner->map.script_index[0], + planner->map.language_index[0], + HB_TAG ('p','r','e','f'), + NULL)) + return &_hb_ot_complex_shaper_indic; + else + return &_hb_ot_complex_shaper_default; + + case HB_SCRIPT_MYANMAR: + /* For Myanmar, we only want to use the Indic shaper if the "new" script + * tag is found. For "old" script tag we want to use the default shaper. */ + if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2')) + return &_hb_ot_complex_shaper_indic; + else + return &_hb_ot_complex_shaper_default; } } diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc new file mode 100644 index 0000000..24d476a --- /dev/null +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc @@ -0,0 +1,378 @@ +/* + * Copyright © 2010,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-private.hh" + + +/* Thai / Lao shaper */ + + +/* PUA shaping */ + + +enum thai_consonant_type_t +{ + NC, + AC, + RC, + DC, + NOT_CONSONANT, + NUM_CONSONANT_TYPES = NOT_CONSONANT +}; + +static thai_consonant_type_t +get_consonant_type (hb_codepoint_t u) +{ + if (u == 0x0E1B || u == 0x0E1D || u == 0x0E1F/* || u == 0x0E2C*/) + return AC; + if (u == 0x0E0D || u == 0x0E10) + return RC; + if (u == 0x0E0E || u == 0x0E0F) + return DC; + if (hb_in_range<hb_codepoint_t> (u, 0x0E01, 0x0E2E)) + return NC; + return NOT_CONSONANT; +} + + +enum thai_mark_type_t +{ + AV, + BV, + T, + NOT_MARK, + NUM_MARK_TYPES = NOT_MARK +}; + +static thai_mark_type_t +get_mark_type (hb_codepoint_t u) +{ + if (u == 0x0E31 || hb_in_range<hb_codepoint_t> (u, 0x0E34, 0x0E37) || + u == 0x0E47 || hb_in_range<hb_codepoint_t> (u, 0x0E4D, 0x0E4E)) + return AV; + if (hb_in_range<hb_codepoint_t> (u, 0x0E38, 0x0E3A)) + return BV; + if (hb_in_range<hb_codepoint_t> (u, 0x0E48, 0x0E4C)) + return T; + return NOT_MARK; +} + + +enum thai_action_t +{ + NOP, + SD, /* Shift combining-mark down */ + SL, /* Shift combining-mark left */ + SDL, /* Shift combining-mark down-left */ + RD /* Remove descender from base */ +}; + +static hb_codepoint_t +thai_pua_shape (hb_codepoint_t u, thai_action_t action, hb_font_t *font) +{ + struct thai_pua_mapping_t { + hb_codepoint_t u; + hb_codepoint_t win_pua; + hb_codepoint_t mac_pua; + } const *pua_mappings = NULL; + static const thai_pua_mapping_t SD_mappings[] = { + {0x0E48, 0xF70A, 0xF88B}, /* MAI EK */ + {0x0E49, 0xF70B, 0xF88E}, /* MAI THO */ + {0x0E4A, 0xF70C, 0xF891}, /* MAI TRI */ + {0x0E4B, 0xF70D, 0xF894}, /* MAI CHATTAWA */ + {0x0E4C, 0xF70E, 0xF897}, /* THANTHAKHAT */ + {0x0E38, 0xF718, 0xF89B}, /* SARA U */ + {0x0E39, 0xF719, 0xF89C}, /* SARA UU */ + {0x0E3A, 0xF71A, 0xF89D}, /* PHINTHU */ + {0x0000, 0x0000, 0x0000} + }; + static const thai_pua_mapping_t SDL_mappings[] = { + {0x0E48, 0xF705, 0xF88C}, /* MAI EK */ + {0x0E49, 0xF706, 0xF88F}, /* MAI THO */ + {0x0E4A, 0xF707, 0xF892}, /* MAI TRI */ + {0x0E4B, 0xF708, 0xF895}, /* MAI CHATTAWA */ + {0x0E4C, 0xF709, 0xF898}, /* THANTHAKHAT */ + {0x0000, 0x0000, 0x0000} + }; + static const thai_pua_mapping_t SL_mappings[] = { + {0x0E48, 0xF713, 0xF88A}, /* MAI EK */ + {0x0E49, 0xF714, 0xF88D}, /* MAI THO */ + {0x0E4A, 0xF715, 0xF890}, /* MAI TRI */ + {0x0E4B, 0xF716, 0xF893}, /* MAI CHATTAWA */ + {0x0E4C, 0xF717, 0xF896}, /* THANTHAKHAT */ + {0x0E31, 0xF710, 0xF884}, /* MAI HAN-AKAT */ + {0x0E34, 0xF701, 0xF885}, /* SARA I */ + {0x0E35, 0xF702, 0xF886}, /* SARA II */ + {0x0E36, 0xF703, 0xF887}, /* SARA UE */ + {0x0E37, 0xF704, 0xF888}, /* SARA UEE */ + {0x0E47, 0xF712, 0xF889}, /* MAITAIKHU */ + {0x0E4D, 0xF711, 0xF899}, /* NIKHAHIT */ + {0x0000, 0x0000, 0x0000} + }; + static const thai_pua_mapping_t RD_mappings[] = { + {0x0E0D, 0xF70F, 0xF89A}, /* YO YING */ + {0x0E10, 0xF700, 0xF89E}, /* THO THAN */ + {0x0000, 0x0000, 0x0000} + }; + + switch (action) { + default: assert (false); /* Fallthrough */ + case NOP: return u; + case SD: pua_mappings = SD_mappings; break; + case SDL: pua_mappings = SDL_mappings; break; + case SL: pua_mappings = SL_mappings; break; + case RD: pua_mappings = RD_mappings; break; + } + for (; pua_mappings->u; pua_mappings++) + if (pua_mappings->u == u) + { + hb_codepoint_t glyph; + if (hb_font_get_glyph (font, pua_mappings->win_pua, 0, &glyph)) + return pua_mappings->win_pua; + if (hb_font_get_glyph (font, pua_mappings->mac_pua, 0, &glyph)) + return pua_mappings->mac_pua; + break; + } + return u; +} + + +static enum thai_above_state_t +{ /* Cluster above looks like: */ + T0, /* ⣤ */ + T1, /* ⣼ */ + T2, /* ⣾ */ + T3, /* ⣿ */ + NUM_ABOVE_STATES +} thai_above_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] = +{ + T0, /* NC */ + T1, /* AC */ + T0, /* RC */ + T0, /* DC */ + T3, /* NOT_CONSONANT */ +}; + +static const struct thai_above_state_machine_edge_t { + thai_action_t action; + thai_above_state_t next_state; +} thai_above_state_machine[NUM_ABOVE_STATES][NUM_MARK_TYPES] = +{ /*AV*/ /*BV*/ /*T*/ +/*T0*/ {{NOP,T3}, {NOP,T0}, {SD, T3}}, +/*T1*/ {{SL, T2}, {NOP,T1}, {SDL,T2}}, +/*T2*/ {{NOP,T3}, {NOP,T2}, {SL, T3}}, +/*T3*/ {{NOP,T3}, {NOP,T3}, {NOP,T3}}, +}; + + +static enum thai_below_state_t +{ + B0, /* No descender */ + B1, /* Removable descender */ + B2, /* Strict descender */ + NUM_BELOW_STATES +} thai_below_start_state[NUM_CONSONANT_TYPES + 1/* For NOT_CONSONANT */] = +{ + B0, /* NC */ + B0, /* AC */ + B1, /* RC */ + B2, /* DC */ + B2, /* NOT_CONSONANT */ +}; + +static const struct thai_below_state_machine_edge_t { + thai_action_t action; + thai_below_state_t next_state; +} thai_below_state_machine[NUM_BELOW_STATES][NUM_MARK_TYPES] = +{ /*AV*/ /*BV*/ /*T*/ +/*B0*/ {{NOP,B0}, {NOP,B2}, {NOP, B0}}, +/*B1*/ {{NOP,B1}, {RD, B2}, {NOP, B1}}, +/*B2*/ {{NOP,B2}, {SD, B2}, {NOP, B2}}, +}; + + +static void +do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_buffer_t *buffer, + hb_font_t *font) +{ + thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT]; + thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT]; + unsigned int base = 0; + + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + { + thai_mark_type_t mt = get_mark_type (info[i].codepoint); + + if (mt == NOT_MARK) { + thai_consonant_type_t ct = get_consonant_type (info[i].codepoint); + above_state = thai_above_start_state[ct]; + below_state = thai_below_start_state[ct]; + base = i; + continue; + } + + const thai_above_state_machine_edge_t &above_edge = thai_above_state_machine[above_state][mt]; + const thai_below_state_machine_edge_t &below_edge = thai_below_state_machine[below_state][mt]; + above_state = above_edge.next_state; + below_state = below_edge.next_state; + + /* At least one of the above/below actions is NOP. */ + thai_action_t action = above_edge.action != NOP ? above_edge.action : below_edge.action; + + if (action == RD) + info[base].codepoint = thai_pua_shape (info[base].codepoint, action, font); + else + info[i].codepoint = thai_pua_shape (info[i].codepoint, action, font); + } +} + + +static void +preprocess_text_thai (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font) +{ + /* This function implements the shaping logic documented here: + * + * http://linux.thai.net/~thep/th-otf/shaping.html + * + * The first shaping rule listed there is needed even if the font has Thai + * OpenType tables. The rest do fallback positioning based on PUA codepoints. + * We implement that only if there exist no Thai GSUB in the font. + */ + + /* 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 AA, *and* move the + * NIKHAHIT 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 user wanted, but the rendering is nevertheless nikhahit above + * chattawa. + * + * Same for Lao. + * + * Note: + * + * Uniscribe also does some below-marks reordering. Namely, it positions U+0E3A + * after U+0E38 and U+0E39. We do that by modifying the ccc for U+0E3A. + * See unicode->modified_combining_class (). Lao does NOT have a U+0E3A + * equivalent. + */ + + + /* + * 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 + * + * Testing shows that Uniscribe reorder the following marks: + * Thai: <0E31,0E34..0E37,0E47..0E4E> + * Lao: <0EB1,0EB4..0EB7,0EC7..0ECE> + * + * 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) (hb_in_ranges<hb_codepoint_t> ((x) & ~0x0080, 0x0E34, 0x0E37, 0x0E47, 0x0E4E, 0x0E31, 0x0E31)) + + 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--; + + if (start + 2 < end) + { + /* Move Nikhahit (end-2) to the beginning */ + buffer->merge_out_clusters (start, end); + 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; + } + else + { + /* Since we decomposed, and NIKHAHIT is combining, merge clusters with the + * previous cluster. */ + if (start) + buffer->merge_out_clusters (start - 1, end); + } + } + buffer->swap_buffers (); + + /* If font has Thai GSUB, we are done. */ + if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0]) + do_thai_pua_shaping (plan, buffer, font); +} + +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = +{ + "thai", + NULL, /* collect_features */ + NULL, /* override_features */ + NULL, /* data_create */ + NULL, /* data_destroy */ + preprocess_text_thai, + NULL, /* normalization_preference */ + NULL, /* decompose */ + NULL, /* compose */ + NULL, /* setup_masks */ + true, /* zero_width_attached_marks */ + false,/* fallback_position */ +}; diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc index eb7777e..6f3426e 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc @@ -138,10 +138,10 @@ recategorize_combining_class (hb_codepoint_t u, /* Lao */ case HB_MODIFIED_COMBINING_CLASS_CCC118: /* sign u / sign uu */ - return HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT; + return HB_UNICODE_COMBINING_CLASS_BELOW; case HB_MODIFIED_COMBINING_CLASS_CCC122: /* mai */ - return HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT; + return HB_UNICODE_COMBINING_CLASS_ABOVE; /* Tibetan */ @@ -161,8 +161,8 @@ recategorize_combining_class (hb_codepoint_t u, } void -_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan, - hb_font_t *font, +_hb_ot_shape_fallback_position_recategorize_marks (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { unsigned int count = buffer->len; @@ -311,7 +311,7 @@ position_around_base (const hb_ot_shape_plan_t *plan, hb_glyph_extents_t component_extents = base_extents; unsigned int last_lig_component = (unsigned int) -1; unsigned int last_combining_class = 255; - hb_glyph_extents_t cluster_extents; + hb_glyph_extents_t cluster_extents = base_extents; /* Initialization is just to shut gcc up. */ for (unsigned int i = base + 1; i < end; i++) if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i])) { 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 index c5fcbea..8112f03 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-normalize-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize-private.hh @@ -35,6 +35,8 @@ /* buffer var allocations, used during the normalization process */ #define glyph_index() var1.u32 +struct hb_ot_shape_plan_t; + 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 */ @@ -44,8 +46,26 @@ enum hb_ot_shape_normalization_mode_t { HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS }; -HB_INTERNAL void _hb_ot_shape_normalize (hb_font_t *font, +HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper, hb_buffer_t *buffer, - hb_ot_shape_normalization_mode_t mode); + hb_font_t *font); + + +struct hb_ot_shape_normalize_context_t +{ + const hb_ot_shape_plan_t *plan; + hb_buffer_t *buffer; + hb_font_t *font; + hb_unicode_funcs_t *unicode; + bool (*decompose) (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b); + bool (*compose) (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab); +}; + #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 18a3f3f..c5325e4 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-normalize.cc @@ -25,6 +25,7 @@ */ #include "hb-ot-shape-normalize-private.hh" +#include "hb-ot-shape-complex-private.hh" #include "hb-ot-shape-private.hh" @@ -81,181 +82,24 @@ * egrep "`echo -n ';('; grep ';<' UnicodeData.txt | cut -d';' -f1 | tr '\n' '|'; echo ') '`" UnicodeData.txt */ -static hb_bool_t -decompose_func (hb_unicode_funcs_t *unicode, - hb_codepoint_t ab, - hb_codepoint_t *a, - hb_codepoint_t *b) +static bool +decompose_unicode (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t ab, + hb_codepoint_t *a, + hb_codepoint_t *b) { - /* XXX FIXME, move these to complex shapers and propagage to normalizer.*/ - switch (ab) { - case 0x0AC9 : return false; - - case 0x0931 : return false; - case 0x0B94 : return false; - - /* These ones have Unicode decompositions, but we do it - * this way to be close to what Uniscribe does. */ - case 0x0DDA : *a = 0x0DD9; *b= 0x0DDA; return true; - case 0x0DDC : *a = 0x0DD9; *b= 0x0DDC; return true; - case 0x0DDD : *a = 0x0DD9; *b= 0x0DDD; return true; - case 0x0DDE : *a = 0x0DD9; *b= 0x0DDE; return true; - - case 0x0F77 : *a = 0x0FB2; *b= 0x0F81; return true; - case 0x0F79 : *a = 0x0FB3; *b= 0x0F81; return true; - case 0x17BE : *a = 0x17C1; *b= 0x17BE; return true; - case 0x17BF : *a = 0x17C1; *b= 0x17BF; return true; - case 0x17C0 : *a = 0x17C1; *b= 0x17C0; return true; - case 0x17C4 : *a = 0x17C1; *b= 0x17C4; return true; - case 0x17C5 : *a = 0x17C1; *b= 0x17C5; return true; - case 0x1925 : *a = 0x1920; *b= 0x1923; return true; - case 0x1926 : *a = 0x1920; *b= 0x1924; return true; - case 0x1B3C : *a = 0x1B42; *b= 0x1B3C; return true; - case 0x1112E : *a = 0x11127; *b= 0x11131; return true; - case 0x1112F : *a = 0x11127; *b= 0x11132; return true; -#if 0 - case 0x0B57 : *a = 0xno decomp, -> RIGHT; return true; - case 0x1C29 : *a = 0xno decomp, -> LEFT; return true; - case 0xA9C0 : *a = 0xno decomp, -> RIGHT; return true; - case 0x111BF : *a = 0xno decomp, -> ABOVE; return true; -#endif - } - return unicode->decompose (ab, a, b); + return c->unicode->decompose (ab, a, b); } -static hb_bool_t -compose_func (hb_unicode_funcs_t *unicode, - hb_codepoint_t a, - hb_codepoint_t b, - hb_codepoint_t *ab) +static bool +compose_unicode (const hb_ot_shape_normalize_context_t *c, + hb_codepoint_t a, + hb_codepoint_t b, + hb_codepoint_t *ab) { - /* XXX, this belongs to indic normalizer. */ - if (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (unicode->general_category (a))) - return false; - /* XXX, add composition-exclusion exceptions to Indic shaper. */ - if (a == 0x09AF && b == 0x09BC) { *ab = 0x09DF; return true; } - - /* XXX, these belong to the hebew / default shaper. */ - /* Hebrew presentation-form shaping. - * https://bugzilla.mozilla.org/show_bug.cgi?id=728866 */ - // Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA; - // note that some letters do not have a dagesh presForm encoded - static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = { - 0xFB30, // ALEF - 0xFB31, // BET - 0xFB32, // GIMEL - 0xFB33, // DALET - 0xFB34, // HE - 0xFB35, // VAV - 0xFB36, // ZAYIN - 0, // HET - 0xFB38, // TET - 0xFB39, // YOD - 0xFB3A, // FINAL KAF - 0xFB3B, // KAF - 0xFB3C, // LAMED - 0, // FINAL MEM - 0xFB3E, // MEM - 0, // FINAL NUN - 0xFB40, // NUN - 0xFB41, // SAMEKH - 0, // AYIN - 0xFB43, // FINAL PE - 0xFB44, // PE - 0, // FINAL TSADI - 0xFB46, // TSADI - 0xFB47, // QOF - 0xFB48, // RESH - 0xFB49, // SHIN - 0xFB4A // TAV - }; - - hb_bool_t found = unicode->compose (a, b, ab); - - if (!found && (b & ~0x7F) == 0x0580) { - // special-case Hebrew presentation forms that are excluded from - // standard normalization, but wanted for old fonts - switch (b) { - case 0x05B4: // HIRIQ - if (a == 0x05D9) { // YOD - *ab = 0xFB1D; - found = true; - } - break; - case 0x05B7: // patah - if (a == 0x05F2) { // YIDDISH YOD YOD - *ab = 0xFB1F; - found = true; - } else if (a == 0x05D0) { // ALEF - *ab = 0xFB2E; - found = true; - } - break; - case 0x05B8: // QAMATS - if (a == 0x05D0) { // ALEF - *ab = 0xFB2F; - found = true; - } - break; - case 0x05B9: // HOLAM - if (a == 0x05D5) { // VAV - *ab = 0xFB4B; - found = true; - } - break; - case 0x05BC: // DAGESH - if (a >= 0x05D0 && a <= 0x05EA) { - *ab = sDageshForms[a - 0x05D0]; - found = (*ab != 0); - } else if (a == 0xFB2A) { // SHIN WITH SHIN DOT - *ab = 0xFB2C; - found = true; - } else if (a == 0xFB2B) { // SHIN WITH SIN DOT - *ab = 0xFB2D; - found = true; - } - break; - case 0x05BF: // RAFE - switch (a) { - case 0x05D1: // BET - *ab = 0xFB4C; - found = true; - break; - case 0x05DB: // KAF - *ab = 0xFB4D; - found = true; - break; - case 0x05E4: // PE - *ab = 0xFB4E; - found = true; - break; - } - break; - case 0x05C1: // SHIN DOT - if (a == 0x05E9) { // SHIN - *ab = 0xFB2A; - found = true; - } else if (a == 0xFB49) { // SHIN WITH DAGESH - *ab = 0xFB2C; - found = true; - } - break; - case 0x05C2: // SIN DOT - if (a == 0x05E9) { // SHIN - *ab = 0xFB2B; - found = true; - } else if (a == 0xFB49) { // SHIN WITH DAGESH - *ab = 0xFB2D; - found = true; - } - break; - } - } - - return found; + return c->unicode->compose (a, b, ab); } - static inline void set_glyph (hb_glyph_info_t &info, hb_font_t *font) { @@ -285,38 +129,38 @@ skip_char (hb_buffer_t *buffer) /* Returns 0 if didn't decompose, number of resulting characters otherwise. */ static inline unsigned int -decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t ab) +decompose (const hb_ot_shape_normalize_context_t *c, bool shortest, hb_codepoint_t ab) { hb_codepoint_t a, b, a_glyph, b_glyph; - if (!decompose_func (buffer->unicode, ab, &a, &b) || - (b && !font->get_glyph (b, 0, &b_glyph))) + if (!c->decompose (c, ab, &a, &b) || + (b && !c->font->get_glyph (b, 0, &b_glyph))) return 0; - bool has_a = font->get_glyph (a, 0, &a_glyph); + bool has_a = c->font->get_glyph (a, 0, &a_glyph); if (shortest && has_a) { /* Output a and b */ - output_char (buffer, a, a_glyph); + output_char (c->buffer, a, a_glyph); if (likely (b)) { - output_char (buffer, b, b_glyph); + output_char (c->buffer, b, b_glyph); return 2; } return 1; } unsigned int ret; - if ((ret = decompose (font, buffer, shortest, a))) { + if ((ret = decompose (c, shortest, a))) { if (b) { - output_char (buffer, b, b_glyph); + output_char (c->buffer, b, b_glyph); return ret + 1; } return ret; } if (has_a) { - output_char (buffer, a, a_glyph); + output_char (c->buffer, a, a_glyph); if (likely (b)) { - output_char (buffer, b, b_glyph); + output_char (c->buffer, b, b_glyph); return 2; } return 1; @@ -327,41 +171,42 @@ decompose (hb_font_t *font, hb_buffer_t *buffer, bool shortest, hb_codepoint_t a /* Returns 0 if didn't decompose, number of resulting characters otherwise. */ static inline bool -decompose_compatibility (hb_font_t *font, hb_buffer_t *buffer, hb_codepoint_t u) +decompose_compatibility (const hb_ot_shape_normalize_context_t *c, hb_codepoint_t u) { unsigned int len, i; hb_codepoint_t decomposed[HB_UNICODE_MAX_DECOMPOSITION_LEN]; hb_codepoint_t glyphs[HB_UNICODE_MAX_DECOMPOSITION_LEN]; - len = buffer->unicode->decompose_compatibility (u, decomposed); + len = c->buffer->unicode->decompose_compatibility (u, decomposed); if (!len) return 0; for (i = 0; i < len; i++) - if (!font->get_glyph (decomposed[i], 0, &glyphs[i])) + if (!c->font->get_glyph (decomposed[i], 0, &glyphs[i])) return 0; for (i = 0; i < len; i++) - output_char (buffer, decomposed[i], glyphs[i]); + output_char (c->buffer, decomposed[i], glyphs[i]); return len; } /* Returns true if recomposition may be benefitial. */ static inline bool -decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest) +decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shortest) { + hb_buffer_t * const buffer = c->buffer; hb_codepoint_t glyph; unsigned int len = 1; /* Kind of a cute waterfall here... */ - if (shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) + if (shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph)) next_char (buffer, glyph); - else if ((len = decompose (font, buffer, shortest, buffer->cur().codepoint))) + else if ((len = decompose (c, shortest, buffer->cur().codepoint))) skip_char (buffer); - else if (!shortest && font->get_glyph (buffer->cur().codepoint, 0, &glyph)) + else if (!shortest && c->font->get_glyph (buffer->cur().codepoint, 0, &glyph)) next_char (buffer, glyph); - else if ((len = decompose_compatibility (font, buffer, buffer->cur().codepoint))) + else if ((len = decompose_compatibility (c, buffer->cur().codepoint))) skip_char (buffer); else next_char (buffer, glyph); /* glyph is initialized in earlier branches. */ @@ -374,49 +219,51 @@ decompose_current_character (hb_font_t *font, hb_buffer_t *buffer, bool shortest } static inline void -handle_variation_selector_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end) +handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end) { + hb_buffer_t * const buffer = c->buffer; for (; buffer->idx < end - 1;) { if (unlikely (buffer->unicode->is_variation_selector (buffer->cur(+1).codepoint))) { /* The next two lines are some ugly lines... But work. */ - font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()); + c->font->get_glyph (buffer->cur().codepoint, buffer->cur(+1).codepoint, &buffer->cur().glyph_index()); buffer->replace_glyphs (2, 1, &buffer->cur().codepoint); } else { - set_glyph (buffer->cur(), font); + set_glyph (buffer->cur(), c->font); buffer->next_glyph (); } } if (likely (buffer->idx < end)) { - set_glyph (buffer->cur(), font); + set_glyph (buffer->cur(), c->font); buffer->next_glyph (); } } /* Returns true if recomposition may be benefitial. */ static inline bool -decompose_multi_char_cluster (hb_font_t *font, hb_buffer_t *buffer, unsigned int end) +decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end) { + hb_buffer_t * const buffer = c->buffer; /* TODO Currently if there's a variation-selector we give-up, it's just too hard. */ for (unsigned int i = buffer->idx; i < end; i++) if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) { - handle_variation_selector_cluster (font, buffer, end); + handle_variation_selector_cluster (c, end); return false; } while (buffer->idx < end) - decompose_current_character (font, buffer, false); + decompose_current_character (c, false); /* We can be smarter here and only return true if there are at least two ccc!=0 marks. * But does not matter. */ return true; } static inline bool -decompose_cluster (hb_font_t *font, hb_buffer_t *buffer, bool short_circuit, unsigned int end) +decompose_cluster (const hb_ot_shape_normalize_context_t *c, bool short_circuit, unsigned int end) { - if (likely (buffer->idx + 1 == end)) - return decompose_current_character (font, buffer, short_circuit); + if (likely (c->buffer->idx + 1 == end)) + return decompose_current_character (c, short_circuit); else - return decompose_multi_char_cluster (font, buffer, end); + return decompose_multi_char_cluster (c, end); } @@ -431,9 +278,22 @@ compare_combining_class (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) void -_hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, - hb_ot_shape_normalization_mode_t mode) +_hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + hb_font_t *font) { + hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference ? + plan->shaper->normalization_preference (&buffer->props) : + HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT; + const hb_ot_shape_normalize_context_t c = { + plan, + buffer, + font, + buffer->unicode, + plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode, + plan->shaper->compose ? plan->shaper->compose : compose_unicode + }; + bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED && mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT; bool can_use_recompose = false; @@ -457,7 +317,7 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, if (buffer->cur().cluster != buffer->info[end].cluster) break; - can_use_recompose = decompose_cluster (font, buffer, short_circuit, end) || can_use_recompose; + can_use_recompose = decompose_cluster (&c, short_circuit, end) || can_use_recompose; } buffer->swap_buffers (); @@ -517,10 +377,10 @@ _hb_ot_shape_normalize (hb_font_t *font, hb_buffer_t *buffer, (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. */ - compose_func (buffer->unicode, - buffer->out_info[starter].codepoint, - buffer->cur().codepoint, - &composed) && + c.compose (&c, + buffer->out_info[starter].codepoint, + buffer->cur().codepoint, + &composed) && /* And the font has glyph for the composite. */ font->get_glyph (composed, 0, &glyph)) { 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 ae01215..23e80b7 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh +++ b/third_party/harfbuzz-ng/src/hb-ot-shape-private.hh @@ -46,7 +46,16 @@ struct hb_ot_shape_plan_t hb_ot_map_t map; const void *data; - inline void substitute_closure (hb_face_t *face, hb_set_t *glyphs) const { map.substitute_closure (this, face, glyphs); } + inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const + { + unsigned int table_index; + switch (table_tag) { + case HB_OT_TAG_GSUB: table_index = 0; break; + case HB_OT_TAG_GPOS: table_index = 1; break; + default: return; + } + map.collect_lookups (table_index, lookups); + } inline void substitute (hb_font_t *font, hb_buffer_t *buffer) const { map.substitute (this, font, buffer); } inline void position (hb_font_t *font, hb_buffer_t *buffer) const { map.position (this, font, buffer); } @@ -65,14 +74,14 @@ struct hb_ot_shape_planner_t face (master_plan->face), props (master_plan->props), shaper (NULL), - map () {} + map (face, &props) {} ~hb_ot_shape_planner_t (void) { map.finish (); } inline void compile (hb_ot_shape_plan_t &plan) { plan.props = props; plan.shaper = shaper; - map.compile (face, &props, plan.map); + map.compile (plan.map); } private: diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape.cc b/third_party/harfbuzz-ng/src/hb-ot-shape.cc index 9a6260a..96461d7 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-shape.cc @@ -175,7 +175,7 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan, hb_ot_shape_planner_t planner (shape_plan); - planner.shaper = hb_ot_shape_complex_categorize (&shape_plan->props); + planner.shaper = hb_ot_shape_complex_categorize (&planner); hb_ot_shape_collect_features (&planner, &shape_plan->props, user_features, num_user_features); @@ -237,7 +237,7 @@ hb_set_unicode_props (hb_buffer_t *buffer) static void hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) { - if (buffer->context_len[0] || + if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || _hb_glyph_info_get_general_category (&buffer->info[0]) != HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) return; @@ -348,8 +348,8 @@ hb_synthesize_glyph_classes (hb_ot_shape_context_t *c) unsigned int count = c->buffer->len; for (unsigned int i = 0; i < count; i++) c->buffer->info[i].glyph_props() = _hb_glyph_info_get_general_category (&c->buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ? - HB_OT_LAYOUT_GLYPH_CLASS_MARK : - HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH; + HB_OT_LAYOUT_GLYPH_PROPS_MARK : + HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; } static inline void @@ -362,10 +362,7 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c) HB_BUFFER_ALLOCATE_VAR (c->buffer, glyph_index); - _hb_ot_shape_normalize (c->font, c->buffer, - c->plan->shaper->normalization_preference ? - c->plan->shaper->normalization_preference (c->plan) : - HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT); + _hb_ot_shape_normalize (c->plan, c->buffer, c->font); hb_ot_shape_setup_masks (c); @@ -455,12 +452,6 @@ hb_ot_position_complex (hb_ot_shape_context_t *c) } static inline void -hb_ot_position_complex_fallback (hb_ot_shape_context_t *c) -{ - _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); -} - -static inline void hb_ot_truetype_kern (hb_ot_shape_context_t *c) { /* TODO Check for kern=0 */ @@ -486,34 +477,33 @@ hb_ot_truetype_kern (hb_ot_shape_context_t *c) } static inline void -hb_position_complex_fallback_visual (hb_ot_shape_context_t *c) -{ - hb_ot_truetype_kern (c); -} - -static inline void hb_ot_position (hb_ot_shape_context_t *c) { hb_ot_position_default (c); hb_bool_t fallback = !hb_ot_position_complex (c); - if (fallback) - hb_ot_position_complex_fallback (c); + if (fallback && c->plan->shaper->fallback_position) + _hb_ot_shape_fallback_position (c->plan, c->font, c->buffer); if (HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction)) hb_buffer_reverse (c->buffer); + /* Visual fallback goes here. */ + if (fallback) - hb_position_complex_fallback_visual (c); + hb_ot_truetype_kern (c); } /* Post-process */ static void -hb_ot_hide_zerowidth (hb_ot_shape_context_t *c) +hb_ot_hide_default_ignorables (hb_ot_shape_context_t *c) { + if (c->buffer->flags & HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES) + return; + hb_codepoint_t space = 0; unsigned int count = c->buffer->len; @@ -557,7 +547,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) hb_ot_substitute (c); hb_ot_position (c); - hb_ot_hide_zerowidth (c); + hb_ot_hide_default_ignorables (c); HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props1); HB_BUFFER_DEALLOCATE_VAR (c->buffer, unicode_props0); @@ -582,16 +572,36 @@ _hb_ot_shape (hb_shape_plan_t *shape_plan, } +void +hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan, + hb_tag_t table_tag, + hb_set_t *lookup_indexes /* OUT */) +{ + /* XXX Does the first part always succeed? */ + HB_SHAPER_DATA_GET (shape_plan)->collect_lookups (table_tag, lookup_indexes); +} -static inline void -hb_ot_map_glyphs_dumb (hb_font_t *font, - hb_buffer_t *buffer) + +/* TODO Move this to hb-ot-shape-normalize, make it do decompose, and make it public. */ +static void +add_char (hb_font_t *font, + hb_unicode_funcs_t *unicode, + hb_bool_t mirror, + hb_codepoint_t u, + hb_set_t *glyphs) { - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - font->get_glyph (buffer->info[i].codepoint, 0, &buffer->info[i].codepoint); + hb_codepoint_t glyph; + if (font->get_glyph (u, 0, &glyph)) + glyphs->add (glyph); + if (mirror) + { + hb_codepoint_t m = unicode->mirroring (u); + if (m != u && font->get_glyph (m, 0, &glyph)) + glyphs->add (glyph); + } } + void hb_ot_shape_glyphs_closure (hb_font_t *font, hb_buffer_t *buffer, @@ -601,29 +611,30 @@ hb_ot_shape_glyphs_closure (hb_font_t *font, { hb_ot_shape_plan_t plan; - buffer->guess_properties (); + buffer->guess_segment_properties (); - /* TODO cache / ensure correct backend, etc. */ - hb_shape_plan_t *shape_plan = hb_shape_plan_create (font->face, &buffer->props, features, num_features, NULL); + const char *shapers[] = {"ot", NULL}; + hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, + features, num_features, shapers); - /* TODO: normalization? have shapers do closure()? */ - /* TODO: Deal with mirrored chars? */ - hb_ot_map_glyphs_dumb (font, buffer); + bool mirror = hb_script_get_horizontal_direction (buffer->props.script) == HB_DIRECTION_RTL; - /* 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++) - glyphs->add (buffer->info[i].codepoint); + add_char (font, buffer->unicode, mirror, buffer->info[i].codepoint, glyphs); + + hb_set_t lookups; + lookups.init (); + hb_ot_shape_plan_collect_lookups (shape_plan, HB_OT_TAG_GSUB, &lookups); /* And find transitive closure. */ hb_set_t copy; copy.init (); - do { copy.set (glyphs); - HB_SHAPER_DATA_GET (shape_plan)->substitute_closure (font->face, glyphs); - } while (!copy.equal (glyphs)); + for (hb_codepoint_t lookup_index = -1; hb_set_next (&lookups, &lookup_index);) + hb_ot_layout_lookup_substitute_closure (font->face, lookup_index, glyphs); + } while (!copy.is_equal (glyphs)); hb_shape_plan_destroy (shape_plan); } diff --git a/third_party/harfbuzz-ng/src/hb-ot-tag.cc b/third_party/harfbuzz-ng/src/hb-ot-tag.cc index ac60e96..91ebec7 100644 --- a/third_party/harfbuzz-ng/src/hb-ot-tag.cc +++ b/third_party/harfbuzz-ng/src/hb-ot-tag.cc @@ -23,7 +23,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod - * Google Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Roozbeh Pournader */ #include "hb-private.hh" @@ -38,6 +38,8 @@ static hb_tag_t hb_ot_old_tag_from_script (hb_script_t script) { + /* This seems to be accurate as of end of 2012. */ + switch ((hb_tag_t) script) { case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT; @@ -91,6 +93,7 @@ hb_ot_new_tag_from_script (hb_script_t script) case HB_SCRIPT_ORIYA: return HB_TAG('o','r','y','2'); case HB_SCRIPT_TAMIL: return HB_TAG('t','m','l','2'); case HB_SCRIPT_TELUGU: return HB_TAG('t','e','l','2'); + case HB_SCRIPT_MYANMAR: return HB_TAG('m','y','m','2'); } return HB_OT_TAG_DEFAULT_SCRIPT; @@ -109,6 +112,7 @@ hb_ot_new_tag_to_script (hb_tag_t tag) case HB_TAG('o','r','y','2'): return HB_SCRIPT_ORIYA; case HB_TAG('t','m','l','2'): return HB_SCRIPT_TAMIL; case HB_TAG('t','e','l','2'): return HB_SCRIPT_TELUGU; + case HB_TAG('m','y','m','2'): return HB_SCRIPT_MYANMAR; } return HB_SCRIPT_UNKNOWN; @@ -165,7 +169,9 @@ typedef struct { * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from * 2008/08/04, matching on name, and finally adjusted manually. * - * Many items still missing. Those are commented out at the end. + * Updated on 2012/12/07 with more research into remaining codes. + * + * Some items still missing. Those are commented out at the end. * Keep sorted for bsearch. */ @@ -173,43 +179,63 @@ static const LangTag ot_languages[] = { {"aa", HB_TAG('A','F','R',' ')}, /* Afar */ {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ + {"ada", HB_TAG('D','N','G',' ')}, /* Dangme */ {"ady", HB_TAG('A','D','Y',' ')}, /* Adyghe */ {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ + {"aii", HB_TAG('S','W','A',' ')}, /* Swadaya Aramaic */ {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ + {"alt", HB_TAG('A','L','T',' ')}, /* [Southern] Altai */ {"am", HB_TAG('A','M','H',' ')}, /* Amharic */ + {"amf", HB_TAG('H','B','N',' ')}, /* Hammer-Banna */ {"ar", HB_TAG('A','R','A',' ')}, /* Arabic */ {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ + {"ath", HB_TAG('A','T','H',' ')}, /* Athapaskan [family] */ + {"atv", HB_TAG('A','L','T',' ')}, /* [Northern] Altai */ {"av", HB_TAG('A','V','R',' ')}, /* Avaric */ {"awa", HB_TAG('A','W','A',' ')}, /* Awadhi */ {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara */ {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani */ {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ + {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi */ + {"bci", HB_TAG('B','A','U',' ')}, /* Baule */ {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ + {"be", HB_TAG('B','E','L',' ')}, /* Belarussian */ {"bem", HB_TAG('B','E','M',' ')}, /* Bemba (Zambia) */ + {"ber", HB_TAG('B','E','R',' ')}, /* Berber [family] */ {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ + {"bfy", HB_TAG('B','A','G',' ')}, /* Baghelkhandi */ {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ {"bho", HB_TAG('B','H','O',' ')}, /* Bhojpuri */ {"bik", HB_TAG('B','I','K',' ')}, /* Bikol */ {"bin", HB_TAG('E','D','O',' ')}, /* Bini */ + {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja */ + {"bla", HB_TAG('B','K','F',' ')}, /* Blackfoot */ + {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe */ {"bm", HB_TAG('B','M','B',' ')}, /* Bambara */ {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ {"br", HB_TAG('B','R','E',' ')}, /* Breton */ + {"bra", HB_TAG('B','R','I',' ')}, /* Braj Bhasha */ {"brh", HB_TAG('B','R','H',' ')}, /* Brahui */ {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) */ + {"bxr", HB_TAG('R','B','U',' ')}, /* Russian Buriat */ + {"byn", HB_TAG('B','I','L',' ')}, /* Bilen */ {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ {"ceb", HB_TAG('C','E','B',' ')}, /* Cebuano */ {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ {"chr", HB_TAG('C','H','R',' ')}, /* Cherokee */ + {"ckt", HB_TAG('C','H','K',' ')}, /* Chukchi */ {"cop", HB_TAG('C','O','P',' ')}, /* Coptic */ {"cr", HB_TAG('C','R','E',' ')}, /* Cree */ {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ + {"crj", HB_TAG('E','C','R',' ')}, /* [Southern] East Cree */ + {"crl", HB_TAG('E','C','R',' ')}, /* [Northern] East Cree */ {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ @@ -222,10 +248,12 @@ static const LangTag ot_languages[] = { {"dar", HB_TAG('D','A','R',' ')}, /* Dargwa */ {"de", HB_TAG('D','E','U',' ')}, /* German */ {"din", HB_TAG('D','N','K',' ')}, /* Dinka */ + {"dje", HB_TAG('D','J','R',' ')}, /* Djerma */ {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ {"doi", HB_TAG('D','G','R',' ')}, /* Dogri */ {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ {"dv", HB_TAG('D','I','V',' ')}, /* Dhivehi */ + {"dyu", HB_TAG('J','U','L',' ')}, /* Jula */ {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ {"efi", HB_TAG('E','F','I',' ')}, /* Efik */ @@ -253,20 +281,27 @@ static const LangTag ot_languages[] = { {"gag", HB_TAG('G','A','G',' ')}, /* Gagauz */ {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */ + {"gez", HB_TAG('G','E','Z',' ')}, /* Ge'ez */ {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ {"gn", HB_TAG('G','U','A',' ')}, /* Guarani */ {"gon", HB_TAG('G','O','N',' ')}, /* Gondi */ {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ + {"gru", HB_TAG('S','O','G',' ')}, /* Sodo Gurage */ {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ {"gv", HB_TAG('M','N','X',' ')}, /* Manx Gaelic */ {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ {"har", HB_TAG('H','R','I',' ')}, /* Harari */ + {"haw", HB_TAG('H','A','W',' ')}, /* Hawaiin */ {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ {"hil", HB_TAG('H','I','L',' ')}, /* Hiligaynon */ + {"hnd", HB_TAG('H','N','D',' ')}, /* [Southern] Hindko */ + {"hne", HB_TAG('C','H','H',' ')}, /* Chattisgarhi */ + {"hno", HB_TAG('H','N','D',' ')}, /* [Northern] Hindko */ {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ + {"hoj", HB_TAG('H','A','R',' ')}, /* Harauti */ {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ {"ht", HB_TAG('H','A','I',' ')}, /* Haitian */ @@ -275,6 +310,8 @@ static const LangTag ot_languages[] = { {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ + {"ijo", HB_TAG('I','J','O',' ')}, /* Ijo [family] */ + {"ilo", HB_TAG('I','L','O',' ')}, /* Ilokano */ {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ {"it", HB_TAG('I','T','A',' ')}, /* Italian */ @@ -282,19 +319,25 @@ static const LangTag ot_languages[] = { {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ + {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ + {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ + {"kex", HB_TAG('K','K','N',' ')}, /* Kokni */ {"kfr", HB_TAG('K','A','C',' ')}, /* Kachchi */ {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ + {"khb", HB_TAG('X','B','D',' ')}, /* Tai Lue */ {"khw", HB_TAG('K','H','W',' ')}, /* Khowar */ {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu */ + {"kjh", HB_TAG('K','H','A',' ')}, /* Khakass */ {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ {"kl", HB_TAG('G','R','N',' ')}, /* Kalaallisut */ {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin */ {"km", HB_TAG('K','H','M',' ')}, /* Central Khmer */ + {"kmb", HB_TAG('M','B','N',' ')}, /* [North] Mbundu */ {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ @@ -312,6 +355,7 @@ static const LangTag ot_languages[] = { {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish */ {"kum", HB_TAG('K','U','M',' ')}, /* Kumyk */ {"kvd", HB_TAG('K','U','I',' ')}, /* Kui (Indonesia) */ + {"kxc", HB_TAG('K','M','S',' ')}, /* Komso */ {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */ {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz */ {"la", HB_TAG('L','A','T',' ')}, /* Latin */ @@ -319,13 +363,19 @@ static const LangTag ot_languages[] = { {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ + {"lez", HB_TAG('L','E','Z',' ')}, /* Lezgi */ + {"lg", HB_TAG('L','U','G',' ')}, /* Luganda */ {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ + {"lmn", HB_TAG('L','A','M',' ')}, /* Lambani */ {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ + {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ + {"lua", HB_TAG('L','U','B',' ')}, /* Luba-Kasai */ {"luo", HB_TAG('L','U','O',' ')}, /* Luo (Kenya and Tanzania) */ - {"luw", HB_TAG('L','U','O',' ')}, /* Luo (Cameroon) */ + {"lus", HB_TAG('M','I','Z',' ')}, /* Mizo */ + {"luy", HB_TAG('L','U','H',' ')}, /* Luhya [macrolanguage] */ {"lv", HB_TAG('L','V','I',' ')}, /* Latvian */ {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ @@ -334,6 +384,7 @@ static const LangTag ot_languages[] = { {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy */ + {"mhr", HB_TAG('L','M','A',' ')}, /* Low Mari */ {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam */ @@ -347,14 +398,17 @@ static const LangTag ot_languages[] = { {"moh", HB_TAG('M','O','H',' ')}, /* Mohawk */ {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ + {"mrj", HB_TAG('H','M','A',' ')}, /* High Mari */ {"ms", HB_TAG('M','L','Y',' ')}, /* Malay */ {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari */ {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ {"mym", HB_TAG('M','E','N',' ')}, /* Me'en */ {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ + {"nag", HB_TAG('N','A','G',' ')}, /* Naga-Assamese */ {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål */ {"nco", HB_TAG('S','I','B',' ')}, /* Sibe */ + {"nd", HB_TAG('N','D','B',' ')}, /* [North] Ndebele */ {"ne", HB_TAG('N','E','P',' ')}, /* Nepali */ {"new", HB_TAG('N','E','W',' ')}, /* Newari */ {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ @@ -364,33 +418,45 @@ static const LangTag ot_languages[] = { {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk */ {"no", HB_TAG('N','O','R',' ')}, /* Norwegian (deprecated) */ + {"nod", HB_TAG('N','T','A',' ')}, /* Northern Tai */ {"nog", HB_TAG('N','O','G',' ')}, /* Nogai */ {"nqo", HB_TAG('N','K','O',' ')}, /* N'Ko */ + {"nr", HB_TAG('N','D','B',' ')}, /* [South] Ndebele */ {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ + {"nso", HB_TAG('S','O','T',' ')}, /* [Northern] Sotho */ {"ny", HB_TAG('C','H','I',' ')}, /* Nyanja */ + {"nyn", HB_TAG('N','K','L',' ')}, /* Nkole */ {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa */ + {"ojs", HB_TAG('O','C','R',' ')}, /* Oji-Cree */ {"om", HB_TAG('O','R','O',' ')}, /* Oromo */ {"or", HB_TAG('O','R','I',' ')}, /* Oriya */ {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ {"pa", HB_TAG('P','A','N',' ')}, /* Panjabi */ + {"pce", HB_TAG('P','L','G',' ')}, /* [Ruching] Palaung */ {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ + {"pll", HB_TAG('P','L','G',' ')}, /* [Shwe] Palaung */ {"plp", HB_TAG('P','A','P',' ')}, /* Palpa */ {"prs", HB_TAG('D','R','I',' ')}, /* Dari */ {"ps", HB_TAG('P','A','S',' ')}, /* Pushto */ {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ {"raj", HB_TAG('R','A','J',' ')}, /* Rajasthani */ + {"rbb", HB_TAG('P','L','G',' ')}, /* [Rumai] Palaung */ {"ria", HB_TAG('R','I','A',' ')}, /* Riang (India) */ {"ril", HB_TAG('R','I','A',' ')}, /* Riang (Myanmar) */ + {"rki", HB_TAG('A','R','K',' ')}, /* Arakanese */ + {"rm", HB_TAG('R','M','S',' ')}, /* Rhaeto-Romanic */ {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ {"rom", HB_TAG('R','O','Y',' ')}, /* Romany */ {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ + {"rw", HB_TAG('R','U','A',' ')}, /* Ruanda */ {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut */ {"sat", HB_TAG('S','A','T',' ')}, /* Santali */ {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ + {"scs", HB_TAG('S','L','A',' ')}, /* [North] Slavey */ {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ @@ -413,6 +479,8 @@ static const LangTag ot_languages[] = { {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian */ {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ {"srr", HB_TAG('S','R','R',' ')}, /* Serer */ + {"ss", HB_TAG('S','W','Z',' ')}, /* Swazi */ + {"st", HB_TAG('S','O','T',' ')}, /* [Southern] Sotho */ {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ {"sva", HB_TAG('S','V','A',' ')}, /* Svan */ @@ -420,31 +488,34 @@ static const LangTag ot_languages[] = { {"swb", HB_TAG('C','M','R',' ')}, /* Comorian */ {"syr", HB_TAG('S','Y','R',' ')}, /* Syriac */ {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ + {"tab", HB_TAG('T','A','B',' ')}, /* Tabasaran */ {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu */ {"te", HB_TAG('T','E','L',' ')}, /* Telugu */ + {"tem", HB_TAG('T','M','N',' ')}, /* Temne */ {"tg", HB_TAG('T','A','J',' ')}, /* Tajik */ {"th", HB_TAG('T','H','A',' ')}, /* Thai */ {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ - {"tnz", HB_TAG('T','N','G',' ')}, /* Tonga (Thailand) */ - {"to", HB_TAG('T','N','G',' ')}, /* Tonga (Tonga Islands) */ - {"tog", HB_TAG('T','N','G',' ')}, /* Tonga (Nyasa) */ - {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ + {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) */ {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ + {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo Aramaic */ {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ + {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvin */ {"udm", HB_TAG('U','D','M',' ')}, /* Udmurt */ {"ug", HB_TAG('U','Y','G',' ')}, /* Uighur */ {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ + {"umb", HB_TAG('M','B','N',' ')}, /* [South] Mbundu */ {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek */ {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ + {"vmw", HB_TAG('M','A','K',' ')}, /* Makua */ {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ @@ -458,115 +529,56 @@ static const LangTag ot_languages[] = { {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ {"zu", HB_TAG('Z','U','L',' ')} /* Zulu */ - /* I couldn't find the language id for these */ - -/*{"??", HB_TAG('A','G','W',' ')},*/ /* Agaw */ -/*{"??", HB_TAG('A','L','S',' ')},*/ /* Alsatian */ -/*{"??", HB_TAG('A','L','T',' ')},*/ /* Altai */ -/*{"??", HB_TAG('A','R','K',' ')},*/ /* Arakanese */ -/*{"??", HB_TAG('A','T','H',' ')},*/ /* Athapaskan */ -/*{"??", HB_TAG('B','A','G',' ')},*/ /* Baghelkhandi */ -/*{"??", HB_TAG('B','A','L',' ')},*/ /* Balkar */ -/*{"??", HB_TAG('B','A','U',' ')},*/ /* Baule */ -/*{"??", HB_TAG('B','B','R',' ')},*/ /* Berber */ + /* The corresponding languages IDs for the following IDs are unclear, + * overlap, or are architecturally weird. Needs more research. */ + +/*{"ahg/awn/xan?", HB_TAG('A','G','W',' ')},*/ /* Agaw */ +/*{"gsw?/gsw-FR?", HB_TAG('A','L','S',' ')},*/ /* Alsatian */ +/*{"krc", HB_TAG('B','A','L',' ')},*/ /* Balkar */ /*{"??", HB_TAG('B','C','R',' ')},*/ /* Bible Cree */ -/*{"??", HB_TAG('B','E','L',' ')},*/ /* Belarussian */ -/*{"??", HB_TAG('B','I','L',' ')},*/ /* Bilen */ -/*{"??", HB_TAG('B','K','F',' ')},*/ /* Blackfoot */ -/*{"??", HB_TAG('B','L','N',' ')},*/ /* Balante */ -/*{"??", HB_TAG('B','M','L',' ')},*/ /* Bamileke */ -/*{"??", HB_TAG('B','R','I',' ')},*/ /* Braj Bhasha */ -/*{"??", HB_TAG('C','H','G',' ')},*/ /* Chaha Gurage */ -/*{"??", HB_TAG('C','H','H',' ')},*/ /* Chattisgarhi */ -/*{"??", HB_TAG('C','H','K',' ')},*/ /* Chukchi */ -/*{"??", HB_TAG('D','J','R',' ')},*/ /* Djerma */ -/*{"??", HB_TAG('D','N','G',' ')},*/ /* Dangme */ -/*{"??", HB_TAG('E','C','R',' ')},*/ /* Eastern Cree */ -/*{"??", HB_TAG('F','A','N',' ')},*/ /* French Antillean */ -/*{"??", HB_TAG('F','L','E',' ')},*/ /* Flemish */ -/*{"??", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */ -/*{"??", HB_TAG('F','T','A',' ')},*/ /* Futa */ -/*{"??", HB_TAG('G','A','R',' ')},*/ /* Garshuni */ -/*{"??", HB_TAG('G','E','Z',' ')},*/ /* Ge'ez */ -/*{"??", HB_TAG('H','A','L',' ')},*/ /* Halam */ -/*{"??", HB_TAG('H','A','R',' ')},*/ /* Harauti */ -/*{"??", HB_TAG('H','A','W',' ')},*/ /* Hawaiin */ -/*{"??", HB_TAG('H','B','N',' ')},*/ /* Hammer-Banna */ -/*{"??", HB_TAG('H','M','A',' ')},*/ /* High Mari */ -/*{"??", HB_TAG('H','N','D',' ')},*/ /* Hindko */ -/*{"??", HB_TAG('I','J','O',' ')},*/ /* Ijo */ -/*{"??", HB_TAG('I','L','O',' ')},*/ /* Ilokano */ -/*{"??", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */ -/*{"??", HB_TAG('J','U','L',' ')},*/ /* Jula */ -/*{"??", HB_TAG('K','A','R',' ')},*/ /* Karachay */ -/*{"??", HB_TAG('K','E','B',' ')},*/ /* Kebena */ -/*{"??", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */ -/*{"??", HB_TAG('K','H','A',' ')},*/ /* Khakass */ -/*{"??", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */ -/*{"??", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */ -/*{"??", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */ -/*{"??", HB_TAG('K','I','S',' ')},*/ /* Kisii */ -/*{"??", HB_TAG('K','K','N',' ')},*/ /* Kokni */ -/*{"??", HB_TAG('K','M','S',' ')},*/ /* Komso */ -/*{"??", HB_TAG('K','O','D',' ')},*/ /* Kodagu */ -/*{"??", HB_TAG('K','O','H',' ')},*/ /* Korean Old Hangul */ -/*{"??", HB_TAG('K','O','N',' ')},*/ /* Kikongo */ -/*{"??", HB_TAG('K','R','K',' ')},*/ /* Karakalpak */ -/*{"??", HB_TAG('K','R','N',' ')},*/ /* Karen */ -/*{"??", HB_TAG('K','U','L',' ')},*/ /* Kulvi */ +/*{"sgw?", HB_TAG('C','H','G',' ')},*/ /* Chaha Gurage */ +/*{"acf/gcf?", HB_TAG('F','A','N',' ')},*/ /* French Antillean */ +/*{"vls/nl-be", HB_TAG('F','L','E',' ')},*/ /* Flemish */ +/*{"enf?/yrk?", HB_TAG('F','N','E',' ')},*/ /* Forest Nenets */ +/*{"fuf?", HB_TAG('F','T','A',' ')},*/ /* Futa */ +/*{"ar-Syrc?", HB_TAG('G','A','R',' ')},*/ /* Garshuni */ +/*{"cfm/rnl?", HB_TAG('H','A','L',' ')},*/ /* Halam */ +/*{"ga-Latg?/Latg?", HB_TAG('I','R','T',' ')},*/ /* Irish Traditional */ +/*{"krc", HB_TAG('K','A','R',' ')},*/ /* Karachay */ +/*{"alw?/ktb?", HB_TAG('K','E','B',' ')},*/ /* Kebena */ +/*{"Geok", HB_TAG('K','G','E',' ')},*/ /* Khutsuri Georgian */ +/*{"kca", HB_TAG('K','H','K',' ')},*/ /* Khanty-Kazim */ +/*{"kca", HB_TAG('K','H','S',' ')},*/ /* Khanty-Shurishkar */ +/*{"kca", HB_TAG('K','H','V',' ')},*/ /* Khanty-Vakhi */ +/*{"guz?/kqs?/kss?", HB_TAG('K','I','S',' ')},*/ /* Kisii */ +/*{"kfa/kfi?/kpb?/xua?/xuj?", HB_TAG('K','O','D',' ')},*/ /* Kodagu */ +/*{"okm?/oko?", HB_TAG('K','O','H',' ')},*/ /* Korean Old Hangul */ +/*{"kon?/ktu?/...", HB_TAG('K','O','N',' ')},*/ /* Kikongo */ +/*{"kfx?", HB_TAG('K','U','L',' ')},*/ /* Kulvi */ /*{"??", HB_TAG('L','A','H',' ')},*/ /* Lahuli */ -/*{"??", HB_TAG('L','A','M',' ')},*/ /* Lambani */ /*{"??", HB_TAG('L','C','R',' ')},*/ /* L-Cree */ -/*{"??", HB_TAG('L','E','Z',' ')},*/ /* Lezgi */ -/*{"??", HB_TAG('L','M','A',' ')},*/ /* Low Mari */ -/*{"??", HB_TAG('L','U','B',' ')},*/ /* Luba */ -/*{"??", HB_TAG('L','U','G',' ')},*/ /* Luganda */ -/*{"??", HB_TAG('L','U','H',' ')},*/ /* Luhya */ -/*{"??", HB_TAG('M','A','K',' ')},*/ /* Makua */ /*{"??", HB_TAG('M','A','L',' ')},*/ /* Malayalam Traditional */ -/*{"??", HB_TAG('M','B','N',' ')},*/ /* Mbundu */ -/*{"??", HB_TAG('M','I','Z',' ')},*/ /* Mizo */ -/*{"??", HB_TAG('M','L','N',' ')},*/ /* Malinke */ -/*{"??", HB_TAG('M','N','K',' ')},*/ /* Maninka */ +/*{"mnk?/mlq?/...", HB_TAG('M','L','N',' ')},*/ /* Malinke */ +/*{"man?/myq?/mku?/msc?/...", HB_TAG('M','N','K',' ')},*/ /* Maninka */ /*{"??", HB_TAG('M','O','R',' ')},*/ /* Moroccan */ -/*{"??", HB_TAG('N','A','G',' ')},*/ /* Naga-Assamese */ /*{"??", HB_TAG('N','C','R',' ')},*/ /* N-Cree */ -/*{"??", HB_TAG('N','D','B',' ')},*/ /* Ndebele */ -/*{"??", HB_TAG('N','G','R',' ')},*/ /* Nagari */ /*{"??", HB_TAG('N','H','C',' ')},*/ /* Norway House Cree */ -/*{"??", HB_TAG('N','K','L',' ')},*/ /* Nkole */ -/*{"??", HB_TAG('N','T','A',' ')},*/ /* Northern Tai */ -/*{"??", HB_TAG('O','C','R',' ')},*/ /* Oji-Cree */ -/*{"??", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */ -/*{"??", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */ -/*{"??", HB_TAG('P','L','G',' ')},*/ /* Palaung */ -/*{"??", HB_TAG('Q','I','N',' ')},*/ /* Chin */ -/*{"??", HB_TAG('R','B','U',' ')},*/ /* Russian Buriat */ +/*{"jpa?/sam?", HB_TAG('P','A','A',' ')},*/ /* Palestinian Aramaic */ +/*{"polyton", HB_TAG('P','G','R',' ')},*/ /* Polytonic Greek */ +/*{"??", HB_TAG('Q','I','N',' ')},*/ /* Asho Chin */ /*{"??", HB_TAG('R','C','R',' ')},*/ /* R-Cree */ -/*{"??", HB_TAG('R','M','S',' ')},*/ /* Rhaeto-Romanic */ -/*{"??", HB_TAG('R','U','A',' ')},*/ /* Ruanda */ -/*{"??", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */ -/*{"??", HB_TAG('S','E','K',' ')},*/ /* Sekota */ -/*{"??", HB_TAG('S','I','G',' ')},*/ /* Silte Gurage */ -/*{"??", HB_TAG('S','L','A',' ')},*/ /* Slavey */ -/*{"??", HB_TAG('S','O','G',' ')},*/ /* Sodo Gurage */ -/*{"??", HB_TAG('S','O','T',' ')},*/ /* Sotho */ -/*{"??", HB_TAG('S','W','A',' ')},*/ /* Swadaya Aramaic */ -/*{"??", HB_TAG('S','W','Z',' ')},*/ /* Swazi */ -/*{"??", HB_TAG('S','X','T',' ')},*/ /* Sutu */ -/*{"??", HB_TAG('T','A','B',' ')},*/ /* Tabasaran */ +/*{"chp?", HB_TAG('S','A','Y',' ')},*/ /* Sayisi */ +/*{"xan?", HB_TAG('S','E','K',' ')},*/ /* Sekota */ +/*{"stv/wle?/xst?", HB_TAG('S','I','G',' ')},*/ /* Silte Gurage */ +/*{"ngo?", HB_TAG('S','X','T',' ')},*/ /* Sutu */ /*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */ -/*{"??", HB_TAG('T','G','N',' ')},*/ /* Tongan */ -/*{"??", HB_TAG('T','M','N',' ')},*/ /* Temne */ -/*{"??", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */ +/*{"tnz?/tog?/toi?", HB_TAG('T','N','G',' ')},*/ /* Tonga */ +/*{"enh?/yrk?", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */ /*{"??", HB_TAG('T','O','D',' ')},*/ /* Todo */ -/*{"??", HB_TAG('T','U','A',' ')},*/ /* Turoyo Aramaic */ -/*{"??", HB_TAG('T','U','V',' ')},*/ /* Tuvin */ /*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */ -/*{"??", HB_TAG('X','B','D',' ')},*/ /* Tai Lue */ /*{"??", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */ /*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */ -/*{"??", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */ +/*{"ii?/Yiii?", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */ /*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ }; diff --git a/third_party/harfbuzz-ng/src/hb-ot.h b/third_party/harfbuzz-ng/src/hb-ot.h index 2d750c3..8073906 100644 --- a/third_party/harfbuzz-ng/src/hb-ot.h +++ b/third_party/harfbuzz-ng/src/hb-ot.h @@ -35,6 +35,7 @@ HB_BEGIN_DECLS +/* TODO remove */ void hb_ot_shape_glyphs_closure (hb_font_t *font, hb_buffer_t *buffer, diff --git a/third_party/harfbuzz-ng/src/hb-private.hh b/third_party/harfbuzz-ng/src/hb-private.hh index 42c0259..be0d505 100644 --- a/third_party/harfbuzz-ng/src/hb-private.hh +++ b/third_party/harfbuzz-ng/src/hb-private.hh @@ -62,6 +62,12 @@ #endif +/* Void! */ +struct _hb_void_t {}; +typedef const _hb_void_t &hb_void_t; +#define HB_VOID (* (const _hb_void_t *) NULL) + + /* Basics */ @@ -76,7 +82,7 @@ static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; } #undef ARRAY_LENGTH template <typename Type, unsigned int n> -static inline unsigned int ARRAY_LENGTH (const Type (&a)[n]) { return n; } +static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; } /* A const version, but does not detect erratically being called on pointers. */ #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0]))) @@ -503,6 +509,10 @@ static inline uint32_t hb_uint32_swap (const uint32_t v) #define hb_be_uint32_get(v) (uint32_t) ((v[0] << 24) + (v[1] << 16) + (v[2] << 8) + v[3]) #define hb_be_uint32_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]) +#define hb_be_uint24_put(v,V) HB_STMT_START { v[0] = (V>>16); v[1] = (V>>8); v[2] (V); } HB_STMT_END +#define hb_be_uint24_get(v) (uint32_t) ((v[0] << 16) + (v[1] << 8) + v[2]) +#define hb_be_uint24_eq(a,b) (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]) + /* ASCII tag/character handling */ @@ -582,7 +592,11 @@ _hb_debug_msg_va (const char *what, } else fprintf (stderr, " " VRBAR LBAR); - if (func) { + if (func) + { + /* Skip "typename" */ + if (0 == strncmp (func, "typename ", 9)) + func += 9; /* Skip return type */ const char *space = strchr (func, ' '); if (space) @@ -657,10 +671,39 @@ _hb_debug_msg<0> (const char *what HB_UNUSED, /* + * Printer + */ + +template <typename T> +struct hb_printer_t {}; + +template <> +struct hb_printer_t<bool> { + const char *print (bool v) { return v ? "true" : "false"; } +}; + +template <> +struct hb_printer_t<hb_void_t> { + const char *print (hb_void_t) { return ""; } +}; + + +/* * Trace */ -template <int max_level> +template <typename T> +static inline void _hb_warn_no_return (bool returned) +{ + if (unlikely (!returned)) { + fprintf (stderr, "OUCH, returned with no call to TRACE_RETURN. This is a bug, please report.\n"); + } +} +template <> +inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED) +{} + +template <int max_level, typename ret_t> struct hb_auto_trace_t { explicit inline hb_auto_trace_t (unsigned int *plevel_, const char *what_, @@ -678,23 +721,23 @@ struct hb_auto_trace_t { } inline ~hb_auto_trace_t (void) { - 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_warn_no_return<ret_t> (returned); + if (!returned) { _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, " "); - return; } - if (plevel) --*plevel; } - inline bool ret (bool v, unsigned int line = 0) + inline ret_t ret (ret_t v, unsigned int line = 0) { 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 (line %d)", v ? "true" : "false", line); + _hb_debug_msg<max_level> (what, obj, NULL, true, plevel ? *plevel : 1, -1, + "return %s (line %d)", + hb_printer_t<ret_t>().print (v), line); if (plevel) --*plevel; plevel = NULL; returned = true; @@ -703,12 +746,12 @@ struct hb_auto_trace_t { private: unsigned int *plevel; - bool returned; const char *what; const void *obj; + bool returned; }; -template <> /* Optimize when tracing is disabled */ -struct hb_auto_trace_t<0> { +template <typename ret_t> /* Optimize when tracing is disabled */ +struct hb_auto_trace_t<0, ret_t> { explicit inline hb_auto_trace_t (unsigned int *plevel_ HB_UNUSED, const char *what HB_UNUSED, const void *obj HB_UNUSED, @@ -716,8 +759,7 @@ struct hb_auto_trace_t<0> { const char *message HB_UNUSED, ...) {} - template <typename T> - inline T ret (T v, unsigned int line = 0) { return v; } + inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; } }; #define TRACE_RETURN(RET) trace.ret (RET, __LINE__) diff --git a/third_party/harfbuzz-ng/src/hb-set-private.hh b/third_party/harfbuzz-ng/src/hb-set-private.hh index 4413579..5e30a7e 100644 --- a/third_party/harfbuzz-ng/src/hb-set-private.hh +++ b/third_party/harfbuzz-ng/src/hb-set-private.hh @@ -98,7 +98,7 @@ struct hb_set_digest_lowest_bits_t private: - mask_t mask_for (hb_codepoint_t g) const { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); } + static inline mask_t mask_for (hb_codepoint_t g) { return ((mask_t) 1) << (g & (sizeof (mask_t) * 8 - 1)); } mask_t mask; }; @@ -137,6 +137,7 @@ struct hb_set_t { hb_object_header_t header; ASSERT_POD (); + bool in_error; inline void init (void) { header.init (); @@ -145,9 +146,12 @@ struct hb_set_t inline void fini (void) { } inline void clear (void) { + if (unlikely (hb_object_is_inert (this))) + return; + in_error = false; memset (elts, 0, sizeof elts); } - inline bool empty (void) const { + inline bool is_empty (void) const { for (unsigned int i = 0; i < ARRAY_LENGTH (elts); i++) if (elts[i]) return false; @@ -155,20 +159,31 @@ struct hb_set_t } inline void add (hb_codepoint_t g) { + if (unlikely (in_error)) return; if (unlikely (g == SENTINEL)) return; if (unlikely (g > MAX_G)) return; elt (g) |= mask (g); } inline void add_range (hb_codepoint_t a, hb_codepoint_t b) { + if (unlikely (in_error)) return; + /* TODO Speedup */ for (unsigned int i = a; i < b + 1; i++) add (i); } inline void del (hb_codepoint_t g) { + if (unlikely (in_error)) return; if (unlikely (g > MAX_G)) return; elt (g) &= ~mask (g); } + inline void del_range (hb_codepoint_t a, hb_codepoint_t b) + { + if (unlikely (in_error)) return; + /* TODO Speedup */ + for (unsigned int i = a; i < b + 1; i++) + del (i); + } inline bool has (hb_codepoint_t g) const { if (unlikely (g > MAX_G)) return false; @@ -185,7 +200,7 @@ struct hb_set_t return true; return false; } - inline bool equal (const hb_set_t *other) const + inline bool is_equal (const hb_set_t *other) const { for (unsigned int i = 0; i < ELTS; i++) if (elts[i] != other->elts[i]) @@ -194,30 +209,41 @@ struct hb_set_t } inline void set (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] = other->elts[i]; } inline void union_ (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] |= other->elts[i]; } inline void intersect (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] &= other->elts[i]; } inline void subtract (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] &= ~other->elts[i]; } inline void symmetric_difference (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] ^= other->elts[i]; } - inline bool next (hb_codepoint_t *codepoint) + inline void invert (void) + { + if (unlikely (in_error)) return; + for (unsigned int i = 0; i < ELTS; i++) + elts[i] = ~elts[i]; + } + inline bool next (hb_codepoint_t *codepoint) const { if (unlikely (*codepoint == SENTINEL)) { hb_codepoint_t i = get_min (); @@ -234,6 +260,28 @@ struct hb_set_t } return false; } + inline bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const + { + hb_codepoint_t i; + + i = *last; + if (!next (&i)) + return false; + + *last = *first = i; + while (next (&i) && i == *last + 1) + (*last)++; + + return true; + } + + inline unsigned int get_population (void) const + { + unsigned int count = 0; + for (unsigned int i = 0; i < ELTS; i++) + count += _hb_popcount32 (elts[i]); + return count; + } inline hb_codepoint_t get_min (void) const { for (unsigned int i = 0; i < ELTS; i++) diff --git a/third_party/harfbuzz-ng/src/hb-set.cc b/third_party/harfbuzz-ng/src/hb-set.cc index 4225e3c..5f427a5 100644 --- a/third_party/harfbuzz-ng/src/hb-set.cc +++ b/third_party/harfbuzz-ng/src/hb-set.cc @@ -32,7 +32,7 @@ hb_set_t * -hb_set_create () +hb_set_create (void) { hb_set_t *set; @@ -49,6 +49,7 @@ hb_set_get_empty (void) { static const hb_set_t _hb_set_nil = { HB_OBJECT_HEADER_STATIC, + true, /* in_error */ {0} /* elts */ }; @@ -73,27 +74,27 @@ 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) +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) +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) +hb_set_allocation_successful (const hb_set_t *set HB_UNUSED) { - return true; + return !set->in_error; } void @@ -103,13 +104,13 @@ hb_set_clear (hb_set_t *set) } hb_bool_t -hb_set_empty (hb_set_t *set) +hb_set_is_empty (const hb_set_t *set) { - return set->empty (); + return set->is_empty (); } hb_bool_t -hb_set_has (hb_set_t *set, +hb_set_has (const hb_set_t *set, hb_codepoint_t codepoint) { return set->has (codepoint); @@ -123,69 +124,105 @@ hb_set_add (hb_set_t *set, } void +hb_set_add_range (hb_set_t *set, + hb_codepoint_t first, + hb_codepoint_t last) +{ + set->add_range (first, last); +} + +void hb_set_del (hb_set_t *set, hb_codepoint_t codepoint) { set->del (codepoint); } +void +hb_set_del_range (hb_set_t *set, + hb_codepoint_t first, + hb_codepoint_t last) +{ + set->del_range (first, last); +} + hb_bool_t -hb_set_equal (hb_set_t *set, - hb_set_t *other) +hb_set_is_equal (const hb_set_t *set, + const hb_set_t *other) { - return set->equal (other); + return set->is_equal (other); } void -hb_set_set (hb_set_t *set, - hb_set_t *other) +hb_set_set (hb_set_t *set, + const hb_set_t *other) { set->set (other); } void -hb_set_union (hb_set_t *set, - hb_set_t *other) +hb_set_union (hb_set_t *set, + const hb_set_t *other) { set->union_ (other); } void -hb_set_intersect (hb_set_t *set, - hb_set_t *other) +hb_set_intersect (hb_set_t *set, + const hb_set_t *other) { set->intersect (other); } void -hb_set_subtract (hb_set_t *set, - hb_set_t *other) +hb_set_subtract (hb_set_t *set, + const hb_set_t *other) { set->subtract (other); } void -hb_set_symmetric_difference (hb_set_t *set, - hb_set_t *other) +hb_set_symmetric_difference (hb_set_t *set, + const hb_set_t *other) { set->symmetric_difference (other); } +void +hb_set_invert (hb_set_t *set) +{ + set->invert (); +} + +unsigned int +hb_set_get_population (const hb_set_t *set) +{ + return set->get_population (); +} + hb_codepoint_t -hb_set_min (hb_set_t *set) +hb_set_get_min (const hb_set_t *set) { return set->get_min (); } hb_codepoint_t -hb_set_max (hb_set_t *set) +hb_set_get_max (const hb_set_t *set) { return set->get_max (); } hb_bool_t -hb_set_next (hb_set_t *set, +hb_set_next (const hb_set_t *set, hb_codepoint_t *codepoint) { return set->next (codepoint); } + +hb_bool_t +hb_set_next_range (const hb_set_t *set, + hb_codepoint_t *first, + hb_codepoint_t *last) +{ + return set->next_range (first, last); +} diff --git a/third_party/harfbuzz-ng/src/hb-set.h b/third_party/harfbuzz-ng/src/hb-set.h index 1838889..291e249 100644 --- a/third_party/harfbuzz-ng/src/hb-set.h +++ b/third_party/harfbuzz-ng/src/hb-set.h @@ -65,16 +65,16 @@ hb_set_get_user_data (hb_set_t *set, /* Returns false if allocation has failed before */ hb_bool_t -hb_set_allocation_successful (hb_set_t *set); +hb_set_allocation_successful (const hb_set_t *set); void hb_set_clear (hb_set_t *set); hb_bool_t -hb_set_empty (hb_set_t *set); +hb_set_is_empty (const hb_set_t *set); hb_bool_t -hb_set_has (hb_set_t *set, +hb_set_has (const hb_set_t *set, hb_codepoint_t codepoint); /* Right now limited to 16-bit integers. Eventually will do full codepoint range, sans -1 @@ -84,47 +84,67 @@ hb_set_add (hb_set_t *set, hb_codepoint_t codepoint); void +hb_set_add_range (hb_set_t *set, + hb_codepoint_t first, + hb_codepoint_t last); + +void hb_set_del (hb_set_t *set, hb_codepoint_t codepoint); +void +hb_set_del_range (hb_set_t *set, + hb_codepoint_t first, + hb_codepoint_t last); + hb_bool_t -hb_set_equal (hb_set_t *set, - hb_set_t *other); +hb_set_is_equal (const hb_set_t *set, + const hb_set_t *other); void -hb_set_set (hb_set_t *set, - hb_set_t *other); +hb_set_set (hb_set_t *set, + const hb_set_t *other); void -hb_set_union (hb_set_t *set, - hb_set_t *other); +hb_set_union (hb_set_t *set, + const hb_set_t *other); void -hb_set_intersect (hb_set_t *set, - hb_set_t *other); +hb_set_intersect (hb_set_t *set, + const hb_set_t *other); void -hb_set_subtract (hb_set_t *set, - hb_set_t *other); +hb_set_subtract (hb_set_t *set, + const hb_set_t *other); void -hb_set_symmetric_difference (hb_set_t *set, - hb_set_t *other); +hb_set_symmetric_difference (hb_set_t *set, + const hb_set_t *other); + +void +hb_set_invert (hb_set_t *set); + +unsigned int +hb_set_get_population (const hb_set_t *set); /* Returns -1 if set empty. */ hb_codepoint_t -hb_set_min (hb_set_t *set); +hb_set_get_min (const hb_set_t *set); /* Returns -1 if set empty. */ hb_codepoint_t -hb_set_max (hb_set_t *set); +hb_set_get_max (const hb_set_t *set); /* Pass -1 in to get started. */ hb_bool_t -hb_set_next (hb_set_t *set, +hb_set_next (const hb_set_t *set, hb_codepoint_t *codepoint); -/* TODO: Add faster iteration API? */ +/* Pass -1 for first and last to get started. */ +hb_bool_t +hb_set_next_range (const hb_set_t *set, + hb_codepoint_t *first, + hb_codepoint_t *last); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/hb-shape-plan-private.hh b/third_party/harfbuzz-ng/src/hb-shape-plan-private.hh index d6a57d6..dd014e3 100644 --- a/third_party/harfbuzz-ng/src/hb-shape-plan-private.hh +++ b/third_party/harfbuzz-ng/src/hb-shape-plan-private.hh @@ -28,9 +28,8 @@ #define HB_SHAPE_PLAN_PRIVATE_HH #include "hb-private.hh" - #include "hb-shape-plan.h" - +#include "hb-object-private.hh" #include "hb-shaper-private.hh" @@ -44,6 +43,7 @@ struct hb_shape_plan_t hb_segment_properties_t props; hb_shape_func_t *shaper_func; + const char *shaper_name; struct hb_shaper_data_t shaper_data; }; diff --git a/third_party/harfbuzz-ng/src/hb-shape-plan.cc b/third_party/harfbuzz-ng/src/hb-shape-plan.cc index 038f6af3..22a226f 100644 --- a/third_party/harfbuzz-ng/src/hb-shape-plan.cc +++ b/third_party/harfbuzz-ng/src/hb-shape-plan.cc @@ -24,8 +24,6 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-private.hh" - #include "hb-shape-plan-private.hh" #include "hb-shaper-private.hh" #include "hb-font-private.hh" @@ -51,6 +49,7 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan, HB_SHAPER_DATA (shaper, shape_plan) = \ HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, user_features, num_user_features); \ shape_plan->shaper_func = _hb_##shaper##_shape; \ + shape_plan->shaper_name = #shaper; \ return; \ } \ } HB_STMT_END @@ -119,9 +118,10 @@ hb_shape_plan_get_empty (void) true, /* default_shaper_list */ NULL, /* face */ - _HB_BUFFER_PROPS_DEFAULT, /* props */ + HB_SEGMENT_PROPERTIES_DEFAULT, /* props */ NULL, /* shaper_func */ + NULL, /* shaper_name */ { #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, @@ -153,9 +153,26 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) free (shape_plan); } +hb_bool_t +hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (shape_plan, key, data, destroy, replace); +} + +void * +hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (shape_plan, key); +} + hb_bool_t -hb_shape_plan_execute (hb_shape_plan *shape_plan, +hb_shape_plan_execute (hb_shape_plan_t *shape_plan, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, @@ -283,3 +300,9 @@ retry: return hb_shape_plan_reference (shape_plan); } + +const char * +hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) +{ + return shape_plan->shaper_name; +} diff --git a/third_party/harfbuzz-ng/src/hb-shape-plan.h b/third_party/harfbuzz-ng/src/hb-shape-plan.h index f1a14a9..8f54552 100644 --- a/third_party/harfbuzz-ng/src/hb-shape-plan.h +++ b/third_party/harfbuzz-ng/src/hb-shape-plan.h @@ -24,52 +24,66 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_H_IN +#error "Include <hb.h> instead." +#endif + #ifndef HB_SHAPE_PLAN_H #define HB_SHAPE_PLAN_H -/* TODO To become public one day */ - -#include "hb-private.hh" - -#include "hb-buffer-private.hh" +#include "hb-common.h" +#include "hb-font.h" +HB_BEGIN_DECLS -typedef struct hb_shape_plan_t hb_shape_plan; - -/* - * hb_shape_plan_t - */ +typedef struct hb_shape_plan_t hb_shape_plan_t; -HB_INTERNAL hb_shape_plan_t * +hb_shape_plan_t * hb_shape_plan_create (hb_face_t *face, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, const char * const *shaper_list); -HB_INTERNAL hb_shape_plan_t * +hb_shape_plan_t * hb_shape_plan_create_cached (hb_face_t *face, const hb_segment_properties_t *props, const hb_feature_t *user_features, unsigned int num_user_features, const char * const *shaper_list); -HB_INTERNAL hb_shape_plan_t * +hb_shape_plan_t * hb_shape_plan_get_empty (void); -HB_INTERNAL hb_shape_plan_t * +hb_shape_plan_t * hb_shape_plan_reference (hb_shape_plan_t *shape_plan); -HB_INTERNAL void +void hb_shape_plan_destroy (hb_shape_plan_t *shape_plan); +hb_bool_t +hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + +void * +hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, + hb_user_data_key_t *key); + -HB_INTERNAL hb_bool_t -hb_shape_plan_execute (hb_shape_plan *shape_plan, +hb_bool_t +hb_shape_plan_execute (hb_shape_plan_t *shape_plan, hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features); +const char * +hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan); + + +HB_END_DECLS #endif /* HB_SHAPE_PLAN_H */ diff --git a/third_party/harfbuzz-ng/src/hb-shape.cc b/third_party/harfbuzz-ng/src/hb-shape.cc index 4d64823..389ce3e 100644 --- a/third_party/harfbuzz-ng/src/hb-shape.cc +++ b/third_party/harfbuzz-ng/src/hb-shape.cc @@ -176,7 +176,7 @@ hb_feature_to_string (hb_feature_t *feature, len += 4; while (len && s[len - 1] == ' ') len--; - if (feature->start != 0 || feature->start != (unsigned int) -1) + if (feature->start != 0 || feature->end != (unsigned int) -1) { s[len++] = '['; if (feature->start) @@ -255,7 +255,7 @@ hb_shape_full (hb_font_t *font, assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE); - buffer->guess_properties (); + buffer->guess_segment_properties (); hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list); hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); diff --git a/third_party/harfbuzz-ng/src/hb-shape.h b/third_party/harfbuzz-ng/src/hb-shape.h index 90a188d..10a35cb 100644 --- a/third_party/harfbuzz-ng/src/hb-shape.h +++ b/third_party/harfbuzz-ng/src/hb-shape.h @@ -52,7 +52,7 @@ hb_bool_t hb_feature_from_string (const char *str, int len, hb_feature_t *feature); -/* something like 128 bytes is more than enough. +/* Something like 128 bytes is more than enough. * nul-terminates. */ void hb_feature_to_string (hb_feature_t *feature, diff --git a/third_party/harfbuzz-ng/src/hb-shaper-list.hh b/third_party/harfbuzz-ng/src/hb-shaper-list.hh index 6c02de4..b9c029e 100644 --- a/third_party/harfbuzz-ng/src/hb-shaper-list.hh +++ b/third_party/harfbuzz-ng/src/hb-shaper-list.hh @@ -29,15 +29,11 @@ #endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */ /* v--- Add new shapers in the right place here. */ + #ifdef HAVE_GRAPHITE2 +/* Only picks up fonts that have a "Silf" table. */ HB_SHAPER_IMPLEMENT (graphite2) #endif -#ifdef HAVE_UNISCRIBE -HB_SHAPER_IMPLEMENT (uniscribe) -#endif -#ifdef HAVE_CORETEXT -HB_SHAPER_IMPLEMENT (coretext) -#endif #ifdef HAVE_OT HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */ @@ -46,9 +42,14 @@ HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */ #ifdef HAVE_HB_OLD HB_SHAPER_IMPLEMENT (old) #endif - #ifdef HAVE_ICU_LE HB_SHAPER_IMPLEMENT (icu_le) #endif +#ifdef HAVE_UNISCRIBE +HB_SHAPER_IMPLEMENT (uniscribe) +#endif +#ifdef HAVE_CORETEXT +HB_SHAPER_IMPLEMENT (coretext) +#endif HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */ diff --git a/third_party/harfbuzz-ng/src/hb-shaper-private.hh b/third_party/harfbuzz-ng/src/hb-shaper-private.hh index 186318d..9d30c1e 100644 --- a/third_party/harfbuzz-ng/src/hb-shaper-private.hh +++ b/third_party/harfbuzz-ng/src/hb-shaper-private.hh @@ -29,8 +29,6 @@ #include "hb-private.hh" -#include "hb-shape-plan.h" /* TODO remove */ - typedef hb_bool_t hb_shape_func_t (hb_shape_plan_t *shape_plan, hb_font_t *font, hb_buffer_t *buffer, diff --git a/third_party/harfbuzz-ng/src/hb-shaper.cc b/third_party/harfbuzz-ng/src/hb-shaper.cc index a16ffc8..1c1aed9 100644 --- a/third_party/harfbuzz-ng/src/hb-shaper.cc +++ b/third_party/harfbuzz-ng/src/hb-shaper.cc @@ -25,8 +25,8 @@ */ #include "hb-private.hh" - #include "hb-shaper-private.hh" +#include "hb-atomic-private.hh" static const hb_shaper_pair_t all_shapers[] = { diff --git a/third_party/harfbuzz-ng/src/hb-tt-font.cc b/third_party/harfbuzz-ng/src/hb-tt-font.cc index b7198ef..c503a40 100644 --- a/third_party/harfbuzz-ng/src/hb-tt-font.cc +++ b/third_party/harfbuzz-ng/src/hb-tt-font.cc @@ -68,7 +68,7 @@ _hb_tt_font_destroy (hb_tt_font_t *tt) static inline const hhea& _get_hhea (hb_face_t *face) { -// return likely (face->tt && face->tt->hhea) ? *face->tt->hhea : Null(hhea); + return likely (face->tt && face->tt->hhea) ? *face->tt->hhea : Null(hhea); } diff --git a/third_party/harfbuzz-ng/src/hb-ucdn.cc b/third_party/harfbuzz-ng/src/hb-ucdn.cc index 3506304..61e6ad3 100644 --- a/third_party/harfbuzz-ng/src/hb-ucdn.cc +++ b/third_party/harfbuzz-ng/src/hb-ucdn.cc @@ -129,57 +129,60 @@ static const hb_script_t ucdn_script_translate[] = static hb_unicode_combining_class_t hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, - void *user_data) + void *user_data HB_UNUSED) { return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode); } static unsigned int hb_ucdn_eastasian_width(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, - void *user_data) + void *user_data HB_UNUSED) { int w = ucdn_get_east_asian_width(unicode); return (w == UCDN_EAST_ASIAN_F || w == UCDN_EAST_ASIAN_W) ? 2 : 1; } static hb_unicode_general_category_t -hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs, - hb_codepoint_t unicode, void *user_data) +hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, + void *user_data HB_UNUSED) { return (hb_unicode_general_category_t)ucdn_get_general_category(unicode); } static hb_codepoint_t hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, - void *user_data) + void *user_data HB_UNUSED) { return ucdn_mirror(unicode); } static hb_script_t hb_ucdn_script(hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, - void *user_data) + void *user_data HB_UNUSED) { return ucdn_script_translate[ucdn_get_script(unicode)]; } static hb_bool_t -hb_ucdn_compose(hb_unicode_funcs_t *ufuncs, hb_codepoint_t a, - hb_codepoint_t b, hb_codepoint_t *ab, void *user_data) +hb_ucdn_compose(hb_unicode_funcs_t *ufuncs, + hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab, + void *user_data HB_UNUSED) { return ucdn_compose(ab, a, b); } static hb_bool_t -hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs, hb_codepoint_t ab, - hb_codepoint_t *a, hb_codepoint_t *b, void *user_data) +hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs, + hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b, + void *user_data HB_UNUSED) { return ucdn_decompose(ab, a, b); } static unsigned int -hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs, hb_codepoint_t u, - hb_codepoint_t *decomposed, void *user_data) +hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs, + hb_codepoint_t u, hb_codepoint_t *decomposed, + void *user_data HB_UNUSED) { return ucdn_compat_decompose(u, decomposed); } diff --git a/third_party/harfbuzz-ng/src/hb-uniscribe.cc b/third_party/harfbuzz-ng/src/hb-uniscribe.cc index 18b88b2..2f01c28 100644 --- a/third_party/harfbuzz-ng/src/hb-uniscribe.cc +++ b/third_party/harfbuzz-ng/src/hb-uniscribe.cc @@ -188,6 +188,22 @@ _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data) free (data); } +LOGFONTW * +hb_uniscribe_font_get_logfontw (hb_font_t *font) +{ + if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; + hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); + return &font_data->log_font; +} + +HFONT +hb_uniscribe_font_get_hfont (hb_font_t *font) +{ + if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; + hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); + return font_data->hfont; +} + /* * shaper shape_plan data @@ -213,23 +229,6 @@ _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_dat * shaper */ -LOGFONTW * -hb_uniscribe_font_get_logfontw (hb_font_t *font) -{ - if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; - return NULL; - hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); - return &font_data->log_font; -} - -HFONT -hb_uniscribe_font_get_hfont (hb_font_t *font) -{ - if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL; - hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font); - return font_data->hfont; -} - hb_bool_t _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, diff --git a/third_party/harfbuzz-ng/src/hb-utf-private.hh b/third_party/harfbuzz-ng/src/hb-utf-private.hh index 8cde827..b9a6519 100644 --- a/third_party/harfbuzz-ng/src/hb-utf-private.hh +++ b/third_party/harfbuzz-ng/src/hb-utf-private.hh @@ -77,8 +77,8 @@ hb_utf_prev (const uint8_t *text, const uint8_t *start, hb_codepoint_t *unicode) { - const uint8_t *end = text; - while (start < text && (*--text & 0xc0) == 0x80 && end - text < 4) + const uint8_t *end = text--; + while (start < text && (*text & 0xc0) == 0x80 && end - text < 4) text--; hb_codepoint_t c = *text, mask; @@ -176,7 +176,7 @@ hb_utf_strlen (const uint16_t *text) static inline const uint32_t * hb_utf_next (const uint32_t *text, - const uint32_t *end, + const uint32_t *end HB_UNUSED, hb_codepoint_t *unicode) { *unicode = *text++; @@ -185,7 +185,7 @@ hb_utf_next (const uint32_t *text, static inline const uint32_t * hb_utf_prev (const uint32_t *text, - const uint32_t *start, + const uint32_t *start HB_UNUSED, hb_codepoint_t *unicode) { *unicode = *--text; diff --git a/third_party/harfbuzz-ng/src/hb.h b/third_party/harfbuzz-ng/src/hb.h index d36040e2..52c479c 100644 --- a/third_party/harfbuzz-ng/src/hb.h +++ b/third_party/harfbuzz-ng/src/hb.h @@ -34,6 +34,7 @@ #include "hb-font.h" #include "hb-set.h" #include "hb-shape.h" +#include "hb-shape-plan.h" #include "hb-unicode.h" #include "hb-version.h" diff --git a/third_party/harfbuzz-ng/src/test-size-params.cc b/third_party/harfbuzz-ng/src/test-size-params.cc new file mode 100644 index 0000000..947b566 --- /dev/null +++ b/third_party/harfbuzz-ng/src/test-size-params.cc @@ -0,0 +1,93 @@ +/* + * Copyright © 2010,2011 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "hb.h" +#include "hb-ot.h" + +#ifdef HAVE_GLIB +#include <glib.h> +#endif +#include <stdlib.h> +#include <stdio.h> + +int +main (int argc, char **argv) +{ + hb_blob_t *blob = NULL; + + if (argc != 2) { + fprintf (stderr, "usage: %s font-file\n", argv[0]); + exit (1); + } + + /* Create the blob */ + { + const char *font_data; + unsigned int len; + hb_destroy_func_t destroy; + void *user_data; + hb_memory_mode_t mm; + +#ifdef HAVE_GLIB + GMappedFile *mf = g_mapped_file_new (argv[1], false, NULL); + font_data = g_mapped_file_get_contents (mf); + len = g_mapped_file_get_length (mf); + destroy = (hb_destroy_func_t) g_mapped_file_unref; + user_data = (void *) mf; + mm = HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE; +#else + FILE *f = fopen (argv[1], "rb"); + fseek (f, 0, SEEK_END); + len = ftell (f); + fseek (f, 0, SEEK_SET); + font_data = (const char *) malloc (len); + if (!font_data) len = 0; + len = fread ((char *) font_data, 1, len, f); + destroy = free; + user_data = (void *) font_data; + fclose (f); + mm = HB_MEMORY_MODE_WRITABLE; +#endif + + blob = hb_blob_create (font_data, len, mm, user_data, destroy); + } + + /* Create the face */ + hb_face_t *face = hb_face_create (blob, 0 /* first face */); + hb_blob_destroy (blob); + blob = NULL; + + unsigned int p[5]; + bool ret = hb_ot_layout_get_size_params (face, p, p+1, p+2, p+3, p+4); + + printf ("%g %u %u %g %g\n", p[0]/10., p[1], p[2], p[3]/10., p[4]/10.); + + return !ret; +} diff --git a/third_party/harfbuzz-ng/src/test-would-substitute.cc b/third_party/harfbuzz-ng/src/test-would-substitute.cc index d15aec4..4731e26 100644 --- a/third_party/harfbuzz-ng/src/test-would-substitute.cc +++ b/third_party/harfbuzz-ng/src/test-would-substitute.cc @@ -99,5 +99,5 @@ main (int argc, char **argv) (argc > 4 && !hb_font_glyph_from_string (font, argv[4], -1, &glyphs[1]))) return 2; - return !hb_ot_layout_would_substitute_lookup (face, strtol (argv[2], NULL, 0), glyphs, len, false); + return !hb_ot_layout_lookup_would_substitute (face, strtol (argv[2], NULL, 0), glyphs, len, false); } |