Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef nsHtml5DocumentBuilder_h
8 #define nsHtml5DocumentBuilder_h
10 #include "nsHtml5PendingNotification.h"
11 #include "nsContentSink.h"
12 #include "nsHtml5DocumentMode.h"
13 #include "nsIDocument.h"
15 typedef nsIContent* nsIContentPtr;
17 enum eHtml5FlushState {
18 eNotFlushing = 0, // not flushing
19 eInFlush = 1, // the Flush() method is on the call stack
20 eInDocUpdate = 2, // inside an update batch on the document
21 eNotifying = 3 // flushing pending append notifications
22 };
24 class nsHtml5DocumentBuilder : public nsContentSink
25 {
26 public:
27 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHtml5DocumentBuilder,
28 nsContentSink)
30 NS_DECL_ISUPPORTS_INHERITED
32 inline void HoldElement(nsIContent* aContent)
33 {
34 mOwnedElements.AppendElement(aContent);
35 }
37 inline bool HaveNotified(nsIContent* aNode)
38 {
39 NS_PRECONDITION(aNode, "HaveNotified called with null argument.");
40 const nsHtml5PendingNotification* start = mPendingNotifications.Elements();
41 const nsHtml5PendingNotification* end = start + mPendingNotifications.Length();
42 for (;;) {
43 nsIContent* parent = aNode->GetParent();
44 if (!parent) {
45 return true;
46 }
47 for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) {
48 if (iter->Contains(parent)) {
49 return iter->HaveNotifiedIndex(parent->IndexOf(aNode));
50 }
51 }
52 aNode = parent;
53 }
54 }
56 void PostPendingAppendNotification(nsIContent* aParent, nsIContent* aChild)
57 {
58 bool newParent = true;
59 const nsIContentPtr* first = mElementsSeenInThisAppendBatch.Elements();
60 const nsIContentPtr* last = first + mElementsSeenInThisAppendBatch.Length() - 1;
61 for (const nsIContentPtr* iter = last; iter >= first; --iter) {
62 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
63 sAppendBatchSlotsExamined++;
64 #endif
65 if (*iter == aParent) {
66 newParent = false;
67 break;
68 }
69 }
70 if (aChild->IsElement()) {
71 mElementsSeenInThisAppendBatch.AppendElement(aChild);
72 }
73 mElementsSeenInThisAppendBatch.AppendElement(aParent);
74 if (newParent) {
75 mPendingNotifications.AppendElement(aParent);
76 }
77 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
78 sAppendBatchExaminations++;
79 #endif
80 }
82 void FlushPendingAppendNotifications()
83 {
84 NS_PRECONDITION(mFlushState == eInDocUpdate, "Notifications flushed outside update");
85 mFlushState = eNotifying;
86 const nsHtml5PendingNotification* start = mPendingNotifications.Elements();
87 const nsHtml5PendingNotification* end = start + mPendingNotifications.Length();
88 for (nsHtml5PendingNotification* iter = (nsHtml5PendingNotification*)start; iter < end; ++iter) {
89 iter->Fire();
90 }
91 mPendingNotifications.Clear();
92 #ifdef DEBUG_NS_HTML5_TREE_OP_EXECUTOR_FLUSH
93 if (mElementsSeenInThisAppendBatch.Length() > sAppendBatchMaxSize) {
94 sAppendBatchMaxSize = mElementsSeenInThisAppendBatch.Length();
95 }
96 #endif
97 mElementsSeenInThisAppendBatch.Clear();
98 NS_ASSERTION(mFlushState == eNotifying, "mFlushState out of sync");
99 mFlushState = eInDocUpdate;
100 }
102 nsresult Init(nsIDocument* aDoc, nsIURI* aURI,
103 nsISupports* aContainer, nsIChannel* aChannel);
105 // Getters and setters for fields from nsContentSink
106 nsIDocument* GetDocument()
107 {
108 return mDocument;
109 }
111 nsNodeInfoManager* GetNodeInfoManager()
112 {
113 return mNodeInfoManager;
114 }
116 /**
117 * Marks this parser as broken and tells the stream parser (if any) to
118 * terminate.
119 *
120 * @return aReason for convenience
121 */
122 virtual nsresult MarkAsBroken(nsresult aReason);
124 /**
125 * Checks if this parser is broken. Returns a non-NS_OK (i.e. non-0)
126 * value if broken.
127 */
128 inline nsresult IsBroken()
129 {
130 return mBroken;
131 }
133 inline void BeginDocUpdate()
134 {
135 NS_PRECONDITION(mFlushState == eInFlush, "Tried to double-open update.");
136 NS_PRECONDITION(mParser, "Started update without parser.");
137 mFlushState = eInDocUpdate;
138 mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
139 }
141 inline void EndDocUpdate()
142 {
143 NS_PRECONDITION(mFlushState != eNotifying, "mFlushState out of sync");
144 if (mFlushState == eInDocUpdate) {
145 FlushPendingAppendNotifications();
146 mFlushState = eInFlush;
147 mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
148 }
149 }
151 void SetDocumentCharsetAndSource(nsACString& aCharset, int32_t aCharsetSource);
153 /**
154 * Sets up style sheet load / parse
155 */
156 void UpdateStyleSheet(nsIContent* aElement);
158 void SetDocumentMode(nsHtml5DocumentMode m);
160 void SetNodeInfoManager(nsNodeInfoManager* aManager)
161 {
162 mNodeInfoManager = aManager;
163 }
165 // nsContentSink methods
166 virtual void UpdateChildCounts();
167 virtual nsresult FlushTags();
169 protected:
170 inline void SetAppendBatchCapacity(uint32_t aCapacity)
171 {
172 mElementsSeenInThisAppendBatch.SetCapacity(aCapacity);
173 }
175 nsHtml5DocumentBuilder(bool aRunsToCompletion);
176 virtual ~nsHtml5DocumentBuilder();
178 private:
179 nsTArray<nsHtml5PendingNotification> mPendingNotifications;
180 nsTArray<nsIContentPtr> mElementsSeenInThisAppendBatch;
181 protected:
182 nsTArray<nsCOMPtr<nsIContent> > mOwnedElements;
183 /**
184 * Non-NS_OK if this parser should refuse to process any more input.
185 * For example, the parser needs to be marked as broken if it drops some
186 * input due to a memory allocation failure. In such a case, the whole
187 * parser needs to be marked as broken, because some input has been lost
188 * and parsing more input could lead to a DOM where pieces of HTML source
189 * that weren't supposed to become scripts become scripts.
190 *
191 * Since NS_OK is actually 0, zeroing operator new takes care of
192 * initializing this.
193 */
194 nsresult mBroken;
195 eHtml5FlushState mFlushState;
196 };
198 #endif // nsHtml5DocumentBuilder_h