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