nsContentSink.h (8774B)
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 "mozilla/Logging.h" 19 #include "mozilla/StaticPrefs_content.h" 20 #include "nsCOMPtr.h" 21 #include "nsCycleCollectionParticipant.h" 22 #include "nsGkAtoms.h" 23 #include "nsICSSLoaderObserver.h" 24 #include "nsIContentSink.h" 25 #include "nsITimer.h" 26 #include "nsString.h" 27 #include "nsStubDocumentObserver.h" 28 #include "nsThreadUtils.h" 29 #include "nsWeakReference.h" 30 31 class nsIURI; 32 class nsIChannel; 33 class nsIDocShell; 34 class nsAtom; 35 class nsIChannel; 36 class nsIContent; 37 class nsNodeInfoManager; 38 39 namespace mozilla { 40 namespace css { 41 class Loader; 42 } // namespace css 43 44 namespace dom { 45 class Document; 46 class ScriptLoader; 47 } // namespace dom 48 49 namespace net { 50 struct LinkHeader; 51 }; 52 } // namespace mozilla 53 54 #ifdef DEBUG 55 56 extern mozilla::LazyLogModule gContentSinkLogModuleInfo; 57 58 # define SINK_TRACE_CALLS 0x1 59 # define SINK_TRACE_REFLOW 0x2 60 # define SINK_ALWAYS_REFLOW 0x4 61 62 # define SINK_LOG_TEST(_lm, _bit) (int((_lm)->Level()) & (_bit)) 63 64 # define SINK_TRACE(_lm, _bit, _args) \ 65 do { \ 66 if (SINK_LOG_TEST(_lm, _bit)) { \ 67 printf_stderr _args; \ 68 } \ 69 } while (0) 70 71 #else 72 # define SINK_TRACE(_lm, _bit, _args) 73 #endif 74 75 #undef SINK_NO_INCREMENTAL 76 77 //---------------------------------------------------------------------- 78 79 class nsContentSink : public nsICSSLoaderObserver, 80 public nsSupportsWeakReference, 81 public nsStubDocumentObserver, 82 public nsITimerCallback, 83 public nsINamed { 84 protected: 85 using Document = mozilla::dom::Document; 86 87 private: 88 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 89 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink, nsICSSLoaderObserver) 90 // nsITimerCallback 91 NS_DECL_NSITIMERCALLBACK 92 93 NS_DECL_NSINAMED 94 95 // nsICSSLoaderObserver 96 NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasDeferred, 97 nsresult aStatus) override; 98 99 // nsIContentSink implementation helpers 100 nsresult WillParseImpl(void); 101 nsresult WillInterruptImpl(void); 102 void WillResumeImpl(); 103 nsresult DidProcessATokenImpl(void); 104 void WillBuildModelImpl(void); 105 void DidBuildModelImpl(bool aTerminated); 106 void DropParserAndPerfHint(void); 107 bool IsScriptExecutingImpl(); 108 void ContinueParsingDocumentAfterCurrentScriptImpl(); 109 110 void NotifyAppend(nsIContent* aContent, uint32_t aStartIndex); 111 112 // nsIDocumentObserver 113 NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE 114 NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE 115 116 virtual void UpdateChildCounts() = 0; 117 118 bool IsTimeToNotify(); 119 120 protected: 121 nsContentSink(); 122 virtual ~nsContentSink(); 123 124 nsresult Init(Document* aDoc, nsIURI* aURI, nsISupports* aContainer, 125 nsIChannel* aChannel); 126 127 nsresult ProcessHTTPHeaders(nsIChannel* aChannel); 128 // aEarlyHintPreloaderId zero means no early hint channel to connect back 129 nsresult ProcessLinkFromHeader(const mozilla::net::LinkHeader& aHeader, 130 uint64_t aEarlyHintPreloaderId); 131 132 // @param aFetchPriority Accepts a case-insensitive fetch priority keyword and 133 // other values too, see 134 // <https://html.spec.whatwg.org/#fetch-priority-attribute>. 135 virtual nsresult ProcessStyleLinkFromHeader( 136 const nsAString& aHref, bool aAlternate, const nsAString& aTitle, 137 const nsAString& aIntegrity, const nsAString& aType, 138 const nsAString& aMedia, const nsAString& aReferrerPolicy, 139 const nsAString& aFetchPriority); 140 141 void PrefetchHref(const nsAString& aHref, const nsAString& aAs, 142 const nsAString& aType, const nsAString& aMedia); 143 void PreloadHref(const nsAString& aHref, const nsAString& aAs, 144 const nsAString& aRel, const nsAString& aType, 145 const nsAString& aMedia, const nsAString& aNonce, 146 const nsAString& aIntegrity, const nsAString& aSrcset, 147 const nsAString& aSizes, const nsAString& aCORS, 148 const nsAString& aReferrerPolicy, 149 uint64_t aEarlyHintPreloaderId, 150 const nsAString& aFetchPriority); 151 152 void PreloadModule(const nsAString& aHref, const nsAString& aAs, 153 const nsAString& aMedia, const nsAString& aNonce, 154 const nsAString& aIntegrity, const nsAString& aCORS, 155 const nsAString& aReferrerPolicy, 156 uint64_t aEarlyHintPreloaderId, 157 const nsAString& aFetchPriority); 158 159 // For PrefetchDNS() aHref can either be the usual 160 // URI format or of the form "//www.hostname.com" without a scheme. 161 void PrefetchDNS(const nsAString& aHref); 162 163 // Gets the cache key (used to identify items in a cache) of the channel. 164 nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey); 165 166 public: 167 // For Preconnect() aHref can either be the usual 168 // URI format or of the form "//www.hostname.com" without a scheme. 169 void Preconnect(const nsAString& aHref, const nsAString& aCrossOrigin); 170 171 protected: 172 // Tries to scroll to the URI's named anchor. Once we've successfully 173 // done that, further calls to this method will be ignored. 174 MOZ_CAN_RUN_SCRIPT_BOUNDARY void ScrollToRef(); 175 176 // Start layout. If aIgnorePendingSheets is true, this will happen even if 177 // we still have stylesheet loads pending. Otherwise, we'll wait until the 178 // stylesheets are all done loading. 179 public: 180 void StartLayout(bool aIgnorePendingSheets); 181 182 static void NotifyDocElementCreated(Document* aDoc); 183 184 Document* GetDocument() { return mDocument; } 185 186 // Later on we might want to make this more involved somehow 187 // (e.g. stop waiting after some timeout or whatnot). 188 bool WaitForPendingSheets() { return mPendingSheetCount > 0; } 189 190 protected: 191 inline int32_t GetNotificationInterval() { 192 if (mDynamicLowerValue) { 193 return 1000; 194 } 195 196 return mozilla::StaticPrefs::content_notify_interval(); 197 } 198 199 virtual nsresult FlushTags() = 0; 200 201 void DoProcessLinkHeader(); 202 203 void StopDeflecting() { 204 mDeflectedCount = mozilla::StaticPrefs::content_sink_perf_deflect_count(); 205 } 206 207 protected: 208 RefPtr<Document> mDocument; 209 RefPtr<nsParserBase> mParser; 210 nsCOMPtr<nsIURI> mDocumentURI; 211 nsCOMPtr<nsIDocShell> mDocShell; 212 RefPtr<nsNodeInfoManager> mNodeInfoManager; 213 RefPtr<mozilla::dom::ScriptLoader> mScriptLoader; 214 215 // back off timer notification after count 216 int32_t mBackoffCount; 217 218 // Time of last notification 219 // Note: mLastNotificationTime is only valid once mLayoutStarted is true. 220 PRTime mLastNotificationTime; 221 222 // Timer used for notification 223 nsCOMPtr<nsITimer> mNotificationTimer; 224 225 uint8_t mLayoutStarted : 1; 226 uint8_t mDynamicLowerValue : 1; 227 uint8_t mParsing : 1; 228 uint8_t mDroppedTimer : 1; 229 // If true, we deferred starting layout until sheets load 230 uint8_t mDeferredLayoutStart : 1; 231 // If true, we deferred notifications until sheets load 232 uint8_t mDeferredFlushTags : 1; 233 // If false, we're not ourselves a document observer; that means we 234 // shouldn't be performing any more content model notifications, 235 // since we're not longer updating our child counts. 236 uint8_t mIsDocumentObserver : 1; 237 // True if this is parser is a fragment parser or an HTML DOMParser. 238 // XML DOMParser leaves this to false for now! 239 uint8_t mRunsToCompletion : 1; 240 // True if we are blocking load event. 241 bool mIsBlockingOnload : 1; 242 243 // 244 // -- Can interrupt parsing members -- 245 // 246 247 // The number of tokens that have been processed since we measured 248 // if it's time to return to the main event loop. 249 uint32_t mDeflectedCount; 250 251 // Is there currently a pending event? 252 bool mHasPendingEvent; 253 254 // When to return to the main event loop 255 uint32_t mCurrentParseEndTime; 256 257 int32_t mBeginLoadTime; 258 259 // Last mouse event or keyboard event time sampled by the content 260 // sink 261 uint32_t mLastSampledUserEventTime; 262 263 int32_t mInMonolithicContainer; 264 265 int32_t mInNotification; 266 uint32_t mUpdatesInNotification; 267 268 uint32_t mPendingSheetCount; 269 270 nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> > 271 mProcessLinkHeaderEvent; 272 }; 273 274 #endif // _nsContentSink_h_