khtml Library API Documentation

dom2_rangeimpl.cpp

00001 
00025 #include "dom/dom_exception.h"
00026 #include "dom_docimpl.h"
00027 #include "dom2_rangeimpl.h"
00028 #include "dom_textimpl.h"
00029 #include "dom_xmlimpl.h"
00030 
00031 using namespace DOM;
00032 
00033 
00034 RangeImpl::RangeImpl(DocumentPtr *_ownerDocument)
00035 {
00036     m_ownerDocument = _ownerDocument;
00037     m_ownerDocument->ref();
00038     m_startContainer = _ownerDocument->document();
00039     m_startContainer->ref();
00040     m_endContainer = _ownerDocument->document();
00041     m_endContainer->ref();
00042     m_startOffset = 0;
00043     m_endOffset = 0;
00044     m_detached = false;
00045 }
00046 
00047 RangeImpl::RangeImpl(DocumentPtr *_ownerDocument,
00048               NodeImpl *_startContainer, long _startOffset,
00049               NodeImpl *_endContainer, long _endOffset)
00050 {
00051     m_ownerDocument = _ownerDocument;
00052     m_ownerDocument->ref();
00053     m_startContainer = _startContainer;
00054     m_startContainer->ref();
00055     m_startOffset = _startOffset;
00056     m_endContainer = _endContainer;
00057     m_endContainer->ref();
00058     m_endOffset = _endOffset;
00059     m_detached = false;
00060 }
00061 
00062 RangeImpl::~RangeImpl()
00063 {
00064     m_ownerDocument->deref();
00065     int exceptioncode = 0;
00066     if (!m_detached)
00067         detach(exceptioncode);
00068 }
00069 
00070 NodeImpl *RangeImpl::startContainer(int &exceptioncode) const
00071 {
00072     if (m_detached) {
00073         exceptioncode = DOMException::INVALID_STATE_ERR;
00074         return 0;
00075     }
00076 
00077     return m_startContainer;
00078 }
00079 
00080 long RangeImpl::startOffset(int &exceptioncode) const
00081 {
00082     if (m_detached) {
00083         exceptioncode = DOMException::INVALID_STATE_ERR;
00084         return 0;
00085     }
00086 
00087     return m_startOffset;
00088 }
00089 
00090 NodeImpl *RangeImpl::endContainer(int &exceptioncode) const
00091 {
00092     if (m_detached) {
00093         exceptioncode = DOMException::INVALID_STATE_ERR;
00094         return 0;
00095     }
00096 
00097     return m_endContainer;
00098 }
00099 
00100 long RangeImpl::endOffset(int &exceptioncode) const
00101 {
00102     if (m_detached) {
00103         exceptioncode = DOMException::INVALID_STATE_ERR;
00104         return 0;
00105     }
00106 
00107     return m_endOffset;
00108 }
00109 
00110 NodeImpl *RangeImpl::commonAncestorContainer(int &exceptioncode)
00111 {
00112     if (m_detached) {
00113         exceptioncode = DOMException::INVALID_STATE_ERR;
00114         return 0;
00115     }
00116 
00117     NodeImpl *com = commonAncestorContainer(m_startContainer,m_endContainer);
00118     if (!com) //  should never happen
00119         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00120     return com;
00121 }
00122 
00123 NodeImpl *RangeImpl::commonAncestorContainer(NodeImpl *containerA, NodeImpl *containerB)
00124 {
00125     NodeImpl *parentStart;
00126 
00127     for (parentStart = containerA; parentStart; parentStart = parentStart->parentNode()) {
00128         NodeImpl *parentEnd = containerB;
00129         while( parentEnd && (parentStart != parentEnd) )
00130             parentEnd = parentEnd->parentNode();
00131 
00132         if(parentStart == parentEnd)  break;
00133     }
00134 
00135     return parentStart;
00136 }
00137 
00138 bool RangeImpl::collapsed(int &exceptioncode) const
00139 {
00140     if (m_detached) {
00141         exceptioncode = DOMException::INVALID_STATE_ERR;
00142         return 0;
00143     }
00144 
00145     return (m_startContainer == m_endContainer && m_startOffset == m_endOffset);
00146 }
00147 
00148 void RangeImpl::setStart( NodeImpl *refNode, long offset, int &exceptioncode )
00149 {
00150     if (m_detached) {
00151         exceptioncode = DOMException::INVALID_STATE_ERR;
00152         return;
00153     }
00154 
00155     if (!refNode) {
00156         exceptioncode = DOMException::NOT_FOUND_ERR;
00157         return;
00158     }
00159 
00160     if (refNode->getDocument() != m_ownerDocument->document()) {
00161         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00162         return;
00163     }
00164 
00165     checkNodeWOffset( refNode, offset, exceptioncode );
00166     if (exceptioncode)
00167         return;
00168 
00169     setStartContainer(refNode);
00170     m_startOffset = offset;
00171 
00172     // check if different root container
00173     NodeImpl *endRootContainer = m_endContainer;
00174     while (endRootContainer->parentNode())
00175         endRootContainer = endRootContainer->parentNode();
00176     NodeImpl *startRootContainer = m_startContainer;
00177     while (startRootContainer->parentNode())
00178         startRootContainer = startRootContainer->parentNode();
00179     if (startRootContainer != endRootContainer)
00180         collapse(true,exceptioncode);
00181     // check if new start after end
00182     else if (compareBoundaryPoints(m_startContainer,m_startOffset,m_endContainer,m_endOffset) > 0)
00183         collapse(true,exceptioncode);
00184 }
00185 
00186 void RangeImpl::setEnd( NodeImpl *refNode, long offset, int &exceptioncode )
00187 {
00188     if (m_detached) {
00189         exceptioncode = DOMException::INVALID_STATE_ERR;
00190         return;
00191     }
00192 
00193     if (!refNode) {
00194         exceptioncode = DOMException::NOT_FOUND_ERR;
00195         return;
00196     }
00197 
00198     if (refNode->getDocument() != m_ownerDocument->document()) {
00199         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00200         return;
00201     }
00202 
00203     checkNodeWOffset( refNode, offset, exceptioncode );
00204     if (exceptioncode)
00205         return;
00206 
00207     setEndContainer(refNode);
00208     m_endOffset = offset;
00209 
00210     // check if different root container
00211     NodeImpl *endRootContainer = m_endContainer;
00212     while (endRootContainer->parentNode())
00213         endRootContainer = endRootContainer->parentNode();
00214     NodeImpl *startRootContainer = m_startContainer;
00215     while (startRootContainer->parentNode())
00216         startRootContainer = startRootContainer->parentNode();
00217     if (startRootContainer != endRootContainer)
00218         collapse(false,exceptioncode);
00219     // check if new end before start
00220     if (compareBoundaryPoints(m_startContainer,m_startOffset,m_endContainer,m_endOffset) > 0)
00221         collapse(false,exceptioncode);
00222 }
00223 
00224 void RangeImpl::collapse( bool toStart, int &exceptioncode )
00225 {
00226     if (m_detached) {
00227         exceptioncode = DOMException::INVALID_STATE_ERR;
00228         return;
00229     }
00230 
00231     if( toStart )   // collapse to start
00232     {
00233         setEndContainer(m_startContainer);
00234         m_endOffset = m_startOffset;
00235     }
00236     else            // collapse to end
00237     {
00238         setStartContainer(m_endContainer);
00239         m_startOffset = m_endOffset;
00240     }
00241 }
00242 
00243 short RangeImpl::compareBoundaryPoints( Range::CompareHow how, RangeImpl *sourceRange, int &exceptioncode )
00244 {
00245     if (m_detached) {
00246         exceptioncode = DOMException::INVALID_STATE_ERR;
00247         return 0;
00248     }
00249 
00250     if (!sourceRange) {
00251         exceptioncode = DOMException::NOT_FOUND_ERR;
00252         return 0;
00253     }
00254 
00255     NodeImpl *thisCont = commonAncestorContainer(exceptioncode);
00256     NodeImpl *sourceCont = sourceRange->commonAncestorContainer(exceptioncode);
00257     if (exceptioncode)
00258         return 0;
00259 
00260     if (thisCont->getDocument() != sourceCont->getDocument()) {
00261         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00262         return 0;
00263     }
00264 
00265     NodeImpl *thisTop = thisCont;
00266     NodeImpl *sourceTop = sourceCont;
00267     while (thisTop->parentNode())
00268     thisTop = thisTop->parentNode();
00269     while (sourceTop->parentNode())
00270     sourceTop = sourceTop->parentNode();
00271     if (thisTop != sourceTop) { // in different DocumentFragments
00272         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00273         return 0;
00274     }
00275 
00276     switch(how)
00277     {
00278     case Range::START_TO_START:
00279         return compareBoundaryPoints( m_startContainer, m_startOffset,
00280                                       sourceRange->startContainer(exceptioncode), sourceRange->startOffset(exceptioncode) );
00281         break;
00282     case Range::START_TO_END:
00283         return compareBoundaryPoints( m_startContainer, m_startOffset,
00284                                       sourceRange->endContainer(exceptioncode), sourceRange->endOffset(exceptioncode) );
00285         break;
00286     case Range::END_TO_END:
00287         return compareBoundaryPoints( m_endContainer, m_endOffset,
00288                                       sourceRange->endContainer(exceptioncode), sourceRange->endOffset(exceptioncode) );
00289         break;
00290     case Range::END_TO_START:
00291         return compareBoundaryPoints( m_endContainer, m_endOffset,
00292                                       sourceRange->startContainer(exceptioncode), sourceRange->startOffset(exceptioncode) );
00293         break;
00294     default:
00295         exceptioncode = DOMException::SYNTAX_ERR;
00296         return 0;
00297     }
00298 }
00299 
00300 short RangeImpl::compareBoundaryPoints( NodeImpl *containerA, long offsetA, NodeImpl *containerB, long offsetB )
00301 {
00302     // see DOM2 traversal & range section 2.5
00303 
00304     // case 1: both points have the same container
00305     if( containerA == containerB )
00306     {
00307         if( offsetA == offsetB )  return 0;    // A is equal to B
00308         if( offsetA < offsetB )  return -1;    // A is before B
00309         else  return 1;                        // A is after B
00310     }
00311 
00312     // case 2: node C (container B or an ancestor) is a child node of A
00313     NodeImpl *c = containerB;
00314     while (c && c->parentNode() != containerA)
00315         c = c->parentNode();
00316     if (c) {
00317         int offsetC = 0;
00318         NodeImpl *n = n = containerA->firstChild();
00319         while (n != c) {
00320             offsetC++;
00321             n = n->nextSibling();
00322         }
00323 
00324         if( offsetA <= offsetC )  return -1;    // A is before B
00325         else  return 1;                        // A is after B
00326     }
00327 
00328     // case 3: node C (container A or an ancestor) is a child node of B
00329     c = containerA;
00330     while (c && c->parentNode() != containerB)
00331         c = c->parentNode();
00332     if (c) {
00333         int offsetC = 0;
00334         NodeImpl *n = n = containerB->firstChild();
00335         while (n != c) {
00336             offsetC++;
00337             n = n->nextSibling();
00338         }
00339 
00340         if( offsetC < offsetB )  return -1;    // A is before B
00341         else  return 1;                        // A is after B
00342     }
00343 
00344     // case 4: containers A & B are siblings, or children of siblings
00345     // ### we need to do a traversal here instead
00346     NodeImpl *cmnRoot = commonAncestorContainer(containerA,containerB);
00347     NodeImpl *childA = containerA;
00348     while (childA->parentNode() != cmnRoot)
00349         childA = childA->parentNode();
00350     NodeImpl *childB = containerB;
00351     while (childB->parentNode() != cmnRoot)
00352         childB = childB->parentNode();
00353 
00354     NodeImpl *n = cmnRoot->firstChild();
00355     int i = 0;
00356     int childAOffset = -1;
00357     int childBOffset = -1;
00358     while (childAOffset < 0 || childBOffset < 0) {
00359         if (n == childA)
00360             childAOffset = i;
00361         if (n == childB)
00362             childBOffset = i;
00363         n = n->nextSibling();
00364         i++;
00365     }
00366 
00367     if( childAOffset == childBOffset )  return 0;    // A is equal to B
00368     if( childAOffset < childBOffset )   return -1;    // A is before B
00369     else  return 1;                        // A is after B
00370 }
00371 
00372 bool RangeImpl::boundaryPointsValid(  )
00373 {
00374     short valid =  compareBoundaryPoints( m_startContainer, m_startOffset,
00375                                           m_endContainer, m_endOffset );
00376     if( valid == 1 )  return false;
00377     else  return true;
00378 
00379 }
00380 
00381 void RangeImpl::deleteContents( int &exceptioncode ) {
00382     if (m_detached) {
00383         exceptioncode = DOMException::INVALID_STATE_ERR;
00384         return;
00385     }
00386 
00387     checkDeleteExtract(exceptioncode);
00388     if (exceptioncode)
00389     return;
00390 
00391     processContents(DELETE_CONTENTS,exceptioncode);
00392 }
00393 
00394 DocumentFragmentImpl *RangeImpl::processContents ( ActionType action, int &exceptioncode )
00395 {
00396     // ### when mutation events are implemented, we will have to take into account
00397     // situations where the tree is being transformed while we delete - ugh!
00398 
00399     // ### perhaps disable node deletion notification for this range while we do this?
00400 
00401     if (collapsed(exceptioncode))
00402         return 0;
00403     if (exceptioncode)
00404         return 0;
00405 
00406     NodeImpl *cmnRoot = commonAncestorContainer(exceptioncode);
00407     if (exceptioncode)
00408         return 0;
00409 
00410     // what is the highest node that partially selects the start of the range?
00411     NodeImpl *partialStart = 0;
00412     if (m_startContainer != cmnRoot) {
00413     partialStart = m_startContainer;
00414     while (partialStart->parentNode() != cmnRoot)
00415         partialStart = partialStart->parentNode();
00416     }
00417 
00418     // what is the highest node that partially selects the end of the range?
00419     NodeImpl *partialEnd = 0;
00420     if (m_endContainer != cmnRoot) {
00421     partialEnd = m_endContainer;
00422     while (partialEnd->parentNode() != cmnRoot)
00423         partialEnd = partialEnd->parentNode();
00424     }
00425 
00426     DocumentFragmentImpl *fragment = 0;
00427     if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
00428         fragment = new DocumentFragmentImpl(m_ownerDocument);
00429 
00430     // Simple case: the start and end containers are the same. We just grab
00431     // everything >= start offset and < end offset
00432     if (m_startContainer == m_endContainer) {
00433         if(m_startContainer->nodeType() == Node::TEXT_NODE ||
00434            m_startContainer->nodeType() == Node::CDATA_SECTION_NODE ||
00435            m_startContainer->nodeType() == Node::COMMENT_NODE) {
00436 
00437             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
00438                 CharacterDataImpl *c = static_cast<CharacterDataImpl*>(m_startContainer->cloneNode(true));
00439                 c->deleteData(m_endOffset,static_cast<CharacterDataImpl*>(m_startContainer)->length()-m_endOffset,exceptioncode);
00440                 c->deleteData(0,m_startOffset,exceptioncode);
00441                 fragment->appendChild(c,exceptioncode);
00442             }
00443             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
00444                 static_cast<CharacterDataImpl*>(m_startContainer)->deleteData(m_startOffset,m_endOffset-m_startOffset,exceptioncode);
00445         }
00446         else if (m_startContainer->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
00447             // ### operate just on data ?
00448         }
00449         else {
00450             NodeImpl *n = m_startContainer->firstChild();
00451             unsigned long i;
00452             for(i = 0; i < m_startOffset; i++) // skip until m_startOffset
00453                 n = n->nextSibling();
00454             while (n && i < m_endOffset) { // delete until m_endOffset
00455         NodeImpl *next = n->nextSibling();
00456                 if (action == EXTRACT_CONTENTS)
00457                     fragment->appendChild(n,exceptioncode); // will remove n from its parent
00458                 else if (action == CLONE_CONTENTS)
00459                     fragment->appendChild(n->cloneNode(true),exceptioncode);
00460                 else
00461                     m_startContainer->removeChild(n,exceptioncode);
00462                 n = next;
00463                 i++;
00464             }
00465         }
00466         collapse(true,exceptioncode);
00467         return fragment;
00468     }
00469 
00470     // Complex case: Start and end containers are different.
00471     // There are three possiblities here:
00472     // 1. Start container == cmnRoot (End container must be a descendant)
00473     // 2. End container == cmnRoot (Start container must be a descendant)
00474     // 3. Neither is cmnRoot, they are both descendants
00475     //
00476     // In case 3, we grab everything after the start (up until a direct child
00477     // of cmnRoot) into leftContents, and everything before the end (up until
00478     // a direct child of cmnRoot) into rightContents. Then we process all
00479     // cmnRoot children between leftContents and rightContents
00480     //
00481     // In case 1 or 2, we skip either processing of leftContents or rightContents,
00482     // in which case the last lot of nodes either goes from the first or last
00483     // child of cmnRoot.
00484     //
00485     // These are deleted, cloned, or extracted (i.e. both) depending on action.
00486 
00487     NodeImpl *leftContents = 0;
00488     if (m_startContainer != cmnRoot) {
00489         // process the left-hand side of the range, up until the last ancestor of
00490         // m_startContainer before cmnRoot
00491         if(m_startContainer->nodeType() == Node::TEXT_NODE ||
00492            m_startContainer->nodeType() == Node::CDATA_SECTION_NODE ||
00493            m_startContainer->nodeType() == Node::COMMENT_NODE) {
00494 
00495             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
00496                 CharacterDataImpl *c = static_cast<CharacterDataImpl*>(m_startContainer->cloneNode(true));
00497                 c->deleteData(0,m_startOffset,exceptioncode);
00498                 leftContents = c;
00499             }
00500             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
00501                 static_cast<CharacterDataImpl*>(m_startContainer)->deleteData(
00502                     m_startOffset,static_cast<CharacterDataImpl*>(m_startContainer)->length()-m_startOffset,exceptioncode);
00503         }
00504         else if (m_startContainer->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
00505             // ### operate just on data ?
00506             // leftContents = ...
00507         }
00508         else {
00509             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
00510         leftContents = m_startContainer->cloneNode(false);
00511             NodeImpl *n = m_startContainer->firstChild();
00512             unsigned long i;
00513             for(i = 0; i < m_startOffset; i++) // skip until m_startOffset
00514                 n = n->nextSibling();
00515             while (n) { // process until end
00516         NodeImpl *next = n->nextSibling();
00517                 if (action == EXTRACT_CONTENTS)
00518                     leftContents->appendChild(n,exceptioncode); // will remove n from m_startContainer
00519                 else if (action == CLONE_CONTENTS)
00520                     leftContents->appendChild(n->cloneNode(true),exceptioncode);
00521                 else
00522                     m_startContainer->removeChild(n,exceptioncode);
00523                 n = next;
00524             }
00525         }
00526 
00527         NodeImpl *leftParent = m_startContainer->parentNode();
00528         NodeImpl *n = m_startContainer->nextSibling();
00529         for (; leftParent != cmnRoot; leftParent = leftParent->parentNode()) {
00530             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
00531         NodeImpl *leftContentsParent = leftParent->cloneNode(false);
00532         leftContentsParent->appendChild(leftContents,exceptioncode);
00533         leftContents = leftContentsParent;
00534         }
00535 
00536             NodeImpl *next;
00537             for (; n; n = next ) {
00538                 next = n->nextSibling();
00539                 if (action == EXTRACT_CONTENTS)
00540                     leftContents->appendChild(n,exceptioncode); // will remove n from leftParent
00541                 else if (action == CLONE_CONTENTS)
00542                     leftContents->appendChild(n->cloneNode(true),exceptioncode);
00543                 else
00544                     leftParent->removeChild(n,exceptioncode);
00545             }
00546             n = leftParent->nextSibling();
00547         }
00548     }
00549 
00550     NodeImpl *rightContents = 0;
00551     if (m_endContainer != cmnRoot) {
00552         // delete the right-hand side of the range, up until the last ancestor of
00553         // m_endContainer before cmnRoot
00554         if(m_endContainer->nodeType() == Node::TEXT_NODE ||
00555            m_endContainer->nodeType() == Node::CDATA_SECTION_NODE ||
00556            m_endContainer->nodeType() == Node::COMMENT_NODE) {
00557 
00558             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
00559                 CharacterDataImpl *c = static_cast<CharacterDataImpl*>(m_endContainer->cloneNode(true));
00560                 c->deleteData(m_endOffset,static_cast<CharacterDataImpl*>(m_endContainer)->length()-m_endOffset,exceptioncode);
00561                 rightContents = c;
00562             }
00563             if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
00564                 static_cast<CharacterDataImpl*>(m_endContainer)->deleteData(0,m_endOffset,exceptioncode);
00565         }
00566         else if (m_startContainer->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
00567             // ### operate just on data ?
00568             // rightContents = ...
00569         }
00570         else {
00571         if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
00572         rightContents = m_endContainer->cloneNode(false);
00573             NodeImpl *n = m_endContainer->firstChild();
00574             unsigned long i;
00575             for(i = 0; i+1 < m_endOffset; i++) // skip to m_endOffset
00576                 n = n->nextSibling();
00577             NodeImpl *prev;
00578             for (; n; n = prev ) {
00579                 prev = n->previousSibling();
00580                 if (action == EXTRACT_CONTENTS)
00581                     rightContents->insertBefore(n,rightContents->firstChild(),exceptioncode); // will remove n from its parent
00582                 else if (action == CLONE_CONTENTS)
00583                     rightContents->insertBefore(n->cloneNode(true),rightContents->firstChild(),exceptioncode);
00584                 else
00585                     m_endContainer->removeChild(n,exceptioncode);
00586             }
00587         }
00588 
00589         NodeImpl *rightParent = m_endContainer->parentNode();
00590         NodeImpl *n = m_endContainer->previousSibling();
00591         for (; rightParent != cmnRoot; rightParent = rightParent->parentNode()) {
00592             if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
00593                 NodeImpl *rightContentsParent = rightParent->cloneNode(false);
00594                 rightContentsParent->appendChild(rightContents,exceptioncode);
00595                 rightContents = rightContentsParent;
00596             }
00597 
00598             NodeImpl *prev;
00599             for (; n; n = prev ) {
00600                 prev = n->previousSibling();
00601                 if (action == EXTRACT_CONTENTS)
00602                     rightContents->insertBefore(n,rightContents->firstChild(),exceptioncode); // will remove n from its parent
00603                 else if (action == CLONE_CONTENTS)
00604                     rightContents->insertBefore(n->cloneNode(true),rightContents->firstChild(),exceptioncode);
00605                 else
00606                     rightParent->removeChild(n,exceptioncode);
00607 
00608             }
00609             n = rightParent->previousSibling();
00610         }
00611     }
00612 
00613     // delete all children of cmnRoot between the start and end container
00614 
00615     NodeImpl *processStart; // child of cmnRooot
00616     if (m_startContainer == cmnRoot) {
00617         unsigned long i;
00618         processStart = m_startContainer->firstChild();
00619         for (i = 0; i < m_startOffset; i++)
00620             processStart = processStart->nextSibling();
00621     }
00622     else {
00623         processStart = m_startContainer;
00624         while (processStart->parentNode() != cmnRoot)
00625             processStart = processStart->parentNode();
00626         processStart = processStart->nextSibling();
00627     }
00628     NodeImpl *processEnd; // child of cmnRooot
00629     if (m_endContainer == cmnRoot) {
00630         unsigned long i;
00631         processEnd = m_endContainer->firstChild();
00632         for (i = 0; i < m_endOffset; i++)
00633             processEnd = processEnd->nextSibling();
00634     }
00635     else {
00636         processEnd = m_endContainer;
00637         while (processEnd->parentNode() != cmnRoot)
00638             processEnd = processEnd->parentNode();
00639     }
00640 
00641     // Now add leftContents, stuff in between, and rightContents to the fragment
00642     // (or just delete the stuff in between)
00643 
00644     if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && leftContents)
00645       fragment->appendChild(leftContents,exceptioncode);
00646 
00647     NodeImpl *next;
00648     NodeImpl *n;
00649     if (processStart) {
00650         for (n = processStart; n && n != processEnd; n = next) {
00651             next = n->nextSibling();
00652 
00653             if (action == EXTRACT_CONTENTS)
00654                 fragment->appendChild(n,exceptioncode); // will remove from cmnRoot
00655             else if (action == CLONE_CONTENTS)
00656                 fragment->appendChild(n->cloneNode(true),exceptioncode);
00657             else
00658                 cmnRoot->removeChild(n,exceptioncode);
00659         }
00660     }
00661 
00662     if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && rightContents)
00663       fragment->appendChild(rightContents,exceptioncode);
00664 
00665     // collapse to the proper position - see spec section 2.6
00666     if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
00667     if (!partialStart && !partialEnd)
00668         collapse(true,exceptioncode);
00669     else if (partialStart) {
00670         setStartContainer(partialStart->parentNode());
00671         setEndContainer(partialStart->parentNode());
00672         m_startOffset = m_endOffset = partialStart->nodeIndex()+1;
00673     }
00674     else if (partialEnd) {
00675         setStartContainer(partialEnd->parentNode());
00676         setEndContainer(partialEnd->parentNode());
00677         m_startOffset = m_endOffset = partialEnd->nodeIndex();
00678     }
00679     }
00680     return fragment;
00681 }
00682 
00683 
00684 DocumentFragmentImpl *RangeImpl::extractContents( int &exceptioncode )
00685 {
00686     if (m_detached) {
00687         exceptioncode = DOMException::INVALID_STATE_ERR;
00688         return 0;
00689     }
00690 
00691     checkDeleteExtract(exceptioncode);
00692     if (exceptioncode)
00693     return 0;
00694 
00695     return processContents(EXTRACT_CONTENTS,exceptioncode);
00696 }
00697 
00698 DocumentFragmentImpl *RangeImpl::cloneContents( int &exceptioncode  )
00699 {
00700     if (m_detached) {
00701         exceptioncode = DOMException::INVALID_STATE_ERR;
00702         return 0;
00703     }
00704 
00705     return processContents(CLONE_CONTENTS,exceptioncode);
00706 }
00707 
00708 void RangeImpl::insertNode( NodeImpl *newNode, int &exceptioncode )
00709 {
00710     if (m_detached) {
00711         exceptioncode = DOMException::INVALID_STATE_ERR;
00712         return;
00713     }
00714 
00715     // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
00716     // the Range is read-only.
00717     NodeImpl *n = m_startContainer;
00718     while (n && !n->isReadOnly())
00719         n = n->parentNode();
00720     if (n) {
00721         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
00722         return;
00723     }
00724 
00725     n = m_endContainer;
00726     while (n && !n->isReadOnly())
00727         n = n->parentNode();
00728     if (n) {
00729         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
00730         return;
00731     }
00732 
00733     // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
00734     // not created from the same document.
00735     if (newNode->getDocument() != m_startContainer->getDocument()) {
00736         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00737         return;
00738     }
00739 
00740 
00741     // HIERARCHY_REQUEST_ERR: Raised if the container of the start of the Range is of a type that
00742     // does not allow children of the type of newNode or if newNode is an ancestor of the container.
00743 
00744     // an extra one here - if a text node is going to split, it must have a parent to insert into
00745     if (m_startContainer->nodeType() == Node::TEXT_NODE && !m_startContainer->parentNode()) {
00746         exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
00747         return;
00748     }
00749 
00750     // In the case where the container is a text node, we check against the container's parent, because
00751     // text nodes get split up upon insertion.
00752     NodeImpl *checkAgainst;
00753     if (m_startContainer->nodeType() == Node::TEXT_NODE)
00754     checkAgainst = m_startContainer->parentNode();
00755     else
00756     checkAgainst = m_startContainer;
00757 
00758     if (newNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
00759     // check each child node, not the DocumentFragment itself
00760         NodeImpl *c;
00761         for (c = newNode->firstChild(); c; c = c->nextSibling()) {
00762         if (!checkAgainst->childTypeAllowed(c->nodeType())) {
00763         exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
00764         return;
00765         }
00766         }
00767     }
00768     else {
00769     if (!checkAgainst->childTypeAllowed(newNode->nodeType())) {
00770         exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
00771         return;
00772     }
00773     }
00774 
00775     for (n = m_startContainer; n; n = n->parentNode()) {
00776         if (n == newNode) {
00777             exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
00778             return;
00779         }
00780     }
00781 
00782     // INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, or Document node.
00783     if( newNode->nodeType() == Node::ATTRIBUTE_NODE ||
00784         newNode->nodeType() == Node::ENTITY_NODE ||
00785         newNode->nodeType() == Node::NOTATION_NODE ||
00786         newNode->nodeType() == Node::DOCUMENT_NODE) {
00787         exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET;
00788         return;
00789     }
00790 
00791     if( m_startContainer->nodeType() == Node::TEXT_NODE ||
00792         m_startContainer->nodeType() == Node::CDATA_SECTION_NODE )
00793     {
00794         TextImpl *newText = static_cast<TextImpl*>(m_startContainer)->splitText(m_startOffset,exceptioncode);
00795         if (exceptioncode)
00796             return;
00797         m_startContainer->parentNode()->insertBefore( newNode, newText, exceptioncode );
00798     }
00799     else {
00800         m_startContainer->insertBefore( newNode, m_startContainer->childNode( m_startOffset ), exceptioncode );
00801     }
00802 }
00803 
00804 DOMString RangeImpl::toString( int &exceptioncode )
00805 {
00806     if (m_detached) {
00807         exceptioncode = DOMException::INVALID_STATE_ERR;
00808         return DOMString();
00809     }
00810 
00811     DOMString text = "";
00812     NodeImpl *n = m_startContainer;
00813     while(n) {
00814         if(n->nodeType() == DOM::Node::TEXT_NODE ||
00815            n->nodeType() == DOM::Node::CDATA_SECTION_NODE) {
00816 
00817             DOMString str;
00818             if (static_cast<TextImpl *>(n)->string())
00819                str = static_cast<TextImpl *>(n)->string()->copy();
00820             if (n == m_endContainer)
00821                 str.truncate(m_endOffset);
00822             if (n == m_startContainer)
00823                 str.remove(0,m_startOffset);
00824             text += str;
00825             if (n == m_endContainer)
00826                 break;
00827         }
00828         else if (n->parentNode() == m_endContainer && !n->nextSibling()) {
00829             break;
00830         }
00831         //if (n == m_endContainer) break;
00832         NodeImpl *next = n->firstChild();
00833         if (!next) next = n->nextSibling();
00834 
00835         while( !next && n->parentNode() ) {
00836             n = n->parentNode();
00837             next = n->nextSibling();
00838         }
00839         n = next;
00840     }
00841     return text;
00842 }
00843 
00844 DOMString RangeImpl::toHTML(  )
00845 {
00846     // ### implement me!!!!
00847     return DOMString();
00848 }
00849 
00850 void RangeImpl::detach( int &exceptioncode )
00851 {
00852     if (m_detached) {
00853         exceptioncode = DOMException::INVALID_STATE_ERR;
00854         return;
00855     }
00856 
00857     if (m_startContainer)
00858         m_startContainer->deref();
00859     m_startContainer = 0;
00860     if (m_endContainer)
00861         m_endContainer->deref();
00862     m_endContainer = 0;
00863     m_detached = true;
00864 }
00865 
00866 bool RangeImpl::isDetached() const
00867 {
00868     return m_detached;
00869 }
00870 
00871 void RangeImpl::checkNodeWOffset( NodeImpl *n, int offset, int &exceptioncode) const
00872 {
00873     if( offset < 0 ) {
00874         exceptioncode = DOMException::INDEX_SIZE_ERR;
00875     }
00876 
00877     switch (n->nodeType()) {
00878     case Node::ENTITY_NODE:
00879     case Node::NOTATION_NODE:
00880     case Node::DOCUMENT_TYPE_NODE:
00881             exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET;
00882         break;
00883         case Node::TEXT_NODE:
00884         case Node::COMMENT_NODE:
00885         case Node::CDATA_SECTION_NODE:
00886             if ( (unsigned long)offset > static_cast<CharacterDataImpl*>(n)->length() )
00887                 exceptioncode = DOMException::INDEX_SIZE_ERR;
00888             break;
00889         case Node::PROCESSING_INSTRUCTION_NODE:
00890             // ### are we supposed to check with just data or the whole contents?
00891             if ( (unsigned long)offset > static_cast<ProcessingInstructionImpl*>(n)->data().length() )
00892                 exceptioncode = DOMException::INDEX_SIZE_ERR;
00893             break;
00894         default:
00895             if ( (unsigned long)offset > n->childNodeCount() )
00896                 exceptioncode = DOMException::INDEX_SIZE_ERR;
00897             break;
00898     }
00899 }
00900 
00901 void RangeImpl::checkNodeBA( NodeImpl *n, int &exceptioncode ) const
00902 {
00903     // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an
00904     // Attr, Document or DocumentFragment node or if refNode is a Document,
00905     // DocumentFragment, Attr, Entity, or Notation node.
00906     NodeImpl *root = n;
00907     while (root->parentNode())
00908     root = root->parentNode();
00909     if (!(root->nodeType() == Node::ATTRIBUTE_NODE ||
00910           root->nodeType() == Node::DOCUMENT_NODE ||
00911           root->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)) {
00912         exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET;
00913         return;
00914     }
00915 
00916     if( n->nodeType() == Node::DOCUMENT_NODE ||
00917         n->nodeType() == Node::DOCUMENT_FRAGMENT_NODE ||
00918         n->nodeType() == Node::ATTRIBUTE_NODE ||
00919         n->nodeType() == Node::ENTITY_NODE ||
00920         n->nodeType() == Node::NOTATION_NODE )
00921         exceptioncode = RangeException::INVALID_NODE_TYPE_ERR  + RangeException::_EXCEPTION_OFFSET;
00922 
00923 }
00924 
00925 RangeImpl *RangeImpl::cloneRange(int &exceptioncode)
00926 {
00927     if (m_detached) {
00928         exceptioncode = DOMException::INVALID_STATE_ERR;
00929         return 0;
00930     }
00931 
00932     return new RangeImpl(m_ownerDocument,m_startContainer,m_startOffset,m_endContainer,m_endOffset);
00933 }
00934 
00935 void RangeImpl::setStartAfter( NodeImpl *refNode, int &exceptioncode )
00936 {
00937     if (m_detached) {
00938         exceptioncode = DOMException::INVALID_STATE_ERR;
00939         return;
00940     }
00941 
00942     if (!refNode) {
00943         exceptioncode = DOMException::NOT_FOUND_ERR;
00944         return;
00945     }
00946 
00947     if (refNode->getDocument() != m_ownerDocument->document()) {
00948         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00949         return;
00950     }
00951 
00952     checkNodeBA( refNode, exceptioncode );
00953     if (exceptioncode)
00954         return;
00955 
00956     setStart( refNode->parentNode(), refNode->nodeIndex()+1, exceptioncode );
00957 }
00958 
00959 void RangeImpl::setEndBefore( NodeImpl *refNode, int &exceptioncode )
00960 {
00961     if (m_detached) {
00962         exceptioncode = DOMException::INVALID_STATE_ERR;
00963         return;
00964     }
00965 
00966     if (!refNode) {
00967         exceptioncode = DOMException::NOT_FOUND_ERR;
00968         return;
00969     }
00970 
00971     if (refNode->getDocument() != m_ownerDocument->document()) {
00972         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00973         return;
00974     }
00975 
00976     checkNodeBA( refNode, exceptioncode );
00977     if (exceptioncode)
00978         return;
00979 
00980     setEnd( refNode->parentNode(), refNode->nodeIndex(), exceptioncode );
00981 }
00982 
00983 void RangeImpl::setEndAfter( NodeImpl *refNode, int &exceptioncode )
00984 {
00985     if (m_detached) {
00986         exceptioncode = DOMException::INVALID_STATE_ERR;
00987         return;
00988     }
00989 
00990     if (!refNode) {
00991         exceptioncode = DOMException::NOT_FOUND_ERR;
00992         return;
00993     }
00994 
00995     if (refNode->getDocument() != m_ownerDocument->document()) {
00996         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
00997         return;
00998     }
00999 
01000     checkNodeBA( refNode, exceptioncode );
01001     if (exceptioncode)
01002         return;
01003 
01004     setEnd( refNode->parentNode(), refNode->nodeIndex()+1, exceptioncode );
01005 
01006 }
01007 
01008 void RangeImpl::selectNode( NodeImpl *refNode, int &exceptioncode )
01009 {
01010     if (m_detached) {
01011         exceptioncode = DOMException::INVALID_STATE_ERR;
01012         return;
01013     }
01014 
01015     if (!refNode) {
01016         exceptioncode = DOMException::NOT_FOUND_ERR;
01017         return;
01018     }
01019 
01020     // INVALID_NODE_TYPE_ERR: Raised if an ancestor of refNode is an Entity, Notation or
01021     // DocumentType node or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation
01022     // node.
01023     NodeImpl *anc;
01024     for (anc = refNode->parentNode(); anc; anc = anc->parentNode()) {
01025         if (anc->nodeType() == Node::ENTITY_NODE ||
01026             anc->nodeType() == Node::NOTATION_NODE ||
01027             anc->nodeType() == Node::DOCUMENT_TYPE_NODE) {
01028 
01029             exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET;
01030             return;
01031         }
01032     }
01033 
01034     if (refNode->nodeType() == Node::DOCUMENT_NODE ||
01035         refNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE ||
01036         refNode->nodeType() == Node::ATTRIBUTE_NODE ||
01037         refNode->nodeType() == Node::ENTITY_NODE ||
01038         refNode->nodeType() == Node::NOTATION_NODE) {
01039 
01040         exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET;
01041         return;
01042     }
01043 
01044     setStartBefore( refNode, exceptioncode );
01045     if (exceptioncode)
01046         return;
01047     setEndAfter( refNode, exceptioncode );
01048 }
01049 
01050 void RangeImpl::selectNodeContents( NodeImpl *refNode, int &exceptioncode )
01051 {
01052     if (m_detached) {
01053         exceptioncode = DOMException::INVALID_STATE_ERR;
01054         return;
01055     }
01056 
01057     if (!refNode) {
01058         exceptioncode = DOMException::NOT_FOUND_ERR;
01059         return;
01060     }
01061 
01062     // INVALID_NODE_TYPE_ERR: Raised if refNode or an ancestor of refNode is an Entity, Notation
01063     // or DocumentType node.
01064     NodeImpl *n;
01065     for (n = refNode; n; n = n->parentNode()) {
01066         if (n->nodeType() == Node::ENTITY_NODE ||
01067             n->nodeType() == Node::NOTATION_NODE ||
01068             n->nodeType() == Node::DOCUMENT_TYPE_NODE) {
01069 
01070             exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET;
01071             return;
01072         }
01073     }
01074 
01075     setStartContainer(refNode);
01076     m_startOffset = 0;
01077     setEndContainer(refNode);
01078     m_endOffset = refNode->childNodeCount();
01079 }
01080 
01081 void RangeImpl::surroundContents( NodeImpl *newParent, int &exceptioncode )
01082 {
01083     if (m_detached) {
01084         exceptioncode = DOMException::INVALID_STATE_ERR;
01085         return;
01086     }
01087 
01088     if( !newParent ) {
01089         exceptioncode = DOMException::NOT_FOUND_ERR;
01090         return;
01091     }
01092 
01093     // INVALID_NODE_TYPE_ERR: Raised if node is an Attr, Entity, DocumentType, Notation,
01094     // Document, or DocumentFragment node.
01095     if( newParent->nodeType() == Node::ATTRIBUTE_NODE ||
01096         newParent->nodeType() == Node::ENTITY_NODE ||
01097         newParent->nodeType() == Node::NOTATION_NODE ||
01098         newParent->nodeType() == Node::DOCUMENT_TYPE_NODE ||
01099         newParent->nodeType() == Node::DOCUMENT_NODE ||
01100         newParent->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
01101         exceptioncode = RangeException::INVALID_NODE_TYPE_ERR + RangeException::_EXCEPTION_OFFSET;
01102         return;
01103     }
01104 
01105     // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
01106     // the Range is read-only.
01107     if (readOnly()) {
01108         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
01109         return;
01110     }
01111 
01112     NodeImpl *n = m_startContainer;
01113     while (n && !n->isReadOnly())
01114         n = n->parentNode();
01115     if (n) {
01116         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
01117         return;
01118     }
01119 
01120     n = m_endContainer;
01121     while (n && !n->isReadOnly())
01122         n = n->parentNode();
01123     if (n) {
01124         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
01125         return;
01126     }
01127 
01128     // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
01129     // not created from the same document.
01130     if (newParent->getDocument() != m_startContainer->getDocument()) {
01131         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
01132         return;
01133     }
01134 
01135     // HIERARCHY_REQUEST_ERR: Raised if the container of the start of the Range is of a type that
01136     // does not allow children of the type of newParent or if newParent is an ancestor of the container
01137     // or if node would end up with a child node of a type not allowed by the type of node.
01138     if (!m_startContainer->childTypeAllowed(newParent->nodeType())) {
01139         exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
01140         return;
01141     }
01142 
01143     for (n = m_startContainer; n; n = n->parentNode()) {
01144         if (n == newParent) {
01145             exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
01146             return;
01147         }
01148     }
01149 
01150     // ### check if node would end up with a child node of a type not allowed by the type of node
01151 
01152     // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-text node.
01153     if (m_startContainer->nodeType() != Node::TEXT_NODE &&
01154         m_startContainer->nodeType() != Node::COMMENT_NODE &&
01155         m_startContainer->nodeType() != Node::CDATA_SECTION_NODE &&
01156         m_startContainer->nodeType() != Node::PROCESSING_INSTRUCTION_NODE) {
01157 
01158         if (m_startOffset > 0 && m_startOffset < m_startContainer->childNodeCount()) {
01159             exceptioncode = RangeException::BAD_BOUNDARYPOINTS_ERR + RangeException::_EXCEPTION_OFFSET;
01160             return;
01161         }
01162     }
01163 
01164     if (m_endContainer->nodeType() != Node::TEXT_NODE &&
01165         m_endContainer->nodeType() != Node::COMMENT_NODE &&
01166         m_endContainer->nodeType() != Node::CDATA_SECTION_NODE &&
01167         m_endContainer->nodeType() != Node::PROCESSING_INSTRUCTION_NODE) {
01168 
01169         if (m_endOffset > 0 && m_endOffset < m_endContainer->childNodeCount()) {
01170             exceptioncode = RangeException::BAD_BOUNDARYPOINTS_ERR + RangeException::_EXCEPTION_OFFSET;
01171             return;
01172         }
01173     }
01174 
01175     while (newParent->firstChild()) {
01176         newParent->removeChild(newParent->firstChild(),exceptioncode);
01177     if (exceptioncode)
01178         return;
01179     }
01180     DocumentFragmentImpl *fragment = extractContents(exceptioncode);
01181     if (exceptioncode)
01182         return;
01183     insertNode( newParent, exceptioncode );
01184     if (exceptioncode)
01185         return;
01186     newParent->appendChild( fragment, exceptioncode );
01187     if (exceptioncode)
01188         return;
01189     selectNode( newParent, exceptioncode );
01190 }
01191 
01192 void RangeImpl::setStartBefore( NodeImpl *refNode, int &exceptioncode )
01193 {
01194     if (m_detached) {
01195         exceptioncode = DOMException::INVALID_STATE_ERR;
01196         return;
01197     }
01198 
01199     if (!refNode) {
01200         exceptioncode = DOMException::NOT_FOUND_ERR;
01201         return;
01202     }
01203 
01204     if (refNode->getDocument() != m_ownerDocument->document()) {
01205         exceptioncode = DOMException::WRONG_DOCUMENT_ERR;
01206         return;
01207     }
01208 
01209     checkNodeBA( refNode, exceptioncode );
01210     if (exceptioncode)
01211         return;
01212 
01213     setStart( refNode->parentNode(), refNode->nodeIndex(), exceptioncode );
01214 }
01215 
01216 void RangeImpl::setStartContainer(NodeImpl *_startContainer)
01217 {
01218     if (m_startContainer == _startContainer)
01219         return;
01220 
01221     if (m_startContainer)
01222         m_startContainer->deref();
01223     m_startContainer = _startContainer;
01224     if (m_startContainer)
01225         m_startContainer->ref();
01226 }
01227 
01228 void RangeImpl::setEndContainer(NodeImpl *_endContainer)
01229 {
01230     if (m_endContainer == _endContainer)
01231         return;
01232 
01233     if (m_endContainer)
01234         m_endContainer->deref();
01235     m_endContainer = _endContainer;
01236     if (m_endContainer)
01237         m_endContainer->ref();
01238 }
01239 
01240 void RangeImpl::checkDeleteExtract(int &exceptioncode) {
01241 
01242     NodeImpl *start;
01243     if (m_startContainer->nodeType() != Node::TEXT_NODE &&
01244     m_startContainer->nodeType() != Node::CDATA_SECTION_NODE &&
01245     m_startContainer->nodeType() != Node::COMMENT_NODE &&
01246     m_startContainer->nodeType() != Node::PROCESSING_INSTRUCTION_NODE) {
01247 
01248     start = m_startContainer->childNode(m_startOffset);
01249     if (!start) {
01250         if (m_startContainer->lastChild())
01251         start = m_startContainer->lastChild()->traverseNextNode();
01252         else
01253         start = m_startContainer->traverseNextNode();
01254     }
01255     }
01256     else
01257     start = m_startContainer;
01258 
01259     NodeImpl *end;
01260     if (m_endContainer->nodeType() != Node::TEXT_NODE &&
01261     m_endContainer->nodeType() != Node::CDATA_SECTION_NODE &&
01262     m_endContainer->nodeType() != Node::COMMENT_NODE &&
01263     m_endContainer->nodeType() != Node::PROCESSING_INSTRUCTION_NODE) {
01264 
01265     end = m_endContainer->childNode(m_endOffset);
01266     if (!end) {
01267         if (m_endContainer->lastChild())
01268         end = m_endContainer->lastChild()->traverseNextNode();
01269         else
01270         end = m_endContainer->traverseNextNode();
01271     }
01272     }
01273     else
01274     end = m_endContainer;
01275 
01276     NodeImpl *n;
01277     for (n = start; n != end; n = n->traverseNextNode()) {
01278     if (n->isReadOnly()) {
01279         exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
01280         return;
01281     }
01282     if (n->nodeType() == Node::DOCUMENT_TYPE_NODE) { // ### is this for only directly under the DF, or anywhere?
01283         exceptioncode = DOMException::HIERARCHY_REQUEST_ERR;
01284         return;
01285     }
01286     }
01287 
01288     if (containedByReadOnly()) {
01289     exceptioncode = DOMException::NO_MODIFICATION_ALLOWED_ERR;
01290     return;
01291     }
01292 }
01293 
01294 
01295 bool RangeImpl::containedByReadOnly() {
01296     NodeImpl *n;
01297     for (n = m_startContainer; n; n = n->parentNode()) {
01298     if (n->isReadOnly())
01299         return true;
01300     }
01301     for (n = m_endContainer; n; n = n->parentNode()) {
01302     if (n->isReadOnly())
01303         return true;
01304     }
01305     return false;
01306 }
01307 
01308 
01309 
01310 
01311 
01312 
01313 
01314 
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:16:32 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001