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 "nsNetUtil.h" 20 #include "nsWeakReference.h" 21 #include "nsCOMPtr.h" 22 #include "nsString.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 #include "mozilla/StaticPrefs_content.h" 31 32 class nsIURI; 33 class nsIChannel; 34 class nsIDocShell; 35 class nsAtom; 36 class nsIChannel; 37 class nsIContent; 38 class nsNodeInfoManager; 39 40 namespace mozilla { 41 namespace css { 42 class Loader; 43 } // namespace css 44 45 namespace dom { 46 class Document; 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 protected: 82 using Document = mozilla::dom::Document; 83 84 private: 85 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 86 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink, nsICSSLoaderObserver) 87 // nsITimerCallback 88 NS_DECL_NSITIMERCALLBACK 89 90 NS_DECL_NSINAMED 91 92 // nsICSSLoaderObserver 93 NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasDeferred, 94 nsresult aStatus) override; 95 96 // nsIContentSink implementation helpers 97 nsresult WillParseImpl(void); 98 nsresult WillInterruptImpl(void); 99 void WillResumeImpl(); 100 nsresult DidProcessATokenImpl(void); 101 void WillBuildModelImpl(void); 102 void DidBuildModelImpl(bool aTerminated); 103 void DropParserAndPerfHint(void); 104 bool IsScriptExecutingImpl(); 105 106 void NotifyAppend(nsIContent* aContent, uint32_t aStartIndex); 107 108 // nsIDocumentObserver 109 NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE 110 NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE 111 112 virtual void UpdateChildCounts() = 0; 113 114 bool IsTimeToNotify(); 115 bool LinkContextIsOurDocument(const nsAString& aAnchor); 116 117 protected: 118 nsContentSink(); 119 virtual ~nsContentSink(); 120 121 nsresult Init(Document* aDoc, nsIURI* aURI, nsISupports* aContainer, 122 nsIChannel* aChannel); 123 124 nsresult ProcessHTTPHeaders(nsIChannel* aChannel); 125 nsresult ProcessLinkFromHeader(const LinkHeader& aHeader); 126 127 virtual nsresult ProcessStyleLinkFromHeader( 128 const nsAString& aHref, bool aAlternate, const nsAString& aTitle, 129 const nsAString& aIntegrity, const nsAString& aType, 130 const nsAString& aMedia, const nsAString& aReferrerPolicy); 131 132 void PrefetchHref(const nsAString& aHref, const nsAString& aAs, 133 const nsAString& aType, const nsAString& aMedia); 134 void PreloadHref(const nsAString& aHref, const nsAString& aAs, 135 const nsAString& aType, const nsAString& aMedia, 136 const nsAString& aIntegrity, const nsAString& aSrcset, 137 const nsAString& aSizes, const nsAString& aCORS, 138 const nsAString& aReferrerPolicy); 139 140 // For PrefetchDNS() aHref can either be the usual 141 // URI format or of the form "//www.hostname.com" without a scheme. 142 void PrefetchDNS(const nsAString& aHref); 143 144 // Gets the cache key (used to identify items in a cache) of the channel. 145 nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey); 146 147 public: 148 // For Preconnect() aHref can either be the usual 149 // URI format or of the form "//www.hostname.com" without a scheme. 150 void Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin); 151 152 protected: 153 // Tries to scroll to the URI's named anchor. Once we've successfully 154 // done that, further calls to this method will be ignored. 155 MOZ_CAN_RUN_SCRIPT_BOUNDARY void ScrollToRef(); 156 157 // Start layout. If aIgnorePendingSheets is true, this will happen even if 158 // we still have stylesheet loads pending. Otherwise, we'll wait until the 159 // stylesheets are all done loading. 160 public: 161 void StartLayout(bool aIgnorePendingSheets); 162 163 static void NotifyDocElementCreated(Document* aDoc); 164 GetDocument()165 Document* GetDocument() { return mDocument; } 166 167 protected: 168 void FavorPerformanceHint(bool perfOverStarvation, uint32_t starvationDelay); 169 GetNotificationInterval()170 inline int32_t GetNotificationInterval() { 171 if (mDynamicLowerValue) { 172 return 1000; 173 } 174 175 return mozilla::StaticPrefs::content_notify_interval(); 176 } 177 178 virtual nsresult FlushTags() = 0; 179 180 // Later on we might want to make this more involved somehow 181 // (e.g. stop waiting after some timeout or whatnot). WaitForPendingSheets()182 bool WaitForPendingSheets() { return mPendingSheetCount > 0; } 183 184 void DoProcessLinkHeader(); 185 StopDeflecting()186 void StopDeflecting() { 187 mDeflectedCount = mozilla::StaticPrefs::content_sink_perf_deflect_count(); 188 } 189 190 protected: 191 RefPtr<Document> mDocument; 192 RefPtr<nsParserBase> mParser; 193 nsCOMPtr<nsIURI> mDocumentURI; 194 nsCOMPtr<nsIDocShell> mDocShell; 195 RefPtr<mozilla::css::Loader> mCSSLoader; 196 RefPtr<nsNodeInfoManager> mNodeInfoManager; 197 RefPtr<mozilla::dom::ScriptLoader> mScriptLoader; 198 199 // back off timer notification after count 200 int32_t mBackoffCount; 201 202 // Time of last notification 203 // Note: mLastNotificationTime is only valid once mLayoutStarted is true. 204 PRTime mLastNotificationTime; 205 206 // Timer used for notification 207 nsCOMPtr<nsITimer> mNotificationTimer; 208 209 uint8_t mLayoutStarted : 1; 210 uint8_t mDynamicLowerValue : 1; 211 uint8_t mParsing : 1; 212 uint8_t mDroppedTimer : 1; 213 // If true, we deferred starting layout until sheets load 214 uint8_t mDeferredLayoutStart : 1; 215 // If true, we deferred notifications until sheets load 216 uint8_t mDeferredFlushTags : 1; 217 // If false, we're not ourselves a document observer; that means we 218 // shouldn't be performing any more content model notifications, 219 // since we're not longer updating our child counts. 220 uint8_t mIsDocumentObserver : 1; 221 // True if this is parser is a fragment parser or an HTML DOMParser. 222 // XML DOMParser leaves this to false for now! 223 uint8_t mRunsToCompletion : 1; 224 // True if we are blocking load event. 225 bool mIsBlockingOnload : 1; 226 227 // 228 // -- Can interrupt parsing members -- 229 // 230 231 // The number of tokens that have been processed since we measured 232 // if it's time to return to the main event loop. 233 uint32_t mDeflectedCount; 234 235 // Is there currently a pending event? 236 bool mHasPendingEvent; 237 238 // When to return to the main event loop 239 uint32_t mCurrentParseEndTime; 240 241 int32_t mBeginLoadTime; 242 243 // Last mouse event or keyboard event time sampled by the content 244 // sink 245 uint32_t mLastSampledUserEventTime; 246 247 int32_t mInMonolithicContainer; 248 249 int32_t mInNotification; 250 uint32_t mUpdatesInNotification; 251 252 uint32_t mPendingSheetCount; 253 254 nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> > 255 mProcessLinkHeaderEvent; 256 }; 257 258 #endif // _nsContentSink_h_ 259