TextDirection SelectionModifier::directionOfSelection() const { InlineBox* startBox = nullptr; InlineBox* endBox = nullptr; // Cache the VisiblePositions because visibleStart() and visibleEnd() // can cause layout, which has the potential to invalidate lineboxes. VisiblePosition startPosition = m_selection.visibleStart(); VisiblePosition endPosition = m_selection.visibleEnd(); if (startPosition.isNotNull()) startBox = computeInlineBoxPosition(startPosition).inlineBox; if (endPosition.isNotNull()) endBox = computeInlineBoxPosition(endPosition).inlineBox; if (startBox && endBox && startBox->direction() == endBox->direction()) return startBox->direction(); return directionOfEnclosingBlock(); }
Position VisiblePosition::rightVisuallyDistinctCandidate() const { Position p = m_deepPosition; if (p.isNull()) return Position(); Position downstreamStart = p.downstream(); TextDirection primaryDirection = p.primaryDirection(); while (true) { InlineBox* box; int offset; p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset); if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); RenderObject* renderer = box->renderer(); while (true) { if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset()) return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); if (!renderer->node()) { box = box->nextLeafChild(); if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); renderer = box->renderer(); offset = box->caretLeftmostOffset(); continue; } offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset); int caretMinOffset = box->caretMinOffset(); int caretMaxOffset = box->caretMaxOffset(); if (offset > caretMinOffset && offset < caretMaxOffset) break; if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) { // Overshot to the right. InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak(); if (!nextBox) { Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); if (positionOnRight.isNull()) return Position(); InlineBox* boxOnRight; int offsetOnRight; positionOnRight.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnRight, offsetOnRight); if (boxOnRight && boxOnRight->root() == box->root()) return Position(); return positionOnRight; } // Reposition at the other logical position corresponding to our edge's visual position and go for another round. box = nextBox; renderer = box->renderer(); offset = nextBox->caretLeftmostOffset(); continue; } ASSERT(offset == box->caretRightmostOffset()); unsigned char level = box->bidiLevel(); InlineBox* nextBox = box->nextLeafChild(); if (box->direction() == primaryDirection) { if (!nextBox) { InlineBox* logicalEnd = 0; if (primaryDirection == LTR ? box->root()->getLogicalEndBoxWithNode(logicalEnd) : box->root()->getLogicalStartBoxWithNode(logicalEnd)) { box = logicalEnd; renderer = box->renderer(); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break; } if (nextBox->bidiLevel() >= level) break; level = nextBox->bidiLevel(); InlineBox* prevBox = box; do { prevBox = prevBox->prevLeafChild(); } while (prevBox && prevBox->bidiLevel() > level); if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA break; // For example, abc 123 ^ CBA or 123 ^ CBA abc box = nextBox; renderer = box->renderer(); offset = box->caretLeftmostOffset(); if (box->direction() == primaryDirection) break; continue; } while (nextBox && !nextBox->renderer()->node()) nextBox = nextBox->nextLeafChild(); if (nextBox) { box = nextBox; renderer = box->renderer(); offset = box->caretLeftmostOffset(); if (box->bidiLevel() > level) { do { nextBox = nextBox->nextLeafChild(); } while (nextBox && nextBox->bidiLevel() > level); if (!nextBox || nextBox->bidiLevel() < level) continue; } } else { // Trailing edge of a secondary run. Set to the leading edge of the entire run. while (true) { while (InlineBox* prevBox = box->prevLeafChild()) { if (prevBox->bidiLevel() < level) break; box = prevBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); while (InlineBox* nextBox = box->nextLeafChild()) { if (nextBox->bidiLevel() < level) break; box = nextBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); } renderer = box->renderer(); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break; } p = createLegacyEditingPosition(renderer->node(), offset); if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) return p; ASSERT(p != m_deepPosition); } }
Position VisiblePosition::rightVisuallyDistinctCandidate() const { Position p = m_deepPosition; if (p.isNull()) return Position(); Position downstreamStart = mostForwardCaretPosition(p); TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); while (true) { InlineBoxPosition boxPosition = computeInlineBoxPosition(p, m_affinity, primaryDirection); InlineBox* box = boxPosition.inlineBox; int offset = boxPosition.offsetInBox; if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); LayoutObject* layoutObject = &box->layoutObject(); while (true) { if ((layoutObject->isReplaced() || layoutObject->isBR()) && offset == box->caretLeftmostOffset()) return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); if (!layoutObject->node()) { box = box->nextLeafChild(); if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); layoutObject = &box->layoutObject(); offset = box->caretLeftmostOffset(); continue; } offset = box->isLeftToRightDirection() ? layoutObject->nextOffset(offset) : layoutObject->previousOffset(offset); int caretMinOffset = box->caretMinOffset(); int caretMaxOffset = box->caretMaxOffset(); if (offset > caretMinOffset && offset < caretMaxOffset) break; if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) { // Overshot to the right. InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak(); if (!nextBox) { Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition); if (positionOnRight.isNull()) return Position(); InlineBox* boxOnRight = computeInlineBoxPosition(positionOnRight, m_affinity, primaryDirection).inlineBox; if (boxOnRight && boxOnRight->root() == box->root()) return Position(); return positionOnRight; } // Reposition at the other logical position corresponding to our edge's visual position and go for another round. box = nextBox; layoutObject = &box->layoutObject(); offset = nextBox->caretLeftmostOffset(); continue; } ASSERT(offset == box->caretRightmostOffset()); unsigned char level = box->bidiLevel(); InlineBox* nextBox = box->nextLeafChild(); if (box->direction() == primaryDirection) { if (!nextBox) { InlineBox* logicalEnd = 0; if (primaryDirection == LTR ? box->root().getLogicalEndBoxWithNode(logicalEnd) : box->root().getLogicalStartBoxWithNode(logicalEnd)) { box = logicalEnd; layoutObject = &box->layoutObject(); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break; } if (nextBox->bidiLevel() >= level) break; level = nextBox->bidiLevel(); InlineBox* prevBox = box; do { prevBox = prevBox->prevLeafChild(); } while (prevBox && prevBox->bidiLevel() > level); if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA break; // For example, abc 123 ^ CBA or 123 ^ CBA abc box = nextBox; layoutObject = &box->layoutObject(); offset = box->caretLeftmostOffset(); if (box->direction() == primaryDirection) break; continue; } while (nextBox && !nextBox->layoutObject().node()) nextBox = nextBox->nextLeafChild(); if (nextBox) { box = nextBox; layoutObject = &box->layoutObject(); offset = box->caretLeftmostOffset(); if (box->bidiLevel() > level) { do { nextBox = nextBox->nextLeafChild(); } while (nextBox && nextBox->bidiLevel() > level); if (!nextBox || nextBox->bidiLevel() < level) continue; } } else { // Trailing edge of a secondary run. Set to the leading edge of the entire run. while (true) { while (InlineBox* prevBox = box->prevLeafChild()) { if (prevBox->bidiLevel() < level) break; box = prevBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); while (InlineBox* nextBox = box->nextLeafChild()) { if (nextBox->bidiLevel() < level) break; box = nextBox; } if (box->bidiLevel() == level) break; level = box->bidiLevel(); } layoutObject = &box->layoutObject(); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break; } p = Position::editingPositionOf(layoutObject->node(), offset); if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) != downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) return p; ASSERT(p != m_deepPosition); } }