예제 #1
0
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;
    }
}
예제 #3
0
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();
    }
}
예제 #4
0
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);
}