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