|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #ifndef nsHtml5TreeOperation_h |
|
6 #define nsHtml5TreeOperation_h |
|
7 |
|
8 #include "nsHtml5DocumentMode.h" |
|
9 #include "nsHtml5HtmlAttributes.h" |
|
10 #include "nsXPCOMStrings.h" |
|
11 #include "mozilla/dom/FromParser.h" |
|
12 |
|
13 class nsIContent; |
|
14 class nsHtml5TreeOpExecutor; |
|
15 class nsHtml5StateSnapshot; |
|
16 class nsHtml5DocumentBuilder; |
|
17 |
|
18 enum eHtml5TreeOperation { |
|
19 #ifdef DEBUG |
|
20 eTreeOpUninitialized, |
|
21 #endif |
|
22 // main HTML5 ops |
|
23 eTreeOpAppend, |
|
24 eTreeOpDetach, |
|
25 eTreeOpAppendChildrenToNewParent, |
|
26 eTreeOpFosterParent, |
|
27 eTreeOpAppendToDocument, |
|
28 eTreeOpAddAttributes, |
|
29 eTreeOpDocumentMode, |
|
30 eTreeOpCreateElementNetwork, |
|
31 eTreeOpCreateElementNotNetwork, |
|
32 eTreeOpSetFormElement, |
|
33 eTreeOpAppendText, |
|
34 eTreeOpAppendIsindexPrompt, |
|
35 eTreeOpFosterParentText, |
|
36 eTreeOpAppendComment, |
|
37 eTreeOpAppendCommentToDocument, |
|
38 eTreeOpAppendDoctypeToDocument, |
|
39 eTreeOpGetDocumentFragmentForTemplate, |
|
40 // Gecko-specific on-pop ops |
|
41 eTreeOpMarkAsBroken, |
|
42 eTreeOpRunScript, |
|
43 eTreeOpRunScriptAsyncDefer, |
|
44 eTreeOpPreventScriptExecution, |
|
45 eTreeOpDoneAddingChildren, |
|
46 eTreeOpDoneCreatingElement, |
|
47 eTreeOpFlushPendingAppendNotifications, |
|
48 eTreeOpSetDocumentCharset, |
|
49 eTreeOpNeedsCharsetSwitchTo, |
|
50 eTreeOpUpdateStyleSheet, |
|
51 eTreeOpProcessMeta, |
|
52 eTreeOpProcessOfflineManifest, |
|
53 eTreeOpMarkMalformedIfScript, |
|
54 eTreeOpStreamEnded, |
|
55 eTreeOpSetStyleLineNumber, |
|
56 eTreeOpSetScriptLineNumberAndFreeze, |
|
57 eTreeOpSvgLoad, |
|
58 eTreeOpMaybeComplainAboutCharset, |
|
59 eTreeOpAddClass, |
|
60 eTreeOpAddViewSourceHref, |
|
61 eTreeOpAddError, |
|
62 eTreeOpAddLineNumberId, |
|
63 eTreeOpAddErrorAtom, |
|
64 eTreeOpAddErrorTwoAtoms, |
|
65 eTreeOpStartLayout |
|
66 }; |
|
67 |
|
68 class nsHtml5TreeOperationStringPair { |
|
69 private: |
|
70 nsString mPublicId; |
|
71 nsString mSystemId; |
|
72 public: |
|
73 nsHtml5TreeOperationStringPair(const nsAString& aPublicId, |
|
74 const nsAString& aSystemId) |
|
75 : mPublicId(aPublicId) |
|
76 , mSystemId(aSystemId) |
|
77 { |
|
78 MOZ_COUNT_CTOR(nsHtml5TreeOperationStringPair); |
|
79 } |
|
80 |
|
81 ~nsHtml5TreeOperationStringPair() |
|
82 { |
|
83 MOZ_COUNT_DTOR(nsHtml5TreeOperationStringPair); |
|
84 } |
|
85 |
|
86 inline void Get(nsAString& aPublicId, nsAString& aSystemId) |
|
87 { |
|
88 aPublicId.Assign(mPublicId); |
|
89 aSystemId.Assign(mSystemId); |
|
90 } |
|
91 }; |
|
92 |
|
93 class nsHtml5TreeOperation { |
|
94 |
|
95 public: |
|
96 /** |
|
97 * Atom is used inside the parser core are either static atoms that are |
|
98 * the same as Gecko-wide static atoms or they are dynamic atoms scoped by |
|
99 * both thread and parser to a particular nsHtml5AtomTable. In order to |
|
100 * such scoped atoms coming into contact with the rest of Gecko, atoms |
|
101 * that are about to exit the parser must go through this method which |
|
102 * reobtains dynamic atoms from the Gecko-global atom table. |
|
103 * |
|
104 * @param aAtom a potentially parser-scoped atom |
|
105 * @return an nsIAtom that's pointer comparable on the main thread with |
|
106 * other not-parser atoms. |
|
107 */ |
|
108 static inline already_AddRefed<nsIAtom> Reget(nsIAtom* aAtom) |
|
109 { |
|
110 if (!aAtom || aAtom->IsStaticAtom()) { |
|
111 return dont_AddRef(aAtom); |
|
112 } |
|
113 nsAutoString str; |
|
114 aAtom->ToString(str); |
|
115 return do_GetAtom(str); |
|
116 } |
|
117 |
|
118 static nsresult AppendTextToTextNode(const char16_t* aBuffer, |
|
119 uint32_t aLength, |
|
120 nsIContent* aTextNode, |
|
121 nsHtml5DocumentBuilder* aBuilder); |
|
122 |
|
123 static nsresult AppendText(const char16_t* aBuffer, |
|
124 uint32_t aLength, |
|
125 nsIContent* aParent, |
|
126 nsHtml5DocumentBuilder* aBuilder); |
|
127 |
|
128 static nsresult Append(nsIContent* aNode, |
|
129 nsIContent* aParent, |
|
130 nsHtml5DocumentBuilder* aBuilder); |
|
131 |
|
132 static nsresult AppendToDocument(nsIContent* aNode, |
|
133 nsHtml5DocumentBuilder* aBuilder); |
|
134 |
|
135 static void Detach(nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder); |
|
136 |
|
137 static nsresult AppendChildrenToNewParent(nsIContent* aNode, |
|
138 nsIContent* aParent, |
|
139 nsHtml5DocumentBuilder* aBuilder); |
|
140 |
|
141 static nsresult FosterParent(nsIContent* aNode, |
|
142 nsIContent* aParent, |
|
143 nsIContent* aTable, |
|
144 nsHtml5DocumentBuilder* aBuilder); |
|
145 |
|
146 static nsresult AddAttributes(nsIContent* aNode, |
|
147 nsHtml5HtmlAttributes* aAttributes, |
|
148 nsHtml5DocumentBuilder* aBuilder); |
|
149 |
|
150 static nsIContent* CreateElement(int32_t aNs, |
|
151 nsIAtom* aName, |
|
152 nsHtml5HtmlAttributes* aAttributes, |
|
153 mozilla::dom::FromParser aFromParser, |
|
154 nsHtml5DocumentBuilder* aBuilder); |
|
155 |
|
156 static void SetFormElement(nsIContent* aNode, nsIContent* aParent); |
|
157 |
|
158 static nsresult AppendIsindexPrompt(nsIContent* parent, |
|
159 nsHtml5DocumentBuilder* aBuilder); |
|
160 |
|
161 static nsresult FosterParentText(nsIContent* aStackParent, |
|
162 char16_t* aBuffer, |
|
163 uint32_t aLength, |
|
164 nsIContent* aTable, |
|
165 nsHtml5DocumentBuilder* aBuilder); |
|
166 |
|
167 static nsresult AppendComment(nsIContent* aParent, |
|
168 char16_t* aBuffer, |
|
169 int32_t aLength, |
|
170 nsHtml5DocumentBuilder* aBuilder); |
|
171 |
|
172 static nsresult AppendCommentToDocument(char16_t* aBuffer, |
|
173 int32_t aLength, |
|
174 nsHtml5DocumentBuilder* aBuilder); |
|
175 |
|
176 static nsresult AppendDoctypeToDocument(nsIAtom* aName, |
|
177 const nsAString& aPublicId, |
|
178 const nsAString& aSystemId, |
|
179 nsHtml5DocumentBuilder* aBuilder); |
|
180 |
|
181 static nsIContent* GetDocumentFragmentForTemplate(nsIContent* aNode); |
|
182 |
|
183 static void PreventScriptExecution(nsIContent* aNode); |
|
184 |
|
185 static void DoneAddingChildren(nsIContent* aNode, |
|
186 nsHtml5DocumentBuilder* aBuilder); |
|
187 |
|
188 static void DoneCreatingElement(nsIContent* aNode); |
|
189 |
|
190 static void SvgLoad(nsIContent* aNode); |
|
191 |
|
192 static void MarkMalformedIfScript(nsIContent* aNode); |
|
193 |
|
194 nsHtml5TreeOperation(); |
|
195 |
|
196 ~nsHtml5TreeOperation(); |
|
197 |
|
198 inline void Init(eHtml5TreeOperation aOpCode) |
|
199 { |
|
200 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
201 "Op code must be uninitialized when initializing."); |
|
202 mOpCode = aOpCode; |
|
203 } |
|
204 |
|
205 inline void Init(eHtml5TreeOperation aOpCode, nsIContentHandle* aNode) |
|
206 { |
|
207 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
208 "Op code must be uninitialized when initializing."); |
|
209 NS_PRECONDITION(aNode, "Initialized tree op with null node."); |
|
210 mOpCode = aOpCode; |
|
211 mOne.node = static_cast<nsIContent**>(aNode); |
|
212 } |
|
213 |
|
214 inline void Init(eHtml5TreeOperation aOpCode, |
|
215 nsIContentHandle* aNode, |
|
216 nsIContentHandle* aParent) |
|
217 { |
|
218 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
219 "Op code must be uninitialized when initializing."); |
|
220 NS_PRECONDITION(aNode, "Initialized tree op with null node."); |
|
221 NS_PRECONDITION(aParent, "Initialized tree op with null parent."); |
|
222 mOpCode = aOpCode; |
|
223 mOne.node = static_cast<nsIContent**>(aNode); |
|
224 mTwo.node = static_cast<nsIContent**>(aParent); |
|
225 } |
|
226 |
|
227 inline void Init(eHtml5TreeOperation aOpCode, |
|
228 const nsACString& aString, |
|
229 int32_t aInt32) |
|
230 { |
|
231 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
232 "Op code must be uninitialized when initializing."); |
|
233 |
|
234 int32_t len = aString.Length(); |
|
235 char* str = new char[len + 1]; |
|
236 const char* start = aString.BeginReading(); |
|
237 for (int32_t i = 0; i < len; ++i) { |
|
238 str[i] = start[i]; |
|
239 } |
|
240 str[len] = '\0'; |
|
241 |
|
242 mOpCode = aOpCode; |
|
243 mOne.charPtr = str; |
|
244 mFour.integer = aInt32; |
|
245 } |
|
246 |
|
247 inline void Init(eHtml5TreeOperation aOpCode, |
|
248 const nsACString& aString, |
|
249 int32_t aInt32, |
|
250 int32_t aLineNumber) |
|
251 { |
|
252 Init(aOpCode, aString, aInt32); |
|
253 mTwo.integer = aLineNumber; |
|
254 } |
|
255 |
|
256 inline void Init(eHtml5TreeOperation aOpCode, |
|
257 nsIContentHandle* aNode, |
|
258 nsIContentHandle* aParent, |
|
259 nsIContentHandle* aTable) |
|
260 { |
|
261 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
262 "Op code must be uninitialized when initializing."); |
|
263 NS_PRECONDITION(aNode, "Initialized tree op with null node."); |
|
264 NS_PRECONDITION(aParent, "Initialized tree op with null parent."); |
|
265 NS_PRECONDITION(aTable, "Initialized tree op with null table."); |
|
266 mOpCode = aOpCode; |
|
267 mOne.node = static_cast<nsIContent**>(aNode); |
|
268 mTwo.node = static_cast<nsIContent**>(aParent); |
|
269 mThree.node = static_cast<nsIContent**>(aTable); |
|
270 } |
|
271 |
|
272 inline void Init(nsHtml5DocumentMode aMode) |
|
273 { |
|
274 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
275 "Op code must be uninitialized when initializing."); |
|
276 mOpCode = eTreeOpDocumentMode; |
|
277 mOne.mode = aMode; |
|
278 } |
|
279 |
|
280 inline void InitScript(nsIContentHandle* aNode) |
|
281 { |
|
282 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
283 "Op code must be uninitialized when initializing."); |
|
284 NS_PRECONDITION(aNode, "Initialized tree op with null node."); |
|
285 mOpCode = eTreeOpRunScript; |
|
286 mOne.node = static_cast<nsIContent**>(aNode); |
|
287 mTwo.state = nullptr; |
|
288 } |
|
289 |
|
290 inline void Init(int32_t aNamespace, |
|
291 nsIAtom* aName, |
|
292 nsHtml5HtmlAttributes* aAttributes, |
|
293 nsIContentHandle* aTarget, |
|
294 bool aFromNetwork) |
|
295 { |
|
296 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
297 "Op code must be uninitialized when initializing."); |
|
298 NS_PRECONDITION(aName, "Initialized tree op with null name."); |
|
299 NS_PRECONDITION(aTarget, "Initialized tree op with null target node."); |
|
300 mOpCode = aFromNetwork ? |
|
301 eTreeOpCreateElementNetwork : |
|
302 eTreeOpCreateElementNotNetwork; |
|
303 mFour.integer = aNamespace; |
|
304 mOne.node = static_cast<nsIContent**>(aTarget); |
|
305 mTwo.atom = aName; |
|
306 if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) { |
|
307 mThree.attributes = nullptr; |
|
308 } else { |
|
309 mThree.attributes = aAttributes; |
|
310 } |
|
311 } |
|
312 |
|
313 inline void Init(eHtml5TreeOperation aOpCode, |
|
314 char16_t* aBuffer, |
|
315 int32_t aLength, |
|
316 nsIContentHandle* aStackParent, |
|
317 nsIContentHandle* aTable) |
|
318 { |
|
319 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
320 "Op code must be uninitialized when initializing."); |
|
321 NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer."); |
|
322 mOpCode = aOpCode; |
|
323 mOne.node = static_cast<nsIContent**>(aStackParent); |
|
324 mTwo.unicharPtr = aBuffer; |
|
325 mThree.node = static_cast<nsIContent**>(aTable); |
|
326 mFour.integer = aLength; |
|
327 } |
|
328 |
|
329 inline void Init(eHtml5TreeOperation aOpCode, |
|
330 char16_t* aBuffer, |
|
331 int32_t aLength, |
|
332 nsIContentHandle* aParent) |
|
333 { |
|
334 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
335 "Op code must be uninitialized when initializing."); |
|
336 NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer."); |
|
337 mOpCode = aOpCode; |
|
338 mOne.node = static_cast<nsIContent**>(aParent); |
|
339 mTwo.unicharPtr = aBuffer; |
|
340 mFour.integer = aLength; |
|
341 } |
|
342 |
|
343 inline void Init(eHtml5TreeOperation aOpCode, |
|
344 char16_t* aBuffer, |
|
345 int32_t aLength) |
|
346 { |
|
347 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
348 "Op code must be uninitialized when initializing."); |
|
349 NS_PRECONDITION(aBuffer, "Initialized tree op with null buffer."); |
|
350 mOpCode = aOpCode; |
|
351 mTwo.unicharPtr = aBuffer; |
|
352 mFour.integer = aLength; |
|
353 } |
|
354 |
|
355 inline void Init(nsIContentHandle* aElement, |
|
356 nsHtml5HtmlAttributes* aAttributes) |
|
357 { |
|
358 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
359 "Op code must be uninitialized when initializing."); |
|
360 NS_PRECONDITION(aElement, "Initialized tree op with null element."); |
|
361 mOpCode = eTreeOpAddAttributes; |
|
362 mOne.node = static_cast<nsIContent**>(aElement); |
|
363 mTwo.attributes = aAttributes; |
|
364 } |
|
365 |
|
366 inline void Init(nsIAtom* aName, |
|
367 const nsAString& aPublicId, |
|
368 const nsAString& aSystemId) |
|
369 { |
|
370 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
371 "Op code must be uninitialized when initializing."); |
|
372 mOpCode = eTreeOpAppendDoctypeToDocument; |
|
373 mOne.atom = aName; |
|
374 mTwo.stringPair = new nsHtml5TreeOperationStringPair(aPublicId, aSystemId); |
|
375 } |
|
376 |
|
377 inline void Init(nsIContentHandle* aElement, |
|
378 const char* aMsgId, |
|
379 nsIAtom* aAtom, |
|
380 nsIAtom* aOtherAtom) |
|
381 { |
|
382 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
383 "Op code must be uninitialized when initializing."); |
|
384 mOpCode = eTreeOpAddError; |
|
385 mOne.node = static_cast<nsIContent**>(aElement); |
|
386 mTwo.charPtr = (char*)aMsgId; |
|
387 mThree.atom = aAtom; |
|
388 mFour.atom = aOtherAtom; |
|
389 } |
|
390 |
|
391 inline void Init(nsIContentHandle* aElement, |
|
392 const char* aMsgId, |
|
393 nsIAtom* aAtom) |
|
394 { |
|
395 Init(aElement, aMsgId, aAtom, nullptr); |
|
396 } |
|
397 |
|
398 inline void Init(nsIContentHandle* aElement, |
|
399 const char* aMsgId) |
|
400 { |
|
401 Init(aElement, aMsgId, nullptr, nullptr); |
|
402 } |
|
403 |
|
404 inline void Init(const char* aMsgId, |
|
405 bool aError, |
|
406 int32_t aLineNumber) |
|
407 { |
|
408 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
409 "Op code must be uninitialized when initializing."); |
|
410 mOpCode = eTreeOpMaybeComplainAboutCharset; |
|
411 mOne.charPtr = const_cast<char*>(aMsgId); |
|
412 mTwo.integer = aError; |
|
413 mThree.integer = aLineNumber; |
|
414 } |
|
415 |
|
416 inline void Init(eHtml5TreeOperation aOpCode, const nsAString& aString) |
|
417 { |
|
418 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
419 "Op code must be uninitialized when initializing."); |
|
420 |
|
421 char16_t* str = NS_StringCloneData(aString); |
|
422 mOpCode = aOpCode; |
|
423 mOne.unicharPtr = str; |
|
424 } |
|
425 |
|
426 inline void Init(eHtml5TreeOperation aOpCode, |
|
427 nsIContentHandle* aNode, |
|
428 int32_t aInt) |
|
429 { |
|
430 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
431 "Op code must be uninitialized when initializing."); |
|
432 NS_PRECONDITION(aNode, "Initialized tree op with null node."); |
|
433 mOpCode = aOpCode; |
|
434 mOne.node = static_cast<nsIContent**>(aNode); |
|
435 mFour.integer = aInt; |
|
436 } |
|
437 |
|
438 inline void Init(nsresult aRv) |
|
439 { |
|
440 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
441 "Op code must be uninitialized when initializing."); |
|
442 NS_PRECONDITION(NS_FAILED(aRv), "Initialized tree op with non-failure."); |
|
443 mOpCode = eTreeOpMarkAsBroken; |
|
444 mOne.result = aRv; |
|
445 } |
|
446 |
|
447 inline void InitAddClass(nsIContentHandle* aNode, const char16_t* aClass) |
|
448 { |
|
449 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
450 "Op code must be uninitialized when initializing."); |
|
451 NS_PRECONDITION(aNode, "Initialized tree op with null node."); |
|
452 NS_PRECONDITION(aClass, "Initialized tree op with null string."); |
|
453 // aClass must be a literal string that does not need freeing |
|
454 mOpCode = eTreeOpAddClass; |
|
455 mOne.node = static_cast<nsIContent**>(aNode); |
|
456 mTwo.unicharPtr = (char16_t*)aClass; |
|
457 } |
|
458 |
|
459 inline void InitAddLineNumberId(nsIContentHandle* aNode, |
|
460 const int32_t aLineNumber) |
|
461 { |
|
462 NS_PRECONDITION(mOpCode == eTreeOpUninitialized, |
|
463 "Op code must be uninitialized when initializing."); |
|
464 NS_PRECONDITION(aNode, "Initialized tree op with null node."); |
|
465 NS_PRECONDITION(aLineNumber > 0, "Initialized tree op with line number."); |
|
466 // aClass must be a literal string that does not need freeing |
|
467 mOpCode = eTreeOpAddLineNumberId; |
|
468 mOne.node = static_cast<nsIContent**>(aNode); |
|
469 mFour.integer = aLineNumber; |
|
470 } |
|
471 |
|
472 inline bool IsRunScript() |
|
473 { |
|
474 return mOpCode == eTreeOpRunScript; |
|
475 } |
|
476 |
|
477 inline void SetSnapshot(nsAHtml5TreeBuilderState* aSnapshot, int32_t aLine) |
|
478 { |
|
479 NS_ASSERTION(IsRunScript(), |
|
480 "Setting a snapshot for a tree operation other than eTreeOpRunScript!"); |
|
481 NS_PRECONDITION(aSnapshot, "Initialized tree op with null snapshot."); |
|
482 mTwo.state = aSnapshot; |
|
483 mFour.integer = aLine; |
|
484 } |
|
485 |
|
486 nsresult Perform(nsHtml5TreeOpExecutor* aBuilder, |
|
487 nsIContent** aScriptElement); |
|
488 |
|
489 private: |
|
490 // possible optimization: |
|
491 // Make the queue take items the size of pointer and make the op code |
|
492 // decide how many operands it dequeues after it. |
|
493 eHtml5TreeOperation mOpCode; |
|
494 union { |
|
495 nsIContent** node; |
|
496 nsIAtom* atom; |
|
497 nsHtml5HtmlAttributes* attributes; |
|
498 nsHtml5DocumentMode mode; |
|
499 char16_t* unicharPtr; |
|
500 char* charPtr; |
|
501 nsHtml5TreeOperationStringPair* stringPair; |
|
502 nsAHtml5TreeBuilderState* state; |
|
503 int32_t integer; |
|
504 nsresult result; |
|
505 } mOne, mTwo, mThree, mFour; |
|
506 }; |
|
507 |
|
508 #endif // nsHtml5TreeOperation_h |