Title: [282270] trunk/Source/WebCore
Revision
282270
Author
an...@apple.com
Date
2021-09-10 08:20:38 -0700 (Fri, 10 Sep 2021)

Log Message

Factor painting functions from LegacyInlineTextBox into a class
https://bugs.webkit.org/show_bug.cgi?id=230147

Reviewed by Alan Bujtas.

Add TextBoxPainter class and move some of the painting functions from LegacyInlineTextBox there.

This patch is largely mechanical but will make it easier to decouple text painting from the legacy
inline boxes in the future.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* rendering/LegacyInlineTextBox.cpp:
(WebCore::LegacyInlineTextBox::paint):
(WebCore::LegacyInlineTextBox::debugTextShadow const):
(WebCore::LegacyInlineTextBox::paintMarkedTexts): Deleted.
(WebCore::LegacyInlineTextBox::paintMarkedTextBackground): Deleted.
(WebCore::LegacyInlineTextBox::paintMarkedTextForeground): Deleted.
(WebCore::LegacyInlineTextBox::paintMarkedTextDecoration): Deleted.
(WebCore::LegacyInlineTextBox::paintCompositionBackground): Deleted.
(WebCore::LegacyInlineTextBox::debugTextShadow): Deleted.
* rendering/LegacyInlineTextBox.h:
(WebCore::LegacyInlineTextBox::paintMarkedTexts): Deleted.
* rendering/MarkedText.h:
* rendering/StyledMarkedText.cpp:
(WebCore::resolveStyleForMarkedText):
(WebCore::computeStyleForUnmarkedMarkedText):
* rendering/StyledMarkedText.h:
* rendering/TextBoxPainter.cpp: Added.
(WebCore::TextBoxPainter::TextBoxPainter):
(WebCore::TextBoxPainter::~TextBoxPainter):
(WebCore::TextBoxPainter::paintCompositionBackground):
(WebCore::TextBoxPainter::paintBackground):
(WebCore::TextBoxPainter::paintForeground):
(WebCore::TextBoxPainter::paintDecoration):
* rendering/TextBoxPainter.h: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (282269 => 282270)


--- trunk/Source/WebCore/ChangeLog	2021-09-10 15:19:46 UTC (rev 282269)
+++ trunk/Source/WebCore/ChangeLog	2021-09-10 15:20:38 UTC (rev 282270)
@@ -1,3 +1,42 @@
+2021-09-10  Antti Koivisto  <an...@apple.com>
+
+        Factor painting functions from LegacyInlineTextBox into a class
+        https://bugs.webkit.org/show_bug.cgi?id=230147
+
+        Reviewed by Alan Bujtas.
+
+        Add TextBoxPainter class and move some of the painting functions from LegacyInlineTextBox there.
+
+        This patch is largely mechanical but will make it easier to decouple text painting from the legacy
+        inline boxes in the future.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * rendering/LegacyInlineTextBox.cpp:
+        (WebCore::LegacyInlineTextBox::paint):
+        (WebCore::LegacyInlineTextBox::debugTextShadow const):
+        (WebCore::LegacyInlineTextBox::paintMarkedTexts): Deleted.
+        (WebCore::LegacyInlineTextBox::paintMarkedTextBackground): Deleted.
+        (WebCore::LegacyInlineTextBox::paintMarkedTextForeground): Deleted.
+        (WebCore::LegacyInlineTextBox::paintMarkedTextDecoration): Deleted.
+        (WebCore::LegacyInlineTextBox::paintCompositionBackground): Deleted.
+        (WebCore::LegacyInlineTextBox::debugTextShadow): Deleted.
+        * rendering/LegacyInlineTextBox.h:
+        (WebCore::LegacyInlineTextBox::paintMarkedTexts): Deleted.
+        * rendering/MarkedText.h:
+        * rendering/StyledMarkedText.cpp:
+        (WebCore::resolveStyleForMarkedText):
+        (WebCore::computeStyleForUnmarkedMarkedText):
+        * rendering/StyledMarkedText.h:
+        * rendering/TextBoxPainter.cpp: Added.
+        (WebCore::TextBoxPainter::TextBoxPainter):
+        (WebCore::TextBoxPainter::~TextBoxPainter):
+        (WebCore::TextBoxPainter::paintCompositionBackground):
+        (WebCore::TextBoxPainter::paintBackground):
+        (WebCore::TextBoxPainter::paintForeground):
+        (WebCore::TextBoxPainter::paintDecoration):
+        * rendering/TextBoxPainter.h: Added.
+
 2021-09-07  Sergio Villar Senin  <svil...@igalia.com>
 
         [css-flexbox] Add support for self-start & self-end css-align-3 positional alignment properties

Modified: trunk/Source/WebCore/Sources.txt (282269 => 282270)


--- trunk/Source/WebCore/Sources.txt	2021-09-10 15:19:46 UTC (rev 282269)
+++ trunk/Source/WebCore/Sources.txt	2021-09-10 15:20:38 UTC (rev 282270)
@@ -2282,6 +2282,7 @@
 rendering/SelectionRangeData.cpp
 rendering/StyledMarkedText.cpp
 rendering/TableLayout.cpp
+rendering/TextBoxPainter.cpp
 rendering/TextDecorationPainter.cpp
 rendering/TextPaintStyle.cpp
 rendering/TextPainter.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (282269 => 282270)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-09-10 15:19:46 UTC (rev 282269)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-09-10 15:20:38 UTC (rev 282270)
@@ -5225,6 +5225,7 @@
 		E43A023B17EB370A004CDD25 /* RenderElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E43A023A17EB370A004CDD25 /* RenderElement.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E43AF8E71AC5B7EC00CA717E /* CacheValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E440AA961C68420800A265CC /* ElementAndTextDescendantIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */; };
+		E440DF5626EB53E0004AF06B /* TextBoxPainter.h in Headers */ = {isa = PBXBuildFile; fileRef = E440DF5426EB53DF004AF06B /* TextBoxPainter.h */; };
 		E440FD5325A4AFDF00F7C849 /* StyledMarkedText.h in Headers */ = {isa = PBXBuildFile; fileRef = E440FD5125A4AFDF00F7C849 /* StyledMarkedText.h */; };
 		E44613A20CD6331000FADA75 /* HTMLAudioElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E44613900CD6331000FADA75 /* HTMLAudioElement.h */; };
 		E44613A50CD6331000FADA75 /* HTMLMediaElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E44613930CD6331000FADA75 /* HTMLMediaElement.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -16291,6 +16292,8 @@
 		E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CacheValidation.cpp; sourceTree = "<group>"; };
 		E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CacheValidation.h; sourceTree = "<group>"; };
 		E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAndTextDescendantIterator.h; sourceTree = "<group>"; };
+		E440DF5426EB53DF004AF06B /* TextBoxPainter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextBoxPainter.h; sourceTree = "<group>"; };
+		E440DF5726EB53EA004AF06B /* TextBoxPainter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextBoxPainter.cpp; sourceTree = "<group>"; };
 		E440FD5125A4AFDF00F7C849 /* StyledMarkedText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyledMarkedText.h; sourceTree = "<group>"; };
 		E440FD5425A4AFEE00F7C849 /* StyledMarkedText.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StyledMarkedText.cpp; sourceTree = "<group>"; };
 		E4451077202C7E0100657D33 /* CompiledSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompiledSelector.h; sourceTree = "<group>"; };
@@ -29867,6 +29870,8 @@
 				A8CFF04C0A154F09000A4234 /* TableLayout.h */,
 				0F54DCE31881051D003EEDBB /* TextAutoSizing.cpp */,
 				0F54DCE41881051D003EEDBB /* TextAutoSizing.h */,
+				E440DF5726EB53EA004AF06B /* TextBoxPainter.cpp */,
+				E440DF5426EB53DF004AF06B /* TextBoxPainter.h */,
 				E447F5B1266CF63D00133F00 /* TextBoxSelectableRange.h */,
 				582DE3221C30C85400BE02A8 /* TextDecorationPainter.cpp */,
 				582DE3231C30C85400BE02A8 /* TextDecorationPainter.h */,
@@ -32553,6 +32558,7 @@
 				318EAD4D1FA91380008CEF86 /* ImageBitmapRenderingContextSettings.h in Headers */,
 				B2A10B920B3818BD00099AA4 /* ImageBuffer.h in Headers */,
 				72BAC3AE23E1F0B0008D741C /* ImageBufferBackend.h in Headers */,
+				E440DF5626EB53E0004AF06B /* TextBoxPainter.h in Headers */,
 				550640B02407587E00AAE045 /* ImageBufferCGBackend.h in Headers */,
 				2D7705C925528D34001D0C94 /* ImageBufferCGBitmapBackend.h in Headers */,
 				727A7F3A24078B84004D2931 /* ImageBufferIOSurfaceBackend.h in Headers */,

Modified: trunk/Source/WebCore/rendering/LegacyInlineTextBox.cpp (282269 => 282270)


--- trunk/Source/WebCore/rendering/LegacyInlineTextBox.cpp	2021-09-10 15:19:46 UTC (rev 282269)
+++ trunk/Source/WebCore/rendering/LegacyInlineTextBox.cpp	2021-09-10 15:20:38 UTC (rev 282270)
@@ -54,6 +54,7 @@
 #include "Settings.h"
 #include "StyledMarkedText.h"
 #include "Text.h"
+#include "TextBoxPainter.h"
 #include "TextBoxSelectableRange.h"
 #include "TextDecorationPainter.h"
 #include "TextPaintStyle.h"
@@ -184,7 +185,7 @@
     return state;
 }
 
-inline const FontCascade& LegacyInlineTextBox::lineFont() const
+const FontCascade& LegacyInlineTextBox::lineFont() const
 {
     return combinedText() ? combinedText()->textCombineFont() : lineStyle().fontCascade();
 }
@@ -213,7 +214,6 @@
     return LayoutRect { topPoint, LayoutSize { width, height } };
 }
 
-// FIXME: Share more code with paintMarkedTextBackground().
 LayoutRect LegacyInlineTextBox::localSelectionRect(unsigned startPos, unsigned endPos) const
 {
     auto [clampedStart, clampedEnd] = selectableRange().clamp(startPos, endPos);
@@ -475,12 +475,8 @@
         return;
     }
 
-    auto* combinedText = this->combinedText();
+    TextBoxPainter textBoxPainter(*this, paintInfo, boxRect);
 
-    bool shouldRotate = !isHorizontal() && !combinedText;
-    if (shouldRotate)
-        context.concatCTM(rotation(boxRect, Clockwise));
-
     // Determine whether or not we have composition underlines to draw.
     bool containsComposition = renderer().textNode() && renderer().frame().editor().compositionNode() == renderer().textNode();
     bool useCustomUnderlines = containsComposition && renderer().frame().editor().compositionUsesCustomUnderlines();
@@ -489,7 +485,7 @@
     // and composition underlines.
     if (paintInfo.phase != PaintPhase::Selection && paintInfo.phase != PaintPhase::TextClip && !isPrinting) {
         if (containsComposition && !useCustomUnderlines)
-            paintCompositionBackground(paintInfo, boxOrigin);
+            textBoxPainter.paintCompositionBackground();
 
         auto selectableRange = this->selectableRange();
 
@@ -509,7 +505,8 @@
         // Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
         auto coalescedStyledMarkedTexts = StyledMarkedText::coalesceAdjacentWithEqualBackground(styledMarkedTexts);
 
-        paintMarkedTexts(paintInfo, MarkedText::PaintPhase::Background, boxRect, coalescedStyledMarkedTexts);
+        for (auto& markedText : coalescedStyledMarkedTexts)
+            textBoxPainter.paintBackground(markedText);
     }
 
     // FIXME: Right now, LegacyInlineTextBoxes never call addRelevantUnpaintedObject() even though they might
@@ -565,7 +562,8 @@
     // Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
     auto coalescedStyledMarkedTexts = StyledMarkedText::coalesceAdjacentWithEqualForeground(styledMarkedTexts);
 
-    paintMarkedTexts(paintInfo, MarkedText::PaintPhase::Foreground, boxRect, coalescedStyledMarkedTexts);
+    for (auto& markedText : coalescedStyledMarkedTexts)
+        textBoxPainter.paintForeground(markedText);
 
     // Paint decorations
     auto textDecorations = lineStyle.textDecorationsInEffect();
@@ -604,15 +602,13 @@
         // Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
         auto coalescedStyledMarkedTexts = StyledMarkedText::coalesceAdjacentWithEqualDecorations(styledMarkedTexts);
 
-        paintMarkedTexts(paintInfo, MarkedText::PaintPhase::Decoration, boxRect, coalescedStyledMarkedTexts, textDecorationSelectionClipOutRect);
+        for (auto& markedText : coalescedStyledMarkedTexts)
+            textBoxPainter.paintDecoration(markedText, textDecorationSelectionClipOutRect);
     }
 
     // 3. Paint fancy decorations, including composition underlines and platform-specific underlines for spelling errors, grammar errors, et cetera.
     if (paintInfo.phase == PaintPhase::Foreground && useCustomUnderlines)
-        paintCompositionUnderlines(paintInfo, boxOrigin);
-    
-    if (shouldRotate)
-        context.concatCTM(rotation(boxRect, Counterclockwise));
+        paintCompositionUnderlines(paintInfo, boxOrigin);    
 }
 
 TextBoxSelectableRange LegacyInlineTextBox::selectableRange() const
@@ -743,185 +739,6 @@
     return textOrigin;
 }
 
-void LegacyInlineTextBox::paintMarkedTexts(PaintInfo& paintInfo, MarkedText::PaintPhase phase, const FloatRect& boxRect, const Vector<StyledMarkedText>& markedTexts, const FloatRect& decorationClipOutRect)
-{
-    switch (phase) {
-    case MarkedText::PaintPhase::Background:
-        for (auto& markedText : markedTexts)
-            paintMarkedTextBackground(paintInfo, boxRect.location(), markedText.style.backgroundColor, markedText.startOffset, markedText.endOffset);
-        return;
-    case MarkedText::PaintPhase::Foreground:
-        for (auto& markedText : markedTexts)
-            paintMarkedTextForeground(paintInfo, boxRect, markedText);
-        return;
-    case MarkedText::PaintPhase::Decoration:
-        for (auto& markedText : markedTexts)
-            paintMarkedTextDecoration(paintInfo, boxRect, decorationClipOutRect, markedText);
-        return;
-    }
-}
-
-void LegacyInlineTextBox::paintMarkedTextBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin, const Color& color, unsigned clampedStartOffset, unsigned clampedEndOffset, MarkedTextBackgroundStyle style)
-{
-    if (clampedStartOffset >= clampedEndOffset)
-        return;
-
-    GraphicsContext& context = paintInfo.context();
-    GraphicsContextStateSaver stateSaver { context };
-    updateGraphicsContext(context, TextPaintStyle { color }); // Don't draw text at all!
-
-    // Note that if the text is truncated, we let the thing being painted in the truncation
-    // draw its own highlight.
-    TextRun textRun = createTextRun();
-
-    const LegacyRootInlineBox& rootBox = root();
-    LayoutUnit selectionBottom = rootBox.selectionBottom();
-    LayoutUnit selectionTop = rootBox.selectionTopAdjustedForPrecedingBlock();
-
-    // Use same y positioning and height as for selection, so that when the selection and this subrange are on
-    // the same word there are no pieces sticking out.
-    LayoutUnit deltaY { renderer().style().isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop };
-    LayoutUnit selectionHeight = std::max<LayoutUnit>(0, selectionBottom - selectionTop);
-
-    LayoutRect selectionRect { LayoutUnit(boxOrigin.x()), LayoutUnit(boxOrigin.y() - deltaY), LayoutUnit(logicalWidth()), selectionHeight };
-    lineFont().adjustSelectionRectForText(textRun, selectionRect, clampedStartOffset, clampedEndOffset);
-
-    // FIXME: Support painting combined text. See <https://bugs.webkit.org/show_bug.cgi?id=180993>.
-    auto backgroundRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, renderer().document().deviceScaleFactor(), textRun.ltr());
-    if (style == MarkedTextBackgroundStyle::Rounded) {
-        backgroundRect.expand(-1, -1);
-        backgroundRect.move(0.5, 0.5);
-        context.fillRoundedRect(FloatRoundedRect { backgroundRect, FloatRoundedRect::Radii { 2 } }, color);
-        return;
-    }
-
-    context.fillRect(backgroundRect, color);
-}
-
-void LegacyInlineTextBox::paintMarkedTextForeground(PaintInfo& paintInfo, const FloatRect& boxRect, const StyledMarkedText& markedText)
-{
-    if (markedText.startOffset >= markedText.endOffset)
-        return;
-
-    GraphicsContext& context = paintInfo.context();
-    const FontCascade& font = lineFont();
-    const RenderStyle& lineStyle = this->lineStyle();
-
-    float emphasisMarkOffset = 0;
-    std::optional<bool> markExistsAndIsAbove = emphasisMarkExistsAndIsAbove(lineStyle);
-    const AtomString& emphasisMark = markExistsAndIsAbove ? lineStyle.textEmphasisMarkString() : nullAtom();
-    if (!emphasisMark.isEmpty())
-        emphasisMarkOffset = *markExistsAndIsAbove ? -font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fontMetrics().descent() + font.emphasisMarkAscent(emphasisMark);
-
-    TextPainter textPainter { context };
-    textPainter.setFont(font);
-    textPainter.setStyle(markedText.style.textStyles);
-    textPainter.setIsHorizontal(isHorizontal());
-    if (markedText.style.textShadow) {
-        textPainter.setShadow(&markedText.style.textShadow.value());
-        if (lineStyle.hasAppleColorFilter())
-            textPainter.setShadowColorFilter(&lineStyle.appleColorFilter());
-    }
-    textPainter.setEmphasisMark(emphasisMark, emphasisMarkOffset, combinedText());
-    if (auto* debugShadow = debugTextShadow())
-        textPainter.setShadow(debugShadow);
-
-    TextRun textRun = createTextRun();
-    textPainter.setGlyphDisplayListIfNeeded(*this, paintInfo, font, context, textRun);
-
-    GraphicsContextStateSaver stateSaver { context, false };
-    if (markedText.type == MarkedText::DraggedContent) {
-        stateSaver.save();
-        context.setAlpha(markedText.style.alpha);
-    }
-    // TextPainter wants the box rectangle and text origin of the entire line box.
-    textPainter.paintRange(textRun, boxRect, textOriginFromBoxRect(boxRect), markedText.startOffset, markedText.endOffset);
-}
-
-void LegacyInlineTextBox::paintMarkedTextDecoration(PaintInfo& paintInfo, const FloatRect& boxRect, const FloatRect& clipOutRect, const StyledMarkedText& markedText)
-{
-    if (m_truncation == cFullTruncation)
-        return;
-
-    GraphicsContext& context = paintInfo.context();
-    updateGraphicsContext(context, markedText.style.textStyles);
-
-    bool isCombinedText = combinedText();
-    if (isCombinedText)
-        context.concatCTM(rotation(boxRect, Clockwise));
-
-    // 1. Compute text selection
-    unsigned startOffset = markedText.startOffset;
-    unsigned endOffset = markedText.endOffset;
-    if (startOffset >= endOffset)
-        return;
-
-    // Note that if the text is truncated, we let the thing being painted in the truncation
-    // draw its own decoration.
-    TextRun textRun = createTextRun();
-
-    // Avoid measuring the text when the entire line box is selected as an optimization.
-    FloatRect snappedSelectionRect = boxRect;
-    if (startOffset || endOffset != textRun.length()) {
-        LayoutRect selectionRect = { boxRect.x(), boxRect.y(), boxRect.width(), boxRect.height() };
-        lineFont().adjustSelectionRectForText(textRun, selectionRect, startOffset, endOffset);
-        snappedSelectionRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, renderer().document().deviceScaleFactor(), textRun.ltr());
-    }
-
-    // 2. Paint
-    auto textDecorations = lineStyle().textDecorationsInEffect();
-    textDecorations.add(TextDecorationPainter::textDecorationsInEffectForStyle(markedText.style.textDecorationStyles));
-    TextDecorationPainter decorationPainter { context, textDecorations, renderer(), isFirstLine(), lineFont(), markedText.style.textDecorationStyles };
-    decorationPainter.setTextRunIterator(LayoutIntegration::textRunFor(this));
-    decorationPainter.setWidth(snappedSelectionRect.width());
-    decorationPainter.setIsHorizontal(isHorizontal());
-    if (markedText.style.textShadow) {
-        decorationPainter.setTextShadow(&markedText.style.textShadow.value());
-        if (lineStyle().hasAppleColorFilter())
-            decorationPainter.setShadowColorFilter(&lineStyle().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(textRun.subRun(startOffset, endOffset - startOffset), textOriginFromBoxRect(snappedSelectionRect), snappedSelectionRect.location());
-    }
-
-    if (isCombinedText)
-        context.concatCTM(rotation(boxRect, Counterclockwise));
-}
-
-void LegacyInlineTextBox::paintCompositionBackground(PaintInfo& paintInfo, const FloatPoint& boxOrigin)
-{
-    auto selectableRange = this->selectableRange();
-
-    if (!renderer().frame().editor().compositionUsesCustomHighlights()) {
-        paintMarkedTextBackground(paintInfo, boxOrigin, CompositionHighlight::defaultCompositionFillColor, selectableRange.clamp(renderer().frame().editor().compositionStart()), selectableRange.clamp(renderer().frame().editor().compositionEnd()));
-        return;
-    }
-
-    for (auto& highlight : renderer().frame().editor().customCompositionHighlights()) {
-        if (highlight.endOffset <= m_start)
-            continue;
-
-        if (highlight.startOffset >= end())
-            break;
-
-        auto [clampedStart, clampedEnd] = selectableRange.clamp(highlight.startOffset, highlight.endOffset);
-        paintMarkedTextBackground(paintInfo, boxOrigin, highlight.color, clampedStart, clampedEnd, MarkedTextBackgroundStyle::Rounded);
-
-        if (highlight.endOffset > end())
-            break;
-    }
-}
-
 void LegacyInlineTextBox::paintCompositionUnderlines(PaintInfo& paintInfo, const FloatPoint& boxOrigin) const
 {
     if (m_truncation == cFullTruncation)
@@ -1089,12 +906,12 @@
     return RenderBlock::updateSecurityDiscCharacters(lineStyle(), WTFMove(result));
 }
 
-inline const RenderCombineText* LegacyInlineTextBox::combinedText() const
+const RenderCombineText* LegacyInlineTextBox::combinedText() const
 {
     return lineStyle().hasTextCombine() && is<RenderCombineText>(renderer()) && downcast<RenderCombineText>(renderer()).isCombined() ? &downcast<RenderCombineText>(renderer()) : nullptr;
 }
 
-ShadowData* LegacyInlineTextBox::debugTextShadow()
+const ShadowData* LegacyInlineTextBox::debugTextShadow() const
 {
     if (!renderer().settings().legacyLineLayoutVisualCoverageEnabled())
         return nullptr;

Modified: trunk/Source/WebCore/rendering/LegacyInlineTextBox.h (282269 => 282270)


--- trunk/Source/WebCore/rendering/LegacyInlineTextBox.h	2021-09-10 15:19:46 UTC (rev 282269)
+++ trunk/Source/WebCore/rendering/LegacyInlineTextBox.h	2021-09-10 15:20:38 UTC (rev 282270)
@@ -163,26 +163,20 @@
     FloatRect calculateDocumentMarkerBounds(const MarkedText&) const;
 
 private:
+    friend class TextBoxPainter;
+
     FloatPoint textOriginFromBoxRect(const FloatRect&) const;
 
-    void paintMarkedTexts(PaintInfo&, MarkedText::PaintPhase, const FloatRect& boxRect, const Vector<StyledMarkedText>&, const FloatRect& decorationClipOutRect = { });
-
     void paintPlatformDocumentMarker(GraphicsContext&, const FloatPoint& boxOrigin, const MarkedText&);
     void paintPlatformDocumentMarkers(GraphicsContext&, const FloatPoint& boxOrigin);
 
-    void paintCompositionBackground(PaintInfo&, const FloatPoint& boxOrigin);
     void paintCompositionUnderlines(PaintInfo&, const FloatPoint& boxOrigin) const;
     void paintCompositionUnderline(PaintInfo&, const FloatPoint& boxOrigin, const CompositionUnderline&) const;
 
-    enum class MarkedTextBackgroundStyle : bool { Default, Rounded };
-    void paintMarkedTextBackground(PaintInfo&, const FloatPoint& boxOrigin, const Color&, unsigned clampedStartOffset, unsigned clampedEndOffset, MarkedTextBackgroundStyle = MarkedTextBackgroundStyle::Default);
-    void paintMarkedTextForeground(PaintInfo&, const FloatRect& boxRect, const StyledMarkedText&);
-    void paintMarkedTextDecoration(PaintInfo&, const FloatRect& boxRect, const FloatRect& clipOutRect, const StyledMarkedText&);
-
     const RenderCombineText* combinedText() const;
     const FontCascade& lineFont() const;
 
-    ShadowData* debugTextShadow();
+    const ShadowData* debugTextShadow() const;
 
     String text(bool ignoreCombinedText = false, bool ignoreHyphen = false) const; // The effective text for the run.
     TextRun createTextRun(bool ignoreCombinedText = false, bool ignoreHyphen = false) const;

Modified: trunk/Source/WebCore/rendering/StyledMarkedText.cpp (282269 => 282270)


--- trunk/Source/WebCore/rendering/StyledMarkedText.cpp	2021-09-10 15:19:46 UTC (rev 282269)
+++ trunk/Source/WebCore/rendering/StyledMarkedText.cpp	2021-09-10 15:20:38 UTC (rev 282270)
@@ -111,7 +111,6 @@
     style.textDecorationStyles = TextDecorationPainter::stylesForRenderer(renderer, lineStyle.textDecorationsInEffect(), isFirstLine);
     style.textStyles = computeTextPaintStyle(renderer.frame(), lineStyle, paintInfo);
     style.textShadow = ShadowData::clone(paintInfo.forceTextColor() ? nullptr : lineStyle.textShadow());
-    style.alpha = 1;
     return style;
 }
 

Modified: trunk/Source/WebCore/rendering/StyledMarkedText.h (282269 => 282270)


--- trunk/Source/WebCore/rendering/StyledMarkedText.h	2021-09-10 15:19:46 UTC (rev 282269)
+++ trunk/Source/WebCore/rendering/StyledMarkedText.h	2021-09-10 15:20:38 UTC (rev 282270)
@@ -46,7 +46,7 @@
         TextPaintStyle textStyles;
         TextDecorationPainter::Styles textDecorationStyles;
         std::optional<ShadowData> textShadow;
-        float alpha;
+        float alpha { 1 };
     };
 
     Style style;

Added: trunk/Source/WebCore/rendering/TextBoxPainter.cpp (0 => 282270)


--- trunk/Source/WebCore/rendering/TextBoxPainter.cpp	                        (rev 0)
+++ trunk/Source/WebCore/rendering/TextBoxPainter.cpp	2021-09-10 15:20:38 UTC (rev 282270)
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2021 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 "TextBoxPainter.h"
+
+#include "CompositionHighlight.h"
+#include "Editor.h"
+#include "GraphicsContext.h"
+#include "LegacyInlineTextBox.h"
+#include "PaintInfo.h"
+#include "StyledMarkedText.h"
+#include "TextPaintStyle.h"
+#include "TextPainter.h"
+
+namespace WebCore {
+
+TextBoxPainter::TextBoxPainter(const LegacyInlineTextBox& textBox, PaintInfo& paintInfo, const FloatRect& boxRect)
+    : m_textBox(textBox)
+    , m_paintInfo(paintInfo)
+    , m_boxRect(boxRect)
+{
+    bool shouldRotate = !m_textBox.isHorizontal() && !m_textBox.combinedText();
+    if (shouldRotate)
+        m_paintInfo.context().concatCTM(rotation(m_boxRect, Clockwise));
+}
+
+TextBoxPainter::~TextBoxPainter()
+{
+    bool shouldRotate = !m_textBox.isHorizontal() && !m_textBox.combinedText();
+    if (shouldRotate)
+        m_paintInfo.context().concatCTM(rotation(m_boxRect, Counterclockwise));
+}
+
+void TextBoxPainter::paintCompositionBackground()
+{
+    auto selectableRange = m_textBox.selectableRange();
+
+    auto& editor = m_textBox.renderer().frame().editor();
+
+    if (!editor.compositionUsesCustomHighlights()) {
+        auto [clampedStart, clampedEnd] = selectableRange.clamp(editor.compositionStart(), editor.compositionEnd());
+
+        paintBackground(clampedStart, clampedEnd, CompositionHighlight::defaultCompositionFillColor);
+        return;
+    }
+
+    for (auto& highlight : editor.customCompositionHighlights()) {
+        if (highlight.endOffset <= m_textBox.start())
+            continue;
+
+        if (highlight.startOffset >= m_textBox.end())
+            break;
+
+        auto [clampedStart, clampedEnd] = selectableRange.clamp(highlight.startOffset, highlight.endOffset);
+
+        paintBackground(clampedStart, clampedEnd, highlight.color, BackgroundStyle::Rounded);
+
+        if (highlight.endOffset > m_textBox.end())
+            break;
+    }
+}
+
+void TextBoxPainter::paintBackground(const StyledMarkedText& markedText)
+{
+    paintBackground(markedText.startOffset, markedText.endOffset, markedText.style.backgroundColor);
+}
+
+void TextBoxPainter::paintBackground(unsigned startOffset, unsigned endOffset, const Color& color, BackgroundStyle backgroundStyle)
+{
+    if (startOffset >= endOffset)
+        return;
+
+    GraphicsContext& context = m_paintInfo.context();
+    GraphicsContextStateSaver stateSaver { context };
+    updateGraphicsContext(context, TextPaintStyle { color }); // Don't draw text at all!
+
+    // Note that if the text is truncated, we let the thing being painted in the truncation
+    // draw its own highlight.
+    TextRun textRun = m_textBox.createTextRun();
+
+    const LegacyRootInlineBox& rootBox = m_textBox.root();
+    LayoutUnit selectionBottom = rootBox.selectionBottom();
+    LayoutUnit selectionTop = rootBox.selectionTopAdjustedForPrecedingBlock();
+
+    // Use same y positioning and height as for selection, so that when the selection and this subrange are on
+    // the same word there are no pieces sticking out.
+    LayoutUnit deltaY { m_textBox.renderer().style().isFlippedLinesWritingMode() ? selectionBottom - m_textBox.logicalBottom() : m_textBox.logicalTop() - selectionTop };
+    LayoutUnit selectionHeight = std::max<LayoutUnit>(0, selectionBottom - selectionTop);
+
+    LayoutRect selectionRect { LayoutUnit(m_boxRect.x()), LayoutUnit(m_boxRect.y() - deltaY), LayoutUnit(m_textBox.logicalWidth()), selectionHeight };
+    m_textBox.lineFont().adjustSelectionRectForText(textRun, selectionRect, startOffset, endOffset);
+
+    // FIXME: Support painting combined text. See <https://bugs.webkit.org/show_bug.cgi?id=180993>.
+    auto backgroundRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_textBox.renderer().document().deviceScaleFactor(), textRun.ltr());
+    if (backgroundStyle == BackgroundStyle::Rounded) {
+        backgroundRect.expand(-1, -1);
+        backgroundRect.move(0.5, 0.5);
+        context.fillRoundedRect(FloatRoundedRect { backgroundRect, FloatRoundedRect::Radii { 2 } }, color);
+        return;
+    }
+
+    context.fillRect(backgroundRect, color);
+}
+
+void TextBoxPainter::paintForeground(const StyledMarkedText& markedText)
+{
+    if (markedText.startOffset >= markedText.endOffset)
+        return;
+
+    GraphicsContext& context = m_paintInfo.context();
+    const FontCascade& font = m_textBox.lineFont();
+    const RenderStyle& lineStyle = m_textBox.lineStyle();
+
+    float emphasisMarkOffset = 0;
+    std::optional<bool> markExistsAndIsAbove = m_textBox.emphasisMarkExistsAndIsAbove(lineStyle);
+    const AtomString& emphasisMark = markExistsAndIsAbove ? lineStyle.textEmphasisMarkString() : nullAtom();
+    if (!emphasisMark.isEmpty())
+        emphasisMarkOffset = *markExistsAndIsAbove ? -font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fontMetrics().descent() + font.emphasisMarkAscent(emphasisMark);
+
+    TextPainter textPainter { context };
+    textPainter.setFont(font);
+    textPainter.setStyle(markedText.style.textStyles);
+    textPainter.setIsHorizontal(m_textBox.isHorizontal());
+    if (markedText.style.textShadow) {
+        textPainter.setShadow(&markedText.style.textShadow.value());
+        if (lineStyle.hasAppleColorFilter())
+            textPainter.setShadowColorFilter(&lineStyle.appleColorFilter());
+    }
+    textPainter.setEmphasisMark(emphasisMark, emphasisMarkOffset, m_textBox.combinedText());
+    if (auto* debugShadow = m_textBox.debugTextShadow())
+        textPainter.setShadow(debugShadow);
+
+    TextRun textRun = m_textBox.createTextRun();
+    textPainter.setGlyphDisplayListIfNeeded(m_textBox, m_paintInfo, font, context, textRun);
+
+    GraphicsContextStateSaver stateSaver { context, false };
+    if (markedText.type == MarkedText::DraggedContent) {
+        stateSaver.save();
+        context.setAlpha(markedText.style.alpha);
+    }
+    // TextPainter wants the box rectangle and text origin of the entire line box.
+    textPainter.paintRange(textRun, m_boxRect, m_textBox.textOriginFromBoxRect(m_boxRect), markedText.startOffset, markedText.endOffset);
+}
+
+void TextBoxPainter::paintDecoration(const StyledMarkedText& markedText, const FloatRect& clipOutRect)
+{
+    if (m_textBox.truncation() == cFullTruncation)
+        return;
+
+    GraphicsContext& context = m_paintInfo.context();
+    const FontCascade& font = m_textBox.lineFont();
+    const RenderStyle& lineStyle = m_textBox.lineStyle();
+
+    updateGraphicsContext(context, markedText.style.textStyles);
+
+    bool isCombinedText = m_textBox.combinedText();
+    if (isCombinedText)
+        context.concatCTM(rotation(m_boxRect, Clockwise));
+
+    // 1. Compute text selection
+    unsigned startOffset = markedText.startOffset;
+    unsigned endOffset = markedText.endOffset;
+    if (startOffset >= endOffset)
+        return;
+
+    // Note that if the text is truncated, we let the thing being painted in the truncation
+    // draw its own decoration.
+    TextRun textRun = m_textBox.createTextRun();
+
+    // Avoid measuring the text when the entire line box is selected as an optimization.
+    FloatRect snappedSelectionRect = m_boxRect;
+    if (startOffset || endOffset != textRun.length()) {
+        LayoutRect selectionRect = { m_boxRect.x(), m_boxRect.y(), m_boxRect.width(), m_boxRect.height() };
+        font.adjustSelectionRectForText(textRun, selectionRect, startOffset, endOffset);
+        snappedSelectionRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_textBox.renderer().document().deviceScaleFactor(), textRun.ltr());
+    }
+
+    // 2. Paint
+    auto textDecorations = lineStyle.textDecorationsInEffect();
+    textDecorations.add(TextDecorationPainter::textDecorationsInEffectForStyle(markedText.style.textDecorationStyles));
+    TextDecorationPainter decorationPainter { context, textDecorations, m_textBox.renderer(), m_textBox.isFirstLine(), font, markedText.style.textDecorationStyles };
+    decorationPainter.setTextRunIterator(LayoutIntegration::textRunFor(&m_textBox));
+    decorationPainter.setWidth(snappedSelectionRect.width());
+    decorationPainter.setIsHorizontal(m_textBox.isHorizontal());
+    if (markedText.style.textShadow) {
+        decorationPainter.setTextShadow(&markedText.style.textShadow.value());
+        if (lineStyle.hasAppleColorFilter())
+            decorationPainter.setShadowColorFilter(&lineStyle.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(textRun.subRun(startOffset, endOffset - startOffset), m_textBox.textOriginFromBoxRect(snappedSelectionRect), snappedSelectionRect.location());
+    }
+
+    if (isCombinedText)
+        context.concatCTM(rotation(m_boxRect, Counterclockwise));
+}
+
+}

Added: trunk/Source/WebCore/rendering/TextBoxPainter.h (0 => 282270)


--- trunk/Source/WebCore/rendering/TextBoxPainter.h	                        (rev 0)
+++ trunk/Source/WebCore/rendering/TextBoxPainter.h	2021-09-10 15:20:38 UTC (rev 282270)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+
+#include "FloatRect.h"
+
+namespace WebCore {
+
+class FontCascade;
+class LegacyInlineTextBox;
+class RenderCombineText;
+struct PaintInfo;
+struct StyledMarkedText;
+
+class TextBoxPainter {
+public:
+    TextBoxPainter(const LegacyInlineTextBox&, PaintInfo&, const FloatRect& boxRect);
+    ~TextBoxPainter();
+
+    void paintCompositionBackground();
+    void paintBackground(const StyledMarkedText&);
+    void paintForeground(const StyledMarkedText&);
+    void paintDecoration(const StyledMarkedText&, const FloatRect& clipOutRect);
+
+private:
+    enum class BackgroundStyle { Normal, Rounded };
+    void paintBackground(unsigned startOffset, unsigned endOffset, const Color&, BackgroundStyle = BackgroundStyle::Normal);
+
+    const LegacyInlineTextBox& m_textBox;
+    PaintInfo& m_paintInfo;
+    const FloatRect m_boxRect;
+};
+
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to