Modified: trunk/Source/WebCore/rendering/TextBoxPainter.cpp (282734 => 282735)
--- trunk/Source/WebCore/rendering/TextBoxPainter.cpp 2021-09-19 04:25:25 UTC (rev 282734)
+++ trunk/Source/WebCore/rendering/TextBoxPainter.cpp 2021-09-19 14:27:51 UTC (rev 282735)
@@ -29,10 +29,14 @@
#include "Editor.h"
#include "EventRegion.h"
#include "GraphicsContext.h"
+#include "LayoutIntegrationLineIterator.h"
+#include "LayoutIntegrationRunIterator.h"
#include "LegacyInlineTextBox.h"
#include "PaintInfo.h"
#include "RenderBlock.h"
+#include "RenderCombineText.h"
#include "RenderText.h"
+#include "ShadowData.h"
#include "StyledMarkedText.h"
#include "TextPaintStyle.h"
#include "TextPainter.h"
@@ -40,13 +44,28 @@
namespace WebCore {
TextBoxPainter::TextBoxPainter(const LegacyInlineTextBox& textBox, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
- : m_textBox(textBox)
- , m_renderer(textBox.renderer())
+ : TextBoxPainter(LayoutIntegration::textRunFor(&textBox), paintInfo, paintOffset)
+{
+ m_emphasisMarkExistsAndIsAbove = textBox.emphasisMarkExistsAndIsAbove(m_style);
+}
+
+TextBoxPainter::TextBoxPainter(const LayoutIntegration::InlineContent& inlineContent, const Layout::Run& run, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+ : TextBoxPainter(LayoutIntegration::textRunFor(inlineContent, run), paintInfo, paintOffset)
+{
+}
+
+TextBoxPainter::TextBoxPainter(LayoutIntegration::TextRunIterator&& textBox, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
+ : m_textBox(WTFMove(textBox))
+ , m_renderer(m_textBox->renderer())
, m_document(m_renderer.document())
+ , m_style(m_textBox->style())
+ , m_paintTextRun(m_textBox->createTextRun())
, m_paintInfo(paintInfo)
- , m_paintRect(computePaintRect(textBox, paintOffset))
+ , m_selectableRange(m_textBox->selectableRange())
+ , m_paintRect(computePaintRect(paintOffset))
+ , m_isFirstLine(m_textBox->line()->isFirst())
, m_isPrinting(m_document.printing())
- , m_haveSelection(!m_isPrinting && m_paintInfo.phase != PaintPhase::TextClip && m_textBox.selectionState() != RenderObject::HighlightState::None)
+ , m_haveSelection(computeHaveSelection())
, m_containsComposition(m_renderer.textNode() && m_renderer.frame().editor().compositionNode() == m_renderer.textNode())
, m_useCustomUnderlines(m_containsComposition && m_renderer.frame().editor().compositionUsesCustomUnderlines())
{
@@ -64,11 +83,11 @@
if (m_paintInfo.phase == PaintPhase::EventRegion) {
if (m_renderer.parent()->visibleToHitTesting())
- m_paintInfo.eventRegionContext->unite(enclosingIntRect(m_paintRect), m_renderer.style());
+ m_paintInfo.eventRegionContext->unite(enclosingIntRect(m_paintRect), m_style);
return;
}
- bool shouldRotate = !m_textBox.isHorizontal() && !m_textBox.combinedText();
+ bool shouldRotate = !textBox().isHorizontal() && !combinedText();
if (shouldRotate)
m_paintInfo.context().concatCTM(rotation(m_paintRect, Clockwise));
@@ -92,9 +111,9 @@
m_paintInfo.context().concatCTM(rotation(m_paintRect, Counterclockwise));
}
-static MarkedText createMarkedTextFromSelectionInBox(const LegacyInlineTextBox& box)
+MarkedText TextBoxPainter::createMarkedTextFromSelectionInBox()
{
- auto [selectionStart, selectionEnd] = box.selectionStartEnd();
+ auto [selectionStart, selectionEnd] = m_renderer.view().selection().rangeForTextBox(m_renderer, m_selectableRange);
if (selectionStart < selectionEnd)
return { selectionStart, selectionEnd, MarkedText::Selection };
return { };
@@ -105,20 +124,18 @@
if (m_containsComposition && !m_useCustomUnderlines)
paintCompositionBackground();
- auto selectableRange = m_textBox.selectableRange();
-
Vector<MarkedText> markedTexts;
- markedTexts.appendVector(MarkedText::collectForDocumentMarkers(m_renderer, selectableRange, MarkedText::PaintPhase::Background));
- markedTexts.appendVector(MarkedText::collectForHighlights(m_renderer, selectableRange, MarkedText::PaintPhase::Background));
+ markedTexts.appendVector(MarkedText::collectForDocumentMarkers(m_renderer, m_selectableRange, MarkedText::PaintPhase::Background));
+ markedTexts.appendVector(MarkedText::collectForHighlights(m_renderer, m_selectableRange, MarkedText::PaintPhase::Background));
#if ENABLE(TEXT_SELECTION)
if (m_haveSelection && !m_useCustomUnderlines && !m_paintInfo.context().paintingDisabled()) {
- auto selectionMarkedText = createMarkedTextFromSelectionInBox(m_textBox);
+ auto selectionMarkedText = createMarkedTextFromSelectionInBox();
if (!selectionMarkedText.isEmpty())
markedTexts.append(WTFMove(selectionMarkedText));
}
#endif
- auto styledMarkedTexts = StyledMarkedText::subdivideAndResolve(markedTexts, m_renderer, m_textBox.isFirstLine(), m_paintInfo);
+ auto styledMarkedTexts = StyledMarkedText::subdivideAndResolve(markedTexts, m_renderer, m_isFirstLine, m_paintInfo);
// Coalesce styles of adjacent marked texts to minimize the number of drawing commands.
auto coalescedStyledMarkedTexts = StyledMarkedText::coalesceAdjacentWithEqualBackground(styledMarkedTexts);
@@ -132,18 +149,16 @@
bool shouldPaintSelectionForeground = m_haveSelection && !m_useCustomUnderlines;
Vector<MarkedText> markedTexts;
if (m_paintInfo.phase != PaintPhase::Selection) {
- auto selectableRange = m_textBox.selectableRange();
-
// The marked texts for the gaps between document markers and selection are implicitly created by subdividing the entire line.
- markedTexts.append({ selectableRange.clamp(m_textBox.start()), selectableRange.clamp(m_textBox.end()), MarkedText::Unmarked });
+ markedTexts.append({ m_selectableRange.clamp(textBox().start()), m_selectableRange.clamp(textBox().end()), MarkedText::Unmarked });
if (!m_isPrinting) {
- markedTexts.appendVector(MarkedText::collectForDocumentMarkers(m_renderer, selectableRange, MarkedText::PaintPhase::Foreground));
- markedTexts.appendVector(MarkedText::collectForHighlights(m_renderer, selectableRange, MarkedText::PaintPhase::Foreground));
+ markedTexts.appendVector(MarkedText::collectForDocumentMarkers(m_renderer, m_selectableRange, MarkedText::PaintPhase::Foreground));
+ markedTexts.appendVector(MarkedText::collectForHighlights(m_renderer, m_selectableRange, MarkedText::PaintPhase::Foreground));
bool shouldPaintDraggedContent = !(m_paintInfo.paintBehavior.contains(PaintBehavior::ExcludeSelection));
if (shouldPaintDraggedContent) {
- auto markedTextsForDraggedContent = MarkedText::collectForDraggedContent(m_renderer, selectableRange);
+ auto markedTextsForDraggedContent = MarkedText::collectForDraggedContent(m_renderer, m_selectableRange);
if (!markedTextsForDraggedContent.isEmpty()) {
shouldPaintSelectionForeground = false;
markedTexts.appendVector(markedTextsForDraggedContent);
@@ -154,12 +169,12 @@
// The selection marked text acts as a placeholder when computing the marked texts for the gaps...
if (shouldPaintSelectionForeground) {
ASSERT(!m_isPrinting);
- auto selectionMarkedText = createMarkedTextFromSelectionInBox(m_textBox);
+ auto selectionMarkedText = createMarkedTextFromSelectionInBox();
if (!selectionMarkedText.isEmpty())
markedTexts.append(WTFMove(selectionMarkedText));
}
- auto styledMarkedTexts = StyledMarkedText::subdivideAndResolve(markedTexts, m_renderer, m_textBox.isFirstLine(), m_paintInfo);
+ auto styledMarkedTexts = StyledMarkedText::subdivideAndResolve(markedTexts, m_renderer, m_isFirstLine, m_paintInfo);
// ... now remove the selection marked text if we are excluding selection.
if (!m_isPrinting && m_paintInfo.paintBehavior.contains(PaintBehavior::ExcludeSelection)) {
@@ -174,16 +189,16 @@
for (auto& markedText : coalescedStyledMarkedTexts)
paintForeground(markedText);
- auto textDecorations = m_textBox.lineStyle().textDecorationsInEffect();
- bool highlightDecorations = !MarkedText::collectForHighlights(m_renderer, m_textBox.selectableRange(), MarkedText::PaintPhase::Decoration).isEmpty();
+ auto textDecorations = m_style.textDecorationsInEffect();
+ bool highlightDecorations = !MarkedText::collectForHighlights(m_renderer, m_selectableRange, MarkedText::PaintPhase::Decoration).isEmpty();
bool lineDecorations = !textDecorations.isEmpty();
if ((lineDecorations || highlightDecorations) && m_paintInfo.phase != PaintPhase::Selection) {
- TextRun textRun = m_textBox.createTextRun();
- unsigned length = m_textBox.truncation().value_or(textRun.length());
+ TextRun textRun = textBox().createTextRun();
+ unsigned length = m_selectableRange.truncation.value_or(textRun.length());
unsigned selectionStart = 0;
unsigned selectionEnd = 0;
if (m_haveSelection)
- std::tie(selectionStart, selectionEnd) = m_textBox.selectionStartEnd();
+ std::tie(selectionStart, selectionEnd) = m_renderer.view().selection().rangeForTextBox(m_renderer, m_selectableRange);
FloatRect textDecorationSelectionClipOutRect;
if ((m_paintInfo.paintBehavior.contains(PaintBehavior::ExcludeSelection)) && selectionStart < selectionEnd && selectionEnd <= length) {
@@ -190,12 +205,12 @@
textDecorationSelectionClipOutRect = m_paintRect;
float logicalWidthBeforeRange;
float logicalWidthAfterRange;
- float logicalSelectionWidth = m_textBox.lineFont().widthOfTextRange(textRun, selectionStart, selectionEnd, nullptr, &logicalWidthBeforeRange, &logicalWidthAfterRange);
+ float logicalSelectionWidth = fontCascade().widthOfTextRange(m_paintTextRun, selectionStart, selectionEnd, nullptr, &logicalWidthBeforeRange, &logicalWidthAfterRange);
// FIXME: Do we need to handle vertical bottom to top text?
- if (!m_textBox.isHorizontal()) {
+ if (!textBox().isHorizontal()) {
textDecorationSelectionClipOutRect.move(0, logicalWidthBeforeRange);
textDecorationSelectionClipOutRect.setHeight(logicalSelectionWidth);
- } else if (m_textBox.direction() == TextDirection::RTL) {
+ } else if (textBox().direction() == TextDirection::RTL) {
textDecorationSelectionClipOutRect.move(logicalWidthAfterRange, 0);
textDecorationSelectionClipOutRect.setWidth(logicalSelectionWidth);
} else {
@@ -214,12 +229,10 @@
void TextBoxPainter::paintCompositionBackground()
{
- auto selectableRange = m_textBox.selectableRange();
-
auto& editor = m_renderer.frame().editor();
if (!editor.compositionUsesCustomHighlights()) {
- auto [clampedStart, clampedEnd] = selectableRange.clamp(editor.compositionStart(), editor.compositionEnd());
+ auto [clampedStart, clampedEnd] = m_selectableRange.clamp(editor.compositionStart(), editor.compositionEnd());
paintBackground(clampedStart, clampedEnd, CompositionHighlight::defaultCompositionFillColor);
return;
@@ -226,17 +239,17 @@
}
for (auto& highlight : editor.customCompositionHighlights()) {
- if (highlight.endOffset <= m_textBox.start())
+ if (highlight.endOffset <= textBox().start())
continue;
- if (highlight.startOffset >= m_textBox.end())
+ if (highlight.startOffset >= textBox().end())
break;
- auto [clampedStart, clampedEnd] = selectableRange.clamp(highlight.startOffset, highlight.endOffset);
+ auto [clampedStart, clampedEnd] = m_selectableRange.clamp(highlight.startOffset, highlight.endOffset);
paintBackground(clampedStart, clampedEnd, highlight.color, BackgroundStyle::Rounded);
- if (highlight.endOffset > m_textBox.end())
+ if (highlight.endOffset > textBox().end())
break;
}
}
@@ -257,22 +270,21 @@
// 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();
+ const auto line = textBox().line();
+ LayoutUnit selectionBottom = line->selectionBottom();
+ LayoutUnit selectionTop = line->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_renderer.style().isFlippedLinesWritingMode() ? selectionBottom - m_textBox.logicalBottom() : m_textBox.logicalTop() - selectionTop };
+ LayoutUnit deltaY { m_style.isFlippedLinesWritingMode() ? selectionBottom - textBox().logicalBottom() : textBox().logicalTop() - selectionTop };
LayoutUnit selectionHeight = std::max<LayoutUnit>(0, selectionBottom - selectionTop);
- LayoutRect selectionRect { LayoutUnit(m_paintRect.x()), LayoutUnit(m_paintRect.y() - deltaY), LayoutUnit(m_textBox.logicalWidth()), selectionHeight };
- m_textBox.lineFont().adjustSelectionRectForText(textRun, selectionRect, startOffset, endOffset);
+ LayoutRect selectionRect { LayoutUnit(m_paintRect.x()), LayoutUnit(m_paintRect.y() - deltaY), LayoutUnit(textBox().logicalWidth()), selectionHeight };
+ fontCascade().adjustSelectionRectForText(m_paintTextRun, selectionRect, startOffset, endOffset);
// FIXME: Support painting combined text. See <https://bugs.webkit.org/show_bug.cgi?id=180993>.
- auto backgroundRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_document.deviceScaleFactor(), textRun.ltr());
+ auto backgroundRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_document.deviceScaleFactor(), m_paintTextRun.ltr());
if (backgroundStyle == BackgroundStyle::Rounded) {
backgroundRect.expand(-1, -1);
backgroundRect.move(0.5, 0.5);
@@ -289,30 +301,30 @@
return;
GraphicsContext& context = m_paintInfo.context();
- const FontCascade& font = m_textBox.lineFont();
- const RenderStyle& lineStyle = m_textBox.lineStyle();
+ const FontCascade& font = fontCascade();
float emphasisMarkOffset = 0;
- std::optional<bool> markExistsAndIsAbove = m_textBox.emphasisMarkExistsAndIsAbove(lineStyle);
- const AtomString& emphasisMark = markExistsAndIsAbove ? lineStyle.textEmphasisMarkString() : nullAtom();
+ const AtomString& emphasisMark = m_emphasisMarkExistsAndIsAbove ? m_style.textEmphasisMarkString() : nullAtom();
if (!emphasisMark.isEmpty())
- emphasisMarkOffset = *markExistsAndIsAbove ? -font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fontMetrics().descent() + font.emphasisMarkAscent(emphasisMark);
+ emphasisMarkOffset = *m_emphasisMarkExistsAndIsAbove ? -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());
+ textPainter.setIsHorizontal(textBox().isHorizontal());
if (markedText.style.textShadow) {
textPainter.setShadow(&markedText.style.textShadow.value());
- if (lineStyle.hasAppleColorFilter())
- textPainter.setShadowColorFilter(&lineStyle.appleColorFilter());
+ if (m_style.hasAppleColorFilter())
+ textPainter.setShadowColorFilter(&m_style.appleColorFilter());
}
- textPainter.setEmphasisMark(emphasisMark, emphasisMarkOffset, m_textBox.combinedText());
- if (auto* debugShadow = m_textBox.debugTextShadow())
+ textPainter.setEmphasisMark(emphasisMark, emphasisMarkOffset, combinedText());
+ if (auto* debugShadow = debugTextShadow())
textPainter.setShadow(debugShadow);
- TextRun textRun = m_textBox.createTextRun();
- textPainter.setGlyphDisplayListIfNeeded(m_textBox, m_paintInfo, font, context, textRun);
+ if (auto* legacyInlineBox = textBox().legacyInlineBox())
+ textPainter.setGlyphDisplayListIfNeeded(*legacyInlineBox, m_paintInfo, font, context, m_paintTextRun);
+ else
+ textPainter.setGlyphDisplayListIfNeeded(*textBox().inlineBox(), m_paintInfo, font, context, m_paintTextRun);
GraphicsContextStateSaver stateSaver { context, false };
if (markedText.type == MarkedText::DraggedContent) {
@@ -320,7 +332,7 @@
context.setAlpha(markedText.style.alpha);
}
// TextPainter wants the box rectangle and text origin of the entire line box.
- textPainter.paintRange(textRun, m_paintRect, m_textBox.textOriginFromBoxRect(m_paintRect), markedText.startOffset, markedText.endOffset);
+ textPainter.paintRange(m_paintTextRun, m_paintRect, textOriginFromPaintRect(m_paintRect), markedText.startOffset, markedText.endOffset);
}
void TextBoxPainter::paintDecoration(const StyledMarkedText& markedText, const FloatRect& clipOutRect)
@@ -332,38 +344,36 @@
return;
GraphicsContext& context = m_paintInfo.context();
- const FontCascade& font = m_textBox.lineFont();
- const RenderStyle& lineStyle = m_textBox.lineStyle();
+ const FontCascade& font = fontCascade();
updateGraphicsContext(context, markedText.style.textStyles);
- bool isCombinedText = m_textBox.combinedText();
+ bool isCombinedText = combinedText();
if (isCombinedText)
context.concatCTM(rotation(m_paintRect, Clockwise));
// 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_paintRect;
- if (startOffset || endOffset != textRun.length()) {
+ if (startOffset || endOffset != m_paintTextRun.length()) {
LayoutRect selectionRect = { m_paintRect.x(), m_paintRect.y(), m_paintRect.width(), m_paintRect.height() };
- font.adjustSelectionRectForText(textRun, selectionRect, startOffset, endOffset);
- snappedSelectionRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_document.deviceScaleFactor(), textRun.ltr());
+ font.adjustSelectionRectForText(m_paintTextRun, selectionRect, startOffset, endOffset);
+ snappedSelectionRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, m_document.deviceScaleFactor(), m_paintTextRun.ltr());
}
// 2. Paint
- auto textDecorations = lineStyle.textDecorationsInEffect();
+ auto textDecorations = m_style.textDecorationsInEffect();
textDecorations.add(TextDecorationPainter::textDecorationsInEffectForStyle(markedText.style.textDecorationStyles));
- TextDecorationPainter decorationPainter { context, textDecorations, m_renderer, m_textBox.isFirstLine(), font, markedText.style.textDecorationStyles };
- decorationPainter.setTextRunIterator(LayoutIntegration::textRunFor(&m_textBox));
+ TextDecorationPainter decorationPainter { context, textDecorations, m_renderer, m_isFirstLine, font, markedText.style.textDecorationStyles };
+ decorationPainter.setTextRunIterator(m_textBox);
decorationPainter.setWidth(snappedSelectionRect.width());
- decorationPainter.setIsHorizontal(m_textBox.isHorizontal());
+ decorationPainter.setIsHorizontal(textBox().isHorizontal());
if (markedText.style.textShadow) {
decorationPainter.setTextShadow(&markedText.style.textShadow.value());
- if (lineStyle.hasAppleColorFilter())
- decorationPainter.setShadowColorFilter(&lineStyle.appleColorFilter());
+ if (m_style.hasAppleColorFilter())
+ decorationPainter.setShadowColorFilter(&m_style.appleColorFilter());
}
{
@@ -376,7 +386,7 @@
if (!clipOutRect.isEmpty())
context.clipOut(clipOutRect);
}
- decorationPainter.paintTextDecoration(textRun.subRun(startOffset, endOffset - startOffset), m_textBox.textOriginFromBoxRect(snappedSelectionRect), snappedSelectionRect.location());
+ decorationPainter.paintTextDecoration(m_paintTextRun.subRun(startOffset, endOffset - startOffset), textOriginFromPaintRect(snappedSelectionRect), snappedSelectionRect.location());
}
if (isCombinedText)
@@ -386,7 +396,7 @@
void TextBoxPainter::paintCompositionUnderlines()
{
for (auto& underline : m_renderer.frame().editor().customCompositionUnderlines()) {
- if (underline.endOffset <= m_textBox.start()) {
+ if (underline.endOffset <= textBox().start()) {
// Underline is completely before this run. This might be an underline that sits
// before the first run we draw, or underlines that were within runs we skipped
// due to truncation.
@@ -393,13 +403,13 @@
continue;
}
- if (underline.startOffset >= m_textBox.end())
+ if (underline.startOffset >= textBox().end())
break; // Underline is completely after this run, bail. A later run will paint it.
// Underline intersects this run. Paint it.
paintCompositionUnderline(underline);
- if (underline.endOffset > m_textBox.end())
+ if (underline.endOffset > textBox().end())
break; // Underline also runs into the next run. Bail now, no more marker advancement.
}
}
@@ -411,29 +421,38 @@
start = logicalWidth - width - start;
}
+static float textPosition(const LayoutIntegration::TextRunIterator& textBox)
+{
+ // When computing the width of a text run, RenderBlock::computeInlineDirectionPositionsForLine() doesn't include the actual offset
+ // from the containing block edge in its measurement. textPosition() should be consistent so the text are rendered in the same width.
+ if (!textBox->logicalLeft())
+ return 0;
+ return textBox->logicalLeft() - textBox->line()->contentLogicalLeft();
+}
+
void TextBoxPainter::paintCompositionUnderline(const CompositionUnderline& underline)
{
float start = 0; // start of line to draw, relative to tx
- float width = m_textBox.logicalWidth(); // how much line to draw
+ float width = textBox().logicalWidth(); // how much line to draw
bool useWholeWidth = true;
- unsigned paintStart = m_textBox.start();
- unsigned paintEnd = m_textBox.end();
+ unsigned paintStart = textBox().start();
+ unsigned paintEnd = textBox().end();
if (paintStart <= underline.startOffset) {
paintStart = underline.startOffset;
useWholeWidth = false;
- start = m_renderer.width(m_textBox.start(), paintStart - m_textBox.start(), m_textBox.textPos(), m_textBox.isFirstLine());
+ start = m_renderer.width(textBox().start(), paintStart - textBox().start(), textPosition(m_textBox), m_isFirstLine);
}
if (paintEnd != underline.endOffset) {
paintEnd = std::min(paintEnd, (unsigned)underline.endOffset);
useWholeWidth = false;
}
- if (m_textBox.truncation()) {
- paintEnd = std::min(paintEnd, m_textBox.start() + *m_textBox.truncation());
+ if (m_selectableRange.truncation) {
+ paintEnd = std::min(paintEnd, textBox().start() + *m_selectableRange.truncation);
useWholeWidth = false;
}
if (!useWholeWidth) {
- width = m_renderer.width(paintStart, paintEnd - paintStart, m_textBox.textPos() + start, m_textBox.isFirstLine());
- mirrorRTLSegment(m_textBox.logicalWidth(), m_textBox.direction(), start, width);
+ width = m_renderer.width(paintStart, paintEnd - paintStart, textPosition(m_textBox) + start, m_isFirstLine);
+ mirrorRTLSegment(textBox().logicalWidth(), textBox().direction(), start, width);
}
// Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline.
@@ -440,8 +459,8 @@
// All other marked text underlines are 1px thick.
// If there's not enough space the underline will touch or overlap characters.
int lineThickness = 1;
- int baseline = m_textBox.lineStyle().fontMetrics().ascent();
- if (underline.thick && m_textBox.logicalHeight() - baseline >= 2)
+ int baseline = m_style.fontMetrics().ascent();
+ if (underline.thick && textBox().logicalHeight() - baseline >= 2)
lineThickness = 2;
// We need to have some space between underlines of subsequent clauses, because some input methods do not use different underline styles for those.
@@ -455,12 +474,12 @@
GraphicsContext& context = m_paintInfo.context();
context.setStrokeColor(underlineColor);
context.setStrokeThickness(lineThickness);
- context.drawLineForText(FloatRect(m_paintRect.x() + start, m_paintRect.y() + m_textBox.logicalHeight() - lineThickness, width, lineThickness), m_document.printing());
+ context.drawLineForText(FloatRect(m_paintRect.x() + start, m_paintRect.y() + textBox().logicalHeight() - lineThickness, width, lineThickness), m_document.printing());
}
void TextBoxPainter::paintPlatformDocumentMarkers()
{
- auto markedTexts = MarkedText::collectForDocumentMarkers(m_renderer, m_textBox.selectableRange(), MarkedText::PaintPhase::Decoration);
+ auto markedTexts = MarkedText::collectForDocumentMarkers(m_renderer, m_selectableRange, MarkedText::PaintPhase::Decoration);
for (auto& markedText : MarkedText::subdivide(markedTexts, MarkedText::OverlapStrategy::Frontmost))
paintPlatformDocumentMarker(markedText);
}
@@ -471,7 +490,7 @@
FloatRect result;
auto markedTexts = MarkedText::collectForDocumentMarkers(textBox.renderer(), textBox.selectableRange(), MarkedText::PaintPhase::Decoration);
for (auto& markedText : MarkedText::subdivide(markedTexts, MarkedText::OverlapStrategy::Frontmost))
- result = unionRect(result, calculateDocumentMarkerBounds(textBox, markedText));
+ result = unionRect(result, calculateDocumentMarkerBounds(LayoutIntegration::textRunFor(&textBox), markedText));
return result;
}
@@ -509,13 +528,12 @@
m_paintInfo.context().drawDotsForDocumentMarker(bounds, lineStyleForMarkedTextType());
}
-FloatRect TextBoxPainter::computePaintRect(const LegacyInlineTextBox& textBox, const LayoutPoint& paintOffset)
+FloatRect TextBoxPainter::computePaintRect(const LayoutPoint& paintOffset)
{
FloatPoint localPaintOffset(paintOffset);
- if (textBox.truncation()) {
- auto& renderer = textBox.renderer();
- if (renderer.containingBlock()->style().isLeftToRightDirection() != textBox.isLeftToRightDirection()) {
+ if (m_selectableRange.truncation) {
+ if (m_renderer.containingBlock()->style().isLeftToRightDirection() != textBox().isLeftToRightDirection()) {
// Make the visible fragment of text hug the edge closest to the rest of the run by moving the origin
// at which we start drawing text.
// e.g. In the case of LTR text truncated in an RTL Context, the correct behavior is:
@@ -524,23 +542,41 @@
// farther to the right.
// NOTE: WebKit's behavior differs from that of IE which appears to just overlay the ellipsis on top of the
// truncated string i.e. |Hello|CBA| -> |...lo|CBA|
- LayoutUnit widthOfVisibleText { renderer.width(textBox.start(), *textBox.truncation(), textBox.textPos(), textBox.isFirstLine()) };
- LayoutUnit widthOfHiddenText { textBox.logicalWidth() - widthOfVisibleText };
- LayoutSize truncationOffset(textBox.isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText, 0_lu);
- localPaintOffset.move(textBox.isHorizontal() ? truncationOffset : truncationOffset.transposedSize());
+ LayoutUnit widthOfVisibleText { m_renderer.width(textBox().start(), *m_selectableRange.truncation, textPosition(m_textBox), m_isFirstLine) };
+ LayoutUnit widthOfHiddenText { textBox().logicalWidth() - widthOfVisibleText };
+ LayoutSize truncationOffset(textBox().isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText, 0_lu);
+ localPaintOffset.move(textBox().isHorizontal() ? truncationOffset : truncationOffset.transposedSize());
}
}
- localPaintOffset.move(0, textBox.lineStyle().isHorizontalWritingMode() ? 0 : -textBox.logicalHeight());
+ localPaintOffset.move(0, m_style.isHorizontalWritingMode() ? 0 : -textBox().logicalHeight());
- FloatPoint boxOrigin = textBox.locationIncludingFlipping();
+ auto locationIncludingFlipping = [&]() -> FloatPoint {
+ auto rect = textBox().rect();
+ if (!m_style.isFlippedBlocksWritingMode())
+ return rect.location();
+ auto& block = textBox().line()->containingBlock();
+ if (block.style().isHorizontalWritingMode())
+ return { rect.x(), block.height() - rect.height() - rect.y() };
+ return { block.width() - rect.width() - rect.x(), rect.y() };
+ };
+
+ FloatPoint boxOrigin = locationIncludingFlipping();
boxOrigin.moveBy(localPaintOffset);
- return { boxOrigin, FloatSize(textBox.logicalWidth(), textBox.logicalHeight()) };
+ return { boxOrigin, FloatSize(textBox().logicalWidth(), textBox().logicalHeight()) };
}
-FloatRect TextBoxPainter::calculateDocumentMarkerBounds(const LegacyInlineTextBox& textBox, const MarkedText& markedText)
+static const FontCascade& fontCascadeFor(const RenderText& renderer, const RenderStyle& textBoxStyle)
{
- auto& font = textBox.lineFont();
+ if (is<RenderCombineText>(renderer))
+ return downcast<RenderCombineText>(renderer).textCombineFont();
+
+ return textBoxStyle.fontCascade();
+}
+
+FloatRect TextBoxPainter::calculateDocumentMarkerBounds(const LayoutIntegration::TextRunIterator& textBox, const MarkedText& markedText)
+{
+ auto& font = fontCascadeFor(textBox->renderer(), textBox->style());
auto ascent = font.fontMetrics().ascent();
auto fontSize = std::min(std::max(font.size(), 10.0f), 40.0f);
auto y = ascent + 0.11035 * fontSize;
@@ -547,14 +583,58 @@
auto height = 0.13247 * fontSize;
// Avoid measuring the text when the entire line box is selected as an optimization.
- if (markedText.startOffset || markedText.endOffset != textBox.selectableRange().clamp(textBox.end())) {
- TextRun run = textBox.createTextRun();
+ if (markedText.startOffset || markedText.endOffset != textBox->selectableRange().clamp(textBox->end())) {
+ TextRun run = textBox->createTextRun();
LayoutRect selectionRect = LayoutRect(0, y, 0, height);
- textBox.lineFont().adjustSelectionRectForText(run, selectionRect, markedText.startOffset, markedText.endOffset);
+ font.adjustSelectionRectForText(run, selectionRect, markedText.startOffset, markedText.endOffset);
return selectionRect;
}
- return FloatRect(0, y, textBox.logicalWidth(), height);
+ return FloatRect(0, y, textBox->logicalWidth(), height);
}
+bool TextBoxPainter::computeHaveSelection() const
+{
+ if (m_isPrinting || m_paintInfo.phase == PaintPhase::TextClip)
+ return false;
+
+ return m_renderer.view().selection().highlightStateForTextBox(m_renderer, m_selectableRange) != RenderObject::HighlightState::None;
}
+
+const RenderCombineText* TextBoxPainter::combinedText() const
+{
+ return is<RenderCombineText>(m_renderer) ? &downcast<RenderCombineText>(m_renderer) : nullptr;
+}
+
+const FontCascade& TextBoxPainter::fontCascade() const
+{
+ return fontCascadeFor(m_renderer, m_style);
+}
+
+FloatPoint TextBoxPainter::textOriginFromPaintRect(const FloatRect& paintRect) const
+{
+ FloatPoint textOrigin { paintRect.x(), paintRect.y() + fontCascade().fontMetrics().ascent() };
+ if (auto* combinedText = this->combinedText()) {
+ if (auto newOrigin = combinedText->computeTextOrigin(paintRect))
+ textOrigin = newOrigin.value();
+ }
+ if (textBox().isHorizontal())
+ textOrigin.setY(roundToDevicePixel(LayoutUnit { textOrigin.y() }, m_renderer.document().deviceScaleFactor()));
+ else
+ textOrigin.setX(roundToDevicePixel(LayoutUnit { textOrigin.x() }, m_renderer.document().deviceScaleFactor()));
+ return textOrigin;
+}
+
+const ShadowData* TextBoxPainter::debugTextShadow() const
+{
+ if (!m_renderer.settings().legacyLineLayoutVisualCoverageEnabled())
+ return nullptr;
+ if (!textBox().legacyInlineBox())
+ return nullptr;
+
+ static NeverDestroyed<ShadowData> debugTextShadow(IntPoint(0, 0), 10, 20, ShadowStyle::Normal, true, SRGBA<uint8_t> { 150, 0, 0, 190 });
+ return &debugTextShadow.get();
+}
+
+
+}