/src/mozilla-central/parser/html/nsHtml5TreeBuilderCppSupplement.h
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | #include "nsError.h" |
8 | | #include "nsIPresShell.h" |
9 | | #include "nsNodeUtils.h" |
10 | | #include "nsIFrame.h" |
11 | | #include "mozilla/CheckedInt.h" |
12 | | #include "mozilla/Likely.h" |
13 | | #include "mozilla/UniquePtr.h" |
14 | | |
15 | | nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsHtml5OplessBuilder* aBuilder) |
16 | | : mode(0) |
17 | | , originalMode(0) |
18 | | , framesetOk(false) |
19 | | , tokenizer(nullptr) |
20 | | , scriptingEnabled(false) |
21 | | , needToDropLF(false) |
22 | | , fragment(false) |
23 | | , contextName(nullptr) |
24 | | , contextNamespace(kNameSpaceID_None) |
25 | | , contextNode(nullptr) |
26 | | , templateModePtr(0) |
27 | | , stackNodesIdx(0) |
28 | | , numStackNodes(0) |
29 | | , currentPtr(0) |
30 | | , listPtr(0) |
31 | | , formPointer(nullptr) |
32 | | , headPointer(nullptr) |
33 | | , deepTreeSurrogateParent(nullptr) |
34 | | , charBufferLen(0) |
35 | | , quirks(false) |
36 | | , isSrcdocDocument(false) |
37 | | , mBuilder(aBuilder) |
38 | | , mViewSource(nullptr) |
39 | | , mOpSink(nullptr) |
40 | | , mHandles(nullptr) |
41 | | , mHandlesUsed(0) |
42 | | , mSpeculativeLoadStage(nullptr) |
43 | | , mBroken(NS_OK) |
44 | | , mCurrentHtmlScriptIsAsyncOrDefer(false) |
45 | | , mPreventScriptExecution(false) |
46 | | #ifdef DEBUG |
47 | | , mActive(false) |
48 | | #endif |
49 | 0 | { |
50 | 0 | MOZ_COUNT_CTOR(nsHtml5TreeBuilder); |
51 | 0 | } |
52 | | |
53 | | nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink* aOpSink, |
54 | | nsHtml5TreeOpStage* aStage) |
55 | | : mode(0) |
56 | | , originalMode(0) |
57 | | , framesetOk(false) |
58 | | , tokenizer(nullptr) |
59 | | , scriptingEnabled(false) |
60 | | , needToDropLF(false) |
61 | | , fragment(false) |
62 | | , contextName(nullptr) |
63 | | , contextNamespace(kNameSpaceID_None) |
64 | | , contextNode(nullptr) |
65 | | , templateModePtr(0) |
66 | | , stackNodesIdx(0) |
67 | | , numStackNodes(0) |
68 | | , currentPtr(0) |
69 | | , listPtr(0) |
70 | | , formPointer(nullptr) |
71 | | , headPointer(nullptr) |
72 | | , deepTreeSurrogateParent(nullptr) |
73 | | , charBufferLen(0) |
74 | | , quirks(false) |
75 | | , isSrcdocDocument(false) |
76 | | , mBuilder(nullptr) |
77 | | , mViewSource(nullptr) |
78 | | , mOpSink(aOpSink) |
79 | | , mHandles(new nsIContent*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH]) |
80 | | , mHandlesUsed(0) |
81 | | , mSpeculativeLoadStage(aStage) |
82 | | , mBroken(NS_OK) |
83 | | , mCurrentHtmlScriptIsAsyncOrDefer(false) |
84 | | , mPreventScriptExecution(false) |
85 | | #ifdef DEBUG |
86 | | , mActive(false) |
87 | | #endif |
88 | 0 | { |
89 | 0 | MOZ_COUNT_CTOR(nsHtml5TreeBuilder); |
90 | 0 | } |
91 | | |
92 | | nsHtml5TreeBuilder::~nsHtml5TreeBuilder() |
93 | 0 | { |
94 | 0 | MOZ_COUNT_DTOR(nsHtml5TreeBuilder); |
95 | 0 | NS_ASSERTION(!mActive, |
96 | 0 | "nsHtml5TreeBuilder deleted without ever calling end() on it!"); |
97 | 0 | mOpQueue.Clear(); |
98 | 0 | } |
99 | | |
100 | | nsIContentHandle* |
101 | | nsHtml5TreeBuilder::createElement(int32_t aNamespace, |
102 | | nsAtom* aName, |
103 | | nsHtml5HtmlAttributes* aAttributes, |
104 | | nsIContentHandle* aIntendedParent, |
105 | | nsHtml5ContentCreatorFunction aCreator) |
106 | 0 | { |
107 | 0 | MOZ_ASSERT(aAttributes, "Got null attributes."); |
108 | 0 | MOZ_ASSERT(aName, "Got null name."); |
109 | 0 | MOZ_ASSERT(aNamespace == kNameSpaceID_XHTML || |
110 | 0 | aNamespace == kNameSpaceID_SVG || |
111 | 0 | aNamespace == kNameSpaceID_MathML, |
112 | 0 | "Bogus namespace."); |
113 | 0 |
|
114 | 0 | if (mBuilder) { |
115 | 0 | RefPtr<nsAtom> name = nsHtml5TreeOperation::Reget(aName); |
116 | 0 |
|
117 | 0 | nsIContent* intendedParent = |
118 | 0 | aIntendedParent ? static_cast<nsIContent*>(aIntendedParent) : nullptr; |
119 | 0 |
|
120 | 0 | // intendedParent == nullptr is a special case where the |
121 | 0 | // intended parent is the document. |
122 | 0 | nsNodeInfoManager* nodeInfoManager = |
123 | 0 | intendedParent ? intendedParent->OwnerDoc()->NodeInfoManager() |
124 | 0 | : mBuilder->GetNodeInfoManager(); |
125 | 0 |
|
126 | 0 | nsIContent* elem; |
127 | 0 | if (aNamespace == kNameSpaceID_XHTML) { |
128 | 0 | elem = nsHtml5TreeOperation::CreateHTMLElement( |
129 | 0 | name, |
130 | 0 | aAttributes, |
131 | 0 | mozilla::dom::FROM_PARSER_FRAGMENT, |
132 | 0 | nodeInfoManager, |
133 | 0 | mBuilder, |
134 | 0 | aCreator.html); |
135 | 0 | } else if (aNamespace == kNameSpaceID_SVG) { |
136 | 0 | elem = nsHtml5TreeOperation::CreateSVGElement( |
137 | 0 | name, |
138 | 0 | aAttributes, |
139 | 0 | mozilla::dom::FROM_PARSER_FRAGMENT, |
140 | 0 | nodeInfoManager, |
141 | 0 | mBuilder, |
142 | 0 | aCreator.svg); |
143 | 0 | } else { |
144 | 0 | MOZ_ASSERT(aNamespace == kNameSpaceID_MathML); |
145 | 0 | elem = nsHtml5TreeOperation::CreateMathMLElement( |
146 | 0 | name, aAttributes, nodeInfoManager, mBuilder); |
147 | 0 | } |
148 | 0 | if (MOZ_UNLIKELY(aAttributes != tokenizer->GetAttributes() && |
149 | 0 | aAttributes != nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES)) { |
150 | 0 | delete aAttributes; |
151 | 0 | } |
152 | 0 | return elem; |
153 | 0 | } |
154 | 0 |
|
155 | 0 | nsIContentHandle* content = AllocateContentHandle(); |
156 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
157 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
158 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
159 | 0 | return nullptr; |
160 | 0 | } |
161 | 0 | treeOp->Init(aNamespace, |
162 | 0 | aName, |
163 | 0 | aAttributes, |
164 | 0 | content, |
165 | 0 | aIntendedParent, |
166 | 0 | !!mSpeculativeLoadStage, |
167 | 0 | aCreator); |
168 | 0 | // mSpeculativeLoadStage is non-null only in the off-the-main-thread |
169 | 0 | // tree builder, which handles the network stream |
170 | 0 |
|
171 | 0 | // Start wall of code for speculative loading and line numbers |
172 | 0 |
|
173 | 0 | if (mSpeculativeLoadStage) { |
174 | 0 | switch (aNamespace) { |
175 | 0 | case kNameSpaceID_XHTML: |
176 | 0 | if (nsGkAtoms::img == aName) { |
177 | 0 | nsHtml5String url = |
178 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); |
179 | 0 | nsHtml5String srcset = |
180 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); |
181 | 0 | nsHtml5String crossOrigin = |
182 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); |
183 | 0 | nsHtml5String referrerPolicy = |
184 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); |
185 | 0 | nsHtml5String sizes = |
186 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); |
187 | 0 | mSpeculativeLoadQueue.AppendElement()->InitImage( |
188 | 0 | url, crossOrigin, referrerPolicy, srcset, sizes); |
189 | 0 | } else if (nsGkAtoms::source == aName) { |
190 | 0 | nsHtml5String srcset = |
191 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_SRCSET); |
192 | 0 | // Sources without srcset cannot be selected. The source could also be |
193 | 0 | // for a media element, but in that context doesn't use srcset. See |
194 | 0 | // comments in nsHtml5SpeculativeLoad.h about <picture> preloading |
195 | 0 | if (srcset) { |
196 | 0 | nsHtml5String sizes = |
197 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_SIZES); |
198 | 0 | nsHtml5String type = |
199 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); |
200 | 0 | nsHtml5String media = |
201 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_MEDIA); |
202 | 0 | mSpeculativeLoadQueue.AppendElement()->InitPictureSource( |
203 | 0 | srcset, sizes, type, media); |
204 | 0 | } |
205 | 0 | } else if (nsGkAtoms::script == aName) { |
206 | 0 | nsHtml5TreeOperation* treeOp = |
207 | 0 | mOpQueue.AppendElement(mozilla::fallible); |
208 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
209 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder( |
210 | 0 | NS_ERROR_OUT_OF_MEMORY); |
211 | 0 | return nullptr; |
212 | 0 | } |
213 | 0 | treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, |
214 | 0 | content, |
215 | 0 | tokenizer->getLineNumber()); |
216 | 0 |
|
217 | 0 | nsHtml5String url = |
218 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_SRC); |
219 | 0 | if (url) { |
220 | 0 | nsHtml5String charset = |
221 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); |
222 | 0 | nsHtml5String type = |
223 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); |
224 | 0 | nsHtml5String crossOrigin = |
225 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); |
226 | 0 | nsHtml5String integrity = |
227 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); |
228 | 0 | bool async = |
229 | 0 | aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC); |
230 | 0 | bool defer = |
231 | 0 | aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER); |
232 | 0 | bool noModule = |
233 | 0 | aAttributes->contains(nsHtml5AttributeName::ATTR_NOMODULE); |
234 | 0 | mSpeculativeLoadQueue.AppendElement()->InitScript( |
235 | 0 | url, |
236 | 0 | charset, |
237 | 0 | type, |
238 | 0 | crossOrigin, |
239 | 0 | integrity, |
240 | 0 | mode == nsHtml5TreeBuilder::IN_HEAD, |
241 | 0 | async, |
242 | 0 | defer, |
243 | 0 | noModule); |
244 | 0 | mCurrentHtmlScriptIsAsyncOrDefer = async || defer; |
245 | 0 | } |
246 | 0 | } else if (nsGkAtoms::link == aName) { |
247 | 0 | nsHtml5String rel = |
248 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_REL); |
249 | 0 | // Not splitting on space here is bogus but the old parser didn't even |
250 | 0 | // do a case-insensitive check. |
251 | 0 | if (rel) { |
252 | 0 | if (rel.LowerCaseEqualsASCII("stylesheet")) { |
253 | 0 | nsHtml5String url = |
254 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); |
255 | 0 | if (url) { |
256 | 0 | nsHtml5String charset = |
257 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CHARSET); |
258 | 0 | nsHtml5String crossOrigin = |
259 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); |
260 | 0 | nsHtml5String integrity = |
261 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); |
262 | 0 | nsHtml5String referrerPolicy = aAttributes->getValue( |
263 | 0 | nsHtml5AttributeName::ATTR_REFERRERPOLICY); |
264 | 0 | mSpeculativeLoadQueue.AppendElement()->InitStyle( |
265 | 0 | url, charset, crossOrigin, referrerPolicy, integrity); |
266 | 0 | } |
267 | 0 | } else if (rel.LowerCaseEqualsASCII("preconnect")) { |
268 | 0 | nsHtml5String url = |
269 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); |
270 | 0 | if (url) { |
271 | 0 | nsHtml5String crossOrigin = |
272 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); |
273 | 0 | mSpeculativeLoadQueue.AppendElement()->InitPreconnect( |
274 | 0 | url, crossOrigin); |
275 | 0 | } |
276 | 0 | } |
277 | 0 | } |
278 | 0 | } else if (nsGkAtoms::video == aName) { |
279 | 0 | nsHtml5String url = |
280 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_POSTER); |
281 | 0 | if (url) { |
282 | 0 | mSpeculativeLoadQueue.AppendElement()->InitImage( |
283 | 0 | url, nullptr, nullptr, nullptr, nullptr); |
284 | 0 | } |
285 | 0 | } else if (nsGkAtoms::style == aName) { |
286 | 0 | nsHtml5TreeOperation* treeOp = |
287 | 0 | mOpQueue.AppendElement(mozilla::fallible); |
288 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
289 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder( |
290 | 0 | NS_ERROR_OUT_OF_MEMORY); |
291 | 0 | return nullptr; |
292 | 0 | } |
293 | 0 | treeOp->Init( |
294 | 0 | eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); |
295 | 0 | } else if (nsGkAtoms::html == aName) { |
296 | 0 | nsHtml5String url = |
297 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); |
298 | 0 | mSpeculativeLoadQueue.AppendElement()->InitManifest(url); |
299 | 0 | } else if (nsGkAtoms::base == aName) { |
300 | 0 | nsHtml5String url = |
301 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); |
302 | 0 | if (url) { |
303 | 0 | mSpeculativeLoadQueue.AppendElement()->InitBase(url); |
304 | 0 | } |
305 | 0 | } else if (nsGkAtoms::meta == aName) { |
306 | 0 | if (nsHtml5Portability::lowerCaseLiteralEqualsIgnoreAsciiCaseString( |
307 | 0 | "content-security-policy", |
308 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_HTTP_EQUIV))) { |
309 | 0 | nsHtml5String csp = |
310 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); |
311 | 0 | if (csp) { |
312 | 0 | mSpeculativeLoadQueue.AppendElement()->InitMetaCSP(csp); |
313 | 0 | } |
314 | 0 | } else if (nsHtml5Portability:: |
315 | 0 | lowerCaseLiteralEqualsIgnoreAsciiCaseString( |
316 | 0 | "referrer", |
317 | 0 | aAttributes->getValue( |
318 | 0 | nsHtml5AttributeName::ATTR_NAME))) { |
319 | 0 | nsHtml5String referrerPolicy = |
320 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CONTENT); |
321 | 0 | if (referrerPolicy) { |
322 | 0 | mSpeculativeLoadQueue.AppendElement()->InitMetaReferrerPolicy( |
323 | 0 | referrerPolicy); |
324 | 0 | } |
325 | 0 | } |
326 | 0 | } |
327 | 0 | break; |
328 | 0 | case kNameSpaceID_SVG: |
329 | 0 | if (nsGkAtoms::image == aName) { |
330 | 0 | nsHtml5String url = |
331 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); |
332 | 0 | if (url) { |
333 | 0 | mSpeculativeLoadQueue.AppendElement()->InitImage( |
334 | 0 | url, nullptr, nullptr, nullptr, nullptr); |
335 | 0 | } |
336 | 0 | } else if (nsGkAtoms::script == aName) { |
337 | 0 | nsHtml5TreeOperation* treeOp = |
338 | 0 | mOpQueue.AppendElement(mozilla::fallible); |
339 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
340 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder( |
341 | 0 | NS_ERROR_OUT_OF_MEMORY); |
342 | 0 | return nullptr; |
343 | 0 | } |
344 | 0 | treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, |
345 | 0 | content, |
346 | 0 | tokenizer->getLineNumber()); |
347 | 0 |
|
348 | 0 | nsHtml5String url = |
349 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); |
350 | 0 | if (url) { |
351 | 0 | nsHtml5String type = |
352 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_TYPE); |
353 | 0 | nsHtml5String crossOrigin = |
354 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); |
355 | 0 | nsHtml5String integrity = |
356 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); |
357 | 0 | mSpeculativeLoadQueue.AppendElement()->InitScript( |
358 | 0 | url, |
359 | 0 | nullptr, |
360 | 0 | type, |
361 | 0 | crossOrigin, |
362 | 0 | integrity, |
363 | 0 | mode == nsHtml5TreeBuilder::IN_HEAD, |
364 | 0 | false, |
365 | 0 | false, |
366 | 0 | false); |
367 | 0 | } |
368 | 0 | } else if (nsGkAtoms::style == aName) { |
369 | 0 | nsHtml5TreeOperation* treeOp = |
370 | 0 | mOpQueue.AppendElement(mozilla::fallible); |
371 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
372 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder( |
373 | 0 | NS_ERROR_OUT_OF_MEMORY); |
374 | 0 | return nullptr; |
375 | 0 | } |
376 | 0 | treeOp->Init( |
377 | 0 | eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); |
378 | 0 |
|
379 | 0 | nsHtml5String url = |
380 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF); |
381 | 0 | if (url) { |
382 | 0 | nsHtml5String crossOrigin = |
383 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_CROSSORIGIN); |
384 | 0 | nsHtml5String integrity = |
385 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_INTEGRITY); |
386 | 0 | nsHtml5String referrerPolicy = |
387 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_REFERRERPOLICY); |
388 | 0 | mSpeculativeLoadQueue.AppendElement()->InitStyle( |
389 | 0 | url, nullptr, crossOrigin, referrerPolicy, integrity); |
390 | 0 | } |
391 | 0 | } |
392 | 0 | break; |
393 | 0 | } |
394 | 0 | } else if (aNamespace != kNameSpaceID_MathML) { |
395 | 0 | // No speculative loader--just line numbers and defer/async check |
396 | 0 | if (nsGkAtoms::style == aName) { |
397 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
398 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
399 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
400 | 0 | return nullptr; |
401 | 0 | } |
402 | 0 | treeOp->Init( |
403 | 0 | eTreeOpSetStyleLineNumber, content, tokenizer->getLineNumber()); |
404 | 0 | } else if (nsGkAtoms::script == aName) { |
405 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
406 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
407 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
408 | 0 | return nullptr; |
409 | 0 | } |
410 | 0 | treeOp->Init(eTreeOpSetScriptLineNumberAndFreeze, |
411 | 0 | content, |
412 | 0 | tokenizer->getLineNumber()); |
413 | 0 | if (aNamespace == kNameSpaceID_XHTML) { |
414 | 0 | mCurrentHtmlScriptIsAsyncOrDefer = |
415 | 0 | aAttributes->contains(nsHtml5AttributeName::ATTR_SRC) && |
416 | 0 | (aAttributes->contains(nsHtml5AttributeName::ATTR_ASYNC) || |
417 | 0 | aAttributes->contains(nsHtml5AttributeName::ATTR_DEFER)); |
418 | 0 | } |
419 | 0 | } else if (aNamespace == kNameSpaceID_XHTML) { |
420 | 0 | if (nsGkAtoms::html == aName) { |
421 | 0 | nsHtml5String url = |
422 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_MANIFEST); |
423 | 0 | nsHtml5TreeOperation* treeOp = |
424 | 0 | mOpQueue.AppendElement(mozilla::fallible); |
425 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
426 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder( |
427 | 0 | NS_ERROR_OUT_OF_MEMORY); |
428 | 0 | return nullptr; |
429 | 0 | } |
430 | 0 | if (url) { |
431 | 0 | nsString |
432 | 0 | urlString; // Not Auto, because using it to hold nsStringBuffer* |
433 | 0 | url.ToString(urlString); |
434 | 0 | treeOp->Init(eTreeOpProcessOfflineManifest, urlString); |
435 | 0 | } else { |
436 | 0 | treeOp->Init(eTreeOpProcessOfflineManifest, EmptyString()); |
437 | 0 | } |
438 | 0 | } else if (nsGkAtoms::base == aName && mViewSource) { |
439 | 0 | nsHtml5String url = |
440 | 0 | aAttributes->getValue(nsHtml5AttributeName::ATTR_HREF); |
441 | 0 | if (url) { |
442 | 0 | mViewSource->AddBase(url); |
443 | 0 | } |
444 | 0 | } |
445 | 0 | } |
446 | 0 | } |
447 | 0 |
|
448 | 0 | // End wall of code for speculative loading |
449 | 0 |
|
450 | 0 | return content; |
451 | 0 | } |
452 | | |
453 | | nsIContentHandle* |
454 | | nsHtml5TreeBuilder::createElement(int32_t aNamespace, |
455 | | nsAtom* aName, |
456 | | nsHtml5HtmlAttributes* aAttributes, |
457 | | nsIContentHandle* aFormElement, |
458 | | nsIContentHandle* aIntendedParent, |
459 | | nsHtml5ContentCreatorFunction aCreator) |
460 | 0 | { |
461 | 0 | nsIContentHandle* content = |
462 | 0 | createElement(aNamespace, aName, aAttributes, aIntendedParent, aCreator); |
463 | 0 | if (aFormElement) { |
464 | 0 | if (mBuilder) { |
465 | 0 | nsHtml5TreeOperation::SetFormElement( |
466 | 0 | static_cast<nsIContent*>(content), |
467 | 0 | static_cast<nsIContent*>(aFormElement)); |
468 | 0 | } else { |
469 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
470 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
471 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
472 | 0 | return nullptr; |
473 | 0 | } |
474 | 0 | treeOp->Init(eTreeOpSetFormElement, content, aFormElement); |
475 | 0 | } |
476 | 0 | } |
477 | 0 | return content; |
478 | 0 | } |
479 | | |
480 | | nsIContentHandle* |
481 | | nsHtml5TreeBuilder::createHtmlElementSetAsRoot( |
482 | | nsHtml5HtmlAttributes* aAttributes) |
483 | 0 | { |
484 | 0 | nsHtml5ContentCreatorFunction creator; |
485 | 0 | // <html> uses NS_NewHTMLSharedElement creator |
486 | 0 | creator.html = NS_NewHTMLSharedElement; |
487 | 0 | nsIContentHandle* content = createElement( |
488 | 0 | kNameSpaceID_XHTML, nsGkAtoms::html, aAttributes, nullptr, creator); |
489 | 0 | if (mBuilder) { |
490 | 0 | nsresult rv = nsHtml5TreeOperation::AppendToDocument( |
491 | 0 | static_cast<nsIContent*>(content), mBuilder); |
492 | 0 | if (NS_FAILED(rv)) { |
493 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
494 | 0 | } |
495 | 0 | } else { |
496 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
497 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
498 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
499 | 0 | return nullptr; |
500 | 0 | } |
501 | 0 | treeOp->Init(eTreeOpAppendToDocument, content); |
502 | 0 | } |
503 | 0 | return content; |
504 | 0 | } |
505 | | |
506 | | nsIContentHandle* |
507 | | nsHtml5TreeBuilder::createAndInsertFosterParentedElement( |
508 | | int32_t aNamespace, |
509 | | nsAtom* aName, |
510 | | nsHtml5HtmlAttributes* aAttributes, |
511 | | nsIContentHandle* aFormElement, |
512 | | nsIContentHandle* aTable, |
513 | | nsIContentHandle* aStackParent, |
514 | | nsHtml5ContentCreatorFunction aCreator) |
515 | 0 | { |
516 | 0 | MOZ_ASSERT(aTable, "Null table"); |
517 | 0 | MOZ_ASSERT(aStackParent, "Null stack parent"); |
518 | 0 |
|
519 | 0 | if (mBuilder) { |
520 | 0 | // Get the foster parent to use as the intended parent when creating |
521 | 0 | // the child element. |
522 | 0 | nsIContent* fosterParent = nsHtml5TreeOperation::GetFosterParent( |
523 | 0 | static_cast<nsIContent*>(aTable), static_cast<nsIContent*>(aStackParent)); |
524 | 0 |
|
525 | 0 | nsIContentHandle* child = createElement( |
526 | 0 | aNamespace, aName, aAttributes, aFormElement, fosterParent, aCreator); |
527 | 0 |
|
528 | 0 | insertFosterParentedChild(child, aTable, aStackParent); |
529 | 0 |
|
530 | 0 | return child; |
531 | 0 | } |
532 | 0 | |
533 | 0 | // Tree op to get the foster parent that we use as the intended parent |
534 | 0 | // when creating the child element. |
535 | 0 | nsHtml5TreeOperation* fosterParentTreeOp = mOpQueue.AppendElement(); |
536 | 0 | NS_ASSERTION(fosterParentTreeOp, "Tree op allocation failed."); |
537 | 0 | nsIContentHandle* fosterParentHandle = AllocateContentHandle(); |
538 | 0 | fosterParentTreeOp->Init( |
539 | 0 | eTreeOpGetFosterParent, aTable, aStackParent, fosterParentHandle); |
540 | 0 |
|
541 | 0 | // Create the element with the correct intended parent. |
542 | 0 | nsIContentHandle* child = createElement( |
543 | 0 | aNamespace, aName, aAttributes, aFormElement, fosterParentHandle, aCreator); |
544 | 0 |
|
545 | 0 | // Insert the child into the foster parent. |
546 | 0 | insertFosterParentedChild(child, aTable, aStackParent); |
547 | 0 |
|
548 | 0 | return child; |
549 | 0 | } |
550 | | |
551 | | void |
552 | | nsHtml5TreeBuilder::detachFromParent(nsIContentHandle* aElement) |
553 | 0 | { |
554 | 0 | MOZ_ASSERT(aElement, "Null element"); |
555 | 0 |
|
556 | 0 | if (mBuilder) { |
557 | 0 | nsHtml5TreeOperation::Detach(static_cast<nsIContent*>(aElement), mBuilder); |
558 | 0 | return; |
559 | 0 | } |
560 | 0 | |
561 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
562 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
563 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
564 | 0 | return; |
565 | 0 | } |
566 | 0 | treeOp->Init(eTreeOpDetach, aElement); |
567 | 0 | } |
568 | | |
569 | | void |
570 | | nsHtml5TreeBuilder::appendElement(nsIContentHandle* aChild, |
571 | | nsIContentHandle* aParent) |
572 | 0 | { |
573 | 0 | MOZ_ASSERT(aChild, "Null child"); |
574 | 0 | MOZ_ASSERT(aParent, "Null parent"); |
575 | 0 | if (deepTreeSurrogateParent) { |
576 | 0 | return; |
577 | 0 | } |
578 | 0 | |
579 | 0 | if (mBuilder) { |
580 | 0 | nsresult rv = |
581 | 0 | nsHtml5TreeOperation::Append(static_cast<nsIContent*>(aChild), |
582 | 0 | static_cast<nsIContent*>(aParent), |
583 | 0 | mBuilder); |
584 | 0 | if (NS_FAILED(rv)) { |
585 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
586 | 0 | } |
587 | 0 | return; |
588 | 0 | } |
589 | 0 |
|
590 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
591 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
592 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
593 | 0 | return; |
594 | 0 | } |
595 | 0 | treeOp->Init(eTreeOpAppend, aChild, aParent); |
596 | 0 | } |
597 | | |
598 | | void |
599 | | nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContentHandle* aOldParent, |
600 | | nsIContentHandle* aNewParent) |
601 | 0 | { |
602 | 0 | MOZ_ASSERT(aOldParent, "Null old parent"); |
603 | 0 | MOZ_ASSERT(aNewParent, "Null new parent"); |
604 | 0 |
|
605 | 0 | if (mBuilder) { |
606 | 0 | nsresult rv = nsHtml5TreeOperation::AppendChildrenToNewParent( |
607 | 0 | static_cast<nsIContent*>(aOldParent), |
608 | 0 | static_cast<nsIContent*>(aNewParent), |
609 | 0 | mBuilder); |
610 | 0 | if (NS_FAILED(rv)) { |
611 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
612 | 0 | } |
613 | 0 | return; |
614 | 0 | } |
615 | 0 |
|
616 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
617 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
618 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
619 | 0 | return; |
620 | 0 | } |
621 | 0 | treeOp->Init(eTreeOpAppendChildrenToNewParent, aOldParent, aNewParent); |
622 | 0 | } |
623 | | |
624 | | void |
625 | | nsHtml5TreeBuilder::insertFosterParentedCharacters( |
626 | | char16_t* aBuffer, |
627 | | int32_t aStart, |
628 | | int32_t aLength, |
629 | | nsIContentHandle* aTable, |
630 | | nsIContentHandle* aStackParent) |
631 | 0 | { |
632 | 0 | MOZ_ASSERT(aBuffer, "Null buffer"); |
633 | 0 | MOZ_ASSERT(aTable, "Null table"); |
634 | 0 | MOZ_ASSERT(aStackParent, "Null stack parent"); |
635 | 0 | MOZ_ASSERT(!aStart, "aStart must always be zero."); |
636 | 0 |
|
637 | 0 | if (mBuilder) { |
638 | 0 | nsresult rv = nsHtml5TreeOperation::FosterParentText( |
639 | 0 | static_cast<nsIContent*>(aStackParent), |
640 | 0 | aBuffer, // XXX aStart always ignored??? |
641 | 0 | aLength, |
642 | 0 | static_cast<nsIContent*>(aTable), |
643 | 0 | mBuilder); |
644 | 0 | if (NS_FAILED(rv)) { |
645 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
646 | 0 | } |
647 | 0 | return; |
648 | 0 | } |
649 | 0 |
|
650 | 0 | auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); |
651 | 0 | if (!bufferCopy) { |
652 | 0 | // Just assigning mBroken instead of generating tree op. The caller |
653 | 0 | // of tokenizeBuffer() will call MarkAsBroken() as appropriate. |
654 | 0 | mBroken = NS_ERROR_OUT_OF_MEMORY; |
655 | 0 | requestSuspension(); |
656 | 0 | return; |
657 | 0 | } |
658 | 0 | |
659 | 0 | memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); |
660 | 0 |
|
661 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
662 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
663 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
664 | 0 | return; |
665 | 0 | } |
666 | 0 | treeOp->Init(eTreeOpFosterParentText, |
667 | 0 | bufferCopy.release(), |
668 | 0 | aLength, |
669 | 0 | aStackParent, |
670 | 0 | aTable); |
671 | 0 | } |
672 | | |
673 | | void |
674 | | nsHtml5TreeBuilder::insertFosterParentedChild(nsIContentHandle* aChild, |
675 | | nsIContentHandle* aTable, |
676 | | nsIContentHandle* aStackParent) |
677 | 0 | { |
678 | 0 | MOZ_ASSERT(aChild, "Null child"); |
679 | 0 | MOZ_ASSERT(aTable, "Null table"); |
680 | 0 | MOZ_ASSERT(aStackParent, "Null stack parent"); |
681 | 0 |
|
682 | 0 | if (mBuilder) { |
683 | 0 | nsresult rv = |
684 | 0 | nsHtml5TreeOperation::FosterParent(static_cast<nsIContent*>(aChild), |
685 | 0 | static_cast<nsIContent*>(aStackParent), |
686 | 0 | static_cast<nsIContent*>(aTable), |
687 | 0 | mBuilder); |
688 | 0 | if (NS_FAILED(rv)) { |
689 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
690 | 0 | } |
691 | 0 | return; |
692 | 0 | } |
693 | 0 |
|
694 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
695 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
696 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
697 | 0 | return; |
698 | 0 | } |
699 | 0 | treeOp->Init(eTreeOpFosterParent, aChild, aStackParent, aTable); |
700 | 0 | } |
701 | | |
702 | | void |
703 | | nsHtml5TreeBuilder::appendCharacters(nsIContentHandle* aParent, |
704 | | char16_t* aBuffer, |
705 | | int32_t aStart, |
706 | | int32_t aLength) |
707 | 0 | { |
708 | 0 | MOZ_ASSERT(aBuffer, "Null buffer"); |
709 | 0 | MOZ_ASSERT(aParent, "Null parent"); |
710 | 0 | MOZ_ASSERT(!aStart, "aStart must always be zero."); |
711 | 0 |
|
712 | 0 | if (mBuilder) { |
713 | 0 | nsresult rv = nsHtml5TreeOperation::AppendText( |
714 | 0 | aBuffer, // XXX aStart always ignored??? |
715 | 0 | aLength, |
716 | 0 | static_cast<nsIContent*>(deepTreeSurrogateParent ? deepTreeSurrogateParent |
717 | 0 | : aParent), |
718 | 0 | mBuilder); |
719 | 0 | if (NS_FAILED(rv)) { |
720 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
721 | 0 | } |
722 | 0 | return; |
723 | 0 | } |
724 | 0 |
|
725 | 0 | auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); |
726 | 0 | if (!bufferCopy) { |
727 | 0 | // Just assigning mBroken instead of generating tree op. The caller |
728 | 0 | // of tokenizeBuffer() will call MarkAsBroken() as appropriate. |
729 | 0 | mBroken = NS_ERROR_OUT_OF_MEMORY; |
730 | 0 | requestSuspension(); |
731 | 0 | return; |
732 | 0 | } |
733 | 0 | |
734 | 0 | memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); |
735 | 0 |
|
736 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
737 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
738 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
739 | 0 | return; |
740 | 0 | } |
741 | 0 | treeOp->Init(eTreeOpAppendText, |
742 | 0 | bufferCopy.release(), |
743 | 0 | aLength, |
744 | 0 | deepTreeSurrogateParent ? deepTreeSurrogateParent : aParent); |
745 | 0 | } |
746 | | |
747 | | void |
748 | | nsHtml5TreeBuilder::appendComment(nsIContentHandle* aParent, |
749 | | char16_t* aBuffer, |
750 | | int32_t aStart, |
751 | | int32_t aLength) |
752 | 0 | { |
753 | 0 | MOZ_ASSERT(aBuffer, "Null buffer"); |
754 | 0 | MOZ_ASSERT(aParent, "Null parent"); |
755 | 0 | MOZ_ASSERT(!aStart, "aStart must always be zero."); |
756 | 0 |
|
757 | 0 | if (deepTreeSurrogateParent) { |
758 | 0 | return; |
759 | 0 | } |
760 | 0 | |
761 | 0 | if (mBuilder) { |
762 | 0 | nsresult rv = nsHtml5TreeOperation::AppendComment( |
763 | 0 | static_cast<nsIContent*>(aParent), |
764 | 0 | aBuffer, // XXX aStart always ignored??? |
765 | 0 | aLength, |
766 | 0 | mBuilder); |
767 | 0 | if (NS_FAILED(rv)) { |
768 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
769 | 0 | } |
770 | 0 | return; |
771 | 0 | } |
772 | 0 |
|
773 | 0 | auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); |
774 | 0 | if (!bufferCopy) { |
775 | 0 | // Just assigning mBroken instead of generating tree op. The caller |
776 | 0 | // of tokenizeBuffer() will call MarkAsBroken() as appropriate. |
777 | 0 | mBroken = NS_ERROR_OUT_OF_MEMORY; |
778 | 0 | requestSuspension(); |
779 | 0 | return; |
780 | 0 | } |
781 | 0 | |
782 | 0 | memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); |
783 | 0 |
|
784 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
785 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
786 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
787 | 0 | return; |
788 | 0 | } |
789 | 0 | treeOp->Init(eTreeOpAppendComment, bufferCopy.release(), aLength, aParent); |
790 | 0 | } |
791 | | |
792 | | void |
793 | | nsHtml5TreeBuilder::appendCommentToDocument(char16_t* aBuffer, |
794 | | int32_t aStart, |
795 | | int32_t aLength) |
796 | 0 | { |
797 | 0 | MOZ_ASSERT(aBuffer, "Null buffer"); |
798 | 0 | MOZ_ASSERT(!aStart, "aStart must always be zero."); |
799 | 0 |
|
800 | 0 | if (mBuilder) { |
801 | 0 | nsresult rv = nsHtml5TreeOperation::AppendCommentToDocument( |
802 | 0 | aBuffer, // XXX aStart always ignored??? |
803 | 0 | aLength, |
804 | 0 | mBuilder); |
805 | 0 | if (NS_FAILED(rv)) { |
806 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
807 | 0 | } |
808 | 0 | return; |
809 | 0 | } |
810 | 0 |
|
811 | 0 | auto bufferCopy = mozilla::MakeUniqueFallible<char16_t[]>(aLength); |
812 | 0 | if (!bufferCopy) { |
813 | 0 | // Just assigning mBroken instead of generating tree op. The caller |
814 | 0 | // of tokenizeBuffer() will call MarkAsBroken() as appropriate. |
815 | 0 | mBroken = NS_ERROR_OUT_OF_MEMORY; |
816 | 0 | requestSuspension(); |
817 | 0 | return; |
818 | 0 | } |
819 | 0 | |
820 | 0 | memcpy(bufferCopy.get(), aBuffer, aLength * sizeof(char16_t)); |
821 | 0 |
|
822 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
823 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
824 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
825 | 0 | return; |
826 | 0 | } |
827 | 0 | treeOp->Init(eTreeOpAppendCommentToDocument, bufferCopy.release(), aLength); |
828 | 0 | } |
829 | | |
830 | | void |
831 | | nsHtml5TreeBuilder::addAttributesToElement(nsIContentHandle* aElement, |
832 | | nsHtml5HtmlAttributes* aAttributes) |
833 | 0 | { |
834 | 0 | MOZ_ASSERT(aElement, "Null element"); |
835 | 0 | MOZ_ASSERT(aAttributes, "Null attributes"); |
836 | 0 |
|
837 | 0 | if (aAttributes == nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES) { |
838 | 0 | return; |
839 | 0 | } |
840 | 0 | |
841 | 0 | if (mBuilder) { |
842 | 0 | MOZ_ASSERT( |
843 | 0 | aAttributes == tokenizer->GetAttributes(), |
844 | 0 | "Using attribute other than the tokenizer's to add to body or html."); |
845 | 0 | nsresult rv = nsHtml5TreeOperation::AddAttributes( |
846 | 0 | static_cast<nsIContent*>(aElement), aAttributes, mBuilder); |
847 | 0 | if (NS_FAILED(rv)) { |
848 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
849 | 0 | } |
850 | 0 | return; |
851 | 0 | } |
852 | 0 |
|
853 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
854 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
855 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
856 | 0 | return; |
857 | 0 | } |
858 | 0 | treeOp->Init(aElement, aAttributes); |
859 | 0 | } |
860 | | |
861 | | void |
862 | | nsHtml5TreeBuilder::markMalformedIfScript(nsIContentHandle* aElement) |
863 | 0 | { |
864 | 0 | MOZ_ASSERT(aElement, "Null element"); |
865 | 0 |
|
866 | 0 | if (mBuilder) { |
867 | 0 | nsHtml5TreeOperation::MarkMalformedIfScript( |
868 | 0 | static_cast<nsIContent*>(aElement)); |
869 | 0 | return; |
870 | 0 | } |
871 | 0 | |
872 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
873 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
874 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
875 | 0 | return; |
876 | 0 | } |
877 | 0 | treeOp->Init(eTreeOpMarkMalformedIfScript, aElement); |
878 | 0 | } |
879 | | |
880 | | void |
881 | | nsHtml5TreeBuilder::start(bool fragment) |
882 | 0 | { |
883 | 0 | mCurrentHtmlScriptIsAsyncOrDefer = false; |
884 | 0 | deepTreeSurrogateParent = nullptr; |
885 | | #ifdef DEBUG |
886 | | mActive = true; |
887 | | #endif |
888 | | } |
889 | | |
890 | | void |
891 | | nsHtml5TreeBuilder::end() |
892 | 0 | { |
893 | 0 | mOpQueue.Clear(); |
894 | | #ifdef DEBUG |
895 | | mActive = false; |
896 | | #endif |
897 | | } |
898 | | |
899 | | void |
900 | | nsHtml5TreeBuilder::appendDoctypeToDocument(nsAtom* aName, |
901 | | nsHtml5String aPublicId, |
902 | | nsHtml5String aSystemId) |
903 | 0 | { |
904 | 0 | MOZ_ASSERT(aName, "Null name"); |
905 | 0 | nsString publicId; // Not Auto, because using it to hold nsStringBuffer* |
906 | 0 | nsString systemId; // Not Auto, because using it to hold nsStringBuffer* |
907 | 0 | aPublicId.ToString(publicId); |
908 | 0 | aSystemId.ToString(systemId); |
909 | 0 | if (mBuilder) { |
910 | 0 | RefPtr<nsAtom> name = nsHtml5TreeOperation::Reget(aName); |
911 | 0 | nsresult rv = nsHtml5TreeOperation::AppendDoctypeToDocument( |
912 | 0 | name, publicId, systemId, mBuilder); |
913 | 0 | if (NS_FAILED(rv)) { |
914 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(rv); |
915 | 0 | } |
916 | 0 | return; |
917 | 0 | } |
918 | 0 |
|
919 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
920 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
921 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
922 | 0 | return; |
923 | 0 | } |
924 | 0 | treeOp->Init(aName, publicId, systemId); |
925 | 0 | // nsXMLContentSink can flush here, but what's the point? |
926 | 0 | // It can also interrupt here, but we can't. |
927 | 0 | } |
928 | | |
929 | | void |
930 | | nsHtml5TreeBuilder::elementPushed(int32_t aNamespace, |
931 | | nsAtom* aName, |
932 | | nsIContentHandle* aElement) |
933 | 0 | { |
934 | 0 | NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || |
935 | 0 | aNamespace == kNameSpaceID_SVG || |
936 | 0 | aNamespace == kNameSpaceID_MathML, |
937 | 0 | "Element isn't HTML, SVG or MathML!"); |
938 | 0 | NS_ASSERTION(aName, "Element doesn't have local name!"); |
939 | 0 | NS_ASSERTION(aElement, "No element!"); |
940 | 0 | /* |
941 | 0 | * The frame constructor uses recursive algorithms, so it can't deal with |
942 | 0 | * arbitrarily deep trees. This is especially a problem on Windows where |
943 | 0 | * the permitted depth of the runtime stack is rather small. |
944 | 0 | * |
945 | 0 | * The following is a protection against author incompetence--not against |
946 | 0 | * malice. There are other ways to make the DOM deep anyway. |
947 | 0 | * |
948 | 0 | * The basic idea is that when the tree builder stack gets too deep, |
949 | 0 | * append operations no longer append to the node that the HTML parsing |
950 | 0 | * algorithm says they should but instead text nodes are append to the last |
951 | 0 | * element that was seen before a magic tree builder stack threshold was |
952 | 0 | * reached and element and comment nodes aren't appended to the DOM at all. |
953 | 0 | * |
954 | 0 | * However, for security reasons, non-child descendant text nodes inside an |
955 | 0 | * SVG script or style element should not become children. Also, non-cell |
956 | 0 | * table elements shouldn't be used as surrogate parents for user experience |
957 | 0 | * reasons. |
958 | 0 | */ |
959 | 0 | if (!deepTreeSurrogateParent && currentPtr >= MAX_REFLOW_DEPTH && |
960 | 0 | !(aName == nsGkAtoms::script || aName == nsGkAtoms::table || |
961 | 0 | aName == nsGkAtoms::thead || aName == nsGkAtoms::tfoot || |
962 | 0 | aName == nsGkAtoms::tbody || aName == nsGkAtoms::tr || |
963 | 0 | aName == nsGkAtoms::colgroup || aName == nsGkAtoms::style)) { |
964 | 0 | deepTreeSurrogateParent = aElement; |
965 | 0 | } |
966 | 0 | if (aNamespace != kNameSpaceID_XHTML) { |
967 | 0 | return; |
968 | 0 | } |
969 | 0 | if (aName == nsGkAtoms::body || aName == nsGkAtoms::frameset) { |
970 | 0 | if (mBuilder) { |
971 | 0 | // InnerHTML and DOMParser shouldn't start layout anyway |
972 | 0 | return; |
973 | 0 | } |
974 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
975 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
976 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
977 | 0 | return; |
978 | 0 | } |
979 | 0 | treeOp->Init(eTreeOpStartLayout); |
980 | 0 | return; |
981 | 0 | } |
982 | 0 | if (aName == nsGkAtoms::input || aName == nsGkAtoms::button) { |
983 | 0 | if (mBuilder) { |
984 | 0 | nsHtml5TreeOperation::DoneCreatingElement( |
985 | 0 | static_cast<nsIContent*>(aElement)); |
986 | 0 | } else { |
987 | 0 | mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement); |
988 | 0 | } |
989 | 0 | return; |
990 | 0 | } |
991 | 0 | if (aName == nsGkAtoms::audio || aName == nsGkAtoms::video || |
992 | 0 | aName == nsGkAtoms::menuitem) { |
993 | 0 | if (mBuilder) { |
994 | 0 | nsHtml5TreeOperation::DoneCreatingElement( |
995 | 0 | static_cast<nsIContent*>(aElement)); |
996 | 0 | } else { |
997 | 0 | mOpQueue.AppendElement()->Init(eTreeOpDoneCreatingElement, aElement); |
998 | 0 | } |
999 | 0 | return; |
1000 | 0 | } |
1001 | 0 | if (mSpeculativeLoadStage && aName == nsGkAtoms::picture) { |
1002 | 0 | // mSpeculativeLoadStage is non-null only in the off-the-main-thread |
1003 | 0 | // tree builder, which handles the network stream |
1004 | 0 | // |
1005 | 0 | // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading |
1006 | 0 | mSpeculativeLoadQueue.AppendElement()->InitOpenPicture(); |
1007 | 0 | } |
1008 | 0 | } |
1009 | | |
1010 | | void |
1011 | | nsHtml5TreeBuilder::elementPopped(int32_t aNamespace, |
1012 | | nsAtom* aName, |
1013 | | nsIContentHandle* aElement) |
1014 | 0 | { |
1015 | 0 | NS_ASSERTION(aNamespace == kNameSpaceID_XHTML || |
1016 | 0 | aNamespace == kNameSpaceID_SVG || |
1017 | 0 | aNamespace == kNameSpaceID_MathML, |
1018 | 0 | "Element isn't HTML, SVG or MathML!"); |
1019 | 0 | NS_ASSERTION(aName, "Element doesn't have local name!"); |
1020 | 0 | NS_ASSERTION(aElement, "No element!"); |
1021 | 0 | if (deepTreeSurrogateParent && currentPtr <= MAX_REFLOW_DEPTH) { |
1022 | 0 | deepTreeSurrogateParent = nullptr; |
1023 | 0 | } |
1024 | 0 | if (aNamespace == kNameSpaceID_MathML) { |
1025 | 0 | return; |
1026 | 0 | } |
1027 | 0 | // we now have only SVG and HTML |
1028 | 0 | if (aName == nsGkAtoms::script) { |
1029 | 0 | if (mPreventScriptExecution) { |
1030 | 0 | if (mBuilder) { |
1031 | 0 | nsHtml5TreeOperation::PreventScriptExecution( |
1032 | 0 | static_cast<nsIContent*>(aElement)); |
1033 | 0 | return; |
1034 | 0 | } |
1035 | 0 | mOpQueue.AppendElement()->Init(eTreeOpPreventScriptExecution, aElement); |
1036 | 0 | return; |
1037 | 0 | } |
1038 | 0 | if (mBuilder) { |
1039 | 0 | return; |
1040 | 0 | } |
1041 | 0 | if (mCurrentHtmlScriptIsAsyncOrDefer) { |
1042 | 0 | NS_ASSERTION(aNamespace == kNameSpaceID_XHTML, |
1043 | 0 | "Only HTML scripts may be async/defer."); |
1044 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1045 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1046 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1047 | 0 | return; |
1048 | 0 | } |
1049 | 0 | treeOp->Init(eTreeOpRunScriptAsyncDefer, aElement); |
1050 | 0 | mCurrentHtmlScriptIsAsyncOrDefer = false; |
1051 | 0 | return; |
1052 | 0 | } |
1053 | 0 | requestSuspension(); |
1054 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1055 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1056 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1057 | 0 | return; |
1058 | 0 | } |
1059 | 0 | treeOp->InitScript(aElement); |
1060 | 0 | return; |
1061 | 0 | } |
1062 | 0 | if (aName == nsGkAtoms::title) { |
1063 | 0 | if (mBuilder) { |
1064 | 0 | nsHtml5TreeOperation::DoneAddingChildren( |
1065 | 0 | static_cast<nsIContent*>(aElement)); |
1066 | 0 | return; |
1067 | 0 | } |
1068 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1069 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1070 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1071 | 0 | return; |
1072 | 0 | } |
1073 | 0 | treeOp->Init(eTreeOpDoneAddingChildren, aElement); |
1074 | 0 | return; |
1075 | 0 | } |
1076 | 0 | if (aName == nsGkAtoms::style || |
1077 | 0 | (aNamespace == kNameSpaceID_XHTML && aName == nsGkAtoms::link)) { |
1078 | 0 | if (mBuilder) { |
1079 | 0 | MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), |
1080 | 0 | "Scripts must be blocked."); |
1081 | 0 | mBuilder->UpdateStyleSheet(static_cast<nsIContent*>(aElement)); |
1082 | 0 | return; |
1083 | 0 | } |
1084 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1085 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1086 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1087 | 0 | return; |
1088 | 0 | } |
1089 | 0 | treeOp->Init(eTreeOpUpdateStyleSheet, aElement); |
1090 | 0 | return; |
1091 | 0 | } |
1092 | 0 | if (aNamespace == kNameSpaceID_SVG) { |
1093 | 0 | if (aName == nsGkAtoms::svg) { |
1094 | 0 | if (mBuilder) { |
1095 | 0 | nsHtml5TreeOperation::SvgLoad(static_cast<nsIContent*>(aElement)); |
1096 | 0 | return; |
1097 | 0 | } |
1098 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1099 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1100 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1101 | 0 | return; |
1102 | 0 | } |
1103 | 0 | treeOp->Init(eTreeOpSvgLoad, aElement); |
1104 | 0 | } |
1105 | 0 | return; |
1106 | 0 | } |
1107 | 0 | // we now have only HTML |
1108 | 0 | // Some HTML nodes need DoneAddingChildren() called to initialize |
1109 | 0 | // properly (e.g. form state restoration). |
1110 | 0 | // XXX expose ElementName group here and do switch |
1111 | 0 | if (aName == nsGkAtoms::object || aName == nsGkAtoms::select || |
1112 | 0 | aName == nsGkAtoms::textarea || aName == nsGkAtoms::output || |
1113 | 0 | aName == nsGkAtoms::head) { |
1114 | 0 | if (mBuilder) { |
1115 | 0 | nsHtml5TreeOperation::DoneAddingChildren( |
1116 | 0 | static_cast<nsIContent*>(aElement)); |
1117 | 0 | return; |
1118 | 0 | } |
1119 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1120 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1121 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1122 | 0 | return; |
1123 | 0 | } |
1124 | 0 | treeOp->Init(eTreeOpDoneAddingChildren, aElement); |
1125 | 0 | return; |
1126 | 0 | } |
1127 | 0 | if (aName == nsGkAtoms::meta && !fragment && !mBuilder) { |
1128 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1129 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1130 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1131 | 0 | return; |
1132 | 0 | } |
1133 | 0 | treeOp->Init(eTreeOpProcessMeta, aElement); |
1134 | 0 | return; |
1135 | 0 | } |
1136 | 0 | if (mSpeculativeLoadStage && aName == nsGkAtoms::picture) { |
1137 | 0 | // mSpeculativeLoadStage is non-null only in the off-the-main-thread |
1138 | 0 | // tree builder, which handles the network stream |
1139 | 0 | // |
1140 | 0 | // See comments in nsHtml5SpeculativeLoad.h about <picture> preloading |
1141 | 0 | mSpeculativeLoadQueue.AppendElement()->InitEndPicture(); |
1142 | 0 | } |
1143 | 0 | } |
1144 | | |
1145 | | void |
1146 | | nsHtml5TreeBuilder::accumulateCharacters(const char16_t* aBuf, |
1147 | | int32_t aStart, |
1148 | | int32_t aLength) |
1149 | 0 | { |
1150 | 0 | MOZ_RELEASE_ASSERT(charBufferLen + aLength <= charBuffer.length, |
1151 | 0 | "About to memcpy past the end of the buffer!"); |
1152 | 0 | memcpy(charBuffer + charBufferLen, aBuf + aStart, sizeof(char16_t) * aLength); |
1153 | 0 | charBufferLen += aLength; |
1154 | 0 | } |
1155 | | |
1156 | | // INT32_MAX is (2^31)-1. Therefore, the highest power-of-two that fits |
1157 | | // is 2^30. Note that this is counting char16_t units. The underlying |
1158 | | // bytes will be twice that, but they fit even in 32-bit size_t even |
1159 | | // if a contiguous chunk of memory of that size is pretty unlikely to |
1160 | | // be available on a 32-bit system. |
1161 | 0 | #define MAX_POWER_OF_TWO_IN_INT32 0x40000000 |
1162 | | |
1163 | | bool |
1164 | | nsHtml5TreeBuilder::EnsureBufferSpace(int32_t aLength) |
1165 | 0 | { |
1166 | 0 | // TODO: Unify nsHtml5Tokenizer::strBuf and nsHtml5TreeBuilder::charBuffer |
1167 | 0 | // so that this method becomes unnecessary. |
1168 | 0 | mozilla::CheckedInt<int32_t> worstCase(charBufferLen); |
1169 | 0 | worstCase += aLength; |
1170 | 0 | if (!worstCase.isValid()) { |
1171 | 0 | return false; |
1172 | 0 | } |
1173 | 0 | if (worstCase.value() > MAX_POWER_OF_TWO_IN_INT32) { |
1174 | 0 | return false; |
1175 | 0 | } |
1176 | 0 | if (!charBuffer) { |
1177 | 0 | if (worstCase.value() < MAX_POWER_OF_TWO_IN_INT32) { |
1178 | 0 | // Add one to round to the next power of two to avoid immediate |
1179 | 0 | // reallocation once there are a few characters in the buffer. |
1180 | 0 | worstCase += 1; |
1181 | 0 | } |
1182 | 0 | charBuffer = jArray<char16_t, int32_t>::newFallibleJArray( |
1183 | 0 | mozilla::RoundUpPow2(worstCase.value())); |
1184 | 0 | if (!charBuffer) { |
1185 | 0 | return false; |
1186 | 0 | } |
1187 | 0 | } else if (worstCase.value() > charBuffer.length) { |
1188 | 0 | jArray<char16_t, int32_t> newBuf = |
1189 | 0 | jArray<char16_t, int32_t>::newFallibleJArray( |
1190 | 0 | mozilla::RoundUpPow2(worstCase.value())); |
1191 | 0 | if (!newBuf) { |
1192 | 0 | return false; |
1193 | 0 | } |
1194 | 0 | memcpy(newBuf, charBuffer, sizeof(char16_t) * size_t(charBufferLen)); |
1195 | 0 | charBuffer = newBuf; |
1196 | 0 | } |
1197 | 0 | return true; |
1198 | 0 | } |
1199 | | |
1200 | | nsIContentHandle* |
1201 | | nsHtml5TreeBuilder::AllocateContentHandle() |
1202 | 0 | { |
1203 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1204 | 0 | MOZ_ASSERT_UNREACHABLE("Must never allocate a handle with builder."); |
1205 | 0 | return nullptr; |
1206 | 0 | } |
1207 | 0 | if (mHandlesUsed == NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH) { |
1208 | 0 | mOldHandles.AppendElement(std::move(mHandles)); |
1209 | 0 | mHandles = mozilla::MakeUnique<nsIContent* []>( |
1210 | 0 | NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH); |
1211 | 0 | mHandlesUsed = 0; |
1212 | 0 | } |
1213 | | #ifdef DEBUG |
1214 | | mHandles[mHandlesUsed] = reinterpret_cast<nsIContent*>(uintptr_t(0xC0DEDBAD)); |
1215 | | #endif |
1216 | | return &mHandles[mHandlesUsed++]; |
1217 | 0 | } |
1218 | | |
1219 | | bool |
1220 | | nsHtml5TreeBuilder::HasScript() |
1221 | 0 | { |
1222 | 0 | uint32_t len = mOpQueue.Length(); |
1223 | 0 | if (!len) { |
1224 | 0 | return false; |
1225 | 0 | } |
1226 | 0 | return mOpQueue.ElementAt(len - 1).IsRunScript(); |
1227 | 0 | } |
1228 | | |
1229 | | bool |
1230 | | nsHtml5TreeBuilder::Flush(bool aDiscretionary) |
1231 | 0 | { |
1232 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1233 | 0 | MOZ_ASSERT_UNREACHABLE("Must never flush with builder."); |
1234 | 0 | return false; |
1235 | 0 | } |
1236 | 0 | if (NS_SUCCEEDED(mBroken)) { |
1237 | 0 | if (!aDiscretionary || !(charBufferLen && currentPtr >= 0 && |
1238 | 0 | stack[currentPtr]->isFosterParenting())) { |
1239 | 0 | // Don't flush text on discretionary flushes if the current element on |
1240 | 0 | // the stack is a foster-parenting element and there's pending text, |
1241 | 0 | // because flushing in that case would make the tree shape dependent on |
1242 | 0 | // where the flush points fall. |
1243 | 0 | flushCharacters(); |
1244 | 0 | } |
1245 | 0 | FlushLoads(); |
1246 | 0 | } |
1247 | 0 | if (mOpSink) { |
1248 | 0 | bool hasOps = !mOpQueue.IsEmpty(); |
1249 | 0 | if (hasOps) { |
1250 | 0 | // If the builder is broken and mOpQueue is not empty, there must be |
1251 | 0 | // one op and it must be eTreeOpMarkAsBroken. |
1252 | 0 | if (NS_FAILED(mBroken)) { |
1253 | 0 | MOZ_ASSERT(mOpQueue.Length() == 1, |
1254 | 0 | "Tree builder is broken with a non-empty op queue whose " |
1255 | 0 | "length isn't 1."); |
1256 | 0 | MOZ_ASSERT(mOpQueue[0].IsMarkAsBroken(), |
1257 | 0 | "Tree builder is broken but the op in queue is not marked " |
1258 | 0 | "as broken."); |
1259 | 0 | } |
1260 | 0 | mOpSink->MoveOpsFrom(mOpQueue); |
1261 | 0 | } |
1262 | 0 | return hasOps; |
1263 | 0 | } |
1264 | 0 | // no op sink: throw away ops |
1265 | 0 | mOpQueue.Clear(); |
1266 | 0 | return false; |
1267 | 0 | } |
1268 | | |
1269 | | void |
1270 | | nsHtml5TreeBuilder::FlushLoads() |
1271 | 0 | { |
1272 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1273 | 0 | MOZ_ASSERT_UNREACHABLE("Must never flush loads with builder."); |
1274 | 0 | return; |
1275 | 0 | } |
1276 | 0 | if (!mSpeculativeLoadQueue.IsEmpty()) { |
1277 | 0 | mSpeculativeLoadStage->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue); |
1278 | 0 | } |
1279 | 0 | } |
1280 | | |
1281 | | void |
1282 | | nsHtml5TreeBuilder::SetDocumentCharset(NotNull<const Encoding*> aEncoding, |
1283 | | int32_t aCharsetSource) |
1284 | 0 | { |
1285 | 0 | if (mBuilder) { |
1286 | 0 | mBuilder->SetDocumentCharsetAndSource(aEncoding, aCharsetSource); |
1287 | 0 | } else if (mSpeculativeLoadStage) { |
1288 | 0 | mSpeculativeLoadQueue.AppendElement()->InitSetDocumentCharset( |
1289 | 0 | aEncoding, aCharsetSource); |
1290 | 0 | } else { |
1291 | 0 | mOpQueue.AppendElement()->Init( |
1292 | 0 | eTreeOpSetDocumentCharset, aEncoding, aCharsetSource); |
1293 | 0 | } |
1294 | 0 | } |
1295 | | |
1296 | | void |
1297 | | nsHtml5TreeBuilder::StreamEnded() |
1298 | 0 | { |
1299 | 0 | MOZ_ASSERT(!mBuilder, "Must not call StreamEnded with builder."); |
1300 | 0 | MOZ_ASSERT(!fragment, "Must not parse fragments off the main thread."); |
1301 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1302 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1303 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1304 | 0 | return; |
1305 | 0 | } |
1306 | 0 | treeOp->Init(eTreeOpStreamEnded); |
1307 | 0 | } |
1308 | | |
1309 | | void |
1310 | | nsHtml5TreeBuilder::NeedsCharsetSwitchTo(NotNull<const Encoding*> aEncoding, |
1311 | | int32_t aCharsetSource, |
1312 | | int32_t aLineNumber) |
1313 | 0 | { |
1314 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1315 | 0 | MOZ_ASSERT_UNREACHABLE("Must never switch charset with builder."); |
1316 | 0 | return; |
1317 | 0 | } |
1318 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1319 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1320 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1321 | 0 | return; |
1322 | 0 | } |
1323 | 0 | treeOp->Init( |
1324 | 0 | eTreeOpNeedsCharsetSwitchTo, aEncoding, aCharsetSource, aLineNumber); |
1325 | 0 | } |
1326 | | |
1327 | | void |
1328 | | nsHtml5TreeBuilder::MaybeComplainAboutCharset(const char* aMsgId, |
1329 | | bool aError, |
1330 | | int32_t aLineNumber) |
1331 | 0 | { |
1332 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1333 | 0 | MOZ_ASSERT_UNREACHABLE("Must never complain about charset with builder."); |
1334 | 0 | return; |
1335 | 0 | } |
1336 | 0 | mOpQueue.AppendElement()->Init(aMsgId, aError, aLineNumber); |
1337 | 0 | } |
1338 | | |
1339 | | void |
1340 | | nsHtml5TreeBuilder::TryToEnableEncodingMenu() |
1341 | 0 | { |
1342 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1343 | 0 | MOZ_ASSERT_UNREACHABLE("Must never disable encoding menu with builder."); |
1344 | 0 | return; |
1345 | 0 | } |
1346 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(); |
1347 | 0 | NS_ASSERTION(treeOp, "Tree op allocation failed."); |
1348 | 0 | treeOp->Init(eTreeOpEnableEncodingMenu); |
1349 | 0 | } |
1350 | | |
1351 | | void |
1352 | | nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState* aSnapshot, |
1353 | | int32_t aLine) |
1354 | 0 | { |
1355 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1356 | 0 | MOZ_ASSERT_UNREACHABLE("Must never use snapshots with builder."); |
1357 | 0 | return; |
1358 | 0 | } |
1359 | 0 | MOZ_ASSERT(HasScript(), "No script to add a snapshot to!"); |
1360 | 0 | MOZ_ASSERT(aSnapshot, "Got null snapshot."); |
1361 | 0 | mOpQueue.ElementAt(mOpQueue.Length() - 1).SetSnapshot(aSnapshot, aLine); |
1362 | 0 | } |
1363 | | |
1364 | | void |
1365 | | nsHtml5TreeBuilder::DropHandles() |
1366 | 0 | { |
1367 | 0 | MOZ_ASSERT(!mBuilder, "Must not drop handles with builder."); |
1368 | 0 | mOldHandles.Clear(); |
1369 | 0 | mHandlesUsed = 0; |
1370 | 0 | } |
1371 | | |
1372 | | void |
1373 | | nsHtml5TreeBuilder::MarkAsBroken(nsresult aRv) |
1374 | 0 | { |
1375 | 0 | if (MOZ_UNLIKELY(mBuilder)) { |
1376 | 0 | MOZ_ASSERT_UNREACHABLE("Must not call this with builder."); |
1377 | 0 | return; |
1378 | 0 | } |
1379 | 0 | mBroken = aRv; |
1380 | 0 | mOpQueue.Clear(); // Previous ops don't matter anymore |
1381 | 0 | mOpQueue.AppendElement()->Init(aRv); |
1382 | 0 | } |
1383 | | |
1384 | | void |
1385 | | nsHtml5TreeBuilder::MarkAsBrokenFromPortability(nsresult aRv) |
1386 | 0 | { |
1387 | 0 | if (mBuilder) { |
1388 | 0 | MarkAsBrokenAndRequestSuspensionWithBuilder(aRv); |
1389 | 0 | return; |
1390 | 0 | } |
1391 | 0 | mBroken = aRv; |
1392 | 0 | requestSuspension(); |
1393 | 0 | } |
1394 | | |
1395 | | void |
1396 | | nsHtml5TreeBuilder::StartPlainTextViewSource(const nsAutoString& aTitle) |
1397 | 0 | { |
1398 | 0 | MOZ_ASSERT(!mBuilder, "Must not view source with builder."); |
1399 | 0 |
|
1400 | 0 | startTag(nsHtml5ElementName::ELT_META, |
1401 | 0 | nsHtml5ViewSourceUtils::NewMetaViewportAttributes(), |
1402 | 0 | false); |
1403 | 0 |
|
1404 | 0 | startTag(nsHtml5ElementName::ELT_TITLE, |
1405 | 0 | nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, |
1406 | 0 | false); |
1407 | 0 |
|
1408 | 0 | // XUL will add the "Source of: " prefix. |
1409 | 0 | uint32_t length = aTitle.Length(); |
1410 | 0 | if (length > INT32_MAX) { |
1411 | 0 | length = INT32_MAX; |
1412 | 0 | } |
1413 | 0 | characters(aTitle.get(), 0, (int32_t)length); |
1414 | 0 | endTag(nsHtml5ElementName::ELT_TITLE); |
1415 | 0 |
|
1416 | 0 | startTag(nsHtml5ElementName::ELT_LINK, |
1417 | 0 | nsHtml5ViewSourceUtils::NewLinkAttributes(), |
1418 | 0 | false); |
1419 | 0 |
|
1420 | 0 | startTag(nsHtml5ElementName::ELT_BODY, |
1421 | 0 | nsHtml5ViewSourceUtils::NewBodyAttributes(), |
1422 | 0 | false); |
1423 | 0 |
|
1424 | 0 | StartPlainTextBody(); |
1425 | 0 | } |
1426 | | |
1427 | | void |
1428 | | nsHtml5TreeBuilder::StartPlainText() |
1429 | 0 | { |
1430 | 0 | MOZ_ASSERT(!mBuilder, "Must not view source with builder."); |
1431 | 0 | startTag(nsHtml5ElementName::ELT_LINK, |
1432 | 0 | nsHtml5PlainTextUtils::NewLinkAttributes(), |
1433 | 0 | false); |
1434 | 0 |
|
1435 | 0 | StartPlainTextBody(); |
1436 | 0 | } |
1437 | | |
1438 | | void |
1439 | | nsHtml5TreeBuilder::StartPlainTextBody() |
1440 | 0 | { |
1441 | 0 | MOZ_ASSERT(!mBuilder, "Must not view source with builder."); |
1442 | 0 | startTag(nsHtml5ElementName::ELT_PRE, |
1443 | 0 | nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES, |
1444 | 0 | false); |
1445 | 0 | needToDropLF = false; |
1446 | 0 | } |
1447 | | |
1448 | | // DocumentModeHandler |
1449 | | void |
1450 | | nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m) |
1451 | 0 | { |
1452 | 0 | if (mBuilder) { |
1453 | 0 | mBuilder->SetDocumentMode(m); |
1454 | 0 | return; |
1455 | 0 | } |
1456 | 0 | if (mSpeculativeLoadStage) { |
1457 | 0 | mSpeculativeLoadQueue.AppendElement()->InitSetDocumentMode(m); |
1458 | 0 | return; |
1459 | 0 | } |
1460 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1461 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1462 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1463 | 0 | return; |
1464 | 0 | } |
1465 | 0 | treeOp->Init(m); |
1466 | 0 | } |
1467 | | |
1468 | | nsIContentHandle* |
1469 | | nsHtml5TreeBuilder::getDocumentFragmentForTemplate(nsIContentHandle* aTemplate) |
1470 | 0 | { |
1471 | 0 | if (mBuilder) { |
1472 | 0 | return nsHtml5TreeOperation::GetDocumentFragmentForTemplate( |
1473 | 0 | static_cast<nsIContent*>(aTemplate)); |
1474 | 0 | } |
1475 | 0 | nsHtml5TreeOperation* treeOp = mOpQueue.AppendElement(mozilla::fallible); |
1476 | 0 | if (MOZ_UNLIKELY(!treeOp)) { |
1477 | 0 | MarkAsBrokenAndRequestSuspensionWithoutBuilder(NS_ERROR_OUT_OF_MEMORY); |
1478 | 0 | return nullptr; |
1479 | 0 | } |
1480 | 0 | nsIContentHandle* fragHandle = AllocateContentHandle(); |
1481 | 0 | treeOp->Init(eTreeOpGetDocumentFragmentForTemplate, aTemplate, fragHandle); |
1482 | 0 | return fragHandle; |
1483 | 0 | } |
1484 | | |
1485 | | nsIContentHandle* |
1486 | | nsHtml5TreeBuilder::getFormPointerForContext(nsIContentHandle* aContext) |
1487 | 0 | { |
1488 | 0 | MOZ_ASSERT(mBuilder, "Must have builder."); |
1489 | 0 | if (!aContext) { |
1490 | 0 | return nullptr; |
1491 | 0 | } |
1492 | 0 | |
1493 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1494 | 0 |
|
1495 | 0 | // aContext must always be an element that already exists |
1496 | 0 | // in the document. |
1497 | 0 | nsIContent* contextNode = static_cast<nsIContent*>(aContext); |
1498 | 0 | nsIContent* currentAncestor = contextNode; |
1499 | 0 |
|
1500 | 0 | // We traverse the ancestors of the context node to find the nearest |
1501 | 0 | // form pointer. This traversal is why aContext must not be an emtpy handle. |
1502 | 0 | nsIContent* nearestForm = nullptr; |
1503 | 0 | while (currentAncestor) { |
1504 | 0 | if (currentAncestor->IsHTMLElement(nsGkAtoms::form)) { |
1505 | 0 | nearestForm = currentAncestor; |
1506 | 0 | break; |
1507 | 0 | } |
1508 | 0 | currentAncestor = currentAncestor->GetParent(); |
1509 | 0 | } |
1510 | 0 |
|
1511 | 0 | if (!nearestForm) { |
1512 | 0 | return nullptr; |
1513 | 0 | } |
1514 | 0 | |
1515 | 0 | return nearestForm; |
1516 | 0 | } |
1517 | | |
1518 | | // Error reporting |
1519 | | |
1520 | | void |
1521 | | nsHtml5TreeBuilder::EnableViewSource(nsHtml5Highlighter* aHighlighter) |
1522 | 0 | { |
1523 | 0 | MOZ_ASSERT(!mBuilder, "Must not view source with builder."); |
1524 | 0 | mViewSource = aHighlighter; |
1525 | 0 | } |
1526 | | |
1527 | | void |
1528 | | nsHtml5TreeBuilder::errStrayStartTag(nsAtom* aName) |
1529 | 0 | { |
1530 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1531 | 0 | mViewSource->AddErrorToCurrentRun("errStrayStartTag2", aName); |
1532 | 0 | } |
1533 | 0 | } |
1534 | | |
1535 | | void |
1536 | | nsHtml5TreeBuilder::errStrayEndTag(nsAtom* aName) |
1537 | 0 | { |
1538 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1539 | 0 | mViewSource->AddErrorToCurrentRun("errStrayEndTag", aName); |
1540 | 0 | } |
1541 | 0 | } |
1542 | | |
1543 | | void |
1544 | | nsHtml5TreeBuilder::errUnclosedElements(int32_t aIndex, nsAtom* aName) |
1545 | 0 | { |
1546 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1547 | 0 | mViewSource->AddErrorToCurrentRun("errUnclosedElements", aName); |
1548 | 0 | } |
1549 | 0 | } |
1550 | | |
1551 | | void |
1552 | | nsHtml5TreeBuilder::errUnclosedElementsImplied(int32_t aIndex, nsAtom* aName) |
1553 | 0 | { |
1554 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1555 | 0 | mViewSource->AddErrorToCurrentRun("errUnclosedElementsImplied", aName); |
1556 | 0 | } |
1557 | 0 | } |
1558 | | |
1559 | | void |
1560 | | nsHtml5TreeBuilder::errUnclosedElementsCell(int32_t aIndex) |
1561 | 0 | { |
1562 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1563 | 0 | mViewSource->AddErrorToCurrentRun("errUnclosedElementsCell"); |
1564 | 0 | } |
1565 | 0 | } |
1566 | | |
1567 | | void |
1568 | | nsHtml5TreeBuilder::errStrayDoctype() |
1569 | 0 | { |
1570 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1571 | 0 | mViewSource->AddErrorToCurrentRun("errStrayDoctype"); |
1572 | 0 | } |
1573 | 0 | } |
1574 | | |
1575 | | void |
1576 | | nsHtml5TreeBuilder::errAlmostStandardsDoctype() |
1577 | 0 | { |
1578 | 0 | if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { |
1579 | 0 | mViewSource->AddErrorToCurrentRun("errAlmostStandardsDoctype"); |
1580 | 0 | } |
1581 | 0 | } |
1582 | | |
1583 | | void |
1584 | | nsHtml5TreeBuilder::errQuirkyDoctype() |
1585 | 0 | { |
1586 | 0 | if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { |
1587 | 0 | mViewSource->AddErrorToCurrentRun("errQuirkyDoctype"); |
1588 | 0 | } |
1589 | 0 | } |
1590 | | |
1591 | | void |
1592 | | nsHtml5TreeBuilder::errNonSpaceInTrailer() |
1593 | 0 | { |
1594 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1595 | 0 | mViewSource->AddErrorToCurrentRun("errNonSpaceInTrailer"); |
1596 | 0 | } |
1597 | 0 | } |
1598 | | |
1599 | | void |
1600 | | nsHtml5TreeBuilder::errNonSpaceAfterFrameset() |
1601 | 0 | { |
1602 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1603 | 0 | mViewSource->AddErrorToCurrentRun("errNonSpaceAfterFrameset"); |
1604 | 0 | } |
1605 | 0 | } |
1606 | | |
1607 | | void |
1608 | | nsHtml5TreeBuilder::errNonSpaceInFrameset() |
1609 | 0 | { |
1610 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1611 | 0 | mViewSource->AddErrorToCurrentRun("errNonSpaceInFrameset"); |
1612 | 0 | } |
1613 | 0 | } |
1614 | | |
1615 | | void |
1616 | | nsHtml5TreeBuilder::errNonSpaceAfterBody() |
1617 | 0 | { |
1618 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1619 | 0 | mViewSource->AddErrorToCurrentRun("errNonSpaceAfterBody"); |
1620 | 0 | } |
1621 | 0 | } |
1622 | | |
1623 | | void |
1624 | | nsHtml5TreeBuilder::errNonSpaceInColgroupInFragment() |
1625 | 0 | { |
1626 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1627 | 0 | mViewSource->AddErrorToCurrentRun("errNonSpaceInColgroupInFragment"); |
1628 | 0 | } |
1629 | 0 | } |
1630 | | |
1631 | | void |
1632 | | nsHtml5TreeBuilder::errNonSpaceInNoscriptInHead() |
1633 | 0 | { |
1634 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1635 | 0 | mViewSource->AddErrorToCurrentRun("errNonSpaceInNoscriptInHead"); |
1636 | 0 | } |
1637 | 0 | } |
1638 | | |
1639 | | void |
1640 | | nsHtml5TreeBuilder::errFooBetweenHeadAndBody(nsAtom* aName) |
1641 | 0 | { |
1642 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1643 | 0 | mViewSource->AddErrorToCurrentRun("errFooBetweenHeadAndBody", aName); |
1644 | 0 | } |
1645 | 0 | } |
1646 | | |
1647 | | void |
1648 | | nsHtml5TreeBuilder::errStartTagWithoutDoctype() |
1649 | 0 | { |
1650 | 0 | if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { |
1651 | 0 | mViewSource->AddErrorToCurrentRun("errStartTagWithoutDoctype"); |
1652 | 0 | } |
1653 | 0 | } |
1654 | | |
1655 | | void |
1656 | | nsHtml5TreeBuilder::errNoSelectInTableScope() |
1657 | 0 | { |
1658 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1659 | 0 | mViewSource->AddErrorToCurrentRun("errNoSelectInTableScope"); |
1660 | 0 | } |
1661 | 0 | } |
1662 | | |
1663 | | void |
1664 | | nsHtml5TreeBuilder::errStartSelectWhereEndSelectExpected() |
1665 | 0 | { |
1666 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1667 | 0 | mViewSource->AddErrorToCurrentRun("errStartSelectWhereEndSelectExpected"); |
1668 | 0 | } |
1669 | 0 | } |
1670 | | |
1671 | | void |
1672 | | nsHtml5TreeBuilder::errStartTagWithSelectOpen(nsAtom* aName) |
1673 | 0 | { |
1674 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1675 | 0 | mViewSource->AddErrorToCurrentRun("errStartTagWithSelectOpen", aName); |
1676 | 0 | } |
1677 | 0 | } |
1678 | | |
1679 | | void |
1680 | | nsHtml5TreeBuilder::errBadStartTagInHead(nsAtom* aName) |
1681 | 0 | { |
1682 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1683 | 0 | mViewSource->AddErrorToCurrentRun("errBadStartTagInHead2", aName); |
1684 | 0 | } |
1685 | 0 | } |
1686 | | |
1687 | | void |
1688 | | nsHtml5TreeBuilder::errImage() |
1689 | 0 | { |
1690 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1691 | 0 | mViewSource->AddErrorToCurrentRun("errImage"); |
1692 | 0 | } |
1693 | 0 | } |
1694 | | |
1695 | | void |
1696 | | nsHtml5TreeBuilder::errIsindex() |
1697 | 0 | { |
1698 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1699 | 0 | mViewSource->AddErrorToCurrentRun("errIsindex"); |
1700 | 0 | } |
1701 | 0 | } |
1702 | | |
1703 | | void |
1704 | | nsHtml5TreeBuilder::errFooSeenWhenFooOpen(nsAtom* aName) |
1705 | 0 | { |
1706 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1707 | 0 | mViewSource->AddErrorToCurrentRun("errFooSeenWhenFooOpen", aName); |
1708 | 0 | } |
1709 | 0 | } |
1710 | | |
1711 | | void |
1712 | | nsHtml5TreeBuilder::errHeadingWhenHeadingOpen() |
1713 | 0 | { |
1714 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1715 | 0 | mViewSource->AddErrorToCurrentRun("errHeadingWhenHeadingOpen"); |
1716 | 0 | } |
1717 | 0 | } |
1718 | | |
1719 | | void |
1720 | | nsHtml5TreeBuilder::errFramesetStart() |
1721 | 0 | { |
1722 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1723 | 0 | mViewSource->AddErrorToCurrentRun("errFramesetStart"); |
1724 | 0 | } |
1725 | 0 | } |
1726 | | |
1727 | | void |
1728 | | nsHtml5TreeBuilder::errNoCellToClose() |
1729 | 0 | { |
1730 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1731 | 0 | mViewSource->AddErrorToCurrentRun("errNoCellToClose"); |
1732 | 0 | } |
1733 | 0 | } |
1734 | | |
1735 | | void |
1736 | | nsHtml5TreeBuilder::errStartTagInTable(nsAtom* aName) |
1737 | 0 | { |
1738 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1739 | 0 | mViewSource->AddErrorToCurrentRun("errStartTagInTable", aName); |
1740 | 0 | } |
1741 | 0 | } |
1742 | | |
1743 | | void |
1744 | | nsHtml5TreeBuilder::errFormWhenFormOpen() |
1745 | 0 | { |
1746 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1747 | 0 | mViewSource->AddErrorToCurrentRun("errFormWhenFormOpen"); |
1748 | 0 | } |
1749 | 0 | } |
1750 | | |
1751 | | void |
1752 | | nsHtml5TreeBuilder::errTableSeenWhileTableOpen() |
1753 | 0 | { |
1754 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1755 | 0 | mViewSource->AddErrorToCurrentRun("errTableSeenWhileTableOpen"); |
1756 | 0 | } |
1757 | 0 | } |
1758 | | |
1759 | | void |
1760 | | nsHtml5TreeBuilder::errStartTagInTableBody(nsAtom* aName) |
1761 | 0 | { |
1762 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1763 | 0 | mViewSource->AddErrorToCurrentRun("errStartTagInTableBody", aName); |
1764 | 0 | } |
1765 | 0 | } |
1766 | | |
1767 | | void |
1768 | | nsHtml5TreeBuilder::errEndTagSeenWithoutDoctype() |
1769 | 0 | { |
1770 | 0 | if (MOZ_UNLIKELY(mViewSource) && !isSrcdocDocument) { |
1771 | 0 | mViewSource->AddErrorToCurrentRun("errEndTagSeenWithoutDoctype"); |
1772 | 0 | } |
1773 | 0 | } |
1774 | | |
1775 | | void |
1776 | | nsHtml5TreeBuilder::errEndTagAfterBody() |
1777 | 0 | { |
1778 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1779 | 0 | mViewSource->AddErrorToCurrentRun("errEndTagAfterBody"); |
1780 | 0 | } |
1781 | 0 | } |
1782 | | |
1783 | | void |
1784 | | nsHtml5TreeBuilder::errEndTagSeenWithSelectOpen(nsAtom* aName) |
1785 | 0 | { |
1786 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1787 | 0 | mViewSource->AddErrorToCurrentRun("errEndTagSeenWithSelectOpen", aName); |
1788 | 0 | } |
1789 | 0 | } |
1790 | | |
1791 | | void |
1792 | | nsHtml5TreeBuilder::errGarbageInColgroup() |
1793 | 0 | { |
1794 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1795 | 0 | mViewSource->AddErrorToCurrentRun("errGarbageInColgroup"); |
1796 | 0 | } |
1797 | 0 | } |
1798 | | |
1799 | | void |
1800 | | nsHtml5TreeBuilder::errEndTagBr() |
1801 | 0 | { |
1802 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1803 | 0 | mViewSource->AddErrorToCurrentRun("errEndTagBr"); |
1804 | 0 | } |
1805 | 0 | } |
1806 | | |
1807 | | void |
1808 | | nsHtml5TreeBuilder::errNoElementToCloseButEndTagSeen(nsAtom* aName) |
1809 | 0 | { |
1810 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1811 | 0 | mViewSource->AddErrorToCurrentRun("errNoElementToCloseButEndTagSeen", |
1812 | 0 | aName); |
1813 | 0 | } |
1814 | 0 | } |
1815 | | |
1816 | | void |
1817 | | nsHtml5TreeBuilder::errHtmlStartTagInForeignContext(nsAtom* aName) |
1818 | 0 | { |
1819 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1820 | 0 | mViewSource->AddErrorToCurrentRun("errHtmlStartTagInForeignContext", aName); |
1821 | 0 | } |
1822 | 0 | } |
1823 | | |
1824 | | void |
1825 | | nsHtml5TreeBuilder::errTableClosedWhileCaptionOpen() |
1826 | 0 | { |
1827 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1828 | 0 | mViewSource->AddErrorToCurrentRun("errTableClosedWhileCaptionOpen"); |
1829 | 0 | } |
1830 | 0 | } |
1831 | | |
1832 | | void |
1833 | | nsHtml5TreeBuilder::errNoTableRowToClose() |
1834 | 0 | { |
1835 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1836 | 0 | mViewSource->AddErrorToCurrentRun("errNoTableRowToClose"); |
1837 | 0 | } |
1838 | 0 | } |
1839 | | |
1840 | | void |
1841 | | nsHtml5TreeBuilder::errNonSpaceInTable() |
1842 | 0 | { |
1843 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1844 | 0 | mViewSource->AddErrorToCurrentRun("errNonSpaceInTable"); |
1845 | 0 | } |
1846 | 0 | } |
1847 | | |
1848 | | void |
1849 | | nsHtml5TreeBuilder::errUnclosedChildrenInRuby() |
1850 | 0 | { |
1851 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1852 | 0 | mViewSource->AddErrorToCurrentRun("errUnclosedChildrenInRuby"); |
1853 | 0 | } |
1854 | 0 | } |
1855 | | |
1856 | | void |
1857 | | nsHtml5TreeBuilder::errStartTagSeenWithoutRuby(nsAtom* aName) |
1858 | 0 | { |
1859 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1860 | 0 | mViewSource->AddErrorToCurrentRun("errStartTagSeenWithoutRuby", aName); |
1861 | 0 | } |
1862 | 0 | } |
1863 | | |
1864 | | void |
1865 | | nsHtml5TreeBuilder::errSelfClosing() |
1866 | 0 | { |
1867 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1868 | 0 | mViewSource->AddErrorToCurrentSlash("errSelfClosing"); |
1869 | 0 | } |
1870 | 0 | } |
1871 | | |
1872 | | void |
1873 | | nsHtml5TreeBuilder::errNoCheckUnclosedElementsOnStack() |
1874 | 0 | { |
1875 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1876 | 0 | mViewSource->AddErrorToCurrentRun("errNoCheckUnclosedElementsOnStack"); |
1877 | 0 | } |
1878 | 0 | } |
1879 | | |
1880 | | void |
1881 | | nsHtml5TreeBuilder::errEndTagDidNotMatchCurrentOpenElement(nsAtom* aName, |
1882 | | nsAtom* aOther) |
1883 | 0 | { |
1884 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1885 | 0 | mViewSource->AddErrorToCurrentRun( |
1886 | 0 | "errEndTagDidNotMatchCurrentOpenElement", aName, aOther); |
1887 | 0 | } |
1888 | 0 | } |
1889 | | |
1890 | | void |
1891 | | nsHtml5TreeBuilder::errEndTagViolatesNestingRules(nsAtom* aName) |
1892 | 0 | { |
1893 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1894 | 0 | mViewSource->AddErrorToCurrentRun("errEndTagViolatesNestingRules", aName); |
1895 | 0 | } |
1896 | 0 | } |
1897 | | |
1898 | | void |
1899 | | nsHtml5TreeBuilder::errEndWithUnclosedElements(nsAtom* aName) |
1900 | 0 | { |
1901 | 0 | if (MOZ_UNLIKELY(mViewSource)) { |
1902 | 0 | mViewSource->AddErrorToCurrentRun("errEndWithUnclosedElements", aName); |
1903 | 0 | } |
1904 | 0 | } |