nsresult
txMozillaXMLOutput::endHTMLElement(nsIContent* aElement)
{
    nsIAtom *atom = aElement->Tag();

    if (mTableState == ADDED_TBODY) {
        NS_ASSERTION(atom == txHTMLAtoms::tbody,
                     "Element flagged as added tbody isn't a tbody");
        PRUint32 last = mCurrentNodeStack.Count() - 1;
        NS_ASSERTION(last != (PRUint32)-1, "empty stack");

        mCurrentNode = mCurrentNodeStack.SafeObjectAt(last);
        mCurrentNodeStack.RemoveObjectAt(last);
        mTableState = static_cast<TableState>
                                 (NS_PTR_TO_INT32(mTableStateStack.pop()));

        return NS_OK;
    }
    else if (mCreatingNewDocument && atom == txHTMLAtoms::meta) {
        // handle HTTP-EQUIV data
        nsAutoString httpEquiv;
        aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::httpEquiv, httpEquiv);
        if (!httpEquiv.IsEmpty()) {
            nsAutoString value;
            aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::content, value);
            if (!value.IsEmpty()) {
                ToLowerCase(httpEquiv);
                nsCOMPtr<nsIAtom> header = do_GetAtom(httpEquiv);
                processHTTPEquiv(header, value);
            }
        }
    }
    
    return NS_OK;
}
nsresult
txMozillaXMLOutput::endHTMLElement(nsIContent* aElement)
{
    nsIAtom *atom = aElement->Tag();

    if (mTableState == ADDED_TBODY) {
        NS_ASSERTION(atom == txHTMLAtoms::tbody,
                     "Element flagged as added tbody isn't a tbody");
        PRUint32 last = mCurrentNodeStack.Count() - 1;
        NS_ASSERTION(last != (PRUint32)-1, "empty stack");

        mCurrentNode = mCurrentNodeStack.SafeObjectAt(last);
        mCurrentNodeStack.RemoveObjectAt(last);
        mTableState = static_cast<TableState>
                                 (NS_PTR_TO_INT32(mTableStateStack.pop()));

        return NS_OK;
    }
    else if (mCreatingNewDocument && atom == txHTMLAtoms::base &&
             !mHaveBaseElement) {
        // The first base wins
        mHaveBaseElement = PR_TRUE;

        nsAutoString value;
        aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::target, value);
        mDocument->SetBaseTarget(value);

        aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::href, value);
        nsCOMPtr<nsIURI> baseURI;
        NS_NewURI(getter_AddRefs(baseURI), value, nsnull);

        if (baseURI) {
            mDocument->SetBaseURI(baseURI); // The document checks if it is legal to set this base
        }
    }
    else if (mCreatingNewDocument && atom == txHTMLAtoms::meta) {
        // handle HTTP-EQUIV data
        nsAutoString httpEquiv;
        aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::httpEquiv, httpEquiv);
        if (!httpEquiv.IsEmpty()) {
            nsAutoString value;
            aElement->GetAttr(kNameSpaceID_None, txHTMLAtoms::content, value);
            if (!value.IsEmpty()) {
                ToLowerCase(httpEquiv);
                nsCOMPtr<nsIAtom> header = do_GetAtom(httpEquiv);
                processHTTPEquiv(header, value);
            }
        }
    }
    
    return NS_OK;
}
void txMozillaXMLOutput::endHTMLElement(nsIDOMElement* aElement)
{
    nsresult rv;
    nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
    NS_ASSERTION(content, "Can't QI to nsIContent");

    nsIAtom *atom = content->Tag();

    if (mTableState == ADDED_TBODY) {
        NS_ASSERTION(atom == txHTMLAtoms::tbody,
                     "Element flagged as added tbody isn't a tbody");
        nsCOMPtr<nsIDOMNode> parent;
        mCurrentNode->GetParentNode(getter_AddRefs(parent));
        mCurrentNode = parent;
        mTableState = NS_STATIC_CAST(TableState,
                                     NS_PTR_TO_INT32(mTableStateStack.pop()));

        return;
    }

    // Load scripts
    if (mNotifier && atom == txHTMLAtoms::script) {
        // Add this script element to the array of loading script elements.
        nsCOMPtr<nsIScriptElement> scriptElement =
            do_QueryInterface(mCurrentNode);
        NS_ASSERTION(scriptElement, "Need script element");
        mNotifier->AddScriptElement(scriptElement);
    }
    // Set document title
    else if (mCreatingNewDocument &&
             atom == txHTMLAtoms::title && !mHaveTitleElement) {
        // The first title wins
        mHaveTitleElement = PR_TRUE;
        nsCOMPtr<nsIDOMNSDocument> domDoc = do_QueryInterface(mDocument);
        nsCOMPtr<nsIDOMNode> textNode;
        aElement->GetFirstChild(getter_AddRefs(textNode));
        if (domDoc && textNode) {
            nsAutoString text;
            textNode->GetNodeValue(text);
            text.CompressWhitespace();
            domDoc->SetTitle(text);
        }
    }
    else if (mCreatingNewDocument && atom == txHTMLAtoms::base &&
             !mHaveBaseElement) {
        // The first base wins
        mHaveBaseElement = PR_TRUE;

        nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
        NS_ASSERTION(doc, "document doesn't implement nsIDocument");
        nsAutoString value;
        content->GetAttr(kNameSpaceID_None, txHTMLAtoms::target, value);
        doc->SetBaseTarget(value);

        content->GetAttr(kNameSpaceID_None, txHTMLAtoms::href, value);
        nsCOMPtr<nsIURI> baseURI;
        rv = NS_NewURI(getter_AddRefs(baseURI), value, nsnull);
        if (NS_FAILED(rv))
            return;
        doc->SetBaseURI(baseURI); // The document checks if it is legal to set this base
    }
    else if (mCreatingNewDocument && atom == txHTMLAtoms::meta) {
        // handle HTTP-EQUIV data
        nsAutoString httpEquiv;
        content->GetAttr(kNameSpaceID_None, txHTMLAtoms::httpEquiv, httpEquiv);
        if (httpEquiv.IsEmpty())
            return;

        nsAutoString value;
        content->GetAttr(kNameSpaceID_None, txHTMLAtoms::content, value);
        if (value.IsEmpty())
            return;
        
        TX_ToLowerCase(httpEquiv);
        nsCOMPtr<nsIAtom> header = do_GetAtom(httpEquiv);
        processHTTPEquiv(header, value);
    }
}