summaryrefslogtreecommitdiffstats
path: root/WebCore/dom/Position.cpp
diff options
context:
space:
mode:
authorFeng Qian <>2009-04-10 18:11:29 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-10 18:11:29 -0700
commit8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch)
tree181bf9a400c30a1bf34ea6d72560e8d00111d549 /WebCore/dom/Position.cpp
parent7ed56f225e0ade046e1c2178977f72b2d896f196 (diff)
downloadexternal_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.zip
external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.gz
external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.bz2
AI 145796: Land the WebKit merge @r42026.
Automated import of CL 145796
Diffstat (limited to 'WebCore/dom/Position.cpp')
-rw-r--r--WebCore/dom/Position.cpp161
1 files changed, 99 insertions, 62 deletions
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<CSSComputedStyleDeclaration> 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 (<br>, 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 (<br>, 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<InlineTextBox*>(otherBox)->start() > textOffset)
+ if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(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<InlineTextBox*>(otherBox)->start() > textOffset)
+ if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(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<InlineTextBox*>(otherBox)->start() >= textOffset)
+ if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(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<InlineTextBox*>(otherBox)->start() >= textOffset)
+ if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(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<int>(box->start()) && !textRenderer->containsReversedText()) {
+ if (m_offset < static_cast<int>(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<int>(box->start()) && !textRenderer->containsReversedText()) {
+ if (m_offset < static_cast<int>(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<int>(box->start()) && offset() < static_cast<int>(box->start() + box->len()))
+ if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(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<Text *>(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