Bug 509666 - Notify the right document in the HTML5 parser when nodes have been moved between documents during the parse. r=bnewman.

--HG--
extra : rebase_source : ecf04f12b213b6be84887b83c98e15817074d374
This commit is contained in:
Henri Sivonen 2009-11-11 10:37:35 +02:00
parent bcac5a67b9
commit 841cc3cb3e

View File

@ -58,6 +58,34 @@
#include "nsIStyleSheetLinkingElement.h" #include "nsIStyleSheetLinkingElement.h"
#include "nsIDOMDocumentType.h" #include "nsIDOMDocumentType.h"
/**
* Helper class that opens a notification batch if the current doc
* is different from the executor doc.
*/
class NS_STACK_CLASS nsHtml5OtherDocUpdate {
public:
nsHtml5OtherDocUpdate(nsIDocument* aCurrentDoc, nsIDocument* aExecutorDoc)
{
NS_PRECONDITION(aCurrentDoc, "Node has no doc?");
NS_PRECONDITION(aExecutorDoc, "Executor has no doc?");
if (NS_LIKELY(aCurrentDoc == aExecutorDoc)) {
mDocument = nsnull;
} else {
mDocument = aCurrentDoc;
aCurrentDoc->BeginUpdate(UPDATE_CONTENT_MODEL);
}
}
~nsHtml5OtherDocUpdate()
{
if (NS_UNLIKELY(mDocument)) {
mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
}
}
private:
nsIDocument* mDocument;
};
nsHtml5TreeOperation::nsHtml5TreeOperation() nsHtml5TreeOperation::nsHtml5TreeOperation()
#ifdef DEBUG #ifdef DEBUG
: mOpCode(eTreeOpUninitialized) : mOpCode(eTreeOpUninitialized)
@ -102,8 +130,27 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
case eTreeOpAppend: { case eTreeOpAppend: {
nsIContent* node = *(mOne.node); nsIContent* node = *(mOne.node);
nsIContent* parent = *(mTwo.node); nsIContent* parent = *(mTwo.node);
aBuilder->PostPendingAppendNotification(parent, node);
nsIDocument* executorDoc = aBuilder->GetDocument();
NS_ASSERTION(executorDoc, "Null doc on executor");
nsIDocument* parentDoc = parent->GetOwnerDoc();
NS_ASSERTION(parentDoc, "Null owner doc on old node.");
if (NS_LIKELY(executorDoc == parentDoc)) {
// the usual case. the parent is in the parser's doc
aBuilder->PostPendingAppendNotification(parent, node);
rv = parent->AppendChildTo(node, PR_FALSE);
return rv;
}
// The parent has been moved to another doc
parentDoc->BeginUpdate(UPDATE_CONTENT_MODEL);
PRUint32 childCount = parent->GetChildCount();
rv = parent->AppendChildTo(node, PR_FALSE); rv = parent->AppendChildTo(node, PR_FALSE);
nsNodeUtils::ContentAppended(parent, childCount);
parentDoc->EndUpdate(UPDATE_CONTENT_MODEL);
return rv; return rv;
} }
case eTreeOpDetach: { case eTreeOpDetach: {
@ -111,6 +158,8 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
aBuilder->FlushPendingAppendNotifications(); aBuilder->FlushPendingAppendNotifications();
nsIContent* parent = node->GetParent(); nsIContent* parent = node->GetParent();
if (parent) { if (parent) {
nsHtml5OtherDocUpdate update(parent->GetOwnerDoc(),
aBuilder->GetDocument());
PRUint32 pos = parent->IndexOf(node); PRUint32 pos = parent->IndexOf(node);
NS_ASSERTION((pos >= 0), "Element not found as child of its parent"); NS_ASSERTION((pos >= 0), "Element not found as child of its parent");
rv = parent->RemoveChildAt(pos, PR_TRUE, PR_FALSE); rv = parent->RemoveChildAt(pos, PR_TRUE, PR_FALSE);
@ -122,6 +171,10 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
nsIContent* node = *(mOne.node); nsIContent* node = *(mOne.node);
nsIContent* parent = *(mTwo.node); nsIContent* parent = *(mTwo.node);
aBuilder->FlushPendingAppendNotifications(); aBuilder->FlushPendingAppendNotifications();
nsHtml5OtherDocUpdate update(parent->GetOwnerDoc(),
aBuilder->GetDocument());
PRUint32 childCount = parent->GetChildCount(); PRUint32 childCount = parent->GetChildCount();
PRBool didAppend = PR_FALSE; PRBool didAppend = PR_FALSE;
while (node->GetChildCount()) { while (node->GetChildCount()) {
@ -142,16 +195,40 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
nsIContent* parent = *(mTwo.node); nsIContent* parent = *(mTwo.node);
nsIContent* table = *(mThree.node); nsIContent* table = *(mThree.node);
nsIContent* foster = table->GetParent(); nsIContent* foster = table->GetParent();
if (foster && foster->IsNodeOfType(nsINode::eELEMENT)) { if (foster && foster->IsNodeOfType(nsINode::eELEMENT)) {
aBuilder->FlushPendingAppendNotifications(); aBuilder->FlushPendingAppendNotifications();
nsHtml5OtherDocUpdate update(foster->GetOwnerDoc(),
aBuilder->GetDocument());
PRUint32 pos = foster->IndexOf(table); PRUint32 pos = foster->IndexOf(table);
rv = foster->InsertChildAt(node, pos, PR_FALSE); rv = foster->InsertChildAt(node, pos, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsNodeUtils::ContentInserted(foster, node, pos); nsNodeUtils::ContentInserted(foster, node, pos);
} else { return rv;
}
nsIDocument* executorDoc = aBuilder->GetDocument();
NS_ASSERTION(executorDoc, "Null doc on executor");
nsIDocument* parentDoc = parent->GetOwnerDoc();
NS_ASSERTION(parentDoc, "Null owner doc on old node.");
if (NS_LIKELY(executorDoc == parentDoc)) {
// the usual case. the parent is in the parser's doc
aBuilder->PostPendingAppendNotification(parent, node); aBuilder->PostPendingAppendNotification(parent, node);
rv = parent->AppendChildTo(node, PR_FALSE); rv = parent->AppendChildTo(node, PR_FALSE);
return rv;
} }
// The parent has been moved to another doc
parentDoc->BeginUpdate(UPDATE_CONTENT_MODEL);
PRUint32 childCount = parent->GetChildCount();
rv = parent->AppendChildTo(node, PR_FALSE);
nsNodeUtils::ContentAppended(parent, childCount);
parentDoc->EndUpdate(UPDATE_CONTENT_MODEL);
return rv; return rv;
} }
case eTreeOpAppendToDocument: { case eTreeOpAppendToDocument: {
@ -168,6 +245,9 @@ nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
nsIContent* node = *(mOne.node); nsIContent* node = *(mOne.node);
nsHtml5HtmlAttributes* attributes = mTwo.attributes; nsHtml5HtmlAttributes* attributes = mTwo.attributes;
nsHtml5OtherDocUpdate update(node->GetOwnerDoc(),
aBuilder->GetDocument());
nsIDocument* document = node->GetCurrentDoc(); nsIDocument* document = node->GetCurrentDoc();
PRInt32 len = attributes->getLength(); PRInt32 len = attributes->getLength();