[iOS] Idempotent text autosizing needs to react properly to viewport changes
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jun 2019 04:51:10 +0000 (04:51 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jun 2019 04:51:10 +0000 (04:51 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198736
<rdar://problem/50591911>

Reviewed by Zalan Bujtas.

Source/WebCore:

Minor refactoring and some adjustments around StyleResolver::adjustRenderStyleForTextAutosizing. See below for
more details, as well as the WebKit ChangeLog.

Test: fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale.html

* css/StyleResolver.cpp:
(WebCore::StyleResolver::adjustRenderStyleForTextAutosizing):

Rewrite this using early return statements, to make it easier to debug why elements fall out of text autosizing.
Additionally, this function currently bails if the initial scale is exactly 1, whereas we can really avoid text
autosizing in the case where the initial scale is at least 1; handle this by making idempotentTextSize return
immediately with the specified size, in the case where the scale is at least 1.

Lastly, remove the null check for element by making this method take an Element&, and only call this from
adjustRenderStyle if the element is nonnull (which matches adjustRenderStyleForSiteSpecificQuirks).

(WebCore::StyleResolver::adjustRenderStyle):
* css/StyleResolver.h:
* rendering/style/TextSizeAdjustment.cpp:
(WebCore::AutosizeStatus::idempotentTextSize):

Source/WebKit:

If idempotent text autosizing is enabled, respond to viewport initial scale changes by forcing a style recalc,
since the amount by which idempotent text autosizing boosts font sizes depends on the Page's initial scale.

* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::resetIdempotentTextAutosizingIfNeeded):
(WebKit::WebPage::viewportConfigurationChanged):

LayoutTests:

Add a new layout test that programmatically adjusts the meta viewport initial scale, and dumps the resulting
computed sizes of several paragraphs of text, after adjusting for text autosizing.

* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale-expected.txt: Added.
* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale-expected.txt [new file with mode: 0644]
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/rendering/style/TextSizeAdjustment.cpp
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

index 8d06b55..004c567 100644 (file)
@@ -1,3 +1,17 @@
+2019-06-11  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Idempotent text autosizing needs to react properly to viewport changes
+        https://bugs.webkit.org/show_bug.cgi?id=198736
+        <rdar://problem/50591911>
+
+        Reviewed by Zalan Bujtas.
+
+        Add a new layout test that programmatically adjusts the meta viewport initial scale, and dumps the resulting
+        computed sizes of several paragraphs of text, after adjusting for text autosizing.
+
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale-expected.txt: Added.
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale.html: Added.
+
 2019-06-11  Zalan Bujtas  <zalan@apple.com>
 
         LayoutTests/fast/events/touch/ios/double-tap-for-double-click* test cases are failing
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale-expected.txt b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale-expected.txt
new file mode 100644 (file)
index 0000000..c0d431f
--- /dev/null
@@ -0,0 +1,41 @@
+At initial scale 1
+none   auto
+8px    8px
+12px   12px
+14px   14px
+16px   16px
+20px   20px
+
+After changing initial scale to 0.5
+none   auto
+8px    13px
+12px   17px
+14px   19px
+16px   19px
+20px   20px
+
+After changing initial scale to 0.75
+none   auto
+8px    10px
+12px   14px
+14px   16px
+16px   16px
+20px   20px
+
+After changing initial scale back to 1
+none   auto
+8px    8px
+12px   12px
+14px   14px
+16px   16px
+20px   20px
+
+After changing initial scale to 1.25
+none   auto
+8px    8px
+12px   12px
+14px   14px
+16px   16px
+20px   20px
+
+
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale.html b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale.html
new file mode 100644 (file)
index 0000000..6e40502
--- /dev/null
@@ -0,0 +1,158 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true contentMode=mobile ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+body, html {
+    margin: 0;
+}
+
+.no-autosizing {
+    -webkit-text-size-adjust: none;
+}
+
+pre, code {
+    color: white;
+    background-color: black;
+    padding: 4px;
+}
+
+.container {
+    border: 1px solid black;
+    padding: 8px 12px 12px 12px;
+    max-width: 320px;
+}
+
+#text0, #text5 {
+    font-size: 8px;
+}
+
+#text1, #text6 {
+    font-size: 12px;
+}
+
+#text2, #text7 {
+    font-size: 14px;
+}
+
+#text3, #text8 {
+    font-size: 16px;
+}
+
+#text4, #text9 {
+    font-size: 20px;
+}
+
+table, td {
+    border: 1px solid gray;
+}
+
+thead, tfoot {
+    background-color: tomato;
+    color: white;
+}
+
+th, td {
+    padding: 4px;
+}
+</style>
+<script src="../../../../resources/ui-helper.js"></script>
+<script type="text/javascript">
+if (window.internals && window.testRunner) {
+    internals.settings.setTextAutosizingEnabled(true);
+    internals.settings.setTextAutosizingUsesIdempotentMode(true);
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+async function dumpTextSizes(description) {
+    if (window.testRunner)
+        await UIHelper.ensurePresentationUpdate();
+
+    const table = document.querySelector("template#table").content.cloneNode("true").firstElementChild;
+    table.querySelector(".description").textContent = description;
+    for (let index = 0; index < 10; ++index) {
+        const computedFontSize = getComputedStyle(document.querySelector(`#text${index}`)).fontSize;
+        table.querySelector(`.text${index}`).textContent = computedFontSize;
+    }
+
+    document.body.appendChild(table);
+    document.body.appendChild(document.createElement("br"));
+}
+
+addEventListener("load", async () => {
+    const metaViewport = document.querySelector("meta");
+    await dumpTextSizes("At initial scale 1");
+
+    metaViewport.content = "width=device-width, initial-scale=0.5";
+    await dumpTextSizes("After changing initial scale to 0.5");
+
+    metaViewport.content = "width=device-width, initial-scale=0.75";
+    await dumpTextSizes("After changing initial scale to 0.75");
+
+    metaViewport.content = "width=device-width, initial-scale=1.0";
+    await dumpTextSizes("After changing initial scale back to 1");
+
+    metaViewport.content = "width=device-width, initial-scale=1.25";
+    await dumpTextSizes("After changing initial scale to 1.25");
+
+    document.querySelector(".text-containers").remove();
+    if (window.testRunner)
+        testRunner.notifyDone();
+});
+</script>
+</head>
+<body>
+    <template id="table">
+        <table>
+            <thead>
+                <tr>
+                    <th colspan="2" class="description"></th>
+                </tr>
+                <tr>
+                    <th>none</th>
+                    <th>auto</th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td class="text0"></td>
+                    <td class="text5"></td>
+                </tr>
+                <tr>
+                    <td class="text1"></td>
+                    <td class="text6"></td>
+                </tr>
+                <tr>
+                    <td class="text2"></td>
+                    <td class="text7"></td>
+                </tr>
+                <tr>
+                    <td class="text3"></td>
+                    <td class="text8"></td>
+                </tr>
+                <tr>
+                    <td class="text4"></td>
+                    <td class="text9"></td>
+                </tr>
+            </tbody>
+        </table>
+    </template>
+    <div class="text-containers">
+        <div class="container no-autosizing">
+            <p id="text0">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text1">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text2">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text3">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text4">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+        </div>
+        <div class="container">
+            <p id="text5">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text6">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text7">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text8">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+            <p id="text9">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet nisi felis, eu scelerisque dolor imperdiet in.</p>
+        </div>
+    </div>
+</body>
+</html>
\ No newline at end of file
index f51216e..4a275d0 100644 (file)
@@ -1,3 +1,32 @@
+2019-06-11  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Idempotent text autosizing needs to react properly to viewport changes
+        https://bugs.webkit.org/show_bug.cgi?id=198736
+        <rdar://problem/50591911>
+
+        Reviewed by Zalan Bujtas.
+
+        Minor refactoring and some adjustments around StyleResolver::adjustRenderStyleForTextAutosizing. See below for
+        more details, as well as the WebKit ChangeLog.
+
+        Test: fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-after-changing-initial-scale.html
+
+        * css/StyleResolver.cpp:
+        (WebCore::StyleResolver::adjustRenderStyleForTextAutosizing):
+
+        Rewrite this using early return statements, to make it easier to debug why elements fall out of text autosizing.
+        Additionally, this function currently bails if the initial scale is exactly 1, whereas we can really avoid text
+        autosizing in the case where the initial scale is at least 1; handle this by making idempotentTextSize return
+        immediately with the specified size, in the case where the scale is at least 1.
+
+        Lastly, remove the null check for element by making this method take an Element&, and only call this from
+        adjustRenderStyle if the element is nonnull (which matches adjustRenderStyleForSiteSpecificQuirks).
+
+        (WebCore::StyleResolver::adjustRenderStyle):
+        * css/StyleResolver.h:
+        * rendering/style/TextSizeAdjustment.cpp:
+        (WebCore::AutosizeStatus::idempotentTextSize):
+
 2019-06-11  Timothy Hatcher  <timothy@apple.com>
 
         Flash when tapping compose button after switching to/from dark mode without restarting Mail.
index a6e2b53..ddd9414 100644 (file)
@@ -877,16 +877,26 @@ static bool hasTextChildren(const Element& element)
     return false;
 }
 
-void StyleResolver::adjustRenderStyleForTextAutosizing(RenderStyle& style, const Element* element)
+void StyleResolver::adjustRenderStyleForTextAutosizing(RenderStyle& style, const Element& element)
 {
     auto newAutosizeStatus = AutosizeStatus::updateStatus(style);
-    auto pageScale = document().page() ? document().page()->initialScale() : 1.0f;
-    if (settings().textAutosizingEnabled() && settings().textAutosizingUsesIdempotentMode() && element && !newAutosizeStatus.shouldSkipSubtree() && !style.textSizeAdjust().isNone() && hasTextChildren(*element) && pageScale != 1.0f) {
-        auto fontDescription = style.fontDescription();
-        fontDescription.setComputedSize(AutosizeStatus::idempotentTextSize(fontDescription.specifiedSize(), pageScale));
-        style.setFontDescription(WTFMove(fontDescription));
-        style.fontCascade().update(&document().fontSelector());
-    }
+    if (!settings().textAutosizingEnabled() || !settings().textAutosizingUsesIdempotentMode())
+        return;
+
+    if (!hasTextChildren(element))
+        return;
+
+    if (style.textSizeAdjust().isNone())
+        return;
+
+    if (newAutosizeStatus.shouldSkipSubtree())
+        return;
+
+    float initialScale = document().page() ? document().page()->initialScale() : 1;
+    auto fontDescription = style.fontDescription();
+    fontDescription.setComputedSize(AutosizeStatus::idempotentTextSize(fontDescription.specifiedSize(), initialScale));
+    style.setFontDescription(WTFMove(fontDescription));
+    style.fontCascade().update(&document().fontSelector());
 }
 #endif
 
@@ -1140,12 +1150,12 @@ void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& par
     style.setEffectiveTouchActions(computeEffectiveTouchActions(style, parentStyle.effectiveTouchActions()));
 #endif
 
+    if (element) {
 #if ENABLE(TEXT_AUTOSIZING)
-    adjustRenderStyleForTextAutosizing(style, element);
+        adjustRenderStyleForTextAutosizing(style, *element);
 #endif
-
-    if (element)
         adjustRenderStyleForSiteSpecificQuirks(style, *element);
+    }
 }
 
 void StyleResolver::adjustRenderStyleForSiteSpecificQuirks(RenderStyle& style, const Element& element)
index ee1207c..2a34b26 100644 (file)
@@ -500,7 +500,7 @@ private:
     // the last reference to a style declaration are garbage collected.
     void sweepMatchedPropertiesCache();
 
-    void adjustRenderStyleForTextAutosizing(RenderStyle&, const Element*);
+    void adjustRenderStyleForTextAutosizing(RenderStyle&, const Element&);
 
     typedef HashMap<unsigned, MatchedPropertiesCacheItem> MatchedPropertiesCache;
     MatchedPropertiesCache m_matchedPropertiesCache;
index 0dbdaa0..0200278 100644 (file)
@@ -70,6 +70,9 @@ bool AutosizeStatus::shouldSkipSubtree() const
 
 float AutosizeStatus::idempotentTextSize(float specifiedSize, float pageScale)
 {
+    if (pageScale >= 1)
+        return specifiedSize;
+
     // This describes a piecewise curve when the page scale is 2/3.
     FloatPoint points[] = { {0.0f, 0.0f}, {6.0f, 9.0f}, {14.0f, 17.0f} };
 
index 6938691..898da32 100644 (file)
@@ -1,3 +1,19 @@
+2019-06-11  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Idempotent text autosizing needs to react properly to viewport changes
+        https://bugs.webkit.org/show_bug.cgi?id=198736
+        <rdar://problem/50591911>
+
+        Reviewed by Zalan Bujtas.
+
+        If idempotent text autosizing is enabled, respond to viewport initial scale changes by forcing a style recalc,
+        since the amount by which idempotent text autosizing boosts font sizes depends on the Page's initial scale.
+
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::resetIdempotentTextAutosizingIfNeeded):
+        (WebKit::WebPage::viewportConfigurationChanged):
+
 2019-06-11  Zalan Bujtas  <zalan@apple.com>
 
         LayoutTests/fast/events/touch/ios/double-tap-for-double-click* test cases are failing
index 677df62..87a3e64 100644 (file)
@@ -1244,6 +1244,7 @@ private:
     void completeSyntheticClick(WebCore::Node& nodeRespondingToClick, const WebCore::FloatPoint& location, OptionSet<WebKit::WebEvent::Modifier>, WebCore::SyntheticClickType, WebCore::PointerID = WebCore::mousePointerID);
     void sendTapHighlightForNodeIfNecessary(uint64_t requestID, WebCore::Node*);
     void resetTextAutosizing();
+    void resetIdempotentTextAutosizingIfNeeded(double previousInitialScale);
     WebCore::VisiblePosition visiblePositionInFocusedNodeForPoint(const WebCore::Frame&, const WebCore::IntPoint&, bool isInteractingWithFocusedElement);
     RefPtr<WebCore::Range> rangeForGranularityAtPoint(WebCore::Frame&, const WebCore::IntPoint&, uint32_t granularity, bool isInteractingWithFocusedElement);
     void dispatchSyntheticMouseEventsForSelectionGesture(SelectionTouch, const WebCore::IntPoint&);
index a64e883..d947ca2 100644 (file)
@@ -3333,10 +3333,27 @@ bool WebPage::shouldIgnoreMetaViewport() const
     return m_page->settings().shouldIgnoreMetaViewport();
 }
 
+void WebPage::resetIdempotentTextAutosizingIfNeeded(double previousInitialScale)
+{
+    if (!m_page->settings().textAutosizingUsesIdempotentMode())
+        return;
+
+    const float minimumScaleChangeBeforeRecomputingTextAutosizing = 0.01;
+    if (std::abs(previousInitialScale - m_page->initialScale()) < minimumScaleChangeBeforeRecomputingTextAutosizing)
+        return;
+
+    if (m_page->initialScale() >= 1 && previousInitialScale >= 1)
+        return;
+
+    m_page->setNeedsRecalcStyleInAllFrames();
+}
+
 void WebPage::viewportConfigurationChanged(ZoomToInitialScale zoomToInitialScale)
 {
+    double previousInitialScale = m_page->initialScale();
     double initialScale = m_viewportConfiguration.initialScale();
     m_page->setInitialScale(initialScale);
+    resetIdempotentTextAutosizingIfNeeded(previousInitialScale);
 
     if (setFixedLayoutSize(m_viewportConfiguration.layoutSize()))
         resetTextAutosizing();