void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
{
    ASSERT(token->type() == HTMLToken::StartTag);
    // Normally HTMLElementStack is responsible for calling finishParsingChildren,
    // but self-closing elements are never in the element stack so the stack
    // doesn't get a chance to tell them that we're done parsing their children.
    attachLater(currentNode(), createHTMLElement(token), true);
    // FIXME: Do we want to acknowledge the token's self-closing flag?
    // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#acknowledge-self-closing-flag
}
nsresult
txMozillaXMLOutput::startHTMLElement(nsIContent* aElement, PRBool aIsHTML)
{
    nsresult rv = NS_OK;
    nsIAtom *atom = aElement->Tag();

    if ((atom != txHTMLAtoms::tr || !aIsHTML) &&
        NS_PTR_TO_INT32(mTableStateStack.peek()) == ADDED_TBODY) {
        PRUint32 last = mCurrentNodeStack.Count() - 1;
        NS_ASSERTION(last != (PRUint32)-1, "empty stack");

        mCurrentNode = mCurrentNodeStack.SafeObjectAt(last);
        mCurrentNodeStack.RemoveObjectAt(last);
        mTableStateStack.pop();
    }

    if (atom == txHTMLAtoms::table && aIsHTML) {
        mTableState = TABLE;
    }
    else if (atom == txHTMLAtoms::tr && aIsHTML &&
             NS_PTR_TO_INT32(mTableStateStack.peek()) == TABLE) {
        nsCOMPtr<nsIContent> tbody;
        rv = createHTMLElement(nsGkAtoms::tbody, getter_AddRefs(tbody));
        NS_ENSURE_SUCCESS(rv, rv);

        rv = mCurrentNode->AppendChildTo(tbody, PR_TRUE);
        NS_ENSURE_SUCCESS(rv, rv);

        rv = mTableStateStack.push(NS_INT32_TO_PTR(ADDED_TBODY));
        NS_ENSURE_SUCCESS(rv, rv);

        if (!mCurrentNodeStack.AppendObject(tbody)) {
            return NS_ERROR_OUT_OF_MEMORY;
        }

        mCurrentNode = tbody;
    }
    else if (atom == txHTMLAtoms::head &&
             mOutputFormat.mMethod == eHTMLOutput) {
        // Insert META tag, according to spec, 16.2, like
        // <META http-equiv="Content-Type" content="text/html; charset=EUC-JP">
        nsCOMPtr<nsIContent> meta;
        rv = createHTMLElement(nsGkAtoms::meta, getter_AddRefs(meta));
        NS_ENSURE_SUCCESS(rv, rv);

        rv = meta->SetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv,
                           NS_LITERAL_STRING("Content-Type"), PR_FALSE);
        NS_ENSURE_SUCCESS(rv, rv);

        nsAutoString metacontent;
        metacontent.Append(mOutputFormat.mMediaType);
        metacontent.AppendLiteral("; charset=");
        metacontent.Append(mOutputFormat.mEncoding);
        rv = meta->SetAttr(kNameSpaceID_None, nsGkAtoms::content,
                           metacontent, PR_FALSE);
        NS_ENSURE_SUCCESS(rv, rv);

        // No need to notify since aElement hasn't been inserted yet
        NS_ASSERTION(!aElement->IsInDoc(), "should not be in doc");
        rv = aElement->AppendChildTo(meta, PR_FALSE);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    return NS_OK;
}
void txMozillaXMLOutput::startHTMLElement(nsIDOMElement* aElement, PRBool aXHTML)
{
    nsresult rv = NS_OK;
    nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
    nsIAtom *atom = content->Tag();

    mDontAddCurrent = (atom == txHTMLAtoms::script);

    if ((atom != txHTMLAtoms::tr || aXHTML) &&
        NS_PTR_TO_INT32(mTableStateStack.peek()) == ADDED_TBODY) {
        nsCOMPtr<nsIDOMNode> parent;
        mCurrentNode->GetParentNode(getter_AddRefs(parent));
        mCurrentNode.swap(parent);
        mTableStateStack.pop();
    }

    if (atom == txHTMLAtoms::table && !aXHTML) {
        mTableState = TABLE;
    }
    else if (atom == txHTMLAtoms::tr && !aXHTML &&
             NS_PTR_TO_INT32(mTableStateStack.peek()) == TABLE) {
        nsCOMPtr<nsIDOMElement> elem;
        rv = createHTMLElement(NS_LITERAL_STRING("tbody"),
                               getter_AddRefs(elem));
        if (NS_FAILED(rv)) {
            return;
        }
        nsCOMPtr<nsIDOMNode> dummy;
        rv = mCurrentNode->AppendChild(elem, getter_AddRefs(dummy));
        if (NS_FAILED(rv)) {
            return;
        }
        rv = mTableStateStack.push(NS_INT32_TO_PTR(ADDED_TBODY));
        if (NS_FAILED(rv)) {
            return;
        }
        mCurrentNode = elem;
    }
    else if (atom == txHTMLAtoms::head &&
             mOutputFormat.mMethod == eHTMLOutput) {
        // Insert META tag, according to spec, 16.2, like
        // <META http-equiv="Content-Type" content="text/html; charset=EUC-JP">
        nsCOMPtr<nsIDOMElement> meta;
        rv = createHTMLElement(NS_LITERAL_STRING("meta"),
                               getter_AddRefs(meta));
        if (NS_FAILED(rv)) {
            return;
        }
        rv = meta->SetAttribute(NS_LITERAL_STRING("http-equiv"),
                                NS_LITERAL_STRING("Content-Type"));
        NS_ASSERTION(NS_SUCCEEDED(rv), "Can't set http-equiv on meta");
        nsAutoString metacontent;
        metacontent.Append(mOutputFormat.mMediaType);
        metacontent.AppendLiteral("; charset=");
        metacontent.Append(mOutputFormat.mEncoding);
        rv = meta->SetAttribute(NS_LITERAL_STRING("content"),
                                metacontent);
        NS_ASSERTION(NS_SUCCEEDED(rv), "Can't set content on meta");
        nsCOMPtr<nsIDOMNode> dummy;
        rv = aElement->AppendChild(meta, getter_AddRefs(dummy));
        NS_ASSERTION(NS_SUCCEEDED(rv), "Can't append meta");
    }
}
void HTMLConstructionSite::insertHTMLElement(AtomicHTMLToken* token)
{
    RefPtr<HTMLElement> element = createHTMLElement(token);
    attachLater(currentNode(), element);
    m_openElements.push(element.release());
}