diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-16 11:45:35 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-07-17 08:59:23 +0000 |
commit | 552906b0f222c5d5dd11b9fd73829d510980461a (patch) | |
tree | 3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/third_party/blink/renderer/platform/fonts | |
parent | 1b05827804eaf047779b597718c03e7d38344261 (diff) | |
download | qtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz |
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/fonts')
72 files changed, 2388 insertions, 561 deletions
diff --git a/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc b/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc index c9a48d57f2f..48295090b57 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.cc @@ -4,7 +4,7 @@ #include "third_party/blink/renderer/platform/fonts/android/font_unique_name_lookup_android.h" #include "mojo/public/mojom/base/shared_memory.mojom-blink.h" -#include "third_party/blink/public/platform/interface_provider.h" +#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" @@ -86,7 +86,7 @@ void FontUniqueNameLookupAndroid::EnsureServiceConnected() { if (service_) return; - Platform::Current()->GetInterfaceProvider()->GetInterface( + Platform::Current()->GetBrowserInterfaceBroker()->GetInterface( service_.BindNewPipeAndPassReceiver()); } diff --git a/chromium/third_party/blink/renderer/platform/fonts/font.cc b/chromium/third_party/blink/renderer/platform/fonts/font.cc index 2b110b2e0e0..7a9414845a0 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font.cc @@ -48,27 +48,20 @@ namespace blink { -Font::Font() : can_shape_word_by_word_(0), shape_word_by_word_computed_(0) {} - -Font::Font(const FontDescription& fd) - : font_description_(fd), - can_shape_word_by_word_(0), - shape_word_by_word_computed_(0) {} - -Font::Font(const Font& other) - : font_description_(other.font_description_), - font_fallback_list_(other.font_fallback_list_), - // TODO(yosin): We should have a comment the reason why don't we copy - // |m_canShapeWordByWord| and |m_shapeWordByWordComputed| from |other|, - // since |operator=()| copies them from |other|. - can_shape_word_by_word_(0), - shape_word_by_word_computed_(0) {} +Font::Font() = default; + +Font::Font(const FontDescription& fd) : font_description_(fd) {} + +Font::Font(const FontDescription& font_description, FontSelector* font_selector) + : font_description_(font_description), + font_fallback_list_( + font_selector ? FontFallbackList::Create(font_selector) : nullptr) {} + +Font::Font(const Font& other) = default; Font& Font::operator=(const Font& other) { font_description_ = other.font_description_; font_fallback_list_ = other.font_fallback_list_; - can_shape_word_by_word_ = other.can_shape_word_by_word_; - shape_word_by_word_computed_ = other.shape_word_by_word_computed_; return *this; } @@ -91,18 +84,6 @@ bool Font::operator==(const Font& other) const { : 0); } -void Font::Update(FontSelector* font_selector) const { - // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, - // but it ends up being reasonably safe (because inherited fonts in the render - // tree pick up the new style anyway. Other copies are transient, e.g., the - // state in the GraphicsContext, and won't stick around long enough to get you - // in trouble). Still, this is pretty disgusting, and could eventually be - // rectified by using RefPtrs for Fonts themselves. - if (!font_fallback_list_) - font_fallback_list_ = FontFallbackList::Create(); - font_fallback_list_->Invalidate(font_selector); -} - namespace { void DrawBlobs(cc::PaintCanvas* canvas, @@ -217,7 +198,10 @@ bool Font::DrawBidiText(cc::PaintCanvas* canvas, TextRunPaintInfo subrun_info(subrun); - ShapeResultBloberizer bloberizer(*this, device_scale_factor); + // Fix regression with -ftrivial-auto-var-init=pattern. See + // crbug.com/1055652. + STACK_UNINITIALIZED ShapeResultBloberizer bloberizer(*this, + device_scale_factor); ShapeResultBuffer buffer; word_shaper.FillResultBuffer(subrun_info, &buffer); float run_width = bloberizer.FillGlyphs(subrun_info, buffer); @@ -422,31 +406,15 @@ int Font::OffsetForPosition(const TextRun& run, } ShapeCache* Font::GetShapeCache() const { - return font_fallback_list_->GetShapeCache(font_description_); + return EnsureFontFallbackList()->GetShapeCache(font_description_); } bool Font::CanShapeWordByWord() const { - if (!shape_word_by_word_computed_) { - can_shape_word_by_word_ = ComputeCanShapeWordByWord(); - shape_word_by_word_computed_ = true; - } - return can_shape_word_by_word_; -} - -bool Font::ComputeCanShapeWordByWord() const { - if (!GetFontDescription().GetTypesettingFeatures()) - return true; - - if (!PrimaryFont()) - return false; - - const FontPlatformData& platform_data = PrimaryFont()->PlatformData(); - TypesettingFeatures features = GetFontDescription().GetTypesettingFeatures(); - return !platform_data.HasSpaceInLigaturesOrKerning(features); + return EnsureFontFallbackList()->CanShapeWordByWord(GetFontDescription()); } void Font::ReportNotDefGlyph() const { - FontSelector* fontSelector = font_fallback_list_->GetFontSelector(); + FontSelector* fontSelector = EnsureFontFallbackList()->GetFontSelector(); // We have a few non-DOM usages of Font code, for example in DragImage::Create // and in EmbeddedObjectPainter::paintReplaced. In those cases, we can't // retrieve a font selector as our connection to a Document object to report diff --git a/chromium/third_party/blink/renderer/platform/fonts/font.h b/chromium/third_party/blink/renderer/platform/fonts/font.h index ca24f5f5e49..2aeb6057caa 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font.h @@ -54,7 +54,6 @@ namespace blink { struct CharacterRange; class FloatPoint; class FloatRect; -class FontData; class FontSelector; class ShapeCache; class TextRun; @@ -66,7 +65,8 @@ class PLATFORM_EXPORT Font { public: Font(); - Font(const FontDescription&); + explicit Font(const FontDescription&); + Font(const FontDescription&, FontSelector*); ~Font(); Font(const Font&); @@ -79,8 +79,6 @@ class PLATFORM_EXPORT Font { return font_description_; } - void Update(FontSelector*) const; - enum CustomFontNotReadyAction { kDoNotPaintIfFontNotReady, kUseFallbackIfFontNotReady @@ -203,7 +201,6 @@ class PLATFORM_EXPORT Font { // loaded. This *should* not happen but in reality it does ever now and then // when, for whatever reason, the last resort font cannot be loaded. const SimpleFontData* PrimaryFont() const; - const FontData* FontDataAt(unsigned) const; // Access the shape cache associated with this particular font object. // Should *not* be retained across layout calls as it may become invalid. @@ -215,8 +212,7 @@ class PLATFORM_EXPORT Font { bool CanShapeWordByWord() const; void SetCanShapeWordByWordForTesting(bool b) { - can_shape_word_by_word_ = b; - shape_word_by_word_computed_ = true; + EnsureFontFallbackList()->SetCanShapeWordByWordForTesting(b); } void ReportNotDefGlyph() const; @@ -226,12 +222,11 @@ class PLATFORM_EXPORT Font { GlyphData GetEmphasisMarkGlyphData(const AtomicString&) const; - bool ComputeCanShapeWordByWord() const; - public: FontSelector* GetFontSelector() const; FontFallbackIterator CreateFontFallbackIterator( FontFallbackPriority fallback_priority) const { + EnsureFontFallbackList(); return FontFallbackIterator(font_description_, font_fallback_list_, fallback_priority); } @@ -246,25 +241,20 @@ class PLATFORM_EXPORT Font { } private: + FontFallbackList* EnsureFontFallbackList() const { + if (!font_fallback_list_) + font_fallback_list_ = FontFallbackList::Create(nullptr); + return font_fallback_list_.get(); + } + FontDescription font_description_; mutable scoped_refptr<FontFallbackList> font_fallback_list_; - mutable unsigned can_shape_word_by_word_ : 1; - mutable unsigned shape_word_by_word_computed_ : 1; - - // For m_fontDescription & m_fontFallbackList access. - friend class CachingWordShaper; }; inline Font::~Font() = default; inline const SimpleFontData* Font::PrimaryFont() const { - DCHECK(font_fallback_list_); - return font_fallback_list_->PrimarySimpleFontData(font_description_); -} - -inline const FontData* Font::FontDataAt(unsigned index) const { - DCHECK(font_fallback_list_); - return font_fallback_list_->FontDataAt(font_description_, index); + return EnsureFontFallbackList()->PrimarySimpleFontData(font_description_); } inline FontSelector* Font::GetFontSelector() const { 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 b4a7e9509cf..396a27aa4fe 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache.cc @@ -386,6 +386,11 @@ void FontCache::InvalidateShapeCache() { PurgeFallbackListShaperCache(); } +void FontCache::InvalidateEnumerationCache() { + TRACE_EVENT0("fonts,ui", "FontCache::InvalidateEnumerationCache"); + font_enumeration_cache_.clear(); +} + void FontCache::Purge(PurgeSeverity purge_severity) { // Ideally we should never be forcing the purge while the // FontCachePurgePreventer is in scope, but we call purge() at any timing @@ -398,6 +403,7 @@ void FontCache::Purge(PurgeSeverity purge_severity) { PurgePlatformFontDataCache(); PurgeFallbackListShaperCache(); + InvalidateEnumerationCache(); } void FontCache::AddClient(FontCacheClient* client) { @@ -418,6 +424,10 @@ uint16_t FontCache::Generation() { void FontCache::Invalidate() { TRACE_EVENT0("fonts,ui", "FontCache::Invalidate"); font_platform_data_cache_.clear(); + // TODO(https://crbug.com/1061630): Determine optimal cache invalidation + // strategy for enumeration. As implemented, the enumeration cache might not + // get invalidated when the system fonts change. + InvalidateEnumerationCache(); generation_++; if (font_cache_clients_) { @@ -524,4 +534,15 @@ FontCache::Bcp47Vector FontCache::GetBcp47LocaleForRequest( return result; } +const std::vector<FontEnumerationEntry>& FontCache::EnumerateAvailableFonts() { + if (font_enumeration_cache_.size() == 0) { + base::TimeTicks enum_start = base::TimeTicks::Now(); + font_enumeration_cache_ = EnumeratePlatformAvailableFonts(); + base::TimeDelta time_taken = base::TimeTicks::Now() - enum_start; + UMA_HISTOGRAM_TIMES("Blink.Fonts.Enumeration.Duration", time_taken); + } + + return font_enumeration_cache_; +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache.h b/chromium/third_party/blink/renderer/platform/fonts/font_cache.h index 08c723bc646..41c63400fbb 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_cache.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache.h @@ -90,21 +90,24 @@ enum class AlternateFontName { kLastResort }; +struct FontEnumerationEntry { + String postscript_name; + String full_name; + String family; +}; + typedef HashMap<unsigned, std::unique_ptr<FontPlatformData>, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> SizedFontPlatformDataSet; -typedef HashMap<FontCacheKey, - SizedFontPlatformDataSet, - FontCacheKeyHash, - FontCacheKeyTraits> - FontPlatformDataCache; +typedef HashMap<FontCacheKey, SizedFontPlatformDataSet> FontPlatformDataCache; typedef HashMap<FallbackListCompositeKey, std::unique_ptr<ShapeCache>, FallbackListCompositeKeyHash, FallbackListCompositeKeyTraits> FallbackListShaperCache; +typedef std::vector<FontEnumerationEntry> FontEnumerationCache; class PLATFORM_EXPORT FontCache { friend class FontCachePurgePreventer; @@ -252,7 +255,13 @@ class PLATFORM_EXPORT FontCache { ShouldRetain = kRetain, bool subpixel_ascent_descent = false); + const std::vector<FontEnumerationEntry>& EnumerateAvailableFonts(); + size_t EnumerationCacheSizeForTesting() { + return font_enumeration_cache_.size(); + } + void InvalidateShapeCache(); + void InvalidateEnumerationCache(); static void CrashWithFontInfo(const FontDescription*); @@ -312,6 +321,7 @@ class PLATFORM_EXPORT FontCache { const FontDescription&, const FontFaceCreationParams&, float font_size); + std::vector<FontEnumerationEntry> EnumeratePlatformAvailableFonts(); sk_sp<SkTypeface> CreateTypeface(const FontDescription&, const FontFaceCreationParams&, @@ -366,6 +376,9 @@ class PLATFORM_EXPORT FontCache { FontPlatformDataCache font_platform_data_cache_; FallbackListShaperCache fallback_list_shaper_cache_; FontDataCache font_data_cache_; + // TODO(https://crbug.com/1061625): Move to the browser process for better + // resource utilization. + FontEnumerationCache font_enumeration_cache_; void PurgePlatformFontDataCache(); void PurgeFallbackListShaperCache(); diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache_client.h b/chromium/third_party/blink/renderer/platform/fonts/font_cache_client.h index 2160fcb2c3b..6b7c90a227d 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_cache_client.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache_client.h @@ -42,7 +42,7 @@ class PLATFORM_EXPORT FontCacheClient virtual ~FontCacheClient() = default; virtual void FontCacheInvalidated() = 0; - virtual void Trace(blink::Visitor* visitor) {} + virtual void Trace(Visitor* visitor) {} }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h b/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h index 90063cb2eac..a860a0ad051 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache_key.h @@ -93,13 +93,19 @@ struct FontCacheKey { } bool operator==(const FontCacheKey& other) const { + bool variation_settings_equal = + (!variation_settings_ && !other.variation_settings_) || + (variation_settings_ && other.variation_settings_ && + *variation_settings_ == *other.variation_settings_); return creation_params_ == other.creation_params_ && font_size_ == other.font_size_ && options_ == other.options_ && device_scale_factor_ == other.device_scale_factor_ && - variation_settings_ == other.variation_settings_ && + variation_settings_equal && is_unique_match_ == other.is_unique_match_; } + bool operator!=(const FontCacheKey& other) const { return !(*this == other); } + static constexpr unsigned PrecisionMultiplier() { return kFontSizePrecisionMultiplier; } @@ -141,4 +147,23 @@ struct FontCacheKeyTraits : WTF::SimpleClassHashTraits<FontCacheKey> { } // namespace blink +namespace WTF { +template <> +struct DefaultHash<blink::FontCacheKey> { + STATIC_ONLY(DefaultHash); + typedef blink::FontCacheKeyHash Hash; +}; + +template <> +struct HashTraits<blink::FontCacheKey> + : WTF::SimpleClassHashTraits<blink::FontCacheKey> { + STATIC_ONLY(HashTraits); + + // std::string's empty state need not be zero in all implementations, + // and it is held within FontFaceCreationParams. + static const bool kEmptyValueIsZero = false; +}; + +} // namespace WTF + #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_CACHE_KEY_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_cache_test.cc b/chromium/third_party/blink/renderer/platform/fonts/font_cache_test.cc index a9233996c15..0f2c270892c 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_cache_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_cache_test.cc @@ -89,4 +89,79 @@ TEST(FontCache, systemFont) { } #endif +class EnumerationConsumer { + public: + explicit EnumerationConsumer( + const std::vector<FontEnumerationEntry>& expectations) { + for (const auto& f : expectations) { + ps_name_set_.insert(f.postscript_name.Utf8()); + full_name_set_.insert(f.full_name.Utf8()); + family_set_.insert(f.family.Utf8()); + } + } + + void Consume(const std::vector<FontEnumerationEntry>& entries) { + for (auto f : entries) { + ps_name_set_.erase(f.postscript_name.Utf8()); + full_name_set_.erase(f.full_name.Utf8()); + family_set_.erase(f.family.Utf8()); + } + } + + bool AllExpectationsMet() { + return ps_name_set_.empty() && full_name_set_.empty() && + family_set_.empty(); + } + + private: + std::set<std::string> ps_name_set_; + std::set<std::string> full_name_set_; + std::set<std::string> family_set_; +}; + +TEST(FontCache, EnumerateAvailableFonts) { + FontCache* font_cache = FontCache::GetFontCache(); + ASSERT_TRUE(font_cache); + + std::vector<FontEnumerationEntry> expectations; + +#if defined(OS_MACOSX) + expectations.push_back(FontEnumerationEntry{"Monaco", "Monaco", "Monaco"}); + expectations.push_back( + FontEnumerationEntry{"Menlo-Regular", "Menlo Regular", "Menlo"}); + expectations.push_back( + FontEnumerationEntry{"Menlo-Bold", "Menlo Bold", "Menlo"}); + expectations.push_back( + FontEnumerationEntry{"Menlo-BoldItalic", "Menlo Bold Italic", "Menlo"}); +#endif + + auto entries = font_cache->EnumerateAvailableFonts(); + auto consumer = EnumerationConsumer(expectations); + + consumer.Consume(entries); + ASSERT_TRUE(consumer.AllExpectationsMet()); +} + +TEST(FontCache, EnumerateAvailableFontsInvalidation) { + FontCache* font_cache = FontCache::GetFontCache(); + ASSERT_TRUE(font_cache); + + // Make sure we start at zero. + font_cache->Invalidate(); + size_t zero = 0; + ASSERT_EQ(zero, font_cache->EnumerationCacheSizeForTesting()); + + // The cache gets populated. + size_t enum_size_1 = font_cache->EnumerateAvailableFonts().size(); + ASSERT_EQ(enum_size_1, font_cache->EnumerationCacheSizeForTesting()); + + // Invalidation clears the cache. + font_cache->Invalidate(); + ASSERT_EQ(zero, font_cache->EnumerationCacheSizeForTesting()); + + // The cache gets re-populated. + size_t enum_size_2 = font_cache->EnumerateAvailableFonts().size(); + ASSERT_EQ(enum_size_1, enum_size_2); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc b/chromium/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc index ecc8454ff02..b00c9e9b10d 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_custom_platform_data.cc @@ -45,16 +45,6 @@ namespace blink { -namespace { -sk_sp<SkFontMgr> FontManagerForSubType( - FontFormatCheck::VariableFontSubType font_sub_type) { - CHECK_NE(font_sub_type, FontFormatCheck::VariableFontSubType::kNotVariable); - if (font_sub_type == FontFormatCheck::VariableFontSubType::kVariableCFF2) - return WebFontTypefaceFactory::FreeTypeFontManager(); - return WebFontTypefaceFactory::FontManagerForVariations(); -} -} // namespace - FontCustomPlatformData::FontCustomPlatformData(sk_sp<SkTypeface> typeface, size_t data_size) : base_typeface_(std::move(typeface)), data_size_(data_size) {} @@ -97,9 +87,14 @@ FontPlatformData FontCustomPlatformData::GetFontPlatformData( SkSetFourByteTag('w', 'd', 't', 'h'), SkFloatToScalar(selection_capabilities.width.clampToRange( selection_request.width))}; + // CSS and OpenType have opposite definitions of direction of slant + // angle. In OpenType positive values turn counter-clockwise, negative + // values clockwise - in CSS positive values are clockwise rotations / + // skew. See note in https://drafts.csswg.org/css-fonts/#font-style-prop - + // map value from CSS to OpenType here. SkFontArguments::Axis slant_axis = { SkSetFourByteTag('s', 'l', 'n', 't'), - SkFloatToScalar(selection_capabilities.slope.clampToRange( + SkFloatToScalar(-selection_capabilities.slope.clampToRange( selection_request.slope))}; axes.push_back(weight_axis); @@ -124,12 +119,8 @@ FontPlatformData FontCustomPlatformData::GetFontPlatformData( axes.push_back(opsz_axis); } - int index; - std::unique_ptr<SkStreamAsset> stream(base_typeface_->openStream(&index)); - sk_sp<SkTypeface> sk_variation_font(FontManagerForSubType(font_sub_type) - ->makeFromStream(std::move(stream), - SkFontArguments().setCollectionIndex(index) - .setAxes(axes.data(), axes.size()))); + sk_sp<SkTypeface> sk_variation_font(base_typeface_->makeClone( + SkFontArguments().setAxes(axes.data(), axes.size()))); if (sk_variation_font) { return_typeface = sk_variation_font; diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_data.h b/chromium/third_party/blink/renderer/platform/fonts/font_data.h index 3535115d1e4..d79e7fd5a70 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_data.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_data.h @@ -57,15 +57,6 @@ class PLATFORM_EXPORT FontData : public RefCounted<FontData> { DISALLOW_COPY_AND_ASSIGN(FontData); }; -#define DEFINE_FONT_DATA_TYPE_CASTS(thisType, predicate) \ - template <typename T> \ - inline thisType* To##thisType(const scoped_refptr<T>& fontData) { \ - return To##thisType(fontData.get()); \ - } \ - DEFINE_TYPE_CASTS(thisType, FontData, fontData, \ - fontData->IsSegmented() == predicate, \ - fontData.IsSegmented() == predicate) - } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_DATA_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_data_cache.cc b/chromium/third_party/blink/renderer/platform/fonts/font_data_cache.cc index 060207ea5e5..680da1679bd 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_data_cache.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_data_cache.cc @@ -132,7 +132,7 @@ bool FontDataCache::PurgeLeastRecentlyUsed(int count) { auto end = inactive_font_data_.end(); auto it = inactive_font_data_.begin(); for (int i = 0; i < count && it != end; ++it, ++i) { - scoped_refptr<SimpleFontData>& font_data = *it.Get(); + const scoped_refptr<SimpleFontData>& font_data = *it; cache_.erase(&(font_data->PlatformData())); // We should not delete SimpleFontData here because deletion can modify // m_inactiveFontData. See http://trac.webkit.org/changeset/44011 diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description.cc b/chromium/third_party/blink/renderer/platform/fonts/font_description.cc index 6f20525f341..9e3ffe63834 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_description.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_description.cc @@ -436,8 +436,6 @@ String FontDescription::ToString(GenericFamilyType familyType) { return "Cursive"; case GenericFamilyType::kFantasyFamily: return "Fantasy"; - case GenericFamilyType::kPictographFamily: - return "Pictograph"; } return "Unknown"; } 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 8d19bd6873c..782b843707b 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_description.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_description.h @@ -63,8 +63,7 @@ class PLATFORM_EXPORT FontDescription { kSansSerifFamily, kMonospaceFamily, kCursiveFamily, - kFantasyFamily, - kPictographFamily + kFantasyFamily }; static String ToString(GenericFamilyType); diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc b/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc index 737580ef6bf..1bb413937f9 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_description_test.cc @@ -63,6 +63,78 @@ TEST(FontDescriptionTest, TestHashCollision) { } } +TEST(FontDescriptionTest, VariationSettingsIdentical) { + FontDescription a; + FontDescription b(a); + + scoped_refptr<FontVariationSettings> settings_a = + FontVariationSettings::Create(); + settings_a->Append(FontVariationAxis("test", 1)); + + scoped_refptr<FontVariationSettings> settings_b = + FontVariationSettings::Create(); + settings_b->Append(FontVariationAxis("test", 1)); + + ASSERT_EQ(*settings_a, *settings_b); + + a.SetVariationSettings(settings_a); + b.SetVariationSettings(settings_b); + + ASSERT_EQ(a, b); + + FontFaceCreationParams test_creation_params; + FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false); + FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false); + + ASSERT_EQ(cache_key_a, cache_key_b); +} + +TEST(FontDescriptionTest, VariationSettingsDifferent) { + FontDescription a; + FontDescription b(a); + + scoped_refptr<FontVariationSettings> settings_a = + FontVariationSettings::Create(); + settings_a->Append(FontVariationAxis("test", 1)); + + scoped_refptr<FontVariationSettings> settings_b = + FontVariationSettings::Create(); + settings_b->Append(FontVariationAxis("0000", 1)); + + ASSERT_NE(*settings_a, *settings_b); + + a.SetVariationSettings(settings_a); + b.SetVariationSettings(settings_b); + + ASSERT_NE(a, b); + + FontFaceCreationParams test_creation_params; + + FontCacheKey cache_key_a = a.CacheKey(test_creation_params, false); + FontCacheKey cache_key_b = b.CacheKey(test_creation_params, false); + + ASSERT_NE(cache_key_a, cache_key_b); + + scoped_refptr<FontVariationSettings> second_settings_a = + FontVariationSettings::Create(); + second_settings_a->Append(FontVariationAxis("test", 1)); + + scoped_refptr<FontVariationSettings> second_settings_b = + FontVariationSettings::Create(); + + ASSERT_NE(*second_settings_a, *second_settings_b); + + a.SetVariationSettings(second_settings_a); + b.SetVariationSettings(second_settings_b); + + ASSERT_NE(a, b); + + FontCacheKey second_cache_key_a = a.CacheKey(test_creation_params, false); + FontCacheKey second_cache_key_b = b.CacheKey(test_creation_params, false); + + ASSERT_NE(second_cache_key_a, second_cache_key_b); +} + TEST(FontDescriptionTest, ToString) { FontDescription description; diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc index 1362d480c4b..eb076725400 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_iterator.cc @@ -153,7 +153,7 @@ scoped_refptr<FontDataForRangeSet> FontFallbackIterator::Next( current_font_data_index_++; if (!font_data->IsLoading()) { scoped_refptr<SimpleFontData> non_segmented = - const_cast<SimpleFontData*>(ToSimpleFontData(font_data)); + const_cast<SimpleFontData*>(To<SimpleFontData>(font_data)); // The fontData object that we have here is tracked in m_fontList of // FontFallbackList and gets released in the font cache when the // FontFallbackList is destroyed. @@ -165,7 +165,7 @@ scoped_refptr<FontDataForRangeSet> FontFallbackIterator::Next( // Iterate over ranges of a segmented font below. - const SegmentedFontData* segmented = ToSegmentedFontData(font_data); + const auto* segmented = To<SegmentedFontData>(font_data); if (fallback_stage_ != kSegmentedFace) { segmented_face_index_ = 0; fallback_stage_ = kSegmentedFace; 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 fa1a455e591..d00d18310bb 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 @@ -39,22 +39,24 @@ namespace blink { -FontFallbackList::FontFallbackList() +FontFallbackList::FontFallbackList(FontSelector* font_selector) : cached_primary_simple_font_data_(nullptr), - font_selector_(nullptr), - font_selector_version_(0), + font_selector_(font_selector), + font_selector_version_(font_selector ? font_selector->Version() : 0), family_index_(0), generation_(FontCache::GetFontCache()->Generation()), - has_loading_fallback_(false) {} + has_loading_fallback_(false), + can_shape_word_by_word_(false), + can_shape_word_by_word_computed_(false) {} -void FontFallbackList::Invalidate(FontSelector* font_selector) { +void FontFallbackList::Invalidate() { ReleaseFontData(); font_list_.clear(); cached_primary_simple_font_data_ = nullptr; family_index_ = 0; has_loading_fallback_ = false; - if (font_selector_ != font_selector) - font_selector_ = font_selector; + can_shape_word_by_word_ = false; + can_shape_word_by_word_computed_ = false; font_selector_version_ = font_selector_ ? font_selector_->Version() : 0; generation_ = FontCache::GetFontCache()->Generation(); } @@ -65,13 +67,18 @@ void FontFallbackList::ReleaseFontData() { if (!font_list_[i]->IsCustomFont()) { DCHECK(!font_list_[i]->IsSegmented()); FontCache::GetFontCache()->ReleaseFontData( - ToSimpleFontData(font_list_[i])); + To<SimpleFontData>(font_list_[i].get())); } } shape_cache_.reset(); // Clear the weak pointer to the cache instance. } bool FontFallbackList::LoadingCustomFonts() const { + // This function is only used for style and layout invalidation purposes. We + // don't need it for invalidation when the feature below is enabled. + if (RuntimeEnabledFeatures::CSSReducedFontLoadingInvalidationsEnabled()) + return false; + if (!has_loading_fallback_) return false; @@ -84,6 +91,8 @@ bool FontFallbackList::LoadingCustomFonts() const { } bool FontFallbackList::ShouldSkipDrawing() const { + DCHECK(IsValid()); + if (!has_loading_fallback_) return false; @@ -96,7 +105,7 @@ bool FontFallbackList::ShouldSkipDrawing() const { } const SimpleFontData* FontFallbackList::DeterminePrimarySimpleFontData( - const FontDescription& font_description) const { + const FontDescription& font_description) { bool should_load_custom_font = true; for (unsigned font_index = 0;; ++font_index) { @@ -114,8 +123,8 @@ const SimpleFontData* FontFallbackList::DeterminePrimarySimpleFontData( return last_resort_fallback; } - if (font_data->IsSegmented() && - !ToSegmentedFontData(font_data)->ContainsCharacter(kSpaceCharacter)) + const auto* segmented = DynamicTo<SegmentedFontData>(font_data); + if (segmented && !segmented->ContainsCharacter(kSpaceCharacter)) continue; const SimpleFontData* font_data_for_space = @@ -128,8 +137,7 @@ const SimpleFontData* FontFallbackList::DeterminePrimarySimpleFontData( if (!font_data_for_space->IsLoadingFallback()) return font_data_for_space; - if (font_data->IsSegmented()) { - const SegmentedFontData* segmented = ToSegmentedFontData(font_data); + if (segmented) { for (unsigned i = 0; i < segmented->NumFaces(); i++) { const SimpleFontData* range_font_data = segmented->FaceAt(i)->FontData(); @@ -212,8 +220,9 @@ FallbackListCompositeKey FontFallbackList::CompositeKey( if (result) { bool is_unique_match = false; key.Add(font_description.CacheKey(params, is_unique_match)); - if (!result->IsSegmented() && !result->IsCustomFont()) - FontCache::GetFontCache()->ReleaseFontData(ToSimpleFontData(result)); + auto* font_data = DynamicTo<SimpleFontData>(result.get()); + if (!font_data && !result->IsCustomFont()) + FontCache::GetFontCache()->ReleaseFontData(font_data); } } current_family = current_family->Next(); @@ -224,7 +233,12 @@ FallbackListCompositeKey FontFallbackList::CompositeKey( const FontData* FontFallbackList::FontDataAt( const FontDescription& font_description, - unsigned realized_font_index) const { + unsigned realized_font_index) { + if (RuntimeEnabledFeatures::CSSReducedFontLoadingInvalidationsEnabled()) { + if (!IsValid()) + Invalidate(); + } + // This fallback font is already in our list. if (realized_font_index < font_list_.size()) return font_list_[realized_font_index].get(); @@ -250,6 +264,34 @@ const FontData* FontFallbackList::FontDataAt( return result.get(); } +bool FontFallbackList::ComputeCanShapeWordByWord( + const FontDescription& font_description) { + if (!font_description.GetTypesettingFeatures()) + return true; + + const SimpleFontData* primary_font = PrimarySimpleFontData(font_description); + if (!primary_font) + return false; + + const FontPlatformData& platform_data = primary_font->PlatformData(); + TypesettingFeatures features = font_description.GetTypesettingFeatures(); + return !platform_data.HasSpaceInLigaturesOrKerning(features); +} + +bool FontFallbackList::CanShapeWordByWord( + const FontDescription& font_description) { + if (RuntimeEnabledFeatures::CSSReducedFontLoadingInvalidationsEnabled()) { + if (!IsValid()) + Invalidate(); + } + + if (!can_shape_word_by_word_computed_) { + can_shape_word_by_word_ = ComputeCanShapeWordByWord(font_description); + can_shape_word_by_word_computed_ = true; + } + return can_shape_word_by_word_; +} + bool FontFallbackList::IsValid() const { if (!font_selector_) return font_selector_version_ == 0; diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h index 4a604216015..6ef8c3774b8 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_fallback_list.h @@ -28,6 +28,7 @@ #include "third_party/blink/renderer/platform/fonts/shaping/shape_cache.h" #include "third_party/blink/renderer/platform/fonts/simple_font_data.h" #include "third_party/blink/renderer/platform/heap/persistent.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/ref_counted.h" @@ -42,13 +43,13 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> { USING_FAST_MALLOC(FontFallbackList); public: - static scoped_refptr<FontFallbackList> Create() { - return base::AdoptRef(new FontFallbackList()); + static scoped_refptr<FontFallbackList> Create(FontSelector* font_selector) { + return base::AdoptRef(new FontFallbackList(font_selector)); } ~FontFallbackList() { ReleaseFontData(); } bool IsValid() const; - void Invalidate(FontSelector*); + void Invalidate(); bool LoadingCustomFonts() const; bool ShouldSkipDrawing() const; @@ -58,7 +59,12 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> { unsigned FontSelectorVersion() const { return font_selector_version_; } uint16_t Generation() const { return generation_; } - ShapeCache* GetShapeCache(const FontDescription& font_description) const { + ShapeCache* GetShapeCache(const FontDescription& font_description) { + if (RuntimeEnabledFeatures::CSSReducedFontLoadingInvalidationsEnabled()) { + if (!IsValid()) + Invalidate(); + } + if (!shape_cache_) { FallbackListCompositeKey key = CompositeKey(font_description); shape_cache_ = @@ -72,6 +78,11 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> { const SimpleFontData* PrimarySimpleFontData( const FontDescription& font_description) { + if (RuntimeEnabledFeatures::CSSReducedFontLoadingInvalidationsEnabled()) { + if (!IsValid()) + Invalidate(); + } + if (!cached_primary_simple_font_data_) { cached_primary_simple_font_data_ = DeterminePrimarySimpleFontData(font_description); @@ -79,28 +90,37 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted<FontFallbackList> { } return cached_primary_simple_font_data_; } - const FontData* FontDataAt(const FontDescription&, unsigned index) const; + const FontData* FontDataAt(const FontDescription&, unsigned index); - FallbackListCompositeKey CompositeKey(const FontDescription&) const; + bool CanShapeWordByWord(const FontDescription&); + + void SetCanShapeWordByWordForTesting(bool b) { + can_shape_word_by_word_ = b; + can_shape_word_by_word_computed_ = true; + } private: - FontFallbackList(); + explicit FontFallbackList(FontSelector* font_selector); scoped_refptr<FontData> GetFontData(const FontDescription&, int& family_index) const; - const SimpleFontData* DeterminePrimarySimpleFontData( - const FontDescription&) const; + const SimpleFontData* DeterminePrimarySimpleFontData(const FontDescription&); + + FallbackListCompositeKey CompositeKey(const FontDescription&) const; void ReleaseFontData(); + bool ComputeCanShapeWordByWord(const FontDescription&); - mutable Vector<scoped_refptr<FontData>, 1> font_list_; - mutable const SimpleFontData* cached_primary_simple_font_data_; - Persistent<FontSelector> font_selector_; + Vector<scoped_refptr<FontData>, 1> font_list_; + const SimpleFontData* cached_primary_simple_font_data_; + const Persistent<FontSelector> font_selector_; unsigned font_selector_version_; - mutable int family_index_; + int family_index_; uint16_t generation_; - mutable bool has_loading_fallback_ : 1; - mutable base::WeakPtr<ShapeCache> shape_cache_; + bool has_loading_fallback_ : 1; + bool can_shape_word_by_word_ : 1; + bool can_shape_word_by_word_computed_ : 1; + base::WeakPtr<ShapeCache> shape_cache_; DISALLOW_COPY_AND_ASSIGN(FontFallbackList); }; diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_global_context.cc b/chromium/third_party/blink/renderer/platform/fonts/font_global_context.cc index ff2fd249e6c..ee1cb3b220c 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_global_context.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_global_context.cc @@ -20,7 +20,9 @@ FontGlobalContext* FontGlobalContext::Get(CreateIfNeeded create_if_needed) { return *font_persistent; } -FontGlobalContext::FontGlobalContext() : harfbuzz_font_funcs_(nullptr) {} +FontGlobalContext::FontGlobalContext() + : harfbuzz_font_funcs_skia_advances_(nullptr), + harfbuzz_font_funcs_harfbuzz_advances_(nullptr) {} FontGlobalContext::~FontGlobalContext() = default; @@ -32,6 +34,15 @@ FontUniqueNameLookup* FontGlobalContext::GetFontUniqueNameLookup() { return Get()->font_unique_name_lookup_.get(); } +HarfBuzzFontCache* FontGlobalContext::GetHarfBuzzFontCache() { + std::unique_ptr<HarfBuzzFontCache>& global_context_harfbuzz_font_cache = + Get()->harfbuzz_font_cache_; + if (!global_context_harfbuzz_font_cache) { + global_context_harfbuzz_font_cache = std::make_unique<HarfBuzzFontCache>(); + } + return global_context_harfbuzz_font_cache.get(); +} + void FontGlobalContext::ClearMemory() { if (!Get(kDoNotCreate)) return; diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_global_context.h b/chromium/third_party/blink/renderer/platform/fonts/font_global_context.h index 63c3c861d6e..37e743c2264 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_global_context.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_global_context.h @@ -6,7 +6,6 @@ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_FONT_GLOBAL_CONTEXT_H_ #include "third_party/blink/renderer/platform/fonts/font_cache.h" -#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/text/layout_locale.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" @@ -17,6 +16,7 @@ namespace blink { class FontCache; class FontUniqueNameLookup; +class HarfBuzzFontCache; enum CreateIfNeeded { kDoNotCreate, kCreate }; @@ -30,16 +30,27 @@ class PLATFORM_EXPORT FontGlobalContext { static inline FontCache& GetFontCache() { return Get()->font_cache_; } - static inline HarfBuzzFontCache& GetHarfBuzzFontCache() { - return Get()->harfbuzz_font_cache_; - } + static HarfBuzzFontCache* GetHarfBuzzFontCache(); + + enum HorizontalAdvanceSource { + kSkiaHorizontalAdvances, + kHarfBuzzHorizontalAdvances + }; - static hb_font_funcs_t* GetHarfBuzzFontFuncs() { - return Get()->harfbuzz_font_funcs_; + static hb_font_funcs_t* GetHarfBuzzFontFuncs( + HorizontalAdvanceSource advance_source) { + if (advance_source == kHarfBuzzHorizontalAdvances) { + return Get()->harfbuzz_font_funcs_harfbuzz_advances_; + } + return Get()->harfbuzz_font_funcs_skia_advances_; } - static void SetHarfBuzzFontFuncs(hb_font_funcs_t* funcs) { - Get()->harfbuzz_font_funcs_ = funcs; + static void SetHarfBuzzFontFuncs(HorizontalAdvanceSource advance_source, + hb_font_funcs_t* funcs) { + if (advance_source == kHarfBuzzHorizontalAdvances) { + Get()->harfbuzz_font_funcs_harfbuzz_advances_ = funcs; + } + Get()->harfbuzz_font_funcs_skia_advances_ = funcs; } static FontUniqueNameLookup* GetFontUniqueNameLookup(); @@ -54,8 +65,9 @@ class PLATFORM_EXPORT FontGlobalContext { ~FontGlobalContext(); FontCache font_cache_; - HarfBuzzFontCache harfbuzz_font_cache_; - hb_font_funcs_t* harfbuzz_font_funcs_; + std::unique_ptr<HarfBuzzFontCache> harfbuzz_font_cache_; + hb_font_funcs_t* harfbuzz_font_funcs_skia_advances_; + hb_font_funcs_t* harfbuzz_font_funcs_harfbuzz_advances_; std::unique_ptr<FontUniqueNameLookup> font_unique_name_lookup_; DISALLOW_COPY_AND_ASSIGN(FontGlobalContext); diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc b/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc index 5e1005a2e4d..a9a0511de03 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.cc @@ -28,6 +28,18 @@ HashSet<T> Intersection(const HashSet<T>& a, const HashSet<T>& b) { namespace blink { +FontMatchingMetrics::FontMatchingMetrics(bool top_level, + ukm::UkmRecorder* ukm_recorder, + ukm::SourceId source_id) + : top_level_(top_level), + ukm_recorder_(ukm_recorder), + source_id_(source_id) { + // Estimate of average page font use from anecdotal browsing session. + constexpr unsigned kEstimatedFontCount = 7; + local_fonts_succeeded_.ReserveCapacityForSize(kEstimatedFontCount); + local_fonts_failed_.ReserveCapacityForSize(kEstimatedFontCount); +} + void FontMatchingMetrics::ReportSuccessfulFontFamilyMatch( const AtomicString& font_family_name) { successful_font_families_.insert(font_family_name); @@ -48,6 +60,16 @@ void FontMatchingMetrics::ReportWebFontFamily( web_font_families_.insert(font_family_name); } +void FontMatchingMetrics::ReportSuccessfulLocalFontMatch( + const AtomicString& font_name) { + local_fonts_succeeded_.insert(font_name); +} + +void FontMatchingMetrics::ReportFailedLocalFontMatch( + const AtomicString& font_name) { + local_fonts_failed_.insert(font_name); +} + void FontMatchingMetrics::PublishUkmMetrics() { ukm::builders::FontMatchAttempts(source_id_) .SetLoadContext(top_level_ ? kTopLevel : kSubFrame) @@ -63,6 +85,10 @@ void FontMatchingMetrics::PublishUkmMetrics() { .SetWebFontFamilyFailures(ukm::GetExponentialBucketMin( Intersection(failed_font_families_, web_font_families_).size(), kUkmFontLoadCountBucketSpacing)) + .SetLocalFontFailures(ukm::GetExponentialBucketMin( + local_fonts_failed_.size(), kUkmFontLoadCountBucketSpacing)) + .SetLocalFontSuccesses(ukm::GetExponentialBucketMin( + local_fonts_succeeded_.size(), kUkmFontLoadCountBucketSpacing)) .Record(ukm_recorder_); } diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.h b/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.h index c31be1c51b5..59827c38e53 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_matching_metrics.h @@ -27,10 +27,7 @@ class PLATFORM_EXPORT FontMatchingMetrics { public: FontMatchingMetrics(bool top_level, ukm::UkmRecorder* ukm_recorder, - ukm::SourceId source_id) - : top_level_(top_level), - ukm_recorder_(ukm_recorder), - source_id_(source_id) {} + ukm::SourceId source_id); // Called when a page attempts to match a font family, and the font family is // available. @@ -46,6 +43,14 @@ class PLATFORM_EXPORT FontMatchingMetrics { // Called when a page attempts to match a web font family. void ReportWebFontFamily(const AtomicString& font_family_name); + // Reports a font listed in a @font-face src:local rule that successfully + // matched. + void ReportSuccessfulLocalFontMatch(const AtomicString& font_name); + + // Reports a font listed in a @font-face src:local rule that didn't + // successfully match. + void ReportFailedLocalFontMatch(const AtomicString& font_name); + // Publishes the number of font family matches attempted (both successful and // otherwise) to UKM. Called at page unload. void PublishUkmMetrics(); @@ -63,6 +68,12 @@ class PLATFORM_EXPORT FontMatchingMetrics { // Web font families the page attempted to match. HashSet<AtomicString> web_font_families_; + // @font-face src:local fonts that successfully matched. + HashSet<AtomicString> local_fonts_succeeded_; + + // @font-face src:local fonts that didn't successfully match. + HashSet<AtomicString> local_fonts_failed_; + // True if this FontMatchingMetrics instance is for a top-level frame, false // otherwise. const bool top_level_ = false; diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_selector.h b/chromium/third_party/blink/renderer/platform/fonts/font_selector.h index 0eaaf9e94fb..0861e6e15c8 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_selector.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_selector.h @@ -71,6 +71,15 @@ class PLATFORM_EXPORT FontSelector : public FontCacheClient { virtual void ReportFailedFontFamilyMatch( const AtomicString& font_family_name) = 0; + // Called when a page attempts to match a font name via a @font-face src:local + // rule, and the font is available. + virtual void ReportSuccessfulLocalFontMatch( + const AtomicString& font_name) = 0; + + // Called when a page attempts to match a font name via a @font-face src:local + // rule, and the font is not available. + virtual void ReportFailedLocalFontMatch(const AtomicString& font_name) = 0; + virtual void RegisterForInvalidationCallbacks(FontSelectorClient*) = 0; virtual void UnregisterForInvalidationCallbacks(FontSelectorClient*) = 0; diff --git a/chromium/third_party/blink/renderer/platform/fonts/font_selector_client.h b/chromium/third_party/blink/renderer/platform/fonts/font_selector_client.h index 649b054fb68..b85832903ab 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/font_selector_client.h +++ b/chromium/third_party/blink/renderer/platform/fonts/font_selector_client.h @@ -17,7 +17,7 @@ class FontSelectorClient : public GarbageCollectedMixin { virtual void FontsNeedUpdate(FontSelector*) = 0; - void Trace(blink::Visitor* visitor) override {} + void Trace(Visitor* visitor) override {} }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/linux/font_unique_name_lookup_linux.cc b/chromium/third_party/blink/renderer/platform/fonts/linux/font_unique_name_lookup_linux.cc index 62d92b7f412..604a895c075 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/linux/font_unique_name_lookup_linux.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/linux/font_unique_name_lookup_linux.cc @@ -19,7 +19,6 @@ sk_sp<SkTypeface> FontUniqueNameLookupLinux::MatchUniqueName( if (!Platform::Current()->GetSandboxSupport()) { LOG(ERROR) << "@font-face src: local() instantiation only available when " "connected to browser process."; - DCHECK(Platform::Current()->GetSandboxSupport()); return nullptr; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/core_text_font_format_support.h b/chromium/third_party/blink/renderer/platform/fonts/mac/core_text_font_format_support.h index 1816f6f49d7..b5f3ffe9738 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/mac/core_text_font_format_support.h +++ b/chromium/third_party/blink/renderer/platform/fonts/mac/core_text_font_format_support.h @@ -9,6 +9,7 @@ namespace blink { bool CoreTextVersionSupportsVariations(); bool CoreTextVersionSupportsColrCpal(); + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_CORE_TEXT_FONT_FORMAT_SUPPORT_H_ 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 f50fc36281d..fedd1b91424 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 @@ -29,8 +29,11 @@ #import "third_party/blink/renderer/platform/fonts/font_cache.h" -#import <AppKit/AppKit.h> #include <memory> + +#import <AppKit/AppKit.h> +#import <CoreText/CoreText.h> + #include "base/location.h" #include "base/mac/foundation_util.h" #include "third_party/blink/public/platform/platform.h" @@ -59,6 +62,22 @@ inLanguage:(id)useNil; @end +namespace { + +NSString* GetLocalizedString(CTFontDescriptorRef fd, CFStringRef attribute) { + base::ScopedCFTypeRef<CFStringRef> cf_str(base::mac::CFCast<CFStringRef>( + CTFontDescriptorCopyLocalizedAttribute(fd, attribute, nullptr))); + return [base::mac::CFToNSCast(cf_str.release()) autorelease]; +} + +NSString* GetString(CTFontDescriptorRef fd, CFStringRef attribute) { + base::ScopedCFTypeRef<CFStringRef> cf_str(base::mac::CFCast<CFStringRef>( + CTFontDescriptorCopyAttribute(fd, attribute))); + return [base::mac::CFToNSCast(cf_str.release()) autorelease]; +} + +} // namespace + namespace blink { const char kColorEmojiFontMac[] = "Apple Color Emoji"; @@ -221,9 +240,12 @@ scoped_refptr<SimpleFontData> FontCache::PlatformFallbackFontForCharacter( substitute_font, platform_data.size(), synthetic_bold, (traits & NSFontItalicTrait) && !(substitute_font_traits & NSFontItalicTrait), - platform_data.Orientation(), + platform_data.Orientation(), font_description.FontOpticalSizing(), nullptr); // No variation paramaters in fallback. + if (!alternate_font) + return nullptr; + return FontDataFromFontPlatformData(alternate_font.get(), kDoNotRetain); } @@ -295,11 +317,43 @@ std::unique_ptr<FontPlatformData> FontCache::CreateFontPlatformData( // the returned FontPlatformData since it will not have a valid SkTypeface. std::unique_ptr<FontPlatformData> platform_data = FontPlatformDataFromNSFont( platform_font, size, synthetic_bold, synthetic_italic, - font_description.Orientation(), font_description.VariationSettings()); - if (!platform_data->Typeface()) { + font_description.Orientation(), font_description.FontOpticalSizing(), + font_description.VariationSettings()); + if (!platform_data || !platform_data->Typeface()) { return nullptr; } return platform_data; } +std::vector<FontEnumerationEntry> FontCache::EnumeratePlatformAvailableFonts() { + DCHECK(RuntimeEnabledFeatures::FontAccessEnabled()); + @autoreleasepool { + std::vector<FontEnumerationEntry> output; + + CFTypeRef values[1] = {kCFBooleanTrue}; + base::ScopedCFTypeRef<CFDictionaryRef> options(CFDictionaryCreate( + kCFAllocatorDefault, + (const void**)kCTFontCollectionRemoveDuplicatesOption, + (const void**)&values, + /*numValues=*/1, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + base::ScopedCFTypeRef<CTFontCollectionRef> collection( + CTFontCollectionCreateFromAvailableFonts(options)); + + base::ScopedCFTypeRef<CFArrayRef> font_descs( + CTFontCollectionCreateMatchingFontDescriptors(collection)); + + for (CFIndex i = 0; i < CFArrayGetCount(font_descs); ++i) { + CTFontDescriptorRef fd = base::mac::CFCast<CTFontDescriptorRef>( + CFArrayGetValueAtIndex(font_descs, i)); + NSString* postscript_name = GetString(fd, kCTFontNameAttribute); + NSString* full_name = GetLocalizedString(fd, kCTFontDisplayNameAttribute); + NSString* family = GetLocalizedString(fd, kCTFontFamilyNameAttribute); + output.push_back(FontEnumerationEntry{String(postscript_name), + String(full_name), String(family)}); + } + return output; + } +} + } // namespace blink 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 8d01704041c..cf25ba022f2 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 @@ -46,7 +46,7 @@ namespace { -static CGFloat toYosemiteFontWeight(blink::FontSelectionValue font_weight) { +static CGFloat toFontWeight(blink::FontSelectionValue font_weight) { static uint64_t ns_font_weights[] = { 0xbfe99999a0000000, // NSFontWeightUltraLight 0xbfe3333340000000, // NSFontWeightThin @@ -181,8 +181,7 @@ NSFont* MatchNSFontFamily(const AtomicString& desired_family_string, // On OSX 10.10+, the default system font has more weights. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunguarded-availability" - font = [NSFont systemFontOfSize:size - weight:toYosemiteFontWeight(desired_weight)]; + font = [NSFont systemFontOfSize:size weight:toFontWeight(desired_weight)]; #pragma clang diagnostic pop if (desired_traits & IMPORTANT_FONT_TRAITS) diff --git a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.h b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.h index b1224beff2c..cd0e338cdb5 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.h +++ b/chromium/third_party/blink/renderer/platform/fonts/mac/font_platform_data_mac.h @@ -31,6 +31,8 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_FONT_PLATFORM_DATA_MAC_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_MAC_FONT_PLATFORM_DATA_MAC_H_ +#include "third_party/blink/renderer/platform/fonts/font_optical_sizing.h" + #include <memory> @class NSFont; @@ -47,6 +49,7 @@ std::unique_ptr<FontPlatformData> FontPlatformDataFromNSFont( bool synthetic_bold, bool synthetic_italic, FontOrientation, + OpticalSizing, FontVariationSettings*); } // namespace blink 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 16bcce4ba40..9bc59e46e5e 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 @@ -27,21 +27,26 @@ #import <AvailabilityMacros.h> #include "base/mac/foundation_util.h" -#include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsobject.h" #include "base/stl_util.h" #import "third_party/blink/public/platform/mac/web_sandbox_support.h" #import "third_party/blink/public/platform/platform.h" #import "third_party/blink/renderer/platform/fonts/font.h" #import "third_party/blink/renderer/platform/fonts/font_platform_data.h" +#import "third_party/blink/renderer/platform/fonts/mac/core_text_font_format_support.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/web_test_support.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/core/SkTypes.h" #import "third_party/skia/include/ports/SkTypeface_mac.h" +namespace { +constexpr SkFourByteTag kOpszTag = SkSetFourByteTag('o', 'p', 's', 'z'); +} + namespace blink { static bool CanLoadInProcess(NSFont* ns_font) { @@ -53,10 +58,10 @@ static bool CanLoadInProcess(NSFont* ns_font) { return ![font_name isEqualToString:@"LastResort"]; } -static CTFontDescriptorRef CascadeToLastResortFontDescriptor() { - static CTFontDescriptorRef descriptor; - if (descriptor) - return descriptor; +static CFDictionaryRef CascadeToLastResortFontAttributes() { + static CFDictionaryRef attributes; + if (attributes) + return attributes; base::ScopedCFTypeRef<CTFontDescriptorRef> last_resort( CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0)); @@ -67,13 +72,10 @@ static CTFontDescriptorRef CascadeToLastResortFontDescriptor() { const void* keys[] = {kCTFontCascadeListAttribute}; const void* values[] = {values_array}; - base::ScopedCFTypeRef<CFDictionaryRef> attributes(CFDictionaryCreate( + attributes = CFDictionaryCreate( kCFAllocatorDefault, keys, values, base::size(keys), - &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - - descriptor = CTFontDescriptorCreateWithAttributes(attributes); - - return descriptor; + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + return attributes; } static sk_sp<SkTypeface> LoadFromBrowserProcess(NSFont* ns_font, @@ -88,20 +90,23 @@ static sk_sp<SkTypeface> LoadFromBrowserProcess(NSFont* ns_font, return nullptr; } - CGFontRef loaded_cg_font; + base::ScopedCFTypeRef<CTFontDescriptorRef> loaded_data_descriptor; uint32_t font_id; if (!sandbox_support->LoadFont(base::mac::NSToCFCast(ns_font), - &loaded_cg_font, &font_id)) { + &loaded_data_descriptor, &font_id)) { // TODO crbug.com/461279: Make this appear in the inspector console? DLOG(ERROR) << "Loading user font \"" << [[ns_font familyName] UTF8String] << "\" from non system location failed. Corrupt or missing font file?"; return nullptr; } - base::ScopedCFTypeRef<CGFontRef> cg_font(loaded_cg_font); - base::ScopedCFTypeRef<CTFontRef> ct_font(CTFontCreateWithGraphicsFont( - cg_font, text_size, 0, CascadeToLastResortFontDescriptor())); - sk_sp<SkTypeface> return_font(SkCreateTypefaceFromCTFont(ct_font, cg_font)); + + base::ScopedCFTypeRef<CTFontDescriptorRef> data_descriptor_with_cascade( + CTFontDescriptorCreateCopyWithAttributes( + loaded_data_descriptor, CascadeToLastResortFontAttributes())); + base::ScopedCFTypeRef<CTFontRef> ct_font(CTFontCreateWithFontDescriptor( + data_descriptor_with_cascade.get(), text_size, 0)); + sk_sp<SkTypeface> return_font = SkMakeTypefaceFromCTFont(ct_font); if (!return_font.get()) // TODO crbug.com/461279: Make this appear in the inspector console? @@ -117,11 +122,12 @@ std::unique_ptr<FontPlatformData> FontPlatformDataFromNSFont( bool synthetic_bold, bool synthetic_italic, FontOrientation orientation, + OpticalSizing optical_sizing, FontVariationSettings* variation_settings) { DCHECK(ns_font); sk_sp<SkTypeface> typeface; if (CanLoadInProcess(ns_font)) { - typeface.reset(SkCreateTypefaceFromCTFont(base::mac::NSToCFCast(ns_font))); + typeface = SkMakeTypefaceFromCTFont(base::mac::NSToCFCast(ns_font)); } else { // In process loading fails for cases where third party font manager // software registers fonts in non system locations such as /Library/Fonts @@ -129,26 +135,79 @@ std::unique_ptr<FontPlatformData> FontPlatformDataFromNSFont( typeface = LoadFromBrowserProcess(ns_font, size); } - if (variation_settings && variation_settings->size() < UINT16_MAX) { - SkFontArguments::Axis axes[variation_settings->size()]; - for (size_t i = 0; i < variation_settings->size(); ++i) { - AtomicString feature_tag = variation_settings->at(i).Tag(); - axes[i] = {AtomicStringToFourByteTag(feature_tag), - SkFloatToScalar(variation_settings->at(i).Value())}; + auto make_typeface_fontplatformdata = [&typeface, &size, &synthetic_bold, + &synthetic_italic, &orientation]() { + return std::make_unique<FontPlatformData>( + std::move(typeface), std::string(), size, synthetic_bold, + synthetic_italic, orientation); + }; + + wtf_size_t valid_configured_axes = + variation_settings && variation_settings->size() < UINT16_MAX + ? variation_settings->size() + : 0; + + // No variable font requested, return static font. + if (!valid_configured_axes && optical_sizing == kNoneOpticalSizing) + return make_typeface_fontplatformdata(); + + if (!typeface) + return nullptr; + + int existing_axes = typeface->getVariationDesignPosition(nullptr, 0); + // Don't apply variation parameters if the font does not have axes or we + // fail to retrieve the existing ones. + if (existing_axes <= 0) + return make_typeface_fontplatformdata(); + + Vector<SkFontArguments::VariationPosition::Coordinate> coordinates_to_set; + coordinates_to_set.resize(existing_axes); + + if (typeface->getVariationDesignPosition(coordinates_to_set.data(), + existing_axes) != existing_axes) { + return make_typeface_fontplatformdata(); + } + + // Iterate over the font's axes and find a missing tag from variation + // settings, special case opsz, track the number of axes reconfigured. + bool axes_reconfigured = false; + for (auto& coordinate : coordinates_to_set) { + // Set opsz to font size but allow having it overriden by + // font-variation-settings in case it has 'opsz'. + if (coordinate.axis == kOpszTag && optical_sizing == kAutoOpticalSizing) { + if (coordinate.value != SkFloatToScalar(size)) { + coordinate.value = SkFloatToScalar(size); + axes_reconfigured = true; + } + } + FontVariationAxis found_variation_setting(AtomicString(), 0); + if (variation_settings && + variation_settings->FindPair(FourByteTagToAtomicString(coordinate.axis), + &found_variation_setting)) { + if (coordinate.value != found_variation_setting.Value()) { + coordinate.value = found_variation_setting.Value(); + axes_reconfigured = true; + } } - sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault()); - // TODO crbug.com/670246: Refactor this to a future Skia API that acccepts - // axis parameters on system fonts directly. - typeface = fm->makeFromStream( - typeface->openStream(nullptr)->duplicate(), - SkFontArguments().setAxes(axes, variation_settings->size())); } - return std::make_unique<FontPlatformData>( - std::move(typeface), - std::string(), // family_ doesn't exist on Mac, this avoids conversion - // from NSString which requires including a //base header - size, synthetic_bold, synthetic_italic, orientation); + if (!axes_reconfigured) { + // No variable axes touched, return the previous typeface. + return make_typeface_fontplatformdata(); + } + + SkFontArguments::VariationPosition variation_design_position{ + coordinates_to_set.data(), coordinates_to_set.size()}; + + sk_sp<SkTypeface> cloned_typeface(typeface->makeClone( + SkFontArguments().setVariationDesignPosition(variation_design_position))); + + if (!cloned_typeface) { + // Applying varition parameters failed, return original typeface. + return make_typeface_fontplatformdata(); + } + typeface = cloned_typeface; + return make_typeface_fontplatformdata(); } void FontPlatformData::SetupSkFont(SkFont* skfont, diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc index 964943fa0b2..2c11652ffcf 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_format_check.cc @@ -4,32 +4,21 @@ #include "third_party/blink/renderer/platform/fonts/opentype/font_format_check.h" -#include "third_party/blink/renderer/platform/wtf/vector.h" -#include "third_party/skia/include/core/SkTypeface.h" - // Include HarfBuzz to have a cross-platform way to retrieve table tags without // having to rely on the platform being able to instantiate this font format. #include <hb.h> -namespace blink { - -namespace { - -struct HarfbuzzBlobDestroyer { - inline void operator()(hb_blob_t* blob) { hb_blob_destroy(blob); } -}; +#include "third_party/blink/renderer/platform/wtf/vector.h" +#include "third_party/harfbuzz-ng/utils/hb_scoped.h" +#include "third_party/skia/include/core/SkTypeface.h" -struct HarfbuzzFaceDestroyer { - inline void operator()(hb_face_t* face) { hb_face_destroy(face); } -}; -} // namespace +namespace blink { FontFormatCheck::FontFormatCheck(sk_sp<SkData> sk_data) { - std::unique_ptr<hb_blob_t, HarfbuzzBlobDestroyer> font_blob(hb_blob_create( + HbScoped<hb_blob_t> font_blob(hb_blob_create( reinterpret_cast<const char*>(sk_data->bytes()), sk_data->size(), HB_MEMORY_MODE_READONLY, nullptr, nullptr)); - std::unique_ptr<hb_face_t, HarfbuzzFaceDestroyer> face( - hb_face_create(font_blob.get(), 0)); + HbScoped<hb_face_t> face(hb_face_create(font_blob.get(), 0)); unsigned table_count = 0; table_count = hb_face_get_table_tags(face.get(), 0, nullptr, nullptr); diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.cc index 733d76d0db4..84c34be7a02 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.cc @@ -5,6 +5,7 @@ #include "third_party/blink/renderer/platform/fonts/opentype/font_settings.h" #include "third_party/blink/renderer/platform/wtf/hash_functions.h" +#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h" #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" #include "third_party/blink/renderer/platform/wtf/text/string_hasher.h" @@ -16,6 +17,13 @@ uint32_t AtomicStringToFourByteTag(AtomicString tag) { return (((tag[0]) << 24) | ((tag[1]) << 16) | ((tag[2]) << 8) | (tag[3])); } +AtomicString FourByteTagToAtomicString(uint32_t tag) { + constexpr size_t tag_size = 4; + LChar tag_string[tag_size] = {(tag >> 24) & 0xFF, (tag >> 16) & 0xFF, + (tag >> 8) & 0xFF, tag & 0xFF}; + return AtomicString(tag_string, tag_size); +} + unsigned FontVariationSettings::GetHash() const { unsigned computed_hash = size() ? 5381 : 0; unsigned num_features = size(); diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.h b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.h index 10ab2aec21e..ea5b8c942f8 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.h +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings.h @@ -17,6 +17,7 @@ namespace blink { uint32_t AtomicStringToFourByteTag(AtomicString tag); +AtomicString FourByteTagToAtomicString(uint32_t tag); template <typename T> class FontTagValuePair { @@ -34,7 +35,7 @@ class FontTagValuePair { private: AtomicString tag_; - const T value_; + T value_; }; template <typename T> @@ -47,6 +48,7 @@ class FontSettings { bool operator==(const FontSettings& other) const { return list_ == other.list_; } + bool operator!=(const FontSettings& other) const { return !(*this == other); } String ToString() const { StringBuilder builder; wtf_size_t num_features = size(); @@ -60,6 +62,20 @@ class FontSettings { } return builder.ToString(); } + + bool FindPair(AtomicString tag, T* found_pair) const { + if (!found_pair) + return false; + + for (auto& pair : list_) { + if (pair.Tag() == tag) { + *found_pair = pair; + return true; + } + } + return false; + } + const T* begin() const { return list_.begin(); } const T* end() const { return list_.end(); } T* begin() { return list_.begin(); } diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc index 5c2fa7d94e8..6a3e0457ac3 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/font_settings_test.cc @@ -61,4 +61,30 @@ TEST(FontSettingsTest, ToString) { } } +TEST(FontSettingsTest, FindTest) { + { + scoped_refptr<FontVariationSettings> settings = + MakeSettings<FontVariationSettings, FontVariationAxis>( + {FontVariationAxis{"a", 42}, FontVariationAxis{"b", 8118}}); + FontVariationAxis found_axis(AtomicString(), 0); + ASSERT_FALSE(settings->FindPair("c", &found_axis)); + ASSERT_FALSE(settings->FindPair("ddddd", &found_axis)); + ASSERT_FALSE(settings->FindPair("", &found_axis)); + ASSERT_EQ(found_axis.Value(), 0); + ASSERT_TRUE(settings->FindPair("a", &found_axis)); + ASSERT_EQ(found_axis.Tag(), AtomicString("a")); + ASSERT_EQ(found_axis.Value(), 42); + ASSERT_TRUE(settings->FindPair("b", &found_axis)); + ASSERT_EQ(found_axis.Tag(), AtomicString("b")); + ASSERT_EQ(found_axis.Value(), 8118); + } +} + +TEST(FontSettingsTest, FindTestEmpty) { + scoped_refptr<FontVariationSettings> settings = + MakeSettings<FontVariationSettings, FontVariationAxis>({}); + FontVariationAxis found_axis(AtomicString(), 0); + ASSERT_FALSE(settings->FindPair("a", &found_axis)); +} + } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc index 4c18c37138f..542975a52ba 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.cc @@ -2,10 +2,13 @@ // 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/opentype/open_type_caps_support.h" - -#include <hb-aat.h> +// clang-format off #include <hb.h> +#include <hb-aat.h> +// clang-format on + +#include "third_party/blink/renderer/platform/fonts/opentype/open_type_caps_support.h" +#include "third_party/harfbuzz-ng/utils/hb_scoped.h" namespace blink { @@ -138,12 +141,10 @@ OpenTypeCapsSupport::FontFormat OpenTypeCapsSupport::GetFontFormat() const { hb_face_t* hb_face = hb_font_get_face( harfbuzz_face_->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout)); - std::unique_ptr<hb_blob_t, decltype(&hb_blob_destroy)> morx_blob( - hb_face_reference_table(hb_face, HB_TAG('m', 'o', 'r', 'x')), - hb_blob_destroy); - std::unique_ptr<hb_blob_t, decltype(&hb_blob_destroy)> mort_blob( - hb_face_reference_table(hb_face, HB_TAG('m', 'o', 'r', 't')), - hb_blob_destroy); + HbScoped<hb_blob_t> morx_blob( + hb_face_reference_table(hb_face, HB_TAG('m', 'o', 'r', 'x'))); + HbScoped<hb_blob_t> mort_blob( + hb_face_reference_table(hb_face, HB_TAG('m', 'o', 'r', 't'))); // TODO(crbug.com/911149): Use hb_aat_layout_has_substitution() for // has_morx_or_mort and hb_ot_layout_has_substitution() for has_gsub once is diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_stretch_data.h b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_stretch_data.h new file mode 100644 index 00000000000..af3cc059903 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_stretch_data.h @@ -0,0 +1,45 @@ +// Copyright 2020 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_OPENTYPE_OPEN_TYPE_MATH_STRETCH_DATA_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_OPEN_TYPE_MATH_STRETCH_DATA_H_ + +#include "base/optional.h" +#include "third_party/blink/renderer/platform/fonts/glyph.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +class PLATFORM_EXPORT OpenTypeMathStretchData { + public: + enum StretchAxis : uint8_t { Horizontal = 0, Vertical = 1 }; + + // https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathGlyphVariantRecordFormat + // Note: Only variantGlyph is considered as using advanceMeasurement can lead + // to inconsistent values compared to what SimpleFontData returns. + using GlyphVariantRecord = Glyph; + + // https://docs.microsoft.com/en-us/typography/opentype/spec/math#glyphPartRecord + struct GlyphPartRecord { + Glyph glyph; + float start_connector_length; + float end_connector_length; + float full_advance; + bool is_extender; + }; + + // https://mathml-refresh.github.io/mathml-core/#the-glyphassembly-table + struct AssemblyParameters { + float connector_overlap{0}; + unsigned repetition_count{0}; + unsigned glyph_count{0}; + float stretch_size{0}; + Vector<GlyphPartRecord> parts; + }; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_OPEN_TYPE_MATH_STRETCH_DATA_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc new file mode 100644 index 00000000000..80d94665ab7 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.cc @@ -0,0 +1,258 @@ +// Copyright 2020 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/opentype/open_type_math_support.h" + +// clang-format off +#include <hb.h> +#include <hb-ot.h> +// clang-format on + +#include "base/bind.h" +#include "base/callback.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" + +namespace { +// HarfBuzz' hb_position_t is a 16.16 fixed-point value. +float HarfBuzzUnitsToFloat(hb_position_t value) { + static const float kFloatToHbRatio = 1.0f / (1 << 16); + return kFloatToHbRatio * value; +} + +// Latin Modern, STIX Two, XITS, Asana, Deja Vu, Libertinus and TeX Gyre fonts +// provide at most 13 size variant and 5 assembly parts. +// See https://chromium-review.googlesource.com/c/chromium/src/+/2074678 +unsigned kMaxHarfBuzzRecords = 20; + +hb_direction_t HarfBuzzDirection( + blink::OpenTypeMathStretchData::StretchAxis stretch_axis) { + return stretch_axis == blink::OpenTypeMathStretchData::StretchAxis::Horizontal + ? HB_DIRECTION_LTR + : HB_DIRECTION_BTT; +} + +} // namespace + +namespace blink { + +bool OpenTypeMathSupport::HasMathData(const HarfBuzzFace* harfbuzz_face) { + if (!harfbuzz_face) + return false; + + hb_font_t* font = + harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout); + DCHECK(font); + hb_face_t* face = hb_font_get_face(font); + DCHECK(face); + + return hb_ot_math_has_data(face); +} + +base::Optional<float> OpenTypeMathSupport::MathConstant( + const HarfBuzzFace* harfbuzz_face, + MathConstants constant) { + if (!HasMathData(harfbuzz_face)) + return base::nullopt; + + hb_font_t* font = + harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout); + DCHECK(font); + + hb_position_t harfbuzz_value = hb_ot_math_get_constant( + font, static_cast<hb_ot_math_constant_t>(constant)); + + switch (constant) { + case kScriptPercentScaleDown: + case kScriptScriptPercentScaleDown: + case kRadicalDegreeBottomRaisePercent: + return base::Optional<float>(harfbuzz_value / 100.0); + case kDelimitedSubFormulaMinHeight: + case kDisplayOperatorMinHeight: + case kMathLeading: + case kAxisHeight: + case kAccentBaseHeight: + case kFlattenedAccentBaseHeight: + case kSubscriptShiftDown: + case kSubscriptTopMax: + case kSubscriptBaselineDropMin: + case kSuperscriptShiftUp: + case kSuperscriptShiftUpCramped: + case kSuperscriptBottomMin: + case kSuperscriptBaselineDropMax: + case kSubSuperscriptGapMin: + case kSuperscriptBottomMaxWithSubscript: + case kSpaceAfterScript: + case kUpperLimitGapMin: + case kUpperLimitBaselineRiseMin: + case kLowerLimitGapMin: + case kLowerLimitBaselineDropMin: + case kStackTopShiftUp: + case kStackTopDisplayStyleShiftUp: + case kStackBottomShiftDown: + case kStackBottomDisplayStyleShiftDown: + case kStackGapMin: + case kStackDisplayStyleGapMin: + case kStretchStackTopShiftUp: + case kStretchStackBottomShiftDown: + case kStretchStackGapAboveMin: + case kStretchStackGapBelowMin: + case kFractionNumeratorShiftUp: + case kFractionNumeratorDisplayStyleShiftUp: + case kFractionDenominatorShiftDown: + case kFractionDenominatorDisplayStyleShiftDown: + case kFractionNumeratorGapMin: + case kFractionNumDisplayStyleGapMin: + case kFractionRuleThickness: + case kFractionDenominatorGapMin: + case kFractionDenomDisplayStyleGapMin: + case kSkewedFractionHorizontalGap: + case kSkewedFractionVerticalGap: + case kOverbarVerticalGap: + case kOverbarRuleThickness: + case kOverbarExtraAscender: + case kUnderbarVerticalGap: + case kUnderbarRuleThickness: + case kUnderbarExtraDescender: + case kRadicalVerticalGap: + case kRadicalDisplayStyleVerticalGap: + case kRadicalRuleThickness: + case kRadicalExtraAscender: + case kRadicalKernBeforeDegree: + case kRadicalKernAfterDegree: + return base::Optional<float>(HarfBuzzUnitsToFloat(harfbuzz_value)); + default: + NOTREACHED(); + } + return base::nullopt; +} + +base::Optional<float> OpenTypeMathSupport::MathItalicCorrection( + const HarfBuzzFace* harfbuzz_face, + Glyph glyph) { + if (!harfbuzz_face) + return base::nullopt; + + hb_font_t* font = + harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout); + + return base::Optional<float>(HarfBuzzUnitsToFloat( + hb_ot_math_get_glyph_italics_correction(font, glyph))); +} + +template <typename HarfBuzzRecordType> +using GetHarfBuzzMathRecordGetter = + base::OnceCallback<unsigned int(hb_font_t* font, + hb_codepoint_t glyph, + hb_direction_t direction, + unsigned int start_offset, + unsigned int* record_count, + HarfBuzzRecordType* record_array)>; + +template <typename HarfBuzzRecordType, typename RecordType> +using HarfBuzzMathRecordConverter = + base::RepeatingCallback<RecordType(HarfBuzzRecordType)>; + +template <typename HarfBuzzRecordType, typename RecordType> +Vector<RecordType> GetHarfBuzzMathRecord( + const HarfBuzzFace* harfbuzz_face, + Glyph base_glyph, + OpenTypeMathStretchData::StretchAxis stretch_axis, + GetHarfBuzzMathRecordGetter<HarfBuzzRecordType> getter, + HarfBuzzMathRecordConverter<HarfBuzzRecordType, RecordType> converter, + base::Optional<RecordType> prepended_record) { + hb_font_t* hb_font = + harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout); + DCHECK(hb_font); + + hb_direction_t hb_stretch_axis = HarfBuzzDirection(stretch_axis); + + // In practice, math fonts have, for a given base glyph and stretch axis only + // provide a few GlyphVariantRecords (size variants of increasing sizes) and + // GlyphPartRecords (parts of a glyph assembly) so it is safe to truncate + // the result vector to a small size. + HarfBuzzRecordType chunk[kMaxHarfBuzzRecords]; + unsigned int count = kMaxHarfBuzzRecords; + std::move(getter).Run(hb_font, base_glyph, hb_stretch_axis, + 0 /* start_offset */, &count, chunk); + + // Create the vector to the determined size and initialize it with the results + // converted from HarfBuzz's ones, prepending any optional record. + Vector<RecordType> result; + result.ReserveInitialCapacity(prepended_record ? count + 1 : count); + if (prepended_record) + result.push_back(*prepended_record); + for (unsigned i = 0; i < count; i++) { + result.push_back(converter.Run(chunk[i])); + } + return result; +} + +Vector<OpenTypeMathStretchData::GlyphVariantRecord> +OpenTypeMathSupport::GetGlyphVariantRecords( + const HarfBuzzFace* harfbuzz_face, + Glyph base_glyph, + OpenTypeMathStretchData::StretchAxis stretch_axis) { + DCHECK(harfbuzz_face); + DCHECK(base_glyph); + + auto getter = base::BindOnce(&hb_ot_math_get_glyph_variants); + auto converter = + base::BindRepeating([](hb_ot_math_glyph_variant_t record) + -> OpenTypeMathStretchData::GlyphVariantRecord { + return record.glyph; + }); + return GetHarfBuzzMathRecord( + harfbuzz_face, base_glyph, stretch_axis, std::move(getter), + std::move(converter), + base::Optional<OpenTypeMathStretchData::GlyphVariantRecord>(base_glyph)); +} + +Vector<OpenTypeMathStretchData::GlyphPartRecord> +OpenTypeMathSupport::GetGlyphPartRecords( + const HarfBuzzFace* harfbuzz_face, + Glyph base_glyph, + OpenTypeMathStretchData::StretchAxis stretch_axis, + float* italic_correction) { + DCHECK(harfbuzz_face); + DCHECK(base_glyph); + + auto getter = base::BindOnce( + [](hb_font_t* font, hb_codepoint_t glyph, hb_direction_t direction, + unsigned int start_offset, unsigned int* parts_count, + hb_ot_math_glyph_part_t* parts) { + hb_position_t italic_correction; + return hb_ot_math_get_glyph_assembly(font, glyph, direction, + start_offset, parts_count, parts, + &italic_correction); + }); + auto converter = + base::BindRepeating([](hb_ot_math_glyph_part_t record) + -> OpenTypeMathStretchData::GlyphPartRecord { + return {record.glyph, + HarfBuzzUnitsToFloat(record.start_connector_length), + HarfBuzzUnitsToFloat(record.end_connector_length), + HarfBuzzUnitsToFloat(record.full_advance), + record.flags & HB_MATH_GLYPH_PART_FLAG_EXTENDER}; + }); + Vector<OpenTypeMathStretchData::GlyphPartRecord> parts = + GetHarfBuzzMathRecord( + harfbuzz_face, base_glyph, stretch_axis, std::move(getter), + std::move(converter), + base::Optional<OpenTypeMathStretchData::GlyphPartRecord>()); + if (italic_correction && !parts.IsEmpty()) { + hb_font_t* hb_font = + harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout); + // A GlyphAssembly subtable exists for the specified font, glyph and stretch + // axis since it has been possible to retrieve the GlyphPartRecords. This + // means that the following call is guaranteed to get an italic correction. + hb_position_t harfbuzz_italic_correction; + hb_ot_math_get_glyph_assembly(hb_font, base_glyph, + HarfBuzzDirection(stretch_axis), 0, nullptr, + nullptr, &harfbuzz_italic_correction); + *italic_correction = HarfBuzzUnitsToFloat(harfbuzz_italic_correction); + } + return parts; +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h new file mode 100644 index 00000000000..633a4d11f2b --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h @@ -0,0 +1,120 @@ +// Copyright 2020 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_OPENTYPE_OPEN_TYPE_MATH_SUPPORT_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_OPEN_TYPE_MATH_SUPPORT_H_ + +#include "base/optional.h" +#include "third_party/blink/renderer/platform/fonts/opentype/open_type_math_stretch_data.h" +#include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" + +namespace blink { + +class HarfBuzzFace; + +class PLATFORM_EXPORT OpenTypeMathSupport { + public: + static bool HasMathData(const HarfBuzzFace*); + + // These constants are defined in the OpenType MATH table: + // https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table + // Their values match the indices in the MathConstants subtable. + enum MathConstants { + kScriptPercentScaleDown = 0, + kScriptScriptPercentScaleDown = 1, + kDelimitedSubFormulaMinHeight = 2, + kDisplayOperatorMinHeight = 3, + kMathLeading = 4, + kAxisHeight = 5, + kAccentBaseHeight = 6, + kFlattenedAccentBaseHeight = 7, + kSubscriptShiftDown = 8, + kSubscriptTopMax = 9, + kSubscriptBaselineDropMin = 10, + kSuperscriptShiftUp = 11, + kSuperscriptShiftUpCramped = 12, + kSuperscriptBottomMin = 13, + kSuperscriptBaselineDropMax = 14, + kSubSuperscriptGapMin = 15, + kSuperscriptBottomMaxWithSubscript = 16, + kSpaceAfterScript = 17, + kUpperLimitGapMin = 18, + kUpperLimitBaselineRiseMin = 19, + kLowerLimitGapMin = 20, + kLowerLimitBaselineDropMin = 21, + kStackTopShiftUp = 22, + kStackTopDisplayStyleShiftUp = 23, + kStackBottomShiftDown = 24, + kStackBottomDisplayStyleShiftDown = 25, + kStackGapMin = 26, + kStackDisplayStyleGapMin = 27, + kStretchStackTopShiftUp = 28, + kStretchStackBottomShiftDown = 29, + kStretchStackGapAboveMin = 30, + kStretchStackGapBelowMin = 31, + kFractionNumeratorShiftUp = 32, + kFractionNumeratorDisplayStyleShiftUp = 33, + kFractionDenominatorShiftDown = 34, + kFractionDenominatorDisplayStyleShiftDown = 35, + kFractionNumeratorGapMin = 36, + kFractionNumDisplayStyleGapMin = 37, + kFractionRuleThickness = 38, + kFractionDenominatorGapMin = 39, + kFractionDenomDisplayStyleGapMin = 40, + kSkewedFractionHorizontalGap = 41, + kSkewedFractionVerticalGap = 42, + kOverbarVerticalGap = 43, + kOverbarRuleThickness = 44, + kOverbarExtraAscender = 45, + kUnderbarVerticalGap = 46, + kUnderbarRuleThickness = 47, + kUnderbarExtraDescender = 48, + kRadicalVerticalGap = 49, + kRadicalDisplayStyleVerticalGap = 50, + kRadicalRuleThickness = 51, + kRadicalExtraAscender = 52, + kRadicalKernBeforeDegree = 53, + kRadicalKernAfterDegree = 54, + kRadicalDegreeBottomRaisePercent = 55 + }; + + // Returns the value of the requested math constant or null if the font does + // not have any OpenType MATH table. All values are 16.16 fixed-point values + // converted to float except percentages (kScriptPercentScaleDown, + // kScriptScriptPercentScaleDown and kRadicalDegreeBottomRaisePercent) which + // are represented by a number between 0 and 1. + // https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathconstants-table + static base::Optional<float> MathConstant(const HarfBuzzFace*, MathConstants); + + // Returns the italic correction corresponding to the specified glyph or null + // if the font does not have any OpenType MATH table. This value provides an + // estimation of how much the glyph is slanted, which can be used e.g. when + // attaching scripts to the glyph. + // https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathitalicscorrectioninfo-table + static base::Optional<float> MathItalicCorrection(const HarfBuzzFace*, Glyph); + + // Returns a vector of GlyphVariantRecords corresponding to the specified + // glyph and stretch axis. The base glyph is always added as the first item. + // https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvariants-table + static Vector<OpenTypeMathStretchData::GlyphVariantRecord> + GetGlyphVariantRecords(const HarfBuzzFace*, + Glyph base_glyph, + OpenTypeMathStretchData::StretchAxis); + + // Returns a vector of GlyphPartRecords corresponding to the specified + // glyph and stretch axis or an empty vector if there is no such construction. + // If the italic_correction parameter is specified and a construction is + // available, then it is set to the italic correction of the glyph assembly. + // https://docs.microsoft.com/en-us/typography/opentype/spec/math#mathvariants-table + static Vector<OpenTypeMathStretchData::GlyphPartRecord> GetGlyphPartRecords( + const HarfBuzzFace*, + Glyph base_glyph, + OpenTypeMathStretchData::StretchAxis, + float* italic_correction = nullptr); +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_OPEN_TYPE_MATH_SUPPORT_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support_test.cc b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support_test.cc new file mode 100644 index 00000000000..c6493f48399 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/opentype/open_type_math_support_test.cc @@ -0,0 +1,466 @@ +// Copyright 2020 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/opentype/open_type_math_support.h" +#include "base/memory/scoped_refptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/opentype/open_type_types.h" +#include "third_party/blink/renderer/platform/testing/font_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" + +namespace { +const UChar32 kLeftBraceCodePoint = '{'; +const UChar32 kOverBraceCodePoint = 0x23DE; +const UChar32 kArabicMathOperatorHahWithDalCodePoint = 0x1EEF1; +const UChar32 kNAryWhiteVerticalBarCodePoint = 0x2AFF; +} // namespace + +namespace blink { + +class OpenTypeMathSupportTest : public testing::Test { + protected: + void SetUp() override { + font_description.SetComputedSize(10.0); + font = Font(font_description); + } + + void TearDown() override {} + + Font CreateMathFont(const String& name, float size = 1000) { + FontDescription::VariantLigatures ligatures; + return blink::test::CreateTestFont( + "MathTestFont", + blink::test::BlinkWebTestsFontsTestDataPath(String("math/") + name), + size, &ligatures); + } + + bool HasMathData(const String& name) { + return OpenTypeMathSupport::HasMathData( + CreateMathFont(name).PrimaryFont()->PlatformData().GetHarfBuzzFace()); + } + + base::Optional<float> MathConstant( + const String& name, + OpenTypeMathSupport::MathConstants constant) { + Font math = CreateMathFont(name); + return OpenTypeMathSupport::MathConstant( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), constant); + } + + FontDescription font_description; + Font font; +}; + +TEST_F(OpenTypeMathSupportTest, HasMathData) { + // Null parameter. + EXPECT_FALSE(OpenTypeMathSupport::HasMathData(nullptr)); + + // Font without a MATH table. + EXPECT_FALSE(HasMathData("math-text.woff")); + + // Font with a MATH table. + EXPECT_TRUE(HasMathData("axisheight5000-verticalarrow14000.woff")); +} + +TEST_F(OpenTypeMathSupportTest, MathConstantNullOpt) { + Font math_text = CreateMathFont("math-text.woff"); + + for (int i = OpenTypeMathSupport::MathConstants::kScriptPercentScaleDown; + i <= + OpenTypeMathSupport::MathConstants::kRadicalDegreeBottomRaisePercent; + i++) { + auto math_constant = static_cast<OpenTypeMathSupport::MathConstants>(i); + + // Null parameter. + EXPECT_FALSE(OpenTypeMathSupport::MathConstant(nullptr, math_constant)); + + // Font without a MATH table. + EXPECT_FALSE(OpenTypeMathSupport::MathConstant( + math_text.PrimaryFont()->PlatformData().GetHarfBuzzFace(), + math_constant)); + } +} + +// See third_party/blink/web_tests/external/wpt/mathml/tools/percentscaledown.py +TEST_F(OpenTypeMathSupportTest, MathConstantPercentScaleDown) { + { + auto result = MathConstant( + "scriptpercentscaledown80-scriptscriptpercentscaledown0.woff", + OpenTypeMathSupport::MathConstants::kScriptPercentScaleDown); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, .8); + } + + { + auto result = MathConstant( + "scriptpercentscaledown0-scriptscriptpercentscaledown40.woff", + OpenTypeMathSupport::MathConstants::kScriptScriptPercentScaleDown); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, .4); + } +} + +// See third_party/blink/web_tests/external/wpt/mathml/tools/fractions.py +TEST_F(OpenTypeMathSupportTest, MathConstantFractions) { + { + auto result = MathConstant( + "fraction-numeratorshiftup11000-axisheight1000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kFractionNumeratorShiftUp); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 11000); + } + + { + auto result = MathConstant( + "fraction-numeratordisplaystyleshiftup2000-axisheight1000-" + "rulethickness1000.woff", + OpenTypeMathSupport::MathConstants:: + kFractionNumeratorDisplayStyleShiftUp); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 2000); + } + + { + auto result = MathConstant( + "fraction-denominatorshiftdown3000-axisheight1000-rulethickness1000." + "woff", + OpenTypeMathSupport::MathConstants::kFractionDenominatorShiftDown); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 3000); + } + + { + auto result = MathConstant( + "fraction-denominatordisplaystyleshiftdown6000-axisheight1000-" + "rulethickness1000.woff", + OpenTypeMathSupport::MathConstants:: + kFractionDenominatorDisplayStyleShiftDown); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 6000); + } + + { + auto result = MathConstant( + "fraction-numeratorgapmin9000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kFractionNumeratorGapMin); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 9000); + } + + { + auto result = MathConstant( + "fraction-numeratordisplaystylegapmin8000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kFractionNumDisplayStyleGapMin); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 8000); + } + + { + auto result = MathConstant( + "fraction-rulethickness10000.woff", + OpenTypeMathSupport::MathConstants::kFractionRuleThickness); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 10000); + } + + { + auto result = MathConstant( + "fraction-denominatorgapmin4000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kFractionDenominatorGapMin); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 4000); + } + + { + auto result = MathConstant( + "fraction-denominatordisplaystylegapmin5000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kFractionDenomDisplayStyleGapMin); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 5000); + } +} + +// See third_party/blink/web_tests/external/wpt/mathml/tools/radicals.py +TEST_F(OpenTypeMathSupportTest, MathConstantRadicals) { + { + auto result = MathConstant( + "radical-degreebottomraisepercent25-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kRadicalDegreeBottomRaisePercent); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, .25); + } + + { + auto result = + MathConstant("radical-verticalgap6000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kRadicalVerticalGap); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 6000); + } + + { + auto result = MathConstant( + "radical-displaystyleverticalgap7000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kRadicalDisplayStyleVerticalGap); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 7000); + } + + { + auto result = + MathConstant("radical-rulethickness8000.woff", + OpenTypeMathSupport::MathConstants::kRadicalRuleThickness); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 8000); + } + + { + auto result = + MathConstant("radical-extraascender3000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kRadicalExtraAscender); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 3000); + } + + { + auto result = MathConstant( + "radical-kernbeforedegree4000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kRadicalKernBeforeDegree); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, 4000); + } + + { + auto result = MathConstant( + "radical-kernafterdegreeminus5000-rulethickness1000.woff", + OpenTypeMathSupport::MathConstants::kRadicalKernAfterDegree); + EXPECT_TRUE(result); + EXPECT_FLOAT_EQ(*result, -5000); + } +} + +TEST_F(OpenTypeMathSupportTest, MathVariantsWithoutTable) { + Font math = CreateMathFont("math-text.woff"); + auto glyph = math.PrimaryFont()->GlyphForCharacter('A'); + + // Horizontal variants. + { + auto variants = OpenTypeMathSupport::GetGlyphVariantRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), glyph, + OpenTypeMathStretchData::StretchAxis::Horizontal); + EXPECT_EQ(variants.size(), 1u); + EXPECT_EQ(variants[0], glyph); + } + + // Vertical variants. + { + auto variants = OpenTypeMathSupport::GetGlyphVariantRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), glyph, + OpenTypeMathStretchData::StretchAxis::Vertical); + EXPECT_EQ(variants.size(), 1u); + EXPECT_EQ(variants[0], glyph); + } + + // Horizontal parts. + { + auto parts = OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), glyph, + OpenTypeMathStretchData::StretchAxis::Horizontal); + EXPECT_TRUE(parts.IsEmpty()); + } + + // // Vertical parts. + { + auto parts = OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), glyph, + OpenTypeMathStretchData::StretchAxis::Vertical); + EXPECT_TRUE(parts.IsEmpty()); + } +} + +TEST_F(OpenTypeMathSupportTest, MathVariantsWithTable) { + // operators.woff contains stretchy operators from the MathML operator + // dictionary (including left and over braces) represented by squares. + // It also contains glyphs h0, h1, h2, h3 and v0, v1, v2, v3 that are + // respectively horizontal and vertical rectangles of increasing size. + // The MathVariants table contains the following data for horizontal + // (respectively vertical) operators: + // - Glyph variants: h0, h1, h2, h3 (respectively v0, v1, v2, v3). + // - Glyph parts: non-extender h2 and extender h1 (respectively v2 and v1). + // For details, see createSizeVariants() and createStretchy() from + // third_party/blink/web_tests/external/wpt/mathml/tools/operator-dictionary.py + + Font math = CreateMathFont("operators.woff"); + auto left_brace = math.PrimaryFont()->GlyphForCharacter(kLeftBraceCodePoint); + auto over_brace = math.PrimaryFont()->GlyphForCharacter(kOverBraceCodePoint); + + // Calculate glyph indices from the last unicode character in the font. + // TODO(https://crbug.com/1057596): Find a better way to access these glyph + // indices. + auto v0 = math.PrimaryFont()->GlyphForCharacter( + kArabicMathOperatorHahWithDalCodePoint) + + 1; + auto h0 = v0 + 1; + auto v1 = h0 + 1; + auto h1 = v1 + 1; + auto v2 = h1 + 1; + auto h2 = v2 + 1; + auto v3 = h2 + 1; + auto h3 = v3 + 1; + + // Vertical variants for vertical operator. + { + auto variants = OpenTypeMathSupport::GetGlyphVariantRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), left_brace, + OpenTypeMathStretchData::StretchAxis::Vertical); + EXPECT_EQ(variants.size(), 5u); + EXPECT_EQ(variants[0], left_brace); + EXPECT_EQ(variants[1], v0); + EXPECT_EQ(variants[2], v1); + EXPECT_EQ(variants[3], v2); + EXPECT_EQ(variants[4], v3); + } + + // Horizontal variants for vertical operator. + { + auto variants = OpenTypeMathSupport::GetGlyphVariantRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), left_brace, + OpenTypeMathStretchData::StretchAxis::Horizontal); + EXPECT_EQ(variants.size(), 1u); + EXPECT_EQ(variants[0], left_brace); + } + + // Horizontal variants for horizontal operator. + { + auto variants = OpenTypeMathSupport::GetGlyphVariantRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), over_brace, + OpenTypeMathStretchData::StretchAxis::Horizontal); + EXPECT_EQ(variants.size(), 5u); + EXPECT_EQ(variants[0], over_brace); + EXPECT_EQ(variants[1], h0); + EXPECT_EQ(variants[2], h1); + EXPECT_EQ(variants[3], h2); + EXPECT_EQ(variants[4], h3); + } + + // Vertical variants for horizontal operator. + { + auto variants = OpenTypeMathSupport::GetGlyphVariantRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), over_brace, + OpenTypeMathStretchData::StretchAxis::Vertical); + EXPECT_EQ(variants.size(), 1u); + EXPECT_EQ(variants[0], over_brace); + } + + // Vertical parts for vertical operator. + { + auto parts = OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), left_brace, + OpenTypeMathStretchData::StretchAxis::Vertical); + EXPECT_EQ(parts.size(), 2u); + EXPECT_EQ(parts[0].glyph, v2); + EXPECT_FLOAT_EQ(parts[0].start_connector_length, 0); + EXPECT_FLOAT_EQ(parts[0].end_connector_length, 1000); + EXPECT_FLOAT_EQ(parts[0].full_advance, 3000); + EXPECT_EQ(parts[0].is_extender, false); + EXPECT_EQ(parts[1].glyph, v1); + EXPECT_FLOAT_EQ(parts[1].start_connector_length, 1000); + EXPECT_FLOAT_EQ(parts[1].end_connector_length, 1000); + EXPECT_FLOAT_EQ(parts[1].full_advance, 2000); + EXPECT_EQ(parts[1].is_extender, true); + } + + // Horizontal parts for vertical operator. + { + auto parts = OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), left_brace, + OpenTypeMathStretchData::StretchAxis::Horizontal); + EXPECT_TRUE(parts.IsEmpty()); + } + + // Horizontal parts for horizontal operator. + { + auto parts = OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), over_brace, + OpenTypeMathStretchData::StretchAxis::Horizontal); + + EXPECT_EQ(parts.size(), 2u); + EXPECT_EQ(parts[0].glyph, h2); + EXPECT_FLOAT_EQ(parts[0].start_connector_length, 0); + EXPECT_FLOAT_EQ(parts[0].end_connector_length, 1000); + EXPECT_FLOAT_EQ(parts[0].full_advance, 3000); + EXPECT_EQ(parts[0].is_extender, false); + + EXPECT_EQ(parts[1].glyph, h1); + EXPECT_FLOAT_EQ(parts[1].start_connector_length, 1000); + EXPECT_FLOAT_EQ(parts[1].end_connector_length, 1000); + EXPECT_FLOAT_EQ(parts[1].full_advance, 2000); + EXPECT_EQ(parts[1].is_extender, true); + } + + // Vertical parts for horizontal operator. + { + auto parts = OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), over_brace, + OpenTypeMathStretchData::StretchAxis::Vertical); + EXPECT_TRUE(parts.IsEmpty()); + } +} + +// See third_party/blink/web_tests/external/wpt/mathml/tools/largeop.py +TEST_F(OpenTypeMathSupportTest, MathItalicCorrection) { + { + Font math = CreateMathFont( + "largeop-displayoperatorminheight2000-2AFF-italiccorrection3000.woff"); + Glyph base_glyph = + math.PrimaryFont()->GlyphForCharacter(kNAryWhiteVerticalBarCodePoint); + + // Retrieve the glyph with italic correction. + Vector<OpenTypeMathStretchData::GlyphVariantRecord> variants = + OpenTypeMathSupport::GetGlyphVariantRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), base_glyph, + OpenTypeMathStretchData::StretchAxis::Vertical); + EXPECT_EQ(variants.size(), 3u); + EXPECT_EQ(variants[0], base_glyph); + EXPECT_EQ(variants[1], base_glyph); + Glyph glyph_with_italic_correction = variants[2]; + + // MathItalicCorrection with a value. + base::Optional<float> glyph_with_italic_correction_value = + OpenTypeMathSupport::MathItalicCorrection( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), + glyph_with_italic_correction); + EXPECT_TRUE(glyph_with_italic_correction_value); + EXPECT_FLOAT_EQ(*glyph_with_italic_correction_value, 3000); + + // GetGlyphPartRecords does not set italic correction when there is no + // construction available. + float italic_correction = -1000; + Vector<OpenTypeMathStretchData::GlyphPartRecord> parts = + OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), base_glyph, + OpenTypeMathStretchData::StretchAxis::Vertical, &italic_correction); + EXPECT_TRUE(parts.IsEmpty()); + EXPECT_FLOAT_EQ(italic_correction, -1000); + } + + { + Font math = CreateMathFont( + "largeop-displayoperatorminheight7000-2AFF-italiccorrection5000.woff"); + Glyph base_glyph = + math.PrimaryFont()->GlyphForCharacter(kNAryWhiteVerticalBarCodePoint); + + // OpenTypeMathSupport::GetGlyphPartRecords sets italic correction. + float italic_correction = -1000; + Vector<OpenTypeMathStretchData::GlyphPartRecord> parts = + OpenTypeMathSupport::GetGlyphPartRecords( + math.PrimaryFont()->PlatformData().GetHarfBuzzFace(), base_glyph, + OpenTypeMathStretchData::StretchAxis::Vertical, &italic_correction); + EXPECT_EQ(parts.size(), 3u); + EXPECT_FLOAT_EQ(italic_correction, 5000); + } +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/segmented_font_data.h b/chromium/third_party/blink/renderer/platform/fonts/segmented_font_data.h index 61b2872c97b..17cc3ed89ec 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/segmented_font_data.h +++ b/chromium/third_party/blink/renderer/platform/fonts/segmented_font_data.h @@ -29,6 +29,7 @@ #include "third_party/blink/renderer/platform/fonts/font_data.h" #include "third_party/blink/renderer/platform/fonts/font_data_for_range_set.h" #include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" class SimpleFontData; @@ -61,7 +62,12 @@ class PLATFORM_EXPORT SegmentedFontData : public FontData { Vector<scoped_refptr<FontDataForRangeSet>, 1> faces_; }; -DEFINE_FONT_DATA_TYPE_CASTS(SegmentedFontData, true); +template <> +struct DowncastTraits<SegmentedFontData> { + static bool AllowFrom(const FontData& fontData) { + return fontData.IsSegmented(); + } +}; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc index 5b020364b1a..a9886bcd928 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shape_iterator.cc @@ -13,8 +13,8 @@ scoped_refptr<const ShapeResult> CachingWordShapeIterator::ShapeWordWithoutSpacing(const TextRun& word_run, const Font* font) { ShapeCacheEntry* cache_entry = shape_cache_->Add(word_run, ShapeCacheEntry()); - if (cache_entry && cache_entry->shape_result_) - return cache_entry->shape_result_; + if (cache_entry && *cache_entry) + return *cache_entry; const String word_text = word_run.NormalizedUTF16(); HarfBuzzShaper shaper(word_text); @@ -25,7 +25,7 @@ CachingWordShapeIterator::ShapeWordWithoutSpacing(const TextRun& word_run, shape_result->SetDeprecatedInkBounds(shape_result->ComputeInkBounds()); if (cache_entry) - cache_entry->shape_result_ = shape_result; + *cache_entry = shape_result; return shape_result; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc index 7e4e2bc6398..68972169da9 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper.cc @@ -37,7 +37,7 @@ namespace blink { ShapeCache* CachingWordShaper::GetShapeCache() const { - return font_.font_fallback_list_->GetShapeCache(font_.font_description_); + return font_.GetShapeCache(); } // Returns the total advance width of the TextRun run. If glyph_bounds @@ -157,7 +157,7 @@ GlyphData CachingWordShaper::EmphasisMarkGlyphData( ShapeResultBuffer buffer; ShapeResultsForRun(GetShapeCache(), &font_, emphasis_mark_run, &buffer); - return buffer.EmphasisMarkGlyphData(font_.font_description_); + return buffer.EmphasisMarkGlyphData(font_.GetFontDescription()); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper_test.cc index 89fea7e10c3..46137b2efdd 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/caching_word_shaper_test.cc @@ -24,7 +24,6 @@ class CachingWordShaperTest : public testing::Test { font_description.SetGenericFamily(FontDescription::kStandardFamily); font = Font(font_description); - font.Update(nullptr); ASSERT_TRUE(font.CanShapeWordByWord()); fallback_fonts = nullptr; cache = std::make_unique<ShapeCache>(); @@ -390,7 +389,6 @@ TEST_F(CachingWordShaperTest, TextOrientationFallbackShouldNotInFallbackList) { font_description.SetOrientation(FontOrientation::kVerticalMixed); Font vertical_mixed_font = Font(font_description); - vertical_mixed_font.Update(nullptr); ASSERT_TRUE(vertical_mixed_font.CanShapeWordByWord()); CachingWordShaper shaper(vertical_mixed_font); 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 4d4a8227312..97fa173bb8b 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 @@ -30,8 +30,10 @@ #include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" -#include <hb-ot.h> +// clang-format off #include <hb.h> +#include <hb-ot.h> +// clang-format on #include <memory> @@ -50,6 +52,7 @@ #include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" +#include "third_party/harfbuzz-ng/utils/hb_scoped.h" #include "third_party/skia/include/core/SkPaint.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkPoint.h" @@ -59,34 +62,40 @@ namespace blink { -void HbFontDeleter::operator()(hb_font_t* font) { - if (font) - hb_font_destroy(font); -} +namespace { -void HbFaceDeleter::operator()(hb_face_t* face) { - if (face) - hb_face_destroy(face); -} +#if defined(OS_MACOSX) +void DetermineTrakSbix(SkTypeface* typeface, bool* has_trak, bool* has_sbix) { + int num_tags = typeface->countTables(); + + SkFontTableTag tags[num_tags]; + + int returned_tags = typeface->getTableTags(tags); + DCHECK_EQ(num_tags, returned_tags); -struct HbSetDeleter { - void operator()(hb_set_t* set) { - if (set) - hb_set_destroy(set); + for (auto& tag : tags) { + if (tag == SkSetFourByteTag('t', 'r', 'a', 'k')) + *has_trak = true; + if (tag == SkSetFourByteTag('s', 'b', 'i', 'x')) + *has_sbix = true; } -}; +} +#endif -using HbSetUniquePtr = std::unique_ptr<hb_set_t, HbSetDeleter>; +} // namespace -static scoped_refptr<HbFontCacheEntry> CreateHbFontCacheEntry(hb_face_t*); +static scoped_refptr<HbFontCacheEntry> CreateHbFontCacheEntry( + hb_face_t*, + SkTypeface* typefaces); HarfBuzzFace::HarfBuzzFace(FontPlatformData* platform_data, uint64_t unique_id) : platform_data_(platform_data), unique_id_(unique_id) { HarfBuzzFontCache::AddResult result = - FontGlobalContext::GetHarfBuzzFontCache().insert(unique_id_, nullptr); + FontGlobalContext::GetHarfBuzzFontCache()->insert(unique_id_, nullptr); if (result.is_new_entry) { - HbFaceUniquePtr face(CreateFace()); - result.stored_value->value = CreateHbFontCacheEntry(face.get()); + HbScoped<hb_face_t> face(CreateFace()); + result.stored_value->value = + CreateHbFontCacheEntry(face.get(), platform_data->Typeface()); } result.stored_value->value->AddRef(); unscaled_font_ = result.stored_value->value->HbFont(); @@ -94,13 +103,14 @@ HarfBuzzFace::HarfBuzzFace(FontPlatformData* platform_data, uint64_t unique_id) } HarfBuzzFace::~HarfBuzzFace() { - HarfBuzzFontCache::iterator result = - FontGlobalContext::GetHarfBuzzFontCache().find(unique_id_); - SECURITY_DCHECK(result != FontGlobalContext::GetHarfBuzzFontCache().end()); + HarfBuzzFontCache* harfbuzz_font_cache = + FontGlobalContext::GetHarfBuzzFontCache(); + HarfBuzzFontCache::iterator result = harfbuzz_font_cache->find(unique_id_); + SECURITY_DCHECK(result != harfbuzz_font_cache->end()); DCHECK(!result.Get()->value->HasOneRef()); result.Get()->value->Release(); if (result.Get()->value->HasOneRef()) - FontGlobalContext::GetHarfBuzzFontCache().erase(unique_id_); + harfbuzz_font_cache->erase(unique_id_); } static hb_bool_t HarfBuzzGetGlyph(hb_font_t* hb_font, @@ -228,7 +238,7 @@ bool HarfBuzzFace::HasSpaceInLigaturesOrKerning(TypesettingFeatures features) { const hb_codepoint_t kInvalidCodepoint = static_cast<hb_codepoint_t>(-1); hb_codepoint_t space = kInvalidCodepoint; - HbSetUniquePtr glyphs(hb_set_create()); + HbScoped<hb_set_t> glyphs(hb_set_create()); // Check whether computing is needed and compute for gpos/gsub. if (features & kKerning && @@ -280,31 +290,43 @@ bool HarfBuzzFace::ShouldSubpixelPosition() { return harfbuzz_font_data_->font_.isSubpixel(); } -static hb_font_funcs_t* HarfBuzzSkiaGetFontFuncs() { - hb_font_funcs_t* funcs = FontGlobalContext::GetHarfBuzzFontFuncs(); +static hb_font_funcs_t* create_populated_hb_font_funcs( + FontGlobalContext::HorizontalAdvanceSource horizontal_advance_source) { + hb_font_funcs_t* funcs = hb_font_funcs_create(); - // We don't set callback functions which we can't support. - // HarfBuzz will use the fallback implementation if they aren't set. - if (!funcs) { - funcs = hb_font_funcs_create(); - hb_font_funcs_set_variation_glyph_func(funcs, HarfBuzzGetGlyph, nullptr, - nullptr); - hb_font_funcs_set_nominal_glyph_func(funcs, HarfBuzzGetNominalGlyph, - nullptr, nullptr); + if (horizontal_advance_source == FontGlobalContext::kSkiaHorizontalAdvances) { hb_font_funcs_set_glyph_h_advance_func( funcs, HarfBuzzGetGlyphHorizontalAdvance, nullptr, nullptr); hb_font_funcs_set_glyph_h_advances_func( funcs, HarfBuzzGetGlyphHorizontalAdvances, 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, - nullptr, nullptr); - hb_font_funcs_set_glyph_extents_func(funcs, HarfBuzzGetGlyphExtents, + } + hb_font_funcs_set_variation_glyph_func(funcs, HarfBuzzGetGlyph, nullptr, + nullptr); + hb_font_funcs_set_nominal_glyph_func(funcs, HarfBuzzGetNominalGlyph, 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_make_immutable(funcs); - FontGlobalContext::SetHarfBuzzFontFuncs(funcs); + hb_font_funcs_set_glyph_v_origin_func(funcs, HarfBuzzGetGlyphVerticalOrigin, + nullptr, nullptr); + hb_font_funcs_set_glyph_extents_func(funcs, HarfBuzzGetGlyphExtents, nullptr, + nullptr); + + hb_font_funcs_make_immutable(funcs); + return funcs; +} + +static hb_font_funcs_t* HarfBuzzSkiaGetFontFuncs( + FontGlobalContext::HorizontalAdvanceSource advance_source) { + hb_font_funcs_t* funcs = + FontGlobalContext::GetHarfBuzzFontFuncs(advance_source); + + // We don't set callback functions which we can't support. + // HarfBuzz will use the fallback implementation if they aren't set. + if (!funcs) { + funcs = create_populated_hb_font_funcs(advance_source); + FontGlobalContext::SetHarfBuzzFontFuncs(advance_source, funcs); } DCHECK(funcs); return funcs; @@ -360,11 +382,10 @@ hb_face_t* HarfBuzzFace::CreateFace() { if (tf_stream && tf_stream->getMemoryBase()) { const void* tf_memory = tf_stream->getMemoryBase(); size_t tf_size = tf_stream->getLength(); - std::unique_ptr<hb_blob_t, void (*)(hb_blob_t*)> face_blob( + HbScoped<hb_blob_t> face_blob( hb_blob_create(reinterpret_cast<const char*>(tf_memory), SafeCast<unsigned int>(tf_size), HB_MEMORY_MODE_READONLY, - tf_stream.release(), DeleteTypefaceStream), - hb_blob_destroy); + tf_stream.release(), DeleteTypefaceStream)); face = hb_face_create(face_blob.get(), ttc_index); } #endif @@ -382,15 +403,39 @@ hb_face_t* HarfBuzzFace::CreateFace() { return face; } -scoped_refptr<HbFontCacheEntry> CreateHbFontCacheEntry(hb_face_t* face) { - HbFontUniquePtr ot_font(hb_font_create(face)); +scoped_refptr<HbFontCacheEntry> CreateHbFontCacheEntry(hb_face_t* face, + SkTypeface* typeface) { + HbScoped<hb_font_t> ot_font(hb_font_create(face)); hb_ot_font_set_funcs(ot_font.get()); + + int axis_count = typeface->getVariationDesignPosition(nullptr, 0); + if (axis_count > 0) { + Vector<SkFontArguments::VariationPosition::Coordinate> axis_values; + axis_values.resize(axis_count); + if (typeface->getVariationDesignPosition(axis_values.data(), + axis_values.size()) > 0) { + hb_font_set_variations( + ot_font.get(), reinterpret_cast<hb_variation_t*>(axis_values.data()), + axis_values.size()); + } + } + // Creating a sub font means that non-available functions // are found from the parent. hb_font_t* unscaled_font = hb_font_create_sub_font(ot_font.get()); scoped_refptr<HbFontCacheEntry> cache_entry = HbFontCacheEntry::Create(unscaled_font); - hb_font_set_funcs(unscaled_font, HarfBuzzSkiaGetFontFuncs(), + + FontGlobalContext::HorizontalAdvanceSource advance_source = + FontGlobalContext::kSkiaHorizontalAdvances; +#if defined(OS_MACOSX) + bool has_trak = false; + bool has_sbix = false; + DetermineTrakSbix(typeface, &has_trak, &has_sbix); + if (has_trak && !has_sbix) + advance_source = FontGlobalContext::kHarfBuzzHorizontalAdvances; +#endif + hb_font_set_funcs(unscaled_font, HarfBuzzSkiaGetFontFuncs(advance_source), cache_entry->HbFontData(), nullptr); return cache_entry; } @@ -423,19 +468,6 @@ hb_font_t* HarfBuzzFace::GetScaledFont( // equivalent of CSS pixels here. hb_font_set_ptem(unscaled_font_, platform_data_->size()); - SkTypeface* typeface = harfbuzz_font_data_->font_.getTypeface(); - int axis_count = typeface->getVariationDesignPosition(nullptr, 0); - if (axis_count > 0) { - Vector<SkFontArguments::VariationPosition::Coordinate> axis_values; - axis_values.resize(axis_count); - if (typeface->getVariationDesignPosition(axis_values.data(), - axis_values.size()) > 0) { - hb_font_set_variations( - unscaled_font_, reinterpret_cast<hb_variation_t*>(axis_values.data()), - axis_values.size()); - } - } - return unscaled_font_; } diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.cc index 02690dd9854..40ad779aaed 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_font_cache.cc @@ -8,7 +8,7 @@ namespace blink { HbFontCacheEntry::HbFontCacheEntry(hb_font_t* font) - : hb_font_(HbFontUniquePtr(font)), + : hb_font_(HbScoped<hb_font_t>(font)), hb_font_data_(std::make_unique<HarfBuzzFontData>()) {} HbFontCacheEntry::~HbFontCacheEntry() = default; 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 5826f0a6bba..d8526a9352a 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 @@ -5,30 +5,18 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FONT_CACHE_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_HARFBUZZ_FONT_CACHE_H_ +#include <hb.h> + #include <memory> #include "third_party/blink/renderer/platform/fonts/font_metrics.h" #include "third_party/blink/renderer/platform/fonts/unicode_range_set.h" - -struct hb_font_t; -struct hb_face_t; +#include "third_party/harfbuzz-ng/utils/hb_scoped.h" namespace blink { struct HarfBuzzFontData; -struct HbFontDeleter { - void operator()(hb_font_t* font); -}; - -using HbFontUniquePtr = std::unique_ptr<hb_font_t, HbFontDeleter>; - -struct HbFaceDeleter { - void operator()(hb_face_t* face); -}; - -using HbFaceUniquePtr = std::unique_ptr<hb_face_t, HbFaceDeleter>; - // Though we have FontCache class, which provides the cache mechanism for // WebKit's font objects, we also need additional caching layer for HarfBuzz to // reduce the number of hb_font_t objects created. Without it, we would create @@ -50,15 +38,17 @@ class HbFontCacheEntry : public RefCounted<HbFontCacheEntry> { private: explicit HbFontCacheEntry(hb_font_t* font); - HbFontUniquePtr hb_font_; + HbScoped<hb_font_t> hb_font_; std::unique_ptr<HarfBuzzFontData> hb_font_data_; }; -typedef HashMap<uint64_t, - scoped_refptr<HbFontCacheEntry>, - WTF::IntHash<uint64_t>, - WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> - HarfBuzzFontCache; +// Declare as derived class in order to be able to forward-declare it as class +// in FontGlobalContext. +class HarfBuzzFontCache + : public HashMap<uint64_t, + scoped_refptr<HbFontCacheEntry>, + WTF::IntHash<uint64_t>, + WTF::UnsignedWithZeroKeyHashTraits<uint64_t>> {}; } // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc index 186cb357c9c..b63c48d9513 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/harfbuzz_shaper_fuzzer.cc @@ -36,9 +36,8 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { Font font(font_description); // Set font size to something other than the default 0 size in // FontDescription, 16 matches the default text size in HTML. + // We don't use a FontSelector here. Only look for system fonts for now. font_description.SetComputedSize(16.0f); - // Only look for system fonts for now. - font.Update(nullptr); HarfBuzzShaper shaper(String(converted_input_buffer, converted_length)); scoped_refptr<ShapeResult> result = shaper.Shape(&font, TextDirection::kLtr); 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 9cca0e58d2b..6c03756d4c4 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 @@ -83,7 +83,6 @@ class HarfBuzzShaperTest : public testing::Test { void SetUp() override { font_description.SetComputedSize(12.0); font = Font(font_description); - font.Update(nullptr); } void TearDown() override {} @@ -101,7 +100,6 @@ class HarfBuzzShaperTest : public testing::Test { font_description.SetFamily(devanagari_family); font = Font(font_description); - font.Update(nullptr); } Font CreateAhem(float size) { @@ -472,7 +470,6 @@ TEST_F(HarfBuzzShaperTest, ShapeTabulationCharacters) { TEST_F(HarfBuzzShaperTest, ShapeVerticalUpright) { font_description.SetOrientation(FontOrientation::kVerticalUpright); font = Font(font_description); - font.Update(nullptr); // This string should create 2 runs, ideographic and Latin, both in upright. String string(u"\u65E5\u65E5\u65E5lllll"); @@ -496,7 +493,6 @@ TEST_F(HarfBuzzShaperTest, ShapeVerticalUpright) { TEST_F(HarfBuzzShaperTest, ShapeVerticalUprightIdeograph) { font_description.SetOrientation(FontOrientation::kVerticalUpright); font = Font(font_description); - font.Update(nullptr); // This string should create one ideograph run. String string(u"\u65E5\u65E6\u65E0\u65D3\u65D0"); @@ -527,7 +523,6 @@ TEST_F(HarfBuzzShaperTest, RangeShapeSmallCaps) { font_description.SetVariantCaps(FontDescription::kSmallCaps); font_description.SetComputedSize(12.0); Font font(font_description); - font.Update(nullptr); // Shaping index 2 to 3 means that case splitting for small caps splits before // character index 2 since the initial 'a' needs to be uppercased, but the @@ -563,7 +558,6 @@ TEST_F(HarfBuzzShaperTest, RangeShapeSmallCaps) { TEST_F(HarfBuzzShaperTest, ShapeVerticalMixed) { font_description.SetOrientation(FontOrientation::kVerticalMixed); font = Font(font_description); - font.Update(nullptr); // This string should create 2 runs, ideographic in upright and Latin in // rotated horizontal. @@ -1634,10 +1628,7 @@ static bool KerningIsHappening(const FontDescription& font_description, kern.SetKerning(FontDescription::kAutoKerning); Font font_no_kern(no_kern); - font_no_kern.Update(nullptr); - Font font_kern(kern); - font_kern.Update(nullptr); HarfBuzzShaper shaper(str); @@ -1749,7 +1740,6 @@ TEST_F(HarfBuzzShaperTest, ShapeVerticalWithoutSubpixelPositionIsRounded) { font_description.SetOrientation(FontOrientation::kVerticalUpright); font = Font(font_description); - font.Update(nullptr); String string(u"\u65E5\u65E5\u65E5"); TextDirection direction = TextDirection::kLtr; @@ -1769,7 +1759,6 @@ TEST_F(HarfBuzzShaperTest, ShapeVerticalWithSubpixelPositionIsRounded) { font_description.SetOrientation(FontOrientation::kVerticalUpright); font = Font(font_description); - font.Update(nullptr); String string(u"\u65E5\u65E5\u65E5"); TextDirection direction = TextDirection::kLtr; diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h index b6a3ff992b0..9dfd507dd0b 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_cache.h @@ -39,11 +39,7 @@ namespace blink { -struct ShapeCacheEntry { - DISALLOW_NEW(); - ShapeCacheEntry() { shape_result_ = nullptr; } - scoped_refptr<const ShapeResult> shape_result_; -}; +using ShapeCacheEntry = scoped_refptr<const ShapeResult>; class ShapeCache { USING_FAST_MALLOC(ShapeCache); @@ -118,7 +114,7 @@ class ShapeCache { if (run.length() > SmallStringKey::Capacity()) return nullptr; - return AddSlowCase(run, entry); + return AddSlowCase(run, std::move(entry)); } void ClearIfVersionChanged(unsigned version) { @@ -140,10 +136,10 @@ class ShapeCache { size_t ByteSize() const { size_t self_byte_size = 0; for (auto cache_entry : single_char_map_) { - self_byte_size += cache_entry.value.shape_result_->ByteSize(); + self_byte_size += cache_entry.value->ByteSize(); } for (auto cache_entry : short_string_map_) { - self_byte_size += cache_entry.value.shape_result_->ByteSize(); + self_byte_size += cache_entry.value->ByteSize(); } return self_byte_size; } @@ -160,7 +156,8 @@ class ShapeCache { // as such use bit 31 (zero-based) to indicate direction. if (run.Direction() == TextDirection::kRtl) key |= (1u << 31); - SingleCharMap::AddResult add_result = single_char_map_.insert(key, entry); + SingleCharMap::AddResult add_result = + single_char_map_.insert(key, std::move(entry)); is_new_entry = add_result.is_new_entry; value = &add_result.stored_value->value; } else { @@ -170,9 +167,8 @@ class ShapeCache { } else { small_string_key = SmallStringKey(run.Span16(), run.Direction()); } - SmallStringMap::AddResult add_result = - short_string_map_.insert(small_string_key, entry); + short_string_map_.insert(small_string_key, std::move(entry)); is_new_entry = add_result.is_new_entry; value = &add_result.stored_value->value; } @@ -202,6 +198,7 @@ class ShapeCache { struct SmallStringKeyHashTraits : WTF::SimpleClassHashTraits<SmallStringKey> { STATIC_ONLY(SmallStringKeyHashTraits); static const bool kHasIsEmptyValueFunction = true; + static const bool kEmptyValueIsZero = false; static bool IsEmptyValue(const SmallStringKey& key) { return key.IsHashTableEmptyValue(); } 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 3a73c9a9d8e..81864362264 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 @@ -565,7 +565,7 @@ unsigned ShapeResult::OffsetToFit(float x, TextDirection line_direction) const { if (IsLtr(line_direction)) return result.left_character_index; - if (x == result.origin_x && IsRtl(Direction())) + if (x == result.origin_x) return result.left_character_index; return result.right_character_index; } @@ -1450,6 +1450,96 @@ scoped_refptr<ShapeResult> ShapeResult::CreateForSpaces(const Font* font, return result; } +scoped_refptr<ShapeResult> ShapeResult::CreateForStretchyMathOperator( + const Font* font, + TextDirection direction, + OpenTypeMathStretchData::StretchAxis stretch_axis, + Glyph glyph_variant, + float stretch_size) { + bool is_horizontal_assembly = + stretch_axis == OpenTypeMathStretchData::StretchAxis::Horizontal; + unsigned start_index = 0; + unsigned num_characters = 1; + scoped_refptr<ShapeResult> result = + ShapeResult::Create(font, start_index, num_characters, direction); + + hb_direction_t hb_direction = + is_horizontal_assembly ? HB_DIRECTION_LTR : HB_DIRECTION_TTB; + unsigned glyph_index = 0; + scoped_refptr<ShapeResult::RunInfo> run = RunInfo::Create( + font->PrimaryFont(), hb_direction, CanvasRotationInVertical::kRegular, + HB_SCRIPT_COMMON, start_index, 1 /* num_glyph */, num_characters); + run->glyph_data_[glyph_index] = {glyph_variant, 0 /* character index */, + true /* IsSafeToBreakBefore */, + stretch_size}; + run->width_ = std::max(0.0f, stretch_size); + + result->width_ = run->width_; + result->num_glyphs_ = run->NumGlyphs(); + result->runs_.push_back(std::move(run)); + + return result; +} + +scoped_refptr<ShapeResult> ShapeResult::CreateForStretchyMathOperator( + const Font* font, + TextDirection direction, + OpenTypeMathStretchData::StretchAxis stretch_axis, + const OpenTypeMathStretchData::AssemblyParameters& assembly_parameters) { + DCHECK(!assembly_parameters.parts.IsEmpty()); + DCHECK_LE(assembly_parameters.glyph_count, HarfBuzzRunGlyphData::kMaxGlyphs); + + bool is_horizontal_assembly = + stretch_axis == OpenTypeMathStretchData::StretchAxis::Horizontal; + unsigned start_index = 0; + unsigned num_characters = 1; + scoped_refptr<ShapeResult> result = + ShapeResult::Create(font, start_index, num_characters, direction); + + hb_direction_t hb_direction = + is_horizontal_assembly ? HB_DIRECTION_LTR : HB_DIRECTION_TTB; + scoped_refptr<ShapeResult::RunInfo> run = RunInfo::Create( + font->PrimaryFont(), hb_direction, CanvasRotationInVertical::kRegular, + HB_SCRIPT_COMMON, start_index, assembly_parameters.glyph_count, + num_characters); + + float overlap = assembly_parameters.connector_overlap; + unsigned part_index = 0; + for (const auto& part : assembly_parameters.parts) { + unsigned repetition_count = + part.is_extender ? assembly_parameters.repetition_count : 1; + if (!repetition_count) + continue; + DCHECK(part_index < assembly_parameters.glyph_count); + for (unsigned repetition_index = 0; repetition_index < repetition_count; + repetition_index++) { + unsigned glyph_index = + is_horizontal_assembly + ? part_index + : assembly_parameters.glyph_count - 1 - part_index; + float full_advance = glyph_index == assembly_parameters.glyph_count - 1 + ? part.full_advance + : part.full_advance - overlap; + run->glyph_data_[glyph_index] = {part.glyph, 0 /* character index */, + !glyph_index /* IsSafeToBreakBefore */, + full_advance}; + if (!is_horizontal_assembly) { + GlyphOffset glyph_offset( + 0, -assembly_parameters.stretch_size + part.full_advance); + run->glyph_data_.SetOffsetAt(glyph_index, glyph_offset); + result->has_vertical_offsets_ |= (glyph_offset.Height() != 0); + } + part_index++; + } + } + run->width_ = std::max(0.0f, assembly_parameters.stretch_size); + + result->width_ = run->width_; + result->num_glyphs_ = run->NumGlyphs(); + result->runs_.push_back(std::move(run)); + return result; +} + void ShapeResult::ToString(StringBuilder* output) const { output->Append("#chars="); output->AppendNumber(num_characters_); 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 eeb7e99b05f..d63fdd62f44 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 @@ -35,6 +35,7 @@ #include "base/containers/span.h" #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/opentype/open_type_math_stretch_data.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/geometry/layout_unit.h" @@ -142,6 +143,17 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { unsigned start_index, unsigned length, float width); + static scoped_refptr<ShapeResult> CreateForStretchyMathOperator( + const Font*, + TextDirection, + OpenTypeMathStretchData::StretchAxis, + Glyph, + float stretch_size); + static scoped_refptr<ShapeResult> CreateForStretchyMathOperator( + const Font*, + TextDirection, + OpenTypeMathStretchData::StretchAxis, + const OpenTypeMathStretchData::AssemblyParameters&); ~ShapeResult(); // Returns a mutable unique instance. If |this| has more than 1 ref count, @@ -495,6 +507,7 @@ class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> { friend class ShapeResultBloberizer; friend class ShapeResultView; friend class ShapeResultTest; + friend class StretchyOperatorShaper; template <bool has_non_zero_glyph_offsets> float ForEachGlyphImpl(float initial_advance, diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc index 17be9dacea0..91a4ccffadc 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_bloberizer_test.cc @@ -39,7 +39,6 @@ class ShapeResultBloberizerTest : public testing::Test { font_description.SetGenericFamily(FontDescription::kStandardFamily); font = Font(font_description); - font.Update(nullptr); ASSERT_TRUE(font.CanShapeWordByWord()); fallback_fonts = nullptr; cache = std::make_unique<ShapeCache>(); @@ -267,7 +266,6 @@ TEST_F(ShapeResultBloberizerTest, CommonAccentLeftToRightFillGlyphBuffer) { bloberizer.FillGlyphs(run_info, buffer); Font reference_font(font_description); - reference_font.Update(nullptr); reference_font.SetCanShapeWordByWordForTesting(false); ShapeResultBloberizer reference_bloberizer(reference_font, 1); @@ -305,7 +303,6 @@ TEST_F(ShapeResultBloberizerTest, CommonAccentRightToLeftFillGlyphBuffer) { bloberizer.FillGlyphs(run_info, buffer); Font reference_font(font_description); - reference_font.Update(nullptr); reference_font.SetCanShapeWordByWordForTesting(false); ShapeResultBloberizer reference_bloberizer(reference_font, 1); diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc index 73f8a4c0fe3..758065226be 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.cc @@ -130,7 +130,7 @@ Vector<CharacterRange> ShapeResultBuffer::IndividualCharacterRanges( float total_width) const { Vector<CharacterRange> ranges; float current_x = direction == TextDirection::kRtl ? total_width : 0; - for (const scoped_refptr<const ShapeResult> result : results_) + for (const scoped_refptr<const ShapeResult>& result : results_) current_x = result->IndividualCharacterRanges(&ranges, current_x); return ranges; } @@ -192,7 +192,7 @@ Vector<double> ShapeResultBuffer::IndividualCharacterAdvances( Vector<double> advances; double current_x = direction == TextDirection::kRtl ? total_width : 0; - for (const scoped_refptr<const ShapeResult> result : results_) { + for (const scoped_refptr<const ShapeResult>& result : results_) { unsigned run_count = result->runs_.size(); result->EnsureGraphemes( 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 a1a6708907c..32fa8f2ab73 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 @@ -211,7 +211,7 @@ struct ShapeResult::RunInfo : public RefCounted<ShapeResult::RunInfo> { } if (!Rtl()) - end = num_characters_; + end = offset + num_characters_; else end = start; start = index; diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc index 3738a170f1d..8dac0939e7b 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/shape_result_test.cc @@ -21,7 +21,6 @@ class ShapeResultTest : public testing::Test { void SetUp() override { font_description.SetComputedSize(12.0); font = Font(font_description); - font.Update(nullptr); FontDescription::VariantLigatures ligatures; arabic_font = blink::test::CreateTestFont( 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 index 9e558346965..dd4998fb3c0 100644 --- 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 @@ -83,6 +83,15 @@ struct ShapeResultView::RunInfoPart { // |base::span<RunInfoPart>|. const RunInfoPart* get() const { return this; } + void ExpandRangeToIncludePartialGlyphs(unsigned offset, + unsigned* from, + unsigned* to) const { + DCHECK_GE(offset + start_index_, offset_); + unsigned part_offset = offset + start_index_ - offset_; + run_->ExpandRangeToIncludePartialGlyphs( + part_offset, reinterpret_cast<int*>(from), reinterpret_cast<int*>(to)); + } + scoped_refptr<const ShapeResult::RunInfo> run_; ShapeResult::RunInfo::GlyphDataRange range_; @@ -633,4 +642,13 @@ FloatRect ShapeResultView::ComputeInkBounds() const { return ink_bounds; } +void ShapeResultView::ExpandRangeToIncludePartialGlyphs(unsigned* from, + unsigned* to) const { + unsigned accumulated_offset = char_index_offset_; + for (const auto& part : Parts()) { + part.ExpandRangeToIncludePartialGlyphs(accumulated_offset, from, to); + accumulated_offset += part.NumCharacters(); + } +} + } // 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 index 591dff49962..05c7fa1563d 100644 --- 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 @@ -145,9 +145,11 @@ class PLATFORM_EXPORT ShapeResultView final } void GetRunFontData(Vector<ShapeResult::RunFontData>*) const; + void ExpandRangeToIncludePartialGlyphs(unsigned* from, unsigned* to) const; + private: template <class ShapeResultType> - ShapeResultView(const ShapeResultType*); + explicit ShapeResultView(const ShapeResultType*); struct RunInfoPart; template <class ShapeResultType> 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 index ce0f6ccb82b..85c46054789 100644 --- 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 @@ -21,7 +21,6 @@ class ShapeResultViewTest : public testing::Test { void SetUp() override { font_description.SetComputedSize(12.0); font = Font(font_description); - font.Update(nullptr); } void TearDown() override {} 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 82eeefad31b..b0296b7f786 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 @@ -52,7 +52,6 @@ class ShapingLineBreakerTest : public testing::Test { void SetUp() override { font_description.SetComputedSize(12.0); font = Font(font_description); - font.Update(nullptr); } void TearDown() override {} diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.cc new file mode 100644 index 00000000000..99c80b364f4 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.cc @@ -0,0 +1,223 @@ +// Copyright 2020 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/stretchy_operator_shaper.h" + +#include <hb-ot.h> +#include <hb.h> +#include <unicode/uchar.h> + +#include "third_party/blink/renderer/platform/fonts/canvas_rotation_in_vertical.h" +#include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h" +#include "third_party/blink/renderer/platform/fonts/shaping/harfbuzz_face.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" +#include "third_party/blink/renderer/platform/geometry/float_rect.h" +#include "third_party/blink/renderer/platform/wtf/text/unicode.h" +#include "ui/gfx/skia_util.h" + +namespace blink { + +namespace { + +// HarfBuzz' hb_position_t is a 16.16 fixed-point value. +inline float HarfBuzzUnitsToFloat(hb_position_t value) { + static const float kFloatToHbRatio = 1.0f / (1 << 16); + return kFloatToHbRatio * value; +} + +inline float GetGlyphStretchSize( + FloatRect bounds, + OpenTypeMathStretchData::StretchAxis stretch_axis) { + return stretch_axis == OpenTypeMathStretchData::StretchAxis::Horizontal + ? bounds.Width() + : bounds.Height(); +} + +inline StretchyOperatorShaper::Metrics ToMetrics(FloatRect bounds) { + return {bounds.Width(), -bounds.Y(), bounds.MaxY()}; +} + +base::Optional<OpenTypeMathStretchData::AssemblyParameters> +GetAssemblyParameters(const HarfBuzzFace* harfbuzz_face, + Glyph base_glyph, + OpenTypeMathStretchData::StretchAxis stretch_axis, + float target_size) { + Vector<OpenTypeMathStretchData::GlyphPartRecord> parts = + OpenTypeMathSupport::GetGlyphPartRecords(harfbuzz_face, base_glyph, + stretch_axis); + if (parts.IsEmpty()) + return base::nullopt; + + hb_font_t* hb_font = + harfbuzz_face->GetScaledFont(nullptr, HarfBuzzFace::NoVerticalLayout); + + auto hb_stretch_axis = + stretch_axis == OpenTypeMathStretchData::StretchAxis::Horizontal + ? HB_DIRECTION_LTR + : HB_DIRECTION_BTT; + + // Go over the assembly parts and determine parameters used below. + // https://mathml-refresh.github.io/mathml-core/#the-glyphassembly-table + float min_connector_overlap = HarfBuzzUnitsToFloat( + hb_ot_math_get_min_connector_overlap(hb_font, hb_stretch_axis)); + float max_connector_overlap = std::numeric_limits<float>::max(); + float non_extender_advance_sum = 0, extender_advance_sum = 0; + unsigned non_extender_count = 0, extender_count = 0; + + for (auto& part : parts) { + // Calculate the count and advance sums of extender and non-extender glyphs. + if (part.is_extender) { + extender_count++; + extender_advance_sum += part.full_advance; + } else { + non_extender_count++; + non_extender_advance_sum += part.full_advance; + } + + // Take into account start connector length for all but the first glyph. + if (part.is_extender || &part != &parts.front()) { + max_connector_overlap = + std::min(max_connector_overlap, part.start_connector_length); + } + + // Take into account end connector length for all but the last glyph. + if (part.is_extender || &part != &parts.back()) { + max_connector_overlap = + std::min(max_connector_overlap, part.end_connector_length); + } + } + + // Check validity conditions indicated in MathML core. + float extender_non_overlapping_advance_sum = + extender_advance_sum - min_connector_overlap * extender_count; + if (extender_count == 0 || max_connector_overlap < min_connector_overlap || + extender_non_overlapping_advance_sum <= 0) + return base::nullopt; + + // Calculate the minimal number of repetitions needed to obtain an assembly + // size of size at least target size (r_min in MathML Core). + unsigned repetition_count = std::max<float>( + std::ceil((target_size - non_extender_advance_sum + + min_connector_overlap * (non_extender_count - 1)) / + extender_non_overlapping_advance_sum), + 0); + + // Calculate the number of glyphs, limiting repetition_count to ensure the + // assembly does not have more than HarfBuzzRunGlyphData::kMaxGlyphs. + DCHECK_LE(non_extender_count, HarfBuzzRunGlyphData::kMaxGlyphs); + repetition_count = std::min<unsigned>( + repetition_count, + (HarfBuzzRunGlyphData::kMaxGlyphs - non_extender_count) / extender_count); + unsigned glyph_count = non_extender_count + repetition_count * extender_count; + DCHECK_LE(glyph_count, HarfBuzzRunGlyphData::kMaxGlyphs); + + // Calculate the maximum overlap (called o_max in MathML Core) and the number + // of glyph in such an assembly (called N in MathML Core). + float connector_overlap = max_connector_overlap; + if (glyph_count > 1) { + float max_connector_overlap_theorical = + (non_extender_advance_sum + repetition_count * extender_advance_sum - + target_size) / + (glyph_count - 1); + connector_overlap = + std::max(min_connector_overlap, + std::min(connector_overlap, max_connector_overlap_theorical)); + } + + // Calculate the assembly size (called AssemblySize(o, r) in MathML Core). + float stretch_size = non_extender_advance_sum + + repetition_count * extender_advance_sum - + connector_overlap * (glyph_count - 1); + + return base::Optional<OpenTypeMathStretchData::AssemblyParameters>( + {connector_overlap, repetition_count, glyph_count, stretch_size, + std::move(parts)}); +} + +} // namespace + +StretchyOperatorShaper::Metrics StretchyOperatorShaper::GetMetrics( + const Font* font, + float target_size) const { + const SimpleFontData* primary_font = font->PrimaryFont(); + const HarfBuzzFace* harfbuzz_face = + primary_font->PlatformData().GetHarfBuzzFace(); + Glyph base_glyph = primary_font->GlyphForCharacter(stretchy_character_); + + FloatRect bounds; + + // Try different glyph variants. + for (auto& variant : OpenTypeMathSupport::GetGlyphVariantRecords( + harfbuzz_face, base_glyph, stretch_axis_)) { + bounds = primary_font->BoundsForGlyph(variant); + if (GetGlyphStretchSize(bounds, stretch_axis_) >= target_size) + return ToMetrics(bounds); + } + + // Try a glyph assembly. + auto params = GetAssemblyParameters(harfbuzz_face, base_glyph, stretch_axis_, + target_size); + if (!params) + return ToMetrics(bounds); + + bounds = stretch_axis_ == OpenTypeMathStretchData::StretchAxis::Horizontal + ? FloatRect(0, 0, params->stretch_size, 0) + : FloatRect(0, -params->stretch_size, 0, params->stretch_size); + + for (auto& part : params->parts) { + // Include dimension of the part, orthogonal to the stretch axis. + auto glyph_bounds = primary_font->BoundsForGlyph(part.glyph); + if (stretch_axis_ == OpenTypeMathStretchData::StretchAxis::Horizontal) { + glyph_bounds.SetX(0); + glyph_bounds.SetWidth(0); + } else { + glyph_bounds.SetY(0); + glyph_bounds.SetHeight(0); + } + bounds.UniteEvenIfEmpty(glyph_bounds); + } + + return ToMetrics(bounds); +} + +scoped_refptr<ShapeResult> StretchyOperatorShaper::Shape( + const Font* font, + float target_size) const { + const SimpleFontData* primary_font = font->PrimaryFont(); + const HarfBuzzFace* harfbuzz_face = + primary_font->PlatformData().GetHarfBuzzFace(); + Glyph base_glyph = primary_font->GlyphForCharacter(stretchy_character_); + + Glyph glyph_variant; + float glyph_variant_stretch_size; + TextDirection direction = TextDirection::kLtr; + + // Try different glyph variants. + for (auto& variant : OpenTypeMathSupport::GetGlyphVariantRecords( + harfbuzz_face, base_glyph, stretch_axis_)) { + glyph_variant = variant; + auto bounds = primary_font->BoundsForGlyph(glyph_variant); + glyph_variant_stretch_size = GetGlyphStretchSize(bounds, stretch_axis_); + if (glyph_variant_stretch_size >= target_size) { + return ShapeResult::CreateForStretchyMathOperator( + font, direction, stretch_axis_, glyph_variant, + glyph_variant_stretch_size); + } + } + + // Try a glyph assembly. + auto params = GetAssemblyParameters(harfbuzz_face, base_glyph, stretch_axis_, + target_size); + if (!params) { + return ShapeResult::CreateForStretchyMathOperator( + font, direction, stretch_axis_, glyph_variant, + glyph_variant_stretch_size); + } + + return ShapeResult::CreateForStretchyMathOperator( + font, direction, stretch_axis_, std::move(*params)); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.h b/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.h new file mode 100644 index 00000000000..4df0edaed15 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper.h @@ -0,0 +1,59 @@ +// Copyright 2020 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_STRETCHY_OPERATOR_SHAPER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_STRETCHY_OPERATOR_SHAPER_H_ + +#include <base/memory/scoped_refptr.h> +#include <unicode/uchar.h> +#include "third_party/blink/renderer/platform/fonts/glyph.h" +#include "third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h" +#include "third_party/blink/renderer/platform/text/text_direction.h" +#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" + +namespace blink { + +class Font; +class ShapeResult; +class StretchyOperatorShaper; + +// TODO(https://crbug.com/1057589): Add a TextDirection parameter, so that it's +// possible to perform glyph-level (rtlm feature) or character-level mirroring +// before stretching. +// https://mathml-refresh.github.io/mathml-core/#algorithms-for-glyph-stretching +class PLATFORM_EXPORT StretchyOperatorShaper final { + DISALLOW_NEW(); + + public: + StretchyOperatorShaper(UChar stretchy_character, + OpenTypeMathStretchData::StretchAxis stretch_axis) + : stretchy_character_(stretchy_character), stretch_axis_(stretch_axis) {} + + // Returns the metrics of the stretched operator for layout purpose. + // May be called multiple times; font and direction may vary between calls. + // https://mathml-refresh.github.io/mathml-core/#dfn-box-metrics-of-a-stretchy-glyph + struct Metrics { + float advance; + float ascent; + float descent; + // TODO(https://crbug.com/1057592): Add italic correction. + }; + Metrics GetMetrics(const Font*, float target_size) const; + + // Shape the stretched operator. The coordinates of the glyph(s) use the same + // origin as the rectangle returned by GetMetrics. + // May be called multiple times; font and direction may vary between calls. + // https://mathml-refresh.github.io/mathml-core/#dfn-shape-a-stretchy-glyph + scoped_refptr<ShapeResult> Shape(const Font*, float target_size) const; + + ~StretchyOperatorShaper() = default; + + private: + const UChar stretchy_character_; + const OpenTypeMathStretchData::StretchAxis stretch_axis_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SHAPING_STRETCHY_OPERATOR_SHAPER_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper_test.cc b/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper_test.cc new file mode 100644 index 00000000000..1fd1aeaf8bb --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/fonts/shaping/stretchy_operator_shaper_test.cc @@ -0,0 +1,264 @@ +// Copyright 2020 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/stretchy_operator_shaper.h" +#include "base/memory/scoped_refptr.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/fonts/font.h" +#include "third_party/blink/renderer/platform/fonts/opentype/open_type_types.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_inline_headers.h" +#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_test_info.h" +#include "third_party/blink/renderer/platform/testing/font_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" + +namespace blink { + +namespace { + +const UChar32 kLeftBraceCodePoint = '{'; +const UChar32 kOverBraceCodePoint = 0x23DE; +const UChar32 kArabicMathOperatorHahWithDalCodePoint = 0x1EEF1; +float kSizeError = .1; + +ShapeResultTestInfo* TestInfo(const scoped_refptr<ShapeResult>& result) { + return static_cast<ShapeResultTestInfo*>(result.get()); +} + +} // namespace + +class StretchyOperatorShaperTest : public testing::Test { + protected: + void SetUp() override { + font_description.SetComputedSize(10.0); + font = Font(font_description); + } + + void TearDown() override {} + + Font CreateMathFont(const String& name, float size = 1000) { + FontDescription::VariantLigatures ligatures; + return blink::test::CreateTestFont( + "MathTestFont", + blink::test::BlinkWebTestsFontsTestDataPath(String("math/") + name), + size, &ligatures); + } + + FontDescription font_description; + Font font; +}; + +// See createStretchy() in +// third_party/blink/web_tests/external/wpt/mathml/tools/operator-dictionary.py +TEST_F(StretchyOperatorShaperTest, GlyphVariants) { + Font math = CreateMathFont("operators.woff"); + + StretchyOperatorShaper vertical_shaper( + kLeftBraceCodePoint, OpenTypeMathStretchData::StretchAxis::Vertical); + StretchyOperatorShaper horizontal_shaper( + kOverBraceCodePoint, OpenTypeMathStretchData::StretchAxis::Horizontal); + + auto left_brace = math.PrimaryFont()->GlyphForCharacter(kLeftBraceCodePoint); + auto over_brace = math.PrimaryFont()->GlyphForCharacter(kOverBraceCodePoint); + + // Calculate glyph indices from the last unicode character in the font. + // TODO(https://crbug.com/1057596): Find a better way to access these glyph + // indices. + auto v0 = math.PrimaryFont()->GlyphForCharacter( + kArabicMathOperatorHahWithDalCodePoint) + + 1; + auto h0 = v0 + 1; + auto v1 = h0 + 1; + auto h1 = v1 + 1; + auto v2 = h1 + 1; + auto h2 = v2 + 1; + + // Stretch operators to target sizes (in font units) 125, 250, 375, 500, 625, + // 750, 875, 1000, 1125, ..., 3750, 3875, 4000. + // + // Shaper tries glyphs over_brace/left_brace, h0/v0, h1/v1, h2/v2, h3/v3 of + // respective sizes 1000, 1000, 2000, 3000 and 4000. It returns the smallest + // glyph larger than the target size. + const unsigned size_count = 4; + const unsigned subdivision = 8; + for (unsigned i = 0; i < size_count; i++) { + for (unsigned j = 1; j <= subdivision; j++) { + // Due to floating-point errors, the actual metrics of the size variants + // might actually be slightly smaller than expected. Reduce the + // target_size by kSizeError to ensure that the shaper picks the desired + // size variant. + float target_size = i * 1000 + (j * 1000 / subdivision) - kSizeError; + + // Metrics of horizontal size variants. + { + auto metrics = horizontal_shaper.GetMetrics(&math, target_size); + EXPECT_NEAR(metrics.advance, (i + 1) * 1000, kSizeError); + EXPECT_NEAR(metrics.ascent, 1000, kSizeError); + EXPECT_FLOAT_EQ(metrics.descent, 0); + } + + // Metrics of vertical size variants. + + { + auto metrics = vertical_shaper.GetMetrics(&math, target_size); + EXPECT_NEAR(metrics.advance, 1000, kSizeError); + EXPECT_NEAR(metrics.ascent, (i + 1) * 1000, kSizeError); + EXPECT_FLOAT_EQ(metrics.descent, 0); + } + + // Shaping of horizontal size variants. + { + scoped_refptr<ShapeResult> result = + horizontal_shaper.Shape(&math, target_size); + EXPECT_EQ(TestInfo(result)->NumberOfRunsForTesting(), 1u); + EXPECT_EQ(TestInfo(result)->RunInfoForTesting(0).NumGlyphs(), 1u); + Glyph expected_variant = i ? h0 + 2 * i : over_brace; + EXPECT_EQ(TestInfo(result)->GlyphForTesting(0, 0), expected_variant); + EXPECT_NEAR(TestInfo(result)->AdvanceForTesting(0, 0), (i + 1) * 1000, + kSizeError); + } + + // Shaping of vertical size variants. + { + scoped_refptr<ShapeResult> result = + vertical_shaper.Shape(&math, target_size); + EXPECT_EQ(TestInfo(result)->NumberOfRunsForTesting(), 1u); + EXPECT_EQ(TestInfo(result)->RunInfoForTesting(0).NumGlyphs(), 1u); + Glyph expected_variant = i ? v0 + 2 * i : left_brace; + EXPECT_EQ(TestInfo(result)->GlyphForTesting(0, 0), expected_variant); + EXPECT_NEAR(TestInfo(result)->AdvanceForTesting(0, 0), (i + 1) * 1000, + kSizeError); + } + } + } + + // Stretch an operator to target sizes (in font units) much larger than 4000. + // + // This will force an assembly with the following parts: + // _____________________________________________________________ + // Part | MaxStartOverlap | MaxEndOverlap | Advance | Extender | + // h2/v2 | 0 | 1000 | 3000 | false | + // h1/v1 | 1000 | 1000 | 2000 | true | + // + // For an assembly made of one non-extender glyph h2/v2 and repetition_count + // copies of extenders h1/v1, the size is + // advance(h2/v2) + repetition_count * (advance(h1/v1) - overlap). + // + // For repetition_count = k and overlap = 750, the size is X = 1250k + 3000. + // + // Since the font min overlap is 500, for repetition_count = k - 1 the size + // is at most Y = 1500k + 1500. + // + // Since the max overlap of parts is 1000, for repetition_count = k + 1 the + // size is at least Z = 1000k + 4000. + // + // { X - 4000 = 1250k - 1000 >= 250 >> kSizeError for k >= 1. + // { X - Y = 1500 - 250k >= 250 >> kSizeError for k <= 5. + // Hence setting the target size to 1250k + 3000 will ensure an assembly of + // k + 1 glyphs and overlap close to 750 for 1 <= k <= 5. + // + // Additionally, X - Z = 250k - 1000 = 250 >> kSizeError for k = 5 so this + // case also verifies that the minimal number of repetitions is actually used. + // + for (unsigned repetition_count = 1; repetition_count <= 5; + repetition_count++) { + // It is not necessary to decrease the target_size by kSizeError here. The + // shaper can just increase overlap by kSizeError / repetition_count to + // reduce the actual size of the assembly. + float overlap = 750; + float target_size = 3000 + repetition_count * (2000 - overlap); + + // Metrics of horizontal assembly. + { + auto metrics = horizontal_shaper.GetMetrics(&math, target_size); + EXPECT_NEAR(metrics.advance, target_size, kSizeError); + EXPECT_NEAR(metrics.ascent, 1000, kSizeError); + EXPECT_FLOAT_EQ(metrics.descent, 0); + } + + // Metrics of vertical assembly. + { + auto metrics = vertical_shaper.GetMetrics(&math, target_size); + EXPECT_NEAR(metrics.advance, 1000, kSizeError); + EXPECT_NEAR(metrics.ascent, target_size, kSizeError); + EXPECT_FLOAT_EQ(metrics.descent, 0); + } + + // Shaping of horizontal assembly. + // From left to right: h2, h1, h1, h1, ... + { + scoped_refptr<ShapeResult> result = + horizontal_shaper.Shape(&math, target_size); + + EXPECT_EQ(TestInfo(result)->NumberOfRunsForTesting(), 1u); + EXPECT_EQ(TestInfo(result)->RunInfoForTesting(0).NumGlyphs(), + repetition_count + 1); + EXPECT_EQ(TestInfo(result)->GlyphForTesting(0, 0), h2); + EXPECT_NEAR(TestInfo(result)->AdvanceForTesting(0, 0), 3000 - overlap, + kSizeError); + for (unsigned i = 0; i < repetition_count - 1; i++) { + EXPECT_EQ(TestInfo(result)->GlyphForTesting(0, i + 1), h1); + EXPECT_NEAR(TestInfo(result)->AdvanceForTesting(0, i + 1), + 2000 - overlap, kSizeError); + } + EXPECT_EQ(TestInfo(result)->GlyphForTesting(0, repetition_count), h1); + EXPECT_NEAR(TestInfo(result)->AdvanceForTesting(0, repetition_count), + 2000, kSizeError); + } + + // Shaping of vertical assembly. + // From bottom to top: v2, v1, v1, v1, ... + { + scoped_refptr<ShapeResult> result = + vertical_shaper.Shape(&math, target_size); + + EXPECT_EQ(TestInfo(result)->NumberOfRunsForTesting(), 1u); + EXPECT_EQ(TestInfo(result)->RunInfoForTesting(0).NumGlyphs(), + repetition_count + 1); + for (unsigned i = 0; i < repetition_count; i++) { + EXPECT_EQ(TestInfo(result)->GlyphForTesting(0, i), v1); + EXPECT_NEAR(TestInfo(result)->AdvanceForTesting(0, i), 2000 - overlap, + kSizeError); + } + EXPECT_EQ(TestInfo(result)->GlyphForTesting(0, repetition_count), v2); + EXPECT_NEAR(TestInfo(result)->AdvanceForTesting(0, repetition_count), + 3000, kSizeError); + } + } + + // Stretch an operator to edge target size values. + // + // These tests verify that it does not cause any assertion or crashes. + { + // Zero. + float target_size = 0; + horizontal_shaper.Shape(&math, target_size); + vertical_shaper.Shape(&math, target_size); + + // Negative. + target_size = -5500; + horizontal_shaper.Shape(&math, target_size); + vertical_shaper.Shape(&math, target_size); + + // Max limit. + target_size = std::numeric_limits<float>::max(); + horizontal_shaper.Shape(&math, target_size); + vertical_shaper.Shape(&math, target_size); + + // Min limit. + target_size = std::numeric_limits<float>::min(); + horizontal_shaper.Shape(&math, target_size); + vertical_shaper.Shape(&math, target_size); + + // More than the max number of glyphs. + // The size of an assembly with one non-extender v2/h2 and k - 1 extenders + // h1/v1 and minimal overlap 500 is Y = 1500k + 1500. + // So target_size - Y >= 250 >> kSizeError if the assembly does not have + // more than the max number of glyphs. + target_size = 1500 * HarfBuzzRunGlyphData::kMaxGlyphs + 1750; + horizontal_shaper.Shape(&math, target_size); + vertical_shaper.Shape(&math, target_size); + } +} + +} // 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 7c5e9561c83..070cde2e8ba 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 @@ -39,6 +39,7 @@ #include "third_party/blink/renderer/platform/fonts/typesetting_features.h" #include "third_party/blink/renderer/platform/geometry/float_rect.h" #include "third_party/blink/renderer/platform/platform_export.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" #include "third_party/blink/renderer/platform/wtf/text/string_hash.h" #include "third_party/skia/include/core/SkFont.h" @@ -245,7 +246,12 @@ ALWAYS_INLINE float SimpleFontData::WidthForGlyph(Glyph glyph) const { #endif } -DEFINE_FONT_DATA_TYPE_CASTS(SimpleFontData, false); +template <> +struct DowncastTraits<SimpleFontData> { + static bool AllowFrom(const FontData& fontData) { + return !fontData.IsSegmented(); + } +}; } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_SIMPLE_FONT_DATA_H_ 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 51bdbb7510c..7537fb4d036 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 @@ -33,6 +33,7 @@ #include <memory> #include <utility> +#include "base/logging.h" #include "build/build_config.h" #include "third_party/blink/public/platform/linux/web_sandbox_support.h" #include "third_party/blink/public/platform/platform.h" @@ -245,6 +246,13 @@ sk_sp<SkTypeface> FontCache::CreateTypeface( name.c_str(), font_description.SkiaFontStyle()); } +#if !defined(OS_MACOSX) +std::vector<FontEnumerationEntry> FontCache::EnumeratePlatformAvailableFonts() { + NOTIMPLEMENTED(); + return std::vector<FontEnumerationEntry>(); +} +#endif // !defined(OS_MACOSX) + #if !defined(OS_WIN) std::unique_ptr<FontPlatformData> FontCache::CreateFontPlatformData( const FontDescription& font_description, 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 6a72122ee22..f638f1c8393 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 @@ -15,6 +15,10 @@ class SkFont; namespace blink { +// TODO: Width functions are affected by issue +// https://bugs.chromium.org/p/skia/issues/detail?id=10123 in Skia, which +// currently does not return trak-free advances on Mac OS 10.15. + void SkFontGetGlyphWidthForHarfBuzz(const SkFont&, hb_codepoint_t, hb_position_t* width); diff --git a/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc b/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc index 9b5a8ed881f..e72f801016a 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/web_font_decoder.cc @@ -30,15 +30,12 @@ #include "third_party/blink/renderer/platform/fonts/web_font_decoder.h" -#include "base/timer/elapsed_timer.h" #include "build/build_config.h" #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/web_font_typeface_factory.h" -#include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/wtf/shared_buffer.h" -#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" #include "third_party/ots/include/ots-memory-stream.h" #include "third_party/skia/include/core/SkStream.h" @@ -145,38 +142,6 @@ ots::TableAction BlinkOTSContext::GetTableAction(uint32_t tag) { } } -void RecordDecodeSpeedHistogram(const char* data, - size_t length, - double decode_time, - size_t decoded_size) { - if (decode_time <= 0) - return; - - double kb_per_second = decoded_size / (1000 * decode_time); - if (length >= 4) { - if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { - DEFINE_THREAD_SAFE_STATIC_LOCAL( - CustomCountHistogram, woff_histogram, - ("WebFont.DecodeSpeed.WOFF", 1000, 300000, 50)); - woff_histogram.Count(kb_per_second); - return; - } - - if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == '2') { - DEFINE_THREAD_SAFE_STATIC_LOCAL( - CustomCountHistogram, woff2_histogram, - ("WebFont.DecodeSpeed.WOFF2", 1000, 300000, 50)); - woff2_histogram.Count(kb_per_second); - return; - } - } - - DEFINE_THREAD_SAFE_STATIC_LOCAL( - CustomCountHistogram, sfnt_histogram, - ("WebFont.DecodeSpeed.SFNT", 1000, 300000, 50)); - sfnt_histogram.Count(kb_per_second); -} - } // namespace sk_sp<SkTypeface> WebFontDecoder::Decode(SharedBuffer* buffer) { @@ -196,14 +161,13 @@ sk_sp<SkTypeface> WebFontDecoder::Decode(SharedBuffer* buffer) { // Most web fonts are compressed, so the result can be much larger than // the original. ots::ExpandingMemoryStream output(buffer->size(), kMaxWebFontSize); - base::ElapsedTimer timer; BlinkOTSContext ots_context; SharedBuffer::DeprecatedFlatData flattened_buffer(buffer); - const char* data = flattened_buffer.Data(); TRACE_EVENT_BEGIN0("blink", "DecodeFont"); - bool ok = ots_context.Process(&output, reinterpret_cast<const uint8_t*>(data), - buffer->size()); + bool ok = ots_context.Process( + &output, reinterpret_cast<const uint8_t*>(flattened_buffer.Data()), + buffer->size()); TRACE_EVENT_END0("blink", "DecodeFont"); if (!ok) { @@ -212,9 +176,6 @@ sk_sp<SkTypeface> WebFontDecoder::Decode(SharedBuffer* buffer) { } const size_t decoded_length = SafeCast<size_t>(output.Tell()); - RecordDecodeSpeedHistogram(data, buffer->size(), timer.Elapsed().InSecondsF(), - decoded_length); - sk_sp<SkData> sk_data = SkData::MakeWithCopy(output.get(), decoded_length); sk_sp<SkTypeface> new_typeface; diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.cc index a563a80074d..9544a0ed0ab 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.cc @@ -49,12 +49,11 @@ void FallbackFamilyStyleCache::Put( String cache_key = makeCacheKey(generic_family, bcp47_language_tag, fallback_priority); - FallbackLruCache::TypefaceVector* existing_typefaces = - recent_fallback_fonts_.Get(cache_key); + TypefaceVector* existing_typefaces = recent_fallback_fonts_.Get(cache_key); if (existing_typefaces) { existing_typefaces->insert(0, sk_ref_sp(typeface)); } else { - FallbackLruCache::TypefaceVector typefaces; + TypefaceVector typefaces; typefaces.push_back(sk_ref_sp(typeface)); recent_fallback_fonts_.Put(std::move(cache_key), std::move(typefaces)); } @@ -67,7 +66,7 @@ void FallbackFamilyStyleCache::Get( UChar32 character, String* fallback_family, SkFontStyle* fallback_style) { - FallbackLruCache::TypefaceVector* typefaces = recent_fallback_fonts_.Get( + TypefaceVector* typefaces = recent_fallback_fonts_.Get( makeCacheKey(generic_family, bcp47_language_tag, fallback_priority)); if (!typefaces) return; diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.h b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.h index 5e8f86ebcf9..770702feb39 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.h +++ b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.h @@ -7,12 +7,15 @@ #include "third_party/blink/renderer/platform/fonts/font_description.h" #include "third_party/blink/renderer/platform/fonts/font_fallback_priority.h" -#include "third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win.h" +#include "third_party/blink/renderer/platform/wtf/lru_cache.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkTypeface.h" namespace blink { +using TypefaceVector = Vector<sk_sp<SkTypeface>>; +using FallbackLruCache = WTF::LruCache<String, TypefaceVector>; + class FallbackFamilyStyleCache { USING_FAST_MALLOC(FallbackFamilyStyleCache); diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win.cc deleted file mode 100644 index 37b6a152785..00000000000 --- a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 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/win/fallback_lru_cache_win.h" - -#include "third_party/blink/renderer/platform/wtf/text/string_hash.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" - -namespace blink { - -FallbackLruCache::FallbackLruCache(size_t max_size) : max_size_(max_size) { - DCHECK_GT(max_size_, 0u); -} - -FallbackLruCache::TypefaceVector* FallbackLruCache::Get(const String& key) { - HashMapType::iterator find_result = map_.find(key); - if (find_result == map_.end()) - return nullptr; - - // Move result to beginning of list. - KeyListNode* node = find_result->value.ListNode(); - ordering_.Remove(node); - ordering_.Push(node); - return find_result->value.value(); -} - -void FallbackLruCache::Put(String&& key, TypefaceVector&& arg) { - HashMapType::iterator find_result = map_.find(key); - if (find_result != map_.end()) { - ordering_.Remove(find_result->value.ListNode()); - map_.erase(find_result); - } - - if (map_.size() >= max_size_) { - RemoveLeastRecentlyUsed(); - } - - std::unique_ptr<KeyListNode> list_node = std::make_unique<KeyListNode>(key); - HashMapType::AddResult add_result = map_.insert( - std::move(key), MappedWithListNode(std::move(arg), std::move(list_node))); - DCHECK(add_result.is_new_entry); - ordering_.Push(add_result.stored_value->value.ListNode()); -} - -void FallbackLruCache::Clear() { - map_.clear(); - ordering_.Clear(); -} - -void FallbackLruCache::RemoveLeastRecentlyUsed() { - KeyListNode* tail = ordering_.Tail(); - ordering_.Remove(tail); - map_.erase(tail->key()); -} - -} // namespace blink diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win.h b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win.h deleted file mode 100644 index 90048e3319a..00000000000 --- a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2019 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/platform_export.h" -#include "third_party/blink/renderer/platform/wtf/doubly_linked_list.h" -#include "third_party/blink/renderer/platform/wtf/hash_map.h" -#include "third_party/blink/renderer/platform/wtf/hash_table_deleted_value_type.h" -#include "third_party/blink/renderer/platform/wtf/text/string_hash.h" -#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" -#include "third_party/skia/include/core/SkRefCnt.h" -#include "third_party/skia/include/core/SkTypeface.h" - -#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_WIN_FALLBACK_LRU_CACHE_WIN_H_ -#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_WIN_FALLBACK_LRU_CACHE_WIN_H_ - -namespace blink { - -/* A LRU cache for storing a a vector of typefaces for a particular key string, - * which would usually be a locale plus potential additional parameters. Uses a - * HashMap for storage and access and a DoublyLinkedList for managing age of - * entries. TODO(https://crbug.com/1010925): Potentially move this to a generic - * LRU Cache implementation once we have such in WTF. */ -class PLATFORM_EXPORT FallbackLruCache { - USING_FAST_MALLOC(FallbackLruCache); - - public: - FallbackLruCache(size_t max_size); - - using TypefaceVector = Vector<sk_sp<SkTypeface>>; - - TypefaceVector* Get(const String& key); - void Put(String&& key, TypefaceVector&& arg); - - void Clear(); - - size_t size() const { return map_.size(); } - - private: - class KeyListNode final : public DoublyLinkedListNode<KeyListNode> { - USING_FAST_MALLOC(KeyListNode); - - public: - friend class DoublyLinkedListNode<KeyListNode>; - KeyListNode(const String& key) : key_(key) {} - - const String& key() const { return key_; } - - private: - String key_; - KeyListNode* prev_{nullptr}; - KeyListNode* next_{nullptr}; - }; - - class MappedWithListNode { - USING_FAST_MALLOC(MappedWithListNode); - - public: - MappedWithListNode(TypefaceVector&& mapped_arg, - std::unique_ptr<KeyListNode>&& list_node) - : mapped_value_(std::move(mapped_arg)), - list_node_(std::move(list_node)) {} - - MappedWithListNode(WTF::HashTableDeletedValueType) { - list_node_.reset(reinterpret_cast<KeyListNode*>(-1)); - } - - TypefaceVector* value() { return &mapped_value_; } - KeyListNode* ListNode() { return list_node_.get(); } - - private: - TypefaceVector mapped_value_; - std::unique_ptr<KeyListNode> list_node_; - }; - - void RemoveLeastRecentlyUsed(); - - using HashMapType = HashMap<String, - MappedWithListNode, - DefaultHash<String>::Hash, - HashTraits<String>, - SimpleClassHashTraits<MappedWithListNode>>; - - HashMapType map_; - DoublyLinkedList<KeyListNode> ordering_; - size_t max_size_; -}; - -} // namespace blink - -#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_WIN_FALLBACK_LRU_CACHE_WIN_H_ diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win_test.cc b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win_test.cc index 92f78aa9e38..917f0111235 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win_test.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/win/fallback_lru_cache_win_test.cc @@ -2,9 +2,12 @@ // 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/win/fallback_lru_cache_win.h" +#include "third_party/blink/renderer/platform/fonts/win/fallback_family_style_cache_win.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/renderer/platform/wtf/text/character_names.h" +#include "third_party/blink/renderer/platform/wtf/text/string_hash.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/skia/include/core/SkFontMgr.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkTypeface.h" @@ -29,7 +32,7 @@ void fillCacheWithDummies(blink::FallbackLruCache& lru_cache, const char* format_string, size_t count) { for (size_t i = 0; i < count; ++i) { - blink::FallbackLruCache::TypefaceVector dummy_typefaces; + blink::TypefaceVector dummy_typefaces; dummy_typefaces.push_back( SkTypeface::MakeFromName(kFontFamilyNameArial, SkFontStyle())); lru_cache.Put(String::Format(format_string, i), std::move(dummy_typefaces)); @@ -48,7 +51,7 @@ TEST(FallbackLruCacheTest, KeepChineseWhenFetched) { // the Chinese font and ensure it's gone. FallbackLruCache lru_cache(kLruCacheTestSize); EXPECT_EQ(lru_cache.size(), 0u); - FallbackLruCache::TypefaceVector fallback_typefaces_zh; + TypefaceVector fallback_typefaces_zh; fallback_typefaces_zh.push_back( fallbackForLocale(kHanSimplifiedLocale, kFirstCJKIdeograph)); lru_cache.Put(kHanSimplifiedLocale, std::move(fallback_typefaces_zh)); @@ -56,8 +59,7 @@ TEST(FallbackLruCacheTest, KeepChineseWhenFetched) { EXPECT_EQ(lru_cache.size(), 1u); fillCacheWithDummies(lru_cache, "dummy_locale_%zu", kLruCacheTestSize - 1); - FallbackLruCache::TypefaceVector* chinese_typefaces = - lru_cache.Get(kHanSimplifiedLocale); + TypefaceVector* chinese_typefaces = lru_cache.Get(kHanSimplifiedLocale); EXPECT_TRUE(chinese_typefaces); EXPECT_TRUE(chinese_typefaces->at(0)->unicharToGlyph(0x4E01)); EXPECT_EQ(lru_cache.size(), kLruCacheTestSize); diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc index 821a6a7afc3..52427643b20 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_cache_skia_win.cc @@ -42,7 +42,7 @@ #include "base/debug/alias.h" #include "base/stl_util.h" #include "base/trace_event/trace_event.h" -#include "third_party/blink/public/platform/interface_provider.h" +#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/fonts/bitmap_glyphs_block_list.h" #include "third_party/blink/renderer/platform/fonts/font_description.h" @@ -229,7 +229,7 @@ void FontCache::SetStatusFontMetrics(const wchar_t* family_name, void FontCache::EnsureServiceConnected() { if (service_) return; - Platform::Current()->GetInterfaceProvider()->GetInterface( + Platform::Current()->GetBrowserInterfaceBroker()->GetInterface( service_.BindNewPipeAndPassReceiver()); } diff --git a/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc index 52555021f7b..13162712b2e 100644 --- a/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc +++ b/chromium/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc @@ -9,8 +9,8 @@ #include "base/files/file_path.h" #include "mojo/public/mojom/base/shared_memory.mojom-blink.h" +#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" #include "third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom-blink.h" -#include "third_party/blink/public/platform/interface_provider.h" #include "third_party/blink/public/platform/platform.h" #include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" @@ -165,7 +165,7 @@ bool FontUniqueNameLookupWin::IsFontUniqueNameLookupReadyForSyncLookup() { void FontUniqueNameLookupWin::EnsureServiceConnected() { if (service_) return; - Platform::Current()->GetInterfaceProvider()->GetInterface( + Platform::Current()->GetBrowserInterfaceBroker()->GetInterface( service_.BindNewPipeAndPassReceiver()); } |