📄 visibleposition.cpp
字号:
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 = Position(renderer->node(), offset); if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd()) return p; }}VisiblePosition VisiblePosition::right(bool stayInEditableContent) const{ Position pos = rightVisuallyDistinctCandidate(); if (pos.atStart() || pos.atEnd()) return VisiblePosition(); VisiblePosition right = VisiblePosition(pos, DOWNSTREAM); ASSERT(right != *this); if (!stayInEditableContent) return right; // FIXME: This may need to do something different from "after". return honorEditableBoundaryAtOrAfter(right);}VisiblePosition VisiblePosition::honorEditableBoundaryAtOrBefore(const VisiblePosition &pos) const{ if (pos.isNull()) return pos; Node* highestRoot = highestEditableRoot(deepEquivalent()); // Return empty position if pos is not somewhere inside the editable region containing this position if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot)) return VisiblePosition(); // Return pos itself if the two are from the very same editable region, or both are non-editable // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too. if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) return pos; // Return empty position if this position is non-editable, but pos is editable // FIXME: Move to the previous non-editable region. if (!highestRoot) return VisiblePosition(); // Return the last position before pos that is in the same editable region as this position return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);}VisiblePosition VisiblePosition::honorEditableBoundaryAtOrAfter(const VisiblePosition &pos) const{ if (pos.isNull()) return pos; Node* highestRoot = highestEditableRoot(deepEquivalent()); // Return empty position if pos is not somewhere inside the editable region containing this position if (highestRoot && !pos.deepEquivalent().node()->isDescendantOf(highestRoot)) return VisiblePosition(); // Return pos itself if the two are from the very same editable region, or both are non-editable // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too. if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) return pos; // Return empty position if this position is non-editable, but pos is editable // FIXME: Move to the next non-editable region. if (!highestRoot) return VisiblePosition(); // Return the next position after pos that is in the same editable region as this position return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);}static Position canonicalizeCandidate(const Position& candidate){ if (candidate.isNull()) return Position(); ASSERT(candidate.isCandidate()); Position upstream = candidate.upstream(); if (upstream.isCandidate()) return upstream; return candidate;}Position VisiblePosition::canonicalPosition(const Position& position){ // FIXME (9535): Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will // ask renderers to paint downstream carets for other renderers. // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate // unless the affinity is upstream. Node* node = position.node(); if (!node) return Position(); node->document()->updateLayoutIgnorePendingStylesheets(); Position candidate = position.upstream(); if (candidate.isCandidate()) return candidate; candidate = position.downstream(); if (candidate.isCandidate()) return candidate; // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave // blocks or enter new ones), we search forward and backward until we find one. Position next = canonicalizeCandidate(nextCandidate(position)); Position prev = canonicalizeCandidate(previousCandidate(position)); Node* nextNode = next.node(); Node* prevNode = prev.node(); // The new position must be in the same editable element. Enforce that first. // Unless the descent is from a non-editable html element to an editable body. if (node->hasTagName(htmlTag) && !node->isContentEditable() && node->document()->body() && node->document()->body()->isContentEditable()) return next.isNotNull() ? next : prev; Node* editingRoot = editableRootForPosition(position); // If the html element is editable, descending into its body will look like a descent // from non-editable to editable content since rootEditableElement() always stops at the body. if (editingRoot && editingRoot->hasTagName(htmlTag) || position.node()->isDocumentNode()) return next.isNotNull() ? next : prev; bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot; bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot; if (prevIsInSameEditableElement && !nextIsInSameEditableElement) return prev; if (nextIsInSameEditableElement && !prevIsInSameEditableElement) return next; if (!nextIsInSameEditableElement && !prevIsInSameEditableElement) return Position(); // The new position should be in the same block flow element. Favor that. Node *originalBlock = node->enclosingBlockFlowElement(); bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock; bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock; if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock) return prev; return next;}UChar VisiblePosition::characterAfter() const{ // We canonicalize to the first of two equivalent candidates, but the second of the two candidates // is the one that will be inside the text node containing the character after this visible position. Position pos = m_deepPosition.downstream(); Node* node = pos.node(); if (!node || !node->isTextNode()) return 0; Text* textNode = static_cast<Text*>(pos.node()); int offset = pos.offset(); if ((unsigned)offset >= textNode->length()) return 0; return textNode->data()[offset];}IntRect VisiblePosition::localCaretRect(RenderObject*& renderer) const{ Node* node = m_deepPosition.node(); if (!node) { renderer = 0; return IntRect(); } renderer = node->renderer(); if (!renderer) return IntRect(); InlineBox* inlineBox; int caretOffset; getInlineBoxAndOffset(inlineBox, caretOffset); if (inlineBox) renderer = inlineBox->renderer(); return renderer->localCaretRect(inlineBox, caretOffset);}IntRect VisiblePosition::absoluteCaretBounds() const{ RenderObject* renderer; IntRect localRect = localCaretRect(renderer); if (localRect.isEmpty() || !renderer) return IntRect(); return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();}int VisiblePosition::xOffsetForVerticalNavigation() const{ RenderObject* renderer; IntRect localRect = localCaretRect(renderer); if (localRect.isEmpty() || !renderer) return 0; // This ignores transforms on purpose, for now. Vertical navigation is done // without consulting transforms, so that 'up' in transformed text is 'up' // relative to the text, not absolute 'up'. return renderer->localToAbsolute(localRect.location()).x();}void VisiblePosition::debugPosition(const char* msg) const{ if (isNull()) fprintf(stderr, "Position [%s]: null\n", msg); else fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, m_deepPosition.node()->nodeName().utf8().data(), m_deepPosition.node(), m_deepPosition.offset());}#ifndef NDEBUGvoid VisiblePosition::formatForDebugger(char* buffer, unsigned length) const{ m_deepPosition.formatForDebugger(buffer, length);}void VisiblePosition::showTreeForThis() const{ m_deepPosition.showTreeForThis();}#endifPassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end){ if (start.isNull() || end.isNull()) return 0; Position s = rangeCompliantEquivalent(start); Position e = rangeCompliantEquivalent(end); return Range::create(s.node()->document(), s.node(), s.offset(), e.node(), e.offset());}VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity){ int exception = 0; return VisiblePosition(r->startContainer(exception), r->startOffset(exception), affinity);}VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity){ int exception = 0; return VisiblePosition(r->endContainer(exception), r->endOffset(exception), affinity);}bool setStart(Range *r, const VisiblePosition &visiblePosition){ if (!r) return false; Position p = rangeCompliantEquivalent(visiblePosition); int code = 0; r->setStart(p.node(), p.offset(), code); return code == 0;}bool setEnd(Range *r, const VisiblePosition &visiblePosition){ if (!r) return false; Position p = rangeCompliantEquivalent(visiblePosition); int code = 0; r->setEnd(p.node(), p.offset(), code); return code == 0;}Node *enclosingBlockFlowElement(const VisiblePosition &visiblePosition){ if (visiblePosition.isNull()) return NULL; return visiblePosition.deepEquivalent().node()->enclosingBlockFlowElement();}bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node){ if (visiblePosition.isNull()) return false; if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node)) return false; VisiblePosition previous = visiblePosition.previous(); return previous.isNull() || !previous.deepEquivalent().node()->isDescendantOf(node);}bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node){ if (visiblePosition.isNull()) return false; if (!visiblePosition.deepEquivalent().node()->isDescendantOf(node)) return false; VisiblePosition next = visiblePosition.next(); return next.isNull() || !next.deepEquivalent().node()->isDescendantOf(node);}} // namespace WebCore#ifndef NDEBUGvoid showTree(const WebCore::VisiblePosition* vpos){ if (vpos) vpos->showTreeForThis();}void showTree(const WebCore::VisiblePosition& vpos){ vpos.showTreeForThis();}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -