diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 15:05:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:33:47 +0000 |
commit | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch) | |
tree | d55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/third_party/blink/renderer/platform/fonts | |
parent | 2b94bfe47ccb6c08047959d1c26e392919550e86 (diff) | |
download | qtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz |
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922
Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/fonts')
55 files changed, 2150 insertions, 875 deletions
diff --git a/chromium/third_party/blink/renderer/platform/fonts/DEPS b/chromium/third_party/blink/renderer/platform/fonts/DEPS index 971791ef45b..d859ec63d6e 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/DEPS +++ b/chromium/third_party/blink/renderer/platform/fonts/DEPS @@ -13,8 +13,6 @@ include_rules = [ "+third_party/blink/renderer/platform/histogram.h", "+third_party/blink/renderer/platform/instrumentation", "+third_party/blink/renderer/platform/language.h", - "+third_party/blink/renderer/platform/layout_test_support.h", - "+third_party/blink/renderer/platform/layout_unit.h", "+third_party/blink/renderer/platform/mac/version_util_mac.h", "+third_party/blink/renderer/platform/platform_export.h", "+third_party/blink/renderer/platform/resolution_units.h", @@ -23,5 +21,6 @@ include_rules = [ "+third_party/blink/renderer/platform/shared_buffer.h", "+third_party/blink/renderer/platform/testing", "+third_party/blink/renderer/platform/text", + "+third_party/blink/renderer/platform/web_test_support.h", "+third_party/blink/renderer/platform/wtf", ] diff --git a/chromium/third_party/blink/renderer/platform/fonts/alternate_font_family.h b/chromium/third_party/blink/renderer/platform/fonts/alternate_font_family.h index 62ae63d6b66..2382615a524 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/alternate_font_family.h +++ b/chromium/third_party/blink/renderer/platform/fonts/alternate_font_family.h @@ -48,20 +48,20 @@ inline const AtomicString& AdjustFamilyNameToAvoidUnsupportedFonts( // 'Courier' is a bitmap font. On Mac on the other hand 'Courier' is // a truetype font. Thus pages asking for Courier are better of // using 'Courier New' on windows. - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Courier)) - return FontFamilyNames::Courier_New; + if (EqualIgnoringASCIICase(family_name, font_family_names::kCourier)) + return font_family_names::kCourierNew; // Alias 'MS Sans Serif' (bitmap font) -> 'Microsoft Sans Serif' // (truetype font). - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::MS_Sans_Serif)) - return FontFamilyNames::Microsoft_Sans_Serif; + if (EqualIgnoringASCIICase(family_name, font_family_names::kMSSansSerif)) + return font_family_names::kMicrosoftSansSerif; // Alias 'MS Serif' (bitmap) -> 'Times New Roman' (truetype font). // Alias 'Times' -> 'Times New Roman' (truetype font). // There's no 'Microsoft Sans Serif-equivalent' for Serif. - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::MS_Serif) || - EqualIgnoringASCIICase(family_name, FontFamilyNames::Times)) - return FontFamilyNames::Times_New_Roman; + if (EqualIgnoringASCIICase(family_name, font_family_names::kMSSerif) || + EqualIgnoringASCIICase(family_name, font_family_names::kTimes)) + return font_family_names::kTimesNewRoman; #endif return family_name; @@ -70,27 +70,27 @@ inline const AtomicString& AdjustFamilyNameToAvoidUnsupportedFonts( inline const AtomicString& AlternateFamilyName( const AtomicString& family_name) { // Alias Courier <-> Courier New - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Courier)) - return FontFamilyNames::Courier_New; + if (EqualIgnoringASCIICase(family_name, font_family_names::kCourier)) + return font_family_names::kCourierNew; #if !defined(OS_WIN) // On Windows, Courier New (truetype font) is always present and // Courier is a bitmap font. So, we don't want to map Courier New to // Courier. - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Courier_New)) - return FontFamilyNames::Courier; + if (EqualIgnoringASCIICase(family_name, font_family_names::kCourierNew)) + return font_family_names::kCourier; #endif // Alias Times and Times New Roman. - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Times)) - return FontFamilyNames::Times_New_Roman; - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Times_New_Roman)) - return FontFamilyNames::Times; + if (EqualIgnoringASCIICase(family_name, font_family_names::kTimes)) + return font_family_names::kTimesNewRoman; + if (EqualIgnoringASCIICase(family_name, font_family_names::kTimesNewRoman)) + return font_family_names::kTimes; // Alias Arial and Helvetica - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Arial)) - return FontFamilyNames::Helvetica; - if (EqualIgnoringASCIICase(family_name, FontFamilyNames::Helvetica)) - return FontFamilyNames::Arial; + if (EqualIgnoringASCIICase(family_name, font_family_names::kArial)) + return font_family_names::kHelvetica; + if (EqualIgnoringASCIICase(family_name, font_family_names::kHelvetica)) + return font_family_names::kArial; return g_empty_atom; } @@ -99,15 +99,15 @@ inline const AtomicString& GetFallbackFontFamily( const FontDescription& description) { switch (description.GenericFamily()) { case FontDescription::kSansSerifFamily: - return FontFamilyNames::sans_serif; + return font_family_names::kSansSerif; case FontDescription::kSerifFamily: - return FontFamilyNames::serif; + return font_family_names::kSerif; case FontDescription::kMonospaceFamily: - return FontFamilyNames::monospace; + return font_family_names::kMonospace; case FontDescription::kCursiveFamily: - return FontFamilyNames::cursive; + return font_family_names::kCursive; case FontDescription::kFantasyFamily: - return FontFamilyNames::fantasy; + return font_family_names::kFantasy; default: // Let the caller use the system default font. return g_empty_atom; diff --git a/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android.cc b/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android.cc index 6c8efc827f5..99aec1d670c 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android.cc @@ -56,7 +56,7 @@ static AtomicString DefaultFontFamily(sk_sp<SkFontMgr> font_manager) { // do here, use "Arial", the value LayoutTheme uses for CSS system font // keywords such as "menu". NOTREACHED(); - return FontFamilyNames::Arial; + return font_family_names::kArial; } static AtomicString DefaultFontFamily() { @@ -99,7 +99,7 @@ AtomicString FontCache::GetGenericFamilyNameForScript( // i18n fonts are likely not monospace. Monospace is mostly used // for code, but when i18n characters appear in monospace, system // fallback can still render the characters. - if (family_name == FontFamilyNames::webkit_monospace) + if (family_name == font_family_names::kWebkitMonospace) return family_name; // The CJK hack below should be removed, at latest when we have diff --git a/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android_test.cc b/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android_test.cc index efe8ddc64ef..5f03b588f82 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/android/font_cache_android_test.cc @@ -39,26 +39,25 @@ TEST(FontCacheAndroid, genericFamilyNameForScript) { FontDescription chinese; chinese.SetLocale(LayoutLocale::Get("zh")); - if (FontFamilyNames::webkit_standard.IsEmpty()) - FontFamilyNames::init(); + font_family_names::Init(); // For non-CJK, getGenericFamilyNameForScript should return the given // familyName. - EXPECT_EQ(FontFamilyNames::webkit_standard, + EXPECT_EQ(font_family_names::kWebkitStandard, FontCache::GetGenericFamilyNameForScript( - FontFamilyNames::webkit_standard, english)); - EXPECT_EQ(FontFamilyNames::webkit_monospace, + font_family_names::kWebkitStandard, english)); + EXPECT_EQ(font_family_names::kWebkitMonospace, FontCache::GetGenericFamilyNameForScript( - FontFamilyNames::webkit_monospace, english)); + font_family_names::kWebkitMonospace, english)); // For CJK, getGenericFamilyNameForScript should return CJK fonts except // monospace. - EXPECT_NE(FontFamilyNames::webkit_standard, + EXPECT_NE(font_family_names::kWebkitStandard, FontCache::GetGenericFamilyNameForScript( - FontFamilyNames::webkit_standard, chinese)); - EXPECT_EQ(FontFamilyNames::webkit_monospace, + font_family_names::kWebkitStandard, chinese)); + EXPECT_EQ(font_family_names::kWebkitMonospace, FontCache::GetGenericFamilyNameForScript( - FontFamilyNames::webkit_monospace, chinese)); + font_family_names::kWebkitMonospace, chinese)); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/font.cc b/chromium/third_party/blink/renderer/platform/fonts/font.cc index def231a9a7a..ef63a49a1f5 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font.cc @@ -31,13 +31,12 @@ #include "third_party/blink/renderer/platform/fonts/font_fallback_iterator.h" #include "third_party/blink/renderer/platform/fonts/font_fallback_list.h" #include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h" -#include "third_party/blink/renderer/platform/fonts/paint_text_blob.h" #include "third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" -#include "third_party/blink/renderer/platform/layout_unit.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/text/bidi_resolver.h" #include "third_party/blink/renderer/platform/text/character.h" #include "third_party/blink/renderer/platform/text/text_run.h" @@ -291,9 +290,8 @@ unsigned InterceptsFromBlobs(const ShapeResultBloberizer::BlobBuffer& blobs, SkScalar* offset_intercepts_buffer = nullptr; if (intercepts_buffer) offset_intercepts_buffer = &intercepts_buffer[num_intervals]; - num_intervals += - paint.getTextBlobIntercepts(blob_info.blob->ToSkTextBlob().get(), - bounds_array, offset_intercepts_buffer); + num_intervals += paint.getTextBlobIntercepts( + blob_info.blob.get(), bounds_array, offset_intercepts_buffer); } return num_intervals; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/font.h b/chromium/third_party/blink/renderer/platform/fonts/font.h index 559bd97f1d3..313afb7a155 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font.h @@ -29,7 +29,7 @@ #include "third_party/blink/renderer/platform/fonts/font_fallback_list.h" #include "third_party/blink/renderer/platform/fonts/font_fallback_priority.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" -#include "third_party/blink/renderer/platform/layout_unit.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/text/tab_size.h" #include "third_party/blink/renderer/platform/text/text_direction.h" diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc b/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc index ac44cca505d..b72da9f7015 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc @@ -89,10 +89,10 @@ FontPlatformData* FontCache::SystemFontPlatformData( const FontDescription& font_description) { const AtomicString& family = FontCache::SystemFontFamily(); #if defined(OS_LINUX) - if (family.IsEmpty() || family == FontFamilyNames::system_ui) + if (family.IsEmpty() || family == font_family_names::kSystemUi) return nullptr; #else - DCHECK(!family.IsEmpty() && family != FontFamilyNames::system_ui); + DCHECK(!family.IsEmpty() && family != font_family_names::kSystemUi); #endif return GetFontPlatformData(font_description, FontFaceCreationParams(family), AlternateFontName::kNoAlternate); @@ -110,7 +110,7 @@ FontPlatformData* FontCache::GetFontPlatformData( #if !defined(OS_MACOSX) if (creation_params.CreationType() == kCreateFontByFamily && - creation_params.Family() == FontFamilyNames::system_ui) { + creation_params.Family() == font_family_names::kSystemUi) { return SystemFontPlatformData(font_description); } #endif @@ -355,7 +355,8 @@ void FontCache::Purge(PurgeSeverity purge_severity) { void FontCache::AddClient(FontCacheClient* client) { CHECK(client); if (!font_cache_clients_) { - font_cache_clients_ = new HeapHashSet<WeakMember<FontCacheClient>>(); + font_cache_clients_ = + MakeGarbageCollected<HeapHashSet<WeakMember<FontCacheClient>>>(); font_cache_clients_.RegisterAsStaticReference(); } DCHECK(!font_cache_clients_->Contains(client)); diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description.h b/chromium/third_party/blink/renderer/platform/fonts/font_description.h index 15a999cb190..925923d8ff1 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_description.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_description.h @@ -179,7 +179,7 @@ class PLATFORM_EXPORT FontDescription { // family is "monospace" bool IsMonospace() const { return GenericFamily() == kMonospaceFamily && !Family().Next() && - Family().Family() == FontFamilyNames::webkit_monospace; + Family().Family() == font_family_names::kWebkitMonospace; } Kerning GetKerning() const { return static_cast<Kerning>(fields_.kerning_); } FontVariantEastAsian VariantEastAsian() const { diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc index a29433a64c5..85e8fbc134c 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.cc @@ -174,7 +174,7 @@ scoped_refptr<FontData> FontFallbackList::GetFontData( if (font_selector_) { // Try the user's preferred standard font. if (scoped_refptr<FontData> data = font_selector_->GetFontData( - font_description, FontFamilyNames::webkit_standard)) + font_description, font_family_names::kWebkitStandard)) return data; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_family_names.json5 b/chromium/third_party/blink/renderer/platform/fonts/font_family_names.json5 index 638bf7995fe..ac7a142f9bf 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_family_names.json5 +++ b/chromium/third_party/blink/renderer/platform/fonts/font_family_names.json5 @@ -1,6 +1,6 @@ { metadata: { - namespace: "FontFamily", + namespace: "font_family_names", export: "PLATFORM_EXPORT", }, diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc b/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc index 0d431a2eb65..abc03f40a1b 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_metrics.cc @@ -33,7 +33,7 @@ #include "third_party/blink/renderer/platform/fonts/font_platform_data.h" #include "third_party/blink/renderer/platform/fonts/vdmx_parser.h" -#include <SkPaint.h> +#include <SkFont.h> #include <SkTypeface.h> namespace blink { @@ -49,13 +49,13 @@ void FontMetrics::AscentDescentWithHacks( unsigned& visual_overflow_inflation_for_ascent, unsigned& visual_overflow_inflation_for_descent, const FontPlatformData& platform_data, - const SkPaint& paint, + const SkFont& font, bool subpixel_ascent_descent) { - SkTypeface* face = paint.getTypeface(); + SkTypeface* face = font.getTypeface(); DCHECK(face); - SkPaint::FontMetrics metrics; - paint.getFontMetrics(&metrics); + SkFontMetrics metrics; + font.getMetrics(&metrics); int vdmx_ascent = 0, vdmx_descent = 0; bool is_vdmx_valid = false; @@ -66,9 +66,9 @@ void FontMetrics::AscentDescentWithHacks( // done. This code should be pushed into FreeType (hinted font metrics). static const uint32_t kVdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X'); int pixel_size = platform_data.size() + 0.5; - if (!paint.isAutohinted() && - (paint.getHinting() == SkPaint::kFull_Hinting || - paint.getHinting() == SkPaint::kNormal_Hinting)) { + if (!font.isForceAutoHinting() && + (font.getHinting() == SkFontHinting::kFull || + font.getHinting() == SkFontHinting::kNormal)) { size_t vdmx_size = face->getTableSize(kVdmxTag); if (vdmx_size && vdmx_size < kMaxVDMXTableSize) { uint8_t* vdmx_table = (uint8_t*)WTF::Partitions::FastMalloc( @@ -132,9 +132,9 @@ void FontMetrics::AscentDescentWithHacks( // incorrectly added to line spacing, so we use a 15% adjustment instead // and add it to the ascent. String family_name = platform_data.FontFamilyName(); - if (family_name == FontFamilyNames::Times || - family_name == FontFamilyNames::Helvetica || - family_name == FontFamilyNames::Courier) + if (family_name == font_family_names::kTimes || + family_name == font_family_names::kHelvetica || + family_name == font_family_names::kCourier) ascent += floorf(((ascent + descent) * 0.15f) + 0.5f); #endif } diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_metrics.h b/chromium/third_party/blink/renderer/platform/fonts/font_metrics.h index fbacc8cfee4..e440a79c627 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_metrics.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_metrics.h @@ -21,11 +21,11 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_METRICS_H_ #include "third_party/blink/renderer/platform/fonts/font_baseline.h" -#include "third_party/blink/renderer/platform/layout_unit.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" -#include <SkPaint.h> +class SkFont; namespace blink { @@ -168,7 +168,7 @@ class FontMetrics { unsigned& visual_overflow_inflation_for_ascent, unsigned& visual_overflow_inflation_for_descent, const FontPlatformData&, - const SkPaint&, + const SkFont&, bool subpixel_ascent_descent = false); private: diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc index 426c7db61e5..64dd8218e9a 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.cc @@ -20,6 +20,7 @@ #include "third_party/blink/renderer/platform/fonts/font_platform_data.h" +#include "SkFont.h" #include "SkTypeface.h" #include "build/build_config.h" #include "hb-ot.h" @@ -28,8 +29,8 @@ #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" #include "third_party/blink/renderer/platform/text/character.h" +#include "third_party/blink/renderer/platform/web_test_support.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/text/character_names.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" @@ -147,11 +148,11 @@ FontPlatformData::FontPlatformData(sk_sp<SkTypeface> typeface, auto system_style = QuerySystemRenderStyle(family_, text_size_, typeface_->fontStyle()); - // In layout tests, ignore system preference for subpixel positioning, + // In web tests, ignore system preference for subpixel positioning, // or explicitly disable if requested. - if (LayoutTestSupport::IsRunningLayoutTest()) { + if (WebTestSupport::IsRunningWebTest()) { system_style.use_subpixel_positioning = - LayoutTestSupport::IsTextSubpixelPositioningAllowedForTest() + WebTestSupport::IsTextSubpixelPositioningAllowedForTest() ? WebFontRenderStyle::kNoPreference : 0; } @@ -281,13 +282,9 @@ unsigned FontPlatformData::GetHash() const { #if !defined(OS_MACOSX) bool FontPlatformData::FontContainsCharacter(UChar32 character) { - PaintFont font; - SetupPaintFont(&font); - font.SetTextEncoding(SkPaint::kUTF32_TextEncoding); - - uint16_t glyph; - font.ToSkPaint().textToGlyphs(&character, sizeof(character), &glyph); - return glyph; + SkFont font; + SetupSkFont(&font); + return font.unicharToGlyph(character); } #endif @@ -314,18 +311,32 @@ WebFontRenderStyle FontPlatformData::QuerySystemRenderStyle( return result; } -void FontPlatformData::SetupPaintFont(PaintFont* font, - float device_scale_factor, - const Font*) const { - style_.ApplyToPaintFont(*font, device_scale_factor); +void FontPlatformData::SetupSkPaint(SkPaint* font, + float device_scale_factor, + const Font*) const { + style_.ApplyToSkPaint(*font, device_scale_factor); + + const float ts = text_size_ >= 0 ? text_size_ : 12; + font->setTextSize(SkFloatToScalar(ts)); + font->setTypeface(typeface_); + font->setFakeBoldText(synthetic_bold_); + font->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); + + font->setEmbeddedBitmapText(!avoid_embedded_bitmaps_); +} + +void FontPlatformData::SetupSkFont(SkFont* font, + float device_scale_factor, + const Font*) const { + style_.ApplyToSkFont(font, device_scale_factor); const float ts = text_size_ >= 0 ? text_size_ : 12; - font->SetTextSize(SkFloatToScalar(ts)); - font->SetTypeface(typeface_); - font->SetFakeBoldText(synthetic_bold_); - font->SetTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); + font->setSize(SkFloatToScalar(ts)); + font->setTypeface(typeface_); + font->setEmbolden(synthetic_bold_); + font->setSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); - font->SetEmbeddedBitmapText(!avoid_embedded_bitmaps_); + font->setEmbeddedBitmaps(!avoid_embedded_bitmaps_); } #endif diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h index ea701d0480a..7c6939331e2 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_platform_data.h @@ -38,7 +38,6 @@ #include "third_party/blink/public/platform/web_font_render_style.h" #include "third_party/blink/renderer/platform/fonts/font_description.h" #include "third_party/blink/renderer/platform/fonts/font_orientation.h" -#include "third_party/blink/renderer/platform/fonts/paint_font.h" #include "third_party/blink/renderer/platform/fonts/small_caps_iterator.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" @@ -66,6 +65,7 @@ inline NSFont* toNSFont(CTFontRef ctFontRef) { } #endif // defined(OS_MACOSX) +class SkFont; class SkTypeface; typedef uint32_t SkFontID; @@ -154,9 +154,14 @@ class PLATFORM_EXPORT FontPlatformData { const WebFontRenderStyle& GetFontRenderStyle() const { return style_; } #endif - void SetupPaintFont(PaintFont*, - float device_scale_factor = 1, - const Font* = nullptr) const; + // TODO(reed): SetupSkPaint is deprecated. Remove this once all call sites + // are moved to SetupSkFont. + void SetupSkPaint(SkPaint*, + float device_scale_factor = 1, + const Font* = nullptr) const; + void SetupSkFont(SkFont*, + float device_scale_factor = 1, + const Font* = nullptr) const; #if defined(OS_WIN) int PaintTextFlags() const { return paint_text_flags_; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_selector.cc b/chromium/third_party/blink/renderer/platform/fonts/font_selector.cc index 90bb107acbc..4e484041c51 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_selector.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_selector.cc @@ -18,7 +18,7 @@ AtomicString FontSelector::FamilyNameFromSettings( #if defined(OS_ANDROID) if (font_description.GenericFamily() == FontDescription::kStandardFamily) { return FontCache::GetGenericFamilyNameForScript( - FontFamilyNames::webkit_standard, font_description); + font_family_names::kWebkitStandard, font_description); } if (generic_family_name.StartsWith("-webkit-")) { @@ -29,19 +29,19 @@ AtomicString FontSelector::FamilyNameFromSettings( UScriptCode script = font_description.GetScript(); if (font_description.GenericFamily() == FontDescription::kStandardFamily) return settings.Standard(script); - if (generic_family_name == FontFamilyNames::webkit_serif) + if (generic_family_name == font_family_names::kWebkitSerif) return settings.Serif(script); - if (generic_family_name == FontFamilyNames::webkit_sans_serif) + if (generic_family_name == font_family_names::kWebkitSansSerif) return settings.SansSerif(script); - if (generic_family_name == FontFamilyNames::webkit_cursive) + if (generic_family_name == font_family_names::kWebkitCursive) return settings.Cursive(script); - if (generic_family_name == FontFamilyNames::webkit_fantasy) + if (generic_family_name == font_family_names::kWebkitFantasy) return settings.Fantasy(script); - if (generic_family_name == FontFamilyNames::webkit_monospace) + if (generic_family_name == font_family_names::kWebkitMonospace) return settings.Fixed(script); - if (generic_family_name == FontFamilyNames::webkit_pictograph) + if (generic_family_name == font_family_names::kWebkitPictograph) return settings.Pictograph(script); - if (generic_family_name == FontFamilyNames::webkit_standard) + if (generic_family_name == font_family_names::kWebkitStandard) return settings.Standard(script); #endif return g_empty_atom; diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm index 8b605043d91..829170dec12 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm +++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_cache_mac.mm @@ -39,9 +39,9 @@ #include "third_party/blink/renderer/platform/fonts/font_platform_data.h" #include "third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/scheduler/public/thread.h" +#include "third_party/blink/renderer/platform/web_test_support.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" @@ -63,12 +63,12 @@ const char kColorEmojiFontMac[] = "Apple Color Emoji"; // static const AtomicString& FontCache::LegacySystemFontFamily() { - return FontFamilyNames::BlinkMacSystemFont; + return font_family_names::kBlinkMacSystemFont; } static void InvalidateFontCache() { if (!IsMainThread()) { - Platform::Current()->MainThread()->GetTaskRunner()->PostTask( + Thread::MainThread()->GetTaskRunner()->PostTask( FROM_HERE, WTF::Bind(&InvalidateFontCache)); return; } @@ -87,9 +87,9 @@ static void FontCacheRegisteredFontsChangedNotificationCallback( } static bool UseHinting() { - // Enable hinting only when antialiasing is disabled in layout tests. - return (LayoutTestSupport::IsRunningLayoutTest() && - !LayoutTestSupport::IsFontAntialiasingEnabledForTest()); + // Enable hinting only when antialiasing is disabled in web tests. + return (WebTestSupport::IsRunningWebTest() && + !WebTestSupport::IsFontAntialiasingEnabledForTest()); } void FontCache::PlatformInit() { @@ -232,7 +232,7 @@ scoped_refptr<SimpleFontData> FontCache::GetLastResortFallbackFont( // For now we'll pick the default that the user would get without changing // any prefs. scoped_refptr<SimpleFontData> simple_font_data = - GetFontData(font_description, FontFamilyNames::Times, + GetFontData(font_description, font_family_names::kTimes, AlternateFontName::kAllowAlternate, should_retain); if (simple_font_data) return simple_font_data; @@ -241,7 +241,7 @@ scoped_refptr<SimpleFontData> FontCache::GetLastResortFallbackFont( // where the user doesn't have it, we fall back on Lucida Grande because // that's guaranteed to be there, according to Nathan Taylor. This is good // enough to avoid a crash at least. - return GetFontData(font_description, FontFamilyNames::Lucida_Grande, + return GetFontData(font_description, font_family_names::kLucidaGrande, AlternateFontName::kAllowAlternate, should_retain); } diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm index c6bced3e598..8d71fc2f18a 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm +++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac.mm @@ -174,7 +174,7 @@ NSFont* MatchNSFontFamily(const AtomicString& desired_family_string, float size) { DCHECK_NE(desired_family_string, FontCache::LegacySystemFontFamily()); - if (desired_family_string == FontFamilyNames::system_ui) { + if (desired_family_string == font_family_names::kSystemUi) { NSFont* font = nil; // Normally we'd use an availability macro here, but // systemFontOfSize:weight: is available but not visible on macOS 10.10, diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm index 67476f5a82b..c1d9ad62145 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm +++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_matcher_mac_test.mm @@ -19,7 +19,7 @@ namespace blink { void TestSystemFontContainsString(FontSelectionValue desired_weight, NSString* substring) { NSFont* font = - MatchNSFontFamily(FontFamilyNames::system_ui, 0, desired_weight, 11); + MatchNSFontFamily(font_family_names::kSystemUi, 0, desired_weight, 11); EXPECT_TRUE([font.description containsString:substring]); } diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm index 33b228f6b8a..97bebbdb53a 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm +++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.mm @@ -30,9 +30,10 @@ #import "third_party/blink/renderer/platform/fonts/font.h" #import "third_party/blink/renderer/platform/fonts/opentype/font_settings.h" #import "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" -#import "third_party/blink/renderer/platform/layout_test_support.h" +#import "third_party/blink/renderer/platform/web_test_support.h" #import "third_party/blink/renderer/platform/wtf/retain_ptr.h" #import "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#import "third_party/skia/include/core/SkFont.h" #import "third_party/skia/include/core/SkStream.h" #import "third_party/skia/include/ports/SkTypeface_mac.h" @@ -111,9 +112,9 @@ static sk_sp<SkTypeface> LoadFromBrowserProcess(NSFont* ns_font, return return_font; } -void FontPlatformData::SetupPaintFont(PaintFont* paint_font, - float, - const Font* font) const { +void FontPlatformData::SetupSkPaint(SkPaint* paint, + float, + const Font* font) const { bool should_smooth_fonts = true; bool should_antialias = true; bool should_subpixel_position = true; @@ -136,23 +137,23 @@ void FontPlatformData::SetupPaintFont(PaintFont* paint_font, } } - if (LayoutTestSupport::IsRunningLayoutTest()) { + if (WebTestSupport::IsRunningWebTest()) { should_smooth_fonts = false; - should_antialias = should_antialias && - LayoutTestSupport::IsFontAntialiasingEnabledForTest(); + should_antialias = + should_antialias && WebTestSupport::IsFontAntialiasingEnabledForTest(); should_subpixel_position = - LayoutTestSupport::IsTextSubpixelPositioningAllowedForTest(); + WebTestSupport::IsTextSubpixelPositioningAllowedForTest(); } - paint_font->SetAntiAlias(should_antialias); - paint_font->SetEmbeddedBitmapText(false); + paint->setAntiAlias(should_antialias); + paint->setEmbeddedBitmapText(false); const float ts = text_size_ >= 0 ? text_size_ : 12; - paint_font->SetTextSize(SkFloatToScalar(ts)); - paint_font->SetTypeface(typeface_); - paint_font->SetFakeBoldText(synthetic_bold_); - paint_font->SetTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); - paint_font->SetLcdRenderText(should_smooth_fonts); - paint_font->SetSubpixelText(should_subpixel_position); + paint->setTextSize(SkFloatToScalar(ts)); + paint->setTypeface(typeface_); + paint->setFakeBoldText(synthetic_bold_); + paint->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); + paint->setLCDRenderText(should_smooth_fonts); + paint->setSubpixelText(should_subpixel_position); // When rendering using CoreGraphics, disable hinting when // webkit-font-smoothing:antialiased or text-rendering:geometricPrecision is @@ -160,7 +161,64 @@ void FontPlatformData::SetupPaintFont(PaintFont* paint_font, if (font && (font->GetFontDescription().FontSmoothing() == kAntialiased || font->GetFontDescription().TextRendering() == kGeometricPrecision)) - paint_font->SetHinting(SkPaint::kNo_Hinting); + paint->setHinting(SkFontHinting::kNone); +} + +void FontPlatformData::SetupSkFont(SkFont* skfont, + float, + const Font* font) const { + bool should_smooth_fonts = true; + bool should_antialias = true; + bool should_subpixel_position = true; + + if (font) { + switch (font->GetFontDescription().FontSmoothing()) { + case kAntialiased: + should_smooth_fonts = false; + break; + case kSubpixelAntialiased: + break; + case kNoSmoothing: + should_antialias = false; + should_smooth_fonts = false; + break; + case kAutoSmoothing: + // For the AutoSmooth case, don't do anything! Keep the default + // settings. + break; + } + } + + if (WebTestSupport::IsRunningWebTest()) { + should_smooth_fonts = false; + should_antialias = + should_antialias && WebTestSupport::IsFontAntialiasingEnabledForTest(); + should_subpixel_position = + WebTestSupport::IsTextSubpixelPositioningAllowedForTest(); + } + + if (should_antialias && should_smooth_fonts) { + skfont->setEdging(SkFont::Edging::kSubpixelAntiAlias); + } else if (should_antialias) { + skfont->setEdging(SkFont::Edging::kAntiAlias); + } else { + skfont->setEdging(SkFont::Edging::kAlias); + } + skfont->setEmbeddedBitmaps(false); + const float ts = text_size_ >= 0 ? text_size_ : 12; + skfont->setSize(SkFloatToScalar(ts)); + skfont->setTypeface(typeface_); + skfont->setEmbolden(synthetic_bold_); + skfont->setSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); + skfont->setSubpixel(should_subpixel_position); + + // When rendering using CoreGraphics, disable hinting when + // webkit-font-smoothing:antialiased or text-rendering:geometricPrecision is + // used. See crbug.com/152304 + if (font && + (font->GetFontDescription().FontSmoothing() == kAntialiased || + font->GetFontDescription().TextRendering() == kGeometricPrecision)) + skfont->setHinting(SkFontHinting::kNone); } FontPlatformData::FontPlatformData(NSFont* ns_font, diff --git a/chromium/third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h b/chromium/third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h index e4b58a8a90b..d42fc22c15f 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h +++ b/chromium/third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h @@ -10,7 +10,7 @@ namespace blink { -class ShapeResult; +class ShapeResultView; // Bridge struct for painting text. Encapsulates info needed by the paint code. struct PLATFORM_EXPORT NGTextFragmentPaintInfo { @@ -23,7 +23,7 @@ struct PLATFORM_EXPORT NGTextFragmentPaintInfo { // The |shape_result| may not contain all characters of the |text|, but is // guaranteed to contain |from| to |to|. - const ShapeResult* shape_result; + const ShapeResultView* shape_result; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc index 0e0a808ac1c..f04b91d087b 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support_mpl.cc @@ -6,6 +6,7 @@ * * ***** END LICENSE BLOCK ***** */ +#include "base/stl_util.h" #include "third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h" #include <hb-ot.h> @@ -29,17 +30,18 @@ bool OpenTypeCapsSupport::SupportsOpenTypeFeature(hb_script_t script, return false; // Get the OpenType tag(s) that match this script code - hb_tag_t script_tags[] = { - HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE, - }; - hb_ot_tags_from_script(static_cast<hb_script_t>(script), &script_tags[0], - &script_tags[1]); + DCHECK_EQ(HB_TAG_NONE, 0u); + hb_tag_t script_tags[2] = {}; + unsigned num_returned_script_tags = base::size(script_tags); + hb_ot_tags_from_script_and_language( + static_cast<hb_script_t>(script), HB_LANGUAGE_INVALID, + &num_returned_script_tags, script_tags, nullptr, nullptr); const hb_tag_t kGSUB = HB_TAG('G', 'S', 'U', 'B'); unsigned script_index = 0; // Identify for which script a GSUB table is available. - hb_ot_layout_table_choose_script(face, kGSUB, script_tags, &script_index, - nullptr); + hb_ot_layout_table_select_script(face, kGSUB, num_returned_script_tags, + script_tags, &script_index, nullptr); if (hb_ot_layout_language_find_feature(face, kGSUB, script_index, HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h index d605c176897..12c90c9b174 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h @@ -29,7 +29,7 @@ #include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { -namespace OpenType { +namespace open_type { struct Int16 { DISALLOW_NEW(); @@ -101,6 +101,6 @@ struct TableBase { } }; -} // namespace OpenType +} // namespace open_type } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_OPEN_TYPE_TYPES_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc index 32362740417..39676595708 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc @@ -33,7 +33,7 @@ #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" namespace blink { -namespace OpenType { +namespace open_type { // The input characters are big-endian (first is most significant). #define OT_MAKE_TAG(ch1, ch2, ch3, ch4) \ @@ -50,46 +50,46 @@ const SkFontTableTag kVORGTag = OT_MAKE_TAG('V', 'O', 'R', 'G'); struct HheaTable { DISALLOW_NEW(); - OpenType::Fixed version; - OpenType::Int16 ascender; - OpenType::Int16 descender; - OpenType::Int16 line_gap; - OpenType::Int16 advance_width_max; - OpenType::Int16 min_left_side_bearing; - OpenType::Int16 min_right_side_bearing; - OpenType::Int16 x_max_extent; - OpenType::Int16 caret_slope_rise; - OpenType::Int16 caret_slope_run; - OpenType::Int16 caret_offset; - OpenType::Int16 reserved[4]; - OpenType::Int16 metric_data_format; - OpenType::UInt16 number_of_h_metrics; + open_type::Fixed version; + open_type::Int16 ascender; + open_type::Int16 descender; + open_type::Int16 line_gap; + open_type::Int16 advance_width_max; + open_type::Int16 min_left_side_bearing; + open_type::Int16 min_right_side_bearing; + open_type::Int16 x_max_extent; + open_type::Int16 caret_slope_rise; + open_type::Int16 caret_slope_run; + open_type::Int16 caret_offset; + open_type::Int16 reserved[4]; + open_type::Int16 metric_data_format; + open_type::UInt16 number_of_h_metrics; }; struct VheaTable { DISALLOW_NEW(); - OpenType::Fixed version; - OpenType::Int16 ascent; - OpenType::Int16 descent; - OpenType::Int16 line_gap; - OpenType::Int16 advance_height_max; - OpenType::Int16 min_top_side_bearing; - OpenType::Int16 min_bottom_side_bearing; - OpenType::Int16 y_max_extent; - OpenType::Int16 caret_slope_rise; - OpenType::Int16 caret_slope_run; - OpenType::Int16 caret_offset; - OpenType::Int16 reserved[4]; - OpenType::Int16 metric_data_format; - OpenType::UInt16 num_of_long_ver_metrics; + open_type::Fixed version; + open_type::Int16 ascent; + open_type::Int16 descent; + open_type::Int16 line_gap; + open_type::Int16 advance_height_max; + open_type::Int16 min_top_side_bearing; + open_type::Int16 min_bottom_side_bearing; + open_type::Int16 y_max_extent; + open_type::Int16 caret_slope_rise; + open_type::Int16 caret_slope_run; + open_type::Int16 caret_offset; + open_type::Int16 reserved[4]; + open_type::Int16 metric_data_format; + open_type::UInt16 num_of_long_ver_metrics; }; struct HmtxTable { DISALLOW_NEW(); struct Entry { DISALLOW_NEW(); - OpenType::UInt16 advance_width; - OpenType::Int16 lsb; + open_type::UInt16 advance_width; + open_type::Int16 lsb; } entries[1]; }; @@ -97,21 +97,21 @@ struct VmtxTable { DISALLOW_NEW(); struct Entry { DISALLOW_NEW(); - OpenType::UInt16 advance_height; - OpenType::Int16 top_side_bearing; + open_type::UInt16 advance_height; + open_type::Int16 top_side_bearing; } entries[1]; }; struct VORGTable { DISALLOW_NEW(); - OpenType::UInt16 major_version; - OpenType::UInt16 minor_version; - OpenType::Int16 default_vert_origin_y; - OpenType::UInt16 num_vert_origin_y_metrics; + open_type::UInt16 major_version; + open_type::UInt16 minor_version; + open_type::Int16 default_vert_origin_y; + open_type::UInt16 num_vert_origin_y_metrics; struct VertOriginYMetrics { DISALLOW_NEW(); - OpenType::UInt16 glyph_index; - OpenType::Int16 vert_origin_y; + open_type::UInt16 glyph_index; + open_type::Int16 vert_origin_y; } vert_origin_y_metrics[1]; size_t RequiredSize() const { @@ -122,7 +122,7 @@ struct VORGTable { #pragma pack() -} // namespace OpenType +} // namespace open_type OpenTypeVerticalData::OpenTypeVerticalData(sk_sp<SkTypeface> typeface) : default_vert_origin_y_(0), @@ -146,9 +146,9 @@ void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) { // Load hhea and hmtx to get x-component of vertical origins. // If these tables are missing, it's not an OpenType font. Vector<char> buffer; - CopyOpenTypeTable(typeface, OpenType::kHheaTag, buffer); - const OpenType::HheaTable* hhea = - OpenType::ValidateTable<OpenType::HheaTable>(buffer); + CopyOpenTypeTable(typeface, open_type::kHheaTag, buffer); + const open_type::HheaTable* hhea = + open_type::ValidateTable<open_type::HheaTable>(buffer); if (!hhea) return; uint16_t count_hmtx_entries = hhea->number_of_h_metrics; @@ -157,9 +157,10 @@ void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) { return; } - CopyOpenTypeTable(typeface, OpenType::kHmtxTag, buffer); - const OpenType::HmtxTable* hmtx = - OpenType::ValidateTable<OpenType::HmtxTable>(buffer, count_hmtx_entries); + CopyOpenTypeTable(typeface, open_type::kHmtxTag, buffer); + const open_type::HmtxTable* hmtx = + open_type::ValidateTable<open_type::HmtxTable>(buffer, + count_hmtx_entries); if (!hmtx) { DLOG(ERROR) << "hhea exists but hmtx does not (or broken)"; return; @@ -170,9 +171,9 @@ void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) { // Load vhea first. This table is required for fonts that support vertical // flow. - CopyOpenTypeTable(typeface, OpenType::kVheaTag, buffer); - const OpenType::VheaTable* vhea = - OpenType::ValidateTable<OpenType::VheaTable>(buffer); + CopyOpenTypeTable(typeface, open_type::kVheaTag, buffer); + const open_type::VheaTable* vhea = + open_type::ValidateTable<open_type::VheaTable>(buffer); if (!vhea) return; uint16_t count_vmtx_entries = vhea->num_of_long_ver_metrics; @@ -182,9 +183,9 @@ void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) { } // Load VORG. This table is optional. - CopyOpenTypeTable(typeface, OpenType::kVORGTag, buffer); - const OpenType::VORGTable* vorg = - OpenType::ValidateTable<OpenType::VORGTable>(buffer); + CopyOpenTypeTable(typeface, open_type::kVORGTag, buffer); + const open_type::VORGTable* vorg = + open_type::ValidateTable<open_type::VORGTable>(buffer); if (vorg && buffer.size() >= vorg->RequiredSize()) { default_vert_origin_y_ = vorg->default_vert_origin_y; uint16_t count_vert_origin_y_metrics = vorg->num_vert_origin_y_metrics; @@ -193,7 +194,7 @@ void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) { vert_origin_y_.Set(0, default_vert_origin_y_); } else { for (uint16_t i = 0; i < count_vert_origin_y_metrics; ++i) { - const OpenType::VORGTable::VertOriginYMetrics& metrics = + const open_type::VORGTable::VertOriginYMetrics& metrics = vorg->vert_origin_y_metrics[i]; vert_origin_y_.Set(metrics.glyph_index, metrics.vert_origin_y); } @@ -202,9 +203,10 @@ void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) { // Load vmtx then. This table is required for fonts that support vertical // flow. - CopyOpenTypeTable(typeface, OpenType::kVmtxTag, buffer); - const OpenType::VmtxTable* vmtx = - OpenType::ValidateTable<OpenType::VmtxTable>(buffer, count_vmtx_entries); + CopyOpenTypeTable(typeface, open_type::kVmtxTag, buffer); + const open_type::VmtxTable* vmtx = + open_type::ValidateTable<open_type::VmtxTable>(buffer, + count_vmtx_entries); if (!vmtx) { DLOG(ERROR) << "vhea exists but vmtx does not (or broken)"; return; @@ -219,20 +221,20 @@ void OpenTypeVerticalData::LoadMetrics(sk_sp<SkTypeface> typeface) { return; wtf_size_t size_extra = - buffer.size() - sizeof(OpenType::VmtxTable::Entry) * count_vmtx_entries; - if (size_extra % sizeof(OpenType::Int16)) { + buffer.size() - sizeof(open_type::VmtxTable::Entry) * count_vmtx_entries; + if (size_extra % sizeof(open_type::Int16)) { DLOG(ERROR) << "vmtx has incorrect tsb count"; return; } wtf_size_t count_top_side_bearings = - count_vmtx_entries + size_extra / sizeof(OpenType::Int16); + count_vmtx_entries + size_extra / sizeof(open_type::Int16); top_side_bearings_.resize(count_top_side_bearings); wtf_size_t i; for (i = 0; i < count_vmtx_entries; ++i) top_side_bearings_[i] = vmtx->entries[i].top_side_bearing; if (i < count_top_side_bearings) { - const OpenType::Int16* p_top_side_bearings_extra = - reinterpret_cast<const OpenType::Int16*>( + const open_type::Int16* p_top_side_bearings_extra = + reinterpret_cast<const open_type::Int16*>( &vmtx->entries[count_vmtx_entries]); for (; i < count_top_side_bearings; ++i, ++p_top_side_bearings_extra) top_side_bearings_[i] = *p_top_side_bearings_extra; @@ -261,7 +263,7 @@ float OpenTypeVerticalData::AdvanceHeight(Glyph glyph) const { } void OpenTypeVerticalData::GetVerticalTranslationsForGlyphs( - const SkPaint& paint, + const SkFont& font, const Glyph* glyphs, size_t count, float* out_xy_array) const { @@ -302,7 +304,7 @@ void OpenTypeVerticalData::GetVerticalTranslationsForGlyphs( float top_side_bearing = top_side_bearing_f_unit * size_per_unit_; SkRect skiaBounds; - SkiaTextMetrics(&paint).GetSkiaBoundsForGlyph(glyph, &skiaBounds); + SkFontGetBoundsForGlyph(font, glyph, &skiaBounds); FloatRect bounds(skiaBounds); out_xy_array[1] = bounds.Y() - top_side_bearing; continue; diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h index 109609279df..d6aa27105a2 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.h @@ -33,10 +33,11 @@ #include "third_party/blink/renderer/platform/wtf/ref_counted.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -#include <SkPaint.h> #include <SkRefCnt.h> #include <SkTypeface.h> +class SkFont; + namespace blink { class PLATFORM_EXPORT OpenTypeVerticalData @@ -55,7 +56,7 @@ class PLATFORM_EXPORT OpenTypeVerticalData bool HasVerticalMetrics() const { return !advance_heights_.IsEmpty(); } float AdvanceHeight(Glyph) const; - void GetVerticalTranslationsForGlyphs(const SkPaint&, + void GetVerticalTranslationsForGlyphs(const SkFont&, const Glyph*, size_t, float* out_xy_array) const; diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc index cd03dc5d349..bdb7d7bc845 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc @@ -28,9 +28,9 @@ namespace blink { -struct TestTable : OpenType::TableBase { - OpenType::Fixed version; - OpenType::Int16 ascender; +struct TestTable : open_type::TableBase { + open_type::Fixed version; + open_type::Int16 ascender; template <typename T> const T* ValidateOffset(const Vector<char>& buffer, uint16_t offset) const { @@ -40,21 +40,21 @@ struct TestTable : OpenType::TableBase { TEST(OpenTypeVerticalDataTest, ValidateTableTest) { Vector<char> buffer(sizeof(TestTable)); - const TestTable* table = OpenType::ValidateTable<TestTable>(buffer); + const TestTable* table = open_type::ValidateTable<TestTable>(buffer); EXPECT_TRUE(table); buffer = Vector<char>(sizeof(TestTable) - 1); - table = OpenType::ValidateTable<TestTable>(buffer); + table = open_type::ValidateTable<TestTable>(buffer); EXPECT_FALSE(table); buffer = Vector<char>(sizeof(TestTable) + 1); - table = OpenType::ValidateTable<TestTable>(buffer); + table = open_type::ValidateTable<TestTable>(buffer); EXPECT_TRUE(table); } TEST(OpenTypeVerticalDataTest, ValidateOffsetTest) { Vector<char> buffer(sizeof(TestTable)); - const TestTable* table = OpenType::ValidateTable<TestTable>(buffer); + const TestTable* table = open_type::ValidateTable<TestTable>(buffer); ASSERT_TRUE(table); // Test overflow diff --git a/chromium/third_party/blink/renderer/platform/fonts/paint_font.h b/chromium/third_party/blink/renderer/platform/fonts/paint_font.h deleted file mode 100644 index 1902b8ba259..00000000000 --- a/chromium/third_party/blink/renderer/platform/fonts/paint_font.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_PAINT_FONT_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_PAINT_FONT_H_ - -#include "cc/paint/paint_font.h" - -namespace blink { -using cc::PaintFont; -} - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_PAINT_FONT_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/paint_text_blob.h b/chromium/third_party/blink/renderer/platform/fonts/paint_text_blob.h deleted file mode 100644 index 978dc6392ca..00000000000 --- a/chromium/third_party/blink/renderer/platform/fonts/paint_text_blob.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_PAINT_TEXT_BLOB_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_PAINT_TEXT_BLOB_H_ - -#include "cc/paint/paint_text_blob.h" -#include "cc/paint/paint_text_blob_builder.h" - -namespace blink { -using cc::PaintTextBlob; -using cc::PaintTextBlobBuilder; -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_PAINT_TEXT_BLOB_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc index 86da0df514e..012238f1901 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator.cc @@ -10,6 +10,26 @@ namespace blink { +namespace { + +// UScriptCode and OpenType script are not 1:1; specifically, both Hiragana and +// Katakana map to 'kana' in OpenType. They will be mapped correctly in +// HarfBuzz, but normalizing earlier helps to reduce splitting runs between +// these scripts. +// https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags +inline UScriptCode getScriptForOpenType(UChar32 ch, UErrorCode* status) { + UScriptCode script = uscript_getScript(ch, status); + if (UNLIKELY(U_FAILURE(*status))) + return script; + if (UNLIKELY(script == USCRIPT_KATAKANA || + script == USCRIPT_KATAKANA_OR_HIRAGANA)) { + return USCRIPT_HIRAGANA; + } + return script; +} + +} // namespace + typedef ScriptData::PairedBracketType PairedBracketType; constexpr int ScriptRunIterator::kMaxScriptCount; @@ -27,6 +47,10 @@ void ICUScriptData::GetScripts(UChar32 ch, UScriptCodeList& dst) const { // regardless of the capacity passed to the call. So count can be greater // than dst->size(), if a later version of the unicode data has more // than kMaxScriptCount items. + + // |uscript_getScriptExtensions| do not need to be collated to + // USCRIPT_HIRAGANA because when ScriptExtensions contains Kana, it contains + // Hira as well, and Hira is always before Kana. int count = uscript_getScriptExtensions(ch, &dst[0], dst.size(), &status); if (status == U_BUFFER_OVERFLOW_ERROR) { // Allow this, we'll just use what we have. @@ -35,7 +59,7 @@ void ICUScriptData::GetScripts(UChar32 ch, UScriptCodeList& dst) const { count = dst.size(); status = U_ZERO_ERROR; } - UScriptCode primary_script = uscript_getScript(ch, &status); + UScriptCode primary_script = getScriptForOpenType(ch, &status); if (U_FAILURE(status)) { DLOG(ERROR) << "Could not get icu script data: " << status << " for 0x" diff --git a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc index 3e2a7a0e6eb..a792bdfb5c8 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/script_run_iterator_test.cc @@ -370,6 +370,50 @@ TEST_F(ScriptRunIteratorTest, Chinese) { CHECK_SCRIPT_RUNS({{"萬國碼", USCRIPT_HAN}}); } +struct JapaneseMixedScript { + const char* string; + // The expected primary_script when the string alone was evaluated. + UScriptCode script; +} japanese_mixed_scripts[] = {{"あ", USCRIPT_HIRAGANA}, + // Katakana should be normalized to Hiragana + {"ア", USCRIPT_HIRAGANA}, + // Script_Extensions=Hira Kana + {"\u30FC", USCRIPT_HIRAGANA}, + // Script_Extensions=Hani Hira Kana + {"\u303C", USCRIPT_HAN}, + // Script_Extensions=Bopo Hang Hani Hira Kana + {"\u3003", USCRIPT_BOPOMOFO}, + // Script_Extensions=Bopo Hang Hani Hira Kana Yiii + {"\u3001", USCRIPT_BOPOMOFO}}; + +class JapaneseMixedScriptTest + : public ScriptRunIteratorTest, + public testing::WithParamInterface<JapaneseMixedScript> {}; + +INSTANTIATE_TEST_CASE_P(ScriptRunIteratorTest, + JapaneseMixedScriptTest, + testing::ValuesIn(japanese_mixed_scripts)); + +TEST_P(JapaneseMixedScriptTest, Data) { + const auto& data = GetParam(); + std::string string(data.string); + + CheckRuns({{string.data(), data.script}}); + + // If the string follows Hiragana or Katakana, or is followed by Hiragnaa or + // Katakana, it should be normalized as Hiragana. + std::string hiragana("か"); + std::string katakana("カ"); + CheckRuns({{(hiragana + string).data(), USCRIPT_HIRAGANA}}); + CheckRuns({{(string + hiragana).data(), USCRIPT_HIRAGANA}}); + + CheckRuns({{(katakana + string).data(), USCRIPT_HIRAGANA}}); + CheckRuns({{(string + katakana).data(), USCRIPT_HIRAGANA}}); + + CheckRuns({{(hiragana + string + katakana).data(), USCRIPT_HIRAGANA}}); + CheckRuns({{(katakana + string + hiragana).data(), USCRIPT_HIRAGANA}}); +} + // Close bracket without matching open is ignored TEST_F(ScriptRunIteratorTest, UnbalancedParens1) { CHECK_SCRIPT_RUNS( diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/case_mapping_harfbuzz_buffer_filler.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/case_mapping_harfbuzz_buffer_filler.cc index 2ab8d8c22be..e6a5fff8636 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/case_mapping_harfbuzz_buffer_filler.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/case_mapping_harfbuzz_buffer_filler.cc @@ -38,8 +38,10 @@ CaseMappingHarfBuzzBufferFiller::CaseMappingHarfBuzzBufferFiller( case_mapped_text.Ensure16Bit(); if (case_mapped_text.length() != text.length()) { - FillSlowCase(case_map_intend, locale, text.Characters16(), text.length(), - start_index, num_characters); + String original_text = text; + original_text.Ensure16Bit(); + FillSlowCase(case_map_intend, locale, original_text.Characters16(), + original_text.length(), start_index, num_characters); return; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/glyph_bounds_accumulator.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/glyph_bounds_accumulator.h new file mode 100644 index 00000000000..06e1adb9fff --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/glyph_bounds_accumulator.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012 Google Inc. All rights reserved. + * Copyright (C) 2013 BlackBerry Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_BOUNDS_ACCUMULATOR_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_BOUNDS_ACCUMULATOR_H_ + +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" +#include "third_party/blink/renderer/platform/geometry/float_rect.h" + +namespace blink { + +// Helper class to accumulate glyph bounding box. +// +// Glyph positions and bounding boxes from HarfBuzz and fonts are in physical +// coordinate, while ShapeResult::glyph_bounding_box_ is in logical coordinate. +// To minimize the number of conversions, this class accumulates the bounding +// boxes in physical coordinate, and convert the accumulated box to logical. +struct GlyphBoundsAccumulator { + // Construct an accumulator with the logical glyph origin. + explicit GlyphBoundsAccumulator(float origin) : origin(origin) {} + + // The accumulated glyph bounding box in physical coordinate, until + // ConvertVerticalRunToLogical(). + FloatRect bounds; + // The current origin, in logical coordinate. + float origin; + + // Unite a glyph bounding box to |bounds|. + template <bool is_horizontal_run> + void Unite(const HarfBuzzRunGlyphData& glyph_data, + FloatRect bounds_for_glyph) { + if (UNLIKELY(bounds_for_glyph.IsEmpty())) + return; + + // Glyphs are drawn at |origin + offset|. Move glyph_bounds to that point. + // All positions in hb_glyph_position_t are relative to the current point. + // https://behdad.github.io/harfbuzz/harfbuzz-Buffers.html#hb-glyph-position-t-struct + if (is_horizontal_run) + bounds_for_glyph.SetX(bounds_for_glyph.X() + origin); + else + bounds_for_glyph.SetY(bounds_for_glyph.Y() + origin); + bounds_for_glyph.Move(glyph_data.offset); + + bounds.Unite(bounds_for_glyph); + } + + // Non-template version of |Unite()|, see above. + void Unite(bool is_horizontal_run, + const HarfBuzzRunGlyphData& glyph, + FloatRect bounds_for_glyph) { + is_horizontal_run ? Unite<true>(glyph, bounds_for_glyph) + : Unite<false>(glyph, bounds_for_glyph); + } + + // Convert vertical run glyph bounding box to logical. Horizontal runs do not + // need conversions because physical and logical are the same. + void ConvertVerticalRunToLogical(const FontMetrics& font_metrics) { + // Convert physical glyph_bounding_box to logical. + bounds = bounds.TransposedRect(); + + // The glyph bounding box of a vertical run uses ideographic baseline. + // Adjust the box Y position because the bounding box of a ShapeResult uses + // alphabetic baseline. + // See diagrams of base lines at + // https://drafts.csswg.org/css-writing-modes-3/#intro-baselines + int baseline_adjust = font_metrics.Ascent(kIdeographicBaseline) - + font_metrics.Ascent(kAlphabeticBaseline); + bounds.SetY(bounds.Y() + baseline_adjust); + } +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_GLYPH_BOUNDS_ACCUMULATOR_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc index b8bdb2a2c02..12a451129b9 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.cc @@ -49,9 +49,6 @@ #include <hb-ot.h> #include <hb.h> -#if defined(OS_MACOSX) -#include <hb-coretext.h> -#endif #include <SkPaint.h> #include <SkPath.h> @@ -123,6 +120,14 @@ static hb_bool_t HarfBuzzGetGlyph(hb_font_t* hb_font, variation_selector, glyph); } +static hb_bool_t HarfBuzzGetNominalGlyph(hb_font_t* hb_font, + void* font_data, + hb_codepoint_t unicode, + hb_codepoint_t* glyph, + void* user_data) { + return HarfBuzzGetGlyph(hb_font, font_data, unicode, 0, glyph, user_data); +} + static hb_position_t HarfBuzzGetGlyphHorizontalAdvance(hb_font_t* hb_font, void* font_data, hb_codepoint_t glyph, @@ -131,24 +136,23 @@ static hb_position_t HarfBuzzGetGlyphHorizontalAdvance(hb_font_t* hb_font, reinterpret_cast<HarfBuzzFontData*>(font_data); hb_position_t advance = 0; - SkiaTextMetrics(&hb_font_data->paint_) - .GetGlyphWidthForHarfBuzz(glyph, &advance); + SkFontGetGlyphWidthForHarfBuzz(hb_font_data->font_, glyph, &advance); return advance; } -static void HarfBuzzGetGlyphHorizontalAdvances(hb_font_t* font, - void* font_data, - unsigned count, - hb_codepoint_t* first_glyph, - unsigned int glyph_stride, - hb_position_t* first_advance, - unsigned int advance_stride, - void* user_data) { +static void HarfBuzzGetGlyphHorizontalAdvances( + hb_font_t* font, + void* font_data, + unsigned count, + const hb_codepoint_t* first_glyph, + unsigned int glyph_stride, + hb_position_t* first_advance, + unsigned int advance_stride, + void* user_data) { HarfBuzzFontData* hb_font_data = reinterpret_cast<HarfBuzzFontData*>(font_data); - SkiaTextMetrics(&hb_font_data->paint_) - .GetGlyphWidthForHarfBuzz(count, first_glyph, glyph_stride, first_advance, - advance_stride); + SkFontGetGlyphWidthForHarfBuzz(hb_font_data->font_, count, first_glyph, + glyph_stride, first_advance, advance_stride); } static hb_bool_t HarfBuzzGetGlyphVerticalOrigin(hb_font_t* hb_font, @@ -166,10 +170,10 @@ static hb_bool_t HarfBuzzGetGlyphVerticalOrigin(hb_font_t* hb_font, float result[] = {0, 0}; Glyph the_glyph = glyph; - vertical_data->GetVerticalTranslationsForGlyphs(hb_font_data->paint_, + vertical_data->GetVerticalTranslationsForGlyphs(hb_font_data->font_, &the_glyph, 1, result); - *x = SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(-result[0]); - *y = SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(-result[1]); + *x = SkiaScalarToHarfBuzzPosition(-result[0]); + *y = SkiaScalarToHarfBuzzPosition(-result[1]); return true; } @@ -182,42 +186,12 @@ static hb_position_t HarfBuzzGetGlyphVerticalAdvance(hb_font_t* hb_font, scoped_refptr<OpenTypeVerticalData> vertical_data = hb_font_data->VerticalData(); if (!vertical_data) { - return SkiaTextMetrics::SkiaScalarToHarfBuzzPosition( - hb_font_data->height_fallback_); + return SkiaScalarToHarfBuzzPosition(hb_font_data->height_fallback_); } Glyph the_glyph = glyph; float advance_height = -vertical_data->AdvanceHeight(the_glyph); - return SkiaTextMetrics::SkiaScalarToHarfBuzzPosition( - SkFloatToScalar(advance_height)); -} - -static hb_position_t HarfBuzzGetGlyphHorizontalKerning( - hb_font_t*, - void* font_data, - hb_codepoint_t left_glyph, - hb_codepoint_t right_glyph, - void*) { - HarfBuzzFontData* hb_font_data = - reinterpret_cast<HarfBuzzFontData*>(font_data); - if (hb_font_data->paint_.isVerticalText()) { - // We don't support cross-stream kerning - return 0; - } - - SkTypeface* typeface = hb_font_data->paint_.getTypeface(); - - const uint16_t glyphs[2] = {static_cast<uint16_t>(left_glyph), - static_cast<uint16_t>(right_glyph)}; - int32_t kerning_adjustments[1] = {0}; - - if (typeface->getKerningPairAdjustments(glyphs, 2, kerning_adjustments)) { - return SkiaTextMetrics::SkiaScalarToHarfBuzzPosition( - SkIntToScalar(kerning_adjustments[0]) * - hb_font_data->SizePerUnit(*typeface)); - } - - return 0; + return SkiaScalarToHarfBuzzPosition(SkFloatToScalar(advance_height)); } static hb_bool_t HarfBuzzGetGlyphExtents(hb_font_t* hb_font, @@ -228,8 +202,7 @@ static hb_bool_t HarfBuzzGetGlyphExtents(hb_font_t* hb_font, HarfBuzzFontData* hb_font_data = reinterpret_cast<HarfBuzzFontData*>(font_data); - SkiaTextMetrics(&hb_font_data->paint_) - .GetGlyphExtentsForHarfBuzz(glyph, extents); + SkFontGetGlyphExtentsForHarfBuzz(hb_font_data->font_, glyph, extents); return true; } @@ -304,7 +277,7 @@ unsigned HarfBuzzFace::UnitsPerEmFromHeadTable() { } bool HarfBuzzFace::ShouldSubpixelPosition() { - return harfbuzz_font_data_->paint_.isSubpixelText(); + return harfbuzz_font_data_->font_.isSubpixel(); } static hb_font_funcs_t* HarfBuzzSkiaGetFontFuncs() { @@ -314,13 +287,16 @@ static hb_font_funcs_t* HarfBuzzSkiaGetFontFuncs() { // HarfBuzz will use the fallback implementation if they aren't set. if (!funcs) { funcs = hb_font_funcs_create(); - hb_font_funcs_set_glyph_func(funcs, HarfBuzzGetGlyph, nullptr, nullptr); + hb_font_funcs_set_variation_glyph_func(funcs, HarfBuzzGetGlyph, nullptr, + nullptr); + hb_font_funcs_set_nominal_glyph_func(funcs, HarfBuzzGetNominalGlyph, + nullptr, nullptr); hb_font_funcs_set_glyph_h_advance_func( funcs, HarfBuzzGetGlyphHorizontalAdvance, nullptr, nullptr); hb_font_funcs_set_glyph_h_advances_func( funcs, HarfBuzzGetGlyphHorizontalAdvances, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func( - funcs, HarfBuzzGetGlyphHorizontalKerning, nullptr, nullptr); + // TODO(https://crbug.com/899718): Replace vertical metrics callbacks with + // HarfBuzz VORG/VMTX internal implementation by deregistering those. hb_font_funcs_set_glyph_v_advance_func( funcs, HarfBuzzGetGlyphVerticalAdvance, nullptr, nullptr); hb_font_funcs_set_glyph_v_origin_func(funcs, HarfBuzzGetGlyphVerticalOrigin, @@ -359,30 +335,26 @@ static hb_blob_t* HarfBuzzSkiaGetTable(hb_face_t* face, WTF::Partitions::FastFree); } +#if !defined(OS_MACOSX) static void DeleteTypefaceStream(void* stream_asset_ptr) { SkStreamAsset* stream_asset = reinterpret_cast<SkStreamAsset*>(stream_asset_ptr); delete stream_asset; } +#endif hb_face_t* HarfBuzzFace::CreateFace() { -#if defined(OS_MACOSX) - // hb_face_t needs to be instantiated using the CoreText constructor for - // compatibility with AAT font, in which case HarfBuzz' CoreText backend is - // used. If we encounter a FreeType backed SkTypeface, for variable fonts on - // Mac OS < 10.12, follow the regular OpenType-only codepath below. - if (platform_data_->CgFont()) { - hb_face_t* face = hb_coretext_face_create(platform_data_->CgFont()); - DCHECK(face); - return face; - } -#endif hb_face_t* face = nullptr; DEFINE_THREAD_SAFE_STATIC_LOCAL(BooleanHistogram, zero_copy_success_histogram, ("Blink.Fonts.HarfBuzzFaceZeroCopyAccess")); SkTypeface* typeface = platform_data_->Typeface(); CHECK(typeface); + // The attempt of doing zero copy-mmaped memory access to the font blobs does + // not work efficiently on Mac, since what is returned from + // typeface->openStream is a synthesized font assembled from copying all font + // tables on Mac. See the implementation of SkTypeface_Mac::onOpenStream. +#if !defined(OS_MACOSX) int ttc_index = 0; SkStreamAsset* typeface_stream = typeface->openStream(&ttc_index); if (typeface_stream && typeface_stream->getMemoryBase()) { @@ -394,6 +366,7 @@ hb_face_t* HarfBuzzFace::CreateFace() { hb_blob_destroy); face = hb_face_create(face_blob.get(), ttc_index); } +#endif // Fallback to table copies if there is no in-memory access. if (!face) { @@ -435,19 +408,15 @@ static_assert( hb_font_t* HarfBuzzFace::GetScaledFont( scoped_refptr<UnicodeRangeSet> range_set, VerticalLayoutCallbacks vertical_layout) const { - PaintFont paint_font; - platform_data_->SetupPaintFont(&paint_font); - paint_font.SetTextEncoding(SkPaint::kGlyphID_TextEncoding); harfbuzz_font_data_->range_set_ = std::move(range_set); - harfbuzz_font_data_->UpdateFallbackMetricsAndScale( - *platform_data_, paint_font.ToSkPaint(), vertical_layout); + harfbuzz_font_data_->UpdateFallbackMetricsAndScale(*platform_data_, + vertical_layout); - int scale = - SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(platform_data_->size()); + int scale = SkiaScalarToHarfBuzzPosition(platform_data_->size()); hb_font_set_scale(unscaled_font_, scale, scale); hb_font_set_ptem(unscaled_font_, platform_data_->size() / kCssPixelsPerPoint); - SkTypeface* typeface = harfbuzz_font_data_->paint_.getTypeface(); + SkTypeface* typeface = harfbuzz_font_data_->font_.getTypeface(); int axis_count = typeface->getVariationDesignPosition(nullptr, 0); if (axis_count > 0) { Vector<SkFontArguments::VariationPosition::Coordinate> axis_values; diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h index 69fa5f128a7..f3645969638 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h @@ -40,7 +40,7 @@ struct HarfBuzzFontData { public: HarfBuzzFontData() - : paint_(), + : font_(), space_in_gpos_(SpaceGlyphInOpenTypeTables::Unknown), space_in_gsub_(SpaceGlyphInOpenTypeTables::Unknown), vertical_data_(nullptr), @@ -51,19 +51,19 @@ struct HarfBuzzFontData { // layout information is found from the font. void UpdateFallbackMetricsAndScale( const FontPlatformData& platform_data, - const SkPaint& paint, HarfBuzzFace::VerticalLayoutCallbacks vertical_layout) { float ascent = 0; float descent = 0; unsigned dummy_ascent_inflation = 0; unsigned dummy_descent_inflation = 0; - paint_ = paint; + font_ = SkFont(); + platform_data.SetupSkFont(&font_); if (UNLIKELY(vertical_layout == HarfBuzzFace::PrepareForVerticalLayout)) { FontMetrics::AscentDescentWithHacks( ascent, descent, dummy_ascent_inflation, dummy_descent_inflation, - platform_data, paint); + platform_data, font_); ascent_fallback_ = ascent; // Simulate the rounding that FontMetrics does so far for returning the // integer Height() @@ -87,7 +87,7 @@ struct HarfBuzzFontData { if (size_per_unit_ != kInvalidFallbackMetricsValue) return size_per_unit_; int units_per_em = typeface.getUnitsPerEm(); - size_per_unit_ = paint_.getTextSize() / units_per_em; + size_per_unit_ = font_.getSize() / units_per_em; return size_per_unit_; } @@ -98,14 +98,14 @@ struct HarfBuzzFontData { DCHECK_NE(size_per_unit_, kInvalidFallbackMetricsValue); vertical_data_ = - OpenTypeVerticalData::CreateUnscaled(paint_.refTypeface()); + OpenTypeVerticalData::CreateUnscaled(font_.refTypeface()); } vertical_data_->SetScaleAndFallbackMetrics(size_per_unit_, ascent_fallback_, height_fallback_); return vertical_data_; } - SkPaint paint_; + SkFont font_; // Capture these scaled fallback metrics from FontPlatformData so that a // OpenTypeVerticalData object can be constructed from them when needed. diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc index 8a59fbb19bc..3cef0162ce7 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.cc @@ -39,6 +39,7 @@ #include <utility> #include "base/memory/ptr_util.h" +#include "build/build_config.h" #include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/font_description.h" #include "third_party/blink/renderer/platform/fonts/font_fallback_iterator.h" @@ -70,8 +71,7 @@ void CheckShapeResultRange(const ShapeResult* result, DCHECK_LE(start, end); unsigned length = end - start; if (length == result->NumCharacters() && - (!length || (start == result->StartIndexForResult() && - end == result->EndIndexForResult()))) + (!length || (start == result->StartIndex() && end == result->EndIndex()))) return; // Log font-family/size as specified. @@ -99,8 +99,7 @@ void CheckShapeResultRange(const ShapeResult* result, // Log the text to shape. log.Append(String::Format(": %u-%u -> %u-%u:", start, end, - result->StartIndexForResult(), - result->EndIndexForResult())); + result->StartIndex(), result->EndIndex())); for (unsigned i = start; i < end; ++i) log.Append(String::Format(" %02X", text[i])); @@ -238,14 +237,6 @@ inline bool ShapeRange(hb_buffer_t* buffer, ? HarfBuzzFace::PrepareForVerticalLayout : HarfBuzzFace::NoVerticalLayout); hb_shape(hb_font, buffer, font_features, font_features_size); - - // We cannot round all glyph positions during hb_shape because the - // hb_font_funcs_set_glyph_h_kerning_func only works for legacy kerning. - // OpenType uses gpos tables for kerning and harfbuzz does not call - // the callback to let us round as we go. - // Without this rounding, we get inconsistent spacing between kern points - // if subpixel positioning is disabled. - // See http://crbug.com/740385. if (!face->ShouldSubpixelPosition()) RoundHarfBuzzBufferPositions(buffer); @@ -336,12 +327,11 @@ void HarfBuzzShaper::CommitGlyphs(RangeData* range_data, // Here we need to specify glyph positions. BufferSlice next_slice; for (const BufferSlice* current_slice = &slice;;) { - ShapeResult::RunInfo* run = new ShapeResult::RunInfo( + auto run = ShapeResult::RunInfo::Create( current_font, direction, canvas_rotation, script, current_slice->start_character_index, current_slice->num_glyphs, current_slice->num_characters); - shape_result->InsertRun(base::WrapUnique(run), - current_slice->start_glyph_index, + shape_result->InsertRun(run, current_slice->start_glyph_index, current_slice->num_glyphs, range_data->buffer); unsigned num_glyphs_inserted = run->NumGlyphs(); if (num_glyphs_inserted == current_slice->num_glyphs) @@ -1004,9 +994,9 @@ scoped_refptr<ShapeResult> HarfBuzzShaper::Shape( } } - // Ensure we have at least one run for StartIndexForResult(). - if (UNLIKELY(result->runs_.IsEmpty() && start)) - result->InsertRunForIndex(start); + // Ensure |start_index_| is updated even when no runs were inserted. + if (UNLIKELY(result->runs_.IsEmpty())) + result->start_index_ = start; #if DCHECK_IS_ON() if (result) diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc index a6c267b157d..35e0d66e541 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_test.cc @@ -16,11 +16,11 @@ #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" #include "third_party/blink/renderer/platform/testing/font_test_helpers.h" #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" #include "third_party/blink/renderer/platform/text/text_break_iterator.h" #include "third_party/blink/renderer/platform/text/text_run.h" +#include "third_party/blink/renderer/platform/web_test_support.h" #include "third_party/blink/renderer/platform/wtf/vector.h" using testing::ElementsAre; @@ -114,40 +114,40 @@ class HarfBuzzShaperTest : public testing::Test { class ScopedSubpixelOverride { public: ScopedSubpixelOverride(bool b) { - prev_layout_test_ = LayoutTestSupport::IsRunningLayoutTest(); + prev_layout_test_ = WebTestSupport::IsRunningWebTest(); prev_subpixel_allowed_ = - LayoutTestSupport::IsTextSubpixelPositioningAllowedForTest(); - prev_antialias_ = LayoutTestSupport::IsFontAntialiasingEnabledForTest(); + WebTestSupport::IsTextSubpixelPositioningAllowedForTest(); + prev_antialias_ = WebTestSupport::IsFontAntialiasingEnabledForTest(); prev_fd_subpixel_ = FontDescription::SubpixelPositioning(); - // This is required for all LayoutTestSupport settings to have effects. - LayoutTestSupport::SetIsRunningLayoutTest(true); + // This is required for all WebTestSupport settings to have effects. + WebTestSupport::SetIsRunningWebTest(true); if (b) { // Allow subpixel positioning. - LayoutTestSupport::SetTextSubpixelPositioningAllowedForTest(true); + WebTestSupport::SetTextSubpixelPositioningAllowedForTest(true); // Now, enable subpixel positioning in platform-specific ways. // Mac always enables subpixel positioning. // On Windows, subpixel positioning also requires antialiasing. - LayoutTestSupport::SetFontAntialiasingEnabledForTest(true); + WebTestSupport::SetFontAntialiasingEnabledForTest(true); // On platforms other than Windows and Mac this needs to be set as // well. FontDescription::SetSubpixelPositioning(true); } else { // Explicitly disallow all subpixel positioning. - LayoutTestSupport::SetTextSubpixelPositioningAllowedForTest(false); + WebTestSupport::SetTextSubpixelPositioningAllowedForTest(false); } } ~ScopedSubpixelOverride() { FontDescription::SetSubpixelPositioning(prev_fd_subpixel_); - LayoutTestSupport::SetFontAntialiasingEnabledForTest(prev_antialias_); - LayoutTestSupport::SetTextSubpixelPositioningAllowedForTest( + WebTestSupport::SetFontAntialiasingEnabledForTest(prev_antialias_); + WebTestSupport::SetTextSubpixelPositioningAllowedForTest( prev_subpixel_allowed_); - LayoutTestSupport::SetIsRunningLayoutTest(prev_layout_test_); + WebTestSupport::SetIsRunningWebTest(prev_layout_test_); // Fonts cached with a different subpixel positioning state are not // automatically invalidated and need to be cleared between test @@ -245,11 +245,9 @@ TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsUnicodeVariants) { // If the specified VS is not in the font, it's mapped to .notdef. // then hb_ot_hide_default_ignorables() swaps it to a space with zero-advance. // http://lists.freedesktop.org/archives/harfbuzz/2015-May/004888.html -#if !defined(OS_MACOSX) EXPECT_EQ(TestInfo(result)->FontDataForTesting(0)->SpaceGlyph(), TestInfo(result)->GlyphForTesting(0, 1)) << test.name; -#endif EXPECT_EQ(0.f, TestInfo(result)->AdvanceForTesting(0, 1)) << test.name; } else { EXPECT_EQ(1u, num_glyphs) << test.name; @@ -413,8 +411,9 @@ TEST_F(HarfBuzzShaperTest, ShapeLatinSegment) { } // Represents the case where a part of a cluster has a different color. -// <div>0x647<span style="color: red;">0x64A</span></div> -// TODO(crbug.com/689155): Still fails on Mac, AAT? +// <div>0x647<span style="color: red;">0x64A</span></ +// Cannot be enabled on Mac yet, compare +// https:// https://github.com/harfbuzz/harfbuzz/issues/1415 #if defined(OS_MACOSX) #define MAYBE_ShapeArabicWithContext DISABLED_ShapeArabicWithContext #else @@ -517,9 +516,6 @@ TEST_F(HarfBuzzShaperTest, ShapeVerticalMixed) { HarfBuzzShaper shaper(string); scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction); - // Check width and bounds are not too much different. ".1" is heuristic. - EXPECT_NEAR(result->Width(), result->Bounds().Width(), result->Width() * .1); - // Shape each run and merge them using CopyRange. Bounds() should match. scoped_refptr<ShapeResult> result1 = shaper.Shape(&font, direction, 0, 3); scoped_refptr<ShapeResult> result2 = @@ -533,15 +529,24 @@ TEST_F(HarfBuzzShaperTest, ShapeVerticalMixed) { EXPECT_EQ(result->Bounds(), composite_result->Bounds()); } -TEST_P(ShapeParameterTest, MissingGlyph) { - // U+FFF0 is not assigned as of Unicode 10.0. - String string( - u"\uFFF0" - u"Hello"); +class ShapeStringTest : public HarfBuzzShaperTest, + public testing::WithParamInterface<const char16_t*> {}; + +INSTANTIATE_TEST_CASE_P(HarfBuzzShaperTest, + ShapeStringTest, + testing::Values( + // U+FFF0 is not assigned as of Unicode 10.0. + u"\uFFF0", + u"\uFFF0Hello", + // U+00AD SOFT HYPHEN often does not have glyphs. + u"\u00AD")); + +TEST_P(ShapeStringTest, MissingGlyph) { + String string(GetParam()); HarfBuzzShaper shaper(string); - scoped_refptr<ShapeResult> result = ShapeWithParameter(&shaper); - EXPECT_EQ(0u, result->StartIndexForResult()); - EXPECT_EQ(string.length(), result->EndIndexForResult()); + scoped_refptr<ShapeResult> result = shaper.Shape(&font, TextDirection::kLtr); + EXPECT_EQ(0u, result->StartIndex()); + EXPECT_EQ(string.length(), result->EndIndex()); } // Test splitting runs by kMaxCharacterIndex using a simple string that has code @@ -640,8 +645,8 @@ TEST_P(ShapeParameterTest, ZeroWidthSpace) { const unsigned length = base::size(string); HarfBuzzShaper shaper(String(string, length)); scoped_refptr<ShapeResult> result = ShapeWithParameter(&shaper); - EXPECT_EQ(0u, result->StartIndexForResult()); - EXPECT_EQ(length, result->EndIndexForResult()); + EXPECT_EQ(0u, result->StartIndex()); + EXPECT_EQ(length, result->EndIndex()); #if DCHECK_IS_ON() result->CheckConsistency(); #endif @@ -717,17 +722,14 @@ static struct GlyphDataRangeTestData { // The two code points form a grapheme cluster, which produces two glyphs. // Character index array should be [0, 0]. {u"\u05E9\u05B0", TextDirection::kRtl, 0, 0, 1, 0, 2}, -#if !defined(OS_MACOSX) // ZWJ tests taken from fast/text/international/zerowidthjoiner.html // Character index array should be [6, 3, 3, 3, 0, 0, 0]. - // Mac shapes differently and that glyph index expectations do not match. {u"\u0639\u200D\u200D\u0639\u200D\u200D\u0639", TextDirection::kRtl, 0, 0, 1, 4, 7}, {u"\u0639\u200D\u200D\u0639\u200D\u200D\u0639", TextDirection::kRtl, 0, 2, 5, 1, 4}, {u"\u0639\u200D\u200D\u0639\u200D\u200D\u0639", TextDirection::kRtl, 0, 4, 7, 0, 1}, -#endif }; std::ostream& operator<<(std::ostream& ostream, @@ -1106,14 +1108,14 @@ TEST_P(ShapeResultCopyRangeTest, Split) { scoped_refptr<ShapeResult> result1 = ShapeResult::Create(&font, 0, direction); result->CopyRange(0, test_data.break_point, result1.get()); EXPECT_EQ(test_data.break_point, result1->NumCharacters()); - EXPECT_EQ(0u, result1->StartIndexForResult()); - EXPECT_EQ(test_data.break_point, result1->EndIndexForResult()); + EXPECT_EQ(0u, result1->StartIndex()); + EXPECT_EQ(test_data.break_point, result1->EndIndex()); scoped_refptr<ShapeResult> result2 = ShapeResult::Create(&font, 0, direction); result->CopyRange(test_data.break_point, string.length(), result2.get()); EXPECT_EQ(string.length() - test_data.break_point, result2->NumCharacters()); - EXPECT_EQ(test_data.break_point, result2->StartIndexForResult()); - EXPECT_EQ(string.length(), result2->EndIndexForResult()); + EXPECT_EQ(test_data.break_point, result2->StartIndex()); + EXPECT_EQ(string.length(), result2->EndIndex()); // Combine them. scoped_refptr<ShapeResult> composite_result = @@ -1301,8 +1303,8 @@ TEST_F(HarfBuzzShaperTest, SubRange) { scoped_refptr<ShapeResult> result = shaper.Shape(&font, direction); scoped_refptr<ShapeResult> sub_range = result->SubRange(4, 7); - DCHECK_EQ(4u, sub_range->StartIndexForResult()); - DCHECK_EQ(7u, sub_range->EndIndexForResult()); + DCHECK_EQ(4u, sub_range->StartIndex()); + DCHECK_EQ(7u, sub_range->EndIndex()); DCHECK_EQ(3u, sub_range->NumCharacters()); DCHECK_EQ(result->Direction(), sub_range->Direction()); } @@ -1399,60 +1401,59 @@ TEST_F(HarfBuzzShaperTest, SafeToBreakLatinDiscretionaryLigatures) { "third_party/MEgalopolis/MEgalopolisExtra.woff"), 16, &ligatures); - // RA and CA form ligatures, most glyph pairs have kerning. - String string(u"ABRACADABRA"); - HarfBuzzShaper shaper(string); + // $ ./hb-shape --shaper=ot --features="dlig=1,kern" --show-flags + // MEgalopolisExtra.ttf "RADDAYoVaDD" + // [R_A=0+1150|D=2+729|D=3+699|A=4+608#1|Y=5+608#1|o=6+696#1|V=7+652#1|a=8+657#1|D=9+729|D=10+729] + // RA Ligature, unkerned D D, D A kerns, A Y kerns, Y o kerns, o V kerns, V a + // kerns, no kerning with D. + String test_word(u"RADDAYoVaDD"); + unsigned safe_to_break_positions[] = {2, 3, 9, 10}; + HarfBuzzShaper shaper(test_word); scoped_refptr<ShapeResult> result = shaper.Shape(&testFont, TextDirection::kLtr); - EXPECT_EQ(6u, result->NextSafeToBreakOffset(1)); // After CA ligature. - EXPECT_EQ(6u, result->NextSafeToBreakOffset(6)); // After CA ligature. - EXPECT_EQ(11u, result->NextSafeToBreakOffset(7)); // At end of string. - EXPECT_EQ(11u, result->NextSafeToBreakOffset(9)); // At end of string. - EXPECT_EQ(11u, result->NextSafeToBreakOffset(10)); // At end of string. - - // Add zero-width spaces at the safe to break offsets. - String refString(u"ABRACA\u200BDAB\u200BRA"); - HarfBuzzShaper refShaper(refString); + + unsigned compare_safe_to_break_position = 0; + for (unsigned i = 1; i < test_word.length() - 1; ++i) { + EXPECT_EQ(safe_to_break_positions[compare_safe_to_break_position], + result->NextSafeToBreakOffset(i)); + if (i == safe_to_break_positions[compare_safe_to_break_position]) + compare_safe_to_break_position++; + } + + // Add zero-width spaces at some of the safe to break offsets. + String inserted_zero_width_spaces = test_word; + inserted_zero_width_spaces.Ensure16Bit(); + unsigned enlarged_by = 0; + for (unsigned safe_to_break_position : safe_to_break_positions) { + inserted_zero_width_spaces.insert(u"\u200B", + safe_to_break_position + enlarged_by++); + } + HarfBuzzShaper refShaper(inserted_zero_width_spaces); scoped_refptr<ShapeResult> referenceResult = refShaper.Shape(&testFont, TextDirection::kLtr); // Results should be identical if it truly is safe to break at the designated - // safe-to-break offsets + // safe-to-break offsets because otherwise, the zero-width spaces would have + // altered the text spacing, for example by breaking apart ligatures or + // kerning pairs. EXPECT_EQ(result->SnappedWidth(), referenceResult->SnappedWidth()); EXPECT_EQ(result->Bounds(), referenceResult->Bounds()); - EXPECT_EQ(result->SnappedStartPositionForOffset(0), - referenceResult->SnappedStartPositionForOffset(0)); - EXPECT_EQ(result->SnappedStartPositionForOffset(1), - referenceResult->SnappedStartPositionForOffset(1)); - EXPECT_EQ(result->SnappedStartPositionForOffset(2), - referenceResult->SnappedStartPositionForOffset(2)); - EXPECT_EQ(result->SnappedStartPositionForOffset(3), - referenceResult->SnappedStartPositionForOffset(3)); - EXPECT_EQ(result->SnappedStartPositionForOffset(4), - referenceResult->SnappedStartPositionForOffset(4)); - EXPECT_EQ(result->SnappedStartPositionForOffset(5), - referenceResult->SnappedStartPositionForOffset(5)); - // First zero-width space is at position 6 so the the matching character in - // the reference results is 7. - EXPECT_EQ(result->SnappedStartPositionForOffset(6), - referenceResult->SnappedStartPositionForOffset(7)); - EXPECT_EQ(result->SnappedStartPositionForOffset(7), - referenceResult->SnappedStartPositionForOffset(8)); - EXPECT_EQ(result->SnappedStartPositionForOffset(8), - referenceResult->SnappedStartPositionForOffset(9)); - - // Second zero-width space is at position 9 so the the matching character in - // the reference results is 11. - EXPECT_EQ(result->SnappedStartPositionForOffset(9), - referenceResult->SnappedStartPositionForOffset(11)); - EXPECT_EQ(result->SnappedStartPositionForOffset(10), - referenceResult->SnappedStartPositionForOffset(12)); + // Zero-width spaces were inserted, so we need to account for that by + // offseting the index that we compare against. + unsigned inserts_offset = 0; + for (unsigned i = 0; i < test_word.length(); ++i) { + if (i == safe_to_break_positions[inserts_offset]) + inserts_offset++; + EXPECT_EQ( + result->SnappedStartPositionForOffset(i), + referenceResult->SnappedStartPositionForOffset(i + inserts_offset)); + } } -// TODO(crbug.com/870712): This test fails on Mac due to AAT shaping and -// font fallback differences on Android. -#if defined(OS_MACOSX) || defined(OS_ANDROID) +// TODO(crbug.com/870712): This test fails due to font fallback differences on +// Android. +#if defined(OS_ANDROID) #define MAYBE_SafeToBreakArabicCommonLigatures \ DISABLED_SafeToBreakArabicCommonLigatures #else @@ -1469,33 +1470,27 @@ TEST_F(HarfBuzzShaperTest, MAYBE_SafeToBreakArabicCommonLigatures) { HarfBuzzShaper shaper(string); scoped_refptr<ShapeResult> result = shaper.Shape(&font, TextDirection::kRtl); - // Safe to break at 0, 3, 4, 5, 7, and 11. - EXPECT_EQ(0u, result->NextSafeToBreakOffset(0)); - EXPECT_EQ(3u, result->NextSafeToBreakOffset(1)); - EXPECT_EQ(3u, result->NextSafeToBreakOffset(2)); - EXPECT_EQ(3u, result->NextSafeToBreakOffset(3)); - EXPECT_EQ(4u, result->NextSafeToBreakOffset(4)); - EXPECT_EQ(5u, result->NextSafeToBreakOffset(5)); - EXPECT_EQ(7u, result->NextSafeToBreakOffset(6)); - EXPECT_EQ(7u, result->NextSafeToBreakOffset(7)); - EXPECT_EQ(11u, result->NextSafeToBreakOffset(8)); - EXPECT_EQ(11u, result->NextSafeToBreakOffset(9)); - EXPECT_EQ(11u, result->NextSafeToBreakOffset(10)); - EXPECT_EQ(11u, result->NextSafeToBreakOffset(11)); - EXPECT_EQ(12u, result->NextSafeToBreakOffset(12)); + std::vector<unsigned> safe_to_break_positions; + +#if defined(OS_MACOSX) + safe_to_break_positions = {0, 2, 3, 4, 11}; +#else + safe_to_break_positions = {0, 3, 4, 5, 7, 11}; +#endif + unsigned compare_safe_to_break_position = 0; + for (unsigned i = 0; i < string.length() - 1; ++i) { + EXPECT_EQ(safe_to_break_positions[compare_safe_to_break_position], + result->NextSafeToBreakOffset(i)); + if (i == safe_to_break_positions[compare_safe_to_break_position]) + compare_safe_to_break_position++; + } } // TODO(layout-dev): Expand RTL test coverage and add tests for mixed // directionality strings. // Test when some characters are missing in |runs_|. -// RTL on Mac may not have runs for all characters. crbug.com/774034 -#if defined(OS_MACOSX) -#define MAYBE_SafeToBreakMissingRun DISABLED_SafeToBreakMissingRun -#else -#define MAYBE_SafeToBreakMissingRun SafeToBreakMissingRun -#endif -TEST_P(ShapeParameterTest, MAYBE_SafeToBreakMissingRun) { +TEST_P(ShapeParameterTest, SafeToBreakMissingRun) { TextDirection direction = GetParam(); scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 8, direction); result->InsertRunForTesting(2, 1, direction, {0}); @@ -1506,8 +1501,8 @@ TEST_P(ShapeParameterTest, MAYBE_SafeToBreakMissingRun) { result->CheckConsistency(); #endif - EXPECT_EQ(2u, result->StartIndexForResult()); - EXPECT_EQ(10u, result->EndIndexForResult()); + EXPECT_EQ(2u, result->StartIndex()); + EXPECT_EQ(10u, result->EndIndex()); EXPECT_EQ(2u, result->NextSafeToBreakOffset(2)); EXPECT_EQ(3u, result->NextSafeToBreakOffset(3)); diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc index 3fbc1ef3978..664b1fcf3fa 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.cc @@ -30,13 +30,17 @@ #include "third_party/blink/renderer/platform/fonts/shaping/shape_cache.h" #include "third_party/blink/renderer/platform/wtf/string_hasher.h" +#if defined(USE_FUNCTION_CITYHASH) +#include "third_party/smhasher/src/City.h" +#endif namespace blink { void ShapeCache::SmallStringKey::HashString() { - // TODO(cavalcantii): replace this for a better hash function, - // see crbug.com/735674. - hash_ = StringHasher::ComputeHash(characters_, length_); +// TODO(cavalcanti): next add xxhash. +#if defined(USE_FUNCTION_CITYHASH) + hash_ = CityHash64((const char*)characters_, length_ * sizeof(UChar)); +#endif } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc index 1c84a168159..11ca1595552 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc @@ -39,9 +39,11 @@ #include "base/containers/adapters.h" #include "base/memory/ptr_util.h" +#include "base/numerics/safe_conversions.h" #include "build/build_config.h" #include "third_party/blink/renderer/platform/fonts/character_range.h" #include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/shaping/glyph_bounds_accumulator.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h" @@ -53,6 +55,18 @@ namespace blink { constexpr unsigned HarfBuzzRunGlyphData::kMaxCharacterIndex; constexpr unsigned HarfBuzzRunGlyphData::kMaxGlyphs; +struct SameSizeAsHarfBuzzRunGlyphData { + uint16_t unsigned_int16; + unsigned bit_fields : 2; + int16_t signed_int16[2]; + float advance; + FloatSize offset; +}; + +static_assert(sizeof(HarfBuzzRunGlyphData) == + sizeof(SameSizeAsHarfBuzzRunGlyphData), + "HarfBuzzRunGlyphData should stay small"); + unsigned ShapeResult::RunInfo::NextSafeToBreakOffset(unsigned offset) const { DCHECK_LE(offset, num_characters_); if (!Rtl()) { @@ -129,7 +143,7 @@ void ShapeResult::EnsureGraphemes(const StringView& text) const { if (is_computed) return; - unsigned result_start_index = StartIndexForResult(); + unsigned result_start_index = StartIndex(); for (const auto& run : runs_) { if (!run) continue; @@ -321,7 +335,8 @@ void ShapeResult::RunInfo::CharacterIndexForXPosition( // representing a sequence of glyphs, of size glyph_sequence_advance. We // linearly interpolate how much space each character takes, and reduce the // sequence to only match the character size. - if (break_glyphs_option == BreakGlyphs) { + if (break_glyphs_option == BreakGlyphs && + glyph_sequence_end > glyph_sequence_start) { int graphemes = NumGraphemes(glyph_sequence_start, glyph_sequence_end); if (graphemes > 1) { float unit_size = result->advance / graphemes; @@ -360,9 +375,23 @@ void HarfBuzzRunGlyphData::SetGlyphAndPositions(uint16_t glyph_id, this->advance = advance; this->offset = offset; this->safe_to_break_before = safe_to_break_before; + this->bounds_before_raw_value = std::numeric_limits<int16_t>::max(); + this->bounds_after_raw_value = std::numeric_limits<int16_t>::max(); +} + +void HarfBuzzRunGlyphData::SetGlyphBounds(LayoutUnit bounds_before, + LayoutUnit bounds_after) { + this->bounds_before_raw_value = + base::IsValueInRangeForNumericType<int16_t>(bounds_before.RawValue()) + ? bounds_before.RawValue() + : std::numeric_limits<int16_t>::max(); + this->bounds_after_raw_value = + base::IsValueInRangeForNumericType<int16_t>(bounds_after.RawValue()) + ? bounds_after.RawValue() + : std::numeric_limits<int16_t>::max(); } -ShapeResult::ShapeResult(const SimpleFontData* font_data, +ShapeResult::ShapeResult(scoped_refptr<const SimpleFontData> font_data, unsigned num_characters, TextDirection direction) : width_(0), @@ -388,7 +417,7 @@ ShapeResult::ShapeResult(const ShapeResult& other) has_vertical_offsets_(other.has_vertical_offsets_) { runs_.ReserveCapacity(other.runs_.size()); for (const auto& run : other.runs_) - runs_.push_back(std::make_unique<RunInfo>(*run)); + runs_.push_back(run->Create(*run.get())); } ShapeResult::~ShapeResult() = default; @@ -438,7 +467,7 @@ unsigned ShapeResult::NextSafeToBreakOffset(unsigned index) const { } } - return EndIndexForResult(); + return EndIndex(); } unsigned ShapeResult::PreviousSafeToBreakOffset(unsigned index) const { @@ -464,7 +493,7 @@ unsigned ShapeResult::PreviousSafeToBreakOffset(unsigned index) const { } } - return StartIndexForResult(); + return StartIndex(); } // If the position is outside of the result, returns the start or the end offset @@ -710,12 +739,10 @@ float ShapeResult::ForEachGlyph(float initial_advance, return total_advance; } -namespace { - -inline unsigned CountGraphemesInCluster(const UChar* str, - unsigned str_length, - uint16_t start_index, - uint16_t end_index) { +unsigned ShapeResult::CountGraphemesInCluster(const UChar* str, + unsigned str_length, + uint16_t start_index, + uint16_t end_index) { if (start_index > end_index) std::swap(start_index, end_index); uint16_t length = end_index - start_index; @@ -732,8 +759,6 @@ inline unsigned CountGraphemesInCluster(const UChar* str, return std::max(0, num_graphemes); } -} // anonymous namespace - float ShapeResult::ForEachGraphemeClusters(const StringView& text, float initial_advance, unsigned from, @@ -914,66 +939,6 @@ float HarfBuzzPositionToFloat(hb_position_t value) { return static_cast<float>(value) / (1 << 16); } -// This is a helper class to accumulate glyph bounding box. -// -// Glyph positions and bounding boxes from HarfBuzz and fonts are in physical -// coordinate, while ShapeResult::glyph_bounding_box_ is in logical coordinate. -// To minimize the number of conversions, this class accumulates the bounding -// boxes in physical coordinate, and convert the accumulated box to logical. -struct GlyphBoundsAccumulator { - // Construct an accumulator with the logical glyph origin. - explicit GlyphBoundsAccumulator(float origin) : origin(origin) {} - - // The accumulated glyph bounding box in physical coordinate, until - // ConvertVerticalRunToLogical(). - FloatRect bounds; - // The current origin, in logical coordinate. - float origin; - - // Unite a glyph bounding box to |bounds|. - template <bool is_horizontal_run> - void Unite(const HarfBuzzRunGlyphData& glyph_data, - FloatRect bounds_for_glyph) { - if (UNLIKELY(bounds_for_glyph.IsEmpty())) - return; - - // Glyphs are drawn at |origin + offset|. Move glyph_bounds to that point. - // All positions in hb_glyph_position_t are relative to the current point. - // https://behdad.github.io/harfbuzz/harfbuzz-Buffers.html#hb-glyph-position-t-struct - if (is_horizontal_run) - bounds_for_glyph.SetX(bounds_for_glyph.X() + origin); - else - bounds_for_glyph.SetY(bounds_for_glyph.Y() + origin); - bounds_for_glyph.Move(glyph_data.offset); - - bounds.Unite(bounds_for_glyph); - } - - // Non-template version of |Unite()|, see above. - void Unite(bool is_horizontal_run, - const HarfBuzzRunGlyphData& glyph, - FloatRect bounds_for_glyph) { - is_horizontal_run ? Unite<true>(glyph, bounds_for_glyph) - : Unite<false>(glyph, bounds_for_glyph); - } - - // Convert vertical run glyph bounding box to logical. Horizontal runs do not - // need conversions because physical and logical are the same. - void ConvertVerticalRunToLogical(const FontMetrics& font_metrics) { - // Convert physical glyph_bounding_box to logical. - bounds = bounds.TransposedRect(); - - // The glyph bounding box of a vertical run uses ideographic baseline. - // Adjust the box Y position because the bounding box of a ShapeResult uses - // alphabetic baseline. - // See diagrams of base lines at - // https://drafts.csswg.org/css-writing-modes-3/#intro-baselines - int baseline_adjust = font_metrics.Ascent(kIdeographicBaseline) - - font_metrics.Ascent(kAlphabeticBaseline); - bounds.SetY(bounds.Y() + baseline_adjust); - } -}; - // Checks whether it's safe to break without reshaping before the given glyph. bool IsSafeToBreakBefore(const hb_glyph_info_t* glyph_infos, unsigned num_glyphs, @@ -1097,7 +1062,24 @@ void ShapeResult::ComputeGlyphPositions(ShapeResult::RunInfo* run, float total_advance = 0.0f; bool has_vertical_offsets = !is_horizontal_run; + // Get glyph bounds from Skia. It's a lot faster if we give it list of glyph + // IDs rather than calling it for each glyph. + // TODO(kojii): MacOS does not benefit from batching the Skia request due to + // https://bugs.chromium.org/p/skia/issues/detail?id=5328, and the cost to + // prepare batching, which is normally much less than the benefit of batching, + // is not ignorable unfortunately. + const SimpleFontData& current_font_data = *run->font_data_; + DCHECK_EQ(num_glyphs, run->glyph_data_.size()); +#if !defined(OS_MACOSX) + Vector<Glyph, 256> glyphs(num_glyphs); + for (unsigned i = 0; i < num_glyphs; i++) + glyphs[i] = glyph_infos[start_glyph + i].codepoint; + Vector<SkRect, 256> bounds_list(num_glyphs); + current_font_data.BoundsForGlyphs(glyphs, &bounds_list); +#endif + // HarfBuzz returns result in visual order, no need to flip for RTL. + GlyphBoundsAccumulator bounds(width_); for (unsigned i = 0; i < num_glyphs; ++i) { uint16_t glyph = glyph_infos[start_glyph + i].codepoint; const hb_glyph_position_t& pos = glyph_positions[start_glyph + i]; @@ -1119,6 +1101,17 @@ void ShapeResult::ComputeGlyphPositions(ShapeResult::RunInfo* run, glyph_data.SetGlyphAndPositions( glyph, character_index, advance, offset, IsSafeToBreakBefore(glyph_infos + start_glyph, num_glyphs, i)); + +#if defined(OS_MACOSX) + FloatRect glyph_bounds = current_font_data.BoundsForGlyph(glyph_data.glyph); +#else + FloatRect glyph_bounds(bounds_list[i]); +#endif + glyph_data.SetGlyphBounds(LayoutUnit(glyph_bounds.X()), + LayoutUnit(glyph_bounds.MaxX())); + bounds.Unite<is_horizontal_run>(glyph_data, glyph_bounds); + bounds.origin += advance; + total_advance += advance; has_vertical_offsets |= (offset.Height() != 0); } @@ -1126,51 +1119,17 @@ void ShapeResult::ComputeGlyphPositions(ShapeResult::RunInfo* run, run->width_ = std::max(0.0f, total_advance); has_vertical_offsets_ |= has_vertical_offsets; - ComputeGlyphBounds<is_horizontal_run>(*run); -} - -template <bool is_horizontal_run> -void ShapeResult::ComputeGlyphBounds(const ShapeResult::RunInfo& run) { - // Skia runs much faster if we give a list of glyph ID rather than calling it - // on each glyph. - const SimpleFontData& current_font_data = *run.font_data_; -#if defined(OS_MACOSX) - // TODO(kojii): MacOS does not benefit from batching the Skia request due to - // https://bugs.chromium.org/p/skia/issues/detail?id=5328 , and the cost to - // prepare batching, which is normally much less than the benefit of batching, - // is not ignorable unfortunately. - GlyphBoundsAccumulator bounds(width_); - for (const HarfBuzzRunGlyphData& glyph_data : run.glyph_data_) { - bounds.Unite<is_horizontal_run>( - glyph_data, current_font_data.BoundsForGlyph(glyph_data.glyph)); - bounds.origin += glyph_data.advance; - } -#else - unsigned num_glyphs = run.glyph_data_.size(); - Vector<Glyph, 256> glyphs(num_glyphs); - for (unsigned i = 0; i < num_glyphs; i++) - glyphs[i] = run.glyph_data_[i].glyph; - Vector<SkRect, 256> bounds_list(num_glyphs); - current_font_data.BoundsForGlyphs(glyphs, &bounds_list); - - GlyphBoundsAccumulator bounds(width_); - for (unsigned i = 0; i < num_glyphs; i++) { - const HarfBuzzRunGlyphData& glyph_data = run.glyph_data_[i]; - bounds.Unite<is_horizontal_run>(glyph_data, FloatRect(bounds_list[i])); - bounds.origin += glyph_data.advance; - } -#endif if (!is_horizontal_run) bounds.ConvertVerticalRunToLogical(current_font_data.GetFontMetrics()); glyph_bounding_box_.Unite(bounds.bounds); } -void ShapeResult::InsertRun(std::unique_ptr<ShapeResult::RunInfo> run_to_insert, +void ShapeResult::InsertRun(scoped_refptr<ShapeResult::RunInfo> run_to_insert, unsigned start_glyph, unsigned num_glyphs, hb_buffer_t* harfbuzz_buffer) { DCHECK_GT(num_glyphs, 0u); - std::unique_ptr<ShapeResult::RunInfo> run(std::move(run_to_insert)); + scoped_refptr<ShapeResult::RunInfo> run(std::move(run_to_insert)); if (run->IsHorizontal()) { // Inserting a horizontal run into a horizontal or vertical result. In both @@ -1190,7 +1149,7 @@ void ShapeResult::InsertRun(std::unique_ptr<ShapeResult::RunInfo> run_to_insert, InsertRun(std::move(run)); } -void ShapeResult::InsertRun(std::unique_ptr<ShapeResult::RunInfo> run) { +void ShapeResult::InsertRun(scoped_refptr<ShapeResult::RunInfo> run) { // The runs are stored in result->m_runs in visual order. For LTR, we place // the run to be inserted before the next run with a bigger character // start index. For RTL, we place the run before the next run with a lower @@ -1219,24 +1178,12 @@ void ShapeResult::InsertRun(std::unique_ptr<ShapeResult::RunInfo> run) { UpdateStartIndex(); } -// Insert a |RunInfo| without glyphs. |StartIndexForResult()| needs a run to -// compute the start character index. When all glyphs are missing, this function -// synthesize a run without glyphs. -void ShapeResult::InsertRunForIndex(unsigned start_character_index) { - DCHECK(runs_.IsEmpty()); - runs_.push_back(std::make_unique<RunInfo>( - primary_font_.get(), !Rtl() ? HB_DIRECTION_LTR : HB_DIRECTION_RTL, - CanvasRotationInVertical::kRegular, HB_SCRIPT_UNKNOWN, - start_character_index, 0, num_characters_)); - UpdateStartIndex(); -} - ShapeResult::RunInfo* ShapeResult::InsertRunForTesting( unsigned start_index, unsigned num_characters, TextDirection direction, Vector<uint16_t> safe_break_offsets) { - std::unique_ptr<RunInfo> run = std::make_unique<ShapeResult::RunInfo>( + auto run = RunInfo::Create( nullptr, IsLtr(direction) ? HB_DIRECTION_LTR : HB_DIRECTION_RTL, CanvasRotationInVertical::kRegular, HB_SCRIPT_COMMON, start_index, num_characters, num_characters); @@ -1264,7 +1211,7 @@ void ShapeResult::ReorderRtlRuns(unsigned run_size_before) { if (runs_.size() == run_size_before + 1) { if (!run_size_before) return; - std::unique_ptr<RunInfo> new_run(std::move(runs_.back())); + scoped_refptr<RunInfo> new_run(std::move(runs_.back())); runs_.Shrink(runs_.size() - 1); runs_.push_front(std::move(new_run)); return; @@ -1272,7 +1219,7 @@ void ShapeResult::ReorderRtlRuns(unsigned run_size_before) { // |push_front| is O(n) that we should not call it multiple times. // Create a new list in the correct order and swap it. - Vector<std::unique_ptr<RunInfo>> new_runs; + Vector<scoped_refptr<RunInfo>> new_runs; new_runs.ReserveInitialCapacity(runs_.size()); for (unsigned i = run_size_before; i < runs_.size(); i++) new_runs.push_back(std::move(runs_[i])); @@ -1346,7 +1293,8 @@ float ShapeResult::LineRightBounds() const { void ShapeResult::CopyRange(unsigned start_offset, unsigned end_offset, - ShapeResult* target) const { + ShapeResult* target, + unsigned* start_run_index) const { if (!runs_.size()) return; @@ -1356,13 +1304,15 @@ void ShapeResult::CopyRange(unsigned start_offset, // When |target| is empty, its character indexes are the specified sub range // of |this|. Otherwise the character indexes are renumbered to be continuous. - int index_diff = !target->num_characters_ - ? 0 - : target->EndIndexForResult() - - std::max(start_offset, StartIndexForResult()); + int index_diff = + !target->num_characters_ + ? 0 + : target->EndIndex() - std::max(start_offset, StartIndex()); unsigned target_run_size_before = target->runs_.size(); float total_width = 0; - for (const auto& run : runs_) { + unsigned run_index = start_run_index ? *start_run_index : 0; + for (; run_index < runs_.size(); run_index++) { + const auto& run = runs_[run_index]; unsigned run_start = run->start_index_; unsigned run_end = run_start + run->num_characters_; @@ -1377,6 +1327,14 @@ void ShapeResult::CopyRange(unsigned start_offset, target->num_characters_ += sub_run->num_characters_; target->num_glyphs_ += sub_run->glyph_data_.size(); target->runs_.push_back(std::move(sub_run)); + + // No need to process runs after the end of the range. + if ((!Rtl() && end_offset <= run_end) || + (Rtl() && start_offset > run_start)) { + if (start_run_index) + *start_run_index = run_index; + break; + } } } @@ -1397,8 +1355,8 @@ void ShapeResult::CopyRange(unsigned start_offset, // operations. If |start_offset| or |end_offset| are the start/end of |this|, // use the current |glyph_bounding_box_| for the side. DCHECK(primary_font_.get() == target->primary_font_.get()); - bool know_left_edge = start_offset <= StartIndexForResult(); - bool know_right_edge = end_offset >= EndIndexForResult(); + bool know_left_edge = start_offset <= StartIndex(); + bool know_right_edge = end_offset >= EndIndex(); if (UNLIKELY(Rtl())) std::swap(know_left_edge, know_right_edge); float left = know_left_edge ? target->width_ + glyph_bounding_box_.X() @@ -1416,19 +1374,21 @@ void ShapeResult::CopyRange(unsigned start_offset, target->UpdateStartIndex(); #if DCHECK_IS_ON() - DCHECK_EQ(target->num_characters_ - target_num_characters_before, - std::min(end_offset, EndIndexForResult()) - - std::max(start_offset, StartIndexForResult())); + DCHECK_EQ( + target->num_characters_ - target_num_characters_before, + std::min(end_offset, EndIndex()) - std::max(start_offset, StartIndex())); target->CheckConsistency(); #endif } -scoped_refptr<ShapeResult> ShapeResult::SubRange(unsigned start_offset, - unsigned end_offset) const { +scoped_refptr<ShapeResult> ShapeResult::SubRange( + unsigned start_offset, + unsigned end_offset, + unsigned* start_run_index) const { scoped_refptr<ShapeResult> sub_range = Create(primary_font_.get(), 0, Direction()); - CopyRange(start_offset, end_offset, sub_range.get()); + CopyRange(start_offset, end_offset, sub_range.get(), start_run_index); return sub_range; } @@ -1436,12 +1396,12 @@ scoped_refptr<ShapeResult> ShapeResult::CopyAdjustedOffset( unsigned start_index) const { scoped_refptr<ShapeResult> result = base::AdoptRef(new ShapeResult(*this)); - if (start_index > result->StartIndexForResult()) { - unsigned delta = start_index - result->StartIndexForResult(); + if (start_index > result->StartIndex()) { + unsigned delta = start_index - result->StartIndex(); for (auto& run : result->runs_) run->start_index_ += delta; } else { - unsigned delta = result->StartIndexForResult() - start_index; + unsigned delta = result->StartIndex() - start_index; for (auto& run : result->runs_) { DCHECK(run->start_index_ >= delta); run->start_index_ -= delta; @@ -1461,7 +1421,7 @@ void ShapeResult::CheckConsistency() const { } DCHECK_EQ(start_index_, ComputeStartIndex()); - const unsigned start_index = StartIndexForResult(); + const unsigned start_index = StartIndex(); unsigned index = start_index; unsigned num_glyphs = 0; if (!Rtl()) { @@ -1480,7 +1440,7 @@ void ShapeResult::CheckConsistency() const { num_glyphs += run->glyph_data_.size(); } } - const unsigned end_index = EndIndexForResult(); + const unsigned end_index = EndIndex(); DCHECK_LE(index, end_index); DCHECK_EQ(end_index - start_index, num_characters_); DCHECK_EQ(num_glyphs, num_glyphs_); @@ -1495,7 +1455,7 @@ scoped_refptr<ShapeResult> ShapeResult::CreateForTabulationCharacters( const SimpleFontData* font_data = font->PrimaryFont(); // Tab characters are always LTR or RTL, not TTB, even when // isVerticalAnyUpright(). - std::unique_ptr<ShapeResult::RunInfo> run = std::make_unique<RunInfo>( + scoped_refptr<ShapeResult::RunInfo> run = RunInfo::Create( font_data, text_run.Rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR, CanvasRotationInVertical::kRegular, HB_SCRIPT_COMMON, 0, count, count); float position = text_run.XPos() + position_offset; @@ -1573,7 +1533,7 @@ std::ostream& operator<<(std::ostream& ostream, template <bool rtl> void ShapeResult::ComputePositionData() const { auto& data = character_position_->data_; - unsigned start_offset = StartIndexForResult(); + unsigned start_offset = StartIndex(); unsigned next_character_index = 0; float run_advance = 0; float last_x_position = 0; diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h index 214f2567f75..72e7d4ee9f9 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result.h @@ -34,14 +34,16 @@ #include <memory> #include "third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h" #include "third_party/blink/renderer/platform/fonts/glyph.h" +#include "third_party/blink/renderer/platform/fonts/simple_font_data.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" -#include "third_party/blink/renderer/platform/layout_unit.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/text/text_direction.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/noncopyable.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" +#include "third_party/blink/renderer/platform/wtf/text/unicode.h" #include "third_party/blink/renderer/platform/wtf/vector.h" struct hb_buffer_t; @@ -52,8 +54,8 @@ struct CharacterRange; class Font; template <typename TextContainerType> class PLATFORM_EXPORT ShapeResultSpacing; -class SimpleFontData; class TextRun; +class ShapeResultView; enum class AdjustMidCluster { // Adjust the middle of a grapheme cluster to the logical end boundary. @@ -142,8 +144,8 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { float start_x = 0) const; // The character start/end index of a range shape result. - unsigned StartIndexForResult() const { return start_index_; } - unsigned EndIndexForResult() const { return start_index_ + num_characters_; } + unsigned StartIndex() const { return start_index_; } + unsigned EndIndex() const { return start_index_ + num_characters_; } void FallbackFonts(HashSet<const SimpleFontData*>*) const; TextDirection Direction() const { return static_cast<TextDirection>(direction_); @@ -162,12 +164,12 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { // Returns the next or previous offsets respectively at which it is safe to // break without reshaping. // The |offset| given and the return value is for the original string, between - // |StartIndexForResult| and |EndIndexForResult|. + // |StartIndex| and |EndIndex|. // TODO(eae): Remove these ones the cached versions are used everywhere. unsigned NextSafeToBreakOffset(unsigned offset) const; unsigned PreviousSafeToBreakOffset(unsigned offset) const; - // Returns the offset, relative to StartIndexForResult, whose (origin, + // Returns the offset, relative to StartIndex, whose (origin, // origin+advance) contains |x|. unsigned OffsetForPosition(float x, BreakGlyphsOption) const; // Returns the offset whose glyph boundary is nearest to |x|. Depends on @@ -194,7 +196,7 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { return CaretOffsetForHitTest(x, text, break_glyphs_option); } - // Returns the position for a given offset, relative to StartIndexForResult. + // Returns the position for a given offset, relative to StartIndex. float PositionForOffset(unsigned offset, AdjustMidCluster = AdjustMidCluster::kToEnd) const; // Similar to |PositionForOffset| with mid-glyph (mid-ligature) support. @@ -222,7 +224,7 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { // break without reshaping. Operates on a cache (that needs to be pre-computed // using EnsurePositionData) and does not take partial glyphs into account. // The |offset| given and the return value is for the original string, between - // |StartIndexForResult| and |EndIndexForResult|. + // |StartIndex| and |EndIndex|. unsigned CachedNextSafeToBreakOffset(unsigned offset) const; unsigned CachedPreviousSafeToBreakOffset(unsigned offset) const; @@ -230,17 +232,33 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { // configured to |ShapeResultSpacing|. // |text_start_offset| adjusts the character index in the ShapeResult before // giving it to |ShapeResultSpacing|. It can be negative if - // |StartIndexForResult()| is larger than the text in |ShapeResultSpacing|. + // |StartIndex()| is larger than the text in |ShapeResultSpacing|. void ApplySpacing(ShapeResultSpacing<String>&, int text_start_offset = 0); scoped_refptr<ShapeResult> ApplySpacingToCopy(ShapeResultSpacing<TextRun>&, const TextRun&) const; // Append a copy of a range within an existing result to another result. - void CopyRange(unsigned start, unsigned end, ShapeResult*) const; + // + // For sequential copies the opaque_context in/out parameter can be used to + // improve performance by avoding a linear scan to find the first run for the + // range. It should be set to zero for the first call and the resulting out + // value for one call is the appropiate input value for the next. + // NOTE: opaque_context assumes non-overlapping ranges. + void CopyRange(unsigned start, + unsigned end, + ShapeResult*, + unsigned* opaque_context = nullptr) const; // Create a new ShapeResult instance from a range within an existing result. + // + // For sequential copies the opaque_context in/out parameter can be used to + // improve performance by avoding a linear scan to find the first run for the + // range. It should be set to zero for the first call and the resulting out + // value for one call is the appropiate input value for the next. + // NOTE: opaque_context assumes non-overlapping ranges. scoped_refptr<ShapeResult> SubRange(unsigned start_offset, - unsigned end_offset) const; + unsigned end_offset, + unsigned* opaque_context = nullptr) const; // Create a new ShapeResult instance with the start offset adjusted. scoped_refptr<ShapeResult> CopyAdjustedOffset(unsigned start_offset) const; @@ -298,7 +316,9 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { #endif protected: - ShapeResult(const SimpleFontData*, unsigned num_characters, TextDirection); + ShapeResult(scoped_refptr<const SimpleFontData>, + unsigned num_characters, + TextDirection); ShapeResult(const Font*, unsigned num_characters, TextDirection); ShapeResult(const ShapeResult&); @@ -313,6 +333,11 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { // |grapheme_| is computed. void EnsureGraphemes(const StringView& text) const; + static unsigned CountGraphemesInCluster(const UChar*, + unsigned str_length, + uint16_t start_index, + uint16_t end_index); + struct GlyphIndexResult { STACK_ALLOCATED(); @@ -382,14 +407,11 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { unsigned start_glyph, unsigned num_glyphs, hb_buffer_t*); - template <bool is_horizontal_run> - void ComputeGlyphBounds(const ShapeResult::RunInfo&); - void InsertRun(std::unique_ptr<ShapeResult::RunInfo>, + void InsertRun(scoped_refptr<ShapeResult::RunInfo>, unsigned start_glyph, unsigned num_glyphs, hb_buffer_t*); - void InsertRun(std::unique_ptr<ShapeResult::RunInfo>); - void InsertRunForIndex(unsigned start_character_index); + void InsertRun(scoped_refptr<ShapeResult::RunInfo>); void ReorderRtlRuns(unsigned run_size_before); unsigned ComputeStartIndex() const; void UpdateStartIndex(); @@ -399,7 +421,7 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { float width_; FloatRect glyph_bounding_box_; - Vector<std::unique_ptr<RunInfo>> runs_; + Vector<scoped_refptr<RunInfo>> runs_; scoped_refptr<const SimpleFontData> primary_font_; mutable std::unique_ptr<CharacterPositionData> character_position_; @@ -418,6 +440,7 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { friend class HarfBuzzShaper; friend class ShapeResultBuffer; friend class ShapeResultBloberizer; + friend class ShapeResultView; }; PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, const ShapeResult&); diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc index d9dc7285a07..2e03906ae6a 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.cc @@ -8,6 +8,7 @@ #include "third_party/blink/renderer/platform/fonts/font.h" #include "third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" #include "third_party/blink/renderer/platform/fonts/text_run_paint_info.h" #include "third_party/blink/renderer/platform/text/text_break_iterator.h" #include "third_party/blink/renderer/platform/text/text_run.h" @@ -39,15 +40,14 @@ void ShapeResultBloberizer::CommitPendingRun() { builder_rotation_ = pending_canvas_rotation_; } - PaintFont run_font; - run_font.SetTextEncoding(SkPaint::kGlyphID_TextEncoding); - pending_font_data_->PlatformData().SetupPaintFont( - &run_font, device_scale_factor_, &font_); + SkFont run_font; + pending_font_data_->PlatformData().SetupSkFont(&run_font, + device_scale_factor_, &font_); const auto run_size = pending_glyphs_.size(); const auto& buffer = HasPendingVerticalOffsets() - ? builder_.AllocRunPos(run_font, run_size) - : builder_.AllocRunPosH(run_font, run_size, 0); + ? builder_.allocRunPos(run_font, run_size) + : builder_.allocRunPosH(run_font, run_size, 0); std::copy(pending_glyphs_.begin(), pending_glyphs_.end(), buffer.glyphs); std::copy(pending_offsets_.begin(), pending_offsets_.end(), buffer.pos); @@ -61,7 +61,7 @@ void ShapeResultBloberizer::CommitPendingBlob() { if (!builder_run_count_) return; - blobs_.emplace_back(builder_.TakeTextBlob(), builder_rotation_); + blobs_.emplace_back(builder_.make(), builder_rotation_); builder_run_count_ = 0; } @@ -74,54 +74,6 @@ const ShapeResultBloberizer::BlobBuffer& ShapeResultBloberizer::Blobs() { return blobs_; } -float ShapeResultBloberizer::FillGlyphs( - const TextRunPaintInfo& run_info, - const ShapeResultBuffer& result_buffer) { - if (CanUseFastPath(run_info.from, run_info.to, run_info.run.length(), - result_buffer.HasVerticalOffsets())) { - return FillFastHorizontalGlyphs(result_buffer, run_info.run.Direction()); - } - - float advance = 0; - auto results = result_buffer.results_; - - if (run_info.run.Rtl()) { - unsigned word_offset = run_info.run.length(); - for (unsigned j = 0; j < results.size(); j++) { - unsigned resolved_index = results.size() - 1 - j; - const scoped_refptr<const ShapeResult>& word_result = results[resolved_index]; - word_offset -= word_result->NumCharacters(); - advance = - FillGlyphsForResult(word_result.get(), run_info.run.ToStringView(), - run_info.from, run_info.to, advance, word_offset); - } - } else { - unsigned word_offset = 0; - for (const auto& word_result : results) { - advance = - FillGlyphsForResult(word_result.get(), run_info.run.ToStringView(), - run_info.from, run_info.to, advance, word_offset); - word_offset += word_result->NumCharacters(); - } - } - - return advance; -} - -float ShapeResultBloberizer::FillGlyphs(const StringView& text, - unsigned from, - unsigned to, - const ShapeResult* result) { - DCHECK(result); - DCHECK(to <= text.length()); - if (CanUseFastPath(from, to, result)) - return FillFastHorizontalGlyphs(result); - - float advance = 0; - float word_offset = 0; - return FillGlyphsForResult(result, text, from, to, advance, word_offset); -} - namespace { inline bool IsSkipInkException(const ShapeResultBloberizer& bloberizer, @@ -205,6 +157,19 @@ void AddFastHorizontalGlyphToBloberizer( advance + glyph_offset.Width()); } +float FillGlyphsForResult(ShapeResultBloberizer* bloberizer, + const ShapeResult* result, + const StringView& text, + unsigned from, + unsigned to, + float initial_advance, + unsigned run_offset) { + GlyphCallbackContext context = {bloberizer, text}; + return result->ForEachGlyph(initial_advance, from, to, run_offset, + AddGlyphToBloberizer, + static_cast<void*>(&context)); +} + class ClusterCallbackContext { WTF_MAKE_NONCOPYABLE(ClusterCallbackContext); STACK_ALLOCATED(); @@ -250,6 +215,63 @@ void AddEmphasisMarkToBloberizer(void* context, } // namespace +float ShapeResultBloberizer::FillGlyphs( + const TextRunPaintInfo& run_info, + const ShapeResultBuffer& result_buffer) { + if (CanUseFastPath(run_info.from, run_info.to, run_info.run.length(), + result_buffer.HasVerticalOffsets())) { + return FillFastHorizontalGlyphs(result_buffer, run_info.run.Direction()); + } + + float advance = 0; + auto results = result_buffer.results_; + + if (run_info.run.Rtl()) { + unsigned word_offset = run_info.run.length(); + for (unsigned j = 0; j < results.size(); j++) { + unsigned resolved_index = results.size() - 1 - j; + const scoped_refptr<const ShapeResult>& word_result = + results[resolved_index]; + word_offset -= word_result->NumCharacters(); + advance = FillGlyphsForResult(this, word_result.get(), + run_info.run.ToStringView(), run_info.from, + run_info.to, advance, word_offset); + } + } else { + unsigned word_offset = 0; + for (const auto& word_result : results) { + advance = FillGlyphsForResult(this, word_result.get(), + run_info.run.ToStringView(), run_info.from, + run_info.to, advance, word_offset); + word_offset += word_result->NumCharacters(); + } + } + + return advance; +} + +float ShapeResultBloberizer::FillGlyphs(const StringView& text, + unsigned from, + unsigned to, + const ShapeResultView* result) { + DCHECK(result); + DCHECK(to <= text.length()); + float initial_advance = 0; + if (CanUseFastPath(from, to, result)) { + DCHECK(!result->HasVerticalOffsets()); + DCHECK_NE(GetType(), ShapeResultBloberizer::Type::kTextIntercepts); + return result->ForEachGlyph(initial_advance, + &AddFastHorizontalGlyphToBloberizer, + static_cast<void*>(this)); + } + + float run_offset = 0; + GlyphCallbackContext context = {this, text}; + return result->ForEachGlyph(initial_advance, from, to, run_offset, + AddGlyphToBloberizer, + static_cast<void*>(&context)); +} + void ShapeResultBloberizer::FillTextEmphasisGlyphs( const TextRunPaintInfo& run_info, const GlyphData& emphasis, @@ -286,11 +308,12 @@ void ShapeResultBloberizer::FillTextEmphasisGlyphs( } } -void ShapeResultBloberizer::FillTextEmphasisGlyphs(const StringView& text, - unsigned from, - unsigned to, - const GlyphData& emphasis, - const ShapeResult* result) { +void ShapeResultBloberizer::FillTextEmphasisGlyphs( + const StringView& text, + unsigned from, + unsigned to, + const GlyphData& emphasis, + const ShapeResultView* result) { FloatPoint glyph_center = emphasis.font_data->BoundsForGlyph(emphasis.glyph).Center(); ClusterCallbackContext context = {this, text, emphasis, glyph_center}; @@ -301,18 +324,6 @@ void ShapeResultBloberizer::FillTextEmphasisGlyphs(const StringView& text, static_cast<void*>(&context)); } -float ShapeResultBloberizer::FillGlyphsForResult(const ShapeResult* result, - const StringView& text, - unsigned from, - unsigned to, - float initial_advance, - unsigned run_offset) { - GlyphCallbackContext context = {this, text}; - return result->ForEachGlyph(initial_advance, from, to, run_offset, - AddGlyphToBloberizer, - static_cast<void*>(&context)); -} - bool ShapeResultBloberizer::CanUseFastPath(unsigned from, unsigned to, unsigned length, @@ -321,11 +332,11 @@ bool ShapeResultBloberizer::CanUseFastPath(unsigned from, GetType() != ShapeResultBloberizer::Type::kTextIntercepts; } -bool ShapeResultBloberizer::CanUseFastPath(unsigned from, - unsigned to, - const ShapeResult* shape_result) { - return from <= shape_result->StartIndexForResult() && - to >= shape_result->EndIndexForResult() && +bool ShapeResultBloberizer::CanUseFastPath( + unsigned from, + unsigned to, + const ShapeResultView* shape_result) { + return from <= shape_result->StartIndex() && to >= shape_result->EndIndex() && !shape_result->HasVerticalOffsets() && GetType() != ShapeResultBloberizer::Type::kTextIntercepts; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h index 86cbcac380a..218321934a9 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer.h @@ -7,7 +7,6 @@ #include "third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h" #include "third_party/blink/renderer/platform/fonts/glyph.h" -#include "third_party/blink/renderer/platform/fonts/paint_text_blob.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" #include "third_party/blink/renderer/platform/geometry/float_point.h" @@ -38,7 +37,7 @@ class PLATFORM_EXPORT ShapeResultBloberizer { float FillGlyphs(const StringView&, unsigned from, unsigned to, - const ShapeResult*); + const ShapeResultView*); void FillTextEmphasisGlyphs(const TextRunPaintInfo&, const GlyphData& emphasis_data, const ShapeResultBuffer&); @@ -46,7 +45,7 @@ class PLATFORM_EXPORT ShapeResultBloberizer { unsigned from, unsigned to, const GlyphData& emphasis_data, - const ShapeResult*); + const ShapeResultView*); void Add(Glyph glyph, const SimpleFontData* font_data, CanvasRotationInVertical canvas_rotation, @@ -93,9 +92,9 @@ class PLATFORM_EXPORT ShapeResultBloberizer { } struct BlobInfo { - BlobInfo(scoped_refptr<PaintTextBlob> b, CanvasRotationInVertical r) + BlobInfo(sk_sp<SkTextBlob> b, CanvasRotationInVertical r) : blob(std::move(b)), rotation(r) {} - scoped_refptr<PaintTextBlob> blob; + sk_sp<SkTextBlob> blob; CanvasRotationInVertical rotation; }; @@ -105,20 +104,13 @@ class PLATFORM_EXPORT ShapeResultBloberizer { private: friend class ShapeResultBloberizerTestInfo; - float FillGlyphsForResult(const ShapeResult*, - const StringView&, - unsigned from, - unsigned to, - float initial_advance, - unsigned run_offset); - // Whether the FillFastHorizontalGlyphs can be used. Only applies for full // runs with no vertical offsets and no text intercepts. bool CanUseFastPath(unsigned from, unsigned to, unsigned length, bool has_vertical_offsets); - bool CanUseFastPath(unsigned from, unsigned to, const ShapeResult*); + bool CanUseFastPath(unsigned from, unsigned to, const ShapeResultView*); float FillFastHorizontalGlyphs(const ShapeResultBuffer&, TextDirection); float FillFastHorizontalGlyphs(const ShapeResult*, float advance = 0); @@ -132,7 +124,7 @@ class PLATFORM_EXPORT ShapeResultBloberizer { const Type type_; // Current text blob state. - PaintTextBlobBuilder builder_; + SkTextBlobBuilder builder_; CanvasRotationInVertical builder_rotation_ = CanvasRotationInVertical::kRegular; size_t builder_run_count_ = 0; diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h index 4ad56a56899..4ad568d79e8 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h @@ -55,6 +55,12 @@ struct HarfBuzzRunGlyphData { uint16_t glyph; unsigned character_index : kCharacterIndexBits; unsigned safe_to_break_before : 1; + + // LayoutUnit like fixed-point values, with 6 fractional and 10 integear bits. + // Can represent values between -1023.98 and 1023.96 which should be enough in + // the vast majority of cases. Max value is reserved to indicate invalid. + int16_t bounds_before_raw_value; + int16_t bounds_after_raw_value; float advance; FloatSize offset; @@ -63,12 +69,43 @@ struct HarfBuzzRunGlyphData { float advance, const FloatSize& offset, bool safe_to_break_before); + void SetGlyphBounds(LayoutUnit bounds_before, LayoutUnit bounds_after); + bool HasValidGlyphBounds() const { + return bounds_before_raw_value != std::numeric_limits<int16_t>::max() && + bounds_after_raw_value != std::numeric_limits<int16_t>::max(); + } + + LayoutUnit GlyphBoundsBefore() const { + LayoutUnit bounds; + bounds.SetRawValue(static_cast<int>(bounds_before_raw_value)); + return bounds; + } + LayoutUnit GlyphBoundsAfter() const { + LayoutUnit bounds; + bounds.SetRawValue(static_cast<int>(bounds_after_raw_value)); + return bounds; + } }; -struct ShapeResult::RunInfo { +struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> { USING_FAST_MALLOC(RunInfo); public: + static scoped_refptr<RunInfo> Create(const SimpleFontData* font, + hb_direction_t dir, + CanvasRotationInVertical canvas_rotation, + hb_script_t script, + unsigned start_index, + unsigned num_glyphs, + unsigned num_characters) { + return base::AdoptRef(new RunInfo(font, dir, canvas_rotation, script, + start_index, num_glyphs, num_characters)); + } + + static scoped_refptr<RunInfo> Create(const RunInfo& other) { + return base::AdoptRef(new RunInfo(other)); + } + RunInfo(const SimpleFontData* font, hb_direction_t dir, CanvasRotationInVertical canvas_rotation, @@ -171,16 +208,16 @@ struct ShapeResult::RunInfo { } // Creates a new RunInfo instance representing a subset of the current run. - std::unique_ptr<RunInfo> CreateSubRun(unsigned start, unsigned end) { + scoped_refptr<RunInfo> CreateSubRun(unsigned start, unsigned end) { DCHECK(end > start); unsigned number_of_characters = std::min(end - start, num_characters_); auto glyphs = FindGlyphDataRange(start, end); unsigned number_of_glyphs = static_cast<unsigned>(std::distance(glyphs.begin, glyphs.end)); - auto run = std::make_unique<RunInfo>( - font_data_.get(), direction_, canvas_rotation_, script_, - start_index_ + start, number_of_glyphs, number_of_characters); + auto run = + Create(font_data_.get(), direction_, canvas_rotation_, script_, + start_index_ + start, number_of_glyphs, number_of_characters); static_assert(base::is_trivially_copyable<HarfBuzzRunGlyphData>::value, "HarfBuzzRunGlyphData should be trivially copyable"); diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc new file mode 100644 index 00000000000..fad054902a6 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.cc @@ -0,0 +1,472 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" + +#include <iterator> +#include "base/containers/adapters.h" +#include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/shaping/glyph_bounds_accumulator.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" + +namespace blink { + +struct ShapeResultView::RunInfoPart { + USING_FAST_MALLOC(RunInfoPart); + + public: + RunInfoPart(scoped_refptr<ShapeResult::RunInfo> run, + ShapeResult::RunInfo::GlyphDataRange range, + unsigned start_index, + unsigned offset, + unsigned num_characters, + float width) + : run_(run), + range_(range), + start_index_(start_index), + offset_(offset), + num_characters_(num_characters), + width_(width) {} + + using const_iterator = const HarfBuzzRunGlyphData*; + const_iterator begin() const { return range_.begin; } + const_iterator end() const { return range_.end; } + using const_reverse_iterator = std::reverse_iterator<const_iterator>; + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const HarfBuzzRunGlyphData& GlyphAt(unsigned index) const { + return *(range_.begin + index); + } + + bool Rtl() const { return run_->Rtl(); } + bool IsHorizontal() const { return run_->IsHorizontal(); } + unsigned NumCharacters() const { return num_characters_; } + unsigned NumGlyphs() const { return range_.end - range_.begin; } + float Width() const { return width_; } + + unsigned PreviousSafeToBreakOffset(unsigned offset) const; + size_t GlyphToCharacterIndex(size_t i) const { + return run_->GlyphToCharacterIndex(i); + } + + scoped_refptr<ShapeResult::RunInfo> run_; + ShapeResult::RunInfo::GlyphDataRange range_; + + // Start index for partial run, adjusted to ensure that runs are continuous. + unsigned start_index_; + + // Offset relative to start index for the original run. + unsigned offset_; + + unsigned num_characters_; + float width_; +}; + +unsigned ShapeResultView::RunInfoPart::PreviousSafeToBreakOffset( + unsigned offset) const { + if (offset >= NumCharacters()) + return NumCharacters(); + if (!Rtl()) { + for (const auto& glyph : base::Reversed(*this)) { + if (glyph.safe_to_break_before && glyph.character_index <= offset) + return glyph.character_index; + } + } else { + for (const auto& glyph : *this) { + if (glyph.safe_to_break_before && glyph.character_index <= offset) + return glyph.character_index; + } + } + + // Next safe break is at the start of the run. + return 0; +} + +ShapeResultView::ShapeResultView(const ShapeResult* other) + : primary_font_(other->primary_font_), + start_index_(0), + num_characters_(0), + num_glyphs_(0), + direction_(other->direction_), + has_vertical_offsets_(other->has_vertical_offsets_), + width_(0) {} + +ShapeResultView::~ShapeResultView() = default; + +scoped_refptr<ShapeResult> ShapeResultView::CreateShapeResult() const { + ShapeResult* new_result = + new ShapeResult(primary_font_, num_characters_, Direction()); + new_result->runs_.ReserveCapacity(parts_.size()); + for (const auto& part : parts_) { + auto new_run = ShapeResult::RunInfo::Create( + part->run_->font_data_.get(), part->run_->direction_, + part->run_->canvas_rotation_, part->run_->script_, part->start_index_, + part->NumGlyphs(), part->num_characters_); + std::copy(part->range_.begin, part->range_.end, + new_run->glyph_data_.begin()); + for (HarfBuzzRunGlyphData& glyph_data : new_run->glyph_data_) { + glyph_data.character_index -= part->offset_; + } + + new_run->start_index_ += char_index_offset_; + new_run->width_ = part->width_; + new_run->num_characters_ = part->num_characters_; + new_result->runs_.push_back(std::move(new_run)); + } + + new_result->start_index_ = start_index_ + char_index_offset_; + new_result->num_glyphs_ = num_glyphs_; + new_result->has_vertical_offsets_ = has_vertical_offsets_; + new_result->width_ = width_; + new_result->glyph_bounding_box_ = glyph_bounding_box_; + + return base::AdoptRef(new_result); +} + +void ShapeResultView::CreateViewsForResult(const ShapeResult* other, + unsigned start_index, + unsigned end_index) { + bool first_result = num_characters_ == 0; + for (const auto& run : other->runs_) { + if (!run) + continue; + unsigned part_start = run->start_index_; + unsigned run_end = part_start + run->num_characters_; + if (start_index < run_end && end_index > part_start) { + ShapeResult::RunInfo::GlyphDataRange range; + + unsigned adjusted_start = + start_index > part_start ? start_index - part_start : 0; + unsigned adjusted_end = std::min(end_index, run_end) - part_start; + DCHECK(adjusted_end > adjusted_start); + unsigned part_characters = adjusted_end - adjusted_start; + float part_width; + + // Avoid O(log n) find operation if the entire run is in range. + if (part_start >= start_index && run_end <= end_index) { + range = {run->glyph_data_.begin(), run->glyph_data_.end()}; + part_width = run->width_; + } else { + range = run->FindGlyphDataRange(adjusted_start, adjusted_end); + part_width = 0; + for (auto* glyph = range.begin; glyph != range.end; glyph++) + part_width += glyph->advance; + } + + // Adjust start_index for runs to be continuous. + unsigned part_start_index; + unsigned part_offset; + if (!run->Rtl()) { // Left-to-right + part_start_index = start_index_ + num_characters_; + part_offset = adjusted_start; + } else { // Right-to-left + part_start_index = run->start_index_ + adjusted_start; + part_offset = adjusted_start; + } + + parts_.push_back(std::make_unique<RunInfoPart>( + run, range, part_start_index, part_offset, part_characters, + part_width)); + + num_characters_ += part_characters; + num_glyphs_ += range.end - range.begin; + width_ += part_width; + } + } + + if (first_result || Rtl()) + start_index_ = ComputeStartIndex(); +} + +scoped_refptr<ShapeResultView> ShapeResultView::Create(const Segment* segments, + size_t segment_count) { + ShapeResultView* out = new ShapeResultView(segments[0].result); + out->AddSegments(segments, segment_count); + return base::AdoptRef(out); +} + +scoped_refptr<ShapeResultView> ShapeResultView::Create( + const ShapeResult* result, + unsigned start_index, + unsigned end_index) { + Segment segment = {result, start_index, end_index}; + return Create(&segment, 1); +} + +scoped_refptr<ShapeResultView> ShapeResultView::Create( + const ShapeResult* result) { + // This specialization is an optimization to allow the bounding box to be + // re-used. + ShapeResultView* out = new ShapeResultView(result); + out->char_index_offset_ = out->Rtl() ? 0 : result->StartIndex(); + out->CreateViewsForResult(result, 0, std::numeric_limits<unsigned>::max()); + out->has_vertical_offsets_ = result->has_vertical_offsets_; + out->glyph_bounding_box_ = result->glyph_bounding_box_; + return base::AdoptRef(out); +} + +void ShapeResultView::AddSegments(const Segment* segments, + size_t segment_count) { + // This method assumes that no parts have been added yet. + DCHECK_EQ(parts_.size(), 0u); + + // Segments are in logical order, runs and parts are in visual order. Iterate + // over segments back-to-front for RTL. + DCHECK_GT(segment_count, 0u); + unsigned last_segment_index = segment_count - 1; + + // Compute start index offset for the overall run. This is added to the start + // index of each glyph to ensure consistency with ShapeResult::SubRange + if (!Rtl()) { // Left-to-right + char_index_offset_ = + std::max(segments[0].result->StartIndex(), segments[0].start_index); + } else { // Right to left + char_index_offset_ = 0; + } + + for (unsigned i = 0; i < segment_count; i++) { + const Segment& segment = segments[Rtl() ? last_segment_index - i : i]; + DCHECK_EQ(segment.result->Direction(), Direction()); + CreateViewsForResult(segment.result, segment.start_index, + segment.end_index); + has_vertical_offsets_ |= segment.result->has_vertical_offsets_; + } + + float origin = 0; + for (const auto& part : parts_) { + if (part->IsHorizontal()) + ComputeBoundsForPart<true>(*part, origin); + else + ComputeBoundsForPart<false>(*part, origin); + origin += part->width_; + } +} + +template <bool is_horizontal_run> +void ShapeResultView::ComputeBoundsForPart(const RunInfoPart& part, + float origin) { + GlyphBoundsAccumulator bounds(origin); + const auto& run = part.run_; + const SimpleFontData* font_data = run->font_data_.get(); + for (const auto& glyph_data : part) { + FloatRect glyph_bounds = glyph_data.HasValidGlyphBounds() + ? FloatRect(glyph_data.GlyphBoundsBefore(), 0, + glyph_data.GlyphBoundsAfter(), 0) + : font_data->BoundsForGlyph(glyph_data.glyph); + + bounds.Unite<is_horizontal_run>(glyph_data, glyph_bounds); + bounds.origin += glyph_data.advance; + } + if (!is_horizontal_run) + bounds.ConvertVerticalRunToLogical(font_data->GetFontMetrics()); + glyph_bounding_box_.Unite(bounds.bounds); +} + +unsigned ShapeResultView::ComputeStartIndex() const { + if (UNLIKELY(parts_.IsEmpty())) + return 0; + const RunInfoPart& first_part = *parts_.front(); + if (!Rtl()) // Left-to-right. + return first_part.start_index_; + // Right-to-left. + unsigned end_index = first_part.start_index_ + first_part.num_characters_; + return end_index - num_characters_; +} + +unsigned ShapeResultView::PreviousSafeToBreakOffset(unsigned index) const { + for (auto it = parts_.rbegin(); it != parts_.rend(); ++it) { + const auto& part = *it; + if (!part) + continue; + + unsigned run_start = part->start_index_; + if (index >= run_start) { + unsigned offset = index - run_start; + if (offset <= part->num_characters_) { + return part->PreviousSafeToBreakOffset(offset) + run_start; + } + if (!Rtl()) { + return run_start + part->num_characters_; + } + } else if (Rtl()) { + if (it == parts_.rbegin()) + return part->start_index_; + const auto& previous_run = *--it; + return previous_run->start_index_ + previous_run->num_characters_; + } + } + + return StartIndex(); +} + +void ShapeResultView::GetRunFontData( + Vector<ShapeResult::RunFontData>* font_data) const { + for (const auto& part : parts_) { + font_data->push_back(ShapeResult::RunFontData( + {part->run_->font_data_.get(), part->end() - part->begin()})); + } +} + +void ShapeResultView::FallbackFonts( + HashSet<const SimpleFontData*>* fallback) const { + DCHECK(fallback); + DCHECK(primary_font_); + for (const auto& part : parts_) { + if (part->run_->font_data_ && part->run_->font_data_ != primary_font_) { + fallback->insert(part->run_->font_data_.get()); + } + } +} + +float ShapeResultView::ForEachGlyph(float initial_advance, + GlyphCallback glyph_callback, + void* context) const { + auto total_advance = initial_advance; + for (const auto& part : parts_) { + const auto& run = part->run_; + bool is_horizontal = HB_DIRECTION_IS_HORIZONTAL(run->direction_); + const SimpleFontData* font_data = run->font_data_.get(); + for (const auto& glyph_data : *part) { + unsigned character_index = glyph_data.character_index + + part->start_index_ + char_index_offset_ - + part->offset_; + glyph_callback(context, character_index, glyph_data.glyph, + glyph_data.offset, total_advance, is_horizontal, + run->canvas_rotation_, font_data); + total_advance += glyph_data.advance; + } + } + + return total_advance; +} + +float ShapeResultView::ForEachGlyph(float initial_advance, + unsigned from, + unsigned to, + unsigned index_offset, + GlyphCallback glyph_callback, + void* context) const { + auto total_advance = initial_advance; + + for (const auto& part : parts_) { + const auto& run = part->run_; + bool is_horizontal = HB_DIRECTION_IS_HORIZONTAL(run->direction_); + const SimpleFontData* font_data = run->font_data_.get(); + + if (!run->Rtl()) { // Left-to-right + for (const auto& glyph_data : *part) { + unsigned character_index = glyph_data.character_index + + part->start_index_ + char_index_offset_ - + part->offset_; + if (character_index >= to) + break; + if (character_index >= from) { + glyph_callback(context, character_index, glyph_data.glyph, + glyph_data.offset, total_advance, is_horizontal, + run->canvas_rotation_, font_data); + } + total_advance += glyph_data.advance; + } + + } else { // Right-to-left + for (const auto& glyph_data : *part) { + unsigned character_index = glyph_data.character_index + + part->start_index_ + char_index_offset_ - + part->offset_; + if (character_index < from) + break; + if (character_index < to) { + glyph_callback(context, character_index, glyph_data.glyph, + glyph_data.offset, total_advance, is_horizontal, + run->canvas_rotation_, font_data); + } + total_advance += glyph_data.advance; + } + } + } + return total_advance; +} + +float ShapeResultView::ForEachGraphemeClusters(const StringView& text, + float initial_advance, + unsigned from, + unsigned to, + unsigned index_offset, + GraphemeClusterCallback callback, + void* context) const { + unsigned run_offset = index_offset; + float advance_so_far = initial_advance; + + for (const auto& part : parts_) { + const auto& run = part->run_; + unsigned graphemes_in_cluster = 1; + float cluster_advance = 0; + bool rtl = Direction() == TextDirection::kRtl; + + // A "cluster" in this context means a cluster as it is used by HarfBuzz: + // The minimal group of characters and corresponding glyphs, that cannot be + // broken down further from a text shaping point of view. A cluster can + // contain multiple glyphs and grapheme clusters, with mutually overlapping + // boundaries. + uint16_t cluster_start = static_cast<uint16_t>( + rtl ? run->start_index_ + run->num_characters_ + run_offset + : run->GlyphToCharacterIndex(0) + run_offset); + + const unsigned num_glyphs = part->NumGlyphs(); + for (unsigned i = 0; i < num_glyphs; ++i) { + const HarfBuzzRunGlyphData& glyph_data = part->GlyphAt(i); + uint16_t current_character_index = glyph_data.character_index + + part->start_index_ + + char_index_offset_ - part->offset_; + + bool is_run_end = (i + 1 == num_glyphs); + bool is_cluster_end = + is_run_end || (run->GlyphToCharacterIndex(i + 1) + run_offset != + current_character_index); + + if ((rtl && current_character_index >= to) || + (!rtl && current_character_index < from)) { + advance_so_far += glyph_data.advance; + rtl ? --cluster_start : ++cluster_start; + continue; + } + + cluster_advance += glyph_data.advance; + + if (text.Is8Bit()) { + callback(context, current_character_index, advance_so_far, 1, + glyph_data.advance, run->canvas_rotation_); + + advance_so_far += glyph_data.advance; + } else if (is_cluster_end) { + uint16_t cluster_end; + if (rtl) { + cluster_end = current_character_index; + } else { + cluster_end = static_cast<uint16_t>( + is_run_end ? run->start_index_ + run->num_characters_ + run_offset + : run->GlyphToCharacterIndex(i + 1) + run_offset); + } + graphemes_in_cluster = ShapeResult::CountGraphemesInCluster( + text.Characters16(), text.length(), cluster_start, cluster_end); + if (!graphemes_in_cluster || !cluster_advance) + continue; + + callback(context, current_character_index, advance_so_far, + graphemes_in_cluster, cluster_advance, run->canvas_rotation_); + advance_so_far += cluster_advance; + + cluster_start = cluster_end; + cluster_advance = 0; + } + } + } + return advance_so_far; +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h new file mode 100644 index 00000000000..214fd54fbc1 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h @@ -0,0 +1,167 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_VIEW_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_VIEW_H_ + +#include <memory> +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" +#include "third_party/blink/renderer/platform/fonts/simple_font_data.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/text/text_direction.h" +#include "third_party/blink/renderer/platform/wtf/forward.h" +#include "third_party/blink/renderer/platform/wtf/noncopyable.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +class ShapeResult; + +// Class representing a read-only composite of views into one or more existing +// shape results. +// Implemented as a list of ref counted RunInfo instances and a start/end +// offset for each, represented using the internal RunInfoPart struct. +// This allows lines to be reference sections of the overall paragraph shape +// results without the memory or computational overhead of a copy. +// +// The example below shows the shape result and the individual lines as +// ShapeResultView instances pointing to the original paragraph results for +// the string "Pack my box with five dozen liquor jugs.": +// ╔═════════════════════════════════════════════════════╗ +// ║ Paragraph with single run, no re-shaping for lines. ║ +// ╟─────────────────────────────────────────────────────╢ +// ║ runs_ ╭───────────────────────────────────────────╮ ║ +// ║ 1: │ Pack my box with five dozen liquor jugs. │ ║ +// ║ ╰───────────────────────────────────────────╯ ║ +// ║ lines ╭───────────────────────────────────────────╮ ║ +// ║ 1: │ Pack my box with -> view, run 1: 0-16 │ ║ +// ║ 2: │ five dozen liquor -> view, run 1: 17-34 │ ║ +// ║ 3: │ jugs. -> view, run 1: 35-40 │ ║ +// ║ ╰───────────────────────────────────────────╯ ║ +// ╚═════════════════════════════════════════════════════╝ +// +// In cases where a portion of the line needs re-shaping the new results are +// added as separate runs at the beginning and/or end of the runs_ vector with a +// reference to zero or more sub-runs in the middle representing the original +// content that could be reused. +// +// In the example below the end of the first line "Jack!" needs to be re-shaped: +// ╔═════════════════════════════════════════════════════╗ +// ║ Paragraph with single run, requiring re-shape. ║ +// ╟─────────────────────────────────────────────────────╢ +// ║ runs_ ╭───────────────────────────────────────────╮ ║ +// ║ 1: │ "Now fax quiz Jack!" my brave ghost pled. │ ║ +// ║ ╰───────────────────────────────────────────╯ ║ +// ║ lines ╭───────────────────────────────────────────╮ ║ +// ║ 1: │ "Now fax quiz -> view, run 1: 0-14 │ ║ +// ║ 1: │ Jack! -> new result/run │ ║ +// ║ 2: │ my brave ghost -> view, run 1: 21-35 │ ║ +// ║ 3: │ pled. -> view, run 1: 41-36 │ ║ +// ║ ╰───────────────────────────────────────────╯ ║ +// ╚═════════════════════════════════════════════════════╝ +// +// In this case the beginning of the first line would be represented as a part +// referecing the a range into the original ShapeResult while the last word wold +// be a separate result owned by the ShapeResultView instance. The second +// and third lines would again be represented as parts. +class PLATFORM_EXPORT ShapeResultView final + : public RefCounted<ShapeResultView> { + public: + // Create a new ShapeResultView from a pre-defined list of segments. + // The segments list is assumed to be in logical order. + struct Segment { + const ShapeResult* result; + unsigned start_index; + unsigned end_index; + }; + static scoped_refptr<ShapeResultView> Create(const Segment*, size_t); + + // Creates a new ShapeResultView from a single segment. + static scoped_refptr<ShapeResultView> Create(const ShapeResult*); + static scoped_refptr<ShapeResultView> Create(const ShapeResult*, + unsigned start_index, + unsigned end_index); + + ~ShapeResultView(); + + scoped_refptr<ShapeResult> CreateShapeResult() const; + + unsigned StartIndex() const { return start_index_ + char_index_offset_; } + unsigned EndIndex() const { return StartIndex() + num_characters_; } + unsigned NumCharacters() const { return num_characters_; } + unsigned NumGlyphs() const { return num_glyphs_; } + float Width() const { return width_; } + LayoutUnit SnappedWidth() const { return LayoutUnit::FromFloatCeil(width_); } + const FloatRect& Bounds() const { return glyph_bounding_box_; } + TextDirection Direction() const { + return static_cast<TextDirection>(direction_); + } + bool Rtl() const { return Direction() == TextDirection::kRtl; } + bool HasVerticalOffsets() const { return has_vertical_offsets_; } + void FallbackFonts(HashSet<const SimpleFontData*>* fallback) const; + + unsigned PreviousSafeToBreakOffset(unsigned index) const; + + float ForEachGlyph(float initial_advance, GlyphCallback, void* context) const; + float ForEachGlyph(float initial_advance, + unsigned from, + unsigned to, + unsigned index_offset, + GlyphCallback, + void* context) const; + + float ForEachGraphemeClusters(const StringView& text, + float initial_advance, + unsigned from, + unsigned to, + unsigned index_offset, + GraphemeClusterCallback, + void* context) const; + + scoped_refptr<const SimpleFontData> PrimaryFont() const { + return primary_font_; + } + void GetRunFontData(Vector<ShapeResult::RunFontData>*) const; + + private: + ShapeResultView(const ShapeResult*); + unsigned ComputeStartIndex() const; + + struct RunInfoPart; + void CreateViewsForResult(const ShapeResult*, + unsigned start_index, + unsigned end_index); + void AddSegments(const Segment*, size_t); + template <bool is_horizontal_run> + void ComputeBoundsForPart(const RunInfoPart&, float origin); + + scoped_refptr<const SimpleFontData> primary_font_; + + mutable unsigned start_index_; // Cached and updated by ComputeStartIndex. + unsigned num_characters_; + unsigned num_glyphs_ : 30; + + // Overall direction for the TextRun, dictates which order each individual + // sub run (represented by RunInfo structs in the m_runs vector) can + // have a different text direction. + unsigned direction_ : 1; + + // Tracks whether any runs contain glyphs with a y-offset != 0. + unsigned has_vertical_offsets_ : 1; + + // Offset of the first component added to the view. Used for compatibility + // with ShapeResult::SubRange + unsigned char_index_offset_; + + float width_; + FloatRect glyph_bounding_box_; + Vector<std::unique_ptr<RunInfoPart>, 4> parts_; + + friend class ShapeResult; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPE_RESULT_VIEW_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc new file mode 100644 index 00000000000..04af141cb59 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_view_test.cc @@ -0,0 +1,366 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h" + +#include <unicode/uscript.h> +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/font_cache.h" +#include "third_party/blink/renderer/platform/fonts/font_test_utilities.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" + +namespace blink { + +class ShapeResultViewTest : public testing::Test { + protected: + void SetUp() override { + font_description.SetComputedSize(12.0); + font = Font(font_description); + font.Update(nullptr); + } + + void TearDown() override {} + + FontCachePurgePreventer font_cache_purge_preventer; + FontDescription font_description; + Font font; +}; + +namespace { + +struct ShapeResultViewGlyphInfo { + unsigned character_index; + Glyph glyph; + float advance; +}; + +void AddGlyphInfo(void* context, + unsigned character_index, + Glyph glyph, + FloatSize glyph_offset, + float advance, + bool is_horizontal, + CanvasRotationInVertical rotation, + const SimpleFontData* font_data) { + auto* list = static_cast<Vector<ShapeResultViewGlyphInfo>*>(context); + ShapeResultViewGlyphInfo glyph_info = {character_index, glyph, advance}; + list->push_back(glyph_info); +} + +bool CompareResultGlyphs(const Vector<ShapeResultViewGlyphInfo>& test, + const Vector<ShapeResultViewGlyphInfo>& reference, + unsigned reference_start, + unsigned num_glyphs) { + float advance_offset = reference[reference_start].advance; + bool glyphs_match = true; + for (unsigned i = 0; i < test.size(); i++) { + const auto& test_glyph = test[i]; + const auto& reference_glyph = reference[i + reference_start]; + if (test_glyph.character_index != reference_glyph.character_index || + test_glyph.glyph != reference_glyph.glyph || + test_glyph.advance != reference_glyph.advance - advance_offset) { + glyphs_match = false; + break; + } + } + if (!glyphs_match) { + fprintf(stderr, "╔══ Actual ═══════╤═══════╤═════════╗ "); + fprintf(stderr, "╔══ Expected ═════╤═══════╤═════════╗\n"); + fprintf(stderr, "║ Character Index │ Glyph │ Advance ║ "); + fprintf(stderr, "║ Character Index │ Glyph │ Advance ║\n"); + fprintf(stderr, "╟─────────────────┼───────┼─────────╢ "); + fprintf(stderr, "╟─────────────────┼───────┼─────────╢\n"); + for (unsigned i = 0; i < test.size(); i++) { + const auto& test_glyph = test[i]; + const auto& reference_glyph = reference[i + reference_start]; + + if (test_glyph.character_index == reference_glyph.character_index) + fprintf(stderr, "║ %10u │", test_glyph.character_index); + else + fprintf(stderr, "║▶ %10u◀│", test_glyph.character_index); + + if (test_glyph.glyph == reference_glyph.glyph) + fprintf(stderr, " %04X │", test_glyph.glyph); + else + fprintf(stderr, "▶ %04X◀│", test_glyph.glyph); + + if (test_glyph.advance == reference_glyph.advance) + fprintf(stderr, " %7.2f ║ ", test_glyph.advance); + else + fprintf(stderr, "▶%7.2f◀║ ", test_glyph.advance); + + fprintf(stderr, "║ %10u │ %04X │ %7.2f ║\n", + reference_glyph.character_index, reference_glyph.glyph, + reference_glyph.advance - advance_offset); + } + fprintf(stderr, "╚═════════════════╧═══════╧═════════╝ "); + fprintf(stderr, "╚═════════════════╧═══════╧═════════╝\n"); + } + return glyphs_match; +} + +} // anonymous namespace + +TEST_F(ShapeResultViewTest, LatinSingleView) { + String string = + To16Bit("Test run with multiple words and breaking opportunities.", 56); + TextDirection direction = TextDirection::kLtr; + + HarfBuzzShaper shaper(string); + scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction); + Vector<ShapeResultViewGlyphInfo> glyphs; + result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs)); + + // Test view at the start of the result: "Test run with multiple" + ShapeResultView::Segment segment = {result.get(), 0, 22}; + auto first4 = ShapeResultView::Create(&segment, 1); + + EXPECT_EQ(first4->StartIndex(), 0u); + EXPECT_EQ(first4->NumCharacters(), 22u); + EXPECT_EQ(first4->NumGlyphs(), 22u); + + Vector<ShapeResultViewGlyphInfo> first4_glyphs; + first4->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&first4_glyphs)); + EXPECT_EQ(first4_glyphs.size(), 22u); + EXPECT_TRUE(CompareResultGlyphs(first4_glyphs, glyphs, 0u, 22u)); + + // Test view in the middle of the result: "multiple words and breaking" + segment = {result.get(), 14, 41}; + auto middle4 = ShapeResultView::Create(&segment, 1); + + EXPECT_EQ(middle4->StartIndex(), 14u); + EXPECT_EQ(middle4->NumCharacters(), 27u); + EXPECT_EQ(middle4->NumGlyphs(), 27u); + + Vector<ShapeResultViewGlyphInfo> middle4_glyphs; + middle4->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&middle4_glyphs)); + EXPECT_EQ(middle4_glyphs.size(), 27u); + EXPECT_TRUE(CompareResultGlyphs(middle4_glyphs, glyphs, 14u, 27u)); + + // Test view at the end of the result: "breaking opportunities." + segment = {result.get(), 33, 56}; + auto last2 = ShapeResultView::Create(&segment, 1); + + EXPECT_EQ(last2->StartIndex(), 33u); + EXPECT_EQ(last2->NumCharacters(), 23u); + EXPECT_EQ(last2->NumGlyphs(), 23u); + + Vector<ShapeResultViewGlyphInfo> last2_glyphs; + last2->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&last2_glyphs)); + EXPECT_EQ(last2_glyphs.size(), 23u); + EXPECT_TRUE(CompareResultGlyphs(last2_glyphs, glyphs, 33u, 23u)); +} + +TEST_F(ShapeResultViewTest, ArabicSingleView) { + String string = To16Bit("عربى نص", 7); + TextDirection direction = TextDirection::kRtl; + + HarfBuzzShaper shaper(string); + scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction); + Vector<ShapeResultViewGlyphInfo> glyphs; + result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs)); + + // Test view at the start of the result: "عربى" + ShapeResultView::Segment segment = {result.get(), 0, 4}; + auto first_word = ShapeResultView::Create(&segment, 1); + Vector<ShapeResultViewGlyphInfo> first_glyphs; + first_word->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&first_glyphs)); + + EXPECT_EQ(first_word->StartIndex(), 0u); + EXPECT_EQ(first_word->NumCharacters(), 4u); + EXPECT_EQ(first_word->NumGlyphs(), 4u); + EXPECT_EQ(first_glyphs.size(), 4u); + + String first_reference_string = To16Bit("عربى", 4); + HarfBuzzShaper first_reference_shaper(first_reference_string); + scoped_refptr<const ShapeResult> first_wortd_reference = + first_reference_shaper.Shape(&font, direction); + Vector<ShapeResultViewGlyphInfo> first_reference_glyphs; + first_wortd_reference->ForEachGlyph( + 0, AddGlyphInfo, static_cast<void*>(&first_reference_glyphs)); + EXPECT_EQ(first_reference_glyphs.size(), 4u); + + EXPECT_TRUE( + CompareResultGlyphs(first_glyphs, first_reference_glyphs, 0u, 4u)); + EXPECT_TRUE(CompareResultGlyphs(first_glyphs, glyphs, 3u, 7u)); + + // Test view at the end of the result: "نص" + segment = {result.get(), 4, 7}; + auto last_word = ShapeResultView::Create(&segment, 1); + Vector<ShapeResultViewGlyphInfo> last_glyphs; + last_word->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&last_glyphs)); + + EXPECT_EQ(last_word->StartIndex(), 4u); + EXPECT_EQ(last_word->NumCharacters(), 3u); + EXPECT_EQ(last_word->NumGlyphs(), 3u); + EXPECT_EQ(last_glyphs.size(), 3u); +} + +TEST_F(ShapeResultViewTest, LatinMultiRun) { + TextDirection direction = TextDirection::kLtr; + HarfBuzzShaper shaper_a(To16Bit("hello", 5)); + HarfBuzzShaper shaper_b(To16Bit(" w", 2)); + HarfBuzzShaper shaper_c(To16Bit("orld", 4)); + HarfBuzzShaper shaper_d(To16Bit("!", 1)); + + // Combine four separate results into a single one to ensure we have a result + // with multiple runs: "hello world!" + scoped_refptr<ShapeResult> result = ShapeResult::Create(&font, 0, direction); + shaper_a.Shape(&font, direction)->CopyRange(0u, 5u, result.get()); + shaper_b.Shape(&font, direction)->CopyRange(0u, 2u, result.get()); + shaper_c.Shape(&font, direction)->CopyRange(0u, 4u, result.get()); + shaper_d.Shape(&font, direction)->CopyRange(0u, 1u, result.get()); + + Vector<ShapeResultViewGlyphInfo> result_glyphs; + result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&result_glyphs)); + + // Create composite view out of multiple segments where at least some of the + // segments have multiple runs: "hello wood wold!" + ShapeResultView::Segment segments[5] = { + {result.get(), 0, 8}, // "hello wo" + {result.get(), 7, 8}, // "o" + {result.get(), 10, 11}, // "d" + {result.get(), 5, 8}, // " wo" + {result.get(), 9, 12}, // "ld!" + }; + auto composite_view = ShapeResultView::Create(&segments[0], 5); + Vector<ShapeResultViewGlyphInfo> view_glyphs; + composite_view->ForEachGlyph(0, AddGlyphInfo, + static_cast<void*>(&view_glyphs)); + + EXPECT_EQ(composite_view->StartIndex(), 0u); + EXPECT_EQ(composite_view->NumCharacters(), 16u); + EXPECT_EQ(composite_view->NumGlyphs(), 16u); + EXPECT_EQ(view_glyphs.size(), 16u); + + HarfBuzzShaper shaper2(To16Bit("hello world!", 12)); + scoped_refptr<const ShapeResult> result2 = shaper2.Shape(&font, direction); + Vector<ShapeResultViewGlyphInfo> glyphs2; + result2->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs2)); + EXPECT_TRUE(CompareResultGlyphs(result_glyphs, glyphs2, 0u, 12u)); + + HarfBuzzShaper reference_shaper(To16Bit("hello wood wold!", 16)); + scoped_refptr<const ShapeResult> reference_result = + reference_shaper.Shape(&font, direction); + Vector<ShapeResultViewGlyphInfo> reference_glyphs; + reference_result->ForEachGlyph(0, AddGlyphInfo, + static_cast<void*>(&reference_glyphs)); + + scoped_refptr<ShapeResult> composite_copy = + ShapeResult::Create(&font, 0, direction); + result->CopyRange(0, 8, composite_copy.get()); + result->CopyRange(7, 8, composite_copy.get()); + result->CopyRange(10, 11, composite_copy.get()); + result->CopyRange(5, 8, composite_copy.get()); + result->CopyRange(9, 12, composite_copy.get()); + + Vector<ShapeResultViewGlyphInfo> composite_copy_glyphs; + composite_copy->ForEachGlyph(0, AddGlyphInfo, + static_cast<void*>(&composite_copy_glyphs)); + + EXPECT_TRUE(CompareResultGlyphs(view_glyphs, reference_glyphs, 0u, 16u)); + EXPECT_TRUE( + CompareResultGlyphs(composite_copy_glyphs, reference_glyphs, 0u, 16u)); +} + +TEST_F(ShapeResultViewTest, LatinCompositeView) { + String string = + To16Bit("Test run with multiple words and breaking opportunities.", 56); + TextDirection direction = TextDirection::kLtr; + + HarfBuzzShaper shaper(string); + scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction); + Vector<ShapeResultViewGlyphInfo> glyphs; + result->ForEachGlyph(0, AddGlyphInfo, static_cast<void*>(&glyphs)); + + String reference_string = To16Bit("multiple breaking opportunities Test", 36); + HarfBuzzShaper reference_shaper(reference_string); + scoped_refptr<const ShapeResult> reference_result = + reference_shaper.Shape(&font, direction); + Vector<ShapeResultViewGlyphInfo> reference_glyphs; + + // Match the character index logic of ShapeResult::CopyRange where the the + // character index of the first result is preserved and all subsequent ones + // are adjusted to be sequential. + // TODO(layout-dev): Arguably both should be updated to renumber the first + // result as well but some callers depend on the existing behavior. + scoped_refptr<ShapeResult> composite_copy = + ShapeResult::Create(&font, 0, direction); + result->CopyRange(14, 23, composite_copy.get()); + result->CopyRange(33, 55, composite_copy.get()); + result->CopyRange(4, 5, composite_copy.get()); + result->CopyRange(0, 4, composite_copy.get()); + EXPECT_EQ(composite_copy->NumCharacters(), reference_result->NumCharacters()); + EXPECT_EQ(composite_copy->NumGlyphs(), reference_result->NumGlyphs()); + composite_copy->ForEachGlyph(0, AddGlyphInfo, + static_cast<void*>(&reference_glyphs)); + + // Create composite view out of multiple segments: + ShapeResultView::Segment segments[4] = { + {result.get(), 14, 23}, // "multiple " + {result.get(), 33, 55}, // "breaking opportunities" + {result.get(), 4, 5}, // " " + {result.get(), 0, 4} // "Test" + }; + auto composite_view = ShapeResultView::Create(&segments[0], 4); + + EXPECT_EQ(composite_view->StartIndex(), composite_copy->StartIndex()); + EXPECT_EQ(composite_view->NumCharacters(), reference_result->NumCharacters()); + EXPECT_EQ(composite_view->NumGlyphs(), reference_result->NumGlyphs()); + + Vector<ShapeResultViewGlyphInfo> composite_glyphs; + composite_view->ForEachGlyph(0, AddGlyphInfo, + static_cast<void*>(&composite_glyphs)); + EXPECT_EQ(composite_glyphs.size(), 36u); + EXPECT_TRUE(CompareResultGlyphs(composite_glyphs, reference_glyphs, 0u, 22u)); +} + +TEST_F(ShapeResultViewTest, MixedScriptsCompositeView) { + String string_a = To16Bit("Test with multiple 字体 ", 22); + String string_b = To16Bit("and 本書.", 7); + TextDirection direction = TextDirection::kLtr; + + HarfBuzzShaper shaper_a(string_a); + scoped_refptr<const ShapeResult> result_a = shaper_a.Shape(&font, direction); + HarfBuzzShaper shaper_b(string_b); + scoped_refptr<const ShapeResult> result_b = shaper_b.Shape(&font, direction); + + String reference_string = To16Bit("Test with multiple 字体 and 本書.", 29); + HarfBuzzShaper reference_shaper(reference_string); + scoped_refptr<const ShapeResult> reference_result = + reference_shaper.Shape(&font, direction); + + // Create a copy using CopyRange and compare with that to ensure that the same + // fonts are used for both the composite and the reference. The combined + // reference_result data might use different fonts, resulting in different + // glyph ids and metrics. + scoped_refptr<ShapeResult> composite_copy = + ShapeResult::Create(&font, 0, direction); + result_a->CopyRange(0, 22, composite_copy.get()); + result_b->CopyRange(0, 7, composite_copy.get()); + EXPECT_EQ(composite_copy->NumCharacters(), reference_result->NumCharacters()); + EXPECT_EQ(composite_copy->NumGlyphs(), reference_result->NumGlyphs()); + Vector<ShapeResultViewGlyphInfo> reference_glyphs; + composite_copy->ForEachGlyph(0, AddGlyphInfo, + static_cast<void*>(&reference_glyphs)); + + ShapeResultView::Segment segments[4] = {{result_a.get(), 0, 22}, + {result_b.get(), 0, 7}}; + auto composite_view = ShapeResultView::Create(&segments[0], 2); + + EXPECT_EQ(composite_view->StartIndex(), 0u); + EXPECT_EQ(composite_view->NumCharacters(), reference_result->NumCharacters()); + EXPECT_EQ(composite_view->NumGlyphs(), reference_result->NumGlyphs()); + + Vector<ShapeResultViewGlyphInfo> composite_glyphs; + composite_view->ForEachGlyph(0, AddGlyphInfo, + static_cast<void*>(&composite_glyphs)); + EXPECT_TRUE(CompareResultGlyphs(composite_glyphs, reference_glyphs, 0u, + reference_glyphs.size())); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc index 655112d0aee..22198066fef 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.cc @@ -8,6 +8,7 @@ #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" #include "third_party/blink/renderer/platform/text/text_break_iterator.h" namespace blink { @@ -215,14 +216,14 @@ inline scoped_refptr<ShapeResult> ShapingLineBreaker::Shape(TextDirection direct // If we further assume that the font kerns with space then even though it's a // valid break opportunity reshaping is required as the combined width of the // two segments "Line " and "breaking" may be different from "Line breaking". -scoped_refptr<const ShapeResult> ShapingLineBreaker::ShapeLine( +scoped_refptr<const ShapeResultView> ShapingLineBreaker::ShapeLine( unsigned start, LayoutUnit available_space, unsigned options, ShapingLineBreaker::Result* result_out) { DCHECK_GE(available_space, LayoutUnit(0)); - unsigned range_start = result_->StartIndexForResult(); - unsigned range_end = result_->EndIndexForResult(); + unsigned range_start = result_->StartIndex(); + unsigned range_end = result_->EndIndex(); DCHECK_GE(start, range_start); DCHECK_LT(start, range_end); result_out->is_hyphenated = false; @@ -287,7 +288,8 @@ scoped_refptr<const ShapeResult> ShapingLineBreaker::ShapeLine( if (first_safe >= break_opportunity.offset) { // There is no safe-to-break, reshape the whole range. result_out->break_offset = break_opportunity.offset; - return Shape(direction, start, break_opportunity.offset); + return ShapeResultView::Create( + Shape(direction, start, break_opportunity.offset).get()); } LayoutUnit original_width = FlipRtl( SnapEnd(result_->CachedPositionForOffset(first_safe - range_start), @@ -354,14 +356,16 @@ scoped_refptr<const ShapeResult> ShapingLineBreaker::ShapeLine( // Create shape results for the line by copying from the re-shaped result (if // reshaping was needed) and the original shape results. - scoped_refptr<ShapeResult> line_result = ShapeResult::Create(font_, 0, direction); + ShapeResultView::Segment segments[3]; unsigned max_length = std::numeric_limits<unsigned>::max(); + unsigned count = 0; if (line_start_result) - line_start_result->CopyRange(0, max_length, line_result.get()); + segments[count++] = {line_start_result.get(), 0, max_length}; if (last_safe > first_safe) - result_->CopyRange(first_safe, last_safe, line_result.get()); + segments[count++] = {result_.get(), first_safe, last_safe}; if (line_end_result) - line_end_result->CopyRange(last_safe, max_length, line_result.get()); + segments[count++] = {line_end_result.get(), last_safe, max_length}; + auto line_result = ShapeResultView::Create(&segments[0], count); DCHECK_GT(break_opportunity.offset, start); DCHECK_LE(break_opportunity.offset, range_end); @@ -376,37 +380,40 @@ scoped_refptr<const ShapeResult> ShapingLineBreaker::ShapeLine( // Shape from the specified offset to the end of the ShapeResult. // If |start| is safe-to-break, this copies the subset of the result. -scoped_refptr<const ShapeResult> ShapingLineBreaker::ShapeToEnd( +scoped_refptr<const ShapeResultView> ShapingLineBreaker::ShapeToEnd( unsigned start, unsigned first_safe, unsigned range_start, unsigned range_end) { DCHECK(result_); - DCHECK_EQ(range_start, result_->StartIndexForResult()); - DCHECK_EQ(range_end, result_->EndIndexForResult()); + DCHECK_EQ(range_start, result_->StartIndex()); + DCHECK_EQ(range_end, result_->EndIndex()); DCHECK_GE(start, range_start); DCHECK_LT(start, range_end); DCHECK_GE(first_safe, start); // If |start| is at the start of the range the entire result object may be - // reused, which avoids creating an extra copy an the sub-range logic. + // reused, which avoids the sub-range logic and bounds computation. if (start == range_start) - return result_; + return ShapeResultView::Create(result_.get()); // If |start| is safe-to-break, no reshape is needed. if (start == first_safe) - return result_->SubRange(start, range_end); + return ShapeResultView::Create(result_.get(), start, range_end); // If no safe-to-break offset is found in range, reshape the entire range. TextDirection direction = result_->Direction(); - if (first_safe >= range_end) - return Shape(direction, start, range_end); + if (first_safe >= range_end) { + scoped_refptr<ShapeResult> line_result = Shape(direction, start, range_end); + return ShapeResultView::Create(line_result.get()); + } // Otherwise reshape to |first_safe|, then copy the rest. - scoped_refptr<ShapeResult> line_result = Shape(direction, start, first_safe); - result_->CopyRange(first_safe, range_end, line_result.get()); - DCHECK_EQ(range_end - start, line_result->NumCharacters()); - return line_result; + scoped_refptr<ShapeResult> line_start = Shape(direction, start, first_safe); + ShapeResultView::Segment segments[2] = { + {line_start.get(), 0, std::numeric_limits<unsigned>::max()}, + {result_.get(), first_safe, range_end}}; + return ShapeResultView::Create(&segments[0], 2); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h index e58db434b6e..159cd3e4068 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h @@ -6,7 +6,7 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_SHAPING_LINE_BREAKER_H_ #include "third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h" -#include "third_party/blink/renderer/platform/layout_unit.h" +#include "third_party/blink/renderer/platform/geometry/layout_unit.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/text/text_direction.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" @@ -15,6 +15,7 @@ namespace blink { class Font; class ShapeResult; +class ShapeResultView; class HarfBuzzShaper; class Hyphenation; class LazyLineBreakIterator; @@ -76,13 +77,13 @@ class PLATFORM_EXPORT ShapingLineBreaker final { // suppress if ShapeResult is not needed when this line overflows. kNoResultIfOverflow = 2, }; - scoped_refptr<const ShapeResult> ShapeLine(unsigned start_offset, - LayoutUnit available_space, - unsigned options, - Result* result_out); - scoped_refptr<const ShapeResult> ShapeLine(unsigned start_offset, - LayoutUnit available_space, - Result* result_out) { + scoped_refptr<const ShapeResultView> ShapeLine(unsigned start_offset, + LayoutUnit available_space, + unsigned options, + Result* result_out); + scoped_refptr<const ShapeResultView> ShapeLine(unsigned start_offset, + LayoutUnit available_space, + Result* result_out) { return ShapeLine(start_offset, available_space, kDefaultOptions, result_out); } @@ -116,10 +117,10 @@ class PLATFORM_EXPORT ShapingLineBreaker final { bool backwards) const; scoped_refptr<ShapeResult> Shape(TextDirection, unsigned start, unsigned end); - scoped_refptr<const ShapeResult> ShapeToEnd(unsigned start, - unsigned first_safe, - unsigned range_start, - unsigned range_end); + scoped_refptr<const ShapeResultView> ShapeToEnd(unsigned start, + unsigned first_safe, + unsigned range_start, + unsigned range_end); const HarfBuzzShaper* shaper_; const Font* font_; diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc index 3b62eec89a7..25ba3d14546 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker_test.cc @@ -11,6 +11,7 @@ #include "third_party/blink/renderer/platform/fonts/font_cache.h" #include "third_party/blink/renderer/platform/fonts/font_test_utilities.h" #include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_view.h" #include "third_party/blink/renderer/platform/text/text_break_iterator.h" #include "third_party/blink/renderer/platform/text/text_run.h" #include "third_party/blink/renderer/platform/wtf/vector.h" @@ -19,12 +20,12 @@ namespace blink { namespace { -scoped_refptr<const ShapeResult> ShapeLine(ShapingLineBreaker* breaker, - unsigned start_offset, - LayoutUnit available_space, - unsigned* break_offset) { +scoped_refptr<const ShapeResultView> ShapeLine(ShapingLineBreaker* breaker, + unsigned start_offset, + LayoutUnit available_space, + unsigned* break_offset) { ShapingLineBreaker::Result result; - scoped_refptr<const ShapeResult> shape_result = + scoped_refptr<const ShapeResultView> shape_result = breaker->ShapeLine(start_offset, available_space, &result); *break_offset = result.break_offset; return shape_result; @@ -109,7 +110,7 @@ TEST_F(ShapingLineBreakerTest, ShapeLineLatin) { ASSERT_LT(first1->SnappedWidth(), first2->SnappedWidth()); ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator); - scoped_refptr<const ShapeResult> line; + scoped_refptr<const ShapeResultView> line; unsigned break_offset = 0; // Test the case where the entire string fits. @@ -195,7 +196,7 @@ TEST_F(ShapingLineBreakerTest, ShapeLineLatinBreakAll) { shaper.Shape(&font, direction, 0, 16); ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator); - scoped_refptr<const ShapeResult> line; + scoped_refptr<const ShapeResultView> line; unsigned break_offset = 0; line = ShapeLine(&breaker, 0, midpoint->SnappedWidth(), &break_offset); @@ -216,7 +217,7 @@ TEST_F(ShapingLineBreakerTest, ShapeLineZeroAvailableWidth) { scoped_refptr<const ShapeResult> result = shaper.Shape(&font, direction); ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator); - scoped_refptr<const ShapeResult> line; + scoped_refptr<const ShapeResultView> line; unsigned break_offset = 0; LayoutUnit zero(0); @@ -288,7 +289,7 @@ TEST_F(ShapingLineBreakerTest, ShapeLineRangeEndMidWord) { shaper.Shape(&font, direction, 0, 2); ShapingLineBreaker breaker(&shaper, &font, result.get(), &break_iterator); - scoped_refptr<const ShapeResult> line; + scoped_refptr<const ShapeResultView> line; unsigned break_offset = 0; line = ShapeLine(&breaker, 0, LayoutUnit::Max(), &break_offset); diff --git a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc index 520dad11c05..d742599579d 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.cc @@ -77,20 +77,18 @@ void SimpleFontData::PlatformInit(bool subpixel_ascent_descent) { return; } - SkPaint::FontMetrics metrics; + SkFontMetrics metrics; - PaintFont font; - platform_data_.SetupPaintFont(&font); - font.SetTextEncoding(SkPaint::kGlyphID_TextEncoding); - paint_ = font.ToSkPaint(); - paint_.getFontMetrics(&metrics); + font_ = SkFont(); + platform_data_.SetupSkFont(&font_); + font_.getMetrics(&metrics); float ascent; float descent; FontMetrics::AscentDescentWithHacks( ascent, descent, visual_overflow_inflation_for_ascent_, - visual_overflow_inflation_for_descent_, platform_data_, paint_, + visual_overflow_inflation_for_descent_, platform_data_, font_, subpixel_ascent_descent); font_metrics_.SetAscent(ascent); @@ -162,7 +160,7 @@ void SimpleFontData::PlatformInit(bool subpixel_ascent_descent) { } #endif - SkTypeface* face = paint_.getTypeface(); + SkTypeface* face = font_.getTypeface(); DCHECK(face); if (int units_per_em = face->getUnitsPerEm()) font_metrics_.SetUnitsPerEm(units_per_em); @@ -350,7 +348,7 @@ FloatRect SimpleFontData::PlatformBoundsForGlyph(Glyph glyph) const { static_assert(sizeof(glyph) == 2, "Glyph id should not be truncated."); SkRect bounds; - SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyph(glyph, &bounds); + SkFontGetBoundsForGlyph(font_, glyph, &bounds); return FloatRect(bounds); } @@ -362,7 +360,7 @@ void SimpleFontData::BoundsForGlyphs(const Vector<Glyph, 256>& glyphs, return; DCHECK_EQ(bounds->size(), glyphs.size()); - SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, bounds->data()); + SkFontGetBoundsForGlyphs(font_, glyphs, bounds->data()); } float SimpleFontData::PlatformWidthForGlyph(Glyph glyph) const { @@ -371,7 +369,7 @@ float SimpleFontData::PlatformWidthForGlyph(Glyph glyph) const { static_assert(sizeof(glyph) == 2, "Glyph id should not be truncated."); - return SkiaTextMetrics(&paint_).GetSkiaWidthForGlyph(glyph); + return SkFontGetWidthForGlyph(font_, glyph); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h index cc4a85d261e..055acafeff3 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h +++ b/chromium/third_party/blink/renderer/platform/fonts/simple_font_data.h @@ -24,7 +24,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SIMPLE_FONT_DATA_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SIMPLE_FONT_DATA_H_ -#include <SkPaint.h> +#include <SkFont.h> #include <memory> #include <utility> @@ -170,7 +170,7 @@ class PLATFORM_EXPORT SimpleFontData : public FontData { float avg_char_width_; FontPlatformData platform_data_; - SkPaint paint_; + SkFont font_; Glyph space_glyph_; float space_width_; diff --git a/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc b/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc index 0c49c09a536..90898dbc4a8 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/skia/font_cache_skia.cc @@ -166,14 +166,14 @@ scoped_refptr<SimpleFontData> FontCache::GetLastResortFallbackFont( if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, sans_creation_params, - (FontFamilyNames::Sans)); + (font_family_names::kSans)); font_platform_data = GetFontPlatformData(description, sans_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, arial_creation_params, - (FontFamilyNames::Arial)); + (font_family_names::kArial)); font_platform_data = GetFontPlatformData(description, arial_creation_params, AlternateFontName::kLastResort); } @@ -182,7 +182,7 @@ scoped_refptr<SimpleFontData> FontCache::GetLastResortFallbackFont( if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, msuigothic_creation_params, - (FontFamilyNames::MS_UI_Gothic)); + (font_family_names::kMSUIGothic)); font_platform_data = GetFontPlatformData(description, msuigothic_creation_params, AlternateFontName::kLastResort); @@ -190,7 +190,7 @@ scoped_refptr<SimpleFontData> FontCache::GetLastResortFallbackFont( if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, mssansserif_creation_params, - (FontFamilyNames::Microsoft_Sans_Serif)); + (font_family_names::kMicrosoftSansSerif)); font_platform_data = GetFontPlatformData(description, mssansserif_creation_params, AlternateFontName::kLastResort); @@ -198,21 +198,21 @@ scoped_refptr<SimpleFontData> FontCache::GetLastResortFallbackFont( if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, segoeui_creation_params, - (FontFamilyNames::Segoe_UI)); + (font_family_names::kSegoeUI)); font_platform_data = GetFontPlatformData( description, segoeui_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, calibri_creation_params, - (FontFamilyNames::Calibri)); + (font_family_names::kCalibri)); font_platform_data = GetFontPlatformData( description, calibri_creation_params, AlternateFontName::kLastResort); } if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, timesnewroman_creation_params, - (FontFamilyNames::Times_New_Roman)); + (font_family_names::kTimesNewRoman)); font_platform_data = GetFontPlatformData(description, timesnewroman_creation_params, AlternateFontName::kLastResort); @@ -220,7 +220,7 @@ scoped_refptr<SimpleFontData> FontCache::GetLastResortFallbackFont( if (!font_platform_data) { DEFINE_THREAD_SAFE_STATIC_LOCAL(const FontFaceCreationParams, couriernew_creation_params, - (FontFamilyNames::Courier_New)); + (font_family_names::kCourierNew)); font_platform_data = GetFontPlatformData(description, couriernew_creation_params, AlternateFontName::kLastResort); @@ -249,7 +249,7 @@ sk_sp<SkTypeface> FontCache::CreateTypeface( #endif AtomicString family = creation_params.Family(); - DCHECK_NE(family, FontFamilyNames::system_ui); + DCHECK_NE(family, font_family_names::kSystemUi); // If we're creating a fallback font (e.g. "-webkit-monospace"), convert the // name into the fallback name (like "monospace") that fontconfig understands. if (!family.length() || family.StartsWith("-webkit-")) { diff --git a/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc b/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc index 77ec6209fab..73a48b721be 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc @@ -7,6 +7,7 @@ #include "build/build_config.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" +#include <SkFont.h> #include <SkPath.h> namespace blink { @@ -18,33 +19,37 @@ T* advance_by_byte_size(T* p, unsigned byte_size) { return reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(p) + byte_size); } -} // namespace - -SkiaTextMetrics::SkiaTextMetrics(const SkPaint* paint) : paint_(paint) { - CHECK(paint_->getTextEncoding() == SkPaint::kGlyphID_TextEncoding); +template <class T> +const T* advance_by_byte_size(const T* p, unsigned byte_size) { + return reinterpret_cast<const T*>(reinterpret_cast<const uint8_t*>(p) + + byte_size); } -void SkiaTextMetrics::GetGlyphWidthForHarfBuzz(hb_codepoint_t codepoint, - hb_position_t* width) { +} // namespace + +void SkFontGetGlyphWidthForHarfBuzz(const SkFont& font, + hb_codepoint_t codepoint, + hb_position_t* width) { DCHECK_LE(codepoint, 0xFFFFu); CHECK(width); SkScalar sk_width; uint16_t glyph = codepoint; - paint_->getTextWidths(&glyph, sizeof(glyph), &sk_width, nullptr); - if (!paint_->isSubpixelText()) + font.getWidths(&glyph, 1, &sk_width, nullptr); + if (!font.isSubpixel()) sk_width = SkScalarRoundToInt(sk_width); *width = SkiaScalarToHarfBuzzPosition(sk_width); } -void SkiaTextMetrics::GetGlyphWidthForHarfBuzz(unsigned count, - hb_codepoint_t* glyphs, - unsigned glyph_stride, - hb_position_t* advances, - unsigned advance_stride) { - // Batch the call to getTextWidths because its function entry cost is not - // cheap. getTextWidths accepts multiple glyphd ID, but not from a sparse +void SkFontGetGlyphWidthForHarfBuzz(const SkFont& font, + unsigned count, + const hb_codepoint_t* glyphs, + const unsigned glyph_stride, + hb_position_t* advances, + unsigned advance_stride) { + // Batch the call to getWidths because its function entry cost is not + // cheap. getWidths accepts multiple glyphd ID, but not from a sparse // array that copy them to a regular array. Vector<Glyph, 256> glyph_array(count); for (unsigned i = 0; i < count; @@ -52,10 +57,9 @@ void SkiaTextMetrics::GetGlyphWidthForHarfBuzz(unsigned count, glyph_array[i] = *glyphs; } Vector<SkScalar, 256> sk_width_array(count); - paint_->getTextWidths(glyph_array.data(), sizeof(Glyph) * count, - sk_width_array.data(), nullptr); + font.getWidths(glyph_array.data(), count, sk_width_array.data(), nullptr); - if (!paint_->isSubpixelText()) { + if (!font.isSubpixel()) { for (unsigned i = 0; i < count; i++) sk_width_array[i] = SkScalarRoundToInt(sk_width_array[i]); } @@ -67,21 +71,34 @@ void SkiaTextMetrics::GetGlyphWidthForHarfBuzz(unsigned count, } } -void SkiaTextMetrics::GetGlyphExtentsForHarfBuzz(hb_codepoint_t codepoint, - hb_glyph_extents_t* extents) { +// HarfBuzz callback to retrieve glyph extents, mainly used by HarfBuzz for +// fallback mark positioning, i.e. the situation when the font does not have +// mark anchors or other mark positioning rules, but instead HarfBuzz is +// supposed to heuristically place combining marks around base glyphs. HarfBuzz +// does this by measuring "ink boxes" of glyphs, and placing them according to +// Unicode mark classes. Above, below, centered or left or right, etc. +void SkFontGetGlyphExtentsForHarfBuzz(const SkFont& font, + hb_codepoint_t codepoint, + hb_glyph_extents_t* extents) { DCHECK_LE(codepoint, 0xFFFFu); CHECK(extents); SkRect sk_bounds; uint16_t glyph = codepoint; - paint_->getTextWidths(&glyph, sizeof(glyph), nullptr, &sk_bounds); - if (!paint_->isSubpixelText()) { +#if defined(OS_MACOSX) + // TODO(drott): Remove this once we have better metrics bounds + // on Mac, https://bugs.chromium.org/p/skia/issues/detail?id=5328 + SkPath path; + font.getPath(glyph, &path); + sk_bounds = path.getBounds(); +#else + font.getWidths(&glyph, 1, nullptr, &sk_bounds); +#endif + if (!font.isSubpixel()) { // Use roundOut() rather than round() to avoid rendering glyphs // outside the visual overflow rect. crbug.com/452914. - SkIRect ir; - sk_bounds.roundOut(&ir); - sk_bounds.set(ir); + sk_bounds.set(sk_bounds.roundOut()); } // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be @@ -92,36 +109,36 @@ void SkiaTextMetrics::GetGlyphExtentsForHarfBuzz(hb_codepoint_t codepoint, extents->height = SkiaScalarToHarfBuzzPosition(-sk_bounds.height()); } -void SkiaTextMetrics::GetSkiaBoundsForGlyph(Glyph glyph, SkRect* bounds) { +void SkFontGetBoundsForGlyph(const SkFont& font, Glyph glyph, SkRect* bounds) { #if defined(OS_MACOSX) // TODO(drott): Remove this once we have better metrics bounds // on Mac, https://bugs.chromium.org/p/skia/issues/detail?id=5328 SkPath path; - paint_->getTextPath(&glyph, sizeof(glyph), 0, 0, &path); + font.getPath(glyph, &path); *bounds = path.getBounds(); #else - paint_->getTextWidths(&glyph, sizeof(glyph), nullptr, bounds); + font.getWidths(&glyph, 1, nullptr, bounds); #endif - if (!paint_->isSubpixelText()) { + if (!font.isSubpixel()) { SkIRect ir; bounds->roundOut(&ir); bounds->set(ir); } } -void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>& glyphs, - SkRect* bounds) { +void SkFontGetBoundsForGlyphs(const SkFont& font, + const Vector<Glyph, 256>& glyphs, + SkRect* bounds) { #if defined(OS_MACOSX) for (unsigned i = 0; i < glyphs.size(); i++) { - GetSkiaBoundsForGlyph(glyphs[i], &bounds[i]); + SkFontGetBoundsForGlyph(font, glyphs[i], &bounds[i]); } #else static_assert(sizeof(Glyph) == 2, "Skia expects 2 bytes glyph id."); - paint_->getTextWidths(glyphs.data(), sizeof(Glyph) * glyphs.size(), nullptr, - bounds); + font.getWidths(glyphs.data(), glyphs.size(), nullptr, bounds); - if (!paint_->isSubpixelText()) { + if (!font.isSubpixel()) { for (unsigned i = 0; i < glyphs.size(); i++) { SkIRect ir; bounds[i].roundOut(&ir); @@ -131,17 +148,17 @@ void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>& glyphs, #endif } -float SkiaTextMetrics::GetSkiaWidthForGlyph(Glyph glyph) { +float SkFontGetWidthForGlyph(const SkFont& font, Glyph glyph) { SkScalar sk_width; - paint_->getTextWidths(&glyph, sizeof(glyph), &sk_width, nullptr); + font.getWidths(&glyph, 1, &sk_width, nullptr); - if (!paint_->isSubpixelText()) + if (!font.isSubpixel()) sk_width = SkScalarRoundToInt(sk_width); return SkScalarToFloat(sk_width); } -hb_position_t SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(SkScalar value) { +hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) { // We treat HarfBuzz hb_position_t as 16.16 fixed-point. static const int kHbPosition1 = 1 << 16; return clampTo<int>(value * kHbPosition1); diff --git a/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h b/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h index 787d8af0375..6a72122ee22 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h +++ b/chromium/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h @@ -7,33 +7,34 @@ #include "third_party/blink/renderer/platform/fonts/glyph.h" -#include <SkPaint.h> #include <hb.h> #include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/skia/include/core/SkRect.h" -namespace blink { - -class SkiaTextMetrics final { - public: - SkiaTextMetrics(const SkPaint*); - - void GetGlyphWidthForHarfBuzz(hb_codepoint_t, hb_position_t* width); - void GetGlyphWidthForHarfBuzz(unsigned count, - hb_codepoint_t* first_glyph, - unsigned glyph_stride, - hb_position_t* first_advance, - unsigned advance_stride); - void GetGlyphExtentsForHarfBuzz(hb_codepoint_t, hb_glyph_extents_t*); +class SkFont; - void GetSkiaBoundsForGlyph(Glyph, SkRect* bounds); - void GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>&, SkRect*); - float GetSkiaWidthForGlyph(Glyph); - - static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value); +namespace blink { - private: - const SkPaint* paint_; -}; +void SkFontGetGlyphWidthForHarfBuzz(const SkFont&, + hb_codepoint_t, + hb_position_t* width); +void SkFontGetGlyphWidthForHarfBuzz(const SkFont&, + unsigned count, + const hb_codepoint_t* first_glyph, + unsigned glyph_stride, + hb_position_t* first_advance, + unsigned advance_stride); +void SkFontGetGlyphExtentsForHarfBuzz(const SkFont&, + hb_codepoint_t, + hb_glyph_extents_t*); + +void SkFontGetBoundsForGlyph(const SkFont&, Glyph, SkRect* bounds); +void SkFontGetBoundsForGlyphs(const SkFont&, + const Vector<Glyph, 256>&, + SkRect*); +float SkFontGetWidthForGlyph(const SkFont&, Glyph); + +hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value); } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/utf16_text_iterator.cc b/chromium/third_party/blink/renderer/platform/fonts/utf16_text_iterator.cc index 3f175552aea..abceeae6a9a 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/utf16_text_iterator.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/utf16_text_iterator.cc @@ -53,7 +53,7 @@ bool UTF16TextIterator::ConsumeSurrogatePair(UChar32& character) { DCHECK(U16_IS_SURROGATE(character)); if (!IsValidSurrogatePair(character)) { - character = WTF::Unicode::kReplacementCharacter; + character = WTF::unicode::kReplacementCharacter; return true; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc b/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc index bf7f7c5d072..b63f8a2051d 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/web_font_render_style.cc @@ -7,14 +7,15 @@ #include "build/build_config.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" #include "third_party/blink/renderer/platform/fonts/font_description.h" -#include "third_party/blink/renderer/platform/fonts/paint_font.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" +#include "third_party/blink/renderer/platform/web_test_support.h" + +#include <SkFont.h> namespace blink { namespace { -SkPaint::Hinting g_skia_hinting = SkPaint::kNormal_Hinting; +SkFontHinting g_skia_hinting = SkFontHinting::kNormal; bool g_use_skia_auto_hint = true; bool g_use_skia_bitmaps = true; bool g_use_skia_anti_alias = true; @@ -28,7 +29,7 @@ void WebFontRenderStyle::SetSkiaFontManager(sk_sp<SkFontMgr> font_mgr) { } // static -void WebFontRenderStyle::SetHinting(SkPaint::Hinting hinting) { +void WebFontRenderStyle::SetHinting(SkFontHinting hinting) { g_skia_hinting = hinting; } @@ -66,8 +67,7 @@ void WebFontRenderStyle::SetSystemFontFamily(const WebString& name) { WebFontRenderStyle WebFontRenderStyle::GetDefault() { WebFontRenderStyle result; result.use_anti_alias = g_use_skia_anti_alias; - result.hint_style = SkPaint::kNo_Hinting; - result.hint_style = g_skia_hinting; + result.hint_style = static_cast<char>(g_skia_hinting); result.use_bitmaps = g_use_skia_bitmaps; result.use_auto_hint = g_use_skia_auto_hint; result.use_anti_alias = g_use_skia_anti_alias; @@ -97,23 +97,46 @@ void WebFontRenderStyle::OverrideWith(const WebFontRenderStyle& other) { use_subpixel_positioning = other.use_subpixel_positioning; } -void WebFontRenderStyle::ApplyToPaintFont(PaintFont& font, - float device_scale_factor) const { - auto sk_hint_style = static_cast<SkPaint::Hinting>(hint_style); - font.SetAntiAlias(use_anti_alias); - font.SetHinting(sk_hint_style); - font.SetEmbeddedBitmapText(use_bitmaps); - font.SetAutohinted(use_auto_hint); +void WebFontRenderStyle::ApplyToSkPaint(SkPaint& font, + float device_scale_factor) const { + auto sk_hint_style = static_cast<SkFontHinting>(hint_style); + font.setAntiAlias(use_anti_alias); + font.setHinting(sk_hint_style); + font.setEmbeddedBitmapText(use_bitmaps); + font.setAutohinted(use_auto_hint); if (use_anti_alias) - font.SetLcdRenderText(use_subpixel_rendering); + font.setLCDRenderText(use_subpixel_rendering); + + // Force-enable subpixel positioning, except when full hinting is requested on + // low-dpi screen or when running web tests. + bool force_subpixel_positioning = + !WebTestSupport::IsRunningWebTest() && + (sk_hint_style != SkFontHinting::kFull || device_scale_factor > 1.0f); + + font.setSubpixelText(force_subpixel_positioning || use_subpixel_positioning); +} + +void WebFontRenderStyle::ApplyToSkFont(SkFont* font, + float device_scale_factor) const { + auto sk_hint_style = static_cast<SkFontHinting>(hint_style); + font->setHinting(sk_hint_style); + font->setEmbeddedBitmaps(use_bitmaps); + font->setForceAutoHinting(use_auto_hint); + if (use_anti_alias && use_subpixel_rendering) { + font->setEdging(SkFont::Edging::kSubpixelAntiAlias); + } else if (use_anti_alias) { + font->setEdging(SkFont::Edging::kAntiAlias); + } else { + font->setEdging(SkFont::Edging::kAlias); + } // Force-enable subpixel positioning, except when full hinting is requested on - // low-dpi screen or when running layout tests. + // low-dpi screen or when running web tests. bool force_subpixel_positioning = - !LayoutTestSupport::IsRunningLayoutTest() && - (sk_hint_style != SkPaint::kFull_Hinting || device_scale_factor > 1.0f); + !WebTestSupport::IsRunningWebTest() && + (sk_hint_style != SkFontHinting::kFull || device_scale_factor > 1.0f); - font.SetSubpixelText(force_subpixel_positioning || use_subpixel_positioning); + font->setSubpixel(force_subpixel_positioning || use_subpixel_positioning); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc index e4ed5f67725..4fc4b20ddfa 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_platform_data_win.cc @@ -32,35 +32,26 @@ #include "third_party/blink/renderer/platform/fonts/font_platform_data.h" #include <windows.h> +#include "SkFont.h" #include "SkTypeface.h" #include "third_party/blink/renderer/platform/fonts/font_cache.h" -#include "third_party/blink/renderer/platform/layout_test_support.h" +#include "third_party/blink/renderer/platform/web_test_support.h" namespace blink { -// Maximum font size, in pixels, at which embedded bitmaps will be used -// if available. -const float kMaxSizeForEmbeddedBitmap = 24.0f; - -void FontPlatformData::SetupPaintFont(PaintFont* font, - float, - const Font*) const { - const float ts = text_size_ >= 0 ? text_size_ : 12; - font->SetTextSize(SkFloatToScalar(text_size_)); - font->SetTypeface(typeface_); - font->SetFakeBoldText(synthetic_bold_); - font->SetTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); +void FontPlatformData::SetupSkPaint(SkPaint* font, float, const Font*) const { + font->setTextSize(SkFloatToScalar(text_size_)); + font->setTypeface(typeface_); + font->setFakeBoldText(synthetic_bold_); + font->setTextSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); uint32_t text_flags = PaintTextFlags(); - uint32_t flags = font->flags(); + uint32_t flags = font->getFlags(); static const uint32_t kTextFlagsMask = SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag | SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kSubpixelText_Flag; flags &= ~kTextFlagsMask; - if (ts <= kMaxSizeForEmbeddedBitmap) - flags |= SkPaint::kEmbeddedBitmapText_Flag; - // Only use sub-pixel positioning if anti aliasing is enabled. Otherwise, // without font smoothing, subpixel text positioning leads to uneven spacing // since subpixel test placement coordinates would be passed to Skia, which @@ -70,16 +61,48 @@ void FontPlatformData::SetupPaintFont(PaintFont* font, if (text_flags & SkPaint::kAntiAlias_Flag) flags |= SkPaint::kSubpixelText_Flag; - if (LayoutTestSupport::IsRunningLayoutTest() && - !LayoutTestSupport::IsTextSubpixelPositioningAllowedForTest()) + if (WebTestSupport::IsRunningWebTest() && + !WebTestSupport::IsTextSubpixelPositioningAllowedForTest()) flags &= ~SkPaint::kSubpixelText_Flag; SkASSERT(!(text_flags & ~kTextFlagsMask)); flags |= text_flags; - font->SetFlags(flags); + font->setFlags(flags); + + font->setEmbeddedBitmapText(!avoid_embedded_bitmaps_); +} + +void FontPlatformData::SetupSkFont(SkFont* font, float, const Font*) const { + font->setSize(SkFloatToScalar(text_size_)); + font->setTypeface(typeface_); + font->setEmbolden(synthetic_bold_); + font->setSkewX(synthetic_italic_ ? -SK_Scalar1 / 4 : 0); + + uint32_t text_flags = PaintTextFlags(); + if (text_flags & SkPaint::kLCDRenderText_Flag) { + font->setEdging(SkFont::Edging::kSubpixelAntiAlias); + } else if (text_flags & SkPaint::kAntiAlias_Flag) { + font->setEdging(SkFont::Edging::kAntiAlias); + } else { + font->setEdging(SkFont::Edging::kAlias); + } + font->setSubpixel(SkToBool(text_flags & SkPaint::kSubpixelText_Flag)); + + // Only use sub-pixel positioning if anti aliasing is enabled. Otherwise, + // without font smoothing, subpixel text positioning leads to uneven spacing + // since subpixel test placement coordinates would be passed to Skia, which + // only has non-antialiased glyphs to draw, so they necessarily get clamped at + // pixel positions, which leads to uneven spacing, either too close or too far + // away from adjacent glyphs. We avoid this by linking the two flags. + if (text_flags & SkPaint::kAntiAlias_Flag) + font->setSubpixel(true); + + if (WebTestSupport::IsRunningWebTest() && + !WebTestSupport::IsTextSubpixelPositioningAllowedForTest()) + font->setSubpixel(false); - font->SetEmbeddedBitmapText(!avoid_embedded_bitmaps_); + font->setEmbeddedBitmaps(!avoid_embedded_bitmaps_); } static bool IsWebFont(const String& family_name) { @@ -91,8 +114,8 @@ static bool IsWebFont(const String& family_name) { } static int ComputePaintTextFlags(String font_family_name) { - if (LayoutTestSupport::IsRunningLayoutTest()) - return LayoutTestSupport::IsFontAntialiasingEnabledForTest() + if (WebTestSupport::IsRunningWebTest()) + return WebTestSupport::IsFontAntialiasingEnabledForTest() ? SkPaint::kAntiAlias_Flag : 0; |