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