NodeImpl *ParentNode::insertBefore(NodeImpl *newChild, NodeImpl *refChild) { bool errorChecking = ownerDocument->getErrorChecking(); if (newChild->isDocumentFragmentImpl()) { // SLOW BUT SAFE: We could insert the whole subtree without // juggling so many next/previous pointers. (Wipe out the // parent's child-list, patch the parent pointers, set the // ends of the list.) But we know some subclasses have special- // case behavior they add to insertBefore(), so we don't risk it. // This approch also takes fewer bytecodes. // NOTE: If one of the children is not a legal child of this // node, throw HIERARCHY_REQUEST_ERR before _any_ of the children // have been transferred. (Alternative behaviors would be to // reparent up to the first failure point or reparent all those // which are acceptable to the target node, neither of which is // as robust. PR-DOM-0818 isn't entirely clear on which it // recommends????? // No need to check kids for right-document; if they weren't, // they wouldn't be kids of that DocFrag. if (errorChecking) { for (NodeImpl *kid = newChild->getFirstChild(); // Prescan kid != null; kid = kid->getNextSibling()) { if (!DocumentImpl::isKidOK(this, kid)) { throw DOM_DOMException( DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } } } while (newChild->hasChildNodes()) { // Move insertBefore(newChild->getFirstChild(),refChild); } return newChild; } // it's a no-op if refChild is the same as newChild if (refChild == newChild) { return newChild; } if (errorChecking) { if (isReadOnly()) { throw DOM_DOMException( DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null); } if (newChild->getOwnerDocument() != ownerDocument) { throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR, null); } if (!DocumentImpl::isKidOK(this, newChild)) { throw DOM_DOMException(DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } // refChild must be a child of this node (or null) if (refChild != null && refChild->getParentNode() != this) { throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null); } // Prevent cycles in the tree // newChild cannot be ancestor of this Node, // and actually cannot be this bool treeSafe = true; for (NodeImpl *a = this; treeSafe && a != null; a = a->getParentNode()) { treeSafe = (newChild != a); } if (!treeSafe) { throw DOM_DOMException(DOM_DOMException::HIERARCHY_REQUEST_ERR, null); } } // Convert to internal type, to avoid repeated casting ChildNode * newInternal = (ChildNode *)newChild; NodeImpl *oldparent = newInternal->getParentNode(); if (oldparent != null) { oldparent->removeChild(newInternal); } // Convert to internal type, to avoid repeated casting ChildNode *refInternal = (ChildNode *)refChild; // Attach up newInternal->ownerNode = this; newInternal->isOwned(true); // Attach before and after // Note: firstChild.previousSibling == lastChild!! if (firstChild == null) { // this our first and only child firstChild = newInternal; newInternal->isFirstChild(true); newInternal->previousSibling = newInternal; } else { if (refInternal == null) { // this is an append ChildNode *lastChild = firstChild->previousSibling; lastChild->nextSibling = newInternal; newInternal->previousSibling = lastChild; firstChild->previousSibling = newInternal; } else { // this is an insert if (refChild == firstChild) { // at the head of the list firstChild->isFirstChild(false); newInternal->nextSibling = firstChild; newInternal->previousSibling = firstChild->previousSibling; firstChild->previousSibling = newInternal; firstChild = newInternal; newInternal->isFirstChild(true); } else { // somewhere in the middle ChildNode *prev = refInternal->previousSibling; newInternal->nextSibling = refInternal; prev->nextSibling = newInternal; refInternal->previousSibling = newInternal; newInternal->previousSibling = prev; } } } changed(); // update cached length if we have any if (fCachedLength != -1) { fCachedLength++; } if (fCachedChildIndex != -1) { // if we happen to insert just before the cached node, update // the cache to the new node to match the cached index if (fCachedChild == refInternal) { fCachedChild = newInternal; } else { // otherwise just invalidate the cache fCachedChildIndex = -1; } } if (this->getOwnerDocument() != null) { typedef RefVectorOf<RangeImpl> RangeImpls; RangeImpls* ranges = this->getOwnerDocument()->getRanges(); if ( ranges != null) { unsigned int sz = ranges->size(); for (unsigned int i =0; i<sz; i++) { ranges->elementAt(i)->updateRangeForInsertedNode(newInternal); } } } return newInternal; };
HTMLElementImpl *HTMLTableElementImpl::insertRow( long index, int &exceptioncode ) { // The DOM requires that we create a tbody if the table is empty // (cf DOM2TS HTMLTableElement31 test) // (note: this is different from "if the table has no sections", since we can have // <TABLE><TR>) if(!firstBody && !head && !foot && !hasChildNodes()) setTBody( new HTMLTableSectionElementImpl(docPtr(), ID_TBODY, true /* implicit */) ); //kdDebug(6030) << k_funcinfo << index << endl; // IE treats index=-1 as default value meaning 'append after last' // This isn't in the DOM. So, not implemented yet. HTMLTableSectionElementImpl* section = 0L; HTMLTableSectionElementImpl* lastSection = 0L; NodeImpl *node = firstChild(); bool append = index == -1; for ( ; node && (index>=0 || append) ; node = node->nextSibling() ) { if ( node->id() == ID_THEAD || node->id() == ID_TFOOT || node->id() == ID_TBODY ) { section = static_cast<HTMLTableSectionElementImpl *>(node); lastSection = section; //kdDebug(6030) << k_funcinfo << "section id=" << node->id() << " rows:" << section->numRows() << endl; if ( !append ) { int rows = section->numRows(); if ( rows > index ) break; else index -= rows; //kdDebug(6030) << " index is now " << index << endl; } } // Note: we now can have both TR and sections (THEAD/TBODY/TFOOT) as children of a TABLE else if ( node->id() == ID_TR ) { section = 0L; //kdDebug(6030) << k_funcinfo << "row" << endl; if (!append && !index) { // Insert row right here, before "node" HTMLTableRowElementImpl* row = new HTMLTableRowElementImpl(docPtr()); insertBefore(row, node, exceptioncode ); return row; } if ( !append ) index--; //kdDebug(6030) << " index is now " << index << endl; } section = 0L; } // Index == 0 means "insert before first row in current section" // or "append after last row" (if there's no current section anymore) if ( !section && ( index == 0 || append ) ) { section = lastSection; index = section ? section->numRows() : 0; } if ( section && ( index >= 0 || append ) ) { //kdDebug(6030) << "Inserting row into section " << section << " at index " << index << endl; return section->insertRow( index, exceptioncode ); } else { // No more sections => index is too big exceptioncode = DOMException::INDEX_SIZE_ERR; return 0L; } }
void XMLTokenizer::finish() { m_source.setFinished(true); if(!m_noErrors) { // An error occurred during parsing of the code. Display an error page to the user (the DOM // tree is created manually and includes an excerpt from the code where the error is located) // ### for multiple error messages, display the code for each (can this happen?) // Clear the document int exceptioncode = 0; while(m_doc->hasChildNodes()) static_cast< NodeImpl * >(m_doc)->removeChild(m_doc->firstChild(), exceptioncode); QString line, errorLocPtr; if(m_handler.errorLine) { QString xmlCode = m_source.data(); QTextIStream stream(&xmlCode); for(unsigned long lineno = 0; lineno < m_handler.errorLine - 1; lineno++) stream.readLine(); line = stream.readLine(); for(unsigned long colno = 0; colno < m_handler.errorCol - 1; colno++) errorLocPtr += " "; errorLocPtr += "^"; } // Create elements for display DocumentImpl *doc = m_doc; NodeImpl *html = doc->createElementNS(XHTML_NAMESPACE, "html"); NodeImpl *body = doc->createElementNS(XHTML_NAMESPACE, "body"); NodeImpl *h1 = doc->createElementNS(XHTML_NAMESPACE, "h1"); NodeImpl *headingText = doc->createTextNode(i18n("XML parsing error")); NodeImpl *errorText = doc->createTextNode(m_handler.errorProtocol()); NodeImpl *hr = 0; NodeImpl *pre = 0; NodeImpl *lineText = 0; NodeImpl *errorLocText = 0; if(!line.isNull()) { hr = doc->createElementNS(XHTML_NAMESPACE, "hr"); pre = doc->createElementNS(XHTML_NAMESPACE, "pre"); lineText = doc->createTextNode(line + "\n"); errorLocText = doc->createTextNode(errorLocPtr); } // Construct DOM tree. We ignore exceptions as we assume they will not be thrown here (due to the // fact we are using a known tag set) doc->appendChild(html, exceptioncode); html->appendChild(body, exceptioncode); if(body) body->appendChild(h1, exceptioncode); h1->appendChild(headingText, exceptioncode); body->appendChild(errorText, exceptioncode); body->appendChild(hr, exceptioncode); body->appendChild(pre, exceptioncode); if(pre) { pre->appendChild(lineText, exceptioncode); pre->appendChild(errorLocText, exceptioncode); } // Close the renderers so that they update their display correctly // ### this should not be necessary, but requires changes in the rendering code... h1->close(); if(pre) pre->close(); body->close(); m_doc->recalcStyle(NodeImpl::Inherit); m_doc->updateRendering(); end(); } else { // Parsing was successful. Now locate all html <script> tags in the document and execute them // one by one addScripts(m_doc); m_scriptsIt = new QPtrListIterator< HTMLScriptElementImpl >(m_scripts); executeScripts(); } }
void ElementImpl::recalcStyle(StyleChange change) { // ### should go away and be done in renderobject RenderStyle *_style = m_render ? m_render->style() : 0; bool hasParentRenderer = parent() ? parent()->attached() : false; #if 0 const char* debug; switch(change) { case NoChange: debug = "NoChange"; break; case NoInherit: debug= "NoInherit"; break; case Inherit: debug = "Inherit"; break; case Force: debug = "Force"; break; } qDebug("recalcStyle(%d: %s, changed: %d)[%p: %s]", change, debug, changed(), this, tagName().string().latin1()); #endif if(hasParentRenderer && (change >= Inherit || changed())) { RenderStyle *newStyle = getDocument()->styleSelector()->styleForElement(this); newStyle->ref(); StyleChange ch = diff(_style, newStyle); if(ch == Detach) { if(attached()) detach(); // ### Suboptimal. Style gets calculated again. attach(); // attach recalulates the style for all children. No need to do it twice. setChanged(false); setHasChangedChild(false); newStyle->deref(); return; } else if(ch != NoChange) { if(m_render && newStyle) { m_render->setStyle(newStyle); } } newStyle->deref(); if(change != Force) change = ch; } // If a changed attribute has ancestor dependencies, restyle all children if(changedAscendentAttribute()) { change = Force; setChangedAscendentAttribute(false); } NodeImpl *n; for(n = _first; n; n = n->nextSibling()) { if(change >= Inherit || n->isTextNode() || n->hasChangedChild() || n->changed()) { // qDebug(" (%p) calling recalcStyle on child %p/%s, change=%d", this, n, n->isElementNode() ? ((ElementImpl // *)n)->tagName().string().latin1() : n->isTextNode() ? "text" : "unknown", change ); n->recalcStyle(change); } } setChanged(false); setHasChangedChild(false); }