1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifndef nsHtml5TreeOpExecutor_h 6 #define nsHtml5TreeOpExecutor_h 7 8 #include "nsAtom.h" 9 #include "nsTraceRefcnt.h" 10 #include "nsHtml5TreeOperation.h" 11 #include "nsHtml5SpeculativeLoad.h" 12 #include "nsTArray.h" 13 #include "nsContentSink.h" 14 #include "nsNodeInfoManager.h" 15 #include "nsHtml5DocumentMode.h" 16 #include "nsIScriptElement.h" 17 #include "nsIParser.h" 18 #include "nsAHtml5TreeOpSink.h" 19 #include "nsHtml5TreeOpStage.h" 20 #include "nsIURI.h" 21 #include "nsTHashSet.h" 22 #include "nsHashKeys.h" 23 #include "mozilla/LinkedList.h" 24 #include "nsHtml5DocumentBuilder.h" 25 26 class nsHtml5Parser; 27 class nsHtml5StreamParser; 28 class nsIContent; 29 namespace mozilla { 30 namespace dom { 31 class Document; 32 } 33 } // namespace mozilla 34 35 class nsHtml5TreeOpExecutor final 36 : public nsHtml5DocumentBuilder, 37 public nsIContentSink, 38 public nsAHtml5TreeOpSink, 39 public mozilla::LinkedListElement<nsHtml5TreeOpExecutor> { 40 friend class nsHtml5FlushLoopGuard; 41 typedef mozilla::dom::ReferrerPolicy ReferrerPolicy; 42 using Encoding = mozilla::Encoding; 43 template <typename T> 44 using NotNull = mozilla::NotNull<T>; 45 46 public: 47 NS_DECL_ISUPPORTS_INHERITED 48 49 private: 50 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH 51 static uint32_t sAppendBatchMaxSize; 52 static uint32_t sAppendBatchSlotsExamined; 53 static uint32_t sAppendBatchExaminations; 54 static uint32_t sLongestTimeOffTheEventLoop; 55 static uint32_t sTimesFlushLoopInterrupted; 56 #endif 57 58 /** 59 * Whether EOF needs to be suppressed 60 */ 61 bool mSuppressEOF; 62 63 bool mReadingFromStage; 64 nsTArray<nsHtml5TreeOperation> mOpQueue; 65 nsHtml5StreamParser* mStreamParser; 66 67 /** 68 * URLs already preloaded/preloading. 69 */ 70 nsTHashSet<nsCString> mPreloadedURLs; 71 72 nsCOMPtr<nsIURI> mSpeculationBaseURI; 73 74 nsCOMPtr<nsIURI> mViewSourceBaseURI; 75 76 /** 77 * Whether the parser has started 78 */ 79 bool mStarted; 80 81 nsHtml5TreeOpStage mStage; 82 83 bool mRunFlushLoopOnStack; 84 85 bool mCallContinueInterruptedParsingIfEnabled; 86 87 /** 88 * Whether this executor has already complained about matters related 89 * to character encoding declarations. 90 */ 91 bool mAlreadyComplainedAboutCharset; 92 93 /** 94 * Whether this executor has already complained about the tree being too 95 * deep. 96 */ 97 bool mAlreadyComplainedAboutDeepTree; 98 99 public: 100 nsHtml5TreeOpExecutor(); 101 102 protected: 103 virtual ~nsHtml5TreeOpExecutor(); 104 105 public: 106 // nsIContentSink 107 108 /** 109 * Unimplemented. For interface compat only. 110 */ 111 NS_IMETHOD WillParse() override; 112 113 /** 114 * 115 */ 116 NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) override; 117 118 /** 119 * Emits EOF. 120 */ 121 NS_IMETHOD DidBuildModel(bool aTerminated) override; 122 123 /** 124 * Forwards to nsContentSink 125 */ 126 NS_IMETHOD WillInterrupt() override; 127 128 /** 129 * Unimplemented. For interface compat only. 130 */ 131 NS_IMETHOD WillResume() override; 132 133 virtual void InitialTranslationCompleted() override; 134 135 /** 136 * Sets the parser. 137 */ 138 NS_IMETHOD SetParser(nsParserBase* aParser) override; 139 140 /** 141 * No-op for backwards compat. 142 */ 143 virtual void FlushPendingNotifications(mozilla::FlushType aType) override; 144 145 /** 146 * Don't call. For interface compat only. 147 */ SetDocumentCharset(NotNull<const Encoding * > aEncoding)148 virtual void SetDocumentCharset(NotNull<const Encoding*> aEncoding) override { 149 MOZ_ASSERT_UNREACHABLE("No one should call this."); 150 } 151 152 /** 153 * Returns the document. 154 */ 155 virtual nsISupports* GetTarget() override; 156 157 virtual void ContinueInterruptedParsingAsync() override; 158 IsScriptExecuting()159 bool IsScriptExecuting() override { return IsScriptExecutingImpl(); } 160 161 // Not from interface 162 SetStreamParser(nsHtml5StreamParser * aStreamParser)163 void SetStreamParser(nsHtml5StreamParser* aStreamParser) { 164 mStreamParser = aStreamParser; 165 } 166 167 void InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState, 168 int32_t aLine); 169 170 bool IsScriptEnabled(); 171 172 virtual nsresult MarkAsBroken(nsresult aReason) override; 173 174 void StartLayout(bool* aInterrupted); 175 176 void PauseDocUpdate(bool* aInterrupted); 177 178 void FlushSpeculativeLoads(); 179 180 void RunFlushLoop(); 181 182 nsresult FlushDocumentWrite(); 183 184 void MaybeSuspend(); 185 186 void Start(); 187 188 void NeedsCharsetSwitchTo(NotNull<const Encoding*> aEncoding, int32_t aSource, 189 uint32_t aLineNumber); 190 191 void MaybeComplainAboutCharset(const char* aMsgId, bool aError, 192 uint32_t aLineNumber); 193 194 void ComplainAboutBogusProtocolCharset(mozilla::dom::Document*); 195 196 void MaybeComplainAboutDeepTree(uint32_t aLineNumber); 197 HasStarted()198 bool HasStarted() { return mStarted; } 199 IsFlushing()200 bool IsFlushing() { return mFlushState >= eInFlush; } 201 202 #ifdef DEBUG IsInFlushLoop()203 bool IsInFlushLoop() { return mRunFlushLoopOnStack; } 204 #endif 205 206 void RunScript(nsIContent* aScriptElement); 207 208 /** 209 * Flush the operations from the tree operations from the argument 210 * queue unconditionally. (This is for the main thread case.) 211 */ 212 virtual void MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) override; 213 214 void ClearOpQueue(); 215 216 void RemoveFromStartOfOpQueue(size_t aNumberOfOpsToRemove); 217 OpQueueLength()218 inline size_t OpQueueLength() { return mOpQueue.Length(); } 219 GetStage()220 nsHtml5TreeOpStage* GetStage() { return &mStage; } 221 StartReadingFromStage()222 void StartReadingFromStage() { mReadingFromStage = true; } 223 224 void StreamEnded(); 225 226 #ifdef DEBUG AssertStageEmpty()227 void AssertStageEmpty() { mStage.AssertEmpty(); } 228 #endif 229 230 nsIURI* GetViewSourceBaseURI(); 231 232 void PreloadScript(const nsAString& aURL, const nsAString& aCharset, 233 const nsAString& aType, const nsAString& aCrossOrigin, 234 const nsAString& aMedia, const nsAString& aIntegrity, 235 ReferrerPolicy aReferrerPolicy, bool aScriptFromHead, 236 bool aAsync, bool aDefer, bool aNoModule, 237 bool aLinkPreload); 238 239 void PreloadStyle(const nsAString& aURL, const nsAString& aCharset, 240 const nsAString& aCrossOrigin, const nsAString& aMedia, 241 const nsAString& aReferrerPolicy, 242 const nsAString& aIntegrity, bool aLinkPreload); 243 244 void PreloadImage(const nsAString& aURL, const nsAString& aCrossOrigin, 245 const nsAString& aMedia, const nsAString& aSrcset, 246 const nsAString& aSizes, 247 const nsAString& aImageReferrerPolicy, bool aLinkPreload, 248 const mozilla::TimeStamp& aInitTimestamp); 249 250 void PreloadOpenPicture(); 251 252 void PreloadEndPicture(); 253 254 void PreloadPictureSource(const nsAString& aSrcset, const nsAString& aSizes, 255 const nsAString& aType, const nsAString& aMedia); 256 257 void PreloadFont(const nsAString& aURL, const nsAString& aCrossOrigin, 258 const nsAString& aMedia, const nsAString& aReferrerPolicy); 259 260 void PreloadFetch(const nsAString& aURL, const nsAString& aCrossOrigin, 261 const nsAString& aMedia, const nsAString& aReferrerPolicy); 262 263 void SetSpeculationBase(const nsAString& aURL); 264 265 void UpdateReferrerInfoFromMeta(const nsAString& aMetaReferrer); 266 267 void AddSpeculationCSP(const nsAString& aCSP); 268 269 void AddBase(const nsAString& aURL); 270 271 private: 272 nsHtml5Parser* GetParser(); 273 274 bool IsExternalViewSource(); 275 276 /** 277 * Get a nsIURI for an nsString if the URL hasn't been preloaded yet. 278 */ 279 already_AddRefed<nsIURI> ConvertIfNotPreloadedYet(const nsAString& aURL); 280 281 /** 282 * The above, plus also checks that the media attribute applies. 283 */ 284 already_AddRefed<nsIURI> ConvertIfNotPreloadedYetAndMediaApplies( 285 const nsAString& aURL, const nsAString& aMedia); 286 287 /** Returns whether the given media attribute applies to mDocument */ 288 bool MediaApplies(const nsAString& aMedia); 289 290 /** 291 * The base URI we would use for current preload operations 292 */ 293 nsIURI* BaseURIForPreload(); 294 295 /** 296 * Returns true if we haven't preloaded this URI yet, and adds it to the 297 * list of preloaded URIs 298 */ 299 bool ShouldPreloadURI(nsIURI* aURI); 300 301 ReferrerPolicy GetPreloadReferrerPolicy(const nsAString& aReferrerPolicy); 302 303 ReferrerPolicy GetPreloadReferrerPolicy(ReferrerPolicy aReferrerPolicy); 304 }; 305 306 #endif // nsHtml5TreeOpExecutor_h 307