Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / parser / html / nsHtml5TreeOperation.cpp
blob867d9ad7ac78ce8799e763db95c06078951aa869
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Communicator client code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Henri Sivonen <hsivonen@iki.fi>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsHtml5TreeOperation.h"
42 #include "nsContentUtils.h"
43 #include "nsNodeUtils.h"
44 #include "nsAttrName.h"
45 #include "nsHtml5TreeBuilder.h"
46 #include "nsIDOMMutationEvent.h"
47 #include "mozAutoDocUpdate.h"
48 #include "nsBindingManager.h"
49 #include "nsXBLBinding.h"
50 #include "nsHtml5DocumentMode.h"
51 #include "nsHtml5HtmlAttributes.h"
52 #include "nsContentCreatorFunctions.h"
53 #include "nsIScriptElement.h"
54 #include "nsIDTD.h"
55 #include "nsTraceRefcnt.h"
56 #include "nsIDOMHTMLFormElement.h"
57 #include "nsIFormControl.h"
58 #include "nsIStyleSheetLinkingElement.h"
59 #include "nsIDOMDocumentType.h"
60 #include "nsIObserverService.h"
61 #include "mozilla/Services.h"
62 #include "nsIMutationObserver.h"
63 #include "nsIFormProcessor.h"
64 #include "nsIServiceManager.h"
65 #include "nsEscape.h"
66 #include "mozilla/dom/Element.h"
68 #ifdef MOZ_SVG
69 #include "nsHtml5SVGLoadDispatcher.h"
70 #endif
72 namespace dom = mozilla::dom;
74 static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
76 /**
77 * Helper class that opens a notification batch if the current doc
78 * is different from the executor doc.
80 class NS_STACK_CLASS nsHtml5OtherDocUpdate {
81 public:
82 nsHtml5OtherDocUpdate(nsIDocument* aCurrentDoc, nsIDocument* aExecutorDoc)
84 NS_PRECONDITION(aCurrentDoc, "Node has no doc?");
85 NS_PRECONDITION(aExecutorDoc, "Executor has no doc?");
86 if (NS_LIKELY(aCurrentDoc == aExecutorDoc)) {
87 mDocument = nsnull;
88 } else {
89 mDocument = aCurrentDoc;
90 aCurrentDoc->BeginUpdate(UPDATE_CONTENT_MODEL);
94 ~nsHtml5OtherDocUpdate()
96 if (NS_UNLIKELY(mDocument)) {
97 mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
100 private:
101 nsIDocument* mDocument;
104 nsHtml5TreeOperation::nsHtml5TreeOperation()
105 #ifdef DEBUG
106 : mOpCode(eTreeOpUninitialized)
107 #endif
109 MOZ_COUNT_CTOR(nsHtml5TreeOperation);
112 nsHtml5TreeOperation::~nsHtml5TreeOperation()
114 MOZ_COUNT_DTOR(nsHtml5TreeOperation);
115 NS_ASSERTION(mOpCode != eTreeOpUninitialized, "Uninitialized tree op.");
116 switch(mOpCode) {
117 case eTreeOpAddAttributes:
118 delete mTwo.attributes;
119 break;
120 case eTreeOpCreateElementNetwork:
121 case eTreeOpCreateElementNotNetwork:
122 delete mThree.attributes;
123 break;
124 case eTreeOpAppendDoctypeToDocument:
125 delete mTwo.stringPair;
126 break;
127 case eTreeOpFosterParentText:
128 case eTreeOpAppendText:
129 case eTreeOpAppendComment:
130 case eTreeOpAppendCommentToDocument:
131 delete[] mTwo.unicharPtr;
132 break;
133 case eTreeOpSetDocumentCharset:
134 case eTreeOpNeedsCharsetSwitchTo:
135 delete[] mOne.charPtr;
136 break;
137 case eTreeOpProcessOfflineManifest:
138 nsMemory::Free(mOne.unicharPtr);
139 break;
140 default: // keep the compiler happy
141 break;
145 nsresult
146 nsHtml5TreeOperation::AppendTextToTextNode(const PRUnichar* aBuffer,
147 PRInt32 aLength,
148 nsIContent* aTextNode,
149 nsHtml5TreeOpExecutor* aBuilder)
151 NS_PRECONDITION(aTextNode, "Got null text node.");
153 if (aBuilder->HaveNotified(aTextNode)) {
154 // This text node has already been notified on, so it's necessary to
155 // notify on the append
156 nsresult rv = NS_OK;
157 PRUint32 oldLength = aTextNode->TextLength();
158 CharacterDataChangeInfo info = {
159 PR_TRUE,
160 oldLength,
161 oldLength,
162 aLength
164 nsNodeUtils::CharacterDataWillChange(aTextNode, &info);
166 rv = aTextNode->AppendText(aBuffer, aLength, PR_FALSE);
167 NS_ENSURE_SUCCESS(rv, rv);
169 nsNodeUtils::CharacterDataChanged(aTextNode, &info);
170 return rv;
173 return aTextNode->AppendText(aBuffer, aLength, PR_FALSE);
177 nsresult
178 nsHtml5TreeOperation::AppendText(const PRUnichar* aBuffer,
179 PRInt32 aLength,
180 nsIContent* aParent,
181 nsHtml5TreeOpExecutor* aBuilder)
183 nsresult rv = NS_OK;
184 nsIContent* lastChild = aParent->GetLastChild();
185 if (lastChild && lastChild->IsNodeOfType(nsINode::eTEXT)) {
186 nsHtml5OtherDocUpdate update(aParent->GetOwnerDoc(),
187 aBuilder->GetDocument());
188 return AppendTextToTextNode(aBuffer,
189 aLength,
190 lastChild,
191 aBuilder);
194 nsCOMPtr<nsIContent> text;
195 NS_NewTextNode(getter_AddRefs(text), aBuilder->GetNodeInfoManager());
196 NS_ASSERTION(text, "Infallible malloc failed?");
197 rv = text->SetText(aBuffer, aLength, PR_FALSE);
198 NS_ENSURE_SUCCESS(rv, rv);
200 return Append(text, aParent, aBuilder);
203 nsresult
204 nsHtml5TreeOperation::Append(nsIContent* aNode,
205 nsIContent* aParent,
206 nsHtml5TreeOpExecutor* aBuilder)
208 nsresult rv = NS_OK;
209 nsIDocument* executorDoc = aBuilder->GetDocument();
210 NS_ASSERTION(executorDoc, "Null doc on executor");
211 nsIDocument* parentDoc = aParent->GetOwnerDoc();
212 NS_ASSERTION(parentDoc, "Null owner doc on old node.");
214 if (NS_LIKELY(executorDoc == parentDoc)) {
215 // the usual case. the parent is in the parser's doc
216 aBuilder->PostPendingAppendNotification(aParent, aNode);
217 rv = aParent->AppendChildTo(aNode, PR_FALSE);
218 return rv;
221 // The parent has been moved to another doc
222 parentDoc->BeginUpdate(UPDATE_CONTENT_MODEL);
224 PRUint32 childCount = aParent->GetChildCount();
225 rv = aParent->AppendChildTo(aNode, PR_FALSE);
226 nsNodeUtils::ContentAppended(aParent, aNode, childCount);
228 parentDoc->EndUpdate(UPDATE_CONTENT_MODEL);
229 return rv;
232 class nsDocElementCreatedNotificationRunner : public nsRunnable
234 public:
235 nsDocElementCreatedNotificationRunner(nsIDocument* aDoc)
236 : mDoc(aDoc)
240 NS_IMETHOD Run()
242 nsContentSink::NotifyDocElementCreated(mDoc);
243 return NS_OK;
246 nsCOMPtr<nsIDocument> mDoc;
249 nsresult
250 nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode,
251 nsHtml5TreeOpExecutor* aBuilder)
253 nsresult rv = NS_OK;
254 aBuilder->FlushPendingAppendNotifications();
255 nsIDocument* doc = aBuilder->GetDocument();
256 PRUint32 childCount = doc->GetChildCount();
257 rv = doc->AppendChildTo(aNode, PR_FALSE);
258 NS_ENSURE_SUCCESS(rv, rv);
259 nsNodeUtils::ContentInserted(doc, aNode, childCount);
261 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
262 "Someone forgot to block scripts");
263 nsContentUtils::AddScriptRunner(
264 new nsDocElementCreatedNotificationRunner(doc));
266 return rv;
269 nsresult
270 nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
271 nsIContent** aScriptElement)
273 nsresult rv = NS_OK;
274 switch(mOpCode) {
275 case eTreeOpAppend: {
276 nsIContent* node = *(mOne.node);
277 nsIContent* parent = *(mTwo.node);
278 return Append(node, parent, aBuilder);
280 case eTreeOpDetach: {
281 nsIContent* node = *(mOne.node);
282 aBuilder->FlushPendingAppendNotifications();
283 nsIContent* parent = node->GetParent();
284 if (parent) {
285 nsHtml5OtherDocUpdate update(parent->GetOwnerDoc(),
286 aBuilder->GetDocument());
287 PRUint32 pos = parent->IndexOf(node);
288 NS_ASSERTION((pos >= 0), "Element not found as child of its parent");
289 rv = parent->RemoveChildAt(pos, PR_TRUE, PR_FALSE);
290 NS_ENSURE_SUCCESS(rv, rv);
292 return rv;
294 case eTreeOpAppendChildrenToNewParent: {
295 nsIContent* node = *(mOne.node);
296 nsIContent* parent = *(mTwo.node);
297 aBuilder->FlushPendingAppendNotifications();
299 nsHtml5OtherDocUpdate update(parent->GetOwnerDoc(),
300 aBuilder->GetDocument());
302 PRUint32 childCount = parent->GetChildCount();
303 PRBool didAppend = PR_FALSE;
304 while (node->GetChildCount()) {
305 nsCOMPtr<nsIContent> child = node->GetChildAt(0);
306 rv = node->RemoveChildAt(0, PR_TRUE, PR_FALSE);
307 NS_ENSURE_SUCCESS(rv, rv);
308 rv = parent->AppendChildTo(child, PR_FALSE);
309 NS_ENSURE_SUCCESS(rv, rv);
310 didAppend = PR_TRUE;
312 if (didAppend) {
313 nsNodeUtils::ContentAppended(parent, parent->GetChildAt(childCount),
314 childCount);
316 return rv;
318 case eTreeOpFosterParent: {
319 nsIContent* node = *(mOne.node);
320 nsIContent* parent = *(mTwo.node);
321 nsIContent* table = *(mThree.node);
322 nsIContent* foster = table->GetParent();
324 if (foster && foster->IsElement()) {
325 aBuilder->FlushPendingAppendNotifications();
327 nsHtml5OtherDocUpdate update(foster->GetOwnerDoc(),
328 aBuilder->GetDocument());
330 PRUint32 pos = foster->IndexOf(table);
331 rv = foster->InsertChildAt(node, pos, PR_FALSE);
332 NS_ENSURE_SUCCESS(rv, rv);
333 nsNodeUtils::ContentInserted(foster, node, pos);
334 return rv;
337 return Append(node, parent, aBuilder);
339 case eTreeOpAppendToDocument: {
340 nsIContent* node = *(mOne.node);
341 return AppendToDocument(node, aBuilder);
343 case eTreeOpAddAttributes: {
344 dom::Element* node = (*(mOne.node))->AsElement();
345 nsHtml5HtmlAttributes* attributes = mTwo.attributes;
347 nsHtml5OtherDocUpdate update(node->GetOwnerDoc(),
348 aBuilder->GetDocument());
350 nsIDocument* document = node->GetCurrentDoc();
352 PRInt32 len = attributes->getLength();
353 for (PRInt32 i = len; i > 0;) {
354 --i;
355 // prefix doesn't need regetting. it is always null or a static atom
356 // local name is never null
357 nsCOMPtr<nsIAtom> localName = Reget(attributes->getLocalName(i));
358 PRInt32 nsuri = attributes->getURI(i);
359 if (!node->HasAttr(nsuri, localName)) {
361 // the manual notification code is based on nsGenericElement
363 nsEventStates stateMask = node->IntrinsicState();
364 nsNodeUtils::AttributeWillChange(node,
365 nsuri,
366 localName,
367 static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION));
369 // prefix doesn't need regetting. it is always null or a static atom
370 // local name is never null
371 node->SetAttr(nsuri, localName, attributes->getPrefix(i), *(attributes->getValue(i)), PR_FALSE);
372 // XXX what to do with nsresult?
374 if (document || node->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
375 nsIDocument* ownerDoc = node->GetOwnerDoc();
376 if (ownerDoc) {
377 nsRefPtr<nsXBLBinding> binding =
378 ownerDoc->BindingManager()->GetBinding(node);
379 if (binding) {
380 binding->AttributeChanged(localName, nsuri, PR_FALSE, PR_FALSE);
385 stateMask ^= node->IntrinsicState();
386 if (!stateMask.IsEmpty() && document) {
387 MOZ_AUTO_DOC_UPDATE(document, UPDATE_CONTENT_STATE, PR_TRUE);
388 document->ContentStatesChanged(node, nsnull, stateMask);
390 nsNodeUtils::AttributeChanged(node,
391 nsuri,
392 localName,
393 static_cast<PRUint8>(nsIDOMMutationEvent::ADDITION));
397 return rv;
399 case eTreeOpCreateElementNetwork:
400 case eTreeOpCreateElementNotNetwork: {
401 nsIContent** target = mOne.node;
402 PRInt32 ns = mInt;
403 nsCOMPtr<nsIAtom> name = Reget(mTwo.atom);
404 nsHtml5HtmlAttributes* attributes = mThree.attributes;
406 PRBool isKeygen = (name == nsHtml5Atoms::keygen && ns == kNameSpaceID_XHTML);
407 if (NS_UNLIKELY(isKeygen)) {
408 name = nsHtml5Atoms::select;
411 nsCOMPtr<nsIContent> newContent;
412 nsCOMPtr<nsINodeInfo> nodeInfo = aBuilder->GetNodeInfoManager()->GetNodeInfo(name, nsnull, ns);
413 NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
414 NS_NewElement(getter_AddRefs(newContent),
415 ns, nodeInfo.forget(),
416 (mOpCode == eTreeOpCreateElementNetwork ?
417 dom::FROM_PARSER_NETWORK
418 : (aBuilder->IsFragmentMode() ?
419 dom::FROM_PARSER_FRAGMENT :
420 dom::FROM_PARSER_DOCUMENT_WRITE)));
421 NS_ASSERTION(newContent, "Element creation created null pointer.");
423 aBuilder->HoldElement(*target = newContent);
425 if (NS_UNLIKELY(name == nsHtml5Atoms::style || name == nsHtml5Atoms::link)) {
426 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
427 if (ssle) {
428 ssle->InitStyleLinkElement(PR_FALSE);
429 ssle->SetEnableUpdates(PR_FALSE);
431 } else if (NS_UNLIKELY(isKeygen)) {
432 // Adapted from CNavDTD
433 nsCOMPtr<nsIFormProcessor> theFormProcessor =
434 do_GetService(kFormProcessorCID, &rv);
435 NS_ENSURE_SUCCESS(rv, rv);
437 nsTArray<nsString> theContent;
438 nsAutoString theAttribute;
440 (void) theFormProcessor->ProvideContent(NS_LITERAL_STRING("select"),
441 theContent,
442 theAttribute);
444 newContent->SetAttr(kNameSpaceID_None,
445 nsGkAtoms::moztype,
446 nsnull,
447 theAttribute,
448 PR_FALSE);
450 nsCOMPtr<nsINodeInfo> optionNodeInfo =
451 aBuilder->GetNodeInfoManager()->GetNodeInfo(nsHtml5Atoms::option,
452 nsnull,
453 kNameSpaceID_XHTML);
455 for (PRUint32 i = 0; i < theContent.Length(); ++i) {
456 nsCOMPtr<nsIContent> optionElt;
457 nsCOMPtr<nsINodeInfo> ni = optionNodeInfo;
458 NS_NewElement(getter_AddRefs(optionElt),
459 optionNodeInfo->NamespaceID(),
460 ni.forget(),
461 (mOpCode == eTreeOpCreateElementNetwork ?
462 dom::FROM_PARSER_NETWORK
463 : (aBuilder->IsFragmentMode() ?
464 dom::FROM_PARSER_FRAGMENT :
465 dom::FROM_PARSER_DOCUMENT_WRITE)));
466 nsCOMPtr<nsIContent> optionText;
467 NS_NewTextNode(getter_AddRefs(optionText),
468 aBuilder->GetNodeInfoManager());
469 (void) optionText->SetText(theContent[i], PR_FALSE);
470 optionElt->AppendChildTo(optionText, PR_FALSE);
471 newContent->AppendChildTo(optionElt, PR_FALSE);
472 newContent->DoneAddingChildren(PR_FALSE);
474 } else if (name == nsHtml5Atoms::frameset && ns == kNameSpaceID_XHTML) {
475 nsIDocument* doc = aBuilder->GetDocument();
476 nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(doc);
477 if (htmlDocument) {
478 // It seems harmless to call this multiple times, since this
479 // is a simple field setter
480 htmlDocument->SetIsFrameset(PR_TRUE);
484 if (!attributes) {
485 return rv;
488 PRInt32 len = attributes->getLength();
489 for (PRInt32 i = len; i > 0;) {
490 --i;
491 // prefix doesn't need regetting. it is always null or a static atom
492 // local name is never null
493 nsCOMPtr<nsIAtom> localName = Reget(attributes->getLocalName(i));
494 if (ns == kNameSpaceID_XHTML &&
495 nsHtml5Atoms::a == name &&
496 nsHtml5Atoms::name == localName) {
497 // This is an HTML5-incompliant Geckoism.
498 // Remove when fixing bug 582361
499 NS_ConvertUTF16toUTF8 cname(*(attributes->getValue(i)));
500 NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
501 newContent->SetAttr(attributes->getURI(i), localName,
502 attributes->getPrefix(i), uv, PR_FALSE);
503 } else {
504 newContent->SetAttr(attributes->getURI(i), localName,
505 attributes->getPrefix(i), *(attributes->getValue(i)), PR_FALSE);
509 return rv;
511 case eTreeOpSetFormElement: {
512 nsIContent* node = *(mOne.node);
513 nsIContent* parent = *(mTwo.node);
514 nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(node));
515 // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl.");
516 // TODO: uncomment the above line when <keygen> (bug 101019) is supported by Gecko
517 nsCOMPtr<nsIDOMHTMLFormElement> formElement(do_QueryInterface(parent));
518 NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement.");
519 // avoid crashing on <keygen>
520 if (formControl &&
521 !node->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) {
522 formControl->SetForm(formElement);
524 return rv;
526 case eTreeOpAppendText: {
527 nsIContent* parent = *mOne.node;
528 PRUnichar* buffer = mTwo.unicharPtr;
529 PRInt32 length = mInt;
530 return AppendText(buffer, length, parent, aBuilder);
532 case eTreeOpAppendIsindexPrompt: {
533 nsIContent* parent = *mOne.node;
534 nsXPIDLString prompt;
535 nsresult rv =
536 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
537 "IsIndexPromptWithSpace", prompt);
538 PRUint32 len = prompt.Length();
539 if (NS_FAILED(rv)) {
540 return rv;
542 if (!len) {
543 // Don't bother appending a zero-length text node.
544 return NS_OK;
546 return AppendText(prompt.BeginReading(), len, parent, aBuilder);
548 case eTreeOpFosterParentText: {
549 nsIContent* stackParent = *mOne.node;
550 PRUnichar* buffer = mTwo.unicharPtr;
551 PRInt32 length = mInt;
552 nsIContent* table = *mThree.node;
554 nsIContent* foster = table->GetParent();
556 if (foster && foster->IsElement()) {
557 aBuilder->FlushPendingAppendNotifications();
559 nsHtml5OtherDocUpdate update(foster->GetOwnerDoc(),
560 aBuilder->GetDocument());
562 PRUint32 pos = foster->IndexOf(table);
564 nsIContent* previousSibling = foster->GetChildAt(pos - 1);
565 if (previousSibling && previousSibling->IsNodeOfType(nsINode::eTEXT)) {
566 return AppendTextToTextNode(buffer,
567 length,
568 previousSibling,
569 aBuilder);
572 nsCOMPtr<nsIContent> text;
573 NS_NewTextNode(getter_AddRefs(text), aBuilder->GetNodeInfoManager());
574 NS_ASSERTION(text, "Infallible malloc failed?");
575 rv = text->SetText(buffer, length, PR_FALSE);
576 NS_ENSURE_SUCCESS(rv, rv);
578 rv = foster->InsertChildAt(text, pos, PR_FALSE);
579 NS_ENSURE_SUCCESS(rv, rv);
580 nsNodeUtils::ContentInserted(foster, text, pos);
581 return rv;
584 return AppendText(buffer, length, stackParent, aBuilder);
586 case eTreeOpAppendComment: {
587 nsIContent* parent = *mOne.node;
588 PRUnichar* buffer = mTwo.unicharPtr;
589 PRInt32 length = mInt;
591 nsCOMPtr<nsIContent> comment;
592 NS_NewCommentNode(getter_AddRefs(comment), aBuilder->GetNodeInfoManager());
593 NS_ASSERTION(comment, "Infallible malloc failed?");
594 rv = comment->SetText(buffer, length, PR_FALSE);
595 NS_ENSURE_SUCCESS(rv, rv);
597 return Append(comment, parent, aBuilder);
599 case eTreeOpAppendCommentToDocument: {
600 PRUnichar* buffer = mTwo.unicharPtr;
601 PRInt32 length = mInt;
603 nsCOMPtr<nsIContent> comment;
604 NS_NewCommentNode(getter_AddRefs(comment), aBuilder->GetNodeInfoManager());
605 NS_ASSERTION(comment, "Infallible malloc failed?");
606 rv = comment->SetText(buffer, length, PR_FALSE);
607 NS_ENSURE_SUCCESS(rv, rv);
609 return AppendToDocument(comment, aBuilder);
611 case eTreeOpAppendDoctypeToDocument: {
612 nsCOMPtr<nsIAtom> name = Reget(mOne.atom);
613 nsHtml5TreeOperationStringPair* pair = mTwo.stringPair;
614 nsString publicId;
615 nsString systemId;
616 pair->Get(publicId, systemId);
618 // Adapted from nsXMLContentSink
619 // Create a new doctype node
620 nsCOMPtr<nsIDOMDocumentType> docType;
621 nsAutoString voidString;
622 voidString.SetIsVoid(PR_TRUE);
623 NS_NewDOMDocumentType(getter_AddRefs(docType),
624 aBuilder->GetNodeInfoManager(),
625 nsnull,
626 name,
627 nsnull,
628 nsnull,
629 publicId,
630 systemId,
631 voidString);
632 NS_ASSERTION(docType, "Doctype creation failed.");
633 nsCOMPtr<nsIContent> asContent = do_QueryInterface(docType);
634 return AppendToDocument(asContent, aBuilder);
636 case eTreeOpRunScript: {
637 nsIContent* node = *(mOne.node);
638 nsAHtml5TreeBuilderState* snapshot = mTwo.state;
639 if (snapshot) {
640 aBuilder->InitializeDocWriteParserState(snapshot, mInt);
642 *aScriptElement = node;
643 return rv;
645 case eTreeOpRunScriptAsyncDefer: {
646 nsIContent* node = *(mOne.node);
647 aBuilder->RunScript(node);
648 return rv;
650 case eTreeOpDoneAddingChildren: {
651 nsIContent* node = *(mOne.node);
652 node->DoneAddingChildren(aBuilder->HaveNotified(node));
653 return rv;
655 case eTreeOpDoneCreatingElement: {
656 nsIContent* node = *(mOne.node);
657 node->DoneCreatingElement();
658 return rv;
660 case eTreeOpFlushPendingAppendNotifications: {
661 aBuilder->FlushPendingAppendNotifications();
662 return rv;
664 case eTreeOpSetDocumentCharset: {
665 char* str = mOne.charPtr;
666 PRInt32 charsetSource = mInt;
667 nsDependentCString dependentString(str);
668 aBuilder->SetDocumentCharsetAndSource(dependentString, charsetSource);
669 return rv;
671 case eTreeOpNeedsCharsetSwitchTo: {
672 char* str = mOne.charPtr;
673 PRInt32 charsetSource = mInt;
674 aBuilder->NeedsCharsetSwitchTo(str, charsetSource);
675 return rv;
677 case eTreeOpUpdateStyleSheet: {
678 nsIContent* node = *(mOne.node);
679 aBuilder->FlushPendingAppendNotifications();
680 aBuilder->UpdateStyleSheet(node);
681 return rv;
683 case eTreeOpProcessMeta: {
684 nsIContent* node = *(mOne.node);
685 rv = aBuilder->ProcessMETATag(node);
686 return rv;
688 case eTreeOpProcessOfflineManifest: {
689 PRUnichar* str = mOne.unicharPtr;
690 nsDependentString dependentString(str);
691 aBuilder->ProcessOfflineManifest(dependentString);
692 return rv;
694 case eTreeOpMarkMalformedIfScript: {
695 nsIContent* node = *(mOne.node);
696 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
697 if (sele) {
698 // Make sure to serialize this script correctly, for nice round tripping.
699 sele->SetIsMalformed();
701 return rv;
703 case eTreeOpStreamEnded: {
704 aBuilder->DidBuildModel(PR_FALSE); // this causes a notifications flush anyway
705 return rv;
707 case eTreeOpStartLayout: {
708 aBuilder->StartLayout(); // this causes a notification flush anyway
709 return rv;
711 case eTreeOpDocumentMode: {
712 aBuilder->SetDocumentMode(mOne.mode);
713 return rv;
715 case eTreeOpSetStyleLineNumber: {
716 nsIContent* node = *(mOne.node);
717 nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(node);
718 NS_ASSERTION(ssle, "Node didn't QI to style.");
719 ssle->SetLineNumber(mInt);
720 return rv;
722 case eTreeOpSetScriptLineNumberAndFreeze: {
723 nsIContent* node = *(mOne.node);
724 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
725 NS_ASSERTION(sele, "Node didn't QI to script.");
726 sele->SetScriptLineNumber(mInt);
727 sele->FreezeUriAsyncDefer();
728 return rv;
730 #ifdef MOZ_SVG
731 case eTreeOpSvgLoad: {
732 nsIContent* node = *(mOne.node);
733 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(node);
734 if (NS_FAILED(NS_DispatchToMainThread(event))) {
735 NS_WARNING("failed to dispatch svg load dispatcher");
737 return rv;
739 #endif
740 default: {
741 NS_NOTREACHED("Bogus tree op");
744 return rv; // keep compiler happy