RangeImpl.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:48k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: RangeImpl.cpp,v 1.12 2001/10/18 18:01:29 tng Exp $
  58.  */
  59. #include <util/RefVectorOf.hpp>
  60. #include "NodeImpl.hpp"
  61. #include "RangeImpl.hpp"
  62. #include "TextImpl.hpp"
  63. #include "DocumentImpl.hpp"
  64. #include "DOM_DOMException.hpp"
  65. #include "DOM_Document.hpp"
  66. #include "DocumentFragmentImpl.hpp"
  67. #include "DOM_Document.hpp"
  68. #include "DOM_RangeException.hpp"
  69. #include "DOM_DOMException.hpp"
  70. #include "DOM_Text.hpp"
  71. //---------------------
  72. // C'tor and D'tor
  73. //---------------------
  74. RangeImpl::RangeImpl(DOM_Document doc)
  75.     :   fDocument(doc),
  76.         fStartContainer(doc),
  77.         fStartOffset(0),
  78.         fEndContainer(doc),
  79.         fEndOffset(0),
  80.         fDetached(false),
  81.         fCollapsed(true),
  82.         fRemoveChild(0)
  83. {
  84. }
  85. RangeImpl::RangeImpl(const RangeImpl& other)
  86. {
  87.     fDocument = other.fDocument;
  88.     fStartContainer = other.fStartContainer;
  89.     fStartOffset = other.fStartOffset;
  90.     fEndContainer = other.fEndContainer;
  91.     fEndOffset = other.fEndOffset;
  92.     fDetached = other.fDetached;
  93.     fCollapsed = other.fCollapsed;
  94.     fRemoveChild = other.fRemoveChild;
  95. }
  96. RangeImpl::~RangeImpl()
  97. {
  98. }
  99. void RangeImpl::unreferenced()
  100. {
  101.     if (((DocumentImpl*)fDocument.fImpl)->ranges != 0L) {
  102.         int sz = ((DocumentImpl*)fDocument.fImpl)->ranges->size();
  103.         for (int i=0; i< sz; i++) {
  104.             if (((DocumentImpl*)fDocument.fImpl)->ranges->elementAt(i) == this) {
  105.                 ((DocumentImpl*)fDocument.fImpl)->ranges->removeElementAt(i);
  106.                 break;
  107.             }
  108.         }
  109.     }
  110. //    delete this;
  111.     RangeImpl* ptr = this;
  112.     delete ptr;
  113. };
  114. //-------------------------------
  115. // Public getter functions
  116. //-------------------------------
  117. DOM_Node RangeImpl::getStartContainer() const
  118. {
  119.     return fStartContainer;
  120. }
  121. unsigned int RangeImpl::getStartOffset() const
  122. {
  123.     return fStartOffset;
  124. }
  125. DOM_Node RangeImpl::getEndContainer() const
  126. {
  127.     return fEndContainer;
  128. }
  129. unsigned int RangeImpl::getEndOffset() const
  130. {
  131.     return fEndOffset;
  132. }
  133. bool RangeImpl::getCollapsed() const
  134. {
  135.     if (fDetached)
  136.     {
  137.         throw DOM_DOMException(
  138.             DOM_DOMException::INVALID_STATE_ERR, null);
  139.     }
  140.     return ((fStartContainer == fEndContainer)
  141.              && (fStartOffset == fEndOffset));
  142. }
  143. //-------------------------------
  144. // Public getter functions
  145. //-------------------------------
  146. void RangeImpl::setStartContainer(const DOM_Node& node)
  147. {
  148.     if (fDetached)
  149.     {
  150.         throw DOM_DOMException(
  151.             DOM_DOMException::INVALID_STATE_ERR, null);
  152.     }
  153.     fStartContainer = node;
  154. }
  155. void RangeImpl::setStartOffset(unsigned int offset)
  156. {
  157.     if (fDetached)
  158.     {
  159.         throw DOM_DOMException(
  160.             DOM_DOMException::INVALID_STATE_ERR, null);
  161.     }
  162.     fStartOffset = offset;
  163. }
  164. void RangeImpl::setEndContainer(const DOM_Node& node)
  165. {
  166.     if (fDetached)
  167.     {
  168.         throw DOM_DOMException(
  169.             DOM_DOMException::INVALID_STATE_ERR, null);
  170.     }
  171.     fEndContainer = node;
  172. }
  173. void RangeImpl::setEndOffset(unsigned int offset)
  174. {
  175.     if (fDetached)
  176.     {
  177.         throw DOM_DOMException(
  178.             DOM_DOMException::INVALID_STATE_ERR, null);
  179.     }
  180.     fEndOffset = offset;
  181. }
  182. void RangeImpl::setStart(const DOM_Node& refNode, unsigned int offset)
  183. {
  184.     validateNode(refNode);
  185.     checkIndex(refNode, offset);
  186.     fStartContainer = refNode;
  187.     fStartOffset    = offset;
  188.     if ((fDocument != refNode.getOwnerDocument() )
  189.         && (refNode.getOwnerDocument().fImpl != 0) )
  190.     {
  191.         fDocument = refNode.getOwnerDocument();
  192.         collapse(true);
  193.     }
  194.     //compare the start and end boundary point
  195.     //collapse if start point is after the end point
  196.     if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1)
  197.         collapse(true); //collapse the range positions to start
  198.     else
  199.         fCollapsed = false;
  200. }
  201. void RangeImpl::setEnd(const DOM_Node& refNode, unsigned int offset)
  202. {
  203.     validateNode(refNode);
  204.     checkIndex(refNode, offset);
  205.     fEndContainer   = refNode;
  206.     fEndOffset      = offset;
  207.     if ((fDocument != refNode.getOwnerDocument() )
  208.         && (refNode.getOwnerDocument().fImpl != 0) )
  209.     {
  210.         fDocument = refNode.getOwnerDocument();
  211.         collapse(false);
  212.     }
  213.     //compare the start and end boundary point
  214.     //collapse if start point is after the end point
  215.     if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1)
  216.         collapse(false); //collapse the range positions to end
  217.     else
  218.         fCollapsed = false;
  219. }
  220. void RangeImpl::setStartBefore(const DOM_Node& refNode)
  221. {
  222.     if( fDetached) {
  223.         throw DOM_DOMException(
  224.             DOM_DOMException::INVALID_STATE_ERR, null);
  225.     }
  226.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  227.         throw DOM_RangeException(
  228.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  229.     }
  230.     fStartContainer = refNode.getParentNode();
  231.    unsigned int i = 0;
  232.     for (DOM_Node n = refNode; n!=null; n = n.getPreviousSibling()) {
  233.         i++;
  234.     }
  235.     if (i == 0)
  236.         fStartOffset = 0;
  237.     else
  238.         fStartOffset = i-1;
  239.     if ((fDocument != refNode.getOwnerDocument())
  240.         && (refNode.getOwnerDocument().fImpl != 0) )
  241.     {
  242.         fDocument = refNode.getOwnerDocument();
  243.         collapse(true);
  244.     }
  245.     //compare the start and end boundary point
  246.     //collapse if start point is after the end point
  247.     if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1)
  248.         collapse(true); //collapse the range positions to start
  249.     else
  250.         fCollapsed = false;
  251. }
  252. void RangeImpl::setStartAfter(const DOM_Node& refNode)
  253. {
  254.     if( fDetached) {
  255.         throw DOM_DOMException(
  256.             DOM_DOMException::INVALID_STATE_ERR, null);
  257.     }
  258.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  259.         throw DOM_RangeException(
  260.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  261.     }
  262.     fStartContainer = refNode.getParentNode();
  263.     unsigned int i = 0;
  264.     for (DOM_Node n = refNode; n!=null; n = n.getPreviousSibling()) {
  265.         i++;
  266.     }
  267.     fStartOffset = i;
  268.     if ((fDocument != refNode.getOwnerDocument() )
  269.         && (refNode.getOwnerDocument().fImpl != 0) )
  270.     {
  271.         fDocument = refNode.getOwnerDocument();
  272.         collapse(true);
  273.     }
  274.     //compare the start and end boundary point
  275.     //collapse if start point is after the end point
  276.     if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1)
  277.         collapse(true); //collapse the range positions to start
  278.     else
  279.         fCollapsed = false;
  280. }
  281. void RangeImpl::setEndBefore(const DOM_Node& refNode)
  282. {
  283.     if( fDetached) {
  284.         throw DOM_DOMException(
  285.             DOM_DOMException::INVALID_STATE_ERR, null);
  286.     }
  287.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  288.         throw DOM_RangeException(
  289.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  290.     }
  291.     fEndContainer = refNode.getParentNode();
  292.     unsigned int i = 0;
  293.     for (DOM_Node n = refNode; n!=null; n = n.getPreviousSibling(), i++) ;
  294.     if (i< 1)
  295.         fEndOffset = 0;
  296.     else
  297.         fEndOffset = i-1;
  298.     if ((fDocument != refNode.getOwnerDocument() )
  299.         && (refNode.getOwnerDocument().fImpl != 0) )
  300.     {
  301.         fDocument = refNode.getOwnerDocument();
  302.         collapse(true);
  303.     }
  304.     //compare the start and end boundary point
  305.     //collapse if start point is after the end point
  306.     if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1)
  307.         collapse(false); //collapse the range positions to end
  308.     else
  309.         fCollapsed = false;
  310. }
  311. void RangeImpl::setEndAfter(const DOM_Node& refNode)
  312. {
  313.     if( fDetached) {
  314.         throw DOM_DOMException(
  315.             DOM_DOMException::INVALID_STATE_ERR, null);
  316.     }
  317.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  318.         throw DOM_RangeException(
  319.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  320.     }
  321.     fEndContainer = refNode.getParentNode();
  322.     unsigned int i = 0;
  323.     for (DOM_Node n = refNode; n!=null; n = n.getPreviousSibling(), i++) ;
  324.     if (i ==0)
  325.         fEndOffset = 0;
  326.     else
  327.         fEndOffset = i;
  328.     if ((fDocument != refNode.getOwnerDocument() )
  329.         && (refNode.getOwnerDocument().fImpl != 0) )
  330.     {
  331.         fDocument = refNode.getOwnerDocument();
  332.         collapse(true);
  333.     }
  334.     //compare the start and end boundary point
  335.     //collapse if start point is after the end point
  336.     if(compareBoundaryPoints(DOM_Range::END_TO_START, this) == 1)
  337.         collapse(false); //collapse the range positions to end
  338.     else
  339.         fCollapsed = false;
  340. }
  341. //-------------------------------
  342. // Public Misc. functions
  343. //-------------------------------
  344. void RangeImpl::detach()
  345. {
  346.     if( fDetached) {
  347.         throw DOM_DOMException(
  348.             DOM_DOMException::INVALID_STATE_ERR, null);
  349.     }
  350.     fDetached = true;
  351.     //nullify nodes
  352.     fStartContainer = 0;
  353.     fStartOffset    = 0;
  354.     fEndContainer   = 0;
  355.     fEndOffset      = 0;
  356.     fCollapsed      = true;
  357.     fRemoveChild    = 0;
  358. }
  359. void RangeImpl::collapse(bool toStart)
  360. {
  361.     if( fDetached) {
  362.         throw DOM_DOMException(
  363.             DOM_DOMException::INVALID_STATE_ERR, null);
  364.     }
  365.     if (toStart) {
  366.         fEndContainer = fStartContainer;
  367.         fEndOffset = fStartOffset;
  368.     } else {
  369.         fStartContainer = fEndContainer;
  370.         fStartOffset = fEndOffset;
  371.     }
  372.     fCollapsed = true;
  373. }
  374. void RangeImpl::selectNode(const DOM_Node& refNode)
  375. {
  376.     validateNode(refNode);
  377.     if ( !isLegalContainedNode(refNode)) {
  378.         throw DOM_RangeException(
  379.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  380.     }
  381.     //First check for the text type node
  382.     if (refNode.getNodeType() ==  DOM_Node::TEXT_NODE)
  383.     {
  384.         //The node itself is the container.
  385.         fStartContainer = refNode;
  386.         fEndContainer   = refNode;
  387.         //Select all the contents of the node
  388.         fStartOffset = 0;
  389.         fEndOffset = ((DOM_Text &)refNode).getLength();
  390.         return;
  391.     }
  392.     DOM_Node parent = refNode.getParentNode();
  393.     if (parent != null ) // REVIST: what to do if it IS null?
  394.     {
  395.         fStartContainer = parent;
  396.         fEndContainer = parent;
  397.         unsigned int i = 0;
  398.         for (DOM_Node n = parent.getFirstChild(); n!=null, n!=refNode; n = n.getNextSibling()) {
  399.             i++;
  400.         }
  401.         fStartOffset = i;
  402.         fEndOffset = fStartOffset+1;
  403.     }
  404. }
  405. void RangeImpl::selectNodeContents(const DOM_Node& node)
  406. {
  407.     validateNode(node);
  408.     fStartContainer = node;
  409.     fEndContainer = node;
  410.     fStartOffset = 0;
  411.     if (node.getNodeType() == DOM_Node::TEXT_NODE ) {
  412.         fEndOffset = ((DOM_Text &)node).getLength();
  413.         return;
  414.     }
  415.     DOM_Node first = node.getFirstChild();
  416.     if (first == null) {
  417.         fEndOffset = 0;
  418.         return;
  419.     }
  420.     unsigned int i = 0;
  421.     for (DOM_Node n = first; n!=null; n = n.getNextSibling()) {
  422.         i++;
  423.     }
  424.     fEndOffset = i;
  425. }
  426. void RangeImpl::surroundContents(DOM_Node& newParent)
  427. {
  428.     if (newParent==null) return;
  429.     //check for elimination criteria
  430.     if( fDetached) {
  431.         throw DOM_DOMException(
  432.             DOM_DOMException::INVALID_STATE_ERR, null);
  433.     }
  434.     if (newParent.getOwnerDocument() !=fDocument) {
  435.         throw DOM_DOMException(
  436.             DOM_DOMException::WRONG_DOCUMENT_ERR, null);
  437.     }
  438.     int type = newParent.getNodeType();
  439.     if ( !isLegalContainedNode(newParent)
  440.         || type == DOM_Node::DOCUMENT_TYPE_NODE)
  441.     {
  442.         throw DOM_RangeException(
  443.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  444.     }
  445.     DOM_Node root = getCommonAncestorContainer();
  446.     DOM_Node realStart = fStartContainer;
  447.     DOM_Node realEnd = fEndContainer;
  448.     if (fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {
  449.         realStart = fStartContainer.getParentNode();
  450.     }
  451.     if (fEndContainer.getNodeType() == DOM_Node::TEXT_NODE) {
  452.         realEnd = fEndContainer.getParentNode();
  453.     }
  454.     if (realStart != realEnd) {
  455.         throw DOM_RangeException(
  456.             DOM_RangeException::BAD_BOUNDARYPOINTS_ERR, null);
  457.     }
  458.     DOM_DocumentFragment frag = extractContents();
  459.     insertNode(newParent);
  460.     newParent.appendChild(frag);
  461.     selectNode(newParent);
  462. }
  463. short RangeImpl::compareBoundaryPoints(DOM_Range::CompareHow how, RangeImpl* srcRange) const
  464. {
  465.     if (fDocument != srcRange->fDocument) {
  466.         throw DOM_DOMException(
  467.             DOM_DOMException::WRONG_DOCUMENT_ERR, null);
  468.     }
  469.     if( fDetached) {
  470.         throw DOM_DOMException(
  471.             DOM_DOMException::INVALID_STATE_ERR, null);
  472.     }
  473.     DOM_Node pointA, pointB;
  474.     int offsetA, offsetB;
  475.     switch (how)
  476.     {
  477.     case (DOM_Range::START_TO_START) :
  478.         pointB = srcRange->getStartContainer();
  479.         pointA = fStartContainer;
  480.         offsetB = srcRange->getStartOffset();
  481.         offsetA = fStartOffset;
  482.         break;
  483.     case (DOM_Range::START_TO_END) :
  484.         pointB = srcRange->getStartContainer();
  485.         pointA = fEndContainer;
  486.         offsetB = srcRange->getStartOffset();
  487.         offsetA = fEndOffset;
  488.         break;
  489.     case (DOM_Range::END_TO_START) :
  490.         pointB = srcRange->getEndContainer();
  491.         pointA = fStartContainer;
  492.         offsetB = srcRange->getEndOffset();
  493.         offsetA = fStartOffset;
  494.         break;
  495.     case (DOM_Range::END_TO_END) :
  496.         pointB = srcRange->getEndContainer();
  497.         pointA = fEndContainer;
  498.         offsetB = srcRange->getEndOffset();
  499.         offsetA = fEndOffset;
  500.         break;
  501.     }
  502.     // case 1: same container
  503.     if (pointA == pointB) {
  504.         if (offsetA < offsetB) return -1; //A before B
  505.         if (offsetA == offsetB) return 0; //A equal to B
  506.         return 1; // A after B
  507.     }
  508.     // case 2: Child C of container A is ancestor of B
  509.     for (DOM_Node node = pointA.getFirstChild(); node != null; node=node.getNextSibling()) {
  510.         if (isAncestorOf(node, pointB)) {
  511.             int index = indexOf(node, pointA);
  512.             if (offsetA <=  index) return -1;
  513.             return 1;
  514.         }
  515.     }
  516.     // case 3: Child C of container B is ancestor of A
  517.     for (DOM_Node nd = pointB.getFirstChild(); nd != null; nd=nd.getNextSibling()) {
  518.         if (isAncestorOf(nd, pointA)) {
  519.             int index = indexOf(nd, pointB);
  520.             if (index < offsetB ) return -1;
  521.             return 1; //B strictly before A
  522.         }
  523.     }
  524.     // case 4: preorder traversal of context tree.
  525.     DOM_Node ancestor = commonAncestorOf(pointA, pointB);
  526.     DOM_Node current = ancestor;
  527.     do {
  528.         if (current == pointA) return -1;
  529.         if (current == pointB) return 1;
  530.         current = nextNode(current, true);
  531.     }
  532.     while (current!=null && current!=ancestor);
  533.     return -2; // this should never happen
  534. }
  535. void RangeImpl:: deleteContents()
  536. {
  537.     traverseContents(DELETE_CONTENTS);
  538. }
  539. DOM_DocumentFragment RangeImpl::extractContents()
  540. {
  541.     checkReadOnly(fStartContainer, fEndContainer, fStartOffset, fEndOffset);
  542.     return traverseContents(EXTRACT_CONTENTS);
  543. }
  544. DOM_DocumentFragment RangeImpl::cloneContents() const
  545. {
  546.     // cast off const.
  547.     return ((RangeImpl *)this)->traverseContents(CLONE_CONTENTS);
  548. }
  549. void RangeImpl::insertNode(DOM_Node& newNode)
  550. {
  551.     if (newNode == null) return; //don't have to do anything
  552.     for (DOM_Node aNode = fStartContainer; aNode!=null; aNode = aNode.getParentNode()) {
  553.         if (aNode.fImpl->isReadOnly()) {
  554.         throw DOM_DOMException(
  555.             DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
  556.     }
  557.     }
  558.     if (fDocument != newNode.getOwnerDocument()) {
  559.         throw DOM_DOMException(
  560.             DOM_DOMException::WRONG_DOCUMENT_ERR, null);
  561.     }
  562.     // Prevent cycles in the tree.
  563.     //isKidOK() is not checked here as its taken care by insertBefore() function
  564.     if (isAncestorOf( newNode, fStartContainer)) {
  565.         throw DOM_DOMException(
  566.             DOM_DOMException::HIERARCHY_REQUEST_ERR, null);
  567.     }
  568.     if( fDetached) {
  569.         throw DOM_DOMException(
  570.             DOM_DOMException::INVALID_STATE_ERR, null);
  571.     }
  572.     int type = newNode.getNodeType();
  573.     if (type == DOM_Node::ATTRIBUTE_NODE
  574.         || type == DOM_Node::ENTITY_NODE
  575.         || type == DOM_Node::NOTATION_NODE
  576.         || type == DOM_Node::DOCUMENT_NODE)
  577.     {
  578.         throw DOM_RangeException(
  579.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  580.     }
  581.     DOM_Node parent;
  582.     DOM_Node next;
  583.     if (fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {
  584.         //set 'parent' and 'next' here
  585.         parent = fStartContainer.getParentNode();
  586.         //split the text nodes
  587.        if (fStartOffset > 0)
  588.             ((DOM_Text &)fStartContainer).splitText(fStartOffset);
  589.         //update the new start information later. After inserting the first newNode
  590.         if (fStartOffset == 0)
  591.             next = fStartContainer;
  592.         else
  593.             next = fStartContainer.getNextSibling();
  594.     } // end of text handling
  595.     else {
  596.         parent = fStartContainer;
  597.         next = fStartContainer.getFirstChild();
  598.         for(unsigned int i = 0; (i < fStartOffset) && (next != null); i++) {
  599.             next=next.getNextSibling();
  600.         }
  601.     }
  602.     if (parent != null) {
  603.         if (next != null)
  604.             parent.insertBefore(newNode, next);
  605.         else
  606.             parent.appendChild(newNode);
  607.     }
  608. }
  609. RangeImpl* RangeImpl::cloneRange() const
  610. {
  611.     if( fDetached) {
  612.         throw DOM_DOMException(
  613.             DOM_DOMException::INVALID_STATE_ERR, null);
  614.     }
  615.     RangeImpl* range = ((DocumentImpl*)fDocument.fImpl)->createRange();
  616.     range->setStart(fStartContainer, fStartOffset);
  617.     range->setEnd(fEndContainer, fEndOffset);
  618.     return range;
  619. }
  620. DOMString RangeImpl::toString() const
  621. {
  622.     if( fDetached) {
  623.         throw DOM_DOMException(
  624.             DOM_DOMException::INVALID_STATE_ERR, null);
  625.     }
  626.     DOM_Node node = fStartContainer;
  627.     DOM_Node stopNode = fEndContainer;
  628.     DOMString tempString;
  629.     if ( (fStartContainer.getNodeType() == DOM_Node::TEXT_NODE)
  630.         || (fStartContainer.getNodeType() == DOM_Node::CDATA_SECTION_NODE) ) {
  631.         if (fStartContainer == fEndContainer) {
  632.             tempString.appendData(fStartContainer.getNodeValue().substringData(fStartOffset, fEndOffset-fStartOffset));
  633.             return tempString;
  634.         } else {
  635.             int length = fStartContainer.getNodeValue().length();
  636.             tempString.appendData(fStartContainer.getNodeValue().substringData(fStartOffset, length - fStartOffset));
  637.             node = nextNode(node, true);
  638.         }
  639.     }else { //fStartContainer is not a TextNode
  640.         node=node.getFirstChild();
  641.         if (fStartOffset>0) { //find a first node within a range, specified by fStartOffset
  642.             unsigned int counter = 0;
  643.             while (counter<fStartOffset && node!=null) {
  644.                 node=node.getNextSibling();
  645.                 counter++;
  646.             }
  647.         }
  648.         if (node == null) {
  649.             node = nextNode(fStartContainer,false);
  650.         }
  651.     }
  652.     if ( fEndContainer.getNodeType()!= DOM_Node::TEXT_NODE &&
  653.         fEndContainer.getNodeType()!= DOM_Node::CDATA_SECTION_NODE ){
  654.         int i=fEndOffset;
  655.         stopNode = fEndContainer.getFirstChild();
  656.         while( i>0 && stopNode!=null ){
  657.             --i;
  658.             stopNode = stopNode.getNextSibling();
  659.         }
  660.         if ( stopNode == null )
  661.             stopNode = nextNode( fEndContainer, false );
  662.     }
  663.     while (node != stopNode) {  //look into all kids of the Range
  664.         if (node == null) break;
  665.         if (node.getNodeType() == DOM_Node::TEXT_NODE
  666.             ||  node.getNodeType() == DOM_Node::CDATA_SECTION_NODE) {
  667.             tempString.appendData(node.getNodeValue());
  668.         }
  669.         node = nextNode(node, true);
  670.     }
  671.     if (fEndContainer.getNodeType() == DOM_Node::TEXT_NODE
  672.         || fEndContainer.getNodeType() == DOM_Node::CDATA_SECTION_NODE) {
  673.         tempString.appendData(fEndContainer.getNodeValue().substringData(0,fEndOffset));
  674.     }
  675.     return tempString;
  676. }
  677. DOM_Document RangeImpl::getDocument()
  678. {
  679.     return fDocument;
  680. }
  681. const DOM_Node RangeImpl::getCommonAncestorContainer() const
  682. {
  683.      return commonAncestorOf(fStartContainer, fEndContainer);
  684. }
  685. //---------------------
  686. //private functions
  687. //---------------------
  688. bool RangeImpl::isValidAncestorType(const DOM_Node& node) const
  689. {
  690.     for (DOM_Node aNode = node; aNode!=null; aNode = aNode.getParentNode()) {
  691.         short type = aNode.getNodeType();
  692.         if ( type == DOM_Node::ENTITY_NODE
  693.             || type == DOM_Node::NOTATION_NODE
  694.             || type == DOM_Node::DOCUMENT_TYPE_NODE)
  695.             return false;
  696.     }
  697.     return true;
  698. }
  699. bool RangeImpl::isAncestorOf(const DOM_Node& a, const DOM_Node& b) {
  700.     for (DOM_Node node=b; node != null; node=node.getParentNode()) {
  701.         if  (node == a) return true;
  702.     }
  703.     return false;
  704. }
  705. bool RangeImpl::hasLegalRootContainer(const DOM_Node& node) const {
  706.     if ( node==null )
  707.         return false;
  708.     DOM_Node rootContainer = node;
  709.     for (; rootContainer.getParentNode()!=null; rootContainer = rootContainer.getParentNode())
  710.         ;
  711.     switch( rootContainer.getNodeType() ) {
  712.         case DOM_Node::ATTRIBUTE_NODE:
  713.         case DOM_Node::DOCUMENT_NODE:
  714.         case DOM_Node::DOCUMENT_FRAGMENT_NODE:
  715.         return true;
  716.     }
  717.     return false;
  718. }
  719. bool RangeImpl::isLegalContainedNode(const DOM_Node& node ) const {
  720.    if ( node==null )
  721.        return false;
  722.    switch( node.getNodeType() )
  723.    {
  724.        case DOM_Node::DOCUMENT_NODE:
  725.        case DOM_Node::DOCUMENT_FRAGMENT_NODE:
  726.        case DOM_Node::ATTRIBUTE_NODE:
  727.        case DOM_Node::ENTITY_NODE:
  728.        case DOM_Node::NOTATION_NODE:
  729.        return false;
  730.    }
  731.    return true;
  732. }
  733. unsigned short RangeImpl::indexOf(const DOM_Node& child, const DOM_Node& parent) const
  734. {
  735.     unsigned short i = 0;
  736.     if (child.getParentNode() != parent) return (unsigned short)-1;
  737.     for(DOM_Node node = child.getPreviousSibling(); node!= null; node=node.getPreviousSibling()) {
  738.         i++;
  739.     }
  740.     return i;
  741. }
  742. void RangeImpl::validateNode(const DOM_Node& node) const
  743. {
  744.     if( fDetached) {
  745.         throw DOM_DOMException(
  746.             DOM_DOMException::INVALID_STATE_ERR, null);
  747.     }
  748.     if ( !isValidAncestorType(node)) {
  749.         throw DOM_RangeException(
  750.             DOM_RangeException::INVALID_NODE_TYPE_ERR, null);
  751.     }
  752. }
  753. const DOM_Node RangeImpl::commonAncestorOf(const DOM_Node& pointA, const DOM_Node& pointB) const
  754. {
  755.     if (fDetached)
  756.             throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
  757.     if (pointA.getOwnerDocument() != pointB.getOwnerDocument())
  758.         throw DOM_DOMException( DOM_DOMException::WRONG_DOCUMENT_ERR, null );
  759.     //if the containers are same then it itself is its common ancestor.
  760.     if (pointA == pointB)
  761.         return pointA;
  762.     typedef RefVectorOf<NodeImpl> VectorNodes;
  763.     VectorNodes* startV= new VectorNodes(1, false);
  764.     DOM_Node node;
  765.     for (node=fStartContainer; node != null; node=node.getParentNode())
  766.     {
  767.         startV->addElement(node.fImpl);
  768.     }
  769.     VectorNodes* endV = new VectorNodes(1, false);
  770.     for (node=fEndContainer; node != null; node=node.getParentNode())
  771.     {
  772.         endV->addElement(node.fImpl);
  773.     }
  774.     int s = startV->size()-1;
  775.     int e = endV->size()-1;
  776.     NodeImpl* commonAncestor;
  777.     while (s>=0 && e>=0) {
  778.         if (startV->elementAt(s) == endV->elementAt(e)) {
  779.             commonAncestor = startV->elementAt(s);
  780.         }
  781.         else  break;
  782.         --s;
  783.         --e;
  784.     }
  785.     delete startV;
  786.     delete endV;
  787.     return DOM_Node(commonAncestor);
  788. }
  789. void RangeImpl::checkIndex(const DOM_Node& node, unsigned int offset) const
  790. {
  791.     if (offset < 0) {
  792.         throw DOM_DOMException( DOM_DOMException::INDEX_SIZE_ERR, null );
  793.     }
  794.     short type = node.getNodeType();
  795.     if((type == DOM_Node::TEXT_NODE
  796.         || type == DOM_Node::CDATA_SECTION_NODE
  797.         || type == DOM_Node::COMMENT_NODE
  798.         || type == DOM_Node::PROCESSING_INSTRUCTION_NODE)) {
  799.         if (offset > node.getNodeValue().length())
  800.             throw DOM_DOMException( DOM_DOMException::INDEX_SIZE_ERR, null );
  801.         else  return;
  802.     }
  803.     DOM_Node child = node.getFirstChild();
  804.     unsigned int i = 0;
  805.     for (; child != null; i++) {
  806.         child = child.getNextSibling();
  807.     }
  808.     if (i < offset) {
  809.         throw DOM_DOMException( DOM_DOMException::INDEX_SIZE_ERR, null );
  810.     }
  811. }
  812. DOM_Node RangeImpl::nextNode(const DOM_Node& node, bool visitChildren) const
  813. {
  814.     if (node == null) return null;
  815.     DOM_Node result;
  816.     if (visitChildren) {
  817.         result = node.getFirstChild();
  818.         if (result != null) {
  819.             return result;
  820.         }
  821.     }
  822.     // if hasSibling, return sibling
  823.     result = node.getNextSibling();
  824.     if (result != null) {
  825.         return result;
  826.     }
  827.     // return parent's 1st sibling.
  828.     DOM_Node parent = node.getParentNode();
  829.     while ( (parent != null) && (parent != fDocument) )
  830.     {
  831.         result = parent.getNextSibling();
  832.         if (result != null) {
  833.             return result;
  834.         } else {
  835.             parent = parent.getParentNode();
  836.             if (parent == fEndContainer) return parent;
  837.         }
  838.     }
  839.     // end of list, return null
  840.     return null;
  841. }
  842. /** This is the master routine invoked to visit the nodes
  843. *   selected by this range.  For each such node, different
  844. *   actions are taken depending on the value of the TraversalType argument.
  845. */
  846. DOM_DocumentFragment RangeImpl::traverseContents(TraversalType how)
  847. {
  848.     if (fDetached)
  849.             throw DOM_DOMException(DOM_DOMException::INVALID_STATE_ERR, null);
  850.     if (fStartContainer == null || fEndContainer == null) {
  851.         return DOM_DocumentFragment(); // REVIST: Throw exception?
  852.     }
  853.     /* Traversal is accomplished by first determining the
  854.        relationship between the endpoints of the range.
  855.        For each of four significant relationships, we will
  856.        delegate the traversal call to a method that
  857.        can make appropriate assumptions.
  858.     */
  859.     // case 1: same container
  860.     if ( fStartContainer == fEndContainer )
  861.         return traverseSameContainer( how );
  862.     // case 2: Child C of start container is ancestor of end container
  863.     for (DOM_Node node = fStartContainer.getFirstChild(); node != null; node=node.getNextSibling()) {
  864.         if (isAncestorOf(node, fEndContainer))
  865.             return traverseCommonStartContainer( node, how );
  866.     }
  867.     // case 3: Child C of end container  is ancestor of start container
  868.     for (DOM_Node nd = fEndContainer.getFirstChild(); nd != null; nd=nd.getNextSibling()) {
  869.         if (isAncestorOf(nd, fStartContainer))
  870.              return traverseCommonEndContainer( nd, how );
  871.         }
  872.     // case 4: preorder traversal of context tree.
  873.     // There is a common ancestor container.  Find the
  874.     // ancestor siblings that are children of that container.
  875.     DOM_Node ancestor = commonAncestorOf(fStartContainer, fEndContainer);
  876.     return traverseCommonAncestors( ancestor, ancestor, how );
  877.     }
  878. /**
  879.  * Visits the nodes selected by this range when we know
  880.  * a-priori that the start and end containers are the same.
  881.  *
  882.  */
  883. DOM_DocumentFragment RangeImpl::traverseSameContainer( int how )
  884. {
  885.     DOM_DocumentFragment frag = null;
  886.     if ( how!=DELETE_CONTENTS)
  887.         frag = fDocument.createDocumentFragment();
  888.     // If selection is empty, just return the fragment
  889.     if ( fStartOffset==fEndOffset )
  890.             return frag;
  891.     DOM_Node current = fStartContainer;
  892.     DOM_Node cloneCurrent = null;
  893.     // Text node needs special case handling
  894.     if ( fStartContainer.getNodeType()== DOM_Node::TEXT_NODE )
  895.     {
  896.         cloneCurrent = fStartContainer.cloneNode(false);
  897.         cloneCurrent.setNodeValue(
  898.             cloneCurrent.getNodeValue().substringData(fStartOffset, fEndOffset - fStartOffset));
  899.         // set the original text node to its new value
  900.         if ( how != CLONE_CONTENTS )
  901.             ((DOM_Text &)fStartContainer).deleteData(fStartOffset, fEndOffset-fStartOffset);
  902.         if ( how != DELETE_CONTENTS)
  903.             frag.appendChild(cloneCurrent);
  904.     }
  905.     else {
  906.         // Copy nodes between the start/end offsets.
  907.         DOM_Node n = getSelectedNode( fStartContainer, fStartOffset );
  908.         int cnt = fEndOffset - fStartOffset;
  909.         while( cnt > 0 )
  910.         {
  911.             DOM_Node sibling = n.getNextSibling();
  912.             DOM_Node xferNode = traverseFullySelected( n, how );
  913.             if ( frag!=null )
  914.                 frag.appendChild( xferNode );
  915.             --cnt;
  916.             n = sibling;
  917.             }
  918.     }
  919.     // Nothing is partially selected, so collapse to start point
  920.     if ( how != CLONE_CONTENTS )
  921.             collapse(true);
  922.     return frag;
  923. }
  924. /**
  925.  * Visits the nodes selected by this range when we know
  926.  * a-priori that the start and end containers are not the
  927.  * same, but the start container is an ancestor of the end container
  928.  *
  929.  */
  930. DOM_DocumentFragment RangeImpl::traverseCommonStartContainer( DOM_Node endAncestor, int how )
  931. {
  932.     DOM_DocumentFragment frag = null;
  933.     if ( how!=DELETE_CONTENTS)
  934.         frag = fDocument.createDocumentFragment();
  935.     DOM_Node n = traverseRightBoundary( endAncestor, how );
  936.     if ( frag!=null )
  937.         frag.appendChild( n );
  938.     int endIdx = indexOf( endAncestor, fStartContainer );
  939.     int cnt = endIdx - fStartOffset;
  940.     if ( cnt <=0 )
  941.     {
  942.         // Collapse to just before the endAncestor, which
  943.         // is partially selected.
  944.         if ( how != CLONE_CONTENTS )
  945.         {
  946.             setEndBefore( endAncestor );
  947.             collapse( false );
  948.         }
  949.         return frag;
  950.     }
  951.     n = endAncestor.getPreviousSibling();
  952.     while( cnt > 0 )
  953.     {
  954.         DOM_Node sibling = n.getPreviousSibling();
  955.         DOM_Node xferNode = traverseFullySelected( n, how );
  956.         if ( frag!=null )
  957.             frag.insertBefore( xferNode, frag.getFirstChild() );
  958.         --cnt;
  959.         n = sibling;
  960.     }
  961.     // Collapse to just before the endAncestor, which
  962.     // is partially selected.
  963.     if ( how != CLONE_CONTENTS )
  964.     {
  965.         setEndBefore( endAncestor );
  966.         collapse( false );
  967.     }
  968.     return frag;
  969. }
  970. /**
  971.  * Visits the nodes selected by this range when we know
  972.  * a-priori that the start and end containers are not the
  973.  * same, but the end container is an ancestor of the start container
  974.  *
  975.  */
  976. DOM_DocumentFragment RangeImpl::traverseCommonEndContainer( DOM_Node startAncestor, int how )
  977. {
  978.     DOM_DocumentFragment frag = null;
  979.     if ( how!=DELETE_CONTENTS)
  980.         frag = fDocument.createDocumentFragment();
  981.     DOM_Node n = traverseLeftBoundary( startAncestor, how );
  982.     if ( frag!=null )
  983.         frag.appendChild( n );
  984.     int startIdx = indexOf( startAncestor, fEndContainer );
  985.     ++startIdx;  // Because we already traversed it....
  986.     int cnt = fEndOffset - startIdx;
  987.     n = startAncestor.getNextSibling();
  988.     while( cnt > 0 )
  989.     {
  990.         DOM_Node sibling = n.getNextSibling();
  991.         DOM_Node xferNode = traverseFullySelected( n, how );
  992.         if ( frag!=null )
  993.             frag.appendChild( xferNode );
  994.         --cnt;
  995.         n = sibling;
  996.     }
  997.     if ( how != CLONE_CONTENTS )
  998.     {
  999.         setStartAfter( startAncestor );
  1000.         collapse( true );
  1001.     }
  1002.     return frag;
  1003. }
  1004. /**
  1005.  * Visits the nodes selected by this range when we know
  1006.  * a-priori that the start and end containers are not
  1007.  * the same, and we also know that neither the start
  1008.  * nor end container is an ancestor of the other.
  1009.  */
  1010. DOM_DocumentFragment RangeImpl::traverseCommonAncestors( DOM_Node startAncestor, DOM_Node endAncestor, int how )
  1011. {
  1012.     DOM_DocumentFragment frag = null;
  1013.     if ( how!=DELETE_CONTENTS)
  1014.         frag = fDocument.createDocumentFragment();
  1015.     DOM_Node n = traverseLeftBoundary( startAncestor, how );
  1016.     if ( frag!=null )
  1017.         frag.appendChild( n );
  1018.     DOM_Node commonParent = startAncestor.getParentNode();
  1019.     int startOffset = indexOf( startAncestor, commonParent );
  1020.     int endOffset = indexOf( endAncestor, commonParent );
  1021.     ++startOffset;
  1022.     int cnt = endOffset - startOffset;
  1023.     DOM_Node sibling = startAncestor.getNextSibling();
  1024.     while( cnt > 0 )
  1025.     {
  1026.         DOM_Node nextSibling = sibling.getNextSibling();
  1027.         n = traverseFullySelected( sibling, how );
  1028.         if ( frag!=null )
  1029.             frag.appendChild( n );
  1030.         sibling = nextSibling;
  1031.         --cnt;
  1032.     }
  1033.     n = traverseRightBoundary( endAncestor, how );
  1034.     if ( frag!=null )
  1035.         frag.appendChild( n );
  1036.     if ( how != CLONE_CONTENTS )
  1037.     {
  1038.         setStartAfter( startAncestor );
  1039.         collapse( true );
  1040.     }
  1041.     return frag;
  1042. }
  1043. /**
  1044.  * Traverses the "right boundary" of this range and
  1045.  * operates on each "boundary node" according to the
  1046.  * how parameter.  It is a-priori assumed
  1047.  * by this method that the right boundary does
  1048.  * not contain the range's start container.
  1049.  *
  1050.  * A "right boundary" is best visualized by thinking
  1051.  * of a sample tree:
  1052.  *                 A
  1053.  *                /|
  1054.  *               / | 
  1055.  *              /  |  
  1056.  *             B   C   D
  1057.  *            /|     /|
  1058.  *           E F G   H I J
  1059.  *
  1060.  * Imagine first a range that begins between the
  1061.  * "E" and "F" nodes and ends between the
  1062.  * "I" and "J" nodes.  The start container is
  1063.  * "B" and the end container is "D".  Given this setup,
  1064.  * the following applies:
  1065.  *
  1066.  * Partially Selected Nodes: B, D<br>
  1067.  * Fully Selected Nodes: F, G, C, H, I
  1068.  *
  1069.  * The "right boundary" is the highest subtree node
  1070.  * that contains the ending container.  The root of
  1071.  * this subtree is always partially selected.
  1072.  *
  1073.  * In this example, the nodes that are traversed
  1074.  * as "right boundary" nodes are: H, I, and D.
  1075.  *
  1076.  */
  1077. DOM_Node RangeImpl::traverseRightBoundary( DOM_Node root, int how )
  1078. {
  1079.     DOM_Node next = getSelectedNode( fEndContainer, fEndOffset-1 );
  1080.     bool isFullySelected = ( next!=fEndContainer );
  1081.     if ( next==root )
  1082.         return traverseNode( next, isFullySelected, false, how );
  1083.     DOM_Node parent = next.getParentNode();
  1084.     DOM_Node clonedParent = traverseNode( parent, false, false, how );
  1085.     while( parent!=null )
  1086.     {
  1087.         while( next!=null )
  1088.         {
  1089.             DOM_Node prevSibling = next.getPreviousSibling();
  1090.             DOM_Node clonedChild =
  1091.                 traverseNode( next, isFullySelected, false, how );
  1092.             if ( how!=DELETE_CONTENTS )
  1093.             {
  1094.                 clonedParent.insertBefore(
  1095.                     clonedChild,
  1096.                     clonedParent.getFirstChild()
  1097.                 );
  1098.             }
  1099.             isFullySelected = true;
  1100.             next = prevSibling;
  1101.         }
  1102.         if ( parent==root )
  1103.             return clonedParent;
  1104.         next = parent.getPreviousSibling();
  1105.         parent = parent.getParentNode();
  1106.         DOM_Node clonedGrandParent = traverseNode( parent, false, false, how );
  1107.         if ( how!=DELETE_CONTENTS )
  1108.             clonedGrandParent.appendChild( clonedParent );
  1109.         clonedParent = clonedGrandParent;
  1110.     }
  1111.     // should never occur
  1112.     return null;
  1113. }
  1114. /**
  1115.  * Traverses the "left boundary" of this range and
  1116.  * operates on each "boundary node" according to the
  1117.  * how parameter.  It is a-priori assumed
  1118.  * by this method that the left boundary does
  1119.  * not contain the range's end container.
  1120.  *
  1121.  * A "left boundary" is best visualized by thinking
  1122.  * of a sample tree:
  1123.  *
  1124.  *                 A
  1125.  *                /|
  1126.  *               / | 
  1127.  *              /  |  
  1128.  *             B   C   D
  1129.  *            /|     /|
  1130.  *           E F G   H I J
  1131.  *
  1132.  * Imagine first a range that begins between the
  1133.  * "E" and "F" nodes and ends between the
  1134.  * "I" and "J" nodes.  The start container is
  1135.  * "B" and the end container is "D".  Given this setup,
  1136.  * the following applies:
  1137.  *
  1138.  * Partially Selected Nodes: B, D<br>
  1139.  * Fully Selected Nodes: F, G, C, H, I
  1140.  *
  1141.  * The "left boundary" is the highest subtree node
  1142.  * that contains the starting container.  The root of
  1143.  * this subtree is always partially selected.
  1144.  *
  1145.  * In this example, the nodes that are traversed
  1146.  * as "left boundary" nodes are: F, G, and B.
  1147.  *
  1148.  */
  1149. DOM_Node RangeImpl::traverseLeftBoundary( DOM_Node root, int how )
  1150. {
  1151.     DOM_Node next = getSelectedNode( getStartContainer(), getStartOffset() );
  1152.     bool isFullySelected = ( next!=getStartContainer() );
  1153.     if ( next==root )
  1154.         return traverseNode( next, isFullySelected, true, how );
  1155.     DOM_Node parent = next.getParentNode();
  1156.     DOM_Node clonedParent = traverseNode( parent, false, true, how );
  1157.     while( parent!=null )
  1158.     {
  1159.         while( next!=null )
  1160.         {
  1161.             DOM_Node nextSibling = next.getNextSibling();
  1162.             DOM_Node clonedChild =
  1163.                 traverseNode( next, isFullySelected, true, how );
  1164.             if ( how!=DELETE_CONTENTS )
  1165.                 clonedParent.appendChild(clonedChild);
  1166.             isFullySelected = true;
  1167.             next = nextSibling;
  1168.         }
  1169.         if ( parent==root )
  1170.             return clonedParent;
  1171.         next = parent.getNextSibling();
  1172.         parent = parent.getParentNode();
  1173.         DOM_Node clonedGrandParent = traverseNode( parent, false, true, how );
  1174.         if ( how!=DELETE_CONTENTS )
  1175.             clonedGrandParent.appendChild( clonedParent );
  1176.         clonedParent = clonedGrandParent;
  1177.     }
  1178.     // should never occur
  1179.     return null;
  1180. }
  1181. /**
  1182.  * Utility method for traversing a single node.
  1183.  * Does not properly handle a text node containing both the
  1184.  * start and end offsets.  Such nodes should
  1185.  * have been previously detected and been routed to traverseTextNode.
  1186.  *
  1187.  */
  1188. DOM_Node RangeImpl::traverseNode( DOM_Node n, bool isFullySelected, bool isLeft, int how )
  1189. {
  1190.     if ( isFullySelected )
  1191.         return traverseFullySelected( n, how );
  1192.     if ( n.getNodeType()== DOM_Node::TEXT_NODE )
  1193.         return traverseTextNode( n, isLeft, how );
  1194.     return traversePartiallySelected( n, how );
  1195. }
  1196. /**
  1197.  * Utility method for traversing a single node when
  1198.  * we know a-priori that the node if fully
  1199.  * selected.
  1200.  *
  1201.  */
  1202. DOM_Node RangeImpl::traverseFullySelected( DOM_Node n, int how )
  1203. {
  1204.     switch( how )
  1205.     {
  1206.     case CLONE_CONTENTS:
  1207.         return n.cloneNode( true );
  1208.     case EXTRACT_CONTENTS:
  1209.         if ( n.getNodeType()== DOM_Node::DOCUMENT_TYPE_NODE )
  1210.         {
  1211.             throw DOM_DOMException(
  1212.                 DOM_DOMException::HIERARCHY_REQUEST_ERR, null);
  1213.         }
  1214.         return n;
  1215.     case DELETE_CONTENTS:
  1216.         n.getParentNode().removeChild(n);
  1217.         return null;
  1218.     }
  1219.     return null;
  1220. }
  1221. /**
  1222.  * Utility method for traversing a single node when
  1223.  * we know a-priori that the node if partially
  1224.  * selected and is not a text node.
  1225.  *
  1226.  */
  1227. DOM_Node RangeImpl::traversePartiallySelected( DOM_Node n, int how )
  1228. {
  1229.     switch( how )
  1230.     {
  1231.     case DELETE_CONTENTS:
  1232.         return null;
  1233.     case CLONE_CONTENTS:
  1234.     case EXTRACT_CONTENTS:
  1235.         return n.cloneNode( false );
  1236.     }
  1237.     return null;
  1238. }
  1239. /**
  1240.  * Utility method for traversing a text node that we know
  1241.  * a-priori to be on a left or right boundary of the range.
  1242.  * This method does not properly handle text nodes that contain
  1243.  * both the start and end points of the range.
  1244.  *
  1245.  */
  1246. DOM_Node RangeImpl::traverseTextNode( DOM_Node n, bool isLeft, int how )
  1247. {
  1248.     DOMString txtValue = n.getNodeValue();
  1249.     DOMString newNodeValue;
  1250.     DOMString oldNodeValue;
  1251.     if ( isLeft )
  1252.     {
  1253.         int offset = getStartOffset();
  1254.         newNodeValue = txtValue.substringData( offset , fStartContainer.getNodeValue().length()-offset);
  1255.         oldNodeValue = txtValue.substringData( 0, offset );
  1256.     }
  1257.     else
  1258.     {
  1259.         int offset = getEndOffset();
  1260.         newNodeValue = txtValue.substringData( 0, offset );
  1261.         oldNodeValue = txtValue.substringData( offset , fEndContainer.getNodeValue().length()-offset );
  1262.     }
  1263.     if ( how != CLONE_CONTENTS )
  1264.         n.setNodeValue( oldNodeValue );
  1265.     if ( how==DELETE_CONTENTS )
  1266.         return null;
  1267.     DOM_Node newNode = n.cloneNode( false );
  1268.     newNode.setNodeValue( newNodeValue );
  1269.     return newNode;
  1270. }
  1271. /**
  1272.  * Utility method to retrieve a child node by index.  This method
  1273.  * assumes the caller is trying to find out which node is
  1274.  * selected by the given index.  Note that if the index is
  1275.  * greater than the number of children, this implies that the
  1276.  * first node selected is the parent node itself.
  1277.  *
  1278.  */
  1279. DOM_Node RangeImpl::getSelectedNode( DOM_Node container, int offset )
  1280. {
  1281.     if ( container.getNodeType() == DOM_Node::TEXT_NODE )
  1282.         return container;
  1283.     // This case is an important convenience for
  1284.     // traverseRightBoundary()
  1285.     if ( offset<0 )
  1286.         return container;
  1287.     DOM_Node child = container.getFirstChild();
  1288.     while( child!=null && offset > 0 )
  1289.     {
  1290.         --offset;
  1291.         child = child.getNextSibling();
  1292.     }
  1293.     if ( child!=null )
  1294.         return child;
  1295.     return container;
  1296. }
  1297. void RangeImpl::checkReadOnly(DOM_Node& start, DOM_Node& end,
  1298.                               unsigned int startOffset, unsigned int endOffset)
  1299. {
  1300.     if ((start == null) || (end == null) ) return;
  1301.     //if both start and end are text check and return
  1302.     if (start.getNodeType() == DOM_Node::TEXT_NODE) {
  1303.         if (start.fImpl->isReadOnly()) {
  1304.             throw DOM_DOMException(
  1305.                 DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
  1306.         }
  1307.         if (start == end)
  1308.             return;
  1309.     }
  1310.     //set the start and end nodes to check
  1311.     DOM_Node sNode = start.getFirstChild();
  1312.     for(unsigned int i = 0; i<startOffset; i++)
  1313.         sNode = sNode.getNextSibling();
  1314.     DOM_Node eNode;
  1315.     if (end.getNodeType() == DOM_Node::TEXT_NODE) {
  1316.         eNode = end; //need to check only till this node
  1317.     }
  1318.     else { //need to check all the kids that fall before the end offset value
  1319.         eNode = end.getFirstChild();
  1320.         for (unsigned int i = 0; i<endOffset-1; i++)
  1321.             eNode = eNode.getNextSibling();
  1322.     }
  1323.     //recursivly search if any node is readonly
  1324.     recurseTreeAndCheck(sNode, eNode);
  1325. }
  1326. void RangeImpl::recurseTreeAndCheck(DOM_Node& start, DOM_Node& end)
  1327. {
  1328.     for(DOM_Node node=start; node != null && node !=end; node=node.getNextSibling())
  1329.     {
  1330.         if (node.fImpl->isReadOnly()) {
  1331.             throw DOM_DOMException(
  1332.                 DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
  1333.         }
  1334.         if (node.hasChildNodes()) {
  1335.             node = node.getFirstChild();
  1336.             recurseTreeAndCheck(node, end);
  1337.         }
  1338.     }
  1339. }
  1340. DOM_Node RangeImpl::removeChild(DOM_Node& parent, DOM_Node& child)
  1341. {
  1342.     fRemoveChild = child; //only a precaution measure not to update this range data before removal
  1343.     DOM_Node n = parent.removeChild(child);
  1344.     fRemoveChild = null;
  1345.     return n;
  1346. }
  1347. //
  1348. // Mutation functions
  1349. //
  1350. /* This function is called from DOM.
  1351. *  The  text has already beeen replaced.
  1352. *  Fix-up any offsets.
  1353. */
  1354. void RangeImpl::receiveReplacedText(NodeImpl* node)
  1355. {
  1356.     if (node == null) return;
  1357.     DOM_Node anode(node);
  1358.     if (anode == fStartContainer
  1359.         && fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {
  1360.         fStartOffset = 0;
  1361.     }
  1362.     if (anode == fEndContainer
  1363.         && fEndContainer.getNodeType() == DOM_Node::TEXT_NODE) {
  1364.         fEndOffset = 0;
  1365.     }
  1366. }
  1367. /** This function is called from DOM.
  1368. *  The  text has already beeen inserted.
  1369. *  Fix-up any offsets.
  1370. */
  1371. void RangeImpl::updateRangeForDeletedText(DOM_Node& node, unsigned int offset, int count)
  1372. {
  1373.     if (node == null) return;
  1374.     if (node == fStartContainer
  1375.         && fStartContainer.getNodeType() == DOM_Node::TEXT_NODE) {
  1376.         if (fStartOffset > offset+count) {
  1377.             fStartOffset = fStartOffset-count;
  1378.         } else if (fStartOffset > offset) {
  1379.             fStartOffset = offset;
  1380.         }
  1381.     }
  1382.     if (node == fEndContainer
  1383.         && fEndContainer.getNodeType() == DOM_Node::TEXT_NODE) {
  1384.         if (fEndOffset > offset+count) {
  1385.             fEndOffset = fEndOffset-count;
  1386.         } else if (fEndOffset > offset) {
  1387.             fEndOffset = offset;
  1388.         }
  1389.     }
  1390. }
  1391. /** This function must be called by the DOM _BEFORE_
  1392. *  a node is deleted, because at that time it is
  1393. *  connected in the DOM tree, which we depend on.
  1394. */
  1395. void RangeImpl::updateRangeForDeletedNode(NodeImpl* node)
  1396. {
  1397.     if (node == null) return;
  1398.     if (fRemoveChild == node) return;
  1399.     DOM_Node tNode(node);
  1400.     if (node->getParentNode() == fStartContainer.fImpl) {
  1401.         unsigned short index = indexOf(tNode, fStartContainer);
  1402.         if ( fStartOffset > index) {
  1403.             fStartOffset--;
  1404.         }
  1405.     }
  1406.     if (node->getParentNode() == fEndContainer.fImpl) {
  1407.         unsigned short index = indexOf(tNode, fEndContainer);
  1408.         if ( fEndOffset > index) {
  1409.             fEndOffset--;
  1410.         }
  1411.     }
  1412.     if (node->getParentNode() != fStartContainer.fImpl
  1413.         ||  node->getParentNode() != fEndContainer.fImpl) {
  1414.         if (isAncestorOf(node, fStartContainer)) {
  1415.             DOM_Node tpNode(node->getParentNode());
  1416.             setStartContainer( tpNode );
  1417.             fStartOffset = indexOf( tNode, tpNode);
  1418.         }
  1419.         if (isAncestorOf(node, fEndContainer)) {
  1420.             DOM_Node tpNode(node->getParentNode());
  1421.             setEndContainer( tpNode );
  1422.             fEndOffset = indexOf( tNode, tpNode);
  1423.         }
  1424.     }
  1425. }
  1426. void RangeImpl::updateRangeForInsertedNode(NodeImpl* node) {
  1427.     if (node == null) return;
  1428.     if (node->getParentNode() == fStartContainer.fImpl) {
  1429.         unsigned int index = indexOf(DOM_Node(node), fStartContainer);
  1430.         if (index < fStartOffset) {
  1431.             fStartOffset++;
  1432.         }
  1433.     }
  1434.     if (node->getParentNode() == fEndContainer.fImpl) {
  1435.         unsigned int index = indexOf(DOM_Node(node), fEndContainer);
  1436.         if (index < fEndOffset) {
  1437.             fEndOffset++;
  1438.         }
  1439.     }
  1440. }
  1441. void RangeImpl::updateSplitInfo(TextImpl* oldNode, TextImpl* startNode, unsigned int offset)
  1442. {
  1443.     if (startNode == null) return;
  1444.     DOM_Text oldText(oldNode);
  1445.     DOM_Text newText(startNode);
  1446.     if (fStartContainer == oldText && fStartOffset > offset) {
  1447.           fStartOffset = fStartOffset - offset;
  1448.         fStartContainer = newText;
  1449.     }
  1450.     if (fEndContainer == oldText && fEndOffset > offset) {
  1451.             fEndContainer = newText;
  1452.        fEndOffset = fEndOffset - offset;
  1453.     }
  1454. }