RangeImpl.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:50k
源码类别:

词法分析

开发平台:

Visual C++

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