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

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2001-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) 2001, 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: DOMRangeImpl.cpp,v 1.14 2003/05/18 14:02:03 knoaman Exp $
  58.  */
  59. #include "DOMRangeImpl.hpp"
  60. #include "DOMDocumentImpl.hpp"
  61. #include "DOMDocumentFragmentImpl.hpp"
  62. #include "DOMCommentImpl.hpp"
  63. #include "DOMProcessingInstructionImpl.hpp"
  64. #include "DOMCasts.hpp"
  65. #include <xercesc/dom/DOMException.hpp>
  66. #include <xercesc/dom/DOMDocument.hpp>
  67. #include <xercesc/dom/DOMRangeException.hpp>
  68. #include <xercesc/dom/DOMText.hpp>
  69. #include <xercesc/dom/DOMProcessingInstruction.hpp>
  70. #include <xercesc/framework/XMLBuffer.hpp>
  71. #include <xercesc/util/Janitor.hpp>
  72. XERCES_CPP_NAMESPACE_BEGIN
  73. //---------------------
  74. // C'tor and D'tor
  75. //---------------------
  76. DOMRangeImpl::DOMRangeImpl(DOMDocument* doc)
  77.     :   fDocument(doc),
  78.         fStartContainer(doc),
  79.         fStartOffset(0),
  80.         fEndContainer(doc),
  81.         fEndOffset(0),
  82.         fDetached(false),
  83.         fCollapsed(true),
  84.         fRemoveChild(0)
  85. {
  86. }
  87. DOMRangeImpl::DOMRangeImpl(const DOMRangeImpl& other)
  88. {
  89.     fDocument = other.fDocument;
  90.     fStartContainer = other.fStartContainer;
  91.     fStartOffset = other.fStartOffset;
  92.     fEndContainer = other.fEndContainer;
  93.     fEndOffset = other.fEndOffset;
  94.     fDetached = other.fDetached;
  95.     fCollapsed = other.fCollapsed;
  96.     fRemoveChild = other.fRemoveChild;
  97. }
  98. DOMRangeImpl::~DOMRangeImpl()
  99. {
  100. }
  101. //-------------------------------
  102. // Public getter functions
  103. //-------------------------------
  104. DOMNode* DOMRangeImpl::getStartContainer() const
  105. {
  106.     if (fDetached)
  107.     {
  108.         throw DOMException(
  109.             DOMException::INVALID_STATE_ERR, 0);
  110.     }
  111.     return fStartContainer;
  112. }
  113. XMLSize_t DOMRangeImpl::getStartOffset() const
  114. {
  115.     if (fDetached)
  116.     {
  117.         throw DOMException(
  118.             DOMException::INVALID_STATE_ERR, 0);
  119.     }
  120.     return fStartOffset;
  121. }
  122. DOMNode* DOMRangeImpl::getEndContainer() const
  123. {
  124.     if (fDetached)
  125.     {
  126.         throw DOMException(
  127.             DOMException::INVALID_STATE_ERR, 0);
  128.     }
  129.     return fEndContainer;
  130. }
  131. XMLSize_t DOMRangeImpl::getEndOffset() const
  132. {
  133.     if (fDetached)
  134.     {
  135.         throw DOMException(
  136.             DOMException::INVALID_STATE_ERR, 0);
  137.     }
  138.     return fEndOffset;
  139. }
  140. bool DOMRangeImpl::getCollapsed() const
  141. {
  142.     if (fDetached)
  143.     {
  144.         throw DOMException(
  145.             DOMException::INVALID_STATE_ERR, 0);
  146.     }
  147.     return ((fStartContainer == fEndContainer)
  148.              && (fStartOffset == fEndOffset));
  149. }
  150. //-------------------------------
  151. // Public setter functions
  152. //-------------------------------
  153. void DOMRangeImpl::setStartContainer(const DOMNode* node)
  154. {
  155.     if (fDetached)
  156.     {
  157.         throw DOMException(
  158.             DOMException::INVALID_STATE_ERR, 0);
  159.     }
  160.     fStartContainer = (DOMNode*) node;
  161. }
  162. void DOMRangeImpl::setStartOffset(XMLSize_t offset)
  163. {
  164.     if (fDetached)
  165.     {
  166.         throw DOMException(
  167.             DOMException::INVALID_STATE_ERR, 0);
  168.     }
  169.     fStartOffset = offset;
  170. }
  171. void DOMRangeImpl::setEndContainer(const DOMNode* node)
  172. {
  173.     if (fDetached)
  174.     {
  175.         throw DOMException(
  176.             DOMException::INVALID_STATE_ERR, 0);
  177.     }
  178.     fEndContainer = (DOMNode*) node;
  179. }
  180. void DOMRangeImpl::setEndOffset(XMLSize_t offset)
  181. {
  182.     if (fDetached)
  183.     {
  184.         throw DOMException(
  185.             DOMException::INVALID_STATE_ERR, 0);
  186.     }
  187.     fEndOffset = offset;
  188. }
  189. void DOMRangeImpl::setStart(const DOMNode* refNode, XMLSize_t offset)
  190. {
  191.     validateNode(refNode);
  192.     checkIndex(refNode, offset);
  193.     // error if not the same owner document
  194.     if (fDocument != refNode->getOwnerDocument()) {
  195.         if ( refNode != fDocument ) {
  196.             collapse(true); //collapse the range positions to start
  197.             fCollapsed = true;
  198.             throw DOMException(
  199.                 DOMException::WRONG_DOCUMENT_ERR, 0);
  200.         }
  201.     }
  202.     fStartContainer = (DOMNode*) refNode;
  203.     fStartOffset    = offset;
  204.     // they may be of same document, but not same root container
  205.     // collapse if not the same root container
  206.     if (!commonAncestorOf(refNode, fEndContainer))
  207.         collapse(true);
  208.     //compare the start and end boundary point
  209.     //collapse if start point is after the end point
  210.     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
  211.         collapse(true); //collapse the range positions to start
  212.     else
  213.         fCollapsed = false;
  214. }
  215. void DOMRangeImpl::setEnd(const DOMNode* refNode, XMLSize_t offset)
  216. {
  217.     validateNode(refNode);
  218.     checkIndex(refNode, offset);
  219.     // error if not the same owner document
  220.     if (fDocument != refNode->getOwnerDocument()) {
  221.         if ( refNode != fDocument ) {
  222.             collapse(false); //collapse the range positions to end
  223.             fCollapsed = true;
  224.             throw DOMException(
  225.                 DOMException::WRONG_DOCUMENT_ERR, 0);
  226.         }
  227.     }
  228.     fEndContainer   = (DOMNode*) refNode;
  229.     fEndOffset      = offset;
  230.     // they may be of same document, but not same root container
  231.     // collapse if not the same root container
  232.     if (!commonAncestorOf(refNode, fStartContainer))
  233.         collapse(false);
  234.     //compare the start and end boundary point
  235.     //collapse if start point is after the end point
  236.     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
  237.         collapse(false); //collapse the range positions to end
  238.     else
  239.         fCollapsed = false;
  240. }
  241. void DOMRangeImpl::setStartBefore(const DOMNode* refNode)
  242. {
  243.     if( fDetached) {
  244.         throw DOMException(
  245.             DOMException::INVALID_STATE_ERR, 0);
  246.     }
  247.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  248.         throw DOMRangeException(
  249.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  250.     }
  251.     // error if not the same owner document
  252.     if (fDocument != refNode->getOwnerDocument()) {
  253.         if ( refNode != fDocument ) {
  254.             collapse(true); //collapse the range positions to start
  255.             fCollapsed = true;
  256.             throw DOMException(
  257.                 DOMException::WRONG_DOCUMENT_ERR, 0);
  258.         }
  259.     }
  260.     fStartContainer = refNode->getParentNode();
  261.    XMLSize_t i = 0;
  262.     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling()) {
  263.         i++;
  264.     }
  265.     if (i == 0)
  266.         fStartOffset = 0;
  267.     else
  268.         fStartOffset = i-1;
  269.     // they may be of same document, but not same root container
  270.     // collapse if not the same root container
  271.     if (!commonAncestorOf(refNode, fEndContainer))
  272.         collapse(true);
  273.     //compare the start and end boundary point
  274.     //collapse if start point is after the end point
  275.     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
  276.         collapse(true); //collapse the range positions to start
  277.     else
  278.         fCollapsed = false;
  279. }
  280. void DOMRangeImpl::setStartAfter(const DOMNode* refNode)
  281. {
  282.     if( fDetached) {
  283.         throw DOMException(
  284.             DOMException::INVALID_STATE_ERR, 0);
  285.     }
  286.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  287.         throw DOMRangeException(
  288.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  289.     }
  290.     // error if not the same owner document
  291.     if (fDocument != refNode->getOwnerDocument()) {
  292.         if ( refNode != fDocument ) {
  293.             collapse(true); //collapse the range positions to start
  294.             fCollapsed = true;
  295.             throw DOMException(
  296.                 DOMException::WRONG_DOCUMENT_ERR, 0);
  297.         }
  298.     }
  299.     fStartContainer = refNode->getParentNode();
  300.     XMLSize_t i = 0;
  301.     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling()) {
  302.         i++;
  303.     }
  304.     fStartOffset = i;
  305.     // they may be of same document, but not same root container
  306.     // collapse if not the same root container
  307.     if (!commonAncestorOf(refNode, fEndContainer))
  308.         collapse(true);
  309.     //compare the start and end boundary point
  310.     //collapse if start point is after the end point
  311.     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
  312.         collapse(true); //collapse the range positions to start
  313.     else
  314.         fCollapsed = false;
  315. }
  316. void DOMRangeImpl::setEndBefore(const DOMNode* refNode)
  317. {
  318.     if( fDetached) {
  319.         throw DOMException(
  320.             DOMException::INVALID_STATE_ERR, 0);
  321.     }
  322.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  323.         throw DOMRangeException(
  324.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  325.     }
  326.     // error if not the same owner document
  327.     if (fDocument != refNode->getOwnerDocument()) {
  328.         if ( refNode != fDocument ) {
  329.             collapse(false); //collapse the range positions to end
  330.             fCollapsed = true;
  331.             throw DOMException(
  332.                 DOMException::WRONG_DOCUMENT_ERR, 0);
  333.         }
  334.     }
  335.     fEndContainer = refNode->getParentNode();
  336.     XMLSize_t i = 0;
  337.     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling(), i++) ;
  338.     if (i< 1)
  339.         fEndOffset = 0;
  340.     else
  341.         fEndOffset = i-1;
  342.     // they may be of same document, but not same root container
  343.     // collapse if not the same root container
  344.     if (!commonAncestorOf(refNode, fStartContainer))
  345.         collapse(false);
  346.     //compare the start and end boundary point
  347.     //collapse if start point is after the end point
  348.     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
  349.         collapse(false); //collapse the range positions to end
  350.     else
  351.         fCollapsed = false;
  352. }
  353. void DOMRangeImpl::setEndAfter(const DOMNode* refNode)
  354. {
  355.     if( fDetached) {
  356.         throw DOMException(
  357.             DOMException::INVALID_STATE_ERR, 0);
  358.     }
  359.     if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) {
  360.         throw DOMRangeException(
  361.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  362.     }
  363.     // error if not the same owner document
  364.     if (fDocument != refNode->getOwnerDocument()) {
  365.         if ( refNode != fDocument ) {
  366.             collapse(false); //collapse the range positions to end
  367.             fCollapsed = true;
  368.             throw DOMException(
  369.                 DOMException::WRONG_DOCUMENT_ERR, 0);
  370.         }
  371.     }
  372.     fEndContainer = refNode->getParentNode();
  373.     XMLSize_t i = 0;
  374.     for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling(), i++) ;
  375.     if (i ==0)
  376.         fEndOffset = 0;
  377.     else
  378.         fEndOffset = i;
  379.     // they may be of same document, but not same root container
  380.     // collapse if not the same root container
  381.     if (!commonAncestorOf(refNode, fStartContainer))
  382.         collapse(false);
  383.     //compare the start and end boundary point
  384.     //collapse if start point is after the end point
  385.     if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1)
  386.         collapse(false); //collapse the range positions to end
  387.     else
  388.         fCollapsed = false;
  389. }
  390. //-------------------------------
  391. // Public Misc. functions
  392. //-------------------------------
  393. void DOMRangeImpl::detach()
  394. {
  395.     if( fDetached) {
  396.         throw DOMException(
  397.             DOMException::INVALID_STATE_ERR, 0);
  398.     }
  399.     ((DOMDocumentImpl *)fDocument)->removeRange(this);
  400.     fDetached = true;
  401.     //0ify nodes
  402.     fStartContainer = 0;
  403.     fStartOffset    = 0;
  404.     fEndContainer   = 0;
  405.     fEndOffset      = 0;
  406.     fCollapsed      = true;
  407.     fRemoveChild    = 0;
  408. }
  409. void DOMRangeImpl::collapse(bool toStart)
  410. {
  411.     if( fDetached) {
  412.         throw DOMException(
  413.             DOMException::INVALID_STATE_ERR, 0);
  414.     }
  415.     if (toStart) {
  416.         fEndContainer = fStartContainer;
  417.         fEndOffset = fStartOffset;
  418.     } else {
  419.         fStartContainer = fEndContainer;
  420.         fStartOffset = fEndOffset;
  421.     }
  422.     fCollapsed = true;
  423. }
  424. void DOMRangeImpl::selectNode(const DOMNode* refNode)
  425. {
  426.     validateNode(refNode);
  427.     if ( !isLegalContainedNode(refNode)) {
  428.         throw DOMRangeException(
  429.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  430.     }
  431.     //First check for the text type node
  432.     short type = refNode->getNodeType();
  433.     if((type == DOMNode::TEXT_NODE
  434.         || type == DOMNode::CDATA_SECTION_NODE
  435.         || type == DOMNode::COMMENT_NODE
  436.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  437.     {
  438.         //The node itself is the container.
  439.         fStartContainer = (DOMNode*) refNode;
  440.         fEndContainer   = (DOMNode*) refNode;
  441.         //Select all the contents of the node
  442.         fStartOffset = 0;
  443.         if (type == DOMNode::PROCESSING_INSTRUCTION_NODE)
  444.             fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)refNode)->getData());
  445.         else
  446.             fEndOffset = ((DOMText *)refNode)->getLength();
  447.         return;
  448.     }
  449.     DOMNode* parent = refNode->getParentNode();
  450.     if (parent != 0 ) // REVIST: what to do if it IS 0?
  451.     {
  452.         fStartContainer = parent;
  453.         fEndContainer = parent;
  454.         XMLSize_t i = 0;
  455.         for (DOMNode* n = parent->getFirstChild(); n!=0 && n!=refNode; n = n->getNextSibling()) {
  456.             i++;
  457.         }
  458.         fStartOffset = i;
  459.         fEndOffset = fStartOffset+1;
  460.     }
  461. }
  462. void DOMRangeImpl::selectNodeContents(const DOMNode* node)
  463. {
  464.     validateNode(node);
  465.     fStartContainer = (DOMNode*) node;
  466.     fEndContainer = (DOMNode*) node;
  467.     fStartOffset = 0;
  468.     short type = node->getNodeType();
  469.     if((type == DOMNode::TEXT_NODE
  470.         || type == DOMNode::CDATA_SECTION_NODE
  471.         || type == DOMNode::COMMENT_NODE)) {
  472.         fEndOffset = ((DOMText *)node)->getLength();
  473.         return;
  474.     }
  475.     if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) {
  476.         fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)node)->getData());
  477.         return;
  478.     }
  479.     DOMNode* first = node->getFirstChild();
  480.     if (first == 0) {
  481.         fEndOffset = 0;
  482.         return;
  483.     }
  484.     XMLSize_t i = 0;
  485.     for (DOMNode* n = first; n!=0; n = n->getNextSibling()) {
  486.         i++;
  487.     }
  488.     fEndOffset = i;
  489. }
  490. void DOMRangeImpl::surroundContents(DOMNode* newParent)
  491. {
  492.     if (newParent==0) return;
  493.     //check for elimination criteria
  494.     if( fDetached) {
  495.         throw DOMException(
  496.             DOMException::INVALID_STATE_ERR, 0);
  497.     }
  498.     if (newParent->getOwnerDocument() !=fDocument) {
  499.         throw DOMException(
  500.             DOMException::WRONG_DOCUMENT_ERR, 0);
  501.     }
  502.     int type = newParent->getNodeType();
  503.     if ( !isLegalContainedNode(newParent)
  504.         || type == DOMNode::DOCUMENT_TYPE_NODE)
  505.     {
  506.         throw DOMRangeException(
  507.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  508.     }
  509.     DOMNode* root = (DOMNode*) getCommonAncestorContainer();
  510.     DOMNode* realStart = fStartContainer;
  511.     DOMNode* realEnd = fEndContainer;
  512.     type = fStartContainer->getNodeType();
  513.     if((type == DOMNode::TEXT_NODE
  514.         || type == DOMNode::CDATA_SECTION_NODE
  515.         || type == DOMNode::COMMENT_NODE
  516.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  517.         realStart = fStartContainer->getParentNode();
  518.     }
  519.     type = fEndContainer->getNodeType();
  520.     if((type == DOMNode::TEXT_NODE
  521.         || type == DOMNode::CDATA_SECTION_NODE
  522.         || type == DOMNode::COMMENT_NODE
  523.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  524.         realEnd = fEndContainer->getParentNode();
  525.     }
  526.     if (realStart != realEnd) {
  527.         throw DOMRangeException(
  528.             DOMRangeException::BAD_BOUNDARYPOINTS_ERR, 0);
  529.     }
  530.     DOMDocumentFragment* frag = (DOMDocumentFragment*) extractContents();
  531.     insertNode(newParent);
  532.     newParent->appendChild(frag);
  533.     selectNode(newParent);
  534. }
  535. short DOMRangeImpl::compareBoundaryPoints(DOMRange::CompareHow how, const DOMRange* srcRange) const
  536. {
  537.     if (fDocument != ((DOMRangeImpl*)srcRange)->fDocument) {
  538.         throw DOMException(
  539.             DOMException::WRONG_DOCUMENT_ERR, 0);
  540.     }
  541.     if( fDetached) {
  542.         throw DOMException(
  543.             DOMException::INVALID_STATE_ERR, 0);
  544.     }
  545.     DOMNode* pointA;
  546.     DOMNode* pointB;
  547.     int offsetA, offsetB;
  548.     switch (how)
  549.     {
  550.     case (DOMRange::START_TO_START) :
  551.         pointB = srcRange->getStartContainer();
  552.         pointA = fStartContainer;
  553.         offsetB = srcRange->getStartOffset();
  554.         offsetA = fStartOffset;
  555.         break;
  556.     case (DOMRange::START_TO_END) :
  557.         pointB = srcRange->getStartContainer();
  558.         pointA = fEndContainer;
  559.         offsetB = srcRange->getStartOffset();
  560.         offsetA = fEndOffset;
  561.         break;
  562.     case (DOMRange::END_TO_START) :
  563.         pointB = srcRange->getEndContainer();
  564.         pointA = fStartContainer;
  565.         offsetB = srcRange->getEndOffset();
  566.         offsetA = fStartOffset;
  567.         break;
  568.     case (DOMRange::END_TO_END) :
  569.         pointB = srcRange->getEndContainer();
  570.         pointA = fEndContainer;
  571.         offsetB = srcRange->getEndOffset();
  572.         offsetA = fEndOffset;
  573.         break;
  574.     }
  575.     // case 1: same container
  576.     if (pointA == pointB) {
  577.         if (offsetA < offsetB) return -1; //A before B
  578.         if (offsetA == offsetB) return 0; //A equal to B
  579.         return 1; // A after B
  580.     }
  581.     // case 2: Child C of container A is ancestor of B
  582.     for (DOMNode* node = pointA->getFirstChild(); node != 0; node=node->getNextSibling()) {
  583.         if (isAncestorOf(node, pointB)) {
  584.             int index = indexOf(node, pointA);
  585.             if (offsetA <=  index) return -1;
  586.             return 1;
  587.         }
  588.     }
  589.     // case 3: Child C of container B is ancestor of A
  590.     for (DOMNode* nd = pointB->getFirstChild(); nd != 0; nd=nd->getNextSibling()) {
  591.         if (isAncestorOf(nd, pointA)) {
  592.             int index = indexOf(nd, pointB);
  593.             if (index < offsetB ) return -1;
  594.             return 1; //B strictly before A
  595.         }
  596.     }
  597.     // case 4: preorder traversal of context tree.
  598.     // Instead of literally walking the context tree in pre-order,
  599.     // we use relative node depth walking which is usually faster
  600.     int depthDiff = 0;
  601.     DOMNode* n = 0;
  602.     for ( n = pointB; n != 0; n = n->getParentNode() )
  603.         depthDiff++;
  604.     for ( n = pointA; n != 0; n = n->getParentNode() )
  605.         depthDiff--;
  606.     while (depthDiff > 0) {
  607.         pointB = pointB->getParentNode();
  608.         depthDiff--;
  609.     }
  610.     while (depthDiff < 0) {
  611.         pointA = pointA->getParentNode();
  612.         depthDiff++;
  613.     }
  614.     for (DOMNode* pB = pointB->getParentNode(),
  615.          *pA = pointA->getParentNode();
  616.          pB != pA;
  617.          pB = pB->getParentNode(), pA = pA->getParentNode() )
  618.     {
  619.         pointB = pB;
  620.         pointA = pA;
  621.     }
  622.     for ( n = pointB->getNextSibling();
  623.          n != 0;
  624.          n = n->getNextSibling() )
  625.     {
  626.         if (n == pointA) {
  627.             return 1;
  628.         }
  629.     }
  630.     return -1;
  631. }
  632. void DOMRangeImpl:: deleteContents()
  633. {
  634.     traverseContents(DELETE_CONTENTS);
  635. }
  636. DOMDocumentFragment* DOMRangeImpl::extractContents()
  637. {
  638.     checkReadOnly(fStartContainer, fEndContainer, fStartOffset, fEndOffset);
  639.     return traverseContents(EXTRACT_CONTENTS);
  640. }
  641. DOMDocumentFragment* DOMRangeImpl::cloneContents() const
  642. {
  643.     // cast off const.
  644.     return ((DOMRangeImpl *)this)->traverseContents(CLONE_CONTENTS);
  645. }
  646. void DOMRangeImpl::insertNode(DOMNode* newNode)
  647. {
  648.     if (newNode == 0) return; //don't have to do anything
  649.     if( fDetached) {
  650.         throw DOMException(
  651.             DOMException::INVALID_STATE_ERR, 0);
  652.     }
  653.     int type = newNode->getNodeType();
  654.     if (type == DOMNode::ATTRIBUTE_NODE
  655.         || type == DOMNode::ENTITY_NODE
  656.         || type == DOMNode::NOTATION_NODE
  657.         || type == DOMNode::DOCUMENT_NODE)
  658.     {
  659.         throw DOMRangeException(
  660.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  661.     }
  662.     // Prevent cycles in the tree.
  663.     //isKidOK() is not checked here as its taken care by insertBefore() function
  664.     if (isAncestorOf( newNode, fStartContainer)) {
  665.         throw DOMException(
  666.             DOMException::HIERARCHY_REQUEST_ERR, 0);
  667.     }
  668.     for (DOMNode* aNode = fStartContainer; aNode!=0; aNode = aNode->getParentNode()) {
  669.         if (castToNodeImpl(newNode)->isReadOnly()) {
  670.         throw DOMException(
  671.             DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  672.     }
  673.     }
  674.     if (fDocument != newNode->getOwnerDocument()) {
  675.         throw DOMException(
  676.             DOMException::WRONG_DOCUMENT_ERR, 0);
  677.     }
  678.     DOMNode* parent;
  679.     DOMNode* next;
  680.     type = fStartContainer->getNodeType();
  681.     if((type == DOMNode::TEXT_NODE
  682.         || type == DOMNode::CDATA_SECTION_NODE
  683.         || type == DOMNode::COMMENT_NODE
  684.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  685.         //set 'parent' and 'next' here
  686.         parent = fStartContainer->getParentNode();
  687.         //split the text nodes
  688.        if (fStartOffset > 0) {
  689.            if (type == DOMNode::COMMENT_NODE)
  690.                ((DOMCommentImpl*)fStartContainer)->splitText(fStartOffset);
  691.            else if (type == DOMNode::PROCESSING_INSTRUCTION_NODE)
  692.                ((DOMProcessingInstructionImpl*)fStartContainer)->splitText(fStartOffset);
  693.            else
  694.                ((DOMText*)fStartContainer)->splitText(fStartOffset);
  695.        }
  696.         //update the new start information later. After inserting the first newNode
  697.         if (fStartOffset == 0)
  698.             next = fStartContainer;
  699.         else
  700.             next = fStartContainer->getNextSibling();
  701.     } // end of text handling
  702.     else {
  703.         parent = fStartContainer;
  704.         next = fStartContainer->getFirstChild();
  705.         for(XMLSize_t i = 0; (i < fStartOffset) && (next != 0); i++) {
  706.             next=next->getNextSibling();
  707.         }
  708.     }
  709.     if (parent != 0) {
  710.         if (next != 0)
  711.             parent->insertBefore(newNode, next);
  712.         else
  713.             parent->appendChild(newNode);
  714.     }
  715. }
  716. DOMRange* DOMRangeImpl::cloneRange() const
  717. {
  718.     if( fDetached) {
  719.         throw DOMException(
  720.             DOMException::INVALID_STATE_ERR, 0);
  721.     }
  722.     DOMRange* range = fDocument->createRange();
  723.     range->setStart(fStartContainer, fStartOffset);
  724.     range->setEnd(fEndContainer, fEndOffset);
  725.     return range;
  726. }
  727. const XMLCh* DOMRangeImpl::toString() const
  728. {
  729.     if( fDetached) {
  730.         throw DOMException(
  731.             DOMException::INVALID_STATE_ERR, 0);
  732.     }
  733.     if ((fStartContainer == fEndContainer) && (fEndOffset == fStartOffset))
  734.         return XMLUni::fgZeroLenString;
  735.     DOMNode* node = fStartContainer;
  736.     DOMNode* stopNode = fEndContainer;
  737.     XMLBuffer retStringBuf(1023, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
  738.     short type = fStartContainer->getNodeType();
  739.     if((type == DOMNode::TEXT_NODE
  740.         || type == DOMNode::CDATA_SECTION_NODE
  741.         || type == DOMNode::COMMENT_NODE
  742.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  743.         if (fStartContainer == fEndContainer) {
  744.             XMLCh* tempString;
  745.             XMLCh temp[4000];
  746.             if ((fEndOffset-fStartOffset) >= 3999)
  747.                 tempString = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  748.                 (
  749.                     (fEndOffset - fStartOffset + 1) * sizeof(XMLCh)
  750.                 );//new XMLCh[fEndOffset-fStartOffset+1];
  751.             else
  752.                 tempString = temp;
  753.             XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, fEndOffset);
  754.             const XMLCh* retString = ((DOMDocumentImpl *)fDocument)->getPooledString(tempString);
  755.             if ((fEndOffset-fStartOffset) >= 3999)
  756.                 XMLPlatformUtils::fgMemoryManager->deallocate(tempString);//delete[] tempString;
  757.             return retString;
  758.         } else {
  759.             XMLSize_t length = XMLString::stringLen(fStartContainer->getNodeValue());
  760.             if (length != fStartOffset) {
  761.                 XMLCh* tempString;
  762.                 XMLCh temp[4000];
  763.                 if ((length - fStartOffset) >= 3999)
  764.                     tempString = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  765.                     (
  766.                         (length - fStartOffset + 1) * sizeof(XMLCh)
  767.                     );//new XMLCh[length - fStartOffset+1];
  768.                 else
  769.                     tempString = temp;
  770.                 XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, length);
  771.                 retStringBuf.append(tempString);
  772.                 if ((length - fStartOffset) >= 3999)
  773.                     XMLPlatformUtils::fgMemoryManager->deallocate(tempString);//delete[] tempString;
  774.             }
  775.             node = nextNode(node, true);
  776.         }
  777.     }else { //fStartContainer is not a TextNode
  778.         node=node->getFirstChild();
  779.         if (fStartOffset>0) { //find a first node within a range, specified by fStartOffset
  780.             XMLSize_t counter = 0;
  781.             while (counter<fStartOffset && node!=0) {
  782.                 node=node->getNextSibling();
  783.                 counter++;
  784.             }
  785.         }
  786.         if (node == 0) {
  787.             node = nextNode(fStartContainer,false);
  788.         }
  789.     }
  790.     type = fEndContainer->getNodeType();
  791.     if((type != DOMNode::TEXT_NODE
  792.         && type != DOMNode::CDATA_SECTION_NODE
  793.         && type != DOMNode::COMMENT_NODE
  794.         && type != DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  795.         int i=fEndOffset;
  796.         stopNode = fEndContainer->getFirstChild();
  797.         while( i>0 && stopNode!=0 ){
  798.             --i;
  799.             stopNode = stopNode->getNextSibling();
  800.         }
  801.         if ( stopNode == 0 )
  802.             stopNode = nextNode( fEndContainer, false );
  803.     }
  804.     while (node != stopNode) {  //look into all kids of the Range
  805.         if (node == 0) break;
  806.         type = node->getNodeType();
  807.         if((type == DOMNode::TEXT_NODE
  808.             || type == DOMNode::CDATA_SECTION_NODE
  809.             || type == DOMNode::COMMENT_NODE
  810.             || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  811.             retStringBuf.append(node->getNodeValue());
  812.         }
  813.         node = nextNode(node, true);
  814.     }
  815.     type = fEndContainer->getNodeType();
  816.     if((type == DOMNode::TEXT_NODE
  817.         || type == DOMNode::CDATA_SECTION_NODE
  818.         || type == DOMNode::COMMENT_NODE
  819.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  820.         if (fEndOffset != 0) {
  821.             XMLCh* tempString;
  822.             XMLCh temp[4000];
  823.             if (fEndOffset >= 3999)
  824.                 tempString = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  825.                 (
  826.                     (fEndOffset+1) * sizeof(XMLCh)
  827.                 );//new XMLCh[fEndOffset+1];
  828.             else
  829.                 tempString = temp;
  830.             XMLString::subString(tempString, fEndContainer->getNodeValue(), 0, fEndOffset);
  831.             retStringBuf.append(tempString);
  832.             if (fEndOffset >= 3999)
  833.                 XMLPlatformUtils::fgMemoryManager->deallocate(tempString);//delete[] tempString;
  834.         }
  835.     }
  836.     return ((DOMDocumentImpl *)fDocument)->getPooledString(retStringBuf.getRawBuffer());
  837. }
  838. DOMDocument* DOMRangeImpl::getDocument()
  839. {
  840.     return fDocument;
  841. }
  842. const DOMNode* DOMRangeImpl::getCommonAncestorContainer() const
  843. {
  844.      return commonAncestorOf(fStartContainer, fEndContainer);
  845. }
  846. void DOMRangeImpl::release()
  847. {
  848.     detach();
  849.     // for performance reason, do not recycle pointer
  850.     // chance that this is allocated again and again is not usual
  851. }
  852. //---------------------
  853. //private functions
  854. //---------------------
  855. bool DOMRangeImpl::isValidAncestorType(const DOMNode* node) const
  856. {
  857.     for (DOMNode* aNode = (DOMNode*) node; aNode!=0; aNode = aNode->getParentNode()) {
  858.         short type = aNode->getNodeType();
  859.         if ( type == DOMNode::ENTITY_NODE
  860.             || type == DOMNode::NOTATION_NODE
  861.             || type == DOMNode::DOCUMENT_TYPE_NODE)
  862.             return false;
  863.     }
  864.     return true;
  865. }
  866. bool DOMRangeImpl::isAncestorOf(const DOMNode* a, const DOMNode* b) {
  867.     for (DOMNode* node = (DOMNode*) b; node != 0; node=node->getParentNode()) {
  868.         if  (node == a) return true;
  869.     }
  870.     return false;
  871. }
  872. bool DOMRangeImpl::hasLegalRootContainer(const DOMNode* node) const {
  873.     if ( node==0 )
  874.         return false;
  875.     DOMNode* rootContainer = (DOMNode*)node;
  876.     for (; rootContainer->getParentNode()!=0; rootContainer = rootContainer->getParentNode())
  877.         ;
  878.     switch( rootContainer->getNodeType() ) {
  879.         case DOMNode::ATTRIBUTE_NODE:
  880.         case DOMNode::DOCUMENT_NODE:
  881.         case DOMNode::DOCUMENT_FRAGMENT_NODE:
  882.         return true;
  883.     }
  884.     return false;
  885. }
  886. bool DOMRangeImpl::isLegalContainedNode(const DOMNode* node ) const {
  887.    if ( node==0 )
  888.        return false;
  889.    switch( node->getNodeType() )
  890.    {
  891.        case DOMNode::DOCUMENT_NODE:
  892.        case DOMNode::DOCUMENT_FRAGMENT_NODE:
  893.        case DOMNode::ATTRIBUTE_NODE:
  894.        case DOMNode::ENTITY_NODE:
  895.        case DOMNode::NOTATION_NODE:
  896.        return false;
  897.    }
  898.    return true;
  899. }
  900. XMLSize_t DOMRangeImpl::indexOf(const DOMNode* child, const DOMNode* parent) const
  901. {
  902.     XMLSize_t i = 0;
  903.     if (child->getParentNode() != parent) return (XMLSize_t)-1;
  904.     for(DOMNode* node = child->getPreviousSibling(); node!= 0; node=node->getPreviousSibling()) {
  905.         i++;
  906.     }
  907.     return i;
  908. }
  909. void DOMRangeImpl::validateNode(const DOMNode* node) const
  910. {
  911.     if( fDetached) {
  912.         throw DOMException(
  913.             DOMException::INVALID_STATE_ERR, 0);
  914.     }
  915.     if ( !isValidAncestorType(node)) {
  916.         throw DOMRangeException(
  917.             DOMRangeException::INVALID_NODE_TYPE_ERR, 0);
  918.     }
  919. }
  920. const DOMNode* DOMRangeImpl::commonAncestorOf(const DOMNode* pointA, const DOMNode* pointB) const
  921. {
  922.     if (fDetached)
  923.             throw DOMException(DOMException::INVALID_STATE_ERR, 0);
  924.     //if the containers are same then it itself is its common ancestor.
  925.     if (pointA == pointB)
  926.         return pointA;
  927.     typedef RefVectorOf<DOMNode> VectorNodes;
  928.     VectorNodes startV(1, false, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
  929.     DOMNode* node;
  930.     for (node=(DOMNode*)pointA; node != 0; node=node->getParentNode())
  931.     {
  932.         startV.addElement(node);
  933.     }
  934.     VectorNodes endV(1, false, ((DOMDocumentImpl *)fDocument)->getMemoryManager());
  935.     for (node=(DOMNode*)pointB; node != 0; node=node->getParentNode())
  936.     {
  937.         endV.addElement(node);
  938.     }
  939.     int s = startV.size()-1;
  940.     int e = endV.size()-1;
  941.     DOMNode* commonAncestor = 0;
  942.     while (s>=0 && e>=0) {
  943.         if (startV.elementAt(s) == endV.elementAt(e)) {
  944.             commonAncestor = startV.elementAt(s);
  945.         }
  946.         else  break;
  947.         --s;
  948.         --e;
  949.     }
  950.     return commonAncestor;
  951. }
  952. void DOMRangeImpl::checkIndex(const DOMNode* node, XMLSize_t offset) const
  953. {
  954.     if (offset < 0) {
  955.         throw DOMException( DOMException::INDEX_SIZE_ERR, 0 );
  956.     }
  957.     short type = node->getNodeType();
  958.     if((type == DOMNode::TEXT_NODE
  959.         || type == DOMNode::CDATA_SECTION_NODE
  960.         || type == DOMNode::COMMENT_NODE
  961.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) {
  962.         if (offset > XMLString::stringLen(node->getNodeValue()))
  963.             throw DOMException( DOMException::INDEX_SIZE_ERR, 0 );
  964.         else  return;
  965.     }
  966.     DOMNode* child = node->getFirstChild();
  967.     XMLSize_t i = 0;
  968.     for (; child != 0; i++) {
  969.         child = child->getNextSibling();
  970.     }
  971.     if (i < offset) {
  972.         throw DOMException( DOMException::INDEX_SIZE_ERR, 0 );
  973.     }
  974. }
  975. DOMNode* DOMRangeImpl::nextNode(const DOMNode* node, bool visitChildren) const
  976. {
  977.     if (node == 0) return 0;
  978.     DOMNode* result;
  979.     if (visitChildren) {
  980.         result = node->getFirstChild();
  981.         if (result != 0) {
  982.             return result;
  983.         }
  984.     }
  985.     // if hasSibling, return sibling
  986.     result = node->getNextSibling();
  987.     if (result != 0) {
  988.         return result;
  989.     }
  990.     // return parent's 1st sibling.
  991.     DOMNode* parent = node->getParentNode();
  992.     while ( (parent != 0) && (parent != fDocument) )
  993.     {
  994.         result = parent->getNextSibling();
  995.         if (result != 0) {
  996.             return result;
  997.         } else {
  998.             parent = parent->getParentNode();
  999.         }
  1000.     }
  1001.     // end of list, return 0
  1002.     return 0;
  1003. }
  1004. /** This is the master routine invoked to visit the nodes
  1005. *   selected by this range.  For each such node, different
  1006. *   actions are taken depending on the value of the TraversalType argument.
  1007. */
  1008. DOMDocumentFragment* DOMRangeImpl::traverseContents(TraversalType how)
  1009. {
  1010.     if (fDetached)
  1011.             throw DOMException(DOMException::INVALID_STATE_ERR, 0);
  1012.     if (fStartContainer == 0 || fEndContainer == 0) {
  1013.         return 0; // REVIST: Throw exception?
  1014.     }
  1015.     /* Traversal is accomplished by first determining the
  1016.        relationship between the endpoints of the range.
  1017.        For each of four significant relationships, we will
  1018.        delegate the traversal call to a method that
  1019.        can make appropriate assumptions.
  1020.     */
  1021.     // case 1: same container
  1022.     if ( fStartContainer == fEndContainer )
  1023.         return traverseSameContainer( how );
  1024.     // case 2: Child C of start container is ancestor of end container
  1025.     // This can be quickly tested by walking the parent chain of
  1026.     // end container
  1027.     int endContainerDepth = 0;
  1028.     for ( DOMNode* c = fEndContainer, *p = c->getParentNode();
  1029.              p != 0;
  1030.              c = p, p = p->getParentNode())
  1031.         {
  1032.             if (p == fStartContainer)
  1033.                 return traverseCommonStartContainer( c, how );
  1034.             ++endContainerDepth;
  1035.         }
  1036.     // case 3: Child C of end container  is ancestor of start container
  1037.     // This can be quickly tested by walking the parent chain of A
  1038.     int startContainerDepth = 0;
  1039.     for ( DOMNode* c2 = fStartContainer, *p2 = c2->getParentNode();
  1040.          p2 != 0;
  1041.          c2 = p2, p2 = p2->getParentNode())
  1042.     {
  1043.         if (p2 == fEndContainer)
  1044.             return traverseCommonEndContainer( c2, how );
  1045.         ++startContainerDepth;
  1046.     }
  1047.     // case 4: There is a common ancestor container.  Find the
  1048.     // ancestor siblings that are children of that container.
  1049.     int depthDiff = startContainerDepth - endContainerDepth;
  1050.     DOMNode* startNode = fStartContainer;
  1051.     while (depthDiff > 0) {
  1052.         startNode = startNode->getParentNode();
  1053.         depthDiff--;
  1054.     }
  1055.     DOMNode* endNode = fEndContainer;
  1056.     while (depthDiff < 0) {
  1057.         endNode = endNode->getParentNode();
  1058.         depthDiff++;
  1059.     }
  1060.     // ascend the ancestor hierarchy until we have a common parent.
  1061.     for( DOMNode* sp = startNode->getParentNode(), *ep = endNode->getParentNode();
  1062.          sp!=ep;
  1063.          sp = sp->getParentNode(), ep = ep->getParentNode() )
  1064.     {
  1065.         startNode = sp;
  1066.         endNode = ep;
  1067.     }
  1068.     return traverseCommonAncestors( startNode, endNode, how );
  1069.     }
  1070. /**
  1071.  * Visits the nodes selected by this range when we know
  1072.  * a-priori that the start and end containers are the same.
  1073.  *
  1074.  */
  1075. DOMDocumentFragment* DOMRangeImpl::traverseSameContainer( int how )
  1076. {
  1077.     DOMDocumentFragment* frag = 0;
  1078.     if ( how!=DELETE_CONTENTS)
  1079.         frag = fDocument->createDocumentFragment();
  1080.     // If selection is empty, just return the fragment
  1081.     if ( fStartOffset==fEndOffset )
  1082.             return frag;
  1083.     DOMNode* current = fStartContainer;
  1084.     DOMNode* cloneCurrent = 0;
  1085.     // Text node needs special case handling
  1086.     short type = fStartContainer->getNodeType();
  1087.     if((type == DOMNode::TEXT_NODE
  1088.         || type == DOMNode::CDATA_SECTION_NODE
  1089.         || type == DOMNode::COMMENT_NODE
  1090.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1091.     {
  1092.         cloneCurrent = fStartContainer->cloneNode(false);
  1093.         if (fEndOffset == fStartOffset) {
  1094.             cloneCurrent->setNodeValue(XMLUni::fgZeroLenString);
  1095.         }
  1096.         else {
  1097.             XMLCh* tempString;
  1098.             XMLCh temp[4000];
  1099.             if (fEndOffset >= 3999)
  1100.                 tempString = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  1101.                 (
  1102.                     (fEndOffset+1) * sizeof(XMLCh)
  1103.                 );//new XMLCh[fEndOffset+1];
  1104.             else
  1105.                 tempString = temp;
  1106.             XMLString::subString(tempString, cloneCurrent->getNodeValue(), fStartOffset, fEndOffset);
  1107.             cloneCurrent->setNodeValue(((DOMDocumentImpl *)fDocument)->getPooledString(tempString));
  1108.             if (fEndOffset >= 3999)
  1109.                 XMLPlatformUtils::fgMemoryManager->deallocate(tempString);//delete[] tempString;
  1110.         }
  1111.         // set the original text node to its new value
  1112.         if ( how != CLONE_CONTENTS ) {
  1113.             if(type == DOMNode::PROCESSING_INSTRUCTION_NODE) {
  1114.                 ((DOMProcessingInstructionImpl*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset);
  1115.             }
  1116.             else
  1117.                 ((DOMCharacterData*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset);
  1118.         }
  1119.         if ( how != DELETE_CONTENTS)
  1120.             frag->appendChild(cloneCurrent);
  1121.     }
  1122.     else {
  1123.         // Copy nodes between the start/end offsets.
  1124.         DOMNode* n = getSelectedNode( fStartContainer, fStartOffset );
  1125.         int cnt = fEndOffset - fStartOffset;
  1126.         while( cnt > 0 && n)
  1127.         {
  1128.             DOMNode* sibling = n->getNextSibling();
  1129.             DOMNode* xferNode = traverseFullySelected( n, how );
  1130.             if ( frag!=0 )
  1131.                 frag->appendChild( xferNode );
  1132.             --cnt;
  1133.             n = sibling;
  1134.         }
  1135.     }
  1136.     // Nothing is partially selected, so collapse to start point
  1137.     if ( how != CLONE_CONTENTS )
  1138.             collapse(true);
  1139.     return frag;
  1140. }
  1141. /**
  1142.  * Visits the nodes selected by this range when we know
  1143.  * a-priori that the start and end containers are not the
  1144.  * same, but the start container is an ancestor of the end container
  1145.  *
  1146.  */
  1147. DOMDocumentFragment* DOMRangeImpl::traverseCommonStartContainer( DOMNode*endAncestor, int how )
  1148. {
  1149.     DOMDocumentFragment* frag = 0;
  1150.     if ( how!=DELETE_CONTENTS)
  1151.         frag = fDocument->createDocumentFragment();
  1152.     DOMNode*n = traverseRightBoundary( endAncestor, how );
  1153.     if ( frag!=0 )
  1154.         frag->appendChild( n );
  1155.     int endIdx = indexOf( endAncestor, fStartContainer );
  1156.     int cnt = endIdx - fStartOffset;
  1157.     if ( cnt <=0 )
  1158.     {
  1159.         // Collapse to just before the endAncestor, which
  1160.         // is partially selected.
  1161.         if ( how != CLONE_CONTENTS )
  1162.         {
  1163.             setEndBefore( endAncestor );
  1164.             collapse( false );
  1165.         }
  1166.         return frag;
  1167.     }
  1168.     n = endAncestor->getPreviousSibling();
  1169.     while( cnt > 0 )
  1170.     {
  1171.         DOMNode* sibling = n->getPreviousSibling();
  1172.         DOMNode* xferNode = traverseFullySelected( n, how );
  1173.         if ( frag!=0 )
  1174.             frag->insertBefore( xferNode, frag->getFirstChild() );
  1175.         --cnt;
  1176.         n = sibling;
  1177.     }
  1178.     // Collapse to just before the endAncestor, which
  1179.     // is partially selected.
  1180.     if ( how != CLONE_CONTENTS )
  1181.     {
  1182.         setEndBefore( endAncestor );
  1183.         collapse( false );
  1184.     }
  1185.     return frag;
  1186. }
  1187. /**
  1188.  * Visits the nodes selected by this range when we know
  1189.  * a-priori that the start and end containers are not the
  1190.  * same, but the end container is an ancestor of the start container
  1191.  *
  1192.  */
  1193. DOMDocumentFragment* DOMRangeImpl::traverseCommonEndContainer( DOMNode*startAncestor, int how )
  1194. {
  1195.     DOMDocumentFragment* frag = 0;
  1196.     if ( how!=DELETE_CONTENTS)
  1197.         frag = fDocument->createDocumentFragment();
  1198.     DOMNode* n = traverseLeftBoundary( startAncestor, how );
  1199.     if ( frag!=0 )
  1200.         frag->appendChild( n );
  1201.     int startIdx = indexOf( startAncestor, fEndContainer );
  1202.     ++startIdx;  // Because we already traversed it....
  1203.     int cnt = fEndOffset - startIdx;
  1204.     n = startAncestor->getNextSibling();
  1205.     while( cnt > 0 )
  1206.     {
  1207.         DOMNode* sibling = n->getNextSibling();
  1208.         DOMNode* xferNode = traverseFullySelected( n, how );
  1209.         if ( frag!=0 )
  1210.             frag->appendChild( xferNode );
  1211.         --cnt;
  1212.         n = sibling;
  1213.     }
  1214.     if ( how != CLONE_CONTENTS )
  1215.     {
  1216.         setStartAfter( startAncestor );
  1217.         collapse( true );
  1218.     }
  1219.     return frag;
  1220. }
  1221. /**
  1222.  * Visits the nodes selected by this range when we know
  1223.  * a-priori that the start and end containers are not
  1224.  * the same, and we also know that neither the start
  1225.  * nor end container is an ancestor of the other.
  1226.  */
  1227. DOMDocumentFragment* DOMRangeImpl::traverseCommonAncestors( DOMNode*startAncestor, DOMNode*endAncestor, int how )
  1228. {
  1229.     DOMDocumentFragment* frag = 0;
  1230.     if ( how!=DELETE_CONTENTS)
  1231.         frag = fDocument->createDocumentFragment();
  1232.     DOMNode*n = traverseLeftBoundary( startAncestor, how );
  1233.     if ( frag!=0 )
  1234.         frag->appendChild( n );
  1235.     DOMNode*commonParent = startAncestor->getParentNode();
  1236.     int startOffset = indexOf( startAncestor, commonParent );
  1237.     int endOffset = indexOf( endAncestor, commonParent );
  1238.     ++startOffset;
  1239.     int cnt = endOffset - startOffset;
  1240.     DOMNode* sibling = startAncestor->getNextSibling();
  1241.     while( cnt > 0 )
  1242.     {
  1243.         DOMNode* nextSibling = sibling->getNextSibling();
  1244.         n = traverseFullySelected( sibling, how );
  1245.         if ( frag!=0 )
  1246.             frag->appendChild( n );
  1247.         sibling = nextSibling;
  1248.         --cnt;
  1249.     }
  1250.     n = traverseRightBoundary( endAncestor, how );
  1251.     if ( frag!=0 )
  1252.         frag->appendChild( n );
  1253.     if ( how != CLONE_CONTENTS )
  1254.     {
  1255.         setStartAfter( startAncestor );
  1256.         collapse( true );
  1257.     }
  1258.     return frag;
  1259. }
  1260. /**
  1261.  * Traverses the "right boundary" of this range and
  1262.  * operates on each "boundary node" according to the
  1263.  * how parameter.  It is a-priori assumed
  1264.  * by this method that the right boundary does
  1265.  * not contain the range's start container.
  1266.  *
  1267.  * A "right boundary" is best visualized by thinking
  1268.  * of a sample tree:
  1269.  *                 A
  1270.  *                /|
  1271.  *               / | 
  1272.  *              /  |  
  1273.  *             B   C   D
  1274.  *            /|     /|
  1275.  *           E F G   H I J
  1276.  *
  1277.  * Imagine first a range that begins between the
  1278.  * "E" and "F" nodes and ends between the
  1279.  * "I" and "J" nodes.  The start container is
  1280.  * "B" and the end container is "D".  Given this setup,
  1281.  * the following applies:
  1282.  *
  1283.  * Partially Selected Nodes: B, D<br>
  1284.  * Fully Selected Nodes: F, G, C, H, I
  1285.  *
  1286.  * The "right boundary" is the highest subtree node
  1287.  * that contains the ending container.  The root of
  1288.  * this subtree is always partially selected.
  1289.  *
  1290.  * In this example, the nodes that are traversed
  1291.  * as "right boundary" nodes are: H, I, and D.
  1292.  *
  1293.  */
  1294. DOMNode* DOMRangeImpl::traverseRightBoundary( DOMNode*root, int how )
  1295. {
  1296.     DOMNode*next = getSelectedNode( fEndContainer, fEndOffset-1 );
  1297.     bool isFullySelected = ( next!=fEndContainer );
  1298.     if ( next==root )
  1299.         return traverseNode( next, isFullySelected, false, how );
  1300.     DOMNode*parent = next->getParentNode();
  1301.     DOMNode*clonedParent = traverseNode( parent, false, false, how );
  1302.     while( parent!=0 )
  1303.     {
  1304.         while( next!=0 )
  1305.         {
  1306.             DOMNode* prevSibling = next->getPreviousSibling();
  1307.             DOMNode* clonedChild =
  1308.                 traverseNode( next, isFullySelected, false, how );
  1309.             if ( how!=DELETE_CONTENTS )
  1310.             {
  1311.                 clonedParent->insertBefore(
  1312.                     clonedChild,
  1313.                     clonedParent->getFirstChild()
  1314.                 );
  1315.             }
  1316.             isFullySelected = true;
  1317.             next = prevSibling;
  1318.         }
  1319.         if ( parent==root )
  1320.             return clonedParent;
  1321.         next = parent->getPreviousSibling();
  1322.         parent = parent->getParentNode();
  1323.         DOMNode* clonedGrandParent = traverseNode( parent, false, false, how );
  1324.         if ( how!=DELETE_CONTENTS )
  1325.             clonedGrandParent->appendChild( clonedParent );
  1326.         clonedParent = clonedGrandParent;
  1327.     }
  1328.     // should never occur
  1329.     return 0;
  1330. }
  1331. /**
  1332.  * Traverses the "left boundary" of this range and
  1333.  * operates on each "boundary node" according to the
  1334.  * how parameter.  It is a-priori assumed
  1335.  * by this method that the left boundary does
  1336.  * not contain the range's end container.
  1337.  *
  1338.  * A "left boundary" is best visualized by thinking
  1339.  * of a sample tree:
  1340.  *
  1341.  *                 A
  1342.  *                /|
  1343.  *               / | 
  1344.  *              /  |  
  1345.  *             B   C   D
  1346.  *            /|     /|
  1347.  *           E F G   H I J
  1348.  *
  1349.  * Imagine first a range that begins between the
  1350.  * "E" and "F" nodes and ends between the
  1351.  * "I" and "J" nodes.  The start container is
  1352.  * "B" and the end container is "D".  Given this setup,
  1353.  * the following applies:
  1354.  *
  1355.  * Partially Selected Nodes: B, D<br>
  1356.  * Fully Selected Nodes: F, G, C, H, I
  1357.  *
  1358.  * The "left boundary" is the highest subtree node
  1359.  * that contains the starting container.  The root of
  1360.  * this subtree is always partially selected.
  1361.  *
  1362.  * In this example, the nodes that are traversed
  1363.  * as "left boundary" nodes are: F, G, and B.
  1364.  *
  1365.  */
  1366. DOMNode* DOMRangeImpl::traverseLeftBoundary( DOMNode*root, int how )
  1367. {
  1368.     DOMNode*next = getSelectedNode( getStartContainer(), getStartOffset() );
  1369.     bool isFullySelected = ( next!=getStartContainer() );
  1370.     if ( next==root )
  1371.         return traverseNode( next, isFullySelected, true, how );
  1372.     DOMNode* parent = next->getParentNode();
  1373.     DOMNode* clonedParent = traverseNode( parent, false, true, how );
  1374.     while( parent!=0 )
  1375.     {
  1376.         while( next!=0 )
  1377.         {
  1378.             DOMNode* nextSibling = next->getNextSibling();
  1379.             DOMNode* clonedChild =
  1380.                 traverseNode( next, isFullySelected, true, how );
  1381.             if ( how!=DELETE_CONTENTS )
  1382.                 clonedParent->appendChild(clonedChild);
  1383.             isFullySelected = true;
  1384.             next = nextSibling;
  1385.         }
  1386.         if ( parent==root )
  1387.             return clonedParent;
  1388.         next = parent->getNextSibling();
  1389.         parent = parent->getParentNode();
  1390.         DOMNode* clonedGrandParent = traverseNode( parent, false, true, how );
  1391.         if ( how!=DELETE_CONTENTS )
  1392.             clonedGrandParent->appendChild( clonedParent );
  1393.         clonedParent = clonedGrandParent;
  1394.     }
  1395.     // should never occur
  1396.     return 0;
  1397. }
  1398. /**
  1399.  * Utility method for traversing a single node.
  1400.  * Does not properly handle a text node containing both the
  1401.  * start and end offsets.  Such nodes should
  1402.  * have been previously detected and been routed to traverseTextNode.
  1403.  *
  1404.  */
  1405. DOMNode* DOMRangeImpl::traverseNode( DOMNode* n, bool isFullySelected, bool isLeft, int how )
  1406. {
  1407.     if ( isFullySelected )
  1408.         return traverseFullySelected( n, how );
  1409.     short type = n->getNodeType();
  1410.     if((type == DOMNode::TEXT_NODE
  1411.         || type == DOMNode::CDATA_SECTION_NODE
  1412.         || type == DOMNode::COMMENT_NODE
  1413.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1414.         return traverseTextNode( n, isLeft, how );
  1415.     return traversePartiallySelected( n, how );
  1416. }
  1417. /**
  1418.  * Utility method for traversing a single node when
  1419.  * we know a-priori that the node if fully
  1420.  * selected.
  1421.  *
  1422.  */
  1423. DOMNode* DOMRangeImpl::traverseFullySelected( DOMNode* n, int how )
  1424. {
  1425.     switch( how )
  1426.     {
  1427.     case CLONE_CONTENTS:
  1428.         return n->cloneNode( true );
  1429.     case EXTRACT_CONTENTS:
  1430.         return n;
  1431.     case DELETE_CONTENTS:
  1432.         // revisit:
  1433.         //   should I release the removed node?
  1434.         //   not released in case user still referencing it externally
  1435.         n->getParentNode()->removeChild(n);
  1436.         return 0;
  1437.     }
  1438.     return 0;
  1439. }
  1440. /**
  1441.  * Utility method for traversing a single node when
  1442.  * we know a-priori that the node if partially
  1443.  * selected and is not a text node.
  1444.  *
  1445.  */
  1446. DOMNode* DOMRangeImpl::traversePartiallySelected( DOMNode*n, int how )
  1447. {
  1448.     switch( how )
  1449.     {
  1450.     case DELETE_CONTENTS:
  1451.         return 0;
  1452.     case CLONE_CONTENTS:
  1453.     case EXTRACT_CONTENTS:
  1454.         return n->cloneNode( false );
  1455.     }
  1456.     return 0;
  1457. }
  1458. /**
  1459.  * Utility method for traversing a text node that we know
  1460.  * a-priori to be on a left or right boundary of the range.
  1461.  * This method does not properly handle text nodes that contain
  1462.  * both the start and end points of the range.
  1463.  *
  1464.  */
  1465. DOMNode* DOMRangeImpl::traverseTextNode( DOMNode*n, bool isLeft, int how )
  1466. {
  1467.     XMLCh* txtValue = XMLString::replicate(n->getNodeValue());
  1468.     ArrayJanitor<XMLCh> janValue(txtValue);
  1469.     if ( isLeft )
  1470.     {
  1471.         int startLen = XMLString::stringLen(fStartContainer->getNodeValue());
  1472.         int offset = getStartOffset();
  1473.         if (offset == 0) {
  1474.             if ( how != CLONE_CONTENTS )
  1475.                 n->setNodeValue(XMLUni::fgZeroLenString);
  1476.         }
  1477.         else {
  1478.             XMLCh* oldNodeValue;
  1479.             XMLCh oldTemp[4000];
  1480.             if (offset >= 3999)  {
  1481.                 oldNodeValue = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  1482.                 (
  1483.                     (offset+1) * sizeof(XMLCh)
  1484.                 );//new XMLCh[offset+1];
  1485.             }
  1486.             else {
  1487.                 oldNodeValue = oldTemp;
  1488.             }
  1489.             XMLString::subString(oldNodeValue, txtValue, 0, offset);
  1490.             if ( how != CLONE_CONTENTS )
  1491.                 n->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(oldNodeValue) );
  1492.             if (offset>= 3999)
  1493.                 XMLPlatformUtils::fgMemoryManager->deallocate(oldNodeValue);//delete[] oldNodeValue;
  1494.         }
  1495.         if ( how==DELETE_CONTENTS )
  1496.             return 0;
  1497.         DOMNode* newNode = n->cloneNode( false );
  1498.         if (startLen == offset) {
  1499.             newNode->setNodeValue(XMLUni::fgZeroLenString);
  1500.         }
  1501.         else {
  1502.             XMLCh* newNodeValue;
  1503.             XMLCh newTemp[4000];
  1504.             if (offset >= 3999)  {
  1505.                 newNodeValue = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  1506.                 (
  1507.                     (offset+1) * sizeof(XMLCh)
  1508.                 );//new XMLCh[offset+1];
  1509.             }
  1510.             else {
  1511.                 newNodeValue = newTemp;
  1512.             }
  1513.             XMLString::subString(newNodeValue, txtValue, offset, startLen);
  1514.             newNode->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(newNodeValue) );
  1515.             if (offset>= 3999)
  1516.                 XMLPlatformUtils::fgMemoryManager->deallocate(newNodeValue);//delete[] newNodeValue;
  1517.         }
  1518.         return newNode;
  1519.     }
  1520.     else
  1521.     {
  1522.         int endLen = XMLString::stringLen(fEndContainer->getNodeValue());
  1523.         int offset = getEndOffset();
  1524.         if (endLen == offset) {
  1525.             if ( how != CLONE_CONTENTS )
  1526.                 n->setNodeValue(XMLUni::fgZeroLenString);
  1527.         }
  1528.         else {
  1529.             XMLCh* oldNodeValue;
  1530.             XMLCh oldTemp[4000];
  1531.             if (offset >= 3999)  {
  1532.                 oldNodeValue = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  1533.                 (
  1534.                     (offset+1) * sizeof(XMLCh)
  1535.                 );//new XMLCh[offset+1];
  1536.             }
  1537.             else {
  1538.                 oldNodeValue = oldTemp;
  1539.             }
  1540.             XMLString::subString(oldNodeValue, txtValue, offset, endLen);
  1541.             if ( how != CLONE_CONTENTS )
  1542.                 n->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(oldNodeValue) );
  1543.             if (offset>= 3999)
  1544.                 XMLPlatformUtils::fgMemoryManager->deallocate(oldNodeValue);//delete[] oldNodeValue;
  1545.         }
  1546.         if ( how==DELETE_CONTENTS )
  1547.             return 0;
  1548.         DOMNode* newNode = n->cloneNode( false );
  1549.         if (offset == 0) {
  1550.             newNode->setNodeValue(XMLUni::fgZeroLenString);
  1551.         }
  1552.         else {
  1553.             XMLCh* newNodeValue;
  1554.             XMLCh newTemp[4000];
  1555.             if (offset >= 3999)  {
  1556.                 newNodeValue = (XMLCh*) XMLPlatformUtils::fgMemoryManager->allocate
  1557.                 (
  1558.                     (offset+1) * sizeof(XMLCh)
  1559.                 );//new XMLCh[offset+1];
  1560.             }
  1561.             else {
  1562.                 newNodeValue = newTemp;
  1563.             }
  1564.             XMLString::subString(newNodeValue, txtValue, 0, offset);
  1565.             newNode->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(newNodeValue) );
  1566.             if (offset>= 3999)
  1567.                 XMLPlatformUtils::fgMemoryManager->deallocate(newNodeValue);//delete[] newNodeValue;
  1568.         }
  1569.         return newNode;
  1570.     }
  1571. }
  1572. /**
  1573.  * Utility method to retrieve a child node by index.  This method
  1574.  * assumes the caller is trying to find out which node is
  1575.  * selected by the given index.  Note that if the index is
  1576.  * greater than the number of children, this implies that the
  1577.  * first node selected is the parent node itself.
  1578.  *
  1579.  */
  1580. DOMNode* DOMRangeImpl::getSelectedNode( DOMNode*container, int offset )
  1581. {
  1582.     short type = container->getNodeType();
  1583.     if((type == DOMNode::TEXT_NODE
  1584.         || type == DOMNode::CDATA_SECTION_NODE
  1585.         || type == DOMNode::COMMENT_NODE
  1586.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1587.         return container;
  1588.     // This case is an important convenience for
  1589.     // traverseRightBoundary()
  1590.     if ( offset<0 )
  1591.         return container;
  1592.     DOMNode*child = container->getFirstChild();
  1593.     while( child!=0 && offset > 0 )
  1594.     {
  1595.         --offset;
  1596.         child = child->getNextSibling();
  1597.     }
  1598.     if ( child!=0 )
  1599.         return child;
  1600.     return container;
  1601. }
  1602. void DOMRangeImpl::checkReadOnly(DOMNode* start, DOMNode* end,
  1603.                               XMLSize_t startOffset, XMLSize_t endOffset)
  1604. {
  1605.     if ((start == 0) || (end == 0) ) return;
  1606.     DOMNode*sNode = 0;
  1607.     short type = start->getNodeType();
  1608.     if ( type == DOMNode::DOCUMENT_TYPE_NODE )
  1609.     {
  1610.         throw DOMException(
  1611.             DOMException::HIERARCHY_REQUEST_ERR, 0);
  1612.     }
  1613.     if((type == DOMNode::TEXT_NODE
  1614.         || type == DOMNode::CDATA_SECTION_NODE
  1615.         || type == DOMNode::COMMENT_NODE
  1616.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1617.     {
  1618.         if (castToNodeImpl(start)->isReadOnly()) {
  1619.             throw DOMException(
  1620.                 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  1621.         }
  1622.         //if both start and end are text check and return
  1623.         if (start == end)
  1624.             return;
  1625.         sNode = start;
  1626.     } else {
  1627.         //set the start and end nodes to check
  1628.         sNode = start->getFirstChild();
  1629.         for(XMLSize_t i = 0; i<startOffset; i++)
  1630.             sNode = sNode->getNextSibling();
  1631.     }
  1632.     DOMNode* eNode;
  1633.     type = end->getNodeType();
  1634.     if ( type == DOMNode::DOCUMENT_TYPE_NODE )
  1635.     {
  1636.         throw DOMException(
  1637.             DOMException::HIERARCHY_REQUEST_ERR, 0);
  1638.     }
  1639.     if((type == DOMNode::TEXT_NODE
  1640.         || type == DOMNode::CDATA_SECTION_NODE
  1641.         || type == DOMNode::COMMENT_NODE
  1642.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1643.     {
  1644.         eNode = end; //need to check only till this node
  1645.     }
  1646.     else { //need to check all the kids that fall before the end offset value
  1647.         eNode = end->getFirstChild();
  1648.         if (endOffset > 0)  {
  1649.             for (XMLSize_t i = 0; i<endOffset-1; i++)
  1650.                 eNode = eNode->getNextSibling();
  1651.         }
  1652.     }
  1653.     //recursivly search if any node is readonly
  1654.     recurseTreeAndCheck(sNode, eNode);
  1655. }
  1656. void DOMRangeImpl::recurseTreeAndCheck(DOMNode* start, DOMNode* end)
  1657. {
  1658.     for(DOMNode* node=start; node != 0 && node !=end; node=node->getNextSibling())
  1659.     {
  1660.         if ( node->getNodeType()== DOMNode::DOCUMENT_TYPE_NODE )
  1661.         {
  1662.             throw DOMException(
  1663.                 DOMException::HIERARCHY_REQUEST_ERR, 0);
  1664.         }
  1665.         if (castToNodeImpl(node)->isReadOnly()) {
  1666.             throw DOMException(
  1667.                 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0);
  1668.         }
  1669.         if (node->hasChildNodes()) {
  1670.             node = node->getFirstChild();
  1671.             recurseTreeAndCheck(node, end);
  1672.         }
  1673.     }
  1674. }
  1675. DOMNode* DOMRangeImpl::removeChild(DOMNode* parent, DOMNode* child)
  1676. {
  1677.     fRemoveChild = child; //only a precaution measure not to update this range data before removal
  1678.     DOMNode*n = parent->removeChild(child);
  1679.     fRemoveChild = 0;
  1680.     return n;
  1681. }
  1682. //
  1683. // Mutation functions
  1684. //
  1685. /* This function is called from DOM.
  1686. *  The  text has already been replaced.
  1687. *  Fix-up any offsets.
  1688. */
  1689. void DOMRangeImpl::receiveReplacedText(DOMNode* node)
  1690. {
  1691.     if (node == 0) return;
  1692.     short type = fStartContainer->getNodeType();
  1693.     if (node == fStartContainer
  1694.         && (type == DOMNode::TEXT_NODE
  1695.         || type == DOMNode::CDATA_SECTION_NODE
  1696.         || type == DOMNode::COMMENT_NODE
  1697.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1698.     {
  1699.         fStartOffset = 0;
  1700.     }
  1701.     type = fEndContainer->getNodeType();
  1702.     if (node == fEndContainer
  1703.         && (type == DOMNode::TEXT_NODE
  1704.         || type == DOMNode::CDATA_SECTION_NODE
  1705.         || type == DOMNode::COMMENT_NODE
  1706.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1707.     {
  1708.         fEndOffset = 0;
  1709.     }
  1710. }
  1711. /** This function is called from DOM.
  1712. *  The  text has already been deleted.
  1713. *  Fix-up any offsets.
  1714. */
  1715. void DOMRangeImpl::updateRangeForDeletedText(DOMNode* node, XMLSize_t offset, int count)
  1716. {
  1717.     if (node == 0) return;
  1718.     short type = fStartContainer->getNodeType();
  1719.     if (node == fStartContainer
  1720.         && (type == DOMNode::TEXT_NODE
  1721.         || type == DOMNode::CDATA_SECTION_NODE
  1722.         || type == DOMNode::COMMENT_NODE
  1723.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1724.     {
  1725.         if (fStartOffset > offset+count) {
  1726.             fStartOffset = fStartOffset-count;
  1727.         } else if (fStartOffset > offset) {
  1728.             fStartOffset = offset;
  1729.         }
  1730.     }
  1731.     type = fEndContainer->getNodeType();
  1732.     if (node == fEndContainer
  1733.         && (type == DOMNode::TEXT_NODE
  1734.         || type == DOMNode::CDATA_SECTION_NODE
  1735.         || type == DOMNode::COMMENT_NODE
  1736.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1737.     {
  1738.         if (fEndOffset > offset+count) {
  1739.             fEndOffset = fEndOffset-count;
  1740.         } else if (fEndOffset > offset) {
  1741.             fEndOffset = offset;
  1742.         }
  1743.     }
  1744. }
  1745. /** This function is called from DOM.
  1746. *  The  text has already beeen inserted.
  1747. *  Fix-up any offsets.
  1748. */
  1749. void DOMRangeImpl::updateRangeForInsertedText(DOMNode* node, XMLSize_t offset, int count)
  1750. {
  1751.     if (node == 0) return;
  1752.     short type = fStartContainer->getNodeType();
  1753.     if (node == fStartContainer
  1754.         && (type == DOMNode::TEXT_NODE
  1755.         || type == DOMNode::CDATA_SECTION_NODE
  1756.         || type == DOMNode::COMMENT_NODE
  1757.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1758.     {
  1759.         if (fStartOffset > offset) {
  1760.             fStartOffset = offset;
  1761.         }
  1762.     }
  1763.     type = fEndContainer->getNodeType();
  1764.     if (node == fEndContainer
  1765.         && (type == DOMNode::TEXT_NODE
  1766.         || type == DOMNode::CDATA_SECTION_NODE
  1767.         || type == DOMNode::COMMENT_NODE
  1768.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1769.     {
  1770.         if (fEndOffset > offset) {
  1771.             fEndOffset = fEndOffset+count;
  1772.         }
  1773.     }
  1774. }
  1775. /** This function must be called by the DOM _BEFORE_
  1776. *  a node is deleted, because at that time it is
  1777. *  connected in the DOM tree, which we depend on.
  1778. */
  1779. void DOMRangeImpl::updateRangeForDeletedNode(DOMNode* node)
  1780. {
  1781.     if (node == 0) return;
  1782.     if (fRemoveChild == node) return;
  1783.     if (node->getParentNode() == fStartContainer) {
  1784.         XMLSize_t index = indexOf(node, fStartContainer);
  1785.         if ( fStartOffset > index) {
  1786.             fStartOffset--;
  1787.         }
  1788.     }
  1789.     if (node->getParentNode() == fEndContainer) {
  1790.         XMLSize_t index = indexOf(node, fEndContainer);
  1791.         if ( fEndOffset > index) {
  1792.             fEndOffset--;
  1793.         }
  1794.     }
  1795.     if (node->getParentNode() != fStartContainer
  1796.         ||  node->getParentNode() != fEndContainer) {
  1797.         if (isAncestorOf(node, fStartContainer)) {
  1798.             DOMNode* tpNode = node->getParentNode();
  1799.             setStartContainer( tpNode );
  1800.             fStartOffset = indexOf( node, tpNode);
  1801.         }
  1802.         if (isAncestorOf(node, fEndContainer)) {
  1803.             DOMNode* tpNode = node->getParentNode();
  1804.             setEndContainer( tpNode );
  1805.             fEndOffset = indexOf( node, tpNode);
  1806.         }
  1807.     }
  1808. }
  1809. void DOMRangeImpl::updateRangeForInsertedNode(DOMNode* node) {
  1810.     if (node == 0) return;
  1811.     if (node->getParentNode() == fStartContainer) {
  1812.         XMLSize_t index = indexOf(node, fStartContainer);
  1813.         if (index < fStartOffset) {
  1814.             fStartOffset++;
  1815.         }
  1816.     }
  1817.     if (node->getParentNode() == fEndContainer) {
  1818.         XMLSize_t index = indexOf(node, fEndContainer);
  1819.         if (index < fEndOffset) {
  1820.             fEndOffset++;
  1821.         }
  1822.     }
  1823. }
  1824. void DOMRangeImpl::updateSplitInfo(DOMNode* oldNode, DOMNode* startNode, XMLSize_t offset)
  1825. {
  1826.     if (startNode == 0) return;
  1827.     short type = fStartContainer->getNodeType();
  1828.     if (oldNode == fStartContainer
  1829.         && (type == DOMNode::TEXT_NODE
  1830.         || type == DOMNode::CDATA_SECTION_NODE
  1831.         || type == DOMNode::COMMENT_NODE
  1832.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1833.     {
  1834.         if (fStartOffset > offset) {
  1835.             fStartOffset = fStartOffset - offset;
  1836.             fStartContainer = startNode;
  1837.         }
  1838.     }
  1839.     type = fEndContainer->getNodeType();
  1840.     if (oldNode == fEndContainer
  1841.         && (type == DOMNode::TEXT_NODE
  1842.         || type == DOMNode::CDATA_SECTION_NODE
  1843.         || type == DOMNode::COMMENT_NODE
  1844.         || type == DOMNode::PROCESSING_INSTRUCTION_NODE))
  1845.     {
  1846.         if (fEndOffset > offset) {
  1847.             fEndContainer = startNode;
  1848.            fEndOffset = fEndOffset - offset;
  1849.         }
  1850.     }
  1851. }
  1852. XERCES_CPP_NAMESPACE_END