Move idempotent text autosizing to StyleTreeResolver
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 May 2019 02:27:20 +0000 (02:27 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 May 2019 02:27:20 +0000 (02:27 +0000)
https://bugs.webkit.org/show_bug.cgi?id=197808
<rdar://problem/50283983>

Reviewed by Antti Koivisto.

Source/WebCore:

This patch migrates the idempotent text autosizing code to live inside style resolution. This is almost
the same as the algorithm that uses the result of layout to calculate autosizing, but this version only
operates on style (and thus doesn't require double layouts). Because it is being run in an environment
with less information, autosizing is occurring in more places, so the curves have been adjusted to make
autosizing not boost as much as the previous implementation did. The new algorithm is modelled after
text-decorations-in-effect. I've claimed 4 of the unused bits in RenderStyle to contain the state of the
autosizing algorithm. StyleResolver::adjustRenderStyle() is where the algorithm is implemented:
- Look at the inherited bits
- Interogate the element's RenderStyle
- Compute new bits for the element, and set them in its RenderStyle
- Based on the newly computed bits, determine whether we should increase the text size
- If so, determine how much using the specified font size, and apply the result to the computed font size

This works because StyleBuilderCustom::applyInheritFontSize() inherits from the specified font size, not
the computed font size.

This patch also will disable autosizing using the other methods (so there aren't two methods of autosizing
fighting each other) and will honor text-size-adjust:none. However, it won't honor text-size-adjust:100%.
If content says text-size-adjust:100%, we will disregard it and take this code path.

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

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* css/CSSComputedStyleDeclaration.cpp:
(WebCore::ComputedStyleExtractor::valueForPropertyinStyle):
* css/CSSProperties.json:
* css/StyleBuilderCustom.h:
(WebCore::computeBaseSpecifiedFontSize):
(WebCore::computeLineHeightMultiplierDueToFontSize):
* css/StyleResolver.cpp:
(WebCore::idempotentTextSize):
(WebCore::hasTextChildren):
(WebCore::StyleResolver::adjustRenderStyle):
(WebCore::StyleResolver::checkForTextSizeAdjust):
* page/FrameViewLayoutContext.cpp:
(WebCore::FrameViewLayoutContext::applyTextSizingIfNeeded):
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::adjustComputedFontSizes):
(WebCore::idempotentTextSize): Deleted.
* rendering/RenderBlockFlow.h:
* rendering/RenderElement.cpp:
(WebCore::includeNonFixedHeight):
(WebCore::RenderElement::adjustComputedFontSizesOnBlocks):
(WebCore::RenderElement::resetTextAutosizing):
* rendering/style/RenderStyle.cpp:
(WebCore::RenderStyle::RenderStyle):
(WebCore::RenderStyle::autosizeStatus const):
(WebCore::RenderStyle::setAutosizeStatus):
* rendering/style/RenderStyle.h:
* rendering/style/TextSizeAdjustment.cpp: Added.
(WebCore::AutosizeStatus::AutosizeStatus):
(WebCore::AutosizeStatus::contains const):
(WebCore::AutosizeStatus::modifiedStatus const):
(WebCore::AutosizeStatus::shouldSkipSubtree const):
* rendering/style/TextSizeAdjustment.h:

LayoutTests:

* fast/text-autosizing/ios/idempotentmode/css-exposure-expected.txt: Added.
* fast/text-autosizing/ios/idempotentmode/css-exposure.html: Added.
* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip-expected.html: Added.
* fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip.html: Added.
* platform/ipad/fast/text-autosizing/text-size-adjust-inline-style-expected.html: Removed.
* platform/ipad/fast/text-autosizing/text-size-adjust-inline-style.html: Removed.
We're intentionally not honoring percentages, because this is the most common way that
text autosizing is disabled (by setting it to 100%) on the Web today. However, Web authors
that have done this did it without knowing the full extent of the behavior change, and
the new idempotent text autosizing code path seems to be a progression in most cases
we've seen.

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text-autosizing/ios/idempotentmode/css-exposure-expected.txt [new file with mode: 0644]
LayoutTests/fast/text-autosizing/ios/idempotentmode/css-exposure.html [new file with mode: 0644]
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip-expected.txt [new file with mode: 0644]
LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip.html [new file with mode: 0644]
LayoutTests/platform/ipad/fast/text-autosizing/text-size-adjust-inline-style-expected.html [deleted file]
LayoutTests/platform/ipad/fast/text-autosizing/text-size-adjust-inline-style.html [deleted file]
Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/css/CSSComputedStyleDeclaration.cpp
Source/WebCore/css/CSSProperties.json
Source/WebCore/css/StyleBuilderCustom.h
Source/WebCore/css/StyleResolver.cpp
Source/WebCore/css/StyleResolver.h
Source/WebCore/page/FrameViewLayoutContext.cpp
Source/WebCore/rendering/RenderBlockFlow.cpp
Source/WebCore/rendering/RenderBlockFlow.h
Source/WebCore/rendering/RenderElement.cpp
Source/WebCore/rendering/style/RenderStyle.cpp
Source/WebCore/rendering/style/RenderStyle.h
Source/WebCore/rendering/style/TextSizeAdjustment.cpp [new file with mode: 0644]
Source/WebCore/rendering/style/TextSizeAdjustment.h

index 90ae311..6fb21f5 100644 (file)
@@ -1,3 +1,23 @@
+2019-05-28  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Move idempotent text autosizing to StyleTreeResolver
+        https://bugs.webkit.org/show_bug.cgi?id=197808
+        <rdar://problem/50283983>
+
+        Reviewed by Antti Koivisto.
+
+        * fast/text-autosizing/ios/idempotentmode/css-exposure-expected.txt: Added.
+        * fast/text-autosizing/ios/idempotentmode/css-exposure.html: Added.
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip-expected.html: Added.
+        * fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip.html: Added.
+        * platform/ipad/fast/text-autosizing/text-size-adjust-inline-style-expected.html: Removed.
+        * platform/ipad/fast/text-autosizing/text-size-adjust-inline-style.html: Removed.
+        We're intentionally not honoring percentages, because this is the most common way that
+        text autosizing is disabled (by setting it to 100%) on the Web today. However, Web authors
+        that have done this did it without knowing the full extent of the behavior change, and 
+        the new idempotent text autosizing code path seems to be a progression in most cases
+        we've seen.
+
 2019-05-28  Simon Fraser  <simon.fraser@apple.com>
 
         Use scroll-velocity-based tile coverage for overflow:scroll
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/css-exposure-expected.txt b/LayoutTests/fast/text-autosizing/ios/idempotentmode/css-exposure-expected.txt
new file mode 100644 (file)
index 0000000..1bcc8d0
--- /dev/null
@@ -0,0 +1,7 @@
+PASS window.getComputedStyle(target).getPropertyValue('-internal-text-autosizing-status') is ""
+PASS target.style.internalTextAutosizingStatus is undefined
+PASS style.sheet.cssRules[0].style.internalTextAutosizingStatus is undefined
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Hello
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/css-exposure.html b/LayoutTests/fast/text-autosizing/ios/idempotentmode/css-exposure.html
new file mode 100644 (file)
index 0000000..2013485
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../../resources/js-test-pre.js"></script>
+<style id="style">
+#dummy {
+    -internal-text-autosizing-status: auto;
+}
+</style>
+</head>
+<body>
+<div id="target" style="-internal-text-autosizing-status: auto;">Hello</div>
+<script>
+const target = document.getElementById("target");
+const style = document.getElementById("style");
+shouldBeEqualToString("window.getComputedStyle(target).getPropertyValue('-internal-text-autosizing-status')", "");
+shouldBe("target.style.internalTextAutosizingStatus", "undefined");
+shouldBe("style.sheet.cssRules[0].style.internalTextAutosizingStatus", "undefined");
+</script>
+<script src="../../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip-expected.txt b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip-expected.txt
new file mode 100644 (file)
index 0000000..339d190
--- /dev/null
@@ -0,0 +1,18 @@
+PASS result is >= 13
+PASS result is >= 13
+PASS result is 12
+PASS result is 12
+PASS result is 12
+PASS result is 12
+PASS result is >= result2
+PASS result is >= 13
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Test
+Test
+Test
+Test
+Test
+TestTestTestTest
+Test
diff --git a/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip.html b/LayoutTests/fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip.html
new file mode 100644 (file)
index 0000000..90cfa6d
--- /dev/null
@@ -0,0 +1,52 @@
+<!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; overflow: auto;"><span id="target2" style="float: right; font-size: 12px;">Test</span></div>
+<div style="background: green;"><span id="target3" style="display: inline-block; font-size: 12px;">Test</span></div>
+<div style="background: green;"><span style="display: inline-block; font-size: 12px;"><span id="target4">Test</span></span></div>
+<div style="background: green;"><span id="target5" style="position: absolute; left: 0px; top: 0px; font-size: 12px;">Test</span></div>
+<div style="background: green;"><span id="target6" style="display: none; font-size: 12px;">Test</span></div>
+<div style="background: green;"><span id="comparison" style="font-size: 12px;">Test<span>Test<span>Test<span id="target7">Test</span></span></span></span></div>
+<div style="background: green;"><span id="target8" style="font-size: 12px; -webkit-text-size-adjust: 100%">Test</span></div>
+<script>
+let result;
+function check(name, shouldGetAutosized) {
+    let target = document.getElementById(name);
+    target.offsetWidth;
+    result = Number.parseInt(window.getComputedStyle(target).getPropertyValue("font-size"));
+    if (shouldGetAutosized)
+        shouldBeGreaterThanOrEqual("result", "13");
+    else
+        shouldBe("result", "12");
+}
+check("target", true);
+check("target2", true);
+check("target3", false);
+check("target4", false);
+check("target5", false);
+check("target6", false);
+
+let target = document.getElementById("target7");
+target.offsetWidth;
+let comparison = document.getElementById("comparison");
+comparison.offsetWidth;
+result = Number.parseInt(window.getComputedStyle(target).getPropertyValue("font-size"));
+let result2 = Number.parseInt(window.getComputedStyle(comparison).getPropertyValue("font-size"));
+shouldBeGreaterThanOrEqual("result", "result2");
+
+check("target8", true);
+</script>
+<script src="../../../../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/platform/ipad/fast/text-autosizing/text-size-adjust-inline-style-expected.html b/LayoutTests/platform/ipad/fast/text-autosizing/text-size-adjust-inline-style-expected.html
deleted file mode 100644 (file)
index 7932fa0..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<style>
-@font-face {
-    font-family: Ahem;
-    src: url("../../../../resources/Ahem.ttf");
-}
-p {
-    font-family: Ahem;
-    font-size: 20px;
-}
-</style>
-</head>
-<body>
-<p style="font-size: 20px">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="font-size: 20px">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="font-size: 10px">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="font-size: 20px">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="font-size: 30px">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="font-size: 40px">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-</body>
-</html>
diff --git a/LayoutTests/platform/ipad/fast/text-autosizing/text-size-adjust-inline-style.html b/LayoutTests/platform/ipad/fast/text-autosizing/text-size-adjust-inline-style.html
deleted file mode 100644 (file)
index bfc6375..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<!-- We intentionally do not call window.internal.settings.setTextAutosizingEnabled(true) to test the default port behavior. -->
-<style>
-@font-face {
-    font-family: Ahem;
-    src: url("../../../../resources/Ahem.ttf");
-}
-p {
-    font-family: Ahem;
-    font-size: 20px;
-}
-</style>
-</head>
-<body>
-<p style="-webkit-text-size-adjust: auto">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="-webkit-text-size-adjust: none">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="-webkit-text-size-adjust: 50%">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="-webkit-text-size-adjust: 100%">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="-webkit-text-size-adjust: 150%">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-<p style="-webkit-text-size-adjust: 200%">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
-</body>
-</html>
index 98153c3..2f0b8ff 100644 (file)
@@ -1,3 +1,71 @@
+2019-05-28  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        Move idempotent text autosizing to StyleTreeResolver
+        https://bugs.webkit.org/show_bug.cgi?id=197808
+        <rdar://problem/50283983>
+
+        Reviewed by Antti Koivisto.
+
+        This patch migrates the idempotent text autosizing code to live inside style resolution. This is almost
+        the same as the algorithm that uses the result of layout to calculate autosizing, but this version only
+        operates on style (and thus doesn't require double layouts). Because it is being run in an environment
+        with less information, autosizing is occurring in more places, so the curves have been adjusted to make
+        autosizing not boost as much as the previous implementation did. The new algorithm is modelled after
+        text-decorations-in-effect. I've claimed 4 of the unused bits in RenderStyle to contain the state of the
+        autosizing algorithm. StyleResolver::adjustRenderStyle() is where the algorithm is implemented:
+        - Look at the inherited bits
+        - Interogate the element's RenderStyle
+        - Compute new bits for the element, and set them in its RenderStyle
+        - Based on the newly computed bits, determine whether we should increase the text size
+        - If so, determine how much using the specified font size, and apply the result to the computed font size
+
+        This works because StyleBuilderCustom::applyInheritFontSize() inherits from the specified font size, not
+        the computed font size.
+
+        This patch also will disable autosizing using the other methods (so there aren't two methods of autosizing
+        fighting each other) and will honor text-size-adjust:none. However, it won't honor text-size-adjust:100%.
+        If content says text-size-adjust:100%, we will disregard it and take this code path.
+
+        Tests: fast/text-autosizing/ios/idempotentmode/css-exposure.html
+               fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-skip.html
+               fast/text-autosizing/ios/idempotentmode/idempotent-autosizing-identity.html
+               fast/text-autosizing/ios/idempotentmode/idempotent-autosizing.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * css/CSSComputedStyleDeclaration.cpp:
+        (WebCore::ComputedStyleExtractor::valueForPropertyinStyle):
+        * css/CSSProperties.json:
+        * css/StyleBuilderCustom.h:
+        (WebCore::computeBaseSpecifiedFontSize):
+        (WebCore::computeLineHeightMultiplierDueToFontSize):
+        * css/StyleResolver.cpp:
+        (WebCore::idempotentTextSize):
+        (WebCore::hasTextChildren):
+        (WebCore::StyleResolver::adjustRenderStyle):
+        (WebCore::StyleResolver::checkForTextSizeAdjust):
+        * page/FrameViewLayoutContext.cpp:
+        (WebCore::FrameViewLayoutContext::applyTextSizingIfNeeded):
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::adjustComputedFontSizes):
+        (WebCore::idempotentTextSize): Deleted.
+        * rendering/RenderBlockFlow.h:
+        * rendering/RenderElement.cpp:
+        (WebCore::includeNonFixedHeight):
+        (WebCore::RenderElement::adjustComputedFontSizesOnBlocks):
+        (WebCore::RenderElement::resetTextAutosizing):
+        * rendering/style/RenderStyle.cpp:
+        (WebCore::RenderStyle::RenderStyle):
+        (WebCore::RenderStyle::autosizeStatus const):
+        (WebCore::RenderStyle::setAutosizeStatus):
+        * rendering/style/RenderStyle.h:
+        * rendering/style/TextSizeAdjustment.cpp: Added.
+        (WebCore::AutosizeStatus::AutosizeStatus):
+        (WebCore::AutosizeStatus::contains const):
+        (WebCore::AutosizeStatus::modifiedStatus const):
+        (WebCore::AutosizeStatus::shouldSkipSubtree const):
+        * rendering/style/TextSizeAdjustment.h:
+
 2019-05-28  Simon Fraser  <simon.fraser@apple.com>
 
         Use scroll-velocity-based tile coverage for overflow:scroll
index ee441ab..f5f7bc8 100644 (file)
@@ -2144,6 +2144,7 @@ rendering/style/StyleScrollSnapPoints.cpp
 rendering/style/StyleSurroundData.cpp
 rendering/style/StyleTransformData.cpp
 rendering/style/StyleVisualData.cpp
+rendering/style/TextSizeAdjustment.cpp
 rendering/style/WillChangeData.cpp
 
 rendering/svg/RenderSVGBlock.cpp
index 25a480e..f6ee1af 100644 (file)
                1CECB3BB21F511AA00F44542 /* WHLSLEntryPointScaffolding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLEntryPointScaffolding.h; sourceTree = "<group>"; };
                1CECB3C621F59C8700F44542 /* WHLSLNativeTypeWriter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WHLSLNativeTypeWriter.cpp; sourceTree = "<group>"; };
                1CECB3C721F59C8700F44542 /* WHLSLNativeTypeWriter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLNativeTypeWriter.h; sourceTree = "<group>"; };
+               1CF0BFD42298706800ED2074 /* TextSizeAdjustment.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TextSizeAdjustment.cpp; sourceTree = "<group>"; };
                1CFAE3220A6D6A3F0032593D /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = /usr/lib/libobjc.dylib; sourceTree = "<absolute>"; };
                1DC553FD211BA12A004B780E /* NavigatorShare.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NavigatorShare.idl; sourceTree = "<group>"; };
                1DC553FF211BA841004B780E /* ShareData.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ShareData.idl; sourceTree = "<group>"; };
                                BC2274760E8366E200E7F975 /* SVGRenderStyleDefs.cpp */,
                                BC2274770E8366E200E7F975 /* SVGRenderStyleDefs.h */,
                                1CB6B4F8217B83930093B9CD /* TextDecorationThickness.h */,
+                               1CF0BFD42298706800ED2074 /* TextSizeAdjustment.cpp */,
                                448B1B780F3A2F9B0047A9E2 /* TextSizeAdjustment.h */,
                                1CB6B4FB217B83940093B9CD /* TextUnderlineOffset.h */,
                                0F15ED591B7EC7C500EDDFEB /* WillChangeData.cpp */,
index 36ae3e1..93caf60 100644 (file)
@@ -2785,6 +2785,9 @@ RefPtr<CSSValue> ComputedStyleExtractor::valueForPropertyinStyle(const RenderSty
 
     switch (propertyID) {
         case CSSPropertyInvalid:
+#if ENABLE(TEXT_AUTOSIZING)
+        case CSSPropertyInternalTextAutosizingStatus:
+#endif
             break;
 
         case CSSPropertyBackgroundColor:
index 8a4ef59..1536159 100644 (file)
             },
             "status": "non-standard"
         },
+        "-internal-text-autosizing-status": {
+            "inherited": true,
+            "codegen-properties": {
+                "skip-builder": true,
+                "enable-if": "ENABLE_TEXT_AUTOSIZING"
+            },
+            "status": "non-standard"
+        },
         "-webkit-text-emphasis": {
             "inherited": true,
             "codegen-properties": {
index fbc9481..c0cd5a1 100644 (file)
@@ -669,7 +669,7 @@ static inline float computeBaseSpecifiedFontSize(const Document& document, const
     if (frame && style.textZoom() != TextZoom::Reset)
         result *= frame->textZoomFactor();
     result *= style.effectiveZoom();
-    if (percentageAutosizingEnabled)
+    if (percentageAutosizingEnabled && !document.settings().textAutosizingUsesIdempotentMode())
         result *= style.textSizeAdjust().multiplier();
     return result;
 }
@@ -701,7 +701,7 @@ static inline float computeLineHeightMultiplierDueToFontSize(const Document& doc
         }
     }
 
-    if (percentageAutosizingEnabled)
+    if (percentageAutosizingEnabled && !document.settings().textAutosizingUsesIdempotentMode())
         return style.textSizeAdjust().multiplier();
     return 1;
 }
index 4e8113f..fb8f87d 100644 (file)
@@ -874,6 +874,29 @@ static OptionSet<TouchAction> computeEffectiveTouchActions(const RenderStyle& st
 }
 #endif
 
+#if ENABLE(TEXT_AUTOSIZING)
+static bool hasTextChildren(const Element& element)
+{
+    for (auto* child = element.firstChild(); child; child = child->nextSibling()) {
+        if (is<Text>(child))
+            return true;
+    }
+    return false;
+}
+
+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());
+    }
+}
+#endif
+
 void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& parentStyle, const RenderStyle* parentBoxStyle, const Element* element)
 {
     // If the composed tree parent has display:contents, the parent box style will be different from the parent style.
@@ -1124,6 +1147,10 @@ void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& par
     style.setEffectiveTouchActions(computeEffectiveTouchActions(style, parentStyle.effectiveTouchActions()));
 #endif
 
+#if ENABLE(TEXT_AUTOSIZING)
+    adjustRenderStyleForTextAutosizing(style, element);
+#endif
+
     if (element)
         adjustRenderStyleForSiteSpecificQuirks(style, *element);
 }
@@ -1820,7 +1847,8 @@ RefPtr<StyleImage> StyleResolver::styleImage(CSSValue& value)
 #if ENABLE(TEXT_AUTOSIZING)
 void StyleResolver::checkForTextSizeAdjust(RenderStyle* style)
 {
-    if (style->textSizeAdjust().isAuto())
+    ASSERT(style);
+    if (style->textSizeAdjust().isAuto() || (settings().textAutosizingUsesIdempotentMode() && !style->textSizeAdjust().isNone()))
         return;
 
     auto newFontDescription = style->fontDescription();
index e25603c..ee1207c 100644 (file)
@@ -500,6 +500,8 @@ private:
     // the last reference to a style declaration are garbage collected.
     void sweepMatchedPropertiesCache();
 
+    void adjustRenderStyleForTextAutosizing(RenderStyle&, const Element*);
+
     typedef HashMap<unsigned, MatchedPropertiesCacheItem> MatchedPropertiesCache;
     MatchedPropertiesCache m_matchedPropertiesCache;
 
index 30ae174..fd1fa60 100644 (file)
@@ -491,9 +491,9 @@ bool FrameViewLayoutContext::canPerformLayout() const
 void FrameViewLayoutContext::applyTextSizingIfNeeded(RenderElement& layoutRoot)
 {
     auto& settings = layoutRoot.settings();
-    if (!settings.textAutosizingEnabled() || renderView()->printing())
-        return;
     bool idempotentMode = settings.textAutosizingUsesIdempotentMode();
+    if (!settings.textAutosizingEnabled() || idempotentMode || renderView()->printing())
+        return;
     auto minimumZoomFontSize = settings.minimumZoomFontSize();
     if (!idempotentMode && !minimumZoomFontSize)
         return;
index 6bfaa82..042c2cc 100644 (file)
@@ -3723,44 +3723,12 @@ static inline float textMultiplier(RenderObject& renderer, float specifiedSize)
     return std::max((1.0f / log10f(specifiedSize) * coefficient), 1.0f);
 }
 
-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)
+void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
 {
     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 (!idempotentMode && visibleWidth >= width())
+    if (visibleWidth >= width())
         return;
     
     unsigned lineCount;
@@ -3798,7 +3766,7 @@ void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth, fl
         auto& fontDescription = oldStyle.fontDescription();
         float specifiedSize = fontDescription.specifiedSize();
         float scaledSize = roundf(specifiedSize * scale);
-        if (idempotentMode || (scaledSize > 0 && scaledSize < minFontSize)) {
+        if (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)
@@ -3806,14 +3774,8 @@ void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth, fl
             if (m_widthForTextAutosizing == -1)
                 m_widthForTextAutosizing = actualWidth;
 
-            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));
-            }
+            float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(text, specifiedSize) : textMultiplier(text, specifiedSize);
+            float 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 c4ce223..bdbbe3c 100644 (file)
@@ -604,7 +604,7 @@ public:
 
 #if ENABLE(TEXT_AUTOSIZING)
     int lineCountForTextAutosizing();
-    void adjustComputedFontSizes(float size, float visibleWidth, float pageScale, bool idempotentMode);
+    void adjustComputedFontSizes(float size, float visibleWidth);
     void resetComputedFontSize()
     {
         m_widthForTextAutosizing = -1;
index 659fa51..292cd39 100644 (file)
@@ -2125,8 +2125,6 @@ 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;
 }
 
@@ -2136,12 +2134,9 @@ 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
@@ -2154,8 +2149,8 @@ void RenderElement::adjustComputedFontSizesOnBlocks(float size, float visibleWid
             depthStack.append(newFixedDepth);
 
         int stackSize = depthStack.size();
-        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
-            downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth, pageScale, idempotentMode);
+        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
+            downcast<RenderBlockFlow>(*descendent).adjustComputedFontSizes(size, visibleWidth);
         newFixedDepth = 0;
     }
 
@@ -2176,7 +2171,6 @@ 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])
@@ -2185,7 +2179,7 @@ void RenderElement::resetTextAutosizing()
             depthStack.append(newFixedDepth);
 
         int stackSize = depthStack.size();
-        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (idempotentMode || !stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
+        if (is<RenderBlockFlow>(*descendent) && !descendent->isListItem() && (!stackSize || currentDepth - depthStack[stackSize - 1] > TextAutoSizingFixedHeightDepth))
             downcast<RenderBlockFlow>(*descendent).resetComputedFontSize();
         newFixedDepth = 0;
     }
index 6f64de3..2e2d658 100644 (file)
@@ -165,6 +165,9 @@ RenderStyle::RenderStyle(CreateDefaultStyleTag)
     m_inheritedFlags.insideLink = static_cast<unsigned>(InsideLink::NotInside);
     m_inheritedFlags.insideDefaultButton = false;
     m_inheritedFlags.writingMode = initialWritingMode();
+#if ENABLE(TEXT_AUTOSIZING)
+    m_inheritedFlags.autosizeStatus = 0;
+#endif
 
     m_nonInheritedFlags.effectiveDisplay = static_cast<unsigned>(initialDisplay());
     m_nonInheritedFlags.originalDisplay = static_cast<unsigned>(initialDisplay());
@@ -489,6 +492,16 @@ bool RenderStyle::equalForTextAutosizing(const RenderStyle& other) const
         && m_rareNonInheritedData->textOverflow == other.m_rareNonInheritedData->textOverflow;
 }
 
+AutosizeStatus RenderStyle::autosizeStatus() const
+{
+    return OptionSet<AutosizeStatus::Fields>::fromRaw(m_inheritedFlags.autosizeStatus);
+}
+
+void RenderStyle::setAutosizeStatus(AutosizeStatus autosizeStatus)
+{
+    m_inheritedFlags.autosizeStatus = autosizeStatus.fields().toRaw();
+}
+
 #endif // ENABLE(TEXT_AUTOSIZING)
 
 bool RenderStyle::inheritedDataShared(const RenderStyle* other) const
index efe1cf8..fcf069c 100644 (file)
@@ -744,6 +744,7 @@ public:
 
 #if ENABLE(TEXT_AUTOSIZING)
     TextSizeAdjustment textSizeAdjust() const { return m_rareInheritedData->textSizeAdjust; }
+    AutosizeStatus autosizeStatus() const;
 #endif
 
     TextSecurity textSecurity() const { return static_cast<TextSecurity>(m_rareInheritedData->textSecurity); }
@@ -1258,6 +1259,7 @@ public:
 
 #if ENABLE(TEXT_AUTOSIZING)
     void setTextSizeAdjust(TextSizeAdjustment adjustment) { SET_VAR(m_rareInheritedData, textSizeAdjust, adjustment); }
+    void setAutosizeStatus(AutosizeStatus);
 #endif
 
     void setTextSecurity(TextSecurity security) { SET_VAR(m_rareInheritedData, textSecurity, static_cast<unsigned>(security)); }
@@ -1845,6 +1847,11 @@ private:
         // CSS Text Layout Module Level 3: Vertical writing support
         unsigned writingMode : 2; // WritingMode
         // 48 bits
+
+#if ENABLE(TEXT_AUTOSIZING)
+        unsigned autosizeStatus : 4;
+#endif
+        // 52 bits
     };
 
     // This constructor is used to implement the replace operation.
diff --git a/Source/WebCore/rendering/style/TextSizeAdjustment.cpp b/Source/WebCore/rendering/style/TextSizeAdjustment.cpp
new file mode 100644 (file)
index 0000000..0dbdaa0
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextSizeAdjustment.h"
+
+#if ENABLE(TEXT_AUTOSIZING)
+
+#include "RenderStyle.h"
+
+namespace WebCore {
+
+AutosizeStatus::AutosizeStatus(OptionSet<Fields> fields)
+    : m_fields(fields)
+{
+}
+
+bool AutosizeStatus::contains(Fields fields) const
+{
+    return m_fields.contains(fields);
+}
+
+AutosizeStatus AutosizeStatus::updateStatus(RenderStyle& style)
+{
+    OptionSet<Fields> result = style.autosizeStatus().fields();
+    if (style.hasOutOfFlowPosition())
+        result.add(Fields::FoundOutOfFlowPosition);
+    switch (style.display()) {
+    case DisplayType::InlineBlock:
+        result.add(Fields::FoundInlineBlock);
+        break;
+    case DisplayType::None:
+        result.add(Fields::FoundDisplayNone);
+        break;
+    default: // FIXME: Add more cases.
+        break;
+    }
+    if (style.height().isFixed())
+        result.add(Fields::FoundFixedHeight);
+    style.setAutosizeStatus(result);
+    return result;
+}
+
+bool AutosizeStatus::shouldSkipSubtree() const
+{
+    return m_fields.containsAny({ Fields::FoundOutOfFlowPosition, Fields::FoundInlineBlock, Fields::FoundFixedHeight, Fields::FoundDisplayNone });
+}
+
+float AutosizeStatus::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, 9.0f}, {14.0f, 17.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(std::round(result), specifiedSize);
+}
+
+}
+
+#endif
index f37c301..9f6b3fb 100644 (file)
 
 #if ENABLE(TEXT_AUTOSIZING)
 
+#include <wtf/OptionSet.h>
+
 namespace WebCore {
 
+class RenderStyle;
+
 enum TextSizeAdjustmentType { AutoTextSizeAdjustment = -1, NoTextSizeAdjustment = -2 };
 
 class TextSizeAdjustment {
@@ -45,6 +49,30 @@ private:
     float m_value;
 };
 
+class AutosizeStatus {
+public:
+    enum class Fields : uint8_t {
+        FoundOutOfFlowPosition = 1 << 0,
+        FoundInlineBlock = 1 << 1,
+        FoundFixedHeight = 1 << 2,
+        FoundDisplayNone = 1 << 3
+        // Adding new values requires giving RenderStyle::InheritedFlags::autosizeStatus additional bits.
+    };
+
+    AutosizeStatus(OptionSet<Fields>);
+    OptionSet<Fields> fields() const { return m_fields; }
+
+    bool contains(Fields) const;
+    bool shouldSkipSubtree() const;
+
+    static float idempotentTextSize(float specifiedSize, float pageScale);
+    static AutosizeStatus updateStatus(RenderStyle&);
+
+private:
+    OptionSet<Fields> m_fields;
+};
+
+
 } // namespace WebCore
 
 #endif // ENABLE(TEXT_AUTOSIZING)