1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 * Base class for the XML and HTML content sinks, which construct a
9 * DOM based on information from the parser.
12 #include "nsContentSink.h"
13 #include "mozilla/Components.h"
14 #include "mozilla/PresShell.h"
15 #include "mozilla/dom/Document.h"
16 #include "mozilla/css/Loader.h"
17 #include "mozilla/dom/SRILogHelper.h"
18 #include "nsStyleLinkElement.h"
19 #include "nsIDocShell.h"
20 #include "nsILoadContext.h"
21 #include "nsIPrefetchService.h"
23 #include "nsNetUtil.h"
24 #include "nsIMIMEHeaderParam.h"
25 #include "nsIProtocolHandler.h"
26 #include "nsIHttpChannel.h"
27 #include "nsIContent.h"
28 #include "nsPresContext.h"
29 #include "nsViewManager.h"
31 #include "nsGkAtoms.h"
32 #include "nsGlobalWindowInner.h"
34 #include "nsIOfflineCacheUpdate.h"
35 #include "nsIApplicationCache.h"
36 #include "nsIApplicationCacheContainer.h"
37 #include "nsIApplicationCacheChannel.h"
38 #include "nsIScriptSecurityManager.h"
39 #include "nsICookieService.h"
40 #include "nsContentUtils.h"
41 #include "nsNodeInfoManager.h"
42 #include "nsIAppShell.h"
43 #include "nsIWidget.h"
44 #include "nsWidgetsCID.h"
45 #include "mozAutoDocUpdate.h"
46 #include "nsIWebNavigation.h"
47 #include "nsGenericHTMLElement.h"
48 #include "nsHTMLDNSPrefetch.h"
49 #include "nsIObserverService.h"
50 #include "mozilla/Preferences.h"
51 #include "mozilla/dom/ServiceWorkerDescriptor.h"
52 #include "mozilla/dom/ScriptLoader.h"
53 #include "nsParserConstants.h"
54 #include "nsSandboxFlags.h"
56 #include "HTMLLinkElement.h"
58 using namespace mozilla
;
59 using namespace mozilla::css
;
60 using namespace mozilla::dom
;
62 LazyLogModule
gContentSinkLogModuleInfo("nscontentsink");
64 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink
)
65 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink
)
67 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink
)
68 NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver
)
69 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference
)
70 NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver
)
71 NS_INTERFACE_MAP_ENTRY(nsIMutationObserver
)
72 NS_INTERFACE_MAP_ENTRY(nsITimerCallback
)
73 NS_INTERFACE_MAP_ENTRY(nsINamed
)
74 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIDocumentObserver
)
77 NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink
)
79 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink
)
81 tmp
->mDocument
->RemoveObserver(tmp
);
83 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument
)
84 NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser
)
85 NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell
)
86 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCSSLoader
)
87 NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager
)
88 NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptLoader
)
89 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
90 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink
)
91 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument
)
92 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser
)
93 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell
)
94 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCSSLoader
)
95 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager
)
96 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader
)
97 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
99 nsContentSink::nsContentSink()
101 mLastNotificationTime(0),
103 mDynamicLowerValue(0),
106 mDeferredLayoutStart(0),
107 mDeferredFlushTags(0),
108 mIsDocumentObserver(0),
109 mRunsToCompletion(0),
110 mIsBlockingOnload(false),
112 mHasPendingEvent(false),
113 mCurrentParseEndTime(0),
115 mLastSampledUserEventTime(0),
116 mInMonolithicContainer(0),
118 mUpdatesInNotification(0),
119 mPendingSheetCount(0) {
120 NS_ASSERTION(!mLayoutStarted
, "What?");
121 NS_ASSERTION(!mDynamicLowerValue
, "What?");
122 NS_ASSERTION(!mParsing
, "What?");
123 NS_ASSERTION(mLastSampledUserEventTime
== 0, "What?");
124 NS_ASSERTION(mDeflectedCount
== 0, "What?");
125 NS_ASSERTION(!mDroppedTimer
, "What?");
126 NS_ASSERTION(mInMonolithicContainer
== 0, "What?");
127 NS_ASSERTION(mInNotification
== 0, "What?");
128 NS_ASSERTION(!mDeferredLayoutStart
, "What?");
131 nsContentSink::~nsContentSink() {
133 // Remove ourselves just to be safe, though we really should have
134 // been removed in DidBuildModel if everything worked right.
135 mDocument
->RemoveObserver(this);
139 bool nsContentSink::sNotifyOnTimer
;
140 int32_t nsContentSink::sBackoffCount
;
141 int32_t nsContentSink::sNotificationInterval
;
142 int32_t nsContentSink::sInteractiveDeflectCount
;
143 int32_t nsContentSink::sPerfDeflectCount
;
144 int32_t nsContentSink::sPendingEventMode
;
145 int32_t nsContentSink::sEventProbeRate
;
146 int32_t nsContentSink::sInteractiveParseTime
;
147 int32_t nsContentSink::sPerfParseTime
;
148 int32_t nsContentSink::sInteractiveTime
;
149 int32_t nsContentSink::sInitialPerfTime
;
150 int32_t nsContentSink::sEnablePerfMode
;
152 void nsContentSink::InitializeStatics() {
153 Preferences::AddBoolVarCache(&sNotifyOnTimer
, "content.notify.ontimer", true);
155 Preferences::AddIntVarCache(&sBackoffCount
, "content.notify.backoffcount",
157 // The gNotificationInterval has a dramatic effect on how long it
158 // takes to initially display content for slow connections.
159 // The current value provides good
160 // incremental display of content without causing an increase
161 // in page load time. If this value is set below 1/10 of second
162 // it starts to impact page load performance.
163 // see bugzilla bug 72138 for more info.
164 Preferences::AddIntVarCache(&sNotificationInterval
, "content.notify.interval",
166 Preferences::AddIntVarCache(&sInteractiveDeflectCount
,
167 "content.sink.interactive_deflect_count", 0);
168 Preferences::AddIntVarCache(&sPerfDeflectCount
,
169 "content.sink.perf_deflect_count", 200);
170 Preferences::AddIntVarCache(&sPendingEventMode
,
171 "content.sink.pending_event_mode", 1);
172 Preferences::AddIntVarCache(&sEventProbeRate
, "content.sink.event_probe_rate",
174 Preferences::AddIntVarCache(&sInteractiveParseTime
,
175 "content.sink.interactive_parse_time", 3000);
176 Preferences::AddIntVarCache(&sPerfParseTime
, "content.sink.perf_parse_time",
178 Preferences::AddIntVarCache(&sInteractiveTime
,
179 "content.sink.interactive_time", 750000);
180 Preferences::AddIntVarCache(&sInitialPerfTime
,
181 "content.sink.initial_perf_time", 2000000);
182 Preferences::AddIntVarCache(&sEnablePerfMode
, "content.sink.enable_perf_mode",
186 nsresult
nsContentSink::Init(Document
* aDoc
, nsIURI
* aURI
,
187 nsISupports
* aContainer
, nsIChannel
* aChannel
) {
188 MOZ_ASSERT(aDoc
, "null ptr");
189 MOZ_ASSERT(aURI
, "null ptr");
191 if (!aDoc
|| !aURI
) {
192 return NS_ERROR_NULL_POINTER
;
198 mDocShell
= do_QueryInterface(aContainer
);
199 mScriptLoader
= mDocument
->ScriptLoader();
201 if (!mRunsToCompletion
) {
203 uint32_t loadType
= 0;
204 mDocShell
->GetLoadType(&loadType
);
205 mDocument
->SetChangeScrollPosWhenScrollingToRef(
206 (loadType
& nsIDocShell::LOAD_CMD_HISTORY
) == 0);
209 ProcessHTTPHeaders(aChannel
);
212 mCSSLoader
= aDoc
->CSSLoader();
214 mNodeInfoManager
= aDoc
->NodeInfoManager();
216 mBackoffCount
= sBackoffCount
;
218 if (sEnablePerfMode
!= 0) {
219 mDynamicLowerValue
= sEnablePerfMode
== 1;
220 FavorPerformanceHint(!mDynamicLowerValue
, 0);
227 nsContentSink::StyleSheetLoaded(StyleSheet
* aSheet
, bool aWasDeferred
,
229 MOZ_ASSERT(!mRunsToCompletion
, "How come a fragment parser observed sheets?");
231 MOZ_ASSERT(mPendingSheetCount
> 0, "How'd that happen?");
232 --mPendingSheetCount
;
234 if (mPendingSheetCount
== 0 &&
235 (mDeferredLayoutStart
|| mDeferredFlushTags
)) {
236 if (mDeferredFlushTags
) {
239 if (mDeferredLayoutStart
) {
240 // We might not have really started layout, since this sheet was still
241 // loading. Do it now. Probably doesn't matter whether we do this
242 // before or after we unblock scripts, but before feels saner. Note
243 // that if mDeferredLayoutStart is true, that means any subclass
244 // StartLayout() stuff that needs to happen has already happened, so we
245 // don't need to worry about it.
249 // Go ahead and try to scroll to our ref if we have one
253 mScriptLoader
->RemoveParserBlockingScriptExecutionBlocker();
259 nsresult
nsContentSink::ProcessHTTPHeaders(nsIChannel
* aChannel
) {
260 nsCOMPtr
<nsIHttpChannel
> httpchannel(do_QueryInterface(aChannel
));
266 // Note that the only header we care about is the "link" header, since we
267 // have all the infrastructure for kicking off stylesheet loads.
269 nsAutoCString linkHeader
;
272 httpchannel
->GetResponseHeader(NS_LITERAL_CSTRING("link"), linkHeader
);
273 if (NS_SUCCEEDED(rv
) && !linkHeader
.IsEmpty()) {
274 mDocument
->SetHeaderData(nsGkAtoms::link
,
275 NS_ConvertASCIItoUTF16(linkHeader
));
277 NS_ASSERTION(!mProcessLinkHeaderEvent
.get(),
278 "Already dispatched an event?");
280 mProcessLinkHeaderEvent
=
281 NewNonOwningRunnableMethod("nsContentSink::DoProcessLinkHeader", this,
282 &nsContentSink::DoProcessLinkHeader
);
283 rv
= NS_DispatchToCurrentThread(mProcessLinkHeaderEvent
.get());
285 mProcessLinkHeaderEvent
.Forget();
292 nsresult
nsContentSink::ProcessHeaderData(nsAtom
* aHeader
,
293 const nsAString
& aValue
,
294 nsIContent
* aContent
) {
296 // necko doesn't process headers coming in from the parser
298 mDocument
->SetHeaderData(aHeader
, aValue
);
300 if (aHeader
== nsGkAtoms::setcookie
&&
301 StaticPrefs::dom_metaElement_setCookie_allowed()) {
302 // Note: Necko already handles cookies set via the channel. We can't just
303 // call SetCookie on the channel because we want to do some security checks
305 nsCOMPtr
<nsICookieService
> cookieServ
=
306 do_GetService(NS_COOKIESERVICE_CONTRACTID
, &rv
);
311 // Get a URI from the document principal
313 // We use the original codebase in case the codebase was changed
316 // Note that a non-codebase principal (eg the system principal) will return
318 nsCOMPtr
<nsIURI
> codebaseURI
;
319 rv
= mDocument
->NodePrincipal()->GetURI(getter_AddRefs(codebaseURI
));
320 NS_ENSURE_TRUE(codebaseURI
, rv
);
322 nsCOMPtr
<nsIChannel
> channel
;
324 mParser
->GetChannel(getter_AddRefs(channel
));
327 rv
= cookieServ
->SetCookieString(codebaseURI
, nullptr,
328 NS_ConvertUTF16toUTF8(aValue
), channel
);
337 void nsContentSink::DoProcessLinkHeader() {
339 mDocument
->GetHeaderData(nsGkAtoms::link
, value
);
340 ProcessLinkHeader(value
);
343 // check whether the Link header field applies to the context resource
344 // see <http://tools.ietf.org/html/rfc5988#section-5.2>
346 bool nsContentSink::LinkContextIsOurDocument(const nsAString
& aAnchor
) {
347 if (aAnchor
.IsEmpty()) {
348 // anchor parameter not present or empty -> same document reference
352 nsIURI
* docUri
= mDocument
->GetDocumentURI();
354 // the document URI might contain a fragment identifier ("#...')
355 // we want to ignore that because it's invisible to the server
356 // and just affects the local interpretation in the recipient
357 nsCOMPtr
<nsIURI
> contextUri
;
358 nsresult rv
= NS_GetURIWithoutRef(docUri
, getter_AddRefs(contextUri
));
365 // resolve anchor against context
366 nsCOMPtr
<nsIURI
> resolvedUri
;
367 rv
= NS_NewURI(getter_AddRefs(resolvedUri
), aAnchor
, nullptr, contextUri
);
375 rv
= contextUri
->Equals(resolvedUri
, &same
);
384 // Decode a parameter value using the encoding defined in RFC 5987 (in place)
386 // charset "'" [ language ] "'" value-chars
388 // returns true when decoding happened successfully (otherwise leaves
389 // passed value alone)
390 bool nsContentSink::Decode5987Format(nsAString
& aEncoded
) {
392 nsCOMPtr
<nsIMIMEHeaderParam
> mimehdrpar
=
393 do_GetService(NS_MIMEHEADERPARAM_CONTRACTID
, &rv
);
394 if (NS_FAILED(rv
)) return false;
396 nsAutoCString asciiValue
;
398 const char16_t
* encstart
= aEncoded
.BeginReading();
399 const char16_t
* encend
= aEncoded
.EndReading();
401 // create a plain ASCII string, aborting if we can't do that
402 // converted form is always shorter than input
403 while (encstart
!= encend
) {
404 if (*encstart
> 0 && *encstart
< 128) {
405 asciiValue
.Append((char)*encstart
);
412 nsAutoString decoded
;
413 nsAutoCString language
;
415 rv
= mimehdrpar
->DecodeRFC5987Param(asciiValue
, language
, decoded
);
416 if (NS_FAILED(rv
)) return false;
422 nsresult
nsContentSink::ProcessLinkHeader(const nsAString
& aLinkData
) {
425 // keep track where we are within the header field
426 bool seenParameters
= false;
428 // parse link content and call process style link
432 nsAutoString titleStar
;
436 nsAutoString crossOrigin
;
437 nsAutoString referrerPolicy
;
440 crossOrigin
.SetIsVoid(true);
442 // copy to work buffer
443 nsAutoString
stringList(aLinkData
);
445 // put an extra null at the end
446 stringList
.Append(kNullCh
);
448 char16_t
* start
= stringList
.BeginWriting();
449 char16_t
* end
= start
;
450 char16_t
* last
= start
;
453 while (*start
!= kNullCh
) {
454 // skip leading space
455 while ((*start
!= kNullCh
) && nsCRT::IsAsciiSpace(*start
)) {
462 bool wasQuotedString
= false;
464 // look for semicolon or comma
465 while (*end
!= kNullCh
&& *end
!= kSemicolon
&& *end
!= kComma
) {
468 if (ch
== kQuote
|| ch
== kLessThan
) {
472 if (quote
== kLessThan
) {
473 quote
= kGreaterThan
;
476 wasQuotedString
= (ch
== kQuote
);
478 char16_t
* closeQuote
= (end
+ 1);
480 // seek closing quote
481 while (*closeQuote
!= kNullCh
&& quote
!= *closeQuote
) {
482 // in quoted-string, "\" is an escape character
483 if (wasQuotedString
&& *closeQuote
== kBackSlash
&&
484 *(closeQuote
+ 1) != kNullCh
) {
491 if (quote
== *closeQuote
) {
494 // skip to close quote
501 if (ch
!= kNullCh
&& ch
!= kSemicolon
&& ch
!= kComma
) {
507 // keep going until semi or comma
508 while (ch
!= kNullCh
&& ch
!= kSemicolon
&& ch
!= kComma
) {
527 if ((*start
== kLessThan
) && (*last
== kGreaterThan
)) {
530 // first instance of <...> wins
531 // also, do not allow hrefs after the first param was seen
532 if (href
.IsEmpty() && !seenParameters
) {
534 href
.StripWhitespace();
537 char16_t
* equals
= start
;
538 seenParameters
= true;
540 while ((*equals
!= kNullCh
) && (*equals
!= kEqual
)) {
544 if (*equals
!= kNullCh
) {
546 nsAutoString
attr(start
);
547 attr
.StripWhitespace();
549 char16_t
* value
= ++equals
;
550 while (nsCRT::IsAsciiSpace(*value
)) {
554 if ((*value
== kQuote
) && (*value
== *last
)) {
559 if (wasQuotedString
) {
561 char16_t
* unescaped
= value
;
562 char16_t
* src
= value
;
564 while (*src
!= kNullCh
) {
565 if (*src
== kBackSlash
&& *(src
+ 1) != kNullCh
) {
568 *unescaped
++ = *src
++;
571 *unescaped
= kNullCh
;
574 if (attr
.LowerCaseEqualsLiteral("rel")) {
577 rel
.CompressWhitespace();
579 } else if (attr
.LowerCaseEqualsLiteral("title")) {
580 if (title
.IsEmpty()) {
582 title
.CompressWhitespace();
584 } else if (attr
.LowerCaseEqualsLiteral("title*")) {
585 if (titleStar
.IsEmpty() && !wasQuotedString
) {
586 // RFC 5987 encoding; uses token format only, so skip if we get
587 // here with a quoted-string
590 if (Decode5987Format(tmp
)) {
592 titleStar
.CompressWhitespace();
594 // header value did not parse, throw it away
595 titleStar
.Truncate();
598 } else if (attr
.LowerCaseEqualsLiteral("type")) {
599 if (type
.IsEmpty()) {
601 type
.StripWhitespace();
603 } else if (attr
.LowerCaseEqualsLiteral("media")) {
604 if (media
.IsEmpty()) {
607 // The HTML5 spec is formulated in terms of the CSS3 spec,
608 // which specifies that media queries are case insensitive.
609 nsContentUtils::ASCIIToLower(media
);
611 } else if (attr
.LowerCaseEqualsLiteral("anchor")) {
612 if (anchor
.IsEmpty()) {
614 anchor
.StripWhitespace();
616 } else if (attr
.LowerCaseEqualsLiteral("crossorigin")) {
617 if (crossOrigin
.IsVoid()) {
618 crossOrigin
.SetIsVoid(false);
620 crossOrigin
.StripWhitespace();
622 } else if (attr
.LowerCaseEqualsLiteral("as")) {
625 as
.CompressWhitespace();
627 } else if (attr
.LowerCaseEqualsLiteral("referrerpolicy")) {
628 // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#referrer-policy-attribute
629 // Specs says referrer policy attribute is an enumerated attribute,
630 // case insensitive and includes the empty string
631 // We will parse the value with AttributeReferrerPolicyFromString
632 // later, which will handle parsing it as an enumerated attribute.
633 if (referrerPolicy
.IsEmpty()) {
634 referrerPolicy
= value
;
641 if (endCh
== kComma
) {
642 // hit a comma, process what we've got so far
644 href
.Trim(" \t\n\r\f"); // trim HTML5 whitespace
645 if (!href
.IsEmpty() && !rel
.IsEmpty()) {
646 rv
= ProcessLinkFromHeader(
648 // prefer RFC 5987 variant over non-I18zed version
649 titleStar
.IsEmpty() ? title
: titleStar
, type
, media
, crossOrigin
,
659 referrerPolicy
.Truncate();
660 crossOrigin
.SetIsVoid(true);
663 seenParameters
= false;
669 href
.Trim(" \t\n\r\f"); // trim HTML5 whitespace
670 if (!href
.IsEmpty() && !rel
.IsEmpty()) {
672 ProcessLinkFromHeader(anchor
, href
, rel
,
673 // prefer RFC 5987 variant over non-I18zed version
674 titleStar
.IsEmpty() ? title
: titleStar
, type
,
675 media
, crossOrigin
, referrerPolicy
, as
);
681 nsresult
nsContentSink::ProcessLinkFromHeader(
682 const nsAString
& aAnchor
, const nsAString
& aHref
, const nsAString
& aRel
,
683 const nsAString
& aTitle
, const nsAString
& aType
, const nsAString
& aMedia
,
684 const nsAString
& aCrossOrigin
, const nsAString
& aReferrerPolicy
,
685 const nsAString
& aAs
) {
686 uint32_t linkTypes
= nsStyleLinkElement::ParseLinkTypes(aRel
);
688 // The link relation may apply to a different resource, specified
689 // in the anchor parameter. For the link relations supported so far,
690 // we simply abort if the link applies to a resource different to the
692 if (!LinkContextIsOurDocument(aAnchor
)) {
696 if (nsContentUtils::PrefetchPreloadEnabled(mDocShell
)) {
697 // prefetch href if relation is "next" or "prefetch"
698 if ((linkTypes
& nsStyleLinkElement::eNEXT
) ||
699 (linkTypes
& nsStyleLinkElement::ePREFETCH
) ||
700 (linkTypes
& nsStyleLinkElement::ePRELOAD
)) {
701 PrefetchPreloadHref(aHref
, mDocument
, linkTypes
, aAs
, aType
, aMedia
);
704 if (!aHref
.IsEmpty() && (linkTypes
& nsStyleLinkElement::eDNS_PREFETCH
)) {
708 if (!aHref
.IsEmpty() && (linkTypes
& nsStyleLinkElement::ePRECONNECT
)) {
709 Preconnect(aHref
, aCrossOrigin
);
713 // is it a stylesheet link?
714 if (!(linkTypes
& nsStyleLinkElement::eSTYLESHEET
)) {
718 bool isAlternate
= linkTypes
& nsStyleLinkElement::eALTERNATE
;
719 return ProcessStyleLinkFromHeader(aHref
, isAlternate
, aTitle
, aType
, aMedia
,
723 nsresult
nsContentSink::ProcessStyleLinkFromHeader(
724 const nsAString
& aHref
, bool aAlternate
, const nsAString
& aTitle
,
725 const nsAString
& aType
, const nsAString
& aMedia
,
726 const nsAString
& aReferrerPolicy
) {
727 if (aAlternate
&& aTitle
.IsEmpty()) {
728 // alternates must have title return without error, for now
732 nsAutoString mimeType
;
734 nsContentUtils::SplitMimeType(aType
, mimeType
, params
);
737 if (!mimeType
.IsEmpty() && !mimeType
.LowerCaseEqualsLiteral("text/css")) {
738 // Unknown stylesheet language
742 nsCOMPtr
<nsIURI
> url
;
743 nsresult rv
= NS_NewURI(getter_AddRefs(url
), aHref
, nullptr,
744 mDocument
->GetDocBaseURI());
747 // The URI is bad, move along, don't propagate the error (for now)
751 Loader::SheetInfo info
{
756 net::AttributeReferrerPolicyFromString(aReferrerPolicy
),
760 aAlternate
? Loader::HasAlternateRel::Yes
: Loader::HasAlternateRel::No
,
761 Loader::IsInline::No
,
762 Loader::IsExplicitlyEnabled::No
,
765 auto loadResultOrErr
=
766 mCSSLoader
->LoadStyleLink(info
, mRunsToCompletion
? nullptr : this);
767 if (loadResultOrErr
.isErr()) {
768 return loadResultOrErr
.unwrapErr();
771 if (loadResultOrErr
.unwrap().ShouldBlock() && !mRunsToCompletion
) {
772 ++mPendingSheetCount
;
773 mScriptLoader
->AddParserBlockingScriptExecutionBlocker();
779 nsresult
nsContentSink::ProcessMETATag(nsIContent
* aContent
) {
780 NS_ASSERTION(aContent
, "missing meta-element");
781 MOZ_ASSERT(aContent
->IsElement());
783 Element
* element
= aContent
->AsElement();
787 // set any HTTP-EQUIV data into document's header data as well as url
789 element
->GetAttr(kNameSpaceID_None
, nsGkAtoms::httpEquiv
, header
);
790 if (!header
.IsEmpty()) {
791 // Ignore META REFRESH when document is sandboxed from automatic features.
792 nsContentUtils::ASCIIToLower(header
);
793 if (nsGkAtoms::refresh
->Equals(header
) &&
794 (mDocument
->GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES
)) {
798 // Don't allow setting cookies in <meta http-equiv> in cookie averse
800 if (nsGkAtoms::setcookie
->Equals(header
) && mDocument
->IsCookieAverse() &&
801 StaticPrefs::dom_metaElement_setCookie_allowed()) {
806 element
->GetAttr(kNameSpaceID_None
, nsGkAtoms::content
, result
);
807 if (!result
.IsEmpty()) {
808 RefPtr
<nsAtom
> fieldAtom(NS_Atomize(header
));
809 rv
= ProcessHeaderData(fieldAtom
, result
, element
);
812 NS_ENSURE_SUCCESS(rv
, rv
);
814 if (element
->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::name
,
815 nsGkAtoms::handheldFriendly
, eIgnoreCase
)) {
817 element
->GetAttr(kNameSpaceID_None
, nsGkAtoms::content
, result
);
818 if (!result
.IsEmpty()) {
819 nsContentUtils::ASCIIToLower(result
);
820 mDocument
->SetHeaderData(nsGkAtoms::handheldFriendly
, result
);
827 void nsContentSink::PrefetchPreloadHref(const nsAString
& aHref
,
828 nsINode
* aSource
, uint32_t aLinkTypes
,
829 const nsAString
& aAs
,
830 const nsAString
& aType
,
831 const nsAString
& aMedia
) {
832 nsCOMPtr
<nsIPrefetchService
> prefetchService(components::Prefetch::Service());
833 if (prefetchService
) {
834 // construct URI using document charset
835 auto encoding
= mDocument
->GetDocumentCharacterSet();
836 nsCOMPtr
<nsIURI
> uri
;
837 NS_NewURI(getter_AddRefs(uri
), aHref
, encoding
, mDocument
->GetDocBaseURI());
839 if (aLinkTypes
& nsStyleLinkElement::ePRELOAD
) {
841 Link::ParseAsValue(aAs
, asAttr
);
842 nsContentPolicyType policyType
= Link::AsValueToContentPolicy(asAttr
);
844 if (policyType
== nsIContentPolicy::TYPE_INVALID
) {
845 // Ignore preload with a wrong or empty as attribute.
849 nsAutoString mimeType
;
850 nsAutoString notUsed
;
851 nsContentUtils::SplitMimeType(aType
, mimeType
, notUsed
);
852 if (!HTMLLinkElement::CheckPreloadAttrs(asAttr
, mimeType
, aMedia
,
854 policyType
= nsIContentPolicy::TYPE_INVALID
;
857 prefetchService
->PreloadURI(uri
, mDocumentURI
, aSource
, policyType
);
859 prefetchService
->PrefetchURI(
860 uri
, mDocumentURI
, aSource
,
861 aLinkTypes
& nsStyleLinkElement::ePREFETCH
);
867 void nsContentSink::PrefetchDNS(const nsAString
& aHref
) {
868 nsAutoString hostname
;
869 bool isHttps
= false;
871 if (StringBeginsWith(aHref
, NS_LITERAL_STRING("//"))) {
872 hostname
= Substring(aHref
, 2);
874 nsCOMPtr
<nsIURI
> uri
;
875 NS_NewURI(getter_AddRefs(uri
), aHref
);
880 bool isLocalResource
= false;
881 rv
= NS_URIChainHasFlags(uri
, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE
,
883 if (NS_SUCCEEDED(rv
) && !isLocalResource
) {
886 CopyUTF8toUTF16(host
, hostname
);
888 uri
->SchemeIs("https", &isHttps
);
891 if (!hostname
.IsEmpty() && nsHTMLDNSPrefetch::IsAllowed(mDocument
)) {
892 nsHTMLDNSPrefetch::PrefetchLow(
893 hostname
, isHttps
, mDocument
->NodePrincipal()->OriginAttributesRef());
897 void nsContentSink::Preconnect(const nsAString
& aHref
,
898 const nsAString
& aCrossOrigin
) {
899 // construct URI using document charset
900 auto encoding
= mDocument
->GetDocumentCharacterSet();
901 nsCOMPtr
<nsIURI
> uri
;
902 NS_NewURI(getter_AddRefs(uri
), aHref
, encoding
, mDocument
->GetDocBaseURI());
904 if (uri
&& mDocument
) {
905 mDocument
->MaybePreconnect(uri
,
906 dom::Element::StringToCORSMode(aCrossOrigin
));
910 nsresult
nsContentSink::SelectDocAppCache(
911 nsIApplicationCache
* aLoadApplicationCache
, nsIURI
* aManifestURI
,
912 bool aFetchedWithHTTPGetOrEquiv
, CacheSelectionAction
* aAction
) {
915 *aAction
= CACHE_SELECTION_NONE
;
917 if (aLoadApplicationCache
) {
918 nsCOMPtr
<nsIURI
> groupURI
;
919 rv
= aLoadApplicationCache
->GetManifestURI(getter_AddRefs(groupURI
));
920 NS_ENSURE_SUCCESS(rv
, rv
);
923 rv
= groupURI
->Equals(aManifestURI
, &equal
);
924 NS_ENSURE_SUCCESS(rv
, rv
);
927 // This is a foreign entry, force a reload to avoid loading the foreign
928 // entry. The entry will be marked as foreign to avoid loading it again.
930 *aAction
= CACHE_SELECTION_RELOAD
;
932 // The http manifest attribute URI is equal to the manifest URI of
933 // the cache the document was loaded from - associate the document with
934 // that cache and invoke the cache update process.
936 nsAutoCString docURISpec
, clientID
;
937 mDocumentURI
->GetAsciiSpec(docURISpec
);
938 aLoadApplicationCache
->GetClientID(clientID
);
939 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
941 ("Selection: assigning app cache %s to document %s",
942 clientID
.get(), docURISpec
.get()));
945 rv
= mDocument
->SetApplicationCache(aLoadApplicationCache
);
946 NS_ENSURE_SUCCESS(rv
, rv
);
948 // Document will be added as implicit entry to the cache as part of
949 // the update process.
950 *aAction
= CACHE_SELECTION_UPDATE
;
953 // The document was not loaded from an application cache
954 // Here we know the manifest has the same origin as the
955 // document. There is call to CheckMayLoad() on it above.
957 if (!aFetchedWithHTTPGetOrEquiv
) {
958 // The document was not loaded using HTTP GET or equivalent
959 // method. The spec says to run the cache selection algorithm w/o
960 // the manifest specified.
961 *aAction
= CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST
;
963 // Always do an update in this case
964 *aAction
= CACHE_SELECTION_UPDATE
;
971 nsresult
nsContentSink::SelectDocAppCacheNoManifest(
972 nsIApplicationCache
* aLoadApplicationCache
, nsIURI
** aManifestURI
,
973 CacheSelectionAction
* aAction
) {
974 *aManifestURI
= nullptr;
975 *aAction
= CACHE_SELECTION_NONE
;
979 if (aLoadApplicationCache
) {
980 // The document was loaded from an application cache, use that
981 // application cache as the document's application cache.
983 nsAutoCString docURISpec
, clientID
;
984 mDocumentURI
->GetAsciiSpec(docURISpec
);
985 aLoadApplicationCache
->GetClientID(clientID
);
986 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
988 ("Selection, no manifest: assigning app cache %s to document %s",
989 clientID
.get(), docURISpec
.get()));
992 rv
= mDocument
->SetApplicationCache(aLoadApplicationCache
);
993 NS_ENSURE_SUCCESS(rv
, rv
);
995 // Return the uri and invoke the update process for the selected
996 // application cache.
997 rv
= aLoadApplicationCache
->GetManifestURI(aManifestURI
);
998 NS_ENSURE_SUCCESS(rv
, rv
);
1000 *aAction
= CACHE_SELECTION_UPDATE
;
1006 void nsContentSink::ProcessOfflineManifest(nsIContent
* aElement
) {
1007 // Only check the manifest for root document nodes.
1008 if (aElement
!= mDocument
->GetRootElement()) {
1012 // Don't bother processing offline manifest for documents
1013 // without a docshell
1018 // Check for a manifest= attribute.
1019 nsAutoString manifestSpec
;
1020 aElement
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::manifest
,
1022 ProcessOfflineManifest(manifestSpec
);
1025 void nsContentSink::ProcessOfflineManifest(const nsAString
& aManifestSpec
) {
1026 // Don't bother processing offline manifest for documents
1027 // without a docshell
1032 // If this document has been interecepted, let's skip the processing of the
1034 if (mDocument
->GetController().isSome()) {
1038 // If the docshell's in private browsing mode, we don't want to do any
1039 // manifest processing.
1040 nsCOMPtr
<nsILoadContext
> loadContext
= do_QueryInterface(mDocShell
);
1041 if (loadContext
->UsePrivateBrowsing()) {
1047 // Grab the application cache the document was loaded from, if any.
1048 nsCOMPtr
<nsIApplicationCache
> applicationCache
;
1050 nsCOMPtr
<nsIApplicationCacheChannel
> applicationCacheChannel
=
1051 do_QueryInterface(mDocument
->GetChannel());
1052 if (applicationCacheChannel
) {
1053 bool loadedFromApplicationCache
;
1054 rv
= applicationCacheChannel
->GetLoadedFromApplicationCache(
1055 &loadedFromApplicationCache
);
1056 if (NS_FAILED(rv
)) {
1060 if (loadedFromApplicationCache
) {
1061 rv
= applicationCacheChannel
->GetApplicationCache(
1062 getter_AddRefs(applicationCache
));
1063 if (NS_FAILED(rv
)) {
1069 if (aManifestSpec
.IsEmpty() && !applicationCache
) {
1070 // Not loaded from an application cache, and no manifest
1071 // attribute. Nothing to do here.
1075 CacheSelectionAction action
= CACHE_SELECTION_NONE
;
1076 nsCOMPtr
<nsIURI
> manifestURI
;
1078 if (aManifestSpec
.IsEmpty()) {
1079 action
= CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST
;
1081 nsContentUtils::NewURIWithDocumentCharset(
1082 getter_AddRefs(manifestURI
), aManifestSpec
, mDocument
, mDocumentURI
);
1087 // Documents must list a manifest from the same origin
1088 rv
= mDocument
->NodePrincipal()->CheckMayLoad(manifestURI
, true, false);
1089 if (NS_FAILED(rv
)) {
1090 action
= CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST
;
1092 // Only continue if the document has permission to use offline APIs or
1093 // when preferences indicate to permit it automatically.
1094 if (!nsContentUtils::OfflineAppAllowed(mDocument
->NodePrincipal()) &&
1095 !nsContentUtils::MaybeAllowOfflineAppByDefault(
1096 mDocument
->NodePrincipal()) &&
1097 !nsContentUtils::OfflineAppAllowed(mDocument
->NodePrincipal())) {
1101 bool fetchedWithHTTPGetOrEquiv
= false;
1102 nsCOMPtr
<nsIHttpChannel
> httpChannel(
1103 do_QueryInterface(mDocument
->GetChannel()));
1105 nsAutoCString method
;
1106 rv
= httpChannel
->GetRequestMethod(method
);
1107 if (NS_SUCCEEDED(rv
))
1108 fetchedWithHTTPGetOrEquiv
= method
.EqualsLiteral("GET");
1111 rv
= SelectDocAppCache(applicationCache
, manifestURI
,
1112 fetchedWithHTTPGetOrEquiv
, &action
);
1113 if (NS_FAILED(rv
)) {
1119 if (action
== CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST
) {
1120 rv
= SelectDocAppCacheNoManifest(applicationCache
,
1121 getter_AddRefs(manifestURI
), &action
);
1122 if (NS_FAILED(rv
)) {
1128 case CACHE_SELECTION_NONE
:
1130 case CACHE_SELECTION_UPDATE
: {
1131 nsCOMPtr
<nsIOfflineCacheUpdateService
> updateService
=
1132 components::OfflineCacheUpdate::Service();
1134 if (updateService
) {
1135 updateService
->ScheduleOnDocumentStop(
1136 manifestURI
, mDocumentURI
, mDocument
->NodePrincipal(), mDocument
);
1140 case CACHE_SELECTION_RELOAD
: {
1141 // This situation occurs only for toplevel documents, see bottom
1142 // of SelectDocAppCache method.
1143 // The document has been loaded from a different offline cache group than
1144 // the manifest it refers to, i.e. this is a foreign entry, mark it as
1145 // such and force a reload to avoid loading it. The next attempt will not
1148 applicationCacheChannel
->MarkOfflineCacheEntryAsForeign();
1150 nsCOMPtr
<nsIWebNavigation
> webNav
= do_QueryInterface(mDocShell
);
1152 webNav
->Stop(nsIWebNavigation::STOP_ALL
);
1153 webNav
->Reload(nsIWebNavigation::LOAD_FLAGS_NONE
);
1158 "Cache selection algorithm didn't decide on proper action");
1163 void nsContentSink::ScrollToRef() {
1164 RefPtr
<Document
> document
= mDocument
;
1165 document
->ScrollToRef();
1168 void nsContentSink::StartLayout(bool aIgnorePendingSheets
) {
1169 AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("nsContentSink::StartLayout", LAYOUT
,
1170 mDocumentURI
->GetSpecOrDefault());
1172 if (mLayoutStarted
) {
1173 // Nothing to do here
1177 mDeferredLayoutStart
= true;
1179 if (!aIgnorePendingSheets
&&
1180 (WaitForPendingSheets() || mDocument
->HasPendingInitialTranslation())) {
1181 // Bail out; we'll start layout when the sheets and l10n load
1185 mDeferredLayoutStart
= false;
1187 // Notify on all our content. If none of our presshells have started layout
1188 // yet it'll be a no-op except for updating our data structures, a la
1189 // UpdateChildCounts() (because we don't want to double-notify on whatever we
1190 // have right now). If some of them _have_ started layout, we want to make
1191 // sure to flush tags instead of just calling UpdateChildCounts() after we
1192 // loop over the shells.
1195 mLayoutStarted
= true;
1196 mLastNotificationTime
= PR_Now();
1198 mDocument
->SetMayStartLayout(true);
1199 RefPtr
<PresShell
> presShell
= mDocument
->GetPresShell();
1200 // Make sure we don't call Initialize() for a shell that has
1201 // already called it. This can happen when the layout frame for
1202 // an iframe is constructed *between* the Embed() call for the
1203 // docshell in the iframe, and the content sink's call to OpenBody().
1205 if (presShell
&& !presShell
->DidInitialize()) {
1206 nsresult rv
= presShell
->Initialize();
1207 if (NS_FAILED(rv
)) {
1212 // If the document we are loading has a reference or it is a
1213 // frameset document, disable the scroll bars on the views.
1215 mDocument
->SetScrollToRef(mDocument
->GetDocumentURI());
1218 void nsContentSink::NotifyAppend(nsIContent
* aContainer
, uint32_t aStartIndex
) {
1222 // Scope so we call EndUpdate before we decrease mInNotification
1224 // Note that aContainer->OwnerDoc() may not be mDocument.
1225 MOZ_AUTO_DOC_UPDATE(aContainer
->OwnerDoc(), true);
1226 nsNodeUtils::ContentAppended(
1227 aContainer
, aContainer
->GetChildAt_Deprecated(aStartIndex
));
1228 mLastNotificationTime
= PR_Now();
1235 nsContentSink::Notify(nsITimer
* timer
) {
1237 // We shouldn't interfere with our normal DidProcessAToken logic
1238 mDroppedTimer
= true;
1242 if (WaitForPendingSheets()) {
1243 mDeferredFlushTags
= true;
1247 // Now try and scroll to the reference
1248 // XXX Should we scroll unconditionally for history loads??
1252 mNotificationTimer
= nullptr;
1256 bool nsContentSink::IsTimeToNotify() {
1257 if (!sNotifyOnTimer
|| !mLayoutStarted
|| !mBackoffCount
||
1258 mInMonolithicContainer
) {
1262 if (WaitForPendingSheets()) {
1263 mDeferredFlushTags
= true;
1267 PRTime now
= PR_Now();
1269 int64_t interval
= GetNotificationInterval();
1270 int64_t diff
= now
- mLastNotificationTime
;
1272 if (diff
> interval
) {
1280 nsresult
nsContentSink::WillInterruptImpl() {
1281 nsresult result
= NS_OK
;
1283 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
1284 SINK_TRACE_CALLS
, ("nsContentSink::WillInterrupt: this=%p", this));
1285 #ifndef SINK_NO_INCREMENTAL
1286 if (WaitForPendingSheets()) {
1287 mDeferredFlushTags
= true;
1288 } else if (sNotifyOnTimer
&& mLayoutStarted
) {
1289 if (mBackoffCount
&& !mInMonolithicContainer
) {
1290 int64_t now
= PR_Now();
1291 int64_t interval
= GetNotificationInterval();
1292 int64_t diff
= now
- mLastNotificationTime
;
1294 // If it's already time for us to have a notification
1295 if (diff
> interval
|| mDroppedTimer
) {
1297 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
1299 ("nsContentSink::WillInterrupt: flushing tags since we've "
1300 "run out time; backoff count: %d",
1302 result
= FlushTags();
1303 if (mDroppedTimer
) {
1305 mDroppedTimer
= false;
1307 } else if (!mNotificationTimer
) {
1309 int32_t delay
= interval
;
1311 // Convert to milliseconds
1312 delay
/= PR_USEC_PER_MSEC
;
1314 NS_NewTimerWithCallback(getter_AddRefs(mNotificationTimer
), this, delay
,
1315 nsITimer::TYPE_ONE_SHOT
);
1316 if (mNotificationTimer
) {
1317 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
1319 ("nsContentSink::WillInterrupt: setting up timer with "
1326 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
1328 ("nsContentSink::WillInterrupt: flushing tags "
1329 "unconditionally"));
1330 result
= FlushTags();
1339 nsresult
nsContentSink::WillResumeImpl() {
1340 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
1341 SINK_TRACE_CALLS
, ("nsContentSink::WillResume: this=%p", this));
1348 nsresult
nsContentSink::DidProcessATokenImpl() {
1349 if (mRunsToCompletion
|| !mParser
) {
1353 // Get the current user event time
1354 PresShell
* presShell
= mDocument
->GetPresShell();
1356 // If there's no pres shell in the document, return early since
1357 // we're not laying anything out here.
1361 // Increase before comparing to gEventProbeRate
1364 // Check if there's a pending event
1365 if (sPendingEventMode
!= 0 && !mHasPendingEvent
&&
1366 (mDeflectedCount
% sEventProbeRate
) == 0) {
1367 nsViewManager
* vm
= presShell
->GetViewManager();
1368 NS_ENSURE_TRUE(vm
, NS_ERROR_FAILURE
);
1369 nsCOMPtr
<nsIWidget
> widget
;
1370 vm
->GetRootWidget(getter_AddRefs(widget
));
1371 mHasPendingEvent
= widget
&& widget
->HasPendingInputEvent();
1374 if (mHasPendingEvent
&& sPendingEventMode
== 2) {
1375 return NS_ERROR_HTMLPARSER_INTERRUPTED
;
1378 // Have we processed enough tokens to check time?
1379 if (!mHasPendingEvent
&&
1380 mDeflectedCount
< uint32_t(mDynamicLowerValue
? sInteractiveDeflectCount
1381 : sPerfDeflectCount
)) {
1385 mDeflectedCount
= 0;
1387 // Check if it's time to return to the main event loop
1388 if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime
) {
1389 return NS_ERROR_HTMLPARSER_INTERRUPTED
;
1395 //----------------------------------------------------------------------
1397 void nsContentSink::FavorPerformanceHint(bool perfOverStarvation
,
1398 uint32_t starvationDelay
) {
1399 static NS_DEFINE_CID(kAppShellCID
, NS_APPSHELL_CID
);
1400 nsCOMPtr
<nsIAppShell
> appShell
= do_GetService(kAppShellCID
);
1402 appShell
->FavorPerformanceHint(perfOverStarvation
, starvationDelay
);
1405 void nsContentSink::BeginUpdate(Document
* aDocument
) {
1406 // Remember nested updates from updates that we started.
1407 if (mInNotification
> 0 && mUpdatesInNotification
< 2) {
1408 ++mUpdatesInNotification
;
1411 // If we're in a script and we didn't do the notification,
1412 // something else in the script processing caused the
1413 // notification to occur. Since this could result in frame
1414 // creation, make sure we've flushed everything before we
1417 if (!mInNotification
++) {
1422 void nsContentSink::EndUpdate(Document
* aDocument
) {
1423 // If we're in a script and we didn't do the notification,
1424 // something else in the script processing caused the
1425 // notification to occur. Update our notion of how much
1426 // has been flushed to include any new content if ending
1427 // this update leaves us not inside a notification.
1428 if (!--mInNotification
) {
1429 UpdateChildCounts();
1433 void nsContentSink::DidBuildModelImpl(bool aTerminated
) {
1435 MOZ_ASSERT(aTerminated
|| mDocument
->GetReadyStateEnum() ==
1436 Document::READYSTATE_LOADING
,
1438 mDocument
->SetReadyStateInternal(Document::READYSTATE_INTERACTIVE
);
1441 if (mScriptLoader
) {
1442 mScriptLoader
->ParsingComplete(aTerminated
);
1445 if (!mDocument
->HaveFiredDOMTitleChange()) {
1446 mDocument
->NotifyPossibleTitleChange(false);
1449 // Cancel a timer if we had one out there
1450 if (mNotificationTimer
) {
1451 SINK_TRACE(static_cast<LogModule
*>(gContentSinkLogModuleInfo
),
1453 ("nsContentSink::DidBuildModel: canceling notification "
1455 mNotificationTimer
->Cancel();
1456 mNotificationTimer
= nullptr;
1460 void nsContentSink::DropParserAndPerfHint(void) {
1462 // Make sure we don't unblock unload too many times
1467 // Do this hack to make sure that the parser
1468 // doesn't get destroyed, accidently, before
1469 // the circularity, between sink & parser, is
1471 // Drop our reference to the parser to get rid of a circular
1473 RefPtr
<nsParserBase
> kungFuDeathGrip(mParser
.forget());
1475 if (mDynamicLowerValue
) {
1476 // Reset the performance hint which was set to FALSE
1477 // when mDynamicLowerValue was set.
1478 FavorPerformanceHint(true, 0);
1481 // Call UnblockOnload only if mRunsToComletion is false and if
1482 // we have already started loading because it's possible that this function
1483 // is called (i.e. the parser is terminated) before we start loading due to
1484 // destroying the window inside unload event callbacks for the previous
1486 if (!mRunsToCompletion
&& mIsBlockingOnload
) {
1487 mDocument
->UnblockOnload(true);
1488 mIsBlockingOnload
= false;
1492 bool nsContentSink::IsScriptExecutingImpl() {
1493 return !!mScriptLoader
->GetCurrentScript();
1496 nsresult
nsContentSink::WillParseImpl(void) {
1497 if (mRunsToCompletion
|| !mDocument
) {
1501 PresShell
* presShell
= mDocument
->GetPresShell();
1506 uint32_t currentTime
= PR_IntervalToMicroseconds(PR_IntervalNow());
1508 if (sEnablePerfMode
== 0) {
1509 nsViewManager
* vm
= presShell
->GetViewManager();
1510 NS_ENSURE_TRUE(vm
, NS_ERROR_FAILURE
);
1511 uint32_t lastEventTime
;
1512 vm
->GetLastUserEventTime(lastEventTime
);
1515 mDocument
->IsInBackgroundWindow() ||
1516 ((currentTime
- mBeginLoadTime
) > uint32_t(sInitialPerfTime
) &&
1517 (currentTime
- lastEventTime
) < uint32_t(sInteractiveTime
));
1519 if (mDynamicLowerValue
!= newDynLower
) {
1520 FavorPerformanceHint(!newDynLower
, 0);
1521 mDynamicLowerValue
= newDynLower
;
1525 mDeflectedCount
= 0;
1526 mHasPendingEvent
= false;
1528 mCurrentParseEndTime
=
1530 (mDynamicLowerValue
? sInteractiveParseTime
: sPerfParseTime
);
1535 void nsContentSink::WillBuildModelImpl() {
1536 if (!mRunsToCompletion
) {
1537 mDocument
->BlockOnload();
1538 mIsBlockingOnload
= true;
1540 mBeginLoadTime
= PR_IntervalToMicroseconds(PR_IntervalNow());
1543 mDocument
->ResetScrolledToRefAlready();
1545 if (mProcessLinkHeaderEvent
.get()) {
1546 mProcessLinkHeaderEvent
.Revoke();
1548 DoProcessLinkHeader();
1553 void nsContentSink::NotifyDocElementCreated(Document
* aDoc
) {
1554 MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
1556 nsCOMPtr
<nsIObserverService
> observerService
=
1557 mozilla::services::GetObserverService();
1558 MOZ_ASSERT(observerService
);
1560 auto* win
= nsGlobalWindowInner::Cast(aDoc
->GetInnerWindow());
1561 bool fireInitialInsertion
= !win
|| !win
->DidFireDocElemInserted();
1563 win
->SetDidFireDocElemInserted();
1565 if (fireInitialInsertion
) {
1566 observerService
->NotifyObservers(ToSupports(aDoc
),
1567 "initial-document-element-inserted",
1568 EmptyString().get());
1570 observerService
->NotifyObservers(
1571 ToSupports(aDoc
), "document-element-inserted", EmptyString().get());
1573 nsContentUtils::DispatchChromeEvent(
1574 aDoc
, ToSupports(aDoc
), NS_LITERAL_STRING("DOMDocElementInserted"),
1575 CanBubble::eYes
, Cancelable::eNo
);
1579 nsContentSink::GetName(nsACString
& aName
) {
1580 aName
.AssignLiteral("nsContentSink_timer");