Title: [292679] trunk
Revision
292679
Author
za...@apple.com
Date
2022-04-09 10:55:18 -0700 (Sat, 09 Apr 2022)

Log Message

REGRESSION (Safari 15.4): Focused element doesn't render outline when it has an underline
https://bugs.webkit.org/show_bug.cgi?id=238998
<rdar://problem/91484512>

Reviewed by Antti Koivisto.

Source/WebCore:

While outline is supposed to be part of the ink overflow(1), WebKit historically has been
treating it as a special "non ink overflow" type of overflow.

This patch is in preparation for transitioning the outline to regular ink overflow.

First we start treating outline as part of ink overflow within IFC and
handle it as special repaint content only at the block (RenderBlockFlow) level.

Test: fast/repaint/incorrect-outline-repaint.html

(1) https://www.w3.org/TR/css-overflow-3/#ink

* layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp:
(WebCore::Layout::computeInkOverflowForInlineLevelBox):
(WebCore::Layout::InlineDisplayContentBuilder::appendAtomicInlineLevelDisplayBox):
(WebCore::Layout::InlineDisplayContentBuilder::appendInlineBoxDisplayBox):
(WebCore::Layout::InlineDisplayContentBuilder::appendSpanningInlineBoxDisplayBox):
(WebCore::Layout::InlineDisplayContentBuilder::adjustVisualGeometryForDisplayBox):
(WebCore::Layout::computeBoxShadowInkOverflow): Deleted.
* layout/integration/LayoutIntegrationInlineContent.cpp:
(WebCore::LayoutIntegration::InlineContent::hasContent const):
* layout/integration/LayoutIntegrationInlineContent.h:
(WebCore::LayoutIntegration::InlineContent::hasVisualOverflow const):
(WebCore::LayoutIntegration::InlineContent::setHasVisualOverflow):
* layout/integration/LayoutIntegrationInlineContentBuilder.cpp:
(WebCore::LayoutIntegration::InlineContentBuilder::createDisplayLines const):
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::layoutModernLines): This may cause overly inflated repaintTop/Bottom when
the ink overflow is not outline based (text stroke only atm) but we will anyway trigger
similar repaint rect on that part later when we process ink overflow.

LayoutTests:

* fast/repaint/incorrect-outline-repaint-expected.txt: Added.
* fast/repaint/incorrect-outline-repaint.html: Added.
* fast/text/simple-line-layout-text-stroke-width.html: now we produce a slightly different (more accurate)
vertical repaint range. However this test is about moving the content horizontally, so let's make this
test more robust by focusing on the horizontal part.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (292678 => 292679)


--- trunk/LayoutTests/ChangeLog	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/LayoutTests/ChangeLog	2022-04-09 17:55:18 UTC (rev 292679)
@@ -1,3 +1,17 @@
+2022-04-09  Alan Bujtas  <za...@apple.com>
+
+        REGRESSION (Safari 15.4): Focused element doesn't render outline when it has an underline
+        https://bugs.webkit.org/show_bug.cgi?id=238998
+        <rdar://problem/91484512>
+
+        Reviewed by Antti Koivisto.
+
+        * fast/repaint/incorrect-outline-repaint-expected.txt: Added.
+        * fast/repaint/incorrect-outline-repaint.html: Added.
+        * fast/text/simple-line-layout-text-stroke-width.html: now we produce a slightly different (more accurate)
+        vertical repaint range. However this test is about moving the content horizontally, so let's make this
+        test more robust by focusing on the horizontal part. 
+
 2022-04-08  Matteo Flores  <matteo_flo...@apple.com>
 
         REBASLINE: [ Monterey wk2 ] 4 http/tests/inspector/paymentrequest/* tests are constant text failures

Added: trunk/LayoutTests/fast/repaint/incorrect-outline-repaint-expected.txt (0 => 292679)


--- trunk/LayoutTests/fast/repaint/incorrect-outline-repaint-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/incorrect-outline-repaint-expected.txt	2022-04-09 17:55:18 UTC (rev 292679)
@@ -0,0 +1,2 @@
+outline
+PASS

Added: trunk/LayoutTests/fast/repaint/incorrect-outline-repaint.html (0 => 292679)


--- trunk/LayoutTests/fast/repaint/incorrect-outline-repaint.html	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/incorrect-outline-repaint.html	2022-04-09 17:55:18 UTC (rev 292679)
@@ -0,0 +1,27 @@
+<style>
+span {
+  font-size: 10px;
+  font-family: Ahem;
+}
+</style>
+<!-- PASS if the green outline is visible -->
+<span id=changeThis>outline</span>
+<pre id=result></pre>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+setTimeout(function() {
+  if (window.internals) {
+    internals.startTrackingRepaints();
+    changeThis.style.outline = "50px solid green";
+    let repaintRects = internals.repaintRectsAsText();
+    internals.stopTrackingRepaints();
+    result.textContent = repaintRects.indexOf('-') == -1 ? "FAIL: 50px outline should produce negative vertical position for repaint" : "PASS";
+    if (window.testRunner)
+      testRunner.notifyDone();
+  } else
+    changeThis.style.outline = "50px solid green";
+}, 0);
+</script>

Modified: trunk/LayoutTests/fast/text/simple-line-layout-text-stroke-width-expected.txt (292678 => 292679)


--- trunk/LayoutTests/fast/text/simple-line-layout-text-stroke-width-expected.txt	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/LayoutTests/fast/text/simple-line-layout-text-stroke-width-expected.txt	2022-04-09 17:55:18 UTC (rev 292679)
@@ -1,4 +1,4 @@
-PASS internals.repaintRectsAsText().indexOf('90 8 62 18') is not -1
+PASS internals.repaintRectsAsText().indexOf('90') is not -1
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/fast/text/simple-line-layout-text-stroke-width.html (292678 => 292679)


--- trunk/LayoutTests/fast/text/simple-line-layout-text-stroke-width.html	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/LayoutTests/fast/text/simple-line-layout-text-stroke-width.html	2022-04-09 17:55:18 UTC (rev 292679)
@@ -22,7 +22,7 @@
 		document.getElementById("foo").style.left = "100px";
 		document.body.offsetWidth;
 		if (window.internals) {
-			shouldNotBe("internals.repaintRectsAsText().indexOf('90 8 62 18')", "-1");
+			shouldNotBe("internals.repaintRectsAsText().indexOf('90')", "-1");
 			internals.stopTrackingRepaints();
 			finishJSTest();
 		}

Modified: trunk/Source/WebCore/ChangeLog (292678 => 292679)


--- trunk/Source/WebCore/ChangeLog	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/Source/WebCore/ChangeLog	2022-04-09 17:55:18 UTC (rev 292679)
@@ -1,3 +1,42 @@
+2022-04-09  Alan Bujtas  <za...@apple.com>
+
+        REGRESSION (Safari 15.4): Focused element doesn't render outline when it has an underline
+        https://bugs.webkit.org/show_bug.cgi?id=238998
+        <rdar://problem/91484512>
+
+        Reviewed by Antti Koivisto.
+
+        While outline is supposed to be part of the ink overflow(1), WebKit historically has been
+        treating it as a special "non ink overflow" type of overflow.
+
+        This patch is in preparation for transitioning the outline to regular ink overflow.
+
+        First we start treating outline as part of ink overflow within IFC and
+        handle it as special repaint content only at the block (RenderBlockFlow) level.
+
+        Test: fast/repaint/incorrect-outline-repaint.html
+
+        (1) https://www.w3.org/TR/css-overflow-3/#ink
+
+        * layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp:
+        (WebCore::Layout::computeInkOverflowForInlineLevelBox):
+        (WebCore::Layout::InlineDisplayContentBuilder::appendAtomicInlineLevelDisplayBox):
+        (WebCore::Layout::InlineDisplayContentBuilder::appendInlineBoxDisplayBox):
+        (WebCore::Layout::InlineDisplayContentBuilder::appendSpanningInlineBoxDisplayBox):
+        (WebCore::Layout::InlineDisplayContentBuilder::adjustVisualGeometryForDisplayBox):
+        (WebCore::Layout::computeBoxShadowInkOverflow): Deleted.
+        * layout/integration/LayoutIntegrationInlineContent.cpp:
+        (WebCore::LayoutIntegration::InlineContent::hasContent const):
+        * layout/integration/LayoutIntegrationInlineContent.h:
+        (WebCore::LayoutIntegration::InlineContent::hasVisualOverflow const):
+        (WebCore::LayoutIntegration::InlineContent::setHasVisualOverflow):
+        * layout/integration/LayoutIntegrationInlineContentBuilder.cpp:
+        (WebCore::LayoutIntegration::InlineContentBuilder::createDisplayLines const):
+        * rendering/RenderBlockFlow.cpp:
+        (WebCore::RenderBlockFlow::layoutModernLines): This may cause overly inflated repaintTop/Bottom when
+        the ink overflow is not outline based (text stroke only atm) but we will anyway trigger 
+        similar repaint rect on that part later when we process ink overflow.
+
 2022-04-09  Sihui Liu  <sihui_...@apple.com>
 
         Move canAccessStorage() check from SecurityOrigin to ScriptExecutionContext

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp (292678 => 292679)


--- trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp	2022-04-09 17:55:18 UTC (rev 292679)
@@ -107,19 +107,34 @@
     return boxes;
 }
 
-static inline bool computeBoxShadowInkOverflow(const RenderStyle& style, FloatRect& inkOverflow)
+static inline bool computeInkOverflowForInlineLevelBox(const RenderStyle& style, FloatRect& inkOverflow)
 {
-    auto topBoxShadow = LayoutUnit { };
-    auto bottomBoxShadow = LayoutUnit { };
-    style.getBoxShadowBlockDirectionExtent(topBoxShadow, bottomBoxShadow);
+    auto hasVisualOverflow = false;
 
-    auto leftBoxShadow = LayoutUnit { };
-    auto rightBoxShadow = LayoutUnit { };
-    style.getBoxShadowInlineDirectionExtent(leftBoxShadow, rightBoxShadow);
-    if (!topBoxShadow && !bottomBoxShadow && !leftBoxShadow && !rightBoxShadow)
-        return false;
-    inkOverflow.inflate(leftBoxShadow.toFloat(), topBoxShadow.toFloat(), rightBoxShadow.toFloat(), bottomBoxShadow.toFloat());
-    return true;
+    auto inflateWithOutline = [&] {
+        if (!style.hasOutlineInVisualOverflow())
+            return;
+        inkOverflow.inflate(style.outlineSize());
+        hasVisualOverflow = true;
+    };
+    inflateWithOutline();
+
+    auto inflateWithBoxShadow = [&] {
+        auto topBoxShadow = LayoutUnit { };
+        auto bottomBoxShadow = LayoutUnit { };
+        style.getBoxShadowBlockDirectionExtent(topBoxShadow, bottomBoxShadow);
+
+        auto leftBoxShadow = LayoutUnit { };
+        auto rightBoxShadow = LayoutUnit { };
+        style.getBoxShadowInlineDirectionExtent(leftBoxShadow, rightBoxShadow);
+        if (!topBoxShadow && !bottomBoxShadow && !leftBoxShadow && !rightBoxShadow)
+            return;
+        inkOverflow.inflate(leftBoxShadow.toFloat(), topBoxShadow.toFloat(), rightBoxShadow.toFloat(), bottomBoxShadow.toFloat());
+        hasVisualOverflow = true;
+    };
+    inflateWithBoxShadow();
+
+    return hasVisualOverflow;
 }
 
 void InlineDisplayContentBuilder::appendTextDisplayBox(const Line::Run& lineRun, const InlineRect& textRunRect, DisplayBoxes& boxes)
@@ -210,7 +225,7 @@
     auto& layoutBox = lineRun.layoutBox();
     auto inkOverflow = [&] {
         auto inkOverflow = FloatRect { borderBoxRect };
-        computeBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow);
+        computeInkOverflowForInlineLevelBox(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow);
         // Atomic inline box contribute to their inline box parents ink overflow at all times (e.g. <span><img></span>).
         m_contentHasInkOverflow = m_contentHasInkOverflow || &layoutBox.parent() != &root();
         return inkOverflow;
@@ -260,7 +275,7 @@
 
     auto inkOverflow = [&] {
         auto inkOverflow = FloatRect { inlineBoxBorderBox };
-        m_contentHasInkOverflow = computeBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
+        m_contentHasInkOverflow = computeInkOverflowForInlineLevelBox(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
         return inkOverflow;
     };
     ASSERT(inlineBox.isInlineBox());
@@ -287,7 +302,7 @@
     auto& layoutBox = lineRun.layoutBox();
     auto inkOverflow = [&] {
         auto inkOverflow = FloatRect { inlineBoxBorderBox };
-        m_contentHasInkOverflow = computeBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
+        m_contentHasInkOverflow = computeInkOverflowForInlineLevelBox(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
         return inkOverflow;
     };
     ASSERT(!inlineBox.isFirstBox());
@@ -532,7 +547,7 @@
 
     auto computeInkOverflow = [&] {
         auto inkOverflow = FloatRect { displayBox.visualRectIgnoringBlockDirection() };
-        m_contentHasInkOverflow = computeBoxShadowInkOverflow(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
+        m_contentHasInkOverflow = computeInkOverflowForInlineLevelBox(!m_lineIndex ? layoutBox.firstLineStyle() : layoutBox.style(), inkOverflow) || m_contentHasInkOverflow;
         displayBox.adjustInkOverflow(inkOverflow);
     };
     computeInkOverflow();

Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.cpp (292678 => 292679)


--- trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.cpp	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.cpp	2022-04-09 17:55:18 UTC (rev 292679)
@@ -45,7 +45,7 @@
 {
     ASSERT(boxes.isEmpty() || boxes[0].isRootInlineBox());
     return boxes.size() > 1;
-};
+}
 
 IteratorRange<const InlineDisplay::Box*> InlineContent::boxesForRect(const LayoutRect& rect) const
 {

Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.h (292678 => 292679)


--- trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.h	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContent.h	2022-04-09 17:55:18 UTC (rev 292679)
@@ -64,6 +64,9 @@
     bool hasMultilinePaintOverlap { false };
 
     bool hasContent() const;
+
+    bool hasVisualOverflow() const { return m_hasVisualOverflow; }
+    void setHasVisualOverflow() { m_hasVisualOverflow = true; }
     
     const Line& lineForBox(const InlineDisplay::Box& box) const { return lines[box.lineIndex()]; }
 
@@ -96,6 +99,7 @@
 
     using InlineBoxIndexCache = HashMap<CheckedRef<const Layout::Box>, Vector<size_t>>;
     mutable std::unique_ptr<InlineBoxIndexCache> m_inlineBoxIndexCache;
+    bool m_hasVisualOverflow { false };
 };
 
 template<typename Function> void InlineContent::traverseNonRootInlineBoxes(const Layout::Box& layoutBox, Function&& function)

Modified: trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContentBuilder.cpp (292678 => 292679)


--- trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContentBuilder.cpp	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/Source/WebCore/layout/integration/LayoutIntegrationInlineContentBuilder.cpp	2022-04-09 17:55:18 UTC (rev 292679)
@@ -90,7 +90,7 @@
     inlineContent.lines.reserveInitialCapacity(lines.size());
     for (size_t lineIndex = 0; lineIndex < lines.size(); ++lineIndex) {
         auto& line = lines[lineIndex];
-        auto scrollableOverflowRect = FloatRect { line.scrollableOverflow() };
+        auto scrollableOverflowRect = line.scrollableOverflow();
 
         auto adjustOverflowLogicalWidthWithBlockFlowQuirk = [&] {
             auto& rootStyle = m_blockFlow.style();
@@ -137,6 +137,8 @@
         }
 
         auto boxCount = boxIndex - firstBoxIndex;
+        if (!inlineContent.hasVisualOverflow() && lineInkOverflowRect != line.scrollableOverflow())
+            inlineContent.setHasVisualOverflow();
         inlineContent.lines.append({ firstBoxIndex, boxCount, FloatRect { line.lineBoxRect() }, line.enclosingTopAndBottom().top, line.enclosingTopAndBottom().bottom, scrollableOverflowRect, lineInkOverflowRect, line.baseline(), line.baselineType(), line.contentLogicalOffset(), line.contentLogicalWidth(), line.isHorizontal() });
     }
 }

Modified: trunk/Source/WebCore/rendering/RenderBlockFlow.cpp (292678 => 292679)


--- trunk/Source/WebCore/rendering/RenderBlockFlow.cpp	2022-04-09 08:35:06 UTC (rev 292678)
+++ trunk/Source/WebCore/rendering/RenderBlockFlow.cpp	2022-04-09 17:55:18 UTC (rev 292679)
@@ -3687,6 +3687,18 @@
     repaintLogicalTop = contentBoxTop;
     repaintLogicalBottom = std::max(oldBorderBoxBottom, newBorderBoxBottom);
 
+    auto inflateRepaintTopAndBottomWithInkOverflow = [&] {
+        auto* inlineContent = layoutFormattingContextLineLayout.inlineContent();
+        if (!inlineContent || !inlineContent->hasVisualOverflow())
+            return;
+        for (auto& line : inlineContent->lines) {
+            auto inkOverflow = LayoutRect { line.inkOverflow() };
+            repaintLogicalTop = std::min(repaintLogicalTop, inkOverflow.y());
+            repaintLogicalBottom = std::max(repaintLogicalBottom, inkOverflow.maxY());
+        }
+    };
+    inflateRepaintTopAndBottomWithInkOverflow();
+
     setLogicalHeight(newBorderBoxBottom);
 }
 #endif
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to