Diff
Modified: trunk/LayoutTests/ChangeLog (286954 => 286955)
--- trunk/LayoutTests/ChangeLog 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/LayoutTests/ChangeLog 2021-12-13 18:23:00 UTC (rev 286955)
@@ -1,3 +1,12 @@
+2021-12-13 Tim Nguyen <n...@apple.com>
+
+ Fix paint order of CSS text decorations
+ https://bugs.webkit.org/show_bug.cgi?id=227445
+
+ Reviewed by Simon Fraser.
+
+ * TestExpectations:
+
2021-12-13 Sergio Villar Senin <svil...@igalia.com>
[css-writing-modes] Use the correct margins in computeInlinePreferredLogicalWidths in orthogonal flows
Modified: trunk/LayoutTests/TestExpectations (286954 => 286955)
--- trunk/LayoutTests/TestExpectations 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/LayoutTests/TestExpectations 2021-12-13 18:23:00 UTC (rev 286955)
@@ -3431,7 +3431,6 @@
webkit.org/b/230041 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-color-selection-001.html [ ImageOnlyFailure ]
webkit.org/b/230041 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-color-selection-pseudo-01.html [ ImageOnlyFailure ]
webkit.org/b/203530 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-line-recalc.html [ ImageOnlyFailure ]
-webkit.org/b/203531 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-propagation-shadow.html [ ImageOnlyFailure ]
webkit.org/b/203528 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-thickness-linethrough-001.html [ ImageOnlyFailure ]
webkit.org/b/203528 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-thickness-overline-001.html [ ImageOnlyFailure ]
webkit.org/b/203528 imported/w3c/web-platform-tests/css/css-text-decor/text-decoration-thickness-scroll-001.html [ ImageOnlyFailure ]
@@ -3471,7 +3470,6 @@
imported/w3c/web-platform-tests/css/css-text-decor/text-emphasis-style-shape-001.xht [ ImageOnlyFailure ]
imported/w3c/web-platform-tests/css/css-text-decor/text-emphasis-style-string-001.xht [ ImageOnlyFailure ]
webkit.org/b/230083 imported/w3c/web-platform-tests/css/css-text-decor/text-underline-offset-001.html [ ImageOnlyFailure ]
-imported/w3c/web-platform-tests/css/css-text-decor/text-underline-offset-zero-position.html [ ImageOnlyFailure ]
# wpt css-position failures
webkit.org/b/203445 [ Debug ] imported/w3c/web-platform-tests/css/css-position/position-absolute-container-dynamic-002.html [ Skip ]
Modified: trunk/Source/WebCore/ChangeLog (286954 => 286955)
--- trunk/Source/WebCore/ChangeLog 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/Source/WebCore/ChangeLog 2021-12-13 18:23:00 UTC (rev 286955)
@@ -1,3 +1,24 @@
+2021-12-13 Tim Nguyen <n...@apple.com>
+
+ Fix paint order of CSS text decorations
+ https://bugs.webkit.org/show_bug.cgi?id=227445
+
+ Reviewed by Simon Fraser.
+
+ * rendering/TextBoxPainter.cpp:
+ (WebCore::TextBoxPainter::paintForegroundAndDecorations):
+ (WebCore::TextBoxPainter::createDecorationPainter):
+ (WebCore::TextBoxPainter::paintBackgroundDecorations):
+ (WebCore::TextBoxPainter::paintForegroundDecorations):
+ (WebCore::TextBoxPainter::paintDecoration): Deleted.
+ * rendering/TextBoxPainter.h:
+ * rendering/TextDecorationPainter.cpp:
+ (WebCore::TextDecorationPainter::paintBackgroundDecorations):
+ (WebCore::TextDecorationPainter::paintForegroundDecorations):
+ (WebCore::TextDecorationPainter::paintLineThrough):
+ (WebCore::TextDecorationPainter::paintTextDecoration): Deleted.
+ * rendering/TextDecorationPainter.h:
+
2021-12-13 Jer Noble <jer.no...@apple.com>
Unreviewed build fix; add a convenience function to safely compare possibly null CFStringRefs.
Modified: trunk/Source/WebCore/rendering/TextBoxPainter.cpp (286954 => 286955)
--- trunk/Source/WebCore/rendering/TextBoxPainter.cpp 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/Source/WebCore/rendering/TextBoxPainter.cpp 2021-12-13 18:23:00 UTC (rev 286955)
@@ -188,9 +188,6 @@
// Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
auto coalescedStyledMarkedTexts = StyledMarkedText::coalesceAdjacentWithEqualForeground(styledMarkedTexts);
- for (auto& markedText : coalescedStyledMarkedTexts)
- paintForeground(markedText);
-
auto textDecorations = m_style.textDecorationsInEffect();
bool highlightDecorations = !MarkedText::collectForHighlights(m_renderer, m_selectableRange, MarkedText::PaintPhase::Decoration).isEmpty();
bool lineDecorations = !textDecorations.isEmpty();
@@ -224,8 +221,27 @@
// Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
auto coalescedStyledMarkedTexts = StyledMarkedText::coalesceAdjacentWithEqualDecorations(styledMarkedTexts);
+ for (auto& markedText : coalescedStyledMarkedTexts) {
+ unsigned startOffset = markedText.startOffset;
+ unsigned endOffset = markedText.endOffset;
+ if (startOffset < endOffset) {
+ // Avoid measuring the text when the entire line box is selected as an optimization.
+ FloatRect snappedSelectionRect = m_paintRect;
+ if (startOffset || endOffset != m_paintTextRun.length()) {
+ LayoutRect selectionRect = { m_paintRect.x(), m_paintRect.y(), m_paintRect.width(), m_paintRect.height() };
+ fontCascade().adjustSelectionRectForText(m_paintTextRun, selectionRect, startOffset, endOffset);
+ snappedSelectionRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_document.deviceScaleFactor(), m_paintTextRun.ltr());
+ }
+
+ TextDecorationPainter decorationPainter = createDecorationPainter(markedText, textDecorationSelectionClipOutRect, snappedSelectionRect);
+ paintBackgroundDecorations(decorationPainter, markedText, snappedSelectionRect);
+ paintForeground(markedText);
+ paintForegroundDecorations(decorationPainter, snappedSelectionRect);
+ }
+ }
+ } else {
for (auto& markedText : coalescedStyledMarkedTexts)
- paintDecoration(markedText, textDecorationSelectionClipOutRect);
+ paintForeground(markedText);
}
}
@@ -339,16 +355,9 @@
textPainter.paintRange(m_paintTextRun, m_paintRect, textOriginFromPaintRect(m_paintRect), markedText.startOffset, markedText.endOffset);
}
-void TextBoxPainter::paintDecoration(const StyledMarkedText& markedText, const FloatRect& clipOutRect)
+TextDecorationPainter TextBoxPainter::createDecorationPainter(const StyledMarkedText& markedText, const FloatRect& clipOutRect, const FloatRect& snappedSelectionRect)
{
- // 1. Compute text selection
- unsigned startOffset = markedText.startOffset;
- unsigned endOffset = markedText.endOffset;
- if (startOffset >= endOffset)
- return;
-
GraphicsContext& context = m_paintInfo.context();
- const FontCascade& font = fontCascade();
updateGraphicsContext(context, markedText.style.textStyles);
@@ -358,16 +367,18 @@
// Note that if the text is truncated, we let the thing being painted in the truncation
// draw its own decoration.
-
- // Avoid measuring the text when the entire line box is selected as an optimization.
- FloatRect snappedSelectionRect = m_paintRect;
- if (startOffset || endOffset != m_paintTextRun.length()) {
- LayoutRect selectionRect = { m_paintRect.x(), m_paintRect.y(), m_paintRect.width(), m_paintRect.height() };
- font.adjustSelectionRectForText(m_paintTextRun, selectionRect, startOffset, endOffset);
- snappedSelectionRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_document.deviceScaleFactor(), m_paintTextRun.ltr());
+ GraphicsContextStateSaver stateSaver { context, false };
+ bool isDraggedContent = markedText.type == MarkedText::DraggedContent;
+ if (isDraggedContent || !clipOutRect.isEmpty()) {
+ stateSaver.save();
+ if (isDraggedContent)
+ context.setAlpha(markedText.style.alpha);
+ if (!clipOutRect.isEmpty())
+ context.clipOut(clipOutRect);
}
- // 2. Paint
+ // Create painter
+ const FontCascade& font = fontCascade();
auto textDecorations = m_style.textDecorationsInEffect();
textDecorations.add(TextDecorationPainter::textDecorationsInEffectForStyle(markedText.style.textDecorationStyles));
TextDecorationPainter decorationPainter { context, textDecorations, m_renderer, m_isFirstLine, font, markedText.style.textDecorationStyles };
@@ -380,21 +391,27 @@
decorationPainter.setShadowColorFilter(&m_style.appleColorFilter());
}
- {
- GraphicsContextStateSaver stateSaver { context, false };
- bool isDraggedContent = markedText.type == MarkedText::DraggedContent;
- if (isDraggedContent || !clipOutRect.isEmpty()) {
- stateSaver.save();
- if (isDraggedContent)
- context.setAlpha(markedText.style.alpha);
- if (!clipOutRect.isEmpty())
- context.clipOut(clipOutRect);
- }
- decorationPainter.paintTextDecoration(m_paintTextRun.subRun(startOffset, endOffset - startOffset), textOriginFromPaintRect(snappedSelectionRect), snappedSelectionRect.location());
+ return decorationPainter;
+}
+
+void TextBoxPainter::paintBackgroundDecorations(TextDecorationPainter& decorationPainter, const StyledMarkedText& markedText, const FloatRect& snappedSelectionRect)
+{
+ decorationPainter.paintBackgroundDecorations(m_paintTextRun.subRun(markedText.startOffset, markedText.endOffset - markedText.startOffset), textOriginFromPaintRect(snappedSelectionRect), snappedSelectionRect.location());
+
+ if (textBox().isCombinedText()) {
+ GraphicsContext& context = m_paintInfo.context();
+ context.concatCTM(rotation(m_paintRect, Counterclockwise));
}
+}
- if (isCombinedText)
+void TextBoxPainter::paintForegroundDecorations(TextDecorationPainter& decorationPainter, const FloatRect& snappedSelectionRect)
+{
+ decorationPainter.paintForegroundDecorations(snappedSelectionRect.location());
+
+ if (textBox().isCombinedText()) {
+ GraphicsContext& context = m_paintInfo.context();
context.concatCTM(rotation(m_paintRect, Counterclockwise));
+ }
}
void TextBoxPainter::paintCompositionUnderlines()
Modified: trunk/Source/WebCore/rendering/TextBoxPainter.h (286954 => 286955)
--- trunk/Source/WebCore/rendering/TextBoxPainter.h 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/Source/WebCore/rendering/TextBoxPainter.h 2021-12-13 18:23:00 UTC (rev 286955)
@@ -39,6 +39,7 @@
class RenderStyle;
class RenderText;
class ShadowData;
+class TextDecorationPainter;
struct CompositionUnderline;
struct MarkedText;
struct PaintInfo;
@@ -71,7 +72,9 @@
void paintBackground(unsigned startOffset, unsigned endOffset, const Color&, BackgroundStyle = BackgroundStyle::Normal);
void paintBackground(const StyledMarkedText&);
void paintForeground(const StyledMarkedText&);
- void paintDecoration(const StyledMarkedText&, const FloatRect& clipOutRect);
+ TextDecorationPainter createDecorationPainter(const StyledMarkedText&, const FloatRect&, const FloatRect&);
+ void paintBackgroundDecorations(TextDecorationPainter&, const StyledMarkedText&, const FloatRect&);
+ void paintForegroundDecorations(TextDecorationPainter&, const FloatRect&);
void paintCompositionUnderline(const CompositionUnderline&);
void paintPlatformDocumentMarker(const MarkedText&);
Modified: trunk/Source/WebCore/rendering/TextDecorationPainter.cpp (286954 => 286955)
--- trunk/Source/WebCore/rendering/TextDecorationPainter.cpp 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/Source/WebCore/rendering/TextDecorationPainter.cpp 2021-12-13 18:23:00 UTC (rev 286955)
@@ -201,7 +201,8 @@
{
}
-void TextDecorationPainter::paintTextDecoration(const TextRun& textRun, const FloatPoint& textOrigin, const FloatPoint& boxOrigin)
+// Paint text-shadow, underline, overline
+void TextDecorationPainter::paintBackgroundDecorations(const TextRun& textRun, const FloatPoint& textOrigin, const FloatPoint& boxOrigin)
{
const auto& fontMetrics = m_lineStyle.fontMetrics();
float textDecorationThickness = m_lineStyle.textDecorationThickness().resolve(m_lineStyle.computedFontSize(), fontMetrics);
@@ -228,10 +229,8 @@
// FIXME: Need to support text-decoration-skip: none.
m_context.drawLineForText(rect, m_isPrinting, style == TextDecorationStyle::Double, strokeStyle);
}
- } else {
- ASSERT(decoration == TextDecorationLine::LineThrough);
- m_context.drawLineForText(rect, m_isPrinting, style == TextDecorationStyle::Double, strokeStyle);
- }
+ } else
+ ASSERT_NOT_REACHED();
};
bool areLinesOpaque = !m_isPrinting && (!m_decorations.contains(TextDecorationLine::Underline) || m_styles.underlineColor.isOpaque())
@@ -293,13 +292,11 @@
rect.move(0, autoTextDecorationThickness - textDecorationThickness - wavyOffset);
paintDecoration(TextDecorationLine::Overline, m_styles.overlineStyle, m_styles.overlineColor, rect);
}
- if (m_decorations.contains(TextDecorationLine::LineThrough)) {
- FloatRect rect(localOrigin, FloatSize(m_width, textDecorationThickness));
- float autoTextDecorationThickness = TextDecorationThickness::createWithAuto().resolve(m_lineStyle.computedFontSize(), fontMetrics);
- auto center = 2 * fontMetrics.floatAscent() / 3 + autoTextDecorationThickness / 2;
- rect.move(0, center - textDecorationThickness / 2);
- paintDecoration(TextDecorationLine::LineThrough, m_styles.linethroughStyle, m_styles.linethroughColor, rect);
- }
+
+ // We only want to paint the shadow, hence the transparent color, not the actual line-through,
+ // which will be painted in paintForegroundDecorations().
+ if (shadow && m_decorations.contains(TextDecorationLine::LineThrough))
+ paintLineThrough(Color::transparentBlack, textDecorationThickness, localOrigin);
} while (shadow);
if (clipping)
@@ -308,6 +305,34 @@
m_context.clearShadow();
}
+void TextDecorationPainter::paintForegroundDecorations(const FloatPoint& boxOrigin)
+{
+ if (!m_decorations.contains(TextDecorationLine::LineThrough))
+ return;
+
+ float textDecorationThickness = m_lineStyle.textDecorationThickness().resolve(m_lineStyle.computedFontSize(), m_lineStyle.fontMetrics());
+ paintLineThrough(m_styles.linethroughColor, textDecorationThickness, boxOrigin);
+}
+
+void TextDecorationPainter::paintLineThrough(const Color& color, float thickness, const FloatPoint& localOrigin)
+{
+ const auto& fontMetrics = m_lineStyle.fontMetrics();
+ FloatRect rect(localOrigin, FloatSize(m_width, thickness));
+ float autoTextDecorationThickness = TextDecorationThickness::createWithAuto().resolve(m_lineStyle.computedFontSize(), fontMetrics);
+ auto center = 2 * fontMetrics.floatAscent() / 3 + autoTextDecorationThickness / 2;
+ rect.move(0, center - thickness / 2);
+
+ m_context.setStrokeColor(color);
+
+ TextDecorationStyle style = m_styles.linethroughStyle;
+ auto strokeStyle = textDecorationStyleToStrokeStyle(style);
+
+ if (style == TextDecorationStyle::Wavy)
+ strokeWavyTextDecoration(m_context, rect, m_lineStyle.computedFontPixelSize());
+ else
+ m_context.drawLineForText(rect, m_isPrinting, style == TextDecorationStyle::Double, strokeStyle);
+}
+
static void collectStylesForRenderer(TextDecorationPainter::Styles& result, const RenderObject& renderer, OptionSet<TextDecorationLine> remainingDecorations, bool firstLineStyle, PseudoId pseudoId)
{
auto extractDecorations = [&] (const RenderStyle& style, OptionSet<TextDecorationLine> decorations) {
Modified: trunk/Source/WebCore/rendering/TextDecorationPainter.h (286954 => 286955)
--- trunk/Source/WebCore/rendering/TextDecorationPainter.h 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/Source/WebCore/rendering/TextDecorationPainter.h 2021-12-13 18:23:00 UTC (rev 286955)
@@ -52,7 +52,9 @@
void setTextShadow(const ShadowData* textShadow) { m_shadow = textShadow; }
void setShadowColorFilter(const FilterOperations* colorFilter) { m_shadowColorFilter = colorFilter; }
- void paintTextDecoration(const TextRun&, const FloatPoint& textOrigin, const FloatPoint& boxOrigin);
+ void paintBackgroundDecorations(const TextRun&, const FloatPoint& textOrigin, const FloatPoint& boxOrigin);
+ void paintForegroundDecorations(const FloatPoint& boxOrigin);
+ void paintLineThrough(const Color&, float thickness, const FloatPoint& localOrigin);
struct Styles {
bool operator==(const Styles&) const;
Modified: trunk/Source/WebCore/style/InlineTextBoxStyle.cpp (286954 => 286955)
--- trunk/Source/WebCore/style/InlineTextBoxStyle.cpp 2021-12-13 18:13:44 UTC (rev 286954)
+++ trunk/Source/WebCore/style/InlineTextBoxStyle.cpp 2021-12-13 18:23:00 UTC (rev 286955)
@@ -189,7 +189,7 @@
}
// These metrics must match where underlines get drawn.
- // FIXME: Share the code in TextDecorationPainter::paintTextDecoration() so we can just query it for the painted geometry.
+ // FIXME: Share the code in TextDecorationPainter::paintBackgroundDecorations() so we can just query it for the painted geometry.
if (decoration & TextDecorationLine::Underline) {
// Compensate for the integral ceiling in GraphicsContext::computeLineBoundsAndAntialiasingModeForText()
int underlineOffset = 1;