Bug 1247796. Use keyboardFocusIndicatorColor for ActiveBorder system color keyword...
[gecko.git] / parser / html / nsHtml5TreeOperation.cpp
bloba2527422924d07f610422d1e04e117906e2576c1
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 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsHtml5TreeOperation.h"
8 #include "nsContentUtils.h"
9 #include "nsDocElementCreatedNotificationRunner.h"
10 #include "nsNodeUtils.h"
11 #include "nsAttrName.h"
12 #include "nsHtml5TreeBuilder.h"
13 #include "nsIDOMMutationEvent.h"
14 #include "mozAutoDocUpdate.h"
15 #include "nsBindingManager.h"
16 #include "nsXBLBinding.h"
17 #include "nsHtml5DocumentMode.h"
18 #include "nsHtml5HtmlAttributes.h"
19 #include "nsContentCreatorFunctions.h"
20 #include "nsIScriptElement.h"
21 #include "nsIDTD.h"
22 #include "nsISupportsImpl.h"
23 #include "nsIDOMHTMLFormElement.h"
24 #include "nsIFormControl.h"
25 #include "nsIStyleSheetLinkingElement.h"
26 #include "nsIDOMDocumentType.h"
27 #include "nsIObserverService.h"
28 #include "mozilla/Services.h"
29 #include "nsIMutationObserver.h"
30 #include "nsIFormProcessor.h"
31 #include "nsIServiceManager.h"
32 #include "nsEscape.h"
33 #include "mozilla/dom/Comment.h"
34 #include "mozilla/dom/Element.h"
35 #include "mozilla/dom/HTMLImageElement.h"
36 #include "mozilla/dom/HTMLTemplateElement.h"
37 #include "nsHtml5SVGLoadDispatcher.h"
38 #include "nsIURI.h"
39 #include "nsIProtocolHandler.h"
40 #include "nsNetUtil.h"
41 #include "nsIHTMLDocument.h"
42 #include "mozilla/Likely.h"
43 #include "nsTextNode.h"
45 using namespace mozilla;
47 static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID);
49 /**
50 * Helper class that opens a notification batch if the current doc
51 * is different from the executor doc.
53 class MOZ_STACK_CLASS nsHtml5OtherDocUpdate {
54 public:
55 nsHtml5OtherDocUpdate(nsIDocument* aCurrentDoc, nsIDocument* aExecutorDoc)
57 NS_PRECONDITION(aCurrentDoc, "Node has no doc?");
58 NS_PRECONDITION(aExecutorDoc, "Executor has no doc?");
59 if (MOZ_LIKELY(aCurrentDoc == aExecutorDoc)) {
60 mDocument = nullptr;
61 } else {
62 mDocument = aCurrentDoc;
63 aCurrentDoc->BeginUpdate(UPDATE_CONTENT_MODEL);
67 ~nsHtml5OtherDocUpdate()
69 if (MOZ_UNLIKELY(mDocument)) {
70 mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
73 private:
74 nsCOMPtr<nsIDocument> mDocument;
77 nsHtml5TreeOperation::nsHtml5TreeOperation()
78 : mOpCode(eTreeOpUninitialized)
80 MOZ_COUNT_CTOR(nsHtml5TreeOperation);
83 nsHtml5TreeOperation::~nsHtml5TreeOperation()
85 MOZ_COUNT_DTOR(nsHtml5TreeOperation);
86 NS_ASSERTION(mOpCode != eTreeOpUninitialized, "Uninitialized tree op.");
87 switch(mOpCode) {
88 case eTreeOpAddAttributes:
89 delete mTwo.attributes;
90 break;
91 case eTreeOpCreateElementNetwork:
92 case eTreeOpCreateElementNotNetwork:
93 delete mThree.attributes;
94 break;
95 case eTreeOpAppendDoctypeToDocument:
96 delete mTwo.stringPair;
97 break;
98 case eTreeOpFosterParentText:
99 case eTreeOpAppendText:
100 case eTreeOpAppendComment:
101 case eTreeOpAppendCommentToDocument:
102 case eTreeOpAddViewSourceHref:
103 case eTreeOpAddViewSourceBase:
104 delete[] mTwo.unicharPtr;
105 break;
106 case eTreeOpSetDocumentCharset:
107 case eTreeOpNeedsCharsetSwitchTo:
108 delete[] mOne.charPtr;
109 break;
110 case eTreeOpProcessOfflineManifest:
111 free(mOne.unicharPtr);
112 break;
113 default: // keep the compiler happy
114 break;
118 nsresult
119 nsHtml5TreeOperation::AppendTextToTextNode(const char16_t* aBuffer,
120 uint32_t aLength,
121 nsIContent* aTextNode,
122 nsHtml5DocumentBuilder* aBuilder)
124 NS_PRECONDITION(aTextNode, "Got null text node.");
125 MOZ_ASSERT(aBuilder);
126 MOZ_ASSERT(aBuilder->IsInDocUpdate());
127 uint32_t oldLength = aTextNode->TextLength();
128 CharacterDataChangeInfo info = {
129 true,
130 oldLength,
131 oldLength,
132 aLength
134 nsNodeUtils::CharacterDataWillChange(aTextNode, &info);
136 nsresult rv = aTextNode->AppendText(aBuffer, aLength, false);
137 NS_ENSURE_SUCCESS(rv, rv);
139 nsNodeUtils::CharacterDataChanged(aTextNode, &info);
140 return rv;
144 nsresult
145 nsHtml5TreeOperation::AppendText(const char16_t* aBuffer,
146 uint32_t aLength,
147 nsIContent* aParent,
148 nsHtml5DocumentBuilder* aBuilder)
150 nsresult rv = NS_OK;
151 nsIContent* lastChild = aParent->GetLastChild();
152 if (lastChild && lastChild->IsNodeOfType(nsINode::eTEXT)) {
153 nsHtml5OtherDocUpdate update(aParent->OwnerDoc(),
154 aBuilder->GetDocument());
155 return AppendTextToTextNode(aBuffer,
156 aLength,
157 lastChild,
158 aBuilder);
161 nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager();
162 RefPtr<nsTextNode> text = new nsTextNode(nodeInfoManager);
163 NS_ASSERTION(text, "Infallible malloc failed?");
164 rv = text->SetText(aBuffer, aLength, false);
165 NS_ENSURE_SUCCESS(rv, rv);
167 return Append(text, aParent, aBuilder);
170 nsresult
171 nsHtml5TreeOperation::Append(nsIContent* aNode,
172 nsIContent* aParent,
173 nsHtml5DocumentBuilder* aBuilder)
175 MOZ_ASSERT(aBuilder);
176 MOZ_ASSERT(aBuilder->IsInDocUpdate());
177 nsresult rv = NS_OK;
178 nsHtml5OtherDocUpdate update(aParent->OwnerDoc(),
179 aBuilder->GetDocument());
180 uint32_t childCount = aParent->GetChildCount();
181 rv = aParent->AppendChildTo(aNode, false);
182 if (NS_SUCCEEDED(rv)) {
183 aNode->SetParserHasNotified();
184 nsNodeUtils::ContentAppended(aParent, aNode, childCount);
186 return rv;
189 nsresult
190 nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode,
191 nsHtml5DocumentBuilder* aBuilder)
193 MOZ_ASSERT(aBuilder);
194 MOZ_ASSERT(aBuilder->GetDocument() == aNode->OwnerDoc());
195 MOZ_ASSERT(aBuilder->IsInDocUpdate());
196 nsresult rv = NS_OK;
198 nsIDocument* doc = aBuilder->GetDocument();
199 uint32_t childCount = doc->GetChildCount();
200 rv = doc->AppendChildTo(aNode, false);
201 if (rv == NS_ERROR_DOM_HIERARCHY_REQUEST_ERR) {
202 aNode->SetParserHasNotified();
203 return NS_OK;
205 NS_ENSURE_SUCCESS(rv, rv);
206 aNode->SetParserHasNotified();
207 nsNodeUtils::ContentInserted(doc, aNode, childCount);
209 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
210 "Someone forgot to block scripts");
211 if (aNode->IsElement()) {
212 nsContentUtils::AddScriptRunner(
213 new nsDocElementCreatedNotificationRunner(doc));
215 return rv;
218 static bool
219 IsElementOrTemplateContent(nsINode* aNode) {
220 if (aNode) {
221 if (aNode->IsElement()) {
222 return true;
223 } else if (aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
224 // Check if the node is a template content.
225 mozilla::dom::DocumentFragment* frag =
226 static_cast<mozilla::dom::DocumentFragment*>(aNode);
227 nsIContent* fragHost = frag->GetHost();
228 if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
229 return true;
233 return false;
236 void
237 nsHtml5TreeOperation::Detach(nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder)
239 MOZ_ASSERT(aBuilder);
240 MOZ_ASSERT(aBuilder->IsInDocUpdate());
241 nsCOMPtr<nsINode> parent = aNode->GetParentNode();
242 if (parent) {
243 nsHtml5OtherDocUpdate update(parent->OwnerDoc(),
244 aBuilder->GetDocument());
245 int32_t pos = parent->IndexOf(aNode);
246 NS_ASSERTION((pos >= 0), "Element not found as child of its parent");
247 parent->RemoveChildAt(pos, true);
251 nsresult
252 nsHtml5TreeOperation::AppendChildrenToNewParent(nsIContent* aNode,
253 nsIContent* aParent,
254 nsHtml5DocumentBuilder* aBuilder)
256 MOZ_ASSERT(aBuilder);
257 MOZ_ASSERT(aBuilder->IsInDocUpdate());
258 nsHtml5OtherDocUpdate update(aParent->OwnerDoc(),
259 aBuilder->GetDocument());
261 uint32_t childCount = aParent->GetChildCount();
262 bool didAppend = false;
263 while (aNode->HasChildren()) {
264 nsCOMPtr<nsIContent> child = aNode->GetFirstChild();
265 aNode->RemoveChildAt(0, true);
266 nsresult rv = aParent->AppendChildTo(child, false);
267 NS_ENSURE_SUCCESS(rv, rv);
268 didAppend = true;
270 if (didAppend) {
271 nsNodeUtils::ContentAppended(aParent, aParent->GetChildAt(childCount),
272 childCount);
274 return NS_OK;
277 nsresult
278 nsHtml5TreeOperation::FosterParent(nsIContent* aNode,
279 nsIContent* aParent,
280 nsIContent* aTable,
281 nsHtml5DocumentBuilder* aBuilder)
283 MOZ_ASSERT(aBuilder);
284 MOZ_ASSERT(aBuilder->IsInDocUpdate());
285 nsIContent* foster = aTable->GetParent();
287 if (IsElementOrTemplateContent(foster)) {
289 nsHtml5OtherDocUpdate update(foster->OwnerDoc(),
290 aBuilder->GetDocument());
292 uint32_t pos = foster->IndexOf(aTable);
293 nsresult rv = foster->InsertChildAt(aNode, pos, false);
294 NS_ENSURE_SUCCESS(rv, rv);
295 nsNodeUtils::ContentInserted(foster, aNode, pos);
296 return rv;
299 return Append(aNode, aParent, aBuilder);
302 nsresult
303 nsHtml5TreeOperation::AddAttributes(nsIContent* aNode,
304 nsHtml5HtmlAttributes* aAttributes,
305 nsHtml5DocumentBuilder* aBuilder)
307 dom::Element* node = aNode->AsElement();
308 nsHtml5OtherDocUpdate update(node->OwnerDoc(),
309 aBuilder->GetDocument());
311 int32_t len = aAttributes->getLength();
312 for (int32_t i = len; i > 0;) {
313 --i;
314 // prefix doesn't need regetting. it is always null or a static atom
315 // local name is never null
316 nsCOMPtr<nsIAtom> localName =
317 Reget(aAttributes->getLocalNameNoBoundsCheck(i));
318 int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
319 if (!node->HasAttr(nsuri, localName)) {
320 // prefix doesn't need regetting. it is always null or a static atom
321 // local name is never null
322 node->SetAttr(nsuri,
323 localName,
324 aAttributes->getPrefixNoBoundsCheck(i),
325 *(aAttributes->getValueNoBoundsCheck(i)),
326 true);
327 // XXX what to do with nsresult?
330 return NS_OK;
334 nsIContent*
335 nsHtml5TreeOperation::CreateElement(int32_t aNs,
336 nsIAtom* aName,
337 nsHtml5HtmlAttributes* aAttributes,
338 mozilla::dom::FromParser aFromParser,
339 nsNodeInfoManager* aNodeInfoManager,
340 nsHtml5DocumentBuilder* aBuilder)
342 bool isKeygen = (aName == nsHtml5Atoms::keygen && aNs == kNameSpaceID_XHTML);
343 if (MOZ_UNLIKELY(isKeygen)) {
344 aName = nsHtml5Atoms::select;
347 nsCOMPtr<dom::Element> newElement;
348 RefPtr<dom::NodeInfo> nodeInfo = aNodeInfoManager->
349 GetNodeInfo(aName, nullptr, aNs, nsIDOMNode::ELEMENT_NODE);
350 NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
351 NS_NewElement(getter_AddRefs(newElement),
352 nodeInfo.forget(),
353 aFromParser);
354 NS_ASSERTION(newElement, "Element creation created null pointer.");
356 dom::Element* newContent = newElement;
357 aBuilder->HoldElement(newElement.forget());
359 if (MOZ_UNLIKELY(aName == nsHtml5Atoms::style || aName == nsHtml5Atoms::link)) {
360 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
361 if (ssle) {
362 ssle->InitStyleLinkElement(false);
363 ssle->SetEnableUpdates(false);
365 } else if (MOZ_UNLIKELY(isKeygen)) {
366 // Adapted from CNavDTD
367 nsresult rv;
368 nsCOMPtr<nsIFormProcessor> theFormProcessor =
369 do_GetService(kFormProcessorCID, &rv);
370 if (NS_FAILED(rv)) {
371 return newContent;
374 nsTArray<nsString> theContent;
375 nsAutoString theAttribute;
377 (void) theFormProcessor->ProvideContent(NS_LITERAL_STRING("select"),
378 theContent,
379 theAttribute);
381 newContent->SetAttr(kNameSpaceID_None,
382 nsGkAtoms::moztype,
383 nullptr,
384 theAttribute,
385 false);
387 RefPtr<dom::NodeInfo> optionNodeInfo =
388 aNodeInfoManager->GetNodeInfo(nsHtml5Atoms::option,
389 nullptr,
390 kNameSpaceID_XHTML,
391 nsIDOMNode::ELEMENT_NODE);
393 for (uint32_t i = 0; i < theContent.Length(); ++i) {
394 nsCOMPtr<dom::Element> optionElt;
395 RefPtr<dom::NodeInfo> ni = optionNodeInfo;
396 NS_NewElement(getter_AddRefs(optionElt),
397 ni.forget(),
398 aFromParser);
399 RefPtr<nsTextNode> optionText = new nsTextNode(aNodeInfoManager);
400 (void) optionText->SetText(theContent[i], false);
401 optionElt->AppendChildTo(optionText, false);
402 newContent->AppendChildTo(optionElt, false);
403 // XXXsmaug Shouldn't we call this after adding all the child nodes.
404 newContent->DoneAddingChildren(false);
408 if (!aAttributes) {
409 return newContent;
412 int32_t len = aAttributes->getLength();
413 for (int32_t i = len; i > 0;) {
414 --i;
415 // prefix doesn't need regetting. it is always null or a static atom
416 // local name is never null
417 nsCOMPtr<nsIAtom> localName =
418 Reget(aAttributes->getLocalNameNoBoundsCheck(i));
419 nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
420 int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
422 if (aNs == kNameSpaceID_XHTML &&
423 nsHtml5Atoms::a == aName &&
424 nsHtml5Atoms::name == localName) {
425 // This is an HTML5-incompliant Geckoism.
426 // Remove when fixing bug 582361
427 NS_ConvertUTF16toUTF8 cname(*(aAttributes->getValueNoBoundsCheck(i)));
428 NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
429 newContent->SetAttr(nsuri,
430 localName,
431 prefix,
433 false);
434 } else {
435 nsString& value = *(aAttributes->getValueNoBoundsCheck(i));
436 newContent->SetAttr(nsuri,
437 localName,
438 prefix,
439 value,
440 false);
442 // Custom element setup may be needed if there is an "is" attribute.
443 if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) {
444 newContent->OwnerDoc()->SetupCustomElement(newContent,
445 newContent->GetNameSpaceID(),
446 &value);
450 return newContent;
453 void
454 nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
456 nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(aNode));
457 nsCOMPtr<nsIDOMHTMLImageElement> domImageElement = do_QueryInterface(aNode);
458 // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl.");
459 // TODO: uncomment the above line when <keygen> (bug 101019) is supported by Gecko
460 nsCOMPtr<nsIDOMHTMLFormElement> formElement(do_QueryInterface(aParent));
461 NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement.");
462 // avoid crashing on <keygen>
463 if (formControl &&
464 !aNode->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) {
465 formControl->SetForm(formElement);
466 } else if (domImageElement) {
467 RefPtr<dom::HTMLImageElement> imageElement =
468 static_cast<dom::HTMLImageElement*>(domImageElement.get());
469 MOZ_ASSERT(imageElement);
470 imageElement->SetForm(formElement);
474 nsresult
475 nsHtml5TreeOperation::AppendIsindexPrompt(nsIContent* parent, nsHtml5DocumentBuilder* aBuilder)
477 nsXPIDLString prompt;
478 nsresult rv =
479 nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
480 "IsIndexPromptWithSpace", prompt);
481 uint32_t len = prompt.Length();
482 if (NS_FAILED(rv)) {
483 return rv;
485 if (!len) {
486 // Don't bother appending a zero-length text node.
487 return NS_OK;
489 return AppendText(prompt.BeginReading(), len, parent, aBuilder);
492 nsresult
493 nsHtml5TreeOperation::FosterParentText(nsIContent* aStackParent,
494 char16_t* aBuffer,
495 uint32_t aLength,
496 nsIContent* aTable,
497 nsHtml5DocumentBuilder* aBuilder)
499 MOZ_ASSERT(aBuilder);
500 MOZ_ASSERT(aBuilder->IsInDocUpdate());
501 nsresult rv = NS_OK;
502 nsIContent* foster = aTable->GetParent();
504 if (IsElementOrTemplateContent(foster)) {
505 nsHtml5OtherDocUpdate update(foster->OwnerDoc(),
506 aBuilder->GetDocument());
508 uint32_t pos = foster->IndexOf(aTable);
510 nsIContent* previousSibling = aTable->GetPreviousSibling();
511 if (previousSibling && previousSibling->IsNodeOfType(nsINode::eTEXT)) {
512 return AppendTextToTextNode(aBuffer,
513 aLength,
514 previousSibling,
515 aBuilder);
518 nsNodeInfoManager* nodeInfoManager = aStackParent->OwnerDoc()->NodeInfoManager();
519 RefPtr<nsTextNode> text = new nsTextNode(nodeInfoManager);
520 NS_ASSERTION(text, "Infallible malloc failed?");
521 rv = text->SetText(aBuffer, aLength, false);
522 NS_ENSURE_SUCCESS(rv, rv);
524 rv = foster->InsertChildAt(text, pos, false);
525 NS_ENSURE_SUCCESS(rv, rv);
526 nsNodeUtils::ContentInserted(foster, text, pos);
527 return rv;
530 return AppendText(aBuffer, aLength, aStackParent, aBuilder);
533 nsresult
534 nsHtml5TreeOperation::AppendComment(nsIContent* aParent,
535 char16_t* aBuffer,
536 int32_t aLength,
537 nsHtml5DocumentBuilder* aBuilder)
539 nsNodeInfoManager* nodeInfoManager = aParent->OwnerDoc()->NodeInfoManager();
540 RefPtr<dom::Comment> comment = new dom::Comment(nodeInfoManager);
541 NS_ASSERTION(comment, "Infallible malloc failed?");
542 nsresult rv = comment->SetText(aBuffer, aLength, false);
543 NS_ENSURE_SUCCESS(rv, rv);
545 return Append(comment, aParent, aBuilder);
548 nsresult
549 nsHtml5TreeOperation::AppendCommentToDocument(char16_t* aBuffer,
550 int32_t aLength,
551 nsHtml5DocumentBuilder* aBuilder)
553 RefPtr<dom::Comment> comment =
554 new dom::Comment(aBuilder->GetNodeInfoManager());
555 NS_ASSERTION(comment, "Infallible malloc failed?");
556 nsresult rv = comment->SetText(aBuffer, aLength, false);
557 NS_ENSURE_SUCCESS(rv, rv);
559 return AppendToDocument(comment, aBuilder);
562 nsresult
563 nsHtml5TreeOperation::AppendDoctypeToDocument(nsIAtom* aName,
564 const nsAString& aPublicId,
565 const nsAString& aSystemId,
566 nsHtml5DocumentBuilder* aBuilder)
568 // Adapted from nsXMLContentSink
569 // Create a new doctype node
570 nsCOMPtr<nsIDOMDocumentType> docType;
571 nsAutoString voidString;
572 voidString.SetIsVoid(true);
573 NS_NewDOMDocumentType(getter_AddRefs(docType),
574 aBuilder->GetNodeInfoManager(),
575 aName,
576 aPublicId,
577 aSystemId,
578 voidString);
579 NS_ASSERTION(docType, "Doctype creation failed.");
580 nsCOMPtr<nsIContent> asContent = do_QueryInterface(docType);
581 return AppendToDocument(asContent, aBuilder);
584 nsIContent*
585 nsHtml5TreeOperation::GetDocumentFragmentForTemplate(nsIContent* aNode)
587 dom::HTMLTemplateElement* tempElem =
588 static_cast<dom::HTMLTemplateElement*>(aNode);
589 RefPtr<dom::DocumentFragment> frag = tempElem->Content();
590 return frag;
593 nsIContent*
594 nsHtml5TreeOperation::GetFosterParent(nsIContent* aTable, nsIContent* aStackParent)
596 nsIContent* tableParent = aTable->GetParent();
597 return IsElementOrTemplateContent(tableParent) ? tableParent : aStackParent;
600 void
601 nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode)
603 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
604 MOZ_ASSERT(sele);
605 sele->PreventExecution();
608 void
609 nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode)
611 aNode->DoneAddingChildren(aNode->HasParserNotified());
614 void
615 nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode)
617 aNode->DoneCreatingElement();
620 void
621 nsHtml5TreeOperation::SvgLoad(nsIContent* aNode)
623 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
624 if (NS_FAILED(NS_DispatchToMainThread(event))) {
625 NS_WARNING("failed to dispatch svg load dispatcher");
629 void
630 nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode)
632 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
633 if (sele) {
634 // Make sure to serialize this script correctly, for nice round tripping.
635 sele->SetIsMalformed();
639 nsresult
640 nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
641 nsIContent** aScriptElement)
643 switch(mOpCode) {
644 case eTreeOpAppend: {
645 nsIContent* node = *(mOne.node);
646 nsIContent* parent = *(mTwo.node);
647 return Append(node, parent, aBuilder);
649 case eTreeOpDetach: {
650 nsIContent* node = *(mOne.node);
651 Detach(node, aBuilder);
652 return NS_OK;
654 case eTreeOpAppendChildrenToNewParent: {
655 nsCOMPtr<nsIContent> node = *(mOne.node);
656 nsIContent* parent = *(mTwo.node);
657 return AppendChildrenToNewParent(node, parent, aBuilder);
659 case eTreeOpFosterParent: {
660 nsIContent* node = *(mOne.node);
661 nsIContent* parent = *(mTwo.node);
662 nsIContent* table = *(mThree.node);
663 return FosterParent(node, parent, table, aBuilder);
665 case eTreeOpAppendToDocument: {
666 nsIContent* node = *(mOne.node);
667 return AppendToDocument(node, aBuilder);
669 case eTreeOpAddAttributes: {
670 nsIContent* node = *(mOne.node);
671 nsHtml5HtmlAttributes* attributes = mTwo.attributes;
672 return AddAttributes(node, attributes, aBuilder);
674 case eTreeOpCreateElementNetwork:
675 case eTreeOpCreateElementNotNetwork: {
676 nsIContent** target = mOne.node;
677 int32_t ns = mFour.integer;
678 nsCOMPtr<nsIAtom> name = Reget(mTwo.atom);
679 nsHtml5HtmlAttributes* attributes = mThree.attributes;
680 nsIContent* intendedParent = mFive.node ? *(mFive.node) : nullptr;
682 // intendedParent == nullptr is a special case where the
683 // intended parent is the document.
684 nsNodeInfoManager* nodeInfoManager = intendedParent ?
685 intendedParent->OwnerDoc()->NodeInfoManager() :
686 aBuilder->GetNodeInfoManager();
688 *target = CreateElement(ns,
689 name,
690 attributes,
691 mOpCode == eTreeOpCreateElementNetwork ?
692 dom::FROM_PARSER_NETWORK :
693 dom::FROM_PARSER_DOCUMENT_WRITE,
694 nodeInfoManager,
695 aBuilder);
696 return NS_OK;
698 case eTreeOpSetFormElement: {
699 nsIContent* node = *(mOne.node);
700 nsIContent* parent = *(mTwo.node);
701 SetFormElement(node, parent);
702 return NS_OK;
704 case eTreeOpAppendText: {
705 nsIContent* parent = *mOne.node;
706 char16_t* buffer = mTwo.unicharPtr;
707 uint32_t length = mFour.integer;
708 return AppendText(buffer, length, parent, aBuilder);
710 case eTreeOpAppendIsindexPrompt: {
711 nsIContent* parent = *mOne.node;
712 return AppendIsindexPrompt(parent, aBuilder);
714 case eTreeOpFosterParentText: {
715 nsIContent* stackParent = *mOne.node;
716 char16_t* buffer = mTwo.unicharPtr;
717 uint32_t length = mFour.integer;
718 nsIContent* table = *mThree.node;
719 return FosterParentText(stackParent, buffer, length, table, aBuilder);
721 case eTreeOpAppendComment: {
722 nsIContent* parent = *mOne.node;
723 char16_t* buffer = mTwo.unicharPtr;
724 int32_t length = mFour.integer;
725 return AppendComment(parent, buffer, length, aBuilder);
727 case eTreeOpAppendCommentToDocument: {
728 char16_t* buffer = mTwo.unicharPtr;
729 int32_t length = mFour.integer;
730 return AppendCommentToDocument(buffer, length, aBuilder);
732 case eTreeOpAppendDoctypeToDocument: {
733 nsCOMPtr<nsIAtom> name = Reget(mOne.atom);
734 nsHtml5TreeOperationStringPair* pair = mTwo.stringPair;
735 nsString publicId;
736 nsString systemId;
737 pair->Get(publicId, systemId);
738 return AppendDoctypeToDocument(name, publicId, systemId, aBuilder);
740 case eTreeOpGetDocumentFragmentForTemplate: {
741 nsIContent* node = *(mOne.node);
742 *mTwo.node = GetDocumentFragmentForTemplate(node);
743 return NS_OK;
745 case eTreeOpGetFosterParent: {
746 nsIContent* table = *(mOne.node);
747 nsIContent* stackParent = *(mTwo.node);
748 nsIContent* fosterParent = GetFosterParent(table, stackParent);
749 *mThree.node = fosterParent;
750 return NS_OK;
752 case eTreeOpMarkAsBroken: {
753 return mOne.result;
755 case eTreeOpRunScript: {
756 nsIContent* node = *(mOne.node);
757 nsAHtml5TreeBuilderState* snapshot = mTwo.state;
758 if (snapshot) {
759 aBuilder->InitializeDocWriteParserState(snapshot, mFour.integer);
761 *aScriptElement = node;
762 return NS_OK;
764 case eTreeOpRunScriptAsyncDefer: {
765 nsIContent* node = *(mOne.node);
766 aBuilder->RunScript(node);
767 return NS_OK;
769 case eTreeOpPreventScriptExecution: {
770 nsIContent* node = *(mOne.node);
771 PreventScriptExecution(node);
772 return NS_OK;
774 case eTreeOpDoneAddingChildren: {
775 nsIContent* node = *(mOne.node);
776 node->DoneAddingChildren(node->HasParserNotified());
777 return NS_OK;
779 case eTreeOpDoneCreatingElement: {
780 nsIContent* node = *(mOne.node);
781 DoneCreatingElement(node);
782 return NS_OK;
784 case eTreeOpSetDocumentCharset: {
785 char* str = mOne.charPtr;
786 int32_t charsetSource = mFour.integer;
787 nsDependentCString dependentString(str);
788 aBuilder->SetDocumentCharsetAndSource(dependentString, charsetSource);
789 return NS_OK;
791 case eTreeOpNeedsCharsetSwitchTo: {
792 char* str = mOne.charPtr;
793 int32_t charsetSource = mFour.integer;
794 int32_t lineNumber = mTwo.integer;
795 aBuilder->NeedsCharsetSwitchTo(str, charsetSource, (uint32_t)lineNumber);
796 return NS_OK;
798 case eTreeOpUpdateStyleSheet: {
799 nsIContent* node = *(mOne.node);
800 aBuilder->UpdateStyleSheet(node);
801 return NS_OK;
803 case eTreeOpProcessMeta: {
804 nsIContent* node = *(mOne.node);
805 return aBuilder->ProcessMETATag(node);
807 case eTreeOpProcessOfflineManifest: {
808 char16_t* str = mOne.unicharPtr;
809 nsDependentString dependentString(str);
810 aBuilder->ProcessOfflineManifest(dependentString);
811 return NS_OK;
813 case eTreeOpMarkMalformedIfScript: {
814 nsIContent* node = *(mOne.node);
815 MarkMalformedIfScript(node);
816 return NS_OK;
818 case eTreeOpStreamEnded: {
819 aBuilder->DidBuildModel(false); // this causes a notifications flush anyway
820 return NS_OK;
822 case eTreeOpStartLayout: {
823 aBuilder->StartLayout(); // this causes a notification flush anyway
824 return NS_OK;
826 case eTreeOpDocumentMode: {
827 aBuilder->SetDocumentMode(mOne.mode);
828 return NS_OK;
830 case eTreeOpSetStyleLineNumber: {
831 nsIContent* node = *(mOne.node);
832 nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(node);
833 NS_ASSERTION(ssle, "Node didn't QI to style.");
834 ssle->SetLineNumber(mFour.integer);
835 return NS_OK;
837 case eTreeOpSetScriptLineNumberAndFreeze: {
838 nsIContent* node = *(mOne.node);
839 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
840 NS_ASSERTION(sele, "Node didn't QI to script.");
841 sele->SetScriptLineNumber(mFour.integer);
842 sele->FreezeUriAsyncDefer();
843 return NS_OK;
845 case eTreeOpSvgLoad: {
846 nsIContent* node = *(mOne.node);
847 SvgLoad(node);
848 return NS_OK;
850 case eTreeOpMaybeComplainAboutCharset: {
851 char* msgId = mOne.charPtr;
852 bool error = mTwo.integer;
853 int32_t lineNumber = mThree.integer;
854 aBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber);
855 return NS_OK;
857 case eTreeOpAddClass: {
858 nsIContent* node = *(mOne.node);
859 char16_t* str = mTwo.unicharPtr;
860 nsDependentString depStr(str);
861 // See viewsource.css for the possible classes
862 nsAutoString klass;
863 node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
864 if (!klass.IsEmpty()) {
865 klass.Append(' ');
866 klass.Append(depStr);
867 node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
868 } else {
869 node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true);
871 return NS_OK;
873 case eTreeOpAddLineNumberId: {
874 nsIContent* node = *(mOne.node);
875 int32_t lineNumber = mFour.integer;
876 nsAutoString val(NS_LITERAL_STRING("line"));
877 val.AppendInt(lineNumber);
878 node->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true);
879 return NS_OK;
881 case eTreeOpAddViewSourceHref: {
882 nsIContent* node = *mOne.node;
883 char16_t* buffer = mTwo.unicharPtr;
884 int32_t length = mFour.integer;
886 nsDependentString relative(buffer, length);
888 nsIDocument* doc = aBuilder->GetDocument();
890 const nsCString& charset = doc->GetDocumentCharacterSet();
891 nsCOMPtr<nsIURI> uri;
892 nsresult rv = NS_NewURI(getter_AddRefs(uri),
893 relative,
894 charset.get(),
895 aBuilder->GetViewSourceBaseURI());
896 NS_ENSURE_SUCCESS(rv, NS_OK);
898 // Reuse the fix for bug 467852
899 // URLs that execute script (e.g. "javascript:" URLs) should just be
900 // ignored. There's nothing reasonable we can do with them, and allowing
901 // them to execute in the context of the view-source window presents a
902 // security risk. Just return the empty string in this case.
903 bool openingExecutesScript = false;
904 rv = NS_URIChainHasFlags(uri,
905 nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT,
906 &openingExecutesScript);
907 if (NS_FAILED(rv) || openingExecutesScript) {
908 return NS_OK;
911 nsAutoCString viewSourceUrl;
913 // URLs that return data (e.g. "http:" URLs) should be prefixed with
914 // "view-source:". URLs that don't return data should just be returned
915 // undecorated.
916 bool doesNotReturnData = false;
917 rv = NS_URIChainHasFlags(uri,
918 nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
919 &doesNotReturnData);
920 NS_ENSURE_SUCCESS(rv, NS_OK);
921 if (!doesNotReturnData) {
922 viewSourceUrl.AssignLiteral("view-source:");
925 nsAutoCString spec;
926 uri->GetSpec(spec);
928 viewSourceUrl.Append(spec);
930 nsAutoString utf16;
931 CopyUTF8toUTF16(viewSourceUrl, utf16);
933 node->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true);
934 return rv;
936 case eTreeOpAddError: {
937 nsIContent* node = *(mOne.node);
938 char* msgId = mTwo.charPtr;
939 nsCOMPtr<nsIAtom> atom = Reget(mThree.atom);
940 nsCOMPtr<nsIAtom> otherAtom = Reget(mFour.atom);
941 // See viewsource.css for the possible classes in addition to "error".
942 nsAutoString klass;
943 node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
944 if (!klass.IsEmpty()) {
945 klass.AppendLiteral(" error");
946 node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
947 } else {
948 node->SetAttr(kNameSpaceID_None,
949 nsGkAtoms::_class,
950 NS_LITERAL_STRING("error"),
951 true);
954 nsresult rv;
955 nsXPIDLString message;
956 if (otherAtom) {
957 const char16_t* params[] = { atom->GetUTF16String(),
958 otherAtom->GetUTF16String() };
959 rv = nsContentUtils::FormatLocalizedString(
960 nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message);
961 NS_ENSURE_SUCCESS(rv, NS_OK);
962 } else if (atom) {
963 const char16_t* params[] = { atom->GetUTF16String() };
964 rv = nsContentUtils::FormatLocalizedString(
965 nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message);
966 NS_ENSURE_SUCCESS(rv, NS_OK);
967 } else {
968 rv = nsContentUtils::GetLocalizedString(
969 nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message);
970 NS_ENSURE_SUCCESS(rv, NS_OK);
973 nsAutoString title;
974 node->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
975 if (!title.IsEmpty()) {
976 title.Append('\n');
977 title.Append(message);
978 node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true);
979 } else {
980 node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true);
982 return rv;
984 case eTreeOpAddViewSourceBase: {
985 char16_t* buffer = mTwo.unicharPtr;
986 int32_t length = mFour.integer;
987 nsDependentString baseUrl(buffer, length);
988 aBuilder->AddBase(baseUrl);
989 return NS_OK;
991 default: {
992 MOZ_CRASH("Bogus tree op");
995 return NS_OK; // keep compiler happy