Title: [295472] trunk
Revision
295472
Author
za...@apple.com
Date
2022-06-10 22:34:43 -0700 (Fri, 10 Jun 2022)

Log Message

Repaint rect does not take into account text-underline-offset
https://bugs.webkit.org/show_bug.cgi?id=241442

Reviewed by Antti Koivisto.

This patch add support for text decoration ink overflow (IFC).

1. Collect decoration ink overflow (logical)
2. Update display box ink overflow (visual)

* Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp:
(WebCore::Layout::InlineDisplayContentBuilder::build):
(WebCore::Layout::InlineDisplayContentBuilder::collectInkOverflowForInlineBoxes):
(WebCore::Layout::visualBottomForTextDecorationContent):
(WebCore::Layout::InlineDisplayContentBuilder::collectInkOverflowForTextDecorations):
* Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.h:
* Source/WebCore/style/InlineTextBoxStyle.cpp:
(WebCore::visualOverflowForDecorations):
(WebCore::defaultGap):
* Source/WebCore/style/InlineTextBoxStyle.h:

Canonical link: https://commits.webkit.org/251477@main

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/fast/css3-text/css3-text-decoration/text-underline-position/underline-visual-overflow-with-subpixel-position-expected.txt (295471 => 295472)


--- trunk/LayoutTests/fast/css3-text/css3-text-decoration/text-underline-position/underline-visual-overflow-with-subpixel-position-expected.txt	2022-06-11 02:44:51 UTC (rev 295471)
+++ trunk/LayoutTests/fast/css3-text/css3-text-decoration/text-underline-position/underline-visual-overflow-with-subpixel-position-expected.txt	2022-06-11 05:34:43 UTC (rev 295472)
@@ -1,5 +1,5 @@
-PASS window.internals.repaintRectsAsText().indexOf('8 8 784 12') is not -1
-PASS window.internals.repaintRectsAsText().indexOf('8 20 784 12') is not -1
+PASS window.internals.repaintRectsAsText().indexOf('8 8 784 13') is not -1
+PASS window.internals.repaintRectsAsText().indexOf('8 20 784 13') is not -1
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/fast/css3-text/css3-text-decoration/text-underline-position/underline-visual-overflow-with-subpixel-position.html (295471 => 295472)


--- trunk/LayoutTests/fast/css3-text/css3-text-decoration/text-underline-position/underline-visual-overflow-with-subpixel-position.html	2022-06-11 02:44:51 UTC (rev 295471)
+++ trunk/LayoutTests/fast/css3-text/css3-text-decoration/text-underline-position/underline-visual-overflow-with-subpixel-position.html	2022-06-11 05:34:43 UTC (rev 295472)
@@ -31,8 +31,8 @@
       elements[i].style.textDecoration = "underline";
     document.body.offsetHeight;
     if (window.internals) {
-        shouldNotBe("window.internals.repaintRectsAsText().indexOf('8 8 784 12')", "-1");
-        shouldNotBe("window.internals.repaintRectsAsText().indexOf('8 20 784 12')", "-1");
+        shouldNotBe("window.internals.repaintRectsAsText().indexOf('8 8 784 13')", "-1");
+        shouldNotBe("window.internals.repaintRectsAsText().indexOf('8 20 784 13')", "-1");
         internals.stopTrackingRepaints();
     }
     finishJSTest();

Added: trunk/LayoutTests/fast/repaint/text-decoration-overflow-repaint-expected.txt (0 => 295472)


--- trunk/LayoutTests/fast/repaint/text-decoration-overflow-repaint-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/text-decoration-overflow-repaint-expected.txt	2022-06-11 05:34:43 UTC (rev 295472)
@@ -0,0 +1,10 @@
+PASS if the underlines are green.
+content
+content
+content
+(repaint rects
+  (rect 48 46 112 25)
+  (rect 39 82 25 112)
+  (rect 39 214 25 112)
+)
+

Added: trunk/LayoutTests/fast/repaint/text-decoration-overflow-repaint.html (0 => 295472)


--- trunk/LayoutTests/fast/repaint/text-decoration-overflow-repaint.html	                        (rev 0)
+++ trunk/LayoutTests/fast/repaint/text-decoration-overflow-repaint.html	2022-06-11 05:34:43 UTC (rev 295472)
@@ -0,0 +1,36 @@
+<style>
+div {
+  margin: 20px;
+  font-family: Ahem;
+}
+span {
+  text-decoration: underline;
+  text-underline-offset: 10px;
+  color: blue;
+}
+</style>
+PASS if the underlines are green.
+<div id=container>
+<div><span>content</span></div>
+<div style="writing-mode: vertical-lr"><span>content</span></div>
+<div style="writing-mode: vertical-rl"><span>content</span></div>
+</div>
+<pre id=result></pre>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+setTimeout(function() {
+  if (window.internals)
+    window.internals.startTrackingRepaints();
+  for (let changeThis of container.getElementsByTagName("span"))
+    changeThis.style.textDecorationColor = "green";
+  if (window.internals) {
+    result.innerText = window.internals.repaintRectsAsText();
+    window.internals.stopTrackingRepaints();
+  }
+  if (window.testRunner)
+    testRunner.notifyDone();
+}, 10);
+</script>
\ No newline at end of file

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h (295471 => 295472)


--- trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h	2022-06-11 02:44:51 UTC (rev 295471)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayBox.h	2022-06-11 05:34:43 UTC (rev 295472)
@@ -137,7 +137,7 @@
     {
         auto offset = physicalTop - top();
         m_unflippedVisualRect.setY(physicalTop);
-        m_inkOverflow.shiftMaxYEdgeTo(m_inkOverflow.y() + offset);
+        m_inkOverflow.setY(m_inkOverflow.y() + offset);
     }
     void setBottom(float physicalBottom)
     {

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


--- trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp	2022-06-11 02:44:51 UTC (rev 295471)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.cpp	2022-06-11 05:34:43 UTC (rev 295472)
@@ -29,6 +29,7 @@
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "FontCascade.h"
+#include "InlineTextBoxStyle.h"
 #include "LayoutBoxGeometry.h"
 #include "LayoutInitialContainingBlock.h"
 #include "TextUtil.h"
@@ -102,6 +103,7 @@
     else
         processNonBidiContent(lineContent, lineBox, displayLine, boxes);
     processOverflownRunsForEllipsis(boxes, displayLine.right());
+    collectInkOverflowForTextDecorations(boxes, displayLine);
     collectInkOverflowForInlineBoxes(boxes);
     return boxes;
 }
@@ -788,7 +790,7 @@
     for (size_t index = boxes.size(); index--;) {
         auto& displayBox = boxes[index];
 
-        auto mayHaveInkOverflow = displayBox.isAtomicInlineLevelBox() || displayBox.isGenericInlineLevelBox() || displayBox.isNonRootInlineBox();
+        auto mayHaveInkOverflow = displayBox.isText() || displayBox.isAtomicInlineLevelBox() || displayBox.isGenericInlineLevelBox() || displayBox.isNonRootInlineBox();
         if (!mayHaveInkOverflow)
             continue;
         if (displayBox.isNonRootInlineBox() && !accumulatedInkOverflowRect.isEmpty())
@@ -805,6 +807,75 @@
     }
 }
 
+static float logicalBottomForTextDecorationContent(const DisplayBoxes& boxes, bool isHorizontalWritingMode)
+{
+    auto logicalBottom = std::optional<float> { };
+    for (auto& displayBox : boxes) {
+        if (displayBox.isRootInlineBox())
+            continue;
+        if (!displayBox.style().textDecorationsInEffect().contains(TextDecorationLine::Underline))
+            continue;
+        if (displayBox.isText() || displayBox.style().textDecorationSkipInk() == TextDecorationSkipInk::None) {
+            auto contentLogicalBottom = isHorizontalWritingMode ? displayBox.bottom() : displayBox.right();
+            logicalBottom = logicalBottom ? std::max(*logicalBottom, contentLogicalBottom) : contentLogicalBottom;
+        }
+    }
+    // This function is not called unless there's at least one run on the line with TextDecorationLine::Underline.
+    ASSERT(logicalBottom);
+    return logicalBottom.value_or(0.f);
+}
+
+void InlineDisplayContentBuilder::collectInkOverflowForTextDecorations(DisplayBoxes& boxes, const InlineDisplay::Line& displayLine)
+{
+    auto logicalBottomForTextDecoration = std::optional<float> { };
+    auto writingMode = root().style().writingMode();
+    auto isHorizontalWritingMode = WebCore::isHorizontalWritingMode(writingMode);
+
+    for (auto& displayBox : boxes) {
+        if (!displayBox.isText())
+            continue;
+
+        auto& style = displayBox.style();
+        auto textDecorations = style.textDecorationsInEffect();
+        if (!textDecorations)
+            continue;
+
+        auto underlineOffset = [&]() -> std::optional<float> {
+            if (!textDecorations.contains(TextDecorationLine::Underline))
+                return { };
+            if (!logicalBottomForTextDecoration)
+                logicalBottomForTextDecoration = logicalBottomForTextDecorationContent(boxes, isHorizontalWritingMode);
+            auto textRunLogicalOffsetFromLineBottom = *logicalBottomForTextDecoration - (isHorizontalWritingMode ? displayBox.bottom() : displayBox.right());
+            // Compensate for the integral ceiling in GraphicsContext::computeLineBoundsAndAntialiasingModeForText()
+            return computeUnderlineOffset({ style, defaultGap(style), UnderlineOffsetArguments::TextUnderlinePositionUnder { displayLine.baselineType(), displayBox.height(), textRunLogicalOffsetFromLineBottom } }) + 1.0f;
+        };
+
+        auto decorationOverflow = visualOverflowForDecorations(style, underlineOffset());
+        if (!decorationOverflow.isEmpty()) {
+            m_contentHasInkOverflow = true;
+            auto inflatedVisualOverflowRect = [&] {
+                auto inkOverflowRect = displayBox.inkOverflow();
+                switch (writingMode) {
+                case WritingMode::TopToBottom:
+                    inkOverflowRect.inflate(decorationOverflow.left, decorationOverflow.top, decorationOverflow.right, decorationOverflow.bottom);
+                    break;
+                case WritingMode::LeftToRight:
+                    inkOverflowRect.inflate(decorationOverflow.bottom, decorationOverflow.right, decorationOverflow.top, decorationOverflow.left);
+                    break;
+                case WritingMode::RightToLeft:
+                    inkOverflowRect.inflate(decorationOverflow.top, decorationOverflow.right, decorationOverflow.bottom, decorationOverflow.left);
+                    break;
+                default:
+                    ASSERT_NOT_REACHED();
+                    break;
+                }
+                return inkOverflowRect;
+            };
+            displayBox.adjustInkOverflow(inflatedVisualOverflowRect());
+        }
+    }
+}
+
 void InlineDisplayContentBuilder::computeIsFirstIsLastBoxForInlineContent(DisplayBoxes& boxes)
 {
     HashMap<const Box*, size_t> lastDisplayBoxForLayoutBoxIndexes;

Modified: trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.h (295471 => 295472)


--- trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.h	2022-06-11 02:44:51 UTC (rev 295471)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/display/InlineDisplayContentBuilder.h	2022-06-11 05:34:43 UTC (rev 295472)
@@ -53,6 +53,7 @@
     void processBidiContent(const LineBuilder::LineContent&, const LineBox&, const InlineDisplay::Line&, DisplayBoxes&);
     void processOverflownRunsForEllipsis(DisplayBoxes&, InlineLayoutUnit lineBoxRight);
     void collectInkOverflowForInlineBoxes(DisplayBoxes&);
+    void collectInkOverflowForTextDecorations(DisplayBoxes&, const InlineDisplay::Line&);
 
     void appendTextDisplayBox(const Line::Run&, const InlineRect&, DisplayBoxes&);
     void appendSoftLineBreakDisplayBox(const Line::Run&, const InlineRect&, DisplayBoxes&);

Modified: trunk/Source/WebCore/style/InlineTextBoxStyle.cpp (295471 => 295472)


--- trunk/Source/WebCore/style/InlineTextBoxStyle.cpp	2022-06-11 02:44:51 UTC (rev 295471)
+++ trunk/Source/WebCore/style/InlineTextBoxStyle.cpp	2022-06-11 05:34:43 UTC (rev 295472)
@@ -244,15 +244,13 @@
 
     // Compensate for the integral ceiling in GraphicsContext::computeLineBoundsAndAntialiasingModeForText()
     int underlineOffset = 1;
-    float textDecorationBaseFontSize = 16;
-    auto defaultGap = lineStyle.computedFontSize() / textDecorationBaseFontSize;
     // FIXME: RenderStyle calls us with empty textRun but only when TextUnderlinePosition is not Under.
     ASSERT(textRun || lineStyle.textUnderlinePosition() != TextUnderlinePosition::Under);
     if (!textRun)
-        underlineOffset += computeUnderlineOffset({ lineStyle, defaultGap });
+        underlineOffset += computeUnderlineOffset({ lineStyle, defaultGap(lineStyle) });
     else {
         underlineOffset += computeUnderlineOffset({ lineStyle
-            , defaultGap
+            , defaultGap(lineStyle)
             , UnderlineOffsetArguments::TextUnderlinePositionUnder { textRun->lineBox()->baselineType(), textRun->logicalBottom() - textRun->logicalTop(), textRunLogicalOffsetFromLineBottom(textRun) }
         });
     }
@@ -263,5 +261,11 @@
 {
     return visualOverflowForDecorations(lineStyle, InlineIterator::TextBoxIterator { });
 }
-    
+
+float defaultGap(const RenderStyle& lineStyle)
+{
+    const float textDecorationBaseFontSize = 16.f;
+    return lineStyle.computedFontSize() / textDecorationBaseFontSize;
 }
+
+}

Modified: trunk/Source/WebCore/style/InlineTextBoxStyle.h (295471 => 295472)


--- trunk/Source/WebCore/style/InlineTextBoxStyle.h	2022-06-11 02:44:51 UTC (rev 295471)
+++ trunk/Source/WebCore/style/InlineTextBoxStyle.h	2022-06-11 05:34:43 UTC (rev 295472)
@@ -53,6 +53,7 @@
     float step { 0 };
 };
 WavyStrokeParameters getWavyStrokeParameters(float fontSize);
+
 GlyphOverflow visualOverflowForDecorations(const RenderStyle& lineStyle);
 GlyphOverflow visualOverflowForDecorations(const RenderStyle& lineStyle, const InlineIterator::TextBoxIterator&);
 GlyphOverflow visualOverflowForDecorations(const RenderStyle& lineStyle, std::optional<float> underlineOffset);
@@ -69,5 +70,6 @@
 };
 float computeUnderlineOffset(const UnderlineOffsetArguments&);
 float textRunLogicalOffsetFromLineBottom(const InlineIterator::TextBoxIterator&);
+float defaultGap(const RenderStyle& lineStyle);
 
 } // namespace WebCore
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to