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