2008-04-01 Darin Adler <darin@apple.com>
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Apr 2008 00:28:29 +0000 (00:28 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Apr 2008 00:28:29 +0000 (00:28 +0000)
        Reviewed by Sam and Antti.

        - fix <rdar://problem/5829565> paste performance slowed down with the Range Acid3 changes

        Added a new class, RangeBoundaryPoint, to use for range boundary points. The "truth" of
        the offset is now stored as a node pointer, and the offset is computed as and when needed.
        This allows us to efficiently update when the DOM tree is changed -- computation of the
        node offsets is deferred until the Range is used later.

        * WebCore.base.exp: Export nodeIndex().

        * WebCore.xcodeproj/project.pbxproj: Added RangeBoundaryPoint.h, removed NodeWithIndexBefore.h
        and NodeWIthIndexAfter.h. Also let Xcode tweak the file formatting.

        * dom/ContainerNode.cpp:
        (WebCore::ContainerNode::childrenChanged): Pass fewer arguments to Document.

        * dom/Document.cpp:
        (WebCore::Document::nodeChildrenChanged): Pass fewer arguments to Range.
        (WebCore::Document::nodeWillBeRemoved): Pass node to range as a raw node pointer; no need for
        the index.
        * dom/Document.h: Take fewer arguments.

        * dom/NodeWithIndexAfter.h: Removed.
        * dom/NodeWithIndexBefore.h: Removed.

        * dom/Range.cpp:
        (WebCore::Range::Range): Changed to use the new RangeBoundaryPoint constructor.
        (WebCore::Range::create): Updated to use RangeBoundaryPoint instead of Position.
        (WebCore::Range::~Range): Ditto.
        (WebCore::Range::startContainer): Ditto.
        (WebCore::Range::startOffset): Ditto.
        (WebCore::Range::endContainer): Ditto.
        (WebCore::Range::endOffset): Ditto.
        (WebCore::Range::commonAncestorContainer): Ditto.
        (WebCore::Range::collapsed): Ditto.
        (WebCore::Range::setStart): Ditto.
        (WebCore::Range::setEnd): Ditto.
        (WebCore::Range::collapse): Ditto.
        (WebCore::Range::isPointInRange): Ditto.
        (WebCore::Range::comparePoint): Ditto.
        (WebCore::Range::compareNode): Ditto.
        (WebCore::Range::compareBoundaryPoints): Ditto.
        (WebCore::Range::boundaryPointsValid): Ditto.
        (WebCore::Range::intersectsNode): Ditto.
        (WebCore::Range::processContents): Ditto.
        (WebCore::Range::cloneContents): Ditto.
        (WebCore::Range::insertNode): Updated to use RangeBoundaryPoint. Also simplified the code
        at the end that updates the range -- not all of it is needed now since most of the fixup
        is done automatically by the range document mutation machinery. The one bit that remains
        is arguably a bug, but we need to keep it to keep passing Acid3 until we get clarification
        that it is indeed a bug (and then Acid3 will probably have to change).
        (WebCore::Range::toString): Update to use RangeBoundaryPoint instead of Position.
        (WebCore::Range::text): Ditto.
        (WebCore::Range::createContextualFragment): Ditto.
        (WebCore::Range::detach): Ditto.
        (WebCore::Range::checkNodeWOffset): Changed case where the offset is a node offset to
        be more efficient by using childNode instead of childNodeCount, and also return the node
        before which is needed to set the value of a RangeBoundaryPoint.
        (WebCore::Range::cloneRange): Ditto.
        (WebCore::Range::setStartAfter): Ditto.
        (WebCore::Range::setEndBefore): Ditto.
        (WebCore::Range::setEndAfter): Ditto.
        (WebCore::Range::selectNode): Ditto.
        (WebCore::Range::selectNodeContents): Ditto.
        (WebCore::Range::surroundContents): Ditto.
        (WebCore::Range::setStartBefore): Ditto.
        (WebCore::Range::checkDeleteExtract): Ditto.
        (WebCore::Range::containedByReadOnly): Ditto.
        (WebCore::Range::firstNode): Ditto.
        (WebCore::Range::editingStartPosition): Ditto.
        (WebCore::Range::pastLastNode): Ditto.
        (WebCore::Range::addLineBoxRects): Ditto.
        (WebCore::Range::formatForDebugger): Ditto.
        (WebCore::Range::maxStartOffset): Ditto.
        (WebCore::Range::maxEndOffset): Ditto.
        (WebCore::boundaryNodeChildrenChanged): Updated to use RangeBoundaryPoint instead of
        Position. Also changed name and changed to just call invalidateOffset.
        (WebCore::Range::nodeChildrenChanged): Changed to take just a container node.
        (WebCore::boundaryNodeWillBeRemoved): Updated to use RangeBoundaryPoint instead of
        Position. Also changed name and changed to update childBefore.
        (WebCore::Range::nodeWillBeRemoved): Changed to just take a Node*.
        (WebCore::boundaryTextInserted): Updated to use RangeBoundaryPoint instead of
        Position. Also changed name.
        (WebCore::Range::textInserted): Ditto.
        (WebCore::boundaryTextRemoved): Ditto.
        (WebCore::Range::textRemoved): Ditto.
        (WebCore::boundaryTextNodesMerged): Ditto.
        (WebCore::Range::textNodesMerged): Ditto.
        (WebCore::boundaryTextNodesSplit): Ditto.
        (WebCore::Range::textNodeSplit): Ditto.

        * dom/Range.h: Updated to use RangeBoundaryPoint instead of Position.

        * dom/RangeBoundaryPoint.h: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@31549 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/WebCore.base.exp
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/dom/ContainerNode.cpp
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/dom/NodeWithIndexAfter.h [deleted file]
WebCore/dom/NodeWithIndexBefore.h [deleted file]
WebCore/dom/Range.cpp
WebCore/dom/Range.h
WebCore/dom/RangeBoundaryPoint.h [new file with mode: 0644]

index 87b587b..715fe18 100644 (file)
@@ -1,3 +1,101 @@
+2008-04-01  Darin Adler  <darin@apple.com>
+
+        Reviewed by Sam and Antti.
+
+        - fix <rdar://problem/5829565> paste performance slowed down with the Range Acid3 changes
+
+        Added a new class, RangeBoundaryPoint, to use for range boundary points. The "truth" of
+        the offset is now stored as a node pointer, and the offset is computed as and when needed.
+        This allows us to efficiently update when the DOM tree is changed -- computation of the
+        node offsets is deferred until the Range is used later.
+
+        * WebCore.base.exp: Export nodeIndex().
+
+        * WebCore.xcodeproj/project.pbxproj: Added RangeBoundaryPoint.h, removed NodeWithIndexBefore.h
+        and NodeWIthIndexAfter.h. Also let Xcode tweak the file formatting.
+
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::childrenChanged): Pass fewer arguments to Document.
+
+        * dom/Document.cpp:
+        (WebCore::Document::nodeChildrenChanged): Pass fewer arguments to Range.
+        (WebCore::Document::nodeWillBeRemoved): Pass node to range as a raw node pointer; no need for
+        the index.
+        * dom/Document.h: Take fewer arguments.
+
+        * dom/NodeWithIndexAfter.h: Removed.
+        * dom/NodeWithIndexBefore.h: Removed.
+
+        * dom/Range.cpp:
+        (WebCore::Range::Range): Changed to use the new RangeBoundaryPoint constructor.
+        (WebCore::Range::create): Updated to use RangeBoundaryPoint instead of Position.
+        (WebCore::Range::~Range): Ditto.
+        (WebCore::Range::startContainer): Ditto.
+        (WebCore::Range::startOffset): Ditto.
+        (WebCore::Range::endContainer): Ditto.
+        (WebCore::Range::endOffset): Ditto.
+        (WebCore::Range::commonAncestorContainer): Ditto.
+        (WebCore::Range::collapsed): Ditto.
+        (WebCore::Range::setStart): Ditto.
+        (WebCore::Range::setEnd): Ditto.
+        (WebCore::Range::collapse): Ditto.
+        (WebCore::Range::isPointInRange): Ditto.
+        (WebCore::Range::comparePoint): Ditto.
+        (WebCore::Range::compareNode): Ditto.
+        (WebCore::Range::compareBoundaryPoints): Ditto.
+        (WebCore::Range::boundaryPointsValid): Ditto.
+        (WebCore::Range::intersectsNode): Ditto.
+        (WebCore::Range::processContents): Ditto.
+        (WebCore::Range::cloneContents): Ditto.
+        (WebCore::Range::insertNode): Updated to use RangeBoundaryPoint. Also simplified the code
+        at the end that updates the range -- not all of it is needed now since most of the fixup
+        is done automatically by the range document mutation machinery. The one bit that remains
+        is arguably a bug, but we need to keep it to keep passing Acid3 until we get clarification
+        that it is indeed a bug (and then Acid3 will probably have to change).
+        (WebCore::Range::toString): Update to use RangeBoundaryPoint instead of Position.
+        (WebCore::Range::text): Ditto.
+        (WebCore::Range::createContextualFragment): Ditto.
+        (WebCore::Range::detach): Ditto.
+        (WebCore::Range::checkNodeWOffset): Changed case where the offset is a node offset to
+        be more efficient by using childNode instead of childNodeCount, and also return the node
+        before which is needed to set the value of a RangeBoundaryPoint.
+        (WebCore::Range::cloneRange): Ditto.
+        (WebCore::Range::setStartAfter): Ditto.
+        (WebCore::Range::setEndBefore): Ditto.
+        (WebCore::Range::setEndAfter): Ditto.
+        (WebCore::Range::selectNode): Ditto.
+        (WebCore::Range::selectNodeContents): Ditto.
+        (WebCore::Range::surroundContents): Ditto.
+        (WebCore::Range::setStartBefore): Ditto.
+        (WebCore::Range::checkDeleteExtract): Ditto.
+        (WebCore::Range::containedByReadOnly): Ditto.
+        (WebCore::Range::firstNode): Ditto.
+        (WebCore::Range::editingStartPosition): Ditto.
+        (WebCore::Range::pastLastNode): Ditto.
+        (WebCore::Range::addLineBoxRects): Ditto.
+        (WebCore::Range::formatForDebugger): Ditto.
+        (WebCore::Range::maxStartOffset): Ditto.
+        (WebCore::Range::maxEndOffset): Ditto.
+        (WebCore::boundaryNodeChildrenChanged): Updated to use RangeBoundaryPoint instead of
+        Position. Also changed name and changed to just call invalidateOffset.
+        (WebCore::Range::nodeChildrenChanged): Changed to take just a container node.
+        (WebCore::boundaryNodeWillBeRemoved): Updated to use RangeBoundaryPoint instead of
+        Position. Also changed name and changed to update childBefore.
+        (WebCore::Range::nodeWillBeRemoved): Changed to just take a Node*.
+        (WebCore::boundaryTextInserted): Updated to use RangeBoundaryPoint instead of
+        Position. Also changed name.
+        (WebCore::Range::textInserted): Ditto.
+        (WebCore::boundaryTextRemoved): Ditto.
+        (WebCore::Range::textRemoved): Ditto.
+        (WebCore::boundaryTextNodesMerged): Ditto.
+        (WebCore::Range::textNodesMerged): Ditto.
+        (WebCore::boundaryTextNodesSplit): Ditto.
+        (WebCore::Range::textNodeSplit): Ditto.
+
+        * dom/Range.h: Updated to use RangeBoundaryPoint instead of Position.
+
+        * dom/RangeBoundaryPoint.h: Added.
+
 2008-04-01  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Sam.
index 5ffa24d..e36f6fb 100644 (file)
@@ -721,6 +721,7 @@ __ZNK7WebCore4KURL4pathEv
 __ZNK7WebCore4KURLcvP5NSURLEv
 __ZNK7WebCore4Node14isDescendantOfEPKS0_
 __ZNK7WebCore4Node18getSubresourceURLsERN3WTF6VectorINS_4KURLELm0EEE
+__ZNK7WebCore4Node9nodeIndexEv
 __ZNK7WebCore4Page10pluginDataEv
 __ZNK7WebCore4Page34inLowQualityImageInterpolationModeEv
 __ZNK7WebCore5Frame10isFrameSetEv
index 89d863c..7eb20d4 100644 (file)
                371F53EA0D2704F900ECE0D5 /* CSSUnicodeRangeValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 371F53E80D2704F900ECE0D5 /* CSSUnicodeRangeValue.cpp */; };
                37919C230B7D188600A56998 /* PositionIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37919C210B7D188600A56998 /* PositionIterator.cpp */; };
                37919C240B7D188600A56998 /* PositionIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 37919C220B7D188600A56998 /* PositionIterator.h */; settings = {ATTRIBUTES = (); }; };
-               37ACCE420DA2980F0089E602 /* FontRenderingMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 37ACCE410DA2980F0089E602 /* FontRenderingMode.h */;settings = {ATTRIBUTES = (Private, ); }; };
+               37ACCE420DA2980F0089E602 /* FontRenderingMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 37ACCE410DA2980F0089E602 /* FontRenderingMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                37F818FD0D657606005E1F05 /* WebCoreURLResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 37F818FB0D657606005E1F05 /* WebCoreURLResponse.h */; settings = {ATTRIBUTES = (Private, ); }; };
                37F818FE0D657606005E1F05 /* WebCoreURLResponse.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37F818FC0D657606005E1F05 /* WebCoreURLResponse.mm */; };
                441B05560CD779B6007C1F18 /* DOMCSSStyleSheetPrivate.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 4429AAEA0CB84DC7007647C5 /* DOMCSSStyleSheetPrivate.h */; };
                9380F47409A11AB4001FDB34 /* Widget.h in Headers */ = {isa = PBXBuildFile; fileRef = 9380F47209A11AB4001FDB34 /* Widget.h */; settings = {ATTRIBUTES = (Private, ); }; };
                9380F47809A11ACC001FDB34 /* WidgetMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9380F47709A11ACC001FDB34 /* WidgetMac.mm */; };
                9382AAB40D8C386100F357A6 /* NodeWithIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 9382AAB10D8C386100F357A6 /* NodeWithIndex.h */; };
-               9382AAB50D8C386100F357A6 /* NodeWithIndexBefore.h in Headers */ = {isa = PBXBuildFile; fileRef = 9382AAB20D8C386100F357A6 /* NodeWithIndexBefore.h */; };
-               9382AAB60D8C386100F357A6 /* NodeWithIndexAfter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9382AAB30D8C386100F357A6 /* NodeWithIndexAfter.h */; };
                93831B570D087D6000E5C984 /* ExceptionCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93831B560D087D6000E5C984 /* ExceptionCode.cpp */; };
                938E65F109F09840008A48EC /* JSHTMLElementWrapperFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 938E65F009F09840008A48EC /* JSHTMLElementWrapperFactory.h */; };
                938E65F709F0985D008A48EC /* JSHTMLElementWrapperFactory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 938E65F609F0985D008A48EC /* JSHTMLElementWrapperFactory.cpp */; };
                93C841FF09CE858300DFF5E5 /* DOMImplementationFront.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93C841FE09CE858300DFF5E5 /* DOMImplementationFront.cpp */; };
                93CCF0270AF6C52900018E89 /* NavigationAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 93CCF0260AF6C52900018E89 /* NavigationAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93CCF0600AF6CA7600018E89 /* NavigationAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93CCF05F0AF6CA7600018E89 /* NavigationAction.cpp */; };
+               93D9D53C0DA27E180077216C /* RangeBoundaryPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D9D53B0DA27E180077216C /* RangeBoundaryPoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93E227E00AF589AD00D48324 /* DocumentLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E227DB0AF589AD00D48324 /* DocumentLoader.cpp */; };
                93E227E10AF589AD00D48324 /* MainResourceLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E227DC0AF589AD00D48324 /* MainResourceLoader.cpp */; };
                93E227E30AF589AD00D48324 /* ResourceLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E227DE0AF589AD00D48324 /* ResourceLoader.cpp */; };
                9380F47209A11AB4001FDB34 /* Widget.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Widget.h; sourceTree = "<group>"; };
                9380F47709A11ACC001FDB34 /* WidgetMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = WidgetMac.mm; sourceTree = "<group>"; };
                9382AAB10D8C386100F357A6 /* NodeWithIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeWithIndex.h; sourceTree = "<group>"; };
-               9382AAB20D8C386100F357A6 /* NodeWithIndexBefore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeWithIndexBefore.h; sourceTree = "<group>"; };
-               9382AAB30D8C386100F357A6 /* NodeWithIndexAfter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeWithIndexAfter.h; sourceTree = "<group>"; };
                93831B560D087D6000E5C984 /* ExceptionCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExceptionCode.cpp; sourceTree = "<group>"; };
                938E65F009F09840008A48EC /* JSHTMLElementWrapperFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSHTMLElementWrapperFactory.h; sourceTree = "<group>"; };
                938E65F609F0985D008A48EC /* JSHTMLElementWrapperFactory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLElementWrapperFactory.cpp; sourceTree = "<group>"; };
                93CA4CA309DF93FA00DF8677 /* tokenizer.flex */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = tokenizer.flex; sourceTree = "<group>"; };
                93CCF0260AF6C52900018E89 /* NavigationAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigationAction.h; sourceTree = "<group>"; };
                93CCF05F0AF6CA7600018E89 /* NavigationAction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigationAction.cpp; sourceTree = "<group>"; };
+               93D9D53B0DA27E180077216C /* RangeBoundaryPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RangeBoundaryPoint.h; sourceTree = "<group>"; };
                93E227DB0AF589AD00D48324 /* DocumentLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentLoader.cpp; sourceTree = "<group>"; };
                93E227DC0AF589AD00D48324 /* MainResourceLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MainResourceLoader.cpp; sourceTree = "<group>"; };
                93E227DD0AF589AD00D48324 /* NetscapePlugInStreamLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetscapePlugInStreamLoader.cpp; sourceTree = "<group>"; };
                                A81872100977D3C0005826D9 /* NodeList.h */,
                                85ACA9FA0A9B631000671E90 /* NodeList.idl */,
                                9382AAB10D8C386100F357A6 /* NodeWithIndex.h */,
-                               9382AAB20D8C386100F357A6 /* NodeWithIndexBefore.h */,
-                               9382AAB30D8C386100F357A6 /* NodeWithIndexAfter.h */,
                                A8EA7EB70A1945D000A8EF5F /* Notation.cpp */,
                                A8EA7EB60A1945D000A8EF5F /* Notation.h */,
                                93EEC1F409C2877700C515D1 /* Notation.idl */,
                                F523D30302DE4476018635CA /* Range.cpp */,
                                F523D30402DE4476018635CA /* Range.h */,
                                936DD03A09CEAC270056AE8C /* Range.idl */,
+                               93D9D53B0DA27E180077216C /* RangeBoundaryPoint.h */,
                                D23CA56B0AB0EB8D005108A5 /* RangeException.h */,
                                D23CA5480AB0E983005108A5 /* RangeException.idl */,
                                85031B350A44EFC700F992E0 /* RegisteredEventListener.cpp */,
                                550A0BCA085F6039007353D6 /* QualifiedName.h in Headers */,
                                B22279720D00BF220071B782 /* RadialGradientAttributes.h in Headers */,
                                93F1991808245E59001E9ABC /* Range.h in Headers */,
+                               93D9D53C0DA27E180077216C /* RangeBoundaryPoint.h in Headers */,
                                D23CA56C0AB0EB8D005108A5 /* RangeException.h in Headers */,
                                BC4368E80C226E32005EFB5F /* Rect.h in Headers */,
                                85031B4C0A44EFC700F992E0 /* RegisteredEventListener.h in Headers */,
                                A9D248070D757E7D00FDF959 /* JSMimeType.h in Headers */,
                                A9D248090D757E7D00FDF959 /* JSMimeTypeArray.h in Headers */,
                                9382AAB40D8C386100F357A6 /* NodeWithIndex.h in Headers */,
-                               9382AAB50D8C386100F357A6 /* NodeWithIndexBefore.h in Headers */,
-                               9382AAB60D8C386100F357A6 /* NodeWithIndexAfter.h in Headers */,
                                4B17CBC90D945B370053F183 /* AccessibilityObject.h in Headers */,
                                4B17CBCD0D945B910053F183 /* AccessibilityObjectWrapper.h in Headers */,
                                512DD8F50D91E6AF000F89EE /* LegacyWebArchive.h in Headers */,
index a2d96e2..7082fe6 100644 (file)
@@ -694,7 +694,7 @@ void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, No
 {
     Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
     if (!changedByParser && childCountDelta)
-        document()->nodeChildrenChanged(this, beforeChange, afterChange, childCountDelta);
+        document()->nodeChildrenChanged(this);
     if (document()->hasNodeListCaches())
         notifyNodeListsChildrenChanged();
 }
index 888d2ce..4837906 100644 (file)
@@ -80,8 +80,6 @@
 #include "NodeFilter.h"
 #include "NodeIterator.h"
 #include "NodeWithIndex.h"
-#include "NodeWithIndexAfter.h"
-#include "NodeWithIndexBefore.h"
 #include "OverflowEvent.h"
 #include "Page.h"
 #include "PlatformKeyboardEvent.h"
@@ -2466,13 +2464,11 @@ void Document::detachNodeIterator(NodeIterator *ni)
     m_nodeIterators.remove(ni);
 }
 
-void Document::nodeChildrenChanged(ContainerNode* container, Node* beforeChange, Node* afterChange, int childCountDelta)
+void Document::nodeChildrenChanged(ContainerNode* container)
 {
-    NodeWithIndexAfter beforeChangeWithIndex(beforeChange);
-    NodeWithIndexBefore afterChangeWithIndex(container, afterChange);
     HashSet<Range*>::const_iterator end = m_ranges.end();
     for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != end; ++it)
-        (*it)->nodeChildrenChanged(beforeChangeWithIndex, afterChangeWithIndex, childCountDelta);
+        (*it)->nodeChildrenChanged(container);
 }
 
 void Document::nodeWillBeRemoved(Node* n)
@@ -2481,10 +2477,9 @@ void Document::nodeWillBeRemoved(Node* n)
     for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != nodeIteratorsEnd; ++it)
         (*it)->nodeWillBeRemoved(n);
 
-    NodeWithIndex nodeWithIndex(n);
     HashSet<Range*>::const_iterator rangesEnd = m_ranges.end();
     for (HashSet<Range*>::const_iterator it = m_ranges.begin(); it != rangesEnd; ++it)
-        (*it)->nodeWillBeRemoved(nodeWithIndex);
+        (*it)->nodeWillBeRemoved(n);
 
     if (Frame* frame = this->frame()) {
         frame->selectionController()->nodeWillBeRemoved(n);
index c4a97dd..b4e3faa 100644 (file)
@@ -479,7 +479,7 @@ public:
     void attachRange(Range*);
     void detachRange(Range*);
 
-    void nodeChildrenChanged(ContainerNode* container, Node* beforeChange, Node* afterChange, int childCountDelta);
+    void nodeChildrenChanged(ContainerNode*);
     void nodeWillBeRemoved(Node*);
 
     void textInserted(Node*, unsigned offset, unsigned length);
diff --git a/WebCore/dom/NodeWithIndexAfter.h b/WebCore/dom/NodeWithIndexAfter.h
deleted file mode 100644 (file)
index 6ce0017..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#ifndef NodeWithIndexAfter_h
-#define NodeWithIndexAfter_h
-
-#include "Node.h"
-
-namespace WebCore {
-
-// Like NodeWithIndex, but treats a node pointer of 0 as meaning
-// "before the last node in the container" and returns the index
-// value after the node rather than the value of the node.
-class NodeWithIndexAfter {
-public:
-    NodeWithIndexAfter(Node* node)
-        : m_node(node)
-        , m_haveIndex(false)
-    {
-    }
-
-    int indexAfter() const
-    {
-        if (!m_haveIndex) {
-            m_indexAfter = m_node ? m_node->nodeIndex() + 1 : 0;
-            m_haveIndex = true;
-        }
-        ASSERT(m_indexAfter == (m_node ? static_cast<int>(m_node->nodeIndex()) + 1 : 0));
-        return m_indexAfter;
-    }
-
-private:
-    Node* m_node;
-    mutable bool m_haveIndex;
-    mutable int m_indexAfter;
-};
-
-}
-
-#endif
diff --git a/WebCore/dom/NodeWithIndexBefore.h b/WebCore/dom/NodeWithIndexBefore.h
deleted file mode 100644 (file)
index bf4a8a2..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2008 Apple Inc. All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#ifndef NodeWithIndexBefore_h
-#define NodeWithIndexBefore_h
-
-#include "ContainerNode.h"
-
-namespace WebCore {
-
-// Same as NodeWithIndex, but treats a node pointer of 0 as meaning
-// "after the last node in the container".
-class NodeWithIndexBefore {
-public:
-    NodeWithIndexBefore(ContainerNode* parent, Node* node)
-        : m_parent(parent)
-        , m_node(node)
-        , m_haveIndex(false)
-    {
-        ASSERT(parent);
-        ASSERT(!node || node->parentNode() == parent);
-    }
-
-    ContainerNode* parent() const { return m_parent; }
-
-    int indexBefore() const
-    {
-        if (!m_haveIndex) {
-            m_indexBefore = m_node ? m_node->nodeIndex() : m_parent->childNodeCount();
-            m_haveIndex = true;
-        }
-        ASSERT(m_indexBefore == static_cast<int>(m_node ? m_node->nodeIndex() : m_parent->childNodeCount()));
-        return m_indexBefore;
-    }
-
-private:
-    ContainerNode* m_parent;
-    Node* m_node;
-    mutable bool m_haveIndex;
-    mutable int m_indexBefore;
-};
-
-}
-
-#endif
index c665797..749cb05 100644 (file)
@@ -32,8 +32,6 @@
 #include "HTMLElement.h"
 #include "HTMLNames.h"
 #include "NodeWithIndex.h"
-#include "NodeWithIndexAfter.h"
-#include "NodeWithIndexBefore.h"
 #include "ProcessingInstruction.h"
 #include "RenderBlock.h"
 #include "Text.h"
@@ -42,9 +40,6 @@
 #include "visible_units.h"
 #include <stdio.h>
 
-// FIXME: Remove this after removing Position::offset() and renaming Position::posOffset to offset.
-#define offset posOffset
-
 namespace WebCore {
 
 using namespace std;
@@ -66,8 +61,8 @@ static RangeCounter rangeCounter;
 
 inline Range::Range(PassRefPtr<Document> ownerDocument)
     : m_ownerDocument(ownerDocument)
-    , m_start(m_ownerDocument, 0)
-    , m_end(m_ownerDocument, 0)
+    , m_start(m_ownerDocument)
+    , m_end(m_ownerDocument)
 {
 #ifndef NDEBUG
     ++RangeCounter::count;
@@ -83,8 +78,8 @@ PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument)
 
 inline Range::Range(PassRefPtr<Document> ownerDocument, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset)
     : m_ownerDocument(ownerDocument)
-    , m_start(m_ownerDocument, 0)
-    , m_end(m_ownerDocument, 0)
+    , m_start(m_ownerDocument)
+    , m_end(m_ownerDocument)
 {
 #ifndef NDEBUG
     ++RangeCounter::count;
@@ -108,12 +103,12 @@ PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, PassRefPtr<N
 
 PassRefPtr<Range> Range::create(PassRefPtr<Document> ownerDocument, const Position& start, const Position& end)
 {
-    return adoptRef(new Range(ownerDocument, start.container.get(), start.offset, end.container.get(), end.offset));
+    return adoptRef(new Range(ownerDocument, start.container.get(), start.posOffset, end.container.get(), end.posOffset));
 }
 
 Range::~Range()
 {
-    if (m_start.container)
+    if (m_start.container())
         m_ownerDocument->detachRange(this);
 
 #ifndef NDEBUG
@@ -123,52 +118,52 @@ Range::~Range()
 
 Node* Range::startContainer(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    return m_start.container.get();
+    return m_start.container();
 }
 
 int Range::startOffset(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    return m_start.offset;
+    return m_start.offset();
 }
 
 Node* Range::endContainer(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    return m_end.container.get();
+    return m_end.container();
 }
 
 int Range::endOffset(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    return m_end.offset;
+    return m_end.offset();
 }
 
 Node* Range::commonAncestorContainer(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    return commonAncestorContainer(m_start.container.get(), m_end.container.get());
+    return commonAncestorContainer(m_start.container(), m_end.container());
 }
 
 Node* Range::commonAncestorContainer(Node* containerA, Node* containerB)
@@ -184,17 +179,17 @@ Node* Range::commonAncestorContainer(Node* containerA, Node* containerB)
 
 bool Range::collapsed(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    return m_start.container == m_end.container && m_start.offset == m_end.offset;
+    return m_start == m_end;
 }
 
 void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -210,30 +205,29 @@ void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
     }
 
     ec = 0;
-    checkNodeWOffset(refNode.get(), offset, ec);
+    Node* childNode = checkNodeWOffset(refNode.get(), offset, ec);
     if (ec)
         return;
 
-    m_start.container = refNode;
-    m_start.offset = offset;
+    m_start.set(refNode, offset, childNode);
 
     // check if different root container
-    Node* endRootContainer = m_end.container.get();
+    Node* endRootContainer = m_end.container();
     while (endRootContainer->parentNode())
         endRootContainer = endRootContainer->parentNode();
-    Node* startRootContainer = m_start.container.get();
+    Node* startRootContainer = m_start.container();
     while (startRootContainer->parentNode())
         startRootContainer = startRootContainer->parentNode();
     if (startRootContainer != endRootContainer)
         collapse(true, ec);
     // check if new start after end
-    else if (compareBoundaryPoints(m_start.container.get(), m_start.offset, m_end.container.get(), m_end.offset) > 0)
+    else if (compareBoundaryPoints(m_start.container(), m_start.offset(), m_end.container(), m_end.offset()) > 0)
         collapse(true, ec);
 }
 
 void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -249,30 +243,29 @@ void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
     }
 
     ec = 0;
-    checkNodeWOffset(refNode.get(), offset, ec);
+    Node* childNode = checkNodeWOffset(refNode.get(), offset, ec);
     if (ec)
         return;
 
-    m_end.container = refNode;
-    m_end.offset = offset;
+    m_end.set(refNode, offset, childNode);
 
     // check if different root container
-    Node* endRootContainer = m_end.container.get();
+    Node* endRootContainer = m_end.container();
     while (endRootContainer->parentNode())
         endRootContainer = endRootContainer->parentNode();
-    Node* startRootContainer = m_start.container.get();
+    Node* startRootContainer = m_start.container();
     while (startRootContainer->parentNode())
         startRootContainer = startRootContainer->parentNode();
     if (startRootContainer != endRootContainer)
         collapse(false, ec);
     // check if new end before start
-    if (compareBoundaryPoints(m_start.container.get(), m_start.offset, m_end.container.get(), m_end.offset) > 0)
+    if (compareBoundaryPoints(m_start.container(), m_start.offset(), m_end.container(), m_end.offset()) > 0)
         collapse(false, ec);
 }
 
 void Range::collapse(bool toStart, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -290,12 +283,12 @@ bool Range::isPointInRange(Node* refNode, int offset, ExceptionCode& ec)
         return false;
     }
 
-    if (!m_start.container && refNode->attached()) {
+    if (!m_start.container() && refNode->attached()) {
         ec = INVALID_STATE_ERR;
         return false;
     }
 
-    if (m_start.container && !refNode->attached()) {
+    if (m_start.container() && !refNode->attached()) {
         // Firefox doesn't throw an exception for this case; it returns false.
         return false;
     }
@@ -310,8 +303,8 @@ bool Range::isPointInRange(Node* refNode, int offset, ExceptionCode& ec)
     if (ec)
         return false;
 
-    return compareBoundaryPoints(refNode, offset, m_start.container.get(), m_start.offset) >= 0
-        && compareBoundaryPoints(refNode, offset, m_end.container.get(), m_end.offset) <= 0;
+    return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) >= 0
+        && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) <= 0;
 }
 
 short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec)
@@ -325,12 +318,12 @@ short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec)
         return 0;
     }
 
-    if (!m_start.container && refNode->attached()) {
+    if (!m_start.container() && refNode->attached()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    if (m_start.container && !refNode->attached()) {
+    if (m_start.container() && !refNode->attached()) {
         // Firefox doesn't throw an exception for this case; it returns -1.
         return -1;
     }
@@ -346,11 +339,11 @@ short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec)
         return 0;
 
     // compare to start, and point comes before
-    if (compareBoundaryPoints(refNode, offset, m_start.container.get(), m_start.offset) < 0)
+    if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) < 0)
         return -1;
 
     // compare to end, and point comes after
-    if (compareBoundaryPoints(refNode, offset, m_end.container.get(), m_end.offset) > 0)
+    if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) > 0)
         return 1;
 
     // point is in the middle of this range, or on the boundary points
@@ -368,12 +361,12 @@ Range::CompareResults Range::compareNode(Node* refNode, ExceptionCode& ec)
         return NODE_BEFORE;
     }
     
-    if (!m_start.container && refNode->attached()) {
+    if (!m_start.container() && refNode->attached()) {
         ec = INVALID_STATE_ERR;
         return NODE_BEFORE;
     }
 
-    if (m_start.container && !refNode->attached()) {
+    if (m_start.container() && !refNode->attached()) {
         // Firefox doesn't throw an exception for this case; it returns 0.
         return NODE_BEFORE;
     }
@@ -407,7 +400,7 @@ Range::CompareResults Range::compareNode(Node* refNode, ExceptionCode& ec)
 
 short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
@@ -443,17 +436,17 @@ short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, Exc
 
     switch (how) {
         case START_TO_START:
-            return compareBoundaryPoints(m_start.container.get(), m_start.offset,
-                sourceRange->m_start.container.get(), sourceRange->m_start.offset);
+            return compareBoundaryPoints(m_start.container(), m_start.offset(),
+                sourceRange->m_start.container(), sourceRange->m_start.offset());
         case START_TO_END:
-            return compareBoundaryPoints(m_start.container.get(), m_start.offset,
-                sourceRange->m_end.container.get(), sourceRange->m_end.offset);
+            return compareBoundaryPoints(m_start.container(), m_start.offset(),
+                sourceRange->m_end.container(), sourceRange->m_end.offset());
         case END_TO_END:
-            return compareBoundaryPoints(m_end.container.get(), m_end.offset,
-                sourceRange->m_end.container.get(), sourceRange->m_end.offset);
+            return compareBoundaryPoints(m_end.container(), m_end.offset(),
+                sourceRange->m_end.container(), sourceRange->m_end.offset());
         case END_TO_START:
-            return compareBoundaryPoints(m_end.container.get(), m_end.offset,
-                sourceRange->m_start.container.get(), sourceRange->m_start.offset);
+            return compareBoundaryPoints(m_end.container(), m_end.offset(),
+                sourceRange->m_start.container(), sourceRange->m_start.offset());
     }
 
     ec = SYNTAX_ERR;
@@ -550,12 +543,12 @@ short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containe
 
 short Range::compareBoundaryPoints(const Position& a, const Position& b)
 {
-    return compareBoundaryPoints(a.container.get(), a.offset, b.container.get(), b.offset);
+    return compareBoundaryPoints(a.container.get(), a.posOffset, b.container.get(), b.posOffset);
 }
 
 bool Range::boundaryPointsValid() const
 {
-    return m_start.container && compareBoundaryPoints(m_start.container.get(), m_start.offset, m_end.container.get(), m_end.offset) <= 0;
+    return m_start.container() && compareBoundaryPoints(m_start.container(), m_start.offset(), m_end.container(), m_end.offset()) <= 0;
 }
 
 void Range::deleteContents(ExceptionCode& ec)
@@ -577,8 +570,8 @@ bool Range::intersectsNode(Node* refNode, ExceptionCode& ec)
         return false;
     }
     
-    if (!m_start.container && refNode->attached()
-            || m_start.container && !refNode->attached()
+    if (!m_start.container() && refNode->attached()
+            || m_start.container() && !refNode->attached()
             || refNode->document() != m_ownerDocument) {
         // Firefox doesn't throw an exception for these cases; it returns false.
         return false;
@@ -627,51 +620,51 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
 
     // what is the highest node that partially selects the start of the range?
     Node* partialStart = 0;
-    if (m_start.container != commonRoot) {
-        partialStart = m_start.container.get();
+    if (m_start.container() != commonRoot) {
+        partialStart = m_start.container();
         while (partialStart->parentNode() != commonRoot)
             partialStart = partialStart->parentNode();
     }
 
     // what is the highest node that partially selects the end of the range?
     Node* partialEnd = 0;
-    if (m_end.container != commonRoot) {
-        partialEnd = m_end.container.get();
+    if (m_end.container() != commonRoot) {
+        partialEnd = m_end.container();
         while (partialEnd->parentNode() != commonRoot)
             partialEnd = partialEnd->parentNode();
     }
 
     // Simple case: the start and end containers are the same. We just grab
     // everything >= start offset and < end offset
-    if (m_start.container == m_end.container) {
-        Node::NodeType startNodeType = m_start.container->nodeType();
+    if (m_start.container() == m_end.container()) {
+        Node::NodeType startNodeType = m_start.container()->nodeType();
         if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
-                RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container->cloneNode(true));
-                c->deleteData(m_end.offset, c->length() - m_end.offset, ec);
-                c->deleteData(0, m_start.offset, ec);
+                RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true));
+                c->deleteData(m_end.offset(), c->length() - m_end.offset(), ec);
+                c->deleteData(0, m_start.offset(), ec);
                 fragment->appendChild(c.release(), ec);
             }
             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
-                static_cast<CharacterData*>(m_start.container.get())->deleteData(m_start.offset, m_end.offset - m_start.offset, ec);
+                static_cast<CharacterData*>(m_start.container())->deleteData(m_start.offset(), m_end.offset() - m_start.offset(), ec);
         } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
-                RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container->cloneNode(true));
-                c->setData(c->data().substring(m_start.offset, m_end.offset - m_start.offset), ec);
+                RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true));
+                c->setData(c->data().substring(m_start.offset(), m_end.offset() - m_start.offset()), ec);
                 fragment->appendChild(c.release(), ec);
             }
             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
-                ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container.get());
+                ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container());
                 String data(pi->data());
-                data.remove(m_start.offset, m_end.offset - m_start.offset);
+                data.remove(m_start.offset(), m_end.offset() - m_start.offset());
                 pi->setData(data, ec);
             }
         } else {
-            Node* n = m_start.container->firstChild();
+            Node* n = m_start.container()->firstChild();
             int i;
-            for (i = 0; n && i < m_start.offset; i++) // skip until start offset
+            for (i = 0; n && i < m_start.offset(); i++) // skip until start offset
                 n = n->nextSibling();
-            int endOffset = m_end.offset;
+            int endOffset = m_end.offset();
             while (n && i < endOffset) { // delete until end offset
                 Node* next = n->nextSibling();
                 if (action == EXTRACT_CONTENTS)
@@ -679,7 +672,7 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
                 else if (action == CLONE_CONTENTS)
                     fragment->appendChild(n->cloneNode(true), ec);
                 else
-                    m_start.container->removeChild(n, ec);
+                    m_start.container()->removeChild(n, ec);
                 n = next;
                 i++;
             }
@@ -705,35 +698,35 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
     // These are deleted, cloned, or extracted (i.e. both) depending on action.
 
     RefPtr<Node> leftContents;
-    if (m_start.container != commonRoot) {
+    if (m_start.container() != commonRoot) {
         // process the left-hand side of the range, up until the last ancestor of
         // start container before commonRoot
-        Node::NodeType startNodeType = m_start.container->nodeType();
+        Node::NodeType startNodeType = m_start.container()->nodeType();
         if (startNodeType == Node::TEXT_NODE || startNodeType == Node::CDATA_SECTION_NODE || startNodeType == Node::COMMENT_NODE) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
-                RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container->cloneNode(true));
-                c->deleteData(0, m_start.offset, ec);
+                RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_start.container()->cloneNode(true));
+                c->deleteData(0, m_start.offset(), ec);
                 leftContents = c.release();
             }
             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
-                static_cast<CharacterData*>(m_start.container.get())->deleteData(
-                    m_start.offset, static_cast<CharacterData*>(m_start.container.get())->length() - m_start.offset, ec);
+                static_cast<CharacterData*>(m_start.container())->deleteData(
+                    m_start.offset(), static_cast<CharacterData*>(m_start.container())->length() - m_start.offset(), ec);
         } else if (startNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
-                RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container->cloneNode(true));
-                c->setData(c->data().substring(m_start.offset), ec);
+                RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_start.container()->cloneNode(true));
+                c->setData(c->data().substring(m_start.offset()), ec);
                 leftContents = c.release();
             }
             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
-                ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container.get());
+                ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_start.container());
                 String data(pi->data());
-                pi->setData(data.left(m_start.offset), ec);
+                pi->setData(data.left(m_start.offset()), ec);
             }
         } else {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
-                leftContents = m_start.container->cloneNode(false);
-            Node* n = m_start.container->firstChild();
-            for (int i = 0; n && i < m_start.offset; i++) // skip until start offset
+                leftContents = m_start.container()->cloneNode(false);
+            Node* n = m_start.container()->firstChild();
+            for (int i = 0; n && i < m_start.offset(); i++) // skip until start offset
                 n = n->nextSibling();
             while (n) { // process until end
                 Node* next = n->nextSibling();
@@ -742,13 +735,13 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
                 else if (action == CLONE_CONTENTS)
                     leftContents->appendChild(n->cloneNode(true), ec);
                 else
-                    m_start.container->removeChild(n, ec);
+                    m_start.container()->removeChild(n, ec);
                 n = next;
             }
         }
 
-        Node* leftParent = m_start.container->parentNode();
-        Node* n = m_start.container->nextSibling();
+        Node* leftParent = m_start.container()->parentNode();
+        Node* n = m_start.container()->nextSibling();
         for (; leftParent != commonRoot; leftParent = leftParent->parentNode()) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
                 RefPtr<Node> leftContentsParent = leftParent->cloneNode(false);
@@ -771,34 +764,34 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
     }
 
     RefPtr<Node> rightContents;
-    if (m_end.container != commonRoot) {
+    if (m_end.container() != commonRoot) {
         // delete the right-hand side of the range, up until the last ancestor of
         // end container before commonRoot
-        Node::NodeType endNodeType = m_end.container->nodeType();
+        Node::NodeType endNodeType = m_end.container()->nodeType();
         if (endNodeType == Node::TEXT_NODE || endNodeType == Node::CDATA_SECTION_NODE || endNodeType == Node::COMMENT_NODE) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
-                RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_end.container->cloneNode(true));
-                c->deleteData(m_end.offset, static_cast<CharacterData*>(m_end.container.get())->length() - m_end.offset, ec);
+                RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_end.container()->cloneNode(true));
+                c->deleteData(m_end.offset(), static_cast<CharacterData*>(m_end.container())->length() - m_end.offset(), ec);
                 rightContents = c;
             }
             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
-                static_cast<CharacterData*>(m_end.container.get())->deleteData(0, m_end.offset, ec);
+                static_cast<CharacterData*>(m_end.container())->deleteData(0, m_end.offset(), ec);
         } else if (endNodeType == Node::PROCESSING_INSTRUCTION_NODE) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
-                RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_end.container->cloneNode(true));
-                c->setData(c->data().left(m_end.offset), ec);
+                RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_end.container()->cloneNode(true));
+                c->setData(c->data().left(m_end.offset()), ec);
                 rightContents = c.release();
             }
             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
-                ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_end.container.get());
-                pi->setData(pi->data().substring(m_end.offset), ec);
+                ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(m_end.container());
+                pi->setData(pi->data().substring(m_end.offset()), ec);
             }
         } else {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
-                rightContents = m_end.container->cloneNode(false);
-            Node* n = m_end.container->firstChild();
-            if (n && m_end.offset) {
-                for (int i = 0; i + 1 < m_end.offset; i++) { // skip to end.offset
+                rightContents = m_end.container()->cloneNode(false);
+            Node* n = m_end.container()->firstChild();
+            if (n && m_end.offset()) {
+                for (int i = 0; i + 1 < m_end.offset(); i++) { // skip to end.offset()
                     Node* next = n->nextSibling();
                     if (!next)
                         break;
@@ -812,13 +805,13 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
                     else if (action == CLONE_CONTENTS)
                         rightContents->insertBefore(n->cloneNode(true), rightContents->firstChild(), ec);
                     else
-                        m_end.container->removeChild(n, ec);
+                        m_end.container()->removeChild(n, ec);
                 }
             }
         }
 
-        Node* rightParent = m_end.container->parentNode();
-        Node* n = m_end.container->previousSibling();
+        Node* rightParent = m_end.container()->parentNode();
+        Node* n = m_end.container()->previousSibling();
         for (; rightParent != commonRoot; rightParent = rightParent->parentNode()) {
             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
                 RefPtr<Node> rightContentsParent = rightParent->cloneNode(false);
@@ -842,23 +835,23 @@ PassRefPtr<DocumentFragment> Range::processContents(ActionType action, Exception
     // delete all children of commonRoot between the start and end container
 
     Node* processStart; // child of commonRoot
-    if (m_start.container == commonRoot) {
-        processStart = m_start.container->firstChild();
-        for (int i = 0; i < m_start.offset; i++)
+    if (m_start.container() == commonRoot) {
+        processStart = m_start.container()->firstChild();
+        for (int i = 0; i < m_start.offset(); i++)
             processStart = processStart->nextSibling();
     } else {
-        processStart = m_start.container.get();
+        processStart = m_start.container();
         while (processStart->parentNode() != commonRoot)
             processStart = processStart->parentNode();
         processStart = processStart->nextSibling();
     }
     Node* processEnd; // child of commonRoot
-    if (m_end.container == commonRoot) {
-        processEnd = m_end.container->firstChild();
-        for (int i = 0; i < m_end.offset; i++)
+    if (m_end.container() == commonRoot) {
+        processEnd = m_end.container()->firstChild();
+        for (int i = 0; i < m_end.offset(); i++)
             processEnd = processEnd->nextSibling();
     } else {
-        processEnd = m_end.container.get();
+        processEnd = m_end.container();
         while (processEnd->parentNode() != commonRoot)
             processEnd = processEnd->parentNode();
     }
@@ -900,7 +893,7 @@ PassRefPtr<DocumentFragment> Range::extractContents(ExceptionCode& ec)
 
 PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
@@ -908,11 +901,13 @@ PassRefPtr<DocumentFragment> Range::cloneContents(ExceptionCode& ec)
     return processContents(CLONE_CONTENTS, ec);
 }
 
-void Range::insertNode(PassRefPtr<Node> newNode, ExceptionCode& ec)
+void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionCode& ec)
 {
+    RefPtr<Node> newNode = prpNewNode;
+
     ec = 0;
 
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -931,7 +926,7 @@ void Range::insertNode(PassRefPtr<Node> newNode, ExceptionCode& ec)
 
     // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
     // not created from the same document.
-    if (newNode->document() != m_start.container->document()) {
+    if (newNode->document() != m_start.container()->document()) {
         ec = WRONG_DOCUMENT_ERR;
         return;
     }
@@ -940,7 +935,8 @@ void Range::insertNode(PassRefPtr<Node> newNode, ExceptionCode& ec)
     // does not allow children of the type of newNode or if newNode is an ancestor of the container.
 
     // an extra one here - if a text node is going to split, it must have a parent to insert into
-    if (m_start.container->nodeType() == Node::TEXT_NODE && !m_start.container->parentNode()) {
+    bool startIsText = m_start.container()->isTextNode();
+    if (startIsText && !m_start.container()->parentNode()) {
         ec = HIERARCHY_REQUEST_ERR;
         return;
     }
@@ -948,27 +944,32 @@ void Range::insertNode(PassRefPtr<Node> newNode, ExceptionCode& ec)
     // In the case where the container is a text node, we check against the container's parent, because
     // text nodes get split up upon insertion.
     Node* checkAgainst;
-    if (m_start.container->nodeType() == Node::TEXT_NODE)
-        checkAgainst = m_start.container->parentNode();
+    if (startIsText)
+        checkAgainst = m_start.container()->parentNode();
     else
-        checkAgainst = m_start.container.get();
+        checkAgainst = m_start.container();
 
-    if (newNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
+    Node::NodeType newNodeType = newNode->nodeType();
+    int numNewChildren;
+    if (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) {
         // check each child node, not the DocumentFragment itself
+        numNewChildren = 0;
         for (Node* c = newNode->firstChild(); c; c = c->nextSibling()) {
             if (!checkAgainst->childTypeAllowed(c->nodeType())) {
                 ec = HIERARCHY_REQUEST_ERR;
                 return;
             }
+            ++numNewChildren;
         }
     } else {
-        if (!checkAgainst->childTypeAllowed(newNode->nodeType())) {
+        numNewChildren = 1;
+        if (!checkAgainst->childTypeAllowed(newNodeType)) {
             ec = HIERARCHY_REQUEST_ERR;
             return;
         }
     }
 
-    for (Node* n = m_start.container.get(); n; n = n->parentNode()) {
+    for (Node* n = m_start.container(); n; n = n->parentNode()) {
         if (n == newNode) {
             ec = HIERARCHY_REQUEST_ERR;
             return;
@@ -976,42 +977,45 @@ void Range::insertNode(PassRefPtr<Node> newNode, ExceptionCode& ec)
     }
 
     // INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, or Document node.
-    if (newNode->nodeType() == Node::ATTRIBUTE_NODE ||
-        newNode->nodeType() == Node::ENTITY_NODE ||
-        newNode->nodeType() == Node::NOTATION_NODE ||
-        newNode->nodeType() == Node::DOCUMENT_NODE) {
+    if (newNodeType == Node::ATTRIBUTE_NODE || newNodeType == Node::ENTITY_NODE
+            || newNodeType == Node::NOTATION_NODE || newNodeType == Node::DOCUMENT_NODE) {
         ec = RangeException::INVALID_NODE_TYPE_ERR;
         return;
     }
 
-    int endOffsetDelta = 0;
-    if (m_start.container->nodeType() == Node::TEXT_NODE ||
-        m_start.container->nodeType() == Node::CDATA_SECTION_NODE) {
-        RefPtr<Text> newText = static_cast<Text*>(m_start.container.get())->splitText(m_start.offset, ec);
+    bool collapsed = m_start == m_end;
+    if (startIsText) {
+        RefPtr<Text> newText = static_cast<Text*>(m_start.container())->splitText(m_start.offset(), ec);
         if (ec)
             return;
-        if (m_start.container == m_end.container)
-            endOffsetDelta = -m_start.offset;
-        m_start.container->parentNode()->insertBefore(newNode, newText.get(), ec);
+        m_start.container()->parentNode()->insertBefore(newNode.release(), newText.get(), ec);
         if (ec)
             return;
-        m_end.container = newText;
+
+        // This special case doesn't seem to match the DOM specification, but it's currently required
+        // to pass Acid3. We might later decide to remove this.
+        if (collapsed)
+            m_end.setToChild(newText.get());
     } else {
-        if (m_start.container == m_end.container) {
-            bool isFragment = newNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
-            endOffsetDelta = isFragment ? newNode->childNodeCount() : 1;
-        }
+        RefPtr<Node> lastChild;
+        if (collapsed)
+            lastChild = (newNodeType == Node::DOCUMENT_FRAGMENT_NODE) ? newNode->lastChild() : newNode;
 
-        m_start.container->insertBefore(newNode, m_start.container->childNode(m_start.offset), ec);
+        int startOffset = m_start.offset();
+        m_start.container()->insertBefore(newNode.release(), m_start.container()->childNode(startOffset), ec);
         if (ec)
             return;
+
+        // This special case doesn't seem to match the DOM specification, but it's currently required
+        // to pass Acid3. We might later decide to remove this.
+        if (collapsed)
+            m_end.set(m_start.container(), startOffset + numNewChildren, lastChild.get());
     }
-    m_end.offset += endOffsetDelta;
 }
 
 String Range::toString(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return String();
     }
@@ -1023,8 +1027,8 @@ String Range::toString(ExceptionCode& ec) const
         if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE) {
             String data = static_cast<CharacterData*>(n)->data();
             int length = data.length();
-            int start = (n == m_start.container) ? min(max(0, m_start.offset), length) : 0;
-            int end = (n == m_end.container) ? min(max(start, m_end.offset), length) : length;
+            int start = (n == m_start.container()) ? min(max(0, m_start.offset()), length) : 0;
+            int end = (n == m_end.container()) ? min(max(start, m_end.offset()), length) : length;
             result.append(data.characters() + start, end - start);
         }
     }
@@ -1039,24 +1043,24 @@ String Range::toHTML() const
 
 String Range::text() const
 {
-    if (!m_start.container)
+    if (!m_start.container())
         return String();
 
     // We need to update layout, since plainText uses line boxes in the render tree.
     // FIXME: As with innerText, we'd like this to work even if there are no render objects.
-    m_start.container->document()->updateLayout();
+    m_start.container()->document()->updateLayout();
 
     return plainText(this);
 }
 
 PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& markup, ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    Node* element = m_start.container->isElementNode() ? m_start.container.get() : m_start.container->parentNode();
+    Node* element = m_start.container()->isElementNode() ? m_start.container() : m_start.container()->parentNode();
     if (!element || !element->isHTMLElement()) {
         ec = NOT_SUPPORTED_ERR;
         return 0;
@@ -1074,7 +1078,7 @@ PassRefPtr<DocumentFragment> Range::createContextualFragment(const String& marku
 
 void Range::detach(ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1085,35 +1089,40 @@ void Range::detach(ExceptionCode& ec)
     m_end.clear();
 }
 
-void Range::checkNodeWOffset(Node* n, int offset, ExceptionCode& ec) const
+Node* Range::checkNodeWOffset(Node* n, int offset, ExceptionCode& ec) const
 {
     switch (n->nodeType()) {
         case Node::DOCUMENT_TYPE_NODE:
         case Node::ENTITY_NODE:
         case Node::NOTATION_NODE:
             ec = RangeException::INVALID_NODE_TYPE_ERR;
-            return;
+            return 0;
         case Node::CDATA_SECTION_NODE:
         case Node::COMMENT_NODE:
         case Node::TEXT_NODE:
             if (static_cast<unsigned>(offset) > static_cast<CharacterData*>(n)->length())
                 ec = INDEX_SIZE_ERR;
-            return;
+            return 0;
         case Node::PROCESSING_INSTRUCTION_NODE:
             if (static_cast<unsigned>(offset) > static_cast<ProcessingInstruction*>(n)->data().length())
                 ec = INDEX_SIZE_ERR;
-            return;
+            return 0;
         case Node::ATTRIBUTE_NODE:
         case Node::DOCUMENT_FRAGMENT_NODE:
         case Node::DOCUMENT_NODE:
         case Node::ELEMENT_NODE:
         case Node::ENTITY_REFERENCE_NODE:
-        case Node::XPATH_NAMESPACE_NODE:
-            if (static_cast<unsigned>(offset) > n->childNodeCount())
+        case Node::XPATH_NAMESPACE_NODE: {
+            if (!offset)
+                return 0;
+            Node* childBefore = n->childNode(offset - 1);
+            if (!childBefore)
                 ec = INDEX_SIZE_ERR;
-            return;
+            return childBefore;
+        }
     }
     ASSERT_NOT_REACHED();
+    return 0;
 }
 
 void Range::checkNodeBA(Node* n, ExceptionCode& ec) const
@@ -1169,17 +1178,17 @@ void Range::checkNodeBA(Node* n, ExceptionCode& ec) const
 
 PassRefPtr<Range> Range::cloneRange(ExceptionCode& ec) const
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    return Range::create(m_ownerDocument, m_start.container, m_start.offset, m_end.container, m_end.offset);
+    return Range::create(m_ownerDocument, m_start.container(), m_start.offset(), m_end.container(), m_end.offset());
 }
 
 void Range::setStartAfter(Node* refNode, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1204,7 +1213,7 @@ void Range::setStartAfter(Node* refNode, ExceptionCode& ec)
 
 void Range::setEndBefore(Node* refNode, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1229,7 +1238,7 @@ void Range::setEndBefore(Node* refNode, ExceptionCode& ec)
 
 void Range::setEndAfter(Node* refNode, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1255,7 +1264,7 @@ void Range::setEndAfter(Node* refNode, ExceptionCode& ec)
 
 void Range::selectNode(Node* refNode, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1317,7 +1326,7 @@ void Range::selectNode(Node* refNode, ExceptionCode& ec)
 
 void Range::selectNodeContents(Node* refNode, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1350,17 +1359,15 @@ void Range::selectNodeContents(Node* refNode, ExceptionCode& ec)
         }
     }
 
-    m_start.container = refNode;
-    m_start.offset = 0;
-    m_end.container = refNode;
-    m_end.offset = maxEndOffset();
+    m_start.setToStart(refNode);
+    m_end.setToEnd(refNode);
 }
 
 void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
 {
     RefPtr<Node> newParent = passNewParent;
 
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1400,15 +1407,15 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
 
     // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
     // not created from the same document.
-    if (newParent->document() != m_start.container->document()) {
+    if (newParent->document() != m_start.container()->document()) {
         ec = WRONG_DOCUMENT_ERR;
         return;
     }
 
-    // Raise a HIERARCHY_REQUEST_ERR if m_start.container doesn't accept children like newParent.
-    Node* parentOfNewParent = m_start.container.get();
+    // Raise a HIERARCHY_REQUEST_ERR if m_start.container() doesn't accept children like newParent.
+    Node* parentOfNewParent = m_start.container();
 
-    // If m_start.container is a character data node, it will be split and it will be its parent that will 
+    // If m_start.container() is a character data node, it will be split and it will be its parent that will 
     // need to accept newParent (or in the case of a comment, it logically "would" be inserted into the parent,
     // although this will fail below for another reason).
     if (parentOfNewParent->isCharacterDataNode())
@@ -1418,7 +1425,7 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
         return;
     }
     
-    if (m_start.container == newParent || m_start.container->isDescendantOf(newParent.get())) {
+    if (m_start.container() == newParent || m_start.container()->isDescendantOf(newParent.get())) {
         ec = HIERARCHY_REQUEST_ERR;
         return;
     }
@@ -1427,14 +1434,14 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
     // allowed by the type of node?
 
     // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
-    if (m_start.container->nodeType() != Node::TEXT_NODE) {
-        if (m_start.offset > 0 && m_start.offset < maxStartOffset()) {
+    if (m_start.container()->nodeType() != Node::TEXT_NODE) {
+        if (m_start.offset() > 0 && m_start.offset() < maxStartOffset()) {
             ec = RangeException::BAD_BOUNDARYPOINTS_ERR;
             return;
         }
     }
-    if (m_end.container->nodeType() != Node::TEXT_NODE) {
-        if (m_end.offset > 0 && m_end.offset < maxEndOffset()) {
+    if (m_end.container()->nodeType() != Node::TEXT_NODE) {
+        if (m_end.offset() > 0 && m_end.offset() < maxEndOffset()) {
             ec = RangeException::BAD_BOUNDARYPOINTS_ERR;
             return;
         }
@@ -1460,7 +1467,7 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
 
 void Range::setStartBefore(Node* refNode, ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1485,7 +1492,7 @@ void Range::setStartBefore(Node* refNode, ExceptionCode& ec)
 
 void Range::checkDeleteExtract(ExceptionCode& ec)
 {
-    if (!m_start.container) {
+    if (!m_start.container()) {
         ec = INVALID_STATE_ERR;
         return;
     }
@@ -1500,7 +1507,7 @@ void Range::checkDeleteExtract(ExceptionCode& ec)
             ec = NO_MODIFICATION_ALLOWED_ERR;
             return;
         }
-        if (n->nodeType() == Node::DOCUMENT_TYPE_NODE) { // ### is this for only directly under the DF, or anywhere?
+        if (n->nodeType() == Node::DOCUMENT_TYPE_NODE) {
             ec = HIERARCHY_REQUEST_ERR;
             return;
         }
@@ -1514,11 +1521,11 @@ void Range::checkDeleteExtract(ExceptionCode& ec)
 
 bool Range::containedByReadOnly() const
 {
-    for (Node* n = m_start.container.get(); n; n = n->parentNode()) {
+    for (Node* n = m_start.container(); n; n = n->parentNode()) {
         if (n->isReadOnlyNode())
             return true;
     }
-    for (Node* n = m_end.container.get(); n; n = n->parentNode()) {
+    for (Node* n = m_end.container(); n; n = n->parentNode()) {
         if (n->isReadOnlyNode())
             return true;
     }
@@ -1527,15 +1534,15 @@ bool Range::containedByReadOnly() const
 
 Node* Range::firstNode() const
 {
-    if (!m_start.container)
+    if (!m_start.container())
         return 0;
-    if (m_start.container->offsetInCharacters())
-        return m_start.container.get();
-    if (Node* child = m_start.container->childNode(m_start.offset))
+    if (m_start.container()->offsetInCharacters())
+        return m_start.container();
+    if (Node* child = m_start.container()->childNode(m_start.offset()))
         return child;
-    if (!m_start.offset)
-        return m_start.container.get();
-    return m_start.container->traverseNextSibling();
+    if (!m_start.offset())
+        return m_start.container();
+    return m_start.container()->traverseNextSibling();
 }
 
 Position Range::editingStartPosition() const
@@ -1545,7 +1552,7 @@ Position Range::editingStartPosition() const
     // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up 
     // with a spurious "mixed" style.
     
-    VisiblePosition visiblePosition(m_start.container.get(), m_start.offset, VP_DEFAULT_AFFINITY);
+    VisiblePosition visiblePosition(m_start.container(), m_start.offset(), VP_DEFAULT_AFFINITY);
     if (visiblePosition.isNull())
         return Position();
 
@@ -1566,13 +1573,13 @@ Position Range::editingStartPosition() const
 
 Node* Range::pastLastNode() const
 {
-    if (!m_start.container || !m_end.container)
+    if (!m_start.container() || !m_end.container())
         return 0;
-    if (m_end.container->offsetInCharacters())
-        return m_end.container->traverseNextSibling();
-    if (Node* child = m_end.container->childNode(m_end.offset))
+    if (m_end.container()->offsetInCharacters())
+        return m_end.container()->traverseNextSibling();
+    if (Node* child = m_end.container()->childNode(m_end.offset()))
         return child;
-    return m_end.container->traverseNextSibling();
+    return m_end.container()->traverseNextSibling();
 }
 
 IntRect Range::boundingBox()
@@ -1588,11 +1595,11 @@ IntRect Range::boundingBox()
 
 void Range::addLineBoxRects(Vector<IntRect>& rects, bool useSelectionHeight)
 {
-    if (!m_start.container || !m_end.container)
+    if (!m_start.container() || !m_end.container())
         return;
 
-    RenderObject* start = m_start.container->renderer();
-    RenderObject* end = m_end.container->renderer();
+    RenderObject* start = m_start.container()->renderer();
+    RenderObject* end = m_end.container()->renderer();
     if (!start || !end)
         return;
 
@@ -1600,8 +1607,8 @@ void Range::addLineBoxRects(Vector<IntRect>& rects, bool useSelectionHeight)
     for (RenderObject* r = start; r && r != stop; r = r->nextInPreOrder()) {
         // only ask leaf render objects for their line box rects
         if (!r->firstChild()) {
-            int startOffset = r == start ? m_start.offset : 0;
-            int endOffset = r == end ? m_end.offset : UINT_MAX;
+            int startOffset = r == start ? m_start.offset() : 0;
+            int endOffset = r == end ? m_end.offset() : INT_MAX;
             r->addLineBoxRects(rects, startOffset, endOffset, useSelectionHeight);
         }
     }
@@ -1614,19 +1621,19 @@ void Range::formatForDebugger(char* buffer, unsigned length) const
     String result;
     String s;
     
-    if (!m_start.container || !m_end.container)
+    if (!m_start.container() || !m_end.container())
         result = "<empty>";
     else {
         char s[FormatBufferSize];
         result += "from offset ";
-        result += String::number(m_start.offset);
+        result += String::number(m_start.offset());
         result += " of ";
-        m_start.container->formatForDebugger(s, FormatBufferSize);
+        m_start.container()->formatForDebugger(s, FormatBufferSize);
         result += s;
         result += " to offset ";
-        result += String::number(m_end.offset);
+        result += String::number(m_end.offset());
         result += " of ";
-        m_end.container->formatForDebugger(s, FormatBufferSize);
+        m_end.container()->formatForDebugger(s, FormatBufferSize);
         result += s;
     }
           
@@ -1657,110 +1664,109 @@ PassRefPtr<Range> rangeOfContents(Node* node)
 
 int Range::maxStartOffset() const
 {
-    if (!m_start.container)
+    if (!m_start.container())
         return 0;
-    if (!m_start.container->offsetInCharacters())
-        return m_start.container->childNodeCount();
-    return m_start.container->maxCharacterOffset();
+    if (!m_start.container()->offsetInCharacters())
+        return m_start.container()->childNodeCount();
+    return m_start.container()->maxCharacterOffset();
 }
 
 int Range::maxEndOffset() const
 {
-    if (!m_end.container)
+    if (!m_end.container())
         return 0;
-    if (!m_end.container->offsetInCharacters())
-        return m_end.container->childNodeCount();
-    return m_end.container->maxCharacterOffset();
+    if (!m_end.container()->offsetInCharacters())
+        return m_end.container()->childNodeCount();
+    return m_end.container()->maxCharacterOffset();
 }
 
-static inline void endpointNodeChildrenChanged(Position& endpoint,
-    NodeWithIndexAfter& beforeChange, NodeWithIndexBefore& afterChange, int childCountDelta)
+static inline void boundaryNodeChildrenChanged(RangeBoundaryPoint& boundary, ContainerNode* container)
 {
-    if (endpoint.container != afterChange.parent())
+    if (!boundary.childBefore())
         return;
-    if (beforeChange.indexAfter() >= endpoint.offset)
+    if (boundary.container() != container)
         return;
-    if (childCountDelta < 0 && afterChange.indexBefore() >= endpoint.offset)
-        endpoint.offset = afterChange.indexBefore();
-    else
-        endpoint.offset += childCountDelta;
+    boundary.invalidateOffset();
 }
 
-void Range::nodeChildrenChanged(NodeWithIndexAfter& beforeChange, NodeWithIndexBefore& afterChange, int childCountDelta)
+void Range::nodeChildrenChanged(ContainerNode* container)
 {
-    ASSERT(afterChange.parent());
-    ASSERT(afterChange.parent()->document() == m_ownerDocument);
-    ASSERT(childCountDelta);
-    endpointNodeChildrenChanged(m_start, beforeChange, afterChange, childCountDelta);
-    endpointNodeChildrenChanged(m_end, beforeChange, afterChange, childCountDelta);
+    ASSERT(container);
+    ASSERT(container->document() == m_ownerDocument);
+    boundaryNodeChildrenChanged(m_start, container);
+    boundaryNodeChildrenChanged(m_end, container);
 }
 
-static inline void endpointNodeWillBeRemoved(Position& endpoint, NodeWithIndex& nodeToBeRemoved)
+static inline void boundaryNodeWillBeRemoved(RangeBoundaryPoint& boundary, Node* nodeToBeRemoved)
 {
-    for (Node* n = endpoint.container.get(); n; n = n->parentNode()) {
-        if (n == nodeToBeRemoved.node()) {
-            endpoint.container = nodeToBeRemoved.node()->parentNode();
-            endpoint.offset = nodeToBeRemoved.index();
+    if (boundary.childBefore() == nodeToBeRemoved) {
+        boundary.childBeforeWillBeRemoved();
+        return;
+    }
+
+    for (Node* n = boundary.container(); n; n = n->parentNode()) {
+        if (n == nodeToBeRemoved) {
+            boundary.setToChild(nodeToBeRemoved);
+            return;
         }
     }
 }
 
-void Range::nodeWillBeRemoved(NodeWithIndex& nodeToBeRemoved)
+void Range::nodeWillBeRemoved(Node* node)
 {
-    ASSERT(nodeToBeRemoved.node());
-    ASSERT(nodeToBeRemoved.node()->document() == m_ownerDocument);
-    ASSERT(nodeToBeRemoved.node() != m_ownerDocument);
-    ASSERT(nodeToBeRemoved.node()->parentNode());
-    endpointNodeWillBeRemoved(m_start, nodeToBeRemoved);
-    endpointNodeWillBeRemoved(m_end, nodeToBeRemoved);
+    ASSERT(node);
+    ASSERT(node->document() == m_ownerDocument);
+    ASSERT(node != m_ownerDocument);
+    ASSERT(node->parentNode());
+    boundaryNodeWillBeRemoved(m_start, node);
+    boundaryNodeWillBeRemoved(m_end, node);
 }
 
-static inline void endpointTextInserted(Position& endpoint, Node* text, unsigned offset, unsigned length)
+static inline void boundaryTextInserted(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
 {
-    if (endpoint.container != text)
+    if (boundary.container() != text)
         return;
-    if (offset >= static_cast<unsigned>(endpoint.offset))
+    unsigned boundaryOffset = boundary.offset();
+    if (offset >= boundaryOffset)
         return;
-    endpoint.offset += length;
+    boundary.setOffset(boundaryOffset + length);
 }
 
 void Range::textInserted(Node* text, unsigned offset, unsigned length)
 {
     ASSERT(text);
     ASSERT(text->document() == m_ownerDocument);
-    endpointTextInserted(m_start, text, offset, length);
-    endpointTextInserted(m_end, text, offset, length);
+    boundaryTextInserted(m_start, text, offset, length);
+    boundaryTextInserted(m_end, text, offset, length);
 }
 
-static inline void endpointTextRemoved(Position& endpoint, Node* text, unsigned offset, unsigned length)
+static inline void boundaryTextRemoved(RangeBoundaryPoint& boundary, Node* text, unsigned offset, unsigned length)
 {
-    if (endpoint.container != text)
+    if (boundary.container() != text)
         return;
-    if (offset >= static_cast<unsigned>(endpoint.offset))
+    unsigned boundaryOffset = boundary.offset();
+    if (offset >= boundaryOffset)
         return;
-    if (offset + length >= static_cast<unsigned>(endpoint.offset))
-        endpoint.offset = offset;
+    if (offset + length >= boundaryOffset)
+        boundary.setOffset(offset);
     else
-        endpoint.offset -= length;
+        boundary.setOffset(boundaryOffset - length);
 }
 
 void Range::textRemoved(Node* text, unsigned offset, unsigned length)
 {
     ASSERT(text);
     ASSERT(text->document() == m_ownerDocument);
-    endpointTextRemoved(m_start, text, offset, length);
-    endpointTextRemoved(m_end, text, offset, length);
+    boundaryTextRemoved(m_start, text, offset, length);
+    boundaryTextRemoved(m_end, text, offset, length);
 }
 
-static inline void endpointTextNodesMerged(Position& endpoint, NodeWithIndex& oldNode, unsigned offset)
+static inline void boundaryTextNodesMerged(RangeBoundaryPoint& boundary, NodeWithIndex& oldNode, unsigned offset)
 {
-    if (endpoint.container == oldNode.node()) {
-        endpoint.container = oldNode.node()->previousSibling();
-        endpoint.offset += offset;
-    } else if (endpoint.container == oldNode.node()->parentNode() && endpoint.offset == oldNode.index()) {
-        endpoint.container = oldNode.node()->previousSibling();
-        endpoint.offset = offset;
-    }
+    if (boundary.container() == oldNode.node())
+        boundary.set(oldNode.node()->previousSibling(), boundary.offset() + offset, 0);
+    else if (boundary.container() == oldNode.node()->parentNode() && boundary.offset() == oldNode.index())
+        boundary.set(oldNode.node()->previousSibling(), offset, 0);
 }
 
 void Range::textNodesMerged(NodeWithIndex& oldNode, unsigned offset)
@@ -1771,18 +1777,18 @@ void Range::textNodesMerged(NodeWithIndex& oldNode, unsigned offset)
     ASSERT(oldNode.node()->isTextNode());
     ASSERT(oldNode.node()->previousSibling());
     ASSERT(oldNode.node()->previousSibling()->isTextNode());
-    endpointTextNodesMerged(m_start, oldNode, offset);
-    endpointTextNodesMerged(m_end, oldNode, offset);
+    boundaryTextNodesMerged(m_start, oldNode, offset);
+    boundaryTextNodesMerged(m_end, oldNode, offset);
 }
 
-static inline void endpointTextNodesSplit(Position& endpoint, Text* oldNode)
+static inline void boundaryTextNodesSplit(RangeBoundaryPoint& boundary, Text* oldNode)
 {
-    if (endpoint.container != oldNode)
+    if (boundary.container() != oldNode)
         return;
-    if (endpoint.offset <= static_cast<int>(oldNode->length()))
+    unsigned boundaryOffset = boundary.offset();
+    if (boundaryOffset <= oldNode->length())
         return;
-    endpoint.container = oldNode->nextSibling();
-    endpoint.offset -= oldNode->length();
+    boundary.set(oldNode->nextSibling(), boundaryOffset - oldNode->length(), 0);
 }
 
 void Range::textNodeSplit(Text* oldNode)
@@ -1793,8 +1799,8 @@ void Range::textNodeSplit(Text* oldNode)
     ASSERT(oldNode->isTextNode());
     ASSERT(oldNode->nextSibling());
     ASSERT(oldNode->nextSibling()->isTextNode());
-    endpointTextNodesSplit(m_start, oldNode);
-    endpointTextNodesSplit(m_end, oldNode);
+    boundaryTextNodesSplit(m_start, oldNode);
+    boundaryTextNodesSplit(m_end, oldNode);
 }
 
 }
index f2342be..2c392d6 100644 (file)
 #ifndef Range_h
 #define Range_h
 
-#include "Position.h"
+#include "RangeBoundaryPoint.h"
 #include <wtf/RefCounted.h>
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
-typedef int ExceptionCode;
-
 class DocumentFragment;
-class Document;
 class NodeWithIndex;
-class NodeWithIndexAfter;
-class NodeWithIndexBefore;
-class IntRect;
-class String;
 class Text;
 
 class Range : public RefCounted<Range> {
@@ -50,10 +43,10 @@ public:
     ~Range();
 
     Document* ownerDocument() const { return m_ownerDocument.get(); }
-    Node* startContainer() const { return m_start.container.get(); }
-    int startOffset() const { return m_start.posOffset; }
-    Node* endContainer() const { return m_end.container.get(); }
-    int endOffset() const { return m_end.posOffset; }
+    Node* startContainer() const { return m_start.container(); }
+    int startOffset() const { return m_start.offset(); }
+    Node* endContainer() const { return m_end.container(); }
+    int endOffset() const { return m_end.offset(); }
 
     Node* startContainer(ExceptionCode&) const;
     int startOffset(ExceptionCode&) const;
@@ -98,8 +91,8 @@ public:
     void surroundContents(PassRefPtr<Node>, ExceptionCode&);
     void setStartBefore(Node*, ExceptionCode&);
 
-    const Position& startPosition() const { return m_start; }
-    const Position& endPosition() const { return m_end; }
+    const Position& startPosition() const { return m_start.position(); }
+    const Position& endPosition() const { return m_end.position(); }
 
     Node* firstNode() const;
     Node* pastLastNode() const;
@@ -109,8 +102,8 @@ public:
     IntRect boundingBox();
     void addLineBoxRects(Vector<IntRect>&, bool useSelectionHeight = false);
 
-    void nodeChildrenChanged(NodeWithIndexAfter& beforeChange, NodeWithIndexBefore& afterChange, int childCountDelta);
-    void nodeWillBeRemoved(NodeWithIndex&);
+    void nodeChildrenChanged(ContainerNode*);
+    void nodeWillBeRemoved(Node*);
 
     void textInserted(Node*, unsigned offset, unsigned length);
     void textRemoved(Node*, unsigned offset, unsigned length);
@@ -125,7 +118,7 @@ private:
     Range(PassRefPtr<Document>);
     Range(PassRefPtr<Document>, PassRefPtr<Node> startContainer, int startOffset, PassRefPtr<Node> endContainer, int endOffset);
 
-    void checkNodeWOffset(Node*, int offset, ExceptionCode&) const;
+    Node* checkNodeWOffset(Node*, int offset, ExceptionCode&) const;
     void checkNodeBA(Node*, ExceptionCode&) const;
     void checkDeleteExtract(ExceptionCode&);
     bool containedByReadOnly() const;
@@ -136,8 +129,8 @@ private:
     PassRefPtr<DocumentFragment> processContents(ActionType, ExceptionCode&);
 
     RefPtr<Document> m_ownerDocument;
-    Position m_start;
-    Position m_end;
+    RangeBoundaryPoint m_start;
+    RangeBoundaryPoint m_end;
 };
 
 PassRefPtr<Range> rangeOfContents(Node*);
diff --git a/WebCore/dom/RangeBoundaryPoint.h b/WebCore/dom/RangeBoundaryPoint.h
new file mode 100644 (file)
index 0000000..4cb7bf5
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef RangeBoundaryPoint_h
+#define RangeBoundaryPoint_h
+
+#include "Node.h"
+#include "Position.h"
+
+namespace WebCore {
+
+class RangeBoundaryPoint {
+public:
+    RangeBoundaryPoint();
+    explicit RangeBoundaryPoint(PassRefPtr<Node> container);
+
+    const Position& position() const;
+    Node* container() const;
+    int offset() const;
+    Node* childBefore() const;
+
+    void clear();
+
+    void set(PassRefPtr<Node> container, int offset, Node* childBefore);
+    void setOffset(int offset);
+    void setToChild(Node* child);
+    void setToStart(PassRefPtr<Node> container);
+    void setToEnd(PassRefPtr<Node> container);
+
+    void childBeforeWillBeRemoved();
+    void invalidateOffset() const;
+
+private:
+    static const int invalidOffset = -1;
+
+    mutable Position m_position;
+    Node* m_childBefore;
+};
+
+inline RangeBoundaryPoint::RangeBoundaryPoint()
+    : m_childBefore(0)
+{
+}
+
+inline RangeBoundaryPoint::RangeBoundaryPoint(PassRefPtr<Node> container)
+    : m_position(container, 0)
+    , m_childBefore(0)
+{
+}
+
+inline Node* RangeBoundaryPoint::container() const
+{
+    return m_position.container.get();
+}
+
+inline Node* RangeBoundaryPoint::childBefore() const
+{
+    return m_childBefore;
+}
+
+inline const Position& RangeBoundaryPoint::position() const
+{
+    if (m_position.posOffset >= 0)
+        return m_position;
+    ASSERT(m_childBefore);
+    m_position.posOffset = m_childBefore->nodeIndex() + 1;
+    return m_position;
+}
+
+inline int RangeBoundaryPoint::offset() const
+{
+    return position().posOffset;
+}
+
+inline void RangeBoundaryPoint::clear()
+{
+    m_position.clear();
+    m_childBefore = 0;
+}
+
+inline void RangeBoundaryPoint::set(PassRefPtr<Node> container, int offset, Node* childBefore)
+{
+    ASSERT(offset >= 0);
+    ASSERT(childBefore == (offset ? container->childNode(offset - 1) : 0));
+    m_position.container = container;
+    m_position.posOffset = offset;
+    m_childBefore = childBefore;
+}
+
+inline void RangeBoundaryPoint::setOffset(int offset)
+{
+    ASSERT(m_position.container);
+    ASSERT(m_position.container->offsetInCharacters());
+    ASSERT(m_position.posOffset >= 0);
+    ASSERT(!m_childBefore);
+    m_position.posOffset = offset;
+}
+
+inline void RangeBoundaryPoint::setToChild(Node* child)
+{
+    ASSERT(child);
+    ASSERT(child->parentNode());
+    m_position.container = child->parentNode();
+    m_childBefore = child->previousSibling();
+    m_position.posOffset = m_childBefore ? invalidOffset : 0;
+}
+
+inline void RangeBoundaryPoint::setToStart(PassRefPtr<Node> container)
+{
+    ASSERT(container);
+    m_position.container = container;
+    m_position.posOffset = 0;
+    m_childBefore = 0;
+}
+
+inline void RangeBoundaryPoint::setToEnd(PassRefPtr<Node> container)
+{
+    ASSERT(container);
+    m_position.container = container;
+    if (m_position.container->offsetInCharacters()) {
+        m_position.posOffset = m_position.container->maxCharacterOffset();
+        m_childBefore = 0;
+    } else {
+        m_childBefore = m_position.container->lastChild();
+        m_position.posOffset = m_childBefore ? invalidOffset : 0;
+    }
+}
+
+inline void RangeBoundaryPoint::childBeforeWillBeRemoved()
+{
+    ASSERT(m_position.posOffset);
+    m_childBefore = m_childBefore->previousSibling();
+    if (!m_childBefore)
+        m_position.posOffset = 0;
+    else if (m_position.posOffset > 0)
+        --m_position.posOffset;
+}
+
+inline void RangeBoundaryPoint::invalidateOffset() const
+{
+    m_position.posOffset = invalidOffset;
+}
+
+inline bool operator==(const RangeBoundaryPoint& a, const RangeBoundaryPoint& b)
+{
+    if (a.container() != b.container())
+        return false;
+    if (a.childBefore() || b.childBefore()) {
+        if (a.childBefore() != b.childBefore())
+            return false;
+    } else {
+        if (a.offset() != b.offset())
+            return false;
+    }
+    return true;
+}
+
+}
+
+#endif