[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