lang=zh needs to defer to system preferences to know whether it should be simplified...
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Jun 2020 17:15:34 +0000 (17:15 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Jun 2020 17:15:34 +0000 (17:15 +0000)
https://bugs.webkit.org/show_bug.cgi?id=212626
<rdar://problem/60227623>

Reviewed by Darin Adler.

Source/WebCore:

If the content says lang="zh" font-family: sans-serif, we have no signal for whether
the content should be traditional or simplified. In this case, we should pick based
on system preferences to make it more likely that we get the right answer.

This is actually what some Cocoa platform text functions were doing, but not all of them.
We need to do it at our level in WebKit to make sure that all our calls to the platform
have consistent behavior. Also, we can cache the result at our level, which is more
performant than if the platform cached it at each platform entry point.

We already started consulting with system preferences to make this decision in r189038.
This patch extends that and fixes it to throughout WebKit.

This doesn't expose any new fingerprinting data, because this information was already
exposed (e.g. by drawing fallback fonts to the canvas and then reading back the pixels).

Tests: fast/text/locale-getComputedStyle.html
       fast/text/international/generic-font-family-language-traditional.html

* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
* css/CSSFontSelector.cpp:
(WebCore::resolveGenericFamily):
* css/CSSProperties.json:
* layout/inlineformatting/InlineLineBreaker.cpp:
(WebCore::Layout::LineBreaker::wordBreakBehavior const):
(WebCore::Layout::LineBreaker::tryBreakingTextRun const):
* platform/graphics/Font.cpp:
(WebCore::Font::systemFallbackFontForCharacter const):
* platform/graphics/FontCache.h:
(WebCore::FontDescriptionKey::FontDescriptionKey):
* platform/graphics/FontCascade.cpp:
(WebCore::FontCascade::widthForSimpleText const):
* platform/graphics/FontCascadeDescription.cpp:
* platform/graphics/FontCascadeDescription.h:
(WebCore::FontCascadeDescription::initialSpecifiedLocale):
(WebCore::FontCascadeDescription::initialLocale): Deleted.
* platform/graphics/FontDescription.cpp:
(WebCore::computeSpecializedChineseLocale):
(WebCore::cachedSpecializedChineseLocale):
(WebCore::fontDescriptionLanguageChanged):
(WebCore::specializedChineseLocale):
(WebCore::FontDescription::setSpecifiedLocale):
(WebCore::FontDescription::setLocale): Deleted.
* platform/graphics/FontDescription.h:
(WebCore::FontDescription::computedLocale const):
(WebCore::FontDescription::specifiedLocale const):
(WebCore::FontDescription::operator== const):
(WebCore::FontDescription::encode const):
(WebCore::FontDescription::decode):
(WebCore::FontDescription::locale const): Deleted.
* platform/graphics/WidthIterator.cpp:
(WebCore::WidthIterator::applyFontTransforms):
* platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::FontCache::systemFallbackForCharacters):
* platform/graphics/cocoa/FontDescriptionCocoa.cpp:
(WebCore::FontDescription::platformResolveGenericFamily):
(WebCore::computeSpecializedChineseLocale): Deleted.
(WebCore::cachedSpecializedChineseLocale): Deleted.
(WebCore::languageChanged): Deleted.
* platform/graphics/cocoa/SystemFontDatabaseCoreText.cpp:
(WebCore::SystemFontDatabaseCoreText::systemFontParameters):
* platform/graphics/mac/ComplexTextControllerCoreText.mm:
(WebCore::ComplexTextController::collectComplexTextRunsForCharacters):
* rendering/RenderQuote.cpp:
(WebCore::RenderQuote::computeText const):
* rendering/RenderText.cpp:
(WebCore::maxWordFragmentWidth):
(WebCore::RenderText::computePreferredLogicalWidths):
(WebCore::applyTextTransform):
* rendering/RenderThemeCocoa.mm:
(WebCore::RenderThemeCocoa::paintApplePayButton):
* rendering/SimpleLineLayoutTextFragmentIterator.cpp:
(WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
(WebCore::SimpleLineLayout::TextFragmentIterator::TextFragmentIterator):
* rendering/line/BreakingContext.h:
(WebCore::BreakingContext::handleText):
* rendering/style/RenderStyle.h:
(WebCore::RenderStyle::computedLocale const):
(WebCore::RenderStyle::specifiedLocale const):
(WebCore::RenderStyle::locale const): Deleted.
* style/StyleBuilderCustom.h:
(WebCore::Style::BuilderCustom::applyValueWebkitLocale):
* style/StyleResolveForDocument.cpp:
(WebCore::Style::resolveForDocument):

LayoutTests:

Make sure the new locale isn't exposed.

* fast/text/locale-getComputedStyle-expected.txt: Added.
* fast/text/locale-getComputedStyle.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262796 268f45cc-cd09-0410-ab3c-d52691b4dbfc

28 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text/locale-getComputedStyle-expected.txt [new file with mode: 0644]
LayoutTests/fast/text/locale-getComputedStyle.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSFontSelector.cpp
Source/WebCore/css/CSSProperties.json
Source/WebCore/layout/inlineformatting/InlineLineBreaker.cpp
Source/WebCore/platform/graphics/Font.cpp
Source/WebCore/platform/graphics/FontCache.h
Source/WebCore/platform/graphics/FontCascade.cpp
Source/WebCore/platform/graphics/FontCascadeDescription.cpp
Source/WebCore/platform/graphics/FontCascadeDescription.h
Source/WebCore/platform/graphics/FontDescription.cpp
Source/WebCore/platform/graphics/FontDescription.h
Source/WebCore/platform/graphics/WidthIterator.cpp
Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
Source/WebCore/platform/graphics/cocoa/FontDescriptionCocoa.cpp
Source/WebCore/platform/graphics/cocoa/SystemFontDatabaseCoreText.cpp
Source/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.mm
Source/WebCore/rendering/RenderQuote.cpp
Source/WebCore/rendering/RenderText.cpp
Source/WebCore/rendering/RenderThemeCocoa.mm
Source/WebCore/rendering/SimpleLineLayoutTextFragmentIterator.cpp
Source/WebCore/rendering/line/BreakingContext.h
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/style/StyleBuilderCustom.h
Source/WebCore/style/StyleResolveForDocument.cpp

index 1459dac..9f17389 100644 (file)
@@ -1,3 +1,16 @@
+2020-06-09  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        lang=zh needs to defer to system preferences to know whether it should be simplified or traditional
+        https://bugs.webkit.org/show_bug.cgi?id=212626
+        <rdar://problem/60227623>
+
+        Reviewed by Darin Adler.
+
+        Make sure the new locale isn't exposed.
+
+        * fast/text/locale-getComputedStyle-expected.txt: Added.
+        * fast/text/locale-getComputedStyle.html: Added.
+
 2020-06-09  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][TFC] Add support for empty table
diff --git a/LayoutTests/fast/text/locale-getComputedStyle-expected.txt b/LayoutTests/fast/text/locale-getComputedStyle-expected.txt
new file mode 100644 (file)
index 0000000..7cec104
--- /dev/null
@@ -0,0 +1,10 @@
+This test makes sure that lang='zh' round-trips through getComputedStyle.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.getComputedStyle(target).getPropertyValue('-webkit-locale') is "zh"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/text/locale-getComputedStyle.html b/LayoutTests/fast/text/locale-getComputedStyle.html
new file mode 100644 (file)
index 0000000..14f591b
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/js-test.js"></script>
+</head>
+<body>
+<div lang="zh" id="target"></div>
+<script>
+description("This test makes sure that lang='zh' round-trips through getComputedStyle.");
+let target = document.getElementById("target");
+shouldBeEqualToString("window.getComputedStyle(target).getPropertyValue('-webkit-locale')", "zh");
+</script>
+</body>
+</html>
index 61bf063..94a04e2 100644 (file)
@@ -1,3 +1,96 @@
+2020-06-09  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        lang=zh needs to defer to system preferences to know whether it should be simplified or traditional
+        https://bugs.webkit.org/show_bug.cgi?id=212626
+        <rdar://problem/60227623>
+
+        Reviewed by Darin Adler.
+
+        If the content says lang="zh" font-family: sans-serif, we have no signal for whether
+        the content should be traditional or simplified. In this case, we should pick based
+        on system preferences to make it more likely that we get the right answer.
+
+        This is actually what some Cocoa platform text functions were doing, but not all of them.
+        We need to do it at our level in WebKit to make sure that all our calls to the platform
+        have consistent behavior. Also, we can cache the result at our level, which is more
+        performant than if the platform cached it at each platform entry point.
+
+        We already started consulting with system preferences to make this decision in r189038.
+        This patch extends that and fixes it to throughout WebKit.
+
+        This doesn't expose any new fingerprinting data, because this information was already
+        exposed (e.g. by drawing fallback fonts to the canvas and then reading back the pixels).
+
+        Tests: fast/text/locale-getComputedStyle.html
+               fast/text/international/generic-font-family-language-traditional.html
+
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::valueForPropertyInStyle):
+        * css/CSSFontSelector.cpp:
+        (WebCore::resolveGenericFamily):
+        * css/CSSProperties.json:
+        * layout/inlineformatting/InlineLineBreaker.cpp:
+        (WebCore::Layout::LineBreaker::wordBreakBehavior const):
+        (WebCore::Layout::LineBreaker::tryBreakingTextRun const):
+        * platform/graphics/Font.cpp:
+        (WebCore::Font::systemFallbackFontForCharacter const):
+        * platform/graphics/FontCache.h:
+        (WebCore::FontDescriptionKey::FontDescriptionKey):
+        * platform/graphics/FontCascade.cpp:
+        (WebCore::FontCascade::widthForSimpleText const):
+        * platform/graphics/FontCascadeDescription.cpp:
+        * platform/graphics/FontCascadeDescription.h:
+        (WebCore::FontCascadeDescription::initialSpecifiedLocale):
+        (WebCore::FontCascadeDescription::initialLocale): Deleted.
+        * platform/graphics/FontDescription.cpp:
+        (WebCore::computeSpecializedChineseLocale):
+        (WebCore::cachedSpecializedChineseLocale):
+        (WebCore::fontDescriptionLanguageChanged):
+        (WebCore::specializedChineseLocale):
+        (WebCore::FontDescription::setSpecifiedLocale):
+        (WebCore::FontDescription::setLocale): Deleted.
+        * platform/graphics/FontDescription.h:
+        (WebCore::FontDescription::computedLocale const):
+        (WebCore::FontDescription::specifiedLocale const):
+        (WebCore::FontDescription::operator== const):
+        (WebCore::FontDescription::encode const):
+        (WebCore::FontDescription::decode):
+        (WebCore::FontDescription::locale const): Deleted.
+        * platform/graphics/WidthIterator.cpp:
+        (WebCore::WidthIterator::applyFontTransforms):
+        * platform/graphics/cocoa/FontCacheCoreText.cpp:
+        (WebCore::FontCache::systemFallbackForCharacters):
+        * platform/graphics/cocoa/FontDescriptionCocoa.cpp:
+        (WebCore::FontDescription::platformResolveGenericFamily):
+        (WebCore::computeSpecializedChineseLocale): Deleted.
+        (WebCore::cachedSpecializedChineseLocale): Deleted.
+        (WebCore::languageChanged): Deleted.
+        * platform/graphics/cocoa/SystemFontDatabaseCoreText.cpp:
+        (WebCore::SystemFontDatabaseCoreText::systemFontParameters):
+        * platform/graphics/mac/ComplexTextControllerCoreText.mm:
+        (WebCore::ComplexTextController::collectComplexTextRunsForCharacters):
+        * rendering/RenderQuote.cpp:
+        (WebCore::RenderQuote::computeText const):
+        * rendering/RenderText.cpp:
+        (WebCore::maxWordFragmentWidth):
+        (WebCore::RenderText::computePreferredLogicalWidths):
+        (WebCore::applyTextTransform):
+        * rendering/RenderThemeCocoa.mm:
+        (WebCore::RenderThemeCocoa::paintApplePayButton):
+        * rendering/SimpleLineLayoutTextFragmentIterator.cpp:
+        (WebCore::SimpleLineLayout::TextFragmentIterator::Style::Style):
+        (WebCore::SimpleLineLayout::TextFragmentIterator::TextFragmentIterator):
+        * rendering/line/BreakingContext.h:
+        (WebCore::BreakingContext::handleText):
+        * rendering/style/RenderStyle.h:
+        (WebCore::RenderStyle::computedLocale const):
+        (WebCore::RenderStyle::specifiedLocale const):
+        (WebCore::RenderStyle::locale const): Deleted.
+        * style/StyleBuilderCustom.h:
+        (WebCore::Style::BuilderCustom::applyValueWebkitLocale):
+        * style/StyleResolveForDocument.cpp:
+        (WebCore::Style::resolveForDocument):
+
 2020-06-09  Zalan Bujtas  <zalan@apple.com>
 
         [LFC][TFC] Add support for empty table
index 61b802a..5bba3a8 100644 (file)
@@ -2954,9 +2954,9 @@ RefPtr<CSSValue> ComputedStyleExtractor::valueForPropertyInStyle(const RenderSty
         case CSSPropertyListStyleType:
             return cssValuePool.createValue(style.listStyleType());
         case CSSPropertyWebkitLocale:
-            if (style.locale().isNull())
+            if (style.specifiedLocale().isNull())
                 return cssValuePool.createIdentifierValue(CSSValueAuto);
-            return cssValuePool.createValue(style.locale(), CSSUnitType::CSS_STRING);
+            return cssValuePool.createValue(style.specifiedLocale(), CSSUnitType::CSS_STRING);
         case CSSPropertyMarginTop:
             return zoomAdjustedPaddingOrMarginPixelValue<&RenderStyle::marginTop, &RenderBoxModelObject::marginTop>(style, renderer);
         case CSSPropertyMarginRight: {
index 6726c7b..7b8b88e 100644 (file)
@@ -265,7 +265,7 @@ void CSSFontSelector::fontCacheInvalidated()
 
 static Optional<AtomString> resolveGenericFamily(Document* document, const FontDescription& fontDescription, const AtomString& familyName)
 {
-    auto platformResult = FontDescription::platformResolveGenericFamily(fontDescription.script(), fontDescription.locale(), familyName);
+    auto platformResult = FontDescription::platformResolveGenericFamily(fontDescription.script(), fontDescription.computedLocale(), familyName);
     if (!platformResult.isNull())
         return platformResult;
 
index c904b86..c7834bb 100644 (file)
             "codegen-properties": {
                 "custom": "Value",
                 "font-property": true,
-                "high-priority": true
+                "high-priority": true,
+                "name-for-methods": "SpecifiedLocale"
             },
             "status": "non-standard"
         },
index 061f4b0..a500fba 100644 (file)
@@ -289,7 +289,7 @@ LineBreaker::WordBreakRule LineBreaker::wordBreakBehavior(const RenderStyle& sty
     if (style.overflowWrap() == OverflowWrap::Break && !m_hasWrapOpportunityAtPreviousPosition)
         return WordBreakRule::AtArbitraryPosition;
 
-    if (!n_hyphenationIsDisabled && style.hyphens() == Hyphens::Auto && canHyphenate(style.locale()))
+    if (!n_hyphenationIsDisabled && style.hyphens() == Hyphens::Auto && canHyphenate(style.computedLocale()))
         return WordBreakRule::OnlyHyphenationAllowed;
 
     return WordBreakRule::NoBreak;
@@ -339,7 +339,7 @@ Optional<LineBreaker::PartialRun> LineBreaker::tryBreakingTextRun(const Run& ove
             return { };
         // Adjust before index to accommodate the limit-after value (it's the last potential hyphen location in this run).
         auto hyphenBefore = std::min(leftSideLength, runLength - limitAfter) + 1;
-        unsigned hyphenLocation = lastHyphenLocation(StringView(inlineTextItem.inlineTextBox().content()).substring(inlineTextItem.start(), inlineTextItem.length()), hyphenBefore, style.locale());
+        unsigned hyphenLocation = lastHyphenLocation(StringView(inlineTextItem.inlineTextBox().content()).substring(inlineTextItem.start(), inlineTextItem.length()), hyphenBefore, style.computedLocale());
         if (!hyphenLocation || hyphenLocation < limitBefore)
             return { };
         // hyphenLocation is relative to the start of this InlineItemText.
index 72358ca..8b61fd0 100644 (file)
@@ -581,7 +581,7 @@ RefPtr<Font> Font::systemFallbackFontForCharacter(UChar32 character, const FontD
         return FontCache::singleton().systemFallbackForCharacters(description, this, isForPlatformFont, FontCache::PreferColoredFont::No, &codeUnit, 1);
     }
 
-    auto key = CharacterFallbackMapKey(description.locale(), character, isForPlatformFont);
+    auto key = CharacterFallbackMapKey(description.computedLocale(), character, isForPlatformFont);
     auto characterAddResult = fontAddResult.iterator->value.add(WTFMove(key), nullptr);
 
     Font*& fallbackFont = characterAddResult.iterator->value;
index 266cb66..546282d 100644 (file)
@@ -78,7 +78,7 @@ struct FontDescriptionKey {
         : m_size(description.computedPixelSize())
         , m_fontSelectionRequest(description.fontSelectionRequest())
         , m_flags(makeFlagsKey(description))
-        , m_locale(description.locale())
+        , m_locale(description.specifiedLocale())
         , m_featureSettings(description.featureSettings())
 #if ENABLE(VARIATION_FONTS)
         , m_variationSettings(description.variationSettings())
@@ -157,7 +157,6 @@ private:
         return {{ first, second }};
     }
 
-    // FontCascade::locale() is explicitly not included in this struct.
     bool m_isDeletedValue { false };
     unsigned m_size { 0 };
     FontSelectionRequest m_fontSelectionRequest;
index 93103cf..691a3e1 100644 (file)
@@ -440,7 +440,7 @@ float FontCascade::widthForSimpleText(StringView text) const
         glyphBuffer.add(glyph, &font, glyphWidth);
     }
     if (hasKerningOrLigatures) {
-        font.applyTransforms(glyphBuffer, 0, enableKerning(), requiresShaping(), fontDescription().locale());
+        font.applyTransforms(glyphBuffer, 0, enableKerning(), requiresShaping(), fontDescription().computedLocale());
         // This is needed only to match the result of the slow path. Same glyph widths but different floating point arithmentics can
         // produce different run width.
         float runWidthDifferenceWithTransformApplied = -runWidth;
index 8eb4471..14a96f7 100644 (file)
@@ -42,6 +42,7 @@ struct SameSizeAsFontCascadeDescription {
     char c;
 #endif
     AtomString string;
+    AtomString string2;
     int16_t fontSelectionRequest[3];
     float size;
     unsigned bitfields1;
index 5b04052..0a7df25 100644 (file)
@@ -132,7 +132,7 @@ public:
     static FontVariantCaps initialVariantCaps() { return FontVariantCaps::Normal; }
     static FontVariantAlternates initialVariantAlternates() { return FontVariantAlternates::Normal; }
     static FontOpticalSizing initialOpticalSizing() { return FontOpticalSizing::Enabled; }
-    static const AtomString& initialLocale() { return nullAtom(); }
+    static const AtomString& initialSpecifiedLocale() { return nullAtom(); }
 
 private:
     RefCountedArray<AtomString> m_families { 1 };
index 8a924f9..99c57f4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Nicholas Shanks <contact@nickshanks.com>
- * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2013 - 2020 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,6 +32,7 @@
 
 #include "FontCascadeDescription.h"
 #include "LocaleToScriptMapping.h"
+#include <wtf/Language.h>
 
 namespace WebCore {
 
@@ -65,10 +66,42 @@ FontDescription::FontDescription()
 {
 }
 
-void FontDescription::setLocale(const AtomString& locale)
+static AtomString computeSpecializedChineseLocale()
 {
-    m_locale = locale;
-    m_script = localeToScriptCodeForFontSelection(m_locale);
+    for (auto& language : userPreferredLanguages()) {
+        if (startsWithLettersIgnoringASCIICase(language, "zh-"))
+            return language;
+    }
+    return AtomString("zh-hans", AtomString::ConstructFromLiteral); // We have no signal. Pick one option arbitrarily.
+}
+
+static AtomString& cachedSpecializedChineseLocale()
+{
+    static NeverDestroyed<AtomString> specializedChineseLocale;
+    return specializedChineseLocale.get();
+}
+
+static void fontDescriptionLanguageChanged(void*)
+{
+    cachedSpecializedChineseLocale() = computeSpecializedChineseLocale();
+}
+
+static const AtomString& specializedChineseLocale()
+{
+    auto& locale = cachedSpecializedChineseLocale();
+    if (cachedSpecializedChineseLocale().isNull()) {
+        static char forNonNullPointer;
+        addLanguageChangeObserver(&forNonNullPointer, &fontDescriptionLanguageChanged); // We will never remove the observer, so all we need is a non-null pointer.
+        fontDescriptionLanguageChanged(nullptr);
+    }
+    return locale;
+}
+
+void FontDescription::setSpecifiedLocale(const AtomString& locale)
+{
+    m_specifiedLocale = locale;
+    m_script = localeToScriptCodeForFontSelection(m_specifiedLocale);
+    m_locale = m_script == USCRIPT_HAN ? specializedChineseLocale() : m_specifiedLocale;
 }
 
 #if !PLATFORM(COCOA)
index 1e6fc74..fd5f2c1 100644 (file)
@@ -51,7 +51,8 @@ public:
     FontRenderingMode renderingMode() const { return static_cast<FontRenderingMode>(m_renderingMode); }
     TextRenderingMode textRenderingMode() const { return static_cast<TextRenderingMode>(m_textRendering); }
     UScriptCode script() const { return static_cast<UScriptCode>(m_script); }
-    const AtomString& locale() const { return m_locale; }
+    const AtomString& computedLocale() const { return m_locale; } // This is what you should be using for things like text shaping and font fallback
+    const AtomString& specifiedLocale() const { return m_specifiedLocale; } // This is what you should be using for web-exposed things like -webkit-locale
 
     FontOrientation orientation() const { return static_cast<FontOrientation>(m_orientation); }
     NonCJKGlyphOrientation nonCJKGlyphOrientation() const { return static_cast<NonCJKGlyphOrientation>(m_nonCJKGlyphOrientation); }
@@ -106,7 +107,7 @@ public:
     void setOrientation(FontOrientation orientation) { m_orientation = static_cast<unsigned>(orientation); }
     void setNonCJKGlyphOrientation(NonCJKGlyphOrientation orientation) { m_nonCJKGlyphOrientation = static_cast<unsigned>(orientation); }
     void setWidthVariant(FontWidthVariant widthVariant) { m_widthVariant = static_cast<unsigned>(widthVariant); } // Make sure new callers of this sync with FontPlatformData::isForTextCombine()!
-    WEBCORE_EXPORT void setLocale(const AtomString&);
+    WEBCORE_EXPORT void setSpecifiedLocale(const AtomString&);
     void setFeatureSettings(FontFeatureSettings&& settings) { m_featureSettings = WTFMove(settings); }
 #if ENABLE(VARIATION_FONTS)
     void setVariationSettings(FontVariationSettings&& settings) { m_variationSettings = WTFMove(settings); }
@@ -144,6 +145,7 @@ private:
     FontFeatureSettings m_featureSettings;
     FontVariationSettings m_variationSettings;
     AtomString m_locale;
+    AtomString m_specifiedLocale;
 
     FontSelectionRequest m_fontSelectionRequest;
     float m_computedSize { 0 }; // Computed size adjusted for the minimum font size and the zoom factor.
@@ -183,7 +185,7 @@ inline bool FontDescription::operator==(const FontDescription& other) const
         && m_orientation == other.m_orientation
         && m_nonCJKGlyphOrientation == other.m_nonCJKGlyphOrientation
         && m_widthVariant == other.m_widthVariant
-        && m_locale == other.m_locale
+        && m_specifiedLocale == other.m_specifiedLocale
         && m_featureSettings == other.m_featureSettings
 #if ENABLE(VARIATION_FONTS)
         && m_variationSettings == other.m_variationSettings
@@ -216,7 +218,7 @@ void FontDescription::encode(Encoder& encoder) const
 #if ENABLE(VARIATION_FONTS)
     encoder << variationSettings();
 #endif
-    encoder << locale();
+    encoder << computedLocale();
     encoder << italic();
     encoder << stretch();
     encoder << weight();
@@ -412,7 +414,7 @@ Optional<FontDescription> FontDescription::decode(Decoder& decoder)
 #if ENABLE(VARIATION_FONTS)
     fontDescription.setVariationSettings(WTFMove(*variationSettings));
 #endif
-    fontDescription.setLocale(*locale);
+    fontDescription.setSpecifiedLocale(*locale);
     fontDescription.setItalic(*italic);
     fontDescription.setStretch(*stretch);
     fontDescription.setWeight(*weight);
index 89fb950..e3007da 100644 (file)
@@ -113,7 +113,7 @@ inline float WidthIterator::applyFontTransforms(GlyphBuffer* glyphBuffer, bool l
     if (!ltr)
         glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount);
 
-    font->applyTransforms(*glyphBuffer, lastGlyphCount, m_enableKerning, m_requiresShaping, m_font->fontDescription().locale());
+    font->applyTransforms(*glyphBuffer, lastGlyphCount, m_enableKerning, m_requiresShaping, m_font->fontDescription().computedLocale());
     glyphBufferSize = glyphBuffer->size();
 
     for (unsigned i = lastGlyphCount; i < glyphBufferSize; ++i)
index f8cdb4a..aa8c52f 100644 (file)
@@ -1465,7 +1465,7 @@ RefPtr<Font> FontCache::systemFallbackForCharacters(const FontDescription& descr
     if (!fullName.isEmpty())
         m_fontNamesRequiringSystemFallbackForPrewarming.add(fullName);
 
-    auto result = lookupFallbackFont(platformData.font(), description.weight(), description.locale(), description.shouldAllowUserInstalledFonts(), characters, length);
+    auto result = lookupFallbackFont(platformData.font(), description.weight(), description.computedLocale(), description.shouldAllowUserInstalledFonts(), characters, length);
     result = preparePlatformFont(result.get(), description, nullptr, { });
 
     if (!result)
index abc59a4..517a7e9 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "SystemFontDatabaseCoreText.h"
 #include <mutex>
-#include <wtf/Language.h>
 
 namespace WebCore {
 
@@ -145,54 +144,23 @@ FontFamilySpecification FontCascadeDescription::effectiveFamilyAt(unsigned index
 
 #endif // USE(PLATFORM_SYSTEM_FALLBACK_LIST)
 
-static String computeSpecializedChineseLocale()
-{
-    const Vector<String>& preferredLanguages = userPreferredLanguages();
-    for (auto& language : preferredLanguages) {
-        if (equalIgnoringASCIICase(language, "zh") || startsWithLettersIgnoringASCIICase(language, "zh-"))
-            return language;
-    }
-    return "zh-hans"_str; // We have no signal. Pick one option arbitrarily.
-}
-
-static String& cachedSpecializedChineseLocale()
-{
-    static NeverDestroyed<String> specializedChineseLocale;
-    return specializedChineseLocale.get();
-}
-
-static void languageChanged(void*)
-{
-    cachedSpecializedChineseLocale() = computeSpecializedChineseLocale();
-}
-
 AtomString FontDescription::platformResolveGenericFamily(UScriptCode script, const AtomString& locale, const AtomString& familyName)
 {
     ASSERT((locale.isNull() && script == USCRIPT_COMMON) || !locale.isNull());
     if (script == USCRIPT_COMMON)
         return nullAtom();
 
-    static std::once_flag onceFlag;
-    std::call_once(onceFlag, [&] {
-        static char dummy;
-        addLanguageChangeObserver(&dummy, &languageChanged); // We will never remove the observer, so all we need is a non-null pointer.
-        languageChanged(nullptr);
-    });
-
-    // FIXME: Delete this once <rdar://problem/47682577> is fixed.
-    auto& usedLocale = script == USCRIPT_HAN ? cachedSpecializedChineseLocale() : locale.string();
-
     // FIXME: Use the system font database to handle standardFamily
     if (familyName == serifFamily)
-        return SystemFontDatabaseCoreText::singleton().serifFamily(usedLocale);
+        return SystemFontDatabaseCoreText::singleton().serifFamily(locale.string());
     if (familyName == sansSerifFamily)
-        return SystemFontDatabaseCoreText::singleton().sansSerifFamily(usedLocale);
+        return SystemFontDatabaseCoreText::singleton().sansSerifFamily(locale.string());
     if (familyName == cursiveFamily)
-        return SystemFontDatabaseCoreText::singleton().cursiveFamily(usedLocale);
+        return SystemFontDatabaseCoreText::singleton().cursiveFamily(locale.string());
     if (familyName == fantasyFamily)
-        return SystemFontDatabaseCoreText::singleton().fantasyFamily(usedLocale);
+        return SystemFontDatabaseCoreText::singleton().fantasyFamily(locale.string());
     if (familyName == monospaceFamily)
-        return SystemFontDatabaseCoreText::singleton().monospaceFamily(usedLocale);
+        return SystemFontDatabaseCoreText::singleton().monospaceFamily(locale.string());
 
     return nullAtom();
 }
index 2fb89c4..2f0b44f 100644 (file)
@@ -183,7 +183,7 @@ Vector<RetainPtr<CTFontDescriptorRef>> SystemFontDatabaseCoreText::computeCascad
 SystemFontDatabaseCoreText::CascadeListParameters SystemFontDatabaseCoreText::systemFontParameters(const FontDescription& description, const AtomString& familyName, SystemFontKind systemFontKind, AllowUserInstalledFonts allowUserInstalledFonts)
 {
     CascadeListParameters result;
-    result.locale = description.locale();
+    result.locale = description.computedLocale();
     result.size = description.computedSize();
     result.italic = isItalic(description.italic());
     result.allowUserInstalledFonts = allowUserInstalledFonts;
index 07ade6b..6ff0e02 100644 (file)
@@ -128,11 +128,11 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp,
         font = m_font.fallbackRangesAt(0).fontForCharacter(baseCharacter);
         if (!font)
             font = &m_font.fallbackRangesAt(0).fontForFirstRange();
-        stringAttributes = adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, font->getCFStringAttributes(m_font.enableKerning(), font->platformData().orientation(), m_font.fontDescription().locale()).get()));
+        stringAttributes = adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, font->getCFStringAttributes(m_font.enableKerning(), font->platformData().orientation(), m_font.fontDescription().computedLocale()).get()));
         // We don't know which font should be used to render this grapheme cluster, so enable CoreText's fallback mechanism by using the CTFont which doesn't have CoreText's fallback disabled.
         CFDictionarySetValue(const_cast<CFMutableDictionaryRef>(stringAttributes.get()), kCTFontAttributeName, font->platformData().font());
     } else
-        stringAttributes = font->getCFStringAttributes(m_font.enableKerning(), font->platformData().orientation(), m_font.fontDescription().locale());
+        stringAttributes = font->getCFStringAttributes(m_font.enableKerning(), font->platformData().orientation(), m_font.fontDescription().computedLocale());
 
     RetainPtr<CTLineRef> line;
 
index 676c112..bbcb5be 100644 (file)
@@ -380,7 +380,7 @@ String RenderQuote::computeText() const
     case QuoteType::CloseQuote:
         if (const QuotesData* quotes = style().quotes())
             return isOpenQuote ? quotes->openQuote(m_depth).impl() : quotes->closeQuote(m_depth).impl();
-        if (const QuotesForLanguage* quotes = quotesForLanguage(style().locale()))
+        if (const QuotesForLanguage* quotes = quotesForLanguage(style().specifiedLocale()))
             return stringForQuoteCharacter(isOpenQuote ? (m_depth ? quotes->open2 : quotes->open1) : (m_depth ? quotes->close2 : quotes->close1));
         // FIXME: Should the default be the quotes for "en" rather than straight quotes?
         return m_depth ? apostropheString() : quotationMarkString();
index 1ccf967..e9fce88 100644 (file)
@@ -739,7 +739,7 @@ static float maxWordFragmentWidth(RenderText& renderer, const RenderStyle& style
     Vector<int, 8> hyphenLocations;
     ASSERT(word.length() >= minimumSuffixLength);
     unsigned hyphenLocation = word.length() - minimumSuffixLength;
-    while ((hyphenLocation = lastHyphenLocation(word, hyphenLocation, style.locale())) >= std::max(minimumPrefixLength, 1U))
+    while ((hyphenLocation = lastHyphenLocation(word, hyphenLocation, style.computedLocale())) >= std::max(minimumPrefixLength, 1U))
         hyphenLocations.append(hyphenLocation);
 
     if (hyphenLocations.isEmpty())
@@ -793,7 +793,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Fo
     auto& string = text();
     unsigned length = string.length();
     auto iteratorMode = mapLineBreakToIteratorMode(style.lineBreak());
-    LazyLineBreakIterator breakIterator(string, style.locale(), iteratorMode);
+    LazyLineBreakIterator breakIterator(string, style.computedLocale(), iteratorMode);
     bool needsWordSpacing = false;
     bool ignoringSpaces = false;
     bool isSpace = false;
@@ -808,7 +808,7 @@ void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Fo
     float maxWordWidth = std::numeric_limits<float>::max();
     unsigned minimumPrefixLength = 0;
     unsigned minimumSuffixLength = 0;
-    if (style.hyphens() == Hyphens::Auto && canHyphenate(style.locale())) {
+    if (style.hyphens() == Hyphens::Auto && canHyphenate(style.computedLocale())) {
         maxWordWidth = 0;
 
         // Map 'hyphenate-limit-{before,after}: auto;' to 2.
@@ -1143,9 +1143,9 @@ String applyTextTransform(const RenderStyle& style, const String& text, UChar pr
     case TextTransform::Capitalize:
         return capitalize(text, previousCharacter); // FIXME: Need to take locale into account.
     case TextTransform::Uppercase:
-        return text.convertToUppercaseWithLocale(style.locale());
+        return text.convertToUppercaseWithLocale(style.computedLocale());
     case TextTransform::Lowercase:
-        return text.convertToLowercaseWithLocale(style.locale());
+        return text.convertToLowercaseWithLocale(style.computedLocale());
     }
     ASSERT_NOT_REACHED();
     return text;
index 12a9da2..ffb0fb1 100644 (file)
@@ -137,7 +137,7 @@ bool RenderThemeCocoa::paintApplePayButton(const RenderObject& renderer, const P
         floatValueForLength(style.borderBottomRightRadius().width, paintRect.width())
     });
 
-    PKDrawApplePayButtonWithCornerRadius(paintInfo.context().platformContext(), CGRectMake(paintRect.x(), -paintRect.maxY(), paintRect.width(), paintRect.height()), 1.0, largestCornerRadius, toPKPaymentButtonType(style.applePayButtonType()), toPKPaymentButtonStyle(style.applePayButtonStyle()), style.locale());
+    PKDrawApplePayButtonWithCornerRadius(paintInfo.context().platformContext(), CGRectMake(paintRect.x(), -paintRect.maxY(), paintRect.width(), paintRect.height()), 1.0, largestCornerRadius, toPKPaymentButtonType(style.applePayButtonType()), toPKPaymentButtonStyle(style.applePayButtonStyle()), style.computedLocale());
     return false;
 }
 
index e445d56..1e27d74 100644 (file)
@@ -50,11 +50,11 @@ TextFragmentIterator::Style::Style(const RenderStyle& style)
     , keepAllWordsForCJK(style.wordBreak() == WordBreak::KeepAll)
     , wordSpacing(font.wordSpacing())
     , tabWidth(collapseWhitespace ? TabSize(0) : style.tabSize())
-    , shouldHyphenate(style.hyphens() == Hyphens::Auto && canHyphenate(style.locale()))
+    , shouldHyphenate(style.hyphens() == Hyphens::Auto && canHyphenate(style.computedLocale()))
     , hyphenStringWidth(shouldHyphenate ? font.width(TextRun(String(style.hyphenString()))) : 0)
     , hyphenLimitBefore(style.hyphenationLimitBefore() < 0 ? 2 : style.hyphenationLimitBefore())
     , hyphenLimitAfter(style.hyphenationLimitAfter() < 0 ? 2 : style.hyphenationLimitAfter())
-    , locale(style.locale())
+    , locale(style.computedLocale())
 {
     if (style.hyphenationLimitLines() > -1)
         hyphenLimitLines = style.hyphenationLimitLines();
@@ -63,7 +63,7 @@ TextFragmentIterator::Style::Style(const RenderStyle& style)
 TextFragmentIterator::TextFragmentIterator(const RenderBlockFlow& flow)
     : m_flowContents(flow)
     , m_currentSegment(m_flowContents.begin())
-    , m_lineBreakIterator(m_currentSegment->text, flow.style().locale())
+    , m_lineBreakIterator(m_currentSegment->text, flow.style().computedLocale())
     , m_style(flow.style())
 {
 }
index 5748d31..d7eb73a 100644 (file)
@@ -695,7 +695,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
     const RenderStyle& style = lineStyle(renderText, m_lineInfo);
     const FontCascade& font = style.fontCascade();
     bool isFixedPitch = font.isFixedPitch();
-    bool canHyphenate = style.hyphens() == Hyphens::Auto && WebCore::canHyphenate(style.locale());
+    bool canHyphenate = style.hyphens() == Hyphens::Auto && WebCore::canHyphenate(style.computedLocale());
     bool canHangPunctuationAtStart = style.hangingPunctuation().contains(HangingPunctuation::First);
     bool canHangPunctuationAtEnd = style.hangingPunctuation().contains(HangingPunctuation::Last);
     bool canHangStopOrCommaAtLineEnd = style.hangingPunctuation().contains(HangingPunctuation::AllowEnd);
@@ -731,7 +731,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
         m_renderTextInfo.text = &renderText;
         m_renderTextInfo.font = &font;
         m_renderTextInfo.layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
-        m_renderTextInfo.lineBreakIterator.resetStringAndReleaseIterator(renderText.text(), style.locale(), iteratorMode);
+        m_renderTextInfo.lineBreakIterator.resetStringAndReleaseIterator(renderText.text(), style.computedLocale(), iteratorMode);
     } else if (m_renderTextInfo.layout && m_renderTextInfo.font != &font) {
         m_renderTextInfo.font = &font;
         m_renderTextInfo.layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
@@ -877,7 +877,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
                     // no more content, and a hyphenated single word would end up on a line by itself. This looks
                     // bad so just don't allow it.
                     if (canHyphenate && !m_width.fitsOnLine() && (m_nextObject || !renderText.containsOnlyHTMLWhitespace(m_current.offset(), renderText.text().length() - m_current.offset()) || isLineEmpty)) {
-                        tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
+                        tryHyphenating(renderText, font, style.computedLocale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
                         if (m_lineBreaker.m_hyphenated) {
                             m_atEnd = true;
                             return false;
@@ -1071,7 +1071,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
         // no more content, and a hyphenated single word would end up on a line by itself. This looks
         // bad so just don't allow it.
         if (canHyphenate && (m_nextObject || isLineEmpty))
-            tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
+            tryHyphenating(renderText, font, style.computedLocale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
 
         if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphen && style.hyphens() != Hyphens::None) {
             hyphenated = true;
index 1b7592f..202aadc 100644 (file)
@@ -593,7 +593,8 @@ public:
     short hyphenationLimitAfter() const { return m_rareInheritedData->hyphenationLimitAfter; }
     short hyphenationLimitLines() const { return m_rareInheritedData->hyphenationLimitLines; }
     const AtomString& hyphenationString() const { return m_rareInheritedData->hyphenationString; }
-    const AtomString& locale() const { return fontDescription().locale(); }
+    const AtomString& computedLocale() const { return fontDescription().computedLocale(); }
+    const AtomString& specifiedLocale() const { return fontDescription().specifiedLocale(); }
     BorderFit borderFit() const { return static_cast<BorderFit>(m_rareNonInheritedData->borderFit); }
     Resize resize() const { return static_cast<Resize>(m_rareNonInheritedData->resize); }
     ColumnAxis columnAxis() const { return static_cast<ColumnAxis>(m_rareNonInheritedData->multiCol->axis); }
index 0c2325a..1c2a4b7 100644 (file)
@@ -751,9 +751,9 @@ inline void BuilderCustom::applyValueWebkitLocale(BuilderState& builderState, CS
 
     FontCascadeDescription fontDescription = builderState.style().fontDescription();
     if (primitiveValue.valueID() == CSSValueAuto)
-        fontDescription.setLocale(nullAtom());
+        fontDescription.setSpecifiedLocale(nullAtom());
     else
-        fontDescription.setLocale(primitiveValue.stringValue());
+        fontDescription.setSpecifiedLocale(primitiveValue.stringValue());
     builderState.setFontDescription(WTFMove(fontDescription));
 }
 
index ceeefdf..a955320 100644 (file)
@@ -63,7 +63,7 @@ RenderStyle resolveForDocument(const Document& document)
     documentStyle.setZoom(!document.printing() ? renderView.frame().pageZoomFactor() : 1);
     documentStyle.setPageScaleTransform(renderView.frame().frameScaleFactor());
     FontCascadeDescription documentFontDescription = documentStyle.fontDescription();
-    documentFontDescription.setLocale(document.contentLanguage());
+    documentFontDescription.setSpecifiedLocale(document.contentLanguage());
     documentStyle.setFontDescription(WTFMove(documentFontDescription));
 
     // This overrides any -webkit-user-modify inherited from the parent iframe.
@@ -108,7 +108,7 @@ RenderStyle resolveForDocument(const Document& document)
     const Settings& settings = renderView.frame().settings();
 
     FontCascadeDescription fontDescription;
-    fontDescription.setLocale(document.contentLanguage());
+    fontDescription.setSpecifiedLocale(document.contentLanguage());
     fontDescription.setRenderingMode(settings.fontRenderingMode());
     fontDescription.setOneFamily(standardFamily);
     fontDescription.setShouldAllowUserInstalledFonts(settings.shouldAllowUserInstalledFonts() ? AllowUserInstalledFonts::Yes : AllowUserInstalledFonts::No);