Bug 515338 - Make HTML5 parser internals not hold nsIContent or regular dynamic atoms. r=bnewman.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user