content/xml/document/src/nsXMLContentSink.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 "nsCOMPtr.h"
michael@0 8 #include "nsXMLContentSink.h"
michael@0 9 #include "nsIParser.h"
michael@0 10 #include "nsIDocument.h"
michael@0 11 #include "nsIDOMDocument.h"
michael@0 12 #include "nsIDOMDocumentType.h"
michael@0 13 #include "nsIContent.h"
michael@0 14 #include "nsIURI.h"
michael@0 15 #include "nsNetUtil.h"
michael@0 16 #include "nsIDocShell.h"
michael@0 17 #include "nsIStyleSheetLinkingElement.h"
michael@0 18 #include "nsIDOMComment.h"
michael@0 19 #include "nsIDOMCDATASection.h"
michael@0 20 #include "DocumentType.h"
michael@0 21 #include "nsHTMLParts.h"
michael@0 22 #include "nsCRT.h"
michael@0 23 #include "nsCSSStyleSheet.h"
michael@0 24 #include "mozilla/css/Loader.h"
michael@0 25 #include "nsGkAtoms.h"
michael@0 26 #include "nsContentUtils.h"
michael@0 27 #include "nsIScriptContext.h"
michael@0 28 #include "nsNameSpaceManager.h"
michael@0 29 #include "nsIServiceManager.h"
michael@0 30 #include "nsIScriptSecurityManager.h"
michael@0 31 #include "nsIContentViewer.h"
michael@0 32 #include "prtime.h"
michael@0 33 #include "prlog.h"
michael@0 34 #include "prmem.h"
michael@0 35 #include "nsRect.h"
michael@0 36 #include "nsIWebNavigation.h"
michael@0 37 #include "nsIScriptElement.h"
michael@0 38 #include "nsScriptLoader.h"
michael@0 39 #include "nsStyleLinkElement.h"
michael@0 40 #include "nsReadableUtils.h"
michael@0 41 #include "nsUnicharUtils.h"
michael@0 42 #include "nsICookieService.h"
michael@0 43 #include "nsIPrompt.h"
michael@0 44 #include "nsIChannel.h"
michael@0 45 #include "nsIPrincipal.h"
michael@0 46 #include "nsXMLPrettyPrinter.h"
michael@0 47 #include "nsNodeInfoManager.h"
michael@0 48 #include "nsContentCreatorFunctions.h"
michael@0 49 #include "nsIContentPolicy.h"
michael@0 50 #include "nsContentPolicyUtils.h"
michael@0 51 #include "nsError.h"
michael@0 52 #include "nsIDOMProcessingInstruction.h"
michael@0 53 #include "nsNodeUtils.h"
michael@0 54 #include "nsIScriptGlobalObject.h"
michael@0 55 #include "nsIHTMLDocument.h"
michael@0 56 #include "mozAutoDocUpdate.h"
michael@0 57 #include "nsMimeTypes.h"
michael@0 58 #include "nsHtml5SVGLoadDispatcher.h"
michael@0 59 #include "nsTextNode.h"
michael@0 60 #include "mozilla/dom/CDATASection.h"
michael@0 61 #include "mozilla/dom/Comment.h"
michael@0 62 #include "mozilla/dom/Element.h"
michael@0 63 #include "mozilla/dom/ProcessingInstruction.h"
michael@0 64
michael@0 65 using namespace mozilla::dom;
michael@0 66
michael@0 67 // XXX Open Issues:
michael@0 68 // 1) what's not allowed - We need to figure out which HTML tags
michael@0 69 // (prefixed with a HTML namespace qualifier) are explicitly not
michael@0 70 // allowed (if any).
michael@0 71 // 2) factoring code with nsHTMLContentSink - There's some amount of
michael@0 72 // common code between this and the HTML content sink. This will
michael@0 73 // increase as we support more and more HTML elements. How can code
michael@0 74 // from the code be factored?
michael@0 75
michael@0 76 nsresult
michael@0 77 NS_NewXMLContentSink(nsIXMLContentSink** aResult,
michael@0 78 nsIDocument* aDoc,
michael@0 79 nsIURI* aURI,
michael@0 80 nsISupports* aContainer,
michael@0 81 nsIChannel* aChannel)
michael@0 82 {
michael@0 83 NS_PRECONDITION(nullptr != aResult, "null ptr");
michael@0 84 if (nullptr == aResult) {
michael@0 85 return NS_ERROR_NULL_POINTER;
michael@0 86 }
michael@0 87 nsXMLContentSink* it = new nsXMLContentSink();
michael@0 88
michael@0 89 nsCOMPtr<nsIXMLContentSink> kungFuDeathGrip = it;
michael@0 90 nsresult rv = it->Init(aDoc, aURI, aContainer, aChannel);
michael@0 91 NS_ENSURE_SUCCESS(rv, rv);
michael@0 92
michael@0 93 return CallQueryInterface(it, aResult);
michael@0 94 }
michael@0 95
michael@0 96 nsXMLContentSink::nsXMLContentSink()
michael@0 97 : mConstrainSize(true),
michael@0 98 mPrettyPrintXML(true)
michael@0 99 {
michael@0 100 }
michael@0 101
michael@0 102 nsXMLContentSink::~nsXMLContentSink()
michael@0 103 {
michael@0 104 if (mText) {
michael@0 105 PR_Free(mText); // Doesn't null out, unlike PR_FREEIF
michael@0 106 }
michael@0 107 }
michael@0 108
michael@0 109 nsresult
michael@0 110 nsXMLContentSink::Init(nsIDocument* aDoc,
michael@0 111 nsIURI* aURI,
michael@0 112 nsISupports* aContainer,
michael@0 113 nsIChannel* aChannel)
michael@0 114 {
michael@0 115 nsresult rv = nsContentSink::Init(aDoc, aURI, aContainer, aChannel);
michael@0 116 NS_ENSURE_SUCCESS(rv, rv);
michael@0 117
michael@0 118 aDoc->AddObserver(this);
michael@0 119 mIsDocumentObserver = true;
michael@0 120
michael@0 121 if (!mDocShell) {
michael@0 122 mPrettyPrintXML = false;
michael@0 123 }
michael@0 124
michael@0 125 mState = eXMLContentSinkState_InProlog;
michael@0 126 mDocElement = nullptr;
michael@0 127
michael@0 128 return NS_OK;
michael@0 129 }
michael@0 130
michael@0 131 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXMLContentSink)
michael@0 132 NS_INTERFACE_MAP_ENTRY(nsIContentSink)
michael@0 133 NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink)
michael@0 134 NS_INTERFACE_MAP_ENTRY(nsIExpatSink)
michael@0 135 NS_INTERFACE_MAP_ENTRY(nsITransformObserver)
michael@0 136 NS_INTERFACE_MAP_END_INHERITING(nsContentSink)
michael@0 137
michael@0 138 NS_IMPL_ADDREF_INHERITED(nsXMLContentSink, nsContentSink)
michael@0 139 NS_IMPL_RELEASE_INHERITED(nsXMLContentSink, nsContentSink)
michael@0 140
michael@0 141 NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLContentSink)
michael@0 142
michael@0 143 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXMLContentSink,
michael@0 144 nsContentSink)
michael@0 145 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentHead)
michael@0 146 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocElement)
michael@0 147 for (uint32_t i = 0, count = tmp->mContentStack.Length(); i < count; i++) {
michael@0 148 const StackNode& node = tmp->mContentStack.ElementAt(i);
michael@0 149 cb.NoteXPCOMChild(node.mContent);
michael@0 150 }
michael@0 151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 152
michael@0 153 // nsIContentSink
michael@0 154 NS_IMETHODIMP
michael@0 155 nsXMLContentSink::WillParse(void)
michael@0 156 {
michael@0 157 return WillParseImpl();
michael@0 158 }
michael@0 159
michael@0 160 NS_IMETHODIMP
michael@0 161 nsXMLContentSink::WillBuildModel(nsDTDMode aDTDMode)
michael@0 162 {
michael@0 163 WillBuildModelImpl();
michael@0 164
michael@0 165 // Notify document that the load is beginning
michael@0 166 mDocument->BeginLoad();
michael@0 167
michael@0 168 // Check for correct load-command for maybe prettyprinting
michael@0 169 if (mPrettyPrintXML) {
michael@0 170 nsAutoCString command;
michael@0 171 GetParser()->GetCommand(command);
michael@0 172 if (!command.EqualsLiteral("view")) {
michael@0 173 mPrettyPrintXML = false;
michael@0 174 }
michael@0 175 }
michael@0 176
michael@0 177 return NS_OK;
michael@0 178 }
michael@0 179
michael@0 180 bool
michael@0 181 nsXMLContentSink::CanStillPrettyPrint()
michael@0 182 {
michael@0 183 return mPrettyPrintXML &&
michael@0 184 (!mPrettyPrintHasFactoredElements || mPrettyPrintHasSpecialRoot);
michael@0 185 }
michael@0 186
michael@0 187 nsresult
michael@0 188 nsXMLContentSink::MaybePrettyPrint()
michael@0 189 {
michael@0 190 if (!CanStillPrettyPrint()) {
michael@0 191 mPrettyPrintXML = false;
michael@0 192
michael@0 193 return NS_OK;
michael@0 194 }
michael@0 195
michael@0 196 // stop observing in order to avoid crashing when replacing content
michael@0 197 mDocument->RemoveObserver(this);
michael@0 198 mIsDocumentObserver = false;
michael@0 199
michael@0 200 // Reenable the CSSLoader so that the prettyprinting stylesheets can load
michael@0 201 if (mCSSLoader) {
michael@0 202 mCSSLoader->SetEnabled(true);
michael@0 203 }
michael@0 204
michael@0 205 nsRefPtr<nsXMLPrettyPrinter> printer;
michael@0 206 nsresult rv = NS_NewXMLPrettyPrinter(getter_AddRefs(printer));
michael@0 207 NS_ENSURE_SUCCESS(rv, rv);
michael@0 208
michael@0 209 bool isPrettyPrinting;
michael@0 210 rv = printer->PrettyPrint(mDocument, &isPrettyPrinting);
michael@0 211 NS_ENSURE_SUCCESS(rv, rv);
michael@0 212
michael@0 213 mPrettyPrinting = isPrettyPrinting;
michael@0 214 return NS_OK;
michael@0 215 }
michael@0 216
michael@0 217 static void
michael@0 218 CheckXSLTParamPI(nsIDOMProcessingInstruction* aPi,
michael@0 219 nsIDocumentTransformer* aProcessor,
michael@0 220 nsIDocument* aDocument)
michael@0 221 {
michael@0 222 nsAutoString target, data;
michael@0 223 aPi->GetTarget(target);
michael@0 224
michael@0 225 // Check for namespace declarations
michael@0 226 if (target.EqualsLiteral("xslt-param-namespace")) {
michael@0 227 aPi->GetData(data);
michael@0 228 nsAutoString prefix, namespaceAttr;
michael@0 229 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::prefix,
michael@0 230 prefix);
michael@0 231 if (!prefix.IsEmpty() &&
michael@0 232 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
michael@0 233 namespaceAttr)) {
michael@0 234 aProcessor->AddXSLTParamNamespace(prefix, namespaceAttr);
michael@0 235 }
michael@0 236 }
michael@0 237
michael@0 238 // Check for actual parameters
michael@0 239 else if (target.EqualsLiteral("xslt-param")) {
michael@0 240 aPi->GetData(data);
michael@0 241 nsAutoString name, namespaceAttr, select, value;
michael@0 242 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::name,
michael@0 243 name);
michael@0 244 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::_namespace,
michael@0 245 namespaceAttr);
michael@0 246 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::select, select)) {
michael@0 247 select.SetIsVoid(true);
michael@0 248 }
michael@0 249 if (!nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::value, value)) {
michael@0 250 value.SetIsVoid(true);
michael@0 251 }
michael@0 252 if (!name.IsEmpty()) {
michael@0 253 nsCOMPtr<nsIDOMNode> doc = do_QueryInterface(aDocument);
michael@0 254 aProcessor->AddXSLTParam(name, namespaceAttr, select, value, doc);
michael@0 255 }
michael@0 256 }
michael@0 257 }
michael@0 258
michael@0 259 NS_IMETHODIMP
michael@0 260 nsXMLContentSink::DidBuildModel(bool aTerminated)
michael@0 261 {
michael@0 262 if (!mParser) {
michael@0 263 // If mParser is null, this parse has already been terminated and must
michael@0 264 // not been terminated again. However, nsDocument may still think that
michael@0 265 // the parse has not been terminated and call back into here in the case
michael@0 266 // where the XML parser has finished but the XSLT transform associated
michael@0 267 // with the document has not.
michael@0 268 return NS_OK;
michael@0 269 }
michael@0 270
michael@0 271 DidBuildModelImpl(aTerminated);
michael@0 272
michael@0 273 if (mXSLTProcessor) {
michael@0 274 // stop observing in order to avoid crashing when replacing content
michael@0 275 mDocument->RemoveObserver(this);
michael@0 276 mIsDocumentObserver = false;
michael@0 277
michael@0 278 // Check for xslt-param and xslt-param-namespace PIs
michael@0 279 for (nsIContent* child = mDocument->GetFirstChild();
michael@0 280 child;
michael@0 281 child = child->GetNextSibling()) {
michael@0 282 if (child->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
michael@0 283 nsCOMPtr<nsIDOMProcessingInstruction> pi = do_QueryInterface(child);
michael@0 284 CheckXSLTParamPI(pi, mXSLTProcessor, mDocument);
michael@0 285 }
michael@0 286 else if (child->IsElement()) {
michael@0 287 // Only honor PIs in the prolog
michael@0 288 break;
michael@0 289 }
michael@0 290 }
michael@0 291
michael@0 292 nsCOMPtr<nsIDOMDocument> currentDOMDoc(do_QueryInterface(mDocument));
michael@0 293 mXSLTProcessor->SetSourceContentModel(currentDOMDoc);
michael@0 294 // Since the processor now holds a reference to us we drop our reference
michael@0 295 // to it to avoid owning cycles
michael@0 296 mXSLTProcessor = nullptr;
michael@0 297 }
michael@0 298 else {
michael@0 299 // Kick off layout for non-XSLT transformed documents.
michael@0 300
michael@0 301 // Check if we want to prettyprint
michael@0 302 MaybePrettyPrint();
michael@0 303
michael@0 304 bool startLayout = true;
michael@0 305
michael@0 306 if (mPrettyPrinting) {
michael@0 307 NS_ASSERTION(!mPendingSheetCount, "Shouldn't have pending sheets here!");
michael@0 308
michael@0 309 // We're pretty-printing now. See whether we should wait up on
michael@0 310 // stylesheet loads
michael@0 311 if (mDocument->CSSLoader()->HasPendingLoads() &&
michael@0 312 NS_SUCCEEDED(mDocument->CSSLoader()->AddObserver(this))) {
michael@0 313 // wait for those sheets to load
michael@0 314 startLayout = false;
michael@0 315 }
michael@0 316 }
michael@0 317
michael@0 318 if (startLayout) {
michael@0 319 StartLayout(false);
michael@0 320
michael@0 321 ScrollToRef();
michael@0 322 }
michael@0 323
michael@0 324 mDocument->RemoveObserver(this);
michael@0 325 mIsDocumentObserver = false;
michael@0 326
michael@0 327 mDocument->EndLoad();
michael@0 328 }
michael@0 329
michael@0 330 DropParserAndPerfHint();
michael@0 331
michael@0 332 return NS_OK;
michael@0 333 }
michael@0 334
michael@0 335 NS_IMETHODIMP
michael@0 336 nsXMLContentSink::OnDocumentCreated(nsIDocument* aResultDocument)
michael@0 337 {
michael@0 338 NS_ENSURE_ARG(aResultDocument);
michael@0 339
michael@0 340 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aResultDocument);
michael@0 341 if (htmlDoc) {
michael@0 342 htmlDoc->SetDocWriteDisabled(true);
michael@0 343 }
michael@0 344
michael@0 345 nsCOMPtr<nsIContentViewer> contentViewer;
michael@0 346 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
michael@0 347 if (contentViewer) {
michael@0 348 return contentViewer->SetDocumentInternal(aResultDocument, true);
michael@0 349 }
michael@0 350 return NS_OK;
michael@0 351 }
michael@0 352
michael@0 353 NS_IMETHODIMP
michael@0 354 nsXMLContentSink::OnTransformDone(nsresult aResult,
michael@0 355 nsIDocument* aResultDocument)
michael@0 356 {
michael@0 357 NS_ASSERTION(NS_FAILED(aResult) || aResultDocument,
michael@0 358 "Don't notify about transform success without a document.");
michael@0 359
michael@0 360 nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aResultDocument);
michael@0 361
michael@0 362 nsCOMPtr<nsIContentViewer> contentViewer;
michael@0 363 mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
michael@0 364
michael@0 365 if (NS_FAILED(aResult) && contentViewer) {
michael@0 366 // Transform failed.
michael@0 367 if (domDoc) {
michael@0 368 aResultDocument->SetMayStartLayout(false);
michael@0 369 // We have an error document.
michael@0 370 contentViewer->SetDOMDocument(domDoc);
michael@0 371 }
michael@0 372 else {
michael@0 373 // We don't have an error document, display the
michael@0 374 // untransformed source document.
michael@0 375 nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(mDocument);
michael@0 376 contentViewer->SetDOMDocument(document);
michael@0 377 }
michael@0 378 }
michael@0 379
michael@0 380 nsCOMPtr<nsIDocument> originalDocument = mDocument;
michael@0 381 if (NS_SUCCEEDED(aResult) || aResultDocument) {
michael@0 382 // Transform succeeded or it failed and we have an error
michael@0 383 // document to display.
michael@0 384 mDocument = aResultDocument;
michael@0 385 nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mDocument);
michael@0 386 if (htmlDoc) {
michael@0 387 htmlDoc->SetDocWriteDisabled(false);
michael@0 388 }
michael@0 389 }
michael@0 390
michael@0 391 // Notify document observers that all the content has been stuck
michael@0 392 // into the document.
michael@0 393 // XXX do we need to notify for things like PIs? Or just the
michael@0 394 // documentElement?
michael@0 395 nsIContent *rootElement = mDocument->GetRootElement();
michael@0 396 if (rootElement) {
michael@0 397 NS_ASSERTION(mDocument->IndexOf(rootElement) != -1,
michael@0 398 "rootElement not in doc?");
michael@0 399 mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
michael@0 400 nsNodeUtils::ContentInserted(mDocument, rootElement,
michael@0 401 mDocument->IndexOf(rootElement));
michael@0 402 mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
michael@0 403 }
michael@0 404
michael@0 405 // Start the layout process
michael@0 406 StartLayout(false);
michael@0 407
michael@0 408 ScrollToRef();
michael@0 409
michael@0 410 originalDocument->EndLoad();
michael@0 411
michael@0 412 return NS_OK;
michael@0 413 }
michael@0 414
michael@0 415 NS_IMETHODIMP
michael@0 416 nsXMLContentSink::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
michael@0 417 bool aWasAlternate,
michael@0 418 nsresult aStatus)
michael@0 419 {
michael@0 420 if (!mPrettyPrinting) {
michael@0 421 return nsContentSink::StyleSheetLoaded(aSheet, aWasAlternate, aStatus);
michael@0 422 }
michael@0 423
michael@0 424 if (!mDocument->CSSLoader()->HasPendingLoads()) {
michael@0 425 mDocument->CSSLoader()->RemoveObserver(this);
michael@0 426 StartLayout(false);
michael@0 427 ScrollToRef();
michael@0 428 }
michael@0 429
michael@0 430 return NS_OK;
michael@0 431 }
michael@0 432
michael@0 433 NS_IMETHODIMP
michael@0 434 nsXMLContentSink::WillInterrupt(void)
michael@0 435 {
michael@0 436 return WillInterruptImpl();
michael@0 437 }
michael@0 438
michael@0 439 NS_IMETHODIMP
michael@0 440 nsXMLContentSink::WillResume(void)
michael@0 441 {
michael@0 442 return WillResumeImpl();
michael@0 443 }
michael@0 444
michael@0 445 NS_IMETHODIMP
michael@0 446 nsXMLContentSink::SetParser(nsParserBase* aParser)
michael@0 447 {
michael@0 448 NS_PRECONDITION(aParser, "Should have a parser here!");
michael@0 449 mParser = aParser;
michael@0 450 return NS_OK;
michael@0 451 }
michael@0 452
michael@0 453 nsresult
michael@0 454 nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
michael@0 455 nsINodeInfo* aNodeInfo, uint32_t aLineNumber,
michael@0 456 nsIContent** aResult, bool* aAppendContent,
michael@0 457 FromParser aFromParser)
michael@0 458 {
michael@0 459 NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
michael@0 460
michael@0 461 *aResult = nullptr;
michael@0 462 *aAppendContent = true;
michael@0 463 nsresult rv = NS_OK;
michael@0 464
michael@0 465 nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
michael@0 466 nsCOMPtr<Element> content;
michael@0 467 rv = NS_NewElement(getter_AddRefs(content), ni.forget(), aFromParser);
michael@0 468 NS_ENSURE_SUCCESS(rv, rv);
michael@0 469
michael@0 470 if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
michael@0 471 || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
michael@0 472 ) {
michael@0 473 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
michael@0 474 sele->SetScriptLineNumber(aLineNumber);
michael@0 475 sele->SetCreatorParser(GetParser());
michael@0 476 mConstrainSize = false;
michael@0 477 }
michael@0 478
michael@0 479 // XHTML needs some special attention
michael@0 480 if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
michael@0 481 mPrettyPrintHasFactoredElements = true;
michael@0 482 }
michael@0 483 else {
michael@0 484 // If we care, find out if we just used a special factory.
michael@0 485 if (!mPrettyPrintHasFactoredElements && !mPrettyPrintHasSpecialRoot &&
michael@0 486 mPrettyPrintXML) {
michael@0 487 mPrettyPrintHasFactoredElements =
michael@0 488 nsContentUtils::NameSpaceManager()->
michael@0 489 HasElementCreator(aNodeInfo->NamespaceID());
michael@0 490 }
michael@0 491
michael@0 492 if (!aNodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
michael@0 493 content.forget(aResult);
michael@0 494
michael@0 495 return NS_OK;
michael@0 496 }
michael@0 497 }
michael@0 498
michael@0 499 if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
michael@0 500 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
michael@0 501 aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
michael@0 502 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
michael@0 503 if (ssle) {
michael@0 504 ssle->InitStyleLinkElement(false);
michael@0 505 if (aFromParser) {
michael@0 506 ssle->SetEnableUpdates(false);
michael@0 507 }
michael@0 508 if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
michael@0 509 ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
michael@0 510 }
michael@0 511 }
michael@0 512 }
michael@0 513
michael@0 514 content.forget(aResult);
michael@0 515
michael@0 516 return NS_OK;
michael@0 517 }
michael@0 518
michael@0 519
michael@0 520 nsresult
michael@0 521 nsXMLContentSink::CloseElement(nsIContent* aContent)
michael@0 522 {
michael@0 523 NS_ASSERTION(aContent, "missing element to close");
michael@0 524
michael@0 525 nsINodeInfo *nodeInfo = aContent->NodeInfo();
michael@0 526
michael@0 527 // Some HTML nodes need DoneAddingChildren() called to initialize
michael@0 528 // properly (eg form state restoration).
michael@0 529 if ((nodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
michael@0 530 (nodeInfo->NameAtom() == nsGkAtoms::select ||
michael@0 531 nodeInfo->NameAtom() == nsGkAtoms::textarea ||
michael@0 532 nodeInfo->NameAtom() == nsGkAtoms::video ||
michael@0 533 nodeInfo->NameAtom() == nsGkAtoms::audio ||
michael@0 534 nodeInfo->NameAtom() == nsGkAtoms::object ||
michael@0 535 nodeInfo->NameAtom() == nsGkAtoms::applet))
michael@0 536 || nodeInfo->NameAtom() == nsGkAtoms::title
michael@0 537 ) {
michael@0 538 aContent->DoneAddingChildren(HaveNotifiedForCurrentContent());
michael@0 539 }
michael@0 540
michael@0 541 if (IsMonolithicContainer(nodeInfo)) {
michael@0 542 mInMonolithicContainer--;
michael@0 543 }
michael@0 544
michael@0 545 if (!nodeInfo->NamespaceEquals(kNameSpaceID_XHTML) &&
michael@0 546 !nodeInfo->NamespaceEquals(kNameSpaceID_SVG)) {
michael@0 547 return NS_OK;
michael@0 548 }
michael@0 549
michael@0 550 if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
michael@0 551 || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
michael@0 552 ) {
michael@0 553 mConstrainSize = true;
michael@0 554 nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aContent);
michael@0 555
michael@0 556 if (mPreventScriptExecution) {
michael@0 557 sele->PreventExecution();
michael@0 558 return NS_OK;
michael@0 559 }
michael@0 560
michael@0 561 // Always check the clock in nsContentSink right after a script
michael@0 562 StopDeflecting();
michael@0 563
michael@0 564 // Now tell the script that it's ready to go. This may execute the script
michael@0 565 // or return true, or neither if the script doesn't need executing.
michael@0 566 bool block = sele->AttemptToExecute();
michael@0 567
michael@0 568 // If the parser got blocked, make sure to return the appropriate rv.
michael@0 569 // I'm not sure if this is actually needed or not.
michael@0 570 if (mParser && !mParser->IsParserEnabled()) {
michael@0 571 // XXX The HTML sink doesn't call BlockParser here, why do we?
michael@0 572 GetParser()->BlockParser();
michael@0 573 block = true;
michael@0 574 }
michael@0 575
michael@0 576 return block ? NS_ERROR_HTMLPARSER_BLOCK : NS_OK;
michael@0 577 }
michael@0 578
michael@0 579 nsresult rv = NS_OK;
michael@0 580 if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
michael@0 581 // Need to check here to make sure this meta tag does not set
michael@0 582 // mPrettyPrintXML to false when we have a special root!
michael@0 583 (!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
michael@0 584 rv = ProcessMETATag(aContent);
michael@0 585 }
michael@0 586 else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
michael@0 587 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
michael@0 588 nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
michael@0 589 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
michael@0 590 if (ssle) {
michael@0 591 ssle->SetEnableUpdates(true);
michael@0 592 bool willNotify;
michael@0 593 bool isAlternate;
michael@0 594 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
michael@0 595 &willNotify,
michael@0 596 &isAlternate);
michael@0 597 if (NS_SUCCEEDED(rv) && willNotify && !isAlternate && !mRunsToCompletion) {
michael@0 598 ++mPendingSheetCount;
michael@0 599 mScriptLoader->AddExecuteBlocker();
michael@0 600 }
michael@0 601 }
michael@0 602 // Look for <link rel="dns-prefetch" href="hostname">
michael@0 603 // and look for <link rel="next" href="hostname"> like in HTML sink
michael@0 604 if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
michael@0 605 nsAutoString relVal;
michael@0 606 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
michael@0 607 if (!relVal.IsEmpty()) {
michael@0 608 uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(relVal);
michael@0 609 bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
michael@0 610 if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
michael@0 611 nsAutoString hrefVal;
michael@0 612 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
michael@0 613 if (!hrefVal.IsEmpty()) {
michael@0 614 PrefetchHref(hrefVal, aContent, hasPrefetch);
michael@0 615 }
michael@0 616 }
michael@0 617 if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
michael@0 618 nsAutoString hrefVal;
michael@0 619 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
michael@0 620 if (!hrefVal.IsEmpty()) {
michael@0 621 PrefetchDNS(hrefVal);
michael@0 622 }
michael@0 623 }
michael@0 624 }
michael@0 625 }
michael@0 626 }
michael@0 627
michael@0 628 return rv;
michael@0 629 }
michael@0 630
michael@0 631 nsresult
michael@0 632 nsXMLContentSink::AddContentAsLeaf(nsIContent *aContent)
michael@0 633 {
michael@0 634 nsresult result = NS_OK;
michael@0 635
michael@0 636 if ((eXMLContentSinkState_InProlog == mState) ||
michael@0 637 (eXMLContentSinkState_InEpilog == mState)) {
michael@0 638 NS_ASSERTION(mDocument, "Fragments have no prolog or epilog");
michael@0 639 mDocument->AppendChildTo(aContent, false);
michael@0 640 }
michael@0 641 else {
michael@0 642 nsCOMPtr<nsIContent> parent = GetCurrentContent();
michael@0 643
michael@0 644 if (parent) {
michael@0 645 result = parent->AppendChildTo(aContent, false);
michael@0 646 }
michael@0 647 }
michael@0 648 return result;
michael@0 649 }
michael@0 650
michael@0 651 // Create an XML parser and an XSL content sink and start parsing
michael@0 652 // the XSL stylesheet located at the given URI.
michael@0 653 nsresult
michael@0 654 nsXMLContentSink::LoadXSLStyleSheet(nsIURI* aUrl)
michael@0 655 {
michael@0 656 nsCOMPtr<nsIDocumentTransformer> processor =
michael@0 657 do_CreateInstance("@mozilla.org/document-transformer;1?type=xslt");
michael@0 658 if (!processor) {
michael@0 659 // No XSLT processor available, continue normal document loading
michael@0 660 return NS_OK;
michael@0 661 }
michael@0 662
michael@0 663 processor->Init(mDocument->NodePrincipal());
michael@0 664 processor->SetTransformObserver(this);
michael@0 665
michael@0 666 nsCOMPtr<nsILoadGroup> loadGroup = mDocument->GetDocumentLoadGroup();
michael@0 667 if (!loadGroup) {
michael@0 668 return NS_ERROR_FAILURE;
michael@0 669 }
michael@0 670
michael@0 671 if (NS_SUCCEEDED(processor->LoadStyleSheet(aUrl, loadGroup))) {
michael@0 672 mXSLTProcessor.swap(processor);
michael@0 673 }
michael@0 674
michael@0 675 // Intentionally ignore errors here, we should continue loading the
michael@0 676 // XML document whether we're able to load the XSLT stylesheet or
michael@0 677 // not.
michael@0 678
michael@0 679 return NS_OK;
michael@0 680 }
michael@0 681
michael@0 682 nsresult
michael@0 683 nsXMLContentSink::ProcessStyleLink(nsIContent* aElement,
michael@0 684 const nsSubstring& aHref,
michael@0 685 bool aAlternate,
michael@0 686 const nsSubstring& aTitle,
michael@0 687 const nsSubstring& aType,
michael@0 688 const nsSubstring& aMedia)
michael@0 689 {
michael@0 690 nsresult rv = NS_OK;
michael@0 691 mPrettyPrintXML = false;
michael@0 692
michael@0 693 nsAutoCString cmd;
michael@0 694 if (mParser)
michael@0 695 GetParser()->GetCommand(cmd);
michael@0 696 if (cmd.EqualsASCII(kLoadAsData))
michael@0 697 return NS_OK; // Do not load stylesheets when loading as data
michael@0 698
michael@0 699 NS_ConvertUTF16toUTF8 type(aType);
michael@0 700 if (type.EqualsIgnoreCase(TEXT_XSL) ||
michael@0 701 type.EqualsIgnoreCase(APPLICATION_XSLT_XML) ||
michael@0 702 type.EqualsIgnoreCase(TEXT_XML) ||
michael@0 703 type.EqualsIgnoreCase(APPLICATION_XML)) {
michael@0 704 if (aAlternate) {
michael@0 705 // don't load alternate XSLT
michael@0 706 return NS_OK;
michael@0 707 }
michael@0 708 // LoadXSLStyleSheet needs a mDocShell.
michael@0 709 if (!mDocShell)
michael@0 710 return NS_OK;
michael@0 711
michael@0 712 nsCOMPtr<nsIURI> url;
michael@0 713 rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
michael@0 714 mDocument->GetDocBaseURI());
michael@0 715 NS_ENSURE_SUCCESS(rv, rv);
michael@0 716
michael@0 717 // Do security check
michael@0 718 nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager();
michael@0 719 rv = secMan->
michael@0 720 CheckLoadURIWithPrincipal(mDocument->NodePrincipal(), url,
michael@0 721 nsIScriptSecurityManager::ALLOW_CHROME);
michael@0 722 NS_ENSURE_SUCCESS(rv, NS_OK);
michael@0 723
michael@0 724 // Do content policy check
michael@0 725 int16_t decision = nsIContentPolicy::ACCEPT;
michael@0 726 rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_XSLT,
michael@0 727 url,
michael@0 728 mDocument->NodePrincipal(),
michael@0 729 aElement,
michael@0 730 type,
michael@0 731 nullptr,
michael@0 732 &decision,
michael@0 733 nsContentUtils::GetContentPolicy(),
michael@0 734 nsContentUtils::GetSecurityManager());
michael@0 735
michael@0 736 NS_ENSURE_SUCCESS(rv, rv);
michael@0 737
michael@0 738 if (NS_CP_REJECTED(decision)) {
michael@0 739 return NS_OK;
michael@0 740 }
michael@0 741
michael@0 742 return LoadXSLStyleSheet(url);
michael@0 743 }
michael@0 744
michael@0 745 // Let nsContentSink deal with css.
michael@0 746 rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
michael@0 747 aTitle, aType, aMedia);
michael@0 748
michael@0 749 // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
michael@0 750 // pending sheets.
michael@0 751
michael@0 752 return rv;
michael@0 753 }
michael@0 754
michael@0 755 NS_IMETHODIMP
michael@0 756 nsXMLContentSink::SetDocumentCharset(nsACString& aCharset)
michael@0 757 {
michael@0 758 if (mDocument) {
michael@0 759 mDocument->SetDocumentCharacterSet(aCharset);
michael@0 760 }
michael@0 761
michael@0 762 return NS_OK;
michael@0 763 }
michael@0 764
michael@0 765 nsISupports *
michael@0 766 nsXMLContentSink::GetTarget()
michael@0 767 {
michael@0 768 return mDocument;
michael@0 769 }
michael@0 770
michael@0 771 bool
michael@0 772 nsXMLContentSink::IsScriptExecuting()
michael@0 773 {
michael@0 774 return IsScriptExecutingImpl();
michael@0 775 }
michael@0 776
michael@0 777 nsresult
michael@0 778 nsXMLContentSink::FlushText(bool aReleaseTextNode)
michael@0 779 {
michael@0 780 nsresult rv = NS_OK;
michael@0 781
michael@0 782 if (mTextLength != 0) {
michael@0 783 if (mLastTextNode) {
michael@0 784 if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) {
michael@0 785 mLastTextNodeSize = 0;
michael@0 786 mLastTextNode = nullptr;
michael@0 787 FlushText(aReleaseTextNode);
michael@0 788 } else {
michael@0 789 bool notify = HaveNotifiedForCurrentContent();
michael@0 790 // We could probably always increase mInNotification here since
michael@0 791 // if AppendText doesn't notify it shouldn't trigger evil code.
michael@0 792 // But just in case it does, we don't want to mask any notifications.
michael@0 793 if (notify) {
michael@0 794 ++mInNotification;
michael@0 795 }
michael@0 796 rv = mLastTextNode->AppendText(mText, mTextLength, notify);
michael@0 797 if (notify) {
michael@0 798 --mInNotification;
michael@0 799 }
michael@0 800
michael@0 801 mLastTextNodeSize += mTextLength;
michael@0 802 mTextLength = 0;
michael@0 803 }
michael@0 804 } else {
michael@0 805 nsRefPtr<nsTextNode> textContent = new nsTextNode(mNodeInfoManager);
michael@0 806
michael@0 807 mLastTextNode = textContent;
michael@0 808
michael@0 809 // Set the text in the text node
michael@0 810 textContent->SetText(mText, mTextLength, false);
michael@0 811 mLastTextNodeSize += mTextLength;
michael@0 812 mTextLength = 0;
michael@0 813
michael@0 814 // Add text to its parent
michael@0 815 rv = AddContentAsLeaf(textContent);
michael@0 816 }
michael@0 817 }
michael@0 818
michael@0 819 if (aReleaseTextNode) {
michael@0 820 mLastTextNodeSize = 0;
michael@0 821 mLastTextNode = nullptr;
michael@0 822 }
michael@0 823
michael@0 824 return rv;
michael@0 825 }
michael@0 826
michael@0 827 nsIContent*
michael@0 828 nsXMLContentSink::GetCurrentContent()
michael@0 829 {
michael@0 830 if (mContentStack.Length() == 0) {
michael@0 831 return nullptr;
michael@0 832 }
michael@0 833 return GetCurrentStackNode()->mContent;
michael@0 834 }
michael@0 835
michael@0 836 StackNode*
michael@0 837 nsXMLContentSink::GetCurrentStackNode()
michael@0 838 {
michael@0 839 int32_t count = mContentStack.Length();
michael@0 840 return count != 0 ? &mContentStack[count-1] : nullptr;
michael@0 841 }
michael@0 842
michael@0 843
michael@0 844 nsresult
michael@0 845 nsXMLContentSink::PushContent(nsIContent *aContent)
michael@0 846 {
michael@0 847 NS_PRECONDITION(aContent, "Null content being pushed!");
michael@0 848 StackNode *sn = mContentStack.AppendElement();
michael@0 849 NS_ENSURE_TRUE(sn, NS_ERROR_OUT_OF_MEMORY);
michael@0 850
michael@0 851 sn->mContent = aContent;
michael@0 852 sn->mNumFlushed = 0;
michael@0 853 return NS_OK;
michael@0 854 }
michael@0 855
michael@0 856 void
michael@0 857 nsXMLContentSink::PopContent()
michael@0 858 {
michael@0 859 int32_t count = mContentStack.Length();
michael@0 860
michael@0 861 if (count == 0) {
michael@0 862 NS_WARNING("Popping empty stack");
michael@0 863 return;
michael@0 864 }
michael@0 865
michael@0 866 mContentStack.RemoveElementAt(count - 1);
michael@0 867 }
michael@0 868
michael@0 869 bool
michael@0 870 nsXMLContentSink::HaveNotifiedForCurrentContent() const
michael@0 871 {
michael@0 872 uint32_t stackLength = mContentStack.Length();
michael@0 873 if (stackLength) {
michael@0 874 const StackNode& stackNode = mContentStack[stackLength - 1];
michael@0 875 nsIContent* parent = stackNode.mContent;
michael@0 876 return stackNode.mNumFlushed == parent->GetChildCount();
michael@0 877 }
michael@0 878 return true;
michael@0 879 }
michael@0 880
michael@0 881 void
michael@0 882 nsXMLContentSink::MaybeStartLayout(bool aIgnorePendingSheets)
michael@0 883 {
michael@0 884 // XXXbz if aIgnorePendingSheets is true, what should we do when
michael@0 885 // mXSLTProcessor or CanStillPrettyPrint()?
michael@0 886 if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
michael@0 887 return;
michael@0 888 }
michael@0 889 StartLayout(aIgnorePendingSheets);
michael@0 890 }
michael@0 891
michael@0 892 ////////////////////////////////////////////////////////////////////////
michael@0 893
michael@0 894 bool
michael@0 895 nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
michael@0 896 nsIAtom* aTagName,
michael@0 897 nsIContent *aContent)
michael@0 898 {
michael@0 899 if (mDocElement)
michael@0 900 return false;
michael@0 901
michael@0 902 // check for root elements that needs special handling for
michael@0 903 // prettyprinting
michael@0 904 if ((aNameSpaceID == kNameSpaceID_XBL &&
michael@0 905 aTagName == nsGkAtoms::bindings) ||
michael@0 906 (aNameSpaceID == kNameSpaceID_XSLT &&
michael@0 907 (aTagName == nsGkAtoms::stylesheet ||
michael@0 908 aTagName == nsGkAtoms::transform))) {
michael@0 909 mPrettyPrintHasSpecialRoot = true;
michael@0 910 if (mPrettyPrintXML) {
michael@0 911 // In this case, disable script execution, stylesheet
michael@0 912 // loading, and auto XLinks since we plan to prettyprint.
michael@0 913 mDocument->ScriptLoader()->SetEnabled(false);
michael@0 914 if (mCSSLoader) {
michael@0 915 mCSSLoader->SetEnabled(false);
michael@0 916 }
michael@0 917 }
michael@0 918 }
michael@0 919
michael@0 920 mDocElement = aContent;
michael@0 921 nsresult rv = mDocument->AppendChildTo(mDocElement, NotifyForDocElement());
michael@0 922 if (NS_FAILED(rv)) {
michael@0 923 // If we return false here, the caller will bail out because it won't
michael@0 924 // find a parent content node to append to, which is fine.
michael@0 925 return false;
michael@0 926 }
michael@0 927
michael@0 928 if (aTagName == nsGkAtoms::html &&
michael@0 929 aNameSpaceID == kNameSpaceID_XHTML) {
michael@0 930 ProcessOfflineManifest(aContent);
michael@0 931 }
michael@0 932
michael@0 933 return true;
michael@0 934 }
michael@0 935
michael@0 936 NS_IMETHODIMP
michael@0 937 nsXMLContentSink::HandleStartElement(const char16_t *aName,
michael@0 938 const char16_t **aAtts,
michael@0 939 uint32_t aAttsCount,
michael@0 940 int32_t aIndex,
michael@0 941 uint32_t aLineNumber)
michael@0 942 {
michael@0 943 return HandleStartElement(aName, aAtts, aAttsCount, aIndex, aLineNumber,
michael@0 944 true);
michael@0 945 }
michael@0 946
michael@0 947 nsresult
michael@0 948 nsXMLContentSink::HandleStartElement(const char16_t *aName,
michael@0 949 const char16_t **aAtts,
michael@0 950 uint32_t aAttsCount,
michael@0 951 int32_t aIndex,
michael@0 952 uint32_t aLineNumber,
michael@0 953 bool aInterruptable)
michael@0 954 {
michael@0 955 NS_PRECONDITION(aIndex >= -1, "Bogus aIndex");
michael@0 956 NS_PRECONDITION(aAttsCount % 2 == 0, "incorrect aAttsCount");
michael@0 957 // Adjust aAttsCount so it's the actual number of attributes
michael@0 958 aAttsCount /= 2;
michael@0 959
michael@0 960 nsresult result = NS_OK;
michael@0 961 bool appendContent = true;
michael@0 962 nsCOMPtr<nsIContent> content;
michael@0 963
michael@0 964 // XXX Hopefully the parser will flag this before we get
michael@0 965 // here. If we're in the epilog, there should be no
michael@0 966 // new elements
michael@0 967 PR_ASSERT(eXMLContentSinkState_InEpilog != mState);
michael@0 968
michael@0 969 FlushText();
michael@0 970 DidAddContent();
michael@0 971
michael@0 972 mState = eXMLContentSinkState_InDocumentElement;
michael@0 973
michael@0 974 int32_t nameSpaceID;
michael@0 975 nsCOMPtr<nsIAtom> prefix, localName;
michael@0 976 nsContentUtils::SplitExpatName(aName, getter_AddRefs(prefix),
michael@0 977 getter_AddRefs(localName), &nameSpaceID);
michael@0 978
michael@0 979 if (!OnOpenContainer(aAtts, aAttsCount, nameSpaceID, localName, aLineNumber)) {
michael@0 980 return NS_OK;
michael@0 981 }
michael@0 982
michael@0 983 nsCOMPtr<nsINodeInfo> nodeInfo;
michael@0 984 nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
michael@0 985 nsIDOMNode::ELEMENT_NODE);
michael@0 986
michael@0 987 result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
michael@0 988 getter_AddRefs(content), &appendContent,
michael@0 989 FROM_PARSER_NETWORK);
michael@0 990 NS_ENSURE_SUCCESS(result, result);
michael@0 991
michael@0 992 // Have to do this before we push the new content on the stack... and have to
michael@0 993 // do that before we set attributes, call BindToTree, etc. Ideally we'd push
michael@0 994 // on the stack inside CreateElement (which is effectively what the HTML sink
michael@0 995 // does), but that's hard with all the subclass overrides going on.
michael@0 996 nsCOMPtr<nsIContent> parent = GetCurrentContent();
michael@0 997
michael@0 998 result = PushContent(content);
michael@0 999 NS_ENSURE_SUCCESS(result, result);
michael@0 1000
michael@0 1001 // Set the ID attribute atom on the node info object for this node
michael@0 1002 // This must occur before the attributes are added so the name
michael@0 1003 // of the id attribute is known.
michael@0 1004 if (aIndex != -1 && NS_SUCCEEDED(result)) {
michael@0 1005 nsCOMPtr<nsIAtom> IDAttr = do_GetAtom(aAtts[aIndex]);
michael@0 1006
michael@0 1007 if (IDAttr) {
michael@0 1008 nodeInfo->SetIDAttributeAtom(IDAttr);
michael@0 1009 }
michael@0 1010 }
michael@0 1011
michael@0 1012 // Set the attributes on the new content element
michael@0 1013 result = AddAttributes(aAtts, content);
michael@0 1014
michael@0 1015 if (NS_OK == result) {
michael@0 1016 // Store the element
michael@0 1017 if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
michael@0 1018 NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
michael@0 1019
michael@0 1020 parent->AppendChildTo(content, false);
michael@0 1021 }
michael@0 1022 }
michael@0 1023
michael@0 1024 // Some HTML nodes need DoneCreatingElement() called to initialize
michael@0 1025 // properly (eg form state restoration).
michael@0 1026 if (nodeInfo->NamespaceID() == kNameSpaceID_XHTML) {
michael@0 1027 if (nodeInfo->NameAtom() == nsGkAtoms::input ||
michael@0 1028 nodeInfo->NameAtom() == nsGkAtoms::button ||
michael@0 1029 nodeInfo->NameAtom() == nsGkAtoms::menuitem ||
michael@0 1030 nodeInfo->NameAtom() == nsGkAtoms::audio ||
michael@0 1031 nodeInfo->NameAtom() == nsGkAtoms::video) {
michael@0 1032 content->DoneCreatingElement();
michael@0 1033 } else if (nodeInfo->NameAtom() == nsGkAtoms::head && !mCurrentHead) {
michael@0 1034 mCurrentHead = content;
michael@0 1035 }
michael@0 1036 }
michael@0 1037
michael@0 1038 if (IsMonolithicContainer(nodeInfo)) {
michael@0 1039 mInMonolithicContainer++;
michael@0 1040 }
michael@0 1041
michael@0 1042 if (content != mDocElement && !mCurrentHead) {
michael@0 1043 // This isn't the root and we're not inside an XHTML <head>.
michael@0 1044 // Might need to start layout
michael@0 1045 MaybeStartLayout(false);
michael@0 1046 }
michael@0 1047
michael@0 1048 if (content == mDocElement) {
michael@0 1049 NotifyDocElementCreated(mDocument);
michael@0 1050 }
michael@0 1051
michael@0 1052 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
michael@0 1053 result;
michael@0 1054 }
michael@0 1055
michael@0 1056 NS_IMETHODIMP
michael@0 1057 nsXMLContentSink::HandleEndElement(const char16_t *aName)
michael@0 1058 {
michael@0 1059 return HandleEndElement(aName, true);
michael@0 1060 }
michael@0 1061
michael@0 1062 nsresult
michael@0 1063 nsXMLContentSink::HandleEndElement(const char16_t *aName,
michael@0 1064 bool aInterruptable)
michael@0 1065 {
michael@0 1066 nsresult result = NS_OK;
michael@0 1067
michael@0 1068 // XXX Hopefully the parser will flag this before we get
michael@0 1069 // here. If we're in the prolog or epilog, there should be
michael@0 1070 // no close tags for elements.
michael@0 1071 PR_ASSERT(eXMLContentSinkState_InDocumentElement == mState);
michael@0 1072
michael@0 1073 FlushText();
michael@0 1074
michael@0 1075 StackNode* sn = GetCurrentStackNode();
michael@0 1076 if (!sn) {
michael@0 1077 return NS_ERROR_UNEXPECTED;
michael@0 1078 }
michael@0 1079
michael@0 1080 nsCOMPtr<nsIContent> content;
michael@0 1081 sn->mContent.swap(content);
michael@0 1082 uint32_t numFlushed = sn->mNumFlushed;
michael@0 1083
michael@0 1084 PopContent();
michael@0 1085 NS_ASSERTION(content, "failed to pop content");
michael@0 1086 #ifdef DEBUG
michael@0 1087 // Check that we're closing the right thing
michael@0 1088 nsCOMPtr<nsIAtom> debugNameSpacePrefix, debugTagAtom;
michael@0 1089 int32_t debugNameSpaceID;
michael@0 1090 nsContentUtils::SplitExpatName(aName, getter_AddRefs(debugNameSpacePrefix),
michael@0 1091 getter_AddRefs(debugTagAtom),
michael@0 1092 &debugNameSpaceID);
michael@0 1093 NS_ASSERTION(content->NodeInfo()->Equals(debugTagAtom, debugNameSpaceID),
michael@0 1094 "Wrong element being closed");
michael@0 1095 #endif
michael@0 1096
michael@0 1097 result = CloseElement(content);
michael@0 1098
michael@0 1099 if (mCurrentHead == content) {
michael@0 1100 mCurrentHead = nullptr;
michael@0 1101 }
michael@0 1102
michael@0 1103 if (mDocElement == content) {
michael@0 1104 // XXXbz for roots that don't want to be appended on open, we
michael@0 1105 // probably need to deal here.... (and stop appending them on open).
michael@0 1106 mState = eXMLContentSinkState_InEpilog;
michael@0 1107
michael@0 1108 // We might have had no occasion to start layout yet. Do so now.
michael@0 1109 MaybeStartLayout(false);
michael@0 1110 }
michael@0 1111
michael@0 1112 int32_t stackLen = mContentStack.Length();
michael@0 1113 if (mNotifyLevel >= stackLen) {
michael@0 1114 if (numFlushed < content->GetChildCount()) {
michael@0 1115 NotifyAppend(content, numFlushed);
michael@0 1116 }
michael@0 1117 mNotifyLevel = stackLen - 1;
michael@0 1118 }
michael@0 1119 DidAddContent();
michael@0 1120
michael@0 1121 if (content->IsSVG(nsGkAtoms::svg)) {
michael@0 1122 FlushTags();
michael@0 1123 nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(content);
michael@0 1124 if (NS_FAILED(NS_DispatchToMainThread(event))) {
michael@0 1125 NS_WARNING("failed to dispatch svg load dispatcher");
michael@0 1126 }
michael@0 1127 }
michael@0 1128
michael@0 1129 return aInterruptable && NS_SUCCEEDED(result) ? DidProcessATokenImpl() :
michael@0 1130 result;
michael@0 1131 }
michael@0 1132
michael@0 1133 NS_IMETHODIMP
michael@0 1134 nsXMLContentSink::HandleComment(const char16_t *aName)
michael@0 1135 {
michael@0 1136 FlushText();
michael@0 1137
michael@0 1138 nsRefPtr<Comment> comment = new Comment(mNodeInfoManager);
michael@0 1139 comment->SetText(nsDependentString(aName), false);
michael@0 1140 nsresult rv = AddContentAsLeaf(comment);
michael@0 1141 DidAddContent();
michael@0 1142
michael@0 1143 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
michael@0 1144 }
michael@0 1145
michael@0 1146 NS_IMETHODIMP
michael@0 1147 nsXMLContentSink::HandleCDataSection(const char16_t *aData,
michael@0 1148 uint32_t aLength)
michael@0 1149 {
michael@0 1150 // XSLT doesn't differentiate between text and cdata and wants adjacent
michael@0 1151 // textnodes merged, so add as text.
michael@0 1152 if (mXSLTProcessor) {
michael@0 1153 return AddText(aData, aLength);
michael@0 1154 }
michael@0 1155
michael@0 1156 FlushText();
michael@0 1157
michael@0 1158 nsRefPtr<CDATASection> cdata = new CDATASection(mNodeInfoManager);
michael@0 1159 cdata->SetText(aData, aLength, false);
michael@0 1160 nsresult rv = AddContentAsLeaf(cdata);
michael@0 1161 DidAddContent();
michael@0 1162
michael@0 1163 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
michael@0 1164 }
michael@0 1165
michael@0 1166 NS_IMETHODIMP
michael@0 1167 nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset,
michael@0 1168 const nsAString & aName,
michael@0 1169 const nsAString & aSystemId,
michael@0 1170 const nsAString & aPublicId,
michael@0 1171 nsISupports* aCatalogData)
michael@0 1172 {
michael@0 1173 FlushText();
michael@0 1174
michael@0 1175 nsresult rv = NS_OK;
michael@0 1176
michael@0 1177 NS_ASSERTION(mDocument, "Shouldn't get here from a document fragment");
michael@0 1178
michael@0 1179 nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
michael@0 1180 NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
michael@0 1181
michael@0 1182 // Create a new doctype node
michael@0 1183 nsCOMPtr<nsIDOMDocumentType> docType;
michael@0 1184 rv = NS_NewDOMDocumentType(getter_AddRefs(docType), mNodeInfoManager,
michael@0 1185 name, aPublicId, aSystemId, aSubset);
michael@0 1186 if (NS_FAILED(rv) || !docType) {
michael@0 1187 return rv;
michael@0 1188 }
michael@0 1189
michael@0 1190 if (aCatalogData && mCSSLoader && mDocument) {
michael@0 1191 // bug 124570 - we only expect additional agent sheets for now -- ignore
michael@0 1192 // exit codes, error are not fatal here, just that the stylesheet won't apply
michael@0 1193 nsCOMPtr<nsIURI> uri(do_QueryInterface(aCatalogData));
michael@0 1194 if (uri) {
michael@0 1195 nsRefPtr<nsCSSStyleSheet> sheet;
michael@0 1196 mCSSLoader->LoadSheetSync(uri, true, true, getter_AddRefs(sheet));
michael@0 1197
michael@0 1198 #ifdef DEBUG
michael@0 1199 nsAutoCString uriStr;
michael@0 1200 uri->GetSpec(uriStr);
michael@0 1201 printf("Loading catalog stylesheet: %s ... %s\n", uriStr.get(), sheet.get() ? "Done" : "Failed");
michael@0 1202 #endif
michael@0 1203 if (sheet) {
michael@0 1204 mDocument->BeginUpdate(UPDATE_STYLE);
michael@0 1205 mDocument->AddCatalogStyleSheet(sheet);
michael@0 1206 mDocument->EndUpdate(UPDATE_STYLE);
michael@0 1207 }
michael@0 1208 }
michael@0 1209 }
michael@0 1210
michael@0 1211 nsCOMPtr<nsIContent> content = do_QueryInterface(docType);
michael@0 1212 NS_ASSERTION(content, "doctype isn't content?");
michael@0 1213
michael@0 1214 rv = mDocument->AppendChildTo(content, false);
michael@0 1215 DidAddContent();
michael@0 1216 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
michael@0 1217 }
michael@0 1218
michael@0 1219 NS_IMETHODIMP
michael@0 1220 nsXMLContentSink::HandleCharacterData(const char16_t *aData,
michael@0 1221 uint32_t aLength)
michael@0 1222 {
michael@0 1223 return HandleCharacterData(aData, aLength, true);
michael@0 1224 }
michael@0 1225
michael@0 1226 nsresult
michael@0 1227 nsXMLContentSink::HandleCharacterData(const char16_t *aData, uint32_t aLength,
michael@0 1228 bool aInterruptable)
michael@0 1229 {
michael@0 1230 nsresult rv = NS_OK;
michael@0 1231 if (aData && mState != eXMLContentSinkState_InProlog &&
michael@0 1232 mState != eXMLContentSinkState_InEpilog) {
michael@0 1233 rv = AddText(aData, aLength);
michael@0 1234 }
michael@0 1235 return aInterruptable && NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
michael@0 1236 }
michael@0 1237
michael@0 1238 NS_IMETHODIMP
michael@0 1239 nsXMLContentSink::HandleProcessingInstruction(const char16_t *aTarget,
michael@0 1240 const char16_t *aData)
michael@0 1241 {
michael@0 1242 FlushText();
michael@0 1243
michael@0 1244 const nsDependentString target(aTarget);
michael@0 1245 const nsDependentString data(aData);
michael@0 1246
michael@0 1247 nsCOMPtr<nsIContent> node =
michael@0 1248 NS_NewXMLProcessingInstruction(mNodeInfoManager, target, data);
michael@0 1249
michael@0 1250 nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
michael@0 1251 if (ssle) {
michael@0 1252 ssle->InitStyleLinkElement(false);
michael@0 1253 ssle->SetEnableUpdates(false);
michael@0 1254 mPrettyPrintXML = false;
michael@0 1255 }
michael@0 1256
michael@0 1257 nsresult rv = AddContentAsLeaf(node);
michael@0 1258 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1259 DidAddContent();
michael@0 1260
michael@0 1261 if (ssle) {
michael@0 1262 // This is an xml-stylesheet processing instruction... but it might not be
michael@0 1263 // a CSS one if the type is set to something else.
michael@0 1264 ssle->SetEnableUpdates(true);
michael@0 1265 bool willNotify;
michael@0 1266 bool isAlternate;
michael@0 1267 rv = ssle->UpdateStyleSheet(mRunsToCompletion ? nullptr : this,
michael@0 1268 &willNotify,
michael@0 1269 &isAlternate);
michael@0 1270 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1271
michael@0 1272 if (willNotify) {
michael@0 1273 // Successfully started a stylesheet load
michael@0 1274 if (!isAlternate && !mRunsToCompletion) {
michael@0 1275 ++mPendingSheetCount;
michael@0 1276 mScriptLoader->AddExecuteBlocker();
michael@0 1277 }
michael@0 1278
michael@0 1279 return NS_OK;
michael@0 1280 }
michael@0 1281 }
michael@0 1282
michael@0 1283 // If it's not a CSS stylesheet PI...
michael@0 1284 nsAutoString type;
michael@0 1285 nsContentUtils::GetPseudoAttributeValue(data, nsGkAtoms::type, type);
michael@0 1286
michael@0 1287 if (mState != eXMLContentSinkState_InProlog ||
michael@0 1288 !target.EqualsLiteral("xml-stylesheet") ||
michael@0 1289 type.IsEmpty() ||
michael@0 1290 type.LowerCaseEqualsLiteral("text/css")) {
michael@0 1291 return DidProcessATokenImpl();
michael@0 1292 }
michael@0 1293
michael@0 1294 nsAutoString href, title, media;
michael@0 1295 bool isAlternate = false;
michael@0 1296
michael@0 1297 // If there was no href, we can't do anything with this PI
michael@0 1298 if (!ParsePIData(data, href, title, media, isAlternate)) {
michael@0 1299 return DidProcessATokenImpl();
michael@0 1300 }
michael@0 1301
michael@0 1302 rv = ProcessStyleLink(node, href, isAlternate, title, type, media);
michael@0 1303 return NS_SUCCEEDED(rv) ? DidProcessATokenImpl() : rv;
michael@0 1304 }
michael@0 1305
michael@0 1306 /* static */
michael@0 1307 bool
michael@0 1308 nsXMLContentSink::ParsePIData(const nsString &aData, nsString &aHref,
michael@0 1309 nsString &aTitle, nsString &aMedia,
michael@0 1310 bool &aIsAlternate)
michael@0 1311 {
michael@0 1312 // If there was no href, we can't do anything with this PI
michael@0 1313 if (!nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::href, aHref)) {
michael@0 1314 return false;
michael@0 1315 }
michael@0 1316
michael@0 1317 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::title, aTitle);
michael@0 1318
michael@0 1319 nsContentUtils::GetPseudoAttributeValue(aData, nsGkAtoms::media, aMedia);
michael@0 1320
michael@0 1321 nsAutoString alternate;
michael@0 1322 nsContentUtils::GetPseudoAttributeValue(aData,
michael@0 1323 nsGkAtoms::alternate,
michael@0 1324 alternate);
michael@0 1325
michael@0 1326 aIsAlternate = alternate.EqualsLiteral("yes");
michael@0 1327
michael@0 1328 return true;
michael@0 1329 }
michael@0 1330
michael@0 1331 NS_IMETHODIMP
michael@0 1332 nsXMLContentSink::HandleXMLDeclaration(const char16_t *aVersion,
michael@0 1333 const char16_t *aEncoding,
michael@0 1334 int32_t aStandalone)
michael@0 1335 {
michael@0 1336 mDocument->SetXMLDeclaration(aVersion, aEncoding, aStandalone);
michael@0 1337
michael@0 1338 return DidProcessATokenImpl();
michael@0 1339 }
michael@0 1340
michael@0 1341 NS_IMETHODIMP
michael@0 1342 nsXMLContentSink::ReportError(const char16_t* aErrorText,
michael@0 1343 const char16_t* aSourceText,
michael@0 1344 nsIScriptError *aError,
michael@0 1345 bool *_retval)
michael@0 1346 {
michael@0 1347 NS_PRECONDITION(aError && aSourceText && aErrorText, "Check arguments!!!");
michael@0 1348 nsresult rv = NS_OK;
michael@0 1349
michael@0 1350 // The expat driver should report the error. We're just cleaning up the mess.
michael@0 1351 *_retval = true;
michael@0 1352
michael@0 1353 mPrettyPrintXML = false;
michael@0 1354
michael@0 1355 mState = eXMLContentSinkState_InProlog;
michael@0 1356
michael@0 1357 // XXX need to stop scripts here -- hsivonen
michael@0 1358
michael@0 1359 // stop observing in order to avoid crashing when removing content
michael@0 1360 mDocument->RemoveObserver(this);
michael@0 1361 mIsDocumentObserver = false;
michael@0 1362
michael@0 1363 // Clear the current content and
michael@0 1364 // prepare to set <parsererror> as the document root
michael@0 1365 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mDocument));
michael@0 1366 if (node) {
michael@0 1367 for (;;) {
michael@0 1368 nsCOMPtr<nsIDOMNode> child, dummy;
michael@0 1369 node->GetLastChild(getter_AddRefs(child));
michael@0 1370 if (!child)
michael@0 1371 break;
michael@0 1372 node->RemoveChild(child, getter_AddRefs(dummy));
michael@0 1373 }
michael@0 1374 }
michael@0 1375 mDocElement = nullptr;
michael@0 1376
michael@0 1377 // Clear any buffered-up text we have. It's enough to set the length to 0.
michael@0 1378 // The buffer itself is allocated when we're created and deleted in our
michael@0 1379 // destructor, so don't mess with it.
michael@0 1380 mTextLength = 0;
michael@0 1381
michael@0 1382 if (mXSLTProcessor) {
michael@0 1383 // Get rid of the XSLT processor.
michael@0 1384 mXSLTProcessor->CancelLoads();
michael@0 1385 mXSLTProcessor = nullptr;
michael@0 1386 }
michael@0 1387
michael@0 1388 // release the nodes on stack
michael@0 1389 mContentStack.Clear();
michael@0 1390 mNotifyLevel = 0;
michael@0 1391
michael@0 1392 rv = HandleProcessingInstruction(MOZ_UTF16("xml-stylesheet"),
michael@0 1393 MOZ_UTF16("href=\"chrome://global/locale/intl.css\" type=\"text/css\""));
michael@0 1394 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1395
michael@0 1396 const char16_t* noAtts[] = { 0, 0 };
michael@0 1397
michael@0 1398 NS_NAMED_LITERAL_STRING(errorNs,
michael@0 1399 "http://www.mozilla.org/newlayout/xml/parsererror.xml");
michael@0 1400
michael@0 1401 nsAutoString parsererror(errorNs);
michael@0 1402 parsererror.Append((char16_t)0xFFFF);
michael@0 1403 parsererror.AppendLiteral("parsererror");
michael@0 1404
michael@0 1405 rv = HandleStartElement(parsererror.get(), noAtts, 0, -1, (uint32_t)-1,
michael@0 1406 false);
michael@0 1407 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1408
michael@0 1409 rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
michael@0 1410 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1411
michael@0 1412 nsAutoString sourcetext(errorNs);
michael@0 1413 sourcetext.Append((char16_t)0xFFFF);
michael@0 1414 sourcetext.AppendLiteral("sourcetext");
michael@0 1415
michael@0 1416 rv = HandleStartElement(sourcetext.get(), noAtts, 0, -1, (uint32_t)-1,
michael@0 1417 false);
michael@0 1418 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1419
michael@0 1420 rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText), false);
michael@0 1421 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1422
michael@0 1423 rv = HandleEndElement(sourcetext.get(), false);
michael@0 1424 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1425
michael@0 1426 rv = HandleEndElement(parsererror.get(), false);
michael@0 1427 NS_ENSURE_SUCCESS(rv, rv);
michael@0 1428
michael@0 1429 FlushTags();
michael@0 1430
michael@0 1431 return NS_OK;
michael@0 1432 }
michael@0 1433
michael@0 1434 nsresult
michael@0 1435 nsXMLContentSink::AddAttributes(const char16_t** aAtts,
michael@0 1436 nsIContent* aContent)
michael@0 1437 {
michael@0 1438 // Add tag attributes to the content attributes
michael@0 1439 nsCOMPtr<nsIAtom> prefix, localName;
michael@0 1440 while (*aAtts) {
michael@0 1441 int32_t nameSpaceID;
michael@0 1442 nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
michael@0 1443 getter_AddRefs(localName), &nameSpaceID);
michael@0 1444
michael@0 1445 // Add attribute to content
michael@0 1446 aContent->SetAttr(nameSpaceID, localName, prefix,
michael@0 1447 nsDependentString(aAtts[1]), false);
michael@0 1448 aAtts += 2;
michael@0 1449 }
michael@0 1450
michael@0 1451 return NS_OK;
michael@0 1452 }
michael@0 1453
michael@0 1454 #define NS_ACCUMULATION_BUFFER_SIZE 4096
michael@0 1455
michael@0 1456 nsresult
michael@0 1457 nsXMLContentSink::AddText(const char16_t* aText,
michael@0 1458 int32_t aLength)
michael@0 1459 {
michael@0 1460 // Create buffer when we first need it
michael@0 1461 if (0 == mTextSize) {
michael@0 1462 mText = (char16_t *) PR_MALLOC(sizeof(char16_t) * NS_ACCUMULATION_BUFFER_SIZE);
michael@0 1463 if (nullptr == mText) {
michael@0 1464 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1465 }
michael@0 1466 mTextSize = NS_ACCUMULATION_BUFFER_SIZE;
michael@0 1467 }
michael@0 1468
michael@0 1469 // Copy data from string into our buffer; flush buffer when it fills up
michael@0 1470 int32_t offset = 0;
michael@0 1471 while (0 != aLength) {
michael@0 1472 int32_t amount = mTextSize - mTextLength;
michael@0 1473 if (0 == amount) {
michael@0 1474 // XSLT wants adjacent textnodes merged.
michael@0 1475 if (mConstrainSize && !mXSLTProcessor) {
michael@0 1476 nsresult rv = FlushText();
michael@0 1477 if (NS_OK != rv) {
michael@0 1478 return rv;
michael@0 1479 }
michael@0 1480
michael@0 1481 amount = mTextSize - mTextLength;
michael@0 1482 }
michael@0 1483 else {
michael@0 1484 mTextSize += aLength;
michael@0 1485 mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize);
michael@0 1486 if (nullptr == mText) {
michael@0 1487 mTextSize = 0;
michael@0 1488
michael@0 1489 return NS_ERROR_OUT_OF_MEMORY;
michael@0 1490 }
michael@0 1491
michael@0 1492 amount = aLength;
michael@0 1493 }
michael@0 1494 }
michael@0 1495 if (amount > aLength) {
michael@0 1496 amount = aLength;
michael@0 1497 }
michael@0 1498 memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount);
michael@0 1499 mTextLength += amount;
michael@0 1500 offset += amount;
michael@0 1501 aLength -= amount;
michael@0 1502 }
michael@0 1503
michael@0 1504 return NS_OK;
michael@0 1505 }
michael@0 1506
michael@0 1507 void
michael@0 1508 nsXMLContentSink::FlushPendingNotifications(mozFlushType aType)
michael@0 1509 {
michael@0 1510 // Only flush tags if we're not doing the notification ourselves
michael@0 1511 // (since we aren't reentrant)
michael@0 1512 if (!mInNotification) {
michael@0 1513 if (mIsDocumentObserver) {
michael@0 1514 // Only flush if we're still a document observer (so that our child
michael@0 1515 // counts should be correct).
michael@0 1516 if (aType >= Flush_ContentAndNotify) {
michael@0 1517 FlushTags();
michael@0 1518 }
michael@0 1519 else {
michael@0 1520 FlushText(false);
michael@0 1521 }
michael@0 1522 }
michael@0 1523 if (aType >= Flush_InterruptibleLayout) {
michael@0 1524 // Make sure that layout has started so that the reflow flush
michael@0 1525 // will actually happen.
michael@0 1526 MaybeStartLayout(true);
michael@0 1527 }
michael@0 1528 }
michael@0 1529 }
michael@0 1530
michael@0 1531 /**
michael@0 1532 * NOTE!! Forked from SinkContext. Please keep in sync.
michael@0 1533 *
michael@0 1534 * Flush all elements that have been seen so far such that
michael@0 1535 * they are visible in the tree. Specifically, make sure
michael@0 1536 * that they are all added to their respective parents.
michael@0 1537 * Also, do notification at the top for all content that
michael@0 1538 * has been newly added so that the frame tree is complete.
michael@0 1539 */
michael@0 1540 nsresult
michael@0 1541 nsXMLContentSink::FlushTags()
michael@0 1542 {
michael@0 1543 mDeferredFlushTags = false;
michael@0 1544 bool oldBeganUpdate = mBeganUpdate;
michael@0 1545 uint32_t oldUpdates = mUpdatesInNotification;
michael@0 1546
michael@0 1547 mUpdatesInNotification = 0;
michael@0 1548 ++mInNotification;
michael@0 1549 {
michael@0 1550 // Scope so we call EndUpdate before we decrease mInNotification
michael@0 1551 mozAutoDocUpdate updateBatch(mDocument, UPDATE_CONTENT_MODEL, true);
michael@0 1552 mBeganUpdate = true;
michael@0 1553
michael@0 1554 // Don't release last text node in case we need to add to it again
michael@0 1555 FlushText(false);
michael@0 1556
michael@0 1557 // Start from the base of the stack (growing downward) and do
michael@0 1558 // a notification from the node that is closest to the root of
michael@0 1559 // tree for any content that has been added.
michael@0 1560
michael@0 1561 int32_t stackPos;
michael@0 1562 int32_t stackLen = mContentStack.Length();
michael@0 1563 bool flushed = false;
michael@0 1564 uint32_t childCount;
michael@0 1565 nsIContent* content;
michael@0 1566
michael@0 1567 for (stackPos = 0; stackPos < stackLen; ++stackPos) {
michael@0 1568 content = mContentStack[stackPos].mContent;
michael@0 1569 childCount = content->GetChildCount();
michael@0 1570
michael@0 1571 if (!flushed && (mContentStack[stackPos].mNumFlushed < childCount)) {
michael@0 1572 NotifyAppend(content, mContentStack[stackPos].mNumFlushed);
michael@0 1573 flushed = true;
michael@0 1574 }
michael@0 1575
michael@0 1576 mContentStack[stackPos].mNumFlushed = childCount;
michael@0 1577 }
michael@0 1578 mNotifyLevel = stackLen - 1;
michael@0 1579 }
michael@0 1580 --mInNotification;
michael@0 1581
michael@0 1582 if (mUpdatesInNotification > 1) {
michael@0 1583 UpdateChildCounts();
michael@0 1584 }
michael@0 1585
michael@0 1586 mUpdatesInNotification = oldUpdates;
michael@0 1587 mBeganUpdate = oldBeganUpdate;
michael@0 1588
michael@0 1589 return NS_OK;
michael@0 1590 }
michael@0 1591
michael@0 1592 /**
michael@0 1593 * NOTE!! Forked from SinkContext. Please keep in sync.
michael@0 1594 */
michael@0 1595 void
michael@0 1596 nsXMLContentSink::UpdateChildCounts()
michael@0 1597 {
michael@0 1598 // Start from the top of the stack (growing upwards) and see if any
michael@0 1599 // new content has been appended. If so, we recognize that reflows
michael@0 1600 // have been generated for it and we should make sure that no
michael@0 1601 // further reflows occur. Note that we have to include stackPos == 0
michael@0 1602 // to properly notify on kids of <html>.
michael@0 1603 int32_t stackLen = mContentStack.Length();
michael@0 1604 int32_t stackPos = stackLen - 1;
michael@0 1605 while (stackPos >= 0) {
michael@0 1606 StackNode & node = mContentStack[stackPos];
michael@0 1607 node.mNumFlushed = node.mContent->GetChildCount();
michael@0 1608
michael@0 1609 stackPos--;
michael@0 1610 }
michael@0 1611 mNotifyLevel = stackLen - 1;
michael@0 1612 }
michael@0 1613
michael@0 1614 bool
michael@0 1615 nsXMLContentSink::IsMonolithicContainer(nsINodeInfo* aNodeInfo)
michael@0 1616 {
michael@0 1617 return ((aNodeInfo->NamespaceID() == kNameSpaceID_XHTML &&
michael@0 1618 (aNodeInfo->NameAtom() == nsGkAtoms::tr ||
michael@0 1619 aNodeInfo->NameAtom() == nsGkAtoms::select ||
michael@0 1620 aNodeInfo->NameAtom() == nsGkAtoms::object ||
michael@0 1621 aNodeInfo->NameAtom() == nsGkAtoms::applet)) ||
michael@0 1622 (aNodeInfo->NamespaceID() == kNameSpaceID_MathML &&
michael@0 1623 (aNodeInfo->NameAtom() == nsGkAtoms::math))
michael@0 1624 );
michael@0 1625 }
michael@0 1626
michael@0 1627 void
michael@0 1628 nsXMLContentSink::ContinueInterruptedParsingIfEnabled()
michael@0 1629 {
michael@0 1630 if (mParser && mParser->IsParserEnabled()) {
michael@0 1631 GetParser()->ContinueInterruptedParsing();
michael@0 1632 }
michael@0 1633 }
michael@0 1634
michael@0 1635 void
michael@0 1636 nsXMLContentSink::ContinueInterruptedParsingAsync()
michael@0 1637 {
michael@0 1638 nsCOMPtr<nsIRunnable> ev = NS_NewRunnableMethod(this,
michael@0 1639 &nsXMLContentSink::ContinueInterruptedParsingIfEnabled);
michael@0 1640
michael@0 1641 NS_DispatchToCurrentThread(ev);
michael@0 1642 }
michael@0 1643
michael@0 1644 nsIParser*
michael@0 1645 nsXMLContentSink::GetParser()
michael@0 1646 {
michael@0 1647 return static_cast<nsIParser*>(mParser.get());
michael@0 1648 }

mercurial