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 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Henri Sivonen <hsivonen@iki.fi>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsContentErrors.h"
42 #include "nsIPresShell.h"
44 #include "nsGUIEvent.h"
45 #include "nsEventDispatcher.h"
46 #include "nsContentUtils.h"
47 #include "nsNodeUtils.h"
49 #define NS_HTML5_TREE_DEPTH_LIMIT 200
53 nsHtml5TreeBuilder::nsHtml5TreeBuilder(nsAHtml5TreeOpSink
* aOpSink
,
54 nsHtml5TreeOpStage
* aStage
)
55 : scriptingEnabled(PR_FALSE
)
61 , mHandles(new nsIContent
*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
])
63 , mSpeculativeLoadStage(aStage
)
64 , mCurrentHtmlScriptIsAsyncOrDefer(PR_FALSE
)
69 MOZ_COUNT_CTOR(nsHtml5TreeBuilder
);
72 nsHtml5TreeBuilder::~nsHtml5TreeBuilder()
74 MOZ_COUNT_DTOR(nsHtml5TreeBuilder
);
75 NS_ASSERTION(!mActive
, "nsHtml5TreeBuilder deleted without ever calling end() on it!");
80 nsHtml5TreeBuilder::createElement(PRInt32 aNamespace
, nsIAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
)
82 NS_PRECONDITION(aAttributes
, "Got null attributes.");
83 NS_PRECONDITION(aName
, "Got null name.");
84 NS_PRECONDITION(aNamespace
== kNameSpaceID_XHTML
||
85 aNamespace
== kNameSpaceID_SVG
||
86 aNamespace
== kNameSpaceID_MathML
,
89 nsIContent
** content
= AllocateContentHandle();
90 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
91 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
92 treeOp
->Init(aNamespace
,
96 !!mSpeculativeLoadStage
);
97 // mSpeculativeLoadStage is non-null only in the off-the-main-thread
98 // tree builder, which handles the network stream
100 // Start wall of code for speculative loading and line numbers
102 if (mSpeculativeLoadStage
) {
103 switch (aNamespace
) {
104 case kNameSpaceID_XHTML
:
105 if (nsHtml5Atoms::img
== aName
) {
106 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRC
);
108 mSpeculativeLoadQueue
.AppendElement()->InitImage(*url
);
110 } else if (nsHtml5Atoms::script
== aName
) {
111 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
112 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
113 treeOp
->Init(eTreeOpSetScriptLineNumberAndFreeze
, content
, tokenizer
->getLineNumber());
115 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_SRC
);
117 nsString
* charset
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
118 nsString
* type
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
119 mSpeculativeLoadQueue
.AppendElement()->InitScript(*url
,
120 (charset
) ? *charset
: EmptyString(),
121 (type
) ? *type
: EmptyString());
122 mCurrentHtmlScriptIsAsyncOrDefer
=
123 aAttributes
->contains(nsHtml5AttributeName::ATTR_ASYNC
) ||
124 aAttributes
->contains(nsHtml5AttributeName::ATTR_DEFER
);
126 } else if (nsHtml5Atoms::link
== aName
) {
127 nsString
* rel
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_REL
);
128 // Not splitting on space here is bogus but the old parser didn't even
129 // do a case-insensitive check.
130 if (rel
&& rel
->LowerCaseEqualsASCII("stylesheet")) {
131 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
133 nsString
* charset
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_CHARSET
);
134 mSpeculativeLoadQueue
.AppendElement()->InitStyle(*url
,
135 (charset
) ? *charset
: EmptyString());
138 } else if (nsHtml5Atoms::video
== aName
) {
139 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_POSTER
);
141 mSpeculativeLoadQueue
.AppendElement()->InitImage(*url
);
143 } else if (nsHtml5Atoms::style
== aName
) {
144 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
145 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
146 treeOp
->Init(eTreeOpSetStyleLineNumber
, content
, tokenizer
->getLineNumber());
147 } else if (nsHtml5Atoms::html
== aName
) {
148 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_MANIFEST
);
150 mSpeculativeLoadQueue
.AppendElement()->InitManifest(*url
);
152 } else if (nsHtml5Atoms::base
== aName
&&
153 (mode
== NS_HTML5TREE_BUILDER_IN_HEAD
||
154 mode
== NS_HTML5TREE_BUILDER_AFTER_HEAD
)) {
156 aAttributes
->getValue(nsHtml5AttributeName::ATTR_HREF
);
158 mSpeculativeLoadQueue
.AppendElement()->InitBase(*url
);
162 case kNameSpaceID_SVG
:
163 if (nsHtml5Atoms::image
== aName
) {
164 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF
);
166 mSpeculativeLoadQueue
.AppendElement()->InitImage(*url
);
168 } else if (nsHtml5Atoms::script
== aName
) {
169 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
170 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
171 treeOp
->Init(eTreeOpSetScriptLineNumberAndFreeze
, content
, tokenizer
->getLineNumber());
173 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF
);
175 nsString
* type
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_TYPE
);
176 mSpeculativeLoadQueue
.AppendElement()->InitScript(*url
,
178 (type
) ? *type
: EmptyString());
180 } else if (nsHtml5Atoms::style
== aName
) {
181 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
182 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
183 treeOp
->Init(eTreeOpSetStyleLineNumber
, content
, tokenizer
->getLineNumber());
185 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_XLINK_HREF
);
187 mSpeculativeLoadQueue
.AppendElement()->InitStyle(*url
, EmptyString());
192 } else if (aNamespace
!= kNameSpaceID_MathML
) {
193 // No speculative loader--just line numbers and defer/async check
194 if (nsHtml5Atoms::style
== aName
) {
195 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
196 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
197 treeOp
->Init(eTreeOpSetStyleLineNumber
, content
, tokenizer
->getLineNumber());
198 } else if (nsHtml5Atoms::script
== aName
) {
199 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
200 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
201 treeOp
->Init(eTreeOpSetScriptLineNumberAndFreeze
, content
, tokenizer
->getLineNumber());
202 if (aNamespace
== kNameSpaceID_XHTML
) {
203 mCurrentHtmlScriptIsAsyncOrDefer
=
204 aAttributes
->contains(nsHtml5AttributeName::ATTR_SRC
) &&
205 (aAttributes
->contains(nsHtml5AttributeName::ATTR_ASYNC
) ||
206 aAttributes
->contains(nsHtml5AttributeName::ATTR_DEFER
));
208 } else if (aNamespace
== kNameSpaceID_XHTML
&& nsHtml5Atoms::html
== aName
) {
209 nsString
* url
= aAttributes
->getValue(nsHtml5AttributeName::ATTR_MANIFEST
);
211 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
212 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
213 treeOp
->Init(eTreeOpProcessOfflineManifest
, *url
);
218 // End wall of code for speculative loading
224 nsHtml5TreeBuilder::createElement(PRInt32 aNamespace
, nsIAtom
* aName
, nsHtml5HtmlAttributes
* aAttributes
, nsIContent
** aFormElement
)
226 nsIContent
** content
= createElement(aNamespace
, aName
, aAttributes
);
228 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
229 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
230 treeOp
->Init(eTreeOpSetFormElement
, content
, aFormElement
);
236 nsHtml5TreeBuilder::createHtmlElementSetAsRoot(nsHtml5HtmlAttributes
* aAttributes
)
238 nsIContent
** content
= createElement(kNameSpaceID_XHTML
, nsHtml5Atoms::html
, aAttributes
);
239 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
240 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
241 treeOp
->Init(eTreeOpAppendToDocument
, content
);
246 nsHtml5TreeBuilder::detachFromParent(nsIContent
** aElement
)
248 NS_PRECONDITION(aElement
, "Null element");
250 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
251 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
252 treeOp
->Init(eTreeOpDetach
, aElement
);
256 nsHtml5TreeBuilder::appendElement(nsIContent
** aChild
, nsIContent
** aParent
)
258 NS_PRECONDITION(aChild
, "Null child");
259 NS_PRECONDITION(aParent
, "Null parent");
260 if (deepTreeSurrogateParent
) {
263 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
264 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
265 treeOp
->Init(eTreeOpAppend
, aChild
, aParent
);
269 nsHtml5TreeBuilder::appendChildrenToNewParent(nsIContent
** aOldParent
, nsIContent
** aNewParent
)
271 NS_PRECONDITION(aOldParent
, "Null old parent");
272 NS_PRECONDITION(aNewParent
, "Null new parent");
274 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
275 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
276 treeOp
->Init(eTreeOpAppendChildrenToNewParent
, aOldParent
, aNewParent
);
280 nsHtml5TreeBuilder::insertFosterParentedCharacters(PRUnichar
* aBuffer
, PRInt32 aStart
, PRInt32 aLength
, nsIContent
** aTable
, nsIContent
** aStackParent
)
282 NS_PRECONDITION(aBuffer
, "Null buffer");
283 NS_PRECONDITION(aTable
, "Null table");
284 NS_PRECONDITION(aStackParent
, "Null stack parent");
286 PRUnichar
* bufferCopy
= new PRUnichar
[aLength
];
287 memcpy(bufferCopy
, aBuffer
, aLength
* sizeof(PRUnichar
));
289 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
290 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
291 treeOp
->Init(eTreeOpFosterParentText
, bufferCopy
, aLength
, aStackParent
, aTable
);
295 nsHtml5TreeBuilder::insertFosterParentedChild(nsIContent
** aChild
, nsIContent
** aTable
, nsIContent
** aStackParent
)
297 NS_PRECONDITION(aChild
, "Null child");
298 NS_PRECONDITION(aTable
, "Null table");
299 NS_PRECONDITION(aStackParent
, "Null stack parent");
301 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
302 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
303 treeOp
->Init(eTreeOpFosterParent
, aChild
, aStackParent
, aTable
);
307 nsHtml5TreeBuilder::appendCharacters(nsIContent
** aParent
, PRUnichar
* aBuffer
, PRInt32 aStart
, PRInt32 aLength
)
309 NS_PRECONDITION(aBuffer
, "Null buffer");
310 NS_PRECONDITION(aParent
, "Null parent");
312 PRUnichar
* bufferCopy
= new PRUnichar
[aLength
];
313 memcpy(bufferCopy
, aBuffer
, aLength
* sizeof(PRUnichar
));
315 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
316 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
317 treeOp
->Init(eTreeOpAppendText
, bufferCopy
, aLength
,
318 deepTreeSurrogateParent
? deepTreeSurrogateParent
: aParent
);
322 nsHtml5TreeBuilder::appendIsindexPrompt(nsIContent
** aParent
)
324 NS_PRECONDITION(aParent
, "Null parent");
326 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
327 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
328 treeOp
->Init(eTreeOpAppendIsindexPrompt
, aParent
);
332 nsHtml5TreeBuilder::appendComment(nsIContent
** aParent
, PRUnichar
* aBuffer
, PRInt32 aStart
, PRInt32 aLength
)
334 NS_PRECONDITION(aBuffer
, "Null buffer");
335 NS_PRECONDITION(aParent
, "Null parent");
336 if (deepTreeSurrogateParent
) {
340 PRUnichar
* bufferCopy
= new PRUnichar
[aLength
];
341 memcpy(bufferCopy
, aBuffer
, aLength
* sizeof(PRUnichar
));
343 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
344 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
345 treeOp
->Init(eTreeOpAppendComment
, bufferCopy
, aLength
, aParent
);
349 nsHtml5TreeBuilder::appendCommentToDocument(PRUnichar
* aBuffer
, PRInt32 aStart
, PRInt32 aLength
)
351 NS_PRECONDITION(aBuffer
, "Null buffer");
353 PRUnichar
* bufferCopy
= new PRUnichar
[aLength
];
354 memcpy(bufferCopy
, aBuffer
, aLength
* sizeof(PRUnichar
));
356 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
357 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
358 treeOp
->Init(eTreeOpAppendCommentToDocument
, bufferCopy
, aLength
);
362 nsHtml5TreeBuilder::addAttributesToElement(nsIContent
** aElement
, nsHtml5HtmlAttributes
* aAttributes
)
364 NS_PRECONDITION(aElement
, "Null element");
365 NS_PRECONDITION(aAttributes
, "Null attributes");
367 if (aAttributes
== nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES
) {
370 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
371 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
372 treeOp
->Init(aElement
, aAttributes
);
376 nsHtml5TreeBuilder::markMalformedIfScript(nsIContent
** aElement
)
378 NS_PRECONDITION(aElement
, "Null element");
380 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
381 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
382 treeOp
->Init(eTreeOpMarkMalformedIfScript
, aElement
);
386 nsHtml5TreeBuilder::start(PRBool fragment
)
388 mCurrentHtmlScriptIsAsyncOrDefer
= PR_FALSE
;
389 deepTreeSurrogateParent
= nsnull
;
396 nsHtml5TreeBuilder::end()
405 nsHtml5TreeBuilder::appendDoctypeToDocument(nsIAtom
* aName
, nsString
* aPublicId
, nsString
* aSystemId
)
407 NS_PRECONDITION(aName
, "Null name");
409 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
410 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
411 treeOp
->Init(aName
, *aPublicId
, *aSystemId
);
412 // nsXMLContentSink can flush here, but what's the point?
413 // It can also interrupt here, but we can't.
417 nsHtml5TreeBuilder::elementPushed(PRInt32 aNamespace
, nsIAtom
* aName
, nsIContent
** aElement
)
419 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
|| aNamespace
== kNameSpaceID_SVG
|| aNamespace
== kNameSpaceID_MathML
, "Element isn't HTML, SVG or MathML!");
420 NS_ASSERTION(aName
, "Element doesn't have local name!");
421 NS_ASSERTION(aElement
, "No element!");
423 * The frame constructor uses recursive algorithms, so it can't deal with
424 * arbitrarily deep trees. This is especially a problem on Windows where
425 * the permitted depth of the runtime stack is rather small.
427 * The following is a protection against author incompetence--not against
428 * malice. There are other ways to make the DOM deep anyway.
430 * The basic idea is that when the tree builder stack gets too deep,
431 * append operations no longer append to the node that the HTML parsing
432 * algorithm says they should but instead text nodes are append to the last
433 * element that was seen before a magic tree builder stack threshold was
434 * reached and element and comment nodes aren't appended to the DOM at all.
436 * However, for security reasons, non-child descendant text nodes inside an
437 * SVG script or style element should not become children. Also, non-cell
438 * table elements shouldn't be used as surrogate parents for user experience
441 if (!deepTreeSurrogateParent
&& currentPtr
>= NS_HTML5_TREE_DEPTH_LIMIT
&&
442 !(aName
== nsHtml5Atoms::script
||
443 aName
== nsHtml5Atoms::table
||
444 aName
== nsHtml5Atoms::thead
||
445 aName
== nsHtml5Atoms::tfoot
||
446 aName
== nsHtml5Atoms::tbody
||
447 aName
== nsHtml5Atoms::tr
||
448 aName
== nsHtml5Atoms::colgroup
||
449 aName
== nsHtml5Atoms::style
)) {
450 deepTreeSurrogateParent
= aElement
;
452 if (aNamespace
!= kNameSpaceID_XHTML
) {
455 if (aName
== nsHtml5Atoms::body
|| aName
== nsHtml5Atoms::frameset
) {
456 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
457 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
458 treeOp
->Init(eTreeOpStartLayout
);
464 nsHtml5TreeBuilder::elementPopped(PRInt32 aNamespace
, nsIAtom
* aName
, nsIContent
** aElement
)
466 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
|| aNamespace
== kNameSpaceID_SVG
|| aNamespace
== kNameSpaceID_MathML
, "Element isn't HTML, SVG or MathML!");
467 NS_ASSERTION(aName
, "Element doesn't have local name!");
468 NS_ASSERTION(aElement
, "No element!");
469 if (deepTreeSurrogateParent
&& currentPtr
<= NS_HTML5_TREE_DEPTH_LIMIT
) {
470 deepTreeSurrogateParent
= nsnull
;
472 if (aNamespace
== kNameSpaceID_MathML
) {
475 // we now have only SVG and HTML
476 if (aName
== nsHtml5Atoms::script
) {
477 if (mCurrentHtmlScriptIsAsyncOrDefer
) {
478 NS_ASSERTION(aNamespace
== kNameSpaceID_XHTML
,
479 "Only HTML scripts may be async/defer.");
480 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
481 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
482 treeOp
->Init(eTreeOpRunScriptAsyncDefer
, aElement
);
483 mCurrentHtmlScriptIsAsyncOrDefer
= PR_FALSE
;
487 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
488 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
489 treeOp
->InitScript(aElement
);
492 if (aName
== nsHtml5Atoms::title
) {
493 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
494 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
495 treeOp
->Init(eTreeOpDoneAddingChildren
, aElement
);
498 if (aName
== nsHtml5Atoms::style
|| (aNamespace
== kNameSpaceID_XHTML
&& aName
== nsHtml5Atoms::link
)) {
499 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
500 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
501 treeOp
->Init(eTreeOpUpdateStyleSheet
, aElement
);
504 if (aNamespace
== kNameSpaceID_SVG
) {
506 if (aName
== nsHtml5Atoms::svg
) {
507 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
508 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
509 treeOp
->Init(eTreeOpSvgLoad
, aElement
);
514 // we now have only HTML
515 // Some HTML nodes need DoneAddingChildren() called to initialize
516 // properly (e.g. form state restoration).
517 // XXX expose ElementName group here and do switch
518 if (aName
== nsHtml5Atoms::object
||
519 aName
== nsHtml5Atoms::applet
) {
520 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
521 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
522 treeOp
->Init(eTreeOpDoneAddingChildren
, aElement
);
525 if (aName
== nsHtml5Atoms::select
||
526 aName
== nsHtml5Atoms::textarea
) {
528 // If form inputs don't belong to a form, their state preservation
529 // won't work right without an append notification flush at this
530 // point. See bug 497861 and bug 539895.
531 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
532 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
533 treeOp
->Init(eTreeOpFlushPendingAppendNotifications
);
535 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
536 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
537 treeOp
->Init(eTreeOpDoneAddingChildren
, aElement
);
540 if (aName
== nsHtml5Atoms::input
||
541 aName
== nsHtml5Atoms::button
) {
543 // If form inputs don't belong to a form, their state preservation
544 // won't work right without an append notification flush at this
545 // point. See bug 497861.
546 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
547 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
548 treeOp
->Init(eTreeOpFlushPendingAppendNotifications
);
550 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
551 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
552 treeOp
->Init(eTreeOpDoneCreatingElement
, aElement
);
555 if (aName
== nsHtml5Atoms::meta
&& !fragment
) {
556 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
557 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
558 treeOp
->Init(eTreeOpProcessMeta
, aElement
);
565 nsHtml5TreeBuilder::accumulateCharacters(const PRUnichar
* aBuf
, PRInt32 aStart
, PRInt32 aLength
)
567 PRInt32 newFillLen
= charBufferLen
+ aLength
;
568 if (newFillLen
> charBuffer
.length
) {
569 PRInt32 newAllocLength
= newFillLen
+ (newFillLen
>> 1);
570 jArray
<PRUnichar
,PRInt32
> newBuf(newAllocLength
);
571 memcpy(newBuf
, charBuffer
, sizeof(PRUnichar
) * charBufferLen
);
572 charBuffer
.release();
575 memcpy(charBuffer
+ charBufferLen
, aBuf
+ aStart
, sizeof(PRUnichar
) * aLength
);
576 charBufferLen
= newFillLen
;
580 nsHtml5TreeBuilder::AllocateContentHandle()
582 if (mHandlesUsed
== NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
) {
583 mOldHandles
.AppendElement(mHandles
.forget());
584 mHandles
= new nsIContent
*[NS_HTML5_TREE_BUILDER_HANDLE_ARRAY_LENGTH
];
588 mHandles
[mHandlesUsed
] = (nsIContent
*)0xC0DEDBAD;
590 return &mHandles
[mHandlesUsed
++];
594 nsHtml5TreeBuilder::HasScript()
596 PRUint32 len
= mOpQueue
.Length();
600 return mOpQueue
.ElementAt(len
- 1).IsRunScript();
604 nsHtml5TreeBuilder::Flush()
608 PRBool hasOps
= !mOpQueue
.IsEmpty();
610 mOpSink
->MoveOpsFrom(mOpQueue
);
616 nsHtml5TreeBuilder::FlushLoads()
618 if (!mSpeculativeLoadQueue
.IsEmpty()) {
619 mSpeculativeLoadStage
->MoveSpeculativeLoadsFrom(mSpeculativeLoadQueue
);
624 nsHtml5TreeBuilder::SetDocumentCharset(nsACString
& aCharset
,
625 PRInt32 aCharsetSource
)
627 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
628 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
629 treeOp
->Init(eTreeOpSetDocumentCharset
, aCharset
, aCharsetSource
);
633 nsHtml5TreeBuilder::StreamEnded()
635 // The fragment mode calls DidBuildModel from nsHtml5Parser.
636 // Letting DidBuildModel be called from the executor in the fragment case
637 // confuses the EndLoad logic of nsHTMLDocument, since nsHTMLDocument
638 // thinks it is dealing with document.written content as opposed to
639 // innerHTML content.
641 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
642 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
643 treeOp
->Init(eTreeOpStreamEnded
);
648 nsHtml5TreeBuilder::NeedsCharsetSwitchTo(const nsACString
& aCharset
)
650 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
651 NS_ASSERTION(treeOp
, "Tree op allocation failed.");
652 treeOp
->Init(eTreeOpNeedsCharsetSwitchTo
, aCharset
);
656 nsHtml5TreeBuilder::AddSnapshotToScript(nsAHtml5TreeBuilderState
* aSnapshot
, PRInt32 aLine
)
658 NS_PRECONDITION(HasScript(), "No script to add a snapshot to!");
659 NS_PRECONDITION(aSnapshot
, "Got null snapshot.");
660 mOpQueue
.ElementAt(mOpQueue
.Length() - 1).SetSnapshot(aSnapshot
, aLine
);
664 nsHtml5TreeBuilder::IsDiscretionaryFlushSafe()
666 return !(charBufferLen
&&
668 stack
[currentPtr
]->fosterParenting
);
671 // DocumentModeHandler
673 nsHtml5TreeBuilder::documentMode(nsHtml5DocumentMode m
)
675 nsHtml5TreeOperation
* treeOp
= mOpQueue
.AppendElement();
676 NS_ASSERTION(treeOp
, "Tree op allocation failed.");