parser/html/nsHtml5TreeOperation.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

     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.
    52  */
    53 class MOZ_STACK_CLASS nsHtml5OtherDocUpdate {
    54   public:
    55     nsHtml5OtherDocUpdate(nsIDocument* aCurrentDoc, nsIDocument* aExecutorDoc)
    56     {
    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);        
    64       }
    65     }
    67     ~nsHtml5OtherDocUpdate()
    68     {
    69       if (MOZ_UNLIKELY(mDocument)) {
    70         mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
    71       }
    72     }
    73   private:
    74     nsIDocument* mDocument;
    75 };
    77 nsHtml5TreeOperation::nsHtml5TreeOperation()
    78 #ifdef DEBUG
    79  : mOpCode(eTreeOpUninitialized)
    80 #endif
    81 {
    82   MOZ_COUNT_CTOR(nsHtml5TreeOperation);
    83 }
    85 nsHtml5TreeOperation::~nsHtml5TreeOperation()
    86 {
    87   MOZ_COUNT_DTOR(nsHtml5TreeOperation);
    88   NS_ASSERTION(mOpCode != eTreeOpUninitialized, "Uninitialized tree op.");
    89   switch(mOpCode) {
    90     case eTreeOpAddAttributes:
    91       delete mTwo.attributes;
    92       break;
    93     case eTreeOpCreateElementNetwork:
    94     case eTreeOpCreateElementNotNetwork:
    95       delete mThree.attributes;
    96       break;
    97     case eTreeOpAppendDoctypeToDocument:
    98       delete mTwo.stringPair;
    99       break;
   100     case eTreeOpFosterParentText:
   101     case eTreeOpAppendText:
   102     case eTreeOpAppendComment:
   103     case eTreeOpAppendCommentToDocument:
   104     case eTreeOpAddViewSourceHref:
   105       delete[] mTwo.unicharPtr;
   106       break;
   107     case eTreeOpSetDocumentCharset:
   108     case eTreeOpNeedsCharsetSwitchTo:
   109       delete[] mOne.charPtr;
   110       break;
   111     case eTreeOpProcessOfflineManifest:
   112       nsMemory::Free(mOne.unicharPtr);
   113       break;
   114     default: // keep the compiler happy
   115       break;
   116   }
   117 }
   119 nsresult
   120 nsHtml5TreeOperation::AppendTextToTextNode(const char16_t* aBuffer,
   121                                            uint32_t aLength,
   122                                            nsIContent* aTextNode,
   123                                            nsHtml5DocumentBuilder* aBuilder)
   124 {
   125   NS_PRECONDITION(aTextNode, "Got null text node.");
   127   if (aBuilder->HaveNotified(aTextNode)) {
   128     // This text node has already been notified on, so it's necessary to
   129     // notify on the append
   130     nsresult rv = NS_OK;
   131     uint32_t oldLength = aTextNode->TextLength();
   132     CharacterDataChangeInfo info = {
   133       true,
   134       oldLength,
   135       oldLength,
   136       aLength
   137     };
   138     nsNodeUtils::CharacterDataWillChange(aTextNode, &info);
   140     rv = aTextNode->AppendText(aBuffer, aLength, false);
   141     NS_ENSURE_SUCCESS(rv, rv);
   143     nsNodeUtils::CharacterDataChanged(aTextNode, &info);
   144     return rv;
   145   }
   147   return aTextNode->AppendText(aBuffer, aLength, false);
   148 }
   151 nsresult
   152 nsHtml5TreeOperation::AppendText(const char16_t* aBuffer,
   153                                  uint32_t aLength,
   154                                  nsIContent* aParent,
   155                                  nsHtml5DocumentBuilder* aBuilder)
   156 {
   157   nsresult rv = NS_OK;
   158   nsIContent* lastChild = aParent->GetLastChild();
   159   if (lastChild && lastChild->IsNodeOfType(nsINode::eTEXT)) {
   160     nsHtml5OtherDocUpdate update(aParent->OwnerDoc(),
   161                                  aBuilder->GetDocument());
   162     return AppendTextToTextNode(aBuffer, 
   163                                 aLength, 
   164                                 lastChild, 
   165                                 aBuilder);
   166   }
   168   nsRefPtr<nsTextNode> text = new nsTextNode(aBuilder->GetNodeInfoManager());
   169   NS_ASSERTION(text, "Infallible malloc failed?");
   170   rv = text->SetText(aBuffer, aLength, false);
   171   NS_ENSURE_SUCCESS(rv, rv);
   173   return Append(text, aParent, aBuilder);
   174 }
   176 nsresult
   177 nsHtml5TreeOperation::Append(nsIContent* aNode,
   178                              nsIContent* aParent,
   179                              nsHtml5DocumentBuilder* aBuilder)
   180 {
   181   nsresult rv = NS_OK;
   182   nsIDocument* executorDoc = aBuilder->GetDocument();
   183   NS_ASSERTION(executorDoc, "Null doc on executor");
   184   nsIDocument* parentDoc = aParent->OwnerDoc();
   185   NS_ASSERTION(parentDoc, "Null owner doc on old node.");
   187   if (MOZ_LIKELY(executorDoc == parentDoc)) {
   188     // the usual case. the parent is in the parser's doc
   189     rv = aParent->AppendChildTo(aNode, false);
   190     if (NS_SUCCEEDED(rv)) {
   191       aBuilder->PostPendingAppendNotification(aParent, aNode);
   192     }
   193     return rv;
   194   }
   196   // The parent has been moved to another doc
   197   parentDoc->BeginUpdate(UPDATE_CONTENT_MODEL);
   199   uint32_t childCount = aParent->GetChildCount();
   200   rv = aParent->AppendChildTo(aNode, false);
   201   if (NS_SUCCEEDED(rv)) {
   202     nsNodeUtils::ContentAppended(aParent, aNode, childCount);
   203   }
   204   parentDoc->EndUpdate(UPDATE_CONTENT_MODEL);
   205   return rv;
   206 }
   208 nsresult
   209 nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode,
   210                                        nsHtml5DocumentBuilder* aBuilder)
   211 {
   212   nsresult rv = NS_OK;
   213   aBuilder->FlushPendingAppendNotifications();
   214   nsIDocument* doc = aBuilder->GetDocument();
   215   uint32_t childCount = doc->GetChildCount();
   216   rv = doc->AppendChildTo(aNode, false);
   217   if (rv == NS_ERROR_DOM_HIERARCHY_REQUEST_ERR) {
   218     return NS_OK;
   219   }
   220   NS_ENSURE_SUCCESS(rv, rv);
   221   nsNodeUtils::ContentInserted(doc, aNode, childCount);
   223   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
   224                "Someone forgot to block scripts");
   225   if (aNode->IsElement()) {
   226     nsContentUtils::AddScriptRunner(
   227         new nsDocElementCreatedNotificationRunner(doc));
   228   }
   229   return rv;
   230 }
   232 static bool
   233 IsElementOrTemplateContent(nsINode* aNode) {
   234   if (aNode) {
   235     if (aNode->IsElement()) {
   236       return true;
   237     } else if (aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
   238       // Check if the node is a template content.
   239       mozilla::dom::DocumentFragment* frag =
   240         static_cast<mozilla::dom::DocumentFragment*>(aNode);
   241       nsIContent* fragHost = frag->GetHost();
   242       if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
   243         return true;
   244       }
   245     }
   246   }
   247   return false;
   248 }
   250 void
   251 nsHtml5TreeOperation::Detach(nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder)
   252 {
   253   aBuilder->FlushPendingAppendNotifications();
   254   nsCOMPtr<nsINode> parent = aNode->GetParentNode();
   255   if (parent) {
   256     nsHtml5OtherDocUpdate update(parent->OwnerDoc(),
   257         aBuilder->GetDocument());
   258     int32_t pos = parent->IndexOf(aNode);
   259     NS_ASSERTION((pos >= 0), "Element not found as child of its parent");
   260     parent->RemoveChildAt(pos, true);
   261   }
   262 }
   264 nsresult
   265 nsHtml5TreeOperation::AppendChildrenToNewParent(nsIContent* aNode,
   266                                                 nsIContent* aParent,
   267                                                 nsHtml5DocumentBuilder* aBuilder)
   268 {
   269   aBuilder->FlushPendingAppendNotifications();
   271   nsHtml5OtherDocUpdate update(aParent->OwnerDoc(),
   272                                aBuilder->GetDocument());
   274   uint32_t childCount = aParent->GetChildCount();
   275   bool didAppend = false;
   276   while (aNode->HasChildren()) {
   277     nsCOMPtr<nsIContent> child = aNode->GetFirstChild();
   278     aNode->RemoveChildAt(0, true);
   279     nsresult rv = aParent->AppendChildTo(child, false);
   280     NS_ENSURE_SUCCESS(rv, rv);
   281     didAppend = true;
   282   }
   283   if (didAppend) {
   284     nsNodeUtils::ContentAppended(aParent, aParent->GetChildAt(childCount),
   285                                  childCount);
   286   }
   287   return NS_OK;
   288 }
   290 nsresult
   291 nsHtml5TreeOperation::FosterParent(nsIContent* aNode,
   292                                    nsIContent* aParent,
   293                                    nsIContent* aTable,
   294                                    nsHtml5DocumentBuilder* aBuilder)
   295 {
   296   nsIContent* foster = aTable->GetParent();
   298   if (IsElementOrTemplateContent(foster)) {
   299     aBuilder->FlushPendingAppendNotifications();
   301     nsHtml5OtherDocUpdate update(foster->OwnerDoc(),
   302                                  aBuilder->GetDocument());
   304     uint32_t pos = foster->IndexOf(aTable);
   305     nsresult rv = foster->InsertChildAt(aNode, pos, false);
   306     NS_ENSURE_SUCCESS(rv, rv);
   307     nsNodeUtils::ContentInserted(foster, aNode, pos);
   308     return rv;
   309   }
   311   return Append(aNode, aParent, aBuilder);
   312 }
   314 nsresult
   315 nsHtml5TreeOperation::AddAttributes(nsIContent* aNode,
   316                                     nsHtml5HtmlAttributes* aAttributes,
   317                                     nsHtml5DocumentBuilder* aBuilder)
   318 {
   319   dom::Element* node = aNode->AsElement();
   320   nsHtml5OtherDocUpdate update(node->OwnerDoc(),
   321                                aBuilder->GetDocument());
   323   int32_t len = aAttributes->getLength();
   324   for (int32_t i = len; i > 0;) {
   325     --i;
   326     // prefix doesn't need regetting. it is always null or a static atom
   327     // local name is never null
   328     nsCOMPtr<nsIAtom> localName =
   329       Reget(aAttributes->getLocalNameNoBoundsCheck(i));
   330     int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
   331     if (!node->HasAttr(nsuri, localName)) {
   332       // prefix doesn't need regetting. it is always null or a static atom
   333       // local name is never null
   334       node->SetAttr(nsuri,
   335                     localName,
   336                     aAttributes->getPrefixNoBoundsCheck(i),
   337                     *(aAttributes->getValueNoBoundsCheck(i)),
   338                     true);
   339       // XXX what to do with nsresult?
   340     }
   341   }
   342   return NS_OK;
   343 }
   346 nsIContent*
   347 nsHtml5TreeOperation::CreateElement(int32_t aNs,
   348                                     nsIAtom* aName,
   349                                     nsHtml5HtmlAttributes* aAttributes,
   350                                     mozilla::dom::FromParser aFromParser,
   351                                     nsHtml5DocumentBuilder* aBuilder)
   352 {
   353   bool isKeygen = (aName == nsHtml5Atoms::keygen && aNs == kNameSpaceID_XHTML);
   354   if (MOZ_UNLIKELY(isKeygen)) {
   355     aName = nsHtml5Atoms::select;
   356   }
   358   nsCOMPtr<dom::Element> newContent;
   359   nsCOMPtr<nsINodeInfo> nodeInfo = aBuilder->GetNodeInfoManager()->
   360     GetNodeInfo(aName, nullptr, aNs, nsIDOMNode::ELEMENT_NODE);
   361   NS_ASSERTION(nodeInfo, "Got null nodeinfo.");
   362   NS_NewElement(getter_AddRefs(newContent),
   363                 nodeInfo.forget(),
   364                 aFromParser);
   365   NS_ASSERTION(newContent, "Element creation created null pointer.");
   367   aBuilder->HoldElement(newContent);
   369   if (MOZ_UNLIKELY(aName == nsHtml5Atoms::style || aName == nsHtml5Atoms::link)) {
   370     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent));
   371     if (ssle) {
   372       ssle->InitStyleLinkElement(false);
   373       ssle->SetEnableUpdates(false);
   374     }
   375   } else if (MOZ_UNLIKELY(isKeygen)) {
   376     // Adapted from CNavDTD
   377     nsresult rv;
   378     nsCOMPtr<nsIFormProcessor> theFormProcessor =
   379       do_GetService(kFormProcessorCID, &rv);
   380     if (NS_FAILED(rv)) {
   381       return newContent;
   382     }
   384     nsTArray<nsString> theContent;
   385     nsAutoString theAttribute;
   387     (void) theFormProcessor->ProvideContent(NS_LITERAL_STRING("select"),
   388                                             theContent,
   389                                             theAttribute);
   391     newContent->SetAttr(kNameSpaceID_None,
   392                         nsGkAtoms::moztype,
   393                         nullptr,
   394                         theAttribute,
   395                         false);
   397     nsCOMPtr<nsINodeInfo> optionNodeInfo =
   398       aBuilder->GetNodeInfoManager()->GetNodeInfo(nsHtml5Atoms::option,
   399                                                   nullptr,
   400                                                   kNameSpaceID_XHTML,
   401                                                   nsIDOMNode::ELEMENT_NODE);
   403     for (uint32_t i = 0; i < theContent.Length(); ++i) {
   404       nsCOMPtr<dom::Element> optionElt;
   405       nsCOMPtr<nsINodeInfo> ni = optionNodeInfo;
   406       NS_NewElement(getter_AddRefs(optionElt),
   407                     ni.forget(),
   408                     aFromParser);
   409       nsRefPtr<nsTextNode> optionText =
   410         new nsTextNode(aBuilder->GetNodeInfoManager());
   411       (void) optionText->SetText(theContent[i], false);
   412       optionElt->AppendChildTo(optionText, false);
   413       newContent->AppendChildTo(optionElt, false);
   414       newContent->DoneAddingChildren(false);
   415     }
   416   }
   418   if (!aAttributes) {
   419     return newContent;
   420   }
   422   int32_t len = aAttributes->getLength();
   423   for (int32_t i = len; i > 0;) {
   424     --i;
   425     // prefix doesn't need regetting. it is always null or a static atom
   426     // local name is never null
   427     nsCOMPtr<nsIAtom> localName =
   428       Reget(aAttributes->getLocalNameNoBoundsCheck(i));
   429     nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i);
   430     int32_t nsuri = aAttributes->getURINoBoundsCheck(i);
   432     if (aNs == kNameSpaceID_XHTML &&
   433         nsHtml5Atoms::a == aName &&
   434         nsHtml5Atoms::name == localName) {
   435       // This is an HTML5-incompliant Geckoism.
   436       // Remove when fixing bug 582361
   437       NS_ConvertUTF16toUTF8 cname(*(aAttributes->getValueNoBoundsCheck(i)));
   438       NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting()));
   439       newContent->SetAttr(nsuri,
   440                           localName,
   441                           prefix,
   442                           uv,
   443                           false);
   444     } else {
   445       nsString& value = *(aAttributes->getValueNoBoundsCheck(i));
   446       newContent->SetAttr(nsuri,
   447                           localName,
   448                           prefix,
   449                           value,
   450                           false);
   452       // Custom element prototype swizzling may be needed if there is an
   453       // "is" attribute.
   454       if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) {
   455         ErrorResult errorResult;
   456         newContent->OwnerDoc()->SwizzleCustomElement(newContent,
   457                                                      value,
   458                                                      newContent->GetNameSpaceID(),
   459                                                      errorResult);
   460       }
   461     }
   462   }
   463   return newContent;
   464 }
   466 void
   467 nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
   468 {
   469   nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(aNode));
   470   nsCOMPtr<nsIDOMHTMLImageElement> domImageElement = do_QueryInterface(aNode);
   471   // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl.");
   472   // TODO: uncomment the above line when <keygen> (bug 101019) is supported by Gecko
   473   nsCOMPtr<nsIDOMHTMLFormElement> formElement(do_QueryInterface(aParent));
   474   NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement.");
   475   // avoid crashing on <keygen>
   476   if (formControl &&
   477       !aNode->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) {
   478     formControl->SetForm(formElement);
   479   } else if (domImageElement) {
   480     nsRefPtr<dom::HTMLImageElement> imageElement =
   481       static_cast<dom::HTMLImageElement*>(domImageElement.get());
   482     MOZ_ASSERT(imageElement);
   483     imageElement->SetForm(formElement);
   484   }
   485 }
   487 nsresult
   488 nsHtml5TreeOperation::AppendIsindexPrompt(nsIContent* parent, nsHtml5DocumentBuilder* aBuilder)
   489 {
   490   nsXPIDLString prompt;
   491   nsresult rv =
   492       nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
   493                                          "IsIndexPromptWithSpace", prompt);
   494   uint32_t len = prompt.Length();
   495   if (NS_FAILED(rv)) {
   496     return rv;
   497   }
   498   if (!len) {
   499     // Don't bother appending a zero-length text node.
   500     return NS_OK;
   501   }
   502   return AppendText(prompt.BeginReading(), len, parent, aBuilder);
   503 }
   505 nsresult
   506 nsHtml5TreeOperation::FosterParentText(nsIContent* aStackParent,
   507                                        char16_t* aBuffer,
   508                                        uint32_t aLength,
   509                                        nsIContent* aTable,
   510                                        nsHtml5DocumentBuilder* aBuilder)
   511 {
   512   nsresult rv = NS_OK;
   513   nsIContent* foster = aTable->GetParent();
   515   if (IsElementOrTemplateContent(foster)) {
   516     aBuilder->FlushPendingAppendNotifications();
   518     nsHtml5OtherDocUpdate update(foster->OwnerDoc(),
   519                                  aBuilder->GetDocument());
   521     uint32_t pos = foster->IndexOf(aTable);
   523     nsIContent* previousSibling = aTable->GetPreviousSibling();
   524     if (previousSibling && previousSibling->IsNodeOfType(nsINode::eTEXT)) {
   525       return AppendTextToTextNode(aBuffer,
   526                                   aLength,
   527                                   previousSibling,
   528                                   aBuilder);
   529     }
   531     nsRefPtr<nsTextNode> text =
   532       new nsTextNode(aBuilder->GetNodeInfoManager());
   533     NS_ASSERTION(text, "Infallible malloc failed?");
   534     rv = text->SetText(aBuffer, aLength, false);
   535     NS_ENSURE_SUCCESS(rv, rv);
   537     rv = foster->InsertChildAt(text, pos, false);
   538     NS_ENSURE_SUCCESS(rv, rv);
   539     nsNodeUtils::ContentInserted(foster, text, pos);
   540     return rv;
   541   }
   543   return AppendText(aBuffer, aLength, aStackParent, aBuilder);
   544 }
   546 nsresult
   547 nsHtml5TreeOperation::AppendComment(nsIContent* aParent,
   548                                     char16_t* aBuffer,
   549                                     int32_t aLength,
   550                                     nsHtml5DocumentBuilder* aBuilder)
   551 {
   552   nsRefPtr<dom::Comment> comment =
   553     new dom::Comment(aBuilder->GetNodeInfoManager());
   554   NS_ASSERTION(comment, "Infallible malloc failed?");
   555   nsresult rv = comment->SetText(aBuffer, aLength, false);
   556   NS_ENSURE_SUCCESS(rv, rv);
   558   return Append(comment, aParent, aBuilder);
   559 }
   561 nsresult
   562 nsHtml5TreeOperation::AppendCommentToDocument(char16_t* aBuffer,
   563                                               int32_t aLength,
   564                                               nsHtml5DocumentBuilder* aBuilder)
   565 {
   566   nsRefPtr<dom::Comment> comment =
   567     new dom::Comment(aBuilder->GetNodeInfoManager());
   568   NS_ASSERTION(comment, "Infallible malloc failed?");
   569   nsresult rv = comment->SetText(aBuffer, aLength, false);
   570   NS_ENSURE_SUCCESS(rv, rv);
   572   return AppendToDocument(comment, aBuilder);
   573 }
   575 nsresult
   576 nsHtml5TreeOperation::AppendDoctypeToDocument(nsIAtom* aName,
   577                                               const nsAString& aPublicId,
   578                                               const nsAString& aSystemId,
   579                                               nsHtml5DocumentBuilder* aBuilder)
   580 {
   581   // Adapted from nsXMLContentSink
   582   // Create a new doctype node
   583   nsCOMPtr<nsIDOMDocumentType> docType;
   584   nsAutoString voidString;
   585   voidString.SetIsVoid(true);
   586   NS_NewDOMDocumentType(getter_AddRefs(docType),
   587                         aBuilder->GetNodeInfoManager(),
   588                         aName,
   589                         aPublicId,
   590                         aSystemId,
   591                         voidString);
   592   NS_ASSERTION(docType, "Doctype creation failed.");
   593   nsCOMPtr<nsIContent> asContent = do_QueryInterface(docType);
   594   return AppendToDocument(asContent, aBuilder);
   595 }
   597 nsIContent*
   598 nsHtml5TreeOperation::GetDocumentFragmentForTemplate(nsIContent* aNode)
   599 {
   600   dom::HTMLTemplateElement* tempElem =
   601     static_cast<dom::HTMLTemplateElement*>(aNode);
   602   nsRefPtr<dom::DocumentFragment> frag = tempElem->Content();
   603   return frag;
   604 }
   606 void
   607 nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode)
   608 {
   609   nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
   610   MOZ_ASSERT(sele);
   611   sele->PreventExecution();
   612 }
   614 void
   615 nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode,
   616                                          nsHtml5DocumentBuilder* aBuilder)
   617 {
   618   aNode->DoneAddingChildren(aBuilder->HaveNotified(aNode));
   619 }
   621 void
   622 nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode)
   623 {
   624   aNode->DoneCreatingElement();
   625 }
   627 void
   628 nsHtml5TreeOperation::SvgLoad(nsIContent* aNode)
   629 {
   630   nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
   631   if (NS_FAILED(NS_DispatchToMainThread(event))) {
   632     NS_WARNING("failed to dispatch svg load dispatcher");
   633   }
   634 }
   636 void
   637 nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode)
   638 {
   639   nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);
   640   if (sele) {
   641     // Make sure to serialize this script correctly, for nice round tripping.
   642     sele->SetIsMalformed();
   643   }
   644 }
   646 nsresult
   647 nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder,
   648                               nsIContent** aScriptElement)
   649 {
   650   switch(mOpCode) {
   651     case eTreeOpAppend: {
   652       nsIContent* node = *(mOne.node);
   653       nsIContent* parent = *(mTwo.node);
   654       return Append(node, parent, aBuilder);
   655     }
   656     case eTreeOpDetach: {
   657       nsIContent* node = *(mOne.node);
   658       Detach(node, aBuilder);
   659       return NS_OK;
   660     }
   661     case eTreeOpAppendChildrenToNewParent: {
   662       nsCOMPtr<nsIContent> node = *(mOne.node);
   663       nsIContent* parent = *(mTwo.node);
   664       return AppendChildrenToNewParent(node, parent, aBuilder);
   665     }
   666     case eTreeOpFosterParent: {
   667       nsIContent* node = *(mOne.node);
   668       nsIContent* parent = *(mTwo.node);
   669       nsIContent* table = *(mThree.node);
   670       return FosterParent(node, parent, table, aBuilder);
   671     }
   672     case eTreeOpAppendToDocument: {
   673       nsIContent* node = *(mOne.node);
   674       return AppendToDocument(node, aBuilder);
   675     }
   676     case eTreeOpAddAttributes: {
   677       nsIContent* node = *(mOne.node);
   678       nsHtml5HtmlAttributes* attributes = mTwo.attributes;
   679       return AddAttributes(node, attributes, aBuilder);
   680     }
   681     case eTreeOpCreateElementNetwork:
   682     case eTreeOpCreateElementNotNetwork: {
   683       nsIContent** target = mOne.node;
   684       int32_t ns = mFour.integer;
   685       nsCOMPtr<nsIAtom> name = Reget(mTwo.atom);
   686       nsHtml5HtmlAttributes* attributes = mThree.attributes;
   688       *target = CreateElement(ns,
   689                               name,
   690                               attributes,
   691                               mOpCode == eTreeOpCreateElementNetwork ?
   692                                 dom::FROM_PARSER_NETWORK :
   693                                 dom::FROM_PARSER_DOCUMENT_WRITE,
   694                               aBuilder);
   695       return NS_OK;
   696     }
   697     case eTreeOpSetFormElement: {
   698       nsIContent* node = *(mOne.node);
   699       nsIContent* parent = *(mTwo.node);
   700       SetFormElement(node, parent);
   701       return NS_OK;
   702     }
   703     case eTreeOpAppendText: {
   704       nsIContent* parent = *mOne.node;
   705       char16_t* buffer = mTwo.unicharPtr;
   706       uint32_t length = mFour.integer;
   707       return AppendText(buffer, length, parent, aBuilder);
   708     }
   709     case eTreeOpAppendIsindexPrompt: {
   710       nsIContent* parent = *mOne.node;
   711       return AppendIsindexPrompt(parent, aBuilder);
   712     }
   713     case eTreeOpFosterParentText: {
   714       nsIContent* stackParent = *mOne.node;
   715       char16_t* buffer = mTwo.unicharPtr;
   716       uint32_t length = mFour.integer;
   717       nsIContent* table = *mThree.node;
   718       return FosterParentText(stackParent, buffer, length, table, aBuilder);
   719     }
   720     case eTreeOpAppendComment: {
   721       nsIContent* parent = *mOne.node;
   722       char16_t* buffer = mTwo.unicharPtr;
   723       int32_t length = mFour.integer;
   724       return AppendComment(parent, buffer, length, aBuilder);
   725     }
   726     case eTreeOpAppendCommentToDocument: {
   727       char16_t* buffer = mTwo.unicharPtr;
   728       int32_t length = mFour.integer;
   729       return AppendCommentToDocument(buffer, length, aBuilder);
   730     }
   731     case eTreeOpAppendDoctypeToDocument: {
   732       nsCOMPtr<nsIAtom> name = Reget(mOne.atom);
   733       nsHtml5TreeOperationStringPair* pair = mTwo.stringPair;
   734       nsString publicId;
   735       nsString systemId;
   736       pair->Get(publicId, systemId);
   737       return AppendDoctypeToDocument(name, publicId, systemId, aBuilder);
   738     }
   739     case eTreeOpGetDocumentFragmentForTemplate: {
   740       nsIContent* node = *(mOne.node);
   741       *mTwo.node = GetDocumentFragmentForTemplate(node);
   742       return NS_OK;
   743     }
   744     case eTreeOpMarkAsBroken: {
   745       return mOne.result;
   746     }
   747     case eTreeOpRunScript: {
   748       nsIContent* node = *(mOne.node);
   749       nsAHtml5TreeBuilderState* snapshot = mTwo.state;
   750       if (snapshot) {
   751         aBuilder->InitializeDocWriteParserState(snapshot, mFour.integer);
   752       }
   753       *aScriptElement = node;
   754       return NS_OK;
   755     }
   756     case eTreeOpRunScriptAsyncDefer: {
   757       nsIContent* node = *(mOne.node);
   758       aBuilder->RunScript(node);
   759       return NS_OK;
   760     }
   761     case eTreeOpPreventScriptExecution: {
   762       nsIContent* node = *(mOne.node);
   763       PreventScriptExecution(node);
   764       return NS_OK;
   765     }
   766     case eTreeOpDoneAddingChildren: {
   767       nsIContent* node = *(mOne.node);
   768       node->DoneAddingChildren(aBuilder->HaveNotified(node));
   769       return NS_OK;
   770     }
   771     case eTreeOpDoneCreatingElement: {
   772       nsIContent* node = *(mOne.node);
   773       DoneCreatingElement(node);
   774       return NS_OK;
   775     }
   776     case eTreeOpFlushPendingAppendNotifications: {
   777       aBuilder->FlushPendingAppendNotifications();
   778       return NS_OK;
   779     }
   780     case eTreeOpSetDocumentCharset: {
   781       char* str = mOne.charPtr;
   782       int32_t charsetSource = mFour.integer;
   783       nsDependentCString dependentString(str);
   784       aBuilder->SetDocumentCharsetAndSource(dependentString, charsetSource);
   785       return NS_OK;
   786     }
   787     case eTreeOpNeedsCharsetSwitchTo: {
   788       char* str = mOne.charPtr;
   789       int32_t charsetSource = mFour.integer;
   790       int32_t lineNumber = mTwo.integer;
   791       aBuilder->NeedsCharsetSwitchTo(str, charsetSource, (uint32_t)lineNumber);
   792       return NS_OK;
   793     }
   794     case eTreeOpUpdateStyleSheet: {
   795       nsIContent* node = *(mOne.node);
   796       aBuilder->FlushPendingAppendNotifications();
   797       aBuilder->UpdateStyleSheet(node);
   798       return NS_OK;
   799     }
   800     case eTreeOpProcessMeta: {
   801       nsIContent* node = *(mOne.node);
   802       return aBuilder->ProcessMETATag(node);
   803     }
   804     case eTreeOpProcessOfflineManifest: {
   805       char16_t* str = mOne.unicharPtr;
   806       nsDependentString dependentString(str);
   807       aBuilder->ProcessOfflineManifest(dependentString);
   808       return NS_OK;
   809     }
   810     case eTreeOpMarkMalformedIfScript: {
   811       nsIContent* node = *(mOne.node);
   812       MarkMalformedIfScript(node);
   813       return NS_OK;
   814     }
   815     case eTreeOpStreamEnded: {
   816       aBuilder->DidBuildModel(false); // this causes a notifications flush anyway
   817       return NS_OK;
   818     }
   819     case eTreeOpStartLayout: {
   820       aBuilder->StartLayout(); // this causes a notification flush anyway
   821       return NS_OK;
   822     }
   823     case eTreeOpDocumentMode: {
   824       aBuilder->SetDocumentMode(mOne.mode);
   825       return NS_OK;
   826     }
   827     case eTreeOpSetStyleLineNumber: {
   828       nsIContent* node = *(mOne.node);
   829       nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(node);
   830       NS_ASSERTION(ssle, "Node didn't QI to style.");
   831       ssle->SetLineNumber(mFour.integer);
   832       return NS_OK;
   833     }
   834     case eTreeOpSetScriptLineNumberAndFreeze: {
   835       nsIContent* node = *(mOne.node);
   836       nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node);
   837       NS_ASSERTION(sele, "Node didn't QI to script.");
   838       sele->SetScriptLineNumber(mFour.integer);
   839       sele->FreezeUriAsyncDefer();
   840       return NS_OK;
   841     }
   842     case eTreeOpSvgLoad: {
   843       nsIContent* node = *(mOne.node);
   844       SvgLoad(node);
   845       return NS_OK;
   846     }
   847     case eTreeOpMaybeComplainAboutCharset: {
   848       char* msgId = mOne.charPtr;
   849       bool error = mTwo.integer;
   850       int32_t lineNumber = mThree.integer;
   851       aBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber);
   852       return NS_OK;
   853     }
   854     case eTreeOpAddClass: {
   855       nsIContent* node = *(mOne.node);
   856       char16_t* str = mTwo.unicharPtr;
   857       nsDependentString depStr(str);
   858       // See viewsource.css for the possible classes
   859       nsAutoString klass;
   860       node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
   861       if (!klass.IsEmpty()) {
   862         klass.Append(' ');
   863         klass.Append(depStr);
   864         node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
   865       } else {
   866         node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true);
   867       }
   868       return NS_OK;
   869     }
   870     case eTreeOpAddLineNumberId: {
   871       nsIContent* node = *(mOne.node);
   872       int32_t lineNumber = mFour.integer;
   873       nsAutoString val(NS_LITERAL_STRING("line"));
   874       val.AppendInt(lineNumber);
   875       node->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true);
   876       return NS_OK;
   877     }
   878     case eTreeOpAddViewSourceHref: {
   879       nsIContent* node = *mOne.node;
   880       char16_t* buffer = mTwo.unicharPtr;
   881       int32_t length = mFour.integer;
   883       nsDependentString relative(buffer, length);
   885       nsIDocument* doc = aBuilder->GetDocument();
   887       const nsCString& charset = doc->GetDocumentCharacterSet();
   888       nsCOMPtr<nsIURI> uri;
   889       nsresult rv = NS_NewURI(getter_AddRefs(uri),
   890                               relative,
   891                               charset.get(),
   892                               aBuilder->GetViewSourceBaseURI());
   893       NS_ENSURE_SUCCESS(rv, NS_OK);
   895       // Reuse the fix for bug 467852
   896       // URLs that execute script (e.g. "javascript:" URLs) should just be
   897       // ignored.  There's nothing reasonable we can do with them, and allowing
   898       // them to execute in the context of the view-source window presents a
   899       // security risk.  Just return the empty string in this case.
   900       bool openingExecutesScript = false;
   901       rv = NS_URIChainHasFlags(uri,
   902                                nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT,
   903                                &openingExecutesScript);
   904       if (NS_FAILED(rv) || openingExecutesScript) {
   905         return NS_OK;
   906       }
   908       nsAutoCString viewSourceUrl;
   910       // URLs that return data (e.g. "http:" URLs) should be prefixed with
   911       // "view-source:".  URLs that don't return data should just be returned
   912       // undecorated.
   913       bool doesNotReturnData = false;
   914       rv = NS_URIChainHasFlags(uri,
   915                                nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA,
   916                                &doesNotReturnData);
   917       NS_ENSURE_SUCCESS(rv, NS_OK);
   918       if (!doesNotReturnData) {
   919         viewSourceUrl.AssignLiteral("view-source:");
   920       }
   922       nsAutoCString spec;
   923       uri->GetSpec(spec);
   925       viewSourceUrl.Append(spec);
   927       nsAutoString utf16;
   928       CopyUTF8toUTF16(viewSourceUrl, utf16);
   930       node->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true);
   931       return rv;
   932     }
   933     case eTreeOpAddError: {
   934       nsIContent* node = *(mOne.node);
   935       char* msgId = mTwo.charPtr;
   936       nsCOMPtr<nsIAtom> atom = Reget(mThree.atom);
   937       nsCOMPtr<nsIAtom> otherAtom = Reget(mFour.atom);
   938       // See viewsource.css for the possible classes in addition to "error".
   939       nsAutoString klass;
   940       node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass);
   941       if (!klass.IsEmpty()) {
   942         klass.Append(NS_LITERAL_STRING(" error"));
   943         node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true);
   944       } else {
   945         node->SetAttr(kNameSpaceID_None,
   946                       nsGkAtoms::_class,
   947                       NS_LITERAL_STRING("error"),
   948                       true);
   949       }
   951       nsresult rv;
   952       nsXPIDLString message;
   953       if (otherAtom) {
   954         const char16_t* params[] = { atom->GetUTF16String(),
   955                                       otherAtom->GetUTF16String() };
   956         rv = nsContentUtils::FormatLocalizedString(
   957           nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message);
   958         NS_ENSURE_SUCCESS(rv, NS_OK);
   959       } else if (atom) {
   960         const char16_t* params[] = { atom->GetUTF16String() };
   961         rv = nsContentUtils::FormatLocalizedString(
   962           nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message);
   963         NS_ENSURE_SUCCESS(rv, NS_OK);
   964       } else {
   965         rv = nsContentUtils::GetLocalizedString(
   966           nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message);
   967         NS_ENSURE_SUCCESS(rv, NS_OK);
   968       }
   970       nsAutoString title;
   971       node->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
   972       if (!title.IsEmpty()) {
   973         title.Append('\n');
   974         title.Append(message);
   975         node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true);
   976       } else {
   977         node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true);
   978       }
   979       return rv;
   980     }
   981     default: {
   982       NS_NOTREACHED("Bogus tree op");
   983     }
   984   }
   985   return NS_OK; // keep compiler happy
   986 }

mercurial