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