From f4ac14944daa5778aa3cdb37113fbc5c774b40bf Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Sat, 7 Jan 2017 19:24:07 +0400 Subject: Update bundled HarfBuzz-NG copy to 1.4.1 Most important changes since 1.0: - New API. - Update to Unicode 9.0.0; add 6 more scripts. - Improved list of language tag mappings. - OpenType 1.8 Font Variations support. - Blacklist GDEF table of certain fonts. - Implement parsing of OpenType MATH table. - Implement CBDT/CBLC color font glyph extents. - Fix mark zeroing types of most shapers. - Allow GPOS cursive connection on marks, and fix the interaction with mark attachment. - Universal Shaping Engine fixes; update to latest draft from Microsoft. - Implement "shaping" of various Unicode space characters, even if the font does not support them. - Allow MultipleSubst to delete a glyph (matching Windows engine). - CoreText backend fixes and optimizations. - Optimizations and other improvements. [ChangeLog] Bundled HarfBuzz-NG copy updated to 1.4.1 Change-Id: Ie398fad8f6d3b98e3236f62a97caedc649511470 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/3rdparty/harfbuzz-ng/src/hb-coretext.cc | 267 +++++++++++++++++----------- 1 file changed, 165 insertions(+), 102 deletions(-) (limited to 'src/3rdparty/harfbuzz-ng/src/hb-coretext.cc') diff --git a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc b/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc index 76c81e48f4..9865bbba41 100644 --- a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc +++ b/src/3rdparty/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" @@ -91,6 +90,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) { @@ -100,15 +122,14 @@ 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 0 if (face->destroy == (hb_destroy_func_t) CGFontRelease) { - data = CGFontRetain ((CGFontRef) face->user_data); + cg_font = CGFontRetain ((CGFontRef) face->user_data); } else { @@ -121,18 +142,119 @@ _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); } } #else FontEngineFaceData *fontEngineFaceData = (FontEngineFaceData *) face->user_data; CoreTextFontEngineData *coreTextFontEngineData = (CoreTextFontEngineData *) fontEngineFaceData->user_data; - data = CGFontRetain (coreTextFontEngineData->cgFont); + cg_font = CGFontRetain (coreTextFontEngineData->cgFont); #endif + return cg_font; +} + +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; + } + + /* crbug.com/576941 and crbug.com/625902 and the investigation in the latter + * bug indicate that the cascade list reconfiguration occasionally causes + * crashes in CoreText on OS X 10.9, thus let's skip this step on older + * operating system versions. Except for the emoji font, where _not_ + * reconfiguring the cascade list causes CoreText crashes. For details, see + * crbug.com/549610 */ + // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h + if (&CTGetCoreTextVersion != NULL && CTGetCoreTextVersion() < 0x00070000) { + CFStringRef fontName = CTFontCopyPostScriptName (ct_font); + bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo; + CFRelease (fontName); + if (!isEmojiFont) + return ct_font; + } + + CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute); + + /* 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) + { + /* The CTFontCreateCopyWithAttributes call fails to stay on the same font + * when reconfiguring the cascade list and may switch to a different font + * when there are fonts that go by the same name, since the descriptor is + * just name and size. + * + * Avoid reconfiguring the cascade lists if the new font is outside the + * system locations that we cannot access from the sandboxed renderer + * process in Blink. This can be detected by the new file URL location + * that the newly found font points to. */ + CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute); + // Keep reconfigured font if URL cannot be retrieved (seems to be the case + // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606 + if (!original_url || !new_url || CFEqual (original_url, new_url)) { + CFRelease (ct_font); + ct_font = new_ct_font; + } else { + CFRelease (new_ct_font); + DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed."); + } + if (new_url) + CFRelease (new_url); + } + else + DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed"); + } + + if (original_url) + CFRelease (original_url); + 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; + } - if (unlikely (!data)) { - DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed"); + /* 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; @@ -141,7 +263,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); } /* @@ -152,7 +276,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; } @@ -160,56 +284,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; -#if 0 - 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); -#else - data->x_mult = data->y_mult = (CGFloat) 64.0f; - FontEngineFaceData *fontEngineFaceData = (FontEngineFaceData *) face->user_data; - CoreTextFontEngineData *coreTextFontEngineData = (CoreTextFontEngineData *) fontEngineFaceData->user_data; - data->ct_font = (CTFontRef) CFRetain (coreTextFontEngineData->ctFont); -#endif - 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); } @@ -222,7 +307,9 @@ struct hb_coretext_shaper_shape_plan_data_t {}; hb_coretext_shaper_shape_plan_data_t * _hb_coretext_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) + unsigned int num_user_features HB_UNUSED, + const int *coords HB_UNUSED, + unsigned int num_coords HB_UNUSED) { return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; } @@ -235,9 +322,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; } @@ -470,7 +558,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(). @@ -479,6 +570,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; @@ -601,7 +693,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 @@ -662,7 +754,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, pchars[chars_len++] = 0xFFFDu; else { pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10); - pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1)); + pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1)); } } @@ -719,7 +811,6 @@ resize_and_retry: scratch += old_scratch_used; scratch_size -= old_scratch_used; } -retry: { string_ref = CFStringCreateWithCharactersNoCopy (NULL, pchars, chars_len, @@ -759,7 +850,7 @@ retry: CFRelease (lang); } CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), - kCTFontAttributeName, font_data->ct_font); + kCTFontAttributeName, face_data->ct_font); if (num_features) { @@ -844,8 +935,6 @@ retry: run_advance = -run_advance; DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); - CFRange range = CTRunGetStringRange (run); - /* CoreText does automatic font fallback (AKA "cascading") for characters * not supported by the requested font, and provides no way to turn it off, * so we must detect if the returned run uses a font other than the requested @@ -854,7 +943,7 @@ retry: */ CFDictionaryRef attributes = CTRunGetAttributes (run); CTFontRef run_ct_font = static_cast(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 @@ -874,15 +963,11 @@ retry: * backend. * * However, even that wouldn't work if we were passed in the CGFont to - * begin with. - * - * Webkit uses a slightly different approach: it installs LastResort - * as fallback chain, and then checks PS name of used font against - * LastResort. That one is safe for any font except for LastResort, - * as opposed to ours, which can fail if we are using any uninstalled - * font that has the same name as an installed font. + * construct a hb_face to begin with. * * See: http://github.com/behdad/harfbuzz/pull/36 + * + * Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098 */ bool matched = false; for (unsigned int i = 0; i < range_records.len; i++) @@ -896,13 +981,13 @@ 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); @@ -912,6 +997,7 @@ retry: } if (!matched) { + CFRange range = CTRunGetStringRange (run); DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", range.location, range.location + range.length); if (!buffer->ensure_inplace (buffer->len + range.length)) @@ -963,13 +1049,7 @@ retry: if (num_glyphs == 0) continue; - /* ### temporary fix for QTBUG-38113 */ - /* CoreText throws away the PDF token, while the OpenType backend will add a zero-advance - * glyph for this. We need to make sure the two produce the same output. */ - UniChar endGlyph = CFStringGetCharacterAtIndex (string_ref, range.location + range.length - 1); - bool endsWithPDF = endGlyph == 0x202c; - - if (!buffer->ensure_inplace (buffer->len + num_glyphs + (endsWithPDF ? 1 : 0))) + if (!buffer->ensure_inplace (buffer->len + num_glyphs)) goto resize_and_retry; hb_glyph_info_t *run_info = buffer->info + buffer->len; @@ -1027,7 +1107,6 @@ 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; @@ -1060,20 +1139,6 @@ retry: info++; } } - if (endsWithPDF) { - /* Ensure a zero-advance glyph the PDF token */ - if (unlikely (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))) { - memmove (run_info + 1, run_info, num_glyphs * sizeof (hb_glyph_info_t)); - info = run_info; - } - info->codepoint = 0xffff; - info->cluster = log_clusters[range.location + range.length - 1]; - info->mask = 0; - info->var1.u32 = 0; - info->var2.u32 = 0; - - buffer->len++; - } SCRATCH_RESTORE(); advances_so_far += run_advance; } @@ -1176,10 +1241,6 @@ fail: * AAT shaper */ -HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, face) -HB_SHAPER_DATA_ENSURE_DECLARE(coretext_aat, font) - - /* * shaper face data */ @@ -1240,7 +1301,9 @@ struct hb_coretext_aat_shaper_shape_plan_data_t {}; hb_coretext_aat_shaper_shape_plan_data_t * _hb_coretext_aat_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) + unsigned int num_user_features HB_UNUSED, + const int *coords HB_UNUSED, + unsigned int num_coords HB_UNUSED) { return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED; } -- cgit v1.2.3