[webkit-changes] cvs commit: WebCore/khtml/xml dom_nodeimpl.cpp
dom_nodeimpl.h dom_position.cpp dom_position.h
Adele
adele at opensource.apple.com
Tue Jul 26 15:45:34 PDT 2005
adele 05/07/26 15:45:34
Modified: . Tag: Safari-2-0-branch ChangeLog
WebCore.pbproj Tag: Safari-2-0-branch project.pbxproj
khtml/editing Tag: Safari-2-0-branch htmlediting.cpp
selection.cpp visible_position.cpp
visible_position.h
khtml/xml Tag: Safari-2-0-branch dom_nodeimpl.cpp
dom_nodeimpl.h dom_position.cpp dom_position.h
Log:
Merged fix from TOT to Safari-2-0-branch. Needed for other editing fixes on the branch.
2005-05-06 David Harrison <harrison at apple.com>
Reviewed by Maciej, Darin.
<rdar://problem/4103339> VisiblePosition and PositionIterator iterators do not return positions in order
* WebCore.pbproj/project.pbxproj:
Removed dom_positioniterator.h and dom_positioniterator.cpp.
* khtml/editing/htmlediting.cpp:
Removed unused include of dom_positioniterator.h and "using" of PositionIterator.
* khtml/editing/selection.cpp:
Removed unused include of dom_positioniterator.h.
* khtml/editing/visible_position.h:
* khtml/editing/visible_position.cpp:
(khtml::VisiblePosition::previousVisiblePosition):
(khtml::VisiblePosition::nextVisiblePosition):
(khtml::VisiblePosition::downstreamDeepEquivalent):
Use Position::next(), Position::previous(), Position::atStart(), Position::atEnd() instead of duplicated code.
* khtml/xml/dom_nodeimpl.h:
* khtml/xml/dom_nodeimpl.cpp:
(NodeImpl::maxDeepOffset):
Added to support Position::next(), Position::previous(), Position::atStart(), Position::atEnd()
* khtml/xml/dom_position.h:
* khtml/xml/dom_position.cpp:
(DOM::Position::previous):
(DOM::Position::next):
(DOM::Position::atStart):
(DOM::Position::atEnd):
Moved here, replacing VisiblePosition's duplicate and PositionIterator. Fixed to
return positions in order and not skip positions.
(DOM::Position::previousCharacterPosition):
(DOM::Position::nextCharacterPosition):
Use Position::next(), Position::previous(), Position::atStart(), Position::atEnd() instead of PositionIterator.
(DOM::isStreamer):
(DOM::Position::upstream):
(DOM::Position::downstream):
Use Position::next(), Position::previous(), Position::atStart(), Position::atEnd() instead of PositionIterator.
* khtml/xml/dom_positioniterator.cpp: Removed.
* khtml/xml/dom_positioniterator.h: Removed.
Removed in favor of Position::next(), Position::previous(), Position::atStart(), Position::atEnd()
Revision Changes Path
No revision
No revision
1.4104.2.76 +53 -0 WebCore/ChangeLog
Index: ChangeLog
===================================================================
RCS file: /cvs/root/WebCore/ChangeLog,v
retrieving revision 1.4104.2.75
retrieving revision 1.4104.2.76
diff -u -r1.4104.2.75 -r1.4104.2.76
--- ChangeLog 26 Jul 2005 21:44:06 -0000 1.4104.2.75
+++ ChangeLog 26 Jul 2005 22:45:21 -0000 1.4104.2.76
@@ -1,5 +1,58 @@
2005-07-26 Adele Peterson <adele at apple.com>
+ Merged fix from TOT to Safari-2-0-branch. Needed for other editing fixes on the branch.
+
+ 2005-05-06 David Harrison <harrison at apple.com>
+
+ Reviewed by Maciej, Darin.
+
+ <rdar://problem/4103339> VisiblePosition and PositionIterator iterators do not return positions in order
+
+ * WebCore.pbproj/project.pbxproj:
+ Removed dom_positioniterator.h and dom_positioniterator.cpp.
+
+ * khtml/editing/htmlediting.cpp:
+ Removed unused include of dom_positioniterator.h and "using" of PositionIterator.
+
+ * khtml/editing/selection.cpp:
+ Removed unused include of dom_positioniterator.h.
+
+ * khtml/editing/visible_position.h:
+ * khtml/editing/visible_position.cpp:
+ (khtml::VisiblePosition::previousVisiblePosition):
+ (khtml::VisiblePosition::nextVisiblePosition):
+ (khtml::VisiblePosition::downstreamDeepEquivalent):
+ Use Position::next(), Position::previous(), Position::atStart(), Position::atEnd() instead of duplicated code.
+
+ * khtml/xml/dom_nodeimpl.h:
+ * khtml/xml/dom_nodeimpl.cpp:
+ (NodeImpl::maxDeepOffset):
+ Added to support Position::next(), Position::previous(), Position::atStart(), Position::atEnd()
+
+ * khtml/xml/dom_position.h:
+ * khtml/xml/dom_position.cpp:
+ (DOM::Position::previous):
+ (DOM::Position::next):
+ (DOM::Position::atStart):
+ (DOM::Position::atEnd):
+ Moved here, replacing VisiblePosition's duplicate and PositionIterator. Fixed to
+ return positions in order and not skip positions.
+
+ (DOM::Position::previousCharacterPosition):
+ (DOM::Position::nextCharacterPosition):
+ Use Position::next(), Position::previous(), Position::atStart(), Position::atEnd() instead of PositionIterator.
+
+ (DOM::isStreamer):
+ (DOM::Position::upstream):
+ (DOM::Position::downstream):
+ Use Position::next(), Position::previous(), Position::atStart(), Position::atEnd() instead of PositionIterator.
+
+ * khtml/xml/dom_positioniterator.cpp: Removed.
+ * khtml/xml/dom_positioniterator.h: Removed.
+ Removed in favor of Position::next(), Position::previous(), Position::atStart(), Position::atEnd()
+
+2005-07-26 Adele Peterson <adele at apple.com>
+
Merged fix from TOT to Safari-2-0-branch
2005-07-12 Justin Garcia <justin.garcia at apple.com>
No revision
No revision
1.524.2.18 +2 -41 WebCore/WebCore.pbproj/Attic/project.pbxproj
Index: project.pbxproj
===================================================================
RCS file: /cvs/root/WebCore/WebCore.pbproj/Attic/project.pbxproj,v
retrieving revision 1.524.2.17
retrieving revision 1.524.2.18
diff -u -r1.524.2.17 -r1.524.2.18
--- project.pbxproj 26 Jul 2005 00:52:11 -0000 1.524.2.17
+++ project.pbxproj 26 Jul 2005 22:45:28 -0000 1.524.2.18
@@ -520,7 +520,6 @@
51F6A3D80663BF04004D2919,
51F6A3E00663C2EC004D2919,
2D90660D0665D937006B6F1A,
- BE02F484066E1C550013A9F6,
BE02D4E8066F908A0076809F,
93D1FEF7067EBF89009CE68A,
9348900606C00363007E7ACE,
@@ -539,8 +538,7 @@
BECE67BE07087B250007C14B,
BEA5E01E075CEDAC0098A432,
9378D9FC07640A46004B97BF,
- EDA5AC98076FB89100DD23EC,
- 65FD9D2E081D727F00636F54,
+ 65FD9D2E081D727F00636F54,
B55772C70883262B00DCA277,
B55772DF08833B6300DCA277,
);
@@ -814,7 +812,6 @@
51F6A3D70663BF04004D2919,
51F6A3DF0663C2EC004D2919,
2D90660E0665D937006B6F1A,
- BE02F485066E1C550013A9F6,
BE02D4E9066F908A0076809F,
BE1A407206CA8A33005B28CF,
BC06F24D06D18A7E004A6FA3,
@@ -831,7 +828,7 @@
BEA5DBDB075CEDA00098A432,
9378D9FB07640A46004B97BF,
51111AC107BD812C00B7162C,
- 65FD9D2D081D727F00636F54,
+ 65FD9D2D081D727F00636F54,
B55772C60883262B00DCA277,
);
isa = PBXSourcesBuildPhase;
@@ -3216,34 +3213,6 @@
settings = {
};
};
- BE02F482066E1C550013A9F6 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.c.h;
- path = dom_positioniterator.h;
- refType = 4;
- sourceTree = "<group>";
- };
- BE02F483066E1C550013A9F6 = {
- fileEncoding = 30;
- isa = PBXFileReference;
- lastKnownFileType = sourcecode.cpp.cpp;
- path = dom_positioniterator.cpp;
- refType = 4;
- sourceTree = "<group>";
- };
- BE02F484066E1C550013A9F6 = {
- fileRef = BE02F482066E1C550013A9F6;
- isa = PBXBuildFile;
- settings = {
- };
- };
- BE02F485066E1C550013A9F6 = {
- fileRef = BE02F483066E1C550013A9F6;
- isa = PBXBuildFile;
- settings = {
- };
- };
BE16801805EDB91A00B87935 = {
fileEncoding = 30;
isa = PBXFileReference;
@@ -3642,12 +3611,6 @@
refType = 4;
sourceTree = "<group>";
};
- EDA4AC98076FB89100DD23EC = {
- fileRef = EDA4AC97076FB89100DD23EC;
- isa = PBXBuildFile;
- settings = {
- };
- };
//ED0
//ED1
//ED2
@@ -7007,8 +6970,6 @@
F523D2FA02DE4476018635CA,
BE91FC8B06133666005E3790,
BE91FC8C06133666005E3790,
- BE02F482066E1C550013A9F6,
- BE02F483066E1C550013A9F6,
F523D2FB02DE4476018635CA,
F523D2FC02DE4476018635CA,
F523D2FD02DE4476018635CA,
No revision
No revision
1.228.8.4 +0 -2 WebCore/khtml/editing/htmlediting.cpp
Index: htmlediting.cpp
===================================================================
RCS file: /cvs/root/WebCore/khtml/editing/htmlediting.cpp,v
retrieving revision 1.228.8.3
retrieving revision 1.228.8.4
diff -u -r1.228.8.3 -r1.228.8.4
--- htmlediting.cpp 7 May 2005 17:46:34 -0000 1.228.8.3
+++ htmlediting.cpp 26 Jul 2005 22:45:31 -0000 1.228.8.4
@@ -35,7 +35,6 @@
#include "dom_elementimpl.h"
#include "dom_nodeimpl.h"
#include "dom_position.h"
-#include "dom_positioniterator.h"
#include "dom_stringimpl.h"
#include "dom_textimpl.h"
#include "dom2_range.h"
@@ -83,7 +82,6 @@
using DOM::NodeImpl;
using DOM::NodeListImpl;
using DOM::Position;
-using DOM::PositionIterator;
using DOM::Range;
using DOM::RangeImpl;
using DOM::StayInBlock;
1.79.8.2 +0 -1 WebCore/khtml/editing/selection.cpp
Index: selection.cpp
===================================================================
RCS file: /cvs/root/WebCore/khtml/editing/selection.cpp,v
retrieving revision 1.79.8.1
retrieving revision 1.79.8.2
diff -u -r1.79.8.1 -r1.79.8.2
--- selection.cpp 22 Jul 2005 01:18:31 -0000 1.79.8.1
+++ selection.cpp 26 Jul 2005 22:45:31 -0000 1.79.8.2
@@ -42,7 +42,6 @@
#include "xml/dom_docimpl.h"
#include "xml/dom_elementimpl.h"
#include "xml/dom_nodeimpl.h"
-#include "xml/dom_positioniterator.h"
#include "xml/dom_textimpl.h"
#include "xml/dom2_rangeimpl.h"
1.39.8.3 +10 -65 WebCore/khtml/editing/visible_position.cpp
Index: visible_position.cpp
===================================================================
RCS file: /cvs/root/WebCore/khtml/editing/visible_position.cpp,v
retrieving revision 1.39.8.2
retrieving revision 1.39.8.3
diff -u -r1.39.8.2 -r1.39.8.3
--- visible_position.cpp 26 Jul 2005 21:14:23 -0000 1.39.8.2
+++ visible_position.cpp 26 Jul 2005 22:45:31 -0000 1.39.8.3
@@ -44,6 +44,7 @@
using DOM::CharacterDataImpl;
using DOM::NodeImpl;
using DOM::offsetInCharacters;
+using DOM::UsingComposedCharacters;
using DOM::Position;
using DOM::Range;
using DOM::RangeImpl;
@@ -197,7 +198,7 @@
Position VisiblePosition::previousVisiblePosition(const Position &pos)
{
- if (pos.isNull() || atStart(pos))
+ if (pos.isNull() || pos.atStart())
return Position();
Position test = deepEquivalent(pos);
@@ -211,8 +212,8 @@
// that is not a candidate. That is wrong! However, our clients seem to
// like it. Gotta lose those clients! (initDownstream and initUpstream)
Position current = test;
- while (!atStart(current)) {
- current = previousPosition(current);
+ while (!current.atStart()) {
+ current = current.previous(UsingComposedCharacters);
if (isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream(StayInBlock)))) {
return current;
}
@@ -223,7 +224,7 @@
Position VisiblePosition::nextVisiblePosition(const Position &pos)
{
- if (pos.isNull() || atEnd(pos))
+ if (pos.isNull() || pos.atEnd())
return Position();
Position test = deepEquivalent(pos);
@@ -231,8 +232,8 @@
Position current = test;
Position downstreamTest = test.downstream(StayInBlock);
- while (!atEnd(current)) {
- current = nextPosition(current);
+ while (!current.atEnd()) {
+ current = current.next(UsingComposedCharacters);
if (isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream(StayInBlock)))) {
return current;
}
@@ -241,62 +242,6 @@
return Position();
}
-Position VisiblePosition::previousPosition(const Position &pos)
-{
- if (pos.isNull())
- return pos;
-
- Position result;
-
- if (pos.offset() <= 0) {
- NodeImpl *prevNode = pos.node()->traversePreviousNode();
- if (prevNode)
- result = Position(prevNode, prevNode->maxOffset());
- }
- else {
- NodeImpl *node = pos.node();
- result = Position(node, node->previousOffset(pos.offset()));
- }
-
- return result;
-}
-
-Position VisiblePosition::nextPosition(const Position &pos)
-{
- if (pos.isNull())
- return pos;
-
- Position result;
-
- if (pos.offset() >= pos.node()->maxOffset()) {
- NodeImpl *nextNode = pos.node()->traverseNextNode();
- if (nextNode)
- result = Position(nextNode, 0);
- }
- else {
- NodeImpl *node = pos.node();
- result = Position(node, node->nextOffset(pos.offset()));
- }
-
- return result;
-}
-
-bool VisiblePosition::atStart(const Position &pos)
-{
- if (pos.isNull())
- return true;
-
- return pos.offset() <= 0 && pos.node()->previousLeafNode() == 0;
-}
-
-bool VisiblePosition::atEnd(const Position &pos)
-{
- if (pos.isNull())
- return true;
-
- return pos.offset() >= pos.node()->maxOffset() && pos.node()->nextLeafNode() == 0;
-}
-
bool VisiblePosition::isCandidate(const Position &pos)
{
if (pos.isNull())
@@ -381,14 +326,14 @@
{
Position pos = m_deepPosition;
- if (pos.isNull() || atEnd(pos))
+ if (pos.isNull() || pos.atEnd())
return pos;
Position downstreamTest = pos.downstream(StayInBlock);
Position current = pos;
- while (!atEnd(current)) {
- current = nextPosition(current);
+ while (!current.atEnd()) {
+ current = current.next(UsingComposedCharacters);
if (isCandidate(current)) {
if (downstreamTest != current.downstream(StayInBlock))
break;
1.21.8.1 +0 -6 WebCore/khtml/editing/visible_position.h
Index: visible_position.h
===================================================================
RCS file: /cvs/root/WebCore/khtml/editing/visible_position.h,v
retrieving revision 1.21
retrieving revision 1.21.8.1
diff -u -r1.21 -r1.21.8.1
--- visible_position.h 4 Mar 2005 22:32:15 -0000 1.21
+++ visible_position.h 26 Jul 2005 22:45:31 -0000 1.21.8.1
@@ -103,12 +103,6 @@
static Position previousVisiblePosition(const Position &);
static Position nextVisiblePosition(const Position &);
- static Position previousPosition(const Position &);
- static Position nextPosition(const Position &);
-
- static bool atStart(const Position &);
- static bool atEnd(const Position &);
-
static bool isCandidate(const Position &);
Position m_deepPosition;
No revision
No revision
1.140.8.5 +12 -0 WebCore/khtml/xml/dom_nodeimpl.cpp
Index: dom_nodeimpl.cpp
===================================================================
RCS file: /cvs/root/WebCore/khtml/xml/dom_nodeimpl.cpp,v
retrieving revision 1.140.8.4
retrieving revision 1.140.8.5
diff -u -r1.140.8.4 -r1.140.8.5
--- dom_nodeimpl.cpp 22 Jul 2005 01:18:34 -0000 1.140.8.4
+++ dom_nodeimpl.cpp 26 Jul 2005 22:45:32 -0000 1.140.8.5
@@ -1401,6 +1401,18 @@
return 1;
}
+// method for editing madness, which allows BR,1 as a position, though that is incorrect
+long NodeImpl::maxDeepOffset() const
+{
+ if (offsetInCharacters(nodeType()))
+ return static_cast<const TextImpl*>(this)->length();
+
+ if (id() == ID_BR || (renderer() && renderer()->isReplaced()))
+ return 1;
+
+ return childNodeCount();
+}
+
long NodeImpl::caretMinOffset() const
{
return renderer() ? renderer()->caretMinOffset() : 0;
1.75.8.5 +1 -0 WebCore/khtml/xml/dom_nodeimpl.h
Index: dom_nodeimpl.h
===================================================================
RCS file: /cvs/root/WebCore/khtml/xml/dom_nodeimpl.h,v
retrieving revision 1.75.8.4
retrieving revision 1.75.8.5
diff -u -r1.75.8.4 -r1.75.8.5
--- dom_nodeimpl.h 22 Jul 2005 03:09:51 -0000 1.75.8.4
+++ dom_nodeimpl.h 26 Jul 2005 22:45:33 -0000 1.75.8.5
@@ -364,6 +364,7 @@
virtual bool childAllowed( NodeImpl *newChild );
virtual long maxOffset() const;
+ long maxDeepOffset() const;
virtual long caretMinOffset() const;
virtual long caretMaxOffset() const;
virtual unsigned long caretMaxRenderedOffset() const;
1.65.8.2 +245 -93 WebCore/khtml/xml/dom_position.cpp
Index: dom_position.cpp
===================================================================
RCS file: /cvs/root/WebCore/khtml/xml/dom_position.cpp,v
retrieving revision 1.65.8.1
retrieving revision 1.65.8.2
diff -u -r1.65.8.1 -r1.65.8.2
--- dom_position.cpp 22 Jul 2005 01:18:34 -0000 1.65.8.1
+++ dom_position.cpp 26 Jul 2005 22:45:33 -0000 1.65.8.2
@@ -31,7 +31,6 @@
#include "css_valueimpl.h"
#include "dom_elementimpl.h"
#include "dom_nodeimpl.h"
-#include "dom_positioniterator.h"
#include "dom2_range.h"
#include "dom2_rangeimpl.h"
#include "dom2_viewsimpl.h"
@@ -160,6 +159,82 @@
return new CSSComputedStyleDeclarationImpl(elem);
}
+Position Position::previous(EUsingComposedCharacters usingComposedCharacters) const
+{
+ NodeImpl *n = node();
+ if (!n)
+ return *this;
+
+ long o = offset();
+ assert(o >= 0);
+
+ if (o > 0) {
+ NodeImpl *child = n->childNode(o - 1);
+ if (child) {
+ return Position(child, child->maxDeepOffset());
+ }
+ // 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 ? n->previousOffset(o) : o - 1);
+ }
+
+ NodeImpl *parent = n->parentNode();
+ if (!parent)
+ return *this;
+
+ return Position(parent, n->nodeIndex());
+}
+
+Position Position::next(EUsingComposedCharacters usingComposedCharacters) const
+{
+ NodeImpl *n = node();
+ if (!n)
+ return *this;
+
+ long o = offset();
+ assert(o >= 0);
+
+ if (o < n->maxDeepOffset()) {
+ NodeImpl *child = n->childNode(o);
+ if (child) {
+ return Position(child, 0);
+ }
+ // 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 ? n->nextOffset(o) : o + 1);
+ }
+
+ NodeImpl *parent = n->parentNode();
+ if (!parent)
+ return *this;
+
+ return Position(parent, n->nodeIndex() + 1);
+}
+
+bool Position::atStart() const
+{
+ NodeImpl *n = node();
+ if (!n)
+ return true;
+
+ return offset() <= 0 && n->parent() == 0;
+}
+
+bool Position::atEnd() const
+{
+ NodeImpl *n = node();
+ if (!n)
+ return true;
+
+ return offset() >= n->maxDeepOffset() && n->parent() == 0;
+}
+
long Position::renderedOffset() const
{
if (!node()->isTextNode())
@@ -184,196 +259,273 @@
return result;
}
+// return first preceding DOM position rendered at a different location, or "this"
Position Position::previousCharacterPosition(EAffinity affinity) const
{
if (isNull())
return Position();
NodeImpl *fromRootEditableElement = node()->rootEditableElement();
- PositionIterator it(*this);
bool atStartOfLine = isFirstVisiblePositionOnLine(VisiblePosition(*this, affinity));
bool rendered = inRenderedContent();
- while (!it.atStart()) {
- Position pos = it.previous();
+ Position currentPos = *this;
+ while (!currentPos.atStart()) {
+ currentPos = currentPos.previous();
- if (pos.node()->rootEditableElement() != fromRootEditableElement)
+ if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
return *this;
if (atStartOfLine || !rendered) {
- if (pos.inRenderedContent())
- return pos;
- }
- else if (rendersInDifferentPosition(pos))
- return pos;
+ if (currentPos.inRenderedContent())
+ return currentPos;
+ } else if (rendersInDifferentPosition(currentPos))
+ return currentPos;
}
return *this;
}
+// return first following position rendered at a different location, or "this"
Position Position::nextCharacterPosition(EAffinity affinity) const
{
if (isNull())
return Position();
NodeImpl *fromRootEditableElement = node()->rootEditableElement();
- PositionIterator it(*this);
bool atEndOfLine = isLastVisiblePositionOnLine(VisiblePosition(*this, affinity));
bool rendered = inRenderedContent();
- while (!it.atEnd()) {
- Position pos = it.next();
+ Position currentPos = *this;
+ while (!currentPos.atEnd()) {
+ currentPos = currentPos.next();
- if (pos.node()->rootEditableElement() != fromRootEditableElement)
+ if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
return *this;
if (atEndOfLine || !rendered) {
- if (pos.inRenderedContent())
- return pos;
- }
- else if (rendersInDifferentPosition(pos))
- return pos;
+ if (currentPos.inRenderedContent())
+ return currentPos;
+ } else if (rendersInDifferentPosition(currentPos))
+ return currentPos;
}
return *this;
}
+// upstream() and downstream() want to return positions that are either in a
+// text node or at just before a non-text node. This method checks for that.
+static bool isStreamer (Position pos)
+{
+ NodeImpl *currentNode = pos.node();
+ if (!currentNode)
+ return true;
+
+ if (currentNode->isAtomicNode())
+ return true;
+
+ 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 a visible DOM position that is either in
+// a text node, or just after a replaced or BR element (btw downstream() also considers empty blocks).
+// If "stayInBlock" is specified, the search stops when it would have entered into a part of the DOM
+// with a different enclosing block, including a nested one. Otherwise, the search stops at the start
+// of the entire DOM tree. If "stayInBlock" stops the search, this method returns the highest previous
+// position that is either in an atomic node (i.e. text) or is the end of a non-atomic node
+// (_regardless_ of visibility). If the end-of-DOM stopped the search, this method returns the
+// highest previous visible node that is either in an atomic node (i.e. text) or is the end of a
+// non-atomic node.
Position Position::upstream(EStayInBlock stayInBlock) const
{
+ // start at equivalent deep position
Position start = equivalentDeepPosition();
NodeImpl *startNode = start.node();
if (!startNode)
return Position();
-
- NodeImpl *block = startNode->enclosingBlockFlowOrTableElement();
- Position lastVisible;
- PositionIterator it(start);
- for (; !it.atStart(); it.previous()) {
- NodeImpl *currentNode = it.current().node();
-
- if (stayInBlock) {
- NodeImpl *currentBlock = currentNode->enclosingBlockFlowOrTableElement();
- if (block != currentBlock)
- return it.next();
- }
+ // iterate backward from there, looking for a qualified position
+ NodeImpl *block = stayInBlock ? startNode->enclosingBlockFlowOrTableElement() : 0;
+ Position lastVisible = *this;
+ Position lastStreamer = *this;
+ Position currentPos = start;
+ for (; !currentPos.atStart(); currentPos = currentPos.previous()) {
+ NodeImpl *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
+ if (stayInBlock && block != currentNode->enclosingBlockFlowOrTableElement())
+ return lastStreamer;
+
+ // track last streamer position (regardless of visibility)
+ if (isStreamer(currentPos))
+ lastStreamer = currentPos;
+ // skip position in unrendered or invisible node
RenderObject *renderer = currentNode->renderer();
- if (!renderer)
- continue;
-
- if (renderer->style()->visibility() != VISIBLE)
+ if (!renderer || renderer->style()->visibility() != VISIBLE)
continue;
- lastVisible = it.current();
+ // track last visible streamer position
+ if (isStreamer(currentPos))
+ lastVisible = currentPos;
+ // return position after replaced or BR elements
if (renderer->isReplaced() || renderer->isBR()) {
- if (it.current().offset() >= renderer->caretMaxOffset())
+ if (currentOffset >= renderer->caretMaxOffset())
return Position(currentNode, renderer->caretMaxOffset());
- else
- continue;
+
+ // we could not have iterated here because we would have returned
+ // this node, caretMaxOffset, so we must have started here
+ assert(currentPos == start);
+ continue;
}
+ // return current position if it is in rendered text
if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
- if (currentNode != startNode)
+ if (currentNode != startNode) {
+ assert(currentOffset >= renderer->caretMaxOffset());
return Position(currentNode, renderer->caretMaxOffset());
+ }
- if (it.current().offset() < 0)
+ if (currentOffset < 0)
continue;
- uint textOffset = it.current().offset();
+ uint textOffset = currentOffset;
RenderText *textRenderer = static_cast<RenderText *>(renderer);
for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
if (textOffset > box->start() && textOffset <= box->start() + box->len())
- return it.current();
- else if (box != textRenderer->lastTextBox() &&
- !box->nextOnLine() &&
- textOffset == box->start() + box->len() + 1)
- return it.current();
+ return currentPos;
+
+ if (box != textRenderer->lastTextBox() &&
+ !box->nextOnLine() &&
+ textOffset == box->start() + box->len() + 1)
+ return currentPos;
}
}
}
-
- return lastVisible.isNotNull() ? lastVisible : *this;
+
+ 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). If "stayInBlock" is specified, the search stops when it would
+// have entered into a part of the DOM with a different enclosing block, including a nested one.
+// Otherwise, the search stops at the end of the entire DOM tree. If "stayInBlock" stops the search,
+// this method returns the first previous position that is either in an atomic node (i.e. text) or is
+// at offset 0 (_regardless_ of visibility). If the end-of-DOM stopped the search, this method returns
+// the first previous visible node that is either in an atomic node (i.e. text) or is at offset 0.
Position Position::downstream(EStayInBlock stayInBlock) const
{
+ // start at equivalent deep position
Position start = equivalentDeepPosition();
NodeImpl *startNode = start.node();
if (!startNode)
return Position();
- NodeImpl *block = startNode->enclosingBlockFlowOrTableElement();
- Position lastVisible;
-
- PositionIterator it(start);
- for (; !it.atEnd(); it.next()) {
- NodeImpl *currentNode = it.current().node();
-
- if (stayInBlock) {
- NodeImpl *currentBlock = currentNode->enclosingBlockFlowOrTableElement();
- if (block != currentBlock)
- return it.previous();
- }
+ // iterate forward from there, looking for a qualified position
+ NodeImpl *block = stayInBlock ? startNode->enclosingBlockFlowOrTableElement() : 0;
+ Position lastVisible = *this;
+ Position lastStreamer = *this;
+ Position currentPos = start;
+ for (; !currentPos.atEnd(); currentPos = currentPos.next()) {
+ NodeImpl *currentNode = currentPos.node();
+ int currentOffset = currentPos.offset();
+
+ // stop before going above the body, up into the head
+ // return the last visible streamer position
+ if (currentNode->id() == ID_BODY && currentOffset >= (int) currentNode->childNodeCount())
+ break;
+
+ // limit traversal to block or table enclosing the original element
+ // return the last streamer position regardless of visibility
+ // NOTE: This includes not going into nested blocks
+ if (stayInBlock && block != currentNode->enclosingBlockFlowOrTableElement())
+ return lastStreamer;
+
+ // track last streamer position (regardless of visibility)
+ if (isStreamer(currentPos))
+ lastStreamer = currentPos;
+ // skip position in unrendered or invisible node
RenderObject *renderer = currentNode->renderer();
- if (!renderer)
+ if (!renderer || renderer->style()->visibility() != VISIBLE)
continue;
+
+ // 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 (NodeImpl *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.
- if (renderer->style()->visibility() != VISIBLE)
- continue;
-
- lastVisible = it.current();
-
- if (currentNode != startNode && renderer->isBlockFlow()) {
- if (it.current().offset() == 0) {
- // If no first child, or first visible child is a not a block, return; otherwise continue.
- if (!currentNode->firstChild())
- return Position(currentNode, 0);
- for (NodeImpl *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.
- else
- return Position(child, 0);
- }
+ return Position(child, 0);
}
- continue;
}
+
+ continue;
}
+ // return position before replaced or BR elements
if (renderer->isReplaced() || renderer->isBR()) {
- if (it.current().offset() <= renderer->caretMinOffset())
+ if (currentOffset <= renderer->caretMinOffset())
return Position(currentNode, renderer->caretMinOffset());
- else
- continue;
+
+ // we could not have iterated here because we would have returned
+ // this node, offset 0, so we must have started here
+ assert(currentPos == start);
+ continue;
}
+ // return current position if it is in rendered text
if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
- if (currentNode != start.node())
+ if (currentNode != startNode) {
+ assert(currentOffset == 0);
return Position(currentNode, renderer->caretMinOffset());
+ }
- if (it.current().offset() < 0)
+ if (currentOffset < 0)
continue;
- uint textOffset = it.current().offset();
+
+ uint textOffset = currentOffset;
RenderText *textRenderer = static_cast<RenderText *>(renderer);
for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
if (textOffset >= box->start() && textOffset <= box->end())
- return it.current();
- else if (box != textRenderer->lastTextBox() &&
- !box->nextOnLine() &&
- textOffset == box->start() + box->len())
- return it.current();
+ return currentPos;
+
+ if (box != textRenderer->lastTextBox() &&
+ !box->nextOnLine() &&
+ textOffset == box->start() + box->len()) {
+ return currentPos;
+ }
}
}
}
- return lastVisible.isNotNull() ? lastVisible : *this;
+ return lastVisible;
}
Position Position::equivalentRangeCompliantPosition() const
1.29.8.1 +7 -0 WebCore/khtml/xml/dom_position.h
Index: dom_position.h
===================================================================
RCS file: /cvs/root/WebCore/khtml/xml/dom_position.h,v
retrieving revision 1.29
retrieving revision 1.29.8.1
diff -u -r1.29 -r1.29.8.1
--- dom_position.h 8 Mar 2005 17:42:38 -0000 1.29
+++ dom_position.h 26 Jul 2005 22:45:33 -0000 1.29.8.1
@@ -37,6 +37,7 @@
class RangeImpl;
enum EStayInBlock { DoNotStayInBlock = false, StayInBlock = true };
+enum EUsingComposedCharacters { NotUsingComposedCharacters = false, UsingComposedCharacters = true };
class Position
{
@@ -59,6 +60,12 @@
ElementImpl *element() const;
CSSComputedStyleDeclarationImpl *computedStyle() const;
+ // Move up or down the DOM by one position
+ Position previous(EUsingComposedCharacters usingComposedCharacters=NotUsingComposedCharacters) const;
+ Position next(EUsingComposedCharacters usingComposedCharacters=NotUsingComposedCharacters) const;
+ bool atStart() const;
+ bool atEnd() const;
+
// FIXME: Make these non-member functions and put them somewhere in the editing directory.
// These aren't really basic "position" operations. More high level editing helper functions.
Position leadingWhitespacePosition(khtml::EAffinity affinity, bool considerNonCollapsibleWhitespace = false) const;
More information about the webkit-changes
mailing list