summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
Diffstat (limited to 'third_party')
-rw-r--r--third_party/WebKit/WebCore/ChangeLog18
-rw-r--r--third_party/WebKit/WebCore/dom/Position.cpp64
-rw-r--r--third_party/WebKit/WebCore/dom/Position.h11
-rw-r--r--third_party/WebKit/WebCore/editing/VisiblePosition.cpp12
4 files changed, 40 insertions, 65 deletions
diff --git a/third_party/WebKit/WebCore/ChangeLog b/third_party/WebKit/WebCore/ChangeLog
index a376884..14907a3 100644
--- a/third_party/WebKit/WebCore/ChangeLog
+++ b/third_party/WebKit/WebCore/ChangeLog
@@ -1,3 +1,21 @@
+2006-03-20 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by darin
+
+ <rdar://problem/3997958>
+ REGRESSION (Mail): Mail takes half of forever to paste >1500 lines - replaceSelectionWithNode
+
+ * dom/Position.cpp:
+ (WebCore::Position::upstream): Avoid calling previous() when we know that
+ it will 1) end the search and 2) be expensive to compute.
+ (WebCore::Position::downstream): Removed some dead code.
+ (WebCore::Position::inRenderedText): Return false for offsets inside composed characters.
+ * dom/Position.h:
+ * editing/VisiblePosition.cpp:
+ (WebCore::VisiblePosition::init): If there are two visually equivalent candidates, we choose
+ the one that occurs first in document order. Using upstream() to find the one that occurs first is
+ much faster than the old code.
+
2006-03-20 Eric Seidel <eseidel@apple.com>
Reviewed by adele & ggaren.
diff --git a/third_party/WebKit/WebCore/dom/Position.cpp b/third_party/WebKit/WebCore/dom/Position.cpp
index 9f18447..9c73b15 100644
--- a/third_party/WebKit/WebCore/dom/Position.cpp
+++ b/third_party/WebKit/WebCore/dom/Position.cpp
@@ -283,15 +283,7 @@ static bool isStreamer(const Position &pos)
return pos.offset() == 0;
}
-// AFAIK no one has a clear, complete definition for this method and how it is used.
-// Here is what I have come to understand from re-working the code after fixing PositionIterator
-// for <rdar://problem/4103339>. See also Ken's comments in the header. Fundamentally, upstream()
-// scans backward in the DOM starting at "this" to return the closest previous visible DOM position
-// that is either in a text node, or just after a replaced or BR element (btw downstream() also
-// considers empty blocks). The search is limited to the enclosing block. If the search would
-// otherwise have entered into a part of the DOM with a different enclosing block, including a
-// nested one, the search stops and this function returns the highest previous visible DOM position
-// that is either in an atomic node (i.e. text) or is the end of a non-atomic node.
+// p.upstream() returns the start of the range of positions that map to the same VisiblePosition as P.
Position Position::upstream() const
{
// start at equivalent deep position
@@ -305,12 +297,12 @@ Position Position::upstream() const
Position lastVisible = *this;
Position currentPos = start;
RootInlineBox *lastRoot = 0;
- for (; !currentPos.atStart(); currentPos = currentPos.previous()) {
+ for (; !currentPos.atStart(); currentPos = currentPos.previous(UsingComposedCharacters)) {
Node *currentNode = currentPos.node();
int currentOffset = currentPos.offset();
- // limit traversal to block or table enclosing the original element
- // NOTE: This includes not going into nested blocks
+ // Don't enter a new enclosing block flow or table element. There is code below that
+ // terminates early if we're about to leave an enclosing block flow or table element.
if (block != currentNode->enclosingBlockFlowOrTableElement())
return lastVisible;
@@ -334,6 +326,13 @@ Position Position::upstream() const
// track last visible streamer position
if (isStreamer(currentPos))
lastVisible = currentPos;
+
+ // Don't leave a block flow or table element. We could rely on code above to terminate and
+ // return lastVisible on the next iteration, but we terminate early to avoid calling previous()
+ // beceause previous() for an offset 0 position calls nodeIndex(), which is O(n).
+ // FIXME: Avoid calling previous on other offset 0 positions.
+ if (currentNode == currentNode->enclosingBlockFlowOrTableElement() && currentOffset == 0)
+ return lastVisible;
// return position after replaced or BR elements
// NOTE: caretMaxOffset() can be less than childNodeCount()!!
@@ -372,15 +371,7 @@ Position Position::upstream() const
return lastVisible;
}
-// AFAIK no one has a clear, complete definition for this method and how it is used.
-// Here is what I have come to understand from re-working the code after fixing PositionIterator
-// for <rdar://problem/4103339>. See also Ken's comments in the header. Fundamentally, downstream()
-// scans forward in the DOM starting at "this" to return the first visible DOM position that is
-// either in a text node, or just before a replaced, BR element, or empty block flow element (i.e.
-// non-text nodes with no children). The search is limited to the enclosing block. If the search
-// would otherwise have entered into a part of the DOM with a different enclosing block, including a
-// nested one, the search stops and this function returns the first previous position that is either
-// in an atomic node (i.e. text) or is at offset 0.
+// P.downstream() returns the end of the range of positions that map to the same VisiblePosition as P.
Position Position::downstream() const
{
Position start = VisiblePosition::deepEquivalent(*this);
@@ -393,7 +384,7 @@ Position Position::downstream() const
Position lastVisible = *this;
Position currentPos = start;
RootInlineBox *lastRoot = 0;
- for (; !currentPos.atEnd(); currentPos = currentPos.next()) {
+ for (; !currentPos.atEnd(); currentPos = currentPos.next(UsingComposedCharacters)) {
Node *currentNode = currentPos.node();
int currentOffset = currentPos.offset();
@@ -402,9 +393,7 @@ Position Position::downstream() const
if (currentNode->hasTagName(bodyTag) && currentOffset >= (int) currentNode->childNodeCount())
break;
- // limit traversal to block or table enclosing the original element
- // return the last visible streamer position
- // NOTE: This includes not going into nested blocks
+ // Do not enter a new enclosing block flow or table element, and don't leave the original one.
if (block != currentNode->enclosingBlockFlowOrTableElement())
return lastVisible;
@@ -428,28 +417,6 @@ Position Position::downstream() const
// track last visible streamer position
if (isStreamer(currentPos))
lastVisible = currentPos;
-
- // if now at a offset 0 of a rendered block flow element...
- // - return current position if the element has no children (i.e. is a leaf)
- // - return child node, offset 0, if the first visible child is not a block flow element
- // - otherwise, skip this position (first visible child is a block, and we will
- // get there eventually via the iterator)
- if ((currentNode != startNode && renderer->isBlockFlow()) && (currentOffset == 0)) {
- if (!currentNode->firstChild())
- return currentPos;
-
- for (Node *child = currentNode->firstChild(); child; child = child->nextSibling()) {
- RenderObject *r = child->renderer();
- if (r && r->style()->visibility() == VISIBLE) {
- if (r->isBlockFlow())
- break; // break causes continue code below to run.
-
- return Position(child, 0);
- }
- }
-
- continue;
- }
// return position before replaced or BR elements
if (editingIgnoresContent(currentNode) || renderer->isBR() || isTableElement(currentNode)) {
@@ -545,7 +512,8 @@ bool Position::inRenderedText() const
return false;
}
if (offset() >= box->m_start && offset() <= box->m_start + box->m_len)
- return true;
+ // Return false for offsets inside composed characters.
+ return offset() == 0 || offset() == textRenderer->nextOffset(textRenderer->previousOffset(offset()));
}
return false;
diff --git a/third_party/WebKit/WebCore/dom/Position.h b/third_party/WebKit/WebCore/dom/Position.h
index 632648a..6509222 100644
--- a/third_party/WebKit/WebCore/dom/Position.h
+++ b/third_party/WebKit/WebCore/dom/Position.h
@@ -66,16 +66,7 @@ public:
Position leadingWhitespacePosition(WebCore::EAffinity affinity, bool considerNonCollapsibleWhitespace = false) const;
Position trailingWhitespacePosition(WebCore::EAffinity affinity, bool considerNonCollapsibleWhitespace = false) const;
- // These functions only consider leaf nodes and blocks.
- // Hence, the results from these functions are idiosyncratic, and until you
- // become familiar with the results, you may find using these functions confusing.
- // I have hopes to make the results of these functions less ambiguous in the near
- // future, and have them consider all nodes, and have the Positions that are
- // returned follow a simple rule: The upstream position is the position
- // earliest in document order that will make the insertion point render in the
- // same position as the caller's position. The same goes for downstream position
- // except that it is the latest position for earliest position in the above
- // description.
+ // p.upstream() through p.downstream() is the range of positions that map to the same VisiblePosition as p.
Position upstream() const;
Position downstream() const;
diff --git a/third_party/WebKit/WebCore/editing/VisiblePosition.cpp b/third_party/WebKit/WebCore/editing/VisiblePosition.cpp
index deb7c127..7769102 100644
--- a/third_party/WebKit/WebCore/editing/VisiblePosition.cpp
+++ b/third_party/WebKit/WebCore/editing/VisiblePosition.cpp
@@ -69,13 +69,11 @@ void VisiblePosition::init(const Position &pos, EAffinity affinity)
pos.node()->getDocument()->updateLayoutIgnorePendingStylesheets();
Position deepPos = deepEquivalent(pos);
if (deepPos.inRenderedContent()) {
- m_deepPosition = deepPos;
- Position previous = previousVisiblePosition(deepPos);
- if (previous.isNotNull()) {
- Position next = nextVisiblePosition(previous);
- if (next.isNotNull())
- m_deepPosition = next;
- }
+ // If two visually equivalent positions are both candidates for being made the m_deepPosition,
+ // (this can happen when two rendered positions have only collapsed whitespace between them for example),
+ // we always choose the one that occurs first in the DOM to canonicalize VisiblePositions.
+ Position upstreamPosition = deepPos.upstream();
+ m_deepPosition = upstreamPosition.inRenderedContent() ? upstreamPosition : deepPos;
} else {
Position next = nextVisiblePosition(deepPos);
Position prev = previousVisiblePosition(deepPos);