bool Node::hasAttributes()
{
    if (!impl) throw DOMException(DOMException::NOT_FOUND_ERR);
    if (!impl->isElementNode()) return false;
    ElementImpl* e = static_cast<ElementImpl*>(impl);
    return e->attributes(true) && e->attributes(true)->length();
}
bool XMLHandler::startElement( const QString& namespaceURI, const QString& /*localName*/, const QString& qName, const QXmlAttributes& atts )
{
    if (m_currentNode->nodeType() == Node::TEXT_NODE)
	exitText();

    ElementImpl *newElement;
    if (namespaceURI.isNull())
	newElement = m_doc->createElement(qName);
    else
	newElement = m_doc->createElementNS(namespaceURI,qName);

    // ### handle exceptions
    int i;
    for (i = 0; i < atts.length(); i++)
	newElement->setAttribute(atts.localName(i),atts.value(i));
    if (m_currentNode->addChild(newElement)) {
	if (m_view)
	    newElement->attach(m_view);
	m_currentNode = newElement;
	return TRUE;
    }
    else {
	delete newElement;
	return FALSE;
    }
}
Beispiel #3
0
void HTMLTableElementImpl::close()
{
    ElementImpl* firstBody = tFirstBody();
    if (firstBody && !firstBody->closed())
        firstBody->close();
    HTMLElementImpl::close();
}
Beispiel #4
0
ElementImpl *HTMLDocumentImpl::createElement(const DOMString &name, int *pExceptioncode)
{
    ElementImpl *e = createHTMLElement(name);
    if(e)
    {
        e->setHTMLCompat(htmlMode() != XHtml);
        return e;
    }
    return DocumentImpl::createElement(name, pExceptioncode);
}
QString NodeImpl::recursive_toHTML( ) const
{
    QString me;

    // Copy who I am into the htmlText string
    if ( nodeType() == Node::TEXT_NODE )
        me = nodeValue().string();
    else
    {   // If I am an element, not a text
        me = QChar('<') + nodeName().string();

        // print attributes
        if( nodeType() == Node::ELEMENT_NODE )
        {
            ElementImpl *el = const_cast<ElementImpl*>(static_cast<const ElementImpl *>(this));
            AttrImpl *attr;
            int exceptioncode;
            NamedNodeMapImpl *attrs = el->attributes();
            unsigned long lmap = attrs->length(exceptioncode);
            for( unsigned int j=0; j<lmap; j++ )
            {
                attr = static_cast<AttrImpl*>(attrs->item(j,exceptioncode));
                me += " " + attr->name().string() + "=\"" + attr->value().string() + "\"";
            }
        }

        // print ending bracket of start tag
        if( firstChild() == 0 )     // if element has no endtag
            me += " />";
        else                        // if element has endtag
            me += ">";
    }

    NodeImpl* n;

    if( (n = firstChild()) )
    {
        // print firstChild
        me += n->recursive_toHTML( );

        // Print my ending tag
        if ( nodeType() != Node::TEXT_NODE )
            me += "</" + nodeName().string() + ">";
    }
    // print next sibling
    if( (n = nextSibling()) )
        me += n->recursive_toHTML( );

    return me;
}
NodeImpl *ElementImpl::cloneNode(bool deep)
{
    // ### we lose the namespace here ... FIXME
    int exceptioncode;
    ElementImpl *clone = getDocument()->createElement(tagName(), exceptioncode);
    if (!clone) return 0;

    // clone attributes
    if (namedAttrMap)
        *clone->attributes() = *namedAttrMap;

    if (deep)
        cloneChildNodes(clone);
    return clone;
}
void NodeImpl::printTree(int indent)
{
    QString ind;
    QString s;
    ind.fill(' ', indent);

    // ### find out why this isn't working
    if(isElementNode())
    {
        s = ind + "<" + nodeName().string();

        ElementImpl *el = const_cast<ElementImpl*>(static_cast<const ElementImpl *>(this));
        AttrImpl *attr;
        int exceptioncode;
        NamedNodeMapImpl *attrs = el->attributes();
        unsigned long lmap = attrs->length(exceptioncode);
        for( unsigned int j=0; j<lmap; j++ )
        {
            attr = static_cast<AttrImpl*>(attrs->item(j,exceptioncode));
            s += " " + attr->name().string() + "=\"" + attr->value().string() + "\"";
        }
        if(!firstChild())
            s += " />";
        else
            s += ">";
    }
    else
        s = ind + "'" + nodeValue().string() + "'";

    kdDebug() << s << endl;

    NodeImpl *child = firstChild();
    while( child )
    {
        child->printTree(indent+2);
        child = child->nextSibling();
    }
    if(isElementNode() && firstChild())
        kdDebug() << ind << "</" << nodeName().string() << ">" << endl;
}
Beispiel #8
0
bool XMLHandler::startElement(const QString &namespaceURI, const QString & /*localName*/, const QString &qName, const QXmlAttributes &atts)
{
    if(currentNode()->nodeType() == Node::TEXT_NODE)
        exitText();

    DOMString nsURI;
    if(!namespaceURI.isNull())
        nsURI = DOMString(namespaceURI);
    else
        // No namespace declared, default to the no namespace
        nsURI = DOMString("");
    ElementImpl *newElement = m_doc->createElementNS(nsURI, qName);
    if(!newElement)
        return false;
    int i;
    for(i = 0; i < atts.length(); i++)
    {
        int exceptioncode = 0;
        QString uriString = atts.uri(i);
        QString qnString = atts.qName(i);
        fixUpNSURI(uriString, qnString);
        DOMString uri(uriString);
        DOMString qn(qnString);
        DOMString val(atts.value(i));
        newElement->setAttributeNS(uri, qn, val, exceptioncode);
        if(exceptioncode) // exception setting attributes
            return false;
    }

    if(newElement->id() == ID_SCRIPT || newElement->id() == makeId(xhtmlNamespace, ID_SCRIPT))
        static_cast< HTMLScriptElementImpl * >(newElement)->setCreatedByParser(true);

    // this is tricky. in general the node doesn't have to attach to the one it's in. as far
    // as standards go this is wrong, but there's literally thousands of documents where
    // we see <p><ul>...</ul></p>. the following code is there for those cases.
    // when we can't attach to the currently holding us node we try to attach to its parent
    bool attached = false;
    for(NodeImpl *current = currentNode(); current; current = current->parent())
    {
        attached = current->addChild(newElement);
        if(attached)
            break;
    }
    if(attached)
    {
        if(m_view && !newElement->attached() && !m_doc->hasPendingSheets())
            newElement->attach();
        pushNode(newElement);
        return true;
    }
    else
    {
        delete newElement;
        return false;
    }

    // ### DOM spec states: "if there is no markup inside an element's content, the text is contained in a
    // single object implementing the Text interface that is the only child of the element."... do we
    // need to ensure that empty elements always have an empty text child?
}
Beispiel #9
0
CSSStyleDeclarationImpl *Editor::selectionComputedStyle(NodeImpl *&nodeToRemove) const
{
    nodeToRemove = 0;

    if (!m_part->xmlDocImpl()) {
        return 0;
    }

    EditorContext *ctx = m_part->editorContext();
    if (ctx->m_selection.state() == Selection::NONE) {
        return 0;
    }

    Range range(ctx->m_selection.toRange());
    Position pos(range.startContainer().handle(), range.startOffset());
    assert(pos.notEmpty());
    ElementImpl *elem = pos.element();
    ElementImpl *styleElement = elem;
    int exceptionCode = 0;

    if (m_typingStyle) {
        styleElement = m_part->xmlDocImpl()->createHTMLElement("SPAN");
//     assert(exceptionCode == 0);

        styleElement->setAttribute(ATTR_STYLE, m_typingStyle->cssText().implementation());
//     assert(exceptionCode == 0);

        TextImpl *text = m_part->xmlDocImpl()->createEditingTextNode("");
        styleElement->appendChild(text, exceptionCode);
        assert(exceptionCode == 0);

        elem->appendChild(styleElement, exceptionCode);
        assert(exceptionCode == 0);

        nodeToRemove = styleElement;
    }

    return new RenderStyleDeclarationImpl(styleElement);
}
bool KHTMLParser::insertNode(NodeImpl *n, bool flat)
{
    int id = n->id();

    // let's be stupid and just try to insert it.
    // this should work if the document is wellformed
#ifdef PARSER_DEBUG
    NodeImpl *tmp = current;
#endif
    NodeImpl *newNode = current->addChild(n);
    if ( newNode ) {
#ifdef PARSER_DEBUG
        kdDebug( 6035 ) << "added " << n->nodeName().string() << " to " << tmp->nodeName().string() << ", new current=" << newNode->nodeName().string() << endl;
#endif
        // don't push elements without end tag on the stack
        if(tagPriority[id] != 0 && !flat)
        {
            pushBlock(id, tagPriority[id]);
            if (newNode == current)
                popBlock(id);
            else
                setCurrent(newNode);
#if SPEED_DEBUG < 2
            if(!n->attached() && HTMLWidget)
                n->attach();
#endif
        }
        else {
#if SPEED_DEBUG < 2
            if(!n->attached() && HTMLWidget)
                n->attach();
            if (n->maintainsState()) {
                document->document()->registerMaintainsState(n);
                QStringList &states = document->document()->restoreState();
                if (!states.isEmpty())
                    n->restoreState(states);
            }
            n->closeRenderer();
#endif
        }

        return true;
    } else {
#ifdef PARSER_DEBUG
        kdDebug( 6035 ) << "ADDING NODE FAILED!!!! current = " << current->nodeName().string() << ", new = " << n->nodeName().string() << endl;
#endif
        // error handling...
        HTMLElementImpl *e;
        bool handled = false;

        // switch according to the element to insert
        switch(id)
        {
        case ID_TR:
        case ID_TH:
        case ID_TD:
            if (inStrayTableContent && !isTableRelatedTag(current->id())) {
                // pop out to the nearest enclosing table-related tag.
                while (!isTableRelatedTag(current->id()))
                    popOneBlock();
                return insertNode(n);
            }
            break;
        case ID_COMMENT:
            break;
        case ID_HEAD:
            // ### alllow not having <HTML> in at all, as per HTML spec
            if (!current->isDocumentNode() && current->id() != ID_HTML )
                return false;
            break;
        // We can deal with a base, meta and link element in the body, by just adding the element to head.
        case ID_META:
        case ID_LINK:
        case ID_BASE:
            if( !head )
                createHead();
            if( head ) {
                if ( head->addChild(n) ) {
#if SPEED_DEBUG < 2
                    if(!n->attached() && HTMLWidget)
                        n->attach();
#endif
                    return true;
                } else {
                    return false;
                }
            }
            break;
        case ID_HTML:
            if (!current->isDocumentNode() ) {
                if ( doc()->firstChild()->id() == ID_HTML) {
                    // we have another <HTML> element.... apply attributes to existing one
                    // make sure we don't overwrite already existing attributes
                    NamedAttrMapImpl *map = static_cast<ElementImpl*>(n)->attributes(true);
                    NamedAttrMapImpl *bmap = static_cast<ElementImpl*>(doc()->firstChild())->attributes(false);
                    bool changed = false;
                    for (unsigned long l = 0; map && l < map->length(); ++l) {
                        AttributeImpl* it = map->attributeItem(l);
                        changed = !bmap->getAttributeItem(it->id());
                        bmap->insertAttribute(it->clone(false));
                    }
                    if ( changed )
                        doc()->recalcStyle( NodeImpl::Inherit );
                }
                return false;
            }
            break;
        case ID_TITLE:
        case ID_STYLE:
            if ( !head )
                createHead();
            if ( head ) {
                DOM::NodeImpl *newNode = head->addChild(n);
                if ( newNode ) {
                    pushBlock(id, tagPriority[id]);
                    setCurrent(newNode);
#if SPEED_DEBUG < 2
                    if(!n->attached() && HTMLWidget)
                        n->attach();
#endif
                } else {
#ifdef PARSER_DEBUG
                    kdDebug( 6035 ) << "adding style before to body failed!!!!" << endl;
#endif
                    discard_until = ID_STYLE + ID_CLOSE_TAG;
                    return false;
                }
                return true;
            } else if(inBody) {
                discard_until = ID_STYLE + ID_CLOSE_TAG;
                return false;
            }
            break;
        // SCRIPT and OBJECT are allowed in the body.
        case ID_BODY:
            if(inBody && doc()->body()) {
                // we have another <BODY> element.... apply attributes to existing one
                // make sure we don't overwrite already existing attributes
                // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor>
                NamedAttrMapImpl *map = static_cast<ElementImpl*>(n)->attributes(true);
                NamedAttrMapImpl *bmap = doc()->body()->attributes(false);
                bool changed = false;
                for (unsigned long l = 0; map && l < map->length(); ++l) {
                    AttributeImpl* it = map->attributeItem(l);
                    changed = !bmap->getAttributeItem(it->id());
                    bmap->insertAttribute(it->clone(false));
                }
                if ( changed )
                    doc()->recalcStyle( NodeImpl::Inherit );
            } else if ( current->isDocumentNode() )
                break;
            return false;
            break;

        // the following is a hack to move non rendered elements
        // outside of tables.
        // needed for broken constructs like <table><form ...><tr>....
        case ID_INPUT:
        {
            ElementImpl *e = static_cast<ElementImpl *>(n);
            DOMString type = e->getAttribute(ATTR_TYPE);

            if ( strcasecmp( type, "hidden" ) == 0 && form) {
                form->addChild(n);
#if SPEED_DEBUG < 2
                if(!n->attached() && HTMLWidget)
                    n->attach();
#endif
                return true;
            }
            break;
        }
        case ID_TEXT:
            // ignore text inside the following elements.
            switch(current->id())
            {
            case ID_SELECT:
                return false;
            default:
                ;
                // fall through!!
            };
            break;
        case ID_DD:
        case ID_DT:
            e = new HTMLDListElementImpl(document);
            if ( insertNode(e) ) {
                insertNode(n);
                return true;
            }
            break;
        case ID_AREA:
        {
            if(map)
            {
                map->addChild(n);
#if SPEED_DEBUG < 2
                if(!n->attached() && HTMLWidget)
                    n->attach();
#endif
                handled = true;
            }
            else
                return false;
            return true;
        }
        default:
            break;
        }

        // switch on the currently active element
        switch(current->id())
        {
        case ID_HTML:
            switch(id)
            {
            case ID_SCRIPT:
            case ID_STYLE:
            case ID_META:
            case ID_LINK:
            case ID_OBJECT:
            case ID_EMBED:
            case ID_TITLE:
            case ID_ISINDEX:
            case ID_BASE:
                if(!head) {
                    head = new HTMLHeadElementImpl(document);
                    e = head;
                    insertNode(e);
                    handled = true;
                }
                break;
            case ID_TEXT: {
                TextImpl *t = static_cast<TextImpl *>(n);
                if (t->containsOnlyWhitespace())
                    return false;
                /* Fall through to default */
            }
            default:
                if ( haveFrameSet ) break;
                e = new HTMLBodyElementImpl(document);
                startBody();
                insertNode(e);
                handled = true;
                break;
            }
            break;
        case ID_HEAD:
            // we can get here only if the element is not allowed in head.
            if (id == ID_HTML)
                return false;
            else {
                // This means the body starts here...
                if ( haveFrameSet ) break;
                popBlock(ID_HEAD);
                e = new HTMLBodyElementImpl(document);
                startBody();
                insertNode(e);
                handled = true;
            }
            break;
        case ID_BODY:
            break;
        case ID_CAPTION:
            // Illegal content in a caption. Close the caption and try again.
            popBlock(ID_CAPTION);
            switch( id ) {
            case ID_THEAD:
            case ID_TFOOT:
            case ID_TBODY:
            case ID_TR:
            case ID_TD:
            case ID_TH:
                return insertNode(n, flat);
            }
            break;
        case ID_TABLE:
        case ID_THEAD:
        case ID_TFOOT:
        case ID_TBODY:
        case ID_TR:
            switch(id)
            {
            case ID_TABLE:
                popBlock(ID_TABLE); // end the table
                handled = true;      // ...and start a new one
                break;
            case ID_TEXT:
            {
                TextImpl *t = static_cast<TextImpl *>(n);
                if (t->containsOnlyWhitespace())
                    return false;
                DOMStringImpl *i = t->string();
                unsigned int pos = 0;
                while(pos < i->l && ( *(i->s+pos) == QChar(' ') ||
                                      *(i->s+pos) == QChar(0xa0))) pos++;
                if(pos == i->l)
                    break;
            }
            default:
            {
                NodeImpl *node = current;
                NodeImpl *parent = node->parentNode();

                NodeImpl *parentparent = parent->parentNode();

                if (n->isTextNode() ||
                        ( node->id() == ID_TR &&
                          ( parent->id() == ID_THEAD ||
                            parent->id() == ID_TBODY ||
                            parent->id() == ID_TFOOT ) && parentparent->id() == ID_TABLE ) ||
                        ( !checkChild( ID_TR, id ) && ( node->id() == ID_THEAD || node->id() == ID_TBODY || node->id() == ID_TFOOT ) &&
                          parent->id() == ID_TABLE ))
                {
                    node = (node->id() == ID_TABLE) ? node :
                           ((node->id() == ID_TR) ? parentparent : parent);
                    NodeImpl *parent = node->parentNode();
                    int exceptioncode = 0;
                    parent->insertBefore( n, node, exceptioncode );
                    if ( exceptioncode ) {
#ifdef PARSER_DEBUG
                        kdDebug( 6035 ) << "adding content before table failed!" << endl;
#endif
                        break;
                    }
                    if (n->isElementNode() && tagPriority[id] != 0 &&
                            !flat && endTag[id] != DOM::FORBIDDEN)
                    {
                        pushBlock(id, tagPriority[id]);
                        setCurrent(n);
                        inStrayTableContent++;
                        blockStack->strayTableContent = true;
                    }
                    return true;
                }

                if ( current->id() == ID_TR )
                    e = new HTMLTableCellElementImpl(document, ID_TD);
                else if ( current->id() == ID_TABLE )
                    e = new HTMLTableSectionElementImpl( document, ID_TBODY, true /* implicit */ );
                else
                    e = new HTMLTableRowElementImpl( document );

                insertNode(e);
                handled = true;
                break;
            } // end default
            } // end switch
            break;
        case ID_OBJECT:
            discard_until = id + ID_CLOSE_TAG;
            return false;
        case ID_UL:
        case ID_OL:
        case ID_DIR:
        case ID_MENU:
            e = new HTMLDivElementImpl(document);
            insertNode(e);
            handled = true;
            break;
        case ID_DL:
            popBlock(ID_DL);
            handled = true;
            break;
        case ID_DT:
            popBlock(ID_DT);
            handled = true;
            break;
        case ID_SELECT:
            if( n->isInline() )
                return false;
            break;
        case ID_P:
        case ID_H1:
        case ID_H2:
        case ID_H3:
        case ID_H4:
        case ID_H5:
        case ID_H6:
            if(!n->isInline())
            {
                popBlock(current->id());
                handled = true;
            }
            break;
        case ID_OPTION:
        case ID_OPTGROUP:
            if (id == ID_OPTGROUP)
            {
                popBlock(current->id());
                handled = true;
            }
            else if(id == ID_SELECT)
            {
                // IE treats a nested select as </select>. Let's do the same
                popBlock( ID_SELECT );
                break;
            }
            break;
        // head elements in the body should be ignored.
        case ID_ADDRESS:
            popBlock(ID_ADDRESS);
            handled = true;
            break;
        case ID_COLGROUP:
            if (id != ID_TEXT) {
                popBlock(ID_COLGROUP);
                handled = true;
            }
            break;
        case ID_FONT:
            popBlock(ID_FONT);
            handled = true;
            break;
        default:
            if(current->isDocumentNode())
            {
                if(current->firstChild() == 0) {
                    e = new HTMLHtmlElementImpl(document);
                    insertNode(e);
                    handled = true;
                }
            }
            else if(current->isInline())
            {
                popInlineBlocks();
                handled = true;
            }
        }

        // if we couldn't handle the error, just rethrow the exception...
        if(!handled)
        {
            //kdDebug( 6035 ) << "Exception handler failed in HTMLPArser::insertNode()" << endl;
            return false;
        }

        return insertNode(n);
    }
}
void KHTMLParser::parseToken(Token *t)
{
    if (t->id > 2*ID_CLOSE_TAG)
    {
        kdDebug( 6035 ) << "Unknown tag!! tagID = " << t->id << endl;
        return;
    }
    if(discard_until) {
        if(t->id == discard_until)
            discard_until = 0;

        // do not skip </iframe>
        if ( discard_until || current->id() + ID_CLOSE_TAG != t->id )
            return;
    }

#ifdef PARSER_DEBUG
    kdDebug( 6035 ) << "\n\n==> parser: processing token " << getTagName(t->id).string() << "(" << t->id << ")"
                    << " current = " << getTagName(current->id()).string() << "(" << current->id() << ")" << endl;
    kdDebug(6035) << " inBody=" << inBody << " haveFrameSet=" << haveFrameSet << endl;
#endif

    // holy shit. apparently some sites use </br> instead of <br>
    // be compatible with IE and NS
    if(t->id == ID_BR+ID_CLOSE_TAG && document->document()->inCompatMode())
        t->id -= ID_CLOSE_TAG;

    if(t->id > ID_CLOSE_TAG)
    {
        processCloseTag(t);
        return;
    }

    // ignore spaces, if we're not inside a paragraph or other inline code
    if( t->id == ID_TEXT && t->text ) {
        if(inBody && !skipMode() && current->id() != ID_STYLE
                && current->id() != ID_TITLE && current->id() != ID_SCRIPT &&
                !t->text->containsOnlyWhitespace())
            haveContent = true;
#ifdef PARSER_DEBUG
        kdDebug(6035) << "length="<< t->text->l << " text='" << QConstString(t->text->s, t->text->l).string() << "'" << endl;
#endif
    }

    NodeImpl *n = getElement(t);
    // just to be sure, and to catch currently unimplemented stuff
    if(!n)
        return;

    // set attributes
    if(n->isElementNode())
    {
        ElementImpl *e = static_cast<ElementImpl *>(n);
        e->setAttributeMap(t->attrs);

        // take care of optional close tags
        if(endTag[e->id()] == DOM::OPTIONAL)
            popBlock(t->id);
    }

    // if this tag is forbidden inside the current context, pop
    // blocks until we are allowed to add it...
    while(forbiddenTag[t->id]) {
#ifdef PARSER_DEBUG
        kdDebug( 6035 ) << "t->id: " << t->id << " is forbidden :-( " << endl;
#endif
        popOneBlock();
    }

    if (!insertNode(n, t->flat))
    {
        // we couldn't insert the node...

        if(n->isElementNode())
        {
            ElementImpl *e = static_cast<ElementImpl *>(n);
            e->setAttributeMap(0);
        }

#ifdef PARSER_DEBUG
        kdDebug( 6035 ) << "insertNode failed current=" << current->id() << ", new=" << n->id() << "!" << endl;
#endif
        if (map == n)
        {
#ifdef PARSER_DEBUG
            kdDebug( 6035 ) << "  --> resetting map!" << endl;
#endif
            map = 0;
        }
        if (form == n)
        {
#ifdef PARSER_DEBUG
            kdDebug( 6035 ) << "   --> resetting form!" << endl;
#endif
            form = 0;
        }
        delete n;
    }
}
bool KHTMLParser::insertNode(NodeImpl *n, bool flat)
{
    int id = n->id();

    // let's be stupid and just try to insert it.
    // this should work if the document is wellformed
#ifdef PARSER_DEBUG
    NodeImpl *tmp = current;
#endif
    NodeImpl *newNode = current->addChild(n);
    if ( newNode ) {
#ifdef PARSER_DEBUG
        kdDebug( 6035 ) << "added " << n->nodeName().string() << " to " << tmp->nodeName().string() << ", new current=" << newNode->nodeName().string() << endl;
#endif

	// have to do this here (and not when creating the node, as we don't know before where we add the LI element to.
	if ( id == ID_LI && n->isElementNode() ) {
	    int cid = current->id();
	    if ( cid != ID_UL && cid != ID_OL )
	    static_cast<HTMLElementImpl*>(n)->addCSSProperty(CSS_PROP_LIST_STYLE_POSITION, CSS_VAL_INSIDE);
	}

	// don't push elements without end tag on the stack
        if(tagPriority[id] != 0 && !flat) {
#if SPEED_DEBUG < 2
            if(!n->attached() && HTMLWidget )
                n->attach();
#endif
	    if(n->isInline()) m_inline = true;
            pushBlock(id, tagPriority[id]);
            current = newNode;
        } else {
#if SPEED_DEBUG < 2
            if(!n->attached() && HTMLWidget)
                n->attach();
            if (n->maintainsState()) {
                document->document()->registerMaintainsState(n);
                QString state(document->document()->nextState());
                if (!state.isNull()) n->restoreState(state);
            }
            if(n->renderer())
                n->renderer()->close();
#endif
	    if(n->isInline()) m_inline = true;
        }

#if SPEED_DEBUG < 1
        if(tagPriority[id] == 0 && n->renderer())
            n->renderer()->calcMinMaxWidth();
#endif
        return true;
    } else {
#ifdef PARSER_DEBUG
        kdDebug( 6035 ) << "ADDING NODE FAILED!!!! current = " << current->nodeName().string() << ", new = " << n->nodeName().string() << endl;
#endif
        // error handling...
        HTMLElementImpl *e;
        bool handled = false;

	// never create anonymous objects just to hold a space.
	if ( id == ID_TEXT &&
	     static_cast<TextImpl *>(n)->string()->l == 1 &&
	     static_cast<TextImpl *>(n)->string()->s[0] == " " )
	    return false;

        // switch according to the element to insert
        switch(id)
        {
        case ID_COMMENT:
            break;
        case ID_HEAD:
            // ### alllow not having <HTML> in at all, as per HTML spec
            if (!current->isDocumentNode() && current->id() != ID_HTML )
                return false;
            break;
        case ID_META:
        case ID_LINK:
        case ID_ISINDEX:
        case ID_BASE:
            if( !head )
                createHead();
            if( head ) {
                if ( head->addChild(n) ) {
#if SPEED_DEBUG < 2
                    if(!n->attached() && HTMLWidget)
                        n->attach();
#endif
		}

                return true;
            }

            break;
        case ID_HTML:
            if (!current->isDocumentNode() ) {
		if ( doc()->firstChild()->id() == ID_HTML) {
		    // we have another <HTML> element.... apply attributes to existing one
		    // make sure we don't overwrite already existing attributes
		    NamedAttrMapImpl *map = static_cast<ElementImpl*>(n)->attributes(true);
		    NamedAttrMapImpl *bmap = static_cast<ElementImpl*>(doc()->firstChild())->attributes(false);
		    bool changed = false;
		    for (unsigned long l = 0; map && l < map->length(); ++l) {
			AttributeImpl* it = map->attributeItem(l);
			changed = !bmap->getAttributeItem(it->id());
			bmap->insertAttribute(new AttributeImpl(it->id(), it->val()));
		    }
		    if ( changed )
			doc()->recalcStyle( NodeImpl::Inherit );
		}
                return false;
	    }
            break;
        case ID_TITLE:
        case ID_STYLE:
            if ( !head )
                createHead();
            if ( head ) {
                DOM::NodeImpl *newNode = head->addChild(n);
                if ( newNode ) {
                    pushBlock(id, tagPriority[id]);
                    current = newNode;
#if SPEED_DEBUG < 2
		    if(!n->attached() && HTMLWidget)
                        n->attach();
#endif
                } else {
#ifdef PARSER_DEBUG
                    kdDebug( 6035 ) << "adding style before to body failed!!!!" << endl;
#endif
                    discard_until = ID_STYLE + ID_CLOSE_TAG;
                    return false;
                }
                return true;
            } else if(inBody) {
                discard_until = id + ID_CLOSE_TAG;
                return false;
            }
            break;
        case ID_SCRIPT:
            // if we failed to insert it, go into skip mode
            discard_until = id + ID_CLOSE_TAG;
            break;
        case ID_BODY:
            if(inBody && doc()->body()) {
                // we have another <BODY> element.... apply attributes to existing one
                // make sure we don't overwrite already existing attributes
                // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor>
                NamedAttrMapImpl *map = static_cast<ElementImpl*>(n)->attributes(true);
                NamedAttrMapImpl *bmap = doc()->body()->attributes(false);
                bool changed = false;
                for (unsigned long l = 0; map && l < map->length(); ++l) {
                    AttributeImpl* it = map->attributeItem(l);
                    changed = !bmap->getAttributeItem(it->id());
                    bmap->insertAttribute(new AttributeImpl(it->id(), it->val()));
                }
                if ( changed )
                    doc()->recalcStyle( NodeImpl::Inherit );
            } else if ( current->isDocumentNode() )
                break;
            return false;
            break;

            // the following is a hack to move non rendered elements
            // outside of tables.
            // needed for broken constructs like <table><form ...><tr>....
        case ID_INPUT:
        {
            ElementImpl *e = static_cast<ElementImpl *>(n);
            DOMString type = e->getAttribute(ATTR_TYPE);

            if ( strcasecmp( type, "hidden" ) != 0 )
                break;
            // Fall through!
        }
        case ID_TEXT:
            // ignore text inside the following elements.
            switch(current->id())
            {
            case ID_SELECT:
                return false;
            default:
                ;
                // fall through!!
            };
            break;
        case ID_DD:
        case ID_DT:
            e = new HTMLDListElementImpl(document);
            if ( insertNode(e) ) {
                insertNode(n);
                return true;
            }
            break;
        case ID_AREA:
        {
            if(map)
            {
                map->addChild(n);
#if SPEED_DEBUG < 2
                if(!n->attached() && HTMLWidget)
		    n->attach();
#endif
                handled = true;
            }
            else
                return false;
            return true;
        }
        case ID_TD:
        case ID_TH:
            // lets try to close the konqblock
            if ( haveKonqBlock ) {
                popBlock( ID__KONQBLOCK );
                haveKonqBlock = false;
                return insertNode( n );
            }
        default:
            break;
        }

        // switch on the currently active element
        switch(current->id())
        {
        case ID_HTML:
            switch(id)
            {
            case ID_SCRIPT:
            case ID_STYLE:
            case ID_META:
            case ID_LINK:
            case ID_OBJECT:
            case ID_EMBED:
            case ID_TITLE:
            case ID_ISINDEX:
            case ID_BASE:
                if(!head) {
                    head = new HTMLHeadElementImpl(document);
                    e = head;
                    insertNode(e);
                    handled = true;
                }
                break;
            default:
                if ( haveFrameSet ) break;
                e = new HTMLBodyElementImpl(document);
                startBody();
                insertNode(e);
                handled = true;
                break;
            }
            break;
        case ID_HEAD:
            // we can get here only if the element is not allowed in head.
            if (id == ID_HTML)
                return false;
            else {
                // This means the body starts here...
                if ( haveFrameSet ) break;
                popBlock(ID_HEAD);
                e = new HTMLBodyElementImpl(document);
                startBody();
                insertNode(e);
                handled = true;
            }
            break;
        case ID_BODY:
            break;
        case ID__KONQBLOCK:
            switch( id ) {
            case ID_THEAD:
            case ID_TFOOT:
            case ID_TBODY:
            case ID_TR:
            case ID_TD:
            case ID_TH:
                // now the actual table contents starts
                // lets close our anonymous block before the table
                // and go ahead!
                popBlock( ID__KONQBLOCK );
                haveKonqBlock = false;
                handled = checkChild( current->id(), id );
                break;
            default:
                break;
            }
            break;
        case ID_TABLE:
        case ID_THEAD:
        case ID_TFOOT:
        case ID_TBODY:
        case ID_TR:
            switch(id)
            {
            case ID_TABLE:
                popBlock(ID_TABLE); // end the table
                handled = checkChild( current->id(), id);
                break;
            case ID_TEXT:
            {
                TextImpl *t = static_cast<TextImpl *>(n);
                DOMStringImpl *i = t->string();
                unsigned int pos = 0;
                while(pos < i->l && ( *(i->s+pos) == QChar(' ') ||
                                      *(i->s+pos) == QChar(0xa0))) pos++;
                if(pos == i->l)
                    break;
            }
            default:
            {
                NodeImpl *node = current;
                NodeImpl *parent = node->parentNode();

                NodeImpl *parentparent = parent->parentNode();

                if(( node->id() == ID_TR &&
                     ( parent->id() == ID_THEAD ||
                       parent->id() == ID_TBODY ||
                       parent->id() == ID_TFOOT ) && parentparent->id() == ID_TABLE ) ||
                   ( !checkChild( ID_TR, id ) && ( node->id() == ID_THEAD || node->id() == ID_TBODY || node->id() == ID_TFOOT ) &&
                     parent->id() == ID_TABLE ) )
                {
                    node = ( node->id() == ID_TR ) ? parentparent : parent;
                    NodeImpl *parent = node->parentNode();
                    int exceptioncode = 0;
                    NodeImpl *container = new HTMLGenericElementImpl( document, ID__KONQBLOCK );
                    parent->insertBefore( container, node, exceptioncode );
                    if ( exceptioncode ) {
#ifdef PARSER_DEBUG
                        kdDebug( 6035 ) << "adding anonymous container before table failed!" << endl;
#endif
                        break;
                    }
                    if ( !container->attached() && HTMLWidget )
			container->attach();
                    pushBlock( ID__KONQBLOCK, tagPriority[ID__KONQBLOCK] );
                    haveKonqBlock = true;
                    current = container;
                    handled = true;
                    break;
                }

                if ( current->id() == ID_TR )
                    e = new HTMLTableCellElementImpl(document, ID_TD);
                else if ( current->id() == ID_TABLE )
                    e = new HTMLTableSectionElementImpl( document, ID_TBODY, true /* implicit */ );
                else
                    e = new HTMLTableRowElementImpl( document );

                insertNode(e);
                handled = true;
                break;
            } // end default
            } // end switch
            break;
        case ID_OBJECT:
            discard_until = id + ID_CLOSE_TAG;
            return false;
        case ID_UL:
        case ID_OL:
        case ID_DIR:
        case ID_MENU:
            e = new HTMLLIElementImpl(document);
            e->addCSSProperty(CSS_PROP_LIST_STYLE_TYPE, CSS_VAL_NONE);
            insertNode(e);
            handled = true;
            break;
        case ID_SELECT:
            if( n->isInline() )
                return false;
            break;
        case ID_P:
        case ID_H1:
        case ID_H2:
        case ID_H3:
        case ID_H4:
        case ID_H5:
        case ID_H6:
            if(!n->isInline())
            {
                popBlock(current->id());
                handled = true;
            }
            break;
        case ID_OPTION:
            if (id == ID_OPTGROUP)
            {
                popBlock(ID_OPTION);
                handled = true;
            }
            else if(id == ID_SELECT)
            {
                // IE treats a nested select as </select>. Let's do the same
                popBlock( ID_SELECT );
                break;
            }
            break;
            // head elements in the body should be ignored.

        case ID_DL:
        case ID_DT:
        case ID_ADDRESS:
        case ID_COLGROUP:
        case ID_FONT:
        case ID_CAPTION:
            popBlock(current->id());
            handled = true;
            break;
        default:
            if(current->isDocumentNode())
            {
                if(current->firstChild() == 0) {
                    e = new HTMLHtmlElementImpl(document);
                    insertNode(e);
                    handled = true;
                }
            }
            else if(current->isInline())
            {
                popInlineBlocks();
                handled = true;
            }
        }

        // if we couldn't handle the error, just rethrow the exception...
        if(!handled)
        {
            //kdDebug( 6035 ) << "Exception handler failed in HTMLPArser::insertNode()" << endl;
            return false;
        }

        return insertNode(n);
    }
}