Bug 515338 - Make HTML5 parser internals not hold nsIContent or regular dynamic atoms. r=bnewman.

This commit is contained in:
Henri Sivonen
2009-09-21 14:43:43 +03:00
parent fc1b8bac73
commit 4384f2fdf0
31 changed files with 713 additions and 447 deletions

View File

@@ -39,22 +39,13 @@
* ***** END LICENSE BLOCK ***** */
#include "nsContentErrors.h"
#include "nsContentCreatorFunctions.h"
#include "nsIDOMDocumentType.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
#include "nsEvent.h"
#include "nsGUIEvent.h"
#include "nsEventDispatcher.h"
#include "nsContentUtils.h"
#include "nsIDOMHTMLFormElement.h"
#include "nsIFormControl.h"
#include "nsNodeUtils.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsTraceRefcnt.h"
#include "mozAutoDocUpdate.h"
#include "nsIScriptElement.h"
#include "nsIDTD.h"
// this really should be autogenerated...
jArray<PRUnichar,PRInt32> nsHtml5TreeBuilder::ISINDEX_PROMPT = jArray<PRUnichar,PRInt32>();
@@ -65,6 +56,8 @@ nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5TreeOpExecutor* aExec)
, formPointer(nsnull)
, headPointer(nsnull)
, mExecutor(aExec)
, mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH])
, mHandlesUsed(0)
#ifdef DEBUG
, mActive(PR_FALSE)
#endif
@@ -79,54 +72,32 @@ nsHtml5TreeBuilder::~nsHtml5TreeBuilder()
mOpQueue.Clear();
}
nsIContent*
nsIContent**
nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes)
{
nsIContent* newContent;
nsCOMPtr<nsINodeInfo> nodeInfo = mExecutor->GetNodeInfoManager()->GetNodeInfo(aName, nsnull, aNamespace);
NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
NS_NewElement(&newContent, nodeInfo->NamespaceID(), nodeInfo, PR_TRUE);
NS_ASSERTION(newContent, "Element creation created null pointer.");
PRInt32 len = aAttributes->getLength();
for (PRInt32 i = 0; i < len; ++i) {
newContent->SetAttr(aAttributes->getURI(i), aAttributes->getLocalName(i), aAttributes->getPrefix(i), *(aAttributes->getValue(i)), PR_FALSE);
// XXX what to do with nsresult?
}
if (aNamespace != kNameSpaceID_MathML && (aName == nsHtml5Atoms::style || (aNamespace == kNameSpaceID_XHTML && aName == nsHtml5Atoms::link))) {
nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
if (ssle) {
ssle->InitStyleLinkElement(PR_FALSE);
ssle->SetEnableUpdates(PR_FALSE);
#if 0
if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
ssle->SetLineNumber(aLineNumber);
}
#endif
}
}
return newContent;
nsIContent** content = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(aNamespace, aName, aAttributes, content);
return content;
}
nsIContent*
nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes, nsIContent* aFormElement)
nsIContent**
nsHtml5TreeBuilder::createElement(PRInt32 aNamespace, nsIAtom* aName, nsHtml5HtmlAttributes* aAttributes, nsIContent** aFormElement)
{
nsIContent* content = createElement(aNamespace, aName, aAttributes);
nsIContent** content = createElement(aNamespace, aName, aAttributes);
if (aFormElement) {
nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(content));
NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl.");
nsCOMPtr<nsIDOMHTMLFormElement> formElement(do_QueryInterface(aFormElement));
NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement.");
if (formControl) { // avoid crashing on <output>
formControl->SetForm(formElement);
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpSetFormElement, content, aFormElement);
}
return content;
}
nsIContent*
nsIContent**
nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttributes)
{
nsIContent* content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes);
nsIContent** content = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::html, aAttributes);
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpAppendToDocument, content);
@@ -134,7 +105,7 @@ nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes* aAttribute
}
void
nsHtml5TreeBuilder::detachFromParent(nsIContent* aElement)
nsHtml5TreeBuilder::detachFromParent(nsIContent** aElement)
{
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
@@ -142,7 +113,7 @@ nsHtml5TreeBuilder::detachFromParent(nsIContent* aElement)
}
void
nsHtml5TreeBuilder::appendElement(nsIContent* aChild, nsIContent* aParent)
nsHtml5TreeBuilder::appendElement(nsIContent** aChild, nsIContent** aParent)
{
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
@@ -150,7 +121,7 @@ nsHtml5TreeBuilder::appendElement(nsIContent* aChild, nsIContent* aParent)
}
void
nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContent* aOldParent, nsIContent* aNewParent)
nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContent** aOldParent, nsIContent** aNewParent)
{
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
@@ -158,20 +129,24 @@ nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContent* aOldParent, nsIContent
}
void
nsHtml5TreeBuilder::insertFosterParentedCharacters(PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength, nsIContent* aTable, nsIContent* aStackParent)
nsHtml5TreeBuilder::insertFosterParentedCharacters(PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength, nsIContent** aTable, nsIContent** aStackParent)
{
nsCOMPtr<nsIContent> text;
NS_NewTextNode(getter_AddRefs(text), mExecutor->GetNodeInfoManager());
// XXX nsresult and comment null check?
text->SetText(aBuffer + aStart, aLength, PR_FALSE);
// XXX nsresult
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** text = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpCreateTextNode, bufferCopy, aLength, text);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpFosterParent, text, aStackParent, aTable);
}
void
nsHtml5TreeBuilder::insertFosterParentedChild(nsIContent* aChild, nsIContent* aTable, nsIContent* aStackParent)
nsHtml5TreeBuilder::insertFosterParentedChild(nsIContent** aChild, nsIContent** aTable, nsIContent** aStackParent)
{
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
@@ -179,61 +154,73 @@ nsHtml5TreeBuilder::insertFosterParentedChild(nsIContent* aChild, nsIContent* aT
}
void
nsHtml5TreeBuilder::appendCharacters(nsIContent* aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
nsHtml5TreeBuilder::appendCharacters(nsIContent** aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
{
nsCOMPtr<nsIContent> text;
NS_NewTextNode(getter_AddRefs(text), mExecutor->GetNodeInfoManager());
// XXX nsresult and comment null check?
text->SetText(aBuffer + aStart, aLength, PR_FALSE);
// XXX nsresult
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** text = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpCreateTextNode, bufferCopy, aLength, text);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(text, aParent);
}
void
nsHtml5TreeBuilder::appendComment(nsIContent* aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
nsHtml5TreeBuilder::appendComment(nsIContent** aParent, PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
{
nsCOMPtr<nsIContent> comment;
NS_NewCommentNode(getter_AddRefs(comment), mExecutor->GetNodeInfoManager());
// XXX nsresult and comment null check?
comment->SetText(aBuffer + aStart, aLength, PR_FALSE);
// XXX nsresult
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** comment = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpCreateComment, bufferCopy, aLength, comment);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(comment, aParent);
}
void
nsHtml5TreeBuilder::appendCommentToDocument(PRUnichar* aBuffer, PRInt32 aStart, PRInt32 aLength)
{
nsCOMPtr<nsIContent> comment;
NS_NewCommentNode(getter_AddRefs(comment), mExecutor->GetNodeInfoManager());
// XXX nsresult and comment null check?
comment->SetText(aBuffer + aStart, aLength, PR_FALSE);
// XXX nsresult
PRUnichar* bufferCopy = new PRUnichar[aLength];
memcpy(bufferCopy, aBuffer, aLength * sizeof(PRUnichar));
nsIContent** comment = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpCreateComment, bufferCopy, aLength, comment);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpAppendToDocument, comment);
}
void
nsHtml5TreeBuilder::addAttributesToElement(nsIContent* aElement, nsHtml5HtmlAttributes* aAttributes)
nsHtml5TreeBuilder::addAttributesToElement(nsIContent** aElement, nsHtml5HtmlAttributes* aAttributes)
{
nsIContent* holder = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::div, aAttributes);
if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) {
return;
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpAddAttributes, holder, aElement);
treeOp->Init(aElement, aAttributes);
}
void
nsHtml5TreeBuilder::markMalformedIfScript(nsIContent* elt)
nsHtml5TreeBuilder::markMalformedIfScript(nsIContent** elt)
{
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(elt);
if (sele) {
// Make sure to serialize this script correctly, for nice round tripping.
sele->SetIsMalformed();
}
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpMarkMalformedIfScript, elt);
}
void
@@ -267,32 +254,21 @@ nsHtml5TreeBuilder::end()
void
nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom* aName, nsString* aPublicId, nsString* aSystemId)
{
// Adapted from nsXMLContentSink
// Create a new doctype node
nsCOMPtr<nsIDOMDocumentType> docType;
nsAutoString voidString;
voidString.SetIsVoid(PR_TRUE);
NS_NewDOMDocumentType(getter_AddRefs(docType),
mExecutor->GetNodeInfoManager(),
nsnull,
aName,
nsnull,
nsnull,
*aPublicId,
*aSystemId,
voidString);
NS_ASSERTION(docType, "Doctype creation failed.");
nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
NS_ASSERTION(content, "doctype isn't content?");
nsIContent** content = AllocateContentHandle();
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(aName, *aPublicId, *aSystemId, content);
treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpAppendToDocument, content);
// nsXMLContentSink can flush here, but what's the point?
// It can also interrupt here, but we can't.
}
void
nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace, nsIAtom* aName, nsIContent* aElement)
nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace, nsIAtom* aName, nsIContent** aElement)
{
NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
NS_ASSERTION(aName, "Element doesn't have local name!");
@@ -314,7 +290,7 @@ nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace, nsIAtom* aName, nsIContent
}
void
nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent* aElement)
nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent** aElement)
{
NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || aNamespace == kNameSpaceID_SVG || aNamespace == kNameSpaceID_MathML, "Element isn't HTML, SVG or MathML!");
NS_ASSERTION(aName, "Element doesn't have local name!");
@@ -326,7 +302,9 @@ nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace, nsIAtom* aName, nsIContent
// we now have only SVG and HTML
if (aName == nsHtml5Atoms::script) {
requestSuspension();
mExecutor->SetScriptElement(aElement);
nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement();
// XXX if null, OOM!
treeOp->Init(eTreeOpRunScript, aElement);
return;
}
if (aName == nsHtml5Atoms::title) {
@@ -415,59 +393,25 @@ nsHtml5TreeBuilder::accumulateCharacters(PRUnichar* aBuf, PRInt32 aStart, PRInt3
charBufferLen = newFillLen;
}
void
nsHtml5TreeBuilder::DoUnlink()
nsIContent**
nsHtml5TreeBuilder::AllocateContentHandle()
{
nsHtml5TreeBuilder* tmp = this;
NS_IF_RELEASE(contextNode);
NS_IF_RELEASE(formPointer);
NS_IF_RELEASE(headPointer);
while (currentPtr > -1) {
stack[currentPtr]->release();
currentPtr--;
if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) {
mOldHandles.AppendElement(mHandles.forget());
mHandles = new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH];
mHandlesUsed = 0;
}
while (listPtr > -1) {
if (listOfActiveFormattingElements[listPtr]) {
listOfActiveFormattingElements[listPtr]->release();
}
listPtr--;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mOpQueue);
return &mHandles[mHandlesUsed++];
}
void
nsHtml5TreeBuilder::DoTraverse(nsCycleCollectionTraversalCallback &cb)
PRBool
nsHtml5TreeBuilder::HasScript()
{
nsHtml5TreeBuilder* tmp = this;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(contextNode);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(formPointer);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(headPointer);
if (stack) {
for (PRInt32 i = 0; i <= currentPtr; i++) {
#ifdef DEBUG_CC
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "stack[i]");
#endif
cb.NoteNativeChild(stack[i], &NS_CYCLE_COLLECTION_NAME(nsHtml5StackNode));
}
}
if (listOfActiveFormattingElements) {
for (PRInt32 i = 0; i <= listPtr; i++) {
if (listOfActiveFormattingElements[i]) {
#ifdef DEBUG_CC
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "listOfActiveFormattingElements[i]");
#endif
cb.NoteNativeChild(listOfActiveFormattingElements[i], &NS_CYCLE_COLLECTION_NAME(nsHtml5StackNode));
}
}
}
const nsHtml5TreeOperation* start = mOpQueue.Elements();
const nsHtml5TreeOperation* end = start + mOpQueue.Length();
for (nsHtml5TreeOperation* iter = (nsHtml5TreeOperation*)start; iter < end; ++iter) {
#ifdef DEBUG_CC
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mOpQueue[i]");
#endif
iter->DoTraverse(cb);
PRUint32 len = mOpQueue.Length();
if (!len) {
return PR_FALSE;
}
return mOpQueue.ElementAt(len - 1).IsRunScript();
}
// DocumentModeHandler