From 8f72e70a9fd78eec56623b3a62e68f16b7b27e28 Mon Sep 17 00:00:00 2001 From: Feng Qian <> Date: Fri, 10 Apr 2009 18:11:29 -0700 Subject: AI 145796: Land the WebKit merge @r42026. Automated import of CL 145796 --- WebCore/dom/Position.cpp | 161 +++++++++++++++++++++++++++++------------------ 1 file changed, 99 insertions(+), 62 deletions(-) (limited to 'WebCore/dom/Position.cpp') diff --git a/WebCore/dom/Position.cpp b/WebCore/dom/Position.cpp index faa4a13..a2591ba 100644 --- a/WebCore/dom/Position.cpp +++ b/WebCore/dom/Position.cpp @@ -43,7 +43,7 @@ namespace WebCore { using namespace HTMLNames; -static Node *nextRenderedEditable(Node *node) +static Node* nextRenderedEditable(Node* node) { while (1) { node = node->nextEditable(); @@ -52,13 +52,13 @@ static Node *nextRenderedEditable(Node *node) RenderObject* renderer = node->renderer(); if (!renderer) continue; - if (renderer->inlineBoxWrapper() || renderer->isText() && toRenderText(renderer)->firstTextBox()) + if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox())) return node; } return 0; } -static Node *previousRenderedEditable(Node *node) +static Node* previousRenderedEditable(Node* node) { while (1) { node = node->previousEditable(); @@ -67,7 +67,7 @@ static Node *previousRenderedEditable(Node *node) RenderObject* renderer = node->renderer(); if (!renderer) continue; - if (renderer->inlineBoxWrapper() || renderer->isText() && toRenderText(renderer)->firstTextBox()) + if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox())) return node; } return 0; @@ -97,60 +97,69 @@ PassRefPtr Position::computedStyle() const return WebCore::computedStyle(elem); } -Position Position::previous(EUsingComposedCharacters usingComposedCharacters) const +Position Position::previous(PositionMoveType moveType) const { - Node *n = node(); + Node* n = node(); if (!n) return *this; - int o = offset(); + int o = m_offset; // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier. ASSERT(o >= 0); if (o > 0) { - Node *child = n->childNode(o - 1); - if (child) { - return Position(child, maxDeepOffset(child)); - } + Node* child = n->childNode(o - 1); + if (child) + return lastDeepEditingPositionForNode(child); + // There are two reasons child might be 0: // 1) The node is node like a text node that is not an element, and therefore has no children. // Going backward one character at a time is correct. // 2) The old offset was a bogus offset like (
, 1), and there is no child. // Going from 1 to 0 is correct. - return Position(n, usingComposedCharacters ? uncheckedPreviousOffset(n, o) : o - 1); + switch (moveType) { + case CodePoint: + return Position(n, o - 1); + case Character: + return Position(n, uncheckedPreviousOffset(n, o)); + case BackwardDeletion: + return Position(n, uncheckedPreviousOffsetForBackwardDeletion(n, o)); + } } - Node *parent = n->parentNode(); + Node* parent = n->parentNode(); if (!parent) return *this; return Position(parent, n->nodeIndex()); } -Position Position::next(EUsingComposedCharacters usingComposedCharacters) const +Position Position::next(PositionMoveType moveType) const { - Node *n = node(); + ASSERT(moveType != BackwardDeletion); + + Node* n = node(); if (!n) return *this; - int o = offset(); + int o = m_offset; // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier. ASSERT(o >= 0); Node* child = n->childNode(o); - if (child || !n->hasChildNodes() && o < maxDeepOffset(n)) { + if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n))) { if (child) - return Position(child, 0); - + return firstDeepEditingPositionForNode(child); + // There are two reasons child might be 0: // 1) The node is node like a text node that is not an element, and therefore has no children. // Going forward one character at a time is correct. // 2) The new offset is a bogus offset like (
, 1), and there is no child. // Going from 0 to 1 is correct. - return Position(n, usingComposedCharacters ? uncheckedNextOffset(n, o) : o + 1); + return Position(n, (moveType == Character) ? uncheckedNextOffset(n, o) : o + 1); } - Node *parent = n->parentNode(); + Node* parent = n->parentNode(); if (!parent) return *this; @@ -162,46 +171,61 @@ int Position::uncheckedPreviousOffset(const Node* n, int current) return n->renderer() ? n->renderer()->previousOffset(current) : current - 1; } +int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current) +{ + return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1; +} + int Position::uncheckedNextOffset(const Node* n, int current) { return n->renderer() ? n->renderer()->nextOffset(current) : current + 1; } -bool Position::atStart() const +bool Position::atFirstEditingPositionForNode() const { - Node *n = node(); - if (!n) + if (isNull()) return true; - - return offset() <= 0 && n->parent() == 0; + return m_offset <= 0; } -bool Position::atEnd() const +bool Position::atLastEditingPositionForNode() const { - Node *n = node(); - if (!n) + if (isNull()) return true; - - return n->parent() == 0 && offset() >= maxDeepOffset(n); + return m_offset >= lastOffsetForEditing(node()); +} + +bool Position::atStartOfTree() const +{ + if (isNull()) + return true; + return !node()->parentNode() && m_offset <= 0; +} + +bool Position::atEndOfTree() const +{ + if (isNull()) + return true; + return !node()->parentNode() && m_offset >= lastOffsetForEditing(node()); } int Position::renderedOffset() const { if (!node()->isTextNode()) - return offset(); + return m_offset; if (!node()->renderer()) - return offset(); + return m_offset; int result = 0; RenderText *textRenderer = toRenderText(node()->renderer()); for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { int start = box->start(); int end = box->start() + box->len(); - if (offset() < start) + if (m_offset < start) return result; - if (offset() <= end) { - result += offset() - start; + if (m_offset <= end) { + result += m_offset - start; return result; } result += box->len(); @@ -221,7 +245,7 @@ Position Position::previousCharacterPosition(EAffinity affinity) const bool rendered = isCandidate(); Position currentPos = *this; - while (!currentPos.atStart()) { + while (!currentPos.atStartOfTree()) { currentPos = currentPos.previous(); if (currentPos.node()->rootEditableElement() != fromRootEditableElement) @@ -249,7 +273,7 @@ Position Position::nextCharacterPosition(EAffinity affinity) const bool rendered = isCandidate(); Position currentPos = *this; - while (!currentPos.atEnd()) { + while (!currentPos.atEndOfTree()) { currentPos = currentPos.next(); if (currentPos.node()->rootEditableElement() != fromRootEditableElement) @@ -265,7 +289,7 @@ Position Position::nextCharacterPosition(EAffinity affinity) const return *this; } -// Whether or not [node, 0] and [node, maxDeepOffset(node)] are their own VisiblePositions. +// Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions. // If true, adjacent candidates are visually distinct. // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate. // FIXME: Share code with isCandidate, if possible. @@ -359,7 +383,7 @@ Position Position::upstream() const // Return position after tables and nodes which have content that can be ignored. if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) { if (currentPos.atEndOfNode()) - return Position(currentNode, maxDeepOffset(currentNode)); + return lastDeepEditingPositionForNode(currentNode); continue; } @@ -396,7 +420,7 @@ Position Position::upstream() const otherBox = otherBox->nextLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast(otherBox)->start() > textOffset) + if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast(otherBox)->start() > textOffset)) continuesOnNextLine = false; } @@ -405,7 +429,7 @@ Position Position::upstream() const otherBox = otherBox->prevLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast(otherBox)->start() > textOffset) + if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast(otherBox)->start() > textOffset)) continuesOnNextLine = false; } @@ -508,7 +532,7 @@ Position Position::downstream() const otherBox = otherBox->nextLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast(otherBox)->start() >= textOffset) + if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast(otherBox)->start() >= textOffset)) continuesOnNextLine = false; } @@ -517,7 +541,7 @@ Position Position::downstream() const otherBox = otherBox->prevLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || otherBox->object() == textRenderer && static_cast(otherBox)->start() >= textOffset) + if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast(otherBox)->start() >= textOffset)) continuesOnNextLine = false; } @@ -534,7 +558,7 @@ bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* render { RenderObject* stop = renderer->nextInPreOrderAfterChildren(); for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder()) - if (o->element()) { + if (o->node()) { if ((o->isText() && toRenderText(o)->linesBoundingBox().height()) || (o->isBox() && toRenderBox(o)->borderBoundingBox().height())) return true; @@ -560,17 +584,17 @@ bool Position::isCandidate() const return false; if (renderer->isBR()) - return offset() == 0 && !nodeIsUserSelectNone(node()->parent()); + return m_offset == 0 && !nodeIsUserSelectNone(node()->parent()); if (renderer->isText()) return inRenderedText() && !nodeIsUserSelectNone(node()); if (isTableElement(node()) || editingIgnoresContent(node())) - return (offset() == 0 || offset() == maxDeepOffset(node())) && !nodeIsUserSelectNone(node()->parent()); + return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(node()->parent()); if (!node()->hasTagName(htmlTag) && renderer->isBlockFlow() && !hasRenderedNonAnonymousDescendantsWithHeight(renderer) && (toRenderBox(renderer)->height() || node()->hasTagName(bodyTag))) - return offset() == 0 && !nodeIsUserSelectNone(node()); + return atFirstEditingPositionForNode() && !nodeIsUserSelectNone(node()); return false; } @@ -586,15 +610,15 @@ bool Position::inRenderedText() const RenderText *textRenderer = toRenderText(renderer); for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - if (offset() < static_cast(box->start()) && !textRenderer->containsReversedText()) { + if (m_offset < static_cast(box->start()) && !textRenderer->containsReversedText()) { // The offset we're looking for is before this node // this means the offset must be in content that is // not rendered. Return false. return false; } - if (box->containsCaretOffset(offset())) + if (box->containsCaretOffset(m_offset)) // Return false for offsets inside composed characters. - return offset() == 0 || offset() == textRenderer->nextOffset(textRenderer->previousOffset(offset())); + return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset)); } return false; @@ -622,13 +646,13 @@ bool Position::isRenderedCharacter() const RenderText* textRenderer = toRenderText(renderer); for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - if (offset() < static_cast(box->start()) && !textRenderer->containsReversedText()) { + if (m_offset < static_cast(box->start()) && !textRenderer->containsReversedText()) { // The offset we're looking for is before this node // this means the offset must be in content that is // not rendered. Return false. return false; } - if (offset() >= static_cast(box->start()) && offset() < static_cast(box->start() + box->len())) + if (m_offset >= static_cast(box->start()) && m_offset < static_cast(box->start() + box->len())) return true; } @@ -656,11 +680,11 @@ bool Position::rendersInDifferentPosition(const Position &pos) const if (node()->hasTagName(brTag)) return false; - if (offset() == pos.offset()) + if (m_offset == pos.m_offset) return false; if (!node()->isTextNode() && !pos.node()->isTextNode()) { - if (offset() != pos.offset()) + if (m_offset != pos.m_offset) return true; } } @@ -734,7 +758,7 @@ Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNo Position prev = previousCharacterPosition(affinity); if (prev != *this && prev.node()->inSameContainingBlockFlowElement(node()) && prev.node()->isTextNode()) { String string = static_cast(prev.node())->data(); - UChar c = string[prev.offset()]; + UChar c = string[prev.m_offset]; if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c)) if (isEditablePosition(prev)) return prev; @@ -809,11 +833,11 @@ static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer) void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const { - caretOffset = offset(); + caretOffset = m_offset; RenderObject* renderer = node()->renderer(); if (!renderer->isText()) { - inlineBox = renderer->inlineBoxWrapper(); - if (!inlineBox || caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()) + inlineBox = renderer->isBox() ? toRenderBox(renderer)->inlineBoxWrapper() : 0; + if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset())) return; } else { RenderText* textRenderer = toRenderText(renderer); @@ -825,7 +849,7 @@ void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDi int caretMinOffset = box->caretMinOffset(); int caretMaxOffset = box->caretMaxOffset(); - if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || caretOffset == caretMaxOffset && box->isLineBreak()) + if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak())) continue; if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) { @@ -943,7 +967,7 @@ void Position::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, node()->nodeName().utf8().data(), node(), offset()); + fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().utf8().data(), node(), m_offset); } #ifndef NDEBUG @@ -957,7 +981,7 @@ void Position::formatForDebugger(char* buffer, unsigned length) const else { char s[1024]; result += "offset "; - result += String::number(offset()); + result += String::number(m_offset); result += " of "; node()->formatForDebugger(s, sizeof(s)); result += s; @@ -984,6 +1008,19 @@ Position endPosition(const Range* r) return r ? r->endPosition() : Position(); } +// NOTE: first/lastDeepEditingPositionForNode can return "editing positions" (like [img, 0]) +// for elements which editing "ignores". the rest of the editing code will treat [img, 0] +// as "the last position before the img" +Position firstDeepEditingPositionForNode(Node* node) +{ + return Position(node, 0); +} + +Position lastDeepEditingPositionForNode(Node* node) +{ + return Position(node, lastOffsetForEditing(node)); +} + } // namespace WebCore #ifndef NDEBUG -- cgit v1.1