1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/nsContentSink.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,363 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * Base class for the XML and HTML content sinks, which construct a 1.11 + * DOM based on information from the parser. 1.12 + */ 1.13 + 1.14 +#ifndef _nsContentSink_h_ 1.15 +#define _nsContentSink_h_ 1.16 + 1.17 +// Base class for contentsink implementations. 1.18 + 1.19 +#include "mozilla/Attributes.h" 1.20 +#include "nsICSSLoaderObserver.h" 1.21 +#include "nsWeakReference.h" 1.22 +#include "nsCOMPtr.h" 1.23 +#include "nsString.h" 1.24 +#include "nsAutoPtr.h" 1.25 +#include "nsGkAtoms.h" 1.26 +#include "nsITimer.h" 1.27 +#include "nsStubDocumentObserver.h" 1.28 +#include "nsIContentSink.h" 1.29 +#include "prlog.h" 1.30 +#include "nsCycleCollectionParticipant.h" 1.31 +#include "nsThreadUtils.h" 1.32 + 1.33 +class nsIDocument; 1.34 +class nsIURI; 1.35 +class nsIChannel; 1.36 +class nsIDocShell; 1.37 +class nsIParser; 1.38 +class nsIAtom; 1.39 +class nsIChannel; 1.40 +class nsIContent; 1.41 +class nsViewManager; 1.42 +class nsNodeInfoManager; 1.43 +class nsScriptLoader; 1.44 +class nsIApplicationCache; 1.45 + 1.46 +namespace mozilla { 1.47 +namespace css { 1.48 +class Loader; 1.49 +} 1.50 +} 1.51 + 1.52 +#ifdef DEBUG 1.53 + 1.54 +extern PRLogModuleInfo* gContentSinkLogModuleInfo; 1.55 + 1.56 +#define SINK_TRACE_CALLS 0x1 1.57 +#define SINK_TRACE_REFLOW 0x2 1.58 +#define SINK_ALWAYS_REFLOW 0x4 1.59 + 1.60 +#define SINK_LOG_TEST(_lm, _bit) (int((_lm)->level) & (_bit)) 1.61 + 1.62 +#define SINK_TRACE(_lm, _bit, _args) \ 1.63 + PR_BEGIN_MACRO \ 1.64 + if (SINK_LOG_TEST(_lm, _bit)) { \ 1.65 + PR_LogPrint _args; \ 1.66 + } \ 1.67 + PR_END_MACRO 1.68 + 1.69 +#else 1.70 +#define SINK_TRACE(_lm, _bit, _args) 1.71 +#endif 1.72 + 1.73 +#undef SINK_NO_INCREMENTAL 1.74 + 1.75 +//---------------------------------------------------------------------- 1.76 + 1.77 +// 1/2 second fudge factor for window creation 1.78 +#define NS_DELAY_FOR_WINDOW_CREATION 500000 1.79 + 1.80 +class nsContentSink : public nsICSSLoaderObserver, 1.81 + public nsSupportsWeakReference, 1.82 + public nsStubDocumentObserver, 1.83 + public nsITimerCallback 1.84 +{ 1.85 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.86 + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink, 1.87 + nsICSSLoaderObserver) 1.88 + // nsITimerCallback 1.89 + NS_DECL_NSITIMERCALLBACK 1.90 + 1.91 + // nsICSSLoaderObserver 1.92 + NS_IMETHOD StyleSheetLoaded(nsCSSStyleSheet* aSheet, bool aWasAlternate, 1.93 + nsresult aStatus) MOZ_OVERRIDE; 1.94 + 1.95 + virtual nsresult ProcessMETATag(nsIContent* aContent); 1.96 + 1.97 + // nsIContentSink implementation helpers 1.98 + NS_HIDDEN_(nsresult) WillParseImpl(void); 1.99 + NS_HIDDEN_(nsresult) WillInterruptImpl(void); 1.100 + NS_HIDDEN_(nsresult) WillResumeImpl(void); 1.101 + NS_HIDDEN_(nsresult) DidProcessATokenImpl(void); 1.102 + NS_HIDDEN_(void) WillBuildModelImpl(void); 1.103 + NS_HIDDEN_(void) DidBuildModelImpl(bool aTerminated); 1.104 + NS_HIDDEN_(void) DropParserAndPerfHint(void); 1.105 + bool IsScriptExecutingImpl(); 1.106 + 1.107 + void NotifyAppend(nsIContent* aContent, uint32_t aStartIndex); 1.108 + 1.109 + // nsIDocumentObserver 1.110 + NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE 1.111 + NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE 1.112 + 1.113 + virtual void UpdateChildCounts() = 0; 1.114 + 1.115 + bool IsTimeToNotify(); 1.116 + bool LinkContextIsOurDocument(const nsSubstring& aAnchor); 1.117 + bool Decode5987Format(nsAString& aEncoded); 1.118 + 1.119 + static void InitializeStatics(); 1.120 + 1.121 +protected: 1.122 + nsContentSink(); 1.123 + virtual ~nsContentSink(); 1.124 + 1.125 + enum CacheSelectionAction { 1.126 + // There is no offline cache manifest specified by the document, 1.127 + // or the document was loaded from a cache other than the one it 1.128 + // specifies via its manifest attribute and IS NOT a top-level 1.129 + // document, or an error occurred during the cache selection 1.130 + // algorithm. 1.131 + CACHE_SELECTION_NONE = 0, 1.132 + 1.133 + // The offline cache manifest must be updated. 1.134 + CACHE_SELECTION_UPDATE = 1, 1.135 + 1.136 + // The document was loaded from a cache other than the one it 1.137 + // specifies via its manifest attribute and IS a top-level 1.138 + // document. In this case, the document is marked as foreign in 1.139 + // the cache it was loaded from and must be reloaded from the 1.140 + // correct cache (the one it specifies). 1.141 + CACHE_SELECTION_RELOAD = 2, 1.142 + 1.143 + // Some conditions require we must reselect the cache without the manifest 1.144 + CACHE_SELECTION_RESELECT_WITHOUT_MANIFEST = 3 1.145 + }; 1.146 + 1.147 + nsresult Init(nsIDocument* aDoc, nsIURI* aURI, 1.148 + nsISupports* aContainer, nsIChannel* aChannel); 1.149 + 1.150 + nsresult ProcessHTTPHeaders(nsIChannel* aChannel); 1.151 + nsresult ProcessHeaderData(nsIAtom* aHeader, const nsAString& aValue, 1.152 + nsIContent* aContent = nullptr); 1.153 + nsresult ProcessLinkHeader(const nsAString& aLinkData); 1.154 + nsresult ProcessLink(const nsSubstring& aAnchor, 1.155 + const nsSubstring& aHref, const nsSubstring& aRel, 1.156 + const nsSubstring& aTitle, const nsSubstring& aType, 1.157 + const nsSubstring& aMedia); 1.158 + 1.159 + virtual nsresult ProcessStyleLink(nsIContent* aElement, 1.160 + const nsSubstring& aHref, 1.161 + bool aAlternate, 1.162 + const nsSubstring& aTitle, 1.163 + const nsSubstring& aType, 1.164 + const nsSubstring& aMedia); 1.165 + 1.166 + void PrefetchHref(const nsAString &aHref, nsINode *aSource, 1.167 + bool aExplicit); 1.168 + 1.169 + // aHref can either be the usual URI format or of the form "//www.hostname.com" 1.170 + // without a scheme. 1.171 + void PrefetchDNS(const nsAString &aHref); 1.172 + 1.173 + // Gets the cache key (used to identify items in a cache) of the channel. 1.174 + nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey); 1.175 + 1.176 + // There is an offline cache manifest attribute specified and the 1.177 + // document is allowed to use the offline cache. Process the cache 1.178 + // selection algorithm for this document and the manifest. Result is 1.179 + // an action that must be taken on the manifest, see 1.180 + // CacheSelectionAction enum above. 1.181 + // 1.182 + // @param aLoadApplicationCache 1.183 + // The application cache from which the load originated, if 1.184 + // any. 1.185 + // @param aManifestURI 1.186 + // The manifest URI listed in the document. 1.187 + // @param aFetchedWithHTTPGetOrEquiv 1.188 + // TRUE if this was fetched using the HTTP GET method. 1.189 + // @param aAction 1.190 + // Out parameter, returns the action that should be performed 1.191 + // by the calling function. 1.192 + nsresult SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache, 1.193 + nsIURI *aManifestURI, 1.194 + bool aFetchedWithHTTPGetOrEquiv, 1.195 + CacheSelectionAction *aAction); 1.196 + 1.197 + // There is no offline cache manifest attribute specified. Process 1.198 + // the cache selection algorithm w/o the manifest. Result is an 1.199 + // action that must be taken, see CacheSelectionAction enum 1.200 + // above. In case the offline cache manifest has to be updated the 1.201 + // manifest URI is returned in aManifestURI. 1.202 + // 1.203 + // @param aLoadApplicationCache 1.204 + // The application cache from which the load originated, if 1.205 + // any. 1.206 + // @param aManifestURI 1.207 + // Out parameter, returns the manifest URI of the cache that 1.208 + // was selected. 1.209 + // @param aAction 1.210 + // Out parameter, returns the action that should be performed 1.211 + // by the calling function. 1.212 + nsresult SelectDocAppCacheNoManifest(nsIApplicationCache *aLoadApplicationCache, 1.213 + nsIURI **aManifestURI, 1.214 + CacheSelectionAction *aAction); 1.215 + 1.216 +public: 1.217 + // Searches for the offline cache manifest attribute and calls one 1.218 + // of the above defined methods to select the document's application 1.219 + // cache, let it be associated with the document and eventually 1.220 + // schedule the cache update process. 1.221 + // This method MUST be called with the empty string as the argument 1.222 + // when there is no manifest attribute! 1.223 + void ProcessOfflineManifest(const nsAString& aManifestSpec); 1.224 + 1.225 + // Extracts the manifest attribute from the element if it is the root 1.226 + // element and calls the above method. 1.227 + void ProcessOfflineManifest(nsIContent *aElement); 1.228 + 1.229 +protected: 1.230 + // Tries to scroll to the URI's named anchor. Once we've successfully 1.231 + // done that, further calls to this method will be ignored. 1.232 + void ScrollToRef(); 1.233 + 1.234 + // Start layout. If aIgnorePendingSheets is true, this will happen even if 1.235 + // we still have stylesheet loads pending. Otherwise, we'll wait until the 1.236 + // stylesheets are all done loading. 1.237 +public: 1.238 + void StartLayout(bool aIgnorePendingSheets); 1.239 + 1.240 + static void NotifyDocElementCreated(nsIDocument* aDoc); 1.241 + 1.242 +protected: 1.243 + void 1.244 + FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay); 1.245 + 1.246 + inline int32_t GetNotificationInterval() 1.247 + { 1.248 + if (mDynamicLowerValue) { 1.249 + return 1000; 1.250 + } 1.251 + 1.252 + return sNotificationInterval; 1.253 + } 1.254 + 1.255 + virtual nsresult FlushTags() = 0; 1.256 + 1.257 + // Later on we might want to make this more involved somehow 1.258 + // (e.g. stop waiting after some timeout or whatnot). 1.259 + bool WaitForPendingSheets() { return mPendingSheetCount > 0; } 1.260 + 1.261 + void DoProcessLinkHeader(); 1.262 + 1.263 + void StopDeflecting() { 1.264 + mDeflectedCount = sPerfDeflectCount; 1.265 + } 1.266 + 1.267 +private: 1.268 + // People shouldn't be allocating this class directly. All subclasses should 1.269 + // be allocated using a zeroing operator new. 1.270 + void* operator new(size_t sz) CPP_THROW_NEW; // Not to be implemented 1.271 + 1.272 +protected: 1.273 + 1.274 + nsCOMPtr<nsIDocument> mDocument; 1.275 + nsRefPtr<nsParserBase> mParser; 1.276 + nsCOMPtr<nsIURI> mDocumentURI; 1.277 + nsCOMPtr<nsIDocShell> mDocShell; 1.278 + nsRefPtr<mozilla::css::Loader> mCSSLoader; 1.279 + nsRefPtr<nsNodeInfoManager> mNodeInfoManager; 1.280 + nsRefPtr<nsScriptLoader> mScriptLoader; 1.281 + 1.282 + // back off timer notification after count 1.283 + int32_t mBackoffCount; 1.284 + 1.285 + // Time of last notification 1.286 + // Note: mLastNotificationTime is only valid once mLayoutStarted is true. 1.287 + PRTime mLastNotificationTime; 1.288 + 1.289 + // Timer used for notification 1.290 + nsCOMPtr<nsITimer> mNotificationTimer; 1.291 + 1.292 + // Have we already called BeginUpdate for this set of content changes? 1.293 + uint8_t mBeganUpdate : 1; 1.294 + uint8_t mLayoutStarted : 1; 1.295 + uint8_t mDynamicLowerValue : 1; 1.296 + uint8_t mParsing : 1; 1.297 + uint8_t mDroppedTimer : 1; 1.298 + // If true, we deferred starting layout until sheets load 1.299 + uint8_t mDeferredLayoutStart : 1; 1.300 + // If true, we deferred notifications until sheets load 1.301 + uint8_t mDeferredFlushTags : 1; 1.302 + // If false, we're not ourselves a document observer; that means we 1.303 + // shouldn't be performing any more content model notifications, 1.304 + // since we're not longer updating our child counts. 1.305 + uint8_t mIsDocumentObserver : 1; 1.306 + // True if this is parser is a fragment parser or an HTML DOMParser. 1.307 + // XML DOMParser leaves this to false for now! 1.308 + uint8_t mRunsToCompletion : 1; 1.309 + 1.310 + // 1.311 + // -- Can interrupt parsing members -- 1.312 + // 1.313 + 1.314 + // The number of tokens that have been processed since we measured 1.315 + // if it's time to return to the main event loop. 1.316 + uint32_t mDeflectedCount; 1.317 + 1.318 + // Is there currently a pending event? 1.319 + bool mHasPendingEvent; 1.320 + 1.321 + // When to return to the main event loop 1.322 + uint32_t mCurrentParseEndTime; 1.323 + 1.324 + int32_t mBeginLoadTime; 1.325 + 1.326 + // Last mouse event or keyboard event time sampled by the content 1.327 + // sink 1.328 + uint32_t mLastSampledUserEventTime; 1.329 + 1.330 + int32_t mInMonolithicContainer; 1.331 + 1.332 + int32_t mInNotification; 1.333 + uint32_t mUpdatesInNotification; 1.334 + 1.335 + uint32_t mPendingSheetCount; 1.336 + 1.337 + nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> > 1.338 + mProcessLinkHeaderEvent; 1.339 + 1.340 + // Do we notify based on time? 1.341 + static bool sNotifyOnTimer; 1.342 + // Back off timer notification after count. 1.343 + static int32_t sBackoffCount; 1.344 + // Notification interval in microseconds 1.345 + static int32_t sNotificationInterval; 1.346 + // How many times to deflect in interactive/perf modes 1.347 + static int32_t sInteractiveDeflectCount; 1.348 + static int32_t sPerfDeflectCount; 1.349 + // 0 = don't check for pending events 1.350 + // 1 = don't deflect if there are pending events 1.351 + // 2 = bail if there are pending events 1.352 + static int32_t sPendingEventMode; 1.353 + // How often to probe for pending events. 1=every token 1.354 + static int32_t sEventProbeRate; 1.355 + // How long to stay off the event loop in interactive/perf modes 1.356 + static int32_t sInteractiveParseTime; 1.357 + static int32_t sPerfParseTime; 1.358 + // How long to be in interactive mode after an event 1.359 + static int32_t sInteractiveTime; 1.360 + // How long to stay in perf mode after initial loading 1.361 + static int32_t sInitialPerfTime; 1.362 + // Should we switch between perf-mode and interactive-mode 1.363 + static int32_t sEnablePerfMode; 1.364 +}; 1.365 + 1.366 +#endif // _nsContentSink_h_