Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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/. */
5 #ifndef nsHtml5TreeOperation_h
6 #define nsHtml5TreeOperation_h
8 #include "nsHtml5DocumentMode.h"
9 #include "nsHtml5HtmlAttributes.h"
10 #include "nsXPCOMStrings.h"
11 #include "mozilla/dom/FromParser.h"
13 class nsIContent;
14 class nsHtml5TreeOpExecutor;
15 class nsHtml5StateSnapshot;
16 class nsHtml5DocumentBuilder;
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 };
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 }
81 ~nsHtml5TreeOperationStringPair()
82 {
83 MOZ_COUNT_DTOR(nsHtml5TreeOperationStringPair);
84 }
86 inline void Get(nsAString& aPublicId, nsAString& aSystemId)
87 {
88 aPublicId.Assign(mPublicId);
89 aSystemId.Assign(mSystemId);
90 }
91 };
93 class nsHtml5TreeOperation {
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 }
118 static nsresult AppendTextToTextNode(const char16_t* aBuffer,
119 uint32_t aLength,
120 nsIContent* aTextNode,
121 nsHtml5DocumentBuilder* aBuilder);
123 static nsresult AppendText(const char16_t* aBuffer,
124 uint32_t aLength,
125 nsIContent* aParent,
126 nsHtml5DocumentBuilder* aBuilder);
128 static nsresult Append(nsIContent* aNode,
129 nsIContent* aParent,
130 nsHtml5DocumentBuilder* aBuilder);
132 static nsresult AppendToDocument(nsIContent* aNode,
133 nsHtml5DocumentBuilder* aBuilder);
135 static void Detach(nsIContent* aNode, nsHtml5DocumentBuilder* aBuilder);
137 static nsresult AppendChildrenToNewParent(nsIContent* aNode,
138 nsIContent* aParent,
139 nsHtml5DocumentBuilder* aBuilder);
141 static nsresult FosterParent(nsIContent* aNode,
142 nsIContent* aParent,
143 nsIContent* aTable,
144 nsHtml5DocumentBuilder* aBuilder);
146 static nsresult AddAttributes(nsIContent* aNode,
147 nsHtml5HtmlAttributes* aAttributes,
148 nsHtml5DocumentBuilder* aBuilder);
150 static nsIContent* CreateElement(int32_t aNs,
151 nsIAtom* aName,
152 nsHtml5HtmlAttributes* aAttributes,
153 mozilla::dom::FromParser aFromParser,
154 nsHtml5DocumentBuilder* aBuilder);
156 static void SetFormElement(nsIContent* aNode, nsIContent* aParent);
158 static nsresult AppendIsindexPrompt(nsIContent* parent,
159 nsHtml5DocumentBuilder* aBuilder);
161 static nsresult FosterParentText(nsIContent* aStackParent,
162 char16_t* aBuffer,
163 uint32_t aLength,
164 nsIContent* aTable,
165 nsHtml5DocumentBuilder* aBuilder);
167 static nsresult AppendComment(nsIContent* aParent,
168 char16_t* aBuffer,
169 int32_t aLength,
170 nsHtml5DocumentBuilder* aBuilder);
172 static nsresult AppendCommentToDocument(char16_t* aBuffer,
173 int32_t aLength,
174 nsHtml5DocumentBuilder* aBuilder);
176 static nsresult AppendDoctypeToDocument(nsIAtom* aName,
177 const nsAString& aPublicId,
178 const nsAString& aSystemId,
179 nsHtml5DocumentBuilder* aBuilder);
181 static nsIContent* GetDocumentFragmentForTemplate(nsIContent* aNode);
183 static void PreventScriptExecution(nsIContent* aNode);
185 static void DoneAddingChildren(nsIContent* aNode,
186 nsHtml5DocumentBuilder* aBuilder);
188 static void DoneCreatingElement(nsIContent* aNode);
190 static void SvgLoad(nsIContent* aNode);
192 static void MarkMalformedIfScript(nsIContent* aNode);
194 nsHtml5TreeOperation();
196 ~nsHtml5TreeOperation();
198 inline void Init(eHtml5TreeOperation aOpCode)
199 {
200 NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
201 "Op code must be uninitialized when initializing.");
202 mOpCode = aOpCode;
203 }
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 }
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 }
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.");
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';
242 mOpCode = aOpCode;
243 mOne.charPtr = str;
244 mFour.integer = aInt32;
245 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
391 inline void Init(nsIContentHandle* aElement,
392 const char* aMsgId,
393 nsIAtom* aAtom)
394 {
395 Init(aElement, aMsgId, aAtom, nullptr);
396 }
398 inline void Init(nsIContentHandle* aElement,
399 const char* aMsgId)
400 {
401 Init(aElement, aMsgId, nullptr, nullptr);
402 }
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 }
416 inline void Init(eHtml5TreeOperation aOpCode, const nsAString& aString)
417 {
418 NS_PRECONDITION(mOpCode == eTreeOpUninitialized,
419 "Op code must be uninitialized when initializing.");
421 char16_t* str = NS_StringCloneData(aString);
422 mOpCode = aOpCode;
423 mOne.unicharPtr = str;
424 }
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 }
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 }
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 }
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 }
472 inline bool IsRunScript()
473 {
474 return mOpCode == eTreeOpRunScript;
475 }
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 }
486 nsresult Perform(nsHtml5TreeOpExecutor* aBuilder,
487 nsIContent** aScriptElement);
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 };
508 #endif // nsHtml5TreeOperation_h