[iOS] Implement idempotent mode for text autosizing
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Apr 2019 06:33:56 +0000 (06:33 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 26 Apr 2019 06:33:56 +0000 (06:33 +0000)
https://bugs.webkit.org/show_bug.cgi?id=197250
<rdar://problem/50211034>

Reviewed by Jon Lee.

Source/WebCore:

Our text autosizing code has this interesting behavior where it is sensitive to the width of the text's container
and the number of lines of text inside the element. Not only is it sensitive to those things, but as those things
change, their values are stored inside the RenderObject itself and then never recomputed. This means that the text
autosizing parameters are sensitive to the entire history of an element. So, a newly created element with the same
style as an existing element can have dramatically different results.

This patch adds a new mode for text autosizing, which isn't sensitive to either of those things, and therefore
maintains the invariant that a newly created element will behave the same as an existing element with the same style.
Instead of using container size, it instead uses the viewport's initial scale. As the viewport's initial scale
changes, new layouts will be triggered, which will cause the autosizing code to use the new value.

Tests: fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html
       fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html

* page/FrameViewLayoutContext.cpp:
(WebCore::FrameViewLayoutContext::applyTextSizingIfNeeded):
* page/Page.cpp:
(WebCore::Page::setInitialScale): WebKit will push the initial scale down into the page.
* page/Page.h:
(WebCore::Page::initialScale const):
* page/SettingsBase.h:
* page/cocoa/SettingsBaseCocoa.mm:
(WebCore::SettingsBase::textAutosizingUsesIdempotentMode):
(WebCore::SettingsBase::defaultTextAutosizingEnabled):
* rendering/RenderBlockFlow.cpp:
(WebCore::idempotentTextSize): Describe a piecewise-linear curve for the text size to follow. The curve scales
depending on the viewport's initial scale.
(WebCore::RenderBlockFlow::adjustComputedFontSizes):
* rendering/RenderBlockFlow.h:
* rendering/RenderElement.cpp:
(WebCore::includeNonFixedHeight): This new mode should consider max-height as well as height when determining if
content overflows.
(WebCore::RenderElement::adjustComputedFontSizesOnBlocks):
(WebCore::RenderElement::resetTextAutosizing):
* rendering/RenderElement.h:
* rendering/RenderObject.h:

Source/WebKit:

Push the initial scale down into the page.

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

LayoutTests:

Add two simple tests that make sure that fonts get autosized > 1x when the layout viewport is wide,
and that fonts don't get autosized when the layout viewport isn't wide.

We don't want to add tons of tests to test exact values because the curve will likely be tweaked
in the future.

* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-expected.txt: Added.
* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity-expected.txt: Added.
* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html: Added.
* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html: Added.

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-expected.txt [new file with mode: 0644]
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity-expected.txt [new file with mode: 0644]
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html [new file with mode: 0644]
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html [new file with mode: 0644]
LayoutTests/platform/mac/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/page/FrameViewLayoutContext.cpp
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebCore/page/Settings.yaml
Source/WebCore/page/SettingsBase.cpp
Source/WebCore/page/SettingsBase.h
Source/WebCore/page/cocoa/SettingsBaseCocoa.mm
Source/WebCore/rendering/RenderBlockFlow.cpp
Source/WebCore/rendering/RenderBlockFlow.h
Source/WebCore/rendering/RenderElement.cpp
Source/WebCore/rendering/RenderObject.h
Source/WebCore/testing/InternalSettings.cpp
Source/WebCore/testing/InternalSettings.h
Source/WebCore/testing/InternalSettings.idl
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

index a7fd6cd..e775e39 100644 (file)
@@ -1,3 +1,22 @@
+2019-04-25  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [iOS] Implement idempotent mode for text autosizing
+        https://bugs.webkit.org/show_bug.cgi?id=197250
+        <rdar://problem/50211034>
+
+        Reviewed by Jon Lee.
+
+        Add two simple tests that make sure that fonts get autosized > 1x when the layout viewport is wide,
+        and that fonts don't get autosized when the layout viewport isn't wide.
+
+        We don't want to add tons of tests to test exact values because the curve will likely be tweaked
+        in the future.
+
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-expected.txt: Added.
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity-expected.txt: Added.
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html: Added.
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html: Added.
+
 2019-04-25  Sihui Liu  <sihui_liu@apple.com>
 
         [ iOS Sim ] REGRESSION (r242986) Layout Test storage/indexeddb/modern/idbtransaction-objectstore-failures-private.html is a flaky failure
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-expected.txt b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-expected.txt
new file mode 100644 (file)
index 0000000..a40f916
--- /dev/null
@@ -0,0 +1,9 @@
+PASS result is >= 13
+PASS result is >= 7
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Test
+Test
+Test
+Test
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity-expected.txt b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity-expected.txt
new file mode 100644 (file)
index 0000000..b3a6f62
--- /dev/null
@@ -0,0 +1,9 @@
+PASS result is 12
+PASS result is 6
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Test
+Test
+Test
+Test
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html
new file mode 100644 (file)
index 0000000..34215c5
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html><!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script>
+if (window.internals) {
+    window.internals.settings.setTextAutosizingEnabled(true);
+    window.internals.settings.setTextAutosizingUsesIdempotentMode(true);
+}
+</script>
+<script src="../../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="background: green;"><span id="target" style="font-size: 12px;">Test</span></div>
+<div style="background: green;"><span style="font-size: 12px;">Test</span></div>
+<div style="background: green;"><span id="target2" style="font-size: 6px;">Test</span></div>
+<div style="background: green;"><span style="font-size: 6px;">Test</span></div>
+<script>
+let target = document.getElementById("target");
+target.offsetWidth;
+let result = Number.parseInt(window.getComputedStyle(target).getPropertyValue("font-size"));
+shouldBe("result", "12");
+
+target = document.getElementById("target2");
+target.offsetWidth;
+result = Number.parseInt(window.getComputedStyle(target).getPropertyValue("font-size"));
+shouldBe("result", "6");
+</script>
+<script src="../../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html
new file mode 100644 (file)
index 0000000..fc0c678
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html><!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta name="viewport" content="initial-scale=0.6666">
+<script>
+if (window.internals) {
+    window.internals.settings.setTextAutosizingEnabled(true);
+    window.internals.settings.setTextAutosizingUsesIdempotentMode(true);
+}
+</script>
+<script src="../../../../resources/js-test-pre.js"></script>
+</head>
+<body>
+<div style="background: green;"><span id="target" style="font-size: 12px;">Test</span></div>
+<div style="background: green;"><span style="font-size: 12px;">Test</span></div>
+<div style="background: green;"><span id="target2" style="font-size: 6px;">Test</span></div>
+<div style="background: green;"><span style="font-size: 6px;">Test</span></div>
+<script>
+let target = document.getElementById("target");
+target.offsetWidth;
+let result = Number.parseInt(window.getComputedStyle(target).getPropertyValue("font-size"));
+shouldBeGreaterThanOrEqual("result", "13");
+
+target = document.getElementById("target2");
+target.offsetWidth;
+result = Number.parseInt(window.getComputedStyle(target).getPropertyValue("font-size"));
+shouldBeGreaterThanOrEqual("result", "7");
+</script>
+<script src="../../../../resources/js-test-post.js"></script>
+</body>
+</html>
index bcc584f..33f6fff 100644 (file)
@@ -22,6 +22,8 @@ fast/images/eps-as-image.html [ Pass ]
 fast/text-autosizing/ios/programmatic-text-size-adjust.html [ Skip ]
 fast/text-autosizing/ios/text-size-adjust-inline-style.html [ Skip ]
 fast/text-autosizing [ Pass ]
+# Tests for idempotent autosizing mode rely on viewport scaling which isn't implemented on Mac.
+fast/text-autosizing/ios/idempotentmode [ Pass Failure ImageOnlyFailure ]
 
 fast/attachment/attachment-subtitle-resize.html [ Pass ]
 
index 251c207..c0e5df1 100644 (file)
@@ -1,3 +1,48 @@
+2019-04-25  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [iOS] Implement idempotent mode for text autosizing
+        https://bugs.webkit.org/show_bug.cgi?id=197250
+        <rdar://problem/50211034>
+
+        Reviewed by Jon Lee.
+
+        Our text autosizing code has this interesting behavior where it is sensitive to the width of the text's container
+        and the number of lines of text inside the element. Not only is it sensitive to those things, but as those things
+        change, their values are stored inside the RenderObject itself and then never recomputed. This means that the text
+        autosizing parameters are sensitive to the entire history of an element. So, a newly created element with the same
+        style as an existing element can have dramatically different results.
+
+        This patch adds a new mode for text autosizing, which isn't sensitive to either of those things, and therefore
+        maintains the invariant that a newly created element will behave the same as an existing element with the same style.
+        Instead of using container size, it instead uses the viewport's initial scale. As the viewport's initial scale
+        changes, new layouts will be triggered, which will cause the autosizing code to use the new value.
+
+        Tests: fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html
+               fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html
+
+        * page/FrameViewLayoutContext.cpp:
+        (WebCore::FrameViewLayoutContext::applyTextSizingIfNeeded):
+        * page/Page.cpp:
+        (WebCore::Page::setInitialScale): WebKit will push the initial scale down into the page.
+        * page/Page.h:
+        (WebCore::Page::initialScale const):
+        * page/SettingsBase.h:
+        * page/cocoa/SettingsBaseCocoa.mm:
+        (WebCore::SettingsBase::textAutosizingUsesIdempotentMode):
+        (WebCore::SettingsBase::defaultTextAutosizingEnabled):
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::idempotentTextSize): Describe a piecewise-linear curve for the text size to follow. The curve scales
+        depending on the viewport's initial scale.
+        (WebCore::RenderBlockFlow::adjustComputedFontSizes):
+        * rendering/RenderBlockFlow.h:
+        * rendering/RenderElement.cpp:
+        (WebCore::includeNonFixedHeight): This new mode should consider max-height as well as height when determining if
+        content overflows.
+        (WebCore::RenderElement::adjustComputedFontSizesOnBlocks):
+        (WebCore::RenderElement::resetTextAutosizing):
+        * rendering/RenderElement.h:
+        * rendering/RenderObject.h:
+
 2019-04-25  Simon Fraser  <simon.fraser@apple.com>
 
         REGRESSION (r234330): 3 legacy-animation-engine/compositing tests are flaky failures
index 5901de0..c61085c 100644 (file)
@@ -493,13 +493,14 @@ void FrameViewLayoutContext::applyTextSizingIfNeeded(RenderElement& layoutRoot)
     auto& settings = layoutRoot.settings();
     if (!settings.textAutosizingEnabled() || renderView()->printing())
         return;
+    bool idempotentMode = settings.textAutosizingUsesIdempotentMode();
     auto minimumZoomFontSize = settings.minimumZoomFontSize();
-    if (!minimumZoomFontSize)
+    if (!idempotentMode && !minimumZoomFontSize)
         return;
     auto textAutosizingWidth = layoutRoot.page().textAutosizingWidth();
     if (auto overrideWidth = settings.textAutosizingWindowSizeOverride().width())
         textAutosizingWidth = overrideWidth;
-    if (!textAutosizingWidth)
+    if (!idempotentMode && !textAutosizingWidth)
         return;
     layoutRoot.adjustComputedFontSizesOnBlocks(minimumZoomFontSize, textAutosizingWidth);
     if (!layoutRoot.needsLayout())
index 965eb47..067c341 100644 (file)
@@ -1077,6 +1077,11 @@ void Page::setDeviceScaleFactor(float scaleFactor)
     pageOverlayController().didChangeDeviceScaleFactor();
 }
 
+void Page::setInitialScale(float initialScale)
+{
+    m_initialScale = initialScale;
+}
+
 void Page::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection)
 {
     if (m_userInterfaceLayoutDirection == userInterfaceLayoutDirection)
index dcd1f2d..666144b 100644 (file)
@@ -353,6 +353,9 @@ public:
     float deviceScaleFactor() const { return m_deviceScaleFactor; }
     WEBCORE_EXPORT void setDeviceScaleFactor(float);
 
+    float initialScale() const { return m_initialScale; }
+    WEBCORE_EXPORT void setInitialScale(float);
+
     float topContentInset() const { return m_topContentInset; }
     WEBCORE_EXPORT void setTopContentInset(float);
 
@@ -834,6 +837,7 @@ private:
 #if ENABLE(TEXT_AUTOSIZING)
     float m_textAutosizingWidth { 0 };
 #endif
+    float m_initialScale { 1.0f };
     
     bool m_suppressScrollbarAnimations { false };
     
index e3e09ee..e47d7eb 100644 (file)
@@ -440,6 +440,10 @@ minimumZoomFontSize:
   type: float
   initial: defaultMinimumZoomFontSize()
   conditional: TEXT_AUTOSIZING
+textAutosizingUsesIdempotentMode:
+  initial: defaultTextAutosizingUsesIdempotentMode()
+  onChange: setNeedsRecalcStyleInAllFrames
+  conditional: TEXT_AUTOSIZING
 
 subpixelAntialiasedLayerTextEnabled:
   initial: false
index a3533e9..582f23b 100644 (file)
@@ -96,6 +96,11 @@ bool SettingsBase::defaultTextAutosizingEnabled()
 {
     return false;
 }
+
+bool SettingsBase::defaultTextAutosizingUsesIdempotentMode()
+{
+    return false;
+}
 #endif
 
 bool SettingsBase::defaultDownloadableBinaryFontsEnabled()
index 3533b8f..42622f1 100644 (file)
@@ -113,6 +113,7 @@ public:
     static const SettingsBase::ForcedAccessibilityValue defaultForcedPrefersReducedMotionAccessibilityValue = ForcedAccessibilityValue::System;
 
     WEBCORE_EXPORT static bool defaultTextAutosizingEnabled();
+    static bool defaultTextAutosizingUsesIdempotentMode();
     WEBCORE_EXPORT static float defaultMinimumZoomFontSize();
     WEBCORE_EXPORT static bool defaultDownloadableBinaryFontsEnabled();
     WEBCORE_EXPORT static bool defaultContentChangeObserverEnabled();
index 0e413d2..a27d303 100644 (file)
@@ -83,7 +83,12 @@ void SettingsBase::initializeDefaultFontFamilies()
 
 bool SettingsBase::defaultTextAutosizingEnabled()
 {
-    return !deviceHasIPadCapability() || [[PAL::getUIApplicationClass() sharedApplication] _isClassic];
+    return true;
+}
+
+bool SettingsBase::defaultTextAutosizingUsesIdempotentMode()
+{
+    return deviceHasIPadCapability() && ![[PAL::getUIApplicationClass() sharedApplication] _isClassic];
 }
 
 #endif
index 0ecf11f..766591c 100644 (file)
@@ -3723,12 +3723,44 @@ static inline float textMultiplier(RenderObject& renderer, float specifiedSize)
     return std::max((1.0f / log10f(specifiedSize) * coefficient), 1.0f);
 }
 
-void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
+static inline float idempotentTextSize(float specifiedSize, float pageScale)
+{
+    // This describes a piecewise curve when the page scale is 2/3.
+    FloatPoint points[] = { {0.0f, 0.0f}, {6.0f, 12.0f}, {12.0f, 18.0f} };
+
+    // When the page scale is 1, the curve should be the identity.
+    // Linearly interpolate between the curve above and identity based on the page scale.
+    // Beware that depending on the specific values picked in the curve, this interpolation might change the shape of the curve for very small pageScales.
+    pageScale = std::min(std::max(pageScale, 0.5f), 1.0f);
+    auto scalePoint = [&](FloatPoint point) {
+        float fraction = 3.0f - 3.0f * pageScale;
+        point.setY(point.x() + (point.y() - point.x()) * fraction);
+        return point;
+    };
+
+    if (specifiedSize <= 0)
+        return 0;
+
+    float result = scalePoint(points[WTF_ARRAY_LENGTH(points) - 1]).y();
+    for (size_t i = 1; i < WTF_ARRAY_LENGTH(points); ++i) {
+        if (points[i].x() < specifiedSize)
+            continue;
+        auto leftPoint = scalePoint(points[i - 1]);
+        auto rightPoint = scalePoint(points[i]);
+        float fraction = (specifiedSize - leftPoint.x()) / (rightPoint.x() - leftPoint.x());
+        result = leftPoint.y() + fraction * (rightPoint.y() - leftPoint.y());
+        break;
+    }
+
+    return std::max(result, specifiedSize);
+}
+
+void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth, float pageScale, bool idempotentMode)
 {
     LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
 
     // Don't do any work if the block is smaller than the visible area.
-    if (visibleWidth >= width())
+    if (!idempotentMode && visibleWidth >= width())
         return;
     
     unsigned lineCount;
@@ -3766,7 +3798,7 @@ void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
         auto& fontDescription = oldStyle.fontDescription();
         float specifiedSize = fontDescription.specifiedSize();
         float scaledSize = roundf(specifiedSize * scale);
-        if (scaledSize > 0 && scaledSize < minFontSize) {
+        if (idempotentMode || (scaledSize > 0 && scaledSize < minFontSize)) {
             // Record the width of the block and the line count the first time we resize text and use it from then on for text resizing.
             // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
             if (m_lineCountForTextAutosizing == NOT_SET)
@@ -3774,8 +3806,15 @@ void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
             if (m_widthForTextAutosizing == -1)
                 m_widthForTextAutosizing = actualWidth;
 
-            float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(text, specifiedSize) : textMultiplier(text, specifiedSize);
-            float candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
+            float candidateNewSize;
+            if (idempotentMode) {
+                float lineTextSize = idempotentTextSize(specifiedSize, pageScale);
+                candidateNewSize = roundf(lineTextSize);
+            } else {
+                float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(text, specifiedSize) : textMultiplier(text, specifiedSize);
+                candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
+            }
+
             if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
                 document().textAutoSizing().addTextNode(*text.textNode(), candidateNewSize);
         }
index bdbbe3c..c4ce223 100644 (file)
@@ -604,7 +604,7 @@ public:
 
 #if ENABLE(TEXT_AUTOSIZING)
     int lineCountForTextAutosizing();
-    void adjustComputedFontSizes(float size, float visibleWidth);
+    void adjustComputedFontSizes(float size, float visibleWidth, float pageScale, bool idempotentMode);
     void resetComputedFontSize()
     {
         m_widthForTextAutosizing = -1;
index fbce49b..49d5ec3 100644 (file)
@@ -2123,6 +2123,8 @@ static RenderObject::BlockContentHeightType includeNonFixedHeight(const RenderOb
         }
         return RenderObject::FixedHeight;
     }
+    if (renderer.document().settings().textAutosizingUsesIdempotentMode() && style.maxHeight().type() == Fixed && is<RenderBlock>(renderer) && style.maxHeight().value() <= downcast<RenderBlock>(renderer).layoutOverflowRect().maxY())
+        return RenderObject::FixedHeight;
     return RenderObject::FlexibleHeight;
 }
 
@@ -2132,9 +2134,12 @@ void RenderElement::adjustComputedFontSizesOnBlocks(float size, float visibleWid
     if (!document)
         return;
 
+    auto pageScale = document->page() ? document->page()->initialScale() : 1.0f;
+
     Vector<int> depthStack;
     int currentDepth = 0;
     int newFixedDepth = 0;
+    auto idempotentMode = document->settings().textAutosizingUsesIdempotentMode();
 
     // We don't apply autosizing to nodes with fixed height normally.
     // But we apply it to nodes which are located deep enough
@@ -2147,8 +2152,8 @@ void RenderElement::adjustComputedFontSizesOnBlocks(float size, float visibleWid
             depthStack.append(newFixedDepth);
 
         int stackSize = depthStack.size();
-        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
-            downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth);
+        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
+            downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth, pageScale, idempotentMode);
         newFixedDepth = 0;
     }
 
@@ -2169,6 +2174,7 @@ void RenderElement::resetTextAutosizing()
     Vector<int> depthStack;
     int currentDepth = 0;
     int newFixedDepth = 0;
+    auto idempotentMode = document->settings().textAutosizingUsesIdempotentMode();
 
     for (RenderObject* descendent = traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth); descendent; descendent = descendent->traverseNext(this, includeNonFixedHeight, currentDepth, newFixedDepth)) {
         while (depthStack.size() > 0 && currentDepth <= depthStack[depthStack.size() - 1])
@@ -2177,7 +2183,7 @@ void RenderElement::resetTextAutosizing()
             depthStack.append(newFixedDepth);
 
         int stackSize = depthStack.size();
-        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
+        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
             downcast<RenderBlockFlow>(*descendent).resetComputedFontSize();
         newFixedDepth = 0;
     }
index 97626df..94b47f5 100644 (file)
@@ -154,7 +154,7 @@ public:
     };
 
     typedef BlockContentHeightType (*HeightTypeTraverseNextInclusionFunction)(const RenderObject&);
-    RenderObject* traverseNext(const RenderObject* stayWithin, HeightTypeTraverseNextInclusionFunction, int& currentDepth,  int& newFixedDepth) const;
+    RenderObject* traverseNext(const RenderObject* stayWithin, HeightTypeTraverseNextInclusionFunction, int& currentDepth, int& newFixedDepth) const;
 #endif
 
     WEBCORE_EXPORT RenderLayer* enclosingLayer() const;
index 76f6683..cd92a47 100644 (file)
@@ -58,6 +58,7 @@ InternalSettings::Backup::Backup(Settings& settings)
 #if ENABLE(TEXT_AUTOSIZING)
     , m_originalTextAutosizingEnabled(settings.textAutosizingEnabled())
     , m_originalTextAutosizingWindowSizeOverride(settings.textAutosizingWindowSizeOverride())
+    , m_originalTextAutosizingUsesIdempotentMode(settings.textAutosizingUsesIdempotentMode())
 #endif
     , m_originalMediaTypeOverride(settings.mediaTypeOverride())
     , m_originalCanvasUsesAcceleratedDrawing(settings.canvasUsesAcceleratedDrawing())
@@ -157,6 +158,7 @@ void InternalSettings::Backup::restoreTo(Settings& settings)
 #if ENABLE(TEXT_AUTOSIZING)
     settings.setTextAutosizingEnabled(m_originalTextAutosizingEnabled);
     settings.setTextAutosizingWindowSizeOverride(m_originalTextAutosizingWindowSizeOverride);
+    settings.setTextAutosizingUsesIdempotentMode(m_originalTextAutosizingUsesIdempotentMode);
 #endif
     settings.setMediaTypeOverride(m_originalMediaTypeOverride);
     settings.setCanvasUsesAcceleratedDrawing(m_originalCanvasUsesAcceleratedDrawing);
@@ -417,6 +419,18 @@ ExceptionOr<void> InternalSettings::setTextAutosizingWindowSizeOverride(int widt
     return { };
 }
 
+ExceptionOr<void> InternalSettings::setTextAutosizingUsesIdempotentMode(bool enabled)
+{
+    if (!m_page)
+        return Exception { InvalidAccessError };
+#if ENABLE(TEXT_AUTOSIZING)
+    settings().setTextAutosizingUsesIdempotentMode(enabled);
+#else
+    UNUSED_PARAM(enabled);
+#endif
+    return { };
+}
+
 ExceptionOr<void> InternalSettings::setMediaTypeOverride(const String& mediaType)
 {
     if (!m_page)
index c178880..b94edc1 100644 (file)
@@ -61,6 +61,7 @@ public:
     ExceptionOr<void> setPictographFontFamily(const String& family, const String& script);
     ExceptionOr<void> setTextAutosizingEnabled(bool);
     ExceptionOr<void> setTextAutosizingWindowSizeOverride(int width, int height);
+    ExceptionOr<void> setTextAutosizingUsesIdempotentMode(bool);
     ExceptionOr<void> setTextAutosizingFontScaleFactor(float);
     ExceptionOr<void> setMediaTypeOverride(const String&);
     ExceptionOr<void> setCanStartMedia(bool);
@@ -155,6 +156,7 @@ private:
 #if ENABLE(TEXT_AUTOSIZING)
         bool m_originalTextAutosizingEnabled;
         IntSize m_originalTextAutosizingWindowSizeOverride;
+        bool m_originalTextAutosizingUsesIdempotentMode;
 #endif
 
         String m_originalMediaTypeOverride;
index 3109844..20a3785 100644 (file)
@@ -49,6 +49,7 @@ enum FontLoadTimingOverride { "Block", "Swap", "Failure" };
 
     [MayThrowException] void setTextAutosizingEnabled(boolean enabled);
     [MayThrowException] void setTextAutosizingWindowSizeOverride(long width, long height);
+    [MayThrowException] void setTextAutosizingUsesIdempotentMode(boolean enabled);
 
     // Media
     [MayThrowException] void setCanStartMedia(boolean enabled);
index 42dc4f4..6024024 100644 (file)
@@ -1,3 +1,17 @@
+2019-04-25  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        [iOS] Implement idempotent mode for text autosizing
+        https://bugs.webkit.org/show_bug.cgi?id=197250
+        <rdar://problem/50211034>
+
+        Reviewed by Jon Lee.
+
+        Push the initial scale down into the page.
+
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::dynamicViewportSizeUpdate):
+        (WebKit::WebPage::viewportConfigurationChanged):
+
 2019-04-25  Alex Christensen  <achristensen@webkit.org>
 
         Make NetworkCache blobs safe for mmap instead of not using blobs
index 986d224..ec80a10 100644 (file)
@@ -2851,7 +2851,8 @@ void WebPage::dynamicViewportSizeUpdate(const FloatSize& viewLayoutSize, const W
     }
 
     LOG_WITH_STREAM(VisibleRects, stream << "WebPage::dynamicViewportSizeUpdate setting view layout size to " << viewLayoutSize);
-    m_viewportConfiguration.setViewLayoutSize(viewLayoutSize);
+    if (m_viewportConfiguration.setViewLayoutSize(viewLayoutSize))
+        viewportConfigurationChanged();
     IntSize newLayoutSize = m_viewportConfiguration.layoutSize();
 
     if (setFixedLayoutSize(newLayoutSize))
@@ -3030,10 +3031,12 @@ void WebPage::resetViewportDefaultConfiguration(WebFrame* frame, bool hasMobileD
 
 void WebPage::viewportConfigurationChanged(ZoomToInitialScale zoomToInitialScale)
 {
+    double initialScale = m_viewportConfiguration.initialScale();
+    m_page->setInitialScale(initialScale);
+
     if (setFixedLayoutSize(m_viewportConfiguration.layoutSize()))
         resetTextAutosizing();
 
-    double initialScale = m_viewportConfiguration.initialScale();
     double scale;
     if (m_userHasChangedPageScaleFactor && zoomToInitialScale == ZoomToInitialScale::No)
         scale = std::max(std::min(pageScaleFactor(), m_viewportConfiguration.maximumScale()), m_viewportConfiguration.minimumScale());