1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/parser/html/nsHtml5DocumentBuilder.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,198 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=78: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef nsHtml5DocumentBuilder_h 1.11 +#define nsHtml5DocumentBuilder_h 1.12 + 1.13 +#include "nsHtml5PendingNotification.h" 1.14 +#include "nsContentSink.h" 1.15 +#include "nsHtml5DocumentMode.h" 1.16 +#include "nsIDocument.h" 1.17 + 1.18 +typedef nsIContent* nsIContentPtr; 1.19 + 1.20 +enum eHtml5FlushState { 1.21 + eNotFlushing = 0, // not flushing 1.22 + eInFlush = 1, // the Flush() method is on the call stack 1.23 + eInDocUpdate = 2, // inside an update batch on the document 1.24 + eNotifying = 3 // flushing pending append notifications 1.25 +}; 1.26 + 1.27 +class nsHtml5DocumentBuilder : public nsContentSink 1.28 +{ 1.29 +public: 1.30 + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHtml5DocumentBuilder, 1.31 + nsContentSink) 1.32 + 1.33 + NS_DECL_ISUPPORTS_INHERITED 1.34 + 1.35 + inline void HoldElement(nsIContent* aContent) 1.36 + { 1.37 + mOwnedElements.AppendElement(aContent); 1.38 + } 1.39 + 1.40 + inline bool HaveNotified(nsIContent* aNode) 1.41 + { 1.42 + NS_PRECONDITION(aNode, "HaveNotified called with null argument."); 1.43 + const nsHtml5PendingNotification* start = mPendingNotifications.Elements(); 1.44 + const nsHtml5PendingNotification* end = start + mPendingNotifications.Length(); 1.45 + for (;;) { 1.46 + nsIContent* parent = aNode->GetParent(); 1.47 + if (!parent) { 1.48 + return true; 1.49 + } 1.50 + for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) { 1.51 + if (iter->Contains(parent)) { 1.52 + return iter->HaveNotifiedIndex(parent->IndexOf(aNode)); 1.53 + } 1.54 + } 1.55 + aNode = parent; 1.56 + } 1.57 + } 1.58 + 1.59 + void PostPendingAppendNotification(nsIContent* aParent, nsIContent* aChild) 1.60 + { 1.61 + bool newParent = true; 1.62 + const nsIContentPtr* first = mElementsSeenInThisAppendBatch.Elements(); 1.63 + const nsIContentPtr* last = first + mElementsSeenInThisAppendBatch.Length() - 1; 1.64 + for (const nsIContentPtr* iter = last; iter >= first; --iter) { 1.65 +#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH 1.66 + sAppendBatchSlotsExamined++; 1.67 +#endif 1.68 + if (*iter == aParent) { 1.69 + newParent = false; 1.70 + break; 1.71 + } 1.72 + } 1.73 + if (aChild->IsElement()) { 1.74 + mElementsSeenInThisAppendBatch.AppendElement(aChild); 1.75 + } 1.76 + mElementsSeenInThisAppendBatch.AppendElement(aParent); 1.77 + if (newParent) { 1.78 + mPendingNotifications.AppendElement(aParent); 1.79 + } 1.80 +#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH 1.81 + sAppendBatchExaminations++; 1.82 +#endif 1.83 + } 1.84 + 1.85 + void FlushPendingAppendNotifications() 1.86 + { 1.87 + NS_PRECONDITION(mFlushState == eInDocUpdate, "Notifications flushed outside update"); 1.88 + mFlushState = eNotifying; 1.89 + const nsHtml5PendingNotification* start = mPendingNotifications.Elements(); 1.90 + const nsHtml5PendingNotification* end = start + mPendingNotifications.Length(); 1.91 + for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) { 1.92 + iter->Fire(); 1.93 + } 1.94 + mPendingNotifications.Clear(); 1.95 +#ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH 1.96 + if (mElementsSeenInThisAppendBatch.Length() > sAppendBatchMaxSize) { 1.97 + sAppendBatchMaxSize = mElementsSeenInThisAppendBatch.Length(); 1.98 + } 1.99 +#endif 1.100 + mElementsSeenInThisAppendBatch.Clear(); 1.101 + NS_ASSERTION(mFlushState == eNotifying, "mFlushState out of sync"); 1.102 + mFlushState = eInDocUpdate; 1.103 + } 1.104 + 1.105 + nsresult Init(nsIDocument* aDoc, nsIURI* aURI, 1.106 + nsISupports* aContainer, nsIChannel* aChannel); 1.107 + 1.108 + // Getters and setters for fields from nsContentSink 1.109 + nsIDocument* GetDocument() 1.110 + { 1.111 + return mDocument; 1.112 + } 1.113 + 1.114 + nsNodeInfoManager* GetNodeInfoManager() 1.115 + { 1.116 + return mNodeInfoManager; 1.117 + } 1.118 + 1.119 + /** 1.120 + * Marks this parser as broken and tells the stream parser (if any) to 1.121 + * terminate. 1.122 + * 1.123 + * @return aReason for convenience 1.124 + */ 1.125 + virtual nsresult MarkAsBroken(nsresult aReason); 1.126 + 1.127 + /** 1.128 + * Checks if this parser is broken. Returns a non-NS_OK (i.e. non-0) 1.129 + * value if broken. 1.130 + */ 1.131 + inline nsresult IsBroken() 1.132 + { 1.133 + return mBroken; 1.134 + } 1.135 + 1.136 + inline void BeginDocUpdate() 1.137 + { 1.138 + NS_PRECONDITION(mFlushState == eInFlush, "Tried to double-open update."); 1.139 + NS_PRECONDITION(mParser, "Started update without parser."); 1.140 + mFlushState = eInDocUpdate; 1.141 + mDocument->BeginUpdate(UPDATE_CONTENT_MODEL); 1.142 + } 1.143 + 1.144 + inline void EndDocUpdate() 1.145 + { 1.146 + NS_PRECONDITION(mFlushState != eNotifying, "mFlushState out of sync"); 1.147 + if (mFlushState == eInDocUpdate) { 1.148 + FlushPendingAppendNotifications(); 1.149 + mFlushState = eInFlush; 1.150 + mDocument->EndUpdate(UPDATE_CONTENT_MODEL); 1.151 + } 1.152 + } 1.153 + 1.154 + void SetDocumentCharsetAndSource(nsACString& aCharset, int32_t aCharsetSource); 1.155 + 1.156 + /** 1.157 + * Sets up style sheet load / parse 1.158 + */ 1.159 + void UpdateStyleSheet(nsIContent* aElement); 1.160 + 1.161 + void SetDocumentMode(nsHtml5DocumentMode m); 1.162 + 1.163 + void SetNodeInfoManager(nsNodeInfoManager* aManager) 1.164 + { 1.165 + mNodeInfoManager = aManager; 1.166 + } 1.167 + 1.168 + // nsContentSink methods 1.169 + virtual void UpdateChildCounts(); 1.170 + virtual nsresult FlushTags(); 1.171 + 1.172 +protected: 1.173 + inline void SetAppendBatchCapacity(uint32_t aCapacity) 1.174 + { 1.175 + mElementsSeenInThisAppendBatch.SetCapacity(aCapacity); 1.176 + } 1.177 + 1.178 + nsHtml5DocumentBuilder(bool aRunsToCompletion); 1.179 + virtual ~nsHtml5DocumentBuilder(); 1.180 + 1.181 +private: 1.182 + nsTArray<nsHtml5PendingNotification> mPendingNotifications; 1.183 + nsTArray<nsIContentPtr> mElementsSeenInThisAppendBatch; 1.184 +protected: 1.185 + nsTArray<nsCOMPtr<nsIContent> > mOwnedElements; 1.186 + /** 1.187 + * Non-NS_OK if this parser should refuse to process any more input. 1.188 + * For example, the parser needs to be marked as broken if it drops some 1.189 + * input due to a memory allocation failure. In such a case, the whole 1.190 + * parser needs to be marked as broken, because some input has been lost 1.191 + * and parsing more input could lead to a DOM where pieces of HTML source 1.192 + * that weren't supposed to become scripts become scripts. 1.193 + * 1.194 + * Since NS_OK is actually 0, zeroing operator new takes care of 1.195 + * initializing this. 1.196 + */ 1.197 + nsresult mBroken; 1.198 + eHtml5FlushState mFlushState; 1.199 +}; 1.200 + 1.201 +#endif // nsHtml5DocumentBuilder_h