Line data Source code
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/. */
6 :
7 : /*
8 : * Base class for the XML and HTML content sinks, which construct a
9 : * DOM based on information from the parser.
10 : */
11 :
12 : #ifndef _nsContentSink_h_
13 : #define _nsContentSink_h_
14 :
15 : // Base class for contentsink implementations.
16 :
17 : #include "mozilla/Attributes.h"
18 : #include "nsICSSLoaderObserver.h"
19 : #include "nsWeakReference.h"
20 : #include "nsCOMPtr.h"
21 : #include "nsString.h"
22 : #include "nsAutoPtr.h"
23 : #include "nsGkAtoms.h"
24 : #include "nsITimer.h"
25 : #include "nsStubDocumentObserver.h"
26 : #include "nsIContentSink.h"
27 : #include "mozilla/Logging.h"
28 : #include "nsCycleCollectionParticipant.h"
29 : #include "nsThreadUtils.h"
30 :
31 : class nsIDocument;
32 : class nsIURI;
33 : class nsIChannel;
34 : class nsIDocShell;
35 : class nsIAtom;
36 : class nsIChannel;
37 : class nsIContent;
38 : class nsNodeInfoManager;
39 : class nsIApplicationCache;
40 :
41 : namespace mozilla {
42 : namespace css {
43 : class Loader;
44 : } // namespace css
45 :
46 : namespace dom {
47 : class ScriptLoader;
48 : } // namespace dom
49 : } // namespace mozilla
50 :
51 : #ifdef DEBUG
52 :
53 : extern mozilla::LazyLogModule gContentSinkLogModuleInfo;
54 :
55 : #define SINK_TRACE_CALLS 0x1
56 : #define SINK_TRACE_REFLOW 0x2
57 : #define SINK_ALWAYS_REFLOW 0x4
58 :
59 : #define SINK_LOG_TEST(_lm, _bit) (int((_lm)->Level()) & (_bit))
60 :
61 : #define SINK_TRACE(_lm, _bit, _args) \
62 : do { \
63 : if (SINK_LOG_TEST(_lm, _bit)) { \
64 : printf_stderr _args; \
65 : } \
66 : } while(0)
67 :
68 : #else
69 : #define SINK_TRACE(_lm, _bit, _args)
70 : #endif
71 :
72 : #undef SINK_NO_INCREMENTAL
73 :
74 : //----------------------------------------------------------------------
75 :
76 : class nsContentSink : public nsICSSLoaderObserver,
77 : public nsSupportsWeakReference,
78 : public nsStubDocumentObserver,
79 : public nsITimerCallback,
80 : public nsINamed
81 : {
82 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
83 1771 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink,
84 : nsICSSLoaderObserver)
85 : // nsITimerCallback
86 : NS_DECL_NSITIMERCALLBACK
87 :
88 : NS_DECL_NSINAMED
89 :
90 : // nsICSSLoaderObserver
91 : NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
92 : bool aWasAlternate,
93 : nsresult aStatus) override;
94 :
95 : virtual nsresult ProcessMETATag(nsIContent* aContent);
96 :
97 : // nsIContentSink implementation helpers
98 : nsresult WillParseImpl(void);
99 : nsresult WillInterruptImpl(void);
100 : nsresult WillResumeImpl(void);
101 : nsresult DidProcessATokenImpl(void);
102 : void WillBuildModelImpl(void);
103 : void DidBuildModelImpl(bool aTerminated);
104 : void DropParserAndPerfHint(void);
105 : bool IsScriptExecutingImpl();
106 :
107 : void NotifyAppend(nsIContent* aContent, uint32_t aStartIndex);
108 :
109 : // nsIDocumentObserver
110 : NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE
111 : NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE
112 :
113 : virtual void UpdateChildCounts() = 0;
114 :
115 : bool IsTimeToNotify();
116 : bool LinkContextIsOurDocument(const nsAString& aAnchor);
117 : bool Decode5987Format(nsAString& aEncoded);
118 :
119 : static void InitializeStatics();
120 :
121 : protected:
122 : nsContentSink();
123 : virtual ~nsContentSink();
124 :
125 : enum CacheSelectionAction {
126 : // There is no offline cache manifest specified by the document,
127 : // or the document was loaded from a cache other than the one it
128 : // specifies via its manifest attribute and IS NOT a top-level
129 : // document, or an error occurred during the cache selection
130 : // algorithm.
131 : CACHE_SELECTION_NONE = 0,
132 :
133 : // The offline cache manifest must be updated.
134 : CACHE_SELECTION_UPDATE = 1,
135 :
136 : // The document was loaded from a cache other than the one it
137 : // specifies via its manifest attribute and IS a top-level
138 : // document. In this case, the document is marked as foreign in
139 : // the cache it was loaded from and must be reloaded from the
140 : // correct cache (the one it specifies).
141 : CACHE_SELECTION_RELOAD = 2,
142 :
143 : // Some conditions require we must reselect the cache without the manifest
144 : CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST = 3
145 : };
146 :
147 : nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
148 : nsISupports* aContainer, nsIChannel* aChannel);
149 :
150 : nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
151 : nsresult ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue,
152 : nsIContent* aContent = nullptr);
153 : nsresult ProcessLinkHeader(const nsAString& aLinkData);
154 : nsresult ProcessLink(const nsAString& aAnchor,
155 : const nsAString& aHref, const nsAString& aRel,
156 : const nsAString& aTitle, const nsAString& aType,
157 : const nsAString& aMedia, const nsAString& aCrossOrigin,
158 : const nsAString& aAs);
159 :
160 : virtual nsresult ProcessStyleLink(nsIContent* aElement,
161 : const nsAString& aHref,
162 : bool aAlternate,
163 : const nsAString& aTitle,
164 : const nsAString& aType,
165 : const nsAString& aMedia);
166 :
167 : void PrefetchPreloadHref(const nsAString &aHref, nsINode *aSource,
168 : uint32_t aLinkTypes, const nsAString& aAs,
169 : const nsAString& aType,
170 : const nsAString& aMedia);
171 :
172 : // For PrefetchDNS() aHref can either be the usual
173 : // URI format or of the form "//www.hostname.com" without a scheme.
174 : void PrefetchDNS(const nsAString &aHref);
175 :
176 : // Gets the cache key (used to identify items in a cache) of the channel.
177 : nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey);
178 :
179 : // There is an offline cache manifest attribute specified and the
180 : // document is allowed to use the offline cache. Process the cache
181 : // selection algorithm for this document and the manifest. Result is
182 : // an action that must be taken on the manifest, see
183 : // CacheSelectionAction enum above.
184 : //
185 : // @param aLoadApplicationCache
186 : // The application cache from which the load originated, if
187 : // any.
188 : // @param aManifestURI
189 : // The manifest URI listed in the document.
190 : // @param aFetchedWithHTTPGetOrEquiv
191 : // TRUE if this was fetched using the HTTP GET method.
192 : // @param aAction
193 : // Out parameter, returns the action that should be performed
194 : // by the calling function.
195 : nsresult SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
196 : nsIURI *aManifestURI,
197 : bool aFetchedWithHTTPGetOrEquiv,
198 : CacheSelectionAction *aAction);
199 :
200 : // There is no offline cache manifest attribute specified. Process
201 : // the cache selection algorithm w/o the manifest. Result is an
202 : // action that must be taken, see CacheSelectionAction enum
203 : // above. In case the offline cache manifest has to be updated the
204 : // manifest URI is returned in aManifestURI.
205 : //
206 : // @param aLoadApplicationCache
207 : // The application cache from which the load originated, if
208 : // any.
209 : // @param aManifestURI
210 : // Out parameter, returns the manifest URI of the cache that
211 : // was selected.
212 : // @param aAction
213 : // Out parameter, returns the action that should be performed
214 : // by the calling function.
215 : nsresult SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache,
216 : nsIURI **aManifestURI,
217 : CacheSelectionAction *aAction);
218 :
219 : public:
220 : // Searches for the offline cache manifest attribute and calls one
221 : // of the above defined methods to select the document's application
222 : // cache, let it be associated with the document and eventually
223 : // schedule the cache update process.
224 : // This method MUST be called with the empty string as the argument
225 : // when there is no manifest attribute!
226 : void ProcessOfflineManifest(const nsAString& aManifestSpec);
227 :
228 : // Extracts the manifest attribute from the element if it is the root
229 : // element and calls the above method.
230 : void ProcessOfflineManifest(nsIContent *aElement);
231 :
232 : // For Preconnect() aHref can either be the usual
233 : // URI format or of the form "//www.hostname.com" without a scheme.
234 : void Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin);
235 :
236 : protected:
237 : // Tries to scroll to the URI's named anchor. Once we've successfully
238 : // done that, further calls to this method will be ignored.
239 : void ScrollToRef();
240 :
241 : // Start layout. If aIgnorePendingSheets is true, this will happen even if
242 : // we still have stylesheet loads pending. Otherwise, we'll wait until the
243 : // stylesheets are all done loading.
244 : public:
245 : void StartLayout(bool aIgnorePendingSheets);
246 :
247 : static void NotifyDocElementCreated(nsIDocument* aDoc);
248 :
249 : protected:
250 : void
251 : FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay);
252 :
253 242 : inline int32_t GetNotificationInterval()
254 : {
255 242 : if (mDynamicLowerValue) {
256 13 : return 1000;
257 : }
258 :
259 229 : return sNotificationInterval;
260 : }
261 :
262 : virtual nsresult FlushTags() = 0;
263 :
264 : // Later on we might want to make this more involved somehow
265 : // (e.g. stop waiting after some timeout or whatnot).
266 268 : bool WaitForPendingSheets() { return mPendingSheetCount > 0; }
267 :
268 : void DoProcessLinkHeader();
269 :
270 5 : void StopDeflecting() {
271 5 : mDeflectedCount = sPerfDeflectCount;
272 5 : }
273 :
274 : protected:
275 :
276 : nsCOMPtr<nsIDocument> mDocument;
277 : RefPtr<nsParserBase> mParser;
278 : nsCOMPtr<nsIURI> mDocumentURI;
279 : nsCOMPtr<nsIDocShell> mDocShell;
280 : RefPtr<mozilla::css::Loader> mCSSLoader;
281 : RefPtr<nsNodeInfoManager> mNodeInfoManager;
282 : RefPtr<mozilla::dom::ScriptLoader> mScriptLoader;
283 :
284 : // back off timer notification after count
285 : int32_t mBackoffCount;
286 :
287 : // Time of last notification
288 : // Note: mLastNotificationTime is only valid once mLayoutStarted is true.
289 : PRTime mLastNotificationTime;
290 :
291 : // Timer used for notification
292 : nsCOMPtr<nsITimer> mNotificationTimer;
293 :
294 : // Have we already called BeginUpdate for this set of content changes?
295 : uint8_t mBeganUpdate : 1;
296 : uint8_t mLayoutStarted : 1;
297 : uint8_t mDynamicLowerValue : 1;
298 : uint8_t mParsing : 1;
299 : uint8_t mDroppedTimer : 1;
300 : // If true, we deferred starting layout until sheets load
301 : uint8_t mDeferredLayoutStart : 1;
302 : // If true, we deferred notifications until sheets load
303 : uint8_t mDeferredFlushTags : 1;
304 : // If false, we're not ourselves a document observer; that means we
305 : // shouldn't be performing any more content model notifications,
306 : // since we're not longer updating our child counts.
307 : uint8_t mIsDocumentObserver : 1;
308 : // True if this is parser is a fragment parser or an HTML DOMParser.
309 : // XML DOMParser leaves this to false for now!
310 : uint8_t mRunsToCompletion : 1;
311 :
312 : //
313 : // -- Can interrupt parsing members --
314 : //
315 :
316 : // The number of tokens that have been processed since we measured
317 : // if it's time to return to the main event loop.
318 : uint32_t mDeflectedCount;
319 :
320 : // Is there currently a pending event?
321 : bool mHasPendingEvent;
322 :
323 : // When to return to the main event loop
324 : uint32_t mCurrentParseEndTime;
325 :
326 : int32_t mBeginLoadTime;
327 :
328 : // Last mouse event or keyboard event time sampled by the content
329 : // sink
330 : uint32_t mLastSampledUserEventTime;
331 :
332 : int32_t mInMonolithicContainer;
333 :
334 : int32_t mInNotification;
335 : uint32_t mUpdatesInNotification;
336 :
337 : uint32_t mPendingSheetCount;
338 :
339 : nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> >
340 : mProcessLinkHeaderEvent;
341 :
342 : // Do we notify based on time?
343 : static bool sNotifyOnTimer;
344 : // Back off timer notification after count.
345 : static int32_t sBackoffCount;
346 : // Notification interval in microseconds
347 : static int32_t sNotificationInterval;
348 : // How many times to deflect in interactive/perf modes
349 : static int32_t sInteractiveDeflectCount;
350 : static int32_t sPerfDeflectCount;
351 : // 0 = don't check for pending events
352 : // 1 = don't deflect if there are pending events
353 : // 2 = bail if there are pending events
354 : static int32_t sPendingEventMode;
355 : // How often to probe for pending events. 1=every token
356 : static int32_t sEventProbeRate;
357 : // How long to stay off the event loop in interactive/perf modes
358 : static int32_t sInteractiveParseTime;
359 : static int32_t sPerfParseTime;
360 : // How long to be in interactive mode after an event
361 : static int32_t sInteractiveTime;
362 : // How long to stay in perf mode after initial loading
363 : static int32_t sInitialPerfTime;
364 : // Should we switch between perf-mode and interactive-mode
365 : static int32_t sEnablePerfMode;
366 : };
367 :
368 : #endif // _nsContentSink_h_
|