1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/parser/html/nsHtml5TreeOperation.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,986 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=78: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsHtml5TreeOperation.h" 1.11 +#include "nsContentUtils.h" 1.12 +#include "nsDocElementCreatedNotificationRunner.h" 1.13 +#include "nsNodeUtils.h" 1.14 +#include "nsAttrName.h" 1.15 +#include "nsHtml5TreeBuilder.h" 1.16 +#include "nsIDOMMutationEvent.h" 1.17 +#include "mozAutoDocUpdate.h" 1.18 +#include "nsBindingManager.h" 1.19 +#include "nsXBLBinding.h" 1.20 +#include "nsHtml5DocumentMode.h" 1.21 +#include "nsHtml5HtmlAttributes.h" 1.22 +#include "nsContentCreatorFunctions.h" 1.23 +#include "nsIScriptElement.h" 1.24 +#include "nsIDTD.h" 1.25 +#include "nsISupportsImpl.h" 1.26 +#include "nsIDOMHTMLFormElement.h" 1.27 +#include "nsIFormControl.h" 1.28 +#include "nsIStyleSheetLinkingElement.h" 1.29 +#include "nsIDOMDocumentType.h" 1.30 +#include "nsIObserverService.h" 1.31 +#include "mozilla/Services.h" 1.32 +#include "nsIMutationObserver.h" 1.33 +#include "nsIFormProcessor.h" 1.34 +#include "nsIServiceManager.h" 1.35 +#include "nsEscape.h" 1.36 +#include "mozilla/dom/Comment.h" 1.37 +#include "mozilla/dom/Element.h" 1.38 +#include "mozilla/dom/HTMLImageElement.h" 1.39 +#include "mozilla/dom/HTMLTemplateElement.h" 1.40 +#include "nsHtml5SVGLoadDispatcher.h" 1.41 +#include "nsIURI.h" 1.42 +#include "nsIProtocolHandler.h" 1.43 +#include "nsNetUtil.h" 1.44 +#include "nsIHTMLDocument.h" 1.45 +#include "mozilla/Likely.h" 1.46 +#include "nsTextNode.h" 1.47 + 1.48 +using namespace mozilla; 1.49 + 1.50 +static NS_DEFINE_CID(kFormProcessorCID, NS_FORMPROCESSOR_CID); 1.51 + 1.52 +/** 1.53 + * Helper class that opens a notification batch if the current doc 1.54 + * is different from the executor doc. 1.55 + */ 1.56 +class MOZ_STACK_CLASS nsHtml5OtherDocUpdate { 1.57 + public: 1.58 + nsHtml5OtherDocUpdate(nsIDocument* aCurrentDoc, nsIDocument* aExecutorDoc) 1.59 + { 1.60 + NS_PRECONDITION(aCurrentDoc, "Node has no doc?"); 1.61 + NS_PRECONDITION(aExecutorDoc, "Executor has no doc?"); 1.62 + if (MOZ_LIKELY(aCurrentDoc == aExecutorDoc)) { 1.63 + mDocument = nullptr; 1.64 + } else { 1.65 + mDocument = aCurrentDoc; 1.66 + aCurrentDoc->BeginUpdate(UPDATE_CONTENT_MODEL); 1.67 + } 1.68 + } 1.69 + 1.70 + ~nsHtml5OtherDocUpdate() 1.71 + { 1.72 + if (MOZ_UNLIKELY(mDocument)) { 1.73 + mDocument->EndUpdate(UPDATE_CONTENT_MODEL); 1.74 + } 1.75 + } 1.76 + private: 1.77 + nsIDocument* mDocument; 1.78 +}; 1.79 + 1.80 +nsHtml5TreeOperation::nsHtml5TreeOperation() 1.81 +#ifdef DEBUG 1.82 + : mOpCode(eTreeOpUninitialized) 1.83 +#endif 1.84 +{ 1.85 + MOZ_COUNT_CTOR(nsHtml5TreeOperation); 1.86 +} 1.87 + 1.88 +nsHtml5TreeOperation::~nsHtml5TreeOperation() 1.89 +{ 1.90 + MOZ_COUNT_DTOR(nsHtml5TreeOperation); 1.91 + NS_ASSERTION(mOpCode != eTreeOpUninitialized, "Uninitialized tree op."); 1.92 + switch(mOpCode) { 1.93 + case eTreeOpAddAttributes: 1.94 + delete mTwo.attributes; 1.95 + break; 1.96 + case eTreeOpCreateElementNetwork: 1.97 + case eTreeOpCreateElementNotNetwork: 1.98 + delete mThree.attributes; 1.99 + break; 1.100 + case eTreeOpAppendDoctypeToDocument: 1.101 + delete mTwo.stringPair; 1.102 + break; 1.103 + case eTreeOpFosterParentText: 1.104 + case eTreeOpAppendText: 1.105 + case eTreeOpAppendComment: 1.106 + case eTreeOpAppendCommentToDocument: 1.107 + case eTreeOpAddViewSourceHref: 1.108 + delete[] mTwo.unicharPtr; 1.109 + break; 1.110 + case eTreeOpSetDocumentCharset: 1.111 + case eTreeOpNeedsCharsetSwitchTo: 1.112 + delete[] mOne.charPtr; 1.113 + break; 1.114 + case eTreeOpProcessOfflineManifest: 1.115 + nsMemory::Free(mOne.unicharPtr); 1.116 + break; 1.117 + default: // keep the compiler happy 1.118 + break; 1.119 + } 1.120 +} 1.121 + 1.122 +nsresult 1.123 +nsHtml5TreeOperation::AppendTextToTextNode(const char16_t* aBuffer, 1.124 + uint32_t aLength, 1.125 + nsIContent* aTextNode, 1.126 + nsHtml5DocumentBuilder* aBuilder) 1.127 +{ 1.128 + NS_PRECONDITION(aTextNode, "Got null text node."); 1.129 + 1.130 + if (aBuilder->HaveNotified(aTextNode)) { 1.131 + // This text node has already been notified on, so it's necessary to 1.132 + // notify on the append 1.133 + nsresult rv = NS_OK; 1.134 + uint32_t oldLength = aTextNode->TextLength(); 1.135 + CharacterDataChangeInfo info = { 1.136 + true, 1.137 + oldLength, 1.138 + oldLength, 1.139 + aLength 1.140 + }; 1.141 + nsNodeUtils::CharacterDataWillChange(aTextNode, &info); 1.142 + 1.143 + rv = aTextNode->AppendText(aBuffer, aLength, false); 1.144 + NS_ENSURE_SUCCESS(rv, rv); 1.145 + 1.146 + nsNodeUtils::CharacterDataChanged(aTextNode, &info); 1.147 + return rv; 1.148 + } 1.149 + 1.150 + return aTextNode->AppendText(aBuffer, aLength, false); 1.151 +} 1.152 + 1.153 + 1.154 +nsresult 1.155 +nsHtml5TreeOperation::AppendText(const char16_t* aBuffer, 1.156 + uint32_t aLength, 1.157 + nsIContent* aParent, 1.158 + nsHtml5DocumentBuilder* aBuilder) 1.159 +{ 1.160 + nsresult rv = NS_OK; 1.161 + nsIContent* lastChild = aParent->GetLastChild(); 1.162 + if (lastChild && lastChild->IsNodeOfType(nsINode::eTEXT)) { 1.163 + nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), 1.164 + aBuilder->GetDocument()); 1.165 + return AppendTextToTextNode(aBuffer, 1.166 + aLength, 1.167 + lastChild, 1.168 + aBuilder); 1.169 + } 1.170 + 1.171 + nsRefPtr<nsTextNode> text = new nsTextNode(aBuilder->GetNodeInfoManager()); 1.172 + NS_ASSERTION(text, "Infallible malloc failed?"); 1.173 + rv = text->SetText(aBuffer, aLength, false); 1.174 + NS_ENSURE_SUCCESS(rv, rv); 1.175 + 1.176 + return Append(text, aParent, aBuilder); 1.177 +} 1.178 + 1.179 +nsresult 1.180 +nsHtml5TreeOperation::Append(nsIContent* aNode, 1.181 + nsIContent* aParent, 1.182 + nsHtml5DocumentBuilder* aBuilder) 1.183 +{ 1.184 + nsresult rv = NS_OK; 1.185 + nsIDocument* executorDoc = aBuilder->GetDocument(); 1.186 + NS_ASSERTION(executorDoc, "Null doc on executor"); 1.187 + nsIDocument* parentDoc = aParent->OwnerDoc(); 1.188 + NS_ASSERTION(parentDoc, "Null owner doc on old node."); 1.189 + 1.190 + if (MOZ_LIKELY(executorDoc == parentDoc)) { 1.191 + // the usual case. the parent is in the parser's doc 1.192 + rv = aParent->AppendChildTo(aNode, false); 1.193 + if (NS_SUCCEEDED(rv)) { 1.194 + aBuilder->PostPendingAppendNotification(aParent, aNode); 1.195 + } 1.196 + return rv; 1.197 + } 1.198 + 1.199 + // The parent has been moved to another doc 1.200 + parentDoc->BeginUpdate(UPDATE_CONTENT_MODEL); 1.201 + 1.202 + uint32_t childCount = aParent->GetChildCount(); 1.203 + rv = aParent->AppendChildTo(aNode, false); 1.204 + if (NS_SUCCEEDED(rv)) { 1.205 + nsNodeUtils::ContentAppended(aParent, aNode, childCount); 1.206 + } 1.207 + parentDoc->EndUpdate(UPDATE_CONTENT_MODEL); 1.208 + return rv; 1.209 +} 1.210 + 1.211 +nsresult 1.212 +nsHtml5TreeOperation::AppendToDocument(nsIContent* aNode, 1.213 + nsHtml5DocumentBuilder* aBuilder) 1.214 +{ 1.215 + nsresult rv = NS_OK; 1.216 + aBuilder->FlushPendingAppendNotifications(); 1.217 + nsIDocument* doc = aBuilder->GetDocument(); 1.218 + uint32_t childCount = doc->GetChildCount(); 1.219 + rv = doc->AppendChildTo(aNode, false); 1.220 + if (rv == NS_ERROR_DOM_HIERARCHY_REQUEST_ERR) { 1.221 + return NS_OK; 1.222 + } 1.223 + NS_ENSURE_SUCCESS(rv, rv); 1.224 + nsNodeUtils::ContentInserted(doc, aNode, childCount); 1.225 + 1.226 + NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 1.227 + "Someone forgot to block scripts"); 1.228 + if (aNode->IsElement()) { 1.229 + nsContentUtils::AddScriptRunner( 1.230 + new nsDocElementCreatedNotificationRunner(doc)); 1.231 + } 1.232 + return rv; 1.233 +} 1.234 + 1.235 +static bool 1.236 +IsElementOrTemplateContent(nsINode* aNode) { 1.237 + if (aNode) { 1.238 + if (aNode->IsElement()) { 1.239 + return true; 1.240 + } else if (aNode->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) { 1.241 + // Check if the node is a template content. 1.242 + mozilla::dom::DocumentFragment* frag = 1.243 + static_cast<mozilla::dom::DocumentFragment*>(aNode); 1.244 + nsIContent* fragHost = frag->GetHost(); 1.245 + if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) { 1.246 + return true; 1.247 + } 1.248 + } 1.249 + } 1.250 + return false; 1.251 +} 1.252 + 1.253 +void 1.254 +nsHtml5TreeOperation::Detach(nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder) 1.255 +{ 1.256 + aBuilder->FlushPendingAppendNotifications(); 1.257 + nsCOMPtr<nsINode> parent = aNode->GetParentNode(); 1.258 + if (parent) { 1.259 + nsHtml5OtherDocUpdate update(parent->OwnerDoc(), 1.260 + aBuilder->GetDocument()); 1.261 + int32_t pos = parent->IndexOf(aNode); 1.262 + NS_ASSERTION((pos >= 0), "Element not found as child of its parent"); 1.263 + parent->RemoveChildAt(pos, true); 1.264 + } 1.265 +} 1.266 + 1.267 +nsresult 1.268 +nsHtml5TreeOperation::AppendChildrenToNewParent(nsIContent* aNode, 1.269 + nsIContent* aParent, 1.270 + nsHtml5DocumentBuilder* aBuilder) 1.271 +{ 1.272 + aBuilder->FlushPendingAppendNotifications(); 1.273 + 1.274 + nsHtml5OtherDocUpdate update(aParent->OwnerDoc(), 1.275 + aBuilder->GetDocument()); 1.276 + 1.277 + uint32_t childCount = aParent->GetChildCount(); 1.278 + bool didAppend = false; 1.279 + while (aNode->HasChildren()) { 1.280 + nsCOMPtr<nsIContent> child = aNode->GetFirstChild(); 1.281 + aNode->RemoveChildAt(0, true); 1.282 + nsresult rv = aParent->AppendChildTo(child, false); 1.283 + NS_ENSURE_SUCCESS(rv, rv); 1.284 + didAppend = true; 1.285 + } 1.286 + if (didAppend) { 1.287 + nsNodeUtils::ContentAppended(aParent, aParent->GetChildAt(childCount), 1.288 + childCount); 1.289 + } 1.290 + return NS_OK; 1.291 +} 1.292 + 1.293 +nsresult 1.294 +nsHtml5TreeOperation::FosterParent(nsIContent* aNode, 1.295 + nsIContent* aParent, 1.296 + nsIContent* aTable, 1.297 + nsHtml5DocumentBuilder* aBuilder) 1.298 +{ 1.299 + nsIContent* foster = aTable->GetParent(); 1.300 + 1.301 + if (IsElementOrTemplateContent(foster)) { 1.302 + aBuilder->FlushPendingAppendNotifications(); 1.303 + 1.304 + nsHtml5OtherDocUpdate update(foster->OwnerDoc(), 1.305 + aBuilder->GetDocument()); 1.306 + 1.307 + uint32_t pos = foster->IndexOf(aTable); 1.308 + nsresult rv = foster->InsertChildAt(aNode, pos, false); 1.309 + NS_ENSURE_SUCCESS(rv, rv); 1.310 + nsNodeUtils::ContentInserted(foster, aNode, pos); 1.311 + return rv; 1.312 + } 1.313 + 1.314 + return Append(aNode, aParent, aBuilder); 1.315 +} 1.316 + 1.317 +nsresult 1.318 +nsHtml5TreeOperation::AddAttributes(nsIContent* aNode, 1.319 + nsHtml5HtmlAttributes* aAttributes, 1.320 + nsHtml5DocumentBuilder* aBuilder) 1.321 +{ 1.322 + dom::Element* node = aNode->AsElement(); 1.323 + nsHtml5OtherDocUpdate update(node->OwnerDoc(), 1.324 + aBuilder->GetDocument()); 1.325 + 1.326 + int32_t len = aAttributes->getLength(); 1.327 + for (int32_t i = len; i > 0;) { 1.328 + --i; 1.329 + // prefix doesn't need regetting. it is always null or a static atom 1.330 + // local name is never null 1.331 + nsCOMPtr<nsIAtom> localName = 1.332 + Reget(aAttributes->getLocalNameNoBoundsCheck(i)); 1.333 + int32_t nsuri = aAttributes->getURINoBoundsCheck(i); 1.334 + if (!node->HasAttr(nsuri, localName)) { 1.335 + // prefix doesn't need regetting. it is always null or a static atom 1.336 + // local name is never null 1.337 + node->SetAttr(nsuri, 1.338 + localName, 1.339 + aAttributes->getPrefixNoBoundsCheck(i), 1.340 + *(aAttributes->getValueNoBoundsCheck(i)), 1.341 + true); 1.342 + // XXX what to do with nsresult? 1.343 + } 1.344 + } 1.345 + return NS_OK; 1.346 +} 1.347 + 1.348 + 1.349 +nsIContent* 1.350 +nsHtml5TreeOperation::CreateElement(int32_t aNs, 1.351 + nsIAtom* aName, 1.352 + nsHtml5HtmlAttributes* aAttributes, 1.353 + mozilla::dom::FromParser aFromParser, 1.354 + nsHtml5DocumentBuilder* aBuilder) 1.355 +{ 1.356 + bool isKeygen = (aName == nsHtml5Atoms::keygen && aNs == kNameSpaceID_XHTML); 1.357 + if (MOZ_UNLIKELY(isKeygen)) { 1.358 + aName = nsHtml5Atoms::select; 1.359 + } 1.360 + 1.361 + nsCOMPtr<dom::Element> newContent; 1.362 + nsCOMPtr<nsINodeInfo> nodeInfo = aBuilder->GetNodeInfoManager()-> 1.363 + GetNodeInfo(aName, nullptr, aNs, nsIDOMNode::ELEMENT_NODE); 1.364 + NS_ASSERTION(nodeInfo, "Got null nodeinfo."); 1.365 + NS_NewElement(getter_AddRefs(newContent), 1.366 + nodeInfo.forget(), 1.367 + aFromParser); 1.368 + NS_ASSERTION(newContent, "Element creation created null pointer."); 1.369 + 1.370 + aBuilder->HoldElement(newContent); 1.371 + 1.372 + if (MOZ_UNLIKELY(aName == nsHtml5Atoms::style || aName == nsHtml5Atoms::link)) { 1.373 + nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(newContent)); 1.374 + if (ssle) { 1.375 + ssle->InitStyleLinkElement(false); 1.376 + ssle->SetEnableUpdates(false); 1.377 + } 1.378 + } else if (MOZ_UNLIKELY(isKeygen)) { 1.379 + // Adapted from CNavDTD 1.380 + nsresult rv; 1.381 + nsCOMPtr<nsIFormProcessor> theFormProcessor = 1.382 + do_GetService(kFormProcessorCID, &rv); 1.383 + if (NS_FAILED(rv)) { 1.384 + return newContent; 1.385 + } 1.386 + 1.387 + nsTArray<nsString> theContent; 1.388 + nsAutoString theAttribute; 1.389 + 1.390 + (void) theFormProcessor->ProvideContent(NS_LITERAL_STRING("select"), 1.391 + theContent, 1.392 + theAttribute); 1.393 + 1.394 + newContent->SetAttr(kNameSpaceID_None, 1.395 + nsGkAtoms::moztype, 1.396 + nullptr, 1.397 + theAttribute, 1.398 + false); 1.399 + 1.400 + nsCOMPtr<nsINodeInfo> optionNodeInfo = 1.401 + aBuilder->GetNodeInfoManager()->GetNodeInfo(nsHtml5Atoms::option, 1.402 + nullptr, 1.403 + kNameSpaceID_XHTML, 1.404 + nsIDOMNode::ELEMENT_NODE); 1.405 + 1.406 + for (uint32_t i = 0; i < theContent.Length(); ++i) { 1.407 + nsCOMPtr<dom::Element> optionElt; 1.408 + nsCOMPtr<nsINodeInfo> ni = optionNodeInfo; 1.409 + NS_NewElement(getter_AddRefs(optionElt), 1.410 + ni.forget(), 1.411 + aFromParser); 1.412 + nsRefPtr<nsTextNode> optionText = 1.413 + new nsTextNode(aBuilder->GetNodeInfoManager()); 1.414 + (void) optionText->SetText(theContent[i], false); 1.415 + optionElt->AppendChildTo(optionText, false); 1.416 + newContent->AppendChildTo(optionElt, false); 1.417 + newContent->DoneAddingChildren(false); 1.418 + } 1.419 + } 1.420 + 1.421 + if (!aAttributes) { 1.422 + return newContent; 1.423 + } 1.424 + 1.425 + int32_t len = aAttributes->getLength(); 1.426 + for (int32_t i = len; i > 0;) { 1.427 + --i; 1.428 + // prefix doesn't need regetting. it is always null or a static atom 1.429 + // local name is never null 1.430 + nsCOMPtr<nsIAtom> localName = 1.431 + Reget(aAttributes->getLocalNameNoBoundsCheck(i)); 1.432 + nsCOMPtr<nsIAtom> prefix = aAttributes->getPrefixNoBoundsCheck(i); 1.433 + int32_t nsuri = aAttributes->getURINoBoundsCheck(i); 1.434 + 1.435 + if (aNs == kNameSpaceID_XHTML && 1.436 + nsHtml5Atoms::a == aName && 1.437 + nsHtml5Atoms::name == localName) { 1.438 + // This is an HTML5-incompliant Geckoism. 1.439 + // Remove when fixing bug 582361 1.440 + NS_ConvertUTF16toUTF8 cname(*(aAttributes->getValueNoBoundsCheck(i))); 1.441 + NS_ConvertUTF8toUTF16 uv(nsUnescape(cname.BeginWriting())); 1.442 + newContent->SetAttr(nsuri, 1.443 + localName, 1.444 + prefix, 1.445 + uv, 1.446 + false); 1.447 + } else { 1.448 + nsString& value = *(aAttributes->getValueNoBoundsCheck(i)); 1.449 + newContent->SetAttr(nsuri, 1.450 + localName, 1.451 + prefix, 1.452 + value, 1.453 + false); 1.454 + 1.455 + // Custom element prototype swizzling may be needed if there is an 1.456 + // "is" attribute. 1.457 + if (kNameSpaceID_None == nsuri && !prefix && nsGkAtoms::is == localName) { 1.458 + ErrorResult errorResult; 1.459 + newContent->OwnerDoc()->SwizzleCustomElement(newContent, 1.460 + value, 1.461 + newContent->GetNameSpaceID(), 1.462 + errorResult); 1.463 + } 1.464 + } 1.465 + } 1.466 + return newContent; 1.467 +} 1.468 + 1.469 +void 1.470 +nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent) 1.471 +{ 1.472 + nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(aNode)); 1.473 + nsCOMPtr<nsIDOMHTMLImageElement> domImageElement = do_QueryInterface(aNode); 1.474 + // NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl."); 1.475 + // TODO: uncomment the above line when <keygen> (bug 101019) is supported by Gecko 1.476 + nsCOMPtr<nsIDOMHTMLFormElement> formElement(do_QueryInterface(aParent)); 1.477 + NS_ASSERTION(formElement, "The form element doesn't implement nsIDOMHTMLFormElement."); 1.478 + // avoid crashing on <keygen> 1.479 + if (formControl && 1.480 + !aNode->HasAttr(kNameSpaceID_None, nsGkAtoms::form)) { 1.481 + formControl->SetForm(formElement); 1.482 + } else if (domImageElement) { 1.483 + nsRefPtr<dom::HTMLImageElement> imageElement = 1.484 + static_cast<dom::HTMLImageElement*>(domImageElement.get()); 1.485 + MOZ_ASSERT(imageElement); 1.486 + imageElement->SetForm(formElement); 1.487 + } 1.488 +} 1.489 + 1.490 +nsresult 1.491 +nsHtml5TreeOperation::AppendIsindexPrompt(nsIContent* parent, nsHtml5DocumentBuilder* aBuilder) 1.492 +{ 1.493 + nsXPIDLString prompt; 1.494 + nsresult rv = 1.495 + nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES, 1.496 + "IsIndexPromptWithSpace", prompt); 1.497 + uint32_t len = prompt.Length(); 1.498 + if (NS_FAILED(rv)) { 1.499 + return rv; 1.500 + } 1.501 + if (!len) { 1.502 + // Don't bother appending a zero-length text node. 1.503 + return NS_OK; 1.504 + } 1.505 + return AppendText(prompt.BeginReading(), len, parent, aBuilder); 1.506 +} 1.507 + 1.508 +nsresult 1.509 +nsHtml5TreeOperation::FosterParentText(nsIContent* aStackParent, 1.510 + char16_t* aBuffer, 1.511 + uint32_t aLength, 1.512 + nsIContent* aTable, 1.513 + nsHtml5DocumentBuilder* aBuilder) 1.514 +{ 1.515 + nsresult rv = NS_OK; 1.516 + nsIContent* foster = aTable->GetParent(); 1.517 + 1.518 + if (IsElementOrTemplateContent(foster)) { 1.519 + aBuilder->FlushPendingAppendNotifications(); 1.520 + 1.521 + nsHtml5OtherDocUpdate update(foster->OwnerDoc(), 1.522 + aBuilder->GetDocument()); 1.523 + 1.524 + uint32_t pos = foster->IndexOf(aTable); 1.525 + 1.526 + nsIContent* previousSibling = aTable->GetPreviousSibling(); 1.527 + if (previousSibling && previousSibling->IsNodeOfType(nsINode::eTEXT)) { 1.528 + return AppendTextToTextNode(aBuffer, 1.529 + aLength, 1.530 + previousSibling, 1.531 + aBuilder); 1.532 + } 1.533 + 1.534 + nsRefPtr<nsTextNode> text = 1.535 + new nsTextNode(aBuilder->GetNodeInfoManager()); 1.536 + NS_ASSERTION(text, "Infallible malloc failed?"); 1.537 + rv = text->SetText(aBuffer, aLength, false); 1.538 + NS_ENSURE_SUCCESS(rv, rv); 1.539 + 1.540 + rv = foster->InsertChildAt(text, pos, false); 1.541 + NS_ENSURE_SUCCESS(rv, rv); 1.542 + nsNodeUtils::ContentInserted(foster, text, pos); 1.543 + return rv; 1.544 + } 1.545 + 1.546 + return AppendText(aBuffer, aLength, aStackParent, aBuilder); 1.547 +} 1.548 + 1.549 +nsresult 1.550 +nsHtml5TreeOperation::AppendComment(nsIContent* aParent, 1.551 + char16_t* aBuffer, 1.552 + int32_t aLength, 1.553 + nsHtml5DocumentBuilder* aBuilder) 1.554 +{ 1.555 + nsRefPtr<dom::Comment> comment = 1.556 + new dom::Comment(aBuilder->GetNodeInfoManager()); 1.557 + NS_ASSERTION(comment, "Infallible malloc failed?"); 1.558 + nsresult rv = comment->SetText(aBuffer, aLength, false); 1.559 + NS_ENSURE_SUCCESS(rv, rv); 1.560 + 1.561 + return Append(comment, aParent, aBuilder); 1.562 +} 1.563 + 1.564 +nsresult 1.565 +nsHtml5TreeOperation::AppendCommentToDocument(char16_t* aBuffer, 1.566 + int32_t aLength, 1.567 + nsHtml5DocumentBuilder* aBuilder) 1.568 +{ 1.569 + nsRefPtr<dom::Comment> comment = 1.570 + new dom::Comment(aBuilder->GetNodeInfoManager()); 1.571 + NS_ASSERTION(comment, "Infallible malloc failed?"); 1.572 + nsresult rv = comment->SetText(aBuffer, aLength, false); 1.573 + NS_ENSURE_SUCCESS(rv, rv); 1.574 + 1.575 + return AppendToDocument(comment, aBuilder); 1.576 +} 1.577 + 1.578 +nsresult 1.579 +nsHtml5TreeOperation::AppendDoctypeToDocument(nsIAtom* aName, 1.580 + const nsAString& aPublicId, 1.581 + const nsAString& aSystemId, 1.582 + nsHtml5DocumentBuilder* aBuilder) 1.583 +{ 1.584 + // Adapted from nsXMLContentSink 1.585 + // Create a new doctype node 1.586 + nsCOMPtr<nsIDOMDocumentType> docType; 1.587 + nsAutoString voidString; 1.588 + voidString.SetIsVoid(true); 1.589 + NS_NewDOMDocumentType(getter_AddRefs(docType), 1.590 + aBuilder->GetNodeInfoManager(), 1.591 + aName, 1.592 + aPublicId, 1.593 + aSystemId, 1.594 + voidString); 1.595 + NS_ASSERTION(docType, "Doctype creation failed."); 1.596 + nsCOMPtr<nsIContent> asContent = do_QueryInterface(docType); 1.597 + return AppendToDocument(asContent, aBuilder); 1.598 +} 1.599 + 1.600 +nsIContent* 1.601 +nsHtml5TreeOperation::GetDocumentFragmentForTemplate(nsIContent* aNode) 1.602 +{ 1.603 + dom::HTMLTemplateElement* tempElem = 1.604 + static_cast<dom::HTMLTemplateElement*>(aNode); 1.605 + nsRefPtr<dom::DocumentFragment> frag = tempElem->Content(); 1.606 + return frag; 1.607 +} 1.608 + 1.609 +void 1.610 +nsHtml5TreeOperation::PreventScriptExecution(nsIContent* aNode) 1.611 +{ 1.612 + nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode); 1.613 + MOZ_ASSERT(sele); 1.614 + sele->PreventExecution(); 1.615 +} 1.616 + 1.617 +void 1.618 +nsHtml5TreeOperation::DoneAddingChildren(nsIContent* aNode, 1.619 + nsHtml5DocumentBuilder* aBuilder) 1.620 +{ 1.621 + aNode->DoneAddingChildren(aBuilder->HaveNotified(aNode)); 1.622 +} 1.623 + 1.624 +void 1.625 +nsHtml5TreeOperation::DoneCreatingElement(nsIContent* aNode) 1.626 +{ 1.627 + aNode->DoneCreatingElement(); 1.628 +} 1.629 + 1.630 +void 1.631 +nsHtml5TreeOperation::SvgLoad(nsIContent* aNode) 1.632 +{ 1.633 + nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode); 1.634 + if (NS_FAILED(NS_DispatchToMainThread(event))) { 1.635 + NS_WARNING("failed to dispatch svg load dispatcher"); 1.636 + } 1.637 +} 1.638 + 1.639 +void 1.640 +nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode) 1.641 +{ 1.642 + nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode); 1.643 + if (sele) { 1.644 + // Make sure to serialize this script correctly, for nice round tripping. 1.645 + sele->SetIsMalformed(); 1.646 + } 1.647 +} 1.648 + 1.649 +nsresult 1.650 +nsHtml5TreeOperation::Perform(nsHtml5TreeOpExecutor* aBuilder, 1.651 + nsIContent** aScriptElement) 1.652 +{ 1.653 + switch(mOpCode) { 1.654 + case eTreeOpAppend: { 1.655 + nsIContent* node = *(mOne.node); 1.656 + nsIContent* parent = *(mTwo.node); 1.657 + return Append(node, parent, aBuilder); 1.658 + } 1.659 + case eTreeOpDetach: { 1.660 + nsIContent* node = *(mOne.node); 1.661 + Detach(node, aBuilder); 1.662 + return NS_OK; 1.663 + } 1.664 + case eTreeOpAppendChildrenToNewParent: { 1.665 + nsCOMPtr<nsIContent> node = *(mOne.node); 1.666 + nsIContent* parent = *(mTwo.node); 1.667 + return AppendChildrenToNewParent(node, parent, aBuilder); 1.668 + } 1.669 + case eTreeOpFosterParent: { 1.670 + nsIContent* node = *(mOne.node); 1.671 + nsIContent* parent = *(mTwo.node); 1.672 + nsIContent* table = *(mThree.node); 1.673 + return FosterParent(node, parent, table, aBuilder); 1.674 + } 1.675 + case eTreeOpAppendToDocument: { 1.676 + nsIContent* node = *(mOne.node); 1.677 + return AppendToDocument(node, aBuilder); 1.678 + } 1.679 + case eTreeOpAddAttributes: { 1.680 + nsIContent* node = *(mOne.node); 1.681 + nsHtml5HtmlAttributes* attributes = mTwo.attributes; 1.682 + return AddAttributes(node, attributes, aBuilder); 1.683 + } 1.684 + case eTreeOpCreateElementNetwork: 1.685 + case eTreeOpCreateElementNotNetwork: { 1.686 + nsIContent** target = mOne.node; 1.687 + int32_t ns = mFour.integer; 1.688 + nsCOMPtr<nsIAtom> name = Reget(mTwo.atom); 1.689 + nsHtml5HtmlAttributes* attributes = mThree.attributes; 1.690 + 1.691 + *target = CreateElement(ns, 1.692 + name, 1.693 + attributes, 1.694 + mOpCode == eTreeOpCreateElementNetwork ? 1.695 + dom::FROM_PARSER_NETWORK : 1.696 + dom::FROM_PARSER_DOCUMENT_WRITE, 1.697 + aBuilder); 1.698 + return NS_OK; 1.699 + } 1.700 + case eTreeOpSetFormElement: { 1.701 + nsIContent* node = *(mOne.node); 1.702 + nsIContent* parent = *(mTwo.node); 1.703 + SetFormElement(node, parent); 1.704 + return NS_OK; 1.705 + } 1.706 + case eTreeOpAppendText: { 1.707 + nsIContent* parent = *mOne.node; 1.708 + char16_t* buffer = mTwo.unicharPtr; 1.709 + uint32_t length = mFour.integer; 1.710 + return AppendText(buffer, length, parent, aBuilder); 1.711 + } 1.712 + case eTreeOpAppendIsindexPrompt: { 1.713 + nsIContent* parent = *mOne.node; 1.714 + return AppendIsindexPrompt(parent, aBuilder); 1.715 + } 1.716 + case eTreeOpFosterParentText: { 1.717 + nsIContent* stackParent = *mOne.node; 1.718 + char16_t* buffer = mTwo.unicharPtr; 1.719 + uint32_t length = mFour.integer; 1.720 + nsIContent* table = *mThree.node; 1.721 + return FosterParentText(stackParent, buffer, length, table, aBuilder); 1.722 + } 1.723 + case eTreeOpAppendComment: { 1.724 + nsIContent* parent = *mOne.node; 1.725 + char16_t* buffer = mTwo.unicharPtr; 1.726 + int32_t length = mFour.integer; 1.727 + return AppendComment(parent, buffer, length, aBuilder); 1.728 + } 1.729 + case eTreeOpAppendCommentToDocument: { 1.730 + char16_t* buffer = mTwo.unicharPtr; 1.731 + int32_t length = mFour.integer; 1.732 + return AppendCommentToDocument(buffer, length, aBuilder); 1.733 + } 1.734 + case eTreeOpAppendDoctypeToDocument: { 1.735 + nsCOMPtr<nsIAtom> name = Reget(mOne.atom); 1.736 + nsHtml5TreeOperationStringPair* pair = mTwo.stringPair; 1.737 + nsString publicId; 1.738 + nsString systemId; 1.739 + pair->Get(publicId, systemId); 1.740 + return AppendDoctypeToDocument(name, publicId, systemId, aBuilder); 1.741 + } 1.742 + case eTreeOpGetDocumentFragmentForTemplate: { 1.743 + nsIContent* node = *(mOne.node); 1.744 + *mTwo.node = GetDocumentFragmentForTemplate(node); 1.745 + return NS_OK; 1.746 + } 1.747 + case eTreeOpMarkAsBroken: { 1.748 + return mOne.result; 1.749 + } 1.750 + case eTreeOpRunScript: { 1.751 + nsIContent* node = *(mOne.node); 1.752 + nsAHtml5TreeBuilderState* snapshot = mTwo.state; 1.753 + if (snapshot) { 1.754 + aBuilder->InitializeDocWriteParserState(snapshot, mFour.integer); 1.755 + } 1.756 + *aScriptElement = node; 1.757 + return NS_OK; 1.758 + } 1.759 + case eTreeOpRunScriptAsyncDefer: { 1.760 + nsIContent* node = *(mOne.node); 1.761 + aBuilder->RunScript(node); 1.762 + return NS_OK; 1.763 + } 1.764 + case eTreeOpPreventScriptExecution: { 1.765 + nsIContent* node = *(mOne.node); 1.766 + PreventScriptExecution(node); 1.767 + return NS_OK; 1.768 + } 1.769 + case eTreeOpDoneAddingChildren: { 1.770 + nsIContent* node = *(mOne.node); 1.771 + node->DoneAddingChildren(aBuilder->HaveNotified(node)); 1.772 + return NS_OK; 1.773 + } 1.774 + case eTreeOpDoneCreatingElement: { 1.775 + nsIContent* node = *(mOne.node); 1.776 + DoneCreatingElement(node); 1.777 + return NS_OK; 1.778 + } 1.779 + case eTreeOpFlushPendingAppendNotifications: { 1.780 + aBuilder->FlushPendingAppendNotifications(); 1.781 + return NS_OK; 1.782 + } 1.783 + case eTreeOpSetDocumentCharset: { 1.784 + char* str = mOne.charPtr; 1.785 + int32_t charsetSource = mFour.integer; 1.786 + nsDependentCString dependentString(str); 1.787 + aBuilder->SetDocumentCharsetAndSource(dependentString, charsetSource); 1.788 + return NS_OK; 1.789 + } 1.790 + case eTreeOpNeedsCharsetSwitchTo: { 1.791 + char* str = mOne.charPtr; 1.792 + int32_t charsetSource = mFour.integer; 1.793 + int32_t lineNumber = mTwo.integer; 1.794 + aBuilder->NeedsCharsetSwitchTo(str, charsetSource, (uint32_t)lineNumber); 1.795 + return NS_OK; 1.796 + } 1.797 + case eTreeOpUpdateStyleSheet: { 1.798 + nsIContent* node = *(mOne.node); 1.799 + aBuilder->FlushPendingAppendNotifications(); 1.800 + aBuilder->UpdateStyleSheet(node); 1.801 + return NS_OK; 1.802 + } 1.803 + case eTreeOpProcessMeta: { 1.804 + nsIContent* node = *(mOne.node); 1.805 + return aBuilder->ProcessMETATag(node); 1.806 + } 1.807 + case eTreeOpProcessOfflineManifest: { 1.808 + char16_t* str = mOne.unicharPtr; 1.809 + nsDependentString dependentString(str); 1.810 + aBuilder->ProcessOfflineManifest(dependentString); 1.811 + return NS_OK; 1.812 + } 1.813 + case eTreeOpMarkMalformedIfScript: { 1.814 + nsIContent* node = *(mOne.node); 1.815 + MarkMalformedIfScript(node); 1.816 + return NS_OK; 1.817 + } 1.818 + case eTreeOpStreamEnded: { 1.819 + aBuilder->DidBuildModel(false); // this causes a notifications flush anyway 1.820 + return NS_OK; 1.821 + } 1.822 + case eTreeOpStartLayout: { 1.823 + aBuilder->StartLayout(); // this causes a notification flush anyway 1.824 + return NS_OK; 1.825 + } 1.826 + case eTreeOpDocumentMode: { 1.827 + aBuilder->SetDocumentMode(mOne.mode); 1.828 + return NS_OK; 1.829 + } 1.830 + case eTreeOpSetStyleLineNumber: { 1.831 + nsIContent* node = *(mOne.node); 1.832 + nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(node); 1.833 + NS_ASSERTION(ssle, "Node didn't QI to style."); 1.834 + ssle->SetLineNumber(mFour.integer); 1.835 + return NS_OK; 1.836 + } 1.837 + case eTreeOpSetScriptLineNumberAndFreeze: { 1.838 + nsIContent* node = *(mOne.node); 1.839 + nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(node); 1.840 + NS_ASSERTION(sele, "Node didn't QI to script."); 1.841 + sele->SetScriptLineNumber(mFour.integer); 1.842 + sele->FreezeUriAsyncDefer(); 1.843 + return NS_OK; 1.844 + } 1.845 + case eTreeOpSvgLoad: { 1.846 + nsIContent* node = *(mOne.node); 1.847 + SvgLoad(node); 1.848 + return NS_OK; 1.849 + } 1.850 + case eTreeOpMaybeComplainAboutCharset: { 1.851 + char* msgId = mOne.charPtr; 1.852 + bool error = mTwo.integer; 1.853 + int32_t lineNumber = mThree.integer; 1.854 + aBuilder->MaybeComplainAboutCharset(msgId, error, (uint32_t)lineNumber); 1.855 + return NS_OK; 1.856 + } 1.857 + case eTreeOpAddClass: { 1.858 + nsIContent* node = *(mOne.node); 1.859 + char16_t* str = mTwo.unicharPtr; 1.860 + nsDependentString depStr(str); 1.861 + // See viewsource.css for the possible classes 1.862 + nsAutoString klass; 1.863 + node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass); 1.864 + if (!klass.IsEmpty()) { 1.865 + klass.Append(' '); 1.866 + klass.Append(depStr); 1.867 + node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true); 1.868 + } else { 1.869 + node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, depStr, true); 1.870 + } 1.871 + return NS_OK; 1.872 + } 1.873 + case eTreeOpAddLineNumberId: { 1.874 + nsIContent* node = *(mOne.node); 1.875 + int32_t lineNumber = mFour.integer; 1.876 + nsAutoString val(NS_LITERAL_STRING("line")); 1.877 + val.AppendInt(lineNumber); 1.878 + node->SetAttr(kNameSpaceID_None, nsGkAtoms::id, val, true); 1.879 + return NS_OK; 1.880 + } 1.881 + case eTreeOpAddViewSourceHref: { 1.882 + nsIContent* node = *mOne.node; 1.883 + char16_t* buffer = mTwo.unicharPtr; 1.884 + int32_t length = mFour.integer; 1.885 + 1.886 + nsDependentString relative(buffer, length); 1.887 + 1.888 + nsIDocument* doc = aBuilder->GetDocument(); 1.889 + 1.890 + const nsCString& charset = doc->GetDocumentCharacterSet(); 1.891 + nsCOMPtr<nsIURI> uri; 1.892 + nsresult rv = NS_NewURI(getter_AddRefs(uri), 1.893 + relative, 1.894 + charset.get(), 1.895 + aBuilder->GetViewSourceBaseURI()); 1.896 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.897 + 1.898 + // Reuse the fix for bug 467852 1.899 + // URLs that execute script (e.g. "javascript:" URLs) should just be 1.900 + // ignored. There's nothing reasonable we can do with them, and allowing 1.901 + // them to execute in the context of the view-source window presents a 1.902 + // security risk. Just return the empty string in this case. 1.903 + bool openingExecutesScript = false; 1.904 + rv = NS_URIChainHasFlags(uri, 1.905 + nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, 1.906 + &openingExecutesScript); 1.907 + if (NS_FAILED(rv) || openingExecutesScript) { 1.908 + return NS_OK; 1.909 + } 1.910 + 1.911 + nsAutoCString viewSourceUrl; 1.912 + 1.913 + // URLs that return data (e.g. "http:" URLs) should be prefixed with 1.914 + // "view-source:". URLs that don't return data should just be returned 1.915 + // undecorated. 1.916 + bool doesNotReturnData = false; 1.917 + rv = NS_URIChainHasFlags(uri, 1.918 + nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, 1.919 + &doesNotReturnData); 1.920 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.921 + if (!doesNotReturnData) { 1.922 + viewSourceUrl.AssignLiteral("view-source:"); 1.923 + } 1.924 + 1.925 + nsAutoCString spec; 1.926 + uri->GetSpec(spec); 1.927 + 1.928 + viewSourceUrl.Append(spec); 1.929 + 1.930 + nsAutoString utf16; 1.931 + CopyUTF8toUTF16(viewSourceUrl, utf16); 1.932 + 1.933 + node->SetAttr(kNameSpaceID_None, nsGkAtoms::href, utf16, true); 1.934 + return rv; 1.935 + } 1.936 + case eTreeOpAddError: { 1.937 + nsIContent* node = *(mOne.node); 1.938 + char* msgId = mTwo.charPtr; 1.939 + nsCOMPtr<nsIAtom> atom = Reget(mThree.atom); 1.940 + nsCOMPtr<nsIAtom> otherAtom = Reget(mFour.atom); 1.941 + // See viewsource.css for the possible classes in addition to "error". 1.942 + nsAutoString klass; 1.943 + node->GetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass); 1.944 + if (!klass.IsEmpty()) { 1.945 + klass.Append(NS_LITERAL_STRING(" error")); 1.946 + node->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, klass, true); 1.947 + } else { 1.948 + node->SetAttr(kNameSpaceID_None, 1.949 + nsGkAtoms::_class, 1.950 + NS_LITERAL_STRING("error"), 1.951 + true); 1.952 + } 1.953 + 1.954 + nsresult rv; 1.955 + nsXPIDLString message; 1.956 + if (otherAtom) { 1.957 + const char16_t* params[] = { atom->GetUTF16String(), 1.958 + otherAtom->GetUTF16String() }; 1.959 + rv = nsContentUtils::FormatLocalizedString( 1.960 + nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message); 1.961 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.962 + } else if (atom) { 1.963 + const char16_t* params[] = { atom->GetUTF16String() }; 1.964 + rv = nsContentUtils::FormatLocalizedString( 1.965 + nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, params, message); 1.966 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.967 + } else { 1.968 + rv = nsContentUtils::GetLocalizedString( 1.969 + nsContentUtils::eHTMLPARSER_PROPERTIES, msgId, message); 1.970 + NS_ENSURE_SUCCESS(rv, NS_OK); 1.971 + } 1.972 + 1.973 + nsAutoString title; 1.974 + node->GetAttr(kNameSpaceID_None, nsGkAtoms::title, title); 1.975 + if (!title.IsEmpty()) { 1.976 + title.Append('\n'); 1.977 + title.Append(message); 1.978 + node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, title, true); 1.979 + } else { 1.980 + node->SetAttr(kNameSpaceID_None, nsGkAtoms::title, message, true); 1.981 + } 1.982 + return rv; 1.983 + } 1.984 + default: { 1.985 + NS_NOTREACHED("Bogus tree op"); 1.986 + } 1.987 + } 1.988 + return NS_OK; // keep compiler happy 1.989 +}