Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / parser / html / nsHtml5TreeOpExecutor.h
blobeb018b4ed7da924f8645fa7e9cd8fccb25ae1c65
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
12 * License.
14 * The Original Code is HTML Parser Gecko integration code.
16 * The Initial Developer of the Original Code is
17 * Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2009
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
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__
41 #include "prtypes.h"
42 #include "nsIAtom.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"
50 #include "nsTArray.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"
60 #include "nsIURI.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;
81 public:
82 NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
83 NS_DECL_ISUPPORTS_INHERITED
84 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHtml5TreeOpExecutor, nsContentSink)
86 private:
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;
93 #endif
95 /**
96 * Whether EOF needs to be suppressed
98 PRBool mSuppressEOF;
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
117 PRBool mStarted;
119 nsHtml5TreeOpStage mStage;
121 eHtml5FlushState mFlushState;
123 PRBool mRunFlushLoopOnStack;
125 PRBool mCallContinueInterruptedParsingIfEnabled;
127 PRBool mFragmentMode;
129 PRBool mPreventScriptExecution;
131 public:
133 nsHtml5TreeOpExecutor();
134 virtual ~nsHtml5TreeOpExecutor();
136 // nsIContentSink
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();
152 return NS_OK;
156 * Emits EOF.
158 NS_IMETHOD DidBuildModel(PRBool aTerminated);
161 * Forwards to nsContentSink
163 NS_IMETHOD WillInterrupt();
166 * Unimplemented. For interface compat only.
168 NS_IMETHOD WillResume();
171 * Sets the parser.
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() {
206 return mDocument;
208 nsNodeInfoManager* GetNodeInfoManager() {
209 return mNodeInfoManager;
211 nsIDocShell* GetDocShell() {
212 return mDocShell;
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++;
276 #endif
277 if (*iter == aParent) {
278 newParent = PR_FALSE;
279 break;
282 if (aChild->IsElement()) {
283 mElementsSeenInThisAppendBatch.AppendElement(aChild);
285 mElementsSeenInThisAppendBatch.AppendElement(aParent);
286 if (newParent) {
287 mPendingNotifications.AppendElement(aParent);
289 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
290 sAppendBatchExaminations++;
291 #endif
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) {
300 iter->Fire();
302 mPendingNotifications.Clear();
303 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
304 if (mElementsSeenInThisAppendBatch.Length() > sAppendBatchMaxSize) {
305 sAppendBatchMaxSize = mElementsSeenInThisAppendBatch.Length();
307 #endif
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();
317 for (;;) {
318 nsIContent* parent = aNode->GetParent();
319 if (!parent) {
320 return PR_TRUE;
322 for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) {
323 if (iter->Contains(parent)) {
324 return iter->HaveNotifiedIndex(parent->IndexOf(aNode));
327 aNode = parent;
331 void StartLayout();
333 void SetDocumentMode(nsHtml5DocumentMode m);
335 nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
336 nsISupports* aContainer, nsIChannel* aChannel);
338 void FlushSpeculativeLoads();
340 void RunFlushLoop();
342 void FlushDocumentWrite();
344 void MaybeSuspend();
346 void Start();
348 void NeedsCharsetSwitchTo(const char* aEncoding, PRInt32 aSource);
350 PRBool IsComplete() {
351 return !mParser;
354 PRBool HasStarted() {
355 return mStarted;
358 PRBool IsFlushing() {
359 return mFlushState >= eInFlush;
362 #ifdef DEBUG
363 PRBool IsInFlushLoop() {
364 return mRunFlushLoopOnStack;
366 #endif
368 void RunScript(nsIContent* aScriptElement);
370 void Reset();
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() {
387 return &mStage;
390 void StartReadingFromStage() {
391 mReadingFromStage = PR_TRUE;
394 void StreamEnded();
396 #ifdef DEBUG
397 void AssertStageEmpty() {
398 mStage.AssertEmpty();
400 #endif
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);
412 private:
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__