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 #ifndef _nsContentSink_h_
13 #define _nsContentSink_h_
15 // Base class for contentsink implementations.
17 #include "mozilla/Attributes.h"
18 #include "nsICSSLoaderObserver.h"
19 #include "nsWeakReference.h"
22 #include "nsGkAtoms.h"
24 #include "nsStubDocumentObserver.h"
25 #include "nsIContentSink.h"
26 #include "mozilla/Logging.h"
27 #include "nsCycleCollectionParticipant.h"
28 #include "nsThreadUtils.h"
29 #include "mozilla/StaticPrefs_content.h"
37 class nsNodeInfoManager
;
38 class nsIApplicationCache
;
49 } // namespace mozilla
53 extern mozilla::LazyLogModule gContentSinkLogModuleInfo
;
55 # define SINK_TRACE_CALLS 0x1
56 # define SINK_TRACE_REFLOW 0x2
57 # define SINK_ALWAYS_REFLOW 0x4
59 # define SINK_LOG_TEST(_lm, _bit) (int((_lm)->Level()) & (_bit))
61 # define SINK_TRACE(_lm, _bit, _args) \
63 if (SINK_LOG_TEST(_lm, _bit)) { \
64 printf_stderr _args; \
69 # define SINK_TRACE(_lm, _bit, _args)
72 #undef SINK_NO_INCREMENTAL
74 //----------------------------------------------------------------------
76 class nsContentSink
: public nsICSSLoaderObserver
,
77 public nsSupportsWeakReference
,
78 public nsStubDocumentObserver
,
79 public nsITimerCallback
,
82 typedef mozilla::dom::Document Document
;
85 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
86 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink
, nsICSSLoaderObserver
)
88 NS_DECL_NSITIMERCALLBACK
92 // nsICSSLoaderObserver
93 NS_IMETHOD
StyleSheetLoaded(mozilla::StyleSheet
* aSheet
, bool aWasDeferred
,
94 nsresult aStatus
) override
;
96 // nsIContentSink implementation helpers
97 nsresult
WillParseImpl(void);
98 nsresult
WillInterruptImpl(void);
99 nsresult
WillResumeImpl(void);
100 nsresult
DidProcessATokenImpl(void);
101 void WillBuildModelImpl(void);
102 void DidBuildModelImpl(bool aTerminated
);
103 void DropParserAndPerfHint(void);
104 bool IsScriptExecutingImpl();
106 void NotifyAppend(nsIContent
* aContent
, uint32_t aStartIndex
);
108 // nsIDocumentObserver
109 NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
110 NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
112 virtual void UpdateChildCounts() = 0;
114 bool IsTimeToNotify();
115 bool LinkContextIsOurDocument(const nsAString
& aAnchor
);
116 bool Decode5987Format(nsAString
& aEncoded
);
120 virtual ~nsContentSink();
122 enum CacheSelectionAction
{
123 // There is no offline cache manifest specified by the document,
124 // or the document was loaded from a cache other than the one it
125 // specifies via its manifest attribute and IS NOT a top-level
126 // document, or an error occurred during the cache selection
128 CACHE_SELECTION_NONE
= 0,
130 // The offline cache manifest must be updated.
131 CACHE_SELECTION_UPDATE
= 1,
133 // The document was loaded from a cache other than the one it
134 // specifies via its manifest attribute and IS a top-level
135 // document. In this case, the document is marked as foreign in
136 // the cache it was loaded from and must be reloaded from the
137 // correct cache (the one it specifies).
138 CACHE_SELECTION_RELOAD
= 2,
140 // Some conditions require we must reselect the cache without the manifest
141 CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST
= 3
144 nsresult
Init(Document
* aDoc
, nsIURI
* aURI
, nsISupports
* aContainer
,
145 nsIChannel
* aChannel
);
147 nsresult
ProcessHTTPHeaders(nsIChannel
* aChannel
);
148 nsresult
ProcessLinkHeader(const nsAString
& aLinkData
);
149 nsresult
ProcessLinkFromHeader(
150 const nsAString
& aAnchor
, const nsAString
& aHref
, const nsAString
& aRel
,
151 const nsAString
& aTitle
, const nsAString
& aIntegrity
,
152 const nsAString
& aSrcset
, const nsAString
& aSizes
, const nsAString
& aType
,
153 const nsAString
& aMedia
, const nsAString
& aCrossOrigin
,
154 const nsAString
& aReferrerPolicy
, const nsAString
& aAs
);
156 virtual nsresult
ProcessStyleLinkFromHeader(
157 const nsAString
& aHref
, bool aAlternate
, const nsAString
& aTitle
,
158 const nsAString
& aIntegrity
, const nsAString
& aType
,
159 const nsAString
& aMedia
, const nsAString
& aReferrerPolicy
);
161 void PrefetchHref(const nsAString
& aHref
, const nsAString
& aAs
,
162 const nsAString
& aType
, const nsAString
& aMedia
);
163 void PreloadHref(const nsAString
& aHref
, const nsAString
& aAs
,
164 const nsAString
& aType
, const nsAString
& aMedia
,
165 const nsAString
& aIntegrity
, const nsAString
& aSrcset
,
166 const nsAString
& aSizes
, const nsAString
& aCORS
,
167 const nsAString
& aReferrerPolicy
);
169 // For PrefetchDNS() aHref can either be the usual
170 // URI format or of the form "//www.hostname.com" without a scheme.
171 void PrefetchDNS(const nsAString
& aHref
);
173 // Gets the cache key (used to identify items in a cache) of the channel.
174 nsresult
GetChannelCacheKey(nsIChannel
* aChannel
, nsACString
& aCacheKey
);
176 // There is an offline cache manifest attribute specified and the
177 // document is allowed to use the offline cache. Process the cache
178 // selection algorithm for this document and the manifest. Result is
179 // an action that must be taken on the manifest, see
180 // CacheSelectionAction enum above.
182 // @param aLoadApplicationCache
183 // The application cache from which the load originated, if
185 // @param aManifestURI
186 // The manifest URI listed in the document.
187 // @param aFetchedWithHTTPGetOrEquiv
188 // TRUE if this was fetched using the HTTP GET method.
190 // Out parameter, returns the action that should be performed
191 // by the calling function.
192 nsresult
SelectDocAppCache(nsIApplicationCache
* aLoadApplicationCache
,
193 nsIURI
* aManifestURI
,
194 bool aFetchedWithHTTPGetOrEquiv
,
195 CacheSelectionAction
* aAction
);
197 // There is no offline cache manifest attribute specified. Process
198 // the cache selection algorithm w/o the manifest. Result is an
199 // action that must be taken, see CacheSelectionAction enum
200 // above. In case the offline cache manifest has to be updated the
201 // manifest URI is returned in aManifestURI.
203 // @param aLoadApplicationCache
204 // The application cache from which the load originated, if
206 // @param aManifestURI
207 // Out parameter, returns the manifest URI of the cache that
210 // Out parameter, returns the action that should be performed
211 // by the calling function.
212 nsresult
SelectDocAppCacheNoManifest(
213 nsIApplicationCache
* aLoadApplicationCache
, nsIURI
** aManifestURI
,
214 CacheSelectionAction
* aAction
);
217 // Searches for the offline cache manifest attribute and calls one
218 // of the above defined methods to select the document's application
219 // cache, let it be associated with the document and eventually
220 // schedule the cache update process.
221 // This method MUST be called with the empty string as the argument
222 // when there is no manifest attribute!
223 void ProcessOfflineManifest(const nsAString
& aManifestSpec
);
225 // Extracts the manifest attribute from the element if it is the root
226 // element and calls the above method.
227 void ProcessOfflineManifest(nsIContent
* aElement
);
229 // For Preconnect() aHref can either be the usual
230 // URI format or of the form "//www.hostname.com" without a scheme.
231 void Preconnect(const nsAString
& aHref
, const nsAString
& aCrossOrigin
);
234 // Tries to scroll to the URI's named anchor. Once we've successfully
235 // done that, further calls to this method will be ignored.
236 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void ScrollToRef();
238 // Start layout. If aIgnorePendingSheets is true, this will happen even if
239 // we still have stylesheet loads pending. Otherwise, we'll wait until the
240 // stylesheets are all done loading.
242 void StartLayout(bool aIgnorePendingSheets
);
244 static void NotifyDocElementCreated(Document
* aDoc
);
246 Document
* GetDocument() { return mDocument
; }
249 void FavorPerformanceHint(bool perfOverStarvation
, uint32_t starvationDelay
);
251 inline int32_t GetNotificationInterval() {
252 if (mDynamicLowerValue
) {
256 return mozilla::StaticPrefs::content_notify_interval();
259 virtual nsresult
FlushTags() = 0;
261 // Later on we might want to make this more involved somehow
262 // (e.g. stop waiting after some timeout or whatnot).
263 bool WaitForPendingSheets() { return mPendingSheetCount
> 0; }
265 void DoProcessLinkHeader();
267 void StopDeflecting() {
268 mDeflectedCount
= mozilla::StaticPrefs::content_sink_perf_deflect_count();
272 RefPtr
<Document
> mDocument
;
273 RefPtr
<nsParserBase
> mParser
;
274 nsCOMPtr
<nsIURI
> mDocumentURI
;
275 nsCOMPtr
<nsIDocShell
> mDocShell
;
276 RefPtr
<mozilla::css::Loader
> mCSSLoader
;
277 RefPtr
<nsNodeInfoManager
> mNodeInfoManager
;
278 RefPtr
<mozilla::dom::ScriptLoader
> mScriptLoader
;
280 // back off timer notification after count
281 int32_t mBackoffCount
;
283 // Time of last notification
284 // Note: mLastNotificationTime is only valid once mLayoutStarted is true.
285 PRTime mLastNotificationTime
;
287 // Timer used for notification
288 nsCOMPtr
<nsITimer
> mNotificationTimer
;
290 uint8_t mLayoutStarted
: 1;
291 uint8_t mDynamicLowerValue
: 1;
292 uint8_t mParsing
: 1;
293 uint8_t mDroppedTimer
: 1;
294 // If true, we deferred starting layout until sheets load
295 uint8_t mDeferredLayoutStart
: 1;
296 // If true, we deferred notifications until sheets load
297 uint8_t mDeferredFlushTags
: 1;
298 // If false, we're not ourselves a document observer; that means we
299 // shouldn't be performing any more content model notifications,
300 // since we're not longer updating our child counts.
301 uint8_t mIsDocumentObserver
: 1;
302 // True if this is parser is a fragment parser or an HTML DOMParser.
303 // XML DOMParser leaves this to false for now!
304 uint8_t mRunsToCompletion
: 1;
305 // True if we are blocking load event.
306 bool mIsBlockingOnload
: 1;
309 // -- Can interrupt parsing members --
312 // The number of tokens that have been processed since we measured
313 // if it's time to return to the main event loop.
314 uint32_t mDeflectedCount
;
316 // Is there currently a pending event?
317 bool mHasPendingEvent
;
319 // When to return to the main event loop
320 uint32_t mCurrentParseEndTime
;
322 int32_t mBeginLoadTime
;
324 // Last mouse event or keyboard event time sampled by the content
326 uint32_t mLastSampledUserEventTime
;
328 int32_t mInMonolithicContainer
;
330 int32_t mInNotification
;
331 uint32_t mUpdatesInNotification
;
333 uint32_t mPendingSheetCount
;
335 nsRevocableEventPtr
<nsRunnableMethod
<nsContentSink
, void, false> >
336 mProcessLinkHeaderEvent
;
339 #endif // _nsContentSink_h_