[LFC][Integration] Make block selection gap painting use iterator
https://bugs.webkit.org/show_bug.cgi?id=230457
Reviewed by Alan Bujtas.
Make the code not depend on legacy inline boxes.
* rendering/LegacyRootInlineBox.cpp:
(WebCore::LegacyRootInlineBox::lineSelectionGap): Deleted.
* rendering/LegacyRootInlineBox.h:
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::logicalLeftSelectionGap):
(WebCore::RenderBlock::logicalRightSelectionGap):
* rendering/RenderBlock.h:
* rendering/RenderBlockFlow.cpp:
(WebCore::RenderBlockFlow::inlineSelectionGaps):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@282736 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index d94cb5b..167a1af 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,5 +1,24 @@
2021-09-19 Antti Koivisto <antti@apple.com>
+ [LFC][Integration] Make block selection gap painting use iterator
+ https://bugs.webkit.org/show_bug.cgi?id=230457
+
+ Reviewed by Alan Bujtas.
+
+ Make the code not depend on legacy inline boxes.
+
+ * rendering/LegacyRootInlineBox.cpp:
+ (WebCore::LegacyRootInlineBox::lineSelectionGap): Deleted.
+ * rendering/LegacyRootInlineBox.h:
+ * rendering/RenderBlock.cpp:
+ (WebCore::RenderBlock::logicalLeftSelectionGap):
+ (WebCore::RenderBlock::logicalRightSelectionGap):
+ * rendering/RenderBlock.h:
+ * rendering/RenderBlockFlow.cpp:
+ (WebCore::RenderBlockFlow::inlineSelectionGaps):
+
+2021-09-19 Antti Koivisto <antti@apple.com>
+
[LFC][Integration] Paint LFC text runs with TextBoxPainter
https://bugs.webkit.org/show_bug.cgi?id=230455
diff --git a/Source/WebCore/rendering/LegacyRootInlineBox.cpp b/Source/WebCore/rendering/LegacyRootInlineBox.cpp
index 66a1282..7bb35f5 100644
--- a/Source/WebCore/rendering/LegacyRootInlineBox.cpp
+++ b/Source/WebCore/rendering/LegacyRootInlineBox.cpp
@@ -428,60 +428,6 @@
return lineSnapAdjustment(newPageLogicalTop - (blockOffset + lineBoxTop()));
}
-GapRects LegacyRootInlineBox::lineSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit selTop, LayoutUnit selHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
-{
- RenderObject::HighlightState lineState = selectionState();
-
- bool leftGap, rightGap;
- blockFlow().getSelectionGapInfo(lineState, leftGap, rightGap);
-
- GapRects result;
-
- auto* firstBox = firstSelectedBox();
- auto* lastBox = lastSelectedBox();
- if (leftGap) {
- result.uniteLeft(blockFlow().logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, &firstBox->parent()->renderer(), LayoutUnit(firstBox->logicalLeft()),
- selTop, selHeight, cache, paintInfo));
- }
- if (rightGap) {
- result.uniteRight(blockFlow().logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, &lastBox->parent()->renderer(), LayoutUnit(lastBox->logicalRight()),
- selTop, selHeight, cache, paintInfo));
- }
-
- // When dealing with bidi text, a non-contiguous selection region is possible.
- // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
- // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the
- // selection will look like (underline denotes selection):
- // |aaa|bbb|AAA|
- // ___ _
- // We can see that the |bbb| run is not part of the selection while the runs around it are.
- if (firstBox && firstBox != lastBox) {
- // Now fill in any gaps on the line that occurred between two selected elements.
- LayoutUnit lastLogicalLeft { firstBox->logicalRight() };
- bool isPreviousBoxSelected = firstBox->selectionState() != RenderObject::HighlightState::None;
- for (auto* box = firstBox->nextLeafOnLine(); box; box = box->nextLeafOnLine()) {
- if (box->selectionState() != RenderObject::HighlightState::None) {
- LayoutRect logicalRect { lastLogicalLeft, selTop, LayoutUnit(box->logicalLeft() - lastLogicalLeft), selHeight };
- logicalRect.move(renderer().isHorizontalWritingMode() ? offsetFromRootBlock : LayoutSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
- LayoutRect gapRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
- if (isPreviousBoxSelected && gapRect.width() > 0 && gapRect.height() > 0) {
- if (paintInfo && box->parent()->renderer().style().visibility() == Visibility::Visible)
- paintInfo->context().fillRect(gapRect, box->parent()->renderer().selectionBackgroundColor());
- // VisibleSelection may be non-contiguous, see comment above.
- result.uniteCenter(gapRect);
- }
- lastLogicalLeft = box->logicalRight();
- }
- if (box == lastBox)
- break;
- isPreviousBoxSelected = box->selectionState() != RenderObject::HighlightState::None;
- }
- }
-
- return result;
-}
-
RenderObject::HighlightState LegacyRootInlineBox::selectionState() const
{
// Walk over all of the selected boxes.
diff --git a/Source/WebCore/rendering/LegacyRootInlineBox.h b/Source/WebCore/rendering/LegacyRootInlineBox.h
index 1a5a7ab..c259440 100644
--- a/Source/WebCore/rendering/LegacyRootInlineBox.h
+++ b/Source/WebCore/rendering/LegacyRootInlineBox.h
@@ -130,9 +130,6 @@
const LegacyInlineBox* firstSelectedBox() const;
const LegacyInlineBox* lastSelectedBox() const;
- GapRects lineSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- LayoutUnit selTop, LayoutUnit selHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
-
using CleanLineFloatList = Vector<WeakPtr<RenderBox>>;
void appendFloat(RenderBox& floatingBox)
{
diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp
index e765df0..04b1297 100644
--- a/Source/WebCore/rendering/RenderBlock.cpp
+++ b/Source/WebCore/rendering/RenderBlock.cpp
@@ -1681,8 +1681,7 @@
return gapRect;
}
-LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderBoxModelObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
+LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, RenderElement* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
LayoutUnit rootBlockLogicalLeft = std::max(logicalLeftSelectionOffset(rootBlock, logicalTop, cache), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight, cache));
@@ -1698,8 +1697,7 @@
return gapRect;
}
-LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderBoxModelObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
+LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, RenderElement* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
LayoutUnit rootBlockLogicalLeft = std::max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalRight,
diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h
index fcfafaf..e8dab47 100644
--- a/Source/WebCore/rendering/RenderBlock.h
+++ b/Source/WebCore/rendering/RenderBlock.h
@@ -173,10 +173,8 @@
VisiblePosition positionForPoint(const LayoutPoint&, const RenderFragmentContainer*) override;
GapRects selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer);
- LayoutRect logicalLeftSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderBoxModelObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
- LayoutRect logicalRightSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
- RenderBoxModelObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
+ LayoutRect logicalLeftSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, RenderElement* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
+ LayoutRect logicalRightSelectionGap(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, RenderElement* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const LogicalSelectionOffsetCaches&, const PaintInfo*);
void getSelectionGapInfo(HighlightState, bool& leftGap, bool& rightGap);
bool isSelectionRoot() const;
diff --git a/Source/WebCore/rendering/RenderBlockFlow.cpp b/Source/WebCore/rendering/RenderBlockFlow.cpp
index 6ac6b9f..79f7276 100644
--- a/Source/WebCore/rendering/RenderBlockFlow.cpp
+++ b/Source/WebCore/rendering/RenderBlockFlow.cpp
@@ -3274,8 +3274,6 @@
GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
{
- GapRects result;
-
bool containsStart = selectionState() == HighlightState::Start || selectionState() == HighlightState::Both;
if (!hasLines()) {
@@ -3285,70 +3283,94 @@
lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
}
- return result;
+ return { };
}
- auto hasSelectedChildren = [&](const LegacyRootInlineBox& root) {
- for (auto* box = root.firstLeafDescendant(); box; box = box->nextLeafOnLine()) {
- if (!is<LegacyInlineTextBox>(*box)) {
- if (box->selectionState() != HighlightState::None)
- return true;
- continue;
- }
-
- auto start = view().selection().startOffset();
- auto end = view().selection().endOffset();
-
- auto& textBox = downcast<LegacyInlineTextBox>(*box);
- switch (textBox.renderer().selectionState()) {
- case RenderObject::HighlightState::None:
- continue;
- case RenderObject::HighlightState::Inside:
- return true;
- case RenderObject::HighlightState::Start:
- end = textBox.renderer().text().length();
- // to handle selection from end of text to end of line
- if (start && start == end)
- start = end - 1;
- break;
- case RenderObject::HighlightState::End:
- start = 0;
- break;
- case RenderObject::HighlightState::Both:
- break;
- }
- if (textBox.selectableRange().intersects(start, end))
- return true;
- }
- return false;
+ auto hasSelectedChildren = [&](const LayoutIntegration::LineIterator& line) {
+ return line->selectionState() != RenderObject::HighlightState::None;
};
- LegacyRootInlineBox* lastSelectedLine = 0;
- LegacyRootInlineBox* curr;
- for (curr = firstRootBox(); curr && !hasSelectedChildren(*curr); curr = curr->nextRootBox()) { }
+ auto lineSelectionGap = [&](const LayoutIntegration::LineIterator& line, LayoutUnit selTop, LayoutUnit selHeight) -> GapRects {
+ RenderObject::HighlightState lineState = line->selectionState();
+
+ bool leftGap, rightGap;
+ getSelectionGapInfo(lineState, leftGap, rightGap);
+
+ GapRects result;
+
+ auto firstBox = line->firstSelectedBox();
+ auto lastBox = line->lastSelectedBox();
+
+ if (leftGap) {
+ result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, firstBox->renderer().parent(), LayoutUnit(firstBox->logicalLeft()),
+ selTop, selHeight, cache, paintInfo));
+ }
+ if (rightGap) {
+ result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastBox->renderer().parent(), LayoutUnit(lastBox->logicalRight()),
+ selTop, selHeight, cache, paintInfo));
+ }
+
+ // When dealing with bidi text, a non-contiguous selection region is possible.
+ // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
+ // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the
+ // selection will look like (underline denotes selection):
+ // |aaa|bbb|AAA|
+ // ___ _
+ // We can see that the |bbb| run is not part of the selection while the runs around it are.
+ if (firstBox && firstBox != lastBox) {
+ // Now fill in any gaps on the line that occurred between two selected elements.
+ LayoutUnit lastLogicalLeft { firstBox->logicalRight() };
+ bool isPreviousBoxSelected = firstBox->selectionState() != RenderObject::HighlightState::None;
+ for (auto box = firstBox; box; box.traverseNextOnLine()) {
+ if (box->selectionState() != RenderObject::HighlightState::None) {
+ LayoutRect logicalRect { lastLogicalLeft, selTop, LayoutUnit(box->logicalLeft() - lastLogicalLeft), selHeight };
+ logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : LayoutSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
+ LayoutRect gapRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
+ if (isPreviousBoxSelected && gapRect.width() > 0 && gapRect.height() > 0) {
+ if (paintInfo && box->renderer().parent()->style().visibility() == Visibility::Visible)
+ paintInfo->context().fillRect(gapRect, box->renderer().parent()->selectionBackgroundColor());
+ // VisibleSelection may be non-contiguous, see comment above.
+ result.uniteCenter(gapRect);
+ }
+ lastLogicalLeft = box->logicalRight();
+ }
+ if (box == lastBox)
+ break;
+ isPreviousBoxSelected = box->selectionState() != RenderObject::HighlightState::None;
+ }
+ }
+
+ return result;
+ };
+
+ LayoutIntegration::LineIterator lastSelectedLine;
+ LayoutIntegration::LineIterator line = LayoutIntegration::firstLineFor(*this);
+ for (; line && !hasSelectedChildren(line); line.traverseNext()) { }
+
+ GapRects result;
// Now paint the gaps for the lines.
- for (; curr && hasSelectedChildren(*curr); curr = curr->nextRootBox()) {
- LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
- LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
+ for (; line && hasSelectedChildren(line); line.traverseNext()) {
+ LayoutUnit selTop = line->selectionTopAdjustedForPrecedingBlock();
+ LayoutUnit selHeight = line->selectionHeightAdjustedForPrecedingBlock();
if (!containsStart && !lastSelectedLine &&
selectionState() != HighlightState::Start && selectionState() != HighlightState::Both && !isRubyBase())
result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
-
- LayoutRect logicalRect { LayoutUnit(curr->logicalLeft()), selTop, LayoutUnit(curr->logicalWidth()), selTop + selHeight };
+
+ LayoutRect logicalRect { LayoutUnit(line->contentLogicalLeft()), selTop, LayoutUnit(line->contentLogicalWidth()), selTop + selHeight };
logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
|| (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
- result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
+ result.unite(lineSelectionGap(line, selTop, selHeight));
- lastSelectedLine = curr;
+ lastSelectedLine = line;
}
if (containsStart && !lastSelectedLine)
// VisibleSelection must start just after our last line.
- lastSelectedLine = lastRootBox();
+ lastSelectedLine = LayoutIntegration::lastLineFor(*this);
if (lastSelectedLine && selectionState() != HighlightState::End && selectionState() != HighlightState::Both) {
// Update our lastY to be the bottom of the last selected line.