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.

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

mercurial