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