GME
13
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one or more 00003 * contributor license agreements. See the NOTICE file distributed with 00004 * this work for additional information regarding copyright ownership. 00005 * The ASF licenses this file to You under the Apache License, Version 2.0 00006 * (the "License"); you may not use this file except in compliance with 00007 * the License. You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* 00019 * $Id: DOMRangeImpl.cpp 676911 2008-07-15 13:27:32Z amassari $ 00020 */ 00021 00022 #include "DOMRangeImpl.hpp" 00023 #include "DOMDocumentImpl.hpp" 00024 #include "DOMDocumentFragmentImpl.hpp" 00025 #include "DOMCommentImpl.hpp" 00026 #include "DOMProcessingInstructionImpl.hpp" 00027 #include "DOMCasts.hpp" 00028 00029 #include <xercesc/dom/DOMException.hpp> 00030 #include <xercesc/dom/DOMDocument.hpp> 00031 #include <xercesc/dom/DOMRangeException.hpp> 00032 #include <xercesc/dom/DOMText.hpp> 00033 #include <xercesc/dom/DOMProcessingInstruction.hpp> 00034 00035 #include <xercesc/framework/XMLBuffer.hpp> 00036 #include <xercesc/util/Janitor.hpp> 00037 00038 XERCES_CPP_NAMESPACE_BEGIN 00039 00040 00041 //--------------------- 00042 // C'tor and D'tor 00043 //--------------------- 00044 00045 DOMRangeImpl::DOMRangeImpl(DOMDocument* doc, MemoryManager* const manager) 00046 00047 : fStartContainer(doc), 00048 fStartOffset(0), 00049 fEndContainer(doc), 00050 fEndOffset(0), 00051 fCollapsed(true), 00052 fDocument(doc), 00053 fDetached(false), 00054 fRemoveChild(0), 00055 fMemoryManager(manager) 00056 { 00057 } 00058 00059 DOMRangeImpl::DOMRangeImpl(const DOMRangeImpl& other) 00060 : DOMRange(other), 00061 fStartContainer(other.fStartContainer), 00062 fStartOffset(other.fStartOffset), 00063 fEndContainer(other.fEndContainer), 00064 fEndOffset(other.fEndOffset), 00065 fCollapsed(other.fCollapsed), 00066 fDocument(other.fDocument), 00067 fDetached(other.fDetached), 00068 fRemoveChild(other.fRemoveChild), 00069 fMemoryManager(other.fMemoryManager) 00070 { 00071 } 00072 00073 DOMRangeImpl::~DOMRangeImpl() 00074 { 00075 } 00076 00077 00078 //------------------------------- 00079 // Public getter functions 00080 //------------------------------- 00081 00082 00083 DOMNode* DOMRangeImpl::getStartContainer() const 00084 { 00085 if (fDetached) 00086 { 00087 throw DOMException( 00088 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00089 } 00090 00091 return fStartContainer; 00092 } 00093 00094 XMLSize_t DOMRangeImpl::getStartOffset() const 00095 { 00096 if (fDetached) 00097 { 00098 throw DOMException( 00099 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00100 } 00101 00102 return fStartOffset; 00103 } 00104 00105 DOMNode* DOMRangeImpl::getEndContainer() const 00106 { 00107 if (fDetached) 00108 { 00109 throw DOMException( 00110 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00111 } 00112 00113 return fEndContainer; 00114 } 00115 00116 XMLSize_t DOMRangeImpl::getEndOffset() const 00117 { 00118 if (fDetached) 00119 { 00120 throw DOMException( 00121 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00122 } 00123 00124 return fEndOffset; 00125 } 00126 00127 00128 00129 bool DOMRangeImpl::getCollapsed() const 00130 { 00131 if (fDetached) 00132 { 00133 throw DOMException( 00134 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00135 } 00136 00137 return ((fStartContainer == fEndContainer) 00138 && (fStartOffset == fEndOffset)); 00139 } 00140 00141 //------------------------------- 00142 // Public setter functions 00143 //------------------------------- 00144 00145 void DOMRangeImpl::setStartContainer(const DOMNode* node) 00146 { 00147 if (fDetached) 00148 { 00149 throw DOMException( 00150 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00151 } 00152 00153 fStartContainer = (DOMNode*) node; 00154 } 00155 00156 void DOMRangeImpl::setStartOffset(XMLSize_t offset) 00157 { 00158 if (fDetached) 00159 { 00160 throw DOMException( 00161 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00162 } 00163 00164 fStartOffset = offset; 00165 } 00166 00167 void DOMRangeImpl::setEndContainer(const DOMNode* node) 00168 { 00169 if (fDetached) 00170 { 00171 throw DOMException( 00172 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00173 } 00174 00175 fEndContainer = (DOMNode*) node; 00176 00177 } 00178 00179 void DOMRangeImpl::setEndOffset(XMLSize_t offset) 00180 { 00181 if (fDetached) 00182 { 00183 throw DOMException( 00184 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00185 } 00186 00187 fEndOffset = offset; 00188 } 00189 00190 void DOMRangeImpl::setStart(const DOMNode* refNode, XMLSize_t offset) 00191 { 00192 validateNode(refNode); 00193 checkIndex(refNode, offset); 00194 00195 // error if not the same owner document 00196 if (fDocument != refNode->getOwnerDocument()) { 00197 if ( refNode != fDocument ) { 00198 collapse(true); //collapse the range positions to start 00199 fCollapsed = true; 00200 throw DOMException( 00201 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00202 } 00203 } 00204 00205 fStartContainer = (DOMNode*) refNode; 00206 fStartOffset = offset; 00207 00208 // they may be of same document, but not same root container 00209 // collapse if not the same root container 00210 if (!commonAncestorOf(refNode, fEndContainer)) 00211 collapse(true); 00212 00213 //compare the start and end boundary point 00214 //collapse if start point is after the end point 00215 if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) 00216 collapse(true); //collapse the range positions to start 00217 else 00218 fCollapsed = false; 00219 } 00220 00221 void DOMRangeImpl::setEnd(const DOMNode* refNode, XMLSize_t offset) 00222 { 00223 validateNode(refNode); 00224 checkIndex(refNode, offset); 00225 00226 // error if not the same owner document 00227 if (fDocument != refNode->getOwnerDocument()) { 00228 if ( refNode != fDocument ) { 00229 collapse(false); //collapse the range positions to end 00230 fCollapsed = true; 00231 throw DOMException( 00232 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00233 } 00234 } 00235 00236 fEndContainer = (DOMNode*) refNode; 00237 fEndOffset = offset; 00238 00239 // they may be of same document, but not same root container 00240 // collapse if not the same root container 00241 if (!commonAncestorOf(refNode, fStartContainer)) 00242 collapse(false); 00243 00244 //compare the start and end boundary point 00245 //collapse if start point is after the end point 00246 if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) 00247 collapse(false); //collapse the range positions to end 00248 else 00249 fCollapsed = false; 00250 } 00251 00252 void DOMRangeImpl::setStartBefore(const DOMNode* refNode) 00253 { 00254 if( fDetached) { 00255 throw DOMException( 00256 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00257 } 00258 if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) { 00259 throw DOMRangeException( 00260 DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 00261 } 00262 00263 // error if not the same owner document 00264 if (fDocument != refNode->getOwnerDocument()) { 00265 if ( refNode != fDocument ) { 00266 collapse(true); //collapse the range positions to start 00267 fCollapsed = true; 00268 throw DOMException( 00269 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00270 } 00271 } 00272 00273 fStartContainer = refNode->getParentNode(); 00274 XMLSize_t i = 0; 00275 for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling()) { 00276 i++; 00277 } 00278 if (i == 0) 00279 fStartOffset = 0; 00280 else 00281 fStartOffset = i-1; 00282 00283 // they may be of same document, but not same root container 00284 // collapse if not the same root container 00285 if (!commonAncestorOf(refNode, fEndContainer)) 00286 collapse(true); 00287 00288 //compare the start and end boundary point 00289 //collapse if start point is after the end point 00290 if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) 00291 collapse(true); //collapse the range positions to start 00292 else 00293 fCollapsed = false; 00294 } 00295 00296 void DOMRangeImpl::setStartAfter(const DOMNode* refNode) 00297 { 00298 if( fDetached) { 00299 throw DOMException( 00300 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00301 } 00302 if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) { 00303 throw DOMRangeException( 00304 DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 00305 } 00306 00307 // error if not the same owner document 00308 if (fDocument != refNode->getOwnerDocument()) { 00309 if ( refNode != fDocument ) { 00310 collapse(true); //collapse the range positions to start 00311 fCollapsed = true; 00312 throw DOMException( 00313 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00314 } 00315 } 00316 00317 fStartContainer = refNode->getParentNode(); 00318 XMLSize_t i = 0; 00319 for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling()) { 00320 i++; 00321 } 00322 00323 fStartOffset = i; 00324 00325 // they may be of same document, but not same root container 00326 // collapse if not the same root container 00327 if (!commonAncestorOf(refNode, fEndContainer)) 00328 collapse(true); 00329 00330 //compare the start and end boundary point 00331 //collapse if start point is after the end point 00332 if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) 00333 collapse(true); //collapse the range positions to start 00334 else 00335 fCollapsed = false; 00336 } 00337 00338 void DOMRangeImpl::setEndBefore(const DOMNode* refNode) 00339 { 00340 if( fDetached) { 00341 throw DOMException( 00342 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00343 } 00344 if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) { 00345 throw DOMRangeException( 00346 DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 00347 } 00348 00349 // error if not the same owner document 00350 if (fDocument != refNode->getOwnerDocument()) { 00351 if ( refNode != fDocument ) { 00352 collapse(false); //collapse the range positions to end 00353 fCollapsed = true; 00354 throw DOMException( 00355 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00356 } 00357 } 00358 00359 fEndContainer = refNode->getParentNode(); 00360 XMLSize_t i = 0; 00361 for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling(), i++) ; 00362 00363 if (i< 1) 00364 fEndOffset = 0; 00365 else 00366 fEndOffset = i-1; 00367 00368 // they may be of same document, but not same root container 00369 // collapse if not the same root container 00370 if (!commonAncestorOf(refNode, fStartContainer)) 00371 collapse(false); 00372 00373 //compare the start and end boundary point 00374 //collapse if start point is after the end point 00375 if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) 00376 collapse(false); //collapse the range positions to end 00377 else 00378 fCollapsed = false; 00379 } 00380 00381 void DOMRangeImpl::setEndAfter(const DOMNode* refNode) 00382 { 00383 if( fDetached) { 00384 throw DOMException( 00385 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00386 } 00387 if ( !hasLegalRootContainer(refNode) || !isLegalContainedNode(refNode)) { 00388 throw DOMRangeException( 00389 DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 00390 } 00391 00392 // error if not the same owner document 00393 if (fDocument != refNode->getOwnerDocument()) { 00394 if ( refNode != fDocument ) { 00395 collapse(false); //collapse the range positions to end 00396 fCollapsed = true; 00397 throw DOMException( 00398 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00399 } 00400 } 00401 00402 fEndContainer = refNode->getParentNode(); 00403 XMLSize_t i = 0; 00404 for (DOMNode* n = (DOMNode*) refNode; n!=0; n = n->getPreviousSibling(), i++) ; 00405 00406 if (i ==0) 00407 fEndOffset = 0; 00408 else 00409 fEndOffset = i; 00410 00411 // they may be of same document, but not same root container 00412 // collapse if not the same root container 00413 if (!commonAncestorOf(refNode, fStartContainer)) 00414 collapse(false); 00415 00416 //compare the start and end boundary point 00417 //collapse if start point is after the end point 00418 if(compareBoundaryPoints(DOMRange::END_TO_START, this) == 1) 00419 collapse(false); //collapse the range positions to end 00420 else 00421 fCollapsed = false; 00422 } 00423 //------------------------------- 00424 // Public Misc. functions 00425 //------------------------------- 00426 void DOMRangeImpl::detach() 00427 { 00428 if( fDetached) { 00429 throw DOMException( 00430 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00431 } 00432 00433 ((DOMDocumentImpl *)fDocument)->removeRange(this); 00434 00435 fDetached = true; 00436 00437 //0ify nodes 00438 fStartContainer = 0; 00439 fStartOffset = 0; 00440 fEndContainer = 0; 00441 fEndOffset = 0; 00442 fCollapsed = true; 00443 00444 fRemoveChild = 0; 00445 } 00446 00447 void DOMRangeImpl::collapse(bool toStart) 00448 { 00449 if( fDetached) { 00450 throw DOMException( 00451 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00452 } 00453 00454 if (toStart) { 00455 fEndContainer = fStartContainer; 00456 fEndOffset = fStartOffset; 00457 } else { 00458 fStartContainer = fEndContainer; 00459 fStartOffset = fEndOffset; 00460 } 00461 fCollapsed = true; 00462 } 00463 00464 void DOMRangeImpl::selectNode(const DOMNode* refNode) 00465 { 00466 validateNode(refNode); 00467 if ( !isLegalContainedNode(refNode)) { 00468 throw DOMRangeException( 00469 DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 00470 } 00471 //First check for the text type node 00472 short type = refNode->getNodeType(); 00473 if((type == DOMNode::TEXT_NODE 00474 || type == DOMNode::CDATA_SECTION_NODE 00475 || type == DOMNode::COMMENT_NODE 00476 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 00477 { 00478 //The node itself is the container. 00479 fStartContainer = (DOMNode*) refNode; 00480 fEndContainer = (DOMNode*) refNode; 00481 00482 //Select all the contents of the node 00483 fStartOffset = 0; 00484 if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) 00485 fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)refNode)->getData()); 00486 else 00487 fEndOffset = ((DOMText *)refNode)->getLength(); 00488 return; 00489 } 00490 00491 DOMNode* parent = refNode->getParentNode(); 00492 if (parent != 0 ) // REVIST: what to do if it IS 0? 00493 { 00494 fStartContainer = parent; 00495 fEndContainer = parent; 00496 00497 XMLSize_t i = 0; 00498 for (DOMNode* n = parent->getFirstChild(); n!=0 && n!=refNode; n = n->getNextSibling()) { 00499 i++; 00500 } 00501 00502 fStartOffset = i; 00503 fEndOffset = fStartOffset+1; 00504 } 00505 } 00506 00507 void DOMRangeImpl::selectNodeContents(const DOMNode* node) 00508 { 00509 validateNode(node); 00510 00511 fStartContainer = (DOMNode*) node; 00512 fEndContainer = (DOMNode*) node; 00513 00514 fStartOffset = 0; 00515 short type = node->getNodeType(); 00516 00517 if((type == DOMNode::TEXT_NODE 00518 || type == DOMNode::CDATA_SECTION_NODE 00519 || type == DOMNode::COMMENT_NODE)) { 00520 00521 fEndOffset = ((DOMText *)node)->getLength(); 00522 return; 00523 } 00524 if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) { 00525 fEndOffset = XMLString::stringLen(((DOMProcessingInstruction*)node)->getData()); 00526 return; 00527 } 00528 00529 DOMNode* first = node->getFirstChild(); 00530 if (first == 0) { 00531 fEndOffset = 0; 00532 return; 00533 } 00534 XMLSize_t i = 0; 00535 for (DOMNode* n = first; n!=0; n = n->getNextSibling()) { 00536 i++; 00537 } 00538 fEndOffset = i; 00539 } 00540 00541 void DOMRangeImpl::surroundContents(DOMNode* newParent) 00542 { 00543 if (newParent==0) return; 00544 00545 //check for elimination criteria 00546 if( fDetached) { 00547 throw DOMException( 00548 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00549 } 00550 00551 if (newParent->getOwnerDocument() !=fDocument) { 00552 throw DOMException( 00553 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00554 } 00555 00556 int type = newParent->getNodeType(); 00557 if ( !isLegalContainedNode(newParent) 00558 || type == DOMNode::DOCUMENT_TYPE_NODE) 00559 { 00560 throw DOMRangeException( 00561 DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 00562 } 00563 00564 DOMNode* realStart = fStartContainer; 00565 DOMNode* realEnd = fEndContainer; 00566 00567 type = fStartContainer->getNodeType(); 00568 if((type == DOMNode::TEXT_NODE 00569 || type == DOMNode::CDATA_SECTION_NODE 00570 || type == DOMNode::COMMENT_NODE 00571 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { 00572 realStart = fStartContainer->getParentNode(); 00573 } 00574 type = fEndContainer->getNodeType(); 00575 if((type == DOMNode::TEXT_NODE 00576 || type == DOMNode::CDATA_SECTION_NODE 00577 || type == DOMNode::COMMENT_NODE 00578 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { 00579 realEnd = fEndContainer->getParentNode(); 00580 } 00581 00582 if (realStart != realEnd) { 00583 throw DOMRangeException( 00584 DOMRangeException::BAD_BOUNDARYPOINTS_ERR, 0, fMemoryManager); 00585 } 00586 00587 DOMDocumentFragment* frag = (DOMDocumentFragment*) extractContents(); 00588 insertNode(newParent); 00589 newParent->appendChild(frag); 00590 selectNode(newParent); 00591 } 00592 00593 00594 short DOMRangeImpl::compareBoundaryPoints(DOMRange::CompareHow how, const DOMRange* srcRange) const 00595 { 00596 if (fDocument != ((DOMRangeImpl*)srcRange)->fDocument) { 00597 throw DOMException( 00598 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00599 } 00600 if( fDetached) { 00601 throw DOMException( 00602 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00603 } 00604 00605 DOMNode* pointA; 00606 DOMNode* pointB; 00607 XMLSize_t offsetA, offsetB; 00608 00609 switch (how) 00610 { 00611 case (DOMRange::START_TO_START) : 00612 pointB = srcRange->getStartContainer(); 00613 pointA = fStartContainer; 00614 offsetB = srcRange->getStartOffset(); 00615 offsetA = fStartOffset; 00616 break; 00617 case (DOMRange::START_TO_END) : 00618 pointB = srcRange->getStartContainer(); 00619 pointA = fEndContainer; 00620 offsetB = srcRange->getStartOffset(); 00621 offsetA = fEndOffset; 00622 break; 00623 case (DOMRange::END_TO_START) : 00624 pointB = srcRange->getEndContainer(); 00625 pointA = fStartContainer; 00626 offsetB = srcRange->getEndOffset(); 00627 offsetA = fStartOffset; 00628 break; 00629 case (DOMRange::END_TO_END) : 00630 pointB = srcRange->getEndContainer(); 00631 pointA = fEndContainer; 00632 offsetB = srcRange->getEndOffset(); 00633 offsetA = fEndOffset; 00634 break; 00635 default: 00636 throw DOMException( 00637 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00638 } 00639 00640 // case 1: same container 00641 if (pointA == pointB) { 00642 if (offsetA < offsetB) return -1; //A before B 00643 if (offsetA == offsetB) return 0; //A equal to B 00644 return 1; // A after B 00645 } 00646 // case 2: Child C of container A is ancestor of B 00647 for (DOMNode* node = pointA->getFirstChild(); node != 0; node=node->getNextSibling()) { 00648 if (isAncestorOf(node, pointB)) { 00649 XMLSize_t index = indexOf(node, pointA); 00650 if (offsetA <= index) return -1; 00651 return 1; 00652 } 00653 } 00654 // case 3: Child C of container B is ancestor of A 00655 for (DOMNode* nd = pointB->getFirstChild(); nd != 0; nd=nd->getNextSibling()) { 00656 if (isAncestorOf(nd, pointA)) { 00657 XMLSize_t index = indexOf(nd, pointB); 00658 if (index < offsetB ) return -1; 00659 return 1; //B strictly before A 00660 } 00661 } 00662 00663 // case 4: preorder traversal of context tree. 00664 // Instead of literally walking the context tree in pre-order, 00665 // we use relative node depth walking which is usually faster 00666 00667 int depthDiff = 0; 00668 DOMNode* n = 0; 00669 for ( n = pointB; n != 0; n = n->getParentNode() ) 00670 depthDiff++; 00671 for ( n = pointA; n != 0; n = n->getParentNode() ) 00672 depthDiff--; 00673 while (depthDiff > 0) { 00674 pointB = pointB->getParentNode(); 00675 depthDiff--; 00676 } 00677 while (depthDiff < 0) { 00678 pointA = pointA->getParentNode(); 00679 depthDiff++; 00680 } 00681 for (DOMNode* pB = pointB->getParentNode(), 00682 *pA = pointA->getParentNode(); 00683 pB != pA; 00684 pB = pB->getParentNode(), pA = pA->getParentNode() ) 00685 { 00686 pointB = pB; 00687 pointA = pA; 00688 } 00689 for ( n = pointB->getNextSibling(); 00690 n != 0; 00691 n = n->getNextSibling() ) 00692 { 00693 if (n == pointA) { 00694 return 1; 00695 } 00696 } 00697 return -1; 00698 } 00699 00700 00701 void DOMRangeImpl:: deleteContents() 00702 { 00703 traverseContents(DELETE_CONTENTS); 00704 } 00705 00706 DOMDocumentFragment* DOMRangeImpl::extractContents() 00707 { 00708 checkReadOnly(fStartContainer, fEndContainer, fStartOffset, fEndOffset); 00709 return traverseContents(EXTRACT_CONTENTS); 00710 } 00711 00712 DOMDocumentFragment* DOMRangeImpl::cloneContents() const 00713 { 00714 // cast off const. 00715 return ((DOMRangeImpl *)this)->traverseContents(CLONE_CONTENTS); 00716 } 00717 00718 00719 void DOMRangeImpl::insertNode(DOMNode* newNode) 00720 { 00721 if (newNode == 0) return; //don't have to do anything 00722 00723 if( fDetached) { 00724 throw DOMException( 00725 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00726 } 00727 00728 int type = newNode->getNodeType(); 00729 if (type == DOMNode::ATTRIBUTE_NODE 00730 || type == DOMNode::ENTITY_NODE 00731 || type == DOMNode::NOTATION_NODE 00732 || type == DOMNode::DOCUMENT_NODE) 00733 { 00734 throw DOMRangeException( 00735 DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 00736 } 00737 00738 // Prevent cycles in the tree. 00739 //isKidOK() is not checked here as its taken care by insertBefore() function 00740 if (isAncestorOf( newNode, fStartContainer)) { 00741 throw DOMException( 00742 DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager); 00743 } 00744 00745 for (DOMNode* aNode = fStartContainer; aNode!=0; aNode = aNode->getParentNode()) { 00746 if (castToNodeImpl(newNode)->isReadOnly()) { 00747 throw DOMException( 00748 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, fMemoryManager); 00749 } 00750 } 00751 00752 if (fDocument != newNode->getOwnerDocument()) { 00753 throw DOMException( 00754 DOMException::WRONG_DOCUMENT_ERR, 0, fMemoryManager); 00755 } 00756 00757 00758 DOMNode* parent; 00759 DOMNode* next; 00760 00761 type = fStartContainer->getNodeType(); 00762 if((type == DOMNode::TEXT_NODE 00763 || type == DOMNode::CDATA_SECTION_NODE 00764 || type == DOMNode::COMMENT_NODE 00765 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { 00766 00767 //set 'parent' and 'next' here 00768 parent = fStartContainer->getParentNode(); 00769 00770 //split the text nodes 00771 if (fStartOffset > 0) { 00772 if (type == DOMNode::COMMENT_NODE) 00773 ((DOMCommentImpl*)fStartContainer)->splitText(fStartOffset); 00774 else if (type == DOMNode::PROCESSING_INSTRUCTION_NODE) 00775 ((DOMProcessingInstructionImpl*)fStartContainer)->splitText(fStartOffset); 00776 else 00777 ((DOMText*)fStartContainer)->splitText(fStartOffset); 00778 } 00779 00780 //update the new start information later. After inserting the first newNode 00781 if (fStartOffset == 0) 00782 next = fStartContainer; 00783 else 00784 next = fStartContainer->getNextSibling(); 00785 00786 } // end of text handling 00787 else { 00788 parent = fStartContainer; 00789 00790 next = fStartContainer->getFirstChild(); 00791 for(XMLSize_t i = 0; (i < fStartOffset) && (next != 0); i++) { 00792 next=next->getNextSibling(); 00793 } 00794 } 00795 00796 if (parent != 0) { 00797 if (next != 0) 00798 parent->insertBefore(newNode, next); 00799 else 00800 parent->appendChild(newNode); 00801 } 00802 } 00803 00804 DOMRange* DOMRangeImpl::cloneRange() const 00805 { 00806 if( fDetached) { 00807 throw DOMException( 00808 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00809 } 00810 00811 DOMRange* range = fDocument->createRange(); 00812 range->setStart(fStartContainer, fStartOffset); 00813 range->setEnd(fEndContainer, fEndOffset); 00814 00815 return range; 00816 } 00817 00818 const XMLCh* DOMRangeImpl::toString() const 00819 { 00820 if( fDetached) { 00821 throw DOMException( 00822 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 00823 } 00824 00825 if ((fStartContainer == fEndContainer) && (fEndOffset == fStartOffset)) 00826 return XMLUni::fgZeroLenString; 00827 00828 DOMNode* node = fStartContainer; 00829 DOMNode* stopNode = fEndContainer; 00830 00831 XMLBuffer retStringBuf(1023, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 00832 short type = fStartContainer->getNodeType(); 00833 if((type == DOMNode::TEXT_NODE 00834 || type == DOMNode::CDATA_SECTION_NODE 00835 || type == DOMNode::COMMENT_NODE 00836 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { 00837 if (fStartContainer == fEndContainer) { 00838 XMLCh* tempString; 00839 XMLCh temp[4000]; 00840 if ((fEndOffset-fStartOffset) >= 3999) 00841 tempString = (XMLCh*) fMemoryManager->allocate 00842 ( 00843 (fEndOffset - fStartOffset + 1) * sizeof(XMLCh) 00844 );//new XMLCh[fEndOffset-fStartOffset+1]; 00845 else 00846 tempString = temp; 00847 00848 XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, fEndOffset, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 00849 const XMLCh* retString = ((DOMDocumentImpl *)fDocument)->getPooledString(tempString); 00850 00851 if ((fEndOffset-fStartOffset) >= 3999) 00852 fMemoryManager->deallocate(tempString);//delete[] tempString; 00853 00854 return retString; 00855 } else { 00856 XMLSize_t length = XMLString::stringLen(fStartContainer->getNodeValue()); 00857 if (length != fStartOffset) { 00858 00859 XMLCh* tempString; 00860 XMLCh temp[4000]; 00861 if ((length - fStartOffset) >= 3999) 00862 tempString = (XMLCh*) fMemoryManager->allocate 00863 ( 00864 (length - fStartOffset + 1) * sizeof(XMLCh) 00865 );//new XMLCh[length - fStartOffset+1]; 00866 else 00867 tempString = temp; 00868 00869 XMLString::subString(tempString, fStartContainer->getNodeValue(), fStartOffset, length, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 00870 retStringBuf.append(tempString); 00871 00872 if ((length - fStartOffset) >= 3999) 00873 fMemoryManager->deallocate(tempString);//delete[] tempString; 00874 } 00875 00876 node = nextNode(node, true); 00877 } 00878 }else { //fStartContainer is not a TextNode 00879 node=node->getFirstChild(); 00880 if (fStartOffset>0) { //find a first node within a range, specified by fStartOffset 00881 XMLSize_t counter = 0; 00882 while (counter<fStartOffset && node!=0) { 00883 node=node->getNextSibling(); 00884 counter++; 00885 } 00886 } 00887 if (node == 0) { 00888 node = nextNode(fStartContainer,false); 00889 } 00890 } 00891 00892 type = fEndContainer->getNodeType(); 00893 if((type != DOMNode::TEXT_NODE 00894 && type != DOMNode::CDATA_SECTION_NODE 00895 && type != DOMNode::COMMENT_NODE 00896 && type != DOMNode::PROCESSING_INSTRUCTION_NODE)) { 00897 int i=(int)fEndOffset; 00898 stopNode = fEndContainer->getFirstChild(); 00899 while( i>0 && stopNode!=0 ){ 00900 --i; 00901 stopNode = stopNode->getNextSibling(); 00902 } 00903 if ( stopNode == 0 ) 00904 stopNode = nextNode( fEndContainer, false ); 00905 } 00906 00907 while (node != stopNode) { //look into all kids of the Range 00908 if (node == 0) break; 00909 type = node->getNodeType(); 00910 00911 if((type == DOMNode::TEXT_NODE 00912 || type == DOMNode::CDATA_SECTION_NODE 00913 || type == DOMNode::COMMENT_NODE 00914 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { 00915 retStringBuf.append(node->getNodeValue()); 00916 } 00917 node = nextNode(node, true); 00918 } 00919 00920 type = fEndContainer->getNodeType(); 00921 if((type == DOMNode::TEXT_NODE 00922 || type == DOMNode::CDATA_SECTION_NODE 00923 || type == DOMNode::COMMENT_NODE 00924 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { 00925 00926 if (fEndOffset != 0) { 00927 00928 XMLCh* tempString; 00929 XMLCh temp[4000]; 00930 if (fEndOffset >= 3999) 00931 tempString = (XMLCh*) fMemoryManager->allocate 00932 ( 00933 (fEndOffset+1) * sizeof(XMLCh) 00934 );//new XMLCh[fEndOffset+1]; 00935 else 00936 tempString = temp; 00937 00938 XMLString::subString(tempString, fEndContainer->getNodeValue(), 0, fEndOffset, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 00939 retStringBuf.append(tempString); 00940 00941 if (fEndOffset >= 3999) 00942 fMemoryManager->deallocate(tempString);//delete[] tempString; 00943 } 00944 } 00945 return ((DOMDocumentImpl *)fDocument)->getPooledString(retStringBuf.getRawBuffer()); 00946 } 00947 00948 DOMDocument* DOMRangeImpl::getDocument() 00949 { 00950 return fDocument; 00951 } 00952 00953 const DOMNode* DOMRangeImpl::getCommonAncestorContainer() const 00954 { 00955 return commonAncestorOf(fStartContainer, fEndContainer); 00956 00957 } 00958 00959 void DOMRangeImpl::release() 00960 { 00961 detach(); 00962 // for performance reason, do not recycle pointer 00963 // chance that this is allocated again and again is not usual 00964 } 00965 00966 //--------------------- 00967 //private functions 00968 //--------------------- 00969 00970 bool DOMRangeImpl::isValidAncestorType(const DOMNode* node) const 00971 { 00972 for (DOMNode* aNode = (DOMNode*) node; aNode!=0; aNode = aNode->getParentNode()) { 00973 short type = aNode->getNodeType(); 00974 if ( type == DOMNode::ENTITY_NODE 00975 || type == DOMNode::NOTATION_NODE 00976 || type == DOMNode::DOCUMENT_TYPE_NODE) 00977 return false; 00978 } 00979 return true; 00980 } 00981 00982 bool DOMRangeImpl::isAncestorOf(const DOMNode* a, const DOMNode* b) { 00983 for (DOMNode* node = (DOMNode*) b; node != 0; node=node->getParentNode()) { 00984 if (node == a) return true; 00985 } 00986 return false; 00987 } 00988 00989 bool DOMRangeImpl::hasLegalRootContainer(const DOMNode* node) const { 00990 if ( node==0 ) 00991 return false; 00992 00993 DOMNode* rootContainer = (DOMNode*)node; 00994 for (; rootContainer->getParentNode()!=0; rootContainer = rootContainer->getParentNode()) 00995 ; 00996 00997 switch( rootContainer->getNodeType() ) { 00998 case DOMNode::ATTRIBUTE_NODE: 00999 case DOMNode::DOCUMENT_NODE: 01000 case DOMNode::DOCUMENT_FRAGMENT_NODE: 01001 return true; 01002 default: 01003 return false; 01004 } 01005 } 01006 01007 bool DOMRangeImpl::isLegalContainedNode(const DOMNode* node ) const { 01008 if ( node==0 ) 01009 return false; 01010 switch( node->getNodeType() ) 01011 { 01012 case DOMNode::DOCUMENT_NODE: 01013 case DOMNode::DOCUMENT_FRAGMENT_NODE: 01014 case DOMNode::ATTRIBUTE_NODE: 01015 case DOMNode::ENTITY_NODE: 01016 case DOMNode::NOTATION_NODE: 01017 return false; 01018 default: 01019 return true; 01020 } 01021 } 01022 01023 XMLSize_t DOMRangeImpl::indexOf(const DOMNode* child, const DOMNode* parent) const 01024 { 01025 XMLSize_t i = 0; 01026 if (child->getParentNode() != parent) return (XMLSize_t)-1; 01027 for(DOMNode* node = child->getPreviousSibling(); node!= 0; node=node->getPreviousSibling()) { 01028 i++; 01029 } 01030 return i; 01031 } 01032 01033 void DOMRangeImpl::validateNode(const DOMNode* node) const 01034 { 01035 if( fDetached) { 01036 throw DOMException( 01037 DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 01038 } 01039 01040 if ( !isValidAncestorType(node)) { 01041 throw DOMRangeException(DOMRangeException::INVALID_NODE_TYPE_ERR, 0, fMemoryManager); 01042 } 01043 } 01044 01045 01046 const DOMNode* DOMRangeImpl::commonAncestorOf(const DOMNode* pointA, const DOMNode* pointB) const 01047 { 01048 if (fDetached) 01049 throw DOMException(DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 01050 01051 //if the containers are same then it itself is its common ancestor. 01052 if (pointA == pointB) 01053 return pointA; 01054 01055 typedef RefVectorOf<DOMNode> VectorNodes; 01056 VectorNodes startV(1, false, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 01057 DOMNode* node; 01058 01059 for (node=(DOMNode*)pointA; node != 0; node=node->getParentNode()) 01060 { 01061 startV.addElement(node); 01062 } 01063 VectorNodes endV(1, false, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 01064 for (node=(DOMNode*)pointB; node != 0; node=node->getParentNode()) 01065 { 01066 endV.addElement(node); 01067 } 01068 01069 XMLSize_t s = startV.size(); 01070 XMLSize_t e = endV.size(); 01071 01072 DOMNode* commonAncestor = 0; 01073 01074 while (s>0 && e>0) { 01075 if (startV.elementAt(s-1) == endV.elementAt(e-1)) { 01076 commonAncestor = startV.elementAt(s-1); 01077 } 01078 else break; 01079 --s; 01080 --e; 01081 } 01082 01083 return commonAncestor; 01084 } 01085 01086 void DOMRangeImpl::checkIndex(const DOMNode* node, XMLSize_t offset) const 01087 { 01088 short type = node->getNodeType(); 01089 01090 if((type == DOMNode::TEXT_NODE 01091 || type == DOMNode::CDATA_SECTION_NODE 01092 || type == DOMNode::COMMENT_NODE 01093 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) { 01094 if (offset > XMLString::stringLen(node->getNodeValue())) 01095 throw DOMException( DOMException::INDEX_SIZE_ERR, 0, fMemoryManager ); 01096 else return; 01097 } 01098 01099 DOMNode* child = node->getFirstChild(); 01100 XMLSize_t i = 0; 01101 for (; child != 0; i++) { 01102 child = child->getNextSibling(); 01103 } 01104 if (i < offset) { 01105 throw DOMException( DOMException::INDEX_SIZE_ERR, 0, fMemoryManager ); 01106 } 01107 01108 } 01109 01110 DOMNode* DOMRangeImpl::nextNode(const DOMNode* node, bool visitChildren) const 01111 { 01112 01113 if (node == 0) return 0; 01114 01115 DOMNode* result; 01116 if (visitChildren) { 01117 result = node->getFirstChild(); 01118 if (result != 0) { 01119 return result; 01120 } 01121 } 01122 01123 // if hasSibling, return sibling 01124 result = node->getNextSibling(); 01125 if (result != 0) { 01126 return result; 01127 } 01128 01129 01130 // return parent's 1st sibling. 01131 DOMNode* parent = node->getParentNode(); 01132 01133 01134 while ( (parent != 0) && (parent != fDocument) ) 01135 { 01136 result = parent->getNextSibling(); 01137 if (result != 0) { 01138 return result; 01139 } else { 01140 parent = parent->getParentNode(); 01141 } 01142 01143 } 01144 // end of list, return 0 01145 return 0; 01146 } 01147 01148 01153 DOMDocumentFragment* DOMRangeImpl::traverseContents(TraversalType how) 01154 { 01155 if (fDetached) 01156 throw DOMException(DOMException::INVALID_STATE_ERR, 0, fMemoryManager); 01157 01158 if (fStartContainer == 0 || fEndContainer == 0) { 01159 return 0; // REVIST: Throw exception? 01160 } 01161 01162 /* Traversal is accomplished by first determining the 01163 relationship between the endpoints of the range. 01164 For each of four significant relationships, we will 01165 delegate the traversal call to a method that 01166 can make appropriate assumptions. 01167 */ 01168 01169 // case 1: same container 01170 if ( fStartContainer == fEndContainer ) 01171 return traverseSameContainer( how ); 01172 01173 // case 2: Child C of start container is ancestor of end container 01174 // This can be quickly tested by walking the parent chain of 01175 // end container 01176 int endContainerDepth = 0; 01177 for ( DOMNode* c = fEndContainer, *p = c->getParentNode(); 01178 p != 0; 01179 c = p, p = p->getParentNode()) 01180 { 01181 if (p == fStartContainer) 01182 return traverseCommonStartContainer( c, how ); 01183 ++endContainerDepth; 01184 } 01185 01186 // case 3: Child C of end container is ancestor of start container 01187 // This can be quickly tested by walking the parent chain of A 01188 int startContainerDepth = 0; 01189 for ( DOMNode* c2 = fStartContainer, *p2 = c2->getParentNode(); 01190 p2 != 0; 01191 c2 = p2, p2 = p2->getParentNode()) 01192 { 01193 if (p2 == fEndContainer) 01194 return traverseCommonEndContainer( c2, how ); 01195 ++startContainerDepth; 01196 } 01197 01198 // case 4: There is a common ancestor container. Find the 01199 // ancestor siblings that are children of that container. 01200 int depthDiff = startContainerDepth - endContainerDepth; 01201 01202 DOMNode* startNode = fStartContainer; 01203 while (depthDiff > 0) { 01204 startNode = startNode->getParentNode(); 01205 depthDiff--; 01206 } 01207 01208 DOMNode* endNode = fEndContainer; 01209 while (depthDiff < 0) { 01210 endNode = endNode->getParentNode(); 01211 depthDiff++; 01212 } 01213 01214 // ascend the ancestor hierarchy until we have a common parent. 01215 for( DOMNode* sp = startNode->getParentNode(), *ep = endNode->getParentNode(); 01216 sp!=ep; 01217 sp = sp->getParentNode(), ep = ep->getParentNode() ) 01218 { 01219 startNode = sp; 01220 endNode = ep; 01221 } 01222 return traverseCommonAncestors( startNode, endNode, how ); 01223 } 01224 01230 DOMDocumentFragment* DOMRangeImpl::traverseSameContainer( int how ) 01231 { 01232 DOMDocumentFragment* frag = 0; 01233 if ( how!=DELETE_CONTENTS) 01234 frag = fDocument->createDocumentFragment(); 01235 01236 // If selection is empty, just return the fragment 01237 if ( fStartOffset==fEndOffset ) 01238 return frag; 01239 01240 DOMNode* cloneCurrent = 0; 01241 01242 // Text node needs special case handling 01243 short type = fStartContainer->getNodeType(); 01244 if((type == DOMNode::TEXT_NODE 01245 || type == DOMNode::CDATA_SECTION_NODE 01246 || type == DOMNode::COMMENT_NODE 01247 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01248 { 01249 cloneCurrent = fStartContainer->cloneNode(false); 01250 if (fEndOffset == fStartOffset) { 01251 cloneCurrent->setNodeValue(XMLUni::fgZeroLenString); 01252 } 01253 else { 01254 XMLCh* tempString; 01255 XMLCh temp[4000]; 01256 if (fEndOffset >= 3999) 01257 tempString = (XMLCh*) fMemoryManager->allocate 01258 ( 01259 (fEndOffset+1) * sizeof(XMLCh) 01260 );//new XMLCh[fEndOffset+1]; 01261 else 01262 tempString = temp; 01263 01264 XMLString::subString(tempString, cloneCurrent->getNodeValue(), fStartOffset, fEndOffset, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 01265 cloneCurrent->setNodeValue(((DOMDocumentImpl *)fDocument)->getPooledString(tempString)); 01266 01267 if (fEndOffset >= 3999) 01268 fMemoryManager->deallocate(tempString);//delete[] tempString; 01269 } 01270 01271 // set the original text node to its new value 01272 if ( how != CLONE_CONTENTS ) { 01273 if(type == DOMNode::PROCESSING_INSTRUCTION_NODE) { 01274 ((DOMProcessingInstructionImpl*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset); 01275 } 01276 else 01277 ((DOMCharacterData*)fStartContainer)->deleteData(fStartOffset, fEndOffset-fStartOffset); 01278 } 01279 if ( how != DELETE_CONTENTS) 01280 frag->appendChild(cloneCurrent); 01281 } 01282 else { 01283 // Copy nodes between the start/end offsets. 01284 DOMNode* n = getSelectedNode( fStartContainer, (int)fStartOffset ); 01285 int cnt = (int)fEndOffset - (int)fStartOffset; 01286 while( cnt > 0 && n) 01287 { 01288 DOMNode* sibling = n->getNextSibling(); 01289 DOMNode* xferNode = traverseFullySelected( n, how ); 01290 if ( frag!=0 ) 01291 frag->appendChild( xferNode ); 01292 --cnt; 01293 n = sibling; 01294 } 01295 } 01296 01297 // Nothing is partially selected, so collapse to start point 01298 if ( how != CLONE_CONTENTS ) 01299 collapse(true); 01300 return frag; 01301 } 01302 01309 DOMDocumentFragment* DOMRangeImpl::traverseCommonStartContainer( DOMNode*endAncestor, int how ) 01310 { 01311 DOMDocumentFragment* frag = 0; 01312 if ( how!=DELETE_CONTENTS) 01313 frag = fDocument->createDocumentFragment(); 01314 DOMNode*n = traverseRightBoundary( endAncestor, how ); 01315 if ( frag!=0 ) 01316 frag->appendChild( n ); 01317 01318 XMLSize_t endIdx = indexOf( endAncestor, fStartContainer ); 01319 if ( endIdx <= fStartOffset ) 01320 { 01321 // Collapse to just before the endAncestor, which 01322 // is partially selected. 01323 if ( how != CLONE_CONTENTS ) 01324 { 01325 setEndBefore( endAncestor ); 01326 collapse( false ); 01327 } 01328 return frag; 01329 } 01330 01331 n = endAncestor->getPreviousSibling(); 01332 int cnt = (int)endIdx - (int)fStartOffset; 01333 while( cnt > 0 ) 01334 { 01335 DOMNode* sibling = n->getPreviousSibling(); 01336 DOMNode* xferNode = traverseFullySelected( n, how ); 01337 if ( frag!=0 ) 01338 frag->insertBefore( xferNode, frag->getFirstChild() ); 01339 --cnt; 01340 n = sibling; 01341 } 01342 // Collapse to just before the endAncestor, which 01343 // is partially selected. 01344 if ( how != CLONE_CONTENTS ) 01345 { 01346 setEndBefore( endAncestor ); 01347 collapse( false ); 01348 } 01349 return frag; 01350 } 01351 01358 DOMDocumentFragment* DOMRangeImpl::traverseCommonEndContainer( DOMNode*startAncestor, int how ) 01359 { 01360 DOMDocumentFragment* frag = 0; 01361 if ( how!=DELETE_CONTENTS) 01362 frag = fDocument->createDocumentFragment(); 01363 DOMNode* n = traverseLeftBoundary( startAncestor, how ); 01364 if ( frag!=0 ) 01365 frag->appendChild( n ); 01366 XMLSize_t startIdx = indexOf( startAncestor, fEndContainer ); 01367 ++startIdx; // Because we already traversed it.... 01368 01369 int cnt = (int)fEndOffset - (int)startIdx; 01370 n = startAncestor->getNextSibling(); 01371 while( cnt > 0 ) 01372 { 01373 DOMNode* sibling = n->getNextSibling(); 01374 DOMNode* xferNode = traverseFullySelected( n, how ); 01375 if ( frag!=0 ) 01376 frag->appendChild( xferNode ); 01377 --cnt; 01378 n = sibling; 01379 } 01380 01381 if ( how != CLONE_CONTENTS ) 01382 { 01383 setStartAfter( startAncestor ); 01384 collapse( true ); 01385 } 01386 01387 return frag; 01388 } 01389 01396 DOMDocumentFragment* DOMRangeImpl::traverseCommonAncestors( DOMNode*startAncestor, DOMNode*endAncestor, int how ) 01397 { 01398 DOMDocumentFragment* frag = 0; 01399 if ( how!=DELETE_CONTENTS) 01400 frag = fDocument->createDocumentFragment(); 01401 01402 DOMNode*n = traverseLeftBoundary( startAncestor, how ); 01403 if ( frag!=0 ) 01404 frag->appendChild( n ); 01405 01406 DOMNode*commonParent = startAncestor->getParentNode(); 01407 XMLSize_t startOffset = indexOf( startAncestor, commonParent ); 01408 XMLSize_t endOffset = indexOf( endAncestor, commonParent ); 01409 ++startOffset; 01410 01411 int cnt = (int)endOffset - (int)startOffset; 01412 DOMNode* sibling = startAncestor->getNextSibling(); 01413 01414 while( cnt > 0 ) 01415 { 01416 DOMNode* nextSibling = sibling->getNextSibling(); 01417 n = traverseFullySelected( sibling, how ); 01418 if ( frag!=0 ) 01419 frag->appendChild( n ); 01420 sibling = nextSibling; 01421 --cnt; 01422 } 01423 01424 n = traverseRightBoundary( endAncestor, how ); 01425 if ( frag!=0 ) 01426 frag->appendChild( n ); 01427 01428 if ( how != CLONE_CONTENTS ) 01429 { 01430 setStartAfter( startAncestor ); 01431 collapse( true ); 01432 } 01433 return frag; 01434 } 01435 01470 DOMNode* DOMRangeImpl::traverseRightBoundary( DOMNode*root, int how ) 01471 { 01472 DOMNode*next = getSelectedNode( fEndContainer, (int)fEndOffset-1 ); 01473 bool isFullySelected = ( next!=fEndContainer ); 01474 01475 if ( next==root ) 01476 return traverseNode( next, isFullySelected, false, how ); 01477 01478 DOMNode*parent = next->getParentNode(); 01479 DOMNode*clonedParent = traverseNode( parent, false, false, how ); 01480 01481 while( parent!=0 ) 01482 { 01483 while( next!=0 ) 01484 { 01485 DOMNode* prevSibling = next->getPreviousSibling(); 01486 DOMNode* clonedChild = 01487 traverseNode( next, isFullySelected, false, how ); 01488 if ( how!=DELETE_CONTENTS ) 01489 { 01490 clonedParent->insertBefore( 01491 clonedChild, 01492 clonedParent->getFirstChild() 01493 ); 01494 } 01495 isFullySelected = true; 01496 next = prevSibling; 01497 } 01498 if ( parent==root ) 01499 return clonedParent; 01500 01501 next = parent->getPreviousSibling(); 01502 parent = parent->getParentNode(); 01503 DOMNode* clonedGrandParent = traverseNode( parent, false, false, how ); 01504 if ( how!=DELETE_CONTENTS ) 01505 clonedGrandParent->appendChild( clonedParent ); 01506 clonedParent = clonedGrandParent; 01507 01508 } 01509 01510 // should never occur 01511 return 0; 01512 } 01513 01549 DOMNode* DOMRangeImpl::traverseLeftBoundary( DOMNode*root, int how ) 01550 { 01551 DOMNode*next = getSelectedNode( getStartContainer(), (int)getStartOffset() ); 01552 bool isFullySelected = ( next!=getStartContainer() ); 01553 01554 if ( next==root ) 01555 return traverseNode( next, isFullySelected, true, how ); 01556 01557 DOMNode* parent = next->getParentNode(); 01558 DOMNode* clonedParent = traverseNode( parent, false, true, how ); 01559 01560 while( parent!=0 ) 01561 { 01562 while( next!=0 ) 01563 { 01564 DOMNode* nextSibling = next->getNextSibling(); 01565 DOMNode* clonedChild = 01566 traverseNode( next, isFullySelected, true, how ); 01567 if ( how!=DELETE_CONTENTS ) 01568 clonedParent->appendChild(clonedChild); 01569 isFullySelected = true; 01570 next = nextSibling; 01571 } 01572 if ( parent==root ) 01573 return clonedParent; 01574 01575 next = parent->getNextSibling(); 01576 parent = parent->getParentNode(); 01577 DOMNode* clonedGrandParent = traverseNode( parent, false, true, how ); 01578 if ( how!=DELETE_CONTENTS ) 01579 clonedGrandParent->appendChild( clonedParent ); 01580 clonedParent = clonedGrandParent; 01581 01582 } 01583 01584 // should never occur 01585 return 0; 01586 01587 } 01588 01596 DOMNode* DOMRangeImpl::traverseNode( DOMNode* n, bool isFullySelected, bool isLeft, int how ) 01597 { 01598 if ( isFullySelected ) 01599 return traverseFullySelected( n, how ); 01600 01601 short type = n->getNodeType(); 01602 01603 if((type == DOMNode::TEXT_NODE 01604 || type == DOMNode::CDATA_SECTION_NODE 01605 || type == DOMNode::COMMENT_NODE 01606 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01607 return traverseTextNode( n, isLeft, how ); 01608 01609 return traversePartiallySelected( n, how ); 01610 } 01611 01618 DOMNode* DOMRangeImpl::traverseFullySelected( DOMNode* n, int how ) 01619 { 01620 switch( how ) 01621 { 01622 case CLONE_CONTENTS: 01623 return n->cloneNode( true ); 01624 case EXTRACT_CONTENTS: 01625 return n; 01626 case DELETE_CONTENTS: 01627 // revisit: 01628 // should I release the removed node? 01629 // not released in case user still referencing it externally 01630 n->getParentNode()->removeChild(n); 01631 return 0; 01632 } 01633 return 0; 01634 } 01635 01642 DOMNode* DOMRangeImpl::traversePartiallySelected( DOMNode*n, int how ) 01643 { 01644 switch( how ) 01645 { 01646 case DELETE_CONTENTS: 01647 return 0; 01648 case CLONE_CONTENTS: 01649 case EXTRACT_CONTENTS: 01650 return n->cloneNode( false ); 01651 } 01652 return 0; 01653 } 01654 01662 DOMNode* DOMRangeImpl::traverseTextNode( DOMNode*n, bool isLeft, int how ) 01663 { 01664 XMLCh* txtValue = XMLString::replicate(n->getNodeValue(), fMemoryManager); 01665 ArrayJanitor<XMLCh> janValue(txtValue, fMemoryManager); 01666 01667 if ( isLeft ) 01668 { 01669 XMLSize_t startLen = XMLString::stringLen(fStartContainer->getNodeValue()); 01670 XMLSize_t offset = getStartOffset(); 01671 01672 if (offset == 0) { 01673 if ( how != CLONE_CONTENTS ) 01674 n->setNodeValue(XMLUni::fgZeroLenString); 01675 } 01676 else { 01677 XMLCh* oldNodeValue; 01678 XMLCh oldTemp[4000]; 01679 01680 if (offset >= 3999) { 01681 oldNodeValue = (XMLCh*) fMemoryManager->allocate 01682 ( 01683 (offset+1) * sizeof(XMLCh) 01684 );//new XMLCh[offset+1]; 01685 } 01686 else { 01687 oldNodeValue = oldTemp; 01688 } 01689 XMLString::subString(oldNodeValue, txtValue, 0, offset, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 01690 01691 if ( how != CLONE_CONTENTS ) 01692 n->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(oldNodeValue) ); 01693 01694 if (offset>= 3999) 01695 fMemoryManager->deallocate(oldNodeValue);//delete[] oldNodeValue; 01696 } 01697 01698 if ( how==DELETE_CONTENTS ) 01699 return 0; 01700 01701 DOMNode* newNode = n->cloneNode( false ); 01702 01703 if (startLen == offset) { 01704 newNode->setNodeValue(XMLUni::fgZeroLenString); 01705 } 01706 else { 01707 XMLCh* newNodeValue; 01708 XMLCh newTemp[4000]; 01709 01710 if (offset >= 3999) { 01711 newNodeValue = (XMLCh*) fMemoryManager->allocate 01712 ( 01713 (offset+1) * sizeof(XMLCh) 01714 );//new XMLCh[offset+1]; 01715 } 01716 else { 01717 newNodeValue = newTemp; 01718 } 01719 XMLString::subString(newNodeValue, txtValue, offset, startLen, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 01720 newNode->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(newNodeValue) ); 01721 01722 if (offset>= 3999) 01723 fMemoryManager->deallocate(newNodeValue);//delete[] newNodeValue; 01724 01725 } 01726 return newNode; 01727 } 01728 else 01729 { 01730 XMLSize_t endLen = XMLString::stringLen(fEndContainer->getNodeValue()); 01731 XMLSize_t offset = getEndOffset(); 01732 01733 if (endLen == offset) { 01734 if ( how != CLONE_CONTENTS ) 01735 n->setNodeValue(XMLUni::fgZeroLenString); 01736 } 01737 else { 01738 XMLCh* oldNodeValue; 01739 XMLCh oldTemp[4000]; 01740 01741 if (offset >= 3999) { 01742 oldNodeValue = (XMLCh*) fMemoryManager->allocate 01743 ( 01744 (offset+1) * sizeof(XMLCh) 01745 );//new XMLCh[offset+1]; 01746 } 01747 else { 01748 oldNodeValue = oldTemp; 01749 } 01750 XMLString::subString(oldNodeValue, txtValue, offset, endLen, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 01751 01752 if ( how != CLONE_CONTENTS ) 01753 n->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(oldNodeValue) ); 01754 01755 if (offset>= 3999) 01756 fMemoryManager->deallocate(oldNodeValue);//delete[] oldNodeValue; 01757 } 01758 01759 if ( how==DELETE_CONTENTS ) 01760 return 0; 01761 01762 DOMNode* newNode = n->cloneNode( false ); 01763 01764 if (offset == 0) { 01765 newNode->setNodeValue(XMLUni::fgZeroLenString); 01766 } 01767 else { 01768 XMLCh* newNodeValue; 01769 XMLCh newTemp[4000]; 01770 01771 if (offset >= 3999) { 01772 newNodeValue = (XMLCh*) fMemoryManager->allocate 01773 ( 01774 (offset+1) * sizeof(XMLCh) 01775 );//new XMLCh[offset+1]; 01776 } 01777 else { 01778 newNodeValue = newTemp; 01779 } 01780 XMLString::subString(newNodeValue, txtValue, 0, offset, ((DOMDocumentImpl *)fDocument)->getMemoryManager()); 01781 newNode->setNodeValue( ((DOMDocumentImpl *)fDocument)->getPooledString(newNodeValue) ); 01782 01783 if (offset>= 3999) 01784 fMemoryManager->deallocate(newNodeValue);//delete[] newNodeValue; 01785 01786 } 01787 return newNode; 01788 } 01789 } 01790 01799 DOMNode* DOMRangeImpl::getSelectedNode( DOMNode*container, int offset ) 01800 { 01801 short type = container->getNodeType(); 01802 if((type == DOMNode::TEXT_NODE 01803 || type == DOMNode::CDATA_SECTION_NODE 01804 || type == DOMNode::COMMENT_NODE 01805 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01806 return container; 01807 01808 // This case is an important convenience for 01809 // traverseRightBoundary() 01810 if ( offset<0 ) 01811 return container; 01812 01813 DOMNode*child = container->getFirstChild(); 01814 while( child!=0 && offset > 0 ) 01815 { 01816 --offset; 01817 child = child->getNextSibling(); 01818 } 01819 if ( child!=0 ) 01820 return child; 01821 return container; 01822 } 01823 01824 void DOMRangeImpl::checkReadOnly(DOMNode* start, DOMNode* end, 01825 XMLSize_t startOffset, XMLSize_t endOffset) 01826 { 01827 if ((start == 0) || (end == 0) ) return; 01828 DOMNode*sNode = 0; 01829 01830 short type = start->getNodeType(); 01831 if ( type == DOMNode::DOCUMENT_TYPE_NODE ) 01832 { 01833 throw DOMException( 01834 DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager); 01835 } 01836 01837 if((type == DOMNode::TEXT_NODE 01838 || type == DOMNode::CDATA_SECTION_NODE 01839 || type == DOMNode::COMMENT_NODE 01840 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01841 { 01842 if (castToNodeImpl(start)->isReadOnly()) { 01843 throw DOMException( 01844 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, fMemoryManager); 01845 } 01846 //if both start and end are text check and return 01847 if (start == end) 01848 return; 01849 01850 sNode = start; 01851 } else { 01852 //set the start and end nodes to check 01853 sNode = start->getFirstChild(); 01854 for(XMLSize_t i = 0; i<startOffset; i++) 01855 sNode = sNode->getNextSibling(); 01856 } 01857 01858 DOMNode* eNode; 01859 type = end->getNodeType(); 01860 if ( type == DOMNode::DOCUMENT_TYPE_NODE ) 01861 { 01862 throw DOMException( 01863 DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager); 01864 } 01865 01866 if((type == DOMNode::TEXT_NODE 01867 || type == DOMNode::CDATA_SECTION_NODE 01868 || type == DOMNode::COMMENT_NODE 01869 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01870 { 01871 eNode = end; //need to check only till this node 01872 } 01873 else { //need to check all the kids that fall before the end offset value 01874 eNode = end->getFirstChild(); 01875 if (endOffset > 0) { 01876 for (XMLSize_t i = 0; i<endOffset-1; i++) 01877 eNode = eNode->getNextSibling(); 01878 } 01879 } 01880 //recursivly search if any node is readonly 01881 recurseTreeAndCheck(sNode, eNode); 01882 } 01883 01884 void DOMRangeImpl::recurseTreeAndCheck(DOMNode* start, DOMNode* end) 01885 { 01886 for(DOMNode* node=start; node != 0 && node !=end; node=node->getNextSibling()) 01887 { 01888 if ( node->getNodeType()== DOMNode::DOCUMENT_TYPE_NODE ) 01889 { 01890 throw DOMException( 01891 DOMException::HIERARCHY_REQUEST_ERR, 0, fMemoryManager); 01892 } 01893 01894 if (castToNodeImpl(node)->isReadOnly()) { 01895 throw DOMException( 01896 DOMException::NO_MODIFICATION_ALLOWED_ERR, 0, fMemoryManager); 01897 } 01898 01899 if (node->hasChildNodes()) { 01900 node = node->getFirstChild(); 01901 recurseTreeAndCheck(node, end); 01902 } 01903 } 01904 } 01905 01906 01907 DOMNode* DOMRangeImpl::removeChild(DOMNode* parent, DOMNode* child) 01908 { 01909 fRemoveChild = child; //only a precaution measure not to update this range data before removal 01910 DOMNode*n = parent->removeChild(child); 01911 fRemoveChild = 0; 01912 return n; 01913 } 01914 01915 01916 // 01917 // Mutation functions 01918 // 01919 01920 01921 /* This function is called from DOM. 01922 * The text has already been replaced. 01923 * Fix-up any offsets. 01924 */ 01925 void DOMRangeImpl::receiveReplacedText(DOMNode* node) 01926 { 01927 if (node == 0) return; 01928 01929 short type = fStartContainer->getNodeType(); 01930 if (node == fStartContainer 01931 && (type == DOMNode::TEXT_NODE 01932 || type == DOMNode::CDATA_SECTION_NODE 01933 || type == DOMNode::COMMENT_NODE 01934 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01935 { 01936 fStartOffset = 0; 01937 } 01938 type = fEndContainer->getNodeType(); 01939 if (node == fEndContainer 01940 && (type == DOMNode::TEXT_NODE 01941 || type == DOMNode::CDATA_SECTION_NODE 01942 || type == DOMNode::COMMENT_NODE 01943 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01944 { 01945 fEndOffset = 0; 01946 } 01947 } 01948 01949 01954 void DOMRangeImpl::updateRangeForDeletedText(DOMNode* node, XMLSize_t offset, XMLSize_t count) 01955 { 01956 if (node == 0) return; 01957 01958 short type = fStartContainer->getNodeType(); 01959 if (node == fStartContainer 01960 && (type == DOMNode::TEXT_NODE 01961 || type == DOMNode::CDATA_SECTION_NODE 01962 || type == DOMNode::COMMENT_NODE 01963 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01964 { 01965 if (fStartOffset > offset+count) { 01966 fStartOffset = fStartOffset-count; 01967 } else if (fStartOffset > offset) { 01968 fStartOffset = offset; 01969 } 01970 } 01971 type = fEndContainer->getNodeType(); 01972 if (node == fEndContainer 01973 && (type == DOMNode::TEXT_NODE 01974 || type == DOMNode::CDATA_SECTION_NODE 01975 || type == DOMNode::COMMENT_NODE 01976 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 01977 { 01978 if (fEndOffset > offset+count) { 01979 fEndOffset = fEndOffset-count; 01980 } else if (fEndOffset > offset) { 01981 fEndOffset = offset; 01982 } 01983 } 01984 } 01985 01986 01987 01992 void DOMRangeImpl::updateRangeForInsertedText(DOMNode* node, XMLSize_t offset, XMLSize_t count) 01993 { 01994 if (node == 0) return; 01995 01996 short type = fStartContainer->getNodeType(); 01997 if (node == fStartContainer 01998 && (type == DOMNode::TEXT_NODE 01999 || type == DOMNode::CDATA_SECTION_NODE 02000 || type == DOMNode::COMMENT_NODE 02001 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 02002 { 02003 if (fStartOffset > offset) { 02004 fStartOffset = offset; 02005 } 02006 } 02007 type = fEndContainer->getNodeType(); 02008 if (node == fEndContainer 02009 && (type == DOMNode::TEXT_NODE 02010 || type == DOMNode::CDATA_SECTION_NODE 02011 || type == DOMNode::COMMENT_NODE 02012 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 02013 { 02014 if (fEndOffset > offset) { 02015 fEndOffset = fEndOffset+count; 02016 } 02017 } 02018 } 02019 02020 02021 02026 void DOMRangeImpl::updateRangeForDeletedNode(DOMNode* node) 02027 { 02028 02029 if (node == 0) return; 02030 if (fRemoveChild == node) return; 02031 02032 if (node->getParentNode() == fStartContainer) { 02033 XMLSize_t index = indexOf(node, fStartContainer); 02034 if ( fStartOffset > index) { 02035 fStartOffset--; 02036 } 02037 } 02038 02039 if (node->getParentNode() == fEndContainer) { 02040 XMLSize_t index = indexOf(node, fEndContainer); 02041 if ( fEndOffset > index) { 02042 fEndOffset--; 02043 } 02044 } 02045 02046 if (node->getParentNode() != fStartContainer 02047 || node->getParentNode() != fEndContainer) { 02048 if (isAncestorOf(node, fStartContainer)) { 02049 DOMNode* tpNode = node->getParentNode(); 02050 setStartContainer( tpNode ); 02051 fStartOffset = indexOf( node, tpNode); 02052 } 02053 if (isAncestorOf(node, fEndContainer)) { 02054 DOMNode* tpNode = node->getParentNode(); 02055 setEndContainer( tpNode ); 02056 fEndOffset = indexOf( node, tpNode); 02057 } 02058 } 02059 02060 } 02061 02062 void DOMRangeImpl::updateRangeForInsertedNode(DOMNode* node) { 02063 if (node == 0) return; 02064 02065 if (node->getParentNode() == fStartContainer) { 02066 XMLSize_t index = indexOf(node, fStartContainer); 02067 if (index < fStartOffset) { 02068 fStartOffset++; 02069 } 02070 } 02071 02072 if (node->getParentNode() == fEndContainer) { 02073 XMLSize_t index = indexOf(node, fEndContainer); 02074 if (index < fEndOffset) { 02075 fEndOffset++; 02076 } 02077 } 02078 } 02079 02080 02081 void DOMRangeImpl::updateSplitInfo(DOMNode* oldNode, DOMNode* startNode, XMLSize_t offset) 02082 { 02083 if (startNode == 0) return; 02084 02085 short type = fStartContainer->getNodeType(); 02086 if (oldNode == fStartContainer 02087 && (type == DOMNode::TEXT_NODE 02088 || type == DOMNode::CDATA_SECTION_NODE 02089 || type == DOMNode::COMMENT_NODE 02090 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 02091 { 02092 if (fStartOffset > offset) { 02093 fStartOffset = fStartOffset - offset; 02094 fStartContainer = startNode; 02095 } 02096 } 02097 02098 type = fEndContainer->getNodeType(); 02099 if (oldNode == fEndContainer 02100 && (type == DOMNode::TEXT_NODE 02101 || type == DOMNode::CDATA_SECTION_NODE 02102 || type == DOMNode::COMMENT_NODE 02103 || type == DOMNode::PROCESSING_INSTRUCTION_NODE)) 02104 { 02105 if (fEndOffset > offset) { 02106 fEndContainer = startNode; 02107 fEndOffset = fEndOffset - offset; 02108 } 02109 } 02110 } 02111 02112 02113 02114 XERCES_CPP_NAMESPACE_END 02115