1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is HTML Parser Gecko integration code.
16 * The Initial Developer of the Original Code is
18 * Portions created by the Initial Developer are Copyright (C) 2009
19 * the Initial Developer. All Rights Reserved.
22 * Henri Sivonen <hsivonen@iki.fi>
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 #ifndef nsHtml5TreeOpExecutor_h__
39 #define nsHtml5TreeOpExecutor_h__
43 #include "nsINameSpaceManager.h"
44 #include "nsIContent.h"
45 #include "nsIDocument.h"
46 #include "nsTraceRefcnt.h"
47 #include "nsHtml5TreeOperation.h"
48 #include "nsHtml5SpeculativeLoad.h"
49 #include "nsHtml5PendingNotification.h"
51 #include "nsContentSink.h"
52 #include "nsNodeInfoManager.h"
53 #include "nsHtml5DocumentMode.h"
54 #include "nsIScriptElement.h"
55 #include "nsIParser.h"
56 #include "nsCOMArray.h"
57 #include "nsAHtml5TreeOpSink.h"
58 #include "nsHtml5TreeOpStage.h"
59 #include "nsHashSets.h"
62 class nsHtml5TreeBuilder
;
63 class nsHtml5Tokenizer
;
64 class nsHtml5StreamParser
;
66 typedef nsIContent
* nsIContentPtr
;
68 enum eHtml5FlushState
{
69 eNotFlushing
= 0, // not flushing
70 eInFlush
= 1, // the Flush() method is on the call stack
71 eInDocUpdate
= 2, // inside an update batch on the document
72 eNotifying
= 3 // flushing pending append notifications
75 class nsHtml5TreeOpExecutor
: public nsContentSink
,
76 public nsIContentSink
,
77 public nsAHtml5TreeOpSink
79 friend class nsHtml5FlushLoopGuard
;
82 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
83 NS_DECL_ISUPPORTS_INHERITED
84 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHtml5TreeOpExecutor
, nsContentSink
)
87 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
88 static PRUint32 sAppendBatchMaxSize
;
89 static PRUint32 sAppendBatchSlotsExamined
;
90 static PRUint32 sAppendBatchExaminations
;
91 static PRUint32 sLongestTimeOffTheEventLoop
;
92 static PRUint32 sTimesFlushLoopInterrupted
;
96 * Whether EOF needs to be suppressed
100 PRBool mReadingFromStage
;
101 nsTArray
<nsHtml5TreeOperation
> mOpQueue
;
102 nsTArray
<nsIContentPtr
> mElementsSeenInThisAppendBatch
;
103 nsTArray
<nsHtml5PendingNotification
> mPendingNotifications
;
104 nsHtml5StreamParser
* mStreamParser
;
105 nsCOMArray
<nsIContent
> mOwnedElements
;
108 * URLs already preloaded/preloading.
110 nsCStringHashSet mPreloadedURLs
;
112 nsCOMPtr
<nsIURI
> mSpeculationBaseURI
;
115 * Whether the parser has started
119 nsHtml5TreeOpStage mStage
;
121 eHtml5FlushState mFlushState
;
123 PRBool mRunFlushLoopOnStack
;
125 PRBool mCallContinueInterruptedParsingIfEnabled
;
127 PRBool mFragmentMode
;
129 PRBool mPreventScriptExecution
;
133 nsHtml5TreeOpExecutor();
134 virtual ~nsHtml5TreeOpExecutor();
139 * Unimplemented. For interface compat only.
141 NS_IMETHOD
WillParse();
146 NS_IMETHOD
WillBuildModel(nsDTDMode aDTDMode
) {
147 NS_ASSERTION(GetDocument()->GetScriptGlobalObject(),
148 "Script global object not ready");
149 mDocument
->AddObserver(this);
150 WillBuildModelImpl();
151 GetDocument()->BeginLoad();
158 NS_IMETHOD
DidBuildModel(PRBool aTerminated
);
161 * Forwards to nsContentSink
163 NS_IMETHOD
WillInterrupt();
166 * Unimplemented. For interface compat only.
168 NS_IMETHOD
WillResume();
173 NS_IMETHOD
SetParser(nsIParser
* aParser
);
176 * No-op for backwards compat.
178 virtual void FlushPendingNotifications(mozFlushType aType
);
181 * Don't call. For interface compat only.
183 NS_IMETHOD
SetDocumentCharset(nsACString
& aCharset
) {
184 NS_NOTREACHED("No one should call this.");
185 return NS_ERROR_NOT_IMPLEMENTED
;
189 * Returns the document.
191 virtual nsISupports
*GetTarget();
193 // nsContentSink methods
194 virtual void UpdateChildCounts();
195 virtual nsresult
FlushTags();
196 virtual void PostEvaluateScript(nsIScriptElement
*aElement
);
197 virtual void ContinueInterruptedParsingAsync();
200 * Sets up style sheet load / parse
202 void UpdateStyleSheet(nsIContent
* aElement
);
204 // Getters and setters for fields from nsContentSink
205 nsIDocument
* GetDocument() {
208 nsNodeInfoManager
* GetNodeInfoManager() {
209 return mNodeInfoManager
;
211 nsIDocShell
* GetDocShell() {
215 PRBool
IsScriptExecuting() {
216 return IsScriptExecutingImpl();
219 void SetNodeInfoManager(nsNodeInfoManager
* aManager
) {
220 mNodeInfoManager
= aManager
;
223 // Not from interface
225 void SetDocumentCharsetAndSource(nsACString
& aCharset
, PRInt32 aCharsetSource
);
227 void SetStreamParser(nsHtml5StreamParser
* aStreamParser
) {
228 mStreamParser
= aStreamParser
;
231 void InitializeDocWriteParserState(nsAHtml5TreeBuilderState
* aState
, PRInt32 aLine
);
233 PRBool
IsScriptEnabled();
236 * Enables the fragment mode.
238 * @param aPreventScriptExecution if true, scripts are prevented from
239 * executing; don't set to false when parsing a fragment directly into
240 * a document--only when parsing to an actual DOM fragment
242 void EnableFragmentMode(PRBool aPreventScriptExecution
) {
243 mFragmentMode
= PR_TRUE
;
244 mCanInterruptParser
= PR_FALSE
; // prevent DropParserAndPerfHint
245 // from unblocking onload
246 mPreventScriptExecution
= aPreventScriptExecution
;
249 PRBool
IsFragmentMode() {
250 return mFragmentMode
;
253 inline void BeginDocUpdate() {
254 NS_PRECONDITION(mFlushState
== eInFlush
, "Tried to double-open update.");
255 NS_PRECONDITION(mParser
, "Started update without parser.");
256 mFlushState
= eInDocUpdate
;
257 mDocument
->BeginUpdate(UPDATE_CONTENT_MODEL
);
260 inline void EndDocUpdate() {
261 NS_PRECONDITION(mFlushState
!= eNotifying
, "mFlushState out of sync");
262 if (mFlushState
== eInDocUpdate
) {
263 FlushPendingAppendNotifications();
264 mFlushState
= eInFlush
;
265 mDocument
->EndUpdate(UPDATE_CONTENT_MODEL
);
269 void PostPendingAppendNotification(nsIContent
* aParent
, nsIContent
* aChild
) {
270 PRBool newParent
= PR_TRUE
;
271 const nsIContentPtr
* first
= mElementsSeenInThisAppendBatch
.Elements();
272 const nsIContentPtr
* last
= first
+ mElementsSeenInThisAppendBatch
.Length() - 1;
273 for (const nsIContentPtr
* iter
= last
; iter
>= first
; --iter
) {
274 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
275 sAppendBatchSlotsExamined
++;
277 if (*iter
== aParent
) {
278 newParent
= PR_FALSE
;
282 if (aChild
->IsElement()) {
283 mElementsSeenInThisAppendBatch
.AppendElement(aChild
);
285 mElementsSeenInThisAppendBatch
.AppendElement(aParent
);
287 mPendingNotifications
.AppendElement(aParent
);
289 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
290 sAppendBatchExaminations
++;
294 void FlushPendingAppendNotifications() {
295 NS_PRECONDITION(mFlushState
== eInDocUpdate
, "Notifications flushed outside update");
296 mFlushState
= eNotifying
;
297 const nsHtml5PendingNotification
* start
= mPendingNotifications
.Elements();
298 const nsHtml5PendingNotification
* end
= start
+ mPendingNotifications
.Length();
299 for (nsHtml5PendingNotification
* iter
= (nsHtml5PendingNotification
*)start
; iter
< end
; ++iter
) {
302 mPendingNotifications
.Clear();
303 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
304 if (mElementsSeenInThisAppendBatch
.Length() > sAppendBatchMaxSize
) {
305 sAppendBatchMaxSize
= mElementsSeenInThisAppendBatch
.Length();
308 mElementsSeenInThisAppendBatch
.Clear();
309 NS_ASSERTION(mFlushState
== eNotifying
, "mFlushState out of sync");
310 mFlushState
= eInDocUpdate
;
313 inline PRBool
HaveNotified(nsIContent
* aNode
) {
314 NS_PRECONDITION(aNode
, "HaveNotified called with null argument.");
315 const nsHtml5PendingNotification
* start
= mPendingNotifications
.Elements();
316 const nsHtml5PendingNotification
* end
= start
+ mPendingNotifications
.Length();
318 nsIContent
* parent
= aNode
->GetParent();
322 for (nsHtml5PendingNotification
* iter
= (nsHtml5PendingNotification
*)start
; iter
< end
; ++iter
) {
323 if (iter
->Contains(parent
)) {
324 return iter
->HaveNotifiedIndex(parent
->IndexOf(aNode
));
333 void SetDocumentMode(nsHtml5DocumentMode m
);
335 nsresult
Init(nsIDocument
* aDoc
, nsIURI
* aURI
,
336 nsISupports
* aContainer
, nsIChannel
* aChannel
);
338 void FlushSpeculativeLoads();
342 void FlushDocumentWrite();
348 void NeedsCharsetSwitchTo(const char* aEncoding
, PRInt32 aSource
);
350 PRBool
IsComplete() {
354 PRBool
HasStarted() {
358 PRBool
IsFlushing() {
359 return mFlushState
>= eInFlush
;
363 PRBool
IsInFlushLoop() {
364 return mRunFlushLoopOnStack
;
368 void RunScript(nsIContent
* aScriptElement
);
372 inline void HoldElement(nsIContent
* aContent
) {
373 mOwnedElements
.AppendObject(aContent
);
376 void DropHeldElements() {
377 mOwnedElements
.Clear();
381 * Flush the operations from the tree operations from the argument
382 * queue unconditionally. (This is for the main thread case.)
384 virtual void MoveOpsFrom(nsTArray
<nsHtml5TreeOperation
>& aOpQueue
);
386 nsHtml5TreeOpStage
* GetStage() {
390 void StartReadingFromStage() {
391 mReadingFromStage
= PR_TRUE
;
397 void AssertStageEmpty() {
398 mStage
.AssertEmpty();
402 void PreloadScript(const nsAString
& aURL
,
403 const nsAString
& aCharset
,
404 const nsAString
& aType
);
406 void PreloadStyle(const nsAString
& aURL
, const nsAString
& aCharset
);
408 void PreloadImage(const nsAString
& aURL
);
410 void SetSpeculationBase(const nsAString
& aURL
);
414 nsHtml5Tokenizer
* GetTokenizer();
417 * Get a nsIURI for an nsString if the URL hasn't been preloaded yet.
419 already_AddRefed
<nsIURI
> ConvertIfNotPreloadedYet(const nsAString
& aURL
);
423 #endif // nsHtml5TreeOpExecutor_h__