summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordrott <drott@chromium.org>2016-02-24 01:10:04 -0800
committerCommit bot <commit-bot@chromium.org>2016-02-24 09:11:19 +0000
commitaa0c4d1c5fa80154d0e9cab3df4c6aad4acb79d6 (patch)
tree3c38766b90e1a3c7dc3851c81d62c8491d7c9851
parent3b1a0eabd9367582b35ffea641da1ee07baf4501 (diff)
downloadchromium_src-aa0c4d1c5fa80154d0e9cab3df4c6aad4acb79d6.zip
chromium_src-aa0c4d1c5fa80154d0e9cab3df4c6aad4acb79d6.tar.gz
chromium_src-aa0c4d1c5fa80154d0e9cab3df4c6aad4acb79d6.tar.bz2
Roll HarfBuzz to 1.2.1
This release of HarfBuzz should help us with two important issues: non-fallback-path AAT shaping performance as well as cases where fallback fails due to ZWJ being shaped with the primary font. BUG=584655,576989 R=eae,kojii,behdad Review URL: https://codereview.chromium.org/1723043002 Cr-Commit-Position: refs/heads/master@{#377246}
-rw-r--r--third_party/harfbuzz-ng/NEWS33
-rw-r--r--third_party/harfbuzz-ng/README.chromium14
-rw-r--r--third_party/harfbuzz-ng/src/hb-blob.cc1
-rw-r--r--third_party/harfbuzz-ng/src/hb-buffer-private.hh3
-rw-r--r--third_party/harfbuzz-ng/src/hb-buffer.cc2
-rw-r--r--third_party/harfbuzz-ng/src/hb-common.cc2
-rw-r--r--third_party/harfbuzz-ng/src/hb-coretext.cc207
-rw-r--r--third_party/harfbuzz-ng/src/hb-directwrite.cc827
-rw-r--r--third_party/harfbuzz-ng/src/hb-directwrite.h34
-rw-r--r--third_party/harfbuzz-ng/src/hb-graphite2.cc71
-rw-r--r--third_party/harfbuzz-ng/src/hb-open-file-private.hh4
-rw-r--r--third_party/harfbuzz-ng/src/hb-open-type-private.hh9
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-head-table.hh4
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh30
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh132
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh6
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh4
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout-private.hh40
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-layout.cc136
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-shape-complex-indic.cc2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc2
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc4
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-shape.cc27
-rw-r--r--third_party/harfbuzz-ng/src/hb-ot-tag.cc4
-rw-r--r--third_party/harfbuzz-ng/src/hb-unicode-private.hh5
-rw-r--r--third_party/harfbuzz-ng/src/hb-version.h6
32 files changed, 1310 insertions, 311 deletions
diff --git a/third_party/harfbuzz-ng/NEWS b/third_party/harfbuzz-ng/NEWS
index 698256d..b1b63b2 100644
--- a/third_party/harfbuzz-ng/NEWS
+++ b/third_party/harfbuzz-ng/NEWS
@@ -1,3 +1,36 @@
+Overview of changes leading to 1.2.1
+Friday, February 23, 2016
+====================================
+
+- CoreText: Fix bug with wrong scale if font scale was changed later.
+ https://github.com/libass/libass/issues/212
+- CoreText: Drastically speed up font initialization.
+- CoreText: Fix tiny leak.
+- Group ZWJ/ZWNJ with previous syllable under cluster-level=0.
+ https://github.com/behdad/harfbuzz/issues/217
+- Add test/shaping/README.md about how to add tests to the suite.
+
+
+Overview of changes leading to 1.2.0
+Friday, February 19, 2016
+====================================
+
+- Fix various issues (hangs mostly) in case of memory allocation failure.
+- Change mark zeroing types of most shapers from BY_UNICODE_LATE to
+ BY_GDEF_LATE. This seems to be what Uniscribe does.
+- Change mark zeroing of USE shaper from NONE to BY_GDEF_EARLY. That's
+ what Windows does.
+- Allow GPOS cursive connection on marks, and fix the interaction with
+ mark attachment. This work resulted in some changes to how mark
+ attachments work. See:
+ https://github.com/behdad/harfbuzz/issues/211
+ https://github.com/behdad/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
+- Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
+- Add nmake-based build system for Windows.
+- Minor speedup.
+- Misc. improvements.
+
+
Overview of changes leading to 1.1.3
Monday, January 11, 2016
====================================
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 16fad93..f6c9be9 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,8 +1,8 @@
Name: harfbuzz-ng
Short Name: harfbuzz-ng
URL: http://harfbuzz.org
-Version: 1.1.3
-Date: 20151124
+Version: 1.2.1
+Date: 20160222
Security Critical: yes
License: MIT
License File: COPYING
@@ -20,5 +20,11 @@ the NEWS file from HarfBuzz' release notes, and bump the version numbers
in README.chromium.
Local changes:
-* Disabled test_langs_sorted() in hb-ot-tag.cc to fix
- "unused function" compile error
+ * Custom revert: Change mark strategy back to UNICODE_LATE from
+ GDEF_LATE for the default shaper - contributed by Behdad to unblock
+ the HarfBuzz roll in Blink while the issue about broken quote glyphs
+ in Times New Roman Italic can be resolved in upstream.
+ * Upstream commit ebd7431f824
+ "Partially revert 86c68c7a2c97"
+ in order to fix mark positioning in
+ fast/text/international/arabic-vertical-offset.html
diff --git a/third_party/harfbuzz-ng/src/hb-blob.cc b/third_party/harfbuzz-ng/src/hb-blob.cc
index a6870dc..fb48f03 100644
--- a/third_party/harfbuzz-ng/src/hb-blob.cc
+++ b/third_party/harfbuzz-ng/src/hb-blob.cc
@@ -104,7 +104,6 @@ hb_blob_create (const char *data,
if (!length ||
length >= 1u << 31 ||
- data + length < data /* overflows */ ||
!(blob = hb_object_create<hb_blob_t> ())) {
if (destroy)
destroy (user_data);
diff --git a/third_party/harfbuzz-ng/src/hb-buffer-private.hh b/third_party/harfbuzz-ng/src/hb-buffer-private.hh
index 4983f84..c8eec3c 100644
--- a/third_party/harfbuzz-ng/src/hb-buffer-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-buffer-private.hh
@@ -56,8 +56,7 @@ enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII = 0x00000001u,
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
- HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE = 0x00000008u,
- HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000010u,
+ HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
/* Reserved for complex shapers' internal use. */
HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc
index c731ed1..5f320bd 100644
--- a/third_party/harfbuzz-ng/src/hb-buffer.cc
+++ b/third_party/harfbuzz-ng/src/hb-buffer.cc
@@ -407,6 +407,8 @@ hb_buffer_t::move_to (unsigned int i)
idx = i;
return true;
}
+ if (unlikely (in_error))
+ return false;
assert (i <= out_len + (len - idx));
diff --git a/third_party/harfbuzz-ng/src/hb-common.cc b/third_party/harfbuzz-ng/src/hb-common.cc
index e091190..140ee0a 100644
--- a/third_party/harfbuzz-ng/src/hb-common.cc
+++ b/third_party/harfbuzz-ng/src/hb-common.cc
@@ -540,7 +540,7 @@ 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_user_data_item_t item = {NULL };
+ hb_user_data_item_t item = {NULL, NULL, NULL};
return items.find (key, &item, lock) ? item.data : NULL;
}
diff --git a/third_party/harfbuzz-ng/src/hb-coretext.cc b/third_party/harfbuzz-ng/src/hb-coretext.cc
index 04cf057..90c6653 100644
--- a/third_party/harfbuzz-ng/src/hb-coretext.cc
+++ b/third_party/harfbuzz-ng/src/hb-coretext.cc
@@ -27,7 +27,6 @@
*/
#define HB_SHAPER coretext
-#define hb_coretext_shaper_face_data_t CGFont
#include "hb-shaper-impl-private.hh"
#include "hb-coretext.h"
@@ -78,6 +77,29 @@ HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
* shaper face data
*/
+static CTFontDescriptorRef
+get_last_resort_font_desc (void)
+{
+ // TODO Handle allocation failures?
+ CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
+ CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
+ (const void **) &last_resort,
+ 1,
+ &kCFTypeArrayCallBacks);
+ CFRelease (last_resort);
+ CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
+ (const void **) &kCTFontCascadeListAttribute,
+ (const void **) &cascade_list,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease (cascade_list);
+
+ CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
+ CFRelease (attributes);
+ return font_desc;
+}
+
static void
release_data (void *info, const void *data, size_t size)
{
@@ -87,14 +109,13 @@ release_data (void *info, const void *data, size_t size)
hb_blob_destroy ((hb_blob_t *) info);
}
-hb_coretext_shaper_face_data_t *
-_hb_coretext_shaper_face_data_create (hb_face_t *face)
+static CGFontRef
+create_cg_font (hb_face_t *face)
{
- hb_coretext_shaper_face_data_t *data = NULL;
-
+ CGFontRef cg_font = NULL;
if (face->destroy == (hb_destroy_func_t) CGFontRelease)
{
- data = CGFontRetain ((CGFontRef) face->user_data);
+ cg_font = CGFontRetain ((CGFontRef) face->user_data);
}
else
{
@@ -107,13 +128,76 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
CGDataProviderRef provider = CGDataProviderCreateWithData (blob, blob_data, blob_length, &release_data);
if (likely (provider))
{
- data = CGFontCreateWithDataProvider (provider);
+ cg_font = CGFontCreateWithDataProvider (provider);
+ if (unlikely (!cg_font))
+ DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
CGDataProviderRelease (provider);
}
}
+ return cg_font;
+}
- if (unlikely (!data)) {
- DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
+static CTFontRef
+create_ct_font (CGFontRef cg_font, CGFloat font_size)
+{
+ CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
+ if (unlikely (!ct_font)) {
+ DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
+ return NULL;
+ }
+
+ /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
+ * font fallback which we don't need anyway. */
+ {
+ CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
+ CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
+ CFRelease (last_resort_font_desc);
+ if (new_ct_font)
+ {
+ CFRelease (ct_font);
+ ct_font = new_ct_font;
+ }
+ else
+ DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
+ }
+
+ return ct_font;
+}
+
+struct hb_coretext_shaper_face_data_t {
+ CGFontRef cg_font;
+ CTFontRef ct_font;
+};
+
+hb_coretext_shaper_face_data_t *
+_hb_coretext_shaper_face_data_create (hb_face_t *face)
+{
+ hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
+ if (unlikely (!data))
+ return NULL;
+
+ data->cg_font = create_cg_font (face);
+ if (unlikely (!data->cg_font))
+ {
+ DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
+ free (data);
+ return NULL;
+ }
+
+ /* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
+ * which can make the font too tight at large sizes. 36pt should be a good semi-neutral
+ * size.
+ *
+ * Since we always create CTFont at a fixed size, our CTFont lives in face_data
+ * instead of font_data. Which is good, because when people change scale on
+ * hb_font_t, we won't need to update our CTFont. */
+ data->ct_font = create_ct_font (data->cg_font, 36.);
+ if (unlikely (!data->ct_font))
+ {
+ DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
+ CFRelease (data->cg_font);
+ free (data);
+ return NULL;
}
return data;
@@ -122,7 +206,9 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
void
_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
{
- CFRelease (data);
+ CFRelease (data->ct_font);
+ CFRelease (data->cg_font);
+ free (data);
}
/*
@@ -133,7 +219,7 @@ 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;
+ return face_data->cg_font;
}
@@ -141,86 +227,17 @@ hb_coretext_face_get_cg_font (hb_face_t *face)
* shaper font data
*/
-struct hb_coretext_shaper_font_data_t {
- CTFontRef ct_font;
- CGFloat x_mult, y_mult; /* From CT space to HB space. */
-};
+struct hb_coretext_shaper_font_data_t {};
hb_coretext_shaper_font_data_t *
-_hb_coretext_shaper_font_data_create (hb_font_t *font)
+_hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
{
- if (unlikely (!hb_coretext_shaper_face_data_ensure (font->face))) return NULL;
-
- hb_coretext_shaper_font_data_t *data = (hb_coretext_shaper_font_data_t *) calloc (1, sizeof (hb_coretext_shaper_font_data_t));
- if (unlikely (!data))
- return NULL;
-
- hb_face_t *face = font->face;
- hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
-
- /* Choose a CoreText font size and calculate multipliers to convert to HarfBuzz space. */
- /* TODO: use upem instead of 36? */
- CGFloat font_size = 36.; /* Default... */
- /* No idea if the following is even a good idea. */
- if (font->y_ppem)
- font_size = font->y_ppem;
-
- if (font_size < 0)
- font_size = -font_size;
- data->x_mult = (CGFloat) font->x_scale / font_size;
- data->y_mult = (CGFloat) font->y_scale / font_size;
- data->ct_font = CTFontCreateWithGraphicsFont (face_data, font_size, NULL, NULL);
- if (unlikely (!data->ct_font)) {
- DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
- free (data);
- return NULL;
- }
-
- /* Create font copy with cascade list that has LastResort first; this speeds up CoreText
- * font fallback which we don't need anyway. */
- {
- // TODO Handle allocation failures?
- CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0);
- CFArrayRef cascade_list = CFArrayCreate (kCFAllocatorDefault,
- (const void **) &last_resort,
- 1,
- &kCFTypeArrayCallBacks);
- CFRelease (last_resort);
- CFDictionaryRef attributes = CFDictionaryCreate (kCFAllocatorDefault,
- (const void **) &kCTFontCascadeListAttribute,
- (const void **) &cascade_list,
- 1,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- CFRelease (cascade_list);
-
- CTFontDescriptorRef new_font_desc = CTFontDescriptorCreateWithAttributes (attributes);
- CFRelease (attributes);
-
- CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (data->ct_font, 0.0, NULL, new_font_desc);
- if (new_ct_font)
- {
- CFRelease (data->ct_font);
- data->ct_font = new_ct_font;
- }
- else
- DEBUG_MSG (CORETEXT, font, "Font copy with empty cascade list failed");
- }
-
- if (unlikely (!data->ct_font)) {
- DEBUG_MSG (CORETEXT, font, "Font CTFontCreateWithGraphicsFont() failed");
- free (data);
- return NULL;
- }
-
- return data;
+ return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
{
- CFRelease (data->ct_font);
- free (data);
}
@@ -246,9 +263,10 @@ _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
- 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;
+ hb_face_t *face = font->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->ct_font;
}
@@ -481,7 +499,10 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
{
hb_face_t *face = font->face;
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
- hb_coretext_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+ CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
+ CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
+ CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
/* Attach marks to their bases, to match the 'ot' shaper.
* Adapted from hb-ot-shape:hb_form_clusters().
@@ -490,6 +511,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
* continue pointing to B2 even though B2 was merged into B1's
* cluster... */
+ if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
{
hb_unicode_funcs_t *unicode = buffer->unicode;
unsigned int count = buffer->len;
@@ -612,7 +634,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
CFRelease (attributes);
- range->font = CTFontCreateCopyWithAttributes (font_data->ct_font, 0.0, NULL, font_desc);
+ range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
CFRelease (font_desc);
}
else
@@ -769,7 +791,7 @@ resize_and_retry:
CFRelease (lang);
}
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
- kCTFontAttributeName, font_data->ct_font);
+ kCTFontAttributeName, face_data->ct_font);
if (num_features)
{
@@ -862,7 +884,7 @@ resize_and_retry:
*/
CFDictionaryRef attributes = CTRunGetAttributes (run);
CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
- if (!CFEqual (run_ct_font, font_data->ct_font))
+ if (!CFEqual (run_ct_font, face_data->ct_font))
{
/* The run doesn't use our main font instance. We have to figure out
* whether font fallback happened, or this is just CoreText giving us
@@ -902,13 +924,13 @@ resize_and_retry:
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
if (run_cg_font)
{
- matched = CFEqual (run_cg_font, face_data);
+ matched = CFEqual (run_cg_font, face_data->cg_font);
CFRelease (run_cg_font);
}
}
if (!matched)
{
- CFStringRef font_ps_name = CTFontCopyName (font_data->ct_font, kCTFontPostScriptNameKey);
+ CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFontPostScriptNameKey);
CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
CFRelease (run_ps_name);
@@ -1028,7 +1050,6 @@ resize_and_retry:
positions = position_buf;
}
hb_glyph_info_t *info = run_info;
- CGFloat x_mult = font_data->x_mult, y_mult = font_data->y_mult;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
diff --git a/third_party/harfbuzz-ng/src/hb-directwrite.cc b/third_party/harfbuzz-ng/src/hb-directwrite.cc
new file mode 100644
index 0000000..af0fd3d
--- /dev/null
+++ b/third_party/harfbuzz-ng/src/hb-directwrite.cc
@@ -0,0 +1,827 @@
+/*
+ * Copyright © 2015 Ebrahim Byagowi
+ *
+ * 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.
+ */
+
+#define HB_SHAPER directwrite
+#include "hb-shaper-impl-private.hh"
+
+#include <dwrite.h>
+
+#include "hb-directwrite.h"
+
+#include "hb-open-file-private.hh"
+#include "hb-ot-name-table.hh"
+#include "hb-ot-tag.h"
+
+
+#ifndef HB_DEBUG_DIRECTWRITE
+#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
+#endif
+
+HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
+HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
+
+/*
+* shaper face data
+*/
+
+struct hb_directwrite_shaper_face_data_t {
+ HANDLE fh;
+ wchar_t face_name[LF_FACESIZE];
+};
+
+/* face_name should point to a wchar_t[LF_FACESIZE] object. */
+static void
+_hb_generate_unique_face_name(wchar_t *face_name, unsigned int *plen)
+{
+ /* We'll create a private name for the font from a UUID using a simple,
+ * somewhat base64-like encoding scheme */
+ const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
+ UUID id;
+ UuidCreate ((UUID*)&id);
+ ASSERT_STATIC (2 + 3 * (16 / 2) < LF_FACESIZE);
+ unsigned int name_str_len = 0;
+ face_name[name_str_len++] = 'F';
+ face_name[name_str_len++] = '_';
+ unsigned char *p = (unsigned char *)&id;
+ for (unsigned int i = 0; i < 16; i += 2)
+ {
+ /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
+ * using the bits in groups of 5,5,6 to select chars from enc.
+ * This will generate 24 characters; with the 'F_' prefix we already provided,
+ * the name will be 26 chars (plus the NUL terminator), so will always fit within
+ * face_name (LF_FACESIZE = 32). */
+ face_name[name_str_len++] = enc[p[i] >> 3];
+ face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
+ face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
+ }
+ face_name[name_str_len] = 0;
+ if (plen)
+ *plen = name_str_len;
+}
+
+/* Destroys blob. */
+static hb_blob_t *
+_hb_rename_font(hb_blob_t *blob, wchar_t *new_name)
+{
+ /* Create a copy of the font data, with the 'name' table replaced by a
+ * table that names the font with our private F_* name created above.
+ * For simplicity, we just append a new 'name' table and update the
+ * sfnt directory; the original table is left in place, but unused.
+ *
+ * The new table will contain just 5 name IDs: family, style, unique,
+ * full, PS. All of them point to the same name data with our unique name.
+ */
+
+ blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
+
+ unsigned int length, new_length, name_str_len;
+ const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
+
+ _hb_generate_unique_face_name (new_name, &name_str_len);
+
+ static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
+
+ unsigned int name_table_length = OT::name::min_size +
+ ARRAY_LENGTH(name_IDs) * OT::NameRecord::static_size +
+ name_str_len * 2; /* for name data in UTF16BE form */
+ unsigned int name_table_offset = (length + 3) & ~3;
+
+ new_length = name_table_offset + ((name_table_length + 3) & ~3);
+ void *new_sfnt_data = calloc(1, new_length);
+ if (!new_sfnt_data)
+ {
+ hb_blob_destroy (blob);
+ return NULL;
+ }
+
+ memcpy(new_sfnt_data, orig_sfnt_data, length);
+
+ OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
+ name.format.set (0);
+ name.count.set (ARRAY_LENGTH (name_IDs));
+ name.stringOffset.set (name.get_size());
+ for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
+ {
+ OT::NameRecord &record = name.nameRecord[i];
+ record.platformID.set(3);
+ record.encodingID.set(1);
+ record.languageID.set(0x0409u); /* English */
+ record.nameID.set(name_IDs[i]);
+ record.length.set(name_str_len * 2);
+ record.offset.set(0);
+ }
+
+ /* Copy string data from new_name, converting wchar_t to UTF16BE. */
+ unsigned char *p = &OT::StructAfter<unsigned char>(name);
+ for (unsigned int i = 0; i < name_str_len; i++)
+ {
+ *p++ = new_name[i] >> 8;
+ *p++ = new_name[i] & 0xff;
+ }
+
+ /* Adjust name table entry to point to new name table */
+ const OT::OpenTypeFontFile &file = *(OT::OpenTypeFontFile *) (new_sfnt_data);
+ unsigned int face_count = file.get_face_count ();
+ for (unsigned int face_index = 0; face_index < face_count; face_index++)
+ {
+ /* Note: doing multiple edits (ie. TTC) can be unsafe. There may be
+ * toe-stepping. But we don't really care. */
+ const OT::OpenTypeFontFace &face = file.get_face (face_index);
+ unsigned int index;
+ if (face.find_table_index (HB_OT_TAG_name, &index))
+ {
+ OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
+ record.checkSum.set_for_data (&name, name_table_length);
+ record.offset.set (name_table_offset);
+ record.length.set (name_table_length);
+ }
+ else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
+ {
+ free (new_sfnt_data);
+ hb_blob_destroy (blob);
+ return NULL;
+ }
+ }
+
+ /* The checkSumAdjustment field in the 'head' table is now wrong,
+ * but that doesn't actually seem to cause any problems so we don't
+ * bother. */
+
+ hb_blob_destroy (blob);
+ return hb_blob_create ((const char *)new_sfnt_data, new_length,
+ HB_MEMORY_MODE_WRITABLE, NULL, free);
+}
+
+hb_directwrite_shaper_face_data_t *
+_hb_directwrite_shaper_face_data_create(hb_face_t *face)
+{
+ hb_directwrite_shaper_face_data_t *data = (hb_directwrite_shaper_face_data_t *)calloc(1, sizeof (hb_directwrite_shaper_face_data_t));
+ if (unlikely (!data))
+ return NULL;
+
+ hb_blob_t *blob = hb_face_reference_blob (face);
+ if (unlikely (!hb_blob_get_length (blob)))
+ DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob");
+
+ blob = _hb_rename_font (blob, data->face_name);
+ if (unlikely (!blob))
+ {
+ free(data);
+ return NULL;
+ }
+
+ DWORD num_fonts_installed;
+ data->fh = AddFontMemResourceEx ((void *)hb_blob_get_data(blob, NULL),
+ hb_blob_get_length (blob),
+ 0, &num_fonts_installed);
+ if (unlikely (!data->fh))
+ {
+ DEBUG_MSG (DIRECTWRITE, face, "Face AddFontMemResourceEx() failed");
+ free (data);
+ return NULL;
+ }
+
+ return data;
+}
+
+void
+_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
+{
+ RemoveFontMemResourceEx(data->fh);
+ free(data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_directwrite_shaper_font_data_t {
+ HDC hdc;
+ LOGFONTW log_font;
+ HFONT hfont;
+};
+
+static bool
+populate_log_font (LOGFONTW *lf,
+ hb_font_t *font)
+{
+ memset (lf, 0, sizeof (*lf));
+ lf->lfHeight = -font->y_scale;
+ lf->lfCharSet = DEFAULT_CHARSET;
+
+ hb_face_t *face = font->face;
+ hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+
+ memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
+
+ return true;
+}
+
+hb_directwrite_shaper_font_data_t *
+_hb_directwrite_shaper_font_data_create (hb_font_t *font)
+{
+ if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
+
+ hb_directwrite_shaper_font_data_t *data = (hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
+ if (unlikely (!data))
+ return NULL;
+
+ data->hdc = GetDC (NULL);
+
+ if (unlikely (!populate_log_font (&data->log_font, font))) {
+ DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed");
+ _hb_directwrite_shaper_font_data_destroy (data);
+ return NULL;
+ }
+
+ data->hfont = CreateFontIndirectW (&data->log_font);
+ if (unlikely (!data->hfont)) {
+ DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed");
+ _hb_directwrite_shaper_font_data_destroy (data);
+ return NULL;
+ }
+
+ if (!SelectObject (data->hdc, data->hfont)) {
+ DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed");
+ _hb_directwrite_shaper_font_data_destroy (data);
+ return NULL;
+ }
+
+ return data;
+}
+
+void
+_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
+{
+ if (data->hdc)
+ ReleaseDC (NULL, data->hdc);
+ if (data->hfont)
+ DeleteObject (data->hfont);
+ free (data);
+}
+
+LOGFONTW *
+hb_directwrite_font_get_logfontw (hb_font_t *font)
+{
+ if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
+ hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+ return &font_data->log_font;
+}
+
+HFONT
+hb_directwrite_font_get_hfont (hb_font_t *font)
+{
+ if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
+ hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+ return font_data->hfont;
+}
+
+
+/*
+ * shaper shape_plan data
+ */
+
+struct hb_directwrite_shaper_shape_plan_data_t {};
+
+hb_directwrite_shaper_shape_plan_data_t *
+_hb_directwrite_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_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
+{
+}
+
+// Most of here TextAnalysis is originally written by Bas Schouten for Mozilla project
+// but now is relicensed to MIT for HarfBuzz use
+class TextAnalysis
+ : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
+{
+public:
+
+ IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
+ IFACEMETHOD_(ULONG, AddRef)() { return 1; }
+ IFACEMETHOD_(ULONG, Release)() { return 1; }
+
+ // A single contiguous run of characters containing the same analysis
+ // results.
+ struct Run
+ {
+ UINT32 mTextStart; // starting text position of this run
+ UINT32 mTextLength; // number of contiguous code units covered
+ UINT32 mGlyphStart; // starting glyph in the glyphs array
+ UINT32 mGlyphCount; // number of glyphs associated with this run of
+ // text
+ DWRITE_SCRIPT_ANALYSIS mScript;
+ UINT8 mBidiLevel;
+ bool mIsSideways;
+
+ inline bool ContainsTextPosition(UINT32 aTextPosition) const
+ {
+ return aTextPosition >= mTextStart
+ && aTextPosition < mTextStart + mTextLength;
+ }
+
+ Run *nextRun;
+ };
+
+public:
+ TextAnalysis(const wchar_t* text,
+ UINT32 textLength,
+ const wchar_t* localeName,
+ DWRITE_READING_DIRECTION readingDirection)
+ : mText(text)
+ , mTextLength(textLength)
+ , mLocaleName(localeName)
+ , mReadingDirection(readingDirection)
+ , mCurrentRun(NULL) { };
+
+ ~TextAnalysis() {
+ // delete runs, except mRunHead which is part of the TextAnalysis object
+ for (Run *run = mRunHead.nextRun; run;) {
+ Run *origRun = run;
+ run = run->nextRun;
+ delete origRun;
+ }
+ }
+
+ STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
+ Run **runHead) {
+ // Analyzes the text using the script analyzer and returns
+ // the result as a series of runs.
+
+ HRESULT hr = S_OK;
+
+ // Initially start out with one result that covers the entire range.
+ // This result will be subdivided by the analysis processes.
+ mRunHead.mTextStart = 0;
+ mRunHead.mTextLength = mTextLength;
+ mRunHead.mBidiLevel =
+ (mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
+ mRunHead.nextRun = NULL;
+ mCurrentRun = &mRunHead;
+
+ // Call each of the analyzers in sequence, recording their results.
+ if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
+ 0,
+ mTextLength,
+ this))) {
+ *runHead = &mRunHead;
+ }
+
+ return hr;
+ }
+
+ // IDWriteTextAnalysisSource implementation
+
+ IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition,
+ OUT WCHAR const** textString,
+ OUT UINT32* textLength)
+ {
+ if (textPosition >= mTextLength) {
+ // No text at this position, valid query though.
+ *textString = NULL;
+ *textLength = 0;
+ }
+ else {
+ *textString = mText + textPosition;
+ *textLength = mTextLength - textPosition;
+ }
+ return S_OK;
+ }
+
+ IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition,
+ OUT WCHAR const** textString,
+ OUT UINT32* textLength)
+ {
+ if (textPosition == 0 || textPosition > mTextLength) {
+ // Either there is no text before here (== 0), or this
+ // is an invalid position. The query is considered valid thouh.
+ *textString = NULL;
+ *textLength = 0;
+ }
+ else {
+ *textString = mText;
+ *textLength = textPosition;
+ }
+ return S_OK;
+ }
+
+ IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
+ GetParagraphReadingDirection() { return mReadingDirection; }
+
+ IFACEMETHODIMP GetLocaleName(UINT32 textPosition,
+ UINT32* textLength,
+ WCHAR const** localeName) {
+ return S_OK;
+ }
+
+ IFACEMETHODIMP
+ GetNumberSubstitution(UINT32 textPosition,
+ OUT UINT32* textLength,
+ OUT IDWriteNumberSubstitution** numberSubstitution)
+ {
+ // We do not support number substitution.
+ *numberSubstitution = NULL;
+ *textLength = mTextLength - textPosition;
+
+ return S_OK;
+ }
+
+ // IDWriteTextAnalysisSink implementation
+
+ IFACEMETHODIMP
+ SetScriptAnalysis(UINT32 textPosition,
+ UINT32 textLength,
+ DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
+ {
+ SetCurrentRun(textPosition);
+ SplitCurrentRun(textPosition);
+ while (textLength > 0) {
+ Run *run = FetchNextRun(&textLength);
+ run->mScript = *scriptAnalysis;
+ }
+
+ return S_OK;
+ }
+
+ IFACEMETHODIMP
+ SetLineBreakpoints(UINT32 textPosition,
+ UINT32 textLength,
+ const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
+
+ IFACEMETHODIMP SetBidiLevel(UINT32 textPosition,
+ UINT32 textLength,
+ UINT8 explicitLevel,
+ UINT8 resolvedLevel) { return S_OK; }
+
+ IFACEMETHODIMP
+ SetNumberSubstitution(UINT32 textPosition,
+ UINT32 textLength,
+ IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
+
+protected:
+ Run *FetchNextRun(IN OUT UINT32* textLength)
+ {
+ // Used by the sink setters, this returns a reference to the next run.
+ // Position and length are adjusted to now point after the current run
+ // being returned.
+
+ Run *origRun = mCurrentRun;
+ // Split the tail if needed (the length remaining is less than the
+ // current run's size).
+ if (*textLength < mCurrentRun->mTextLength) {
+ SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
+ }
+ else {
+ // Just advance the current run.
+ mCurrentRun = mCurrentRun->nextRun;
+ }
+ *textLength -= origRun->mTextLength;
+
+ // Return a reference to the run that was just current.
+ return origRun;
+ }
+
+ void SetCurrentRun(UINT32 textPosition)
+ {
+ // Move the current run to the given position.
+ // Since the analyzers generally return results in a forward manner,
+ // this will usually just return early. If not, find the
+ // corresponding run for the text position.
+
+ if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
+ return;
+ }
+
+ for (Run *run = &mRunHead; run; run = run->nextRun) {
+ if (run->ContainsTextPosition(textPosition)) {
+ mCurrentRun = run;
+ return;
+ }
+ }
+ //NS_NOTREACHED("We should always be able to find the text position in one \
+ // of our runs");
+ }
+
+ void SplitCurrentRun(UINT32 splitPosition)
+ {
+ if (!mCurrentRun) {
+ //NS_ASSERTION(false, "SplitCurrentRun called without current run.");
+ // Shouldn't be calling this when no current run is set!
+ return;
+ }
+ // Split the current run.
+ if (splitPosition <= mCurrentRun->mTextStart) {
+ // No need to split, already the start of a run
+ // or before it. Usually the first.
+ return;
+ }
+ Run *newRun = new Run;
+
+ *newRun = *mCurrentRun;
+
+ // Insert the new run in our linked list.
+ newRun->nextRun = mCurrentRun->nextRun;
+ mCurrentRun->nextRun = newRun;
+
+ // Adjust runs' text positions and lengths.
+ UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
+ newRun->mTextStart += splitPoint;
+ newRun->mTextLength -= splitPoint;
+ mCurrentRun->mTextLength = splitPoint;
+ mCurrentRun = newRun;
+ }
+
+protected:
+ // Input
+ // (weak references are fine here, since this class is a transient
+ // stack-based helper that doesn't need to copy data)
+ UINT32 mTextLength;
+ const WCHAR* mText;
+ const WCHAR* mLocaleName;
+ DWRITE_READING_DIRECTION mReadingDirection;
+
+ // Current processing state.
+ Run *mCurrentRun;
+
+ // Output is a list of runs starting here
+ Run mRunHead;
+};
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_directwrite_shape(hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features)
+{
+ hb_face_t *face = font->face;
+ hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
+ hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
+
+ // factory probably should be cached
+ IDWriteFactory* dwriteFactory;
+ DWriteCreateFactory(
+ DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown**>(&dwriteFactory)
+ );
+
+ IDWriteGdiInterop *gdiInterop;
+ dwriteFactory->GetGdiInterop (&gdiInterop);
+ IDWriteFontFace* fontFace;
+ gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace);
+
+ IDWriteTextAnalyzer* analyzer;
+ dwriteFactory->CreateTextAnalyzer (&analyzer);
+
+ unsigned int scratch_size;
+ hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
+#define ALLOCATE_ARRAY(Type, name, len) \
+ Type *name = (Type *) scratch; \
+ { \
+ unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
+ assert (_consumed <= scratch_size); \
+ scratch += _consumed; \
+ scratch_size -= _consumed; \
+ }
+
+#define utf16_index() var1.u32
+
+ ALLOCATE_ARRAY(WCHAR, pchars, buffer->len * 2);
+
+ unsigned int chars_len = 0;
+ for (unsigned int i = 0; i < buffer->len; i++)
+ {
+ hb_codepoint_t c = buffer->info[i].codepoint;
+ buffer->info[i].utf16_index() = chars_len;
+ if (likely(c <= 0xFFFFu))
+ pchars[chars_len++] = c;
+ else if (unlikely(c > 0x10FFFFu))
+ pchars[chars_len++] = 0xFFFDu;
+ else {
+ pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
+ pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
+ }
+ }
+
+ ALLOCATE_ARRAY(WORD, log_clusters, chars_len);
+ if (num_features)
+ {
+ /* Need log_clusters to assign features. */
+ chars_len = 0;
+ for (unsigned int i = 0; i < buffer->len; i++)
+ {
+ hb_codepoint_t c = buffer->info[i].codepoint;
+ unsigned int cluster = buffer->info[i].cluster;
+ log_clusters[chars_len++] = cluster;
+ if (hb_in_range(c, 0x10000u, 0x10FFFFu))
+ log_clusters[chars_len++] = cluster; /* Surrogates. */
+ }
+ }
+
+ HRESULT hr;
+ // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
+
+ DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ?
+ DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
+ DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
+
+ /*
+ * There's an internal 16-bit limit on some things inside the analyzer,
+ * but we never attempt to shape a word longer than 64K characters
+ * in a single gfxShapedWord, so we cannot exceed that limit.
+ */
+ UINT32 length = buffer->len;
+
+ TextAnalysis analysis(pchars, length, NULL, readingDirection);
+ TextAnalysis::Run *runHead;
+ hr = analysis.GenerateResults(analyzer, &runHead);
+
+ if (FAILED(hr)) {
+ //NS_WARNING("Analyzer failed to generate results.");
+ return false;
+ }
+
+ UINT32 maxGlyphs = 3 * length / 2 + 16;
+
+#define INITIAL_GLYPH_SIZE 400
+ UINT16* clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+ UINT16* glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+ DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
+ DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
+ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+
+ UINT32 actualGlyphs;
+
+ bool backward = HB_DIRECTION_IS_BACKWARD(buffer->props.direction);
+
+ wchar_t lang[4];
+ mbstowcs(lang, hb_language_to_string(buffer->props.language), 4);
+ hr = analyzer->GetGlyphs(pchars, length,
+ fontFace, FALSE,
+ buffer->props.direction,
+ &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
+ maxGlyphs, clusters, textProperties,
+ glyphs, glyphProperties, &actualGlyphs);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+ free(clusters);
+ free(glyphs);
+ free(textProperties);
+ free(glyphProperties);
+
+ clusters = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+ glyphs = (UINT16*)malloc(INITIAL_GLYPH_SIZE * sizeof(UINT16));
+ textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
+ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_TEXT_PROPERTIES));
+ glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
+ malloc(INITIAL_GLYPH_SIZE * sizeof(DWRITE_SHAPING_GLYPH_PROPERTIES));
+
+ hr = analyzer->GetGlyphs(pchars, length,
+ fontFace, FALSE,
+ buffer->props.direction,
+ &runHead->mScript, (const wchar_t*)lang, NULL, NULL, NULL, 0,
+ maxGlyphs, clusters, textProperties,
+ glyphs, glyphProperties, &actualGlyphs);
+ }
+ if (FAILED(hr)) {
+ //NS_WARNING("Analyzer failed to get glyphs.");
+ return false;
+ }
+
+ FLOAT advances[400];
+ DWRITE_GLYPH_OFFSET offsets[400];
+
+
+ /* The -2 in the following is to compensate for possible
+ * alignment needed after the WORD array. sizeof(WORD) == 2. */
+ unsigned int glyphs_size = (scratch_size * sizeof (int)-2)
+ / (sizeof (WORD) +
+ 4 + // sizeof (SCRIPT_GLYPHPROP) +
+ sizeof (int) +
+ 8 + // sizeof (GOFFSET) +
+ sizeof (uint32_t));
+ ALLOCATE_ARRAY(uint32_t, vis_clusters, glyphs_size);
+
+#undef ALLOCATE_ARRAY
+
+ hr = analyzer->GetGlyphPlacements(pchars,
+ clusters,
+ textProperties,
+ length,
+ glyphs,
+ glyphProperties,
+ actualGlyphs,
+ fontFace,
+ face->get_upem(),
+ FALSE,
+ FALSE,
+ &runHead->mScript,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ advances,
+ offsets);
+
+ if (FAILED(hr)) {
+ //NS_WARNING("Analyzer failed to get glyph placements.");
+ return false;
+ }
+
+ unsigned int glyphs_len = actualGlyphs;
+
+ /* Ok, we've got everything we need, now compose output buffer,
+ * very, *very*, carefully! */
+
+ /* Calculate visual-clusters. That's what we ship. */
+ for (unsigned int i = 0; i < glyphs_len; i++)
+ vis_clusters[i] = -1;
+ for (unsigned int i = 0; i < buffer->len; i++) {
+ uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
+ //*p = MIN (*p, buffer->info[i].cluster);
+ }
+ for (unsigned int i = 1; i < glyphs_len; i++)
+ if (vis_clusters[i] == -1)
+ vis_clusters[i] = vis_clusters[i - 1];
+
+#undef utf16_index
+
+ //if (unlikely (!buffer->ensure (glyphs_len)))
+ // FAIL ("Buffer in error");
+
+#undef FAIL
+
+ /* Set glyph infos */
+ buffer->len = 0;
+ for (unsigned int i = 0; i < glyphs_len; i++)
+ {
+ hb_glyph_info_t *info = &buffer->info[buffer->len++];
+
+ info->codepoint = glyphs[i];
+ info->cluster = vis_clusters[i];
+
+ /* The rest is crap. Let's store position info there for now. */
+ info->mask = advances[i];
+ info->var1.u32 = offsets[i].ascenderOffset;
+ info->var2.u32 = -offsets[i].advanceOffset;
+ }
+
+ free(clusters);
+ free(glyphs);
+ free(textProperties);
+ free(glyphProperties);
+
+ /* Set glyph positions */
+ buffer->clear_positions ();
+ for (unsigned int i = 0; i < glyphs_len; i++)
+ {
+ hb_glyph_info_t *info = &buffer->info[i];
+ hb_glyph_position_t *pos = &buffer->pos[i];
+
+ /* TODO vertical */
+ pos->x_advance = info->mask;
+ pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
+ pos->y_offset = info->var2.u32;
+ }
+
+ if (backward)
+ hb_buffer_reverse (buffer);
+
+ /* Wow, done! */
+ return true;
+}
diff --git a/third_party/harfbuzz-ng/src/hb-directwrite.h b/third_party/harfbuzz-ng/src/hb-directwrite.h
new file mode 100644
index 0000000..adf33df
--- /dev/null
+++ b/third_party/harfbuzz-ng/src/hb-directwrite.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2015 Ebrahim Byagowi
+ *
+ * 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.
+ */
+
+#ifndef HB_DIRECTWRITE_H
+#define HB_DIRECTWRITE_H
+
+#include "hb.h"
+
+HB_BEGIN_DECLS
+
+HB_END_DECLS
+
+#endif /* HB_UNISCRIBE_H */
diff --git a/third_party/harfbuzz-ng/src/hb-graphite2.cc b/third_party/harfbuzz-ng/src/hb-graphite2.cc
index f41093a..c32318d 100644
--- a/third_party/harfbuzz-ng/src/hb-graphite2.cc
+++ b/third_party/harfbuzz-ng/src/hb-graphite2.cc
@@ -216,6 +216,7 @@ struct hb_graphite2_cluster_t {
unsigned int base_glyph;
unsigned int num_glyphs;
unsigned int cluster;
+ float advance;
};
hb_bool_t
@@ -310,6 +311,12 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
hb_codepoint_t *pg = gids;
clusters[0].cluster = buffer->info[0].cluster;
+ float curradv = HB_DIRECTION_IS_BACKWARD(buffer->props.direction) ? gr_slot_origin_X(gr_seg_first_slot(seg)) : 0.;
+ if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ {
+ curradv = gr_slot_origin_X(gr_seg_first_slot(seg));
+ clusters[0].advance = gr_seg_advance_X(seg) - curradv;
+ }
for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
{
unsigned int before = gr_slot_before (is);
@@ -320,6 +327,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
{
clusters[ci-1].num_chars += clusters[ci].num_chars;
clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
+ clusters[ci-1].advance += clusters[ci].advance;
ci--;
}
@@ -331,13 +339,24 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
c->num_chars = before - c->base_char;
c->base_glyph = ic;
c->num_glyphs = 0;
- ci++;
+ if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ {
+ ci++;
+ clusters[ci].advance = curradv - gr_slot_origin_X(is);
+ } else {
+ clusters[ci].advance = gr_slot_origin_X(is) - curradv;
+ ci++;
+ }
+ curradv = gr_slot_origin_X(is);
}
clusters[ci].num_glyphs++;
if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
}
+
+ if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ clusters[ci].advance = gr_seg_advance_X(seg) - curradv;
ci++;
for (unsigned int i = 0; i < ci; ++i)
@@ -347,6 +366,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
info->codepoint = gids[clusters[i].base_glyph + j];
info->cluster = clusters[i].cluster;
+ info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance
}
}
buffer->len = glyph_count;
@@ -355,49 +375,44 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan,
/* Positioning. */
if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
{
- hb_glyph_position_t *pPos;
- for (pPos = hb_buffer_get_glyph_positions (buffer, NULL), is = gr_seg_first_slot (seg);
- is; pPos++, is = gr_slot_next_in_segment (is))
+ int currclus = -1;
+ const hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
+ curradvx = 0;
+ for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
{
pPos->x_offset = gr_slot_origin_X (is) - curradvx;
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
- pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
+ if (info->cluster != currclus) {
+ pPos->x_advance = info->var1.i32;
+ curradvx += pPos->x_advance;
+ currclus = info->cluster;
+ } else
+ pPos->x_advance = 0.;
+
pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
- curradvx += pPos->x_advance;
curradvy += pPos->y_advance;
}
- pPos[-1].x_advance += gr_seg_advance_X(seg) - curradvx;
}
else
{
- hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL) + buffer->len - 1;
- const hb_glyph_info_t *info = buffer->info + buffer->len - 1;
- const hb_glyph_info_t *tinfo;
- const gr_slot *tis;
int currclus = -1;
- float clusx = 0., clusy = 0.;
- for (is = gr_seg_last_slot (seg); is; pPos--, info--, is = gr_slot_prev_in_segment (is))
+ const hb_glyph_info_t *info = buffer->info;
+ hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, NULL);
+ curradvx = gr_seg_advance_X(seg);
+ for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
{
if (info->cluster != currclus)
{
- curradvx += clusx;
- curradvy += clusy;
+ pPos->x_advance = info->var1.i32;
+ if (currclus != -1) curradvx -= info[-1].var1.i32;
currclus = info->cluster;
- clusx = 0.;
- clusy = 0.;
- for (tis = is, tinfo = info; tis && tinfo->cluster == currclus; tis = gr_slot_prev_in_segment (tis), tinfo--)
- {
- clusx += gr_slot_advance_X (tis, grface, grfont);
- clusy += gr_slot_advance_Y (tis, grface, grfont) * yscale;
- }
- curradvx += clusx;
- curradvy += clusy;
- }
- pPos->x_advance = gr_slot_advance_X (is, grface, grfont);
+ } else
+ pPos->x_advance = 0.;
+
pPos->y_advance = gr_slot_advance_Y (is, grface, grfont) * yscale;
- curradvx -= pPos->x_advance;
curradvy -= pPos->y_advance;
- pPos->x_offset = gr_slot_origin_X (is) - curradvx;
+ pPos->x_offset = gr_slot_origin_X (is) - curradvx + pPos->x_advance;
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
}
hb_buffer_reverse_clusters (buffer);
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 152230a..5357ddc 100644
--- a/third_party/harfbuzz-ng/src/hb-open-file-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-open-file-private.hh
@@ -140,7 +140,7 @@ struct TTCHeaderVersion1
protected:
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
- FixedVersion version; /* Version of the TTC Header (1.0),
+ FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG>
table; /* Array of offsets to the OffsetTable for each font
@@ -187,7 +187,7 @@ struct TTCHeader
union {
struct {
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
- FixedVersion version; /* Version of the TTC Header (1.0 or 2.0),
+ FixedVersion<>version; /* Version of the TTC Header (1.0 or 2.0),
* 0x00010000u or 0x00020000u */
} header;
TTCHeaderVersion1 version1;
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 6323da8..6a52000 100644
--- a/third_party/harfbuzz-ng/src/hb-open-type-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh
@@ -739,9 +739,10 @@ struct CheckSum : ULONG
* Version Numbers
*/
+template <typename FixedType=USHORT>
struct FixedVersion
{
- inline uint32_t to_int (void) const { return (major << 16) + minor; }
+ inline uint32_t to_int (void) const { return (major << sizeof(FixedType)) + minor; }
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -749,10 +750,10 @@ struct FixedVersion
return_trace (c->check_struct (this));
}
- USHORT major;
- USHORT minor;
+ FixedType major;
+ FixedType minor;
public:
- DEFINE_SIZE_STATIC (4);
+ DEFINE_SIZE_STATIC (2 * sizeof(FixedType));
};
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 60644be..9c3e51e 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
@@ -61,9 +61,9 @@ struct head
}
protected:
- FixedVersion version; /* Version of the head table--currently
+ FixedVersion<>version; /* Version of the head table--currently
* 0x00010000u for version 1.0. */
- FixedVersion fontRevision; /* Set by font manufacturer. */
+ FixedVersion<>fontRevision; /* Set by font manufacturer. */
ULONG checkSumAdjustment; /* To compute: set it to 0, sum the
* entire font as ULONG, then store
* 0xB1B0AFBAu - sum. */
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 2411453..c8e9536 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
@@ -56,7 +56,7 @@ struct _hea
}
public:
- FixedVersion version; /* 0x00010000u for version 1.0. */
+ FixedVersion<>version; /* 0x00010000u for version 1.0. */
FWORD ascender; /* Typographic ascent. */
FWORD descender; /* Typographic descent. */
FWORD lineGap; /* Typographic line gap. */
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 64829ac..6c7bac0 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
@@ -1170,6 +1170,21 @@ struct Device
inline hb_position_t get_y_delta (hb_font_t *font) const
{ return get_delta (font->y_ppem, font->y_scale); }
+ inline unsigned int get_size (void) const
+ {
+ unsigned int f = deltaFormat;
+ if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
+ return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
+ }
+
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
+ }
+
+ private:
+
inline int get_delta (unsigned int ppem, int scale) const
{
if (!ppem) return 0;
@@ -1180,8 +1195,6 @@ struct Device
return (int) (pixels * (int64_t) scale / ppem);
}
-
-
inline int get_delta_pixels (unsigned int ppem_size) const
{
unsigned int f = deltaFormat;
@@ -1205,19 +1218,6 @@ struct Device
return delta;
}
- inline unsigned int get_size (void) const
- {
- unsigned int f = deltaFormat;
- if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size;
- return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
- }
-
- inline bool sanitize (hb_sanitize_context_t *c) const
- {
- TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && c->check_range (this, this->get_size ()));
- }
-
protected:
USHORT startSize; /* Smallest size to correct--in ppem */
USHORT endSize; /* Largest size to correct--in ppem */
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 bc36436..2b4bc5a 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
@@ -409,7 +409,7 @@ struct GDEF
protected:
- FixedVersion version; /* Version of the GDEF table--currently
+ FixedVersion<>version; /* Version of the GDEF table--currently
* 0x00010002u */
OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
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 5ea70fb..bbe390c 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
@@ -36,8 +36,17 @@ namespace OT {
/* buffer **position** var allocations */
-#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
-#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
+#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
+#define attach_type() var.u8[2] /* attachment type */
+/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
+
+enum attach_type_t {
+ ATTACH_TYPE_NONE = 0X00,
+
+ /* Each attachment should be either a mark or a cursive; can't be both. */
+ ATTACH_TYPE_MARK = 0X01,
+ ATTACH_TYPE_CURSIVE = 0X02,
+};
/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
@@ -425,7 +434,8 @@ struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage orde
hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = base_x - mark_x;
o.y_offset = base_y - mark_y;
- o.attach_lookback() = buffer->idx - glyph_pos;
+ o.attach_type() = ATTACH_TYPE_MARK;
+ o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
buffer->idx++;
@@ -907,9 +917,6 @@ struct CursivePosFormat1
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
- /* We don't handle mark glyphs here. */
- if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return_trace (false);
-
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
if (!this_record.exitAnchor) return_trace (false);
@@ -993,8 +1000,9 @@ struct CursivePosFormat1
*/
reverse_cursive_minor_offset (pos, child, c->direction, parent);
- pos[child].cursive_chain() = parent - child;
- buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE;
+ pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
+ pos[child].attach_chain() = (int) parent - (int) child;
+ buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
pos[child].y_offset = y_offset;
else
@@ -1069,7 +1077,7 @@ struct MarkBasePosFormat1
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return_trace (false);
- /* now we search backwards for a non-mark glyph */
+ /* Now we search backwards for a non-mark glyph */
hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
@@ -1081,7 +1089,7 @@ struct MarkBasePosFormat1
} while (1);
/* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
- if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+ //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
if (base_index == NOT_COVERED) return_trace (false);
@@ -1170,14 +1178,14 @@ struct MarkLigPosFormat1
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return_trace (false);
- /* now we search backwards for a non-mark glyph */
+ /* Now we search backwards for a non-mark glyph */
hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
if (!skippy_iter.prev ()) return_trace (false);
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
- if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
+ //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int j = skippy_iter.idx;
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
@@ -1501,7 +1509,8 @@ struct GPOS : GSUBGPOS
{ return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
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);
+ static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
+ static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
inline bool sanitize (hb_sanitize_context_t *c) const
{
@@ -1518,13 +1527,13 @@ struct GPOS : GSUBGPOS
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
{
- unsigned int j = pos[i].cursive_chain();
- if (likely (!j))
+ int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+ if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
return;
- j += i;
+ pos[i].attach_chain() = 0;
- pos[i].cursive_chain() = 0;
+ unsigned int j = (int) i + chain;
/* Stop if we see new parent in the chain. */
if (j == new_parent)
@@ -1537,62 +1546,68 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc
else
pos[j].x_offset = -pos[i].x_offset;
- pos[j].cursive_chain() = i - j;
+ pos[j].attach_chain() = -chain;
+ pos[j].attach_type() = type;
}
static void
-fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
+propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
{
- unsigned int j = pos[i].cursive_chain();
- if (likely (!j))
+ /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
+ * offset of glyph they are attached to. */
+ int chain = pos[i].attach_chain(), type = pos[i].attach_type();
+ if (likely (!chain))
return;
- j += i;
+ unsigned int j = (int) i + chain;
- pos[i].cursive_chain() = 0;
-
- fix_cursive_minor_offset (pos, j, direction);
-
- if (HB_DIRECTION_IS_HORIZONTAL (direction))
- pos[i].y_offset += pos[j].y_offset;
- else
- pos[i].x_offset += pos[j].x_offset;
-}
+ pos[i].attach_chain() = 0;
-static void
-fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
-{
- if (likely (!(pos[i].attach_lookback())))
- return;
+ propagate_attachment_offsets (pos, j, direction);
- unsigned int j = i - pos[i].attach_lookback();
+ assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
- pos[i].x_offset += pos[j].x_offset;
- pos[i].y_offset += pos[j].y_offset;
+ if (type & ATTACH_TYPE_CURSIVE)
+ {
+ if (HB_DIRECTION_IS_HORIZONTAL (direction))
+ pos[i].y_offset += pos[j].y_offset;
+ else
+ pos[i].x_offset += pos[j].x_offset;
+ }
+ else /*if (type & ATTACH_TYPE_MARK)*/
+ {
+ pos[i].x_offset += pos[j].x_offset;
+ pos[i].y_offset += pos[j].y_offset;
- if (HB_DIRECTION_IS_FORWARD (direction))
- for (unsigned int k = j; k < i; k++) {
- pos[i].x_offset -= pos[k].x_advance;
- pos[i].y_offset -= pos[k].y_advance;
- }
- else
- for (unsigned int k = j + 1; k < i + 1; k++) {
- pos[i].x_offset += pos[k].x_advance;
- pos[i].y_offset += pos[k].y_advance;
- }
+ assert (j < i);
+ if (HB_DIRECTION_IS_FORWARD (direction))
+ for (unsigned int k = j; k < i; k++) {
+ pos[i].x_offset -= pos[k].x_advance;
+ pos[i].y_offset -= pos[k].y_advance;
+ }
+ else
+ for (unsigned int k = j + 1; k < i + 1; k++) {
+ pos[i].x_offset += pos[k].x_advance;
+ pos[i].y_offset += pos[k].y_advance;
+ }
+ }
}
void
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
- buffer->clear_positions ();
-
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
- buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
+ buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
+}
+
+void
+GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+{
+ //_hb_buffer_assert_gsubgpos_vars (buffer);
}
void
-GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
+GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
_hb_buffer_assert_gsubgpos_vars (buffer);
@@ -1600,15 +1615,10 @@ GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
hb_direction_t direction = buffer->props.direction;
- /* Handle cursive connections */
- if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE)
- for (unsigned int i = 0; i < len; i++)
- fix_cursive_minor_offset (pos, i, direction);
-
/* Handle attachments */
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
for (unsigned int i = 0; i < len; i++)
- fix_mark_attachment (pos, i, direction);
+ propagate_attachment_offsets (pos, i, direction);
}
@@ -1637,8 +1647,8 @@ template <typename context_t>
}
-#undef attach_lookback
-#undef cursive_chain
+#undef attach_chain
+#undef attach_type
} /* namespace OT */
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 459a1a3..38c2c64 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
@@ -1268,7 +1268,6 @@ struct GSUB : GSUBGPOS
{ return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
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 bool sanitize (hb_sanitize_context_t *c) const
{
@@ -1297,11 +1296,6 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
}
}
-void
-GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
-{
-}
-
/* Out-of-class implementation for methods recursing */
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 d6db005..691334c 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
@@ -971,7 +971,7 @@ static inline bool apply_lookup (hb_apply_context_t *c,
match_positions[j] += delta;
}
- for (unsigned int i = 0; i < lookupCount; i++)
+ for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
{
unsigned int idx = lookupRecord[i].sequenceIndex;
if (idx >= count)
@@ -2277,7 +2277,7 @@ struct GSUBGPOS
}
protected:
- FixedVersion version; /* Version of the GSUB/GPOS table--initially set
+ FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
* to 0x00010000u */
OffsetTo<ScriptList>
scriptList; /* ScriptList table */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
index 7e199c2..c306849 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
@@ -218,7 +218,7 @@ struct JSTF
}
protected:
- FixedVersion version; /* Version of the JSTF table--initially set
+ FixedVersion<>version; /* Version of the JSTF table--initially set
* to 0x00010000u */
RecordArrayOf<JstfScript>
scriptList; /* Array of JstfScripts--listed
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 f48184f..b5c670f 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
@@ -99,21 +99,20 @@ hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
const hb_ot_layout_lookup_accelerator_t &accel);
-/* Should be called after all the substitute_lookup's are done */
-HB_INTERNAL void
-hb_ot_layout_substitute_finish (hb_font_t *font,
- hb_buffer_t *buffer);
-
-
-/* Should be called before all the position_lookup's are done. Resets positions to zero. */
+/* Should be called before all the position_lookup's are done. */
HB_INTERNAL void
hb_ot_layout_position_start (hb_font_t *font,
hb_buffer_t *buffer);
-/* Should be called after all the position_lookup's are done */
+/* Should be called after all the position_lookup's are done, to finish advances. */
HB_INTERNAL void
-hb_ot_layout_position_finish (hb_font_t *font,
- hb_buffer_t *buffer);
+hb_ot_layout_position_finish_advances (hb_font_t *font,
+ hb_buffer_t *buffer);
+
+/* Should be called after hb_ot_layout_position_finish_advances, to finish offsets. */
+HB_INTERNAL void
+hb_ot_layout_position_finish_offsets (hb_font_t *font,
+ hb_buffer_t *buffer);
@@ -257,8 +256,11 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
if (u == 0x200Cu) props |= UPROPS_MASK_ZWNJ;
if (u == 0x200Du) props |= UPROPS_MASK_ZWJ;
}
- else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK (gen_cat)))
+ else if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL (gen_cat)))
{
+ /* The above check is just an optimization to let in only things we need further
+ * processing on. */
+
/* Only Mn and Mc can have non-zero ccc:
* http://www.unicode.org/policies/stability_policy.html#Property_Value
* """
@@ -273,6 +275,16 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer)
* the "else if".
*/
props |= unicode->modified_combining_class (info->codepoint)<<8;
+
+ /* Recategorize emoji skin-tone modifiers as Unicode mark, so they
+ * behave correctly in non-native directionality. They originally
+ * are MODIFIER_SYMBOL. Fixes:
+ * https://github.com/behdad/harfbuzz/issues/169
+ */
+ if (unlikely (hb_in_range (u, 0x1F3FBu, 0x1F3FFu)))
+ {
+ props = gen_cat = HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
+ }
}
}
@@ -353,6 +365,12 @@ _hb_glyph_info_is_zwj (const hb_glyph_info_t *info)
return !!(info->unicode_props() & UPROPS_MASK_ZWJ);
}
+static inline hb_bool_t
+_hb_glyph_info_is_joiner (const hb_glyph_info_t *info)
+{
+ return !!(info->unicode_props() & (UPROPS_MASK_ZWNJ | UPROPS_MASK_ZWJ));
+}
+
static inline void
_hb_glyph_info_flip_joiners (hb_glyph_info_t *info)
{
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
index 9fc88f6..adf232b 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
@@ -771,12 +771,6 @@ hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
OT::GSUB::substitute_start (font, buffer);
}
-void
-hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
-{
- OT::GSUB::substitute_finish (font, buffer);
-}
-
/**
* hb_ot_layout_lookup_substitute_closure:
*
@@ -811,9 +805,15 @@ hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
}
void
-hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
+hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer)
+{
+ OT::GPOS::position_finish_advances (font, buffer);
+}
+
+void
+hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
{
- OT::GPOS::position_finish (font, buffer);
+ OT::GPOS::position_finish_offsets (font, buffer);
}
/**
@@ -902,20 +902,79 @@ struct GPOSProxy
};
-template <typename Obj>
+struct hb_get_subtables_context_t :
+ OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
+{
+ template <typename Type>
+ static inline bool apply_to (const void *obj, OT::hb_apply_context_t *c)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return typed_obj->apply (c);
+ }
+
+ typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_apply_context_t *c);
+
+ struct hb_applicable_t
+ {
+ inline void init (const void *obj_, hb_apply_func_t apply_func_)
+ {
+ obj = obj_;
+ apply_func = apply_func_;
+ }
+
+ inline bool apply (OT::hb_apply_context_t *c) const { return apply_func (obj, c); }
+
+ private:
+ const void *obj;
+ hb_apply_func_t apply_func;
+ };
+
+ typedef hb_auto_array_t<hb_applicable_t> array_t;
+
+ /* Dispatch interface. */
+ inline const char *get_name (void) { return "GET_SUBTABLES"; }
+ template <typename T>
+ inline return_t dispatch (const T &obj)
+ {
+ hb_applicable_t *entry = array.push();
+ if (likely (entry))
+ entry->init (&obj, apply_to<T>);
+ return HB_VOID;
+ }
+ static return_t default_return_value (void) { return HB_VOID; }
+ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
+
+ hb_get_subtables_context_t (array_t &array_) :
+ array (array_),
+ debug_depth (0) {}
+
+ array_t &array;
+ unsigned int debug_depth;
+};
+
static inline bool
apply_forward (OT::hb_apply_context_t *c,
- const Obj &obj,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const hb_ot_layout_lookup_accelerator_t &accel,
+ const hb_get_subtables_context_t::array_t &subtables)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
while (buffer->idx < buffer->len && !buffer->in_error)
{
+ bool applied = false;
if (accel.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
- c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
- obj.apply (c))
+ c->check_glyph_property (&buffer->cur(), c->lookup_props))
+ {
+ for (unsigned int i = 0; i < subtables.len; i++)
+ if (subtables[i].apply (c))
+ {
+ applied = true;
+ break;
+ }
+ }
+
+ if (applied)
ret = true;
else
buffer->next_glyph ();
@@ -923,11 +982,10 @@ apply_forward (OT::hb_apply_context_t *c,
return ret;
}
-template <typename Obj>
static inline bool
apply_backward (OT::hb_apply_context_t *c,
- const Obj &obj,
- const hb_ot_layout_lookup_accelerator_t &accel)
+ const hb_ot_layout_lookup_accelerator_t &accel,
+ const hb_get_subtables_context_t::array_t &subtables)
{
bool ret = false;
hb_buffer_t *buffer = c->buffer;
@@ -935,9 +993,15 @@ apply_backward (OT::hb_apply_context_t *c,
{
if (accel.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
- c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
- obj.apply (c))
- ret = true;
+ c->check_glyph_property (&buffer->cur(), c->lookup_props))
+ {
+ for (unsigned int i = 0; i < subtables.len; i++)
+ if (subtables[i].apply (c))
+ {
+ ret = true;
+ break;
+ }
+ }
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
@@ -946,26 +1010,6 @@ apply_backward (OT::hb_apply_context_t *c,
return ret;
}
-struct hb_apply_forward_context_t :
- OT::hb_dispatch_context_t<hb_apply_forward_context_t, bool, HB_DEBUG_APPLY>
-{
- inline const char *get_name (void) { return "APPLY_FWD"; }
- template <typename T>
- inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
- static return_t default_return_value (void) { return false; }
- bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
-
- hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
- const hb_ot_layout_lookup_accelerator_t &accel_) :
- c (c_),
- accel (accel_),
- debug_depth (0) {}
-
- OT::hb_apply_context_t *c;
- const hb_ot_layout_lookup_accelerator_t &accel;
- unsigned int debug_depth;
-};
-
template <typename Proxy>
static inline void
apply_string (OT::hb_apply_context_t *c,
@@ -979,6 +1023,10 @@ apply_string (OT::hb_apply_context_t *c,
c->set_lookup_props (lookup.get_props ());
+ hb_get_subtables_context_t::array_t subtables;
+ hb_get_subtables_context_t c_get_subtables (subtables);
+ lookup.dispatch (&c_get_subtables);
+
if (likely (!lookup.is_reverse ()))
{
/* in/out forward substitution/positioning */
@@ -987,13 +1035,7 @@ apply_string (OT::hb_apply_context_t *c,
buffer->idx = 0;
bool ret;
- if (lookup.get_subtable_count () == 1)
- {
- hb_apply_forward_context_t c_forward (c, accel);
- ret = lookup.dispatch (&c_forward);
- }
- else
- ret = apply_forward (c, lookup, accel);
+ ret = apply_forward (c, accel, subtables);
if (ret)
{
if (!Proxy::inplace)
@@ -1009,7 +1051,7 @@ apply_string (OT::hb_apply_context_t *c,
buffer->remove_output ();
buffer->idx = buffer->len - 1;
- apply_backward (c, lookup, accel);
+ apply_backward (c, accel, subtables);
}
}
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 27105af..943e390 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
@@ -58,7 +58,7 @@ struct maxp
/* We only implement version 0.5 as none of the extra fields in version 1.0 are useful. */
protected:
- FixedVersion version; /* Version of the maxp table (0.5 or 1.0),
+ FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0),
* 0x00005000u or 0x00010000u. */
USHORT numGlyphs; /* The number of glyphs in the font. */
public:
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 880aa91..21256de 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
@@ -1246,7 +1246,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len &&
+ while (buffer->idx < buffer->len && !buffer->in_error &&
last_syllable == buffer->cur().syllable() &&
buffer->cur().indic_category() == OT_Repha)
buffer->next_glyph ();
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
index 4d34468..7b04344 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar.cc
@@ -451,7 +451,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->idx = 0;
unsigned int last_syllable = 0;
- while (buffer->idx < buffer->len)
+ while (buffer->idx < buffer->len && !buffer->in_error)
{
unsigned int syllable = buffer->cur().syllable();
syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F);
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
index bd7c5e1..58392b6 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-thai.cc
@@ -377,6 +377,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
false,/* fallback_position */
};
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
index 03bcfee..a77b531 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-tibetan.cc
@@ -57,6 +57,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
true, /* fallback_position */
};
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
index 0f66783..6fbfe2b 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-use.cc
@@ -522,7 +522,7 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
/* TODO Set glyph_props? */
/* Insert dottedcircle after possible Repha. */
- while (buffer->idx < buffer->len &&
+ while (buffer->idx < buffer->len && !buffer->in_error &&
last_syllable == buffer->cur().syllable() &&
buffer->cur().use_category() == USE_R)
buffer->next_glyph ();
@@ -583,6 +583,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
NULL, /* decompose */
compose_use,
setup_masks_use,
- HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
+ HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
false, /* fallback_position */
};
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape.cc b/third_party/harfbuzz-ng/src/hb-ot-shape.cc
index 1d9783e..c13d94b 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape.cc
@@ -145,7 +145,7 @@ _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
struct hb_ot_shaper_font_data_t {};
hb_ot_shaper_font_data_t *
-_hb_ot_shaper_font_data_create (hb_font_t *font)
+_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
{
return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@@ -267,13 +267,14 @@ hb_form_clusters (hb_buffer_t *buffer)
buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES)
return;
- /* Loop duplicated in hb_ensure_native_direction(). */
+ /* Loop duplicated in hb_ensure_native_direction(), and in _hb-coretext.cc */
unsigned int base = 0;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 1; i < count; i++)
{
- if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))))
+ if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])) &&
+ !_hb_glyph_info_is_joiner (&info[i])))
{
buffer->merge_clusters (base, i);
base = i;
@@ -584,8 +585,6 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
c->plan->substitute (c->font, buffer);
- hb_ot_layout_substitute_finish (c->font, buffer);
-
return;
}
@@ -635,10 +634,6 @@ zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
static inline void
zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
{
- /* This one is a hack; Technically GDEF can mark ASCII glyphs as marks, but we don't listen. */
- if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII))
- return;
-
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
@@ -686,9 +681,12 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
static inline bool
hb_ot_position_complex (hb_ot_shape_context_t *c)
{
+ hb_ot_layout_position_start (c->font, c->buffer);
+
bool ret = false;
unsigned int count = c->buffer->len;
bool has_positioning = (bool) hb_ot_layout_has_positioning (c->face);
+
/* If the font has no GPOS, AND, no fallback positioning will
* happen, AND, direction is forward, then when zeroing mark
* widths, we shift the mark with it, such that the mark
@@ -763,22 +761,23 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
break;
}
+ /* Finishing off GPOS has to follow a certain order. */
+ hb_ot_layout_position_finish_advances (c->font, c->buffer);
+ hb_ot_zero_width_default_ignorables (c);
+ hb_ot_layout_position_finish_offsets (c->font, c->buffer);
+
return ret;
}
static inline void
hb_ot_position (hb_ot_shape_context_t *c)
{
- hb_ot_layout_position_start (c->font, c->buffer);
+ c->buffer->clear_positions ();
hb_ot_position_default (c);
hb_bool_t fallback = !hb_ot_position_complex (c);
- hb_ot_zero_width_default_ignorables (c);
-
- hb_ot_layout_position_finish (c->font, c->buffer);
-
if (fallback && c->plan->shaper->fallback_position)
_hb_ot_shape_fallback_position (c->plan, c->font, c->buffer);
diff --git a/third_party/harfbuzz-ng/src/hb-ot-tag.cc b/third_party/harfbuzz-ng/src/hb-ot-tag.cc
index 5a3f4f9..9a6a120 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-tag.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-tag.cc
@@ -927,7 +927,7 @@ hb_ot_tag_to_language (hb_tag_t tag)
}
}
-#if 0
+#ifdef MAIN
static inline void
test_langs_sorted (void)
{
@@ -942,9 +942,7 @@ test_langs_sorted (void)
}
}
}
-#endif
-#ifdef MAIN
int
main (void)
{
diff --git a/third_party/harfbuzz-ng/src/hb-unicode-private.hh b/third_party/harfbuzz-ng/src/hb-unicode-private.hh
index ecbec51..44fbe58 100644
--- a/third_party/harfbuzz-ng/src/hb-unicode-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-unicode-private.hh
@@ -357,9 +357,10 @@ extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
FLAG (HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK) | \
FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
-#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK(gen_cat) \
+#define HB_UNICODE_GENERAL_CATEGORY_IS_NON_ENCLOSING_MARK_OR_MODIFIER_SYMBOL(gen_cat) \
(FLAG_SAFE (gen_cat) & \
(FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK) | \
- FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)))
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) | \
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL)))
#endif /* HB_UNICODE_PRIVATE_HH */
diff --git a/third_party/harfbuzz-ng/src/hb-version.h b/third_party/harfbuzz-ng/src/hb-version.h
index 848720f..3456e7d 100644
--- a/third_party/harfbuzz-ng/src/hb-version.h
+++ b/third_party/harfbuzz-ng/src/hb-version.h
@@ -37,10 +37,10 @@ HB_BEGIN_DECLS
#define HB_VERSION_MAJOR 1
-#define HB_VERSION_MINOR 1
-#define HB_VERSION_MICRO 3
+#define HB_VERSION_MINOR 2
+#define HB_VERSION_MICRO 1
-#define HB_VERSION_STRING "1.1.3"
+#define HB_VERSION_STRING "1.2.1"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \