2 * Copyright (c) 2007 Henri Sivonen
3 * Copyright (c) 2007-2017 Mozilla Foundation
4 * Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
5 * Foundation, and Opera Software ASA.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
27 * The comments following this one that use the same comment syntax as this
28 * comment are quotes from the WHATWG HTML 5 spec as of 27 June 2007
29 * amended as of June 28 2007.
30 * That document came with this statement:
31 * "© Copyright 2004-2007 Apple Computer, Inc., Mozilla Foundation, and
32 * Opera Software ASA. You are granted a license to use, reproduce and
33 * create derivative works of this document."
36 package nu
.validator
.htmlparser
.impl
;
38 import java
.util
.Arrays
;
39 import java
.util
.HashMap
;
42 import org
.xml
.sax
.ErrorHandler
;
43 import org
.xml
.sax
.Locator
;
44 import org
.xml
.sax
.SAXException
;
45 import org
.xml
.sax
.SAXParseException
;
47 import nu
.validator
.htmlparser
.annotation
.Auto
;
48 import nu
.validator
.htmlparser
.annotation
.Const
;
49 import nu
.validator
.htmlparser
.annotation
.IdType
;
50 import nu
.validator
.htmlparser
.annotation
.Inline
;
51 import nu
.validator
.htmlparser
.annotation
.Literal
;
52 import nu
.validator
.htmlparser
.annotation
.Local
;
53 import nu
.validator
.htmlparser
.annotation
.NoLength
;
54 import nu
.validator
.htmlparser
.annotation
.NsUri
;
55 import nu
.validator
.htmlparser
.common
.DocumentMode
;
56 import nu
.validator
.htmlparser
.common
.DocumentModeHandler
;
57 import nu
.validator
.htmlparser
.common
.Interner
;
58 import nu
.validator
.htmlparser
.common
.TokenHandler
;
59 import nu
.validator
.htmlparser
.common
.XmlViolationPolicy
;
61 public abstract class TreeBuilder
<T
> implements TokenHandler
,
65 * Array version of U+FFFD.
67 private static final @NoLength char[] REPLACEMENT_CHARACTER
= { '\uFFFD' };
69 // Start dispatch groups
71 final static int OTHER
= 0;
73 final static int A
= 1;
75 final static int BASE
= 2;
77 final static int BODY
= 3;
79 final static int BR
= 4;
81 final static int BUTTON
= 5;
83 final static int CAPTION
= 6;
85 final static int COL
= 7;
87 final static int COLGROUP
= 8;
89 final static int FORM
= 9;
91 final static int FRAME
= 10;
93 final static int FRAMESET
= 11;
95 final static int IMAGE
= 12;
97 final static int INPUT
= 13;
99 final static int RT_OR_RP
= 14;
101 final static int LI
= 15;
103 final static int LINK_OR_BASEFONT_OR_BGSOUND
= 16;
105 final static int MATH
= 17;
107 final static int META
= 18;
109 final static int SVG
= 19;
111 final static int HEAD
= 20;
113 final static int HR
= 22;
115 final static int HTML
= 23;
117 final static int NOBR
= 24;
119 final static int NOFRAMES
= 25;
121 final static int NOSCRIPT
= 26;
123 final static int OPTGROUP
= 27;
125 final static int OPTION
= 28;
127 final static int P
= 29;
129 final static int PLAINTEXT
= 30;
131 final static int SCRIPT
= 31;
133 final static int SELECT
= 32;
135 final static int STYLE
= 33;
137 final static int TABLE
= 34;
139 final static int TEXTAREA
= 35;
141 final static int TITLE
= 36;
143 final static int TR
= 37;
145 final static int XMP
= 38;
147 final static int TBODY_OR_THEAD_OR_TFOOT
= 39;
149 final static int TD_OR_TH
= 40;
151 final static int DD_OR_DT
= 41;
153 final static int H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6
= 42;
155 final static int MARQUEE_OR_APPLET
= 43;
157 final static int PRE_OR_LISTING
= 44;
159 final static int B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U
= 45;
161 final static int UL_OR_OL_OR_DL
= 46;
163 final static int IFRAME
= 47;
165 final static int EMBED
= 48;
167 final static int AREA_OR_WBR
= 49;
169 final static int DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU
= 50;
171 final static int ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY
= 51;
173 final static int RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR
= 52;
175 final static int RB_OR_RTC
= 53;
177 final static int PARAM_OR_SOURCE_OR_TRACK
= 55;
179 final static int MGLYPH_OR_MALIGNMARK
= 56;
181 final static int MI_MO_MN_MS_MTEXT
= 57;
183 final static int ANNOTATION_XML
= 58;
185 final static int FOREIGNOBJECT_OR_DESC
= 59;
187 final static int NOEMBED
= 60;
189 final static int FIELDSET
= 61;
191 final static int OUTPUT
= 62;
193 final static int OBJECT
= 63;
195 final static int FONT
= 64;
197 final static int KEYGEN
= 65;
199 final static int TEMPLATE
= 66;
201 final static int IMG
= 67;
203 // start insertion modes
205 private static final int IN_ROW
= 0;
207 private static final int IN_TABLE_BODY
= 1;
209 private static final int IN_TABLE
= 2;
211 private static final int IN_CAPTION
= 3;
213 private static final int IN_CELL
= 4;
215 private static final int FRAMESET_OK
= 5;
217 private static final int IN_BODY
= 6;
219 private static final int IN_HEAD
= 7;
221 private static final int IN_HEAD_NOSCRIPT
= 8;
225 private static final int IN_COLUMN_GROUP
= 9;
229 private static final int IN_SELECT_IN_TABLE
= 10;
231 private static final int IN_SELECT
= 11;
235 private static final int AFTER_BODY
= 12;
239 private static final int IN_FRAMESET
= 13;
241 private static final int AFTER_FRAMESET
= 14;
245 private static final int INITIAL
= 15;
247 // could add fall-through
249 private static final int BEFORE_HTML
= 16;
251 // could add fall-through
253 private static final int BEFORE_HEAD
= 17;
257 private static final int AFTER_HEAD
= 18;
261 private static final int AFTER_AFTER_BODY
= 19;
265 private static final int AFTER_AFTER_FRAMESET
= 20;
269 private static final int TEXT
= 21;
271 private static final int IN_TEMPLATE
= 22;
273 // start charset states
275 private static final int CHARSET_INITIAL
= 0;
277 private static final int CHARSET_C
= 1;
279 private static final int CHARSET_H
= 2;
281 private static final int CHARSET_A
= 3;
283 private static final int CHARSET_R
= 4;
285 private static final int CHARSET_S
= 5;
287 private static final int CHARSET_E
= 6;
289 private static final int CHARSET_T
= 7;
291 private static final int CHARSET_EQUALS
= 8;
293 private static final int CHARSET_SINGLE_QUOTED
= 9;
295 private static final int CHARSET_DOUBLE_QUOTED
= 10;
297 private static final int CHARSET_UNQUOTED
= 11;
301 @Literal private final static String
[] QUIRKY_PUBLIC_IDS
= {
302 "+//silmaril//dtd html pro v0r11 19970101//",
303 "-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
304 "-//as//dtd html 3.0 aswedit + extensions//",
305 "-//ietf//dtd html 2.0 level 1//",
306 "-//ietf//dtd html 2.0 level 2//",
307 "-//ietf//dtd html 2.0 strict level 1//",
308 "-//ietf//dtd html 2.0 strict level 2//",
309 "-//ietf//dtd html 2.0 strict//",
310 "-//ietf//dtd html 2.0//",
311 "-//ietf//dtd html 2.1e//",
312 "-//ietf//dtd html 3.0//",
313 "-//ietf//dtd html 3.2 final//",
314 "-//ietf//dtd html 3.2//",
315 "-//ietf//dtd html 3//",
316 "-//ietf//dtd html level 0//",
317 "-//ietf//dtd html level 1//",
318 "-//ietf//dtd html level 2//",
319 "-//ietf//dtd html level 3//",
320 "-//ietf//dtd html strict level 0//",
321 "-//ietf//dtd html strict level 1//",
322 "-//ietf//dtd html strict level 2//",
323 "-//ietf//dtd html strict level 3//",
324 "-//ietf//dtd html strict//",
325 "-//ietf//dtd html//",
326 "-//metrius//dtd metrius presentational//",
327 "-//microsoft//dtd internet explorer 2.0 html strict//",
328 "-//microsoft//dtd internet explorer 2.0 html//",
329 "-//microsoft//dtd internet explorer 2.0 tables//",
330 "-//microsoft//dtd internet explorer 3.0 html strict//",
331 "-//microsoft//dtd internet explorer 3.0 html//",
332 "-//microsoft//dtd internet explorer 3.0 tables//",
333 "-//netscape comm. corp.//dtd html//",
334 "-//netscape comm. corp.//dtd strict html//",
335 "-//o'reilly and associates//dtd html 2.0//",
336 "-//o'reilly and associates//dtd html extended 1.0//",
337 "-//o'reilly and associates//dtd html extended relaxed 1.0//",
338 "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
339 "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
340 "-//spyglass//dtd html 2.0 extended//",
341 "-//sq//dtd html 2.0 hotmetal + extensions//",
342 "-//sun microsystems corp.//dtd hotjava html//",
343 "-//sun microsystems corp.//dtd hotjava strict html//",
344 "-//w3c//dtd html 3 1995-03-24//", "-//w3c//dtd html 3.2 draft//",
345 "-//w3c//dtd html 3.2 final//", "-//w3c//dtd html 3.2//",
346 "-//w3c//dtd html 3.2s draft//", "-//w3c//dtd html 4.0 frameset//",
347 "-//w3c//dtd html 4.0 transitional//",
348 "-//w3c//dtd html experimental 19960712//",
349 "-//w3c//dtd html experimental 970421//", "-//w3c//dtd w3 html//",
350 "-//w3o//dtd w3 html 3.0//", "-//webtechs//dtd mozilla html 2.0//",
351 "-//webtechs//dtd mozilla html//" };
353 private static final int NOT_FOUND_ON_STACK
= Integer
.MAX_VALUE
;
357 private static final @Local String HTML_LOCAL
= "html";
361 private int mode
= INITIAL
;
363 private int originalMode
= INITIAL
;
366 * Used only when moving back to IN_BODY.
368 private boolean framesetOk
= true;
370 protected Tokenizer tokenizer
;
374 protected ErrorHandler errorHandler
;
376 private DocumentModeHandler documentModeHandler
;
380 private boolean scriptingEnabled
= false;
382 private boolean needToDropLF
;
386 private boolean wantingComments
;
390 private boolean fragment
;
392 private @Local String contextName
;
394 private @NsUri String contextNamespace
;
396 private T contextNode
;
399 * Stack of template insertion modes
401 private @Auto int[] templateModeStack
;
404 * Current template mode stack pointer.
406 private int templateModePtr
= -1;
408 private @Auto StackNode
<T
>[] stackNodes
;
411 * Index of the earliest possible unused or empty element in stackNodes.
413 private int stackNodesIdx
= -1;
415 private int numStackNodes
= 0;
417 private @Auto StackNode
<T
>[] stack
;
419 private int currentPtr
= -1;
421 private @Auto StackNode
<T
>[] listOfActiveFormattingElements
;
423 private int listPtr
= -1;
425 private T formPointer
;
427 private T headPointer
;
429 protected @Auto char[] charBuffer
;
431 protected int charBufferLen
= 0;
433 private boolean quirks
= false;
435 private boolean forceNoQuirks
= false;
439 private boolean reportingDoctype
= true;
441 private XmlViolationPolicy namePolicy
= XmlViolationPolicy
.ALTER_INFOSET
;
443 private final Map
<String
, LocatorImpl
> idLocations
= new HashMap
<String
, LocatorImpl
>();
447 protected TreeBuilder() {
452 * Reports an condition that would make the infoset incompatible with XML
455 * @throws SAXException
456 * @throws SAXParseException
458 protected void fatal() throws SAXException
{
461 // CPPONLY: @Inline private @Creator Object htmlCreator(@HtmlCreator Object htmlCreator) {
462 // CPPONLY: @Creator Object creator;
463 // CPPONLY: creator.html = htmlCreator;
464 // CPPONLY: return creator;
467 // CPPONLY: @Inline private @Creator Object svgCreator(@SvgCreator Object svgCreator) {
468 // CPPONLY: @Creator Object creator;
469 // CPPONLY: creator.svg = svgCreator;
470 // CPPONLY: return creator;
475 protected final void fatal(Exception e
) throws SAXException
{
476 SAXParseException spe
= new SAXParseException(e
.getMessage(),
478 if (errorHandler
!= null) {
479 errorHandler
.fatalError(spe
);
484 final void fatal(String s
) throws SAXException
{
485 SAXParseException spe
= new SAXParseException(s
, tokenizer
);
486 if (errorHandler
!= null) {
487 errorHandler
.fatalError(spe
);
493 * Reports a Parse Error.
497 * @throws SAXException
499 final void err(String message
) throws SAXException
{
500 if (errorHandler
== null) {
507 * Reports a Parse Error without checking if an error handler is present.
511 * @throws SAXException
513 final void errNoCheck(String message
) throws SAXException
{
514 SAXParseException spe
= new SAXParseException(message
, tokenizer
);
515 errorHandler
.error(spe
);
518 private void errListUnclosedStartTags(int eltPos
) throws SAXException
{
519 if (currentPtr
!= -1) {
520 for (int i
= currentPtr
; i
> eltPos
; i
--) {
521 reportUnclosedElementNameAndLocation(i
);
527 * Reports the name and location of an unclosed element.
529 * @throws SAXException
531 private final void reportUnclosedElementNameAndLocation(int pos
) throws SAXException
{
532 StackNode
<T
> node
= stack
[pos
];
533 if (node
.isOptionalEndTag()) {
536 TaintableLocatorImpl locator
= node
.getLocator();
537 if (locator
.isTainted()) {
540 locator
.markTainted();
541 SAXParseException spe
= new SAXParseException(
542 "Unclosed element \u201C" + node
.popName
+ "\u201D.", locator
);
543 errorHandler
.error(spe
);
551 * @throws SAXException
553 final void warn(String message
) throws SAXException
{
554 if (errorHandler
== null) {
557 SAXParseException spe
= new SAXParseException(message
, tokenizer
);
558 errorHandler
.warning(spe
);
562 * Reports a warning with an explicit locator
566 * @throws SAXException
568 final void warn(String message
, Locator locator
) throws SAXException
{
569 if (errorHandler
== null) {
572 SAXParseException spe
= new SAXParseException(message
, locator
);
573 errorHandler
.warning(spe
);
578 @SuppressWarnings("unchecked") public final void startTokenization(Tokenizer self
) throws SAXException
{
580 stackNodes
= new StackNode
[64];
581 stack
= new StackNode
[64];
582 templateModeStack
= new int[64];
583 listOfActiveFormattingElements
= new StackNode
[64];
584 needToDropLF
= false;
585 originalMode
= INITIAL
;
586 templateModePtr
= -1;
595 wantingComments
= wantsComments();
603 if (contextNode
!= null) {
606 elt
= createHtmlElementSetAsRoot(tokenizer
.emptyAttributes());
608 // When the context node is not in the HTML namespace, contrary
609 // to the spec, the first node on the stack is not set to "html"
610 // in the HTML namespace. Instead, it is set to a node that has
611 // the characteristics of the appropriate "adjusted current node".
612 // This way, there is no need to perform "adjusted current node"
613 // checks during tree construction. Instead, it's sufficient to
614 // just look at the current node. However, this also means that it
615 // is not safe to treat "html" in the HTML namespace as a sentinel
616 // that ends stack popping. Instead, stack popping loops that are
617 // meant not to pop the first element on the stack need to check
618 // for currentPos becoming zero.
619 if (contextNamespace
== "http://www.w3.org/2000/svg") {
620 ElementName elementName
= ElementName
.SVG
;
621 if ("title" == contextName
|| "desc" == contextName
622 || "foreignObject" == contextName
) {
623 // These elements are all alike and we don't care about
625 elementName
= ElementName
.FOREIGNOBJECT
;
627 // This is the SVG variant of the StackNode constructor.
628 StackNode
<T
> node
= createStackNode(elementName
,
629 elementName
.getCamelCaseName(), elt
631 , errorHandler
== null ?
null
632 : new TaintableLocatorImpl(tokenizer
)
636 stack
[currentPtr
] = node
;
637 tokenizer
.setState(Tokenizer
.DATA
);
638 // The frameset-ok flag is set even though <frameset> never
639 // ends up being allowed as HTML frameset in the fragment case.
641 } else if (contextNamespace
== "http://www.w3.org/1998/Math/MathML") {
642 ElementName elementName
= ElementName
.MATH
;
643 if ("mi" == contextName
|| "mo" == contextName
644 || "mn" == contextName
|| "ms" == contextName
645 || "mtext" == contextName
) {
646 // These elements are all alike and we don't care about
648 elementName
= ElementName
.MTEXT
;
649 } else if ("annotation-xml" == contextName
) {
650 elementName
= ElementName
.ANNOTATION_XML
;
651 // Blink does not check the encoding attribute of the
652 // annotation-xml element innerHTML is being set on.
653 // Let's do the same at least until
654 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=26783
657 // This is the MathML variant of the StackNode constructor.
658 StackNode
<T
> node
= createStackNode(elementName
, elt
,
659 elementName
.getName(), false
661 , errorHandler
== null ?
null
662 : new TaintableLocatorImpl(tokenizer
)
666 stack
[currentPtr
] = node
;
667 tokenizer
.setState(Tokenizer
.DATA
);
668 // The frameset-ok flag is set even though <frameset> never
669 // ends up being allowed as HTML frameset in the fragment case.
672 StackNode
<T
> node
= createStackNode(ElementName
.HTML
, elt
674 , errorHandler
== null ?
null
675 : new TaintableLocatorImpl(tokenizer
)
679 stack
[currentPtr
] = node
;
680 if ("template" == contextName
) {
681 pushTemplateMode(IN_TEMPLATE
);
683 resetTheInsertionMode();
684 formPointer
= getFormPointerForContext(contextNode
);
685 if ("title" == contextName
|| "textarea" == contextName
) {
686 tokenizer
.setState(Tokenizer
.RCDATA
);
687 } else if ("style" == contextName
|| "xmp" == contextName
688 || "iframe" == contextName
|| "noembed" == contextName
689 || "noframes" == contextName
690 || (scriptingEnabled
&& "noscript" == contextName
)) {
691 tokenizer
.setState(Tokenizer
.RAWTEXT
);
692 } else if ("plaintext" == contextName
) {
693 tokenizer
.setState(Tokenizer
.PLAINTEXT
);
694 } else if ("script" == contextName
) {
695 tokenizer
.setState(Tokenizer
.SCRIPT_DATA
);
697 tokenizer
.setState(Tokenizer
.DATA
);
702 // If we are viewing XML source, put a foreign element permanently
703 // on the stack so that cdataSectionAllowed() returns true.
704 // CPPONLY: if (tokenizer.isViewingXmlSource()) {
705 // CPPONLY: T elt = createElement("http://www.w3.org/2000/svg",
707 // CPPONLY: tokenizer.emptyAttributes(), null,
708 // CPPONLY: svgCreator(NS_NewSVGSVGElement));
709 // CPPONLY: StackNode<T> node = createStackNode(ElementName.SVG,
712 // CPPONLY: currentPtr++;
713 // CPPONLY: stack[currentPtr] = node;
718 public final void doctype(@Local String name
, String publicIdentifier
,
719 String systemIdentifier
, boolean forceQuirks
) throws SAXException
{
720 needToDropLF
= false;
721 if (!isInForeign() && mode
== INITIAL
) {
723 if (reportingDoctype
) {
725 String emptyString
= Portability
.newEmptyString();
726 appendDoctypeToDocument(name
== null ?
"" : name
,
727 publicIdentifier
== null ? emptyString
729 systemIdentifier
== null ? emptyString
731 Portability
.releaseString(emptyString
);
735 if (isQuirky(name
, publicIdentifier
, systemIdentifier
,
738 documentModeInternal(DocumentMode
.QUIRKS_MODE
,
739 publicIdentifier
, systemIdentifier
);
740 } else if (isAlmostStandards(publicIdentifier
,
742 errAlmostStandardsDoctype();
743 documentModeInternal(
744 DocumentMode
.ALMOST_STANDARDS_MODE
,
745 publicIdentifier
, systemIdentifier
);
748 if ((Portability
.literalEqualsString(
749 "-//W3C//DTD HTML 4.0//EN", publicIdentifier
) && (systemIdentifier
== null || Portability
.literalEqualsString(
750 "http://www.w3.org/TR/REC-html40/strict.dtd",
752 || (Portability
.literalEqualsString(
753 "-//W3C//DTD HTML 4.01//EN",
754 publicIdentifier
) && (systemIdentifier
== null || Portability
.literalEqualsString(
755 "http://www.w3.org/TR/html4/strict.dtd",
757 || (Portability
.literalEqualsString(
758 "-//W3C//DTD XHTML 1.0 Strict//EN",
759 publicIdentifier
) && Portability
.literalEqualsString(
760 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd",
762 || (Portability
.literalEqualsString(
763 "-//W3C//DTD XHTML 1.1//EN",
764 publicIdentifier
) && Portability
.literalEqualsString(
765 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd",
769 err("Obsolete doctype. Expected \u201C<!DOCTYPE html>\u201D.");
770 } else if (!((systemIdentifier
== null || Portability
.literalEqualsString(
771 "about:legacy-compat", systemIdentifier
)) && publicIdentifier
== null)) {
772 err("Legacy doctype. Expected \u201C<!DOCTYPE html>\u201D.");
775 documentModeInternal(DocumentMode
.STANDARDS_MODE
,
776 publicIdentifier
, systemIdentifier
);
781 * Then, switch to the root element mode of the tree construction
788 * A DOCTYPE token Parse error.
797 public final void comment(@NoLength char[] buf
, int start
, int length
)
798 throws SAXException
{
799 needToDropLF
= false;
801 if (!wantingComments
) {
805 if (!isInForeign()) {
809 case AFTER_AFTER_BODY
:
810 case AFTER_AFTER_FRAMESET
:
812 * A comment token Append a Comment node to the Document
813 * object with the data attribute set to the data given in
816 appendCommentToDocument(buf
, start
, length
);
820 * A comment token Append a Comment node to the first
821 * element in the stack of open elements (the html element),
822 * with the data attribute set to the data given in the
826 appendComment(stack
[0].node
, buf
, start
, length
);
833 * A comment token Append a Comment node to the current node with the
834 * data attribute set to the data given in the comment token.
837 appendComment(stack
[currentPtr
].node
, buf
, start
, length
);
842 * @see nu.validator.htmlparser.common.TokenHandler#characters(char[], int,
845 public final void characters(@Const @NoLength char[] buf
, int start
, int length
)
846 throws SAXException
{
847 // Note: Can't attach error messages to EOF in C++ yet
849 // CPPONLY: if (tokenizer.isViewingXmlSource()) {
853 needToDropLF
= false;
854 if (buf
[start
] == '\n') {
863 // optimize the most common case
868 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
869 reconstructTheActiveFormattingElements();
871 // CPPONLY: MOZ_FALLTHROUGH;
873 accumulateCharacters(buf
, start
, length
);
878 accumulateCharactersForced(buf
, start
, length
);
881 int end
= start
+ length
;
882 charactersloop
: for (int i
= start
; i
< end
; i
++) {
890 * A character token that is one of one of U+0009
891 * CHARACTER TABULATION, U+000A LINE FEED (LF),
892 * U+000C FORM FEED (FF), or U+0020 SPACE
904 case IN_HEAD_NOSCRIPT
:
906 case IN_COLUMN_GROUP
:
910 * Append the character to the current node.
919 accumulateCharacters(buf
, start
, i
925 * Reconstruct the active formatting
928 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
930 reconstructTheActiveFormattingElements();
933 * Append the token's character to the
936 break charactersloop
;
938 case IN_SELECT_IN_TABLE
:
939 break charactersloop
;
943 accumulateCharactersForced(buf
, i
, 1);
947 case AFTER_AFTER_BODY
:
948 case AFTER_AFTER_FRAMESET
:
950 accumulateCharacters(buf
, start
, i
955 * Reconstruct the active formatting
959 reconstructTheActiveFormattingElements();
961 * Append the token's character to the
966 // CPPONLY: MOZ_FALLTHROUGH_ASSERT();
969 * A character token that is not one of one of
970 * U+0009 CHARACTER TABULATION, U+000A LINE FEED
971 * (LF), U+000C FORM FEED (FF), or U+0020 SPACE
979 // XXX figure out a way to report this in the Gecko View Source case
980 err("Non-space characters found without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
984 * Set the document to quirks mode.
986 documentModeInternal(
987 DocumentMode
.QUIRKS_MODE
, null,
990 * Then, switch to the root element mode of
991 * the tree construction stage
995 * and reprocess the current token.
1001 * Create an HTMLElement node with the tag
1002 * name html, in the HTML namespace. Append
1003 * it to the Document object.
1005 // No need to flush characters here,
1006 // because there's nothing to flush.
1007 appendHtmlElementToDocumentAndPush();
1008 /* Switch to the main mode */
1011 * reprocess the current token.
1017 accumulateCharacters(buf
, start
, i
1022 * /Act as if a start tag token with the tag
1023 * name "head" and no attributes had been
1027 appendToCurrentNodeAndPushHeadElement(HtmlAttributes
.EMPTY_ATTRIBUTES
);
1030 * then reprocess the current token.
1032 * This will result in an empty head element
1033 * being generated, with the current token
1034 * being reprocessed in the "after head"
1041 accumulateCharacters(buf
, start
, i
1046 * Act as if an end tag token with the tag
1047 * name "head" had been seen,
1053 * and reprocess the current token.
1057 case IN_HEAD_NOSCRIPT
:
1059 accumulateCharacters(buf
, start
, i
1064 * Parse error. Act as if an end tag with
1065 * the tag name "noscript" had been seen
1067 errNonSpaceInNoscriptInHead();
1072 * and reprocess the current token.
1078 accumulateCharacters(buf
, start
, i
1083 * Act as if a start tag token with the tag
1084 * name "body" and no attributes had been
1088 appendToCurrentNodeAndPushBodyElement();
1091 * and then reprocess the current token.
1105 accumulateCharacters(buf
, start
, i
1110 * Reconstruct the active formatting
1113 if (!isInForeignButNotHtmlOrMathTextIntegrationPoint()) {
1115 reconstructTheActiveFormattingElements();
1118 * Append the token's character to the
1121 break charactersloop
;
1125 accumulateCharactersForced(buf
, i
, 1);
1128 case IN_COLUMN_GROUP
:
1130 accumulateCharacters(buf
, start
, i
1135 * Act as if an end tag with the tag name
1136 * "colgroup" had been seen, and then, if
1137 * that token wasn't ignored, reprocess the
1140 if (currentPtr
== 0 || stack
[currentPtr
].getGroup() ==
1141 TreeBuilder
.TEMPLATE
) {
1142 errNonSpaceInColgroupInFragment();
1152 case IN_SELECT_IN_TABLE
:
1153 break charactersloop
;
1155 errNonSpaceAfterBody();
1157 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
1162 accumulateCharacters(buf
, start
, i
1164 // start index is adjusted below.
1169 errNonSpaceInFrameset();
1175 case AFTER_FRAMESET
:
1177 accumulateCharacters(buf
, start
, i
1179 // start index is adjusted below.
1184 errNonSpaceAfterFrameset();
1190 case AFTER_AFTER_BODY
:
1194 errNonSpaceInTrailer();
1196 * Switch back to the main mode and
1197 * reprocess the token.
1199 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
1202 case AFTER_AFTER_FRAMESET
:
1204 accumulateCharacters(buf
, start
, i
1206 // start index is adjusted below.
1211 errNonSpaceInTrailer();
1221 accumulateCharacters(buf
, start
, end
- start
);
1227 * @see nu.validator.htmlparser.common.TokenHandler#zeroOriginatingReplacementCharacter()
1229 public void zeroOriginatingReplacementCharacter() throws SAXException
{
1231 accumulateCharacters(REPLACEMENT_CHARACTER
, 0, 1);
1234 if (currentPtr
>= 0) {
1235 if (isSpecialParentInForeign(stack
[currentPtr
])) {
1238 accumulateCharacters(REPLACEMENT_CHARACTER
, 0, 1);
1243 * @see nu.validator.htmlparser.common.TokenHandler#zeroOrReplacementCharacter()
1245 public void zeroOrReplacementCharacter() throws SAXException
{
1246 zeroOriginatingReplacementCharacter();
1249 public final void eof() throws SAXException
{
1251 // Note: Can't attach error messages to EOF in C++ yet
1259 err("End of file seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
1263 * Set the document to quirks mode.
1265 documentModeInternal(DocumentMode
.QUIRKS_MODE
, null, null);
1267 * Then, switch to the root element mode of the tree
1268 * construction stage
1272 * and reprocess the current token.
1277 * Create an HTMLElement node with the tag name html, in the
1278 * HTML namespace. Append it to the Document object.
1280 appendHtmlElementToDocumentAndPush();
1281 // XXX application cache manifest
1282 /* Switch to the main mode */
1285 * reprocess the current token.
1289 appendToCurrentNodeAndPushHeadElement(HtmlAttributes
.EMPTY_ATTRIBUTES
);
1294 if (errorHandler
!= null && currentPtr
> 1) {
1295 errEofWithUnclosedElements();
1298 while (currentPtr
> 0) {
1303 case IN_HEAD_NOSCRIPT
:
1305 errEofWithUnclosedElements();
1307 while (currentPtr
> 1) {
1313 appendToCurrentNodeAndPushBodyElement();
1319 case IN_SELECT_IN_TABLE
:
1321 case IN_COLUMN_GROUP
:
1327 // i > 0 to stop in time in the foreign fragment case.
1328 openelementloop
: for (int i
= currentPtr
; i
> 0; i
--) {
1329 int group
= stack
[i
].getGroup();
1334 case TBODY_OR_THEAD_OR_TFOOT
:
1340 errEofWithUnclosedElements();
1341 break openelementloop
;
1346 if (isTemplateModeStackEmpty()) {
1350 // fall through to IN_TEMPLATE
1351 // CPPONLY: MOZ_FALLTHROUGH;
1353 int eltPos
= findLast("template");
1354 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
1358 if (errorHandler
!= null) {
1359 errListUnclosedStartTags(0);
1361 while (currentPtr
>= eltPos
) {
1364 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
1366 resetTheInsertionMode();
1372 if (errorHandler
!= null) {
1373 errNoCheck("End of file seen when expecting text or an end tag.");
1374 errListUnclosedStartTags(0);
1377 // XXX mark script as already executed
1378 if (originalMode
== AFTER_HEAD
) {
1382 mode
= originalMode
;
1386 if (errorHandler
!= null && currentPtr
> 0) {
1387 errEofWithUnclosedElements();
1392 case AFTER_FRAMESET
:
1393 case AFTER_AFTER_BODY
:
1394 case AFTER_AFTER_FRAMESET
:
1397 if (currentPtr
== 0) { // This silliness is here to poison
1398 // buggy compiler optimizations in
1400 System
.currentTimeMillis();
1406 while (currentPtr
> 0) {
1416 * @see nu.validator.htmlparser.common.TokenHandler#endTokenization()
1418 public final void endTokenization() throws SAXException
{
1423 templateModeStack
= null;
1424 if (stack
!= null) {
1425 while (currentPtr
> -1) {
1426 stack
[currentPtr
].release(this);
1431 if (listOfActiveFormattingElements
!= null) {
1432 while (listPtr
> -1) {
1433 if (listOfActiveFormattingElements
[listPtr
] != null) {
1434 listOfActiveFormattingElements
[listPtr
].release(this);
1438 listOfActiveFormattingElements
= null;
1440 if (stackNodes
!= null) {
1441 for (int i
= 0; i
< numStackNodes
; i
++) {
1442 assert stackNodes
[i
].isUnused();
1443 Portability
.delete(stackNodes
[i
]);
1450 idLocations
.clear();
1456 public final void startTag(ElementName elementName
,
1457 HtmlAttributes attributes
, boolean selfClosing
) throws SAXException
{
1461 boolean wasSelfClosing
= selfClosing
;
1462 boolean voidElement
= false;
1463 if (errorHandler
!= null) {
1465 @IdType String id
= attributes
.getId();
1466 if (id
!= null && !isTemplateContents()) {
1467 LocatorImpl oldLoc
= idLocations
.get(id
);
1468 if (oldLoc
!= null) {
1469 err("Duplicate ID \u201C" + id
+ "\u201D.");
1470 errorHandler
.warning(new SAXParseException(
1471 "The first occurrence of ID \u201C" + id
1472 + "\u201D was here.", oldLoc
));
1474 idLocations
.put(id
, new LocatorImpl(tokenizer
));
1481 needToDropLF
= false;
1482 starttagloop
: for (;;) {
1483 int group
= elementName
.getGroup();
1484 @Local String name
= elementName
.getName();
1485 if (isInForeign()) {
1486 StackNode
<T
> currentNode
= stack
[currentPtr
];
1487 @NsUri String currNs
= currentNode
.ns
;
1488 if (!(currentNode
.isHtmlIntegrationPoint() || (currNs
== "http://www.w3.org/1998/Math/MathML" && ((currentNode
.getGroup() == MI_MO_MN_MS_MTEXT
&& group
!= MGLYPH_OR_MALIGNMARK
) || (currentNode
.getGroup() == ANNOTATION_XML
&& group
== SVG
))))) {
1490 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U
:
1491 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU
:
1494 case RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR
:
1496 case UL_OR_OL_OR_DL
:
1499 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6
:
1506 case PRE_OR_LISTING
:
1509 // re-check FONT to deal with the special case
1510 if (!(group
== FONT
&& !(attributes
.contains(AttributeName
.COLOR
)
1511 || attributes
.contains(AttributeName
.FACE
) || attributes
.contains(AttributeName
.SIZE
)))) {
1512 errHtmlStartTagInForeignContext(name
);
1514 while (!isSpecialParentInForeign(stack
[currentPtr
])) {
1517 continue starttagloop
;
1520 // CPPONLY: MOZ_FALLTHROUGH;
1522 if ("http://www.w3.org/2000/svg" == currNs
) {
1523 attributes
.adjustForSvg();
1525 appendVoidElementToCurrentMayFosterSVG(
1526 elementName
, attributes
);
1527 selfClosing
= false;
1529 appendToCurrentNodeAndPushElementMayFosterSVG(
1530 elementName
, attributes
);
1532 attributes
= null; // CPP
1535 attributes
.adjustForMath();
1537 appendVoidElementToCurrentMayFosterMathML(
1538 elementName
, attributes
);
1539 selfClosing
= false;
1541 appendToCurrentNodeAndPushElementMayFosterMathML(
1542 elementName
, attributes
);
1544 attributes
= null; // CPP
1548 } // foreignObject / annotation-xml
1555 pushTemplateMode(IN_COLUMN_GROUP
);
1556 mode
= IN_COLUMN_GROUP
;
1561 case TBODY_OR_THEAD_OR_TFOOT
:
1563 pushTemplateMode(IN_TABLE
);
1569 pushTemplateMode(IN_TABLE_BODY
);
1570 mode
= IN_TABLE_BODY
;
1575 pushTemplateMode(IN_ROW
);
1580 checkMetaCharset(attributes
);
1581 appendVoidElementToCurrentMayFoster(
1584 selfClosing
= false;
1588 attributes
= null; // CPP
1591 startTagTitleInHead(elementName
, attributes
);
1592 attributes
= null; // CPP
1595 case LINK_OR_BASEFONT_OR_BGSOUND
:
1596 appendVoidElementToCurrentMayFoster(
1599 selfClosing
= false;
1603 attributes
= null; // CPP
1606 startTagScriptInHead(elementName
, attributes
);
1607 attributes
= null; // CPP
1611 startTagGenericRawText(elementName
, attributes
);
1612 attributes
= null; // CPP
1615 startTagTemplateInHead(elementName
, attributes
);
1616 attributes
= null; // CPP
1620 pushTemplateMode(IN_BODY
);
1628 clearStackBackTo(findLastOrRoot(TreeBuilder
.TR
));
1629 appendToCurrentNodeAndPushElement(
1634 attributes
= null; // CPP
1639 case TBODY_OR_THEAD_OR_TFOOT
:
1641 eltPos
= findLastOrRoot(TreeBuilder
.TR
);
1643 assert fragment
|| isTemplateContents();
1644 errNoTableRowToClose();
1647 clearStackBackTo(eltPos
);
1649 mode
= IN_TABLE_BODY
;
1652 // fall through to IN_TABLE
1654 // CPPONLY: MOZ_FALLTHROUGH;
1658 clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
1659 appendToCurrentNodeAndPushElement(
1663 attributes
= null; // CPP
1666 errStartTagInTableBody(name
);
1667 clearStackBackTo(findLastInTableScopeOrRootTemplateTbodyTheadTfoot());
1668 appendToCurrentNodeAndPushElement(
1670 HtmlAttributes
.EMPTY_ATTRIBUTES
);
1676 case TBODY_OR_THEAD_OR_TFOOT
:
1677 eltPos
= findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
1678 if (eltPos
== 0 || stack
[eltPos
].getGroup() == TEMPLATE
) {
1679 assert fragment
|| isTemplateContents();
1680 errStrayStartTag(name
);
1683 clearStackBackTo(eltPos
);
1689 // fall through to IN_TABLE
1691 // CPPONLY: MOZ_FALLTHROUGH;
1693 intableloop
: for (;;) {
1696 clearStackBackTo(findLastOrRoot(TreeBuilder
.TABLE
));
1698 appendToCurrentNodeAndPushElement(
1702 attributes
= null; // CPP
1705 clearStackBackTo(findLastOrRoot(TreeBuilder
.TABLE
));
1706 appendToCurrentNodeAndPushElement(
1709 mode
= IN_COLUMN_GROUP
;
1710 attributes
= null; // CPP
1713 clearStackBackTo(findLastOrRoot(TreeBuilder
.TABLE
));
1714 appendToCurrentNodeAndPushElement(
1715 ElementName
.COLGROUP
,
1716 HtmlAttributes
.EMPTY_ATTRIBUTES
);
1717 mode
= IN_COLUMN_GROUP
;
1718 continue starttagloop
;
1719 case TBODY_OR_THEAD_OR_TFOOT
:
1720 clearStackBackTo(findLastOrRoot(TreeBuilder
.TABLE
));
1721 appendToCurrentNodeAndPushElement(
1724 mode
= IN_TABLE_BODY
;
1725 attributes
= null; // CPP
1729 clearStackBackTo(findLastOrRoot(TreeBuilder
.TABLE
));
1730 appendToCurrentNodeAndPushElement(
1732 HtmlAttributes
.EMPTY_ATTRIBUTES
);
1733 mode
= IN_TABLE_BODY
;
1734 continue starttagloop
;
1736 // fall through to IN_HEAD
1739 errTableSeenWhileTableOpen();
1740 eltPos
= findLastInTableScope(name
);
1741 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
1742 assert fragment
|| isTemplateContents();
1745 generateImpliedEndTags();
1746 if (errorHandler
!= null && !isCurrent("table")) {
1747 errNoCheckUnclosedElementsOnStack();
1749 while (currentPtr
>= eltPos
) {
1752 resetTheInsertionMode();
1753 continue starttagloop
;
1755 // XXX need to manage much more stuff
1759 appendToCurrentNodeAndPushElement(
1762 originalMode
= mode
;
1764 tokenizer
.setStateAndEndTagExpectation(
1765 Tokenizer
.SCRIPT_DATA
, elementName
);
1766 attributes
= null; // CPP
1769 appendToCurrentNodeAndPushElement(
1772 originalMode
= mode
;
1774 tokenizer
.setStateAndEndTagExpectation(
1775 Tokenizer
.RAWTEXT
, elementName
);
1776 attributes
= null; // CPP
1779 errStartTagInTable(name
);
1780 if (!Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
1782 attributes
.getValue(AttributeName
.TYPE
))) {
1785 appendVoidInputToCurrent(
1788 selfClosing
= false;
1792 attributes
= null; // CPP
1795 if (formPointer
!= null || isTemplateContents()) {
1796 errFormWhenFormOpen();
1799 errStartTagInTable(name
);
1800 appendVoidFormToCurrent(attributes
);
1801 attributes
= null; // CPP
1805 errStartTagInTable(name
);
1806 // fall through to IN_BODY
1810 // CPPONLY: MOZ_FALLTHROUGH;
1816 case TBODY_OR_THEAD_OR_TFOOT
:
1819 eltPos
= findLastInTableScope("caption");
1820 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
1821 assert fragment
|| isTemplateContents();
1822 errStrayStartTag(name
);
1825 generateImpliedEndTags();
1826 if (errorHandler
!= null && currentPtr
!= eltPos
) {
1827 errNoCheckUnclosedElementsOnStack();
1829 while (currentPtr
>= eltPos
) {
1832 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
1836 // fall through to IN_BODY
1838 // CPPONLY: MOZ_FALLTHROUGH;
1844 case TBODY_OR_THEAD_OR_TFOOT
:
1847 eltPos
= findLastInTableScopeTdTh();
1848 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
1852 closeTheCell(eltPos
);
1856 // fall through to IN_BODY
1858 // CPPONLY: MOZ_FALLTHROUGH;
1862 if (mode
== FRAMESET_OK
) {
1863 if (currentPtr
== 0 || stack
[1].getGroup() != BODY
) {
1864 assert fragment
|| isTemplateContents();
1865 errStrayStartTag(name
);
1869 detachFromParent(stack
[1].node
);
1870 while (currentPtr
> 0) {
1873 appendToCurrentNodeAndPushElement(
1877 attributes
= null; // CPP
1881 errStrayStartTag(name
);
1884 // NOT falling through!
1885 case PRE_OR_LISTING
:
1889 case MARQUEE_OR_APPLET
:
1903 if (mode
== FRAMESET_OK
1904 && !(group
== INPUT
&& Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
1906 attributes
.getValue(AttributeName
.TYPE
)))) {
1910 // CPPONLY: MOZ_FALLTHROUGH;
1912 // fall through to IN_BODY
1914 // CPPONLY: MOZ_FALLTHROUGH;
1916 inbodyloop
: for (;;) {
1919 errStrayStartTag(name
);
1920 if (!fragment
&& !isTemplateContents()) {
1921 addAttributesToHtml(attributes
);
1922 attributes
= null; // CPP
1926 case LINK_OR_BASEFONT_OR_BGSOUND
:
1932 // Fall through to IN_HEAD
1935 if (currentPtr
== 0 || stack
[1].getGroup() != BODY
|| isTemplateContents()) {
1936 assert fragment
|| isTemplateContents();
1937 errStrayStartTag(name
);
1940 errFooSeenWhenFooOpen(name
);
1942 if (mode
== FRAMESET_OK
) {
1945 if (addAttributesToBody(attributes
)) {
1946 attributes
= null; // CPP
1950 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU
:
1951 case UL_OR_OL_OR_DL
:
1952 case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY
:
1954 appendToCurrentNodeAndPushElementMayFoster(
1957 attributes
= null; // CPP
1959 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6
:
1961 if (stack
[currentPtr
].getGroup() == H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6
) {
1962 errHeadingWhenHeadingOpen();
1965 appendToCurrentNodeAndPushElementMayFoster(
1968 attributes
= null; // CPP
1972 appendToCurrentNodeAndPushElementMayFoster(
1974 attributes
, formPointer
);
1975 attributes
= null; // CPP
1977 case PRE_OR_LISTING
:
1979 appendToCurrentNodeAndPushElementMayFoster(
1982 needToDropLF
= true;
1983 attributes
= null; // CPP
1986 if (formPointer
!= null && !isTemplateContents()) {
1987 errFormWhenFormOpen();
1991 appendToCurrentNodeAndPushFormElementMayFoster(attributes
);
1992 attributes
= null; // CPP
1997 eltPos
= currentPtr
;
1999 StackNode
<T
> node
= stack
[eltPos
]; // weak
2001 if (node
.getGroup() == group
) { // LI or
2003 generateImpliedEndTagsExceptFor(node
.name
);
2004 if (errorHandler
!= null
2005 && eltPos
!= currentPtr
) {
2006 errUnclosedElementsImplied(eltPos
, name
);
2008 while (currentPtr
>= eltPos
) {
2012 } else if (eltPos
== 0 || (node
.isSpecial()
2013 && (node
.ns
!= "http://www.w3.org/1999/xhtml"
2014 || (node
.name
!= "p"
2015 && node
.name
!= "address"
2016 && node
.name
!= "div")))) {
2022 appendToCurrentNodeAndPushElementMayFoster(
2025 attributes
= null; // CPP
2029 appendToCurrentNodeAndPushElementMayFoster(
2032 tokenizer
.setStateAndEndTagExpectation(
2033 Tokenizer
.PLAINTEXT
, elementName
);
2034 attributes
= null; // CPP
2037 int activeAPos
= findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker("a");
2038 if (activeAPos
!= -1) {
2039 errFooSeenWhenFooOpen(name
);
2040 StackNode
<T
> activeA
= listOfActiveFormattingElements
[activeAPos
];
2042 adoptionAgencyEndTag("a");
2043 removeFromStack(activeA
);
2044 activeAPos
= findInListOfActiveFormattingElements(activeA
);
2045 if (activeAPos
!= -1) {
2046 removeFromListOfActiveFormattingElements(activeAPos
);
2048 activeA
.release(this);
2050 reconstructTheActiveFormattingElements();
2051 appendToCurrentNodeAndPushFormattingElementMayFoster(
2054 attributes
= null; // CPP
2056 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U
:
2058 reconstructTheActiveFormattingElements();
2059 maybeForgetEarlierDuplicateFormattingElement(elementName
.getName(), attributes
);
2060 appendToCurrentNodeAndPushFormattingElementMayFoster(
2063 attributes
= null; // CPP
2066 reconstructTheActiveFormattingElements();
2067 if (TreeBuilder
.NOT_FOUND_ON_STACK
!= findLastInScope("nobr")) {
2068 errFooSeenWhenFooOpen(name
);
2069 adoptionAgencyEndTag("nobr");
2070 reconstructTheActiveFormattingElements();
2072 appendToCurrentNodeAndPushFormattingElementMayFoster(
2075 attributes
= null; // CPP
2078 eltPos
= findLastInScope(name
);
2079 if (eltPos
!= TreeBuilder
.NOT_FOUND_ON_STACK
) {
2080 errFooSeenWhenFooOpen(name
);
2081 generateImpliedEndTags();
2082 if (errorHandler
!= null
2083 && !isCurrent(name
)) {
2084 errUnclosedElementsImplied(eltPos
, name
);
2086 while (currentPtr
>= eltPos
) {
2089 continue starttagloop
;
2091 reconstructTheActiveFormattingElements();
2092 appendToCurrentNodeAndPushElementMayFoster(
2094 attributes
, formPointer
);
2095 attributes
= null; // CPP
2099 reconstructTheActiveFormattingElements();
2100 appendToCurrentNodeAndPushElementMayFoster(
2102 attributes
, formPointer
);
2104 attributes
= null; // CPP
2106 case MARQUEE_OR_APPLET
:
2107 reconstructTheActiveFormattingElements();
2108 appendToCurrentNodeAndPushElementMayFoster(
2112 attributes
= null; // CPP
2115 // The only quirk. Blame Hixie and
2120 appendToCurrentNodeAndPushElementMayFoster(
2124 attributes
= null; // CPP
2130 reconstructTheActiveFormattingElements();
2131 // FALL THROUGH to PARAM_OR_SOURCE_OR_TRACK
2132 // CPPONLY: MOZ_FALLTHROUGH;
2133 case PARAM_OR_SOURCE_OR_TRACK
:
2134 appendVoidElementToCurrentMayFoster(
2137 selfClosing
= false;
2141 attributes
= null; // CPP
2145 appendVoidElementToCurrentMayFoster(
2148 selfClosing
= false;
2152 attributes
= null; // CPP
2156 elementName
= ElementName
.IMG
;
2157 continue starttagloop
;
2160 reconstructTheActiveFormattingElements();
2161 appendVoidElementToCurrentMayFoster(
2162 elementName
, attributes
,
2164 selfClosing
= false;
2168 attributes
= null; // CPP
2171 appendToCurrentNodeAndPushElementMayFoster(
2173 attributes
, formPointer
);
2174 tokenizer
.setStateAndEndTagExpectation(
2175 Tokenizer
.RCDATA
, elementName
);
2176 originalMode
= mode
;
2178 needToDropLF
= true;
2179 attributes
= null; // CPP
2183 reconstructTheActiveFormattingElements();
2184 appendToCurrentNodeAndPushElementMayFoster(
2187 originalMode
= mode
;
2189 tokenizer
.setStateAndEndTagExpectation(
2190 Tokenizer
.RAWTEXT
, elementName
);
2191 attributes
= null; // CPP
2194 if (!scriptingEnabled
) {
2195 reconstructTheActiveFormattingElements();
2196 appendToCurrentNodeAndPushElementMayFoster(
2199 attributes
= null; // CPP
2202 // CPPONLY: MOZ_FALLTHROUGH;
2206 startTagGenericRawText(elementName
, attributes
);
2207 attributes
= null; // CPP
2210 reconstructTheActiveFormattingElements();
2211 appendToCurrentNodeAndPushElementMayFoster(
2213 attributes
, formPointer
);
2217 case IN_COLUMN_GROUP
:
2221 mode
= IN_SELECT_IN_TABLE
;
2227 attributes
= null; // CPP
2231 if (isCurrent("option")) {
2234 reconstructTheActiveFormattingElements();
2235 appendToCurrentNodeAndPushElementMayFoster(
2238 attributes
= null; // CPP
2241 eltPos
= findLastInScope("ruby");
2242 if (eltPos
!= NOT_FOUND_ON_STACK
) {
2243 generateImpliedEndTags();
2245 if (eltPos
!= currentPtr
) {
2246 if (eltPos
== NOT_FOUND_ON_STACK
) {
2247 errStartTagSeenWithoutRuby(name
);
2249 errUnclosedChildrenInRuby();
2252 appendToCurrentNodeAndPushElementMayFoster(
2255 attributes
= null; // CPP
2258 eltPos
= findLastInScope("ruby");
2259 if (eltPos
!= NOT_FOUND_ON_STACK
) {
2260 generateImpliedEndTagsExceptFor("rtc");
2262 if (eltPos
!= currentPtr
) {
2263 if (!isCurrent("rtc")) {
2264 if (eltPos
== NOT_FOUND_ON_STACK
) {
2265 errStartTagSeenWithoutRuby(name
);
2267 errUnclosedChildrenInRuby();
2271 appendToCurrentNodeAndPushElementMayFoster(
2274 attributes
= null; // CPP
2277 reconstructTheActiveFormattingElements();
2278 attributes
.adjustForMath();
2280 appendVoidElementToCurrentMayFosterMathML(
2281 elementName
, attributes
);
2282 selfClosing
= false;
2284 appendToCurrentNodeAndPushElementMayFosterMathML(
2285 elementName
, attributes
);
2287 attributes
= null; // CPP
2290 reconstructTheActiveFormattingElements();
2291 attributes
.adjustForSvg();
2293 appendVoidElementToCurrentMayFosterSVG(
2296 selfClosing
= false;
2298 appendToCurrentNodeAndPushElementMayFosterSVG(
2299 elementName
, attributes
);
2301 attributes
= null; // CPP
2306 case TBODY_OR_THEAD_OR_TFOOT
:
2312 errStrayStartTag(name
);
2315 reconstructTheActiveFormattingElements();
2316 appendToCurrentNodeAndPushElementMayFoster(
2318 attributes
, formPointer
);
2319 attributes
= null; // CPP
2322 reconstructTheActiveFormattingElements();
2323 appendToCurrentNodeAndPushElementMayFoster(
2326 attributes
= null; // CPP
2330 // CPPONLY: MOZ_FALLTHROUGH;
2332 inheadloop
: for (;;) {
2335 errStrayStartTag(name
);
2336 if (!fragment
&& !isTemplateContents()) {
2337 addAttributesToHtml(attributes
);
2338 attributes
= null; // CPP
2342 case LINK_OR_BASEFONT_OR_BGSOUND
:
2343 appendVoidElementToCurrentMayFoster(
2346 selfClosing
= false;
2350 attributes
= null; // CPP
2353 // Fall through to IN_HEAD_NOSCRIPT
2356 startTagTitleInHead(elementName
, attributes
);
2357 attributes
= null; // CPP
2360 if (scriptingEnabled
) {
2361 appendToCurrentNodeAndPushElement(
2364 originalMode
= mode
;
2366 tokenizer
.setStateAndEndTagExpectation(
2367 Tokenizer
.RAWTEXT
, elementName
);
2369 appendToCurrentNodeAndPushElementMayFoster(
2372 mode
= IN_HEAD_NOSCRIPT
;
2374 attributes
= null; // CPP
2377 startTagScriptInHead(elementName
, attributes
);
2378 attributes
= null; // CPP
2382 startTagGenericRawText(elementName
, attributes
);
2383 attributes
= null; // CPP
2387 errFooSeenWhenFooOpen(name
);
2388 /* Ignore the token. */
2391 startTagTemplateInHead(elementName
, attributes
);
2392 attributes
= null; // CPP
2397 continue starttagloop
;
2400 // CPPONLY: MOZ_FALLTHROUGH;
2401 case IN_HEAD_NOSCRIPT
:
2404 // XXX did Hixie really mean to omit "base"
2406 errStrayStartTag(name
);
2407 if (!fragment
&& !isTemplateContents()) {
2408 addAttributesToHtml(attributes
);
2409 attributes
= null; // CPP
2412 case LINK_OR_BASEFONT_OR_BGSOUND
:
2413 appendVoidElementToCurrentMayFoster(
2416 selfClosing
= false;
2420 attributes
= null; // CPP
2423 checkMetaCharset(attributes
);
2424 appendVoidElementToCurrentMayFoster(
2427 selfClosing
= false;
2431 attributes
= null; // CPP
2435 appendToCurrentNodeAndPushElement(
2438 originalMode
= mode
;
2440 tokenizer
.setStateAndEndTagExpectation(
2441 Tokenizer
.RAWTEXT
, elementName
);
2442 attributes
= null; // CPP
2445 errFooSeenWhenFooOpen(name
);
2448 errFooSeenWhenFooOpen(name
);
2451 errBadStartTagInNoscriptInHead(name
);
2456 case IN_COLUMN_GROUP
:
2459 errStrayStartTag(name
);
2460 if (!fragment
&& !isTemplateContents()) {
2461 addAttributesToHtml(attributes
);
2462 attributes
= null; // CPP
2466 appendVoidElementToCurrentMayFoster(
2469 selfClosing
= false;
2473 attributes
= null; // CPP
2476 startTagTemplateInHead(elementName
, attributes
);
2477 attributes
= null; // CPP
2480 if (currentPtr
== 0 || stack
[currentPtr
].getGroup() == TEMPLATE
) {
2481 assert fragment
|| isTemplateContents();
2482 errGarbageInColgroup();
2489 case IN_SELECT_IN_TABLE
:
2492 case TBODY_OR_THEAD_OR_TFOOT
:
2496 errStartTagWithSelectOpen(name
);
2497 eltPos
= findLastInTableScope("select");
2498 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
2500 break starttagloop
; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
2502 while (currentPtr
>= eltPos
) {
2505 resetTheInsertionMode();
2508 // fall through to IN_SELECT
2510 // CPPONLY: MOZ_FALLTHROUGH;
2514 errStrayStartTag(name
);
2516 addAttributesToHtml(attributes
);
2517 attributes
= null; // CPP
2521 if (isCurrent("option")) {
2524 appendToCurrentNodeAndPushElement(
2527 attributes
= null; // CPP
2530 if (isCurrent("option")) {
2533 if (isCurrent("optgroup")) {
2536 appendToCurrentNodeAndPushElement(
2539 attributes
= null; // CPP
2542 errStartSelectWhereEndSelectExpected();
2543 eltPos
= findLastInTableScope(name
);
2544 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
2546 errNoSelectInTableScope();
2549 while (currentPtr
>= eltPos
) {
2552 resetTheInsertionMode();
2557 errStartTagWithSelectOpen(name
);
2558 eltPos
= findLastInTableScope("select");
2559 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
2563 while (currentPtr
>= eltPos
) {
2566 resetTheInsertionMode();
2569 startTagScriptInHead(elementName
, attributes
);
2570 attributes
= null; // CPP
2573 startTagTemplateInHead(elementName
, attributes
);
2574 attributes
= null; // CPP
2577 if (isCurrent("option")) {
2580 if (isCurrent("optgroup")) {
2583 appendVoidElementToCurrent(elementName
, attributes
);
2584 selfClosing
= false;
2588 attributes
= null; // CPP
2591 errStrayStartTag(name
);
2597 errStrayStartTag(name
);
2598 if (!fragment
&& !isTemplateContents()) {
2599 addAttributesToHtml(attributes
);
2600 attributes
= null; // CPP
2604 errStrayStartTag(name
);
2605 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
2611 appendToCurrentNodeAndPushElement(
2614 attributes
= null; // CPP
2617 appendVoidElementToCurrentMayFoster(
2620 selfClosing
= false;
2624 attributes
= null; // CPP
2627 // fall through to AFTER_FRAMESET
2629 // CPPONLY: MOZ_FALLTHROUGH;
2630 case AFTER_FRAMESET
:
2633 errStrayStartTag(name
);
2634 if (!fragment
&& !isTemplateContents()) {
2635 addAttributesToHtml(attributes
);
2636 attributes
= null; // CPP
2640 appendToCurrentNodeAndPushElement(
2643 originalMode
= mode
;
2645 tokenizer
.setStateAndEndTagExpectation(
2646 Tokenizer
.RAWTEXT
, elementName
);
2647 attributes
= null; // CPP
2650 errStrayStartTag(name
);
2657 errStartTagWithoutDoctype();
2660 * Set the document to quirks mode.
2662 documentModeInternal(DocumentMode
.QUIRKS_MODE
, null, null);
2664 * Then, switch to the root element mode of the tree
2665 * construction stage
2669 * and reprocess the current token.
2675 // optimize error check and streaming SAX by
2677 // "html" handling here.
2678 if (attributes
== HtmlAttributes
.EMPTY_ATTRIBUTES
) {
2679 // This has the right magic side effect
2682 // makes attributes in SAX Tree mutable.
2683 appendHtmlElementToDocumentAndPush();
2685 appendHtmlElementToDocumentAndPush(attributes
);
2687 // XXX application cache should fire here
2689 attributes
= null; // CPP
2693 * Create an HTMLElement node with the tag name
2694 * html, in the HTML namespace. Append it to the
2697 appendHtmlElementToDocumentAndPush();
2698 /* Switch to the main mode */
2701 * reprocess the current token.
2708 errStrayStartTag(name
);
2709 if (!fragment
&& !isTemplateContents()) {
2710 addAttributesToHtml(attributes
);
2711 attributes
= null; // CPP
2716 * A start tag whose tag name is "head"
2718 * Create an element for the token.
2720 * Set the head element pointer to this new element
2723 * Append the new element to the current node and
2724 * push it onto the stack of open elements.
2726 appendToCurrentNodeAndPushHeadElement(attributes
);
2728 * Change the insertion mode to "in head".
2731 attributes
= null; // CPP
2735 * Any other start tag token
2737 * Act as if a start tag token with the tag name
2738 * "head" and no attributes had been seen,
2740 appendToCurrentNodeAndPushHeadElement(HtmlAttributes
.EMPTY_ATTRIBUTES
);
2743 * then reprocess the current token.
2745 * This will result in an empty head element being
2746 * generated, with the current token being
2747 * reprocessed in the "after head" insertion mode.
2754 errStrayStartTag(name
);
2755 if (!fragment
&& !isTemplateContents()) {
2756 addAttributesToHtml(attributes
);
2757 attributes
= null; // CPP
2761 if (attributes
.getLength() == 0) {
2762 // This has the right magic side effect
2765 // makes attributes in SAX Tree mutable.
2766 appendToCurrentNodeAndPushBodyElement();
2768 appendToCurrentNodeAndPushBodyElement(attributes
);
2772 attributes
= null; // CPP
2775 appendToCurrentNodeAndPushElement(
2779 attributes
= null; // CPP
2782 errFooBetweenHeadAndBody(name
);
2783 pushHeadPointerOntoStack();
2784 StackNode
<T
> headOnStack
= stack
[currentPtr
];
2785 startTagTemplateInHead(elementName
, attributes
);
2786 removeFromStack(headOnStack
);
2787 attributes
= null; // CPP
2790 case LINK_OR_BASEFONT_OR_BGSOUND
:
2791 errFooBetweenHeadAndBody(name
);
2792 pushHeadPointerOntoStack();
2793 appendVoidElementToCurrentMayFoster(
2796 selfClosing
= false;
2801 attributes
= null; // CPP
2804 errFooBetweenHeadAndBody(name
);
2805 checkMetaCharset(attributes
);
2806 pushHeadPointerOntoStack();
2807 appendVoidElementToCurrentMayFoster(
2810 selfClosing
= false;
2815 attributes
= null; // CPP
2818 errFooBetweenHeadAndBody(name
);
2819 pushHeadPointerOntoStack();
2820 appendToCurrentNodeAndPushElement(
2823 originalMode
= mode
;
2825 tokenizer
.setStateAndEndTagExpectation(
2826 Tokenizer
.SCRIPT_DATA
, elementName
);
2827 attributes
= null; // CPP
2831 errFooBetweenHeadAndBody(name
);
2832 pushHeadPointerOntoStack();
2833 appendToCurrentNodeAndPushElement(
2836 originalMode
= mode
;
2838 tokenizer
.setStateAndEndTagExpectation(
2839 Tokenizer
.RAWTEXT
, elementName
);
2840 attributes
= null; // CPP
2843 errFooBetweenHeadAndBody(name
);
2844 pushHeadPointerOntoStack();
2845 appendToCurrentNodeAndPushElement(
2848 originalMode
= mode
;
2850 tokenizer
.setStateAndEndTagExpectation(
2851 Tokenizer
.RCDATA
, elementName
);
2852 attributes
= null; // CPP
2855 errStrayStartTag(name
);
2858 appendToCurrentNodeAndPushBodyElement();
2862 case AFTER_AFTER_BODY
:
2865 errStrayStartTag(name
);
2866 if (!fragment
&& !isTemplateContents()) {
2867 addAttributesToHtml(attributes
);
2868 attributes
= null; // CPP
2872 errStrayStartTag(name
);
2874 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
2877 case AFTER_AFTER_FRAMESET
:
2880 errStrayStartTag(name
);
2881 if (!fragment
&& !isTemplateContents()) {
2882 addAttributesToHtml(attributes
);
2883 attributes
= null; // CPP
2887 startTagGenericRawText(elementName
, attributes
);
2888 attributes
= null; // CPP
2891 errStrayStartTag(name
);
2896 break starttagloop
; // Avoid infinite loop if the assertion
2903 } else if (wasSelfClosing
&& voidElement
2904 && tokenizer
.getErrorProfile() != null
2905 && tokenizer
.getErrorProfile().get("html-strict") != null) {
2906 warn("Trailing slash on void elements has no effect and interacts"
2907 + " badly with unquoted attribute values.");
2910 // CPPONLY: if (mBuilder == null && attributes != HtmlAttributes.EMPTY_ATTRIBUTES) {
2911 // CPPONLY: Portability.delete(attributes);
2915 private void startTagTitleInHead(ElementName elementName
, HtmlAttributes attributes
) throws SAXException
{
2916 appendToCurrentNodeAndPushElementMayFoster(elementName
, attributes
);
2917 originalMode
= mode
;
2919 tokenizer
.setStateAndEndTagExpectation(Tokenizer
.RCDATA
, elementName
);
2922 private void startTagGenericRawText(ElementName elementName
, HtmlAttributes attributes
) throws SAXException
{
2923 appendToCurrentNodeAndPushElementMayFoster(elementName
, attributes
);
2924 originalMode
= mode
;
2926 tokenizer
.setStateAndEndTagExpectation(Tokenizer
.RAWTEXT
, elementName
);
2929 private void startTagScriptInHead(ElementName elementName
, HtmlAttributes attributes
) throws SAXException
{
2930 // XXX need to manage much more stuff here if supporting document.write()
2931 appendToCurrentNodeAndPushElementMayFoster(elementName
, attributes
);
2932 originalMode
= mode
;
2934 tokenizer
.setStateAndEndTagExpectation(Tokenizer
.SCRIPT_DATA
, elementName
);
2937 private void startTagTemplateInHead(ElementName elementName
, HtmlAttributes attributes
) throws SAXException
{
2938 appendToCurrentNodeAndPushElement(elementName
, attributes
);
2941 originalMode
= mode
;
2943 pushTemplateMode(IN_TEMPLATE
);
2946 private boolean isTemplateContents() {
2947 return TreeBuilder
.NOT_FOUND_ON_STACK
!= findLast("template");
2950 private boolean isTemplateModeStackEmpty() {
2951 return templateModePtr
== -1;
2954 private boolean isSpecialParentInForeign(StackNode
<T
> stackNode
) {
2955 @NsUri String ns
= stackNode
.ns
;
2956 return ("http://www.w3.org/1999/xhtml" == ns
)
2957 || (stackNode
.isHtmlIntegrationPoint())
2958 || (("http://www.w3.org/1998/Math/MathML" == ns
) && (stackNode
.getGroup() == MI_MO_MN_MS_MTEXT
));
2964 * C++ memory note: The return value must be released.
2967 * @throws SAXException
2968 * @throws StopSniffingException
2970 public static String
extractCharsetFromContent(String attributeValue
2971 // CPPONLY: , TreeBuilder tb
2973 // This is a bit ugly. Converting the string to char array in order to
2974 // make the portability layer smaller.
2975 int charsetState
= CHARSET_INITIAL
;
2978 @Auto char[] buffer
= Portability
.newCharArrayFromString(attributeValue
);
2980 charsetloop
: for (int i
= 0; i
< buffer
.length
; i
++) {
2982 switch (charsetState
) {
2983 case CHARSET_INITIAL
:
2987 charsetState
= CHARSET_C
;
2996 charsetState
= CHARSET_H
;
2999 charsetState
= CHARSET_INITIAL
;
3006 charsetState
= CHARSET_A
;
3009 charsetState
= CHARSET_INITIAL
;
3016 charsetState
= CHARSET_R
;
3019 charsetState
= CHARSET_INITIAL
;
3026 charsetState
= CHARSET_S
;
3029 charsetState
= CHARSET_INITIAL
;
3036 charsetState
= CHARSET_E
;
3039 charsetState
= CHARSET_INITIAL
;
3046 charsetState
= CHARSET_T
;
3049 charsetState
= CHARSET_INITIAL
;
3061 charsetState
= CHARSET_EQUALS
;
3066 case CHARSET_EQUALS
:
3076 charsetState
= CHARSET_SINGLE_QUOTED
;
3080 charsetState
= CHARSET_DOUBLE_QUOTED
;
3084 charsetState
= CHARSET_UNQUOTED
;
3087 case CHARSET_SINGLE_QUOTED
:
3095 case CHARSET_DOUBLE_QUOTED
:
3103 case CHARSET_UNQUOTED
:
3120 if (charsetState
== CHARSET_UNQUOTED
) {
3121 end
= buffer
.length
;
3126 return Portability
.newStringFromBuffer(buffer
, start
, end
3128 // CPPONLY: , tb, false
3134 private void checkMetaCharset(HtmlAttributes attributes
)
3135 throws SAXException
{
3136 String charset
= attributes
.getValue(AttributeName
.CHARSET
);
3137 if (charset
!= null) {
3138 if (tokenizer
.internalEncodingDeclaration(charset
)) {
3139 requestSuspension();
3144 if (!Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
3146 attributes
.getValue(AttributeName
.HTTP_EQUIV
))) {
3149 String content
= attributes
.getValue(AttributeName
.CONTENT
);
3150 if (content
!= null) {
3151 String extract
= TreeBuilder
.extractCharsetFromContent(content
3154 // remember not to return early without releasing the string
3155 if (extract
!= null) {
3156 if (tokenizer
.internalEncodingDeclaration(extract
)) {
3157 requestSuspension();
3160 Portability
.releaseString(extract
);
3164 public final void endTag(ElementName elementName
) throws SAXException
{
3166 needToDropLF
= false;
3168 int group
= elementName
.getGroup();
3169 @Local String name
= elementName
.getName();
3170 endtagloop
: for (;;) {
3171 if (isInForeign()) {
3172 if (stack
[currentPtr
].name
!= name
) {
3173 if (currentPtr
== 0) {
3174 errStrayEndTag(name
);
3176 errEndTagDidNotMatchCurrentOpenElement(name
, stack
[currentPtr
].popName
);
3179 eltPos
= currentPtr
;
3180 int origPos
= currentPtr
;
3183 assert fragment
: "We can get this close to the root of the stack in foreign content only in the fragment case.";
3186 if (stack
[eltPos
].name
== name
) {
3187 while (currentPtr
>= eltPos
) {
3188 popForeign(origPos
, eltPos
);
3192 if (stack
[--eltPos
].ns
== "http://www.w3.org/1999/xhtml") {
3201 // fall through to IN_HEAD
3204 errStrayEndTag(name
);
3207 // CPPONLY: MOZ_FALLTHROUGH;
3211 eltPos
= findLastOrRoot(TreeBuilder
.TR
);
3213 assert fragment
|| isTemplateContents();
3214 errNoTableRowToClose();
3217 clearStackBackTo(eltPos
);
3219 mode
= IN_TABLE_BODY
;
3222 eltPos
= findLastOrRoot(TreeBuilder
.TR
);
3224 assert fragment
|| isTemplateContents();
3225 errNoTableRowToClose();
3228 clearStackBackTo(eltPos
);
3230 mode
= IN_TABLE_BODY
;
3232 case TBODY_OR_THEAD_OR_TFOOT
:
3233 if (findLastInTableScope(name
) == TreeBuilder
.NOT_FOUND_ON_STACK
) {
3234 errStrayEndTag(name
);
3237 eltPos
= findLastOrRoot(TreeBuilder
.TR
);
3239 assert fragment
|| isTemplateContents();
3240 errNoTableRowToClose();
3243 clearStackBackTo(eltPos
);
3245 mode
= IN_TABLE_BODY
;
3253 errStrayEndTag(name
);
3256 // fall through to IN_TABLE
3258 // CPPONLY: MOZ_FALLTHROUGH;
3261 case TBODY_OR_THEAD_OR_TFOOT
:
3262 eltPos
= findLastOrRoot(name
);
3264 errStrayEndTag(name
);
3267 clearStackBackTo(eltPos
);
3272 eltPos
= findLastInTableScopeOrRootTemplateTbodyTheadTfoot();
3273 if (eltPos
== 0 || stack
[eltPos
].getGroup() == TEMPLATE
) {
3274 assert fragment
|| isTemplateContents();
3275 errStrayEndTag(name
);
3278 clearStackBackTo(eltPos
);
3289 errStrayEndTag(name
);
3292 // fall through to IN_TABLE
3294 // CPPONLY: MOZ_FALLTHROUGH;
3298 eltPos
= findLast("table");
3299 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3300 assert fragment
|| isTemplateContents();
3301 errStrayEndTag(name
);
3304 while (currentPtr
>= eltPos
) {
3307 resetTheInsertionMode();
3314 case TBODY_OR_THEAD_OR_TFOOT
:
3317 errStrayEndTag(name
);
3320 // fall through to IN_HEAD
3323 errStrayEndTag(name
);
3324 // fall through to IN_BODY
3326 // CPPONLY: MOZ_FALLTHROUGH;
3330 eltPos
= findLastInTableScope("caption");
3331 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3334 generateImpliedEndTags();
3335 if (errorHandler
!= null && currentPtr
!= eltPos
) {
3336 errUnclosedElements(eltPos
, name
);
3338 while (currentPtr
>= eltPos
) {
3341 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3345 eltPos
= findLastInTableScope("caption");
3347 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3348 assert fragment
|| isTemplateContents();
3349 errStrayEndTag(name
);
3352 generateImpliedEndTags();
3353 if (errorHandler
!= null && currentPtr
!= eltPos
) {
3354 errUnclosedElements(eltPos
, name
);
3356 while (currentPtr
>= eltPos
) {
3359 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3366 case TBODY_OR_THEAD_OR_TFOOT
:
3369 errStrayEndTag(name
);
3372 // fall through to IN_BODY
3374 // CPPONLY: MOZ_FALLTHROUGH;
3378 eltPos
= findLastInTableScope(name
);
3379 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3380 errStrayEndTag(name
);
3383 generateImpliedEndTags();
3384 if (errorHandler
!= null && !isCurrent(name
)) {
3385 errUnclosedElements(eltPos
, name
);
3387 while (currentPtr
>= eltPos
) {
3390 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3394 case TBODY_OR_THEAD_OR_TFOOT
:
3396 if (findLastInTableScope(name
) == TreeBuilder
.NOT_FOUND_ON_STACK
) {
3397 assert name
== "tbody" || name
== "tfoot" || name
== "thead" || fragment
|| isTemplateContents();
3398 errStrayEndTag(name
);
3401 closeTheCell(findLastInTableScopeTdTh());
3408 errStrayEndTag(name
);
3411 // fall through to IN_BODY
3413 // CPPONLY: MOZ_FALLTHROUGH;
3418 if (!isSecondOnStackBody()) {
3419 assert fragment
|| isTemplateContents();
3420 errStrayEndTag(name
);
3423 assert currentPtr
>= 1;
3424 if (errorHandler
!= null) {
3425 uncloseloop1
: for (int i
= 2; i
<= currentPtr
; i
++) {
3426 switch (stack
[i
].getGroup()) {
3430 case OPTION
: // is this possible?
3435 case TBODY_OR_THEAD_OR_TFOOT
:
3438 errEndWithUnclosedElements(name
);
3446 if (!isSecondOnStackBody()) {
3447 assert fragment
|| isTemplateContents();
3448 errStrayEndTag(name
);
3451 if (errorHandler
!= null) {
3452 uncloseloop2
: for (int i
= 0; i
<= currentPtr
; i
++) {
3453 switch (stack
[i
].getGroup()) {
3459 case TBODY_OR_THEAD_OR_TFOOT
:
3465 errEndWithUnclosedElements(name
);
3472 case DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU
:
3473 case UL_OR_OL_OR_DL
:
3474 case PRE_OR_LISTING
:
3477 case ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIALOG_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SEARCH_OR_SECTION_OR_SUMMARY
:
3478 eltPos
= findLastInScope(name
);
3479 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3480 errStrayEndTag(name
);
3482 generateImpliedEndTags();
3483 if (errorHandler
!= null && !isCurrent(name
)) {
3484 errUnclosedElements(eltPos
, name
);
3486 while (currentPtr
>= eltPos
) {
3492 if (!isTemplateContents()) {
3493 if (formPointer
== null) {
3494 errStrayEndTag(name
);
3498 eltPos
= findLastInScope(name
);
3499 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3500 errStrayEndTag(name
);
3503 generateImpliedEndTags();
3504 if (errorHandler
!= null && !isCurrent(name
)) {
3505 errUnclosedElements(eltPos
, name
);
3507 removeFromStack(eltPos
);
3510 eltPos
= findLastInScope(name
);
3511 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3512 errStrayEndTag(name
);
3515 generateImpliedEndTags();
3516 if (errorHandler
!= null && !isCurrent(name
)) {
3517 errUnclosedElements(eltPos
, name
);
3519 while (currentPtr
>= eltPos
) {
3525 eltPos
= findLastInButtonScope("p");
3526 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3527 errNoElementToCloseButEndTagSeen("p");
3528 // XXX Can the 'in foreign' case happen anymore?
3529 if (isInForeign()) {
3530 errHtmlStartTagInForeignContext(name
);
3531 // Check for currentPtr for the fragment
3533 while (currentPtr
>= 0 && stack
[currentPtr
].ns
!= "http://www.w3.org/1999/xhtml") {
3537 appendVoidElementToCurrentMayFoster(
3539 HtmlAttributes
.EMPTY_ATTRIBUTES
);
3542 generateImpliedEndTagsExceptFor("p");
3543 assert eltPos
!= TreeBuilder
.NOT_FOUND_ON_STACK
;
3544 if (errorHandler
!= null && eltPos
!= currentPtr
) {
3545 errUnclosedElements(eltPos
, name
);
3547 while (currentPtr
>= eltPos
) {
3552 eltPos
= findLastInListScope(name
);
3553 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3554 errNoElementToCloseButEndTagSeen(name
);
3556 generateImpliedEndTagsExceptFor(name
);
3557 if (errorHandler
!= null
3558 && eltPos
!= currentPtr
) {
3559 errUnclosedElements(eltPos
, name
);
3561 while (currentPtr
>= eltPos
) {
3567 eltPos
= findLastInScope(name
);
3568 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3569 errNoElementToCloseButEndTagSeen(name
);
3571 generateImpliedEndTagsExceptFor(name
);
3572 if (errorHandler
!= null
3573 && eltPos
!= currentPtr
) {
3574 errUnclosedElements(eltPos
, name
);
3576 while (currentPtr
>= eltPos
) {
3581 case H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6
:
3582 eltPos
= findLastInScopeHn();
3583 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3584 errStrayEndTag(name
);
3586 generateImpliedEndTags();
3587 if (errorHandler
!= null && !isCurrent(name
)) {
3588 errUnclosedElements(eltPos
, name
);
3590 while (currentPtr
>= eltPos
) {
3596 case MARQUEE_OR_APPLET
:
3597 eltPos
= findLastInScope(name
);
3598 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3599 errStrayEndTag(name
);
3601 generateImpliedEndTags();
3602 if (errorHandler
!= null && !isCurrent(name
)) {
3603 errUnclosedElements(eltPos
, name
);
3605 while (currentPtr
>= eltPos
) {
3608 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3613 if (isInForeign()) {
3614 // XXX can this happen anymore?
3615 errHtmlStartTagInForeignContext(name
);
3616 // Check for currentPtr for the fragment
3618 while (currentPtr
>= 0 && stack
[currentPtr
].ns
!= "http://www.w3.org/1999/xhtml") {
3622 reconstructTheActiveFormattingElements();
3623 appendVoidElementToCurrentMayFoster(
3625 HtmlAttributes
.EMPTY_ATTRIBUTES
);
3628 // fall through to IN_HEAD;
3631 case KEYGEN
: // XXX??
3632 case PARAM_OR_SOURCE_OR_TRACK
:
3639 case NOEMBED
: // XXX???
3640 case NOFRAMES
: // XXX??
3643 case TEXTAREA
: // XXX??
3644 errStrayEndTag(name
);
3647 if (scriptingEnabled
) {
3648 errStrayEndTag(name
);
3651 // CPPONLY: MOZ_FALLTHROUGH;
3653 case B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U
:
3656 if (adoptionAgencyEndTag(name
)) {
3659 // else handle like any other tag
3660 // CPPONLY: MOZ_FALLTHROUGH;
3662 if (isCurrent(name
)) {
3667 eltPos
= currentPtr
;
3669 StackNode
<T
> node
= stack
[eltPos
];
3670 if (node
.ns
== "http://www.w3.org/1999/xhtml" && node
.name
== name
) {
3671 generateImpliedEndTags();
3672 if (errorHandler
!= null
3673 && !isCurrent(name
)) {
3674 errUnclosedElements(eltPos
, name
);
3676 while (currentPtr
>= eltPos
) {
3680 } else if (eltPos
== 0 || node
.isSpecial()) {
3681 errStrayEndTag(name
);
3687 // CPPONLY: MOZ_FALLTHROUGH;
3701 endTagTemplateInHead();
3704 errStrayEndTag(name
);
3707 case IN_HEAD_NOSCRIPT
:
3714 errStrayEndTag(name
);
3719 errStrayEndTag(name
);
3722 case IN_COLUMN_GROUP
:
3725 if (currentPtr
== 0 || stack
[currentPtr
].getGroup() ==
3726 TreeBuilder
.TEMPLATE
) {
3727 assert fragment
|| isTemplateContents();
3728 errGarbageInColgroup();
3735 errStrayEndTag(name
);
3738 endTagTemplateInHead();
3741 if (currentPtr
== 0 || stack
[currentPtr
].getGroup() ==
3742 TreeBuilder
.TEMPLATE
) {
3743 assert fragment
|| isTemplateContents();
3744 errGarbageInColgroup();
3751 case IN_SELECT_IN_TABLE
:
3755 case TBODY_OR_THEAD_OR_TFOOT
:
3758 errEndTagSeenWithSelectOpen(name
);
3759 if (findLastInTableScope(name
) != TreeBuilder
.NOT_FOUND_ON_STACK
) {
3760 eltPos
= findLastInTableScope("select");
3761 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3763 break endtagloop
; // http://www.w3.org/Bugs/Public/show_bug.cgi?id=8375
3765 while (currentPtr
>= eltPos
) {
3768 resetTheInsertionMode();
3774 // fall through to IN_SELECT
3776 // CPPONLY: MOZ_FALLTHROUGH;
3780 if (isCurrent("option")) {
3784 errStrayEndTag(name
);
3788 if (isCurrent("option")
3789 && "optgroup" == stack
[currentPtr
- 1].name
) {
3792 if (isCurrent("optgroup")) {
3795 errStrayEndTag(name
);
3799 eltPos
= findLastInTableScope("select");
3800 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3802 errStrayEndTag(name
);
3805 while (currentPtr
>= eltPos
) {
3808 resetTheInsertionMode();
3811 endTagTemplateInHead();
3814 errStrayEndTag(name
);
3821 errStrayEndTag(name
);
3824 mode
= AFTER_AFTER_BODY
;
3828 errEndTagAfterBody();
3829 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
3835 if (currentPtr
== 0) {
3837 errStrayEndTag(name
);
3841 if ((!fragment
) && !isCurrent("frameset")) {
3842 mode
= AFTER_FRAMESET
;
3846 errStrayEndTag(name
);
3849 case AFTER_FRAMESET
:
3852 mode
= AFTER_AFTER_FRAMESET
;
3855 errStrayEndTag(name
);
3862 errEndTagSeenWithoutDoctype();
3865 * Set the document to quirks mode.
3867 documentModeInternal(DocumentMode
.QUIRKS_MODE
, null, null);
3869 * Then, switch to the root element mode of the tree
3870 * construction stage
3874 * and reprocess the current token.
3884 * Create an HTMLElement node with the tag name
3885 * html, in the HTML namespace. Append it to the
3888 appendHtmlElementToDocumentAndPush();
3889 /* Switch to the main mode */
3892 * reprocess the current token.
3896 errStrayEndTag(name
);
3905 appendToCurrentNodeAndPushHeadElement(HtmlAttributes
.EMPTY_ATTRIBUTES
);
3909 errStrayEndTag(name
);
3915 endTagTemplateInHead();
3920 appendToCurrentNodeAndPushBodyElement();
3924 errStrayEndTag(name
);
3927 case AFTER_AFTER_BODY
:
3928 errStrayEndTag(name
);
3929 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
3931 case AFTER_AFTER_FRAMESET
:
3932 errStrayEndTag(name
);
3935 // XXX need to manage insertion point here
3937 if (originalMode
== AFTER_HEAD
) {
3940 mode
= originalMode
;
3946 private void endTagTemplateInHead() throws SAXException
{
3947 int eltPos
= findLast("template");
3948 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
3949 errStrayEndTag("template");
3952 generateImpliedEndTagsThoroughly();
3953 if (errorHandler
!= null && !isCurrent("template")) {
3954 errUnclosedElements(eltPos
, "template");
3956 while (currentPtr
>= eltPos
) {
3959 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
3961 resetTheInsertionMode();
3964 private int findLastInTableScopeOrRootTemplateTbodyTheadTfoot() {
3965 for (int i
= currentPtr
; i
> 0; i
--) {
3966 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml"
3967 && (stack
[i
].getGroup() == TreeBuilder
.TBODY_OR_THEAD_OR_TFOOT
3968 || stack
[i
].getGroup() == TreeBuilder
.TEMPLATE
)) {
3975 private int findLast(@Local String name
) {
3976 for (int i
= currentPtr
; i
> 0; i
--) {
3977 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml" && stack
[i
].name
== name
) {
3981 return TreeBuilder
.NOT_FOUND_ON_STACK
;
3984 private int findLastInTableScope(@Local String name
) {
3985 for (int i
= currentPtr
; i
> 0; i
--) {
3986 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml") {
3987 if (stack
[i
].name
== name
) {
3989 } else if (stack
[i
].name
== "table" || stack
[i
].name
== "template") {
3990 return TreeBuilder
.NOT_FOUND_ON_STACK
;
3994 return TreeBuilder
.NOT_FOUND_ON_STACK
;
3997 private int findLastInButtonScope(@Local String name
) {
3998 for (int i
= currentPtr
; i
> 0; i
--) {
3999 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml") {
4000 if (stack
[i
].name
== name
) {
4002 } else if (stack
[i
].name
== "button") {
4003 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4007 if (stack
[i
].isScoping()) {
4008 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4011 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4014 private int findLastInScope(@Local String name
) {
4015 for (int i
= currentPtr
; i
> 0; i
--) {
4016 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml" && stack
[i
].name
== name
) {
4018 } else if (stack
[i
].isScoping()) {
4019 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4022 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4025 private int findLastInListScope(@Local String name
) {
4026 for (int i
= currentPtr
; i
> 0; i
--) {
4027 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml") {
4028 if (stack
[i
].name
== name
) {
4030 } else if (stack
[i
].name
== "ul" || stack
[i
].name
== "ol") {
4031 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4035 if (stack
[i
].isScoping()) {
4036 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4039 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4042 private int findLastInScopeHn() {
4043 for (int i
= currentPtr
; i
> 0; i
--) {
4044 if (stack
[i
].getGroup() == TreeBuilder
.H1_OR_H2_OR_H3_OR_H4_OR_H5_OR_H6
) {
4046 } else if (stack
[i
].isScoping()) {
4047 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4050 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4053 private void generateImpliedEndTagsExceptFor(@Local String name
)
4054 throws SAXException
{
4056 StackNode
<T
> node
= stack
[currentPtr
];
4057 switch (node
.getGroup()) {
4065 if (node
.ns
== "http://www.w3.org/1999/xhtml" && node
.name
== name
) {
4076 private void generateImpliedEndTags() throws SAXException
{
4078 switch (stack
[currentPtr
].getGroup()) {
4094 private void generateImpliedEndTagsThoroughly() throws SAXException
{
4096 switch (stack
[currentPtr
].getGroup()) {
4106 case TBODY_OR_THEAD_OR_TFOOT
:
4117 private boolean isSecondOnStackBody() {
4118 return currentPtr
>= 1 && stack
[1].getGroup() == TreeBuilder
.BODY
;
4121 private void documentModeInternal(DocumentMode m
, String publicIdentifier
,
4122 String systemIdentifier
)
4123 throws SAXException
{
4125 if (forceNoQuirks
) {
4126 // Srcdoc documents are always rendered in standards mode.
4128 if (documentModeHandler
!= null) {
4129 documentModeHandler
.documentMode(
4130 DocumentMode
.STANDARDS_MODE
4139 quirks
= (m
== DocumentMode
.QUIRKS_MODE
);
4140 if (documentModeHandler
!= null) {
4141 documentModeHandler
.documentMode(
4144 , publicIdentifier
, systemIdentifier
4149 documentMode(m
, publicIdentifier
, systemIdentifier
);
4153 private boolean isAlmostStandards(String publicIdentifier
,
4154 String systemIdentifier
) {
4155 if (Portability
.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
4156 "-//w3c//dtd xhtml 1.0 transitional//", publicIdentifier
)) {
4159 if (Portability
.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
4160 "-//w3c//dtd xhtml 1.0 frameset//", publicIdentifier
)) {
4163 if (systemIdentifier
!= null) {
4164 if (Portability
.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
4165 "-//w3c//dtd html 4.01 transitional//", publicIdentifier
)) {
4168 if (Portability
.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
4169 "-//w3c//dtd html 4.01 frameset//", publicIdentifier
)) {
4176 private boolean isQuirky(@Local String name
, String publicIdentifier
,
4177 String systemIdentifier
, boolean forceQuirks
) {
4181 if (name
!= HTML_LOCAL
) {
4184 if (publicIdentifier
!= null) {
4185 for (int i
= 0; i
< TreeBuilder
.QUIRKY_PUBLIC_IDS
.length
; i
++) {
4186 if (Portability
.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
4187 TreeBuilder
.QUIRKY_PUBLIC_IDS
[i
], publicIdentifier
)) {
4191 if (Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4192 "-//w3o//dtd w3 html strict 3.0//en//", publicIdentifier
)
4193 || Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4194 "-/w3c/dtd html 4.0 transitional/en",
4196 || Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4197 "html", publicIdentifier
)) {
4201 if (systemIdentifier
== null) {
4202 if (Portability
.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
4203 "-//w3c//dtd html 4.01 transitional//", publicIdentifier
)) {
4205 } else if (Portability
.lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(
4206 "-//w3c//dtd html 4.01 frameset//", publicIdentifier
)) {
4209 } else if (Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
4210 "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd",
4211 systemIdentifier
)) {
4217 private void closeTheCell(int eltPos
) throws SAXException
{
4218 generateImpliedEndTags();
4219 if (errorHandler
!= null && eltPos
!= currentPtr
) {
4220 errUnclosedElementsCell(eltPos
);
4222 while (currentPtr
>= eltPos
) {
4225 clearTheListOfActiveFormattingElementsUpToTheLastMarker();
4230 private int findLastInTableScopeTdTh() {
4231 for (int i
= currentPtr
; i
> 0; i
--) {
4232 @Local String name
= stack
[i
].name
;
4233 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml") {
4234 if ("td" == name
|| "th" == name
) {
4236 } else if (name
== "table" || name
== "template") {
4237 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4241 return TreeBuilder
.NOT_FOUND_ON_STACK
;
4244 private void clearStackBackTo(int eltPos
) throws SAXException
{
4245 int eltGroup
= stack
[eltPos
].getGroup();
4246 while (currentPtr
> eltPos
) { // > not >= intentional
4247 if (stack
[currentPtr
].ns
== "http://www.w3.org/1999/xhtml"
4248 && stack
[currentPtr
].getGroup() == TEMPLATE
4249 && (eltGroup
== TABLE
|| eltGroup
== TBODY_OR_THEAD_OR_TFOOT
|| eltGroup
== TR
|| eltPos
== 0)) {
4256 private void resetTheInsertionMode() {
4260 for (int i
= currentPtr
; i
>= 0; i
--) {
4265 if (!(contextNamespace
== "http://www.w3.org/1999/xhtml" && (contextName
== "td" || contextName
== "th"))) {
4267 // Make sure we are parsing a fragment otherwise the context element doesn't make sense.
4269 ns
= contextNamespace
;
4272 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
; // XXX from Hixie's email
4276 if ("select" == name
) {
4277 int ancestorIndex
= i
;
4278 while (ancestorIndex
> 0) {
4279 StackNode
<T
> ancestor
= stack
[ancestorIndex
--];
4280 if ("http://www.w3.org/1999/xhtml" == ancestor
.ns
) {
4281 if ("template" == ancestor
.name
) {
4284 if ("table" == ancestor
.name
) {
4285 mode
= IN_SELECT_IN_TABLE
;
4292 } else if ("td" == name
|| "th" == name
) {
4295 } else if ("tr" == name
) {
4298 } else if ("tbody" == name
|| "thead" == name
|| "tfoot" == name
) {
4299 mode
= IN_TABLE_BODY
;
4301 } else if ("caption" == name
) {
4304 } else if ("colgroup" == name
) {
4305 mode
= IN_COLUMN_GROUP
;
4307 } else if ("table" == name
) {
4310 } else if ("http://www.w3.org/1999/xhtml" != ns
) {
4311 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
4313 } else if ("template" == name
) {
4314 assert templateModePtr
>= 0;
4315 mode
= templateModeStack
[templateModePtr
];
4317 } else if ("head" == name
) {
4318 if (name
== contextName
) {
4319 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
; // really
4324 } else if ("body" == name
) {
4325 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
4327 } else if ("frameset" == name
) {
4328 // TODO: Fragment case. Add error reporting.
4331 } else if ("html" == name
) {
4332 if (headPointer
== null) {
4333 // TODO: Fragment case. Add error reporting.
4339 } else if (i
== 0) {
4340 mode
= framesetOk ? FRAMESET_OK
: IN_BODY
;
4347 * @throws SAXException
4350 private void implicitlyCloseP() throws SAXException
{
4351 int eltPos
= findLastInButtonScope("p");
4352 if (eltPos
== TreeBuilder
.NOT_FOUND_ON_STACK
) {
4355 generateImpliedEndTagsExceptFor("p");
4356 if (errorHandler
!= null && eltPos
!= currentPtr
) {
4357 errUnclosedElementsImplied(eltPos
, "p");
4359 while (currentPtr
>= eltPos
) {
4364 private boolean debugOnlyClearLastStackSlot() {
4365 stack
[currentPtr
] = null;
4369 private boolean debugOnlyClearLastListSlot() {
4370 listOfActiveFormattingElements
[listPtr
] = null;
4374 private void pushTemplateMode(int mode
) {
4376 if (templateModePtr
== templateModeStack
.length
) {
4377 int[] newStack
= new int[templateModeStack
.length
+ 64];
4378 System
.arraycopy(templateModeStack
, 0, newStack
, 0, templateModeStack
.length
);
4379 templateModeStack
= newStack
;
4381 templateModeStack
[templateModePtr
] = mode
;
4384 @SuppressWarnings("unchecked") private void push(StackNode
<T
> node
) throws SAXException
{
4386 if (currentPtr
== stack
.length
) {
4387 StackNode
<T
>[] newStack
= new StackNode
[stack
.length
+ 64];
4388 System
.arraycopy(stack
, 0, newStack
, 0, stack
.length
);
4391 stack
[currentPtr
] = node
;
4392 elementPushed(node
.ns
, node
.popName
, node
.node
);
4395 @SuppressWarnings("unchecked") private void silentPush(StackNode
<T
> node
) throws SAXException
{
4397 if (currentPtr
== stack
.length
) {
4398 StackNode
<T
>[] newStack
= new StackNode
[stack
.length
+ 64];
4399 System
.arraycopy(stack
, 0, newStack
, 0, stack
.length
);
4402 stack
[currentPtr
] = node
;
4405 @SuppressWarnings("unchecked") private void append(StackNode
<T
> node
) {
4407 if (listPtr
== listOfActiveFormattingElements
.length
) {
4408 StackNode
<T
>[] newList
= new StackNode
[listOfActiveFormattingElements
.length
+ 64];
4409 System
.arraycopy(listOfActiveFormattingElements
, 0, newList
, 0,
4410 listOfActiveFormattingElements
.length
);
4411 listOfActiveFormattingElements
= newList
;
4413 listOfActiveFormattingElements
[listPtr
] = node
;
4416 @Inline private void insertMarker() {
4420 private void clearTheListOfActiveFormattingElementsUpToTheLastMarker() {
4421 while (listPtr
> -1) {
4422 if (listOfActiveFormattingElements
[listPtr
] == null) {
4426 listOfActiveFormattingElements
[listPtr
].release(this);
4431 @Inline private boolean isCurrent(@Local String name
) {
4432 return stack
[currentPtr
].ns
== "http://www.w3.org/1999/xhtml" &&
4433 name
== stack
[currentPtr
].name
;
4436 private void removeFromStack(int pos
) throws SAXException
{
4437 if (currentPtr
== pos
) {
4441 stack
[pos
].release(this);
4442 System
.arraycopy(stack
, pos
+ 1, stack
, pos
, currentPtr
- pos
);
4443 assert debugOnlyClearLastStackSlot();
4448 private void removeFromStack(StackNode
<T
> node
) throws SAXException
{
4449 if (stack
[currentPtr
] == node
) {
4452 int pos
= currentPtr
- 1;
4453 while (pos
>= 0 && stack
[pos
] != node
) {
4462 System
.arraycopy(stack
, pos
+ 1, stack
, pos
, currentPtr
- pos
);
4467 private void removeFromListOfActiveFormattingElements(int pos
) {
4468 assert listOfActiveFormattingElements
[pos
] != null;
4469 listOfActiveFormattingElements
[pos
].release(this);
4470 if (pos
== listPtr
) {
4471 assert debugOnlyClearLastListSlot();
4475 assert pos
< listPtr
;
4476 System
.arraycopy(listOfActiveFormattingElements
, pos
+ 1,
4477 listOfActiveFormattingElements
, pos
, listPtr
- pos
);
4478 assert debugOnlyClearLastListSlot();
4483 * Adoption agency algorithm.
4485 * @param name subject as described in the specified algorithm.
4486 * @return Returns true if the algorithm has completed and there is nothing remaining to
4487 * be done. Returns false if the algorithm needs to "act as described in the 'any other
4488 * end tag' entry" as described in the specified algorithm.
4489 * @throws SAXException
4491 private boolean adoptionAgencyEndTag(@Local String name
) throws SAXException
{
4492 // This check intends to ensure that for properly nested tags, closing tags will match
4493 // against the stack instead of the listOfActiveFormattingElements.
4494 if (stack
[currentPtr
].ns
== "http://www.w3.org/1999/xhtml" &&
4495 stack
[currentPtr
].name
== name
&&
4496 findInListOfActiveFormattingElements(stack
[currentPtr
]) == -1) {
4497 // If the current element matches the name but isn't on the list of active
4498 // formatting elements, then it is possible that the list was mangled by the Noah's Ark
4499 // clause. In this case, we want to match the end tag against the stack instead of
4500 // proceeding with the AAA algorithm that may match against the list of
4501 // active formatting elements (and possibly mangle the tree in unexpected ways).
4506 // If you crash around here, perhaps some stack node variable claimed to
4507 // be a weak ref isn't.
4508 for (int i
= 0; i
< 8; ++i
) {
4509 int formattingEltListPos
= listPtr
;
4510 while (formattingEltListPos
> -1) {
4511 StackNode
<T
> listNode
= listOfActiveFormattingElements
[formattingEltListPos
]; // weak ref
4512 if (listNode
== null) {
4513 formattingEltListPos
= -1;
4515 } else if (listNode
.name
== name
) {
4518 formattingEltListPos
--;
4520 if (formattingEltListPos
== -1) {
4523 // this *looks* like a weak ref to the list of formatting elements
4524 StackNode
<T
> formattingElt
= listOfActiveFormattingElements
[formattingEltListPos
];
4525 int formattingEltStackPos
= currentPtr
;
4526 boolean inScope
= true;
4527 while (formattingEltStackPos
> -1) {
4528 StackNode
<T
> node
= stack
[formattingEltStackPos
]; // weak ref
4529 if (node
== formattingElt
) {
4531 } else if (node
.isScoping()) {
4534 formattingEltStackPos
--;
4536 if (formattingEltStackPos
== -1) {
4537 errNoElementToCloseButEndTagSeen(name
);
4538 removeFromListOfActiveFormattingElements(formattingEltListPos
);
4542 errNoElementToCloseButEndTagSeen(name
);
4545 // stackPos now points to the formatting element and it is in scope
4546 if (formattingEltStackPos
!= currentPtr
) {
4547 errEndTagViolatesNestingRules(name
);
4549 int furthestBlockPos
= formattingEltStackPos
+ 1;
4550 while (furthestBlockPos
<= currentPtr
) {
4551 StackNode
<T
> node
= stack
[furthestBlockPos
]; // weak ref
4552 assert furthestBlockPos
> 0: "How is formattingEltStackPos + 1 not > 0?";
4553 if (node
.isSpecial()) {
4558 if (furthestBlockPos
> currentPtr
) {
4559 // no furthest block
4560 while (currentPtr
>= formattingEltStackPos
) {
4563 removeFromListOfActiveFormattingElements(formattingEltListPos
);
4566 // commonAncestor is used for running the algorithm and
4567 // insertionCommonAncestor is used for the actual insertions to
4568 // keep them depth-limited.
4569 StackNode
<T
> commonAncestor
= stack
[formattingEltStackPos
- 1]; // weak ref
4570 T insertionCommonAncestor
= nodeFromStackWithBlinkCompat(formattingEltStackPos
- 1); // weak ref
4571 StackNode
<T
> furthestBlock
= stack
[furthestBlockPos
]; // weak ref
4572 // detachFromParent(furthestBlock.node); XXX AAA CHANGE
4573 int bookmark
= formattingEltListPos
;
4574 int nodePos
= furthestBlockPos
;
4575 StackNode
<T
> lastNode
= furthestBlock
; // weak ref
4580 if (nodePos
== formattingEltStackPos
) {
4583 StackNode
<T
> node
= stack
[nodePos
]; // weak ref
4584 int nodeListPos
= findInListOfActiveFormattingElements(node
);
4586 if (j
> 3 && nodeListPos
!= -1) {
4587 removeFromListOfActiveFormattingElements(nodeListPos
);
4589 // Adjust the indices into the list to account
4590 // for the removal of nodeListPos.
4591 if (nodeListPos
<= formattingEltListPos
) {
4592 formattingEltListPos
--;
4594 if (nodeListPos
<= bookmark
) {
4598 // Update position to reflect removal from list.
4602 if (nodeListPos
== -1) {
4603 assert formattingEltStackPos
< nodePos
;
4604 assert bookmark
< nodePos
;
4605 assert furthestBlockPos
> nodePos
;
4606 removeFromStack(nodePos
); // node is now a bad pointer in C++
4610 // now node is both on stack and in the list
4611 if (nodePos
== furthestBlockPos
) {
4612 bookmark
= nodeListPos
+ 1;
4614 // if (hasChildren(node.node)) { XXX AAA CHANGE
4615 assert node
== listOfActiveFormattingElements
[nodeListPos
];
4616 assert node
== stack
[nodePos
];
4617 T clone
= createElement("http://www.w3.org/1999/xhtml",
4618 node
.name
, node
.attributes
.cloneAttributes(), insertionCommonAncestor
4619 // CPPONLY: , htmlCreator(node.getHtmlCreator())
4621 StackNode
<T
> newNode
= createStackNode(node
.getFlags(), node
.ns
,
4622 node
.name
, clone
, node
.popName
, node
.attributes
4623 // CPPONLY: , node.getHtmlCreator()
4627 ); // creation ownership goes to stack
4628 node
.dropAttributes(); // adopt ownership to newNode
4629 stack
[nodePos
] = newNode
;
4630 newNode
.retain(); // retain for list
4631 listOfActiveFormattingElements
[nodeListPos
] = newNode
;
4632 node
.release(this); // release from stack
4633 node
.release(this); // release from list
4636 detachFromParent(lastNode
.node
);
4637 appendElement(lastNode
.node
, nodeFromStackWithBlinkCompat(nodePos
));
4640 // If we insert into a foster parent, for simplicity, we insert
4641 // accoding to the spec without Blink's depth limit.
4642 if (commonAncestor
.isFosterParenting()) {
4644 detachFromParent(lastNode
.node
);
4645 insertIntoFosterParent(lastNode
.node
);
4647 detachFromParent(lastNode
.node
);
4648 appendElement(lastNode
.node
, insertionCommonAncestor
);
4650 T clone
= createElement("http://www.w3.org/1999/xhtml",
4652 formattingElt
.attributes
.cloneAttributes(), furthestBlock
.node
4653 // CPPONLY: , htmlCreator(formattingElt.getHtmlCreator())
4655 StackNode
<T
> formattingClone
= createStackNode(
4656 formattingElt
.getFlags(), formattingElt
.ns
,
4657 formattingElt
.name
, clone
, formattingElt
.popName
,
4658 formattingElt
.attributes
4659 // CPPONLY: , formattingElt.getHtmlCreator()
4661 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
4663 ); // Ownership transfers to stack below
4664 formattingElt
.dropAttributes(); // transfer ownership to
4666 appendChildrenToNewParent(furthestBlock
.node
, clone
);
4667 appendElement(clone
, furthestBlock
.node
);
4668 removeFromListOfActiveFormattingElements(formattingEltListPos
);
4669 insertIntoListOfActiveFormattingElements(formattingClone
, bookmark
);
4670 assert formattingEltStackPos
< furthestBlockPos
;
4671 removeFromStack(formattingEltStackPos
);
4672 // furthestBlockPos is now off by one and points to the slot after
4674 insertIntoStack(formattingClone
, furthestBlockPos
);
4679 private void insertIntoStack(StackNode
<T
> node
, int position
)
4680 throws SAXException
{
4681 assert currentPtr
+ 1 < stack
.length
;
4682 assert position
<= currentPtr
+ 1;
4683 if (position
== currentPtr
+ 1) {
4686 System
.arraycopy(stack
, position
, stack
, position
+ 1,
4687 (currentPtr
- position
) + 1);
4689 stack
[position
] = node
;
4693 private void insertIntoListOfActiveFormattingElements(
4694 StackNode
<T
> formattingClone
, int bookmark
) {
4695 formattingClone
.retain();
4696 assert listPtr
+ 1 < listOfActiveFormattingElements
.length
;
4697 if (bookmark
<= listPtr
) {
4698 System
.arraycopy(listOfActiveFormattingElements
, bookmark
,
4699 listOfActiveFormattingElements
, bookmark
+ 1,
4700 (listPtr
- bookmark
) + 1);
4703 listOfActiveFormattingElements
[bookmark
] = formattingClone
;
4706 private int findInListOfActiveFormattingElements(StackNode
<T
> node
) {
4707 for (int i
= listPtr
; i
>= 0; i
--) {
4708 if (node
== listOfActiveFormattingElements
[i
]) {
4715 private int findInListOfActiveFormattingElementsContainsBetweenEndAndLastMarker(
4716 @Local String name
) {
4717 for (int i
= listPtr
; i
>= 0; i
--) {
4718 StackNode
<T
> node
= listOfActiveFormattingElements
[i
];
4721 } else if (node
.name
== name
) {
4729 private void maybeForgetEarlierDuplicateFormattingElement(
4730 @Local String name
, HtmlAttributes attributes
) throws SAXException
{
4733 for (int i
= listPtr
; i
>= 0; i
--) {
4734 StackNode
<T
> node
= listOfActiveFormattingElements
[i
];
4738 if (node
.name
== name
&& node
.attributes
.equalsAnother(attributes
)) {
4744 removeFromListOfActiveFormattingElements(candidate
);
4748 private int findLastOrRoot(@Local String name
) {
4749 for (int i
= currentPtr
; i
> 0; i
--) {
4750 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml" && stack
[i
].name
== name
) {
4757 private int findLastOrRoot(int group
) {
4758 for (int i
= currentPtr
; i
> 0; i
--) {
4759 if (stack
[i
].ns
== "http://www.w3.org/1999/xhtml" && stack
[i
].getGroup() == group
) {
4767 * Attempt to add attribute to the body element.
4768 * @param attributes the attributes
4769 * @return <code>true</code> iff the attributes were added
4770 * @throws SAXException
4772 private boolean addAttributesToBody(HtmlAttributes attributes
)
4773 throws SAXException
{
4775 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
4777 if (currentPtr
>= 1) {
4778 StackNode
<T
> body
= stack
[1];
4779 if (body
.getGroup() == TreeBuilder
.BODY
) {
4780 addAttributesToElement(body
.node
, attributes
);
4787 private void addAttributesToHtml(HtmlAttributes attributes
)
4788 throws SAXException
{
4790 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
4792 addAttributesToElement(stack
[0].node
, attributes
);
4795 private void pushHeadPointerOntoStack() throws SAXException
{
4796 assert headPointer
!= null;
4797 assert mode
== AFTER_HEAD
;
4799 silentPush(createStackNode(ElementName
.HEAD
, headPointer
4801 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
4807 * @throws SAXException
4810 private void reconstructTheActiveFormattingElements() throws SAXException
{
4811 if (listPtr
== -1) {
4814 StackNode
<T
> mostRecent
= listOfActiveFormattingElements
[listPtr
];
4815 if (mostRecent
== null || isInStack(mostRecent
)) {
4818 int entryPos
= listPtr
;
4821 if (entryPos
== -1) {
4824 if (listOfActiveFormattingElements
[entryPos
] == null) {
4827 if (isInStack(listOfActiveFormattingElements
[entryPos
])) {
4831 while (entryPos
< listPtr
) {
4833 StackNode
<T
> entry
= listOfActiveFormattingElements
[entryPos
];
4834 StackNode
<T
> current
= stack
[currentPtr
];
4837 if (current
.isFosterParenting()) {
4838 clone
= createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", entry
.name
,
4839 entry
.attributes
.cloneAttributes()
4840 // CPPONLY: , htmlCreator(entry.getHtmlCreator())
4843 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
4844 clone
= createElement("http://www.w3.org/1999/xhtml", entry
.name
,
4845 entry
.attributes
.cloneAttributes(), currentNode
4846 // CPPONLY: , htmlCreator(entry.getHtmlCreator())
4848 appendElement(clone
, currentNode
);
4851 StackNode
<T
> entryClone
= createStackNode(entry
.getFlags(),
4852 entry
.ns
, entry
.name
, clone
, entry
.popName
,
4854 // CPPONLY: , entry.getHtmlCreator()
4856 , entry
.getLocator()
4860 entry
.dropAttributes(); // transfer ownership to entryClone
4863 // stack takes ownership of the local variable
4864 listOfActiveFormattingElements
[entryPos
] = entryClone
;
4865 // overwriting the old entry on the list, so release & retain
4866 entry
.release(this);
4867 entryClone
.retain();
4871 void notifyUnusedStackNode(int idxInStackNodes
) {
4872 // stackNodesIdx is the earliest possible index of a stack node that might be unused,
4873 // so update the index if necessary.
4874 if (idxInStackNodes
< stackNodesIdx
) {
4875 stackNodesIdx
= idxInStackNodes
;
4879 @SuppressWarnings("unchecked") private StackNode
<T
> getUnusedStackNode() {
4880 // Search for an unused stack node.
4881 while (stackNodesIdx
< numStackNodes
) {
4882 if (stackNodes
[stackNodesIdx
].isUnused()) {
4883 return stackNodes
[stackNodesIdx
++];
4888 if (stackNodesIdx
< stackNodes
.length
) {
4889 // No unused stack nodes, but there is still space in the storage array.
4890 stackNodes
[stackNodesIdx
] = new StackNode
<T
>(stackNodesIdx
);
4892 return stackNodes
[stackNodesIdx
++];
4895 // Could not find an unused stack node and storage array is full.
4896 StackNode
<T
>[] newStack
= new StackNode
[stackNodes
.length
+ 64];
4897 System
.arraycopy(stackNodes
, 0, newStack
, 0, stackNodes
.length
);
4898 stackNodes
= newStack
;
4900 // Create a new stack node and return it.
4901 stackNodes
[stackNodesIdx
] = new StackNode
<T
>(stackNodesIdx
);
4903 return stackNodes
[stackNodesIdx
++];
4906 private StackNode
<T
> createStackNode(int flags
, @NsUri String ns
, @Local String name
, T node
,
4907 @Local String popName
, HtmlAttributes attributes
4908 // CPPONLY: , @HtmlCreator Object htmlCreator
4910 , TaintableLocatorImpl locator
4913 StackNode
<T
> instance
= getUnusedStackNode();
4914 instance
.setValues(flags
, ns
, name
, node
, popName
, attributes
4915 // CPPONLY: , htmlCreator
4923 private StackNode
<T
> createStackNode(ElementName elementName
, T node
4925 , TaintableLocatorImpl locator
4928 StackNode
<T
> instance
= getUnusedStackNode();
4929 instance
.setValues(elementName
, node
4937 private StackNode
<T
> createStackNode(ElementName elementName
, T node
, HtmlAttributes attributes
4939 , TaintableLocatorImpl locator
4942 StackNode
<T
> instance
= getUnusedStackNode();
4943 instance
.setValues(elementName
, node
, attributes
4951 private StackNode
<T
> createStackNode(ElementName elementName
, T node
, @Local String popName
4953 , TaintableLocatorImpl locator
4956 StackNode
<T
> instance
= getUnusedStackNode();
4957 instance
.setValues(elementName
, node
, popName
4965 private StackNode
<T
> createStackNode(ElementName elementName
, @Local String popName
, T node
4967 , TaintableLocatorImpl locator
4970 StackNode
<T
> instance
= getUnusedStackNode();
4971 instance
.setValues(elementName
, popName
, node
4979 private StackNode
<T
> createStackNode(ElementName elementName
, T node
, @Local String popName
,
4980 boolean markAsIntegrationPoint
4982 , TaintableLocatorImpl locator
4985 StackNode
<T
> instance
= getUnusedStackNode();
4986 instance
.setValues(elementName
, node
, popName
, markAsIntegrationPoint
4994 private void insertIntoFosterParent(T child
) throws SAXException
{
4995 int tablePos
= findLastOrRoot(TreeBuilder
.TABLE
);
4996 int templatePos
= findLastOrRoot(TreeBuilder
.TEMPLATE
);
4998 if (templatePos
>= tablePos
) {
4999 appendElement(child
, stack
[templatePos
].node
);
5003 StackNode
<T
> node
= stack
[tablePos
];
5004 insertFosterParentedChild(child
, node
.node
, stack
[tablePos
- 1].node
);
5007 private T
createAndInsertFosterParentedElement(@NsUri String ns
, @Local String name
,
5008 HtmlAttributes attributes
5009 // CPPONLY: , @Creator Object creator
5010 ) throws SAXException
{
5011 return createAndInsertFosterParentedElement(ns
, name
, attributes
, null
5012 // CPPONLY: , creator
5016 private T
createAndInsertFosterParentedElement(@NsUri String ns
, @Local String name
,
5017 HtmlAttributes attributes
, T form
5018 // CPPONLY: , @Creator Object creator
5019 ) throws SAXException
{
5020 int tablePos
= findLastOrRoot(TreeBuilder
.TABLE
);
5021 int templatePos
= findLastOrRoot(TreeBuilder
.TEMPLATE
);
5023 if (templatePos
>= tablePos
) {
5024 T child
= createElement(ns
, name
, attributes
, form
, stack
[templatePos
].node
5025 // CPPONLY: , creator
5027 appendElement(child
, stack
[templatePos
].node
);
5031 StackNode
<T
> node
= stack
[tablePos
];
5032 return createAndInsertFosterParentedElement(ns
, name
, attributes
, form
, node
.node
, stack
[tablePos
- 1].node
5033 // CPPONLY: , creator
5037 private boolean isInStack(StackNode
<T
> node
) {
5038 for (int i
= currentPtr
; i
>= 0; i
--) {
5039 if (stack
[i
] == node
) {
5046 private void popTemplateMode() {
5050 private void pop() throws SAXException
{
5051 StackNode
<T
> node
= stack
[currentPtr
];
5052 assert debugOnlyClearLastStackSlot();
5054 elementPopped(node
.ns
, node
.popName
, node
.node
);
5058 private void popForeign(int origPos
, int eltPos
) throws SAXException
{
5059 StackNode
<T
> node
= stack
[currentPtr
];
5060 if (origPos
!= currentPtr
|| eltPos
!= currentPtr
) {
5061 markMalformedIfScript(node
.node
);
5063 assert debugOnlyClearLastStackSlot();
5065 elementPopped(node
.ns
, node
.popName
, node
.node
);
5069 private void silentPop() throws SAXException
{
5070 StackNode
<T
> node
= stack
[currentPtr
];
5071 assert debugOnlyClearLastStackSlot();
5076 private void popOnEof() throws SAXException
{
5077 StackNode
<T
> node
= stack
[currentPtr
];
5078 assert debugOnlyClearLastStackSlot();
5080 markMalformedIfScript(node
.node
);
5081 elementPopped(node
.ns
, node
.popName
, node
.node
);
5086 private void checkAttributes(HtmlAttributes attributes
, @NsUri String ns
)
5087 throws SAXException
{
5088 if (errorHandler
!= null) {
5089 int len
= attributes
.getXmlnsLength();
5090 for (int i
= 0; i
< len
; i
++) {
5091 AttributeName name
= attributes
.getXmlnsAttributeName(i
);
5092 if (name
== AttributeName
.XMLNS
) {
5093 String xmlns
= attributes
.getXmlnsValue(i
);
5094 if (!ns
.equals(xmlns
)) {
5095 err("Bad value \u201C"
5097 + "\u201D for the attribute \u201Cxmlns\u201D (only \u201C"
5098 + ns
+ "\u201D permitted here).");
5099 switch (namePolicy
) {
5103 warn("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0.");
5106 fatal("Attribute \u201Cxmlns\u201D is not serializable as XML 1.0.");
5110 } else if (ns
!= "http://www.w3.org/1999/xhtml"
5111 && name
== AttributeName
.XMLNS_XLINK
) {
5112 String xmlns
= attributes
.getXmlnsValue(i
);
5113 if (!"http://www.w3.org/1999/xlink".equals(xmlns
)) {
5114 err("Bad value \u201C"
5116 + "\u201D for the attribute \u201Cxmlns:link\u201D (only \u201Chttp://www.w3.org/1999/xlink\u201D permitted here).");
5117 switch (namePolicy
) {
5121 warn("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics.");
5124 fatal("Attribute \u201Cxmlns:xlink\u201D with a value other than \u201Chttp://www.w3.org/1999/xlink\u201D is not serializable as XML 1.0 without changing document semantics.");
5129 err("Attribute \u201C" + attributes
.getXmlnsLocalName(i
)
5130 + "\u201D not allowed here.");
5131 switch (namePolicy
) {
5135 warn("Attribute with the local name \u201C"
5136 + attributes
.getXmlnsLocalName(i
)
5137 + "\u201D is not serializable as XML 1.0.");
5140 fatal("Attribute with the local name \u201C"
5141 + attributes
.getXmlnsLocalName(i
)
5142 + "\u201D is not serializable as XML 1.0.");
5148 attributes
.processNonNcNames(this, namePolicy
);
5151 private String
checkPopName(@Local String name
) throws SAXException
{
5152 if (NCName
.isNCName(name
)) {
5155 switch (namePolicy
) {
5157 warn("Element name \u201C" + name
5158 + "\u201D cannot be represented as XML 1.0.");
5161 warn("Element name \u201C" + name
5162 + "\u201D cannot be represented as XML 1.0.");
5163 return NCName
.escapeName(name
);
5165 fatal("Element name \u201C" + name
5166 + "\u201D cannot be represented as XML 1.0.");
5169 return null; // keep compiler happy
5174 private void appendHtmlElementToDocumentAndPush(HtmlAttributes attributes
)
5175 throws SAXException
{
5177 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5179 T elt
= createHtmlElementSetAsRoot(attributes
);
5180 StackNode
<T
> node
= createStackNode(ElementName
.HTML
,
5183 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5189 private void appendHtmlElementToDocumentAndPush() throws SAXException
{
5190 appendHtmlElementToDocumentAndPush(tokenizer
.emptyAttributes());
5193 private void appendToCurrentNodeAndPushHeadElement(HtmlAttributes attributes
)
5194 throws SAXException
{
5196 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5198 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5199 T elt
= createElement("http://www.w3.org/1999/xhtml", "head", attributes
, currentNode
5201 * head uses NS_NewHTMLSharedElement creator
5203 // CPPONLY: , htmlCreator(NS_NewHTMLSharedElement)
5205 appendElement(elt
, currentNode
);
5207 StackNode
<T
> node
= createStackNode(ElementName
.HEAD
,
5210 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5216 private void appendToCurrentNodeAndPushBodyElement(HtmlAttributes attributes
)
5217 throws SAXException
{
5218 appendToCurrentNodeAndPushElement(ElementName
.BODY
,
5222 private void appendToCurrentNodeAndPushBodyElement() throws SAXException
{
5223 appendToCurrentNodeAndPushBodyElement(tokenizer
.emptyAttributes());
5226 private void appendToCurrentNodeAndPushFormElementMayFoster(
5227 HtmlAttributes attributes
) throws SAXException
{
5229 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5233 StackNode
<T
> current
= stack
[currentPtr
];
5234 if (current
.isFosterParenting()) {
5236 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", "form", attributes
5237 // CPPONLY: , htmlCreator(NS_NewHTMLFormElement)
5240 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5241 elt
= createElement("http://www.w3.org/1999/xhtml", "form", attributes
, currentNode
5242 // CPPONLY: , htmlCreator(NS_NewHTMLFormElement)
5244 appendElement(elt
, currentNode
);
5247 if (!isTemplateContents()) {
5251 StackNode
<T
> node
= createStackNode(ElementName
.FORM
,
5254 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5260 private void appendToCurrentNodeAndPushFormattingElementMayFoster(
5261 ElementName elementName
, HtmlAttributes attributes
)
5262 throws SAXException
{
5264 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5266 // This method can't be called for custom elements
5267 HtmlAttributes clone
= attributes
.cloneAttributes();
5268 // Attributes must not be read after calling createElement, because
5269 // createElement may delete attributes in C++.
5271 StackNode
<T
> current
= stack
[currentPtr
];
5272 if (current
.isFosterParenting()) {
5274 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName
.getName(), attributes
5275 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5278 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5279 elt
= createElement("http://www.w3.org/1999/xhtml", elementName
.getName(), attributes
, currentNode
5280 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5282 appendElement(elt
, currentNode
);
5284 StackNode
<T
> node
= createStackNode(elementName
, elt
, clone
5286 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5291 node
.retain(); // append doesn't retain itself
5294 private void appendToCurrentNodeAndPushElement(ElementName elementName
,
5295 HtmlAttributes attributes
)
5296 throws SAXException
{
5298 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5300 // This method can't be called for custom elements
5301 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5302 T elt
= createElement("http://www.w3.org/1999/xhtml", elementName
.getName(), attributes
, currentNode
5303 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5305 appendElement(elt
, currentNode
);
5306 if (ElementName
.TEMPLATE
== elementName
) {
5307 elt
= getDocumentFragmentForTemplate(elt
);
5309 StackNode
<T
> node
= createStackNode(elementName
, elt
5311 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5317 private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName
,
5318 HtmlAttributes attributes
)
5319 throws SAXException
{
5320 @Local String popName
= elementName
.getName();
5322 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5323 if (!elementName
.isInterned()) {
5324 popName
= checkPopName(popName
);
5328 StackNode
<T
> current
= stack
[currentPtr
];
5329 if (current
.isFosterParenting()) {
5331 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName
, attributes
5332 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5335 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5336 elt
= createElement("http://www.w3.org/1999/xhtml", popName
, attributes
, currentNode
5337 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5339 appendElement(elt
, currentNode
);
5341 StackNode
<T
> node
= createStackNode(elementName
, elt
, popName
5343 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5349 private void appendToCurrentNodeAndPushElementMayFosterMathML(
5350 ElementName elementName
, HtmlAttributes attributes
)
5351 throws SAXException
{
5352 @Local String popName
= elementName
.getName();
5354 checkAttributes(attributes
, "http://www.w3.org/1998/Math/MathML");
5355 if (!elementName
.isInterned()) {
5356 popName
= checkPopName(popName
);
5359 boolean markAsHtmlIntegrationPoint
= false;
5360 if (ElementName
.ANNOTATION_XML
== elementName
5361 && annotationXmlEncodingPermitsHtml(attributes
)) {
5362 markAsHtmlIntegrationPoint
= true;
5364 // Attributes must not be read after calling createElement(), since
5365 // createElement may delete the object in C++.
5367 StackNode
<T
> current
= stack
[currentPtr
];
5368 if (current
.isFosterParenting()) {
5370 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName
, attributes
5371 // CPPONLY: , htmlCreator(null)
5374 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5375 elt
= createElement("http://www.w3.org/1998/Math/MathML", popName
, attributes
, currentNode
5376 // CPPONLY: , htmlCreator(null)
5378 appendElement(elt
, currentNode
);
5380 StackNode
<T
> node
= createStackNode(elementName
, elt
, popName
,
5381 markAsHtmlIntegrationPoint
5383 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5390 T
getDocumentFragmentForTemplate(T template
) {
5394 T
getFormPointerForContext(T context
) {
5399 private boolean annotationXmlEncodingPermitsHtml(HtmlAttributes attributes
) {
5400 String encoding
= attributes
.getValue(AttributeName
.ENCODING
);
5401 if (encoding
== null) {
5404 return Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
5405 "application/xhtml+xml", encoding
)
5406 || Portability
.lowerCaseLiteralEqualsIgnoreAsciiCaseString(
5407 "text/html", encoding
);
5410 private void appendToCurrentNodeAndPushElementMayFosterSVG(
5411 ElementName elementName
, HtmlAttributes attributes
)
5412 throws SAXException
{
5413 @Local String popName
= elementName
.getCamelCaseName();
5415 checkAttributes(attributes
, "http://www.w3.org/2000/svg");
5416 if (!elementName
.isInterned()) {
5417 popName
= checkPopName(popName
);
5421 StackNode
<T
> current
= stack
[currentPtr
];
5422 if (current
.isFosterParenting()) {
5424 elt
= createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName
, attributes
5425 // CPPONLY: , svgCreator(elementName.getSvgCreator())
5428 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5429 elt
= createElement("http://www.w3.org/2000/svg", popName
, attributes
, currentNode
5430 // CPPONLY: , svgCreator(elementName.getSvgCreator())
5432 appendElement(elt
, currentNode
);
5434 StackNode
<T
> node
= createStackNode(elementName
, popName
, elt
5436 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5442 private void appendToCurrentNodeAndPushElementMayFoster(ElementName elementName
,
5443 HtmlAttributes attributes
, T form
)
5444 throws SAXException
{
5446 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5448 // Can't be called for custom elements
5450 T formOwner
= form
== null || fragment
|| isTemplateContents() ?
null : form
;
5451 StackNode
<T
> current
= stack
[currentPtr
];
5452 if (current
.isFosterParenting()) {
5454 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", elementName
.getName(),
5455 attributes
, formOwner
5456 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5459 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5460 elt
= createElement("http://www.w3.org/1999/xhtml", elementName
.getName(),
5461 attributes
, formOwner
, currentNode
5462 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5464 appendElement(elt
, currentNode
);
5466 StackNode
<T
> node
= createStackNode(elementName
, elt
5468 , errorHandler
== null ?
null : new TaintableLocatorImpl(tokenizer
)
5474 private void appendVoidElementToCurrent(
5475 ElementName elementName
, HtmlAttributes attributes
)
5476 throws SAXException
{
5477 @Local String popName
= elementName
.getName();
5479 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5480 if (!elementName
.isInterned()) {
5481 popName
= checkPopName(popName
);
5484 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5485 T elt
= createElement("http://www.w3.org/1999/xhtml", popName
, attributes
, currentNode
5486 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5488 appendElement(elt
, currentNode
);
5489 elementPushed("http://www.w3.org/1999/xhtml", popName
, elt
);
5490 elementPopped("http://www.w3.org/1999/xhtml", popName
, elt
);
5493 private void appendVoidElementToCurrentMayFoster(
5494 ElementName elementName
, HtmlAttributes attributes
, T form
) throws SAXException
{
5495 @Local String name
= elementName
.getName();
5497 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5499 // Can't be called for custom elements
5501 T formOwner
= form
== null || fragment
|| isTemplateContents() ?
null : form
;
5502 StackNode
<T
> current
= stack
[currentPtr
];
5503 if (current
.isFosterParenting()) {
5505 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", name
,
5506 attributes
, formOwner
5507 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5510 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5511 elt
= createElement("http://www.w3.org/1999/xhtml", name
,
5512 attributes
, formOwner
, currentNode
5513 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5515 appendElement(elt
, currentNode
);
5517 elementPushed("http://www.w3.org/1999/xhtml", name
, elt
);
5518 elementPopped("http://www.w3.org/1999/xhtml", name
, elt
);
5521 private void appendVoidElementToCurrentMayFoster(
5522 ElementName elementName
, HtmlAttributes attributes
)
5523 throws SAXException
{
5524 @Local String popName
= elementName
.getName();
5526 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5527 if (!elementName
.isInterned()) {
5528 popName
= checkPopName(popName
);
5532 StackNode
<T
> current
= stack
[currentPtr
];
5533 if (current
.isFosterParenting()) {
5535 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1999/xhtml", popName
, attributes
5536 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5539 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5540 elt
= createElement("http://www.w3.org/1999/xhtml", popName
, attributes
, currentNode
5541 // CPPONLY: , htmlCreator(elementName.getHtmlCreator())
5543 appendElement(elt
, currentNode
);
5545 elementPushed("http://www.w3.org/1999/xhtml", popName
, elt
);
5546 elementPopped("http://www.w3.org/1999/xhtml", popName
, elt
);
5549 private void appendVoidElementToCurrentMayFosterSVG(
5550 ElementName elementName
, HtmlAttributes attributes
)
5551 throws SAXException
{
5552 @Local String popName
= elementName
.getCamelCaseName();
5554 checkAttributes(attributes
, "http://www.w3.org/2000/svg");
5555 if (!elementName
.isInterned()) {
5556 popName
= checkPopName(popName
);
5560 StackNode
<T
> current
= stack
[currentPtr
];
5561 if (current
.isFosterParenting()) {
5563 elt
= createAndInsertFosterParentedElement("http://www.w3.org/2000/svg", popName
, attributes
5564 // CPPONLY: , svgCreator(elementName.getSvgCreator())
5567 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5568 elt
= createElement("http://www.w3.org/2000/svg", popName
, attributes
, currentNode
5569 // CPPONLY: , svgCreator(elementName.getSvgCreator())
5571 appendElement(elt
, currentNode
);
5573 elementPushed("http://www.w3.org/2000/svg", popName
, elt
);
5574 elementPopped("http://www.w3.org/2000/svg", popName
, elt
);
5577 private void appendVoidElementToCurrentMayFosterMathML(
5578 ElementName elementName
, HtmlAttributes attributes
)
5579 throws SAXException
{
5580 @Local String popName
= elementName
.getName();
5582 checkAttributes(attributes
, "http://www.w3.org/1998/Math/MathML");
5583 if (!elementName
.isInterned()) {
5584 popName
= checkPopName(popName
);
5588 StackNode
<T
> current
= stack
[currentPtr
];
5589 if (current
.isFosterParenting()) {
5591 elt
= createAndInsertFosterParentedElement("http://www.w3.org/1998/Math/MathML", popName
, attributes
5592 // CPPONLY: , htmlCreator(null)
5595 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5596 elt
= createElement("http://www.w3.org/1998/Math/MathML", popName
, attributes
, currentNode
5597 // CPPONLY: , htmlCreator(null)
5599 appendElement(elt
, currentNode
);
5601 elementPushed("http://www.w3.org/1998/Math/MathML", popName
, elt
);
5602 elementPopped("http://www.w3.org/1998/Math/MathML", popName
, elt
);
5605 private void appendVoidInputToCurrent(HtmlAttributes attributes
, T form
) throws SAXException
{
5607 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5609 // Can't be called for custom elements
5610 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5611 T elt
= createElement("http://www.w3.org/1999/xhtml", "input", attributes
,
5612 form
== null || fragment
|| isTemplateContents() ?
null : form
, currentNode
5613 // CPPONLY: , htmlCreator(NS_NewHTMLInputElement)
5615 appendElement(elt
, currentNode
);
5616 elementPushed("http://www.w3.org/1999/xhtml", "input", elt
);
5617 elementPopped("http://www.w3.org/1999/xhtml", "input", elt
);
5620 private void appendVoidFormToCurrent(HtmlAttributes attributes
) throws SAXException
{
5622 checkAttributes(attributes
, "http://www.w3.org/1999/xhtml");
5624 T currentNode
= nodeFromStackWithBlinkCompat(currentPtr
);
5625 T elt
= createElement("http://www.w3.org/1999/xhtml", "form",
5626 attributes
, currentNode
5627 // CPPONLY: , htmlCreator(NS_NewHTMLFormElement)
5630 // ownership transferred to form pointer
5631 appendElement(elt
, currentNode
);
5632 elementPushed("http://www.w3.org/1999/xhtml", "form", elt
);
5633 elementPopped("http://www.w3.org/1999/xhtml", "form", elt
);
5638 private final void accumulateCharactersForced(@Const @NoLength char[] buf
,
5639 int start
, int length
) throws SAXException
{
5640 System
.arraycopy(buf
, start
, charBuffer
, charBufferLen
, length
);
5641 charBufferLen
+= length
;
5644 @Override public void ensureBufferSpace(int inputLength
)
5645 throws SAXException
{
5646 // TODO: Unify Tokenizer.strBuf and TreeBuilder.charBuffer so that
5647 // this method becomes unnecessary.
5648 int worstCase
= charBufferLen
+ inputLength
;
5649 if (charBuffer
== null) {
5650 // Add an arbitrary small value to avoid immediate reallocation
5651 // once there are a few characters in the buffer.
5652 charBuffer
= new char[worstCase
+ 128];
5653 } else if (worstCase
> charBuffer
.length
) {
5654 // HotSpot reportedly allocates memory with 8-byte accuracy, so
5655 // there's no point in trying to do math here to avoid slop.
5656 // Maybe we should add some small constant to worstCase here
5657 // but not doing that without profiling. In C++ with jemalloc,
5658 // the corresponding method should do math to round up here
5660 char[] newBuf
= new char[worstCase
];
5661 System
.arraycopy(charBuffer
, 0, newBuf
, 0, charBufferLen
);
5662 charBuffer
= newBuf
;
5668 protected void accumulateCharacters(@Const @NoLength char[] buf
, int start
,
5669 int length
) throws SAXException
{
5670 appendCharacters(stack
[currentPtr
].node
, buf
, start
, length
);
5673 // ------------------------------- //
5675 protected final void requestSuspension() {
5676 tokenizer
.requestSuspension();
5679 protected abstract T
createElement(@NsUri String ns
, @Local String name
,
5680 HtmlAttributes attributes
, T intendedParent
5681 // CPPONLY: , @Creator Object creator
5682 ) throws SAXException
;
5684 protected T
createElement(@NsUri String ns
, @Local String name
,
5685 HtmlAttributes attributes
, T form
, T intendedParent
5686 // CPPONLY: , @Creator Object creator
5687 ) throws SAXException
{
5688 return createElement("http://www.w3.org/1999/xhtml", name
, attributes
, intendedParent
5689 // CPPONLY: , creator
5693 protected abstract T
createHtmlElementSetAsRoot(HtmlAttributes attributes
)
5694 throws SAXException
;
5696 protected abstract void detachFromParent(T element
) throws SAXException
;
5698 protected abstract boolean hasChildren(T element
) throws SAXException
;
5700 protected abstract void appendElement(T child
, T newParent
)
5701 throws SAXException
;
5703 protected abstract void appendChildrenToNewParent(T oldParent
, T newParent
)
5704 throws SAXException
;
5706 protected abstract void insertFosterParentedChild(T child
, T table
,
5707 T stackParent
) throws SAXException
;
5709 // We don't generate CPP code for this method because it is not used in generated CPP
5710 // code. Instead, the form owner version of this method is called with a null form owner.
5713 protected abstract T
createAndInsertFosterParentedElement(@NsUri String ns
, @Local String name
,
5714 HtmlAttributes attributes
, T table
, T stackParent
) throws SAXException
;
5718 protected T
createAndInsertFosterParentedElement(@NsUri String ns
, @Local String name
,
5719 HtmlAttributes attributes
, T form
, T table
, T stackParent
5720 // CPPONLY: , @Creator Object creator
5721 ) throws SAXException
{
5722 return createAndInsertFosterParentedElement(ns
, name
, attributes
, table
, stackParent
);
5725 protected abstract void insertFosterParentedCharacters(
5726 @NoLength char[] buf
, int start
, int length
, T table
, T stackParent
)
5727 throws SAXException
;
5729 protected abstract void appendCharacters(T parent
, @NoLength char[] buf
,
5730 int start
, int length
) throws SAXException
;
5732 protected abstract void appendComment(T parent
, @NoLength char[] buf
,
5733 int start
, int length
) throws SAXException
;
5735 protected abstract void appendCommentToDocument(@NoLength char[] buf
,
5736 int start
, int length
) throws SAXException
;
5738 protected abstract void addAttributesToElement(T element
,
5739 HtmlAttributes attributes
) throws SAXException
;
5741 protected void markMalformedIfScript(T elt
) throws SAXException
{
5745 protected void start(boolean fragmentMode
) throws SAXException
{
5749 protected void end() throws SAXException
{
5753 protected void appendDoctypeToDocument(@Local String name
,
5754 String publicIdentifier
, String systemIdentifier
)
5755 throws SAXException
{
5759 protected void elementPushed(@NsUri String ns
, @Local String name
, T node
)
5760 throws SAXException
{
5764 protected void elementPopped(@NsUri String ns
, @Local String name
, T node
)
5765 throws SAXException
{
5771 protected void documentMode(DocumentMode m
, String publicIdentifier
,
5772 String systemIdentifier
)
5773 throws SAXException
{
5778 * @see nu.validator.htmlparser.common.TokenHandler#wantsComments()
5780 public boolean wantsComments() {
5781 return wantingComments
;
5784 public void setIgnoringComments(boolean ignoreComments
) {
5785 wantingComments
= !ignoreComments
;
5789 * Sets the errorHandler.
5791 * @param errorHandler
5792 * the errorHandler to set
5794 public final void setErrorHandler(ErrorHandler errorHandler
) {
5795 this.errorHandler
= errorHandler
;
5799 * Returns the errorHandler.
5801 * @return the errorHandler
5803 public ErrorHandler
getErrorHandler() {
5804 return errorHandler
;
5808 * The argument MUST be an interned string or <code>null</code>.
5812 public final void setFragmentContext(@Local String context
) {
5813 this.contextName
= context
;
5814 this.contextNamespace
= "http://www.w3.org/1999/xhtml";
5815 this.contextNode
= null;
5816 this.fragment
= (contextName
!= null);
5817 this.quirks
= false;
5823 * @see nu.validator.htmlparser.common.TokenHandler#cdataSectionAllowed()
5825 @Inline public boolean cdataSectionAllowed() throws SAXException
{
5826 return isInForeign();
5829 private boolean isInForeign() {
5830 return currentPtr
>= 0
5831 && stack
[currentPtr
].ns
!= "http://www.w3.org/1999/xhtml";
5834 private boolean isInForeignButNotHtmlOrMathTextIntegrationPoint() {
5835 if (currentPtr
< 0) {
5838 return !isSpecialParentInForeign(stack
[currentPtr
]);
5842 * The argument MUST be an interned string or <code>null</code>.
5846 public final void setFragmentContext(@Local String context
,
5847 @NsUri String ns
, T node
, boolean quirks
) {
5849 if (!((context
== null && ns
== null)
5850 || "http://www.w3.org/1999/xhtml" == ns
5851 || "http://www.w3.org/2000/svg" == ns
|| "http://www.w3.org/1998/Math/MathML" == ns
)) {
5852 throw new IllegalArgumentException(
5853 "The namespace must be the HTML, SVG or MathML namespace (or null when the local name is null). Got: "
5857 this.contextName
= context
;
5858 this.contextNamespace
= ns
;
5859 this.contextNode
= node
;
5860 this.fragment
= (contextName
!= null);
5861 this.quirks
= quirks
;
5864 protected final T
currentNode() {
5865 return stack
[currentPtr
].node
;
5869 * Returns the scriptingEnabled.
5871 * @return the scriptingEnabled
5873 public boolean isScriptingEnabled() {
5874 return scriptingEnabled
;
5878 * Sets the scriptingEnabled.
5880 * @param scriptingEnabled
5881 * the scriptingEnabled to set
5883 public void setScriptingEnabled(boolean scriptingEnabled
) {
5884 this.scriptingEnabled
= scriptingEnabled
;
5887 public void setForceNoQuirks(boolean forceNoQuirks
) {
5888 this.forceNoQuirks
= forceNoQuirks
;
5891 // Redundant method retained because previously public.
5892 public void setIsSrcdocDocument(boolean isSrcdocDocument
) {
5893 this.setForceNoQuirks(isSrcdocDocument
);
5898 public void setNamePolicy(XmlViolationPolicy namePolicy
) {
5899 this.namePolicy
= namePolicy
;
5903 * Sets the documentModeHandler.
5905 * @param documentModeHandler
5906 * the documentModeHandler to set
5908 public void setDocumentModeHandler(DocumentModeHandler documentModeHandler
) {
5909 this.documentModeHandler
= documentModeHandler
;
5913 * Sets the reportingDoctype.
5915 * @param reportingDoctype
5916 * the reportingDoctype to set
5918 public void setReportingDoctype(boolean reportingDoctype
) {
5919 this.reportingDoctype
= reportingDoctype
;
5925 * Flushes the pending characters. Public for document.write use cases only.
5926 * @throws SAXException
5928 public final void flushCharacters() throws SAXException
{
5929 if (charBufferLen
> 0) {
5930 if ((mode
== IN_TABLE
|| mode
== IN_TABLE_BODY
|| mode
== IN_ROW
)
5931 && charBufferContainsNonWhitespace()) {
5932 errNonSpaceInTable();
5933 reconstructTheActiveFormattingElements();
5934 if (!stack
[currentPtr
].isFosterParenting()) {
5935 // reconstructing gave us a new current node
5936 appendCharacters(currentNode(), charBuffer
, 0,
5942 int tablePos
= findLastOrRoot(TreeBuilder
.TABLE
);
5943 int templatePos
= findLastOrRoot(TreeBuilder
.TEMPLATE
);
5945 if (templatePos
>= tablePos
) {
5946 appendCharacters(stack
[templatePos
].node
, charBuffer
, 0, charBufferLen
);
5951 StackNode
<T
> tableElt
= stack
[tablePos
];
5952 insertFosterParentedCharacters(charBuffer
, 0, charBufferLen
,
5953 tableElt
.node
, stack
[tablePos
- 1].node
);
5957 appendCharacters(currentNode(), charBuffer
, 0, charBufferLen
);
5962 private boolean charBufferContainsNonWhitespace() {
5963 for (int i
= 0; i
< charBufferLen
; i
++) {
5964 switch (charBuffer
[i
]) {
5979 * Creates a comparable snapshot of the tree builder state. Snapshot
5980 * creation is only supported immediately after a script end tag has been
5981 * processed. In C++ the caller is responsible for calling
5982 * <code>delete</code> on the returned object.
5984 * @return a snapshot.
5985 * @throws SAXException
5987 @SuppressWarnings("unchecked") public TreeBuilderState
<T
> newSnapshot()
5988 throws SAXException
{
5989 StackNode
<T
>[] listCopy
= new StackNode
[listPtr
+ 1];
5990 for (int i
= 0; i
< listCopy
.length
; i
++) {
5991 StackNode
<T
> node
= listOfActiveFormattingElements
[i
];
5993 StackNode
<T
> newNode
= new StackNode
<T
>(-1);
5994 newNode
.setValues(node
.getFlags(), node
.ns
,
5995 node
.name
, node
.node
, node
.popName
,
5996 node
.attributes
.cloneAttributes()
5997 // CPPONLY: , node.getHtmlCreator()
6002 listCopy
[i
] = newNode
;
6007 StackNode
<T
>[] stackCopy
= new StackNode
[currentPtr
+ 1];
6008 for (int i
= 0; i
< stackCopy
.length
; i
++) {
6009 StackNode
<T
> node
= stack
[i
];
6010 int listIndex
= findInListOfActiveFormattingElements(node
);
6011 if (listIndex
== -1) {
6012 StackNode
<T
> newNode
= new StackNode
<T
>(-1);
6013 newNode
.setValues(node
.getFlags(), node
.ns
,
6014 node
.name
, node
.node
, node
.popName
,
6016 // CPPONLY: , node.getHtmlCreator()
6021 stackCopy
[i
] = newNode
;
6023 stackCopy
[i
] = listCopy
[listIndex
];
6024 stackCopy
[i
].retain();
6027 int[] templateModeStackCopy
= new int[templateModePtr
+ 1];
6028 System
.arraycopy(templateModeStack
, 0, templateModeStackCopy
, 0,
6029 templateModeStackCopy
.length
);
6030 return new StateSnapshot
<T
>(stackCopy
, listCopy
, templateModeStackCopy
, formPointer
,
6031 headPointer
, mode
, originalMode
, framesetOk
,
6032 needToDropLF
, quirks
);
6035 public boolean snapshotMatches(TreeBuilderState
<T
> snapshot
) {
6036 StackNode
<T
>[] stackCopy
= snapshot
.getStack();
6037 int stackLen
= snapshot
.getStackLength();
6038 StackNode
<T
>[] listCopy
= snapshot
.getListOfActiveFormattingElements();
6039 int listLen
= snapshot
.getListOfActiveFormattingElementsLength();
6040 int[] templateModeStackCopy
= snapshot
.getTemplateModeStack();
6041 int templateModeStackLen
= snapshot
.getTemplateModeStackLength();
6043 if (stackLen
!= currentPtr
+ 1
6044 || listLen
!= listPtr
+ 1
6045 || templateModeStackLen
!= templateModePtr
+ 1
6046 || formPointer
!= snapshot
.getFormPointer()
6047 || headPointer
!= snapshot
.getHeadPointer()
6048 || mode
!= snapshot
.getMode()
6049 || originalMode
!= snapshot
.getOriginalMode()
6050 || framesetOk
!= snapshot
.isFramesetOk()
6051 || needToDropLF
!= snapshot
.isNeedToDropLF()
6052 || quirks
!= snapshot
.isQuirks()) { // maybe just assert quirks
6055 for (int i
= listLen
- 1; i
>= 0; i
--) {
6056 if (listCopy
[i
] == null
6057 && listOfActiveFormattingElements
[i
] == null) {
6059 } else if (listCopy
[i
] == null
6060 || listOfActiveFormattingElements
[i
] == null) {
6063 if (listCopy
[i
].node
!= listOfActiveFormattingElements
[i
].node
) {
6064 return false; // it's possible that this condition is overly
6068 for (int i
= stackLen
- 1; i
>= 0; i
--) {
6069 if (stackCopy
[i
].node
!= stack
[i
].node
) {
6073 for (int i
= templateModeStackLen
- 1; i
>=0; i
--) {
6074 if (templateModeStackCopy
[i
] != templateModeStack
[i
]) {
6081 @SuppressWarnings("unchecked") public void loadState(
6082 TreeBuilderState
<T
> snapshot
)
6083 throws SAXException
{
6084 // CPPONLY: mCurrentHtmlScriptCannotDocumentWriteOrBlock = false;
6085 StackNode
<T
>[] stackCopy
= snapshot
.getStack();
6086 int stackLen
= snapshot
.getStackLength();
6087 StackNode
<T
>[] listCopy
= snapshot
.getListOfActiveFormattingElements();
6088 int listLen
= snapshot
.getListOfActiveFormattingElementsLength();
6089 int[] templateModeStackCopy
= snapshot
.getTemplateModeStack();
6090 int templateModeStackLen
= snapshot
.getTemplateModeStackLength();
6092 for (int i
= 0; i
<= listPtr
; i
++) {
6093 if (listOfActiveFormattingElements
[i
] != null) {
6094 listOfActiveFormattingElements
[i
].release(this);
6097 if (listOfActiveFormattingElements
.length
< listLen
) {
6098 listOfActiveFormattingElements
= new StackNode
[listLen
];
6100 listPtr
= listLen
- 1;
6102 for (int i
= 0; i
<= currentPtr
; i
++) {
6103 stack
[i
].release(this);
6105 if (stack
.length
< stackLen
) {
6106 stack
= new StackNode
[stackLen
];
6108 currentPtr
= stackLen
- 1;
6110 if (templateModeStack
.length
< templateModeStackLen
) {
6111 templateModeStack
= new int[templateModeStackLen
];
6113 templateModePtr
= templateModeStackLen
- 1;
6115 for (int i
= 0; i
< listLen
; i
++) {
6116 StackNode
<T
> node
= listCopy
[i
];
6118 StackNode
<T
> newNode
= createStackNode(node
.getFlags(), node
.ns
,
6119 node
.name
, node
.node
,
6121 node
.attributes
.cloneAttributes()
6122 // CPPONLY: , node.getHtmlCreator()
6127 listOfActiveFormattingElements
[i
] = newNode
;
6129 listOfActiveFormattingElements
[i
] = null;
6132 for (int i
= 0; i
< stackLen
; i
++) {
6133 StackNode
<T
> node
= stackCopy
[i
];
6134 int listIndex
= findInArray(node
, listCopy
);
6135 if (listIndex
== -1) {
6136 StackNode
<T
> newNode
= createStackNode(node
.getFlags(), node
.ns
,
6137 node
.name
, node
.node
,
6140 // CPPONLY: , node.getHtmlCreator()
6147 stack
[i
] = listOfActiveFormattingElements
[listIndex
];
6151 System
.arraycopy(templateModeStackCopy
, 0, templateModeStack
, 0, templateModeStackLen
);
6152 formPointer
= snapshot
.getFormPointer();
6153 headPointer
= snapshot
.getHeadPointer();
6154 mode
= snapshot
.getMode();
6155 originalMode
= snapshot
.getOriginalMode();
6156 framesetOk
= snapshot
.isFramesetOk();
6157 needToDropLF
= snapshot
.isNeedToDropLF();
6158 quirks
= snapshot
.isQuirks();
6161 private int findInArray(StackNode
<T
> node
, StackNode
<T
>[] arr
) {
6162 for (int i
= listPtr
; i
>= 0; i
--) {
6163 if (node
== arr
[i
]) {
6171 * Returns <code>stack[stackPos].node</code> if <code>stackPos</code> is
6172 * smaller than Blink's magic limit or the node at Blink's magic limit
6175 * In order to get Blink-compatible handling of excessive deeply-nested
6176 * markup, this method must be used to obtain the node that is used as the
6177 * parent node of an insertion.
6179 * Blink's magic number is 512, but our counting is off by one compared to
6180 * Blink's way of counting, so in order to get the same
6181 * externally-observable outcome, we use 511 as our magic number.
6183 * @param stackPos the stack position to attempt to read
6184 * @return node at the position capped to Blink's magic number
6185 * @throws SAXException
6187 private T
nodeFromStackWithBlinkCompat(int stackPos
) throws SAXException
{
6188 // Magic number if off by one relative to Blink's magic number, but the
6189 // outcome is the same, because the counting is different by one.
6190 if (stackPos
> 511) {
6192 return stack
[511].node
;
6194 return stack
[stackPos
].node
;
6197 * @see nu.validator.htmlparser.impl.TreeBuilderState#getFormPointer()
6200 public T
getFormPointer() {
6205 * Returns the headPointer.
6207 * @return the headPointer
6210 public T
getHeadPointer() {
6215 * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElements()
6218 public StackNode
<T
>[] getListOfActiveFormattingElements() {
6219 return listOfActiveFormattingElements
;
6223 * @see nu.validator.htmlparser.impl.TreeBuilderState#getStack()
6226 public StackNode
<T
>[] getStack() {
6231 * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStack()
6234 public int[] getTemplateModeStack() {
6235 return templateModeStack
;
6244 public int getMode() {
6249 * Returns the originalMode.
6251 * @return the originalMode
6254 public int getOriginalMode() {
6255 return originalMode
;
6259 * Returns the framesetOk.
6261 * @return the framesetOk
6264 public boolean isFramesetOk() {
6269 * Returns the needToDropLF.
6271 * @return the needToDropLF
6274 public boolean isNeedToDropLF() {
6275 return needToDropLF
;
6279 * Returns the quirks.
6281 * @return the quirks
6284 public boolean isQuirks() {
6289 * @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElementsLength()
6292 public int getListOfActiveFormattingElementsLength() {
6297 * @see nu.validator.htmlparser.impl.TreeBuilderState#getStackLength()
6300 public int getStackLength() {
6301 return currentPtr
+ 1;
6305 * @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStackLength()
6308 public int getTemplateModeStackLength() {
6309 return templateModePtr
+ 1;
6313 * Complains about an over-deep tree. Theoretically this should just be
6314 * a warning, but in practice authors should take this as an error.
6316 * @throws SAXException
6318 private void errDeepTree() throws SAXException
{
6319 err("The document tree is more than 513 elements deep, which causes Firefox and Chrome to flatten the tree.");
6323 * Reports a stray start tag.
6324 * @param name the name of the stray tag
6326 * @throws SAXException
6328 private void errStrayStartTag(@Local String name
) throws SAXException
{
6329 err("Stray start tag \u201C" + name
+ "\u201D.");
6333 * Reports a stray end tag.
6334 * @param name the name of the stray tag
6336 * @throws SAXException
6338 private void errStrayEndTag(@Local String name
) throws SAXException
{
6339 err("Stray end tag \u201C" + name
+ "\u201D.");
6343 * Reports a state when elements expected to be closed were not.
6345 * @param eltPos the position of the start tag on the stack of the element
6347 * @param name the name of the end tag
6349 * @throws SAXException
6351 private void errUnclosedElements(int eltPos
, @Local String name
) throws SAXException
{
6352 errNoCheck("End tag \u201C" + name
+ "\u201D seen, but there were open elements.");
6353 errListUnclosedStartTags(eltPos
);
6357 * Reports a state when elements expected to be closed ahead of an implied
6358 * end tag but were not.
6360 * @param eltPos the position of the start tag on the stack of the element
6362 * @param name the name of the end tag
6364 * @throws SAXException
6366 private void errUnclosedElementsImplied(int eltPos
, String name
) throws SAXException
{
6367 errNoCheck("End tag \u201C" + name
+ "\u201D implied, but there were open elements.");
6368 errListUnclosedStartTags(eltPos
);
6372 * Reports a state when elements expected to be closed ahead of an implied
6375 * @param eltPos the position of the start tag on the stack of the element
6377 * @throws SAXException
6379 private void errUnclosedElementsCell(int eltPos
) throws SAXException
{
6380 errNoCheck("A table cell was implicitly closed, but there were open elements.");
6381 errListUnclosedStartTags(eltPos
);
6384 private void errStrayDoctype() throws SAXException
{
6385 err("Stray doctype.");
6388 private void errAlmostStandardsDoctype() throws SAXException
{
6389 if (!forceNoQuirks
) {
6390 err("Almost standards mode doctype. Expected \u201C<!DOCTYPE html>\u201D.");
6394 private void errQuirkyDoctype() throws SAXException
{
6395 if (!forceNoQuirks
) {
6396 err("Quirky doctype. Expected \u201C<!DOCTYPE html>\u201D.");
6400 private void errNonSpaceInTrailer() throws SAXException
{
6401 err("Non-space character in page trailer.");
6404 private void errNonSpaceAfterFrameset() throws SAXException
{
6405 err("Non-space after \u201Cframeset\u201D.");
6408 private void errNonSpaceInFrameset() throws SAXException
{
6409 err("Non-space in \u201Cframeset\u201D.");
6412 private void errNonSpaceAfterBody() throws SAXException
{
6413 err("Non-space character after body.");
6416 private void errNonSpaceInColgroupInFragment() throws SAXException
{
6417 err("Non-space in \u201Ccolgroup\u201D when parsing fragment.");
6420 private void errNonSpaceInNoscriptInHead() throws SAXException
{
6421 err("Non-space character inside \u201Cnoscript\u201D inside \u201Chead\u201D.");
6424 private void errFooBetweenHeadAndBody(@Local String name
) throws SAXException
{
6425 if (errorHandler
== null) {
6428 errNoCheck("\u201C" + name
+ "\u201D element between \u201Chead\u201D and \u201Cbody\u201D.");
6431 private void errStartTagWithoutDoctype() throws SAXException
{
6432 if (!forceNoQuirks
) {
6433 err("Start tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
6437 private void errNoSelectInTableScope() throws SAXException
{
6438 err("No \u201Cselect\u201D in table scope.");
6441 private void errStartSelectWhereEndSelectExpected() throws SAXException
{
6442 err("\u201Cselect\u201D start tag where end tag expected.");
6445 private void errStartTagWithSelectOpen(@Local String name
)
6446 throws SAXException
{
6447 if (errorHandler
== null) {
6450 errNoCheck("\u201C" + name
6451 + "\u201D start tag with \u201Cselect\u201D open.");
6454 private void errBadStartTagInNoscriptInHead(@Local String name
) throws SAXException
{
6455 if (errorHandler
== null) {
6458 errNoCheck("Bad start tag in \u201C" + name
6459 + "\u201D in \u201Cnoscript\u201D in \u201Chead\u201D.");
6462 private void errImage() throws SAXException
{
6463 err("Saw a start tag \u201Cimage\u201D.");
6466 private void errFooSeenWhenFooOpen(@Local String name
) throws SAXException
{
6467 if (errorHandler
== null) {
6470 errNoCheck("Start tag \u201C" + name
+ "\u201D seen but an element of the same type was already open.");
6473 private void errHeadingWhenHeadingOpen() throws SAXException
{
6474 err("Heading cannot be a child of another heading.");
6477 private void errFramesetStart() throws SAXException
{
6478 err("\u201Cframeset\u201D start tag seen.");
6481 private void errNoCellToClose() throws SAXException
{
6482 err("No cell to close.");
6485 private void errStartTagInTable(@Local String name
) throws SAXException
{
6486 if (errorHandler
== null) {
6489 errNoCheck("Start tag \u201C" + name
6490 + "\u201D seen in \u201Ctable\u201D.");
6493 private void errFormWhenFormOpen() throws SAXException
{
6494 err("Saw a \u201Cform\u201D start tag, but there was already an active \u201Cform\u201D element. Nested forms are not allowed. Ignoring the tag.");
6497 private void errTableSeenWhileTableOpen() throws SAXException
{
6498 err("Start tag for \u201Ctable\u201D seen but the previous \u201Ctable\u201D is still open.");
6501 private void errStartTagInTableBody(@Local String name
) throws SAXException
{
6502 if (errorHandler
== null) {
6505 errNoCheck("\u201C" + name
+ "\u201D start tag in table body.");
6508 private void errEndTagSeenWithoutDoctype() throws SAXException
{
6509 if (!forceNoQuirks
) {
6510 err("End tag seen without seeing a doctype first. Expected \u201C<!DOCTYPE html>\u201D.");
6514 private void errEndTagAfterBody() throws SAXException
{
6515 err("Saw an end tag after \u201Cbody\u201D had been closed.");
6518 private void errEndTagSeenWithSelectOpen(@Local String name
) throws SAXException
{
6519 if (errorHandler
== null) {
6522 errNoCheck("\u201C" + name
6523 + "\u201D end tag with \u201Cselect\u201D open.");
6526 private void errGarbageInColgroup() throws SAXException
{
6527 err("Garbage in \u201Ccolgroup\u201D fragment.");
6530 private void errEndTagBr() throws SAXException
{
6531 err("End tag \u201Cbr\u201D.");
6534 private void errNoElementToCloseButEndTagSeen(@Local String name
)
6535 throws SAXException
{
6536 if (errorHandler
== null) {
6539 errNoCheck("No \u201C" + name
+ "\u201D element in scope but a \u201C"
6540 + name
+ "\u201D end tag seen.");
6543 private void errHtmlStartTagInForeignContext(@Local String name
)
6544 throws SAXException
{
6545 if (errorHandler
== null) {
6548 errNoCheck("HTML start tag \u201C" + name
6549 + "\u201D in a foreign namespace context.");
6552 private void errNoTableRowToClose() throws SAXException
{
6553 err("No table row to close.");
6556 private void errNonSpaceInTable() throws SAXException
{
6557 err("Misplaced non-space characters inside a table.");
6560 private void errUnclosedChildrenInRuby() throws SAXException
{
6561 if (errorHandler
== null) {
6564 errNoCheck("Unclosed children in \u201Cruby\u201D.");
6567 private void errStartTagSeenWithoutRuby(@Local String name
) throws SAXException
{
6568 if (errorHandler
== null) {
6571 errNoCheck("Start tag \u201C"
6573 + "\u201D seen without a \u201Cruby\u201D element being open.");
6576 private void errSelfClosing() throws SAXException
{
6577 if (errorHandler
== null) {
6580 errNoCheck("Self-closing syntax (\u201C/>\u201D) used on a non-void HTML element. Ignoring the slash and treating as a start tag.");
6583 private void errNoCheckUnclosedElementsOnStack() throws SAXException
{
6584 errNoCheck("Unclosed elements on stack.");
6587 private void errEndTagDidNotMatchCurrentOpenElement(@Local String name
,
6588 @Local String currOpenName
) throws SAXException
{
6589 if (errorHandler
== null) {
6592 errNoCheck("End tag \u201C"
6594 + "\u201D did not match the name of the current open element (\u201C"
6595 + currOpenName
+ "\u201D).");
6598 private void errEndTagViolatesNestingRules(@Local String name
) throws SAXException
{
6599 if (errorHandler
== null) {
6602 errNoCheck("End tag \u201C" + name
+ "\u201D violates nesting rules.");
6605 private void errEofWithUnclosedElements() throws SAXException
{
6606 if (errorHandler
== null) {
6609 errNoCheck("End of file seen and there were open elements.");
6610 // just report all remaining unclosed elements
6611 errListUnclosedStartTags(0);
6615 * Reports arriving at/near end of document with unclosed elements remaining.
6619 * @throws SAXException
6621 private void errEndWithUnclosedElements(@Local String name
) throws SAXException
{
6622 if (errorHandler
== null) {
6625 errNoCheck("End tag for \u201C"
6627 + "\u201D seen, but there were unclosed elements.");
6628 // just report all remaining unclosed elements
6629 errListUnclosedStartTags(0);