PageRenderTime 39ms CodeModel.GetById 13ms app.highlight 21ms RepoModel.GetById 1ms app.codeStats 0ms

/parser/html/nsHtml5TreeOpExecutor.h

http://github.com/zpao/v8monkey
C Header | 445 lines | 255 code | 82 blank | 108 comment | 18 complexity | cf18012464c6cd9cbcf177f4358e5db2 MD5 | raw file
  1/* ***** BEGIN LICENSE BLOCK *****
  2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3 *
  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/
  8 *
  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.
 13 *
 14 * The Original Code is HTML Parser Gecko integration code.
 15 *
 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.
 20 *
 21 * Contributor(s):
 22 *   Henri Sivonen <hsivonen@iki.fi>
 23 *
 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.
 35 *
 36 * ***** END LICENSE BLOCK ***** */
 37
 38#ifndef nsHtml5TreeOpExecutor_h__
 39#define nsHtml5TreeOpExecutor_h__
 40
 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"
 61
 62class nsHtml5Parser;
 63class nsHtml5TreeBuilder;
 64class nsHtml5Tokenizer;
 65class nsHtml5StreamParser;
 66
 67typedef nsIContent* nsIContentPtr;
 68
 69enum eHtml5FlushState {
 70  eNotFlushing = 0,  // not flushing
 71  eInFlush = 1,      // the Flush() method is on the call stack
 72  eInDocUpdate = 2,  // inside an update batch on the document
 73  eNotifying = 3     // flushing pending append notifications
 74};
 75
 76class nsHtml5TreeOpExecutor : public nsContentSink,
 77                              public nsIContentSink,
 78                              public nsAHtml5TreeOpSink
 79{
 80  friend class nsHtml5FlushLoopGuard;
 81
 82  public:
 83    NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
 84    NS_DECL_ISUPPORTS_INHERITED
 85    NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHtml5TreeOpExecutor, nsContentSink)
 86
 87  private:
 88#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
 89    static PRUint32    sAppendBatchMaxSize;
 90    static PRUint32    sAppendBatchSlotsExamined;
 91    static PRUint32    sAppendBatchExaminations;
 92    static PRUint32    sLongestTimeOffTheEventLoop;
 93    static PRUint32    sTimesFlushLoopInterrupted;
 94#endif
 95
 96    /**
 97     * Whether EOF needs to be suppressed
 98     */
 99    bool                                 mSuppressEOF;
100    
101    bool                                 mReadingFromStage;
102    nsTArray<nsHtml5TreeOperation>       mOpQueue;
103    nsTArray<nsIContentPtr>              mElementsSeenInThisAppendBatch;
104    nsTArray<nsHtml5PendingNotification> mPendingNotifications;
105    nsHtml5StreamParser*                 mStreamParser;
106    nsCOMArray<nsIContent>               mOwnedElements;
107    
108    /**
109     * URLs already preloaded/preloading.
110     */
111    nsCStringHashSet mPreloadedURLs;
112
113    nsCOMPtr<nsIURI> mSpeculationBaseURI;
114
115    nsCOMPtr<nsIURI> mViewSourceBaseURI;
116
117    /**
118     * Whether the parser has started
119     */
120    bool                          mStarted;
121
122    nsHtml5TreeOpStage            mStage;
123
124    eHtml5FlushState              mFlushState;
125
126    bool                          mRunFlushLoopOnStack;
127
128    bool                          mCallContinueInterruptedParsingIfEnabled;
129
130    /**
131     * True if this parser should refuse to process any more input.
132     * Currently, the only way a parser can break is if it drops some input
133     * due to a memory allocation failure. In such a case, the whole parser
134     * needs to be marked as broken, because some input has been lost and
135     * parsing more input could lead to a DOM where pieces of HTML source
136     * that weren't supposed to become scripts become scripts.
137     */
138    bool                          mBroken;
139
140  public:
141  
142    nsHtml5TreeOpExecutor(bool aRunsToCompletion = false);
143    virtual ~nsHtml5TreeOpExecutor();
144  
145    // nsIContentSink
146
147    /**
148     * Unimplemented. For interface compat only.
149     */
150    NS_IMETHOD WillParse();
151
152    /**
153     * 
154     */
155    NS_IMETHOD WillBuildModel(nsDTDMode aDTDMode) {
156      NS_ASSERTION(!mDocShell || GetDocument()->GetScriptGlobalObject(),
157                   "Script global object not ready");
158      mDocument->AddObserver(this);
159      WillBuildModelImpl();
160      GetDocument()->BeginLoad();
161      return NS_OK;
162    }
163
164    /**
165     * Emits EOF.
166     */
167    NS_IMETHOD DidBuildModel(bool aTerminated);
168
169    /**
170     * Forwards to nsContentSink
171     */
172    NS_IMETHOD WillInterrupt();
173
174    /**
175     * Unimplemented. For interface compat only.
176     */
177    NS_IMETHOD WillResume();
178
179    /**
180     * Sets the parser.
181     */
182    NS_IMETHOD SetParser(nsParserBase* aParser);
183
184    /**
185     * No-op for backwards compat.
186     */
187    virtual void FlushPendingNotifications(mozFlushType aType);
188
189    /**
190     * Don't call. For interface compat only.
191     */
192    NS_IMETHOD SetDocumentCharset(nsACString& aCharset) {
193    	NS_NOTREACHED("No one should call this.");
194    	return NS_ERROR_NOT_IMPLEMENTED;
195    }
196
197    /**
198     * Returns the document.
199     */
200    virtual nsISupports *GetTarget();
201  
202    // nsContentSink methods
203    virtual void UpdateChildCounts();
204    virtual nsresult FlushTags();
205    virtual void ContinueInterruptedParsingAsync();
206 
207    /**
208     * Sets up style sheet load / parse
209     */
210    void UpdateStyleSheet(nsIContent* aElement);
211
212    // Getters and setters for fields from nsContentSink
213    nsIDocument* GetDocument() {
214      return mDocument;
215    }
216    nsNodeInfoManager* GetNodeInfoManager() {
217      return mNodeInfoManager;
218    }
219    nsIDocShell* GetDocShell() {
220      return mDocShell;
221    }
222
223    bool IsScriptExecuting() {
224      return IsScriptExecutingImpl();
225    }
226    
227    void SetNodeInfoManager(nsNodeInfoManager* aManager) {
228      mNodeInfoManager = aManager;
229    }
230    
231    // Not from interface
232
233    void SetDocumentCharsetAndSource(nsACString& aCharset, PRInt32 aCharsetSource);
234
235    void SetStreamParser(nsHtml5StreamParser* aStreamParser) {
236      mStreamParser = aStreamParser;
237    }
238    
239    void InitializeDocWriteParserState(nsAHtml5TreeBuilderState* aState, PRInt32 aLine);
240
241    bool IsScriptEnabled();
242
243    /**
244     * Enables the fragment mode.
245     *
246     * @param aPreventScriptExecution if true, scripts are prevented from
247     * executing; don't set to false when parsing a fragment directly into
248     * a document--only when parsing to an actual DOM fragment
249     */
250    void EnableFragmentMode(bool aPreventScriptExecution) {
251      mPreventScriptExecution = aPreventScriptExecution;
252    }
253    
254    void PreventScriptExecution() {
255      mPreventScriptExecution = true;
256    }
257
258    bool BelongsToStringParser() {
259      return mRunsToCompletion;
260    }
261
262    /**
263     * Marks this parser as broken and tells the stream parser (if any) to
264     * terminate.
265     */
266    void MarkAsBroken();
267
268    /**
269     * Checks if this parser is broken.
270     */
271    inline bool IsBroken() {
272      NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
273      return mBroken;
274    }
275
276    inline void BeginDocUpdate() {
277      NS_PRECONDITION(mFlushState == eInFlush, "Tried to double-open update.");
278      NS_PRECONDITION(mParser, "Started update without parser.");
279      mFlushState = eInDocUpdate;
280      mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
281    }
282
283    inline void EndDocUpdate() {
284      NS_PRECONDITION(mFlushState != eNotifying, "mFlushState out of sync");
285      if (mFlushState == eInDocUpdate) {
286        FlushPendingAppendNotifications();
287        mFlushState = eInFlush;
288        mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
289      }
290    }
291
292    void PostPendingAppendNotification(nsIContent* aParent, nsIContent* aChild) {
293      bool newParent = true;
294      const nsIContentPtr* first = mElementsSeenInThisAppendBatch.Elements();
295      const nsIContentPtr* last = first + mElementsSeenInThisAppendBatch.Length() - 1;
296      for (const nsIContentPtr* iter = last; iter >= first; --iter) {
297#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
298        sAppendBatchSlotsExamined++;
299#endif
300        if (*iter == aParent) {
301          newParent = false;
302          break;
303        }
304      }
305      if (aChild->IsElement()) {
306        mElementsSeenInThisAppendBatch.AppendElement(aChild);
307      }
308      mElementsSeenInThisAppendBatch.AppendElement(aParent);
309      if (newParent) {
310        mPendingNotifications.AppendElement(aParent);
311      }
312#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
313      sAppendBatchExaminations++;
314#endif
315    }
316
317    void FlushPendingAppendNotifications() {
318      NS_PRECONDITION(mFlushState == eInDocUpdate, "Notifications flushed outside update");
319      mFlushState = eNotifying;
320      const nsHtml5PendingNotification* start = mPendingNotifications.Elements();
321      const nsHtml5PendingNotification* end = start + mPendingNotifications.Length();
322      for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) {
323        iter->Fire();
324      }
325      mPendingNotifications.Clear();
326#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
327      if (mElementsSeenInThisAppendBatch.Length() > sAppendBatchMaxSize) {
328        sAppendBatchMaxSize = mElementsSeenInThisAppendBatch.Length();
329      }
330#endif
331      mElementsSeenInThisAppendBatch.Clear();
332      NS_ASSERTION(mFlushState == eNotifying, "mFlushState out of sync");
333      mFlushState = eInDocUpdate;
334    }
335    
336    inline bool HaveNotified(nsIContent* aNode) {
337      NS_PRECONDITION(aNode, "HaveNotified called with null argument.");
338      const nsHtml5PendingNotification* start = mPendingNotifications.Elements();
339      const nsHtml5PendingNotification* end = start + mPendingNotifications.Length();
340      for (;;) {
341        nsIContent* parent = aNode->GetParent();
342        if (!parent) {
343          return true;
344        }
345        for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) {
346          if (iter->Contains(parent)) {
347            return iter->HaveNotifiedIndex(parent->IndexOf(aNode));
348          }
349        }
350        aNode = parent;
351      }
352    }
353
354    void StartLayout();
355    
356    void SetDocumentMode(nsHtml5DocumentMode m);
357
358    nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
359                  nsISupports* aContainer, nsIChannel* aChannel);
360
361    void FlushSpeculativeLoads();
362                  
363    void RunFlushLoop();
364
365    void FlushDocumentWrite();
366
367    void MaybeSuspend();
368
369    void Start();
370
371    void NeedsCharsetSwitchTo(const char* aEncoding, PRInt32 aSource);
372    
373    bool IsComplete() {
374      return !mParser;
375    }
376    
377    bool HasStarted() {
378      return mStarted;
379    }
380    
381    bool IsFlushing() {
382      return mFlushState >= eInFlush;
383    }
384
385#ifdef DEBUG
386    bool IsInFlushLoop() {
387      return mRunFlushLoopOnStack;
388    }
389#endif
390    
391    void RunScript(nsIContent* aScriptElement);
392    
393    void Reset();
394    
395    inline void HoldElement(nsIContent* aContent) {
396      mOwnedElements.AppendObject(aContent);
397    }
398
399    void DropHeldElements();
400
401    /**
402     * Flush the operations from the tree operations from the argument
403     * queue unconditionally. (This is for the main thread case.)
404     */
405    virtual void MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue);
406    
407    nsHtml5TreeOpStage* GetStage() {
408      return &mStage;
409    }
410    
411    void StartReadingFromStage() {
412      mReadingFromStage = true;
413    }
414
415    void StreamEnded();
416    
417#ifdef DEBUG
418    void AssertStageEmpty() {
419      mStage.AssertEmpty();
420    }
421#endif
422
423    nsIURI* GetViewSourceBaseURI();
424
425    void PreloadScript(const nsAString& aURL,
426                       const nsAString& aCharset,
427                       const nsAString& aType);
428
429    void PreloadStyle(const nsAString& aURL, const nsAString& aCharset);
430
431    void PreloadImage(const nsAString& aURL, const nsAString& aCrossOrigin);
432
433    void SetSpeculationBase(const nsAString& aURL);
434
435  private:
436    nsHtml5Parser* GetParser();
437
438    /**
439     * Get a nsIURI for an nsString if the URL hasn't been preloaded yet.
440     */
441    already_AddRefed<nsIURI> ConvertIfNotPreloadedYet(const nsAString& aURL);
442
443};
444
445#endif // nsHtml5TreeOpExecutor_h__